Home | History | Annotate | Line # | Download | only in ypxfr
      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 (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  *
     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
     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
    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
    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
    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
    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
    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 *
    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
    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
    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
    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
    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
    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
    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
    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
    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