1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 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 <stdio.h> 38 #include <stdio_ext.h> 39 #include <stdlib.h> 40 #include <signal.h> 41 #include <rpc/rpc.h> 42 #include <memory.h> 43 #include <netconfig.h> 44 #include <syslog.h> 45 #include <rpcsvc/yp_prot.h> 46 #include "yp_b.h" 47 #include <sys/resource.h> 48 #include <sys/stropts.h> 49 #include <unistd.h> 50 #include <rpc/nettype.h> 51 #include <string.h> 52 #include <tiuser.h> 53 54 55 #ifdef DEBUG 56 #define RPC_SVC_FG 57 #endif 58 59 #define _RPCSVC_CLOSEDOWN 120 60 #define YPBIND_ERR_ERR 1 /* Internal error */ 61 #define YPBIND_ERR_NOSERV 2 /* No bound server for passed domain */ 62 #define YPBIND_ERR_RESC 3 /* System resource allocation failure */ 63 #define YPBIND_ERR_NODOMAIN 4 /* Domain doesn't exist */ 64 65 static int _rpcpmstart; /* Started by a port monitor ? */ 66 static int _rpcsvcdirty; /* Still serving ? */ 67 int setok = YPSETNONE; /* who is allowed to ypset */ 68 int broadcast = 0; 69 int cache_okay = 0; /* if set, then bindings are cached in files */ 70 71 extern int sigcld_event; 72 extern void broadcast_proc_exit(); 73 extern int __rpc_negotiate_uid(); 74 extern bool_t __rpcbind_is_up(); 75 extern void ypbind_init_default(); 76 static void set_signal_handlers(); 77 static void clear_bindings(); 78 static void unregister(int); 79 static int void_close(void *, int); 80 void closedown(); 81 void ypbindprog_3(); 82 void ypbindprog_2(); 83 void msgout(); 84 extern void cache_transport(); 85 extern void clean_cache(); 86 87 int 88 main(argc, argv) 89 int argc; 90 char **argv; 91 { 92 pid_t pid; 93 int pfd[2]; 94 char domain[256], servers[300]; 95 char **Argv = argv; 96 struct netconfig *nconf; 97 void *nc_handle; 98 int loopback_found = 0, udp_found = 0; 99 int pipe_closed = 0; 100 struct rlimit rl; 101 int connmaxrec = RPC_MAXDATASIZE; 102 uint32_t inet_tpts = 0, inet6_tpts = 0; 103 uint32_t inet_desired_tpts = 0, inet6_desired_tpts = 0; 104 bool_t exclbind = TRUE; 105 106 if (geteuid() != 0) { 107 (void) fprintf(stderr, "must be root to run %s\n", argv[0]); 108 exit(1); 109 } 110 111 argc--; 112 argv++; 113 114 while (argc > 0) { 115 if (strcmp(*argv, "-ypset") == 0) { 116 setok = YPSETALL; 117 } else if (strcmp(*argv, "-ypsetme") == 0) { 118 setok = YPSETLOCAL; 119 } else if (strcmp(*argv, "-broadcast") == 0) { 120 broadcast = TRUE; 121 } else { 122 fprintf(stderr, 123 "usage: ypbind [-broadcast] [-ypset] [-ypsetme]\n"); 124 exit(1); 125 } 126 argc--, 127 argv++; 128 } 129 130 if (setok == YPSETALL) { 131 fprintf(stderr, 132 "ypbind -ypset: allowing ypset! (this is REALLY insecure)\n"); 133 } 134 if (setok == YPSETLOCAL) { 135 fprintf(stderr, 136 "ypbind -ypsetme: allowing local ypset! (this is insecure)\n"); 137 } 138 if (broadcast == TRUE) { 139 fprintf(stderr, 140 "ypbind -broadcast: allowing broadcast! \ 141 (insecure and transport dependent)\n"); 142 } 143 144 if (getdomainname(domain, sizeof (domain)) == 0) { 145 sprintf(servers, "%s/%s/ypservers", BINDING, domain); 146 if (!broadcast && access(servers, R_OK) != 0) { 147 (void) fprintf(stderr, 148 "%s: no info on servers - run ypinit -c\n", Argv[0]); 149 exit(1); 150 } 151 } else { 152 (void) fprintf(stderr, "%s: domainname not set - exiting\n", 153 Argv[0]); 154 exit(1); 155 } 156 157 getrlimit(RLIMIT_NOFILE, &rl); 158 rl.rlim_cur = rl.rlim_max; 159 setrlimit(RLIMIT_NOFILE, &rl); 160 161 (void) enable_extended_FILE_stdio(-1, -1); 162 163 openlog("ypbind", LOG_PID, LOG_DAEMON); 164 165 /* 166 * If stdin looks like a TLI endpoint, we assume 167 * that we were started by a port monitor. If 168 * t_getstate fails with TBADF, this is not a 169 * TLI endpoint. 170 */ 171 _rpcpmstart = (t_getstate(0) != -1 || t_errno != TBADF); 172 173 if (!__rpcbind_is_up()) { 174 msgout("terminating: rpcbind is not running"); 175 exit(1); 176 } 177 178 if (_rpcpmstart) { 179 /* 180 * We were invoked by ypbind with the request on stdin. 181 * 182 * XXX - This is not the normal way ypbind is used 183 * and has never been tested. 184 */ 185 char *netid; 186 struct netconfig *nconf = NULL; 187 SVCXPRT *transp; 188 int pmclose; 189 extern char *getenv(); 190 191 /* 192 * Set non-blocking mode and maximum record size for 193 * connection oriented RPC transports. 194 */ 195 if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) { 196 msgout("unable to set maximum RPC record size"); 197 } 198 199 clear_bindings(); 200 if ((netid = getenv("NLSPROVIDER")) == NULL) { 201 #ifdef DEBUG 202 msgout("cannot get transport name"); 203 #endif 204 } else if ((nconf = getnetconfigent(netid)) == NULL) { 205 #ifdef DEBUG 206 msgout("cannot get transport info"); 207 #endif 208 } 209 210 pmclose = (t_getstate(0) != T_DATAXFER); 211 if ((transp = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) { 212 msgout("cannot create server handle"); 213 exit(1); 214 } 215 216 if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { 217 if ((setok != YPSETNONE) && 218 __rpc_negotiate_uid(transp->xp_fd)) { 219 syslog(LOG_ERR, 220 "could not negotiate with loopback tranport %s", 221 nconf->nc_netid); 222 } 223 } 224 if (nconf) 225 freenetconfigent(nconf); 226 if (!svc_reg(transp, YPBINDPROG, YPBINDVERS, ypbindprog_3, 0)) { 227 msgout("unable to register (YPBINDPROG, YPBINDVERS)."); 228 exit(1); 229 } 230 if (!svc_reg(transp, YPBINDPROG, YPBINDVERS_2, 231 ypbindprog_2, 0)) { 232 msgout( 233 "unable to register (YPBINDPROG, YPBINDVERS_2)."); 234 exit(1); 235 } 236 /* version 2 and version 1 are the same as far as we care */ 237 if (!svc_reg(transp, YPBINDPROG, YPBINDVERS_1, 238 ypbindprog_2, 0)) { 239 msgout( 240 "unable to register (YPBINDPROG, YPBINDVERS_1)."); 241 exit(1); 242 } 243 set_signal_handlers(); 244 if (pmclose) { 245 (void) signal(SIGALRM, closedown); 246 (void) alarm(_RPCSVC_CLOSEDOWN); 247 } 248 #ifdef INIT_DEFAULT 249 ypbind_init_default(); 250 #endif 251 svc_run(); 252 msgout("svc_run returned"); 253 exit(1); 254 /* NOTREACHED */ 255 } 256 #ifndef RPC_SVC_FG 257 /* 258 * In normal operation, ypbind forks a child to do all the work 259 * so that it can run in background. But, if the parent exits 260 * too soon during system startup, clients will start trying to 261 * talk to the child ypbind before it is ready. This can cause 262 * spurious client errors. 263 * 264 * To prevent these problems, the parent process creates a pipe, 265 * which is inherited by the child, and waits for the child to 266 * close its end. This happens explicitly before the child goes 267 * into svc_run(), or as a side-effect of exiting. 268 */ 269 if (pipe(pfd) == -1) { 270 perror("pipe"); 271 exit(1); 272 } 273 pid = fork(); 274 if (pid < 0) { 275 perror("cannot fork"); 276 exit(1); 277 } 278 if (pid) { 279 /* 280 * The parent waits for the child to close its end of 281 * the pipe (to indicate that it is ready to process 282 * requests). The read blocks until the child does 283 * a close (the "domain" array is just a handy buffer). 284 */ 285 close(pfd[1]); 286 read(pfd[0], domain, sizeof (domain)); 287 exit(0); 288 } 289 /* close all files except pfd[1] */ 290 (void) fdwalk(void_close, &pfd[1]); 291 (void) open("/dev/null", O_RDONLY); 292 (void) open("/dev/null", O_WRONLY); 293 (void) dup(1); 294 setsid(); 295 #endif 296 clean_cache(); /* make sure there are no left-over files */ 297 cache_okay = cache_check(); 298 cache_pid(); 299 300 /* 301 * Set non-blocking mode and maximum record size for 302 * connection oriented RPC transports. 303 */ 304 if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) { 305 msgout("unable to set maximum RPC record size"); 306 } 307 308 /* 309 * Prevent our non-priv udp and tcp ports bound w/wildcard addr 310 * from being hijacked by a bind to a more specific addr. 311 */ 312 if (!rpc_control(__RPC_SVC_EXCLBIND_SET, &exclbind)) { 313 msgout("warning: unable to set udp/tcp EXCLBIND"); 314 } 315 316 #ifdef INIT_DEFAULT 317 ypbind_init_default(); 318 #endif 319 320 nc_handle = __rpc_setconf("netpath"); /* open netconfig file */ 321 if (nc_handle == NULL) { 322 syslog(LOG_ERR, "could not read /etc/netconfig, exiting.."); 323 exit(1); 324 } 325 326 /* 327 * The parent waits for the child to close its end of 328 * the pipe (to indicate that it is ready to process 329 * requests). Now the non-diskless client will wait because the 330 * cache file is valid. 331 */ 332 if (cache_okay) { 333 close(pfd[1]); 334 pipe_closed = 1; 335 } 336 337 clear_bindings(); 338 339 while (nconf = __rpc_getconf(nc_handle)) { 340 SVCXPRT *xprt; 341 342 if (!__rpcbind_is_up()) { 343 msgout("terminating: rpcbind is not running"); 344 exit(1); 345 } 346 if ((xprt = svc_tp_create(ypbindprog_3, 347 YPBINDPROG, YPBINDVERS, nconf)) == NULL) { 348 msgout("terminating: cannot create rpcbind handle"); 349 exit(1); 350 } 351 352 cache_transport(nconf, xprt, YPBINDVERS); 353 354 /* support ypbind V2 and V1, but only on udp/tcp transports */ 355 if (((strcmp(nconf->nc_protofmly, NC_INET) == 0) || 356 (strcmp(nconf->nc_protofmly, NC_INET6))) && 357 ((nconf->nc_semantics == NC_TPI_CLTS) || 358 (nconf->nc_semantics == NC_TPI_COTS_ORD))) { 359 360 if (strcmp(nconf->nc_protofmly, NC_INET)) { 361 inet_desired_tpts |= 1 >> nconf->nc_semantics; 362 } else { 363 inet6_desired_tpts |= 1 >> nconf->nc_semantics; 364 } 365 366 (void) rpcb_unset(YPBINDPROG, YPBINDVERS_2, nconf); 367 if (!svc_reg(xprt, YPBINDPROG, YPBINDVERS_2, 368 ypbindprog_2, nconf)) { 369 syslog(LOG_INFO, 370 "unable to register (YPBINDPROG, YPBINDVERS_2) [%s]", 371 nconf->nc_netid); 372 continue; 373 } 374 375 cache_transport(nconf, xprt, YPBINDVERS_2); 376 377 /* For NC_INET, register v1 as well; error is fatal */ 378 if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { 379 (void) rpcb_unset(YPBINDPROG, YPBINDVERS_1, 380 nconf); 381 if (!svc_reg(xprt, YPBINDPROG, YPBINDVERS_1, 382 ypbindprog_2, nconf)) { 383 syslog(LOG_ERR, 384 "unable to register (YPBINDPROG, YPBINDVERS_1)."); 385 exit(1); 386 } 387 } 388 389 cache_transport(nconf, xprt, YPBINDVERS_1); 390 391 if (nconf->nc_semantics == NC_TPI_CLTS) 392 udp_found++; 393 394 if (strcmp(nconf->nc_protofmly, NC_INET)) { 395 inet_tpts |= 1 >> nconf->nc_semantics; 396 } else { 397 inet6_tpts |= 1 >> nconf->nc_semantics; 398 } 399 } 400 if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { 401 loopback_found++; 402 if ((setok != YPSETNONE) && 403 __rpc_negotiate_uid(xprt->xp_fd)) { 404 syslog(LOG_ERR, 405 "could not negotiate with loopback tranport %s", 406 nconf->nc_netid); 407 } 408 /* 409 * On a diskless client: 410 * The parent waits for the child to close its end of 411 * the pipe (to indicate that it is ready to process 412 * requests). Now the diskless client will wait 413 * only if ypbind is registered on the loopback. 414 */ 415 if ((!pipe_closed) && 416 ((nconf->nc_semantics == NC_TPI_COTS) || 417 (nconf->nc_semantics == NC_TPI_COTS_ORD))) { 418 close(pfd[1]); 419 pipe_closed = 1; 420 } 421 } 422 } 423 424 /* Did we manage to register all IPv4 or all IPv6 transports ? */ 425 if (inet_tpts != 0 && inet_tpts != inet_desired_tpts) { 426 syslog(LOG_ERR, 427 "unable to register all %s transports, exiting..", 428 NC_INET); 429 exit(1); 430 } else if (inet6_tpts != 0 && inet6_tpts != inet6_desired_tpts) { 431 syslog(LOG_ERR, 432 "unable to register all %s transports, exiting..", 433 NC_INET6); 434 exit(1); 435 } 436 437 if (!pipe_closed) { 438 close(pfd[1]); 439 pipe_closed = 1; 440 } 441 __rpc_endconf(nc_handle); 442 if (!loopback_found) { 443 syslog(LOG_ERR, 444 "could not find loopback transports, exiting.."); 445 exit(1); 446 } 447 if (!udp_found) { 448 syslog(LOG_ERR, 449 "could not find inet-clts (udp) transport, exiting.."); 450 exit(1); 451 } 452 set_signal_handlers(); 453 svc_run(); 454 syslog(LOG_ERR, "svc_run returned, exiting.."); 455 exit(1); 456 /* NOTREACHED */ 457 } 458 459 /* 460 * Callback function for fdwalk() to close all files. 461 */ 462 static int 463 void_close(void *pfdp, int fd) 464 { 465 if (fd != *(int *)pfdp) 466 (void) close(fd); 467 return (0); 468 } 469 470 void 471 ypbindprog_3(rqstp, transp) 472 struct svc_req *rqstp; 473 register SVCXPRT *transp; 474 { 475 union { 476 ypbind_domain ypbindproc_domain_3_arg; 477 ypbind_setdom ypbindproc_setdom_3_arg; 478 } argument; 479 char *result; 480 bool_t (*xdr_argument)(), (*xdr_result)(); 481 char *(*local)(); 482 483 if (sigcld_event) 484 broadcast_proc_exit(); 485 486 _rpcsvcdirty = 1; 487 switch (rqstp->rq_proc) { 488 case YPBINDPROC_NULL: 489 xdr_argument = xdr_void; 490 xdr_result = xdr_void; 491 local = (char *(*)()) ypbindproc_null_3; 492 break; 493 494 case YPBINDPROC_DOMAIN: 495 xdr_argument = xdr_ypbind_domain; 496 xdr_result = xdr_ypbind_resp; 497 local = (char *(*)()) ypbindproc_domain_3; 498 break; 499 500 case YPBINDPROC_SETDOM: 501 xdr_argument = xdr_ypbind_setdom; 502 xdr_result = xdr_void; 503 local = (char *(*)()) ypbindproc_setdom_3; 504 break; 505 506 default: 507 svcerr_noproc(transp); 508 _rpcsvcdirty = 0; 509 return; 510 } 511 (void) memset((char *)&argument, 0, sizeof (argument)); 512 if (!svc_getargs(transp, (xdrproc_t)xdr_argument, (char *)&argument)) { 513 svcerr_decode(transp); 514 _rpcsvcdirty = 0; 515 return; 516 } 517 if (rqstp->rq_proc == YPBINDPROC_SETDOM) 518 result = (*local)(&argument, rqstp, transp); 519 else 520 result = (*local)(&argument, rqstp); 521 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { 522 svcerr_systemerr(transp); 523 } 524 if (!svc_freeargs(transp, (xdrproc_t)xdr_argument, (char *)&argument)) { 525 syslog(LOG_ERR, "unable to free arguments"); 526 exit(1); 527 } 528 _rpcsvcdirty = 0; 529 } 530 531 void 532 ypbindprog_2(rqstp, transp) 533 struct svc_req *rqstp; 534 register SVCXPRT *transp; 535 { 536 union { 537 domainname_2 ypbindproc_domain_2_arg; 538 ypbind_setdom_2 ypbindproc_setdom_2_arg; 539 } argument; 540 char *result; 541 bool_t (*xdr_argument)(), (*xdr_result)(); 542 char *(*local)(); 543 544 if (sigcld_event) 545 broadcast_proc_exit(); 546 547 _rpcsvcdirty = 1; 548 switch (rqstp->rq_proc) { 549 case YPBINDPROC_NULL: 550 xdr_argument = xdr_void; 551 xdr_result = xdr_void; 552 /* XXX - don't need two null procedures */ 553 local = (char *(*)()) ypbindproc_null_3; 554 break; 555 556 case YPBINDPROC_DOMAIN: 557 xdr_argument = (bool_t (*)())xdr_ypdomain_wrap_string; 558 xdr_result = xdr_ypbind_resp_2; 559 local = (char *(*)()) ypbindproc_domain_2; 560 break; 561 562 case YPBINDPROC_SETDOM: /* not supported, fall through to error */ 563 default: 564 svcerr_noproc(transp); 565 _rpcsvcdirty = 0; 566 return; 567 } 568 (void) memset((char *)&argument, 0, sizeof (argument)); 569 if (!svc_getargs(transp, (xdrproc_t)xdr_argument, (char *)&argument)) { 570 svcerr_decode(transp); 571 _rpcsvcdirty = 0; 572 return; 573 } 574 result = (*local)(&argument, rqstp); 575 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { 576 svcerr_systemerr(transp); 577 } 578 if (!svc_freeargs(transp, (xdrproc_t)xdr_argument, (char *)&argument)) { 579 syslog(LOG_ERR, "unable to free arguments"); 580 exit(1); 581 } 582 _rpcsvcdirty = 0; 583 } 584 585 /* 586 * We clear out any old bindings that might have been 587 * left behind. If there is already a ypbind running, 588 * it will no longer get requests. We are in control 589 * now. We ignore the error from rpcb_unset() because 590 * this is just a "best effort". If the rpcb_unset() 591 * does fail, we will get an error in svc_reg(). By 592 * using 0 for the last argument we are telling the 593 * portmapper to remove the bindings for all transports. 594 */ 595 static 596 void 597 clear_bindings() 598 { 599 rpcb_unset(YPBINDPROG, YPBINDVERS, 0); 600 rpcb_unset(YPBINDPROG, YPBINDVERS_2, 0); 601 rpcb_unset(YPBINDPROG, YPBINDVERS_1, 0); 602 } 603 604 /* 605 * This routine is called when we are killed (by most signals). 606 * It first tries to unregister with the portmapper. Then it 607 * resets the signal handler to the default so that if we get 608 * the same signal, we will just go away. We clean up our 609 * children by doing a hold in SIGTERM and then killing the 610 * process group (-getpid()) with SIGTERM. Finally, we redeliver 611 * the signal to ourselves (the handler was reset to the default) 612 * so that we will do the normal handling (e.g., coredump). 613 * If we can't kill ourselves, we get drastic and just exit 614 * after sleeping for a couple of seconds. 615 * 616 * This code was taken from the SunOS version of ypbind. 617 */ 618 static 619 void 620 unregister(int code) 621 { 622 clear_bindings(); 623 clean_cache(); 624 signal(code, SIG_DFL); /* to prevent recursive calls to unregister */ 625 fprintf(stderr, "ypbind: goind down on signal %d\n", code); 626 sighold(SIGCHLD); 627 sighold(SIGTERM); 628 kill(-getpid(), SIGTERM); /* kill process group (i.e., children) */ 629 sigrelse(SIGTERM); 630 kill(getpid(), code); /* throw signal again */ 631 sleep(2); 632 exit(-1); 633 } 634 635 static 636 void 637 set_signal_handlers() 638 { 639 int i; 640 641 for (i = 1; i <= SIGTERM; i++) { 642 if (i == SIGCHLD) 643 continue; 644 else if (i == SIGHUP) 645 signal(i, SIG_IGN); 646 else 647 signal(i, unregister); 648 } 649 } 650 651 void 652 msgout(msg) 653 char *msg; 654 { 655 #ifdef RPC_SVC_FG 656 if (_rpcpmstart) 657 syslog(LOG_ERR, msg); 658 else 659 (void) fprintf(stderr, "%s\n", msg); 660 #else 661 syslog(LOG_ERR, msg); 662 #endif 663 } 664 665 void 666 closedown() 667 { 668 if (_rpcsvcdirty == 0) { 669 int i, openfd; 670 struct t_info tinfo; 671 672 if (t_getinfo(0, &tinfo) || (tinfo.servtype == T_CLTS)) 673 exit(0); 674 675 for (i = 0, openfd = 0; i < svc_max_pollfd && openfd < 2; i++) 676 if (svc_pollfd[i].fd >= 0) 677 openfd++; 678 679 if (openfd <= 1) 680 exit(0); 681 } 682 (void) alarm(_RPCSVC_CLOSEDOWN); 683 } 684