ypxfr.c revision 1.7 1 /* $NetBSD: ypxfr.c,v 1.7 1998/08/27 20:31:03 ross 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.7 1998/08/27 20:31:03 ross 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
385 return status;
386 }
387
388 void
389 get_map(client, domain, map, incallback)
390 CLIENT *client;
391 char *domain, *map;
392 struct ypall_callback *incallback;
393 {
394
395 (void)yp_all_host(client, domain, map, incallback);
396 }
397
398 DBM *
399 create_db(domain, map, temp_map)
400 char *domain, *map, *temp_map;
401 {
402 char db_temp[255];
403 DBM *db;
404
405 snprintf(db_temp, sizeof(db_temp), "%s/%s/%s",
406 YP_DB_PATH, domain, temp_map);
407 db_temp[sizeof(db_temp) - 1] = '\0';
408
409 db = ypdb_open(db_temp, O_RDWR|O_CREAT|O_EXCL, 0444);
410
411 return db;
412 }
413
414 int
415 install_db(domain, map, temp_map)
416 char *domain, *map, *temp_map;
417 {
418 char db_name[255], db_temp[255];
419
420 snprintf(db_name, sizeof(db_name), "%s/%s/%s%s",
421 YP_DB_PATH, domain, map, YPDB_SUFFIX);
422 db_name[sizeof(db_name) - 1] = '\0';
423
424 snprintf(db_temp, sizeof(db_temp), "%s/%s/%s%s",
425 YP_DB_PATH, domain, temp_map, YPDB_SUFFIX);
426 db_temp[sizeof(db_temp) - 1] = '\0';
427
428 if (rename(db_temp, db_name)) {
429 warn("can't rename `%s' -> `%s'", db_temp, db_name);
430 return YPPUSH_YPERR;
431 }
432
433 return YPPUSH_SUCC;
434 }
435
436 int
437 unlink_db(domain, map, temp_map)
438 char *domain, *map, *temp_map;
439 {
440 char db_temp[255];
441
442 snprintf(db_temp, sizeof(db_temp), "%s/%s/%s%s",
443 YP_DB_PATH, domain, temp_map, YPDB_SUFFIX);
444 db_temp[sizeof(db_temp) - 1] = '\0';
445
446 if (unlink(db_temp)) {
447 warn("can't unlink `%s'", db_temp);
448 return YPPUSH_YPERR;
449 }
450
451 return YPPUSH_SUCC;
452 }
453
454 int
455 add_order(db, ordernum)
456 DBM *db;
457 u_int ordernum;
458 {
459 char datestr[11];
460 datum key, val;
461 char keystr[] = YP_LAST_KEY;
462 int status;
463
464 snprintf(datestr, sizeof(datestr), "%010d", ordernum);
465 datestr[sizeof(datestr) - 1] = '\0';
466
467 key.dptr = keystr;
468 key.dsize = strlen(keystr);
469
470 val.dptr = datestr;
471 val.dsize = strlen(datestr);
472
473 status = ypdb_store(db, key, val, YPDB_INSERT);
474 if(status >= 0)
475 status = YPPUSH_SUCC;
476 else
477 status = YPPUSH_DBM;
478
479 return (status);
480 }
481
482 int
483 add_master(client, domain, map, db)
484 CLIENT *client;
485 char *domain, *map;
486 DBM *db;
487 {
488 char keystr[] = YP_MASTER_KEY;
489 char *master;
490 int status;
491 datum key, val;
492
493 master = NULL;
494
495 /* Get MASTER */
496 status = yp_master_host(client, domain, map, &master);
497
498 if (master != NULL) {
499 key.dptr = keystr;
500 key.dsize = strlen(keystr);
501
502 val.dptr = master;
503 val.dsize = strlen(master);
504
505 status = ypdb_store(db, key, val, YPDB_INSERT);
506 if (status >= 0)
507 status = YPPUSH_SUCC;
508 else
509 status = YPPUSH_DBM;
510 }
511
512 return status;
513 }
514
515 int
516 add_interdomain(client, domain, map, db)
517 CLIENT *client;
518 char *domain, *map;
519 DBM *db;
520 {
521 char keystr[] = YP_INTERDOMAIN_KEY;
522 char *value;
523 int vallen;
524 int status;
525 datum k, v;
526
527 /* Get INTERDOMAIN */
528 k.dptr = keystr;
529 k.dsize = strlen(keystr);
530
531 status = yp_match_host(client, domain, map,
532 k.dptr, k.dsize, &value, &vallen);
533
534 if (status == 0 && value) {
535 v.dptr = value;
536 v.dsize = vallen;
537
538 if (v.dptr != NULL) {
539 status = ypdb_store(db, k, v, YPDB_INSERT);
540 if (status >= 0)
541 status = YPPUSH_SUCC;
542 else
543 status = YPPUSH_DBM;
544 }
545 }
546
547 return status;
548 }
549
550 int
551 add_secure(client, domain, map, db)
552 CLIENT *client;
553 char *domain, *map;
554 DBM *db;
555 {
556 char keystr[] = YP_SECURE_KEY;
557 char *value;
558 int vallen;
559 int status;
560 datum k, v;
561
562 /* Get SECURE */
563 k.dptr = keystr;
564 k.dsize = strlen(keystr);
565
566 status = yp_match_host(client, domain, map,
567 k.dptr, k.dsize, &value, &vallen);
568
569 if (status > 0) {
570 v.dptr = value;
571 v.dsize = vallen;
572
573 if (v.dptr != NULL) {
574 status = ypdb_store(db, k, v, YPDB_INSERT);
575 if (status >= 0)
576 status = YPPUSH_SUCC;
577 else
578 status = YPPUSH_DBM;
579 }
580 }
581
582 return status;
583 }
584
585 int
586 send_clear(client)
587 CLIENT *client;
588 {
589 struct timeval tv;
590 int r;
591 int status;
592
593 status = YPPUSH_SUCC;
594
595 tv.tv_sec = 10;
596 tv.tv_usec = 0;
597
598 /* Send CLEAR */
599 r = clnt_call(client, YPPROC_CLEAR, xdr_void, 0, xdr_void, 0, tv);
600 if (r != RPC_SUCCESS) {
601 clnt_perror(client, "yp_clear: clnt_call");
602 status = YPPUSH_RPC;
603 }
604
605 return status;
606 }
607
608 int
609 send_reply(client, status, tid)
610 CLIENT *client;
611 int status, tid;
612 {
613 struct timeval tv;
614 struct ypresp_xfr resp;
615 int r;
616
617 tv.tv_sec = 10;
618 tv.tv_usec = 0;
619
620 resp.transid = tid;
621 resp.xfrstat = status;
622
623 /* Send XFRRESP */
624 r = clnt_call(client, YPPUSHPROC_XFRRESP, xdr_ypresp_xfr, &resp,
625 xdr_void, 0, tv);
626 if (r != RPC_SUCCESS) {
627 clnt_perror(client, "yppushresp_xdr: clnt_call");
628 status = YPPUSH_RPC;
629 }
630
631 return status;
632 }
633