ypbind.c revision 6732
11927Swollman/*
21927Swollman * Copyright (c) 1992/3 Theo de Raadt <deraadt@fsa.ca>
31927Swollman * All rights reserved.
41927Swollman *
51927Swollman * Redistribution and use in source and binary forms, with or without
61927Swollman * modification, are permitted provided that the following conditions
71927Swollman * are met:
81927Swollman * 1. Redistributions of source code must retain the above copyright
91927Swollman *    notice, this list of conditions and the following disclaimer.
101927Swollman * 2. Redistributions in binary form must reproduce the above copyright
111927Swollman *    notice, this list of conditions and the following disclaimer in the
121927Swollman *    documentation and/or other materials provided with the distribution.
131927Swollman * 3. The name of the author may not be used to endorse or promote
141927Swollman *    products derived from this software without specific prior written
151927Swollman *    permission.
161927Swollman *
171927Swollman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
181927Swollman * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
191927Swollman * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201927Swollman * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
211927Swollman * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221927Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231927Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241927Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251927Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261927Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271927Swollman * SUCH DAMAGE.
281927Swollman */
291927Swollman
301927Swollman#ifndef LINT
316732Swpaulstatic char rcsid[] = "$Id: ypbind.c,v 1.3 1995/02/16 01:21:44 wpaul Exp $";
321927Swollman#endif
331927Swollman
341927Swollman#include <sys/param.h>
351927Swollman#include <sys/types.h>
361927Swollman#include <sys/ioctl.h>
371927Swollman#include <sys/signal.h>
381927Swollman#include <sys/socket.h>
391927Swollman#include <sys/file.h>
401927Swollman#include <sys/fcntl.h>
411927Swollman#include <sys/uio.h>
426478Swpaul#include <syslog.h>
431927Swollman#include <stdio.h>
441927Swollman#include <errno.h>
451927Swollman#include <ctype.h>
461927Swollman#include <dirent.h>
471927Swollman#include <netdb.h>
481927Swollman#include <string.h>
491927Swollman#include <rpc/rpc.h>
501927Swollman#include <rpc/xdr.h>
511927Swollman#include <net/if.h>
526732Swpaul#include <netinet/in.h>
531927Swollman#include <arpa/inet.h>
541927Swollman#include <rpc/pmap_clnt.h>
551927Swollman#include <rpc/pmap_prot.h>
561927Swollman#include <rpc/pmap_rmt.h>
571927Swollman#include <unistd.h>
581927Swollman#include <rpcsvc/yp_prot.h>
591927Swollman#include <rpcsvc/ypclnt.h>
601927Swollman
611927Swollman#ifndef BINDINGDIR
621927Swollman#define BINDINGDIR "/var/yp/binding"
631927Swollman#endif
641927Swollman
656478Swpaul/*
666478Swpaul * Number of seconds to wait before for ping replies before we
676478Swpaul * decide that our server is dead.
686478Swpaul */
696478Swpaul#ifndef FAIL_THRESHOLD
706478Swpaul#define FAIL_THRESHOLD 20
716478Swpaul#endif
726478Swpaul
731927Swollmanstruct _dom_binding {
741927Swollman	struct _dom_binding *dom_pnext;
751927Swollman	char dom_domain[YPMAXDOMAIN + 1];
761927Swollman	struct sockaddr_in dom_server_addr;
771927Swollman	unsigned short int dom_server_port;
781927Swollman	int dom_socket;
791927Swollman	CLIENT *dom_client;
801927Swollman	long int dom_vers;
811927Swollman	time_t dom_check_t;
821927Swollman	int dom_lockfd;
831927Swollman	int dom_alive;
846478Swpaul	int dom_answered;
856478Swpaul	int dom_interval;
861927Swollman};
871927Swollman
881927Swollmanextern bool_t xdr_domainname(), xdr_ypbind_resp();
891927Swollmanextern bool_t xdr_ypreq_key(), xdr_ypresp_val();
901927Swollmanextern bool_t xdr_ypbind_setdom();
911927Swollman
921927Swollmanchar *domainname;
931927Swollman
941927Swollmanstruct _dom_binding *ypbindlist;
951927Swollmanint check;
961927Swollman
971927Swollman#define YPSET_NO	0
981927Swollman#define YPSET_LOCAL	1
991927Swollman#define YPSET_ALL	2
1001927Swollmanint ypsetmode = YPSET_NO;
1011927Swollman
1026732Swpaulint ypsecuremode = 0;
1036732Swpaul
1041927Swollmanint rpcsock;
1051927Swollmanstruct rmtcallargs rmtca;
1061927Swollmanstruct rmtcallres rmtcr;
1071927Swollmanchar rmtcr_outval;
1081927Swollmanu_long rmtcr_port;
1091927SwollmanSVCXPRT *udptransp, *tcptransp;
1101927Swollman
1111927Swollmanvoid *
1121927Swollmanypbindproc_null_2(transp, argp, clnt)
1131927SwollmanSVCXPRT *transp;
1141927Swollmanvoid *argp;
1151927SwollmanCLIENT *clnt;
1161927Swollman{
1171927Swollman	static char res;
1181927Swollman
1191927Swollman	bzero((char *)&res, sizeof(res));
1201927Swollman	return (void *)&res;
1211927Swollman}
1221927Swollman
1231927Swollmanstruct ypbind_resp *
1241927Swollmanypbindproc_domain_2(transp, argp, clnt)
1251927SwollmanSVCXPRT *transp;
1261927Swollmanchar *argp;
1271927SwollmanCLIENT *clnt;
1281927Swollman{
1291927Swollman	static struct ypbind_resp res;
1301927Swollman	struct _dom_binding *ypdb;
1311927Swollman	char path[MAXPATHLEN];
1321927Swollman
1331927Swollman	bzero((char *)&res, sizeof res);
1341927Swollman	res.ypbind_status = YPBIND_FAIL_VAL;
1351927Swollman
1361927Swollman	for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext)
1371927Swollman		if( strcmp(ypdb->dom_domain, argp) == 0)
1381927Swollman			break;
1391927Swollman
1401927Swollman	if(ypdb==NULL) {
1411927Swollman		ypdb = (struct _dom_binding *)malloc(sizeof *ypdb);
1421927Swollman		bzero((char *)ypdb, sizeof *ypdb);
1431927Swollman		strncpy(ypdb->dom_domain, argp, sizeof ypdb->dom_domain);
1441927Swollman		ypdb->dom_vers = YPVERS;
1451927Swollman		ypdb->dom_alive = 0;
1461927Swollman		ypdb->dom_lockfd = -1;
1471927Swollman		sprintf(path, "%s/%s.%d", BINDINGDIR, ypdb->dom_domain, ypdb->dom_vers);
1481927Swollman		unlink(path);
1491927Swollman		ypdb->dom_pnext = ypbindlist;
1501927Swollman		ypbindlist = ypdb;
1511927Swollman		return NULL;
1521927Swollman	}
1531927Swollman
1541927Swollman	if(ypdb->dom_alive==0)
1551927Swollman		return NULL;
1561927Swollman
1571927Swollman#if 0
1581927Swollman	delta = ypdb->dom_check_t - ypdb->dom_ask_t;
1591927Swollman	if( !(ypdb->dom_ask_t==0 || delta > 5)) {
1601927Swollman		ypdb->dom_ask_t = time(NULL);
1611927Swollman		/*
1621927Swollman		 * Hmm. More than 2 requests in 5 seconds have indicated that my
1631927Swollman		 * binding is possibly incorrect. Ok, make myself unalive, and
1641927Swollman		 * find out what the actual state is.
1651927Swollman		 */
1661927Swollman		if(ypdb->dom_lockfd!=-1)
1671927Swollman			close(ypdb->dom_lockfd);
1681927Swollman		ypdb->dom_lockfd = -1;
1691927Swollman		ypdb->dom_alive = 0;
1701927Swollman		ypdb->dom_lockfd = -1;
1711927Swollman		sprintf(path, "%s/%s.%d", BINDINGDIR, ypdb->dom_domain, ypdb->dom_vers);
1721927Swollman		unlink(path);
1731927Swollman		return NULL;
1741927Swollman	}
1751927Swollman#endif
1761927Swollman
1771927Swollmananswer:
1781927Swollman	res.ypbind_status = YPBIND_SUCC_VAL;
1791927Swollman	res.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr.s_addr =
1801927Swollman		ypdb->dom_server_addr.sin_addr.s_addr;
1811927Swollman	res.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port =
1821927Swollman		ypdb->dom_server_port;
1831927Swollman	/*printf("domain %s at %s/%d\n", ypdb->dom_domain,
1841927Swollman		inet_ntoa(ypdb->dom_server_addr.sin_addr),
1851927Swollman		ntohs(ypdb->dom_server_addr.sin_port));*/
1861927Swollman	return &res;
1871927Swollman}
1881927Swollman
1891927Swollmanbool_t *
1901927Swollmanypbindproc_setdom_2(transp, argp, clnt)
1911927SwollmanSVCXPRT *transp;
1921927Swollmanstruct ypbind_setdom *argp;
1931927SwollmanCLIENT *clnt;
1941927Swollman{
1951927Swollman	struct sockaddr_in *fromsin, bindsin;
1963033Sdg	static char res;
1971927Swollman
1981927Swollman	bzero((char *)&res, sizeof(res));
1991927Swollman	fromsin = svc_getcaller(transp);
2001927Swollman
2011927Swollman	switch(ypsetmode) {
2021927Swollman	case YPSET_LOCAL:
2031927Swollman		if( fromsin->sin_addr.s_addr != htonl(INADDR_LOOPBACK))
2041927Swollman			return (void *)NULL;
2051927Swollman		break;
2061927Swollman	case YPSET_ALL:
2071927Swollman		break;
2081927Swollman	case YPSET_NO:
2091927Swollman	default:
2101927Swollman		return (void *)NULL;
2111927Swollman	}
2121927Swollman
2131927Swollman	if(ntohs(fromsin->sin_port) >= IPPORT_RESERVED)
2141927Swollman		return (void *)&res;
2151927Swollman
2161927Swollman	if(argp->ypsetdom_vers != YPVERS)
2171927Swollman		return (void *)&res;
2181927Swollman
2191927Swollman	bzero((char *)&bindsin, sizeof bindsin);
2201927Swollman	bindsin.sin_family = AF_INET;
2211927Swollman	bindsin.sin_addr.s_addr = argp->ypsetdom_addr.s_addr;
2221927Swollman	bindsin.sin_port = argp->ypsetdom_port;
2231927Swollman	rpc_received(argp->ypsetdom_domain, &bindsin, 1);
2241927Swollman
2251927Swollman	res = 1;
2261927Swollman	return (void *)&res;
2271927Swollman}
2281927Swollman
2291927Swollmanstatic void
2301927Swollmanypbindprog_2(rqstp, transp)
2311927Swollmanstruct svc_req *rqstp;
2321927Swollmanregister SVCXPRT *transp;
2331927Swollman{
2341927Swollman	union {
2351927Swollman		char ypbindproc_domain_2_arg[MAXHOSTNAMELEN];
2361927Swollman		struct ypbind_setdom ypbindproc_setdom_2_arg;
2371927Swollman	} argument;
2381927Swollman	struct authunix_parms *creds;
2391927Swollman	char *result;
2401927Swollman	bool_t (*xdr_argument)(), (*xdr_result)();
2411927Swollman	char *(*local)();
2421927Swollman
2431927Swollman	switch (rqstp->rq_proc) {
2441927Swollman	case YPBINDPROC_NULL:
2451927Swollman		xdr_argument = xdr_void;
2461927Swollman		xdr_result = xdr_void;
2471927Swollman		local = (char *(*)()) ypbindproc_null_2;
2481927Swollman		break;
2491927Swollman
2501927Swollman	case YPBINDPROC_DOMAIN:
2511927Swollman		xdr_argument = xdr_domainname;
2521927Swollman		xdr_result = xdr_ypbind_resp;
2531927Swollman		local = (char *(*)()) ypbindproc_domain_2;
2541927Swollman		break;
2551927Swollman
2561927Swollman	case YPBINDPROC_SETDOM:
2571927Swollman		switch(rqstp->rq_cred.oa_flavor) {
2581927Swollman		case AUTH_UNIX:
2591927Swollman			creds = (struct authunix_parms *)rqstp->rq_clntcred;
2601927Swollman			if( creds->aup_uid != 0) {
2611927Swollman				svcerr_auth(transp, AUTH_BADCRED);
2621927Swollman				return;
2631927Swollman			}
2641927Swollman			break;
2651927Swollman		default:
2661927Swollman			svcerr_auth(transp, AUTH_TOOWEAK);
2671927Swollman			return;
2681927Swollman		}
2691927Swollman
2701927Swollman		xdr_argument = xdr_ypbind_setdom;
2711927Swollman		xdr_result = xdr_void;
2721927Swollman		local = (char *(*)()) ypbindproc_setdom_2;
2731927Swollman		break;
2741927Swollman
2751927Swollman	default:
2761927Swollman		svcerr_noproc(transp);
2771927Swollman		return;
2781927Swollman	}
2791927Swollman	bzero((char *)&argument, sizeof(argument));
2801927Swollman	if (!svc_getargs(transp, xdr_argument, &argument)) {
2811927Swollman		svcerr_decode(transp);
2821927Swollman		return;
2831927Swollman	}
2841927Swollman	result = (*local)(transp, &argument, rqstp);
2851927Swollman	if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
2861927Swollman		svcerr_systemerr(transp);
2871927Swollman	}
2881927Swollman	return;
2891927Swollman}
2901927Swollman
2911927Swollmanmain(argc, argv)
2921927Swollmanchar **argv;
2931927Swollman{
2941927Swollman	char path[MAXPATHLEN];
2951927Swollman	struct timeval tv;
2961927Swollman	fd_set fdsr;
2971927Swollman	int width;
2981927Swollman	int i;
2991927Swollman
3001927Swollman	yp_get_default_domain(&domainname);
3011927Swollman	if( domainname[0] == '\0') {
3021927Swollman		fprintf(stderr, "domainname not set. Aborting.\n");
3031927Swollman		exit(1);
3041927Swollman	}
3051927Swollman
3061927Swollman	for(i=1; i<argc; i++) {
3071927Swollman		if( strcmp("-ypset", argv[i]) == 0)
3081927Swollman			ypsetmode = YPSET_ALL;
3091927Swollman		else if (strcmp("-ypsetme", argv[i]) == 0)
3106732Swpaul		        ypsetmode = YPSET_LOCAL;
3116732Swpaul		else if (strcmp("-s", argv[i]) == 0)
3126732Swpaul		        ypsecuremode++;
3131927Swollman	}
3141927Swollman
3151927Swollman	/* blow away everything in BINDINGDIR */
3161927Swollman
3171927Swollman
3181927Swollman
3191927Swollman#ifdef DAEMON
3201927Swollman	switch(fork()) {
3211927Swollman	case 0:
3221927Swollman		break;
3231927Swollman	case -1:
3241927Swollman		perror("fork");
3251927Swollman		exit(1);
3261927Swollman	default:
3271927Swollman		exit(0);
3281927Swollman	}
3291927Swollman	setsid();
3301927Swollman#endif
3311927Swollman
3321927Swollman	pmap_unset(YPBINDPROG, YPBINDVERS);
3331927Swollman
3341927Swollman	udptransp = svcudp_create(RPC_ANYSOCK);
3351927Swollman	if (udptransp == NULL) {
3361927Swollman		fprintf(stderr, "cannot create udp service.");
3371927Swollman		exit(1);
3381927Swollman	}
3391927Swollman	if (!svc_register(udptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2,
3401927Swollman	    IPPROTO_UDP)) {
3411927Swollman		fprintf(stderr, "unable to register (YPBINDPROG, YPBINDVERS, udp).");
3421927Swollman		exit(1);
3431927Swollman	}
3441927Swollman
3451927Swollman	tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0);
3461927Swollman	if (tcptransp == NULL) {
3471927Swollman		fprintf(stderr, "cannot create tcp service.");
3481927Swollman		exit(1);
3491927Swollman	}
3501927Swollman
3511927Swollman	if (!svc_register(tcptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2,
3521927Swollman	    IPPROTO_TCP)) {
3531927Swollman		fprintf(stderr, "unable to register (YPBINDPROG, YPBINDVERS, tcp).");
3541927Swollman		exit(1);
3551927Swollman	}
3561927Swollman
3571927Swollman	if( (rpcsock=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
3581927Swollman		perror("socket");
3591927Swollman		return -1;
3601927Swollman	}
3611927Swollman
3621927Swollman	fcntl(rpcsock, F_SETFL, fcntl(rpcsock, F_GETFL, 0) | FNDELAY);
3631927Swollman	i = 1;
3641927Swollman	setsockopt(rpcsock, SOL_SOCKET, SO_BROADCAST, &i, sizeof(i));
3651927Swollman	rmtca.prog = YPPROG;
3661927Swollman	rmtca.vers = YPVERS;
3671927Swollman	rmtca.proc = YPPROC_DOMAIN_NONACK;
3681927Swollman	rmtca.xdr_args = NULL;		/* set at call time */
3691927Swollman	rmtca.args_ptr = NULL;		/* set at call time */
3701927Swollman	rmtcr.port_ptr = &rmtcr_port;
3711927Swollman	rmtcr.xdr_results = xdr_bool;
3721927Swollman	rmtcr.results_ptr = (caddr_t)&rmtcr_outval;
3731927Swollman
3741927Swollman	/* build initial domain binding, make it "unsuccessful" */
3751927Swollman	ypbindlist = (struct _dom_binding *)malloc(sizeof *ypbindlist);
3761927Swollman	bzero((char *)ypbindlist, sizeof *ypbindlist);
3771927Swollman	strncpy(ypbindlist->dom_domain, domainname, sizeof ypbindlist->dom_domain);
3781927Swollman	ypbindlist->dom_vers = YPVERS;
3796478Swpaul	ypbindlist->dom_interval = 0;
3801927Swollman	ypbindlist->dom_alive = 0;
3816478Swpaul	ypbindlist->dom_answered = 0;
3821927Swollman	ypbindlist->dom_lockfd = -1;
3836478Swpaul	ypbindlist->dom_check_t = time(NULL) + ypbindlist->dom_interval;
3841927Swollman	sprintf(path, "%s/%s.%d", BINDINGDIR, ypbindlist->dom_domain,
3851927Swollman		ypbindlist->dom_vers);
3861927Swollman	(void)unlink(path);
3871927Swollman
3886478Swpaul	openlog(argv[0], LOG_PID, LOG_AUTH);
3891927Swollman	width = getdtablesize();
3906478Swpaul
3911927Swollman	while(1) {
3921927Swollman		fdsr = svc_fdset;
3931927Swollman		FD_SET(rpcsock, &fdsr);
3941927Swollman		tv.tv_sec = 1;
3951927Swollman		tv.tv_usec = 0;
3961927Swollman
3971927Swollman		switch(select(width, &fdsr, NULL, NULL, &tv)) {
3981927Swollman		case 0:
3991927Swollman			checkwork();
4001927Swollman			break;
4011927Swollman		case -1:
4021927Swollman			perror("select\n");
4031927Swollman			break;
4041927Swollman		default:
4051927Swollman			if(FD_ISSET(rpcsock, &fdsr)) {
4061927Swollman				FD_CLR(rpcsock, &fdsr);
4071927Swollman				handle_replies();
4081927Swollman			}
4091927Swollman			svc_getreqset(&fdsr);
4101927Swollman			break;
4111927Swollman		}
4121927Swollman	}
4131927Swollman}
4141927Swollman
4151927Swollman/*
4161927Swollman * change to do something like this:
4171927Swollman *
4181927Swollman * STATE	TIME		ACTION		NEWTIME	NEWSTATE
4191927Swollman * no binding	t==*		broadcast 	t=2	no binding
4201927Swollman * binding	t==60		check server	t=10	binding
4211927Swollman * binding	t=10		broadcast	t=2	no binding
4221927Swollman */
4236478Swpaul
4246478Swpaul/*
4256478Swpaul * The above comment makes no sense whatsoever. This is what should
4266478Swpaul * be happening:
4276478Swpaul *
4286478Swpaul * - If we have any servers in our binding list marked alive, ping
4296478Swpaul *   them _and them alone_ only once every 60 seconds to make sure
4306478Swpaul *   they haven't crapped out on us (i.e. bother only the servers
4316478Swpaul *   we know about: *DON'T* continually bother everybody with broadcast
4326478Swpaul *   packets every 5 seconds like we used to).
4336478Swpaul * - If they don't respond within FAIL_THRESHOLD seconds after the ping,
4346478Swpaul *   they're toast: mark them unalive and start to scream and shout.
4356478Swpaul * - If we don't have any servers marked alive, then we're in desperate
4366478Swpaul *   trouble and we need to broadcast a cry for help every 5 seconds
4376478Swpaul *   until somebody answers us.
4386478Swpaul */
4396478Swpaul
4401927Swollmancheckwork()
4411927Swollman{
4421927Swollman	struct _dom_binding *ypdb;
4431927Swollman	time_t t;
4441927Swollman
4451927Swollman	for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) {
4466478Swpaul		time(&t);
4476478Swpaul		if (ypdb->dom_check_t < t) {
4486478Swpaul			broadcast(ypdb->dom_domain,
4496478Swpaul				ypdb->dom_server_addr, ypdb->dom_alive);
4506478Swpaul			ypdb->dom_check_t = t + ypdb->dom_interval;
4516478Swpaul			ypdb->dom_answered = 0;
4526478Swpaul		} else
4536478Swpaul		if (!ypdb->dom_answered && ypdb->dom_alive &&
4546478Swpaul				ypdb->dom_check_t < (t + FAIL_THRESHOLD)) {
4556732Swpaul			ypdb->dom_check_t = ypdb->dom_alive =
4566478Swpaul				ypdb->dom_vers = 0;
4576478Swpaul			ypdb->dom_interval = 5;
4586732Swpaul			syslog (LOG_NOTICE,
4596732Swpaul				"NIS server [%s] for domain %s not responding.",
4606732Swpaul				inet_ntoa(ypdb->dom_server_addr.sin_addr),
4616732Swpaul				ypdb->dom_domain);
4621927Swollman		}
4631927Swollman	}
4641927Swollman}
4651927Swollman
4666478Swpaulbroadcast(dom, saddr, direct)
4671927Swollmanchar *dom;
4686478Swpaulstruct sockaddr_in saddr;
4696478Swpaulint direct;
4701927Swollman{
4711927Swollman	struct rpc_msg rpcmsg;
4721927Swollman	char buf[1400], inbuf[8192];
4731927Swollman	enum clnt_stat st;
4741927Swollman	struct timeval tv;
4751927Swollman	int outlen, i, sock, len;
4761927Swollman	struct sockaddr_in bsin;
4771927Swollman	struct ifconf ifc;
4781927Swollman	struct ifreq ifreq, *ifr;
4791927Swollman	struct in_addr in;
4801927Swollman	AUTH *rpcua;
4811927Swollman	XDR rpcxdr;
4821927Swollman
4831927Swollman	rmtca.xdr_args = xdr_domainname;
4841927Swollman	rmtca.args_ptr = dom;
4851927Swollman
4861927Swollman	bzero((char *)&bsin, sizeof bsin);
4871927Swollman	bsin.sin_family = AF_INET;
4881927Swollman	bsin.sin_port = htons(PMAPPORT);
4891927Swollman
4901927Swollman	bzero((char *)&rpcxdr, sizeof rpcxdr);
4911927Swollman	bzero((char *)&rpcmsg, sizeof rpcmsg);
4921927Swollman
4931927Swollman	rpcua = authunix_create_default();
4941927Swollman	if( rpcua == (AUTH *)NULL) {
4951927Swollman		/*printf("cannot get unix auth\n");*/
4961927Swollman		return RPC_SYSTEMERROR;
4971927Swollman	}
4981927Swollman	rpcmsg.rm_direction = CALL;
4991927Swollman	rpcmsg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
5001927Swollman	rpcmsg.rm_call.cb_prog = PMAPPROG;
5011927Swollman	rpcmsg.rm_call.cb_vers = PMAPVERS;
5021927Swollman	rpcmsg.rm_call.cb_proc = PMAPPROC_CALLIT;
5031927Swollman	rpcmsg.rm_call.cb_cred = rpcua->ah_cred;
5041927Swollman	rpcmsg.rm_call.cb_verf = rpcua->ah_verf;
5051927Swollman
5061927Swollman	gettimeofday(&tv, (struct timezone *)0);
5071927Swollman	rpcmsg.rm_xid = (int)dom;
5081927Swollman	tv.tv_usec = 0;
5091927Swollman	xdrmem_create(&rpcxdr, buf, sizeof buf, XDR_ENCODE);
5101927Swollman	if( (!xdr_callmsg(&rpcxdr, &rpcmsg)) ) {
5111927Swollman		st = RPC_CANTENCODEARGS;
5121927Swollman		AUTH_DESTROY(rpcua);
5131927Swollman		return st;
5141927Swollman	}
5151927Swollman	if( (!xdr_rmtcall_args(&rpcxdr, &rmtca)) ) {
5161927Swollman		st = RPC_CANTENCODEARGS;
5171927Swollman		AUTH_DESTROY(rpcua);
5181927Swollman		return st;
5191927Swollman	}
5201927Swollman	outlen = (int)xdr_getpos(&rpcxdr);
5211927Swollman	xdr_destroy(&rpcxdr);
5221927Swollman	if(outlen<1) {
5231927Swollman		AUTH_DESTROY(rpcua);
5241927Swollman		return st;
5251927Swollman	}
5261927Swollman	AUTH_DESTROY(rpcua);
5271927Swollman
5281927Swollman	/* find all networks and send the RPC packet out them all */
5291927Swollman	if( (sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
5301927Swollman		perror("socket");
5311927Swollman		return -1;
5321927Swollman	}
5331927Swollman
5346478Swpaul	/*
5356478Swpaul	 * It's impolite to blast broadcast packets all over the place
5366478Swpaul	 * when we don't really have to.
5376478Swpaul	 */
5386478Swpaul	if (!direct) {
5396478Swpaul		ifc.ifc_len = sizeof inbuf;
5406478Swpaul		ifc.ifc_buf = inbuf;
5416478Swpaul		if( ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
5426478Swpaul			close(sock);
5436478Swpaul			perror("ioctl(SIOCGIFCONF)");
5446478Swpaul			return -1;
5456478Swpaul		}
5466478Swpaul		ifr = ifc.ifc_req;
5476478Swpaul		ifreq.ifr_name[0] = '\0';
5486478Swpaul		for(i=0; i<ifc.ifc_len; i+=len, ifr=(struct ifreq *)((caddr_t)ifr+len)) {
5491927Swollman#if defined(BSD) && BSD >= 199103
5506478Swpaul			len = sizeof ifr->ifr_name + ifr->ifr_addr.sa_len;
5511927Swollman#else
5526478Swpaul			len = sizeof ifc.ifc_len / sizeof(struct ifreq);
5531927Swollman#endif
5546478Swpaul			ifreq = *ifr;
5556478Swpaul			if( ifreq.ifr_addr.sa_family != AF_INET)
5561927Swollman				continue;
5576478Swpaul			if( ioctl(sock, SIOCGIFFLAGS, &ifreq) < 0) {
5586478Swpaul				perror("ioctl(SIOCGIFFLAGS)");
5596478Swpaul				continue;
5601927Swollman			}
5616478Swpaul			if( (ifreq.ifr_flags & IFF_UP) == 0)
5621927Swollman				continue;
5631927Swollman
5646478Swpaul			ifreq.ifr_flags &= (IFF_LOOPBACK | IFF_BROADCAST);
5656478Swpaul			if( ifreq.ifr_flags==IFF_BROADCAST ) {
5666478Swpaul				if( ioctl(sock, SIOCGIFBRDADDR, &ifreq) < 0 ) {
5676478Swpaul					perror("ioctl(SIOCGIFBRDADDR)");
5686478Swpaul					continue;
5696478Swpaul				}
5706478Swpaul			} else if( ifreq.ifr_flags==IFF_LOOPBACK ) {
5716478Swpaul				if( ioctl(sock, SIOCGIFADDR, &ifreq) < 0 ) {
5726478Swpaul					perror("ioctl(SIOCGIFADDR)");
5736478Swpaul					continue;
5746478Swpaul				}
5756478Swpaul			} else
5766478Swpaul				continue;
5776478Swpaul			in = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
5786478Swpaul			bsin.sin_addr = in;
5796478Swpaul			if( sendto(rpcsock, buf, outlen, 0,
5806478Swpaul				(struct sockaddr *)&bsin, sizeof bsin) < 0 )
5816478Swpaul				perror("sendto");
5826478Swpaul		}
5836478Swpaul	} else {
5846478Swpaul		in = ((struct sockaddr_in *)&saddr)->sin_addr;
5851927Swollman		bsin.sin_addr = in;
5861927Swollman		if( sendto(rpcsock, buf, outlen, 0, (struct sockaddr *)&bsin,
5871927Swollman		   sizeof bsin) < 0 )
5881927Swollman			perror("sendto");
5891927Swollman	}
5906478Swpaul
5911927Swollman	close(sock);
5921927Swollman	return 0;
5931927Swollman}
5941927Swollman
5951927Swollman/*enum clnt_stat*/
5961927Swollmanhandle_replies()
5971927Swollman{
5981927Swollman	char buf[1400];
5991927Swollman	int fromlen, inlen;
6001927Swollman	struct sockaddr_in raddr;
6011927Swollman	struct rpc_msg msg;
6021927Swollman	XDR xdr;
6031927Swollman
6041927Swollmanrecv_again:
6051927Swollman	bzero((char *)&xdr, sizeof(xdr));
6061927Swollman	bzero((char *)&msg, sizeof(msg));
6071927Swollman	msg.acpted_rply.ar_verf = _null_auth;
6081927Swollman	msg.acpted_rply.ar_results.where = (caddr_t)&rmtcr;
6091927Swollman	msg.acpted_rply.ar_results.proc = xdr_rmtcallres;
6101927Swollman
6111927Swollmantry_again:
6121927Swollman	fromlen = sizeof (struct sockaddr);
6131927Swollman	inlen = recvfrom(rpcsock, buf, sizeof buf, 0,
6141927Swollman		(struct sockaddr *)&raddr, &fromlen);
6151927Swollman	if(inlen<0) {
6161927Swollman		if(errno==EINTR)
6171927Swollman			goto try_again;
6181927Swollman		return RPC_CANTRECV;
6191927Swollman	}
6201927Swollman	if(inlen<sizeof(u_long))
6211927Swollman		goto recv_again;
6221927Swollman
6231927Swollman	/*
6241927Swollman	 * see if reply transaction id matches sent id.
6251927Swollman	 * If so, decode the results.
6261927Swollman	 */
6271927Swollman	xdrmem_create(&xdr, buf, (u_int)inlen, XDR_DECODE);
6281927Swollman	if( xdr_replymsg(&xdr, &msg)) {
6291927Swollman		if( (msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
6301927Swollman		   (msg.acpted_rply.ar_stat == SUCCESS)) {
6311927Swollman			raddr.sin_port = htons((u_short)rmtcr_port);
6321927Swollman			rpc_received(msg.rm_xid, &raddr, 0);
6331927Swollman		}
6341927Swollman	}
6351927Swollman	xdr.x_op = XDR_FREE;
6361927Swollman	msg.acpted_rply.ar_results.proc = xdr_void;
6371927Swollman	xdr_destroy(&xdr);
6381927Swollman
6391927Swollman	return RPC_SUCCESS;
6401927Swollman}
6411927Swollman
6421927Swollman/*
6431927Swollman * LOOPBACK IS MORE IMPORTANT: PUT IN HACK
6441927Swollman */
6451927Swollmanrpc_received(dom, raddrp, force)
6461927Swollmanchar *dom;
6471927Swollmanstruct sockaddr_in *raddrp;
6481927Swollmanint force;
6491927Swollman{
6501927Swollman	struct _dom_binding *ypdb;
6511927Swollman	struct iovec iov[2];
6521927Swollman	struct ypbind_resp ybr;
6531927Swollman	char path[MAXPATHLEN];
6541927Swollman	int fd;
6551927Swollman
6566732Swpaul	/*printf("returned from %s/%d about %s\n", inet_ntoa(raddrp->sin_addr),
6576732Swpaul	       ntohs(raddrp->sin_port), dom);*/
6581927Swollman
6591927Swollman	if(dom==NULL)
6601927Swollman		return;
6611927Swollman
6626732Swpaul	/* if in securemode, check originating port number */
6636732Swpaul	if (ypsecuremode && (ntohs(raddrp->sin_port) >= IPPORT_RESERVED)) {
6646732Swpaul	    syslog(LOG_WARNING, "Rejected NIS server on [%s/%d] for domain %s.",
6656732Swpaul		   inet_ntoa(raddrp->sin_addr), ntohs(raddrp->sin_port),
6666732Swpaul		   dom);
6676732Swpaul	    return;
6686732Swpaul	}
6696732Swpaul
6701927Swollman	for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext)
6711927Swollman		if( strcmp(ypdb->dom_domain, dom) == 0)
6721927Swollman			break;
6731927Swollman
6741927Swollman	if(ypdb==NULL) {
6751927Swollman		if(force==0)
6761927Swollman			return;
6771927Swollman		ypdb = (struct _dom_binding *)malloc(sizeof *ypdb);
6781927Swollman		bzero((char *)ypdb, sizeof *ypdb);
6791927Swollman		strncpy(ypdb->dom_domain, dom, sizeof ypdb->dom_domain);
6801927Swollman		ypdb->dom_lockfd = -1;
6811927Swollman		ypdb->dom_pnext = ypbindlist;
6821927Swollman		ypbindlist = ypdb;
6831927Swollman	}
6841927Swollman
6856478Swpaul	/* soft update, alive, less than FAIL_THRESHOLD seconds old */
6866478Swpaul	if(ypdb->dom_alive==1 && (force==0 || ypdb->dom_answered == 0)
6876732Swpaul		&& (ypdb->dom_check_t - FAIL_THRESHOLD) > time(NULL)
6886732Swpaul		&& (ypdb->dom_server_addr.sin_port == raddrp->sin_port)) {
6896478Swpaul		ypdb->dom_answered = 1;
6906478Swpaul		ypdb->dom_interval = 60;
6911927Swollman		return;
6926478Swpaul	}
6931927Swollman
6946478Swpaul	/*
6956478Swpaul	 * We've recovered from a crash: inform the world.
6966478Swpaul	 */
6976478Swpaul	if (ypdb->dom_vers == 0)
6986478Swpaul		syslog(LOG_NOTICE, "NIS server [%s] for domain %s OK.",
6996732Swpaul			inet_ntoa(raddrp->sin_addr), ypdb->dom_domain);
7006478Swpaul
7011927Swollman	bcopy((char *)raddrp, (char *)&ypdb->dom_server_addr,
7021927Swollman		sizeof ypdb->dom_server_addr);
7036478Swpaul
7041927Swollman	ypdb->dom_vers = YPVERS;
7051927Swollman	ypdb->dom_alive = 1;
7066478Swpaul	ypdb->dom_answered = 1;
7076478Swpaul	ypdb->dom_interval = 60;
7086478Swpaul	ypdb->dom_check_t = time(NULL) + ypdb->dom_interval;
7091927Swollman
7101927Swollman	if(ypdb->dom_lockfd != -1)
7111927Swollman		close(ypdb->dom_lockfd);
7121927Swollman
7131927Swollman	sprintf(path, "%s/%s.%d", BINDINGDIR,
7141927Swollman		ypdb->dom_domain, ypdb->dom_vers);
7151927Swollman#ifdef O_SHLOCK
7161927Swollman	if( (fd=open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1) {
7171927Swollman		(void)mkdir(BINDINGDIR, 0755);
7181927Swollman		if( (fd=open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1)
7191927Swollman			return;
7201927Swollman	}
7211927Swollman#else
7221927Swollman	if( (fd=open(path, O_CREAT|O_RDWR|O_TRUNC, 0644)) == -1) {
7231927Swollman		(void)mkdir(BINDINGDIR, 0755);
7241927Swollman		if( (fd=open(path, O_CREAT|O_RDWR|O_TRUNC, 0644)) == -1)
7251927Swollman			return;
7261927Swollman	}
7271927Swollman	flock(fd, LOCK_SH);
7281927Swollman#endif
7291927Swollman
7301927Swollman	/*
7311927Swollman	 * ok, if BINDINGDIR exists, and we can create the binding file,
7321927Swollman	 * then write to it..
7331927Swollman	 */
7341927Swollman	ypdb->dom_lockfd = fd;
7351927Swollman
7361927Swollman	iov[0].iov_base = (caddr_t)&(udptransp->xp_port);
7371927Swollman	iov[0].iov_len = sizeof udptransp->xp_port;
7381927Swollman	iov[1].iov_base = (caddr_t)&ybr;
7391927Swollman	iov[1].iov_len = sizeof ybr;
7401927Swollman
7411927Swollman	bzero(&ybr, sizeof ybr);
7421927Swollman	ybr.ypbind_status = YPBIND_SUCC_VAL;
7431927Swollman	ybr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr = raddrp->sin_addr;
7441927Swollman	ybr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port = raddrp->sin_port;
7451927Swollman
7461927Swollman	if( writev(ypdb->dom_lockfd, iov, 2) != iov[0].iov_len + iov[1].iov_len) {
7471927Swollman		perror("write");
7481927Swollman		close(ypdb->dom_lockfd);
7491927Swollman		ypdb->dom_lockfd = -1;
7501927Swollman		return;
7511927Swollman	}
7521927Swollman}
753