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