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