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