import less(1)
[unleashed/tickless.git] / usr / src / lib / libc / port / nsl / yp_bind.c
blob549a669f84e9842fdce1331966212fe524c111e5
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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
32 * California.
34 #include "mt.h"
35 #include "rpc_mt.h"
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <errno.h>
42 #include <unistd.h>
43 #include <rpc/rpc.h>
44 #include <netconfig.h>
45 #include <netdir.h>
46 #include <syslog.h>
47 #include "yp_b.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 *,
61 int *);
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
80 #ifdef DEBUG
81 #define YPTIMEOUT 120 /* Total seconds for timeout */
82 #define YPINTER_TRY 60 /* Seconds between tries */
83 #else
84 #define YPTIMEOUT 20 /* Total seconds for timeout */
85 #define YPINTER_TRY 5 /* Seconds between tries */
86 #endif
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 */
93 0 /* Microseconds */
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
115 * count is zero.
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.
125 void
126 free_dom_binding(struct dom_binding *p)
128 if (p->ref_count != 0) {
129 p->need_free = 1;
130 return;
132 (void) check_rdev(p);
133 clnt_destroy(p->dom_client);
134 free(p->dom_domain);
135 free(p);
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.
147 static void
148 __yp_unbind_nolock(char *domain)
150 struct dom_binding *p;
151 struct dom_binding **prev;
153 if ((domain == NULL) || (strlen(domain) == 0)) {
154 return;
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
167 * for now.
169 for (prev = &bound_domains; (p = *prev) != 0; prev = &p->dom_pnext) {
171 if (strcmp(domain, p->dom_domain) == 0) {
172 if (!p->cache_bad) {
173 p->cache_bad = 1;
174 break;
176 *prev = p->dom_pnext;
177 free_dom_binding(p);
178 break;
185 void
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
199 * all requests.
201 static void
202 newborn(void)
204 static pid_t mypid; /* Cached to detect forks */
205 pid_t testpid;
206 struct dom_binding *p, *q;
208 if ((testpid = getpid()) != mypid) {
210 mypid = testpid;
212 for (p = bound_domains; p != 0; p = q) {
213 q = p->dom_pnext;
214 free_dom_binding(p);
216 bound_domains = 0;
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
226 * otherwise.
228 * MT-safe because it is only invoked from __yp_dobind(), which serializes
229 * all requests.
231 static bool
232 check_binding(char *domain, struct dom_binding **binding)
234 struct dom_binding *pdomb;
235 struct ypbind_resp *ypbind_resp;
236 int status;
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.
250 *binding = pdomb;
251 return (TRUE);
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);
262 if (pdomb == 0)
263 return (FALSE);
264 *binding = pdomb;
265 return (TRUE);
267 return (FALSE);
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))
280 static int
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;
286 int status;
287 struct ypbind_resp resp;
288 struct dom_binding *pdomb;
290 nconf = getnetconfigent(netid);
291 if (nconf == 0)
292 goto err;
294 svcaddr = malloc(sizeof (struct netbuf));
295 if (svcaddr == 0)
296 goto err;
298 svcaddr->maxlen = SOCKADDR_SIZE;
299 svcaddr->buf = malloc(SOCKADDR_SIZE);
300 if (svcaddr->buf == 0)
301 goto err;
303 if (!rpcb_getaddr(YPPROG, YPVERS, nconf, svcaddr, addr))
304 goto err;
306 binding = malloc(sizeof (struct ypbind_binding));
307 if (binding == 0)
308 goto err;
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)
316 goto err;
318 resp.ypbind_status = YPBIND_SUCC_VAL;
319 resp.ypbind_resp_u.ypbind_bindinfo = binding;
321 (void) mutex_lock(&bound_domains_lock);
322 newborn();
323 pdomb = load_dom_binding(&resp, domain, &status);
324 (void) mutex_unlock(&bound_domains_lock);
326 return (pdomb != 0);
328 err:
329 if (nconf)
330 freenetconfigent(nconf);
331 if (svcaddr) {
332 free(svcaddr->buf);
333 free(svcaddr);
335 if (binding) {
336 free(binding->ypbind_servername);
337 free(binding);
339 return (0);
344 __yp_add_binding(char *domain, char *addr) {
346 int ret = __yp_add_binding_netid(domain, addr, "udp6");
348 if (ret == 0)
349 ret = __yp_add_binding_netid(domain, addr, "udp");
351 return (ret);
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
359 * modules.
361 * MT-safe because it is only invoked from __yp_dobind(), which serializes
362 * all requests.
364 static struct dom_binding *
365 load_dom_binding(struct ypbind_resp *ypbind_res, char *domain, int *err)
367 int fd;
368 struct dom_binding *pdomb;
370 pdomb = NULL;
372 if ((pdomb = malloc(sizeof (struct dom_binding))) == NULL) {
373 syslog(LOG_ERR, "load_dom_binding: malloc failure.");
374 *err = YPERR_RESRC;
375 return (NULL);
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,
386 __ypipbufsize);
387 if (pdomb->dom_client == NULL) {
388 clnt_pcreateerror("yp_bind: clnt_tli_create");
389 free(pdomb);
390 *err = YPERR_RPC;
391 return (NULL);
393 #ifdef DEBUG
394 (void) printf("yp_bind: clnt_tli_create suceeded\n");
395 #endif
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);
401 free(pdomb);
402 *err = YPERR_RESRC;
403 return (NULL);
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;
410 set_rdev(pdomb);
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 */
419 return (pdomb);
423 * XXX special code for handling C2 (passwd.adjunct) lookups when we need
424 * a reserved port.
426 static int
427 tli_open_rsvdport(struct netconfig *nconf)
429 int fd;
431 if (nconf == NULL)
432 return (-1);
434 fd = t_open(nconf->nc_device, O_RDWR, NULL);
435 if (fd == -1)
436 return (-1);
438 if (netdir_options(nconf, ND_SET_RESERVEDPORT, fd, NULL) == -1) {
439 if (t_bind(fd, NULL, NULL) == -1) {
440 (void) t_close(fd);
441 return (-1);
444 return (fd);
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
451 * modules.
453 * MT-safe because it is only invoked from __yp_dobind(), which serializes
454 * all requests.
456 * XXX special version for handling C2 (passwd.adjunct) lookups when we need
457 * a reserved port.
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,
464 int *err)
466 struct dom_binding *pdomb;
467 int fd;
469 pdomb = NULL;
471 if ((pdomb = malloc(sizeof (struct dom_binding))) == NULL) {
472 syslog(LOG_ERR, "load_dom_binding_rsvdport: malloc failure.");
473 *err = YPERR_RESRC;
474 return (NULL);
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);
482 if (fd < 0) {
483 clnt_pcreateerror("yp_bind: tli_open_rsvdport");
484 free(pdomb);
485 *err = YPERR_RPC;
486 return (NULL);
488 pdomb->dom_client = clnt_tli_create(fd,
489 pdomb->dom_binding->ypbind_nconf,
490 pdomb->dom_binding->ypbind_svcaddr,
491 YPPROG, YPVERS, __ypipbufsize,
492 __ypipbufsize);
493 if (pdomb->dom_client == NULL) {
494 clnt_pcreateerror("yp_bind: clnt_tli_create");
495 free(pdomb);
496 *err = YPERR_RPC;
497 return (NULL);
499 #ifdef DEBUG
500 (void) printf("yp_bind: clnt_tli_create suceeded\n");
501 #endif
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);
507 free(pdomb);
508 *err = YPERR_RESRC;
509 return (NULL);
512 (void) strcpy(pdomb->dom_domain, domain); /* Remember the domain name */
513 pdomb->ref_count = 0;
514 pdomb->need_free = 0;
515 set_rdev(pdomb);
516 (void) mutex_init(&pdomb->server_name_lock, USYNC_THREAD, 0);
517 return (pdomb);
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
525 * YPERR_xxxx.
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(
534 char *domain,
535 struct dom_binding **binding, /* if result==0, ptr to dom_binding */
536 int hardlookup)
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;
543 int first_try = 1;
544 CLIENT *tb = NULL;
546 if ((domain == NULL) ||(strlen(domain) == 0))
547 return (YPERR_BADARGS);
549 (void) mutex_lock(&bound_domains_lock);
551 * ===>
552 * If someone managed to fork() while we were holding this lock,
553 * we'll probably end up hanging on the lock. Tant pis.
555 newborn();
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
572 * had changed.
574 * If the cache is bad, then we call yp_unbind to remove
575 * the binding.
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
581 * cache again.
583 if ((*binding)->cache_bad) {
584 __yp_unbind_nolock(domain);
585 } else {
586 (*binding)->cache_bad = 1;
587 (void) mutex_unlock(&bound_domains_lock);
588 yp_unbind(domain);
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);
593 return (0);
598 do {
599 if (first_try)
600 first_try = 0;
601 else {
603 * ===> sleep() -- Ugh. And with the lock held, too.
605 (void) sleep(_ypsleeptime);
607 tb = __clnt_create_loopback(YPBINDPROG, YPBINDVERS, &err);
608 if (tb == NULL) {
609 if (ypbind_running(err, rpc_createerr.cf_stat))
610 continue;
611 break;
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) {
627 /* lost ypbind? */
628 clnt_perror(tb,
629 "ypbindproc_domain_3: can't contact ypbind");
630 clnt_destroy(tb);
631 tb = NULL;
632 continue;
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);
640 if (pdomb == 0) {
641 err = status;
642 clnt_destroy(tb);
643 tb = NULL;
644 continue;
646 clnt_destroy(tb);
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 ==
653 YPBIND_ERR_NOSERV)
654 err = YPERR_DOMAIN;
655 else
656 err = YPERR_YPBIND;
657 clnt_destroy(tb);
658 tb = NULL;
659 } while (hardlookup);
661 if (tb != NULL)
662 clnt_destroy(tb);
663 (void) mutex_unlock(&bound_domains_lock);
664 if (err)
665 return (err);
666 return (YPERR_DOMAIN);
670 __yp_dobind(
671 char *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));
678 void
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
693 * YPERR_xxxx.
695 * MT-safe because it serializes on bound_domains_lock.
697 * XXX special version for handling C2 (passwd.adjunct) lookups when we need
698 * a reserved port.
699 * This returns an uncached binding which the caller has to free using
700 * free_dom_binding().
703 __yp_dobind_rsvdport_cflookup(
704 char *domain,
705 struct dom_binding **binding, /* if result==0, ptr to dom_binding */
706 int hardlookup)
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;
712 int first_try = 1;
713 CLIENT *tb = NULL;
715 if ((domain == NULL) ||(strlen(domain) == 0))
716 return (YPERR_BADARGS);
718 (void) mutex_lock(&bound_domains_lock);
720 * ===>
721 * If someone managed to fork() while we were holding this lock,
722 * we'll probably end up hanging on the lock. Tant pis.
724 newborn();
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
733 * talk to ypbind.
735 if ((*binding)->cache_bad) {
736 __yp_unbind_nolock(domain);
737 } else {
738 pdomb = load_dom_binding_rsvdport(
739 (*binding)->dom_binding,
740 domain, &status);
741 if (pdomb == 0) {
742 (void) mutex_unlock(&bound_domains_lock);
743 return (status);
745 pdomb->ref_count += 1;
746 (void) mutex_unlock(&bound_domains_lock);
747 *binding = pdomb; /* Return ptr to the binding entry */
748 return (0);
752 do {
753 if (first_try)
754 first_try = 0;
755 else {
757 * ===> sleep() -- Ugh. And with the lock held, too.
759 (void) sleep(_ypsleeptime);
761 tb = __clnt_create_loopback(YPBINDPROG, YPBINDVERS, &err);
762 if (tb == NULL) {
763 if (ypbind_running(err, rpc_createerr.cf_stat))
764 continue;
765 break;
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) {
781 /* lost ypbind? */
782 clnt_perror(tb,
783 "ypbindproc_domain_3: can't contact ypbind");
784 clnt_destroy(tb);
785 tb = NULL;
786 continue;
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,
795 domain, &status);
796 if (pdomb == 0) {
797 err = status;
798 clnt_destroy(tb);
799 tb = NULL;
800 continue;
802 clnt_destroy(tb);
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 ==
809 YPBIND_ERR_NOSERV)
810 err = YPERR_DOMAIN;
811 else
812 err = YPERR_YPBIND;
813 clnt_destroy(tb);
814 tb = NULL;
815 } while (hardlookup);
817 if (tb != NULL)
818 clnt_destroy(tb);
819 (void) mutex_unlock(&bound_domains_lock);
820 if (err)
821 return (err);
822 return (YPERR_DOMAIN);
826 __yp_dobind_rsvdport(
827 char *domain,
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;
843 int res;
845 res = __yp_dobind(domain, &binding);
846 if (res == 0)
847 __yp_rel_binding(binding);
848 return (res);
851 static char *
852 __default_domain(void)
854 char temp[256];
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);
864 return (0);
866 if (strlen(temp) > 0) {
867 default_domain = malloc((strlen(temp) + 1));
868 if (default_domain == 0) {
869 (void) mutex_unlock(&default_domain_lock);
870 return (0);
872 (void) strcpy(default_domain, temp);
873 (void) mutex_unlock(&default_domain_lock);
874 return (default_domain);
876 (void) mutex_unlock(&default_domain_lock);
877 return (0);
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)
890 return (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;
901 int outvallen, stat;
902 char *domain;
904 if ((domain = __default_domain()) == 0)
905 return (FALSE);
906 *ddn = domain;
907 /* does the map exist ? */
908 in = (char)0xff;
909 stat = yp_match(domain, map, &in, 1, &outval, &outvallen);
910 free(outval);
911 switch (stat) {
913 case 0: /* it actually succeeded! */
914 case YPERR_KEY: /* no such key in map */
915 case YPERR_NOMORE:
916 case YPERR_BUSY:
917 return (TRUE);
919 return (FALSE);
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.
927 CLIENT *
928 __clnt_create_loopback(rpcprog_t prog, rpcvers_t vers, int *err)
930 struct netconfig *nconf;
931 CLIENT *clnt = NULL;
932 void *nc_handle; /* Net config handle */
934 *err = 0;
935 nc_handle = setnetconfig();
936 if (nc_handle == NULL) {
937 /* fails to open netconfig file */
938 rpc_createerr.cf_stat = RPC_FAILED;
939 *err = YPERR_RPC;
940 return (NULL);
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);
948 break;
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;
957 return (clnt);
960 static CLIENT *
961 getclnt(rpcprog_t prog, rpcvers_t vers, struct netconfig *nconf, int *err)
963 int fd;
964 struct netbuf *svcaddr; /* servers address */
965 CLIENT *cl;
966 struct nd_addrlist *nas;
967 struct nd_hostserv rpcbind_hs;
968 struct t_call sndcall;
969 char uaddress[1024]; /* XXX maxlen ?? */
970 RPCB parms;
971 enum clnt_stat clnt_st;
972 char *ua;
973 struct timeval tv = { 30, 0 };
975 if (nconf == NULL) {
976 rpc_createerr.cf_stat = RPC_TLIERROR;
977 *err = YPERR_RPC;
978 return (NULL);
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))) {
988 goto create_client;
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;
1003 *err = YPERR_RPC;
1004 return (NULL);
1006 if ((fd = t_open(nconf->nc_device, O_RDWR, NULL)) == -1) {
1007 rpc_createerr.cf_stat = RPC_TLIERROR;
1008 *err = YPERR_RPC;
1009 return (NULL);
1011 if (t_bind(fd, NULL, NULL) == -1) {
1012 rpc_createerr.cf_stat = RPC_TLIERROR;
1013 *err = YPERR_RPC;
1014 (void) t_close(fd);
1015 return (NULL);
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;
1023 (void) t_close(fd);
1024 *err = YPERR_PMAP;
1025 return (NULL);
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);
1034 if (cl == NULL) {
1035 (void) t_close(fd);
1036 *err = YPERR_PMAP;
1037 return (NULL);
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;
1044 ua = uaddress;
1045 clnt_st = CLNT_CALL(cl, RPCBPROC_GETADDR, xdr_rpcb, (char *)&parms,
1046 xdr_wrapstring, (char *)&ua, tv);
1047 (void) t_close(fd);
1048 clnt_destroy(cl);
1049 if (clnt_st != RPC_SUCCESS) {
1050 *err = YPERR_YPBIND;
1051 return (NULL);
1053 if (strlen(uaddress) == 0) {
1054 *err = YPERR_YPBIND;
1055 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
1056 return (NULL);
1059 create_client:
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);
1064 if (cl == NULL) {
1065 *err = YPERR_YPBIND;
1066 return (NULL);
1069 * The fd should be closed while destroying the handle.
1071 return (cl);
1074 static int
1075 get_cached_transport(struct netconfig *nconf, int vers, char *uaddress,
1076 int ulen)
1078 ssize_t st;
1079 int fd;
1081 (void) snprintf(uaddress, ulen,
1082 "%s/xprt.%s.%d", BINDING, nconf->nc_netid, vers);
1083 fd = open(uaddress, O_RDONLY);
1084 if (fd == -1)
1085 return (0);
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)) {
1090 (void) close(fd);
1091 return (0);
1094 st = read(fd, uaddress, ulen);
1095 if (st == -1) {
1096 (void) close(fd);
1097 return (0);
1100 (void) close(fd);
1101 return (1);
1104 static ypbind_resp *
1105 get_cached_domain(char *domain)
1107 FILE *fp;
1108 int st;
1109 char filename[300];
1110 static ypbind_resp res;
1111 XDR xdrs;
1113 (void) snprintf(filename, sizeof (filename),
1114 "%s/%s/cache_binding", BINDING, domain);
1115 fp = fopen(filename, "rF");
1116 if (fp == 0)
1117 return (0);
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)) {
1122 (void) fclose(fp);
1123 return (0);
1126 xdrstdio_create(&xdrs, fp, XDR_DECODE);
1128 (void) memset((char *)&res, 0, sizeof (res));
1129 st = xdr_ypbind_resp(&xdrs, &res);
1131 xdr_destroy(&xdrs);
1132 (void) fclose(fp);
1134 if (st)
1135 return (&res);
1137 return (0);
1140 static int
1141 ypbind_running(int err, int status)
1143 char filename[300];
1144 int st;
1145 int fd;
1147 (void) snprintf(filename, sizeof (filename), "%s/ypbind.pid", BINDING);
1148 fd = open(filename, O_RDONLY);
1149 if (fd == -1) {
1150 if ((err == YPERR_YPBIND) && (status != RPC_PROGNOTREGISTERED))
1151 return (1);
1152 return (0);
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)) {
1158 (void) close(fd);
1159 return (0);
1162 (void) close(fd);
1163 return (1);
1166 static void
1167 set_rdev(struct dom_binding *pdomb)
1169 int fd;
1170 struct stat stbuf;
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");
1175 pdomb->fd = -1;
1176 return;
1178 pdomb->fd = fd;
1179 pdomb->rdev = stbuf.st_rdev;
1182 static int
1183 check_rdev(struct dom_binding *pdomb)
1185 struct stat stbuf;
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);
1195 return (0);
1197 if (pdomb->rdev != stbuf.st_rdev) {
1198 syslog(LOG_DEBUG,
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);
1203 return (0);
1205 return (1); /* fd is okay */