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