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