1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 /*
30 * Portions of this source code were derived from Berkeley
31 * under license from the Regents of the University of
32 * California.
33 */
34 #include "mt.h"
35 #include "../rpc/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>
51
52 #define BFSIZE (YPMAXDOMAIN + 32) /* size of binding file */
53 int __ypipbufsize = 8192; /* size used for clnt_tli_create */
54
55 /* This should match the one in ypbind.c */
56
57 extern int getdomainname(char *, int);
58
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 *);
67
68 static char nullstring[] = "";
69 /*
70 * Time parameters when talking to the ypbind and pmap processes
71 */
72
73 #define YPSLEEPTIME 5 /* Time to sleep between tries */
74 unsigned int _ypsleeptime = YPSLEEPTIME;
75
76 /*
77 * Time parameters when talking to the ypserv process
78 */
79
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
87
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 */
94 };
95
96 static mutex_t default_domain_lock = DEFAULTMUTEX;
97 static char *default_domain;
98
99 /*
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.
116 */
117 static mutex_t bound_domains_lock = DEFAULTMUTEX;
118 static struct dom_binding *bound_domains; /* List of bound domains */
119
120
121 /*
122 * Must be called with bound_domains_lock held or with a dom_binding
123 * that cannot be referenced by another thread.
124 */
125 void
free_dom_binding(struct dom_binding * p)126 free_dom_binding(struct dom_binding *p)
127 {
128 if (p->ref_count != 0) {
129 p->need_free = 1;
130 return;
131 }
132 (void) check_rdev(p);
133 clnt_destroy(p->dom_client);
134 free(p->dom_domain);
135 free(p);
136 }
137
138 /*
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.
143 *
144 * yp_unbind is MT-safe because it serializes on bound_domains_lock.
145 */
146
147 static void
__yp_unbind_nolock(char * domain)148 __yp_unbind_nolock(char *domain)
149 {
150 struct dom_binding *p;
151 struct dom_binding **prev;
152
153 if ((domain == NULL) || (strlen(domain) == 0)) {
154 return;
155 }
156
157 /*
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.
163 *
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.
168 */
169 for (prev = &bound_domains; (p = *prev) != 0; prev = &p->dom_pnext) {
170
171 if (strcmp(domain, p->dom_domain) == 0) {
172 if (!p->cache_bad) {
173 p->cache_bad = 1;
174 break;
175 }
176 *prev = p->dom_pnext;
177 free_dom_binding(p);
178 break;
179 }
180
181 }
182 }
183
184
185 void
yp_unbind(char * domain)186 yp_unbind(char *domain)
187 {
188 (void) mutex_lock(&bound_domains_lock);
189 __yp_unbind_nolock(domain);
190 (void) mutex_unlock(&bound_domains_lock);
191 }
192
193
194 /*
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.
197 *
198 * MT-safe because it is only invoked from __yp_dobind(), which serializes
199 * all requests.
200 */
201 static void
newborn(void)202 newborn(void)
203 {
204 static pid_t mypid; /* Cached to detect forks */
205 pid_t testpid;
206 struct dom_binding *p, *q;
207
208 if ((testpid = getpid()) != mypid) {
209
210 mypid = testpid;
211
212 for (p = bound_domains; p != 0; p = q) {
213 q = p->dom_pnext;
214 free_dom_binding(p);
215 }
216 bound_domains = 0;
217 }
218 }
219
220 /*
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.
227 *
228 * MT-safe because it is only invoked from __yp_dobind(), which serializes
229 * all requests.
230 */
231 static bool
check_binding(char * domain,struct dom_binding ** binding)232 check_binding(char *domain, struct dom_binding **binding)
233 {
234 struct dom_binding *pdomb;
235 struct ypbind_resp *ypbind_resp;
236 int status;
237
238 for (pdomb = bound_domains; pdomb != NULL; pdomb = pdomb->dom_pnext) {
239
240 if (strcmp(domain, pdomb->dom_domain) == 0) {
241 /*
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.
248 */
249
250 *binding = pdomb;
251 return (TRUE);
252 }
253 }
254
255 /*
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.
259 */
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);
266 }
267 return (FALSE);
268 }
269
270 /*
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.
277 */
278
279 #define SOCKADDR_SIZE (sizeof (struct sockaddr_in6))
280 static int
__yp_add_binding_netid(char * domain,char * addr,char * netid)281 __yp_add_binding_netid(char *domain, char *addr, char *netid)
282 {
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;
289
290 nconf = getnetconfigent(netid);
291 if (nconf == 0)
292 goto err;
293
294 svcaddr = malloc(sizeof (struct netbuf));
295 if (svcaddr == 0)
296 goto err;
297
298 svcaddr->maxlen = SOCKADDR_SIZE;
299 svcaddr->buf = malloc(SOCKADDR_SIZE);
300 if (svcaddr->buf == 0)
301 goto err;
302
303 if (!rpcb_getaddr(YPPROG, YPVERS, nconf, svcaddr, addr))
304 goto err;
305
306 binding = malloc(sizeof (struct ypbind_binding));
307 if (binding == 0)
308 goto err;
309
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;
317
318 resp.ypbind_status = YPBIND_SUCC_VAL;
319 resp.ypbind_resp_u.ypbind_bindinfo = binding;
320
321 (void) mutex_lock(&bound_domains_lock);
322 newborn();
323 pdomb = load_dom_binding(&resp, domain, &status);
324 (void) mutex_unlock(&bound_domains_lock);
325
326 return (pdomb != 0);
327
328 err:
329 if (nconf)
330 freenetconfigent(nconf);
331 if (svcaddr) {
332 if (svcaddr->buf)
333 free(svcaddr->buf);
334 free(svcaddr);
335 }
336 if (binding) {
337 if (binding->ypbind_servername)
338 free(binding->ypbind_servername);
339 free(binding);
340 }
341 return (0);
342 }
343
344
345 int
__yp_add_binding(char * domain,char * addr)346 __yp_add_binding(char *domain, char *addr) {
347
348 int ret = __yp_add_binding_netid(domain, addr, "udp6");
349
350 if (ret == 0)
351 ret = __yp_add_binding_netid(domain, addr, "udp");
352
353 return (ret);
354 }
355
356
357 /*
358 * This allocates some memory for a domain binding, initialize it, and
359 * returns a pointer to it. Based on the program version we ended up
360 * talking to ypbind with, fill out an opvector of appropriate protocol
361 * modules.
362 *
363 * MT-safe because it is only invoked from __yp_dobind(), which serializes
364 * all requests.
365 */
366 static struct dom_binding *
load_dom_binding(struct ypbind_resp * ypbind_res,char * domain,int * err)367 load_dom_binding(struct ypbind_resp *ypbind_res, char *domain, int *err)
368 {
369 int fd;
370 struct dom_binding *pdomb;
371
372 pdomb = NULL;
373
374 if ((pdomb = malloc(sizeof (struct dom_binding))) == NULL) {
375 syslog(LOG_ERR, "load_dom_binding: malloc failure.");
376 *err = YPERR_RESRC;
377 return (NULL);
378 }
379
380 pdomb->dom_binding = ypbind_res->ypbind_resp_u.ypbind_bindinfo;
381 /*
382 * Open up a path to the server, which will remain active globally.
383 */
384 pdomb->dom_client = clnt_tli_create(RPC_ANYFD,
385 pdomb->dom_binding->ypbind_nconf,
386 pdomb->dom_binding->ypbind_svcaddr,
387 YPPROG, YPVERS, __ypipbufsize,
388 __ypipbufsize);
389 if (pdomb->dom_client == NULL) {
390 clnt_pcreateerror("yp_bind: clnt_tli_create");
391 free(pdomb);
392 *err = YPERR_RPC;
393 return (NULL);
394 }
395 #ifdef DEBUG
396 (void) printf("yp_bind: clnt_tli_create suceeded\n");
397 #endif
398
399 pdomb->dom_pnext = bound_domains; /* Link this to the list as */
400 pdomb->dom_domain = malloc(strlen(domain) + (unsigned)1);
401 if (pdomb->dom_domain == NULL) {
402 clnt_destroy(pdomb->dom_client);
403 free(pdomb);
404 *err = YPERR_RESRC;
405 return (NULL);
406 }
407 /*
408 * We may not have loaded from a cache file, but we assume the
409 * cache is good until we find out otherwise.
410 */
411 pdomb->cache_bad = 0;
412 set_rdev(pdomb);
413 if (clnt_control(pdomb->dom_client, CLGET_FD, (char *)&fd))
414 (void) fcntl(fd, F_SETFD, 1); /* make it "close on exec" */
415
416 (void) strcpy(pdomb->dom_domain, domain); /* Remember the domain name */
417 pdomb->ref_count = 0;
418 pdomb->need_free = 0;
419 (void) mutex_init(&pdomb->server_name_lock, USYNC_THREAD, 0);
420 bound_domains = pdomb; /* ... the head entry */
421 return (pdomb);
422 }
423
424 /*
425 * XXX special code for handling C2 (passwd.adjunct) lookups when we need
426 * a reserved port.
427 */
428 static int
tli_open_rsvdport(struct netconfig * nconf)429 tli_open_rsvdport(struct netconfig *nconf)
430 {
431 int fd;
432
433 if (nconf == NULL)
434 return (-1);
435
436 fd = t_open(nconf->nc_device, O_RDWR, NULL);
437 if (fd == -1)
438 return (-1);
439
440 if (netdir_options(nconf, ND_SET_RESERVEDPORT, fd, NULL) == -1) {
441 if (t_bind(fd, NULL, NULL) == -1) {
442 (void) t_close(fd);
443 return (-1);
444 }
445 }
446 return (fd);
447 }
448
449 /*
450 * This allocates some memory for a domain binding, initialize it, and
451 * returns a pointer to it. Based on the program version we ended up
452 * talking to ypbind with, fill out an opvector of appropriate protocol
453 * modules.
454 *
455 * MT-safe because it is only invoked from __yp_dobind(), which serializes
456 * all requests.
457 *
458 * XXX special version for handling C2 (passwd.adjunct) lookups when we need
459 * a reserved port.
460 *
461 * Note that the binding is not cached. The caller has to free the binding
462 * using free_dom_binding().
463 */
464 static struct dom_binding *
load_dom_binding_rsvdport(struct ypbind_binding * dom_binding,char * domain,int * err)465 load_dom_binding_rsvdport(struct ypbind_binding *dom_binding, char *domain,
466 int *err)
467 {
468 struct dom_binding *pdomb;
469 int fd;
470
471 pdomb = NULL;
472
473 if ((pdomb = malloc(sizeof (struct dom_binding))) == NULL) {
474 syslog(LOG_ERR, "load_dom_binding_rsvdport: malloc failure.");
475 *err = YPERR_RESRC;
476 return (NULL);
477 }
478
479 pdomb->dom_binding = dom_binding;
480 /*
481 * Open up a path to the server, which will remain active globally.
482 */
483 fd = tli_open_rsvdport(pdomb->dom_binding->ypbind_nconf);
484 if (fd < 0) {
485 clnt_pcreateerror("yp_bind: tli_open_rsvdport");
486 free(pdomb);
487 *err = YPERR_RPC;
488 return (NULL);
489 }
490 pdomb->dom_client = clnt_tli_create(fd,
491 pdomb->dom_binding->ypbind_nconf,
492 pdomb->dom_binding->ypbind_svcaddr,
493 YPPROG, YPVERS, __ypipbufsize,
494 __ypipbufsize);
495 if (pdomb->dom_client == NULL) {
496 clnt_pcreateerror("yp_bind: clnt_tli_create");
497 free(pdomb);
498 *err = YPERR_RPC;
499 return (NULL);
500 }
501 #ifdef DEBUG
502 (void) printf("yp_bind: clnt_tli_create suceeded\n");
503 #endif
504 (void) CLNT_CONTROL(pdomb->dom_client, CLSET_FD_CLOSE, NULL);
505
506 pdomb->dom_domain = malloc(strlen(domain) + (unsigned)1);
507 if (pdomb->dom_domain == NULL) {
508 clnt_destroy(pdomb->dom_client);
509 free(pdomb);
510 *err = YPERR_RESRC;
511 return (NULL);
512 }
513
514 (void) strcpy(pdomb->dom_domain, domain); /* Remember the domain name */
515 pdomb->ref_count = 0;
516 pdomb->need_free = 0;
517 set_rdev(pdomb);
518 (void) mutex_init(&pdomb->server_name_lock, USYNC_THREAD, 0);
519 return (pdomb);
520 }
521
522 /*
523 * Attempts to locate a yellow pages server that serves a passed domain. If
524 * one is found, an entry is created on the static list of domain-server pairs
525 * pointed to by cell bound_domains, a udp path to the server is created and
526 * the function returns 0. Otherwise, the function returns a defined errorcode
527 * YPERR_xxxx.
528 *
529 * MT-safe because it serializes on bound_domains_lock.
530 *
531 * If hardlookup is set then loop forever until success, else try 4
532 * times (each try is relatively short) max.
533 */
534 int
__yp_dobind_cflookup(char * domain,struct dom_binding ** binding,int hardlookup)535 __yp_dobind_cflookup(
536 char *domain,
537 struct dom_binding **binding, /* if result==0, ptr to dom_binding */
538 int hardlookup)
539
540 {
541 struct dom_binding *pdomb; /* Ptr to new domain binding */
542 struct ypbind_resp *ypbind_resp; /* Response from local ypbinder */
543 struct ypbind_domain ypbd;
544 int status, err = YPERR_DOMAIN;
545 int first_try = 1;
546 CLIENT *tb = NULL;
547
548 if ((domain == NULL) ||(strlen(domain) == 0))
549 return (YPERR_BADARGS);
550
551 (void) mutex_lock(&bound_domains_lock);
552 /*
553 * ===>
554 * If someone managed to fork() while we were holding this lock,
555 * we'll probably end up hanging on the lock. Tant pis.
556 */
557 newborn();
558
559 if (check_binding(domain, binding)) {
560 /*
561 * If the cache is okay and if the underlying file
562 * descriptor is okay (application did not close it).
563 * then use the binding.
564 */
565 if (!(*binding)->cache_bad && check_rdev(*binding)) {
566 (*binding)->ref_count += 1;
567 (void) mutex_unlock(&bound_domains_lock);
568 return (0); /* We are bound */
569 }
570
571 /*
572 * If we get here, one of two things happened: the
573 * cache is bad, or the underlying file descriptor
574 * had changed.
575 *
576 * If the cache is bad, then we call yp_unbind to remove
577 * the binding.
578 *
579 * If the file descriptor has changed, then we call
580 * yp_unbind to remove the binding (we set cache_bad
581 * to force yp_unbind to do the remove), and then
582 * call check_binding to reload the binding from the
583 * cache again.
584 */
585 if ((*binding)->cache_bad) {
586 __yp_unbind_nolock(domain);
587 } else {
588 (*binding)->cache_bad = 1;
589 (void) mutex_unlock(&bound_domains_lock);
590 yp_unbind(domain);
591 (void) mutex_lock(&bound_domains_lock);
592 if (check_binding(domain, binding)) {
593 (*binding)->ref_count += 1;
594 (void) mutex_unlock(&bound_domains_lock);
595 return (0);
596 }
597 }
598 }
599
600 do {
601 if (first_try)
602 first_try = 0;
603 else {
604 /*
605 * ===> sleep() -- Ugh. And with the lock held, too.
606 */
607 (void) sleep(_ypsleeptime);
608 }
609 tb = __clnt_create_loopback(YPBINDPROG, YPBINDVERS, &err);
610 if (tb == NULL) {
611 if (ypbind_running(err, rpc_createerr.cf_stat))
612 continue;
613 break;
614 }
615 ypbd.ypbind_domainname = domain;
616 ypbd.ypbind_vers = YPVERS;
617 /*
618 * The interface to ypbindproc_domain_3 is MT-unsafe, but we're
619 * OK as long as we're the only ones who call it and we
620 * serialize all requests (for all domains). Otherwise,
621 * change the interface (pass in the ypbind_resp struct).
622 */
623 ypbind_resp = ypbindproc_domain_3(&ypbd, tb);
624 /*
625 * Although we talk to ypbind on loopback,
626 * it gives us a udp address for the ypserv.
627 */
628 if (ypbind_resp == NULL) {
629 /* lost ypbind? */
630 clnt_perror(tb,
631 "ypbindproc_domain_3: can't contact ypbind");
632 clnt_destroy(tb);
633 tb = NULL;
634 continue;
635 }
636 if (ypbind_resp->ypbind_status == YPBIND_SUCC_VAL) {
637 /*
638 * Local ypbind has let us in on the ypserv's address,
639 * go get in touch with it !
640 */
641 pdomb = load_dom_binding(ypbind_resp, domain, &status);
642 if (pdomb == 0) {
643 err = status;
644 clnt_destroy(tb);
645 tb = NULL;
646 continue;
647 }
648 clnt_destroy(tb);
649 pdomb->ref_count += 1;
650 (void) mutex_unlock(&bound_domains_lock);
651 *binding = pdomb; /* Return ptr to the binding entry */
652 return (0); /* This is the go path */
653 }
654 if (ypbind_resp->ypbind_resp_u.ypbind_error ==
655 YPBIND_ERR_NOSERV)
656 err = YPERR_DOMAIN;
657 else
658 err = YPERR_YPBIND;
659 clnt_destroy(tb);
660 tb = NULL;
661 } while (hardlookup);
662
663 if (tb != NULL)
664 clnt_destroy(tb);
665 (void) mutex_unlock(&bound_domains_lock);
666 if (err)
667 return (err);
668 return (YPERR_DOMAIN);
669 }
670
671 int
__yp_dobind(char * domain,struct dom_binding ** binding)672 __yp_dobind(
673 char *domain,
674 struct dom_binding **binding) /* if result == 0, ptr to dom_binding */
675 {
676 /* traditional __yp_dobind loops forever so set hardlookup */
677 return (__yp_dobind_cflookup(domain, binding, 1));
678 }
679
680 void
__yp_rel_binding(struct dom_binding * binding)681 __yp_rel_binding(struct dom_binding *binding)
682 {
683 (void) mutex_lock(&bound_domains_lock);
684 binding->ref_count -= 1;
685 if (binding->need_free && binding->ref_count == 0)
686 free_dom_binding(binding);
687 (void) mutex_unlock(&bound_domains_lock);
688 }
689
690 /*
691 * Attempts to locate a yellow pages server that serves a passed domain. If
692 * one is found, an entry is created on the static list of domain-server pairs
693 * pointed to by cell bound_domains, a udp path to the server is created and
694 * the function returns 0. Otherwise, the function returns a defined errorcode
695 * YPERR_xxxx.
696 *
697 * MT-safe because it serializes on bound_domains_lock.
698 *
699 * XXX special version for handling C2 (passwd.adjunct) lookups when we need
700 * a reserved port.
701 * This returns an uncached binding which the caller has to free using
702 * free_dom_binding().
703 */
704 int
__yp_dobind_rsvdport_cflookup(char * domain,struct dom_binding ** binding,int hardlookup)705 __yp_dobind_rsvdport_cflookup(
706 char *domain,
707 struct dom_binding **binding, /* if result==0, ptr to dom_binding */
708 int hardlookup)
709 {
710 struct dom_binding *pdomb; /* Ptr to new domain binding */
711 struct ypbind_resp *ypbind_resp; /* Response from local ypbinder */
712 struct ypbind_domain ypbd;
713 int status, err = YPERR_DOMAIN;
714 int first_try = 1;
715 CLIENT *tb = NULL;
716
717 if ((domain == NULL) ||(strlen(domain) == 0))
718 return (YPERR_BADARGS);
719
720 (void) mutex_lock(&bound_domains_lock);
721 /*
722 * ===>
723 * If someone managed to fork() while we were holding this lock,
724 * we'll probably end up hanging on the lock. Tant pis.
725 */
726 newborn();
727
728 /*
729 * Check for existing bindings and use the information in the binding
730 * to create a transport endpoint with a reserved port.
731 */
732 if (check_binding(domain, binding)) {
733 /*
734 * If the cache is bad, yp_unbind() the entry again and then
735 * talk to ypbind.
736 */
737 if ((*binding)->cache_bad) {
738 __yp_unbind_nolock(domain);
739 } else {
740 pdomb = load_dom_binding_rsvdport(
741 (*binding)->dom_binding,
742 domain, &status);
743 if (pdomb == 0) {
744 (void) mutex_unlock(&bound_domains_lock);
745 return (status);
746 }
747 pdomb->ref_count += 1;
748 (void) mutex_unlock(&bound_domains_lock);
749 *binding = pdomb; /* Return ptr to the binding entry */
750 return (0);
751 }
752 }
753
754 do {
755 if (first_try)
756 first_try = 0;
757 else {
758 /*
759 * ===> sleep() -- Ugh. And with the lock held, too.
760 */
761 (void) sleep(_ypsleeptime);
762 }
763 tb = __clnt_create_loopback(YPBINDPROG, YPBINDVERS, &err);
764 if (tb == NULL) {
765 if (ypbind_running(err, rpc_createerr.cf_stat))
766 continue;
767 break;
768 }
769 ypbd.ypbind_domainname = domain;
770 ypbd.ypbind_vers = YPVERS;
771 /*
772 * The interface to ypbindproc_domain_3 is MT-unsafe, but we're
773 * OK as long as we're the only ones who call it and we
774 * serialize all requests (for all domains). Otherwise,
775 * change the interface (pass in the ypbind_resp struct).
776 */
777 ypbind_resp = ypbindproc_domain_3(&ypbd, tb);
778 /*
779 * Although we talk to ypbind on loopback,
780 * it gives us a udp address for the ypserv.
781 */
782 if (ypbind_resp == NULL) {
783 /* lost ypbind? */
784 clnt_perror(tb,
785 "ypbindproc_domain_3: can't contact ypbind");
786 clnt_destroy(tb);
787 tb = NULL;
788 continue;
789 }
790 if (ypbind_resp->ypbind_status == YPBIND_SUCC_VAL) {
791 /*
792 * Local ypbind has let us in on the ypserv's address,
793 * go get in touch with it !
794 */
795 pdomb = load_dom_binding_rsvdport(
796 ypbind_resp->ypbind_resp_u.ypbind_bindinfo,
797 domain, &status);
798 if (pdomb == 0) {
799 err = status;
800 clnt_destroy(tb);
801 tb = NULL;
802 continue;
803 }
804 clnt_destroy(tb);
805 pdomb->ref_count += 1;
806 (void) mutex_unlock(&bound_domains_lock);
807 *binding = pdomb; /* Return ptr to the binding entry */
808 return (0); /* This is the go path */
809 }
810 if (ypbind_resp->ypbind_resp_u.ypbind_error ==
811 YPBIND_ERR_NOSERV)
812 err = YPERR_DOMAIN;
813 else
814 err = YPERR_YPBIND;
815 clnt_destroy(tb);
816 tb = NULL;
817 } while (hardlookup);
818
819 if (tb != NULL)
820 clnt_destroy(tb);
821 (void) mutex_unlock(&bound_domains_lock);
822 if (err)
823 return (err);
824 return (YPERR_DOMAIN);
825 }
826
827 int
__yp_dobind_rsvdport(char * domain,struct dom_binding ** binding)828 __yp_dobind_rsvdport(
829 char *domain,
830 struct dom_binding **binding) /* if result==0, ptr to dom_binding */
831 {
832 /* traditional __yp_dobind_rsvdport loops forever so set hardlookup */
833 return (__yp_dobind_rsvdport_cflookup(domain, binding, 1));
834 }
835
836 /*
837 * This is a "wrapper" function for __yp_dobind for vanilla user-level
838 * functions which neither know nor care about struct dom_bindings.
839 */
840 int
yp_bind(char * domain)841 yp_bind(char *domain)
842 {
843
844 struct dom_binding *binding;
845 int res;
846
847 res = __yp_dobind(domain, &binding);
848 if (res == 0)
849 __yp_rel_binding(binding);
850 return (res);
851 }
852
853 static char *
__default_domain(void)854 __default_domain(void)
855 {
856 char temp[256];
857
858 (void) mutex_lock(&default_domain_lock);
859
860 if (default_domain) {
861 (void) mutex_unlock(&default_domain_lock);
862 return (default_domain);
863 }
864 if (getdomainname(temp, sizeof (temp)) < 0) {
865 (void) mutex_unlock(&default_domain_lock);
866 return (0);
867 }
868 if (strlen(temp) > 0) {
869 default_domain = malloc((strlen(temp) + 1));
870 if (default_domain == 0) {
871 (void) mutex_unlock(&default_domain_lock);
872 return (0);
873 }
874 (void) strcpy(default_domain, temp);
875 (void) mutex_unlock(&default_domain_lock);
876 return (default_domain);
877 }
878 (void) mutex_unlock(&default_domain_lock);
879 return (0);
880 }
881
882 /*
883 * This is a wrapper for the system call getdomainname which returns a
884 * ypclnt.h error code in the failure case. It also checks to see that
885 * the domain name is non-null, knowing that the null string is going to
886 * get rejected elsewhere in the yp client package.
887 */
888 int
yp_get_default_domain(char ** domain)889 yp_get_default_domain(char **domain)
890 {
891 if ((*domain = __default_domain()) != 0)
892 return (0);
893 return (YPERR_YPERR);
894 }
895
896 /*
897 * ===> Nobody uses this, do they? Can we nuke it?
898 */
899 int
usingypmap(char ** ddn,char * map)900 usingypmap(char **ddn, char *map)
901 {
902 char in, *outval = NULL;
903 int outvallen, stat;
904 char *domain;
905
906 if ((domain = __default_domain()) == 0)
907 return (FALSE);
908 *ddn = domain;
909 /* does the map exist ? */
910 in = (char)0xff;
911 stat = yp_match(domain, map, &in, 1, &outval, &outvallen);
912 if (outval != NULL)
913 free(outval);
914 switch (stat) {
915
916 case 0: /* it actually succeeded! */
917 case YPERR_KEY: /* no such key in map */
918 case YPERR_NOMORE:
919 case YPERR_BUSY:
920 return (TRUE);
921 }
922 return (FALSE);
923 }
924
925 /*
926 * Creates a quick connection on a connection oriented loopback
927 * transport. Fails quickly without timeout. Only naming service
928 * it goes to is straddr.so.
929 */
930 CLIENT *
__clnt_create_loopback(rpcprog_t prog,rpcvers_t vers,int * err)931 __clnt_create_loopback(rpcprog_t prog, rpcvers_t vers, int *err)
932 {
933 struct netconfig *nconf;
934 CLIENT *clnt = NULL;
935 void *nc_handle; /* Net config handle */
936
937 *err = 0;
938 nc_handle = setnetconfig();
939 if (nc_handle == NULL) {
940 /* fails to open netconfig file */
941 rpc_createerr.cf_stat = RPC_FAILED;
942 *err = YPERR_RPC;
943 return (NULL);
944 }
945 while (nconf = getnetconfig(nc_handle))
946 /* Try only one connection oriented loopback transport */
947 if ((strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) &&
948 ((nconf->nc_semantics == NC_TPI_COTS) ||
949 (nconf->nc_semantics == NC_TPI_COTS_ORD))) {
950 clnt = getclnt(prog, vers, nconf, err);
951 break;
952 }
953 (void) endnetconfig(nc_handle);
954
955 if (clnt == NULL) { /* no loopback transport available */
956 if (rpc_createerr.cf_stat == 0)
957 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
958 if (*err == 0) *err = YPERR_RPC;
959 }
960 return (clnt);
961 }
962
963 static CLIENT *
getclnt(rpcprog_t prog,rpcvers_t vers,struct netconfig * nconf,int * err)964 getclnt(rpcprog_t prog, rpcvers_t vers, struct netconfig *nconf, int *err)
965 {
966 int fd;
967 struct netbuf *svcaddr; /* servers address */
968 CLIENT *cl;
969 struct nd_addrlist *nas;
970 struct nd_hostserv rpcbind_hs;
971 struct t_call sndcall;
972 char uaddress[1024]; /* XXX maxlen ?? */
973 RPCB parms;
974 enum clnt_stat clnt_st;
975 char *ua;
976 struct timeval tv = { 30, 0 };
977
978 if (nconf == NULL) {
979 rpc_createerr.cf_stat = RPC_TLIERROR;
980 *err = YPERR_RPC;
981 return (NULL);
982 }
983
984 /*
985 * The ypbind process might cache its transport address.
986 * If we can get at it, then we will use it and avoid
987 * wasting time talking to rpcbind.
988 */
989
990 if (get_cached_transport(nconf, vers, uaddress, sizeof (uaddress))) {
991 goto create_client;
992 }
993
994 /*
995 * Check to see if local rpcbind is up or not. If it
996 * isn't, it is best that the application should realize
997 * yp is not up and take a remedial action. This is to
998 * avoid the minute long timeout incurred by rpcbind_getaddr.
999 * Looks like the only way to accomplish this it is to unfold
1000 * rpcb_getaddr and make a few changes. Alas !
1001 */
1002 rpcbind_hs.h_host = HOST_SELF_CONNECT;
1003 rpcbind_hs.h_serv = "rpcbind";
1004 if (netdir_getbyname(nconf, &rpcbind_hs, &nas) != ND_OK) {
1005 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
1006 *err = YPERR_RPC;
1007 return (NULL);
1008 }
1009 if ((fd = t_open(nconf->nc_device, O_RDWR, NULL)) == -1) {
1010 rpc_createerr.cf_stat = RPC_TLIERROR;
1011 *err = YPERR_RPC;
1012 return (NULL);
1013 }
1014 if (t_bind(fd, NULL, NULL) == -1) {
1015 rpc_createerr.cf_stat = RPC_TLIERROR;
1016 *err = YPERR_RPC;
1017 (void) t_close(fd);
1018 return (NULL);
1019 }
1020 sndcall.addr = *(nas->n_addrs);
1021 sndcall.opt.len = 0;
1022 sndcall.udata.len = 0;
1023 if (t_connect(fd, &sndcall, NULL) == -1) {
1024 netdir_free((char *)nas, ND_ADDRLIST);
1025 rpc_createerr.cf_stat = RPC_TLIERROR;
1026 (void) t_close(fd);
1027 *err = YPERR_PMAP;
1028 return (NULL);
1029 }
1030
1031 /*
1032 * Get the address of the server
1033 */
1034 cl = clnt_tli_create(fd, nconf, nas->n_addrs,
1035 RPCBPROG, RPCBVERS, __ypipbufsize, __ypipbufsize);
1036 netdir_free((char *)nas, ND_ADDRLIST);
1037 if (cl == NULL) {
1038 (void) t_close(fd);
1039 *err = YPERR_PMAP;
1040 return (NULL);
1041 }
1042 parms.r_prog = prog;
1043 parms.r_vers = vers;
1044 parms.r_netid = nconf->nc_netid;
1045 parms.r_addr = nullstring;
1046 parms.r_owner = nullstring;
1047 ua = uaddress;
1048 clnt_st = CLNT_CALL(cl, RPCBPROC_GETADDR, xdr_rpcb, (char *)&parms,
1049 xdr_wrapstring, (char *)&ua, tv);
1050 (void) t_close(fd);
1051 clnt_destroy(cl);
1052 if (clnt_st != RPC_SUCCESS) {
1053 *err = YPERR_YPBIND;
1054 return (NULL);
1055 }
1056 if (strlen(uaddress) == 0) {
1057 *err = YPERR_YPBIND;
1058 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
1059 return (NULL);
1060 }
1061
1062 create_client:
1063 svcaddr = uaddr2taddr(nconf, uaddress);
1064 cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr, prog, vers,
1065 __ypipbufsize, __ypipbufsize);
1066 netdir_free((char *)svcaddr, ND_ADDR);
1067 if (cl == NULL) {
1068 *err = YPERR_YPBIND;
1069 return (NULL);
1070 }
1071 /*
1072 * The fd should be closed while destroying the handle.
1073 */
1074 return (cl);
1075 }
1076
1077 static int
get_cached_transport(struct netconfig * nconf,int vers,char * uaddress,int ulen)1078 get_cached_transport(struct netconfig *nconf, int vers, char *uaddress,
1079 int ulen)
1080 {
1081 ssize_t st;
1082 int fd;
1083
1084 (void) snprintf(uaddress, ulen,
1085 "%s/xprt.%s.%d", BINDING, nconf->nc_netid, vers);
1086 fd = open(uaddress, O_RDONLY);
1087 if (fd == -1)
1088 return (0);
1089
1090 /* if first byte is not locked, then ypbind must not be running */
1091 st = lockf(fd, F_TEST, 1);
1092 if (st != -1 || (errno != EAGAIN && errno != EACCES)) {
1093 (void) close(fd);
1094 return (0);
1095 }
1096
1097 st = read(fd, uaddress, ulen);
1098 if (st == -1) {
1099 (void) close(fd);
1100 return (0);
1101 }
1102
1103 (void) close(fd);
1104 return (1);
1105 }
1106
1107 static ypbind_resp *
get_cached_domain(char * domain)1108 get_cached_domain(char *domain)
1109 {
1110 FILE *fp;
1111 int st;
1112 char filename[300];
1113 static ypbind_resp res;
1114 XDR xdrs;
1115
1116 (void) snprintf(filename, sizeof (filename),
1117 "%s/%s/cache_binding", BINDING, domain);
1118 fp = fopen(filename, "rF");
1119 if (fp == 0)
1120 return (0);
1121
1122 /* if first byte is not locked, then ypbind must not be running */
1123 st = lockf(fileno(fp), F_TEST, 1);
1124 if (st != -1 || (errno != EAGAIN && errno != EACCES)) {
1125 (void) fclose(fp);
1126 return (0);
1127 }
1128
1129 xdrstdio_create(&xdrs, fp, XDR_DECODE);
1130
1131 (void) memset((char *)&res, 0, sizeof (res));
1132 st = xdr_ypbind_resp(&xdrs, &res);
1133
1134 xdr_destroy(&xdrs);
1135 (void) fclose(fp);
1136
1137 if (st)
1138 return (&res);
1139
1140 return (0);
1141 }
1142
1143 static int
ypbind_running(int err,int status)1144 ypbind_running(int err, int status)
1145 {
1146 char filename[300];
1147 int st;
1148 int fd;
1149
1150 (void) snprintf(filename, sizeof (filename), "%s/ypbind.pid", BINDING);
1151 fd = open(filename, O_RDONLY);
1152 if (fd == -1) {
1153 if ((err == YPERR_YPBIND) && (status != RPC_PROGNOTREGISTERED))
1154 return (1);
1155 return (0);
1156 }
1157
1158 /* if first byte is not locked, then ypbind must not be running */
1159 st = lockf(fd, F_TEST, 1);
1160 if (st != -1 || (errno != EAGAIN && errno != EACCES)) {
1161 (void) close(fd);
1162 return (0);
1163 }
1164
1165 (void) close(fd);
1166 return (1);
1167 }
1168
1169 static void
set_rdev(struct dom_binding * pdomb)1170 set_rdev(struct dom_binding *pdomb)
1171 {
1172 int fd;
1173 struct stat stbuf;
1174
1175 if (clnt_control(pdomb->dom_client, CLGET_FD, (char *)&fd) != TRUE ||
1176 fstat(fd, &stbuf) == -1) {
1177 syslog(LOG_DEBUG, "ypbind client: can't get rdev");
1178 pdomb->fd = -1;
1179 return;
1180 }
1181 pdomb->fd = fd;
1182 pdomb->rdev = stbuf.st_rdev;
1183 }
1184
1185 static int
check_rdev(struct dom_binding * pdomb)1186 check_rdev(struct dom_binding *pdomb)
1187 {
1188 struct stat stbuf;
1189
1190 if (pdomb->fd == -1)
1191 return (1); /* can't check it, assume it is okay */
1192
1193 if (fstat(pdomb->fd, &stbuf) == -1) {
1194 syslog(LOG_DEBUG, "yp_bind client: can't stat %d", pdomb->fd);
1195 /* could be because file descriptor was closed */
1196 /* it's not our file descriptor, so don't try to close it */
1197 clnt_control(pdomb->dom_client, CLSET_FD_NCLOSE, NULL);
1198 return (0);
1199 }
1200 if (pdomb->rdev != stbuf.st_rdev) {
1201 syslog(LOG_DEBUG,
1202 "yp_bind client: fd %d changed, old=0x%x, new=0x%x",
1203 pdomb->fd, pdomb->rdev, stbuf.st_rdev);
1204 /* it's not our file descriptor, so don't try to close it */
1205 clnt_control(pdomb->dom_client, CLSET_FD_NCLOSE, NULL);
1206 return (0);
1207 }
1208 return (1); /* fd is okay */
1209 }
1210