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