4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 * Portions of this source code were derived from Berkeley
31 * under license from the Regents of the University of
39 #include <sys/types.h>
44 #include <netconfig.h>
48 #include <rpcsvc/yp_prot.h>
49 #include <rpcsvc/ypclnt.h>
50 #include <sys/tiuser.h>
52 #define BFSIZE (YPMAXDOMAIN + 32) /* size of binding file */
53 int __ypipbufsize
= 8192; /* size used for clnt_tli_create */
55 /* This should match the one in ypbind.c */
57 extern int getdomainname(char *, int);
59 static CLIENT
*getclnt(rpcprog_t
, rpcvers_t
, struct netconfig
*, int *);
60 static struct dom_binding
*load_dom_binding(struct ypbind_resp
*, char *,
62 static ypbind_resp
*get_cached_domain(char *);
63 static int get_cached_transport(struct netconfig
*, int, char *, int);
64 static int ypbind_running(int, int);
65 static void set_rdev(struct dom_binding
*);
66 static int check_rdev(struct dom_binding
*);
68 static char nullstring
[] = "";
70 * Time parameters when talking to the ypbind and pmap processes
73 #define YPSLEEPTIME 5 /* Time to sleep between tries */
74 unsigned int _ypsleeptime
= YPSLEEPTIME
;
77 * Time parameters when talking to the ypserv process
81 #define YPTIMEOUT 120 /* Total seconds for timeout */
82 #define YPINTER_TRY 60 /* Seconds between tries */
84 #define YPTIMEOUT 20 /* Total seconds for timeout */
85 #define YPINTER_TRY 5 /* Seconds between tries */
88 #define MAX_TRIES_FOR_NEW_YP 1 /* Number of times we'll try to */
89 /* get a new YP server before */
90 /* we'll settle for an old one. */
91 struct timeval _ypserv_timeout
= {
92 YPTIMEOUT
, /* Seconds */
96 static mutex_t default_domain_lock
= DEFAULTMUTEX
;
97 static char *default_domain
;
100 * The bound_domains_lock serializes all action in yp_unbind(), __yp_dobind(),
101 * newborn(), check_binding() and laod_dom_binding(), not just the direct
102 * manipulation of the bound_domains list.
103 * It also protects all of the fields within a domain binding except
104 * the server_name field (which is protected by the server_name_lock).
105 * A better implementation might try to serialize each domain separately,
106 * but normally we're only dealing with one domain (the default) anyway.
107 * To avoid one thread freeing a domain binding while another is using
108 * the binding, we maintain a reference count for each binding. The
109 * reference count is incremented in __yp_dobind. The thread calls
110 * __yp_rel_binding() when it has finished using the binding (which
111 * decrements the reference count). If the reference count is non-zero
112 * when a thread tries to free a binding, the need_free flag is set and
113 * the free is delayed. The __yp_rel_binding() routine checks the flag
114 * and calls the free routine if the flag is set and the reference
117 static mutex_t bound_domains_lock
= DEFAULTMUTEX
;
118 static struct dom_binding
*bound_domains
; /* List of bound domains */
122 * Must be called with bound_domains_lock held or with a dom_binding
123 * that cannot be referenced by another thread.
126 free_dom_binding(struct dom_binding
*p
)
128 if (p
->ref_count
!= 0) {
132 (void) check_rdev(p
);
133 clnt_destroy(p
->dom_client
);
139 * Attempts to find a dom_binding in the list at bound_domains having the
140 * domain name field equal to the passed domain name, and removes it if found.
141 * The domain-server binding will not exist after the call to this function.
142 * All resources associated with the binding will be freed.
144 * yp_unbind is MT-safe because it serializes on bound_domains_lock.
148 __yp_unbind_nolock(char *domain
)
150 struct dom_binding
*p
;
151 struct dom_binding
**prev
;
153 if ((domain
== NULL
) || (strlen(domain
) == 0)) {
158 * If we used a cache file to bind, then we will mark the
159 * cache bad. This will cause a subsequent call to __yp_dobind
160 * to ignore the cache and talk to ypbind. Otherwise, we
161 * have already gotten a binding by talking to ypbind and
162 * the binding is not good.
164 * An optimization could be to check to see if the cache
165 * file has changed (ypbind is pointing at a new server) and
166 * reload the binding from it. But that is too much work
169 for (prev
= &bound_domains
; (p
= *prev
) != 0; prev
= &p
->dom_pnext
) {
171 if (strcmp(domain
, p
->dom_domain
) == 0) {
176 *prev
= p
->dom_pnext
;
186 yp_unbind(char *domain
)
188 (void) mutex_lock(&bound_domains_lock
);
189 __yp_unbind_nolock(domain
);
190 (void) mutex_unlock(&bound_domains_lock
);
195 * This checks to see if this is a new process incarnation which has
196 * inherited bindings from a parent, and unbinds the world if so.
198 * MT-safe because it is only invoked from __yp_dobind(), which serializes
204 static pid_t mypid
; /* Cached to detect forks */
206 struct dom_binding
*p
, *q
;
208 if ((testpid
= getpid()) != mypid
) {
212 for (p
= bound_domains
; p
!= 0; p
= q
) {
221 * This checks that the socket for a domain which has already been bound
222 * hasn't been closed or changed under us. If it has, unbind the domain
223 * without closing the socket, which may be in use by some higher level
224 * code. This returns TRUE and points the binding parameter at the found
225 * dom_binding if the binding is found and the socket looks OK, and FALSE
228 * MT-safe because it is only invoked from __yp_dobind(), which serializes
232 check_binding(char *domain
, struct dom_binding
**binding
)
234 struct dom_binding
*pdomb
;
235 struct ypbind_resp
*ypbind_resp
;
238 for (pdomb
= bound_domains
; pdomb
!= NULL
; pdomb
= pdomb
->dom_pnext
) {
240 if (strcmp(domain
, pdomb
->dom_domain
) == 0) {
242 * XXX How do we really make sure the udp connection hasn't
243 * changes under us ? If it happens and we can't detect it,
244 * the appliction is doomed !
245 * POLICY: Let nobody do a yp_bind or __yp_dobind explicitly
246 * and forget to to yp_unbind it. All apps should go
247 * through the standard yp_match/first etc. functions.
256 * We check to see if we can do a quick bind to ypserv.
257 * If we can, then we load the binding (i.e., add it to our
258 * cache of bindings) and then return it.
260 if ((ypbind_resp
= get_cached_domain(domain
)) != 0) {
261 pdomb
= load_dom_binding(ypbind_resp
, domain
, &status
);
271 * This routine adds a binding for a particular server to our
272 * list of bound domains. We check to see if there is actually
273 * a yp server at the given address. If not, or if there is
274 * any other error, we return 0. We have to malloc the binding
275 * structure because that is what a call to ypbind returns and
276 * we are basically doing what a call to ypbind would do.
279 #define SOCKADDR_SIZE (sizeof (struct sockaddr_in6))
281 __yp_add_binding_netid(char *domain
, char *addr
, char *netid
)
283 struct netconfig
*nconf
= 0;
284 struct netbuf
*svcaddr
= 0;
285 struct ypbind_binding
*binding
= 0;
287 struct ypbind_resp resp
;
288 struct dom_binding
*pdomb
;
290 nconf
= getnetconfigent(netid
);
294 svcaddr
= malloc(sizeof (struct netbuf
));
298 svcaddr
->maxlen
= SOCKADDR_SIZE
;
299 svcaddr
->buf
= malloc(SOCKADDR_SIZE
);
300 if (svcaddr
->buf
== 0)
303 if (!rpcb_getaddr(YPPROG
, YPVERS
, nconf
, svcaddr
, addr
))
306 binding
= malloc(sizeof (struct ypbind_binding
));
310 binding
->ypbind_hi_vers
= YPVERS
;
311 binding
->ypbind_lo_vers
= YPVERS
;
312 binding
->ypbind_nconf
= nconf
;
313 binding
->ypbind_svcaddr
= svcaddr
;
314 binding
->ypbind_servername
= (char *)strdup(addr
);
315 if (binding
->ypbind_servername
== 0)
318 resp
.ypbind_status
= YPBIND_SUCC_VAL
;
319 resp
.ypbind_resp_u
.ypbind_bindinfo
= binding
;
321 (void) mutex_lock(&bound_domains_lock
);
323 pdomb
= load_dom_binding(&resp
, domain
, &status
);
324 (void) mutex_unlock(&bound_domains_lock
);
330 freenetconfigent(nconf
);
336 free(binding
->ypbind_servername
);
344 __yp_add_binding(char *domain
, char *addr
) {
346 int ret
= __yp_add_binding_netid(domain
, addr
, "udp6");
349 ret
= __yp_add_binding_netid(domain
, addr
, "udp");
356 * This allocates some memory for a domain binding, initialize it, and
357 * returns a pointer to it. Based on the program version we ended up
358 * talking to ypbind with, fill out an opvector of appropriate protocol
361 * MT-safe because it is only invoked from __yp_dobind(), which serializes
364 static struct dom_binding
*
365 load_dom_binding(struct ypbind_resp
*ypbind_res
, char *domain
, int *err
)
368 struct dom_binding
*pdomb
;
372 if ((pdomb
= malloc(sizeof (struct dom_binding
))) == NULL
) {
373 syslog(LOG_ERR
, "load_dom_binding: malloc failure.");
378 pdomb
->dom_binding
= ypbind_res
->ypbind_resp_u
.ypbind_bindinfo
;
380 * Open up a path to the server, which will remain active globally.
382 pdomb
->dom_client
= clnt_tli_create(RPC_ANYFD
,
383 pdomb
->dom_binding
->ypbind_nconf
,
384 pdomb
->dom_binding
->ypbind_svcaddr
,
385 YPPROG
, YPVERS
, __ypipbufsize
,
387 if (pdomb
->dom_client
== NULL
) {
388 clnt_pcreateerror("yp_bind: clnt_tli_create");
394 (void) printf("yp_bind: clnt_tli_create suceeded\n");
397 pdomb
->dom_pnext
= bound_domains
; /* Link this to the list as */
398 pdomb
->dom_domain
= malloc(strlen(domain
) + (unsigned)1);
399 if (pdomb
->dom_domain
== NULL
) {
400 clnt_destroy(pdomb
->dom_client
);
406 * We may not have loaded from a cache file, but we assume the
407 * cache is good until we find out otherwise.
409 pdomb
->cache_bad
= 0;
411 if (clnt_control(pdomb
->dom_client
, CLGET_FD
, (char *)&fd
))
412 (void) fcntl(fd
, F_SETFD
, 1); /* make it "close on exec" */
414 (void) strcpy(pdomb
->dom_domain
, domain
); /* Remember the domain name */
415 pdomb
->ref_count
= 0;
416 pdomb
->need_free
= 0;
417 (void) mutex_init(&pdomb
->server_name_lock
, USYNC_THREAD
, 0);
418 bound_domains
= pdomb
; /* ... the head entry */
423 * XXX special code for handling C2 (passwd.adjunct) lookups when we need
427 tli_open_rsvdport(struct netconfig
*nconf
)
434 fd
= t_open(nconf
->nc_device
, O_RDWR
, NULL
);
438 if (netdir_options(nconf
, ND_SET_RESERVEDPORT
, fd
, NULL
) == -1) {
439 if (t_bind(fd
, NULL
, NULL
) == -1) {
448 * This allocates some memory for a domain binding, initialize it, and
449 * returns a pointer to it. Based on the program version we ended up
450 * talking to ypbind with, fill out an opvector of appropriate protocol
453 * MT-safe because it is only invoked from __yp_dobind(), which serializes
456 * XXX special version for handling C2 (passwd.adjunct) lookups when we need
459 * Note that the binding is not cached. The caller has to free the binding
460 * using free_dom_binding().
462 static struct dom_binding
*
463 load_dom_binding_rsvdport(struct ypbind_binding
*dom_binding
, char *domain
,
466 struct dom_binding
*pdomb
;
471 if ((pdomb
= malloc(sizeof (struct dom_binding
))) == NULL
) {
472 syslog(LOG_ERR
, "load_dom_binding_rsvdport: malloc failure.");
477 pdomb
->dom_binding
= dom_binding
;
479 * Open up a path to the server, which will remain active globally.
481 fd
= tli_open_rsvdport(pdomb
->dom_binding
->ypbind_nconf
);
483 clnt_pcreateerror("yp_bind: tli_open_rsvdport");
488 pdomb
->dom_client
= clnt_tli_create(fd
,
489 pdomb
->dom_binding
->ypbind_nconf
,
490 pdomb
->dom_binding
->ypbind_svcaddr
,
491 YPPROG
, YPVERS
, __ypipbufsize
,
493 if (pdomb
->dom_client
== NULL
) {
494 clnt_pcreateerror("yp_bind: clnt_tli_create");
500 (void) printf("yp_bind: clnt_tli_create suceeded\n");
502 (void) CLNT_CONTROL(pdomb
->dom_client
, CLSET_FD_CLOSE
, NULL
);
504 pdomb
->dom_domain
= malloc(strlen(domain
) + (unsigned)1);
505 if (pdomb
->dom_domain
== NULL
) {
506 clnt_destroy(pdomb
->dom_client
);
512 (void) strcpy(pdomb
->dom_domain
, domain
); /* Remember the domain name */
513 pdomb
->ref_count
= 0;
514 pdomb
->need_free
= 0;
516 (void) mutex_init(&pdomb
->server_name_lock
, USYNC_THREAD
, 0);
521 * Attempts to locate a yellow pages server that serves a passed domain. If
522 * one is found, an entry is created on the static list of domain-server pairs
523 * pointed to by cell bound_domains, a udp path to the server is created and
524 * the function returns 0. Otherwise, the function returns a defined errorcode
527 * MT-safe because it serializes on bound_domains_lock.
529 * If hardlookup is set then loop forever until success, else try 4
530 * times (each try is relatively short) max.
533 __yp_dobind_cflookup(
535 struct dom_binding
**binding
, /* if result==0, ptr to dom_binding */
539 struct dom_binding
*pdomb
; /* Ptr to new domain binding */
540 struct ypbind_resp
*ypbind_resp
; /* Response from local ypbinder */
541 struct ypbind_domain ypbd
;
542 int status
, err
= YPERR_DOMAIN
;
546 if ((domain
== NULL
) ||(strlen(domain
) == 0))
547 return (YPERR_BADARGS
);
549 (void) mutex_lock(&bound_domains_lock
);
552 * If someone managed to fork() while we were holding this lock,
553 * we'll probably end up hanging on the lock. Tant pis.
557 if (check_binding(domain
, binding
)) {
559 * If the cache is okay and if the underlying file
560 * descriptor is okay (application did not close it).
561 * then use the binding.
563 if (!(*binding
)->cache_bad
&& check_rdev(*binding
)) {
564 (*binding
)->ref_count
+= 1;
565 (void) mutex_unlock(&bound_domains_lock
);
566 return (0); /* We are bound */
570 * If we get here, one of two things happened: the
571 * cache is bad, or the underlying file descriptor
574 * If the cache is bad, then we call yp_unbind to remove
577 * If the file descriptor has changed, then we call
578 * yp_unbind to remove the binding (we set cache_bad
579 * to force yp_unbind to do the remove), and then
580 * call check_binding to reload the binding from the
583 if ((*binding
)->cache_bad
) {
584 __yp_unbind_nolock(domain
);
586 (*binding
)->cache_bad
= 1;
587 (void) mutex_unlock(&bound_domains_lock
);
589 (void) mutex_lock(&bound_domains_lock
);
590 if (check_binding(domain
, binding
)) {
591 (*binding
)->ref_count
+= 1;
592 (void) mutex_unlock(&bound_domains_lock
);
603 * ===> sleep() -- Ugh. And with the lock held, too.
605 (void) sleep(_ypsleeptime
);
607 tb
= __clnt_create_loopback(YPBINDPROG
, YPBINDVERS
, &err
);
609 if (ypbind_running(err
, rpc_createerr
.cf_stat
))
613 ypbd
.ypbind_domainname
= domain
;
614 ypbd
.ypbind_vers
= YPVERS
;
616 * The interface to ypbindproc_domain_3 is MT-unsafe, but we're
617 * OK as long as we're the only ones who call it and we
618 * serialize all requests (for all domains). Otherwise,
619 * change the interface (pass in the ypbind_resp struct).
621 ypbind_resp
= ypbindproc_domain_3(&ypbd
, tb
);
623 * Although we talk to ypbind on loopback,
624 * it gives us a udp address for the ypserv.
626 if (ypbind_resp
== NULL
) {
629 "ypbindproc_domain_3: can't contact ypbind");
634 if (ypbind_resp
->ypbind_status
== YPBIND_SUCC_VAL
) {
636 * Local ypbind has let us in on the ypserv's address,
637 * go get in touch with it !
639 pdomb
= load_dom_binding(ypbind_resp
, domain
, &status
);
647 pdomb
->ref_count
+= 1;
648 (void) mutex_unlock(&bound_domains_lock
);
649 *binding
= pdomb
; /* Return ptr to the binding entry */
650 return (0); /* This is the go path */
652 if (ypbind_resp
->ypbind_resp_u
.ypbind_error
==
659 } while (hardlookup
);
663 (void) mutex_unlock(&bound_domains_lock
);
666 return (YPERR_DOMAIN
);
672 struct dom_binding
**binding
) /* if result == 0, ptr to dom_binding */
674 /* traditional __yp_dobind loops forever so set hardlookup */
675 return (__yp_dobind_cflookup(domain
, binding
, 1));
679 __yp_rel_binding(struct dom_binding
*binding
)
681 (void) mutex_lock(&bound_domains_lock
);
682 binding
->ref_count
-= 1;
683 if (binding
->need_free
&& binding
->ref_count
== 0)
684 free_dom_binding(binding
);
685 (void) mutex_unlock(&bound_domains_lock
);
689 * Attempts to locate a yellow pages server that serves a passed domain. If
690 * one is found, an entry is created on the static list of domain-server pairs
691 * pointed to by cell bound_domains, a udp path to the server is created and
692 * the function returns 0. Otherwise, the function returns a defined errorcode
695 * MT-safe because it serializes on bound_domains_lock.
697 * XXX special version for handling C2 (passwd.adjunct) lookups when we need
699 * This returns an uncached binding which the caller has to free using
700 * free_dom_binding().
703 __yp_dobind_rsvdport_cflookup(
705 struct dom_binding
**binding
, /* if result==0, ptr to dom_binding */
708 struct dom_binding
*pdomb
; /* Ptr to new domain binding */
709 struct ypbind_resp
*ypbind_resp
; /* Response from local ypbinder */
710 struct ypbind_domain ypbd
;
711 int status
, err
= YPERR_DOMAIN
;
715 if ((domain
== NULL
) ||(strlen(domain
) == 0))
716 return (YPERR_BADARGS
);
718 (void) mutex_lock(&bound_domains_lock
);
721 * If someone managed to fork() while we were holding this lock,
722 * we'll probably end up hanging on the lock. Tant pis.
727 * Check for existing bindings and use the information in the binding
728 * to create a transport endpoint with a reserved port.
730 if (check_binding(domain
, binding
)) {
732 * If the cache is bad, yp_unbind() the entry again and then
735 if ((*binding
)->cache_bad
) {
736 __yp_unbind_nolock(domain
);
738 pdomb
= load_dom_binding_rsvdport(
739 (*binding
)->dom_binding
,
742 (void) mutex_unlock(&bound_domains_lock
);
745 pdomb
->ref_count
+= 1;
746 (void) mutex_unlock(&bound_domains_lock
);
747 *binding
= pdomb
; /* Return ptr to the binding entry */
757 * ===> sleep() -- Ugh. And with the lock held, too.
759 (void) sleep(_ypsleeptime
);
761 tb
= __clnt_create_loopback(YPBINDPROG
, YPBINDVERS
, &err
);
763 if (ypbind_running(err
, rpc_createerr
.cf_stat
))
767 ypbd
.ypbind_domainname
= domain
;
768 ypbd
.ypbind_vers
= YPVERS
;
770 * The interface to ypbindproc_domain_3 is MT-unsafe, but we're
771 * OK as long as we're the only ones who call it and we
772 * serialize all requests (for all domains). Otherwise,
773 * change the interface (pass in the ypbind_resp struct).
775 ypbind_resp
= ypbindproc_domain_3(&ypbd
, tb
);
777 * Although we talk to ypbind on loopback,
778 * it gives us a udp address for the ypserv.
780 if (ypbind_resp
== NULL
) {
783 "ypbindproc_domain_3: can't contact ypbind");
788 if (ypbind_resp
->ypbind_status
== YPBIND_SUCC_VAL
) {
790 * Local ypbind has let us in on the ypserv's address,
791 * go get in touch with it !
793 pdomb
= load_dom_binding_rsvdport(
794 ypbind_resp
->ypbind_resp_u
.ypbind_bindinfo
,
803 pdomb
->ref_count
+= 1;
804 (void) mutex_unlock(&bound_domains_lock
);
805 *binding
= pdomb
; /* Return ptr to the binding entry */
806 return (0); /* This is the go path */
808 if (ypbind_resp
->ypbind_resp_u
.ypbind_error
==
815 } while (hardlookup
);
819 (void) mutex_unlock(&bound_domains_lock
);
822 return (YPERR_DOMAIN
);
826 __yp_dobind_rsvdport(
828 struct dom_binding
**binding
) /* if result==0, ptr to dom_binding */
830 /* traditional __yp_dobind_rsvdport loops forever so set hardlookup */
831 return (__yp_dobind_rsvdport_cflookup(domain
, binding
, 1));
835 * This is a "wrapper" function for __yp_dobind for vanilla user-level
836 * functions which neither know nor care about struct dom_bindings.
839 yp_bind(char *domain
)
842 struct dom_binding
*binding
;
845 res
= __yp_dobind(domain
, &binding
);
847 __yp_rel_binding(binding
);
852 __default_domain(void)
856 (void) mutex_lock(&default_domain_lock
);
858 if (default_domain
) {
859 (void) mutex_unlock(&default_domain_lock
);
860 return (default_domain
);
862 if (getdomainname(temp
, sizeof (temp
)) < 0) {
863 (void) mutex_unlock(&default_domain_lock
);
866 if (strlen(temp
) > 0) {
867 default_domain
= malloc((strlen(temp
) + 1));
868 if (default_domain
== 0) {
869 (void) mutex_unlock(&default_domain_lock
);
872 (void) strcpy(default_domain
, temp
);
873 (void) mutex_unlock(&default_domain_lock
);
874 return (default_domain
);
876 (void) mutex_unlock(&default_domain_lock
);
881 * This is a wrapper for the system call getdomainname which returns a
882 * ypclnt.h error code in the failure case. It also checks to see that
883 * the domain name is non-null, knowing that the null string is going to
884 * get rejected elsewhere in the yp client package.
887 yp_get_default_domain(char **domain
)
889 if ((*domain
= __default_domain()) != 0)
891 return (YPERR_YPERR
);
895 * ===> Nobody uses this, do they? Can we nuke it?
898 usingypmap(char **ddn
, char *map
)
900 char in
, *outval
= NULL
;
904 if ((domain
= __default_domain()) == 0)
907 /* does the map exist ? */
909 stat
= yp_match(domain
, map
, &in
, 1, &outval
, &outvallen
);
913 case 0: /* it actually succeeded! */
914 case YPERR_KEY
: /* no such key in map */
923 * Creates a quick connection on a connection oriented loopback
924 * transport. Fails quickly without timeout. Only naming service
925 * it goes to is straddr.so.
928 __clnt_create_loopback(rpcprog_t prog
, rpcvers_t vers
, int *err
)
930 struct netconfig
*nconf
;
932 void *nc_handle
; /* Net config handle */
935 nc_handle
= setnetconfig();
936 if (nc_handle
== NULL
) {
937 /* fails to open netconfig file */
938 rpc_createerr
.cf_stat
= RPC_FAILED
;
942 while (nconf
= getnetconfig(nc_handle
))
943 /* Try only one connection oriented loopback transport */
944 if ((strcmp(nconf
->nc_protofmly
, NC_LOOPBACK
) == 0) &&
945 ((nconf
->nc_semantics
== NC_TPI_COTS
) ||
946 (nconf
->nc_semantics
== NC_TPI_COTS_ORD
))) {
947 clnt
= getclnt(prog
, vers
, nconf
, err
);
950 (void) endnetconfig(nc_handle
);
952 if (clnt
== NULL
) { /* no loopback transport available */
953 if (rpc_createerr
.cf_stat
== 0)
954 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
955 if (*err
== 0) *err
= YPERR_RPC
;
961 getclnt(rpcprog_t prog
, rpcvers_t vers
, struct netconfig
*nconf
, int *err
)
964 struct netbuf
*svcaddr
; /* servers address */
966 struct nd_addrlist
*nas
;
967 struct nd_hostserv rpcbind_hs
;
968 struct t_call sndcall
;
969 char uaddress
[1024]; /* XXX maxlen ?? */
971 enum clnt_stat clnt_st
;
973 struct timeval tv
= { 30, 0 };
976 rpc_createerr
.cf_stat
= RPC_TLIERROR
;
982 * The ypbind process might cache its transport address.
983 * If we can get at it, then we will use it and avoid
984 * wasting time talking to rpcbind.
987 if (get_cached_transport(nconf
, vers
, uaddress
, sizeof (uaddress
))) {
992 * Check to see if local rpcbind is up or not. If it
993 * isn't, it is best that the application should realize
994 * yp is not up and take a remedial action. This is to
995 * avoid the minute long timeout incurred by rpcbind_getaddr.
996 * Looks like the only way to accomplish this it is to unfold
997 * rpcb_getaddr and make a few changes. Alas !
999 rpcbind_hs
.h_host
= HOST_SELF_CONNECT
;
1000 rpcbind_hs
.h_serv
= "rpcbind";
1001 if (netdir_getbyname(nconf
, &rpcbind_hs
, &nas
) != ND_OK
) {
1002 rpc_createerr
.cf_stat
= RPC_N2AXLATEFAILURE
;
1006 if ((fd
= t_open(nconf
->nc_device
, O_RDWR
, NULL
)) == -1) {
1007 rpc_createerr
.cf_stat
= RPC_TLIERROR
;
1011 if (t_bind(fd
, NULL
, NULL
) == -1) {
1012 rpc_createerr
.cf_stat
= RPC_TLIERROR
;
1017 sndcall
.addr
= *(nas
->n_addrs
);
1018 sndcall
.opt
.len
= 0;
1019 sndcall
.udata
.len
= 0;
1020 if (t_connect(fd
, &sndcall
, NULL
) == -1) {
1021 netdir_free((char *)nas
, ND_ADDRLIST
);
1022 rpc_createerr
.cf_stat
= RPC_TLIERROR
;
1029 * Get the address of the server
1031 cl
= clnt_tli_create(fd
, nconf
, nas
->n_addrs
,
1032 RPCBPROG
, RPCBVERS
, __ypipbufsize
, __ypipbufsize
);
1033 netdir_free((char *)nas
, ND_ADDRLIST
);
1039 parms
.r_prog
= prog
;
1040 parms
.r_vers
= vers
;
1041 parms
.r_netid
= nconf
->nc_netid
;
1042 parms
.r_addr
= nullstring
;
1043 parms
.r_owner
= nullstring
;
1045 clnt_st
= CLNT_CALL(cl
, RPCBPROC_GETADDR
, xdr_rpcb
, (char *)&parms
,
1046 xdr_wrapstring
, (char *)&ua
, tv
);
1049 if (clnt_st
!= RPC_SUCCESS
) {
1050 *err
= YPERR_YPBIND
;
1053 if (strlen(uaddress
) == 0) {
1054 *err
= YPERR_YPBIND
;
1055 rpc_createerr
.cf_stat
= RPC_PROGNOTREGISTERED
;
1060 svcaddr
= uaddr2taddr(nconf
, uaddress
);
1061 cl
= clnt_tli_create(RPC_ANYFD
, nconf
, svcaddr
, prog
, vers
,
1062 __ypipbufsize
, __ypipbufsize
);
1063 netdir_free((char *)svcaddr
, ND_ADDR
);
1065 *err
= YPERR_YPBIND
;
1069 * The fd should be closed while destroying the handle.
1075 get_cached_transport(struct netconfig
*nconf
, int vers
, char *uaddress
,
1081 (void) snprintf(uaddress
, ulen
,
1082 "%s/xprt.%s.%d", BINDING
, nconf
->nc_netid
, vers
);
1083 fd
= open(uaddress
, O_RDONLY
);
1087 /* if first byte is not locked, then ypbind must not be running */
1088 st
= lockf(fd
, F_TEST
, 1);
1089 if (st
!= -1 || (errno
!= EAGAIN
&& errno
!= EACCES
)) {
1094 st
= read(fd
, uaddress
, ulen
);
1104 static ypbind_resp
*
1105 get_cached_domain(char *domain
)
1110 static ypbind_resp res
;
1113 (void) snprintf(filename
, sizeof (filename
),
1114 "%s/%s/cache_binding", BINDING
, domain
);
1115 fp
= fopen(filename
, "rF");
1119 /* if first byte is not locked, then ypbind must not be running */
1120 st
= lockf(fileno(fp
), F_TEST
, 1);
1121 if (st
!= -1 || (errno
!= EAGAIN
&& errno
!= EACCES
)) {
1126 xdrstdio_create(&xdrs
, fp
, XDR_DECODE
);
1128 (void) memset((char *)&res
, 0, sizeof (res
));
1129 st
= xdr_ypbind_resp(&xdrs
, &res
);
1141 ypbind_running(int err
, int status
)
1147 (void) snprintf(filename
, sizeof (filename
), "%s/ypbind.pid", BINDING
);
1148 fd
= open(filename
, O_RDONLY
);
1150 if ((err
== YPERR_YPBIND
) && (status
!= RPC_PROGNOTREGISTERED
))
1155 /* if first byte is not locked, then ypbind must not be running */
1156 st
= lockf(fd
, F_TEST
, 1);
1157 if (st
!= -1 || (errno
!= EAGAIN
&& errno
!= EACCES
)) {
1167 set_rdev(struct dom_binding
*pdomb
)
1172 if (clnt_control(pdomb
->dom_client
, CLGET_FD
, (char *)&fd
) != TRUE
||
1173 fstat(fd
, &stbuf
) == -1) {
1174 syslog(LOG_DEBUG
, "ypbind client: can't get rdev");
1179 pdomb
->rdev
= stbuf
.st_rdev
;
1183 check_rdev(struct dom_binding
*pdomb
)
1187 if (pdomb
->fd
== -1)
1188 return (1); /* can't check it, assume it is okay */
1190 if (fstat(pdomb
->fd
, &stbuf
) == -1) {
1191 syslog(LOG_DEBUG
, "yp_bind client: can't stat %d", pdomb
->fd
);
1192 /* could be because file descriptor was closed */
1193 /* it's not our file descriptor, so don't try to close it */
1194 clnt_control(pdomb
->dom_client
, CLSET_FD_NCLOSE
, NULL
);
1197 if (pdomb
->rdev
!= stbuf
.st_rdev
) {
1199 "yp_bind client: fd %d changed, old=0x%x, new=0x%x",
1200 pdomb
->fd
, pdomb
->rdev
, stbuf
.st_rdev
);
1201 /* it's not our file descriptor, so don't try to close it */
1202 clnt_control(pdomb
->dom_client
, CLSET_FD_NCLOSE
, NULL
);
1205 return (1); /* fd is okay */