1 /* $NetBSD: ypxfr.c,v 1.21 2017/05/04 16:26:10 sevan Exp $ */
2
3 /*
4 * Copyright (c) 1994 Mats O Jansson <moj@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 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
17 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 #ifndef lint
31 __RCSID("$NetBSD: ypxfr.c,v 1.21 2017/05/04 16:26:10 sevan Exp $");
32 #endif
33
34 #include <sys/param.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <sys/socket.h>
38
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
41
42 #include <err.h>
43 #include <netdb.h>
44 #include <string.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <syslog.h>
48 #include <unistd.h>
49
50 #include <rpc/rpc.h>
51 #include <rpc/xdr.h>
52 #include <rpcsvc/yp_prot.h>
53 #include <rpcsvc/ypclnt.h>
54
55 #include "yplib_host.h"
56 #include "ypdb.h"
57 #include "ypdef.h"
58
59 DBM *db;
60
61 static int yperr2yppush(int);
62 static int ypxfr_foreach(int, char *, int, char *, int, char *);
63
64 int get_local_ordernum(char *, char *, u_int *);
65 int get_remote_ordernum(CLIENT *, char *, char *, u_int, u_int *);
66 void get_map(CLIENT *, char *, char *, struct ypall_callback *);
67 DBM *create_db(char *, char *, char *, size_t);
68 int install_db(char *, char *, char *);
69 int unlink_db(char *, char *, char *);
70 int add_order(DBM *, u_int);
71 int add_master(CLIENT *, char *, char *, DBM *);
72 int add_interdomain(CLIENT *, char *, char *, DBM *);
73 int add_secure(CLIENT *, char *, char *, DBM *);
74 int send_clear(CLIENT *);
75 int send_reply(CLIENT *, int, int);
76
77 int
main(int argc,char ** argv)78 main(int argc, char **argv)
79 {
80 int need_usage = 0, cflag = 0, fflag = 0, Cflag = 0;
81 int ch;
82 char *domain;
83 char *host = NULL;
84 char *srcdomain = NULL;
85 char *tid = NULL;
86 char *prog = NULL;
87 char *ipadd = NULL;
88 char *port = NULL;
89 char *map = NULL;
90 u_int ordernum, new_ordernum;
91 struct ypall_callback callback;
92 CLIENT *client;
93 char temp_map[MAXPATHLEN];
94 int status, xfr_status;
95
96 status = YPPUSH_SUCC;
97 client = NULL;
98
99 if (yp_get_default_domain(&domain))
100 errx(1, "can't get YP domain name");
101
102 while ((ch = getopt(argc, argv, "cd:fh:s:C:")) != -1) {
103 switch (ch) {
104 case 'c':
105 cflag = 1;
106 break;
107
108 case 'd':
109 domain = optarg;
110 break;
111
112 case 'f':
113 fflag = 1;
114 break;
115
116 case 'h':
117 host = optarg;
118 break;
119
120 case 's':
121 srcdomain = optarg;
122 break;
123
124 case 'C':
125 if (optind + 3 >= argc) {
126 need_usage = 1;
127 optind = argc;
128 break;
129 }
130 Cflag = 1;
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] [-C tid prog ipadd port] "
151 "[-d domain] [-h host] [-s domain] mapname\n",
152 getprogname());
153 exit(1);
154 }
155
156 #ifdef DEBUG
157 openlog("ypxfr", LOG_PID, LOG_DAEMON);
158
159 syslog(LOG_DEBUG, "ypxfr: Arguments:");
160 syslog(LOG_DEBUG, "YP clear to local: %s", (cflag) ? "no" : "yes");
161 syslog(LOG_DEBUG, " Force transfer: %s", (fflag) ? "yes" : "no");
162 syslog(LOG_DEBUG, " domain: %s", domain);
163 syslog(LOG_DEBUG, " host: %s", host);
164 syslog(LOG_DEBUG, " source domain: %s", srcdomain);
165 syslog(LOG_DEBUG, " transid: %s", tid);
166 syslog(LOG_DEBUG, " prog: %s", prog);
167 syslog(LOG_DEBUG, " port: %s", port);
168 syslog(LOG_DEBUG, " ipadd: %s", ipadd);
169 syslog(LOG_DEBUG, " map: %s", map);
170 #endif
171
172 if (fflag != 0)
173 ordernum = 0;
174 else {
175 status = get_local_ordernum(domain, map, &ordernum);
176 if (status < 0)
177 goto punt;
178 }
179
180 #ifdef DEBUG
181 syslog(LOG_DEBUG, "Get Master");
182 #endif
183
184 if (host == NULL) {
185 if (srcdomain == NULL)
186 status = yp_master(domain, map, &host);
187 else
188 status = yp_master(srcdomain, map, &host);
189
190 if (status == 0)
191 status = YPPUSH_SUCC;
192 else {
193 status = YPPUSH_MADDR;
194 goto punt;
195 }
196 }
197
198 #ifdef DEBUG
199 syslog(LOG_DEBUG, "Connect host: %s", host);
200 #endif
201
202 client = yp_bind_host(host, YPPROG, YPVERS, 0, 1);
203
204 status = get_remote_ordernum(client, domain, map, ordernum,
205 &new_ordernum);
206
207
208 if (status == YPPUSH_SUCC) {
209 /* Create temporary db */
210 db = create_db(domain, map, temp_map, sizeof(temp_map));
211 if (db == NULL)
212 status = YPPUSH_DBM;
213
214 /* Add ORDER */
215 if (status > 0)
216 status = add_order(db, new_ordernum);
217
218 /* Add MASTER */
219 if (status > 0)
220 status = add_master(client, domain, map, db);
221
222 /* Add INTERDOMAIN */
223 if (status > 0)
224 status = add_interdomain(client, domain, map, db);
225
226 /* Add SECURE */
227 if (status > 0)
228 status = add_secure(client, domain, map, db);
229
230 if (status > 0) {
231 callback.foreach = ypxfr_foreach;
232 get_map(client, domain, map, &callback);
233 }
234
235 /* Close db */
236 if (db != NULL)
237 ypdb_close(db);
238
239 /* Rename db */
240 if (status > 0)
241 status = install_db(domain, map, temp_map);
242 else
243 (void) unlink_db(domain, map, temp_map);
244 }
245
246 punt:
247 xfr_status = status;
248
249 if (client != NULL)
250 clnt_destroy(client);
251
252 /* YP_CLEAR */
253 if (!cflag) {
254 client = yp_bind_local(YPPROG, YPVERS);
255 status = send_clear(client);
256 clnt_destroy(client);
257 }
258
259 if (Cflag > 0) {
260 /* Send Response */
261 client = yp_bind_host(ipadd, atoi(prog), 1, atoi(port), 0);
262 status = send_reply(client, xfr_status, atoi(tid));
263 clnt_destroy(client);
264 }
265
266 exit (0);
267 }
268
269 /*
270 * yperr2yppush: convert error codes from functions like yp_order_host,
271 * yp_master_host, and yp_match_host into YPPUSH rpc status values.
272 */
273 static int
yperr2yppush(int yperr)274 yperr2yppush(int yperr) {
275 switch (yperr) {
276 case YPERR_DOMAIN:
277 return(YPPUSH_NODOM);
278 case YPERR_MAP:
279 return(YPPUSH_NOMAP);
280 case YPERR_KEY:
281 return(YPPUSH_YPERR);
282 case YPERR_BADDB:
283 return(YPPUSH_YPERR);
284 }
285
286 /*
287 * generic error status for the rest (BADARGS, RPC, YPERR, RESRC,
288 * NOMORE, PMAP, YPBIND, YPSERV, NODOM, VERS, ACCESS, BUSY)
289 */
290 return(YPPUSH_XFRERR); /* generic error status */
291 }
292
293 static int
ypxfr_foreach(int status,char * keystr,int keylen,char * valstr,int vallen,char * data)294 ypxfr_foreach(int status, char *keystr, int keylen, char *valstr,
295 int vallen, char *data)
296 {
297 datum key, val;
298
299 if (status == YP_NOMORE)
300 return (0);
301
302 keystr[keylen] = '\0';
303 valstr[vallen] = '\0';
304
305 key.dptr = keystr;
306 key.dsize = strlen(keystr);
307
308 val.dptr = valstr;
309 val.dsize = strlen(valstr);
310
311 /* XXX: suspect... ignoring return value here */
312 ypdb_store(db, key, val, YPDB_INSERT);
313
314 return (0);
315 }
316
317 int
get_local_ordernum(char * domain,char * map,u_int * lordernum)318 get_local_ordernum(char *domain, char *map, u_int *lordernum)
319 {
320 char map_path[1024];
321 char order_key[] = YP_LAST_KEY;
322 char order[MAX_LAST_LEN+1];
323 struct stat finfo;
324 DBM *ldb;
325 datum k, v;
326 unsigned int status;
327
328 status = YPPUSH_SUCC;
329
330 snprintf(map_path, sizeof(map_path), "%s/%s", YP_DB_PATH, domain);
331
332 /* Make sure we serve the domain. */
333 if ((stat(map_path, &finfo)) != 0 ||
334 (S_ISDIR(finfo.st_mode) == 0)) {
335 warnx("domain `%s' not found locally", domain);
336 status = YPPUSH_NODOM;
337 goto out;
338 }
339
340 /* Make sure we serve the map. */
341 snprintf(map_path, sizeof(map_path), "%s/%s/%s%s",
342 YP_DB_PATH, domain, map, YPDB_SUFFIX);
343 if (stat(map_path, &finfo) != 0) {
344 status = YPPUSH_NOMAP;
345 goto out;
346 }
347
348 /* Open the map file. */
349 snprintf(map_path, sizeof(map_path), "%s/%s/%s",
350 YP_DB_PATH, domain, map);
351 ldb = ypdb_open(map_path);
352 if (ldb == NULL) {
353 status = YPPUSH_DBM;
354 goto out;
355 }
356
357 k.dptr = (char *)&order_key;
358 k.dsize = YP_LAST_LEN;
359
360 v = ypdb_fetch(ldb, k);
361
362 if (v.dptr == NULL)
363 *lordernum = 0;
364 else {
365 strncpy(order, v.dptr, v.dsize);
366 order[v.dsize] = '\0';
367 *lordernum = (u_int)atoi((char *)&order);
368 }
369 ypdb_close(ldb);
370
371 out:
372 if ((status == YPPUSH_NOMAP) || (status == YPPUSH_DBM)) {
373 *lordernum = 0;
374 status = YPPUSH_SUCC;
375 }
376
377 return (status);
378 }
379
380 int
get_remote_ordernum(CLIENT * client,char * domain,char * map,u_int lordernum,u_int * rordernum)381 get_remote_ordernum(CLIENT *client, char *domain, char *map,
382 u_int lordernum, u_int *rordernum)
383 {
384 int status;
385
386 status = yp_order_host(client, domain, map, (int *)rordernum);
387
388 if (status == 0) {
389 if (*rordernum <= lordernum)
390 status = YPPUSH_AGE;
391 else
392 status = YPPUSH_SUCC;
393 } else {
394 status = yperr2yppush(status);
395 }
396
397 return status;
398 }
399
400 void
get_map(CLIENT * client,char * domain,char * map,struct ypall_callback * incallback)401 get_map(CLIENT *client, char *domain, char *map,
402 struct ypall_callback *incallback)
403 {
404
405 (void)yp_all_host(client, domain, map, incallback);
406 }
407
408 DBM *
create_db(char * domain,char * map,char * db_temp,size_t db_temp_len)409 create_db(char *domain, char *map, char *db_temp, size_t db_temp_len)
410 {
411 static const char template[] = "ypdbXXXXXX";
412 DBM *ldb;
413
414 snprintf(db_temp, db_temp_len, "%s/%s/%s",
415 YP_DB_PATH, domain, template);
416
417 ldb = ypdb_mktemp(db_temp);
418
419 return ldb;
420 }
421
422 int
install_db(char * domain,char * map,char * db_temp)423 install_db(char *domain, char *map, char *db_temp)
424 {
425 char db_name[MAXPATHLEN];
426
427 snprintf(db_name, sizeof(db_name), "%s/%s/%s%s",
428 YP_DB_PATH, domain, map, YPDB_SUFFIX);
429
430 if (rename(db_temp, db_name)) {
431 warn("can't rename `%s' -> `%s'", db_temp, db_name);
432 return YPPUSH_YPERR;
433 }
434
435 return YPPUSH_SUCC;
436 }
437
438 int
unlink_db(char * domain,char * map,char * db_temp)439 unlink_db(char *domain, char *map, char *db_temp)
440 {
441
442 if (unlink(db_temp)) {
443 warn("can't unlink `%s'", db_temp);
444 return YPPUSH_YPERR;
445 }
446
447 return YPPUSH_SUCC;
448 }
449
450 int
add_order(DBM * ldb,u_int ordernum)451 add_order(DBM *ldb, 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
460 key.dptr = keystr;
461 key.dsize = strlen(keystr);
462
463 val.dptr = datestr;
464 val.dsize = strlen(datestr);
465
466 status = ypdb_store(ldb, key, val, YPDB_INSERT);
467 if(status >= 0)
468 status = YPPUSH_SUCC;
469 else
470 status = YPPUSH_DBM;
471
472 return (status);
473 }
474
475 int
add_master(CLIENT * client,char * domain,char * map,DBM * ldb)476 add_master(CLIENT *client, char *domain, char *map, DBM *ldb)
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(ldb, key, val, YPDB_INSERT);
496 if (status >= 0)
497 status = YPPUSH_SUCC;
498 else
499 status = YPPUSH_DBM;
500 } else {
501 status = yperr2yppush(status);
502 }
503
504 return status;
505 }
506
507 int
add_interdomain(CLIENT * client,char * domain,char * map,DBM * ldb)508 add_interdomain(CLIENT *client, char *domain, char *map, DBM *ldb)
509 {
510 char keystr[] = YP_INTERDOMAIN_KEY;
511 char *value;
512 int vallen;
513 int status;
514 datum k, v;
515
516 /* Get INTERDOMAIN */
517 k.dptr = keystr;
518 k.dsize = strlen(keystr);
519
520 status = yp_match_host(client, domain, map,
521 k.dptr, k.dsize, &value, &vallen);
522
523 if (status == YPERR_KEY) {
524 /* this is an optional key/val, so it may not be present */
525 status = YPPUSH_SUCC;
526 } else if (status == 0 && value) {
527 v.dptr = value;
528 v.dsize = vallen;
529
530 if (v.dptr != NULL) {
531 status = ypdb_store(ldb, k, v, YPDB_INSERT);
532 if (status >= 0)
533 status = YPPUSH_SUCC;
534 else
535 status = YPPUSH_DBM;
536 }
537 } else {
538 status = yperr2yppush(status);
539 }
540
541 return status;
542 }
543
544 int
add_secure(CLIENT * client,char * domain,char * map,DBM * ldb)545 add_secure(CLIENT *client, char *domain, char *map, DBM *ldb)
546 {
547 char keystr[] = YP_SECURE_KEY;
548 char *value;
549 int vallen;
550 int status;
551 datum k, v;
552
553 /* Get SECURE */
554 k.dptr = keystr;
555 k.dsize = strlen(keystr);
556
557 status = yp_match_host(client, domain, map,
558 k.dptr, k.dsize, &value, &vallen);
559
560 if (status == YPERR_KEY) {
561 /* this is an optional key/val, so it may not be present */
562 status = YPPUSH_SUCC;
563 } else if (status == 0 && value != 0) {
564 v.dptr = value;
565 v.dsize = vallen;
566
567 if (v.dptr != NULL) {
568 status = ypdb_store(ldb, k, v, YPDB_INSERT);
569 if (status >= 0)
570 status = YPPUSH_SUCC;
571 else
572 status = YPPUSH_DBM;
573 }
574 } else {
575 status = yperr2yppush(status);
576 }
577
578 return status;
579 }
580
581 int
send_clear(CLIENT * client)582 send_clear(CLIENT *client)
583 {
584 struct timeval tv;
585 int r;
586 int status;
587
588 status = YPPUSH_SUCC;
589
590 tv.tv_sec = 10;
591 tv.tv_usec = 0;
592
593 /* Send CLEAR */
594 r = clnt_call(client, YPPROC_CLEAR, xdr_void, 0, xdr_void, 0, tv);
595 if (r != RPC_SUCCESS) {
596 clnt_perror(client, "yp_clear: clnt_call");
597 status = YPPUSH_RPC;
598 }
599
600 return status;
601 }
602
603 int
send_reply(CLIENT * client,int status,int tid)604 send_reply(CLIENT *client, int status, int tid)
605 {
606 struct timeval tv;
607 struct ypresp_xfr resp;
608 int r;
609
610 tv.tv_sec = 10;
611 tv.tv_usec = 0;
612
613 resp.transid = tid;
614 resp.xfrstat = status;
615
616 /* Send XFRRESP */
617 r = clnt_call(client, YPPUSHPROC_XFRRESP, xdr_ypresp_xfr, &resp,
618 xdr_void, 0, tv);
619 if (r != RPC_SUCCESS) {
620 clnt_perror(client, "yppushresp_xdr: clnt_call");
621 status = YPPUSH_RPC;
622 }
623
624 return status;
625 }
626