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