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