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 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 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 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 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 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 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 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 * 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 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 * 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 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 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 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 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 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 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 * 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 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 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 * 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 * 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 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 * 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 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 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 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