ypxfr.c revision 1.4 1 /* $NetBSD: ypxfr.c,v 1.4 1997/07/18 21:57:24 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 1994 Mats O Jansson <moj (at) stacken.kth.se>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Mats O Jansson
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
22 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <sys/socket.h>
37
38 #include <netinet/in.h>
39 #include <arpa/inet.h>
40
41 #include <err.h>
42 #include <fcntl.h>
43 #include <netdb.h>
44 #include <string.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <unistd.h>
48
49 #include <rpc/rpc.h>
50 #include <rpc/xdr.h>
51 #include <rpcsvc/yp_prot.h>
52 #include <rpcsvc/ypclnt.h>
53
54 #include "yplib_host.h"
55 #include "yplog.h"
56 #include "ypdb.h"
57 #include "ypdef.h"
58
59 extern char *__progname; /* from crt0.o */
60 extern char *optarg;
61 extern int optind;
62
63 DBM *db;
64
65 static int ypxfr_foreach __P((int, char *, int, char *, int, char *));
66
67 int main __P((int, char *[]));
68 int get_local_ordernum __P((char *, char *, u_int *));
69 int get_remote_ordernum __P((CLIENT *, char *, char *, u_int, u_int *));
70 void get_map __P((CLIENT *, char *, char *, struct ypall_callback *));
71 DBM *create_db __P((char *, char *, char *));
72 int install_db __P((char *, char *, char *));
73 int unlink_db __P((char *, char *, char *));
74 int add_order __P((DBM *, u_int));
75 int add_master __P((CLIENT *, char *, char *, DBM *));
76 int add_interdomain __P((CLIENT *, char *, char *, DBM *));
77 int add_secure __P((CLIENT *, char *, char *, DBM *));
78 int send_clear __P((CLIENT *));
79 int send_reply __P((CLIENT *, int, int));
80
81 int
82 main(argc, argv)
83 int argc;
84 char *argv[];
85 {
86 int need_usage = 0, cflag = 0, fflag = 0, Cflag = 0;
87 int ch;
88 char *domain;
89 char *host = NULL;
90 char *srcdomain = NULL;
91 char *tid = NULL;
92 char *prog = NULL;
93 char *ipadd = NULL;
94 char *port = NULL;
95 char *map = NULL;
96 u_int ordernum, new_ordernum;
97 struct ypall_callback callback;
98 CLIENT *client;
99 char mapname[] = "ypdbXXXXXX";
100 int status, xfr_status;
101
102 status = YPPUSH_SUCC;
103 client = NULL;
104
105 if (yp_get_default_domain(&domain))
106 errx(1, "can't get YP domain name");
107
108 while ((ch = getopt(argc, argv, "cd:fh:s:C:")) != -1) {
109 switch (ch) {
110 case 'c':
111 cflag = 1;
112 break;
113
114 case 'd':
115 domain = optarg;
116 break;
117
118 case 'f':
119 fflag = 1;
120 break;
121
122 case 'h':
123 host = optarg;
124 break;
125
126 case 's':
127 srcdomain = optarg;
128 break;
129
130 case 'C':
131 if (optind + 3 >= argc) {
132 need_usage = 1;
133 optind = argc;
134 break;
135 }
136 Cflag = 1;
137 tid = optarg;
138 prog = argv[optind++];
139 ipadd = argv[optind++];
140 port = argv[optind++];
141 break;
142
143 default:
144 need_usage = 1;
145 }
146 }
147 argc -= optind; argv += optind;
148
149 if (argc != 1)
150 need_usage = 1;
151
152 map = argv[0];
153
154 if (need_usage) {
155 status = YPPUSH_BADARGS;
156 fprintf(stderr, "usage: %s [-cf] [-d domain] [-h host] %s\n",
157 __progname, "[-s domain] [-C tid prog ipadd port] mapname");
158 goto punt;
159 }
160
161 ypopenlog();
162
163 yplog("ypxfr: Arguments:");
164 yplog("YP clear to local: %s", (cflag) ? "no" : "yes");
165 yplog(" Force transfer: %s", (fflag) ? "yes" : "no");
166 yplog(" domain: %s", domain);
167 yplog(" host: %s", host);
168 yplog(" source domain: %s", srcdomain);
169 yplog(" transid: %s", tid);
170 yplog(" prog: %s", prog);
171 yplog(" port: %s", port);
172 yplog(" ipadd: %s", ipadd);
173 yplog(" map: %s", map);
174
175 if (fflag != 0)
176 ordernum = 0;
177 else {
178 status = get_local_ordernum(domain, map, &ordernum);
179 if (status < 0)
180 goto punt;
181 }
182
183 yplog("Get Master");
184
185 if (host == NULL) {
186 if (srcdomain == NULL)
187 status = yp_master(domain,map,&host);
188 else
189 status = yp_master(srcdomain,map,&host);
190
191 if (status == 0)
192 status = YPPUSH_SUCC;
193 else {
194 status = -status;
195 goto punt;
196 }
197 }
198
199 yplog("Connect host: %s", host);
200
201 client = yp_bind_host(host,YPPROG,YPVERS,0,1);
202
203 status = get_remote_ordernum(client,domain,map,
204 ordernum,&new_ordernum);
205
206
207 if (status == YPPUSH_SUCC) {
208 /* Create temporary db */
209 mktemp(mapname);
210 db = create_db(domain,map,mapname);
211 if (db == NULL)
212 status = YPPUSH_DBM;
213
214 /* Add ORDER */
215 if (status > 0)
216 status = add_order(db, new_ordernum);
217
218 /* Add MASTER */
219 if (status > 0)
220 status = add_master(client, domain, map, db);
221
222 /* Add INTERDOMAIN */
223 if (status > 0)
224 status = add_interdomain(client, domain, map, db);
225
226 /* Add SECURE */
227 if (status > 0)
228 status = add_secure(client, domain, map, db);
229
230 if (status > 0) {
231 callback.foreach = ypxfr_foreach;
232 get_map(client, domain, map, &callback);
233 }
234
235 /* Close db */
236 if (db != NULL)
237 ypdb_close(db);
238
239 /* Rename db */
240 if (status > 0)
241 status = install_db(domain, map, mapname);
242 else
243 status = unlink_db(domain, map, mapname);
244 }
245
246 punt:
247 xfr_status = status;
248
249 if (client != NULL)
250 clnt_destroy(client);
251
252 /* YP_CLEAR */
253 if (!cflag) {
254 client = yp_bind_local(YPPROG, YPVERS);
255 status = send_clear(client);
256 clnt_destroy(client);
257 }
258
259 if (Cflag > 0) {
260 /* Send Response */
261 client = yp_bind_host(ipadd, atoi(prog), 1, atoi(port), 0);
262 status = send_reply(client, xfr_status, atoi(tid));
263 clnt_destroy(client);
264 }
265
266 exit (0);
267 }
268
269 static int
270 ypxfr_foreach(status, keystr, keylen, valstr, vallen, data)
271 int status;
272 char *keystr;
273 int keylen;
274 char *valstr;
275 int vallen;
276 char *data;
277 {
278 datum key, val;
279
280 if (status == YP_NOMORE)
281 return (0);
282
283 keystr[keylen] = '\0';
284 valstr[vallen] = '\0';
285
286 key.dptr = keystr;
287 key.dsize = strlen(keystr);
288
289 val.dptr = valstr;
290 val.dsize = strlen(valstr);
291
292 ypdb_store(db, key, val, YPDB_INSERT);
293
294 return (0);
295 }
296
297 int
298 get_local_ordernum(domain, map, lordernum)
299 char *domain, *map;
300 u_int *lordernum;
301 {
302 char map_path[1024];
303 char order_key[] = YP_LAST_KEY;
304 char order[MAX_LAST_LEN+1];
305 struct stat finfo;
306 DBM *db;
307 datum k,v;
308 int status;
309
310 status = YPPUSH_SUCC;
311
312 snprintf(map_path, sizeof(map_path), "%s/%s", YP_DB_PATH, domain);
313 map_path[sizeof(map_path) - 1] = '\0';
314
315 /* Make sure we serve the domain. */
316 if ((stat(map_path, &finfo)) != 0 ||
317 (S_ISDIR(finfo.st_mode) == 0)) {
318 warnx("domain `%s' not found locally", domain);
319 status = YPPUSH_NODOM;
320 goto out;
321 }
322
323 /* Make sure we serve the map. */
324 snprintf(map_path, sizeof(map_path), "%s/%s/%s%s",
325 YP_DB_PATH, domain, map, YPDB_SUFFIX);
326 map_path[sizeof(map_path) - 1] = '\0';
327 if (stat(map_path, &finfo) != 0) {
328 status = YPPUSH_NOMAP;
329 goto out;
330 }
331
332 /* Open the map file. */
333 snprintf(map_path, sizeof(map_path), "%s/%s/%s",
334 YP_DB_PATH, domain, map);
335 map_path[sizeof(map_path) - 1] = '\0';
336 db = ypdb_open(map_path, O_RDONLY, 0444);
337 if (db == NULL) {
338 status = YPPUSH_DBM;
339 goto out;
340 }
341
342 k.dptr = (char *)&order_key;
343 k.dsize = YP_LAST_LEN;
344
345 v = ypdb_fetch(db, k);
346 ypdb_close(db);
347
348 if (v.dptr == NULL)
349 *lordernum = 0;
350 else {
351 strncpy(order, v.dptr, v.dsize);
352 order[v.dsize] = '\0';
353 *lordernum = (u_int)atoi((char *)&order);
354 }
355
356 out:
357 if ((status == YPPUSH_NOMAP) || (status == YPPUSH_DBM)) {
358 *lordernum = 0;
359 status = YPPUSH_SUCC;
360 }
361
362 return (status);
363 }
364
365 int
366 get_remote_ordernum(client, domain, map, lordernum, rordernum)
367 CLIENT *client;
368 char *domain, *map;
369 u_int lordernum, *rordernum;
370 {
371 int status;
372
373 status = yp_order_host(client, domain, map, (int *)rordernum);
374
375 if (status == 0)
376 if (*rordernum <= lordernum)
377 status = YPPUSH_AGE;
378 else
379 status = YPPUSH_SUCC;
380
381 return status;
382 }
383
384 void
385 get_map(client, domain, map, incallback)
386 CLIENT *client;
387 char *domain, *map;
388 struct ypall_callback *incallback;
389 {
390
391 (void)yp_all_host(client, domain, map, incallback);
392 }
393
394 DBM *
395 create_db(domain, map, temp_map)
396 char *domain, *map, *temp_map;
397 {
398 char db_temp[255];
399 DBM *db;
400
401 snprintf(db_temp, sizeof(db_temp), "%s/%s/%s",
402 YP_DB_PATH, domain, temp_map);
403 db_temp[sizeof(db_temp) - 1] = '\0';
404
405 db = ypdb_open(db_temp, O_RDWR|O_CREAT|O_EXCL, 0444);
406
407 return db;
408 }
409
410 int
411 install_db(domain,map,temp_map)
412 char *domain, *map, *temp_map;
413 {
414 char db_name[255], db_temp[255];
415
416 snprintf(db_name, sizeof(db_name), "%s/%s/%s%s",
417 YP_DB_PATH, domain, map, YPDB_SUFFIX);
418 db_name[sizeof(db_name) - 1] = '\0';
419
420 snprintf(db_temp, sizeof(db_temp), "%s/%s/%s%s",
421 YP_DB_PATH, domain, temp_map, YPDB_SUFFIX);
422 db_temp[sizeof(db_temp) - 1] = '\0';
423
424 if (rename(db_temp, db_name)) {
425 warn("can't rename `%s' -> `%s'", db_temp, db_name);
426 return YPPUSH_YPERR;
427 }
428
429 return YPPUSH_SUCC;
430 }
431
432 int
433 unlink_db(domain, map, temp_map)
434 char *domain, *map, *temp_map;
435 {
436 char db_temp[255];
437
438 snprintf(db_temp, sizeof(db_temp), "%s/%s/%s%s",
439 YP_DB_PATH, domain, temp_map, YPDB_SUFFIX);
440 db_temp[sizeof(db_temp) - 1] = '\0';
441
442 if (unlink(db_temp)) {
443 warn("can't unlink `%s'", db_temp);
444 return YPPUSH_YPERR;
445 }
446
447 return YPPUSH_SUCC;
448 }
449
450 int
451 add_order(db, ordernum)
452 DBM *db;
453 u_int ordernum;
454 {
455 char datestr[11];
456 datum key, val;
457 char keystr[] = YP_LAST_KEY;
458 int status;
459
460 snprintf(datestr, sizeof(datestr), "%010d", ordernum);
461 datestr[sizeof(datestr) - 1] = '\0';
462
463 key.dptr = keystr;
464 key.dsize = strlen(keystr);
465
466 val.dptr = datestr;
467 val.dsize = strlen(datestr);
468
469 status = ypdb_store(db, key, val, YPDB_INSERT);
470 if(status >= 0)
471 status = YPPUSH_SUCC;
472 else
473 status = YPPUSH_DBM;
474
475 return (status);
476 }
477
478 int
479 add_master(client, domain, map, db)
480 CLIENT *client;
481 char *domain, *map;
482 DBM *db;
483 {
484 char keystr[] = YP_MASTER_KEY;
485 char *master;
486 int status;
487 datum key,val;
488
489 master = NULL;
490
491 /* Get MASTER */
492 status = yp_master_host(client, domain, map, &master);
493
494 if (master != NULL) {
495 key.dptr = keystr;
496 key.dsize = strlen(keystr);
497
498 val.dptr = master;
499 val.dsize = strlen(master);
500
501 status = ypdb_store(db, key, val, YPDB_INSERT);
502 if (status >= 0)
503 status = YPPUSH_SUCC;
504 else
505 status = YPPUSH_DBM;
506 }
507
508 return status;
509 }
510
511 int
512 add_interdomain(client, domain, map, db)
513 CLIENT *client;
514 char *domain, *map;
515 DBM *db;
516 {
517 char keystr[] = YP_INTERDOMAIN_KEY;
518 char *value;
519 int vallen;
520 int status;
521 datum k, v;
522
523 /* Get INTERDOMAIN */
524 k.dptr = keystr;
525 k.dsize = strlen(keystr);
526
527 status = yp_match_host(client, domain, map,
528 k.dptr, k.dsize, &value, &vallen);
529
530 if (status == 0 && value) {
531 v.dptr = value;
532 v.dsize = vallen;
533
534 if (v.dptr != NULL) {
535 status = ypdb_store(db, k, v, YPDB_INSERT);
536 if (status >= 0)
537 status = YPPUSH_SUCC;
538 else
539 status = YPPUSH_DBM;
540 }
541 }
542
543 return status;
544 }
545
546 int
547 add_secure(client, domain, map, db)
548 CLIENT *client;
549 char *domain, *map;
550 DBM *db;
551 {
552 char keystr[] = YP_SECURE_KEY;
553 char *value;
554 int vallen;
555 int status;
556 datum k, v;
557
558 /* Get SECURE */
559 k.dptr = keystr;
560 k.dsize = strlen(keystr);
561
562 status = yp_match_host(client, domain, map,
563 k.dptr, k.dsize, &value, &vallen);
564
565 if (status > 0) {
566 v.dptr = value;
567 v.dsize = vallen;
568
569 if (v.dptr != NULL) {
570 status = ypdb_store(db, k, v, YPDB_INSERT);
571 if (status >= 0)
572 status = YPPUSH_SUCC;
573 else
574 status = YPPUSH_DBM;
575 }
576 }
577
578 return status;
579 }
580
581 int
582 send_clear(client)
583 CLIENT *client;
584 {
585 struct timeval tv;
586 int r;
587 int status;
588
589 status = YPPUSH_SUCC;
590
591 tv.tv_sec = 10;
592 tv.tv_usec = 0;
593
594 /* Send CLEAR */
595 r = clnt_call(client, YPPROC_CLEAR, xdr_void, 0, xdr_void, 0, tv);
596 if (r != RPC_SUCCESS) {
597 clnt_perror(client, "yp_clear: clnt_call");
598 status = YPPUSH_RPC;
599 }
600
601 return status;
602 }
603
604 int
605 send_reply(client, status, tid)
606 CLIENT *client;
607 int status, tid;
608 {
609 struct timeval tv;
610 struct ypresp_xfr resp;
611 int r;
612
613 tv.tv_sec = 10;
614 tv.tv_usec = 0;
615
616 resp.transid = tid;
617 resp.xfrstat = status;
618
619 /* Send XFRRESP */
620 r = clnt_call(client, YPPUSHPROC_XFRRESP, xdr_ypresp_xfr, &resp,
621 xdr_void, 0, tv);
622 if (r != RPC_SUCCESS) {
623 clnt_perror(client, "yppushresp_xdr: clnt_call");
624 status = YPPUSH_RPC;
625 }
626
627 return status;
628 }
629