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