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