4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 * Portions of this source code were derived from Berkeley
32 * under license from the Regents of the University of
36 #pragma ident "%Z%%M% %I% %E% SMI"
43 #include <netconfig.h>
49 #include <netinet/in.h>
50 #include <sys/statvfs.h>
51 #include <rpcsvc/nis.h>
52 #include <sys/systeminfo.h>
58 #define YPSERVERS "ypservers"
60 void ypbind_init_default();
61 static int ypbind_pipe_setdom();
63 static bool firsttime
= TRUE
;
64 static struct domain
*known_domains
;
66 extern struct netconfig
*__rpc_getconf();
67 extern void *__rpc_setconf(), *__rpc_endconf();
68 extern CLIENT
*__clnt_tp_create_bootstrap();
69 extern char *inet_ntoa();
70 extern int __rpc_get_local_uid();
72 extern listofnames
*names();
73 extern void free_listofnames();
75 #define PINGTIME 10 /* Timeout for the ypservers list */
76 #define PINGTOTTIM 5 /* Total seconds for ping timeout */
78 static void broadcast_setup();
79 static void sigcld_handler();
80 static struct ypbind_binding
*dup_ypbind_binding();
81 static struct netbuf
*dup_netbuf();
82 static void free_ypbind_binding();
83 static void enable_exit();
84 static void ypbind_ping();
85 static struct domain
*ypbind_point_to_domain();
86 static bool ypbind_broadcast_ack();
87 static int pong_servers();
89 void uncache_binding();
93 extern int cache_okay
;
96 * Need to differentiate between RPC_UNKNOWNHOST returned by the RPC
97 * library, and the same error caused by a local lookup failure in
98 * /etc/hosts and/or /etc/inet/ipnodes.
100 int hostNotKnownLocally
;
104 ypbindproc_null_3(argp
, clnt
)
110 return ((void *) & res
);
116 static bool done
= FALSE
;
120 sigset(SIGCHLD
, (void (*)())sigcld_handler
);
124 int sigcld_event
= 0;
131 fprintf(stderr
, "ypbind sighandler: got SIGCLD signal (event=%d)\n",
138 * This is a Unix SIGCHILD handler that notices when a broadcaster child
139 * process has exited, and retrieves the exit status. The broadcaster pid
140 * is set to 0. If the broadcaster succeeded, dom_report_success will be
145 broadcast_proc_exit()
149 register struct domain
*pdom
;
150 bool succeeded
= FALSE
;
153 /* ==== Why WEXITED? */
154 while ((ret
= waitid(P_ALL
, 0, &infop
, WNOHANG
| WEXITED
)) != -1) {
155 switch (infop
.si_code
) {
157 succeeded
= infop
.si_status
== 0;
173 "ypbind event_handler: got wait from %d status = %d\n",
174 pid
, infop
.si_status
);
177 /* to aid the progeny print the infamous "not responding" message */
180 for (pdom
= known_domains
; pdom
!= (struct domain
*)NULL
;
181 pdom
= pdom
->dom_pnext
) {
183 if (pdom
->dom_broadcaster_pid
== pid
) {
186 "ypbind event_handler: got match %s\n", pdom
->dom_name
);
189 broadcast_setup(pdom
);
191 if (pdom
->broadcaster_pipe
!= 0) {
192 xdr_destroy(&(pdom
->broadcaster_xdr
));
193 fclose(pdom
->broadcaster_pipe
);
194 pdom
->broadcaster_pipe
= 0;
195 pdom
->broadcaster_fd
= -1;
197 pdom
->dom_broadcaster_pid
= 0;
207 broadcast_setup(pdom
)
212 memset(&req
, 0, sizeof (req
));
213 if (pdom
->broadcaster_pipe
) {
214 pdom
->dom_report_success
= -1;
215 if (xdr_ypbind_setdom(&(pdom
->broadcaster_xdr
), &req
)) {
217 fprintf(stderr
, "parent: broadcast_setup: got xdr ok \n");
219 ypbindproc_setdom_3(&req
, (struct svc_req
*)NULL
,
221 xdr_free(xdr_ypbind_setdom
, (char *)&req
);
222 gettimeofday(&(pdom
->lastping
), NULL
);
226 fprintf(stderr
, "ypbind parent: xdr_ypbind_setdom failed\n");
232 fprintf(stderr
, "ypbind: internal error -- no broadcaster pipe\n");
237 #define YPBIND_PINGHOLD_DOWN 5
238 /* Same as the ypbind_get_binding() routine in SunOS */
241 ypbindproc_domain_3(argp
, clnt
)
245 static ypbind_resp resp
;
246 struct domain
*cur_domain
;
250 memset((char *)&resp
, 0, sizeof (resp
));
253 fprintf(stderr
, "\nypbindproc_domain_3: domain: %s\n",
254 argp
->ypbind_domainname
);
257 if ((int)strlen(argp
->ypbind_domainname
) > YPMAXDOMAIN
) {
259 resp
.ypbind_status
= YPBIND_FAIL_VAL
;
260 resp
.ypbind_resp_u
.ypbind_error
= YPBIND_ERR_NOSERV
;
264 if ((cur_domain
= ypbind_point_to_domain(argp
->ypbind_domainname
)) !=
265 (struct domain
*)NULL
) {
266 if (cur_domain
->dom_boundp
) {
270 (void) gettimeofday(&tp
, NULL
);
271 if ((tp
.tv_sec
- cur_domain
->lastping
.tv_sec
) >
272 YPBIND_PINGHOLD_DOWN
) {
274 fprintf(stderr
, "domain is bound pinging: %s\n",
275 argp
->ypbind_domainname
);
277 (void) ypbind_ping(cur_domain
);
282 * Bound or not, return the current state of the binding.
285 if (cur_domain
->dom_boundp
) {
287 fprintf(stderr
, "server is up for domain: %s\n",
288 argp
->ypbind_domainname
);
290 resp
.ypbind_status
= YPBIND_SUCC_VAL
;
291 resp
.ypbind_resp_u
.ypbind_bindinfo
=
292 cur_domain
->dom_binding
;
295 fprintf(stderr
, "domain is NOT bound returning: %s %d\n",
296 argp
->ypbind_domainname
, cur_domain
->dom_error
);
298 resp
.ypbind_status
= YPBIND_FAIL_VAL
;
299 resp
.ypbind_resp_u
.ypbind_error
=
300 cur_domain
->dom_error
;
304 resp
.ypbind_status
= YPBIND_FAIL_VAL
;
305 resp
.ypbind_resp_u
.ypbind_error
= YPBIND_ERR_RESC
;
308 * RETURN NOW: if successful, otherwise
309 * RETURN LATER: after spawning off a child to do the "broadcast" work.
311 if (resp
.ypbind_status
== YPBIND_SUCC_VAL
) {
313 fprintf(stderr
, "yp_b_subr: returning success to yp_b_svc %d\n",
319 /* Go about the broadcast (really, pinging here) business */
321 if ((cur_domain
) && (!cur_domain
->dom_boundp
) &&
322 (!cur_domain
->dom_broadcaster_pid
)) {
324 fprintf(stderr
, "yp_b_subr: fork: boundp=%d broadcast_pid=%d\n",
325 cur_domain
->dom_boundp
, cur_domain
->dom_broadcaster_pid
);
328 * The current domain is unbound, and there is no child
329 * process active now. Fork off a child who will beg to the
330 * ypservers list one by one or broadcast and accept whoever
331 * commands the right domain.
333 if (pipe(fildes
) < 0) {
335 fprintf(stderr
, "yp_b_subr: returning pipe failure to yp_b_svc %d\n",
342 sighold(SIGCLD
); /* add it to ypbind's signal mask */
343 cur_domain
->dom_report_success
++;
345 if (bpid
!= 0) { /* parent */
346 if (bpid
> 0) { /* parent started */
348 cur_domain
->dom_broadcaster_pid
= bpid
;
349 cur_domain
->broadcaster_fd
= fildes
[0];
350 cur_domain
->broadcaster_pipe
=
351 fdopen(fildes
[0], "r");
352 if (cur_domain
->broadcaster_pipe
)
353 xdrstdio_create(&(cur_domain
->broadcaster_xdr
),
354 (cur_domain
->broadcaster_pipe
), XDR_DECODE
);
357 fprintf(stderr
, "ypbindproc_domain_3: %s starting pid = %d try = %d\n",
358 cur_domain
->dom_name
, bpid
,
359 cur_domain
->dom_report_success
);
360 fprintf(stderr
, "yp_b_subr: returning after spawning, to yp_b_svc %d\n",
364 /* remove it from ypbind's signal mask */
366 } else { /* fork failed */
371 fprintf(stderr
, "yp_b_subr: returning fork failure to yp_b_svc %d\n",
378 /* child only code */
381 cur_domain
->broadcaster_fd
= fildes
[1];
382 cur_domain
->broadcaster_pipe
= fdopen(fildes
[1], "w");
383 if (cur_domain
->broadcaster_pipe
)
384 xdrstdio_create(&(cur_domain
->broadcaster_xdr
),
385 (cur_domain
->broadcaster_pipe
), XDR_ENCODE
);
387 perror("fdopen-pipe");
390 exit(pong_servers(cur_domain
));
393 fprintf(stderr
, "yp_b_subr: lazy returns failure status yp_b_svc %d\n",
401 * call ypbindproc_domain_3 and convert results
403 * This adds support for YP clients that send requests on
404 * ypbind version 1 & 2 (i.e. clients before we started
405 * using universal addresses and netbufs). This is supported
406 * for binary compatibility for static 4.x programs. The
407 * assumption used to be that clients coming in with ypbind vers 1
408 * should be given the address of a server serving ypserv version 1.
409 * However, since yp_bind routines in 4.x YP library try
410 * to connect with ypserv version 2, even if they requested
411 * binding using ypbind version 1, the ypbind process will
412 * "always" look for only ypserv version 2 servers for all
413 * (ypbind vers 1, 2, & 3) clients.
416 ypbindproc_domain_2(argp
, clnt
)
422 static ypbind_resp_2 resp
;
424 arg_3
.ypbind_domainname
= *argp
;
425 resp_3
= ypbindproc_domain_3(&arg_3
, clnt
);
428 resp
.ypbind_status
= resp_3
->ypbind_status
;
429 if (resp_3
->ypbind_status
== YPBIND_SUCC_VAL
) {
430 struct sockaddr_in
*sin
;
431 struct ypbind_binding_2
*bi
;
433 sin
= (struct sockaddr_in
*)
434 resp_3
->ypbind_resp_u
.ypbind_bindinfo
->ypbind_svcaddr
->buf
;
435 if (sin
->sin_family
== AF_INET
) {
436 bi
= &resp
.ypbind_respbody_2
.ypbind_bindinfo
;
437 memcpy(&(bi
->ypbind_binding_port
), &sin
->sin_port
, 2);
438 memcpy(&(bi
->ypbind_binding_addr
), &sin
->sin_addr
, 4);
440 resp
.ypbind_respbody_2
.ypbind_error
= YPBIND_ERR_NOSERV
;
443 resp
.ypbind_respbody_2
.ypbind_error
=
444 resp_3
->ypbind_resp_u
.ypbind_error
;
449 /* used to exchange information between pong_servers and ypbind_broadcast_ack */
450 struct domain
*process_current_domain
;
453 pong_servers(domain_struct
)
454 struct domain
*domain_struct
; /* to pass back */
456 char *domain
= domain_struct
->dom_name
;
459 listofnames
*list
, *lin
;
460 char serverfile
[MAXNAMLEN
];
461 struct timeval timeout
;
462 int isok
= 0, res
= -1;
463 struct netconfig
*nconf
;
466 char rpcdomain
[YPMAXDOMAIN
+1];
470 * If the ``domain'' name passed in is not the same as the RPC
471 * domain set from /etc/defaultdomain. Then we set ``firsttime''
472 * to TRUE so no error messages are ever syslog()-ed this
473 * prevents a possible Denial of Service attack.
475 inforet
= sysinfo(SI_SRPC_DOMAIN
, &(rpcdomain
[0]), YPMAXDOMAIN
);
476 if ((inforet
> 0) && (strcmp(domain
, rpcdomain
) != 0))
480 enum clnt_stat stat
= RPC_SUCCESS
;
482 fprintf(stderr
, "pong_servers: doing an rpc_broadcast\n");
485 * Here we do the real SunOS thing that users love. Do a
486 * broadcast on the network and find out the ypserv. No need
487 * to do "ypinit -c", no setting up /etc/hosts file, and no
488 * recursion looking up the server's IP address.
490 process_current_domain
= domain_struct
;
491 stat
= rpc_broadcast(YPPROG
, YPVERS
, YPPROC_DOMAIN_NONACK
,
492 (xdrproc_t
)xdr_ypdomain_wrap_string
, (caddr_t
)&domain
,
493 xdr_int
, (caddr_t
)&isok
,
494 (resultproc_t
)ypbind_broadcast_ack
, "udp");
495 if (stat
== RPC_SYSTEMERROR
|| stat
== RPC_UNKNOWNPROTO
||
496 stat
== RPC_CANTRECV
|| stat
== RPC_CANTSEND
||
497 stat
== RPC_NOBROADCAST
||
498 stat
== RPC_N2AXLATEFAILURE
) {
499 syslog(LOG_ERR
, "RPC/Transport subsystem failure %s\n",
503 if (domain_struct
->broadcaster_pipe
== 0)
504 /* init binding case */
505 return (domain_struct
->dom_boundp
- 1);
506 if (domain_struct
->dom_boundp
) {
507 res
= ypbind_pipe_setdom(NULL
, domain
,
508 NULL
, domain_struct
);
509 if (domain_struct
->dom_report_success
> 0)
511 "NIS server for domain \"%s\" OK", domain
);
512 } else if (firsttime
== FALSE
)
514 "NIS server not responding for domain \"%s\"; still trying", domain
);
518 fprintf(stderr
, "pong_servers: ponging servers one by one\n");
521 * Do the politically correct thing.. transport independent and
522 * secure (trusts only listed servers).
526 * get list of possible servers for this domain
530 * get alias for domain: Things of the past..
532 * (void) yp_getalias(domain, domain_alias, NAME_MAX);
534 sprintf(serverfile
, "%s/%s/%s", BINDING
, domain
, YPSERVERS
);
536 fprintf(stderr
, "pong_servers: serverfile %s\n", serverfile
);
538 list
= names(serverfile
);
540 if (firsttime
== FALSE
)
542 "service not installed, use /usr/sbin/ypinit -c");
546 for (list
= lin
; list
; list
= list
->nextname
) {
547 servername
= strtok(list
->name
, " \t\n");
548 if (servername
== NULL
) continue;
550 /* Check all datagram_v transports for this server */
551 if ((handle
= __rpc_setconf("datagram_v")) == NULL
) {
553 "ypbind: RPC operation on /etc/netconfig failed");
554 free_listofnames(lin
);
560 while (clnt2
== 0 && (nconf
= __rpc_getconf(handle
)) != 0) {
563 * We use only datagram here. It is expected to be udp.
564 * VERY IMPORTANT: __clnt_tp_create_bootstrap is a
565 * hacked up version that does not do netdir_getbyname.
567 hostNotKnownLocally
= 0;
569 __clnt_tp_create_bootstrap(servername
, YPPROG
, YPVERS
, nconf
);
571 if (nconf_count
== 0) {
573 "ypbind: RPC operation on /etc/netconfig failed");
574 free_listofnames(lin
);
579 if (rpc_createerr
.cf_stat
== RPC_UNKNOWNHOST
&&
580 hostNotKnownLocally
) {
582 "NIS server %s is not in local host files !", servername
);
585 clnt_pcreateerror("ypbind");
589 timeout
.tv_sec
= PINGTIME
;
591 if ((enum clnt_stat
) clnt_call(clnt2
,
592 YPPROC_DOMAIN
, (xdrproc_t
)xdr_ypdomain_wrap_string
,
593 (char *)&domain
, xdr_int
,
594 (char *)&isok
, timeout
) == RPC_SUCCESS
) {
596 if (domain_struct
->dom_report_success
> 0) {
598 "NIS server for domain \"%s\" OK", domain
);
600 if (domain_struct
->broadcaster_pipe
== 0) {
601 /* init binding case --parent */
602 struct netconfig
*setnc
;
604 struct ypbind_binding
*b
=
605 domain_struct
->dom_binding
;
608 getnetconfigent(clnt2
->cl_netid
);
610 /* ASSERT: This shouldn't happen ! */
612 (struct ypbind_binding
*)calloc(1, sizeof (*b
));
613 domain_struct
->dom_binding
= b
;
615 __rpc_endconf(handle
);
617 free_listofnames(lin
);
623 b
->ypbind_nconf
= setnc
;
624 clnt_control(clnt2
, CLGET_SVC_ADDR
,
626 if (b
->ypbind_svcaddr
) {
627 if (b
->ypbind_svcaddr
->buf
)
628 free(b
->ypbind_svcaddr
->buf
);
629 free(b
->ypbind_svcaddr
);
631 b
->ypbind_svcaddr
= dup_netbuf(&setua
);
632 if (b
->ypbind_servername
)
633 free(b
->ypbind_servername
);
634 b
->ypbind_servername
=
636 b
->ypbind_hi_vers
= YPVERS
;
637 b
->ypbind_lo_vers
= YPVERS
;
638 __rpc_endconf(handle
);
639 domain_struct
->dom_boundp
= TRUE
;
641 free_listofnames(lin
);
644 res
= ypbind_pipe_setdom(clnt2
, domain
,
645 servername
, domain_struct
);
646 __rpc_endconf(handle
);
648 free_listofnames(lin
);
652 "server %s doesn't serve domain %s\n",
656 clnt_perror(clnt2
, servername
);
661 * We tried all servers, none obliged !
662 * After ypbind is started up it will not be bound
663 * immediately. This is normal, no error message
664 * is needed. Although, with the ypbind_init_default
665 * it will be bound immediately.
667 if (firsttime
== FALSE
) {
669 "NIS server not responding for domain \"%s\"; still trying", domain
);
671 free_listofnames(lin
);
672 __rpc_endconf(handle
);
678 struct netbuf
*inbuf
;
680 struct netbuf
*outbuf
;
685 (struct netbuf
*)calloc(1, sizeof (struct netbuf
))) == NULL
)
687 if ((outbuf
->buf
= malloc(inbuf
->len
)) == NULL
) {
691 outbuf
->len
= inbuf
->len
;
692 outbuf
->maxlen
= inbuf
->len
;
693 (void) memcpy(outbuf
->buf
, inbuf
->buf
, inbuf
->len
);
698 * This is called by the broadcast rpc routines to process the responses
699 * coming back from the broadcast request. Since the form of the request
700 * which is used in ypbind_broadcast_bind is "respond only in the positive
701 * case", we know that we have a server.
702 * The internet address of the responding server will be picked up from
703 * the saddr parameter, and stuffed into the domain. The domain's boundp
704 * field will be set TRUE. The first responding server (or the first one
705 * which is on a reserved port) will be the bound server for the domain.
708 ypbind_broadcast_ack(ptrue
, nbuf
, nconf
)
711 struct netconfig
*nconf
;
713 struct ypbind_binding b
;
715 process_current_domain
->dom_boundp
= TRUE
;
716 b
.ypbind_nconf
= nconf
;
717 b
.ypbind_svcaddr
= nbuf
;
718 b
.ypbind_servername
= "\000";
719 b
.ypbind_hi_vers
= YPVERS
;
720 b
.ypbind_lo_vers
= YPVERS
;
721 free_ypbind_binding(process_current_domain
->dom_binding
);
722 process_current_domain
->dom_binding
= dup_ypbind_binding(&b
);
727 * WARNING: This routine is entered only by the child process.
728 * Called if it pongs/broadcasts okay.
731 ypbind_pipe_setdom(client
, domain
, servername
, opaque_domain
)
735 struct domain
*opaque_domain
;
737 struct netconfig
*setnc
;
743 setd
.ypsetdom_domain
= domain
;
744 if (client
== NULL
&& opaque_domain
->dom_binding
) {
746 fprintf(stderr
, "ypbind_pipe_setdom: child broadcast case ");
748 /* ypbind_broadcast_ack already setup dom_binding for us */
749 setd
.ypsetdom_bindinfo
= opaque_domain
->dom_binding
;
752 fprintf(stderr
, "ypbind_pipe_setdom: child unicast case ");
754 setnc
= getnetconfigent(client
->cl_netid
);
757 fprintf(stderr
, "PANIC: shouldn't happen\n");
759 fclose(opaque_domain
->broadcaster_pipe
);
760 close(opaque_domain
->broadcaster_fd
);
763 clnt_control(client
, CLGET_SVC_ADDR
, (char *)&setua
);
764 setb
.ypbind_nconf
= setnc
;
765 setb
.ypbind_svcaddr
= &setua
;
766 setb
.ypbind_servername
= servername
;
767 setb
.ypbind_hi_vers
= YPVERS
;
768 setb
.ypbind_lo_vers
= YPVERS
;
769 setd
.ypsetdom_bindinfo
= &setb
;
771 * Let's hardcode versions, that is the only ypserv we support anyway.
772 * Avoid the song and dance of recursively calling ypbind_ping
773 * for no reason. Consistent with the 4.1 policy, that if ypbind gets
774 * a request on new binder protocol, the requestor is looking for the
775 * new ypserv. And, we have even higher binder protocol version i.e. 3.
781 " saving server settings, \nsupports versions %d thru %d\n",
782 setd
.ypsetdom_bindinfo
->ypbind_lo_vers
,
783 setd
.ypsetdom_bindinfo
->ypbind_hi_vers
);
786 if (opaque_domain
->broadcaster_pipe
== 0) {
788 fprintf(stderr
, "PANIC: shouldn't be in this function\n");
793 fprintf(stderr
, "child: doing xdr_ypbind_setdom\n");
795 retval
= xdr_ypbind_setdom(&(opaque_domain
->broadcaster_xdr
), &setd
);
796 xdr_destroy(&(opaque_domain
->broadcaster_xdr
));
797 fclose(opaque_domain
->broadcaster_pipe
);
798 close(opaque_domain
->broadcaster_fd
);
800 * This child process is about to exit. Don't bother freeing memory.
805 "YPBIND pipe_setdom failed \n(xdr failure) to server %s\n",
806 servername
? servername
: "");
811 fprintf(stderr
, "ypbind_pipe_setdom: YPBIND OK-set to server %s\n",
812 servername
? servername
: "");
817 /* Same as ypbind_set_binding in SunOS */
819 * We use a trick from SunOS to return an error to the ypset command
820 * when we are not allowing the domain to be set. We do a svcerr_noprog()
821 * to send RPC_PROGUNAVAIL to ypset. We also return NULL so that
822 * our caller (ypbindprog_3) won't try to return a result. This
823 * hack is necessary because the YPBINDPROC_SETDOM procedure is defined
824 * in the protocol to return xdr_void, so we don't have a direct way to
825 * return an error to the client.
829 ypbindproc_setdom_3(argp
, rqstp
, transp
)
831 struct svc_req
*rqstp
;
834 struct domain
*a_domain
;
836 static char res
; /* dummy for void * return */
839 if ((int)strlen(argp
->ypsetdom_domain
) > YPMAXDOMAIN
) {
842 svcerr_systemerr(transp
);
848 if (transp
!= NULL
) {
849 /* find out who originated the request */
851 struct netconfig
*nconf
;
853 who
= svc_getrpccaller(transp
);
854 if ((nconf
= getnetconfigent(transp
->xp_netid
))
855 == (struct netconfig
*)NULL
) {
856 svcerr_systemerr(transp
);
859 if (strcmp(nconf
->nc_protofmly
, NC_LOOPBACK
) == 0) {
860 uaddr
= strdup("local host");
862 uaddr
= taddr2uaddr(nconf
, who
);
864 if (setok
!= YPSETALL
) {
865 /* for -ypset, it falls through and let anybody do a setdom ! */
866 if (strcmp(nconf
->nc_protofmly
, NC_LOOPBACK
) != 0) {
868 "ypset request from %s not on loopback, \
869 cannot set ypbind to %s", uaddr
? uaddr
: "unknown source",
870 argp
->ypsetdom_bindinfo
->ypbind_servername
);
873 freenetconfigent(nconf
);
874 svcerr_noprog(transp
);
879 if (strcmp(nconf
->nc_protofmly
,
882 "ypset request to %s from %s failed - ypset not allowed",
883 argp
->ypsetdom_bindinfo
->ypbind_servername
, uaddr
);
886 freenetconfigent(nconf
);
887 svcerr_noprog(transp
);
890 if (__rpc_get_local_uid(transp
,
892 syslog(LOG_ERR
, "ypset request from \
893 unidentified local user on %s - ypset not allowed",
897 freenetconfigent(nconf
);
898 svcerr_noprog(transp
);
901 if (caller_uid
!= 0) {
903 "Set domain request to host %s \
904 from local non-root user %ld failed - ypset not allowed",
905 argp
->ypsetdom_bindinfo
->ypbind_servername
, caller_uid
);
908 freenetconfigent(nconf
);
909 svcerr_noprog(transp
);
914 syslog(LOG_ERR
, "Set domain request from %s : \
915 setting server for domain %s to %s", uaddr
? uaddr
: "UNKNOWN SOURCE",
916 argp
->ypsetdom_domain
, argp
->ypsetdom_bindinfo
->ypbind_servername
);
919 freenetconfigent(nconf
);
922 if ((a_domain
= ypbind_point_to_domain(argp
->ypsetdom_domain
))
923 != (struct domain
*)NULL
) {
924 /* setting binding; old may be invalid */
925 uncache_binding(a_domain
);
927 /* this does the set -- should copy the structure */
928 free_ypbind_binding(a_domain
->dom_binding
);
929 if ((a_domain
->dom_binding
=
930 dup_ypbind_binding(argp
->ypsetdom_bindinfo
)) == NULL
) {
931 syslog(LOG_ERR
, "ypbindproc_setdom_3: out of memory, ",
932 "dup_ypbind_binding failed\n");
934 svcerr_noprog(transp
);
939 gettimeofday(&(a_domain
->lastping
), NULL
);
940 a_domain
->dom_boundp
= TRUE
;
941 cache_binding(a_domain
);
943 fprintf(stderr
, "ypbindproc_setdom_3: setting domain %s to server %s\n",
944 argp
->ypsetdom_domain
,
945 argp
->ypsetdom_bindinfo
->ypbind_servername
);
953 * This returns a pointer to a domain entry. If no such domain existed on
954 * the list previously, an entry will be allocated, initialized, and linked
955 * to the list. Note: If no memory can be malloc-ed for the domain structure,
956 * the functional value will be (struct domain *) NULL.
958 static struct domain
*
959 ypbind_point_to_domain(pname
)
960 register char *pname
;
962 register struct domain
*pdom
;
965 for (pdom
= known_domains
; pdom
!= (struct domain
*)NULL
;
966 pdom
= pdom
->dom_pnext
) {
967 if (strcmp(pname
, pdom
->dom_name
) == 0)
971 /* Not found. Add it to the list */
973 if (pdom
= (struct domain
*)calloc(1, sizeof (struct domain
))) {
974 pdom
->dom_name
= strdup(pname
);
975 if (pdom
->dom_name
== NULL
) {
978 "ypbind_point_to_domain: strdup failed\n");
981 pdom
->dom_pnext
= known_domains
;
982 known_domains
= pdom
;
983 pdom
->dom_boundp
= FALSE
;
984 pdom
->dom_vers
= YPVERS
; /* This doesn't talk to old ypserv */
985 pdom
->dom_binding
= NULL
;
986 pdom
->dom_error
= YPBIND_ERR_NOSERV
;
987 pdom
->ping_clnt
= (CLIENT
*)NULL
;
988 pdom
->dom_report_success
= -1;
989 pdom
->dom_broadcaster_pid
= 0;
990 pdom
->broadcaster_pipe
= 0;
992 pdom
->lastping
.tv_sec
= 0;
993 pdom
->lastping
.tv_usec
= 0; /* require ping */
995 sprintf(buf
, "%s/%s/cache_binding", BINDING
, pdom
->dom_name
);
996 pdom
->cache_file
= strdup(buf
);
998 * We don't give an error if pdom->cache_file is not set.
999 * If we got null (out of memory), then we just won't use
1000 * the cache file in cache_binding() (assuming the
1001 * application gets that far.
1005 syslog(LOG_ERR
, "ypbind_point_to_domain: malloc failed\n");
1012 struct domain
*pdom
;
1014 struct timeval timeout
;
1018 if (pdom
->dom_boundp
== FALSE
)
1020 vers
= pdom
->dom_vers
;
1022 if (pdom
->ping_clnt
== (CLIENT
*) NULL
) {
1023 pdom
->ping_clnt
= __nis_clnt_create(RPC_ANYFD
,
1024 pdom
->dom_binding
->ypbind_nconf
, 0,
1025 pdom
->dom_binding
->ypbind_svcaddr
, 0,
1026 YPPROG
, vers
, 0, 0);
1029 if (pdom
->ping_clnt
== (CLIENT
*) NULL
) {
1030 perror("clnt_tli_create");
1031 clnt_pcreateerror("ypbind_ping()");
1032 pdom
->dom_boundp
= FALSE
;
1033 pdom
->dom_error
= YPBIND_ERR_NOSERV
;
1039 fprintf(stderr
, "ypbind: ypbind_ping()\n");
1041 timeout
.tv_sec
= PINGTOTTIM
;
1042 timeout
.tv_usec
= 0;
1043 if (clnt_call(pdom
->ping_clnt
,
1044 YPPROC_DOMAIN
, (xdrproc_t
)xdr_ypdomain_wrap_string
,
1045 (char *)&pdom
->dom_name
, xdr_int
, (char *)&isok
,
1046 timeout
) == RPC_SUCCESS
) {
1047 pdom
->dom_boundp
= isok
;
1048 pdom
->dom_binding
->ypbind_lo_vers
= vers
;
1049 pdom
->dom_binding
->ypbind_hi_vers
= vers
;
1052 "Server pinged successfully, supports versions %d thru %d\n",
1053 pdom
->dom_binding
->ypbind_lo_vers
,
1054 pdom
->dom_binding
->ypbind_hi_vers
);
1057 clnt_perror(pdom
->ping_clnt
, "ping");
1058 pdom
->dom_boundp
= FALSE
;
1059 pdom
->dom_error
= YPBIND_ERR_NOSERV
;
1061 (void) gettimeofday(&(pdom
->lastping
), NULL
);
1062 if (pdom
->ping_clnt
)
1063 clnt_destroy(pdom
->ping_clnt
);
1064 pdom
->ping_clnt
= (CLIENT
*)NULL
;
1065 if (pdom
->dom_boundp
)
1066 cache_binding(pdom
);
1069 static struct ypbind_binding
*
1070 dup_ypbind_binding(a
)
1071 struct ypbind_binding
*a
;
1073 struct ypbind_binding
*b
;
1074 struct netconfig
*nca
, *ncb
;
1075 struct netbuf
*nxa
, *nxb
;
1078 b
= (struct ypbind_binding
*)calloc(1, sizeof (*b
));
1081 b
->ypbind_hi_vers
= a
->ypbind_hi_vers
;
1082 b
->ypbind_lo_vers
= a
->ypbind_lo_vers
;
1083 b
->ypbind_servername
=
1084 a
->ypbind_servername
? strdup(a
->ypbind_servername
) : NULL
;
1085 ncb
= (b
->ypbind_nconf
=
1086 (struct netconfig
*)calloc(1, sizeof (struct netconfig
)));
1087 nxb
= (b
->ypbind_svcaddr
=
1088 (struct netbuf
*)calloc(1, sizeof (struct netbuf
)));
1089 nca
= a
->ypbind_nconf
;
1090 nxa
= a
->ypbind_svcaddr
;
1091 ncb
->nc_flag
= nca
->nc_flag
;
1093 nca
->nc_protofmly
? strdup(nca
->nc_protofmly
) : NULL
;
1095 nca
->nc_proto
? strdup(nca
->nc_proto
) : NULL
;
1096 ncb
->nc_semantics
= nca
->nc_semantics
;
1098 nca
->nc_netid
? strdup(nca
->nc_netid
) : NULL
;
1100 nca
->nc_device
? strdup(nca
->nc_device
) : NULL
;
1101 ncb
->nc_nlookups
= nca
->nc_nlookups
;
1102 ncb
->nc_lookups
= (char **)calloc(nca
->nc_nlookups
, sizeof (char *));
1103 if (ncb
->nc_lookups
== NULL
) {
1105 free(ncb
->nc_device
);
1107 free(ncb
->nc_netid
);
1109 free(ncb
->nc_proto
);
1110 if (ncb
->nc_protofmly
)
1111 free(ncb
->nc_protofmly
);
1116 if (b
->ypbind_servername
)
1117 free(b
->ypbind_servername
);
1122 for (i
= 0; i
< nca
->nc_nlookups
; i
++)
1123 ncb
->nc_lookups
[i
] =
1124 nca
->nc_lookups
[i
] ? strdup(nca
->nc_lookups
[i
]) : NULL
;
1125 for (i
= 0; i
< 8; i
++)
1126 ncb
->nc_unused
[i
] = nca
->nc_unused
[i
];
1127 nxb
->maxlen
= nxa
->maxlen
;
1128 nxb
->len
= nxa
->len
;
1129 nxb
->buf
= malloc(nxa
->maxlen
);
1130 if (nxb
->buf
== NULL
) {
1131 for (i
= 0; i
< nca
->nc_nlookups
; i
++)
1132 if (ncb
->nc_lookups
[i
])
1133 free(ncb
->nc_lookups
[i
]);
1134 free(ncb
->nc_lookups
);
1136 free(ncb
->nc_device
);
1138 free(ncb
->nc_netid
);
1140 free(ncb
->nc_proto
);
1141 if (ncb
->nc_protofmly
)
1142 free(ncb
->nc_protofmly
);
1147 if (b
->ypbind_servername
)
1148 free(b
->ypbind_servername
);
1153 memcpy(nxb
->buf
, nxa
->buf
, nxb
->len
);
1158 free_ypbind_binding(b
)
1159 struct ypbind_binding
*b
;
1163 netdir_free((char *)b
->ypbind_svcaddr
, ND_ADDR
);
1164 free(b
->ypbind_servername
);
1165 freenetconfigent(b
->ypbind_nconf
);
1170 * Preloads teh default domain's domain binding. Domain binding for the
1171 * local node's default domain for ypserv version 2 (YPVERS) will be
1172 * set up. This may make it a little slower to start ypbind during
1173 * boot time, but would make it easy on other domains that rely on
1177 ypbind_init_default()
1180 struct domain
*cur_domain
;
1182 if (getdomainname(domain
, 256) == 0) {
1183 cur_domain
= ypbind_point_to_domain(domain
);
1185 if (cur_domain
== (struct domain
*)NULL
) {
1188 (void) pong_servers(cur_domain
);
1193 xdr_ypbind_binding_2(xdrs
, objp
)
1195 ypbind_binding_2
*objp
;
1197 if (!xdr_opaque(xdrs
, (char *)&(objp
->ypbind_binding_addr
), 4))
1199 if (!xdr_opaque(xdrs
, (char *)&(objp
->ypbind_binding_port
), 2))
1205 xdr_ypbind_resp_2(xdrs
, objp
)
1207 ypbind_resp_2
*objp
;
1209 if (!xdr_ypbind_resptype(xdrs
, &objp
->ypbind_status
))
1211 switch (objp
->ypbind_status
) {
1212 case YPBIND_FAIL_VAL
:
1213 if (!xdr_u_long(xdrs
, &objp
->ypbind_respbody_2
.ypbind_error
))
1216 case YPBIND_SUCC_VAL
:
1217 if (!xdr_ypbind_binding_2(xdrs
,
1218 &objp
->ypbind_respbody_2
.ypbind_bindinfo
))
1228 * The following is some caching code to improve the performance of
1229 * yp clients. In the days of yore, a client would talk to rpcbind
1230 * to get the address for ypbind, then talk to ypbind to get the
1231 * address of the server. If a lot of clients are doing this at
1232 * the same time, then rpcbind and ypbind get bogged down and clients
1233 * start to time out.
1235 * We cache two things: the current address for ypserv, and the
1236 * transport addresses for talking to ypbind. These are saved in
1237 * files in /var/yp. To get the address of ypserv, the client opens
1238 * a file and reads the address. It does not have to talk to rpcbind
1239 * or ypbind. If this file is not available, then it can read the
1240 * the transport address for talking to ypbind without bothering
1241 * rpcbind. If this also fails, then it uses the old method of
1242 * talking to rpcbind and then ypbind.
1244 * We lock the first byte of the cache files after writing to them.
1245 * This indicates to the client that they contents are valid. The
1246 * client should test the lock. If the lock is held, then it can
1247 * use the contents. If the lock test fails, then the contents should
1252 * Cache new binding information for a domain in a file. If the
1253 * new binding is the same as the old, then we skip it. We xdr
1254 * a 'ypbind_resp', which is what would be returned by a call to
1255 * the YBINDPROCP_DOMAIN service. We xdr the data because it is
1256 * easier than writing the data out field by field. It would be
1257 * nice if there were an xdrfd_create() that was similar to
1258 * xdrstdio_create(). Instead, we do an fdopen and use xdrstdio_create().
1262 struct domain
*pdom
;
1267 struct ypbind_resp resp
;
1272 /* if the domain doesn't have a cache file, then skip it */
1273 if (pdom
->cache_file
== 0)
1277 * If we already had a cache file for this domain, remove it. If
1278 * a client just started accessing it, then it will either find
1279 * it unlocked (and not use it), or continue to use it with
1280 * old information. This is not a problem, the client will
1281 * either fail to talk to ypserv and try to bind again, or
1282 * will continue to use the old server.
1284 if (pdom
->cache_fp
) {
1285 fclose(pdom
->cache_fp
); /* automatically unlocks */
1286 unlink(pdom
->cache_file
);
1290 fd
= open(pdom
->cache_file
, O_CREAT
|O_WRONLY
, 0444);
1294 pdom
->cache_fp
= fdopen(fd
, "w");
1295 if (pdom
->cache_fp
== 0) {
1300 xdrstdio_create(&xdrs
, pdom
->cache_fp
, XDR_ENCODE
);
1301 resp
.ypbind_status
= YPBIND_SUCC_VAL
;
1302 resp
.ypbind_resp_u
.ypbind_bindinfo
= pdom
->dom_binding
;
1304 if (!xdr_ypbind_resp(&xdrs
, &resp
)) {
1306 unlink(pdom
->cache_file
);
1307 fclose(pdom
->cache_fp
);
1311 xdr_destroy(&xdrs
); /* flushes xdr but leaves fp open */
1313 /* we lock the first byte to indicate that the file is valid */
1314 lseek(fd
, 0L, SEEK_SET
);
1315 st
= lockf(fd
, F_LOCK
, 1);
1317 unlink(pdom
->cache_file
);
1318 fclose(pdom
->cache_fp
);
1324 uncache_binding(pdom
)
1325 struct domain
*pdom
;
1330 if (pdom
->cache_fp
!= 0) {
1331 unlink(pdom
->cache_file
);
1332 fclose(pdom
->cache_fp
);
1338 * Cache a transport address for talking to ypbind. We convert the
1339 * transport address to a universal address and save that in a file.
1340 * The file lives in the binding directory because it does not depend
1344 cache_transport(nconf
, xprt
, vers
)
1345 struct netconfig
*nconf
;
1358 sprintf(filename
, "%s/xprt.%s.%d",
1359 BINDING
, nconf
->nc_netid
, vers
);
1361 unlink(filename
); /* remove any old version */
1363 uaddr
= taddr2uaddr(nconf
, &xprt
->xp_ltaddr
);
1367 fd
= open(filename
, O_CREAT
|O_WRONLY
, 0444); /* readable by all */
1373 len
= strlen(uaddr
) + 1; /* include terminating null */
1374 st
= write(fd
, uaddr
, len
);
1384 /* we lock the first byte to indicate that the file is valid */
1385 lseek(fd
, 0L, SEEK_SET
);
1386 st
= lockf(fd
, F_LOCK
, 1);
1394 * Create a file that clients can check to see if we are running.
1408 sprintf(filename
, "%s/ypbind.pid", BINDING
);
1410 unlink(filename
); /* remove any old version */
1412 fd
= open(filename
, O_CREAT
|O_WRONLY
, 0444); /* readable by all */
1417 sprintf(spid
, "%d\n", getpid());
1420 st
= write(fd
, spid
, len
);
1427 /* we lock the first byte to indicate that the file is valid */
1428 lseek(fd
, 0L, SEEK_SET
);
1429 st
= lockf(fd
, F_LOCK
, 1);
1435 /* we keep 'fd' open so that the lock will continue to be held */
1439 * We are called once at startup (when the known_domains list is empty)
1440 * to clean up left-over files. We are also called right before
1441 * exiting. In the latter case case we don't bother closing descriptors
1442 * in the entries in the domain list because they will be closed
1443 * automatically (and unlocked) when we exit.
1445 * We ignore the cache_okay flag because it is important that we remove
1446 * all cache files (left-over files can temporarily confuse clients).
1451 struct domain
*pdom
;
1453 struct dirent
*dirent
;
1456 /* close and unlink cache files for each domain */
1457 for (pdom
= known_domains
; pdom
!= (struct domain
*)NULL
;
1458 pdom
= pdom
->dom_pnext
) {
1459 if (pdom
->cache_file
)
1460 unlink(pdom
->cache_file
);
1463 sprintf(filename
, "%s/ypbind.pid", BINDING
);
1466 dir
= opendir(BINDING
);
1469 /* Directory could not be opened. */
1470 syslog(LOG_ERR
, "opendir failed with [%s]", strerror(errno
));
1474 while ((dirent
= readdir(dir
)) != 0) {
1475 if (strncmp(dirent
->d_name
, "xprt.", 5) == 0) {
1476 sprintf(filename
, "%s/%s", BINDING
, dirent
->d_name
);
1478 rewinddir(dir
); /* removing file may harm iteration */
1485 * We only want to use the cache stuff on local file systems.
1486 * For remote file systems (e.g., NFS, the locking overhead is
1487 * worse than the overhead of loopback RPC, so the caching
1488 * wouldn't buy us anything. In addition, if the remote locking
1489 * software isn't configured before we start, then we would
1490 * block when we try to lock.
1492 * We don't have a direct way to tell if a file system is local
1493 * or remote, so we assume it is local unless it is NFS.
1499 struct statvfs stbuf
;
1501 st
= statvfs(BINDING
, &stbuf
);
1503 syslog(LOG_ERR
, "statvfs failed with [%s]", strerror(errno
));
1507 /* we use strncasecmp to get NFS, NFS3, nfs, nfs3, etc. */
1508 if (strncasecmp(stbuf
.f_basetype
, "NFS", 3) == 0)