ypxfr.c revision 1.9 1 /* $NetBSD: ypxfr.c,v 1.9 1999/07/25 09:36:02 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.9 1999/07/25 09:36:02 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 <syslog.h>
53 #include <unistd.h>
54
55 #include <rpc/rpc.h>
56 #include <rpc/xdr.h>
57 #include <rpcsvc/yp_prot.h>
58 #include <rpcsvc/ypclnt.h>
59
60 #include "yplib_host.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 #ifdef DEBUG
165 openlog(__progname, LOG_PID, LOG_DAEMON);
166
167 syslog(LOG_DEBUG, "ypxfr: Arguments:");
168 syslog(LOG_DEBUG, "YP clear to local: %s", (cflag) ? "no" : "yes");
169 syslog(LOG_DEBUG, " Force transfer: %s", (fflag) ? "yes" : "no");
170 syslog(LOG_DEBUG, " domain: %s", domain);
171 syslog(LOG_DEBUG, " host: %s", host);
172 syslog(LOG_DEBUG, " source domain: %s", srcdomain);
173 syslog(LOG_DEBUG, " transid: %s", tid);
174 syslog(LOG_DEBUG, " prog: %s", prog);
175 syslog(LOG_DEBUG, " port: %s", port);
176 syslog(LOG_DEBUG, " ipadd: %s", ipadd);
177 syslog(LOG_DEBUG, " map: %s", map);
178 #endif
179
180 if (fflag != 0)
181 ordernum = 0;
182 else {
183 status = get_local_ordernum(domain, map, &ordernum);
184 if (status < 0)
185 goto punt;
186 }
187
188 syslog(LOG_DEBUG, "Get Master");
189
190 if (host == NULL) {
191 if (srcdomain == NULL)
192 status = yp_master(domain, map, &host);
193 else
194 status = yp_master(srcdomain, map, &host);
195
196 if (status == 0)
197 status = YPPUSH_SUCC;
198 else {
199 status = -status;
200 goto punt;
201 }
202 }
203
204 syslog(LOG_DEBUG, "Connect host: %s", host);
205
206 client = yp_bind_host(host, YPPROG, YPVERS, 0, 1);
207
208 status = get_remote_ordernum(client, domain, map, ordernum,
209 &new_ordernum);
210
211
212 if (status == YPPUSH_SUCC) {
213 /* Create temporary db */
214 mktemp(mapname);
215 db = create_db(domain, map, mapname);
216 if (db == NULL)
217 status = YPPUSH_DBM;
218
219 /* Add ORDER */
220 if (status > 0)
221 status = add_order(db, new_ordernum);
222
223 /* Add MASTER */
224 if (status > 0)
225 status = add_master(client, domain, map, db);
226
227 /* Add INTERDOMAIN */
228 if (status > 0)
229 status = add_interdomain(client, domain, map, db);
230
231 /* Add SECURE */
232 if (status > 0)
233 status = add_secure(client, domain, map, db);
234
235 if (status > 0) {
236 callback.foreach = ypxfr_foreach;
237 get_map(client, domain, map, &callback);
238 }
239
240 /* Close db */
241 if (db != NULL)
242 ypdb_close(db);
243
244 /* Rename db */
245 if (status > 0)
246 status = install_db(domain, map, mapname);
247 else
248 status = unlink_db(domain, map, mapname);
249 }
250
251 punt:
252 xfr_status = status;
253
254 if (client != NULL)
255 clnt_destroy(client);
256
257 /* YP_CLEAR */
258 if (!cflag) {
259 client = yp_bind_local(YPPROG, YPVERS);
260 status = send_clear(client);
261 clnt_destroy(client);
262 }
263
264 if (Cflag > 0) {
265 /* Send Response */
266 client = yp_bind_host(ipadd, atoi(prog), 1, atoi(port), 0);
267 status = send_reply(client, xfr_status, atoi(tid));
268 clnt_destroy(client);
269 }
270
271 exit (0);
272 }
273
274 static int
275 ypxfr_foreach(status, keystr, keylen, valstr, vallen, data)
276 int status;
277 char *keystr;
278 int keylen;
279 char *valstr;
280 int vallen;
281 char *data;
282 {
283 datum key, val;
284
285 if (status == YP_NOMORE)
286 return (0);
287
288 keystr[keylen] = '\0';
289 valstr[vallen] = '\0';
290
291 key.dptr = keystr;
292 key.dsize = strlen(keystr);
293
294 val.dptr = valstr;
295 val.dsize = strlen(valstr);
296
297 ypdb_store(db, key, val, YPDB_INSERT);
298
299 return (0);
300 }
301
302 int
303 get_local_ordernum(domain, map, lordernum)
304 char *domain, *map;
305 u_int *lordernum;
306 {
307 char map_path[1024];
308 char order_key[] = YP_LAST_KEY;
309 char order[MAX_LAST_LEN+1];
310 struct stat finfo;
311 DBM *db;
312 datum k, v;
313 int status;
314
315 status = YPPUSH_SUCC;
316
317 snprintf(map_path, sizeof(map_path), "%s/%s", YP_DB_PATH, domain);
318 map_path[sizeof(map_path) - 1] = '\0';
319
320 /* Make sure we serve the domain. */
321 if ((stat(map_path, &finfo)) != 0 ||
322 (S_ISDIR(finfo.st_mode) == 0)) {
323 warnx("domain `%s' not found locally", domain);
324 status = YPPUSH_NODOM;
325 goto out;
326 }
327
328 /* Make sure we serve the map. */
329 snprintf(map_path, sizeof(map_path), "%s/%s/%s%s",
330 YP_DB_PATH, domain, map, YPDB_SUFFIX);
331 map_path[sizeof(map_path) - 1] = '\0';
332 if (stat(map_path, &finfo) != 0) {
333 status = YPPUSH_NOMAP;
334 goto out;
335 }
336
337 /* Open the map file. */
338 snprintf(map_path, sizeof(map_path), "%s/%s/%s",
339 YP_DB_PATH, domain, map);
340 map_path[sizeof(map_path) - 1] = '\0';
341 db = ypdb_open(map_path, O_RDONLY, 0444);
342 if (db == NULL) {
343 status = YPPUSH_DBM;
344 goto out;
345 }
346
347 k.dptr = (char *)&order_key;
348 k.dsize = YP_LAST_LEN;
349
350 v = ypdb_fetch(db, k);
351
352 if (v.dptr == NULL)
353 *lordernum = 0;
354 else {
355 strncpy(order, v.dptr, v.dsize);
356 order[v.dsize] = '\0';
357 *lordernum = (u_int)atoi((char *)&order);
358 }
359 ypdb_close(db);
360
361 out:
362 if ((status == YPPUSH_NOMAP) || (status == YPPUSH_DBM)) {
363 *lordernum = 0;
364 status = YPPUSH_SUCC;
365 }
366
367 return (status);
368 }
369
370 int
371 get_remote_ordernum(client, domain, map, lordernum, rordernum)
372 CLIENT *client;
373 char *domain, *map;
374 u_int lordernum, *rordernum;
375 {
376 int status;
377
378 status = yp_order_host(client, domain, map, (int *)rordernum);
379
380 if (status == 0) {
381 if (*rordernum <= lordernum)
382 status = YPPUSH_AGE;
383 else
384 status = YPPUSH_SUCC;
385 }
386
387 return status;
388 }
389
390 void
391 get_map(client, domain, map, incallback)
392 CLIENT *client;
393 char *domain, *map;
394 struct ypall_callback *incallback;
395 {
396
397 (void)yp_all_host(client, domain, map, incallback);
398 }
399
400 DBM *
401 create_db(domain, map, temp_map)
402 char *domain, *map, *temp_map;
403 {
404 char db_temp[255];
405 DBM *db;
406
407 snprintf(db_temp, sizeof(db_temp), "%s/%s/%s",
408 YP_DB_PATH, domain, temp_map);
409 db_temp[sizeof(db_temp) - 1] = '\0';
410
411 db = ypdb_open(db_temp, O_RDWR|O_CREAT|O_EXCL, 0444);
412
413 return db;
414 }
415
416 int
417 install_db(domain, map, temp_map)
418 char *domain, *map, *temp_map;
419 {
420 char db_name[255], db_temp[255];
421
422 snprintf(db_name, sizeof(db_name), "%s/%s/%s%s",
423 YP_DB_PATH, domain, map, YPDB_SUFFIX);
424 db_name[sizeof(db_name) - 1] = '\0';
425
426 snprintf(db_temp, sizeof(db_temp), "%s/%s/%s%s",
427 YP_DB_PATH, domain, temp_map, YPDB_SUFFIX);
428 db_temp[sizeof(db_temp) - 1] = '\0';
429
430 if (rename(db_temp, db_name)) {
431 warn("can't rename `%s' -> `%s'", db_temp, db_name);
432 return YPPUSH_YPERR;
433 }
434
435 return YPPUSH_SUCC;
436 }
437
438 int
439 unlink_db(domain, map, temp_map)
440 char *domain, *map, *temp_map;
441 {
442 char db_temp[255];
443
444 snprintf(db_temp, sizeof(db_temp), "%s/%s/%s%s",
445 YP_DB_PATH, domain, temp_map, YPDB_SUFFIX);
446 db_temp[sizeof(db_temp) - 1] = '\0';
447
448 if (unlink(db_temp)) {
449 warn("can't unlink `%s'", db_temp);
450 return YPPUSH_YPERR;
451 }
452
453 return YPPUSH_SUCC;
454 }
455
456 int
457 add_order(db, ordernum)
458 DBM *db;
459 u_int ordernum;
460 {
461 char datestr[11];
462 datum key, val;
463 char keystr[] = YP_LAST_KEY;
464 int status;
465
466 snprintf(datestr, sizeof(datestr), "%010d", ordernum);
467 datestr[sizeof(datestr) - 1] = '\0';
468
469 key.dptr = keystr;
470 key.dsize = strlen(keystr);
471
472 val.dptr = datestr;
473 val.dsize = strlen(datestr);
474
475 status = ypdb_store(db, key, val, YPDB_INSERT);
476 if(status >= 0)
477 status = YPPUSH_SUCC;
478 else
479 status = YPPUSH_DBM;
480
481 return (status);
482 }
483
484 int
485 add_master(client, domain, map, db)
486 CLIENT *client;
487 char *domain, *map;
488 DBM *db;
489 {
490 char keystr[] = YP_MASTER_KEY;
491 char *master;
492 int status;
493 datum key, val;
494
495 master = NULL;
496
497 /* Get MASTER */
498 status = yp_master_host(client, domain, map, &master);
499
500 if (master != NULL) {
501 key.dptr = keystr;
502 key.dsize = strlen(keystr);
503
504 val.dptr = master;
505 val.dsize = strlen(master);
506
507 status = ypdb_store(db, key, val, YPDB_INSERT);
508 if (status >= 0)
509 status = YPPUSH_SUCC;
510 else
511 status = YPPUSH_DBM;
512 }
513
514 return status;
515 }
516
517 int
518 add_interdomain(client, domain, map, db)
519 CLIENT *client;
520 char *domain, *map;
521 DBM *db;
522 {
523 char keystr[] = YP_INTERDOMAIN_KEY;
524 char *value;
525 int vallen;
526 int status;
527 datum k, v;
528
529 /* Get INTERDOMAIN */
530 k.dptr = keystr;
531 k.dsize = strlen(keystr);
532
533 status = yp_match_host(client, domain, map,
534 k.dptr, k.dsize, &value, &vallen);
535
536 if (status == 0 && value) {
537 v.dptr = value;
538 v.dsize = vallen;
539
540 if (v.dptr != NULL) {
541 status = ypdb_store(db, k, v, YPDB_INSERT);
542 if (status >= 0)
543 status = YPPUSH_SUCC;
544 else
545 status = YPPUSH_DBM;
546 }
547 }
548
549 return status;
550 }
551
552 int
553 add_secure(client, domain, map, db)
554 CLIENT *client;
555 char *domain, *map;
556 DBM *db;
557 {
558 char keystr[] = YP_SECURE_KEY;
559 char *value;
560 int vallen;
561 int status;
562 datum k, v;
563
564 /* Get SECURE */
565 k.dptr = keystr;
566 k.dsize = strlen(keystr);
567
568 status = yp_match_host(client, domain, map,
569 k.dptr, k.dsize, &value, &vallen);
570
571 if (status > 0) {
572 v.dptr = value;
573 v.dsize = vallen;
574
575 if (v.dptr != NULL) {
576 status = ypdb_store(db, k, v, YPDB_INSERT);
577 if (status >= 0)
578 status = YPPUSH_SUCC;
579 else
580 status = YPPUSH_DBM;
581 }
582 }
583
584 return status;
585 }
586
587 int
588 send_clear(client)
589 CLIENT *client;
590 {
591 struct timeval tv;
592 int r;
593 int status;
594
595 status = YPPUSH_SUCC;
596
597 tv.tv_sec = 10;
598 tv.tv_usec = 0;
599
600 /* Send CLEAR */
601 r = clnt_call(client, YPPROC_CLEAR, xdr_void, 0, xdr_void, 0, tv);
602 if (r != RPC_SUCCESS) {
603 clnt_perror(client, "yp_clear: clnt_call");
604 status = YPPUSH_RPC;
605 }
606
607 return status;
608 }
609
610 int
611 send_reply(client, status, tid)
612 CLIENT *client;
613 int status, tid;
614 {
615 struct timeval tv;
616 struct ypresp_xfr resp;
617 int r;
618
619 tv.tv_sec = 10;
620 tv.tv_usec = 0;
621
622 resp.transid = tid;
623 resp.xfrstat = status;
624
625 /* Send XFRRESP */
626 r = clnt_call(client, YPPUSHPROC_XFRRESP, xdr_ypresp_xfr, &resp,
627 xdr_void, 0, tv);
628 if (r != RPC_SUCCESS) {
629 clnt_perror(client, "yppushresp_xdr: clnt_call");
630 status = YPPUSH_RPC;
631 }
632
633 return status;
634 }
635