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 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 /* 29 * University Copyright- Copyright (c) 1982, 1986, 1988 30 * The Regents of the University of California 31 * All Rights Reserved 32 * 33 * University Acknowledgment- Portions of this document are derived from 34 * software developed by the University of California, Berkeley, and its 35 * contributors. 36 */ 37 38 #pragma ident "%Z%%M% %I% %E% SMI" 39 40 /* 41 * rpcbind.c 42 * Implements the program, version to address mapping for rpc. 43 * 44 */ 45 46 #include <dlfcn.h> 47 #include <stdio.h> 48 #include <sys/types.h> 49 #include <unistd.h> 50 #include <stdlib.h> 51 #include <string.h> 52 #include <rpc/rpc.h> 53 #include <netconfig.h> 54 #include <netdir.h> 55 #include <errno.h> 56 #include <sys/wait.h> 57 #include <signal.h> 58 #include <string.h> 59 #include <stdlib.h> 60 #include <thread.h> 61 #include <synch.h> 62 #include <deflt.h> 63 #include <stdarg.h> 64 #ifdef PORTMAP 65 #include <netinet/in.h> 66 #endif 67 #include <arpa/inet.h> 68 #include <sys/termios.h> 69 #include "rpcbind.h" 70 #include <sys/syslog.h> 71 #include <sys/stat.h> 72 #include <syslog.h> 73 #include <string.h> 74 #include <sys/time.h> 75 #include <sys/resource.h> 76 #include <rpcsvc/daemon_utils.h> 77 #include <priv_utils.h> 78 #include <libscf.h> 79 80 #ifdef PORTMAP 81 extern void pmap_service(struct svc_req *, SVCXPRT *xprt); 82 #endif 83 extern void rpcb_service_3(struct svc_req *, SVCXPRT *xprt); 84 extern void rpcb_service_4(struct svc_req *, SVCXPRT *xprt); 85 extern void read_warmstart(void); 86 extern void write_warmstart(void); 87 extern int Is_ipv6present(void); 88 89 #define MAX_FILEDESC_LIMIT 1023 90 91 static void terminate(int); 92 static void detachfromtty(void); 93 static void parseargs(int, char *[]); 94 static void rbllist_add(ulong_t, ulong_t, struct netconfig *, struct netbuf *); 95 static int init_transport(struct netconfig *); 96 static int check_netconfig(void); 97 98 static boolean_t check_hostserv(struct netconfig *, const char *, const char *); 99 static void rpcb_check_init(void); 100 101 102 /* Global variables */ 103 #ifdef ND_DEBUG 104 int debugging = 1; /* Tell me what's going on */ 105 #else 106 int debugging = 0; /* Tell me what's going on */ 107 #endif 108 static int ipv6flag = 0; 109 int doabort = 0; /* When debugging, do an abort on errors */ 110 static int listen_backlog = 64; 111 rpcblist_ptr list_rbl; /* A list of version 3/4 rpcbind services */ 112 char *loopback_dg; /* Datagram loopback transport, for set and unset */ 113 char *loopback_vc; /* COTS loopback transport, for set and unset */ 114 char *loopback_vc_ord; /* COTS_ORD loopback transport, for set and unset */ 115 116 boolean_t verboselog = B_FALSE; 117 boolean_t wrap_enabled = B_FALSE; 118 boolean_t allow_indirect = B_TRUE; 119 120 /* Local Variable */ 121 static int warmstart = 0; /* Grab a old copy of registrations */ 122 123 #ifdef PORTMAP 124 PMAPLIST *list_pml; /* A list of version 2 rpcbind services */ 125 char *udptrans; /* Name of UDP transport */ 126 char *tcptrans; /* Name of TCP transport */ 127 char *udp_uaddr; /* Universal UDP address */ 128 char *tcp_uaddr; /* Universal TCP address */ 129 #endif 130 static char servname[] = "rpcbind"; 131 static char superuser[] = "superuser"; 132 133 static const char daemon_dir[] = DAEMON_DIR; 134 135 int 136 main(int argc, char *argv[]) 137 { 138 struct netconfig *nconf; 139 void *nc_handle; /* Net config handle */ 140 struct rlimit rl; 141 int maxrecsz = RPC_MAXDATASIZE; 142 143 parseargs(argc, argv); 144 145 getrlimit(RLIMIT_NOFILE, &rl); 146 147 if (rl.rlim_cur < MAX_FILEDESC_LIMIT) { 148 if (rl.rlim_max <= MAX_FILEDESC_LIMIT) 149 rl.rlim_cur = rl.rlim_max; 150 else 151 rl.rlim_cur = MAX_FILEDESC_LIMIT; 152 setrlimit(RLIMIT_NOFILE, &rl); 153 } 154 openlog("rpcbind", LOG_CONS, LOG_DAEMON); 155 156 /* 157 * Create the daemon directory in /var/run 158 */ 159 if (mkdir(daemon_dir, DAEMON_DIR_MODE) == 0 || errno == EEXIST) { 160 chmod(daemon_dir, DAEMON_DIR_MODE); 161 chown(daemon_dir, DAEMON_UID, DAEMON_GID); 162 } else { 163 syslog(LOG_ERR, "failed to create \"%s\": %m", daemon_dir); 164 } 165 166 /* 167 * These privileges are required for the t_bind check rpcbind uses 168 * to determine whether a service is still live or not. 169 */ 170 if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, DAEMON_UID, 171 DAEMON_GID, PRIV_NET_PRIVADDR, PRIV_SYS_NFS, (char *)NULL) == -1) { 172 fprintf(stderr, "Insufficient privileges\n"); 173 exit(1); 174 } 175 176 /* 177 * Enable non-blocking mode and maximum record size checks for 178 * connection oriented transports. 179 */ 180 if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) { 181 syslog(LOG_INFO, "unable to set RPC max record size"); 182 } 183 184 nc_handle = setnetconfig(); /* open netconfig file */ 185 if (nc_handle == NULL) { 186 syslog(LOG_ERR, "could not read /etc/netconfig"); 187 exit(1); 188 } 189 loopback_dg = ""; 190 loopback_vc = ""; 191 loopback_vc_ord = ""; 192 #ifdef PORTMAP 193 udptrans = ""; 194 tcptrans = ""; 195 #endif 196 197 { 198 /* 199 * rpcbind is the first application to encounter the 200 * various netconfig files. check_netconfig() verifies 201 * that they are set up correctly and complains loudly 202 * if not. 203 */ 204 int trouble; 205 206 trouble = check_netconfig(); 207 if (trouble) { 208 syslog(LOG_ERR, 209 "%s: found %d errors with network configuration files. Exiting.", 210 argv[0], trouble); 211 fprintf(stderr, 212 "%s: found %d errors with network configuration files. Exiting.\n", 213 argv[0], trouble); 214 exit(1); 215 } 216 } 217 ipv6flag = Is_ipv6present(); 218 rpcb_check_init(); 219 while (nconf = getnetconfig(nc_handle)) { 220 if (nconf->nc_flag & NC_VISIBLE) 221 init_transport(nconf); 222 } 223 endnetconfig(nc_handle); 224 225 if ((loopback_dg[0] == NULL) && (loopback_vc[0] == NULL) && 226 (loopback_vc_ord[0] == NULL)) { 227 syslog(LOG_ERR, "could not find loopback transports"); 228 exit(1); 229 } 230 231 /* catch the usual termination signals for graceful exit */ 232 (void) signal(SIGINT, terminate); 233 (void) signal(SIGTERM, terminate); 234 (void) signal(SIGQUIT, terminate); 235 /* ignore others that could get sent */ 236 (void) signal(SIGHUP, SIG_IGN); 237 (void) signal(SIGUSR1, SIG_IGN); 238 (void) signal(SIGUSR2, SIG_IGN); 239 if (warmstart) { 240 read_warmstart(); 241 } 242 if (debugging) { 243 printf("rpcbind debugging enabled."); 244 if (doabort) { 245 printf(" Will abort on errors!\n"); 246 } else { 247 printf("\n"); 248 } 249 } else { 250 detachfromtty(); 251 } 252 253 /* These are basic privileges we do not need */ 254 __fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_SESSION, 255 PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL); 256 257 my_svc_run(); 258 syslog(LOG_ERR, "svc_run returned unexpectedly"); 259 rpcbind_abort(); 260 /* NOTREACHED */ 261 } 262 263 /* 264 * Increments a counter each time a problem is found with the network 265 * configuration information. 266 */ 267 static int 268 check_netconfig(void) 269 { 270 void *nc; 271 void *dlcookie; 272 int busted = 0; 273 int i; 274 int lo_clts_found = 0, lo_cots_found = 0, lo_cotsord_found = 0; 275 struct netconfig *nconf, *np; 276 struct stat sb; 277 278 nc = setnetconfig(); 279 if (nc == NULL) { 280 if (debugging) 281 fprintf(stderr, 282 "setnetconfig() failed: %s\n", nc_sperror()); 283 syslog(LOG_ALERT, "setnetconfig() failed: %s", nc_sperror()); 284 return (1); 285 } 286 while (np = getnetconfig(nc)) { 287 if ((np->nc_flag & NC_VISIBLE) == 0) 288 continue; 289 if (debugging) 290 fprintf(stderr, "checking netid \"%s\"\n", 291 np->nc_netid); 292 if (strcmp(np->nc_protofmly, NC_LOOPBACK) == 0) 293 switch (np->nc_semantics) { 294 case NC_TPI_CLTS: 295 lo_clts_found = 1; 296 break; 297 298 case NC_TPI_COTS: 299 lo_cots_found = 1; 300 break; 301 302 case NC_TPI_COTS_ORD: 303 lo_cotsord_found = 1; 304 break; 305 } 306 if (stat(np->nc_device, &sb) == -1 && errno == ENOENT) { 307 if (debugging) 308 fprintf(stderr, "\tdevice %s does not exist\n", 309 np->nc_device); 310 syslog(LOG_ERR, "netid %s: device %s does not exist", 311 np->nc_netid, np->nc_device); 312 busted++; 313 } else 314 if (debugging) 315 fprintf(stderr, "\tdevice %s present\n", 316 np->nc_device); 317 for (i = 0; i < np->nc_nlookups; i++) { 318 char *libname = np->nc_lookups[i]; 319 320 if ((dlcookie = dlopen(libname, RTLD_LAZY)) == NULL) { 321 char *dlerrstr; 322 323 dlerrstr = dlerror(); 324 if (debugging) { 325 fprintf(stderr, 326 "\tnetid %s: dlopen of name-to-address library %s failed\ndlerror: %s", 327 np->nc_netid, libname, dlerrstr ? dlerrstr : ""); 328 } 329 syslog(LOG_ERR, 330 "netid %s: dlopen of name-to-address library %s failed", 331 np->nc_netid, libname); 332 if (dlerrstr) 333 syslog(LOG_ERR, "%s", dlerrstr); 334 busted++; 335 } else { 336 if (debugging) 337 fprintf(stderr, 338 "\tdlopen of name-to-address library %s succeeded\n", libname); 339 (void) dlclose(dlcookie); 340 } 341 } 342 nconf = getnetconfigent(np->nc_netid); 343 344 if (!check_hostserv(nconf, HOST_SELF, "")) 345 busted++; 346 if (!check_hostserv(nconf, HOST_SELF_CONNECT, "")) 347 busted++; 348 if (!check_hostserv(nconf, HOST_SELF, "rpcbind")) 349 busted++; 350 if (!check_hostserv(nconf, HOST_SELF_CONNECT, "rpcbind")) 351 busted++; 352 353 freenetconfigent(nconf); 354 } 355 endnetconfig(nc); 356 357 if (lo_clts_found) { 358 if (debugging) 359 fprintf(stderr, "Found CLTS loopback transport\n"); 360 } else { 361 syslog(LOG_ALERT, "no CLTS loopback transport found\n"); 362 if (debugging) 363 fprintf(stderr, "no CLTS loopback transport found\n"); 364 } 365 if (lo_cots_found) { 366 if (debugging) 367 fprintf(stderr, "Found COTS loopback transport\n"); 368 } else { 369 syslog(LOG_ALERT, "no COTS loopback transport found\n"); 370 if (debugging) 371 fprintf(stderr, "no COTS loopback transport found\n"); 372 } 373 if (lo_cotsord_found) { 374 if (debugging) 375 fprintf(stderr, "Found COTS ORD loopback transport\n"); 376 } else { 377 syslog(LOG_ALERT, "no COTS ORD loopback transport found\n"); 378 if (debugging) 379 fprintf(stderr, 380 "no COTS ORD loopback transport found\n"); 381 } 382 383 return (busted); 384 } 385 386 /* 387 * Adds the entry into the rpcbind database. 388 * If PORTMAP, then for UDP and TCP, it adds the entries for version 2 also 389 * Returns 0 if succeeds, else fails 390 */ 391 static int 392 init_transport(struct netconfig *nconf) 393 { 394 int fd; 395 struct t_bind *taddr, *baddr; 396 SVCXPRT *my_xprt; 397 struct nd_addrlist *nas; 398 struct nd_hostserv hs; 399 int status; /* bound checking ? */ 400 static int msgprt = 0; 401 402 static int setopt_reuseaddr(int); 403 static int setup_callit(int); 404 405 if ((nconf->nc_semantics != NC_TPI_CLTS) && 406 (nconf->nc_semantics != NC_TPI_COTS) && 407 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 408 return (1); /* not my type */ 409 410 if ((strcmp(nconf->nc_protofmly, NC_INET6) == 0) && !ipv6flag) { 411 if (!msgprt) 412 syslog(LOG_DEBUG, 413 "/etc/netconfig has IPv6 entries but IPv6 is not configured"); 414 msgprt++; 415 return (1); 416 } 417 #ifdef ND_DEBUG 418 { 419 int i; 420 char **s; 421 422 (void) fprintf(stderr, "%s: %d lookup routines :\n", 423 nconf->nc_netid, nconf->nc_nlookups); 424 for (i = 0, s = nconf->nc_lookups; i < nconf->nc_nlookups; i++, s++) 425 fprintf(stderr, "[%d] - %s\n", i, *s); 426 } 427 #endif 428 429 if ((fd = t_open(nconf->nc_device, O_RDWR, NULL)) < 0) { 430 syslog(LOG_ERR, "%s: cannot open connection: %s", 431 nconf->nc_netid, t_errlist[t_errno]); 432 return (1); 433 } 434 435 /* 436 * Negotiate for returning the ucred of the caller. This should 437 * done before enabling the endpoint for service via 438 * t_bind() so that requests to rpcbind contain the uid. 439 */ 440 svc_fd_negotiate_ucred(fd); 441 442 taddr = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR); 443 baddr = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR); 444 if ((baddr == NULL) || (taddr == NULL)) { 445 syslog(LOG_ERR, "%s: cannot allocate netbuf: %s", 446 nconf->nc_netid, t_errlist[t_errno]); 447 exit(1); 448 } 449 450 /* Get rpcbind's address on this transport */ 451 hs.h_host = HOST_SELF; 452 hs.h_serv = servname; 453 if (netdir_getbyname(nconf, &hs, &nas)) 454 goto error; 455 456 /* Copy the address */ 457 taddr->addr.len = nas->n_addrs->len; 458 memcpy(taddr->addr.buf, nas->n_addrs->buf, (int)nas->n_addrs->len); 459 #ifdef ND_DEBUG 460 { 461 /* for debugging print out our universal address */ 462 char *uaddr; 463 464 uaddr = taddr2uaddr(nconf, nas->n_addrs); 465 (void) fprintf(stderr, "rpcbind : my address is %s\n", uaddr); 466 (void) free(uaddr); 467 } 468 #endif 469 netdir_free((char *)nas, ND_ADDRLIST); 470 471 if (nconf->nc_semantics == NC_TPI_CLTS) 472 taddr->qlen = 0; 473 else 474 taddr->qlen = listen_backlog; 475 476 if (strcmp(nconf->nc_proto, NC_TCP) == 0) { 477 /* 478 * Sm: If we are running then set SO_REUSEADDR option 479 * so that we can bind to our preferred address even if 480 * previous connections are in FIN_WAIT state 481 */ 482 #ifdef ND_DEBUG 483 fprintf(stdout, "Setting SO_REUSEADDR.\n"); 484 #endif 485 if (setopt_reuseaddr(fd) == -1) { 486 syslog(LOG_ERR, "Couldn't set SO_REUSEADDR option"); 487 } 488 } 489 490 if (t_bind(fd, taddr, baddr) != 0) { 491 syslog(LOG_ERR, "%s: cannot bind: %s", 492 nconf->nc_netid, t_errlist[t_errno]); 493 goto error; 494 } 495 496 497 if (memcmp(taddr->addr.buf, baddr->addr.buf, (int)baddr->addr.len)) { 498 syslog(LOG_ERR, "%s: address in use", nconf->nc_netid); 499 goto error; 500 } 501 502 my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, baddr, 0, 0); 503 if (my_xprt == (SVCXPRT *)NULL) { 504 syslog(LOG_ERR, "%s: could not create service", 505 nconf->nc_netid); 506 goto error; 507 } 508 509 /* set up multicast address for RPC CALL_IT, IPv6 */ 510 511 if ((strcmp(nconf->nc_protofmly, NC_INET6) == 0) && 512 (strcmp(nconf->nc_proto, NC_UDP) == 0)) { 513 if (setup_callit(fd) < 0) { 514 syslog(LOG_ERR, "Unable to join IPv6 multicast group \ 515 for rpc broadcast %s", RPCB_MULTICAST_ADDR); 516 } 517 } 518 519 if (strcmp(nconf->nc_proto, NC_TCP) == 0) { 520 svc_control(my_xprt, SVCSET_KEEPALIVE, (void *) TRUE); 521 } 522 523 #ifdef PORTMAP 524 /* 525 * Register both the versions for tcp/ip and udp/ip 526 */ 527 if ((strcmp(nconf->nc_protofmly, NC_INET) == 0) && 528 ((strcmp(nconf->nc_proto, NC_TCP) == 0) || 529 (strcmp(nconf->nc_proto, NC_UDP) == 0))) { 530 PMAPLIST *pml; 531 532 if (!svc_register(my_xprt, PMAPPROG, PMAPVERS, 533 pmap_service, NULL)) { 534 syslog(LOG_ERR, "could not register on %s", 535 nconf->nc_netid); 536 goto error; 537 } 538 pml = (PMAPLIST *)malloc((uint_t)sizeof (PMAPLIST)); 539 if (pml == (PMAPLIST *)NULL) { 540 syslog(LOG_ERR, "no memory!"); 541 exit(1); 542 } 543 pml->pml_map.pm_prog = PMAPPROG; 544 pml->pml_map.pm_vers = PMAPVERS; 545 pml->pml_map.pm_port = PMAPPORT; 546 if (strcmp(nconf->nc_proto, NC_TCP) == 0) { 547 if (tcptrans[0]) { 548 syslog(LOG_ERR, 549 "cannot have more than one TCP transport"); 550 goto error; 551 } 552 tcptrans = strdup(nconf->nc_netid); 553 pml->pml_map.pm_prot = IPPROTO_TCP; 554 555 /* Let's snarf the universal address */ 556 /* "h1.h2.h3.h4.p1.p2" */ 557 tcp_uaddr = taddr2uaddr(nconf, &baddr->addr); 558 } else { 559 if (udptrans[0]) { 560 syslog(LOG_ERR, 561 "cannot have more than one UDP transport"); 562 goto error; 563 } 564 udptrans = strdup(nconf->nc_netid); 565 pml->pml_map.pm_prot = IPPROTO_UDP; 566 567 /* Let's snarf the universal address */ 568 /* "h1.h2.h3.h4.p1.p2" */ 569 udp_uaddr = taddr2uaddr(nconf, &baddr->addr); 570 } 571 pml->pml_next = list_pml; 572 list_pml = pml; 573 574 /* Add version 3 information */ 575 pml = (PMAPLIST *)malloc((uint_t)sizeof (PMAPLIST)); 576 if (pml == (PMAPLIST *)NULL) { 577 syslog(LOG_ERR, "no memory!"); 578 exit(1); 579 } 580 pml->pml_map = list_pml->pml_map; 581 pml->pml_map.pm_vers = RPCBVERS; 582 pml->pml_next = list_pml; 583 list_pml = pml; 584 585 /* Add version 4 information */ 586 pml = (PMAPLIST *)malloc((uint_t)sizeof (PMAPLIST)); 587 if (pml == (PMAPLIST *)NULL) { 588 syslog(LOG_ERR, "no memory!"); 589 exit(1); 590 } 591 pml->pml_map = list_pml->pml_map; 592 pml->pml_map.pm_vers = RPCBVERS4; 593 pml->pml_next = list_pml; 594 list_pml = pml; 595 596 /* Also add version 2 stuff to rpcbind list */ 597 rbllist_add(PMAPPROG, PMAPVERS, nconf, &baddr->addr); 598 } 599 #endif 600 601 /* version 3 registration */ 602 if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS, rpcb_service_3, NULL)) { 603 syslog(LOG_ERR, "could not register %s version 3", 604 nconf->nc_netid); 605 goto error; 606 } 607 rbllist_add(RPCBPROG, RPCBVERS, nconf, &baddr->addr); 608 609 /* version 4 registration */ 610 if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS4, rpcb_service_4, NULL)) { 611 syslog(LOG_ERR, "could not register %s version 4", 612 nconf->nc_netid); 613 goto error; 614 } 615 rbllist_add(RPCBPROG, RPCBVERS4, nconf, &baddr->addr); 616 617 if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { 618 if (nconf->nc_semantics == NC_TPI_CLTS) 619 loopback_dg = strdup(nconf->nc_netid); 620 else if (nconf->nc_semantics == NC_TPI_COTS) 621 loopback_vc = strdup(nconf->nc_netid); 622 else if (nconf->nc_semantics == NC_TPI_COTS_ORD) 623 loopback_vc_ord = strdup(nconf->nc_netid); 624 } 625 626 /* decide if bound checking works for this transport */ 627 status = add_bndlist(nconf, taddr, baddr); 628 #ifdef BIND_DEBUG 629 if (status < 0) { 630 fprintf(stderr, "Error in finding bind status for %s\n", 631 nconf->nc_netid); 632 } else if (status == 0) { 633 fprintf(stderr, "check binding for %s\n", 634 nconf->nc_netid); 635 } else if (status > 0) { 636 fprintf(stderr, "No check binding for %s\n", 637 nconf->nc_netid); 638 } 639 #endif 640 /* 641 * rmtcall only supported on CLTS transports for now. 642 * only needed when we are allowing indirect calls 643 */ 644 if (allow_indirect && nconf->nc_semantics == NC_TPI_CLTS) { 645 status = create_rmtcall_fd(nconf); 646 647 #ifdef BIND_DEBUG 648 if (status < 0) { 649 fprintf(stderr, "Could not create rmtcall fd for %s\n", 650 nconf->nc_netid); 651 } else { 652 fprintf(stderr, "rmtcall fd for %s is %d\n", 653 nconf->nc_netid, status); 654 } 655 #endif 656 } 657 (void) t_free((char *)taddr, T_BIND); 658 (void) t_free((char *)baddr, T_BIND); 659 return (0); 660 error: 661 (void) t_free((char *)taddr, T_BIND); 662 (void) t_free((char *)baddr, T_BIND); 663 (void) t_close(fd); 664 return (1); 665 } 666 667 static void 668 rbllist_add(ulong_t prog, ulong_t vers, struct netconfig *nconf, 669 struct netbuf *addr) 670 { 671 rpcblist_ptr rbl; 672 673 rbl = (rpcblist_ptr)malloc((uint_t)sizeof (rpcblist)); 674 if (rbl == (rpcblist_ptr)NULL) { 675 syslog(LOG_ERR, "no memory!"); 676 exit(1); 677 } 678 679 rbl->rpcb_map.r_prog = prog; 680 rbl->rpcb_map.r_vers = vers; 681 rbl->rpcb_map.r_netid = strdup(nconf->nc_netid); 682 rbl->rpcb_map.r_addr = taddr2uaddr(nconf, addr); 683 rbl->rpcb_map.r_owner = strdup(superuser); 684 rbl->rpcb_next = list_rbl; /* Attach to global list */ 685 list_rbl = rbl; 686 } 687 688 /* 689 * Catch the signal and die 690 */ 691 /* ARGSUSED */ 692 static void 693 terminate(int sig) 694 { 695 syslog(LOG_ERR, "rpcbind terminating on signal."); 696 write_warmstart(); /* Dump yourself */ 697 exit(2); 698 } 699 700 void 701 rpcbind_abort(void) 702 { 703 write_warmstart(); /* Dump yourself */ 704 abort(); 705 } 706 707 /* 708 * detach from tty 709 */ 710 static void 711 detachfromtty(void) 712 { 713 close(0); 714 close(1); 715 close(2); 716 switch (forkall()) { 717 case (pid_t)-1: 718 perror("fork"); 719 break; 720 case 0: 721 break; 722 default: 723 exit(0); 724 } 725 setsid(); 726 (void) open("/dev/null", O_RDWR, 0); 727 dup(0); 728 dup(0); 729 } 730 731 /* get command line options */ 732 static void 733 parseargs(int argc, char *argv[]) 734 { 735 int c; 736 int tmp; 737 738 while ((c = getopt(argc, argv, "dwal:")) != EOF) { 739 switch (c) { 740 case 'd': 741 debugging = 1; 742 break; 743 case 'a': 744 doabort = 1; /* when debugging, do an abort on */ 745 break; /* errors; for rpcbind developers */ 746 /* only! */ 747 case 'w': 748 warmstart = 1; 749 break; 750 751 case 'l': 752 if (sscanf(optarg, "%d", &tmp)) { 753 if (tmp > listen_backlog) { 754 listen_backlog = tmp; 755 } 756 } 757 break; 758 default: /* error */ 759 fprintf(stderr, 760 "usage: rpcbind [-d] [-w] [-l listen_backlog]\n"); 761 exit(1); 762 } 763 } 764 if (doabort && !debugging) { 765 fprintf(stderr, 766 "-a (abort) specified without -d (debugging) -- ignored.\n"); 767 doabort = 0; 768 } 769 } 770 771 static int 772 setopt_reuseaddr(int fd) 773 { 774 struct t_optmgmt req, resp; 775 struct opthdr *opt; 776 char reqbuf[128]; 777 int *ip; 778 779 opt = (struct opthdr *)reqbuf; 780 opt->level = SOL_SOCKET; 781 opt->name = SO_REUSEADDR; 782 opt->len = sizeof (int); 783 784 ip = (int *)&reqbuf[sizeof (struct opthdr)]; 785 *ip = 1; 786 787 req.flags = T_NEGOTIATE; 788 req.opt.len = sizeof (struct opthdr) + opt->len; 789 req.opt.buf = (char *)opt; 790 791 resp.flags = 0; 792 resp.opt.buf = reqbuf; 793 resp.opt.maxlen = sizeof (reqbuf); 794 795 if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) { 796 t_error("t_optmgmt"); 797 return (-1); 798 } 799 return (0); 800 } 801 802 static int 803 setup_callit(int fd) 804 { 805 struct ipv6_mreq mreq; 806 struct t_optmgmt req, resp; 807 struct opthdr *opt; 808 char reqbuf[ sizeof (struct ipv6_mreq) + 24]; 809 struct ipv6_mreq *pmreq; 810 811 opt = (struct opthdr *)reqbuf; 812 813 opt->level = IPPROTO_IPV6; 814 opt->name = IPV6_ADD_MEMBERSHIP; 815 opt->len = sizeof (struct ipv6_mreq); 816 817 /* multicast address */ 818 (void) inet_pton(AF_INET6, RPCB_MULTICAST_ADDR, 819 mreq.ipv6mr_multiaddr.s6_addr); 820 mreq.ipv6mr_interface = 0; 821 822 /* insert it into opt */ 823 pmreq = (struct ipv6_mreq *)&reqbuf[sizeof (struct opthdr)]; 824 memcpy(pmreq, &mreq, sizeof (struct ipv6_mreq)); 825 826 req.flags = T_NEGOTIATE; 827 req.opt.len = sizeof (struct opthdr) + opt->len; 828 req.opt.buf = (char *)opt; 829 830 resp.flags = 0; 831 resp.opt.buf = reqbuf; 832 resp.opt.maxlen = sizeof (reqbuf); 833 834 if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) { 835 t_error("t_optmgmt"); 836 return (-1); 837 } 838 return (0); 839 } 840 841 static boolean_t 842 check_hostserv(struct netconfig *nconf, const char *host, const char *serv) 843 { 844 struct nd_hostserv nh; 845 struct nd_addrlist *na; 846 const char *hostname = host; 847 const char *servname = serv; 848 int retval; 849 850 if (strcmp(host, HOST_SELF) == 0) 851 hostname = "HOST_SELF"; 852 else if (strcmp(host, HOST_SELF_CONNECT) == 0) 853 hostname = "HOST_SELF_CONNECT"; 854 855 if (serv[0] == '\0') 856 servname = "<any>"; 857 858 nh.h_host = (char *)host; 859 nh.h_serv = (char *)serv; 860 861 retval = netdir_getbyname(nconf, &nh, &na); 862 if (retval != ND_OK || na->n_cnt == 0) { 863 if (retval == ND_OK) 864 netdir_free(na, ND_ADDRLIST); 865 866 syslog(LOG_ALERT, "netid %s: cannot find an address for host " 867 "%s, service \"%s\"", nconf->nc_netid, hostname, servname); 868 if (debugging) { 869 (void) fprintf(stderr, "\tnetdir_getbyname for %s, " 870 "service \"%s\" failed\n", hostname, servname); 871 } 872 return (B_FALSE); 873 } 874 netdir_free(na, ND_ADDRLIST); 875 876 if (debugging) { 877 (void) fprintf(stderr, "\tnetdir_getbyname for %s, service " 878 "service \"%s\" succeeded\n", hostname, servname); 879 } 880 return (B_TRUE); 881 } 882 883 #define DEFRPCBIND "/etc/default/rpcbind" 884 885 /* Maximum outstanding syslog requests */ 886 #define MAXLOG 100 887 /* Maximum length: the messages generated are fairly short; no hostnames. */ 888 #define MAXMSG 128 889 890 typedef struct logmsg { 891 struct logmsg *log_next; 892 int log_pri; 893 char log_msg[MAXMSG]; 894 } logmsg; 895 896 static logmsg *loghead = NULL; 897 static logmsg **logtailp = &loghead; 898 static mutex_t logmutex = DEFAULTMUTEX; 899 static cond_t logcond = DEFAULTCV; 900 static int logcount = 0; 901 902 /*ARGSUSED*/ 903 static void * 904 logthread(void *arg) 905 { 906 while (1) { 907 logmsg *msg; 908 (void) mutex_lock(&logmutex); 909 while ((msg = loghead) == NULL) 910 (void) cond_wait(&logcond, &logmutex); 911 912 loghead = msg->log_next; 913 logcount--; 914 if (loghead == NULL) { 915 logtailp = &loghead; 916 logcount = 0; 917 } 918 (void) mutex_unlock(&logmutex); 919 syslog(msg->log_pri, "%s", msg->log_msg); 920 free(msg); 921 } 922 /* NOTREACHED */ 923 } 924 925 /* 926 * Initialize: read the configuration parameters from the default file. 927 */ 928 static void 929 rpcb_check_init(void) 930 { 931 thread_t tid; 932 scf_simple_prop_t *prop; 933 uint8_t *bool; 934 935 if ((prop = scf_simple_prop_get(NULL, NULL, "config", 936 "enable_tcpwrappers")) != NULL) { 937 938 if ((bool = scf_simple_prop_next_boolean(prop)) != NULL) { 939 wrap_enabled = (*bool == 0) ? B_FALSE : B_TRUE; 940 } else { 941 syslog(LOG_ALERT, "enable_tcpwrappers no value %s", 942 scf_strerror(scf_error())); 943 } 944 scf_simple_prop_free(prop); 945 } else { 946 syslog(LOG_ALERT, "unable to get enable_tcpwrappers %s", 947 scf_strerror(scf_error())); 948 } 949 if ((prop = scf_simple_prop_get(NULL, NULL, "config", 950 "verbose_logging")) != NULL) { 951 952 if ((bool = scf_simple_prop_next_boolean(prop)) != NULL) { 953 verboselog = (*bool == 0) ? B_FALSE : B_TRUE; 954 } else { 955 syslog(LOG_ALERT, "verboselog no value %s", 956 scf_strerror(scf_error())); 957 } 958 scf_simple_prop_free(prop); 959 } else { 960 syslog(LOG_ALERT, "unable to get verbose_logging %s", 961 scf_strerror(scf_error())); 962 } 963 if ((prop = scf_simple_prop_get(NULL, NULL, "config", 964 "allow_indirect")) != NULL) { 965 966 if ((bool = scf_simple_prop_next_boolean(prop)) != NULL) { 967 allow_indirect = (*bool == 0) ? B_FALSE : B_TRUE; 968 } else { 969 syslog(LOG_ALERT, "allow_indirect no value %s", 970 scf_strerror(scf_error())); 971 } 972 scf_simple_prop_free(prop); 973 } else { 974 syslog(LOG_ALERT, "unable to get allow_indirect %s", 975 scf_strerror(scf_error())); 976 } 977 978 if (wrap_enabled) 979 (void) thr_create(NULL, 0, logthread, NULL, THR_DETACHED, &tid); 980 } 981 982 /* 983 * qsyslog() - queue a request for syslog(); if syslog blocks, the other 984 * thread blocks; we make sure we don't run out of memory by allowing 985 * only a limited number of outstandig syslog() requests. 986 */ 987 void 988 qsyslog(int pri, const char *fmt, ...) 989 { 990 logmsg *msg = malloc(sizeof (*msg)); 991 int oldcount; 992 va_list ap; 993 994 if (msg == NULL) 995 return; 996 997 msg->log_pri = pri; 998 999 va_start(ap, fmt); 1000 (void) vsnprintf(msg->log_msg, sizeof (msg->log_msg), fmt, ap); 1001 va_end(ap); 1002 1003 msg->log_next = NULL; 1004 1005 (void) mutex_lock(&logmutex); 1006 oldcount = logcount; 1007 if (logcount < MAXLOG) { 1008 logcount++; 1009 *logtailp = msg; 1010 logtailp = &msg->log_next; 1011 } else { 1012 free(msg); 1013 } 1014 (void) mutex_unlock(&logmutex); 1015 if (oldcount == 0) 1016 (void) cond_signal(&logcond); 1017 } 1018