Home | History | Annotate | Line # | Download | only in ypbind
ypbind.c revision 1.25
      1 /*	$NetBSD: ypbind.c,v 1.25 1996/07/09 06:34:12 thorpej Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1992, 1993 Theo de Raadt <deraadt (at) fsa.ca>
      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 Theo de Raadt.
     18  * 4. The name of the author may not be used to endorse or promote
     19  *    products derived from this software without specific prior written
     20  *    permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     23  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     24  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
     26  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32  * SUCH DAMAGE.
     33  */
     34 
     35 #ifndef LINT
     36 static char rcsid[] = "$NetBSD: ypbind.c,v 1.25 1996/07/09 06:34:12 thorpej Exp $";
     37 #endif
     38 
     39 #include <sys/param.h>
     40 #include <sys/types.h>
     41 #include <sys/ioctl.h>
     42 #include <sys/signal.h>
     43 #include <sys/socket.h>
     44 #include <sys/file.h>
     45 #include <sys/fcntl.h>
     46 #include <sys/uio.h>
     47 #include <sys/syslog.h>
     48 #include <sys/stat.h>
     49 #include <stdio.h>
     50 #include <stdlib.h>
     51 #include <errno.h>
     52 #include <ctype.h>
     53 #include <dirent.h>
     54 #include <netdb.h>
     55 #include <string.h>
     56 #include <err.h>
     57 #include <rpc/rpc.h>
     58 #include <rpc/xdr.h>
     59 #include <net/if.h>
     60 #include <arpa/inet.h>
     61 #include <rpc/pmap_clnt.h>
     62 #include <rpc/pmap_prot.h>
     63 #include <rpc/pmap_rmt.h>
     64 #include <unistd.h>
     65 #include <rpcsvc/yp_prot.h>
     66 #include <rpcsvc/ypclnt.h>
     67 
     68 #ifndef O_SHLOCK
     69 #define O_SHLOCK 0
     70 #endif
     71 
     72 #define BUFSIZE		1400
     73 #define BINDINGDIR	"/var/yp/binding"
     74 #define YPBINDLOCK	"/var/run/ypbind.lock"
     75 
     76 struct _dom_binding {
     77 	struct _dom_binding *dom_pnext;
     78 	char dom_domain[YPMAXDOMAIN + 1];
     79 	struct sockaddr_in dom_server_addr;
     80 	unsigned short int dom_server_port;
     81 	int dom_socket;
     82 	CLIENT *dom_client;
     83 	long int dom_vers;
     84 	time_t dom_check_t;
     85 	time_t dom_ask_t;
     86 	int dom_lockfd;
     87 	int dom_alive;
     88 	int dom_xid;
     89 };
     90 
     91 static char *domainname;
     92 
     93 static struct _dom_binding *ypbindlist;
     94 static int check;
     95 
     96 #define YPSET_NO	0
     97 #define YPSET_LOCAL	1
     98 #define YPSET_ALL	2
     99 static int ypsetmode = YPSET_NO;
    100 #ifdef DEBUG
    101 static int debug;
    102 #endif
    103 
    104 static int rpcsock, pingsock;
    105 static struct rmtcallargs rmtca;
    106 static struct rmtcallres rmtcr;
    107 static char rmtcr_outval;
    108 static u_long rmtcr_port;
    109 static SVCXPRT *udptransp, *tcptransp;
    110 
    111 
    112 static void usage __P((void));
    113 static struct _dom_binding *makebinding __P((const char *));
    114 static int makelock __P((struct _dom_binding *));
    115 static void removelock __P((struct _dom_binding *));
    116 static void *ypbindproc_null_2 __P((SVCXPRT *, void *));
    117 static void *ypbindproc_domain_2 __P((SVCXPRT *, void *));
    118 static void *ypbindproc_setdom_2 __P((SVCXPRT *, void *));
    119 static void ypbindprog_2 __P((struct svc_req *, SVCXPRT *));
    120 static void checkwork __P((void));
    121 static int ping __P((struct _dom_binding *));
    122 static int broadcast __P((struct _dom_binding *));
    123 static enum clnt_stat handle_replies __P((void));
    124 static enum clnt_stat handle_ping __P((void));
    125 static void rpc_received __P((char *, struct sockaddr_in *, int));
    126 static struct _dom_binding *xid2ypdb __P((int));
    127 static int unique_xid __P((struct _dom_binding *));
    128 static struct _dom_binding *xid2ypdb __P((int xid));
    129 static int unique_xid __P((struct _dom_binding *ypdb));
    130 
    131 static void
    132 usage()
    133 {
    134 	extern char *__progname;
    135 	char *opt = "";
    136 #ifdef DEBUG
    137 	opt = " [-d]";
    138 #endif
    139 	(void) fprintf(stderr, "Usage: %s [-ypset|-ypsetme]%s\n",
    140 	    __progname, opt);
    141 	exit(1);
    142 }
    143 
    144 static struct _dom_binding *
    145 makebinding(dm)
    146 	const char *dm;
    147 {
    148 	struct _dom_binding *ypdb;
    149 
    150 	if ((ypdb = (struct _dom_binding *)malloc(sizeof *ypdb)) == NULL)
    151 		err(1, "makebinding");
    152 
    153 	(void) memset(ypdb, 0, sizeof *ypdb);
    154 	(void) strncpy(ypdb->dom_domain, dm, sizeof ypdb->dom_domain);
    155 	ypdb->dom_domain[sizeof(ypdb->dom_domain) - 1] = '\0';
    156 	return ypdb;
    157 }
    158 
    159 static int
    160 makelock(ypdb)
    161 	struct _dom_binding *ypdb;
    162 {
    163 	int fd;
    164 	char path[MAXPATHLEN];
    165 
    166 	(void) snprintf(path, sizeof(path), "%s/%s.%ld", BINDINGDIR,
    167 	    ypdb->dom_domain, ypdb->dom_vers);
    168 
    169 	if ((fd = open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1) {
    170 		(void) mkdir(BINDINGDIR, 0755);
    171 		if ((fd = open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1)
    172 			return -1;
    173 	}
    174 
    175 #if O_SHLOCK == 0
    176 	(void) flock(fd, LOCK_SH);
    177 #endif
    178 	return fd;
    179 }
    180 
    181 static void
    182 removelock(ypdb)
    183 	struct _dom_binding *ypdb;
    184 {
    185 	char path[MAXPATHLEN];
    186 
    187 	(void) snprintf(path, sizeof(path), "%s/%s.%ld",
    188 	    BINDINGDIR, ypdb->dom_domain, ypdb->dom_vers);
    189 	(void) unlink(path);
    190 }
    191 
    192 static void *
    193 ypbindproc_null_2(transp, argp)
    194 	SVCXPRT *transp;
    195 	void *argp;
    196 {
    197 	static char res;
    198 
    199 #ifdef DEBUG
    200 	if (debug)
    201 		printf("ypbindproc_null_2\n");
    202 #endif
    203 	(void) memset(&res, 0, sizeof(res));
    204 	return (void *)&res;
    205 }
    206 
    207 static void *
    208 ypbindproc_domain_2(transp, argp)
    209 	SVCXPRT *transp;
    210 	void *argp;
    211 {
    212 	static struct ypbind_resp res;
    213 	struct _dom_binding *ypdb;
    214 	char *arg = *(char **) argp;
    215 	time_t now;
    216 
    217 #ifdef DEBUG
    218 	if (debug)
    219 		printf("ypbindproc_domain_2 %s\n", arg);
    220 #endif
    221 	(void) memset(&res, 0, sizeof res);
    222 	res.ypbind_status = YPBIND_FAIL_VAL;
    223 
    224 	for (ypdb = ypbindlist; ypdb; ypdb = ypdb->dom_pnext)
    225 		if (!strcmp(ypdb->dom_domain, arg))
    226 			break;
    227 
    228 	if (ypdb == NULL) {
    229 		ypdb = makebinding(arg);
    230 		ypdb->dom_vers = YPVERS;
    231 		ypdb->dom_alive = 0;
    232 		ypdb->dom_lockfd = -1;
    233 		removelock(ypdb);
    234 		ypdb->dom_xid = unique_xid(ypdb);
    235 		ypdb->dom_pnext = ypbindlist;
    236 		ypbindlist = ypdb;
    237 		check++;
    238 #ifdef DEBUG
    239 		if (debug)
    240 			printf("unknown domain %s\n", arg);
    241 #endif
    242 		return NULL;
    243 	}
    244 
    245 	if (ypdb->dom_alive == 0) {
    246 #ifdef DEBUG
    247 		if (debug)
    248 			printf("dead domain %s\n", arg);
    249 #endif
    250 		return NULL;
    251 	}
    252 
    253 #ifdef HEURISTIC
    254 	time(&now);
    255 	if (now < ypdb->dom_ask_t + 5) {
    256 		/*
    257 		 * Hmm. More than 2 requests in 5 seconds have indicated
    258 		 * that my binding is possibly incorrect.
    259 		 * Ok, do an immediate poll of the server.
    260 		 */
    261 		if (ypdb->dom_check_t >= now) {
    262 			/* don't flood it */
    263 			ypdb->dom_check_t = 0;
    264 			check++;
    265 		}
    266 	}
    267 	ypdb->dom_ask_t = now;
    268 #endif
    269 
    270 	res.ypbind_status = YPBIND_SUCC_VAL;
    271 	res.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr.s_addr =
    272 		ypdb->dom_server_addr.sin_addr.s_addr;
    273 	res.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port =
    274 		ypdb->dom_server_port;
    275 #ifdef DEBUG
    276 	if (debug)
    277 		printf("domain %s at %s/%d\n", ypdb->dom_domain,
    278 		    inet_ntoa(ypdb->dom_server_addr.sin_addr),
    279 		    ntohs(ypdb->dom_server_addr.sin_port));
    280 #endif
    281 	return &res;
    282 }
    283 
    284 static void *
    285 ypbindproc_setdom_2(transp, argp)
    286 	SVCXPRT *transp;
    287 	void *argp;
    288 {
    289 	struct ypbind_setdom *sd = argp;
    290 	struct sockaddr_in *fromsin, bindsin;
    291 	static bool_t res;
    292 
    293 #ifdef DEBUG
    294 	if (debug)
    295 		printf("ypbindproc_setdom_2 %s\n", inet_ntoa(bindsin.sin_addr));
    296 #endif
    297 	(void) memset(&res, 0, sizeof(res));
    298 	fromsin = svc_getcaller(transp);
    299 
    300 	switch (ypsetmode) {
    301 	case YPSET_LOCAL:
    302 		if (fromsin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) {
    303 #ifdef DEBUG
    304 			if (debug)
    305 				printf("ypset from %s denied\n",
    306 				    inet_ntoa(fromsin->sin_addr));
    307 #endif
    308 			return NULL;
    309 		}
    310 		break;
    311 	case YPSET_ALL:
    312 		break;
    313 	case YPSET_NO:
    314 	default:
    315 #ifdef DEBUG
    316 		if (debug)
    317 			printf("ypset denied\n");
    318 #endif
    319 		return NULL;
    320 	}
    321 
    322 	if (ntohs(fromsin->sin_port) >= IPPORT_RESERVED) {
    323 #ifdef DEBUG
    324 		if (debug)
    325 			printf("ypset from unpriviledged port denied\n");
    326 #endif
    327 		return &res;
    328 	}
    329 
    330 	if (sd->ypsetdom_vers != YPVERS) {
    331 #ifdef DEBUG
    332 		if (debug)
    333 			printf("ypset with wrong version denied\n");
    334 #endif
    335 		return &res;
    336 	}
    337 
    338 	(void) memset(&bindsin, 0, sizeof bindsin);
    339 	bindsin.sin_family = AF_INET;
    340 	bindsin.sin_len = sizeof(bindsin);
    341 	bindsin.sin_addr = sd->ypsetdom_addr;
    342 	bindsin.sin_port = sd->ypsetdom_port;
    343 	rpc_received(sd->ypsetdom_domain, &bindsin, 1);
    344 
    345 #ifdef DEBUG
    346 	if (debug)
    347 		printf("ypset to %s succeeded\n", inet_ntoa(bindsin.sin_addr));
    348 #endif
    349 	res = 1;
    350 	return &res;
    351 }
    352 
    353 static void
    354 ypbindprog_2(rqstp, transp)
    355 	struct svc_req *rqstp;
    356 	register SVCXPRT *transp;
    357 {
    358 	union {
    359 		char ypbindproc_domain_2_arg[YPMAXDOMAIN + 1];
    360 		struct ypbind_setdom ypbindproc_setdom_2_arg;
    361 	} argument;
    362 	struct authunix_parms *creds;
    363 	char *result;
    364 	xdrproc_t xdr_argument, xdr_result;
    365 	void *(*local) __P((SVCXPRT *, void *));
    366 
    367 	switch (rqstp->rq_proc) {
    368 	case YPBINDPROC_NULL:
    369 		xdr_argument = xdr_void;
    370 		xdr_result = xdr_void;
    371 		local = ypbindproc_null_2;
    372 		break;
    373 
    374 	case YPBINDPROC_DOMAIN:
    375 		xdr_argument = xdr_ypdomain_wrap_string;
    376 		xdr_result = xdr_ypbind_resp;
    377 		local = ypbindproc_domain_2;
    378 		break;
    379 
    380 	case YPBINDPROC_SETDOM:
    381 		switch (rqstp->rq_cred.oa_flavor) {
    382 		case AUTH_UNIX:
    383 			creds = (struct authunix_parms *)rqstp->rq_clntcred;
    384 			if (creds->aup_uid != 0) {
    385 				svcerr_auth(transp, AUTH_BADCRED);
    386 				return;
    387 			}
    388 			break;
    389 		default:
    390 			svcerr_auth(transp, AUTH_TOOWEAK);
    391 			return;
    392 		}
    393 
    394 		xdr_argument = xdr_ypbind_setdom;
    395 		xdr_result = xdr_void;
    396 		local = ypbindproc_setdom_2;
    397 		break;
    398 
    399 	default:
    400 		svcerr_noproc(transp);
    401 		return;
    402 	}
    403 	(void) memset(&argument, 0, sizeof(argument));
    404 	if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) {
    405 		svcerr_decode(transp);
    406 		return;
    407 	}
    408 	result = (*local)(transp, &argument);
    409 	if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
    410 		svcerr_systemerr(transp);
    411 	}
    412 	return;
    413 }
    414 
    415 int
    416 main(argc, argv)
    417 	int argc;
    418 	char *argv[];
    419 {
    420 	struct timeval tv;
    421 	fd_set fdsr;
    422 	int width, lockfd;
    423 	int evil = 0, one;
    424 
    425 	yp_get_default_domain(&domainname);
    426 	if (domainname[0] == '\0')
    427 		errx(1, "Domainname not set. Aborting.");
    428 
    429 	while (--argc) {
    430 		++argv;
    431 		if (!strcmp("-ypset", *argv))
    432 			ypsetmode = YPSET_ALL;
    433 		else if (!strcmp("-ypsetme", *argv))
    434 			ypsetmode = YPSET_LOCAL;
    435 #ifdef DEBUG
    436 		else if (!strcmp("-d", *argv))
    437 			debug++;
    438 #endif
    439 		else
    440 			usage();
    441 	}
    442 
    443 	/* blow away everything in BINDINGDIR */
    444 
    445 	lockfd = open(YPBINDLOCK, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644);
    446 	if (lockfd == -1)
    447 		err(1, "Cannot create %s", YPBINDLOCK);
    448 
    449 #if O_SHLOCK == 0
    450 	(void) flock(lockfd, LOCK_SH);
    451 #endif
    452 
    453 	(void) pmap_unset(YPBINDPROG, YPBINDVERS);
    454 
    455 	udptransp = svcudp_create(RPC_ANYSOCK);
    456 	if (udptransp == NULL)
    457 		errx(1, "Cannot create udp service.");
    458 
    459 	if (!svc_register(udptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2,
    460 	    IPPROTO_UDP))
    461 		errx(1, "Unable to register (YPBINDPROG, YPBINDVERS, udp).");
    462 
    463 	tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0);
    464 	if (tcptransp == NULL)
    465 		errx(1, "Cannot create tcp service.");
    466 
    467 	if (!svc_register(tcptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2,
    468 	    IPPROTO_TCP))
    469 		errx(1, "Unable to register (YPBINDPROG, YPBINDVERS, tcp).");
    470 
    471 	if ((rpcsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
    472 		err(1, "rpc socket");
    473 	if ((pingsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
    474 		err(1, "ping socket");
    475 
    476 	(void) fcntl(rpcsock, F_SETFL, fcntl(rpcsock, F_GETFL, 0) | FNDELAY);
    477 	(void) fcntl(pingsock, F_SETFL, fcntl(pingsock, F_GETFL, 0) | FNDELAY);
    478 
    479 	one = 1;
    480 	(void) setsockopt(rpcsock, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one));
    481 	rmtca.prog = YPPROG;
    482 	rmtca.vers = YPVERS;
    483 	rmtca.proc = YPPROC_DOMAIN_NONACK;
    484 	rmtca.xdr_args = NULL;		/* set at call time */
    485 	rmtca.args_ptr = NULL;		/* set at call time */
    486 	rmtcr.port_ptr = &rmtcr_port;
    487 	rmtcr.xdr_results = xdr_bool;
    488 	rmtcr.results_ptr = (caddr_t)&rmtcr_outval;
    489 
    490 	/* build initial domain binding, make it "unsuccessful" */
    491 	ypbindlist = makebinding(domainname);
    492 	ypbindlist->dom_vers = YPVERS;
    493 	ypbindlist->dom_alive = 0;
    494 	ypbindlist->dom_lockfd = -1;
    495 	removelock(ypbindlist);
    496 
    497 	checkwork();
    498 
    499 	while (1) {
    500 		width = svc_maxfd;
    501 		if (rpcsock > width)
    502 			width = rpcsock;
    503 		if (pingsock > width)
    504 			width = pingsock;
    505 		width++;
    506 
    507 		fdsr = svc_fdset;
    508 		FD_SET(rpcsock, &fdsr);
    509 		FD_SET(pingsock, &fdsr);
    510 		tv.tv_sec = 1;
    511 		tv.tv_usec = 0;
    512 
    513 		switch (select(width, &fdsr, NULL, NULL, &tv)) {
    514 		case 0:
    515 			checkwork();
    516 			break;
    517 		case -1:
    518 			warn("select");
    519 			break;
    520 		default:
    521 			if (FD_ISSET(rpcsock, &fdsr))
    522 				handle_replies();
    523 			if (FD_ISSET(pingsock, &fdsr))
    524 				handle_ping();
    525 			svc_getreqset(&fdsr);
    526 			if (check)
    527 				checkwork();
    528 			break;
    529 		}
    530 
    531 		if (!evil && ypbindlist->dom_alive) {
    532 			evil = 1;
    533 #ifdef DEBUG
    534 			if (!debug)
    535 #endif
    536 				daemon(0, 0);
    537 		}
    538 	}
    539 }
    540 
    541 /*
    542  * State transition is done like this:
    543  *
    544  * STATE	EVENT		ACTION			NEWSTATE	TIMEOUT
    545  * no binding	timeout		broadcast 		no binding	5 sec
    546  * no binding	answer		--			binding		60 sec
    547  * binding	timeout		ping server		checking	5 sec
    548  * checking	timeout		ping server + broadcast	checking	5 sec
    549  * checking	answer		--			binding		60 sec
    550  */
    551 void
    552 checkwork()
    553 {
    554 	struct _dom_binding *ypdb;
    555 	time_t t;
    556 
    557 	check = 0;
    558 
    559 	time(&t);
    560 	for (ypdb = ypbindlist; ypdb; ypdb = ypdb->dom_pnext) {
    561 		if (ypdb->dom_check_t < t) {
    562 			if (ypdb->dom_alive == 1)
    563 				ping(ypdb);
    564 			else
    565 				broadcast(ypdb);
    566 			time(&t);
    567 			ypdb->dom_check_t = t + 5;
    568 		}
    569 	}
    570 }
    571 
    572 int
    573 ping(ypdb)
    574 	struct _dom_binding *ypdb;
    575 {
    576 	char *dom = ypdb->dom_domain;
    577 	struct rpc_msg msg;
    578 	char buf[BUFSIZE];
    579 	enum clnt_stat st;
    580 	int outlen;
    581 	AUTH *rpcua;
    582 	XDR xdr;
    583 
    584 	(void) memset(&xdr, 0, sizeof xdr);
    585 	(void) memset(&msg, 0, sizeof msg);
    586 
    587 	rpcua = authunix_create_default();
    588 	if (rpcua == NULL) {
    589 #ifdef DEBUG
    590 		if (debug)
    591 			printf("cannot get unix auth\n");
    592 #endif
    593 		return RPC_SYSTEMERROR;
    594 	}
    595 
    596 	msg.rm_direction = CALL;
    597 	msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
    598 	msg.rm_call.cb_prog = YPPROG;
    599 	msg.rm_call.cb_vers = YPVERS;
    600 	msg.rm_call.cb_proc = YPPROC_DOMAIN_NONACK;
    601 	msg.rm_call.cb_cred = rpcua->ah_cred;
    602 	msg.rm_call.cb_verf = rpcua->ah_verf;
    603 
    604 	msg.rm_xid = ypdb->dom_xid;
    605 	xdrmem_create(&xdr, buf, sizeof buf, XDR_ENCODE);
    606 	if (!xdr_callmsg(&xdr, &msg)) {
    607 		st = RPC_CANTENCODEARGS;
    608 		AUTH_DESTROY(rpcua);
    609 		return st;
    610 	}
    611 	if (!xdr_ypdomain_wrap_string(&xdr, &dom)) {
    612 		st = RPC_CANTENCODEARGS;
    613 		AUTH_DESTROY(rpcua);
    614 		return st;
    615 	}
    616 	outlen = (int)xdr_getpos(&xdr);
    617 	xdr_destroy(&xdr);
    618 	if (outlen < 1) {
    619 		st = RPC_CANTENCODEARGS;
    620 		AUTH_DESTROY(rpcua);
    621 		return st;
    622 	}
    623 	AUTH_DESTROY(rpcua);
    624 
    625 	ypdb->dom_alive = 2;
    626 	if (sendto(pingsock, buf, outlen, 0,
    627 		   (struct sockaddr *)&ypdb->dom_server_addr,
    628 		   sizeof ypdb->dom_server_addr) == -1)
    629 		warn("ping: sendto");
    630 	return 0;
    631 
    632 }
    633 
    634 int
    635 broadcast(ypdb)
    636 	struct _dom_binding *ypdb;
    637 {
    638 	char *dom = ypdb->dom_domain;
    639 	struct rpc_msg msg;
    640 	char buf[BUFSIZE], inbuf[8192];
    641 	enum clnt_stat st;
    642 	int outlen, i, sock, len;
    643 	struct sockaddr_in bindsin;
    644 	struct ifconf ifc;
    645 	struct ifreq ifreq, *ifr;
    646 	struct in_addr in;
    647 	AUTH *rpcua;
    648 	XDR xdr;
    649 
    650 	rmtca.xdr_args = xdr_ypdomain_wrap_string;
    651 	rmtca.args_ptr = (char *)&dom;
    652 
    653 	(void) memset(&xdr, 0, sizeof xdr);
    654 	(void) memset(&msg, 0, sizeof msg);
    655 
    656 	rpcua = authunix_create_default();
    657 	if (rpcua == NULL) {
    658 #ifdef DEBUG
    659 		if (debug)
    660 			printf("cannot get unix auth\n");
    661 #endif
    662 		return RPC_SYSTEMERROR;
    663 	}
    664 	msg.rm_direction = CALL;
    665 	msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
    666 	msg.rm_call.cb_prog = PMAPPROG;
    667 	msg.rm_call.cb_vers = PMAPVERS;
    668 	msg.rm_call.cb_proc = PMAPPROC_CALLIT;
    669 	msg.rm_call.cb_cred = rpcua->ah_cred;
    670 	msg.rm_call.cb_verf = rpcua->ah_verf;
    671 
    672 	msg.rm_xid = ypdb->dom_xid;
    673 	xdrmem_create(&xdr, buf, sizeof buf, XDR_ENCODE);
    674 	if (!xdr_callmsg(&xdr, &msg)) {
    675 		st = RPC_CANTENCODEARGS;
    676 		AUTH_DESTROY(rpcua);
    677 		return st;
    678 	}
    679 	if (!xdr_rmtcall_args(&xdr, &rmtca)) {
    680 		st = RPC_CANTENCODEARGS;
    681 		AUTH_DESTROY(rpcua);
    682 		return st;
    683 	}
    684 	outlen = (int)xdr_getpos(&xdr);
    685 	xdr_destroy(&xdr);
    686 	if (outlen < 1) {
    687 		st = RPC_CANTENCODEARGS;
    688 		AUTH_DESTROY(rpcua);
    689 		return st;
    690 	}
    691 	AUTH_DESTROY(rpcua);
    692 
    693 	if (ypdb->dom_lockfd != -1) {
    694 		(void) close(ypdb->dom_lockfd);
    695 		ypdb->dom_lockfd = -1;
    696 		removelock(ypdb);
    697 	}
    698 
    699 	(void) memset(&bindsin, 0, sizeof bindsin);
    700 	bindsin.sin_family = AF_INET;
    701 	bindsin.sin_len = sizeof(bindsin);
    702 	bindsin.sin_port = htons(PMAPPORT);
    703 
    704 	if (ypdb->dom_alive == 2) {
    705 		/*
    706 		 * This resolves the following situation:
    707 		 * ypserver on other subnet was once bound,
    708 		 * but rebooted and is now using a different port
    709 		 */
    710 		bindsin.sin_addr = ypdb->dom_server_addr.sin_addr;
    711 		if (sendto(rpcsock, buf, outlen, 0, (struct sockaddr *)&bindsin,
    712 			   sizeof bindsin) == -1)
    713 			warn("broadcast: sendto");
    714 	}
    715 	/* find all networks and send the RPC packet out them all */
    716 	if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
    717 		warn("broadcast: socket");
    718 		return -1;
    719 	}
    720 
    721 	ifc.ifc_len = sizeof inbuf;
    722 	ifc.ifc_buf = inbuf;
    723 	if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
    724 		(void) close(sock);
    725 		warn("broadcast: ioctl(SIOCGIFCONF)");
    726 		return -1;
    727 	}
    728 	ifr = ifc.ifc_req;
    729 	ifreq.ifr_name[0] = '\0';
    730 	for (i = 0; i < ifc.ifc_len; i += len, ifr = (struct ifreq *)((caddr_t)ifr + len)) {
    731 #if defined(BSD) && BSD >= 199103
    732 		len = sizeof ifr->ifr_name + ifr->ifr_addr.sa_len;
    733 #else
    734 		len = sizeof ifc.ifc_len / sizeof(struct ifreq);
    735 #endif
    736 		ifreq = *ifr;
    737 		if (ifreq.ifr_addr.sa_family != AF_INET)
    738 			continue;
    739 		if (ioctl(sock, SIOCGIFFLAGS, &ifreq) < 0) {
    740 			warn("broadcast: ioctl(SIOCGIFFLAGS)");
    741 			continue;
    742 		}
    743 		if ((ifreq.ifr_flags & IFF_UP) == 0)
    744 			continue;
    745 
    746 		ifreq.ifr_flags &= (IFF_LOOPBACK | IFF_BROADCAST);
    747 		if (ifreq.ifr_flags == IFF_BROADCAST) {
    748 			if (ioctl(sock, SIOCGIFBRDADDR, &ifreq) < 0) {
    749 				warn("broadcast: ioctl(SIOCGIFBRDADDR)");
    750 				continue;
    751 			}
    752 		} else if (ifreq.ifr_flags == IFF_LOOPBACK) {
    753 			if (ioctl(sock, SIOCGIFADDR, &ifreq) < 0) {
    754 				warn("broadcast: ioctl(SIOCGIFADDR)");
    755 				continue;
    756 			}
    757 		} else
    758 			continue;
    759 
    760 		in = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
    761 		bindsin.sin_addr = in;
    762 		if (sendto(rpcsock, buf, outlen, 0, (struct sockaddr *)&bindsin,
    763 			   sizeof bindsin) == -1)
    764 			warn("broadcast: sendto");
    765 	}
    766 	(void) close(sock);
    767 	return 0;
    768 }
    769 
    770 static enum clnt_stat
    771 handle_replies()
    772 {
    773 	char buf[BUFSIZE];
    774 	int fromlen, inlen;
    775 	struct _dom_binding *ypdb;
    776 	struct sockaddr_in raddr;
    777 	struct rpc_msg msg;
    778 	XDR xdr;
    779 
    780 recv_again:
    781 	(void) memset(&xdr, 0, sizeof(xdr));
    782 	(void) memset(&msg, 0, sizeof(msg));
    783 	msg.acpted_rply.ar_verf = _null_auth;
    784 	msg.acpted_rply.ar_results.where = (caddr_t)&rmtcr;
    785 	msg.acpted_rply.ar_results.proc = xdr_rmtcallres;
    786 
    787 try_again:
    788 	fromlen = sizeof (struct sockaddr);
    789 	inlen = recvfrom(rpcsock, buf, sizeof buf, 0,
    790 		(struct sockaddr *)&raddr, &fromlen);
    791 	if (inlen < 0) {
    792 		if (errno == EINTR)
    793 			goto try_again;
    794 		return RPC_CANTRECV;
    795 	}
    796 	if (inlen < sizeof(u_int32_t))
    797 		goto recv_again;
    798 
    799 	/*
    800 	 * see if reply transaction id matches sent id.
    801 	 * If so, decode the results.
    802 	 */
    803 	xdrmem_create(&xdr, buf, (u_int)inlen, XDR_DECODE);
    804 	if (xdr_replymsg(&xdr, &msg)) {
    805 		if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
    806 		    (msg.acpted_rply.ar_stat == SUCCESS)) {
    807 			raddr.sin_port = htons((u_short)rmtcr_port);
    808 			ypdb = xid2ypdb(msg.rm_xid);
    809 			if (ypdb != NULL)
    810 				rpc_received(ypdb->dom_domain, &raddr, 0);
    811 		}
    812 	}
    813 	xdr.x_op = XDR_FREE;
    814 	msg.acpted_rply.ar_results.proc = xdr_void;
    815 	xdr_destroy(&xdr);
    816 
    817 	return RPC_SUCCESS;
    818 }
    819 
    820 static enum clnt_stat
    821 handle_ping()
    822 {
    823 	char buf[BUFSIZE];
    824 	int fromlen, inlen;
    825 	struct _dom_binding *ypdb;
    826 	struct sockaddr_in raddr;
    827 	struct rpc_msg msg;
    828 	XDR xdr;
    829 	bool_t res;
    830 
    831 recv_again:
    832 	(void) memset(&xdr, 0, sizeof(xdr));
    833 	(void) memset(&msg, 0, sizeof(msg));
    834 	msg.acpted_rply.ar_verf = _null_auth;
    835 	msg.acpted_rply.ar_results.where = (caddr_t)&res;
    836 	msg.acpted_rply.ar_results.proc = xdr_bool;
    837 
    838 try_again:
    839 	fromlen = sizeof (struct sockaddr);
    840 	inlen = recvfrom(pingsock, buf, sizeof buf, 0,
    841 		(struct sockaddr *)&raddr, &fromlen);
    842 	if (inlen < 0) {
    843 		if (errno == EINTR)
    844 			goto try_again;
    845 		return RPC_CANTRECV;
    846 	}
    847 	if (inlen < sizeof(u_int32_t))
    848 		goto recv_again;
    849 
    850 	/*
    851 	 * see if reply transaction id matches sent id.
    852 	 * If so, decode the results.
    853 	 */
    854 	xdrmem_create(&xdr, buf, (u_int)inlen, XDR_DECODE);
    855 	if (xdr_replymsg(&xdr, &msg)) {
    856 		if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
    857 		    (msg.acpted_rply.ar_stat == SUCCESS)) {
    858 			ypdb = xid2ypdb(msg.rm_xid);
    859 			if (ypdb != NULL)
    860 				rpc_received(ypdb->dom_domain, &raddr, 0);
    861 		}
    862 	}
    863 	xdr.x_op = XDR_FREE;
    864 	msg.acpted_rply.ar_results.proc = xdr_void;
    865 	xdr_destroy(&xdr);
    866 
    867 	return RPC_SUCCESS;
    868 }
    869 
    870 /*
    871  * LOOPBACK IS MORE IMPORTANT: PUT IN HACK
    872  */
    873 void
    874 rpc_received(dom, raddrp, force)
    875 	char *dom;
    876 	struct sockaddr_in *raddrp;
    877 	int force;
    878 {
    879 	struct _dom_binding *ypdb;
    880 	struct iovec iov[2];
    881 	struct ypbind_resp ybr;
    882 	int fd;
    883 
    884 #ifdef DEBUG
    885 	if (debug)
    886 		printf("returned from %s about %s\n",
    887 		    inet_ntoa(raddrp->sin_addr), dom);
    888 #endif
    889 
    890 	if (dom == NULL)
    891 		return;
    892 
    893 	for (ypdb = ypbindlist; ypdb; ypdb = ypdb->dom_pnext)
    894 		if (!strcmp(ypdb->dom_domain, dom))
    895 			break;
    896 
    897 	if (ypdb == NULL) {
    898 		if (force == 0)
    899 			return;
    900 		ypdb = makebinding(dom);
    901 		ypdb->dom_lockfd = -1;
    902 		ypdb->dom_pnext = ypbindlist;
    903 		ypbindlist = ypdb;
    904 	}
    905 
    906 	/* soft update, alive */
    907 	if (ypdb->dom_alive == 1 && force == 0) {
    908 		if (!memcmp(&ypdb->dom_server_addr, raddrp,
    909 			    sizeof ypdb->dom_server_addr)) {
    910 			ypdb->dom_alive = 1;
    911 			/* recheck binding in 60 sec */
    912 			ypdb->dom_check_t = time(NULL) + 60;
    913 		}
    914 		return;
    915 	}
    916 
    917 	(void) memcpy(&ypdb->dom_server_addr, raddrp,
    918 	    sizeof ypdb->dom_server_addr);
    919 	/* recheck binding in 60 seconds */
    920 	ypdb->dom_check_t = time(NULL) + 60;
    921 	ypdb->dom_vers = YPVERS;
    922 	ypdb->dom_alive = 1;
    923 
    924 	if (ypdb->dom_lockfd != -1)
    925 		(void) close(ypdb->dom_lockfd);
    926 
    927 	if ((fd = makelock(ypdb)) == -1)
    928 		return;
    929 
    930 	/*
    931 	 * ok, if BINDINGDIR exists, and we can create the binding file,
    932 	 * then write to it..
    933 	 */
    934 	ypdb->dom_lockfd = fd;
    935 
    936 	iov[0].iov_base = (caddr_t)&(udptransp->xp_port);
    937 	iov[0].iov_len = sizeof udptransp->xp_port;
    938 	iov[1].iov_base = (caddr_t)&ybr;
    939 	iov[1].iov_len = sizeof ybr;
    940 
    941 	(void) memset(&ybr, 0, sizeof ybr);
    942 	ybr.ypbind_status = YPBIND_SUCC_VAL;
    943 	ybr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr =
    944 	    raddrp->sin_addr;
    945 	ybr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port =
    946 	    raddrp->sin_port;
    947 
    948 	if (writev(ypdb->dom_lockfd, iov, 2) !=
    949 	    iov[0].iov_len + iov[1].iov_len) {
    950 		warnx("writev");
    951 		(void) close(ypdb->dom_lockfd);
    952 		removelock(ypdb);
    953 		ypdb->dom_lockfd = -1;
    954 	}
    955 }
    956 
    957 static struct _dom_binding *
    958 xid2ypdb(xid)
    959 	int xid;
    960 {
    961 	struct _dom_binding *ypdb;
    962 
    963 	for (ypdb = ypbindlist; ypdb; ypdb = ypdb->dom_pnext)
    964 		if (ypdb->dom_xid == xid)
    965 			break;
    966 	return (ypdb);
    967 }
    968 
    969 static int
    970 unique_xid(ypdb)
    971 	struct _dom_binding *ypdb;
    972 {
    973 	int tmp_xid;
    974 
    975 	tmp_xid = (long)ypdb & 0xffffffff;
    976 	while (xid2ypdb(tmp_xid) != NULL)
    977 		tmp_xid++;
    978 
    979 	return tmp_xid;
    980 }
    981