ypbind.c revision 8246
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
318246Swpaulstatic char rcsid[] = "$Id: ypbind.c,v 1.8 1995/04/26 19:03:14 wpaul Exp $";
321927Swollman#endif
331927Swollman
341927Swollman#include <sys/param.h>
351927Swollman#include <sys/types.h>
368091Swpaul#include <sys/wait.h>
371927Swollman#include <sys/ioctl.h>
381927Swollman#include <sys/signal.h>
391927Swollman#include <sys/socket.h>
401927Swollman#include <sys/file.h>
411927Swollman#include <sys/fcntl.h>
428091Swpaul#include <sys/stat.h>
431927Swollman#include <sys/uio.h>
446478Swpaul#include <syslog.h>
451927Swollman#include <stdio.h>
461927Swollman#include <errno.h>
471927Swollman#include <ctype.h>
481927Swollman#include <dirent.h>
491927Swollman#include <netdb.h>
501927Swollman#include <string.h>
511927Swollman#include <rpc/rpc.h>
521927Swollman#include <rpc/xdr.h>
531927Swollman#include <net/if.h>
546732Swpaul#include <netinet/in.h>
551927Swollman#include <arpa/inet.h>
561927Swollman#include <rpc/pmap_clnt.h>
571927Swollman#include <rpc/pmap_prot.h>
581927Swollman#include <rpc/pmap_rmt.h>
591927Swollman#include <unistd.h>
608091Swpaul#include <stdlib.h>
611927Swollman#include <rpcsvc/yp_prot.h>
621927Swollman#include <rpcsvc/ypclnt.h>
631927Swollman
641927Swollman#ifndef BINDINGDIR
651927Swollman#define BINDINGDIR "/var/yp/binding"
661927Swollman#endif
671927Swollman
686478Swpaul/*
698091Swpaul * Ping the server once every PING_INTERVAL seconds to make sure it's
708091Swpaul * still there.
716478Swpaul */
728091Swpaul#ifndef PING_INTERVAL
738091Swpaul#define PING_INTERVAL 60
748091Swpaul#endif
756478Swpaul#ifndef FAIL_THRESHOLD
766478Swpaul#define FAIL_THRESHOLD 20
776478Swpaul#endif
786478Swpaul
791927Swollmanstruct _dom_binding {
801927Swollman	struct _dom_binding *dom_pnext;
811927Swollman	char dom_domain[YPMAXDOMAIN + 1];
821927Swollman	struct sockaddr_in dom_server_addr;
838091Swpaul	CLIENT *client_handle;
841927Swollman	long int dom_vers;
851927Swollman	int dom_lockfd;
861927Swollman	int dom_alive;
878091Swpaul	int dom_broadcasting;
888091Swpaul	int dom_default;
898091Swpaul	time_t dom_check;
901927Swollman};
911927Swollman
921927Swollmanextern bool_t xdr_domainname(), xdr_ypbind_resp();
931927Swollmanextern bool_t xdr_ypreq_key(), xdr_ypresp_val();
941927Swollmanextern bool_t xdr_ypbind_setdom();
951927Swollman
968091Swpaulvoid	checkwork __P((void));
978091Swpaulvoid	*ypbindproc_null_2 __P((SVCXPRT *, void *, CLIENT *));
988091Swpaulbool_t	*ypbindproc_setdom_2 __P((SVCXPRT *, struct ypbind_setdom *, CLIENT *));
998091Swpaulvoid	rpc_received __P((char *, struct sockaddr_in *, int ));
1008091Swpaulvoid	broadcast __P((struct _dom_binding *));
1018091Swpaulint	ping __P((struct _dom_binding *, int));
1028091Swpaulvoid	handle_children __P(( int ));
1038091Swpaul
1048091Swpaulstatic char *broad_domain;
1051927Swollmanchar *domainname;
1061927Swollmanstruct _dom_binding *ypbindlist;
1071927Swollman
1081927Swollman#define YPSET_NO	0
1091927Swollman#define YPSET_LOCAL	1
1101927Swollman#define YPSET_ALL	2
1111927Swollmanint ypsetmode = YPSET_NO;
1126732Swpaulint ypsecuremode = 0;
1136732Swpaul
1148091Swpaul/* No more than MAX_CHILDREN child broadcasters at a time. */
1158091Swpaul#define MAX_CHILDREN 5
1168091Swpaulint child_fds[FD_SETSIZE];
1178091Swpaulstatic int fd[2];
1188091Swpaulint children = 0;
1198091Swpaul
1201927SwollmanSVCXPRT *udptransp, *tcptransp;
1211927Swollman
1221927Swollmanvoid *
1231927Swollmanypbindproc_null_2(transp, argp, clnt)
1241927SwollmanSVCXPRT *transp;
1251927Swollmanvoid *argp;
1261927SwollmanCLIENT *clnt;
1271927Swollman{
1281927Swollman	static char res;
1291927Swollman
1301927Swollman	bzero((char *)&res, sizeof(res));
1311927Swollman	return (void *)&res;
1321927Swollman}
1331927Swollman
1341927Swollmanstruct ypbind_resp *
1351927Swollmanypbindproc_domain_2(transp, argp, clnt)
1361927SwollmanSVCXPRT *transp;
1371927Swollmanchar *argp;
1381927SwollmanCLIENT *clnt;
1391927Swollman{
1401927Swollman	static struct ypbind_resp res;
1411927Swollman	struct _dom_binding *ypdb;
1421927Swollman	char path[MAXPATHLEN];
1431927Swollman
1441927Swollman	bzero((char *)&res, sizeof res);
1451927Swollman	res.ypbind_status = YPBIND_FAIL_VAL;
1467982Swpaul	res.ypbind_respbody.ypbind_error = YPBIND_ERR_NOSERV;
1471927Swollman
1481927Swollman	for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext)
1491927Swollman		if( strcmp(ypdb->dom_domain, argp) == 0)
1501927Swollman			break;
1511927Swollman
1521927Swollman	if(ypdb==NULL) {
1531927Swollman		ypdb = (struct _dom_binding *)malloc(sizeof *ypdb);
1548246Swpaul		if (ypdb == NULL) {
1558246Swpaul			syslog(LOG_WARNING, "malloc: %s", strerror(errno));
1568246Swpaul			res.ypbind_respbody.ypbind_error = YPBIND_ERR_RESC;
1578246Swpaul			return;
1588246Swpaul		}
1591927Swollman		bzero((char *)ypdb, sizeof *ypdb);
1601927Swollman		strncpy(ypdb->dom_domain, argp, sizeof ypdb->dom_domain);
1611927Swollman		ypdb->dom_vers = YPVERS;
1621927Swollman		ypdb->dom_alive = 0;
1638091Swpaul		ypdb->dom_default = 0;
1641927Swollman		ypdb->dom_lockfd = -1;
1658091Swpaul		sprintf(path, "%s/%s.%ld", BINDINGDIR, ypdb->dom_domain, ypdb->dom_vers);
1661927Swollman		unlink(path);
1671927Swollman		ypdb->dom_pnext = ypbindlist;
1681927Swollman		ypbindlist = ypdb;
1697982Swpaul		return &res;
1701927Swollman	}
1711927Swollman
1721927Swollman	if(ypdb->dom_alive==0)
1737982Swpaul		return &res;
1741927Swollman
1758091Swpaul	if (ping(ypdb, 1))
1768091Swpaul		return &res;
1771927Swollman
1781927Swollman	res.ypbind_status = YPBIND_SUCC_VAL;
1798246Swpaul	res.ypbind_respbody.ypbind_error = 0; /* Success */
1801927Swollman	res.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr.s_addr =
1811927Swollman		ypdb->dom_server_addr.sin_addr.s_addr;
1821927Swollman	res.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port =
1838091Swpaul		ypdb->dom_server_addr.sin_port;
1841927Swollman	/*printf("domain %s at %s/%d\n", ypdb->dom_domain,
1851927Swollman		inet_ntoa(ypdb->dom_server_addr.sin_addr),
1861927Swollman		ntohs(ypdb->dom_server_addr.sin_port));*/
1871927Swollman	return &res;
1881927Swollman}
1891927Swollman
1901927Swollmanbool_t *
1911927Swollmanypbindproc_setdom_2(transp, argp, clnt)
1921927SwollmanSVCXPRT *transp;
1931927Swollmanstruct ypbind_setdom *argp;
1941927SwollmanCLIENT *clnt;
1951927Swollman{
1961927Swollman	struct sockaddr_in *fromsin, bindsin;
1973033Sdg	static char res;
1981927Swollman
1991927Swollman	bzero((char *)&res, sizeof(res));
2001927Swollman	fromsin = svc_getcaller(transp);
2011927Swollman
2021927Swollman	switch(ypsetmode) {
2031927Swollman	case YPSET_LOCAL:
2041927Swollman		if( fromsin->sin_addr.s_addr != htonl(INADDR_LOOPBACK))
2051927Swollman			return (void *)NULL;
2061927Swollman		break;
2071927Swollman	case YPSET_ALL:
2081927Swollman		break;
2091927Swollman	case YPSET_NO:
2101927Swollman	default:
2111927Swollman		return (void *)NULL;
2121927Swollman	}
2131927Swollman
2141927Swollman	if(ntohs(fromsin->sin_port) >= IPPORT_RESERVED)
2151927Swollman		return (void *)&res;
2161927Swollman
2171927Swollman	if(argp->ypsetdom_vers != YPVERS)
2181927Swollman		return (void *)&res;
2191927Swollman
2201927Swollman	bzero((char *)&bindsin, sizeof bindsin);
2211927Swollman	bindsin.sin_family = AF_INET;
2221927Swollman	bindsin.sin_addr.s_addr = argp->ypsetdom_addr.s_addr;
2231927Swollman	bindsin.sin_port = argp->ypsetdom_port;
2241927Swollman	rpc_received(argp->ypsetdom_domain, &bindsin, 1);
2251927Swollman
2261927Swollman	res = 1;
2271927Swollman	return (void *)&res;
2281927Swollman}
2291927Swollman
2301927Swollmanstatic void
2311927Swollmanypbindprog_2(rqstp, transp)
2321927Swollmanstruct svc_req *rqstp;
2331927Swollmanregister SVCXPRT *transp;
2341927Swollman{
2351927Swollman	union {
2361927Swollman		char ypbindproc_domain_2_arg[MAXHOSTNAMELEN];
2371927Swollman		struct ypbind_setdom ypbindproc_setdom_2_arg;
2381927Swollman	} argument;
2391927Swollman	struct authunix_parms *creds;
2401927Swollman	char *result;
2411927Swollman	bool_t (*xdr_argument)(), (*xdr_result)();
2421927Swollman	char *(*local)();
2431927Swollman
2441927Swollman	switch (rqstp->rq_proc) {
2451927Swollman	case YPBINDPROC_NULL:
2461927Swollman		xdr_argument = xdr_void;
2471927Swollman		xdr_result = xdr_void;
2481927Swollman		local = (char *(*)()) ypbindproc_null_2;
2491927Swollman		break;
2501927Swollman
2511927Swollman	case YPBINDPROC_DOMAIN:
2521927Swollman		xdr_argument = xdr_domainname;
2531927Swollman		xdr_result = xdr_ypbind_resp;
2541927Swollman		local = (char *(*)()) ypbindproc_domain_2;
2551927Swollman		break;
2561927Swollman
2571927Swollman	case YPBINDPROC_SETDOM:
2581927Swollman		switch(rqstp->rq_cred.oa_flavor) {
2591927Swollman		case AUTH_UNIX:
2601927Swollman			creds = (struct authunix_parms *)rqstp->rq_clntcred;
2611927Swollman			if( creds->aup_uid != 0) {
2621927Swollman				svcerr_auth(transp, AUTH_BADCRED);
2631927Swollman				return;
2641927Swollman			}
2651927Swollman			break;
2661927Swollman		default:
2671927Swollman			svcerr_auth(transp, AUTH_TOOWEAK);
2681927Swollman			return;
2691927Swollman		}
2701927Swollman
2711927Swollman		xdr_argument = xdr_ypbind_setdom;
2721927Swollman		xdr_result = xdr_void;
2731927Swollman		local = (char *(*)()) ypbindproc_setdom_2;
2741927Swollman		break;
2751927Swollman
2761927Swollman	default:
2771927Swollman		svcerr_noproc(transp);
2781927Swollman		return;
2791927Swollman	}
2801927Swollman	bzero((char *)&argument, sizeof(argument));
2811927Swollman	if (!svc_getargs(transp, xdr_argument, &argument)) {
2821927Swollman		svcerr_decode(transp);
2831927Swollman		return;
2841927Swollman	}
2851927Swollman	result = (*local)(transp, &argument, rqstp);
2861927Swollman	if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
2871927Swollman		svcerr_systemerr(transp);
2881927Swollman	}
2891927Swollman	return;
2901927Swollman}
2911927Swollman
2928091Swpaul/* Jack the reaper */
2938091Swpaulvoid reaper(sig)
2948091Swpaulint sig;
2958091Swpaul{
2968091Swpaul	int st;
2978091Swpaul
2988091Swpaul	wait3(&st, WNOHANG, NULL);
2998091Swpaul}
3008091Swpaul
3018091Swpaulvoid
3021927Swollmanmain(argc, argv)
3038091Swpaulint argc;
3041927Swollmanchar **argv;
3051927Swollman{
3061927Swollman	char path[MAXPATHLEN];
3071927Swollman	struct timeval tv;
3081927Swollman	fd_set fdsr;
3091927Swollman	int i;
3101927Swollman
3111927Swollman	yp_get_default_domain(&domainname);
3121927Swollman	if( domainname[0] == '\0') {
3131927Swollman		fprintf(stderr, "domainname not set. Aborting.\n");
3141927Swollman		exit(1);
3151927Swollman	}
3161927Swollman
3171927Swollman	for(i=1; i<argc; i++) {
3181927Swollman		if( strcmp("-ypset", argv[i]) == 0)
3191927Swollman			ypsetmode = YPSET_ALL;
3201927Swollman		else if (strcmp("-ypsetme", argv[i]) == 0)
3216732Swpaul		        ypsetmode = YPSET_LOCAL;
3226732Swpaul		else if (strcmp("-s", argv[i]) == 0)
3236732Swpaul		        ypsecuremode++;
3241927Swollman	}
3251927Swollman
3261927Swollman	/* blow away everything in BINDINGDIR */
3271927Swollman
3281927Swollman
3291927Swollman
3301927Swollman#ifdef DAEMON
3311927Swollman	switch(fork()) {
3321927Swollman	case 0:
3331927Swollman		break;
3341927Swollman	case -1:
3351927Swollman		perror("fork");
3361927Swollman		exit(1);
3371927Swollman	default:
3381927Swollman		exit(0);
3391927Swollman	}
3401927Swollman	setsid();
3411927Swollman#endif
3421927Swollman
3431927Swollman	pmap_unset(YPBINDPROG, YPBINDVERS);
3441927Swollman
3451927Swollman	udptransp = svcudp_create(RPC_ANYSOCK);
3461927Swollman	if (udptransp == NULL) {
3471927Swollman		fprintf(stderr, "cannot create udp service.");
3481927Swollman		exit(1);
3491927Swollman	}
3501927Swollman	if (!svc_register(udptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2,
3511927Swollman	    IPPROTO_UDP)) {
3521927Swollman		fprintf(stderr, "unable to register (YPBINDPROG, YPBINDVERS, udp).");
3531927Swollman		exit(1);
3541927Swollman	}
3551927Swollman
3561927Swollman	tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0);
3571927Swollman	if (tcptransp == NULL) {
3581927Swollman		fprintf(stderr, "cannot create tcp service.");
3591927Swollman		exit(1);
3601927Swollman	}
3611927Swollman
3621927Swollman	if (!svc_register(tcptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2,
3631927Swollman	    IPPROTO_TCP)) {
3641927Swollman		fprintf(stderr, "unable to register (YPBINDPROG, YPBINDVERS, tcp).");
3651927Swollman		exit(1);
3661927Swollman	}
3671927Swollman
3681927Swollman	/* build initial domain binding, make it "unsuccessful" */
3691927Swollman	ypbindlist = (struct _dom_binding *)malloc(sizeof *ypbindlist);
3708246Swpaul	if (ypbindlist == NULL) {
3718246Swpaul		perror("malloc");
3728246Swpaul		exit(1);
3738246Swpaul	}
3741927Swollman	bzero((char *)ypbindlist, sizeof *ypbindlist);
3751927Swollman	strncpy(ypbindlist->dom_domain, domainname, sizeof ypbindlist->dom_domain);
3761927Swollman	ypbindlist->dom_vers = YPVERS;
3771927Swollman	ypbindlist->dom_alive = 0;
3781927Swollman	ypbindlist->dom_lockfd = -1;
3798091Swpaul	ypbindlist->client_handle = NULL;
3808091Swpaul	ypbindlist->dom_default = 1;
3818091Swpaul	sprintf(path, "%s/%s.%ld", BINDINGDIR, ypbindlist->dom_domain,
3821927Swollman		ypbindlist->dom_vers);
3831927Swollman	(void)unlink(path);
3841927Swollman
3858091Swpaul	/* Initialize children fds. */
3868091Swpaul	for (i = 0; i < FD_SETSIZE; i++)
3878091Swpaul		child_fds[i] = -1;
3888091Swpaul
3898246Swpaul	openlog(argv[0], LOG_PID, LOG_DAEMON);
3906478Swpaul
3911927Swollman	while(1) {
3921927Swollman		fdsr = svc_fdset;
3938091Swpaul
3948091Swpaul		for (i = 0; i < FD_SETSIZE; i++)
3958091Swpaul			if (child_fds[i] > 0 )
3968091Swpaul				FD_SET(child_fds[i], &fdsr);
3978091Swpaul
3981927Swollman		tv.tv_sec = 1;
3991927Swollman		tv.tv_usec = 0;
4001927Swollman
4018091Swpaul		switch(select(_rpc_dtablesize(), &fdsr, NULL, NULL, &tv)) {
4021927Swollman		case 0:
4031927Swollman			checkwork();
4048091Swpaul			reaper();
4051927Swollman			break;
4061927Swollman		case -1:
4078246Swpaul			syslog(LOG_WARNING, "select: %s", strerror(errno));
4081927Swollman			break;
4091927Swollman		default:
4108091Swpaul			for(i = 0; i < FD_SETSIZE; i++) {
4118091Swpaul				if (child_fds[i] > 0 && FD_ISSET(child_fds[i],&fdsr)) {
4128091Swpaul					handle_children(child_fds[i]);
4138091Swpaul					close(child_fds[i]);
4148091Swpaul					FD_CLR(child_fds[i], &fdsr);
4158091Swpaul					child_fds[i] = -1;
4168091Swpaul					children--;
4178091Swpaul
4188091Swpaul				}
4191927Swollman			}
4201927Swollman			svc_getreqset(&fdsr);
4211927Swollman			break;
4221927Swollman		}
4231927Swollman	}
4241927Swollman}
4251927Swollman
4268091Swpaulvoid
4271927Swollmancheckwork()
4281927Swollman{
4291927Swollman	struct _dom_binding *ypdb;
4301927Swollman	time_t t;
4311927Swollman
4328091Swpaul	time(&t);
4331927Swollman	for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) {
4348091Swpaul		if (!ypdb->dom_alive && !ypdb->dom_broadcasting) {
4358091Swpaul			if (!ypdb->dom_default)
4368091Swpaul				ypdb->dom_alive = 1;
4378091Swpaul			ypdb->dom_broadcasting = 1;
4388091Swpaul			broadcast(ypdb);
4391927Swollman		}
4408091Swpaul		if (ypdb->dom_alive && ypdb->dom_check < t)
4418091Swpaul			ping(ypdb, 0);
4421927Swollman	}
4431927Swollman}
4441927Swollman
4458091Swpaul/* The clnt_broadcast() callback mechanism sucks. */
4468091Swpaul
4478091Swpaul/*
4488091Swpaul * Receive results from broadcaster. Don't worry about passing
4498091Swpaul * bogus info to rpc_received() -- it can handle it.
4508091Swpaul */
4518091Swpaulvoid handle_children(i)
4528091Swpaulint i;
4538091Swpaul{
4548091Swpaul	char buf[YPMAXDOMAIN + 1];
4558091Swpaul	struct sockaddr_in addr;
4568091Swpaul
4578091Swpaul	if (read(i, &buf, sizeof(buf)) < 0)
4588246Swpaul		syslog(LOG_WARNING, "could not read from child: %s", strerror(errno));
4598091Swpaul	if (read(i, &addr, sizeof(struct sockaddr_in)) < 0)
4608246Swpaul		syslog(LOG_WARNING, "could not read from child: %s", strerror(errno));
4618091Swpaul	rpc_received((char *)&buf, &addr, 0);
4628091Swpaul}
4638091Swpaul
4648091Swpaul/*
4658091Swpaul * Send our dying words back to our parent before we perish.
4668091Swpaul */
4678091Swpaulint
4688091Swpaultell_parent(dom, addr)
4691927Swollmanchar *dom;
4708091Swpaulstruct sockaddr_in *addr;
4711927Swollman{
4728091Swpaul	char buf[YPMAXDOMAIN + 1];
4738091Swpaul	struct timeval timeout;
4748091Swpaul	fd_set fds;
4751927Swollman
4768091Swpaul	timeout.tv_sec = 5;
4778091Swpaul	timeout.tv_usec = 0;
4781927Swollman
4798091Swpaul	sprintf (buf, "%s", broad_domain);
4808091Swpaul	if (write(fd[1], &buf, sizeof(buf)) < 0)
4818091Swpaul		return(1);
4821927Swollman
4838091Swpaul	/*
4848091Swpaul	 * Stay in sync with parent: wait for it to read our first
4858091Swpaul	 * message before sending the second.
4868091Swpaul	 */
4871927Swollman
4888091Swpaul	FD_ZERO(&fds);
4898091Swpaul	FD_SET(fd[1], &fds);
4908091Swpaul	if (select(FD_SETSIZE, NULL, &fds, NULL, &timeout) == -1)
4918091Swpaul		return(1);
4928091Swpaul	if (FD_ISSET(fd[1], &fds)) {
4938091Swpaul		if (write(fd[1], addr, sizeof(struct sockaddr_in)) < 0)
4948091Swpaul			return(1);
4958091Swpaul	} else {
4968091Swpaul		return(1);
4971927Swollman	}
4981927Swollman
4998091Swpaul	close(fd[1]);
5008091Swpaul	return (0);
5018091Swpaul}
5021927Swollman
5038091Swpaulbool_t broadcast_result(out, addr)
5048091Swpaulbool_t *out;
5058091Swpaulstruct sockaddr_in *addr;
5068091Swpaul{
5078091Swpaul	if (tell_parent(&broad_domain, addr))
5088091Swpaul		syslog(LOG_WARNING, "lost connection to parent");
5098091Swpaul	return TRUE;
5108091Swpaul}
5118091Swpaul
5128091Swpaul/*
5138091Swpaul * The right way to send RPC broadcasts.
5148091Swpaul * Use the clnt_broadcast() RPC service. Unfortunately, clnt_broadcast()
5158091Swpaul * blocks while waiting for replies, so we have to fork off seperate
5168091Swpaul * broadcaster processes that do the waiting and then transmit their
5178091Swpaul * results back to the parent for processing. We also have to remember
5188091Swpaul * to save the name of the domain we're trying to bind in a global
5198091Swpaul * variable since clnt_broadcast() provides no way to pass things to
5208091Swpaul * the 'eachresult' callback function.
5218091Swpaul */
5228091Swpaulvoid
5238091Swpaulbroadcast(ypdb)
5248091Swpaulstruct _dom_binding *ypdb;
5258091Swpaul{
5268091Swpaul	bool_t out = FALSE;
5278091Swpaul	enum clnt_stat stat;
5288091Swpaul	int i;
5298091Swpaul
5308091Swpaul	if (children > MAX_CHILDREN)
5318091Swpaul		return;
5328091Swpaul
5338091Swpaul	broad_domain = ypdb->dom_domain;
5348091Swpaul
5358091Swpaul	if (pipe(fd) < 0) {
5368091Swpaul		syslog(LOG_WARNING, "pipe: %s",strerror(errno));
5378091Swpaul		return;
5381927Swollman	}
5391927Swollman
5408091Swpaul	switch(fork()) {
5418091Swpaul	case 0:
5428091Swpaul		close(fd[0]);
5438091Swpaul		break;
5448091Swpaul	case -1:
5458091Swpaul		syslog(LOG_WARNING, "fork: %s", strerror(errno));
5468091Swpaul		close(fd[1]);
5478091Swpaul		close(fd[0]);
5488091Swpaul		return;
5498091Swpaul	default:
5508091Swpaul		for (i = 0; i < FD_SETSIZE; i++) {
5518091Swpaul			if (child_fds[i] < 0) {
5528091Swpaul				child_fds[i] = fd[0];
5538091Swpaul				break;
5541927Swollman			}
5556478Swpaul		}
5568091Swpaul		close(fd[1]);
5578091Swpaul		children++;
5588091Swpaul		return;
5591927Swollman	}
5606478Swpaul
5618091Swpaul	close(ypdb->dom_lockfd);
5628091Swpaul	stat = clnt_broadcast(YPPROG, YPVERS, YPPROC_DOMAIN_NONACK,
5638091Swpaul	    xdr_domainname, (char *)ypdb->dom_domain, xdr_bool, (char *)&out,
5648091Swpaul	    broadcast_result);
5658091Swpaul
5668091Swpaul	if (stat != RPC_SUCCESS) {
5678091Swpaul		syslog(LOG_WARNING, "NIS server for domain %s not responding",
5688091Swpaul			ypdb->dom_domain);
5698091Swpaul		bzero((char *)&ypdb->dom_server_addr,
5708091Swpaul						sizeof(struct sockaddr_in));
5718091Swpaul		if (tell_parent(&ypdb->dom_domain, &ypdb->dom_server_addr))
5728091Swpaul			syslog(LOG_WARNING, "lost connection to parent");
5738091Swpaul	}
5748091Swpaul	exit(0);
5751927Swollman}
5761927Swollman
5778091Swpaul/*
5788091Swpaul * The right way to check if a server is alive.
5798091Swpaul * Attempt to get a client handle pointing to the server and send a
5808091Swpaul * YPPROC_DOMAIN_NONACK. If we don't get a response, we invalidate
5818091Swpaul * this binding entry, which will cause checkwork() to dispatch a
5828091Swpaul * broadcaster process. Note that we treat non-default domains
5838091Swpaul * specially: once bound, we keep tabs on our server, but if it
5848091Swpaul * goes away and fails to respond after one round of broadcasting, we
5858091Swpaul * abandon it until a client specifically references it again. We make
5868091Swpaul * every effort to keep our default domain bound, however, since we
5878091Swpaul * need it to keep the system on its feet.
5888091Swpaul */
5898091Swpaulint
5908091Swpaulping(ypdb, force)
5918091Swpaulstruct _dom_binding *ypdb;
5928091Swpaulint force;
5931927Swollman{
5948091Swpaul	bool_t out;
5958091Swpaul	struct timeval interval, timeout;
5968091Swpaul	enum clnt_stat stat;
5978091Swpaul	int rpcsock = RPC_ANYSOCK;
5988091Swpaul	time_t t;
5991927Swollman
6008091Swpaul	interval.tv_sec = 5;
6018091Swpaul	interval.tv_usec = 0;
6028091Swpaul	timeout.tv_sec = FAIL_THRESHOLD;
6038091Swpaul	timeout.tv_usec = 0;
6041927Swollman
6058091Swpaul	if (ypdb->dom_broadcasting)
6068091Swpaul		return(1);
6078091Swpaul
6088091Swpaul	if (!ypdb->dom_default && ypdb->dom_vers == -1 && !force)
6098091Swpaul		return(1);
6108091Swpaul
6118091Swpaul	if (ypdb->client_handle == NULL) {
6128091Swpaul		if ((ypdb->client_handle = clntudp_bufcreate(
6138091Swpaul			&ypdb->dom_server_addr, YPPROG, YPVERS,
6148091Swpaul			interval, &rpcsock, RPCSMALLMSGSIZE,
6158091Swpaul			RPCSMALLMSGSIZE)) == (CLIENT *)NULL) {
6168091Swpaul			/* Can't get a handle: we're dead. */
6178091Swpaul			ypdb->client_handle = NULL;
6188091Swpaul			ypdb->dom_alive = 0;
6198091Swpaul			ypdb->dom_vers = -1;
6208091Swpaul			flock(ypdb->dom_lockfd, LOCK_UN);
6218091Swpaul			return(1);
6228091Swpaul		}
6231927Swollman	}
6241927Swollman
6258091Swpaul	if ((stat = clnt_call(ypdb->client_handle, YPPROC_DOMAIN_NONACK,
6268091Swpaul		xdr_domainname, (char *)ypdb->dom_domain,
6278091Swpaul		xdr_bool, (char *)&out, timeout)) != RPC_SUCCESS) {
6288091Swpaul		ypdb->client_handle = NULL;
6298091Swpaul		ypdb->dom_alive = 0;
6308091Swpaul		ypdb->dom_vers = -1;
6318091Swpaul		flock(ypdb->dom_lockfd, LOCK_UN);
6328091Swpaul		return(1);
6338091Swpaul	}
6341927Swollman	/*
6358091Swpaul	 * We pinged successfully. Reset the timer.
6361927Swollman	 */
6378091Swpaul	time(&t);
6388091Swpaul	ypdb->dom_check = t + PING_INTERVAL;
6391927Swollman
6408091Swpaul	return(0);
6411927Swollman}
6421927Swollman
6438091Swpaulvoid rpc_received(dom, raddrp, force)
6441927Swollmanchar *dom;
6451927Swollmanstruct sockaddr_in *raddrp;
6461927Swollmanint force;
6471927Swollman{
6481927Swollman	struct _dom_binding *ypdb;
6491927Swollman	struct iovec iov[2];
6501927Swollman	struct ypbind_resp ybr;
6511927Swollman	char path[MAXPATHLEN];
6521927Swollman	int fd;
6531927Swollman
6546732Swpaul	/*printf("returned from %s/%d about %s\n", inet_ntoa(raddrp->sin_addr),
6556732Swpaul	       ntohs(raddrp->sin_port), dom);*/
6561927Swollman
6571927Swollman	if(dom==NULL)
6581927Swollman		return;
6591927Swollman
6608091Swpaul	for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext)
6618091Swpaul		if( strcmp(ypdb->dom_domain, dom) == 0)
6628091Swpaul			break;
6638091Swpaul
6646732Swpaul	/* if in securemode, check originating port number */
6656732Swpaul	if (ypsecuremode && (ntohs(raddrp->sin_port) >= IPPORT_RESERVED)) {
6666732Swpaul	    syslog(LOG_WARNING, "Rejected NIS server on [%s/%d] for domain %s.",
6676732Swpaul		   inet_ntoa(raddrp->sin_addr), ntohs(raddrp->sin_port),
6686732Swpaul		   dom);
6698246Swpaul	    if (ypdb != NULL) {
6708246Swpaul		ypdb->dom_broadcasting = 0;
6718246Swpaul		ypdb->dom_alive = 0;
6728246Swpaul	    }
6736732Swpaul	    return;
6746732Swpaul	}
6756732Swpaul
6768246Swpaul	if (raddrp->sin_addr.s_addr == (long)0) {
6778246Swpaul		ypdb->dom_broadcasting = 0;
6788246Swpaul		ypdb->dom_alive = 0;
6798246Swpaul		return;
6808246Swpaul	}
6818246Swpaul
6821927Swollman	if(ypdb==NULL) {
6838246Swpaul		if (force == 0)
6841927Swollman			return;
6851927Swollman		ypdb = (struct _dom_binding *)malloc(sizeof *ypdb);
6868246Swpaul		if (ypdb == NULL) {
6878246Swpaul			syslog(LOG_WARNING, "malloc: %s", strerror(errno));
6888246Swpaul			return;
6898246Swpaul		}
6901927Swollman		bzero((char *)ypdb, sizeof *ypdb);
6911927Swollman		strncpy(ypdb->dom_domain, dom, sizeof ypdb->dom_domain);
6921927Swollman		ypdb->dom_lockfd = -1;
6938091Swpaul		ypdb->dom_default = 0;
6948246Swpaul		ypdb->dom_alive = 0;
6958246Swpaul		ypdb->dom_broadcasting = 0;
6961927Swollman		ypdb->dom_pnext = ypbindlist;
6971927Swollman		ypbindlist = ypdb;
6981927Swollman	}
6991927Swollman
7008091Swpaul	/* We've recovered from a crash: inform the world. */
7018091Swpaul	if (ypdb->dom_vers = -1 && ypdb->dom_server_addr.sin_addr.s_addr)
7028091Swpaul		syslog(LOG_WARNING, "NIS server for domain %s OK",
7038091Swpaul							ypdb->dom_domain);
7046478Swpaul
7051927Swollman	bcopy((char *)raddrp, (char *)&ypdb->dom_server_addr,
7061927Swollman		sizeof ypdb->dom_server_addr);
7076478Swpaul
7081927Swollman	ypdb->dom_vers = YPVERS;
7091927Swollman	ypdb->dom_alive = 1;
7108091Swpaul	ypdb->dom_broadcasting = 0;
7111927Swollman
7121927Swollman	if(ypdb->dom_lockfd != -1)
7131927Swollman		close(ypdb->dom_lockfd);
7141927Swollman
7158091Swpaul	sprintf(path, "%s/%s.%ld", BINDINGDIR,
7161927Swollman		ypdb->dom_domain, ypdb->dom_vers);
7171927Swollman#ifdef O_SHLOCK
7187864Swpaul	if( (fd=open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1) {
7191927Swollman		(void)mkdir(BINDINGDIR, 0755);
7207864Swpaul		if( (fd=open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1)
7211927Swollman			return;
7221927Swollman	}
7231927Swollman#else
7247864Swpaul	if( (fd=open(path, O_CREAT|O_RDWR|O_TRUNC, 0644)) == -1) {
7251927Swollman		(void)mkdir(BINDINGDIR, 0755);
7267864Swpaul		if( (fd=open(path, O_CREAT|O_RDWR|O_TRUNC, 0644)) == -1)
7271927Swollman			return;
7281927Swollman	}
7291927Swollman	flock(fd, LOCK_SH);
7301927Swollman#endif
7311927Swollman
7321927Swollman	/*
7331927Swollman	 * ok, if BINDINGDIR exists, and we can create the binding file,
7341927Swollman	 * then write to it..
7351927Swollman	 */
7361927Swollman	ypdb->dom_lockfd = fd;
7371927Swollman
7381927Swollman	iov[0].iov_base = (caddr_t)&(udptransp->xp_port);
7391927Swollman	iov[0].iov_len = sizeof udptransp->xp_port;
7401927Swollman	iov[1].iov_base = (caddr_t)&ybr;
7411927Swollman	iov[1].iov_len = sizeof ybr;
7421927Swollman
7431927Swollman	bzero(&ybr, sizeof ybr);
7441927Swollman	ybr.ypbind_status = YPBIND_SUCC_VAL;
7451927Swollman	ybr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr = raddrp->sin_addr;
7461927Swollman	ybr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port = raddrp->sin_port;
7471927Swollman
7481927Swollman	if( writev(ypdb->dom_lockfd, iov, 2) != iov[0].iov_len + iov[1].iov_len) {
7498091Swpaul		syslog(LOG_WARNING, "write: %s", strerror(errno));
7501927Swollman		close(ypdb->dom_lockfd);
7511927Swollman		ypdb->dom_lockfd = -1;
7521927Swollman		return;
7531927Swollman	}
7541927Swollman}
755