1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 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 "ypsym.h" 39 #include <stdlib.h> 40 #include "yp_b.h" 41 #include <string.h> 42 #include <limits.h> 43 #include <netconfig.h> 44 #include <netdir.h> 45 #include <rpc/clnt.h> 46 #include <syslog.h> 47 #include <sys/time.h> 48 #include <unistd.h> 49 #include <netinet/in.h> 50 #include <sys/statvfs.h> 51 #include <rpcsvc/nis.h> 52 #include <sys/systeminfo.h> 53 54 #ifndef NULL 55 #define NULL 0 56 #endif 57 58 #define YPSERVERS "ypservers" 59 60 void ypbind_init_default(); 61 static int ypbind_pipe_setdom(); 62 63 static bool firsttime = TRUE; 64 static struct domain *known_domains; 65 66 extern struct netconfig *__rpc_getconf(); 67 extern void *__rpc_setconf(), *__rpc_endconf(); 68 extern CLIENT *__clnt_tp_create_bootstrap(); 69 extern char *inet_ntoa(); 70 extern int __rpc_get_local_uid(); 71 72 extern listofnames *names(); 73 extern void free_listofnames(); 74 75 #define PINGTIME 10 /* Timeout for the ypservers list */ 76 #define PINGTOTTIM 5 /* Total seconds for ping timeout */ 77 78 static void broadcast_setup(); 79 static void sigcld_handler(); 80 static struct ypbind_binding *dup_ypbind_binding(); 81 static struct netbuf *dup_netbuf(); 82 static void free_ypbind_binding(); 83 static void enable_exit(); 84 static void ypbind_ping(); 85 static struct domain *ypbind_point_to_domain(); 86 static bool ypbind_broadcast_ack(); 87 static int pong_servers(); 88 void cache_binding(); 89 void uncache_binding(); 90 91 extern int setok; 92 extern int broadcast; 93 extern int cache_okay; 94 95 /* 96 * Need to differentiate between RPC_UNKNOWNHOST returned by the RPC 97 * library, and the same error caused by a local lookup failure in 98 * /etc/hosts and/or /etc/inet/ipnodes. 99 */ 100 int hostNotKnownLocally; 101 102 /*ARGSUSED*/ 103 void * 104 ypbindproc_null_3(argp, clnt) 105 void *argp; 106 CLIENT *clnt; 107 { 108 static char res; 109 110 return ((void *) & res); 111 } 112 113 static void 114 enable_exit() 115 { 116 static bool done = FALSE; 117 118 if (!done) { 119 done = TRUE; 120 sigset(SIGCHLD, (void (*)())sigcld_handler); 121 } 122 } 123 124 int sigcld_event = 0; 125 126 static void 127 sigcld_handler() 128 { 129 sigcld_event++; 130 #ifdef DEBUG 131 fprintf(stderr, "ypbind sighandler: got SIGCLD signal (event=%d)\n", 132 sigcld_event); 133 #endif 134 } 135 136 137 /* 138 * This is a Unix SIGCHILD handler that notices when a broadcaster child 139 * process has exited, and retrieves the exit status. The broadcaster pid 140 * is set to 0. If the broadcaster succeeded, dom_report_success will be 141 * be set to -1. 142 */ 143 144 void 145 broadcast_proc_exit() 146 { 147 int pid, ret; 148 siginfo_t infop; 149 register struct domain *pdom; 150 bool succeeded = FALSE; 151 152 sigcld_event = 0; 153 /* ==== Why WEXITED? */ 154 while ((ret = waitid(P_ALL, 0, &infop, WNOHANG | WEXITED)) != -1) { 155 switch (infop.si_code) { 156 case CLD_EXITED: 157 succeeded = infop.si_status == 0; 158 break; 159 case CLD_KILLED: 160 case CLD_DUMPED: 161 succeeded = FALSE; 162 break; 163 case CLD_TRAPPED: 164 case CLD_STOPPED: 165 case CLD_CONTINUED: 166 enable_exit(); 167 return; 168 } 169 pid = infop.si_pid; 170 171 #ifdef DEBUG 172 fprintf(stderr, 173 "ypbind event_handler: got wait from %d status = %d\n", 174 pid, infop.si_status); 175 #endif 176 177 /* to aid the progeny print the infamous "not responding" message */ 178 firsttime = FALSE; 179 180 for (pdom = known_domains; pdom != (struct domain *)NULL; 181 pdom = pdom->dom_pnext) { 182 183 if (pdom->dom_broadcaster_pid == pid) { 184 #ifdef DEBUG 185 fprintf(stderr, 186 "ypbind event_handler: got match %s\n", pdom->dom_name); 187 #endif 188 if (succeeded) { 189 broadcast_setup(pdom); 190 } 191 if (pdom->broadcaster_pipe != 0) { 192 xdr_destroy(&(pdom->broadcaster_xdr)); 193 fclose(pdom->broadcaster_pipe); 194 pdom->broadcaster_pipe = 0; 195 pdom->broadcaster_fd = -1; 196 } 197 pdom->dom_broadcaster_pid = 0; 198 199 break; 200 } 201 } 202 } /* while loop */ 203 enable_exit(); 204 } 205 206 static void 207 broadcast_setup(pdom) 208 struct domain *pdom; 209 { 210 ypbind_setdom req; 211 212 memset(&req, 0, sizeof (req)); 213 if (pdom->broadcaster_pipe) { 214 pdom->dom_report_success = -1; 215 if (xdr_ypbind_setdom(&(pdom->broadcaster_xdr), &req)) { 216 #ifdef DEBUG 217 fprintf(stderr, "parent: broadcast_setup: got xdr ok \n"); 218 #endif 219 ypbindproc_setdom_3(&req, (struct svc_req *)NULL, 220 (SVCXPRT *)NULL); 221 xdr_free(xdr_ypbind_setdom, (char *)&req); 222 gettimeofday(&(pdom->lastping), NULL); 223 } 224 #ifdef DEBUG 225 else { 226 fprintf(stderr, "ypbind parent: xdr_ypbind_setdom failed\n"); 227 } 228 #endif 229 } 230 #ifdef DEBUG 231 else { 232 fprintf(stderr, "ypbind: internal error -- no broadcaster pipe\n"); 233 } 234 #endif 235 } 236 237 #define YPBIND_PINGHOLD_DOWN 5 238 /* Same as the ypbind_get_binding() routine in SunOS */ 239 /*ARGSUSED*/ 240 ypbind_resp * 241 ypbindproc_domain_3(argp, clnt) 242 ypbind_domain *argp; 243 CLIENT *clnt; 244 { 245 static ypbind_resp resp; 246 struct domain *cur_domain; 247 int bpid; 248 int fildes[2]; 249 250 memset((char *)&resp, 0, sizeof (resp)); 251 252 #ifdef DEBUG 253 fprintf(stderr, "\nypbindproc_domain_3: domain: %s\n", 254 argp->ypbind_domainname); 255 #endif 256 257 if ((int)strlen(argp->ypbind_domainname) > YPMAXDOMAIN) { 258 259 resp.ypbind_status = YPBIND_FAIL_VAL; 260 resp.ypbind_resp_u.ypbind_error = YPBIND_ERR_NOSERV; 261 return (&resp); 262 } 263 264 if ((cur_domain = ypbind_point_to_domain(argp->ypbind_domainname)) != 265 (struct domain *)NULL) { 266 if (cur_domain->dom_boundp) { 267 268 struct timeval tp; 269 270 (void) gettimeofday(&tp, NULL); 271 if ((tp.tv_sec - cur_domain->lastping.tv_sec) > 272 YPBIND_PINGHOLD_DOWN) { 273 #ifdef DEBUG 274 fprintf(stderr, "domain is bound pinging: %s\n", 275 argp->ypbind_domainname); 276 #endif 277 (void) ypbind_ping(cur_domain); 278 } 279 } 280 281 /* 282 * Bound or not, return the current state of the binding. 283 */ 284 285 if (cur_domain->dom_boundp) { 286 #ifdef DEBUG 287 fprintf(stderr, "server is up for domain: %s\n", 288 argp->ypbind_domainname); 289 #endif 290 resp.ypbind_status = YPBIND_SUCC_VAL; 291 resp.ypbind_resp_u.ypbind_bindinfo = 292 cur_domain->dom_binding; 293 } else { 294 #ifdef DEBUG 295 fprintf(stderr, "domain is NOT bound returning: %s %d\n", 296 argp->ypbind_domainname, cur_domain->dom_error); 297 #endif 298 resp.ypbind_status = YPBIND_FAIL_VAL; 299 resp.ypbind_resp_u.ypbind_error = 300 cur_domain->dom_error; 301 } 302 303 } else { 304 resp.ypbind_status = YPBIND_FAIL_VAL; 305 resp.ypbind_resp_u.ypbind_error = YPBIND_ERR_RESC; 306 } 307 /* 308 * RETURN NOW: if successful, otherwise 309 * RETURN LATER: after spawning off a child to do the "broadcast" work. 310 */ 311 if (resp.ypbind_status == YPBIND_SUCC_VAL) { 312 #ifdef DEBUG 313 fprintf(stderr, "yp_b_subr: returning success to yp_b_svc %d\n", 314 resp.ypbind_status); 315 #endif 316 return (&resp); 317 } 318 319 /* Go about the broadcast (really, pinging here) business */ 320 321 if ((cur_domain) && (!cur_domain->dom_boundp) && 322 (!cur_domain->dom_broadcaster_pid)) { 323 #ifdef DEBUG 324 fprintf(stderr, "yp_b_subr: fork: boundp=%d broadcast_pid=%d\n", 325 cur_domain->dom_boundp, cur_domain->dom_broadcaster_pid); 326 #endif 327 /* 328 * The current domain is unbound, and there is no child 329 * process active now. Fork off a child who will beg to the 330 * ypservers list one by one or broadcast and accept whoever 331 * commands the right domain. 332 */ 333 if (pipe(fildes) < 0) { 334 #ifdef DEBUG 335 fprintf(stderr, "yp_b_subr: returning pipe failure to yp_b_svc %d\n", 336 resp.ypbind_status); 337 #endif 338 return (&resp); 339 } 340 341 enable_exit(); 342 sighold(SIGCLD); /* add it to ypbind's signal mask */ 343 cur_domain->dom_report_success++; 344 bpid = fork(); 345 if (bpid != 0) { /* parent */ 346 if (bpid > 0) { /* parent started */ 347 close(fildes[1]); 348 cur_domain->dom_broadcaster_pid = bpid; 349 cur_domain->broadcaster_fd = fildes[0]; 350 cur_domain->broadcaster_pipe = 351 fdopen(fildes[0], "r"); 352 if (cur_domain->broadcaster_pipe) 353 xdrstdio_create(&(cur_domain->broadcaster_xdr), 354 (cur_domain->broadcaster_pipe), XDR_DECODE); 355 356 #ifdef DEBUG 357 fprintf(stderr, "ypbindproc_domain_3: %s starting pid = %d try = %d\n", 358 cur_domain->dom_name, bpid, 359 cur_domain->dom_report_success); 360 fprintf(stderr, "yp_b_subr: returning after spawning, to yp_b_svc %d\n", 361 resp.ypbind_status); 362 #endif 363 sigrelse(SIGCLD); 364 /* remove it from ypbind's signal mask */ 365 return (&resp); 366 } else { /* fork failed */ 367 perror("fork"); 368 close(fildes[0]); 369 close(fildes[1]); 370 #ifdef DEBUG 371 fprintf(stderr, "yp_b_subr: returning fork failure to yp_b_svc %d\n", 372 resp.ypbind_status); 373 #endif 374 sigrelse(SIGCLD); 375 return (&resp); 376 } 377 } /* end parent */ 378 /* child only code */ 379 sigrelse(SIGCLD); 380 close(fildes[0]); 381 cur_domain->broadcaster_fd = fildes[1]; 382 cur_domain->broadcaster_pipe = fdopen(fildes[1], "w"); 383 if (cur_domain->broadcaster_pipe) 384 xdrstdio_create(&(cur_domain->broadcaster_xdr), 385 (cur_domain->broadcaster_pipe), XDR_ENCODE); 386 else { 387 perror("fdopen-pipe"); 388 exit(-1); 389 } 390 exit(pong_servers(cur_domain)); 391 } 392 #ifdef DEBUG 393 fprintf(stderr, "yp_b_subr: lazy returns failure status yp_b_svc %d\n", 394 resp.ypbind_status); 395 #endif 396 return (&resp); 397 } 398 399 400 /* 401 * call ypbindproc_domain_3 and convert results 402 * 403 * This adds support for YP clients that send requests on 404 * ypbind version 1 & 2 (i.e. clients before we started 405 * using universal addresses and netbufs). This is supported 406 * for binary compatibility for static 4.x programs. The 407 * assumption used to be that clients coming in with ypbind vers 1 408 * should be given the address of a server serving ypserv version 1. 409 * However, since yp_bind routines in 4.x YP library try 410 * to connect with ypserv version 2, even if they requested 411 * binding using ypbind version 1, the ypbind process will 412 * "always" look for only ypserv version 2 servers for all 413 * (ypbind vers 1, 2, & 3) clients. 414 */ 415 ypbind_resp_2 * 416 ypbindproc_domain_2(argp, clnt) 417 domainname_2 *argp; 418 CLIENT *clnt; 419 { 420 ypbind_domain arg_3; 421 ypbind_resp *resp_3; 422 static ypbind_resp_2 resp; 423 424 arg_3.ypbind_domainname = *argp; 425 resp_3 = ypbindproc_domain_3(&arg_3, clnt); 426 if (resp_3 == NULL) 427 return (NULL); 428 resp.ypbind_status = resp_3->ypbind_status; 429 if (resp_3->ypbind_status == YPBIND_SUCC_VAL) { 430 struct sockaddr_in *sin; 431 struct ypbind_binding_2 *bi; 432 433 sin = (struct sockaddr_in *) 434 resp_3->ypbind_resp_u.ypbind_bindinfo->ypbind_svcaddr->buf; 435 if (sin->sin_family == AF_INET) { 436 bi = &resp.ypbind_respbody_2.ypbind_bindinfo; 437 memcpy(&(bi->ypbind_binding_port), &sin->sin_port, 2); 438 memcpy(&(bi->ypbind_binding_addr), &sin->sin_addr, 4); 439 } else { 440 resp.ypbind_respbody_2.ypbind_error = YPBIND_ERR_NOSERV; 441 } 442 } else { 443 resp.ypbind_respbody_2.ypbind_error = 444 resp_3->ypbind_resp_u.ypbind_error; 445 } 446 return (&resp); 447 } 448 449 /* used to exchange information between pong_servers and ypbind_broadcast_ack */ 450 struct domain *process_current_domain; 451 452 int 453 pong_servers(domain_struct) 454 struct domain *domain_struct; /* to pass back */ 455 { 456 char *domain = domain_struct->dom_name; 457 CLIENT *clnt2; 458 char *servername; 459 listofnames *list, *lin; 460 char serverfile[MAXNAMLEN]; 461 struct timeval timeout; 462 int isok = 0, res = -1; 463 struct netconfig *nconf; 464 void *handle; 465 int nconf_count; 466 char rpcdomain[YPMAXDOMAIN+1]; 467 long inforet; 468 469 /* 470 * If the ``domain'' name passed in is not the same as the RPC 471 * domain set from /etc/defaultdomain. Then we set ``firsttime'' 472 * to TRUE so no error messages are ever syslog()-ed this 473 * prevents a possible Denial of Service attack. 474 */ 475 inforet = sysinfo(SI_SRPC_DOMAIN, &(rpcdomain[0]), YPMAXDOMAIN); 476 if ((inforet > 0) && (strcmp(domain, rpcdomain) != 0)) 477 firsttime = TRUE; 478 479 if (broadcast) { 480 enum clnt_stat stat = RPC_SUCCESS; 481 #ifdef DEBUG 482 fprintf(stderr, "pong_servers: doing an rpc_broadcast\n"); 483 #endif 484 /* 485 * Here we do the real SunOS thing that users love. Do a 486 * broadcast on the network and find out the ypserv. No need 487 * to do "ypinit -c", no setting up /etc/hosts file, and no 488 * recursion looking up the server's IP address. 489 */ 490 process_current_domain = domain_struct; 491 stat = rpc_broadcast(YPPROG, YPVERS, YPPROC_DOMAIN_NONACK, 492 (xdrproc_t)xdr_ypdomain_wrap_string, (caddr_t)&domain, 493 xdr_int, (caddr_t)&isok, 494 (resultproc_t)ypbind_broadcast_ack, "udp"); 495 if (stat == RPC_SYSTEMERROR || stat == RPC_UNKNOWNPROTO || 496 stat == RPC_CANTRECV || stat == RPC_CANTSEND || 497 stat == RPC_NOBROADCAST || 498 stat == RPC_N2AXLATEFAILURE) { 499 syslog(LOG_ERR, "RPC/Transport subsystem failure %s\n", 500 clnt_sperrno(stat)); 501 exit(-1); 502 } 503 if (domain_struct->broadcaster_pipe == 0) 504 /* init binding case */ 505 return (domain_struct->dom_boundp - 1); 506 if (domain_struct->dom_boundp) { 507 res = ypbind_pipe_setdom(NULL, domain, 508 NULL, domain_struct); 509 if (domain_struct->dom_report_success > 0) 510 syslog(LOG_ERR, 511 "NIS server for domain \"%s\" OK", domain); 512 } else if (firsttime == FALSE) 513 syslog(LOG_ERR, 514 "NIS server not responding for domain \"%s\"; still trying", domain); 515 return (res); 516 } 517 #ifdef DEBUG 518 fprintf(stderr, "pong_servers: ponging servers one by one\n"); 519 #endif 520 /* 521 * Do the politically correct thing.. transport independent and 522 * secure (trusts only listed servers). 523 */ 524 525 /* 526 * get list of possible servers for this domain 527 */ 528 529 /* 530 * get alias for domain: Things of the past.. 531 * sysvconfig(); 532 * (void) yp_getalias(domain, domain_alias, NAME_MAX); 533 */ 534 sprintf(serverfile, "%s/%s/%s", BINDING, domain, YPSERVERS); 535 #ifdef DEBUG 536 fprintf(stderr, "pong_servers: serverfile %s\n", serverfile); 537 #endif 538 list = names(serverfile); 539 if (list == NULL) { 540 if (firsttime == FALSE) 541 syslog(LOG_ERR, 542 "service not installed, use /usr/sbin/ypinit -c"); 543 return (-1); 544 } 545 lin = list; 546 for (list = lin; list; list = list->nextname) { 547 servername = strtok(list->name, " \t\n"); 548 if (servername == NULL) continue; 549 550 /* Check all datagram_v transports for this server */ 551 if ((handle = __rpc_setconf("datagram_v")) == NULL) { 552 syslog(LOG_ERR, 553 "ypbind: RPC operation on /etc/netconfig failed"); 554 free_listofnames(lin); 555 return (-1); 556 } 557 558 nconf_count = 0; 559 clnt2 = 0; 560 while (clnt2 == 0 && (nconf = __rpc_getconf(handle)) != 0) { 561 nconf_count++; 562 /* 563 * We use only datagram here. It is expected to be udp. 564 * VERY IMPORTANT: __clnt_tp_create_bootstrap is a 565 * hacked up version that does not do netdir_getbyname. 566 */ 567 hostNotKnownLocally = 0; 568 clnt2 = 569 __clnt_tp_create_bootstrap(servername, YPPROG, YPVERS, nconf); 570 } 571 if (nconf_count == 0) { 572 syslog(LOG_ERR, 573 "ypbind: RPC operation on /etc/netconfig failed"); 574 free_listofnames(lin); 575 return (-1); 576 } 577 578 if (clnt2 == 0) { 579 if (rpc_createerr.cf_stat == RPC_UNKNOWNHOST && 580 hostNotKnownLocally) { 581 syslog(LOG_ERR, 582 "NIS server %s is not in local host files !", servername); 583 } 584 perror(servername); 585 clnt_pcreateerror("ypbind"); 586 continue; 587 } 588 589 timeout.tv_sec = PINGTIME; 590 timeout.tv_usec = 0; 591 if ((enum clnt_stat) clnt_call(clnt2, 592 YPPROC_DOMAIN, (xdrproc_t)xdr_ypdomain_wrap_string, 593 (char *)&domain, xdr_int, 594 (char *)&isok, timeout) == RPC_SUCCESS) { 595 if (isok) { 596 if (domain_struct->dom_report_success > 0) { 597 syslog(LOG_ERR, 598 "NIS server for domain \"%s\" OK", domain); 599 } 600 if (domain_struct->broadcaster_pipe == 0) { 601 /* init binding case --parent */ 602 struct netconfig *setnc; 603 struct netbuf setua; 604 struct ypbind_binding *b = 605 domain_struct->dom_binding; 606 607 setnc = 608 getnetconfigent(clnt2->cl_netid); 609 if (b == NULL) { 610 /* ASSERT: This shouldn't happen ! */ 611 b = 612 (struct ypbind_binding *)calloc(1, sizeof (*b)); 613 domain_struct->dom_binding = b; 614 if (b == NULL) { 615 __rpc_endconf(handle); 616 clnt_destroy(clnt2); 617 free_listofnames(lin); 618 return (-2); 619 } 620 } 621 622 623 b->ypbind_nconf = setnc; 624 clnt_control(clnt2, CLGET_SVC_ADDR, 625 (char *)&setua); 626 if (b->ypbind_svcaddr) { 627 if (b->ypbind_svcaddr->buf) 628 free(b->ypbind_svcaddr->buf); 629 free(b->ypbind_svcaddr); 630 } 631 b->ypbind_svcaddr = dup_netbuf(&setua); 632 if (b->ypbind_servername) 633 free(b->ypbind_servername); 634 b->ypbind_servername = 635 strdup(servername); 636 b->ypbind_hi_vers = YPVERS; 637 b->ypbind_lo_vers = YPVERS; 638 __rpc_endconf(handle); 639 domain_struct->dom_boundp = TRUE; 640 clnt_destroy(clnt2); 641 free_listofnames(lin); 642 return (0); 643 } 644 res = ypbind_pipe_setdom(clnt2, domain, 645 servername, domain_struct); 646 __rpc_endconf(handle); 647 clnt_destroy(clnt2); 648 free_listofnames(lin); 649 return (res); 650 } else { 651 syslog(LOG_ERR, 652 "server %s doesn't serve domain %s\n", 653 servername, domain); 654 } 655 } else { 656 clnt_perror(clnt2, servername); 657 } 658 clnt_destroy(clnt2); 659 } 660 /* 661 * We tried all servers, none obliged ! 662 * After ypbind is started up it will not be bound 663 * immediately. This is normal, no error message 664 * is needed. Although, with the ypbind_init_default 665 * it will be bound immediately. 666 */ 667 if (firsttime == FALSE) { 668 syslog(LOG_ERR, 669 "NIS server not responding for domain \"%s\"; still trying", domain); 670 } 671 free_listofnames(lin); 672 __rpc_endconf(handle); 673 return (-2); 674 } 675 676 struct netbuf * 677 dup_netbuf(inbuf) 678 struct netbuf *inbuf; 679 { 680 struct netbuf *outbuf; 681 682 if (inbuf == NULL) 683 return (NULL); 684 if ((outbuf = 685 (struct netbuf *)calloc(1, sizeof (struct netbuf))) == NULL) 686 return (NULL); 687 if ((outbuf->buf = malloc(inbuf->len)) == NULL) { 688 free(outbuf); 689 return (NULL); 690 } 691 outbuf->len = inbuf->len; 692 outbuf->maxlen = inbuf->len; 693 (void) memcpy(outbuf->buf, inbuf->buf, inbuf->len); 694 return (outbuf); 695 } 696 697 /* 698 * This is called by the broadcast rpc routines to process the responses 699 * coming back from the broadcast request. Since the form of the request 700 * which is used in ypbind_broadcast_bind is "respond only in the positive 701 * case", we know that we have a server. 702 * The internet address of the responding server will be picked up from 703 * the saddr parameter, and stuffed into the domain. The domain's boundp 704 * field will be set TRUE. The first responding server (or the first one 705 * which is on a reserved port) will be the bound server for the domain. 706 */ 707 bool 708 ypbind_broadcast_ack(ptrue, nbuf, nconf) 709 bool *ptrue; 710 struct netbuf *nbuf; 711 struct netconfig *nconf; 712 { 713 struct ypbind_binding b; 714 715 process_current_domain->dom_boundp = TRUE; 716 b.ypbind_nconf = nconf; 717 b.ypbind_svcaddr = nbuf; 718 b.ypbind_servername = "\000"; 719 b.ypbind_hi_vers = YPVERS; 720 b.ypbind_lo_vers = YPVERS; 721 free_ypbind_binding(process_current_domain->dom_binding); 722 process_current_domain->dom_binding = dup_ypbind_binding(&b); 723 return (TRUE); 724 } 725 726 /* 727 * WARNING: This routine is entered only by the child process. 728 * Called if it pongs/broadcasts okay. 729 */ 730 static int 731 ypbind_pipe_setdom(client, domain, servername, opaque_domain) 732 CLIENT *client; 733 char *servername; 734 char *domain; 735 struct domain *opaque_domain; 736 { 737 struct netconfig *setnc; 738 struct netbuf setua; 739 ypbind_binding setb; 740 ypbind_setdom setd; 741 int retval; 742 743 setd.ypsetdom_domain = domain; 744 if (client == NULL && opaque_domain->dom_binding) { 745 #ifdef DEBUG 746 fprintf(stderr, "ypbind_pipe_setdom: child broadcast case "); 747 #endif 748 /* ypbind_broadcast_ack already setup dom_binding for us */ 749 setd.ypsetdom_bindinfo = opaque_domain->dom_binding; 750 } else if (client) { 751 #ifdef DEBUG 752 fprintf(stderr, "ypbind_pipe_setdom: child unicast case "); 753 #endif 754 setnc = getnetconfigent(client->cl_netid); 755 if (setnc == NULL) { 756 #ifdef DEBUG 757 fprintf(stderr, "PANIC: shouldn't happen\n"); 758 #endif 759 fclose(opaque_domain->broadcaster_pipe); 760 close(opaque_domain->broadcaster_fd); 761 return (-2); 762 } 763 clnt_control(client, CLGET_SVC_ADDR, (char *)&setua); 764 setb.ypbind_nconf = setnc; 765 setb.ypbind_svcaddr = &setua; 766 setb.ypbind_servername = servername; 767 setb.ypbind_hi_vers = YPVERS; 768 setb.ypbind_lo_vers = YPVERS; 769 setd.ypsetdom_bindinfo = &setb; 770 /* 771 * Let's hardcode versions, that is the only ypserv we support anyway. 772 * Avoid the song and dance of recursively calling ypbind_ping 773 * for no reason. Consistent with the 4.1 policy, that if ypbind gets 774 * a request on new binder protocol, the requestor is looking for the 775 * new ypserv. And, we have even higher binder protocol version i.e. 3. 776 */ 777 } else 778 return (-1); 779 #ifdef DEBUG 780 fprintf(stderr, 781 " saving server settings, \nsupports versions %d thru %d\n", 782 setd.ypsetdom_bindinfo->ypbind_lo_vers, 783 setd.ypsetdom_bindinfo->ypbind_hi_vers); 784 #endif 785 786 if (opaque_domain->broadcaster_pipe == 0) { 787 #ifdef DEBUG 788 fprintf(stderr, "PANIC: shouldn't be in this function\n"); 789 #endif 790 return (-2); 791 } 792 #ifdef DEBUG 793 fprintf(stderr, "child: doing xdr_ypbind_setdom\n"); 794 #endif 795 retval = xdr_ypbind_setdom(&(opaque_domain->broadcaster_xdr), &setd); 796 xdr_destroy(&(opaque_domain->broadcaster_xdr)); 797 fclose(opaque_domain->broadcaster_pipe); 798 close(opaque_domain->broadcaster_fd); 799 /* 800 * This child process is about to exit. Don't bother freeing memory. 801 */ 802 if (!retval) { 803 #ifdef DEBUG 804 fprintf(stderr, 805 "YPBIND pipe_setdom failed \n(xdr failure) to server %s\n", 806 servername ? servername : ""); 807 #endif 808 return (-3); 809 } 810 #ifdef DEBUG 811 fprintf(stderr, "ypbind_pipe_setdom: YPBIND OK-set to server %s\n", 812 servername ? servername : ""); 813 #endif 814 return (0); 815 } 816 817 /* Same as ypbind_set_binding in SunOS */ 818 /* 819 * We use a trick from SunOS to return an error to the ypset command 820 * when we are not allowing the domain to be set. We do a svcerr_noprog() 821 * to send RPC_PROGUNAVAIL to ypset. We also return NULL so that 822 * our caller (ypbindprog_3) won't try to return a result. This 823 * hack is necessary because the YPBINDPROC_SETDOM procedure is defined 824 * in the protocol to return xdr_void, so we don't have a direct way to 825 * return an error to the client. 826 */ 827 /*ARGSUSED*/ 828 void * 829 ypbindproc_setdom_3(argp, rqstp, transp) 830 ypbind_setdom *argp; 831 struct svc_req *rqstp; 832 SVCXPRT *transp; 833 { 834 struct domain *a_domain; 835 struct netbuf *who; 836 static char res; /* dummy for void * return */ 837 uid_t caller_uid; 838 839 if ((int)strlen(argp->ypsetdom_domain) > YPMAXDOMAIN) { 840 841 if (transp) { 842 svcerr_systemerr(transp); 843 return (0); 844 } 845 return (&res); 846 } 847 848 if (transp != NULL) { 849 /* find out who originated the request */ 850 char *uaddr; 851 struct netconfig *nconf; 852 853 who = svc_getrpccaller(transp); 854 if ((nconf = getnetconfigent(transp->xp_netid)) 855 == (struct netconfig *)NULL) { 856 svcerr_systemerr(transp); 857 return (0); 858 } 859 if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { 860 uaddr = strdup("local host"); 861 } else { 862 uaddr = taddr2uaddr(nconf, who); 863 } 864 if (setok != YPSETALL) { 865 /* for -ypset, it falls through and let anybody do a setdom ! */ 866 if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) != 0) { 867 syslog(LOG_ERR, 868 "ypset request from %s not on loopback, \ 869 cannot set ypbind to %s", uaddr ? uaddr : "unknown source", 870 argp->ypsetdom_bindinfo->ypbind_servername); 871 if (uaddr) 872 free(uaddr); 873 freenetconfigent(nconf); 874 svcerr_noprog(transp); 875 return (0); 876 } 877 switch (setok) { 878 case YPSETNONE: 879 if (strcmp(nconf->nc_protofmly, 880 NC_LOOPBACK) == 0) 881 syslog(LOG_ERR, 882 "ypset request to %s from %s failed - ypset not allowed", 883 argp->ypsetdom_bindinfo->ypbind_servername, uaddr); 884 if (uaddr) 885 free(uaddr); 886 freenetconfigent(nconf); 887 svcerr_noprog(transp); 888 return (0); 889 case YPSETLOCAL: 890 if (__rpc_get_local_uid(transp, 891 &caller_uid) < 0) { 892 syslog(LOG_ERR, "ypset request from \ 893 unidentified local user on %s - ypset not allowed", 894 transp->xp_netid); 895 if (uaddr) 896 free(uaddr); 897 freenetconfigent(nconf); 898 svcerr_noprog(transp); 899 return (0); 900 } 901 if (caller_uid != 0) { 902 syslog(LOG_ERR, 903 "Set domain request to host %s \ 904 from local non-root user %ld failed - ypset not allowed", 905 argp->ypsetdom_bindinfo->ypbind_servername, caller_uid); 906 if (uaddr) 907 free(uaddr); 908 freenetconfigent(nconf); 909 svcerr_noprog(transp); 910 return (0); 911 } 912 } 913 } 914 syslog(LOG_ERR, "Set domain request from %s : \ 915 setting server for domain %s to %s", uaddr ? uaddr : "UNKNOWN SOURCE", 916 argp->ypsetdom_domain, argp->ypsetdom_bindinfo->ypbind_servername); 917 if (uaddr) 918 free(uaddr); 919 freenetconfigent(nconf); 920 } 921 922 if ((a_domain = ypbind_point_to_domain(argp->ypsetdom_domain)) 923 != (struct domain *)NULL) { 924 /* setting binding; old may be invalid */ 925 uncache_binding(a_domain); 926 927 /* this does the set -- should copy the structure */ 928 free_ypbind_binding(a_domain->dom_binding); 929 if ((a_domain->dom_binding = 930 dup_ypbind_binding(argp->ypsetdom_bindinfo)) == NULL) { 931 syslog(LOG_ERR, "ypbindproc_setdom_3: out of memory, ", 932 "dup_ypbind_binding failed\n"); 933 if (transp) { 934 svcerr_noprog(transp); 935 return (0); 936 } 937 return (&res); 938 } 939 gettimeofday(&(a_domain->lastping), NULL); 940 a_domain->dom_boundp = TRUE; 941 cache_binding(a_domain); 942 #ifdef DEBUG 943 fprintf(stderr, "ypbindproc_setdom_3: setting domain %s to server %s\n", 944 argp->ypsetdom_domain, 945 argp->ypsetdom_bindinfo->ypbind_servername); 946 #endif 947 } 948 949 return (&res); 950 } 951 952 /* 953 * This returns a pointer to a domain entry. If no such domain existed on 954 * the list previously, an entry will be allocated, initialized, and linked 955 * to the list. Note: If no memory can be malloc-ed for the domain structure, 956 * the functional value will be (struct domain *) NULL. 957 */ 958 static struct domain * 959 ypbind_point_to_domain(pname) 960 register char *pname; 961 { 962 register struct domain *pdom; 963 char buf[300]; 964 965 for (pdom = known_domains; pdom != (struct domain *)NULL; 966 pdom = pdom->dom_pnext) { 967 if (strcmp(pname, pdom->dom_name) == 0) 968 return (pdom); 969 } 970 971 /* Not found. Add it to the list */ 972 973 if (pdom = (struct domain *)calloc(1, sizeof (struct domain))) { 974 pdom->dom_name = strdup(pname); 975 if (pdom->dom_name == NULL) { 976 free((char *)pdom); 977 syslog(LOG_ERR, 978 "ypbind_point_to_domain: strdup failed\n"); 979 return (NULL); 980 } 981 pdom->dom_pnext = known_domains; 982 known_domains = pdom; 983 pdom->dom_boundp = FALSE; 984 pdom->dom_vers = YPVERS; /* This doesn't talk to old ypserv */ 985 pdom->dom_binding = NULL; 986 pdom->dom_error = YPBIND_ERR_NOSERV; 987 pdom->ping_clnt = (CLIENT *)NULL; 988 pdom->dom_report_success = -1; 989 pdom->dom_broadcaster_pid = 0; 990 pdom->broadcaster_pipe = 0; 991 pdom->bindfile = -1; 992 pdom->lastping.tv_sec = 0; 993 pdom->lastping.tv_usec = 0; /* require ping */ 994 pdom->cache_fp = 0; 995 sprintf(buf, "%s/%s/cache_binding", BINDING, pdom->dom_name); 996 pdom->cache_file = strdup(buf); 997 /* 998 * We don't give an error if pdom->cache_file is not set. 999 * If we got null (out of memory), then we just won't use 1000 * the cache file in cache_binding() (assuming the 1001 * application gets that far. 1002 */ 1003 } 1004 else 1005 syslog(LOG_ERR, "ypbind_point_to_domain: malloc failed\n"); 1006 1007 return (pdom); 1008 } 1009 1010 static void 1011 ypbind_ping(pdom) 1012 struct domain *pdom; 1013 { 1014 struct timeval timeout; 1015 int vers; 1016 int isok; 1017 1018 if (pdom->dom_boundp == FALSE) 1019 return; 1020 vers = pdom->dom_vers; 1021 1022 if (pdom->ping_clnt == (CLIENT *) NULL) { 1023 pdom->ping_clnt = __nis_clnt_create(RPC_ANYFD, 1024 pdom->dom_binding->ypbind_nconf, 0, 1025 pdom->dom_binding->ypbind_svcaddr, 0, 1026 YPPROG, vers, 0, 0); 1027 } 1028 1029 if (pdom->ping_clnt == (CLIENT *) NULL) { 1030 perror("clnt_tli_create"); 1031 clnt_pcreateerror("ypbind_ping()"); 1032 pdom->dom_boundp = FALSE; 1033 pdom->dom_error = YPBIND_ERR_NOSERV; 1034 return; 1035 } 1036 1037 1038 #ifdef DEBUG 1039 fprintf(stderr, "ypbind: ypbind_ping()\n"); 1040 #endif 1041 timeout.tv_sec = PINGTOTTIM; 1042 timeout.tv_usec = 0; 1043 if (clnt_call(pdom->ping_clnt, 1044 YPPROC_DOMAIN, (xdrproc_t)xdr_ypdomain_wrap_string, 1045 (char *)&pdom->dom_name, xdr_int, (char *)&isok, 1046 timeout) == RPC_SUCCESS) { 1047 pdom->dom_boundp = isok; 1048 pdom->dom_binding->ypbind_lo_vers = vers; 1049 pdom->dom_binding->ypbind_hi_vers = vers; 1050 #ifdef DEBUG 1051 fprintf(stderr, 1052 "Server pinged successfully, supports versions %d thru %d\n", 1053 pdom->dom_binding->ypbind_lo_vers, 1054 pdom->dom_binding->ypbind_hi_vers); 1055 #endif 1056 } else { 1057 clnt_perror(pdom->ping_clnt, "ping"); 1058 pdom->dom_boundp = FALSE; 1059 pdom->dom_error = YPBIND_ERR_NOSERV; 1060 } 1061 (void) gettimeofday(&(pdom->lastping), NULL); 1062 if (pdom->ping_clnt) 1063 clnt_destroy(pdom->ping_clnt); 1064 pdom->ping_clnt = (CLIENT *)NULL; 1065 if (pdom->dom_boundp) 1066 cache_binding(pdom); 1067 } 1068 1069 static struct ypbind_binding * 1070 dup_ypbind_binding(a) 1071 struct ypbind_binding *a; 1072 { 1073 struct ypbind_binding *b; 1074 struct netconfig *nca, *ncb; 1075 struct netbuf *nxa, *nxb; 1076 int i; 1077 1078 b = (struct ypbind_binding *)calloc(1, sizeof (*b)); 1079 if (b == NULL) 1080 return (b); 1081 b->ypbind_hi_vers = a->ypbind_hi_vers; 1082 b->ypbind_lo_vers = a->ypbind_lo_vers; 1083 b->ypbind_servername = 1084 a->ypbind_servername ? strdup(a->ypbind_servername) : NULL; 1085 ncb = (b->ypbind_nconf = 1086 (struct netconfig *)calloc(1, sizeof (struct netconfig))); 1087 nxb = (b->ypbind_svcaddr = 1088 (struct netbuf *)calloc(1, sizeof (struct netbuf))); 1089 nca = a->ypbind_nconf; 1090 nxa = a->ypbind_svcaddr; 1091 ncb->nc_flag = nca->nc_flag; 1092 ncb->nc_protofmly = 1093 nca->nc_protofmly ? strdup(nca->nc_protofmly) : NULL; 1094 ncb->nc_proto = 1095 nca->nc_proto ? strdup(nca->nc_proto) : NULL; 1096 ncb->nc_semantics = nca->nc_semantics; 1097 ncb->nc_netid = 1098 nca->nc_netid ? strdup(nca->nc_netid) : NULL; 1099 ncb->nc_device = 1100 nca->nc_device ? strdup(nca->nc_device) : NULL; 1101 ncb->nc_nlookups = nca->nc_nlookups; 1102 ncb->nc_lookups = (char **)calloc(nca->nc_nlookups, sizeof (char *)); 1103 if (ncb->nc_lookups == NULL) { 1104 if (ncb->nc_device) 1105 free(ncb->nc_device); 1106 if (ncb->nc_netid) 1107 free(ncb->nc_netid); 1108 if (ncb->nc_proto) 1109 free(ncb->nc_proto); 1110 if (ncb->nc_protofmly) 1111 free(ncb->nc_protofmly); 1112 if (nxb) 1113 free(nxb); 1114 if (ncb) 1115 free(ncb); 1116 if (b->ypbind_servername) 1117 free(b->ypbind_servername); 1118 if (b) 1119 free(b); 1120 return (NULL); 1121 } 1122 for (i = 0; i < nca->nc_nlookups; i++) 1123 ncb->nc_lookups[i] = 1124 nca->nc_lookups[i] ? strdup(nca->nc_lookups[i]) : NULL; 1125 for (i = 0; i < 8; i++) 1126 ncb->nc_unused[i] = nca->nc_unused[i]; 1127 nxb->maxlen = nxa->maxlen; 1128 nxb->len = nxa->len; 1129 nxb->buf = malloc(nxa->maxlen); 1130 if (nxb->buf == NULL) { 1131 for (i = 0; i < nca->nc_nlookups; i++) 1132 if (ncb->nc_lookups[i]) 1133 free(ncb->nc_lookups[i]); 1134 free(ncb->nc_lookups); 1135 if (ncb->nc_device) 1136 free(ncb->nc_device); 1137 if (ncb->nc_netid) 1138 free(ncb->nc_netid); 1139 if (ncb->nc_proto) 1140 free(ncb->nc_proto); 1141 if (ncb->nc_protofmly) 1142 free(ncb->nc_protofmly); 1143 if (nxb) 1144 free(nxb); 1145 if (ncb) 1146 free(ncb); 1147 if (b->ypbind_servername) 1148 free(b->ypbind_servername); 1149 if (b) 1150 free(b); 1151 return (NULL); 1152 } 1153 memcpy(nxb->buf, nxa->buf, nxb->len); 1154 return (b); 1155 } 1156 1157 static void 1158 free_ypbind_binding(b) 1159 struct ypbind_binding *b; 1160 { 1161 if (b == NULL) 1162 return; 1163 netdir_free((char *)b->ypbind_svcaddr, ND_ADDR); 1164 free(b->ypbind_servername); 1165 freenetconfigent(b->ypbind_nconf); 1166 free(b); 1167 } 1168 1169 /* 1170 * Preloads teh default domain's domain binding. Domain binding for the 1171 * local node's default domain for ypserv version 2 (YPVERS) will be 1172 * set up. This may make it a little slower to start ypbind during 1173 * boot time, but would make it easy on other domains that rely on 1174 * this binding. 1175 */ 1176 void 1177 ypbind_init_default() 1178 { 1179 char domain[256]; 1180 struct domain *cur_domain; 1181 1182 if (getdomainname(domain, 256) == 0) { 1183 cur_domain = ypbind_point_to_domain(domain); 1184 1185 if (cur_domain == (struct domain *)NULL) { 1186 abort(); 1187 } 1188 (void) pong_servers(cur_domain); 1189 } 1190 } 1191 1192 bool_t 1193 xdr_ypbind_binding_2(xdrs, objp) 1194 register XDR *xdrs; 1195 ypbind_binding_2 *objp; 1196 { 1197 if (!xdr_opaque(xdrs, (char *)&(objp->ypbind_binding_addr), 4)) 1198 return (FALSE); 1199 if (!xdr_opaque(xdrs, (char *)&(objp->ypbind_binding_port), 2)) 1200 return (FALSE); 1201 return (TRUE); 1202 } 1203 1204 bool_t 1205 xdr_ypbind_resp_2(xdrs, objp) 1206 register XDR *xdrs; 1207 ypbind_resp_2 *objp; 1208 { 1209 if (!xdr_ypbind_resptype(xdrs, &objp->ypbind_status)) 1210 return (FALSE); 1211 switch (objp->ypbind_status) { 1212 case YPBIND_FAIL_VAL: 1213 if (!xdr_u_long(xdrs, &objp->ypbind_respbody_2.ypbind_error)) 1214 return (FALSE); 1215 break; 1216 case YPBIND_SUCC_VAL: 1217 if (!xdr_ypbind_binding_2(xdrs, 1218 &objp->ypbind_respbody_2.ypbind_bindinfo)) 1219 return (FALSE); 1220 break; 1221 default: 1222 return (FALSE); 1223 } 1224 return (TRUE); 1225 } 1226 1227 /* 1228 * The following is some caching code to improve the performance of 1229 * yp clients. In the days of yore, a client would talk to rpcbind 1230 * to get the address for ypbind, then talk to ypbind to get the 1231 * address of the server. If a lot of clients are doing this at 1232 * the same time, then rpcbind and ypbind get bogged down and clients 1233 * start to time out. 1234 * 1235 * We cache two things: the current address for ypserv, and the 1236 * transport addresses for talking to ypbind. These are saved in 1237 * files in /var/yp. To get the address of ypserv, the client opens 1238 * a file and reads the address. It does not have to talk to rpcbind 1239 * or ypbind. If this file is not available, then it can read the 1240 * the transport address for talking to ypbind without bothering 1241 * rpcbind. If this also fails, then it uses the old method of 1242 * talking to rpcbind and then ypbind. 1243 * 1244 * We lock the first byte of the cache files after writing to them. 1245 * This indicates to the client that they contents are valid. The 1246 * client should test the lock. If the lock is held, then it can 1247 * use the contents. If the lock test fails, then the contents should 1248 * be ignored. 1249 */ 1250 1251 /* 1252 * Cache new binding information for a domain in a file. If the 1253 * new binding is the same as the old, then we skip it. We xdr 1254 * a 'ypbind_resp', which is what would be returned by a call to 1255 * the YBINDPROCP_DOMAIN service. We xdr the data because it is 1256 * easier than writing the data out field by field. It would be 1257 * nice if there were an xdrfd_create() that was similar to 1258 * xdrstdio_create(). Instead, we do an fdopen and use xdrstdio_create(). 1259 */ 1260 void 1261 cache_binding(pdom) 1262 struct domain *pdom; 1263 { 1264 int st; 1265 int fd; 1266 XDR xdrs; 1267 struct ypbind_resp resp; 1268 1269 if (!cache_okay) 1270 return; 1271 1272 /* if the domain doesn't have a cache file, then skip it */ 1273 if (pdom->cache_file == 0) 1274 return; 1275 1276 /* 1277 * If we already had a cache file for this domain, remove it. If 1278 * a client just started accessing it, then it will either find 1279 * it unlocked (and not use it), or continue to use it with 1280 * old information. This is not a problem, the client will 1281 * either fail to talk to ypserv and try to bind again, or 1282 * will continue to use the old server. 1283 */ 1284 if (pdom->cache_fp) { 1285 fclose(pdom->cache_fp); /* automatically unlocks */ 1286 unlink(pdom->cache_file); 1287 pdom->cache_fp = 0; 1288 } 1289 1290 fd = open(pdom->cache_file, O_CREAT|O_WRONLY, 0444); 1291 if (fd == -1) 1292 return; 1293 1294 pdom->cache_fp = fdopen(fd, "w"); 1295 if (pdom->cache_fp == 0) { 1296 close(fd); 1297 return; 1298 } 1299 1300 xdrstdio_create(&xdrs, pdom->cache_fp, XDR_ENCODE); 1301 resp.ypbind_status = YPBIND_SUCC_VAL; 1302 resp.ypbind_resp_u.ypbind_bindinfo = pdom->dom_binding; 1303 1304 if (!xdr_ypbind_resp(&xdrs, &resp)) { 1305 xdr_destroy(&xdrs); 1306 unlink(pdom->cache_file); 1307 fclose(pdom->cache_fp); 1308 pdom->cache_fp = 0; 1309 return; 1310 } 1311 xdr_destroy(&xdrs); /* flushes xdr but leaves fp open */ 1312 1313 /* we lock the first byte to indicate that the file is valid */ 1314 lseek(fd, 0L, SEEK_SET); 1315 st = lockf(fd, F_LOCK, 1); 1316 if (st == -1) { 1317 unlink(pdom->cache_file); 1318 fclose(pdom->cache_fp); 1319 pdom->cache_fp = 0; 1320 } 1321 } 1322 1323 void 1324 uncache_binding(pdom) 1325 struct domain *pdom; 1326 { 1327 if (!cache_okay) 1328 return; 1329 1330 if (pdom->cache_fp != 0) { 1331 unlink(pdom->cache_file); 1332 fclose(pdom->cache_fp); 1333 pdom->cache_fp = 0; 1334 } 1335 } 1336 1337 /* 1338 * Cache a transport address for talking to ypbind. We convert the 1339 * transport address to a universal address and save that in a file. 1340 * The file lives in the binding directory because it does not depend 1341 * on the domain. 1342 */ 1343 void 1344 cache_transport(nconf, xprt, vers) 1345 struct netconfig *nconf; 1346 SVCXPRT *xprt; 1347 int vers; 1348 { 1349 char filename[300]; 1350 char *uaddr; 1351 int fd; 1352 int st; 1353 int len; 1354 1355 if (!cache_okay) 1356 return; 1357 1358 sprintf(filename, "%s/xprt.%s.%d", 1359 BINDING, nconf->nc_netid, vers); 1360 1361 unlink(filename); /* remove any old version */ 1362 1363 uaddr = taddr2uaddr(nconf, &xprt->xp_ltaddr); 1364 if (uaddr == 0) 1365 return; 1366 1367 fd = open(filename, O_CREAT|O_WRONLY, 0444); /* readable by all */ 1368 if (fd == -1) { 1369 free(uaddr); 1370 return; 1371 } 1372 1373 len = strlen(uaddr) + 1; /* include terminating null */ 1374 st = write(fd, uaddr, len); 1375 if (st != len) { 1376 close(fd); 1377 unlink(filename); 1378 free(uaddr); 1379 return; 1380 } 1381 1382 free(uaddr); 1383 1384 /* we lock the first byte to indicate that the file is valid */ 1385 lseek(fd, 0L, SEEK_SET); 1386 st = lockf(fd, F_LOCK, 1); 1387 if (st == -1) { 1388 close(fd); 1389 unlink(filename); 1390 } 1391 } 1392 1393 /* 1394 * Create a file that clients can check to see if we are running. 1395 */ 1396 void 1397 cache_pid() 1398 { 1399 char filename[300]; 1400 char spid[15]; 1401 int fd; 1402 int st; 1403 int len; 1404 1405 if (!cache_okay) 1406 return; 1407 1408 sprintf(filename, "%s/ypbind.pid", BINDING); 1409 1410 unlink(filename); /* remove any old version */ 1411 1412 fd = open(filename, O_CREAT|O_WRONLY, 0444); /* readable by all */ 1413 if (fd == -1) { 1414 return; 1415 } 1416 1417 sprintf(spid, "%d\n", getpid()); 1418 1419 len = strlen(spid); 1420 st = write(fd, spid, len); 1421 if (st != len) { 1422 close(fd); 1423 unlink(filename); 1424 return; 1425 } 1426 1427 /* we lock the first byte to indicate that the file is valid */ 1428 lseek(fd, 0L, SEEK_SET); 1429 st = lockf(fd, F_LOCK, 1); 1430 if (st == -1) { 1431 close(fd); 1432 unlink(filename); 1433 } 1434 1435 /* we keep 'fd' open so that the lock will continue to be held */ 1436 } 1437 1438 /* 1439 * We are called once at startup (when the known_domains list is empty) 1440 * to clean up left-over files. We are also called right before 1441 * exiting. In the latter case case we don't bother closing descriptors 1442 * in the entries in the domain list because they will be closed 1443 * automatically (and unlocked) when we exit. 1444 * 1445 * We ignore the cache_okay flag because it is important that we remove 1446 * all cache files (left-over files can temporarily confuse clients). 1447 */ 1448 void 1449 clean_cache() 1450 { 1451 struct domain *pdom; 1452 DIR *dir; 1453 struct dirent *dirent; 1454 char filename[300]; 1455 1456 /* close and unlink cache files for each domain */ 1457 for (pdom = known_domains; pdom != (struct domain *)NULL; 1458 pdom = pdom->dom_pnext) { 1459 if (pdom->cache_file) 1460 unlink(pdom->cache_file); 1461 } 1462 1463 sprintf(filename, "%s/ypbind.pid", BINDING); 1464 unlink(filename); 1465 1466 dir = opendir(BINDING); 1467 1468 if (dir == NULL) { 1469 /* Directory could not be opened. */ 1470 syslog(LOG_ERR, "opendir failed with [%s]", strerror(errno)); 1471 return; 1472 } 1473 1474 while ((dirent = readdir(dir)) != 0) { 1475 if (strncmp(dirent->d_name, "xprt.", 5) == 0) { 1476 sprintf(filename, "%s/%s", BINDING, dirent->d_name); 1477 unlink(filename); 1478 rewinddir(dir); /* removing file may harm iteration */ 1479 } 1480 } 1481 closedir(dir); 1482 } 1483 1484 /* 1485 * We only want to use the cache stuff on local file systems. 1486 * For remote file systems (e.g., NFS, the locking overhead is 1487 * worse than the overhead of loopback RPC, so the caching 1488 * wouldn't buy us anything. In addition, if the remote locking 1489 * software isn't configured before we start, then we would 1490 * block when we try to lock. 1491 * 1492 * We don't have a direct way to tell if a file system is local 1493 * or remote, so we assume it is local unless it is NFS. 1494 */ 1495 int 1496 cache_check() 1497 { 1498 int st; 1499 struct statvfs stbuf; 1500 1501 st = statvfs(BINDING, &stbuf); 1502 if (st == -1) { 1503 syslog(LOG_ERR, "statvfs failed with [%s]", strerror(errno)); 1504 return (0); 1505 } 1506 1507 /* we use strncasecmp to get NFS, NFS3, nfs, nfs3, etc. */ 1508 if (strncasecmp(stbuf.f_basetype, "NFS", 3) == 0) 1509 return (0); 1510 return (1); 1511 } 1512