ypbind.c revision 8246
1/*
2 * Copyright (c) 1992/3 Theo de Raadt <deraadt@fsa.ca>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote
14 *    products derived from this software without specific prior written
15 *    permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
18 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#ifndef LINT
31static char rcsid[] = "$Id: ypbind.c,v 1.8 1995/04/26 19:03:14 wpaul Exp $";
32#endif
33
34#include <sys/param.h>
35#include <sys/types.h>
36#include <sys/wait.h>
37#include <sys/ioctl.h>
38#include <sys/signal.h>
39#include <sys/socket.h>
40#include <sys/file.h>
41#include <sys/fcntl.h>
42#include <sys/stat.h>
43#include <sys/uio.h>
44#include <syslog.h>
45#include <stdio.h>
46#include <errno.h>
47#include <ctype.h>
48#include <dirent.h>
49#include <netdb.h>
50#include <string.h>
51#include <rpc/rpc.h>
52#include <rpc/xdr.h>
53#include <net/if.h>
54#include <netinet/in.h>
55#include <arpa/inet.h>
56#include <rpc/pmap_clnt.h>
57#include <rpc/pmap_prot.h>
58#include <rpc/pmap_rmt.h>
59#include <unistd.h>
60#include <stdlib.h>
61#include <rpcsvc/yp_prot.h>
62#include <rpcsvc/ypclnt.h>
63
64#ifndef BINDINGDIR
65#define BINDINGDIR "/var/yp/binding"
66#endif
67
68/*
69 * Ping the server once every PING_INTERVAL seconds to make sure it's
70 * still there.
71 */
72#ifndef PING_INTERVAL
73#define PING_INTERVAL 60
74#endif
75#ifndef FAIL_THRESHOLD
76#define FAIL_THRESHOLD 20
77#endif
78
79struct _dom_binding {
80	struct _dom_binding *dom_pnext;
81	char dom_domain[YPMAXDOMAIN + 1];
82	struct sockaddr_in dom_server_addr;
83	CLIENT *client_handle;
84	long int dom_vers;
85	int dom_lockfd;
86	int dom_alive;
87	int dom_broadcasting;
88	int dom_default;
89	time_t dom_check;
90};
91
92extern bool_t xdr_domainname(), xdr_ypbind_resp();
93extern bool_t xdr_ypreq_key(), xdr_ypresp_val();
94extern bool_t xdr_ypbind_setdom();
95
96void	checkwork __P((void));
97void	*ypbindproc_null_2 __P((SVCXPRT *, void *, CLIENT *));
98bool_t	*ypbindproc_setdom_2 __P((SVCXPRT *, struct ypbind_setdom *, CLIENT *));
99void	rpc_received __P((char *, struct sockaddr_in *, int ));
100void	broadcast __P((struct _dom_binding *));
101int	ping __P((struct _dom_binding *, int));
102void	handle_children __P(( int ));
103
104static char *broad_domain;
105char *domainname;
106struct _dom_binding *ypbindlist;
107
108#define YPSET_NO	0
109#define YPSET_LOCAL	1
110#define YPSET_ALL	2
111int ypsetmode = YPSET_NO;
112int ypsecuremode = 0;
113
114/* No more than MAX_CHILDREN child broadcasters at a time. */
115#define MAX_CHILDREN 5
116int child_fds[FD_SETSIZE];
117static int fd[2];
118int children = 0;
119
120SVCXPRT *udptransp, *tcptransp;
121
122void *
123ypbindproc_null_2(transp, argp, clnt)
124SVCXPRT *transp;
125void *argp;
126CLIENT *clnt;
127{
128	static char res;
129
130	bzero((char *)&res, sizeof(res));
131	return (void *)&res;
132}
133
134struct ypbind_resp *
135ypbindproc_domain_2(transp, argp, clnt)
136SVCXPRT *transp;
137char *argp;
138CLIENT *clnt;
139{
140	static struct ypbind_resp res;
141	struct _dom_binding *ypdb;
142	char path[MAXPATHLEN];
143
144	bzero((char *)&res, sizeof res);
145	res.ypbind_status = YPBIND_FAIL_VAL;
146	res.ypbind_respbody.ypbind_error = YPBIND_ERR_NOSERV;
147
148	for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext)
149		if( strcmp(ypdb->dom_domain, argp) == 0)
150			break;
151
152	if(ypdb==NULL) {
153		ypdb = (struct _dom_binding *)malloc(sizeof *ypdb);
154		if (ypdb == NULL) {
155			syslog(LOG_WARNING, "malloc: %s", strerror(errno));
156			res.ypbind_respbody.ypbind_error = YPBIND_ERR_RESC;
157			return;
158		}
159		bzero((char *)ypdb, sizeof *ypdb);
160		strncpy(ypdb->dom_domain, argp, sizeof ypdb->dom_domain);
161		ypdb->dom_vers = YPVERS;
162		ypdb->dom_alive = 0;
163		ypdb->dom_default = 0;
164		ypdb->dom_lockfd = -1;
165		sprintf(path, "%s/%s.%ld", BINDINGDIR, ypdb->dom_domain, ypdb->dom_vers);
166		unlink(path);
167		ypdb->dom_pnext = ypbindlist;
168		ypbindlist = ypdb;
169		return &res;
170	}
171
172	if(ypdb->dom_alive==0)
173		return &res;
174
175	if (ping(ypdb, 1))
176		return &res;
177
178	res.ypbind_status = YPBIND_SUCC_VAL;
179	res.ypbind_respbody.ypbind_error = 0; /* Success */
180	res.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr.s_addr =
181		ypdb->dom_server_addr.sin_addr.s_addr;
182	res.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port =
183		ypdb->dom_server_addr.sin_port;
184	/*printf("domain %s at %s/%d\n", ypdb->dom_domain,
185		inet_ntoa(ypdb->dom_server_addr.sin_addr),
186		ntohs(ypdb->dom_server_addr.sin_port));*/
187	return &res;
188}
189
190bool_t *
191ypbindproc_setdom_2(transp, argp, clnt)
192SVCXPRT *transp;
193struct ypbind_setdom *argp;
194CLIENT *clnt;
195{
196	struct sockaddr_in *fromsin, bindsin;
197	static char res;
198
199	bzero((char *)&res, sizeof(res));
200	fromsin = svc_getcaller(transp);
201
202	switch(ypsetmode) {
203	case YPSET_LOCAL:
204		if( fromsin->sin_addr.s_addr != htonl(INADDR_LOOPBACK))
205			return (void *)NULL;
206		break;
207	case YPSET_ALL:
208		break;
209	case YPSET_NO:
210	default:
211		return (void *)NULL;
212	}
213
214	if(ntohs(fromsin->sin_port) >= IPPORT_RESERVED)
215		return (void *)&res;
216
217	if(argp->ypsetdom_vers != YPVERS)
218		return (void *)&res;
219
220	bzero((char *)&bindsin, sizeof bindsin);
221	bindsin.sin_family = AF_INET;
222	bindsin.sin_addr.s_addr = argp->ypsetdom_addr.s_addr;
223	bindsin.sin_port = argp->ypsetdom_port;
224	rpc_received(argp->ypsetdom_domain, &bindsin, 1);
225
226	res = 1;
227	return (void *)&res;
228}
229
230static void
231ypbindprog_2(rqstp, transp)
232struct svc_req *rqstp;
233register SVCXPRT *transp;
234{
235	union {
236		char ypbindproc_domain_2_arg[MAXHOSTNAMELEN];
237		struct ypbind_setdom ypbindproc_setdom_2_arg;
238	} argument;
239	struct authunix_parms *creds;
240	char *result;
241	bool_t (*xdr_argument)(), (*xdr_result)();
242	char *(*local)();
243
244	switch (rqstp->rq_proc) {
245	case YPBINDPROC_NULL:
246		xdr_argument = xdr_void;
247		xdr_result = xdr_void;
248		local = (char *(*)()) ypbindproc_null_2;
249		break;
250
251	case YPBINDPROC_DOMAIN:
252		xdr_argument = xdr_domainname;
253		xdr_result = xdr_ypbind_resp;
254		local = (char *(*)()) ypbindproc_domain_2;
255		break;
256
257	case YPBINDPROC_SETDOM:
258		switch(rqstp->rq_cred.oa_flavor) {
259		case AUTH_UNIX:
260			creds = (struct authunix_parms *)rqstp->rq_clntcred;
261			if( creds->aup_uid != 0) {
262				svcerr_auth(transp, AUTH_BADCRED);
263				return;
264			}
265			break;
266		default:
267			svcerr_auth(transp, AUTH_TOOWEAK);
268			return;
269		}
270
271		xdr_argument = xdr_ypbind_setdom;
272		xdr_result = xdr_void;
273		local = (char *(*)()) ypbindproc_setdom_2;
274		break;
275
276	default:
277		svcerr_noproc(transp);
278		return;
279	}
280	bzero((char *)&argument, sizeof(argument));
281	if (!svc_getargs(transp, xdr_argument, &argument)) {
282		svcerr_decode(transp);
283		return;
284	}
285	result = (*local)(transp, &argument, rqstp);
286	if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
287		svcerr_systemerr(transp);
288	}
289	return;
290}
291
292/* Jack the reaper */
293void reaper(sig)
294int sig;
295{
296	int st;
297
298	wait3(&st, WNOHANG, NULL);
299}
300
301void
302main(argc, argv)
303int argc;
304char **argv;
305{
306	char path[MAXPATHLEN];
307	struct timeval tv;
308	fd_set fdsr;
309	int i;
310
311	yp_get_default_domain(&domainname);
312	if( domainname[0] == '\0') {
313		fprintf(stderr, "domainname not set. Aborting.\n");
314		exit(1);
315	}
316
317	for(i=1; i<argc; i++) {
318		if( strcmp("-ypset", argv[i]) == 0)
319			ypsetmode = YPSET_ALL;
320		else if (strcmp("-ypsetme", argv[i]) == 0)
321		        ypsetmode = YPSET_LOCAL;
322		else if (strcmp("-s", argv[i]) == 0)
323		        ypsecuremode++;
324	}
325
326	/* blow away everything in BINDINGDIR */
327
328
329
330#ifdef DAEMON
331	switch(fork()) {
332	case 0:
333		break;
334	case -1:
335		perror("fork");
336		exit(1);
337	default:
338		exit(0);
339	}
340	setsid();
341#endif
342
343	pmap_unset(YPBINDPROG, YPBINDVERS);
344
345	udptransp = svcudp_create(RPC_ANYSOCK);
346	if (udptransp == NULL) {
347		fprintf(stderr, "cannot create udp service.");
348		exit(1);
349	}
350	if (!svc_register(udptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2,
351	    IPPROTO_UDP)) {
352		fprintf(stderr, "unable to register (YPBINDPROG, YPBINDVERS, udp).");
353		exit(1);
354	}
355
356	tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0);
357	if (tcptransp == NULL) {
358		fprintf(stderr, "cannot create tcp service.");
359		exit(1);
360	}
361
362	if (!svc_register(tcptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2,
363	    IPPROTO_TCP)) {
364		fprintf(stderr, "unable to register (YPBINDPROG, YPBINDVERS, tcp).");
365		exit(1);
366	}
367
368	/* build initial domain binding, make it "unsuccessful" */
369	ypbindlist = (struct _dom_binding *)malloc(sizeof *ypbindlist);
370	if (ypbindlist == NULL) {
371		perror("malloc");
372		exit(1);
373	}
374	bzero((char *)ypbindlist, sizeof *ypbindlist);
375	strncpy(ypbindlist->dom_domain, domainname, sizeof ypbindlist->dom_domain);
376	ypbindlist->dom_vers = YPVERS;
377	ypbindlist->dom_alive = 0;
378	ypbindlist->dom_lockfd = -1;
379	ypbindlist->client_handle = NULL;
380	ypbindlist->dom_default = 1;
381	sprintf(path, "%s/%s.%ld", BINDINGDIR, ypbindlist->dom_domain,
382		ypbindlist->dom_vers);
383	(void)unlink(path);
384
385	/* Initialize children fds. */
386	for (i = 0; i < FD_SETSIZE; i++)
387		child_fds[i] = -1;
388
389	openlog(argv[0], LOG_PID, LOG_DAEMON);
390
391	while(1) {
392		fdsr = svc_fdset;
393
394		for (i = 0; i < FD_SETSIZE; i++)
395			if (child_fds[i] > 0 )
396				FD_SET(child_fds[i], &fdsr);
397
398		tv.tv_sec = 1;
399		tv.tv_usec = 0;
400
401		switch(select(_rpc_dtablesize(), &fdsr, NULL, NULL, &tv)) {
402		case 0:
403			checkwork();
404			reaper();
405			break;
406		case -1:
407			syslog(LOG_WARNING, "select: %s", strerror(errno));
408			break;
409		default:
410			for(i = 0; i < FD_SETSIZE; i++) {
411				if (child_fds[i] > 0 && FD_ISSET(child_fds[i],&fdsr)) {
412					handle_children(child_fds[i]);
413					close(child_fds[i]);
414					FD_CLR(child_fds[i], &fdsr);
415					child_fds[i] = -1;
416					children--;
417
418				}
419			}
420			svc_getreqset(&fdsr);
421			break;
422		}
423	}
424}
425
426void
427checkwork()
428{
429	struct _dom_binding *ypdb;
430	time_t t;
431
432	time(&t);
433	for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) {
434		if (!ypdb->dom_alive && !ypdb->dom_broadcasting) {
435			if (!ypdb->dom_default)
436				ypdb->dom_alive = 1;
437			ypdb->dom_broadcasting = 1;
438			broadcast(ypdb);
439		}
440		if (ypdb->dom_alive && ypdb->dom_check < t)
441			ping(ypdb, 0);
442	}
443}
444
445/* The clnt_broadcast() callback mechanism sucks. */
446
447/*
448 * Receive results from broadcaster. Don't worry about passing
449 * bogus info to rpc_received() -- it can handle it.
450 */
451void handle_children(i)
452int i;
453{
454	char buf[YPMAXDOMAIN + 1];
455	struct sockaddr_in addr;
456
457	if (read(i, &buf, sizeof(buf)) < 0)
458		syslog(LOG_WARNING, "could not read from child: %s", strerror(errno));
459	if (read(i, &addr, sizeof(struct sockaddr_in)) < 0)
460		syslog(LOG_WARNING, "could not read from child: %s", strerror(errno));
461	rpc_received((char *)&buf, &addr, 0);
462}
463
464/*
465 * Send our dying words back to our parent before we perish.
466 */
467int
468tell_parent(dom, addr)
469char *dom;
470struct sockaddr_in *addr;
471{
472	char buf[YPMAXDOMAIN + 1];
473	struct timeval timeout;
474	fd_set fds;
475
476	timeout.tv_sec = 5;
477	timeout.tv_usec = 0;
478
479	sprintf (buf, "%s", broad_domain);
480	if (write(fd[1], &buf, sizeof(buf)) < 0)
481		return(1);
482
483	/*
484	 * Stay in sync with parent: wait for it to read our first
485	 * message before sending the second.
486	 */
487
488	FD_ZERO(&fds);
489	FD_SET(fd[1], &fds);
490	if (select(FD_SETSIZE, NULL, &fds, NULL, &timeout) == -1)
491		return(1);
492	if (FD_ISSET(fd[1], &fds)) {
493		if (write(fd[1], addr, sizeof(struct sockaddr_in)) < 0)
494			return(1);
495	} else {
496		return(1);
497	}
498
499	close(fd[1]);
500	return (0);
501}
502
503bool_t broadcast_result(out, addr)
504bool_t *out;
505struct sockaddr_in *addr;
506{
507	if (tell_parent(&broad_domain, addr))
508		syslog(LOG_WARNING, "lost connection to parent");
509	return TRUE;
510}
511
512/*
513 * The right way to send RPC broadcasts.
514 * Use the clnt_broadcast() RPC service. Unfortunately, clnt_broadcast()
515 * blocks while waiting for replies, so we have to fork off seperate
516 * broadcaster processes that do the waiting and then transmit their
517 * results back to the parent for processing. We also have to remember
518 * to save the name of the domain we're trying to bind in a global
519 * variable since clnt_broadcast() provides no way to pass things to
520 * the 'eachresult' callback function.
521 */
522void
523broadcast(ypdb)
524struct _dom_binding *ypdb;
525{
526	bool_t out = FALSE;
527	enum clnt_stat stat;
528	int i;
529
530	if (children > MAX_CHILDREN)
531		return;
532
533	broad_domain = ypdb->dom_domain;
534
535	if (pipe(fd) < 0) {
536		syslog(LOG_WARNING, "pipe: %s",strerror(errno));
537		return;
538	}
539
540	switch(fork()) {
541	case 0:
542		close(fd[0]);
543		break;
544	case -1:
545		syslog(LOG_WARNING, "fork: %s", strerror(errno));
546		close(fd[1]);
547		close(fd[0]);
548		return;
549	default:
550		for (i = 0; i < FD_SETSIZE; i++) {
551			if (child_fds[i] < 0) {
552				child_fds[i] = fd[0];
553				break;
554			}
555		}
556		close(fd[1]);
557		children++;
558		return;
559	}
560
561	close(ypdb->dom_lockfd);
562	stat = clnt_broadcast(YPPROG, YPVERS, YPPROC_DOMAIN_NONACK,
563	    xdr_domainname, (char *)ypdb->dom_domain, xdr_bool, (char *)&out,
564	    broadcast_result);
565
566	if (stat != RPC_SUCCESS) {
567		syslog(LOG_WARNING, "NIS server for domain %s not responding",
568			ypdb->dom_domain);
569		bzero((char *)&ypdb->dom_server_addr,
570						sizeof(struct sockaddr_in));
571		if (tell_parent(&ypdb->dom_domain, &ypdb->dom_server_addr))
572			syslog(LOG_WARNING, "lost connection to parent");
573	}
574	exit(0);
575}
576
577/*
578 * The right way to check if a server is alive.
579 * Attempt to get a client handle pointing to the server and send a
580 * YPPROC_DOMAIN_NONACK. If we don't get a response, we invalidate
581 * this binding entry, which will cause checkwork() to dispatch a
582 * broadcaster process. Note that we treat non-default domains
583 * specially: once bound, we keep tabs on our server, but if it
584 * goes away and fails to respond after one round of broadcasting, we
585 * abandon it until a client specifically references it again. We make
586 * every effort to keep our default domain bound, however, since we
587 * need it to keep the system on its feet.
588 */
589int
590ping(ypdb, force)
591struct _dom_binding *ypdb;
592int force;
593{
594	bool_t out;
595	struct timeval interval, timeout;
596	enum clnt_stat stat;
597	int rpcsock = RPC_ANYSOCK;
598	time_t t;
599
600	interval.tv_sec = 5;
601	interval.tv_usec = 0;
602	timeout.tv_sec = FAIL_THRESHOLD;
603	timeout.tv_usec = 0;
604
605	if (ypdb->dom_broadcasting)
606		return(1);
607
608	if (!ypdb->dom_default && ypdb->dom_vers == -1 && !force)
609		return(1);
610
611	if (ypdb->client_handle == NULL) {
612		if ((ypdb->client_handle = clntudp_bufcreate(
613			&ypdb->dom_server_addr, YPPROG, YPVERS,
614			interval, &rpcsock, RPCSMALLMSGSIZE,
615			RPCSMALLMSGSIZE)) == (CLIENT *)NULL) {
616			/* Can't get a handle: we're dead. */
617			ypdb->client_handle = NULL;
618			ypdb->dom_alive = 0;
619			ypdb->dom_vers = -1;
620			flock(ypdb->dom_lockfd, LOCK_UN);
621			return(1);
622		}
623	}
624
625	if ((stat = clnt_call(ypdb->client_handle, YPPROC_DOMAIN_NONACK,
626		xdr_domainname, (char *)ypdb->dom_domain,
627		xdr_bool, (char *)&out, timeout)) != RPC_SUCCESS) {
628		ypdb->client_handle = NULL;
629		ypdb->dom_alive = 0;
630		ypdb->dom_vers = -1;
631		flock(ypdb->dom_lockfd, LOCK_UN);
632		return(1);
633	}
634	/*
635	 * We pinged successfully. Reset the timer.
636	 */
637	time(&t);
638	ypdb->dom_check = t + PING_INTERVAL;
639
640	return(0);
641}
642
643void rpc_received(dom, raddrp, force)
644char *dom;
645struct sockaddr_in *raddrp;
646int force;
647{
648	struct _dom_binding *ypdb;
649	struct iovec iov[2];
650	struct ypbind_resp ybr;
651	char path[MAXPATHLEN];
652	int fd;
653
654	/*printf("returned from %s/%d about %s\n", inet_ntoa(raddrp->sin_addr),
655	       ntohs(raddrp->sin_port), dom);*/
656
657	if(dom==NULL)
658		return;
659
660	for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext)
661		if( strcmp(ypdb->dom_domain, dom) == 0)
662			break;
663
664	/* if in securemode, check originating port number */
665	if (ypsecuremode && (ntohs(raddrp->sin_port) >= IPPORT_RESERVED)) {
666	    syslog(LOG_WARNING, "Rejected NIS server on [%s/%d] for domain %s.",
667		   inet_ntoa(raddrp->sin_addr), ntohs(raddrp->sin_port),
668		   dom);
669	    if (ypdb != NULL) {
670		ypdb->dom_broadcasting = 0;
671		ypdb->dom_alive = 0;
672	    }
673	    return;
674	}
675
676	if (raddrp->sin_addr.s_addr == (long)0) {
677		ypdb->dom_broadcasting = 0;
678		ypdb->dom_alive = 0;
679		return;
680	}
681
682	if(ypdb==NULL) {
683		if (force == 0)
684			return;
685		ypdb = (struct _dom_binding *)malloc(sizeof *ypdb);
686		if (ypdb == NULL) {
687			syslog(LOG_WARNING, "malloc: %s", strerror(errno));
688			return;
689		}
690		bzero((char *)ypdb, sizeof *ypdb);
691		strncpy(ypdb->dom_domain, dom, sizeof ypdb->dom_domain);
692		ypdb->dom_lockfd = -1;
693		ypdb->dom_default = 0;
694		ypdb->dom_alive = 0;
695		ypdb->dom_broadcasting = 0;
696		ypdb->dom_pnext = ypbindlist;
697		ypbindlist = ypdb;
698	}
699
700	/* We've recovered from a crash: inform the world. */
701	if (ypdb->dom_vers = -1 && ypdb->dom_server_addr.sin_addr.s_addr)
702		syslog(LOG_WARNING, "NIS server for domain %s OK",
703							ypdb->dom_domain);
704
705	bcopy((char *)raddrp, (char *)&ypdb->dom_server_addr,
706		sizeof ypdb->dom_server_addr);
707
708	ypdb->dom_vers = YPVERS;
709	ypdb->dom_alive = 1;
710	ypdb->dom_broadcasting = 0;
711
712	if(ypdb->dom_lockfd != -1)
713		close(ypdb->dom_lockfd);
714
715	sprintf(path, "%s/%s.%ld", BINDINGDIR,
716		ypdb->dom_domain, ypdb->dom_vers);
717#ifdef O_SHLOCK
718	if( (fd=open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1) {
719		(void)mkdir(BINDINGDIR, 0755);
720		if( (fd=open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1)
721			return;
722	}
723#else
724	if( (fd=open(path, O_CREAT|O_RDWR|O_TRUNC, 0644)) == -1) {
725		(void)mkdir(BINDINGDIR, 0755);
726		if( (fd=open(path, O_CREAT|O_RDWR|O_TRUNC, 0644)) == -1)
727			return;
728	}
729	flock(fd, LOCK_SH);
730#endif
731
732	/*
733	 * ok, if BINDINGDIR exists, and we can create the binding file,
734	 * then write to it..
735	 */
736	ypdb->dom_lockfd = fd;
737
738	iov[0].iov_base = (caddr_t)&(udptransp->xp_port);
739	iov[0].iov_len = sizeof udptransp->xp_port;
740	iov[1].iov_base = (caddr_t)&ybr;
741	iov[1].iov_len = sizeof ybr;
742
743	bzero(&ybr, sizeof ybr);
744	ybr.ypbind_status = YPBIND_SUCC_VAL;
745	ybr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr = raddrp->sin_addr;
746	ybr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port = raddrp->sin_port;
747
748	if( writev(ypdb->dom_lockfd, iov, 2) != iov[0].iov_len + iov[1].iov_len) {
749		syslog(LOG_WARNING, "write: %s", strerror(errno));
750		close(ypdb->dom_lockfd);
751		ypdb->dom_lockfd = -1;
752		return;
753	}
754}
755