ypbind.c revision 226690
133965Sjdp/*
2130561Sobrien * Copyright (c) 1992/3 Theo de Raadt <deraadt@fsa.ca>
3218822Sdim * All rights reserved.
433965Sjdp *
533965Sjdp * Redistribution and use in source and binary forms, with or without
633965Sjdp * modification, are permitted provided that the following conditions
7104834Sobrien * are met:
833965Sjdp * 1. Redistributions of source code must retain the above copyright
9104834Sobrien *    notice, this list of conditions and the following disclaimer.
10104834Sobrien * 2. Redistributions in binary form must reproduce the above copyright
11104834Sobrien *    notice, this list of conditions and the following disclaimer in the
12104834Sobrien *    documentation and/or other materials provided with the distribution.
1333965Sjdp * 3. The name of the author may not be used to endorse or promote
14104834Sobrien *    products derived from this software without specific prior written
15104834Sobrien *    permission.
16104834Sobrien *
17104834Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
1833965Sjdp * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19104834Sobrien * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20104834Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
21218822Sdim * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2233965Sjdp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23218822Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2433965Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2533965Sjdp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2633965Sjdp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2733965Sjdp * SUCH DAMAGE.
2833965Sjdp */
2933965Sjdp
3033965Sjdp#include <sys/cdefs.h>
3133965Sjdp__FBSDID("$FreeBSD: head/usr.sbin/ypbind/ypbind.c 226690 2011-10-24 14:35:31Z glebius $");
3233965Sjdp
3333965Sjdp#include <sys/param.h>
3433965Sjdp#include <sys/types.h>
3533965Sjdp#include <sys/wait.h>
3633965Sjdp#include <sys/ioctl.h>
3733965Sjdp#include <sys/mman.h>
3833965Sjdp#include <sys/signal.h>
3933965Sjdp#include <sys/socket.h>
4033965Sjdp#include <sys/file.h>
4133965Sjdp#include <sys/fcntl.h>
4233965Sjdp#include <sys/stat.h>
4333965Sjdp#include <sys/uio.h>
4433965Sjdp#include <ctype.h>
4533965Sjdp#include <dirent.h>
46218822Sdim#include <err.h>
4733965Sjdp#include <errno.h>
48218822Sdim#include <netdb.h>
49218822Sdim#include <signal.h>
50218822Sdim#include <stdio.h>
5133965Sjdp#include <stdlib.h>
5233965Sjdp#include <string.h>
5360484Sobrien#include <syslog.h>
5460484Sobrien#include <unistd.h>
55218822Sdim#include <rpc/rpc.h>
56218822Sdim#include <rpc/xdr.h>
57218822Sdim#include <net/if.h>
58218822Sdim#include <netinet/in.h>
59218822Sdim#include <arpa/inet.h>
60218822Sdim#include <rpc/pmap_clnt.h>
61218822Sdim#include <rpc/pmap_prot.h>
62218822Sdim#include <rpc/pmap_rmt.h>
63218822Sdim#include <rpc/rpc_com.h>
64218822Sdim#include <rpcsvc/yp.h>
6578828Sobrien#include <rpcsvc/ypclnt.h>
6678828Sobrien#include "yp_ping.h"
6778828Sobrien
6878828Sobrien#ifndef BINDINGDIR
6978828Sobrien#define BINDINGDIR "/var/yp/binding"
7078828Sobrien#endif
71218822Sdim
72218822Sdim#ifndef YPBINDLOCK
7378828Sobrien#define YPBINDLOCK "/var/run/ypbind.lock"
7478828Sobrien#endif
7578828Sobrien
76218822Sdimstruct _dom_binding {
7778828Sobrien	struct _dom_binding *dom_pnext;
78218822Sdim	char dom_domain[YPMAXDOMAIN + 1];
79218822Sdim	struct sockaddr_in dom_server_addr;
80218822Sdim	long int dom_vers;
8160484Sobrien	int dom_lockfd;
8233965Sjdp	int dom_alive;
8333965Sjdp	int dom_broadcast_pid;
8433965Sjdp	int dom_pipe_fds[2];
85130561Sobrien	int dom_default;
86218822Sdim};
8733965Sjdp
8889857Sobrien#define READFD ypdb->dom_pipe_fds[0]
89104834Sobrien#define WRITEFD ypdb->dom_pipe_fds[1]
90218822Sdim#define BROADFD broad_domain->dom_pipe_fds[1]
9133965Sjdp
92130561Sobrienextern bool_t xdr_domainname(), xdr_ypbind_resp();
9333965Sjdpextern bool_t xdr_ypreq_key(), xdr_ypresp_val();
94130561Sobrienextern bool_t xdr_ypbind_setdom();
9533965Sjdp
9633965Sjdpvoid	checkwork(void);
9733965Sjdpvoid	*ypbindproc_null_2_yp(SVCXPRT *, void *, CLIENT *);
9833965Sjdpvoid	*ypbindproc_setdom_2_yp(SVCXPRT *, struct ypbind_setdom *, CLIENT *);
9933965Sjdpvoid	rpc_received(char *, struct sockaddr_in *, int);
100218822Sdimvoid	broadcast(struct _dom_binding *);
101218822Sdimint	ping(struct _dom_binding *);
10233965Sjdpint	tell_parent(char *, struct sockaddr_in *);
10333965Sjdpvoid	handle_children(struct _dom_binding *);
10433965Sjdpvoid	reaper(int);
10533965Sjdpvoid	terminate(int);
10633965Sjdpvoid	yp_restricted_mode(char *);
107104834Sobrienint	verify(struct in_addr);
10833965Sjdp
10933965Sjdpchar *domain_name;
11033965Sjdpstruct _dom_binding *ypbindlist;
11133965Sjdpstatic struct _dom_binding *broad_domain;
11233965Sjdp
11333965Sjdp#define YPSET_NO	0
114218822Sdim#define YPSET_LOCAL	1
11533965Sjdp#define YPSET_ALL	2
11633965Sjdpint ypsetmode = YPSET_NO;
11733965Sjdpint ypsecuremode = 0;
11833965Sjdpint ppid;
11933965Sjdp
12033965Sjdp#define NOT_RESPONDING_HYSTERESIS 10
12133965Sjdpstatic int not_responding_count = 0;
12233965Sjdp
12333965Sjdp/*
12433965Sjdp * Special restricted mode variables: when in restricted mode, only the
12533965Sjdp * specified restricted_domain will be bound, and only the servers listed
12633965Sjdp * in restricted_addrs will be used for binding.
12733965Sjdp */
12833965Sjdp#define RESTRICTED_SERVERS 10
12933965Sjdpint yp_restricted = 0;
13033965Sjdpint yp_manycast = 0;
13133965Sjdpstruct in_addr restricted_addrs[RESTRICTED_SERVERS];
13233965Sjdp
13333965Sjdp/* No more than MAX_CHILDREN child broadcasters at a time. */
13433965Sjdp#ifndef MAX_CHILDREN
13533965Sjdp#define MAX_CHILDREN 5
13633965Sjdp#endif
137218822Sdim/* No more than MAX_DOMAINS simultaneous domains */
13833965Sjdp#ifndef MAX_DOMAINS
13933965Sjdp#define MAX_DOMAINS 200
14033965Sjdp#endif
14133965Sjdp/* RPC timeout value */
142130561Sobrien#ifndef FAIL_THRESHOLD
143218822Sdim#define FAIL_THRESHOLD 20
14433965Sjdp#endif
145218822Sdim
146218822Sdim/* Number of times to fish for a response froma particular set of hosts */
147218822Sdim#ifndef MAX_RETRIES
148218822Sdim#define MAX_RETRIES 30
149218822Sdim#endif
150218822Sdim
151218822Sdimint retries = 0;
152218822Sdimint children = 0;
153218822Sdimint domains = 0;
154218822Sdimint yplockfd;
155218822Sdimfd_set fdsr;
156218822Sdim
157218822SdimSVCXPRT *udptransp, *tcptransp;
158218822Sdim
159218822Sdimvoid *
160218822Sdimypbindproc_null_2_yp(SVCXPRT *transp, void *argp, CLIENT *clnt)
161218822Sdim{
162218822Sdim	static char res;
163218822Sdim
164218822Sdim	bzero(&res, sizeof(res));
165218822Sdim	return &res;
166218822Sdim}
167218822Sdim
168218822Sdimstruct ypbind_resp *
16933965Sjdpypbindproc_domain_2_yp(SVCXPRT *transp, domainname *argp, CLIENT *clnt)
17033965Sjdp{
171218822Sdim	static struct ypbind_resp res;
172218822Sdim	struct _dom_binding *ypdb;
173218822Sdim	char path[MAXPATHLEN];
174218822Sdim
175218822Sdim	bzero(&res, sizeof res);
176218822Sdim	res.ypbind_status = YPBIND_FAIL_VAL;
17733965Sjdp	res.ypbind_resp_u.ypbind_error = YPBIND_ERR_NOSERV;
178218822Sdim
17933965Sjdp	if (strchr(*argp, '/')) {
18033965Sjdp		syslog(LOG_WARNING, "Domain name '%s' has embedded slash -- \
18133965Sjdprejecting.", *argp);
18233965Sjdp		return(&res);
183218822Sdim	}
18433965Sjdp
18533965Sjdp	for (ypdb = ypbindlist; ypdb; ypdb = ypdb->dom_pnext) {
18633965Sjdp		if (strcmp(ypdb->dom_domain, *argp) == 0)
18733965Sjdp			break;
18833965Sjdp		}
18933965Sjdp
19033965Sjdp	if (ypdb == NULL) {
191130561Sobrien		if (yp_restricted) {
192218822Sdim			syslog(LOG_NOTICE, "Running in restricted mode -- request to bind domain \"%s\" rejected.\n", *argp);
19333965Sjdp			return (&res);
194218822Sdim		}
19533965Sjdp
19633965Sjdp		if (domains >= MAX_DOMAINS) {
19733965Sjdp			syslog(LOG_WARNING, "domain limit (%d) exceeded",
19833965Sjdp							MAX_DOMAINS);
19933965Sjdp			res.ypbind_resp_u.ypbind_error = YPBIND_ERR_RESC;
20033965Sjdp			return (&res);
20133965Sjdp		}
20233965Sjdp		ypdb = (struct _dom_binding *)malloc(sizeof *ypdb);
20333965Sjdp		if (ypdb == NULL) {
204130561Sobrien			syslog(LOG_WARNING, "malloc: %m");
20533965Sjdp			res.ypbind_resp_u.ypbind_error = YPBIND_ERR_RESC;
20633965Sjdp			return (&res);
20733965Sjdp		}
20833965Sjdp		bzero(ypdb, sizeof *ypdb);
209104834Sobrien		strncpy(ypdb->dom_domain, *argp, sizeof ypdb->dom_domain);
21033965Sjdp		ypdb->dom_vers = YPVERS;
211130561Sobrien		ypdb->dom_alive = 0;
21233965Sjdp		ypdb->dom_default = 0;
21333965Sjdp		ypdb->dom_lockfd = -1;
21433965Sjdp		sprintf(path, "%s/%s.%ld", BINDINGDIR,
21533965Sjdp					ypdb->dom_domain, ypdb->dom_vers);
216104834Sobrien		unlink(path);
21733965Sjdp		ypdb->dom_pnext = ypbindlist;
218130561Sobrien		ypbindlist = ypdb;
21933965Sjdp		domains++;
22033965Sjdp	}
22133965Sjdp
22233965Sjdp	if (ping(ypdb)) {
22333965Sjdp		return (&res);
22433965Sjdp	}
22533965Sjdp
22633965Sjdp	res.ypbind_status = YPBIND_SUCC_VAL;
22733965Sjdp	res.ypbind_resp_u.ypbind_error = 0; /* Success */
22833965Sjdp	*(u_int32_t *)&res.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr =
22933965Sjdp		ypdb->dom_server_addr.sin_addr.s_addr;
23033965Sjdp	*(u_short *)&res.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port =
23133965Sjdp		ypdb->dom_server_addr.sin_port;
23233965Sjdp	/*printf("domain %s at %s/%d\n", ypdb->dom_domain,
23333965Sjdp		inet_ntoa(ypdb->dom_server_addr.sin_addr),
23433965Sjdp		ntohs(ypdb->dom_server_addr.sin_port));*/
23533965Sjdp	return (&res);
23633965Sjdp}
23733965Sjdp
23833965Sjdpvoid *
239218822Sdimypbindproc_setdom_2_yp(SVCXPRT *transp, ypbind_setdom *argp, CLIENT *clnt)
24033965Sjdp{
24133965Sjdp	struct sockaddr_in *fromsin, bindsin;
24233965Sjdp	static char		*result = NULL;
24333965Sjdp
24433965Sjdp	if (strchr(argp->ypsetdom_domain, '/')) {
24533965Sjdp		syslog(LOG_WARNING, "Domain name '%s' has embedded slash -- \
24633965Sjdprejecting.", argp->ypsetdom_domain);
24733965Sjdp		return(NULL);
24833965Sjdp	}
24933965Sjdp	fromsin = svc_getcaller(transp);
250130561Sobrien
25133965Sjdp	switch (ypsetmode) {
25233965Sjdp	case YPSET_LOCAL:
25333965Sjdp		if (fromsin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) {
25433965Sjdp			svcerr_noprog(transp);
255130561Sobrien			return(NULL);
25633965Sjdp		}
25733965Sjdp		break;
25833965Sjdp	case YPSET_ALL:
25933965Sjdp		break;
260130561Sobrien	case YPSET_NO:
26133965Sjdp	default:
26233965Sjdp		svcerr_noprog(transp);
26333965Sjdp		return(NULL);
26433965Sjdp	}
26533965Sjdp
26633965Sjdp	if (ntohs(fromsin->sin_port) >= IPPORT_RESERVED) {
26733965Sjdp		svcerr_noprog(transp);
26833965Sjdp		return(NULL);
26933965Sjdp	}
27033965Sjdp
27133965Sjdp	if (argp->ypsetdom_vers != YPVERS) {
27233965Sjdp		svcerr_noprog(transp);
27333965Sjdp		return(NULL);
27433965Sjdp	}
27533965Sjdp
27633965Sjdp	bzero(&bindsin, sizeof bindsin);
27733965Sjdp	bindsin.sin_family = AF_INET;
27833965Sjdp	bindsin.sin_addr.s_addr = *(u_int32_t *)argp->ypsetdom_binding.ypbind_binding_addr;
27933965Sjdp	bindsin.sin_port = *(u_short *)argp->ypsetdom_binding.ypbind_binding_port;
280218822Sdim	rpc_received(argp->ypsetdom_domain, &bindsin, 1);
28133965Sjdp
282218822Sdim	return((void *) &result);
283218822Sdim}
284218822Sdim
285218822Sdimvoid
286218822Sdimypbindprog_2(struct svc_req *rqstp, register SVCXPRT *transp)
287218822Sdim{
288218822Sdim	union {
289218822Sdim		domainname ypbindproc_domain_2_arg;
290218822Sdim		struct ypbind_setdom ypbindproc_setdom_2_arg;
291218822Sdim	} argument;
292218822Sdim	struct authunix_parms *creds;
293218822Sdim	char *result;
294218822Sdim	bool_t (*xdr_argument)(), (*xdr_result)();
295218822Sdim	char *(*local)();
296218822Sdim
297218822Sdim	switch (rqstp->rq_proc) {
298218822Sdim	case YPBINDPROC_NULL:
299218822Sdim		xdr_argument = xdr_void;
300218822Sdim		xdr_result = xdr_void;
301218822Sdim		local = (char *(*)()) ypbindproc_null_2_yp;
302218822Sdim		break;
303218822Sdim
304218822Sdim	case YPBINDPROC_DOMAIN:
305218822Sdim		xdr_argument = xdr_domainname;
306218822Sdim		xdr_result = xdr_ypbind_resp;
307218822Sdim		local = (char *(*)()) ypbindproc_domain_2_yp;
308218822Sdim		break;
309218822Sdim
310218822Sdim	case YPBINDPROC_SETDOM:
311218822Sdim		switch (rqstp->rq_cred.oa_flavor) {
312218822Sdim		case AUTH_UNIX:
313218822Sdim			creds = (struct authunix_parms *)rqstp->rq_clntcred;
314218822Sdim			if (creds->aup_uid != 0) {
31533965Sjdp				svcerr_auth(transp, AUTH_BADCRED);
316218822Sdim				return;
317218822Sdim			}
318218822Sdim			break;
319218822Sdim		default:
320218822Sdim			svcerr_auth(transp, AUTH_TOOWEAK);
321218822Sdim			return;
32233965Sjdp		}
323218822Sdim
32433965Sjdp		xdr_argument = xdr_ypbind_setdom;
325218822Sdim		xdr_result = xdr_void;
326218822Sdim		local = (char *(*)()) ypbindproc_setdom_2_yp;
327218822Sdim		break;
328218822Sdim
329218822Sdim	default:
330218822Sdim		svcerr_noproc(transp);
331218822Sdim		return;
332218822Sdim	}
333218822Sdim	bzero(&argument, sizeof(argument));
334218822Sdim	if (!svc_getargs(transp, (xdrproc_t)xdr_argument, &argument)) {
335218822Sdim		svcerr_decode(transp);
336218822Sdim		return;
337218822Sdim	}
338218822Sdim	result = (*local)(transp, &argument, rqstp);
339218822Sdim	if (result != NULL &&
34033965Sjdp	    !svc_sendreply(transp, (xdrproc_t)xdr_result, result)) {
34133965Sjdp		svcerr_systemerr(transp);
34233965Sjdp	}
34333965Sjdp	return;
34433965Sjdp}
34533965Sjdp
34633965Sjdp/* Jack the reaper */
34733965Sjdpvoid
34833965Sjdpreaper(int sig)
34933965Sjdp{
350130561Sobrien	int st;
351218822Sdim
352218822Sdim	while (wait3(&st, WNOHANG, NULL) > 0)
353218822Sdim		children--;
354218822Sdim}
355218822Sdim
35633965Sjdpvoid
357218822Sdimterminate(int sig)
35833965Sjdp{
35989857Sobrien	struct _dom_binding *ypdb;
36033965Sjdp	char path[MAXPATHLEN];
36133965Sjdp
36233965Sjdp	if (ppid != getpid())
36333965Sjdp		exit(0);
36433965Sjdp
36533965Sjdp	for (ypdb = ypbindlist; ypdb; ypdb = ypdb->dom_pnext) {
36633965Sjdp		close(ypdb->dom_lockfd);
36733965Sjdp		if (ypdb->dom_broadcast_pid)
36833965Sjdp			kill(ypdb->dom_broadcast_pid, SIGINT);
36933965Sjdp		sprintf(path, "%s/%s.%ld", BINDINGDIR,
37033965Sjdp			ypdb->dom_domain, ypdb->dom_vers);
37133965Sjdp		unlink(path);
37233965Sjdp	}
37333965Sjdp	close(yplockfd);
37433965Sjdp	unlink(YPBINDLOCK);
37533965Sjdp	pmap_unset(YPBINDPROG, YPBINDVERS);
37633965Sjdp	exit(0);
37733965Sjdp}
37833965Sjdp
37933965Sjdpint
38033965Sjdpmain(int argc, char *argv[])
38133965Sjdp{
38233965Sjdp	struct timeval tv;
38333965Sjdp	int i;
38433965Sjdp	DIR *dird;
38533965Sjdp	struct dirent *dirp;
38633965Sjdp	struct _dom_binding *ypdb, *next;
38733965Sjdp
38833965Sjdp	/* Check that another ypbind isn't already running. */
38933965Sjdp	if ((yplockfd = (open(YPBINDLOCK, O_RDONLY|O_CREAT, 0444))) == -1)
39033965Sjdp		err(1, "%s", YPBINDLOCK);
39133965Sjdp
39233965Sjdp	if (flock(yplockfd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK)
39333965Sjdp		errx(1, "another ypbind is already running. Aborting");
39433965Sjdp
39533965Sjdp	/* XXX domainname will be overriden if we use restricted mode */
39633965Sjdp	yp_get_default_domain(&domain_name);
39733965Sjdp	if (domain_name[0] == '\0')
39833965Sjdp		errx(1, "domainname not set. Aborting");
39933965Sjdp
40033965Sjdp	for (i = 1; i<argc; i++) {
40189857Sobrien		if (strcmp("-ypset", argv[i]) == 0)
40233965Sjdp			ypsetmode = YPSET_ALL;
40389857Sobrien		else if (strcmp("-ypsetme", argv[i]) == 0)
40433965Sjdp		        ypsetmode = YPSET_LOCAL;
40533965Sjdp		else if (strcmp("-s", argv[i]) == 0)
40633965Sjdp		        ypsecuremode++;
40789857Sobrien		else if (strcmp("-S", argv[i]) == 0 && argc > i)
40833965Sjdp			yp_restricted_mode(argv[++i]);
40989857Sobrien		else if (strcmp("-m", argv[i]) == 0)
41033965Sjdp			yp_manycast++;
41189857Sobrien		else
41233965Sjdp			errx(1, "unknown option: %s", argv[i]);
41389857Sobrien	}
414130561Sobrien
41533965Sjdp	/* blow away everything in BINDINGDIR (if it exists) */
41633965Sjdp
41733965Sjdp	if ((dird = opendir(BINDINGDIR)) != NULL) {
41833965Sjdp		char path[MAXPATHLEN];
419130561Sobrien		while ((dirp = readdir(dird)) != NULL)
420218822Sdim			if (strcmp(dirp->d_name, ".") &&
42133965Sjdp			    strcmp(dirp->d_name, "..")) {
42233965Sjdp				sprintf(path,"%s/%s",BINDINGDIR,dirp->d_name);
42333965Sjdp				unlink(path);
424218822Sdim			}
42533965Sjdp		closedir(dird);
42633965Sjdp	}
42733965Sjdp
42877298Sobrien#ifdef DAEMON
42933965Sjdp	if (daemon(0,0))
430130561Sobrien		err(1, "fork");
43133965Sjdp#endif
43233965Sjdp
43333965Sjdp	pmap_unset(YPBINDPROG, YPBINDVERS);
43433965Sjdp
43533965Sjdp	udptransp = svcudp_create(RPC_ANYSOCK);
436130561Sobrien	if (udptransp == NULL)
43733965Sjdp		errx(1, "cannot create udp service");
43833965Sjdp	if (!svc_register(udptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2,
43933965Sjdp	    IPPROTO_UDP))
44033965Sjdp		errx(1, "unable to register (YPBINDPROG, YPBINDVERS, udp)");
44133965Sjdp
44233965Sjdp	tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0);
44333965Sjdp	if (tcptransp == NULL)
44433965Sjdp		errx(1, "cannot create tcp service");
44533965Sjdp
44633965Sjdp	if (!svc_register(tcptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2,
447130561Sobrien	    IPPROTO_TCP))
44833965Sjdp		errx(1, "unable to register (YPBINDPROG, YPBINDVERS, tcp)");
44933965Sjdp
45033965Sjdp	/* build initial domain binding, make it "unsuccessful" */
451218822Sdim	ypbindlist = (struct _dom_binding *)malloc(sizeof *ypbindlist);
45233965Sjdp	if (ypbindlist == NULL)
45333965Sjdp		errx(1, "malloc");
45433965Sjdp	bzero(ypbindlist, sizeof *ypbindlist);
45589857Sobrien	strncpy(ypbindlist->dom_domain, domain_name, sizeof ypbindlist->dom_domain);
45689857Sobrien	ypbindlist->dom_vers = YPVERS;
45733965Sjdp	ypbindlist->dom_alive = 0;
45833965Sjdp	ypbindlist->dom_lockfd = -1;
45933965Sjdp	ypbindlist->dom_default = 1;
46033965Sjdp	domains++;
46133965Sjdp
46233965Sjdp	signal(SIGCHLD, reaper);
46333965Sjdp	signal(SIGTERM, terminate);
46433965Sjdp
46533965Sjdp	ppid = getpid(); /* Remember who we are. */
46633965Sjdp
46733965Sjdp	openlog(argv[0], LOG_PID, LOG_DAEMON);
46833965Sjdp
46933965Sjdp	if (madvise(NULL, 0, MADV_PROTECT) != 0)
47033965Sjdp		syslog(LOG_WARNING, "madvise(): %m");
47133965Sjdp
47233965Sjdp	/* Kick off the default domain */
473130561Sobrien	broadcast(ypbindlist);
47433965Sjdp
47533965Sjdp	while (1) {
47633965Sjdp		fdsr = svc_fdset;
477130561Sobrien
47833965Sjdp		tv.tv_sec = 60;
47933965Sjdp		tv.tv_usec = 0;
48033965Sjdp
48133965Sjdp		switch (select(_rpc_dtablesize(), &fdsr, NULL, NULL, &tv)) {
48233965Sjdp		case 0:
48333965Sjdp			checkwork();
484130561Sobrien			break;
485218822Sdim		case -1:
486218822Sdim			if (errno != EINTR)
487218822Sdim				syslog(LOG_WARNING, "select: %m");
48833965Sjdp			break;
48933965Sjdp		default:
49033965Sjdp			for (ypdb = ypbindlist; ypdb; ypdb = next) {
49133965Sjdp				next = ypdb->dom_pnext;
49233965Sjdp				if (READFD > 0 && FD_ISSET(READFD, &fdsr)) {
493218822Sdim					handle_children(ypdb);
49433965Sjdp					if (children == (MAX_CHILDREN - 1))
49533965Sjdp						checkwork();
49633965Sjdp				}
49733965Sjdp			}
49833965Sjdp			svc_getreqset(&fdsr);
49933965Sjdp			break;
50089857Sobrien		}
50189857Sobrien	}
50233965Sjdp
50333965Sjdp	/* NOTREACHED */
50433965Sjdp	exit(1);
50533965Sjdp}
50633965Sjdp
507218822Sdimvoid
508130561Sobriencheckwork(void)
50933965Sjdp{
51033965Sjdp	struct _dom_binding *ypdb;
51133965Sjdp
512130561Sobrien	for (ypdb = ypbindlist; ypdb; ypdb = ypdb->dom_pnext)
51333965Sjdp		ping(ypdb);
51433965Sjdp}
51533965Sjdp
516130561Sobrien/* The clnt_broadcast() callback mechanism sucks. */
51733965Sjdp
51833965Sjdp/*
51933965Sjdp * Receive results from broadcaster. Don't worry about passing
52033965Sjdp * bogus info to rpc_received() -- it can handle it. Note that we
52133965Sjdp * must be sure to invalidate the dom_pipe_fds descriptors here:
52233965Sjdp * since descriptors can be re-used, we have to make sure we
52333965Sjdp * don't mistake one of the RPC descriptors for one of the pipes.
52433965Sjdp * What's weird is that forgetting to invalidate the pipe descriptors
52533965Sjdp * doesn't always result in an error (otherwise I would have caught
52633965Sjdp * the mistake much sooner), even though logically it should.
52733965Sjdp */
52833965Sjdpvoid
52933965Sjdphandle_children(struct _dom_binding *ypdb)
53033965Sjdp{
53133965Sjdp	char buf[YPMAXDOMAIN + 1];
53233965Sjdp	struct sockaddr_in addr;
53333965Sjdp	int d = 0, a = 0;
53433965Sjdp	struct _dom_binding *y, *prev = NULL;
53533965Sjdp	char path[MAXPATHLEN];
53633965Sjdp
53733965Sjdp	if ((d = read(READFD, &buf, sizeof(buf))) <= 0)
53833965Sjdp		syslog(LOG_WARNING, "could not read from child: %m");
53933965Sjdp
540104834Sobrien	if ((a = read(READFD, &addr, sizeof(struct sockaddr_in))) < 0)
541218822Sdim		syslog(LOG_WARNING, "could not read from child: %m");
542104834Sobrien
54333965Sjdp	close(READFD);
54433965Sjdp	FD_CLR(READFD, &fdsr);
54533965Sjdp	FD_CLR(READFD, &svc_fdset);
54633965Sjdp	READFD = WRITEFD = -1;
54733965Sjdp	if (d > 0 && a > 0)
54833965Sjdp		rpc_received(buf, &addr, 0);
54933965Sjdp	else {
55033965Sjdp		for (y = ypbindlist; y; y = y->dom_pnext) {
55133965Sjdp			if (y == ypdb)
55233965Sjdp				break;
55333965Sjdp			prev = y;
55433965Sjdp		}
55533965Sjdp		switch (ypdb->dom_default) {
556130561Sobrien		case 0:
55733965Sjdp			if (prev == NULL)
558218822Sdim				ypbindlist = y->dom_pnext;
55933965Sjdp			else
560130561Sobrien				prev->dom_pnext = y->dom_pnext;
56189857Sobrien			sprintf(path, "%s/%s.%ld", BINDINGDIR,
56289857Sobrien				ypdb->dom_domain, YPVERS);
56389857Sobrien			close(ypdb->dom_lockfd);
56489857Sobrien			unlink(path);
56589857Sobrien			free(ypdb);
56633965Sjdp			domains--;
56733965Sjdp			return;
568130561Sobrien		case 1:
56933965Sjdp			ypdb->dom_broadcast_pid = 0;
57033965Sjdp			ypdb->dom_alive = 0;
57133965Sjdp			broadcast(ypdb);
57233965Sjdp			return;
57333965Sjdp		default:
574218822Sdim			break;
575218822Sdim		}
576218822Sdim	}
577218822Sdim
578218822Sdim	return;
579218822Sdim}
58033965Sjdp
581104834Sobrien/*
58233965Sjdp * Send our dying words back to our parent before we perish.
583218822Sdim */
584218822Sdimint
585218822Sdimtell_parent(char *dom, struct sockaddr_in *addr)
586218822Sdim{
58733965Sjdp	char buf[YPMAXDOMAIN + 1];
58833965Sjdp	struct timeval timeout;
58933965Sjdp	fd_set fds;
590218822Sdim
591218822Sdim	timeout.tv_sec = 5;
592218822Sdim	timeout.tv_usec = 0;
59333965Sjdp
59433965Sjdp	sprintf(buf, "%s", broad_domain->dom_domain);
59533965Sjdp	if (write(BROADFD, &buf, sizeof(buf)) < 0)
59633965Sjdp		return(1);
59733965Sjdp
59833965Sjdp	/*
59933965Sjdp	 * Stay in sync with parent: wait for it to read our first
60033965Sjdp	 * message before sending the second.
60133965Sjdp	 */
60233965Sjdp
60389857Sobrien	FD_ZERO(&fds);
60489857Sobrien	FD_SET(BROADFD, &fds);
605218822Sdim	if (select(FD_SETSIZE, NULL, &fds, NULL, &timeout) == -1)
60633965Sjdp		return(1);
607130561Sobrien	if (FD_ISSET(BROADFD, &fds)) {
60833965Sjdp		if (write(BROADFD, addr, sizeof(struct sockaddr_in)) < 0)
60933965Sjdp			return(1);
61033965Sjdp	} else {
61133965Sjdp		return(1);
61233965Sjdp	}
613218822Sdim
61433965Sjdp	close(BROADFD);
615130561Sobrien	return (0);
61633965Sjdp}
61733965Sjdp
61833965Sjdpbool_t broadcast_result(out, addr)
61933965Sjdpbool_t *out;
62033965Sjdpstruct sockaddr_in *addr;
62133965Sjdp{
62233965Sjdp	if (retries >= MAX_RETRIES) {
62333965Sjdp		bzero(addr, sizeof(struct sockaddr_in));
62433965Sjdp		if (tell_parent(broad_domain->dom_domain, addr))
62533965Sjdp			syslog(LOG_WARNING, "lost connection to parent");
62633965Sjdp		return (TRUE);
62733965Sjdp	}
62833965Sjdp
62933965Sjdp	if (yp_restricted && verify(addr->sin_addr)) {
63033965Sjdp		retries++;
63133965Sjdp		syslog(LOG_NOTICE, "NIS server at %s not in restricted mode access list -- rejecting.\n",inet_ntoa(addr->sin_addr));
63233965Sjdp		return (FALSE);
633218822Sdim	} else {
63433965Sjdp		if (tell_parent(broad_domain->dom_domain, addr))
63533965Sjdp			syslog(LOG_WARNING, "lost connection to parent");
63689857Sobrien		return (TRUE);
63733965Sjdp	}
638218822Sdim}
639218822Sdim
640218822Sdim/*
641218822Sdim * The right way to send RPC broadcasts.
642218822Sdim * Use the clnt_broadcast() RPC service. Unfortunately, clnt_broadcast()
643130561Sobrien * blocks while waiting for replies, so we have to fork off separate
64433965Sjdp * broadcaster processes that do the waiting and then transmit their
64533965Sjdp * results back to the parent for processing. We also have to remember
64633965Sjdp * to save the name of the domain we're trying to bind in a global
64733965Sjdp * variable since clnt_broadcast() provides no way to pass things to
64833965Sjdp * the 'eachresult' callback function.
64933965Sjdp */
65033965Sjdpvoid
651130561Sobrienbroadcast(struct _dom_binding *ypdb)
652218822Sdim{
653218822Sdim	bool_t out = FALSE;
654218822Sdim	enum clnt_stat stat;
655218822Sdim
656218822Sdim	if (children >= MAX_CHILDREN || ypdb->dom_broadcast_pid)
65733965Sjdp		return;
65833965Sjdp
65933965Sjdp	if (pipe(ypdb->dom_pipe_fds) < 0) {
66033965Sjdp		syslog(LOG_WARNING, "pipe: %m");
66133965Sjdp		return;
66233965Sjdp	}
66333965Sjdp
66433965Sjdp	if (ypdb->dom_vers == -1 && (long)ypdb->dom_server_addr.sin_addr.s_addr) {
66533965Sjdp		if (not_responding_count++ >= NOT_RESPONDING_HYSTERESIS) {
66633965Sjdp			not_responding_count = NOT_RESPONDING_HYSTERESIS;
66733965Sjdp			syslog(LOG_WARNING, "NIS server [%s] for domain \"%s\" not responding",
66833965Sjdp			    inet_ntoa(ypdb->dom_server_addr.sin_addr), ypdb->dom_domain);
66933965Sjdp		}
67033965Sjdp	}
67133965Sjdp
67233965Sjdp	broad_domain = ypdb;
67333965Sjdp	flock(ypdb->dom_lockfd, LOCK_UN);
67433965Sjdp
67533965Sjdp	switch ((ypdb->dom_broadcast_pid = fork())) {
676130561Sobrien	case 0:
67733965Sjdp		close(READFD);
67833965Sjdp		signal(SIGCHLD, SIG_DFL);
67933965Sjdp		signal(SIGTERM, SIG_DFL);
68033965Sjdp		break;
681130561Sobrien	case -1:
68233965Sjdp		syslog(LOG_WARNING, "fork: %m");
68333965Sjdp		close(READFD);
68433965Sjdp		close(WRITEFD);
68533965Sjdp		return;
68633965Sjdp	default:
68733965Sjdp		close(WRITEFD);
68833965Sjdp		FD_SET(READFD, &svc_fdset);
68933965Sjdp		children++;
69033965Sjdp		return;
69133965Sjdp	}
69233965Sjdp
69333965Sjdp	/* Release all locks before doing anything else. */
69433965Sjdp	while (ypbindlist) {
69533965Sjdp		close(ypbindlist->dom_lockfd);
69633965Sjdp		ypbindlist = ypbindlist->dom_pnext;
69733965Sjdp	}
69833965Sjdp	close(yplockfd);
69933965Sjdp
70033965Sjdp	/*
70133965Sjdp	 * Special 'many-cast' behavior. If we're in restricted mode,
702104834Sobrien	 * we have a list of possible server addresses to try. What
703104834Sobrien	 * we can do is transmit to each ypserv's YPPROC_DOMAIN_NONACK
704104834Sobrien	 * procedure and time the replies. Whoever replies fastest
705104834Sobrien	 * gets to be our server. Note that this is not a broadcast
70633965Sjdp	 * operation: we transmit uni-cast datagrams only.
70733965Sjdp	 */
70833965Sjdp	if (yp_restricted && yp_manycast) {
70933965Sjdp		short			port;
71033965Sjdp		int			i;
71133965Sjdp		struct sockaddr_in	sin;
71233965Sjdp
71333965Sjdp		i = __yp_ping(restricted_addrs, yp_restricted,
71433965Sjdp				ypdb->dom_domain, &port);
71533965Sjdp		if (i == -1) {
716218822Sdim			bzero(&ypdb->dom_server_addr,
71733965Sjdp			    sizeof(struct sockaddr_in));
71833965Sjdp			if (tell_parent(ypdb->dom_domain,
71933965Sjdp				&ypdb->dom_server_addr))
720218822Sdim			syslog(LOG_WARNING, "lost connection to parent");
72133965Sjdp		} else {
72233965Sjdp			bzero(&sin, sizeof(struct sockaddr_in));
72333965Sjdp			bcopy(&restricted_addrs[i],
724218822Sdim			    &sin.sin_addr, sizeof(struct in_addr));
72533965Sjdp			sin.sin_family = AF_INET;
72633965Sjdp			sin.sin_port = port;
72733965Sjdp			if (tell_parent(broad_domain->dom_domain, &sin))
72833965Sjdp				syslog(LOG_WARNING,
72933965Sjdp					"lost connection to parent");
73033965Sjdp		}
73133965Sjdp		_exit(0);
73233965Sjdp	}
73333965Sjdp
73433965Sjdp	retries = 0;
73533965Sjdp
73633965Sjdp	{
73733965Sjdp		char *ptr;
73833965Sjdp
73933965Sjdp		ptr = ypdb->dom_domain;
74033965Sjdp		stat = clnt_broadcast(YPPROG, YPVERS, YPPROC_DOMAIN_NONACK,
74133965Sjdp	    		(xdrproc_t)xdr_domainname, &ptr,
74233965Sjdp		        (xdrproc_t)xdr_bool, &out,
74333965Sjdp	    		(resultproc_t)broadcast_result);
74433965Sjdp	}
74533965Sjdp
74633965Sjdp	if (stat != RPC_SUCCESS) {
74733965Sjdp		bzero(&ypdb->dom_server_addr,
74833965Sjdp		    sizeof(struct sockaddr_in));
74933965Sjdp		if (tell_parent(ypdb->dom_domain, &ypdb->dom_server_addr))
75033965Sjdp			syslog(LOG_WARNING, "lost connection to parent");
75133965Sjdp	}
75233965Sjdp
75333965Sjdp	_exit(0);
75433965Sjdp}
75533965Sjdp
75633965Sjdp/*
75733965Sjdp * The right way to check if a server is alive.
75833965Sjdp * Attempt to get a client handle pointing to the server and send a
75933965Sjdp * YPPROC_DOMAIN. If we can't get a handle or we get a reply of FALSE,
76033965Sjdp * we invalidate this binding entry and send out a broadcast to try to
76133965Sjdp * establish a new binding. Note that we treat non-default domains
76233965Sjdp * specially: once bound, we keep tabs on our server, but if it
76333965Sjdp * goes away and fails to respond after one round of broadcasting, we
76433965Sjdp * abandon it until a client specifically references it again. We make
76533965Sjdp * every effort to keep our default domain bound, however, since we
76633965Sjdp * need it to keep the system on its feet.
76733965Sjdp */
76833965Sjdpint
76933965Sjdpping(struct _dom_binding *ypdb)
77033965Sjdp{
77133965Sjdp	bool_t out;
77233965Sjdp	struct timeval interval, timeout;
77333965Sjdp	enum clnt_stat stat;
77433965Sjdp	int rpcsock = RPC_ANYSOCK;
77533965Sjdp	CLIENT *client_handle;
77633965Sjdp
77733965Sjdp	interval.tv_sec = FAIL_THRESHOLD;
77833965Sjdp	interval.tv_usec = 0;
77933965Sjdp	timeout.tv_sec = FAIL_THRESHOLD;
78033965Sjdp	timeout.tv_usec = 0;
78133965Sjdp
78233965Sjdp	if (ypdb->dom_broadcast_pid)
78333965Sjdp		return(1);
78433965Sjdp
78533965Sjdp	if ((client_handle = clntudp_bufcreate(&ypdb->dom_server_addr,
78633965Sjdp		YPPROG, YPVERS, interval, &rpcsock, RPCSMALLMSGSIZE,
78733965Sjdp		RPCSMALLMSGSIZE)) == (CLIENT *)NULL) {
78833965Sjdp		/* Can't get a handle: we're dead. */
78933965Sjdp		ypdb->dom_alive = 0;
79033965Sjdp		ypdb->dom_vers = -1;
79133965Sjdp		broadcast(ypdb);
79233965Sjdp		return(1);
79333965Sjdp	}
79433965Sjdp
79533965Sjdp	{
79633965Sjdp		char *ptr;
79733965Sjdp
79833965Sjdp		ptr = ypdb->dom_domain;
79933965Sjdp
80033965Sjdp		stat = clnt_call(client_handle, YPPROC_DOMAIN,
80133965Sjdp		    (xdrproc_t)xdr_domainname, &ptr,
80233965Sjdp		    (xdrproc_t)xdr_bool, &out, timeout);
80333965Sjdp		if (stat != RPC_SUCCESS || out == FALSE) {
80433965Sjdp			ypdb->dom_alive = 0;
80533965Sjdp			ypdb->dom_vers = -1;
80633965Sjdp			clnt_destroy(client_handle);
80733965Sjdp			broadcast(ypdb);
80833965Sjdp			return(1);
80933965Sjdp		}
81033965Sjdp	}
81133965Sjdp
81233965Sjdp	clnt_destroy(client_handle);
81333965Sjdp	return(0);
81433965Sjdp}
81533965Sjdp
81633965Sjdpvoid
81733965Sjdprpc_received(char *dom, struct sockaddr_in *raddrp, int force)
81833965Sjdp{
81933965Sjdp	struct _dom_binding *ypdb, *prev = NULL;
82033965Sjdp	struct iovec iov[2];
82133965Sjdp	struct ypbind_resp ybr;
82233965Sjdp	char path[MAXPATHLEN];
82333965Sjdp	int fd;
82433965Sjdp
82533965Sjdp	/*printf("returned from %s/%d about %s\n", inet_ntoa(raddrp->sin_addr),
82633965Sjdp	       ntohs(raddrp->sin_port), dom);*/
82733965Sjdp
82833965Sjdp	if (dom == NULL)
82933965Sjdp		return;
830218822Sdim
831218822Sdim	for (ypdb = ypbindlist; ypdb; ypdb = ypdb->dom_pnext) {
83233965Sjdp		if (strcmp(ypdb->dom_domain, dom) == 0)
83333965Sjdp			break;
83433965Sjdp		prev = ypdb;
835130561Sobrien	}
83633965Sjdp
83733965Sjdp	if (ypdb && force) {
83833965Sjdp		if (ypdb->dom_broadcast_pid) {
83933965Sjdp			kill(ypdb->dom_broadcast_pid, SIGINT);
840130561Sobrien			close(READFD);
841218822Sdim			FD_CLR(READFD, &fdsr);
84233965Sjdp			FD_CLR(READFD, &svc_fdset);
84333965Sjdp			READFD = WRITEFD = -1;
84433965Sjdp		}
84533965Sjdp	}
84633965Sjdp
84733965Sjdp	/* if in secure mode, check originating port number */
848218822Sdim	if ((ypsecuremode && (ntohs(raddrp->sin_port) >= IPPORT_RESERVED))) {
84933965Sjdp	    syslog(LOG_WARNING, "Rejected NIS server on [%s/%d] for domain %s.",
850218822Sdim		   inet_ntoa(raddrp->sin_addr), ntohs(raddrp->sin_port),
85133965Sjdp		   dom);
85233965Sjdp	    if (ypdb != NULL) {
85333965Sjdp		ypdb->dom_broadcast_pid = 0;
85433965Sjdp		ypdb->dom_alive = 0;
85533965Sjdp	    }
85633965Sjdp	    return;
85733965Sjdp	}
85833965Sjdp
85933965Sjdp	if (raddrp->sin_addr.s_addr == (long)0) {
86033965Sjdp		switch (ypdb->dom_default) {
86133965Sjdp		case 0:
862130561Sobrien			if (prev == NULL)
86333965Sjdp				ypbindlist = ypdb->dom_pnext;
86433965Sjdp			else
865218822Sdim				prev->dom_pnext = ypdb->dom_pnext;
86633965Sjdp			sprintf(path, "%s/%s.%ld", BINDINGDIR,
867130561Sobrien				ypdb->dom_domain, YPVERS);
86833965Sjdp			close(ypdb->dom_lockfd);
869130561Sobrien			unlink(path);
87033965Sjdp			free(ypdb);
87189857Sobrien			domains--;
87289857Sobrien			return;
873218822Sdim		case 1:
87433965Sjdp			ypdb->dom_broadcast_pid = 0;
875130561Sobrien			ypdb->dom_alive = 0;
87633965Sjdp			broadcast(ypdb);
87733965Sjdp			return;
87833965Sjdp		default:
87933965Sjdp			break;
88033965Sjdp		}
88133965Sjdp	}
88233965Sjdp
88333965Sjdp	if (ypdb == NULL) {
88433965Sjdp		if (force == 0)
88533965Sjdp			return;
886218822Sdim		ypdb = (struct _dom_binding *)malloc(sizeof *ypdb);
88733965Sjdp		if (ypdb == NULL) {
88833965Sjdp			syslog(LOG_WARNING, "malloc: %m");
88933965Sjdp			return;
89033965Sjdp		}
89133965Sjdp		bzero(ypdb, sizeof *ypdb);
892130561Sobrien		strncpy(ypdb->dom_domain, dom, sizeof ypdb->dom_domain);
89333965Sjdp		ypdb->dom_lockfd = -1;
89433965Sjdp		ypdb->dom_default = 0;
89533965Sjdp		ypdb->dom_pnext = ypbindlist;
89633965Sjdp		ypbindlist = ypdb;
89733965Sjdp	}
89833965Sjdp
899130561Sobrien	/* We've recovered from a crash: inform the world. */
900218822Sdim	if (ypdb->dom_vers == -1 && ypdb->dom_server_addr.sin_addr.s_addr) {
90133965Sjdp		if (not_responding_count >= NOT_RESPONDING_HYSTERESIS) {
90233965Sjdp			not_responding_count = 0;
90333965Sjdp			syslog(LOG_WARNING, "NIS server [%s] for domain \"%s\" OK",
90433965Sjdp			    inet_ntoa(raddrp->sin_addr), ypdb->dom_domain);
90533965Sjdp		}
90633965Sjdp	}
90733965Sjdp
90833965Sjdp	bcopy(raddrp, &ypdb->dom_server_addr,
90933965Sjdp		sizeof ypdb->dom_server_addr);
91033965Sjdp
91133965Sjdp	ypdb->dom_vers = YPVERS;
91233965Sjdp	ypdb->dom_alive = 1;
91333965Sjdp	ypdb->dom_broadcast_pid = 0;
91433965Sjdp
91533965Sjdp	if (ypdb->dom_lockfd != -1)
91633965Sjdp		close(ypdb->dom_lockfd);
91733965Sjdp
91833965Sjdp	sprintf(path, "%s/%s.%ld", BINDINGDIR,
91933965Sjdp		ypdb->dom_domain, ypdb->dom_vers);
92033965Sjdp#ifdef O_SHLOCK
921218822Sdim	if ((fd = open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1) {
92233965Sjdp		(void)mkdir(BINDINGDIR, 0755);
92333965Sjdp		if ((fd = open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1)
92433965Sjdp			return;
92533965Sjdp	}
92633965Sjdp#else
927130561Sobrien	if ((fd = open(path, O_CREAT|O_RDWR|O_TRUNC, 0644)) == -1) {
92833965Sjdp		(void)mkdir(BINDINGDIR, 0755);
929130561Sobrien		if ((fd = open(path, O_CREAT|O_RDWR|O_TRUNC, 0644)) == -1)
930218822Sdim			return;
93133965Sjdp	}
93233965Sjdp	flock(fd, LOCK_SH);
93333965Sjdp#endif
93433965Sjdp
93533965Sjdp	/*
936130561Sobrien	 * ok, if BINDINGDIR exists, and we can create the binding file,
93733965Sjdp	 * then write to it..
93833965Sjdp	 */
93933965Sjdp	ypdb->dom_lockfd = fd;
94033965Sjdp
94133965Sjdp	iov[0].iov_base = (char *)&(udptransp->xp_port);
942218822Sdim	iov[0].iov_len = sizeof udptransp->xp_port;
94333965Sjdp	iov[1].iov_base = (char *)&ybr;
944218822Sdim	iov[1].iov_len = sizeof ybr;
94533965Sjdp
94633965Sjdp	bzero(&ybr, sizeof ybr);
94733965Sjdp	ybr.ypbind_status = YPBIND_SUCC_VAL;
94833965Sjdp	*(u_int32_t *)&ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr = raddrp->sin_addr.s_addr;
94933965Sjdp	*(u_short *)&ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port = raddrp->sin_port;
95033965Sjdp
95133965Sjdp	if (writev(ypdb->dom_lockfd, iov, 2) != iov[0].iov_len + iov[1].iov_len) {
95233965Sjdp		syslog(LOG_WARNING, "write: %m");
95333965Sjdp		close(ypdb->dom_lockfd);
95433965Sjdp		ypdb->dom_lockfd = -1;
95533965Sjdp		return;
95633965Sjdp	}
957218822Sdim}
95833965Sjdp
95933965Sjdp/*
96033965Sjdp * Check address against list of allowed servers. Return 0 if okay,
96133965Sjdp * 1 if not matched.
96233965Sjdp */
963104834Sobrienint
96433965Sjdpverify(struct in_addr addr)
96533965Sjdp{
96633965Sjdp	int i;
96733965Sjdp
96833965Sjdp	for (i = 0; i < RESTRICTED_SERVERS; i++)
96933965Sjdp		if (!bcmp(&addr, &restricted_addrs[i], sizeof(struct in_addr)))
97033965Sjdp			return(0);
97133965Sjdp
97233965Sjdp	return(1);
97333965Sjdp}
974218822Sdim
97533965Sjdp/*
97633965Sjdp * Try to set restricted mode. We default to normal mode if we can't
97733965Sjdp * resolve the specified hostnames.
97833965Sjdp */
97933965Sjdpvoid
98033965Sjdpyp_restricted_mode(char *args)
98133965Sjdp{
98233965Sjdp	struct hostent *h;
98333965Sjdp	int i = 0;
98433965Sjdp	char *s;
985218822Sdim
986218822Sdim	/* Find the restricted domain. */
987218822Sdim	if ((s = strsep(&args, ",")) == NULL)
988218822Sdim		return;
989218822Sdim	domain_name = s;
990218822Sdim
99133965Sjdp	/* Get the addresses of the servers. */
99233965Sjdp	while ((s = strsep(&args, ",")) != NULL && i < RESTRICTED_SERVERS) {
99333965Sjdp		if ((h = gethostbyname(s)) == NULL)
99433965Sjdp			return;
99533965Sjdp		bcopy (h->h_addr_list[0], &restricted_addrs[i],
99633965Sjdp		    sizeof(struct in_addr));
99733965Sjdp		i++;
99877298Sobrien	}
99933965Sjdp
100033965Sjdp	/* ypset and ypsetme not allowed with restricted mode */
100133965Sjdp	ypsetmode = YPSET_NO;
100233965Sjdp
100333965Sjdp	yp_restricted = i;
100433965Sjdp	return;
100533965Sjdp}
100633965Sjdp