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