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