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 /* 38 * rpcbind.c 39 * Implements the program, version to address mapping for rpc. 40 * 41 */ 42 43 #include <dlfcn.h> 44 #include <stdio.h> 45 #include <stdio_ext.h> 46 #include <sys/types.h> 47 #include <unistd.h> 48 #include <stdlib.h> 49 #include <string.h> 50 #include <rpc/rpc.h> 51 #include <netconfig.h> 52 #include <netdir.h> 53 #include <errno.h> 54 #include <sys/wait.h> 55 #include <signal.h> 56 #include <string.h> 57 #include <stdlib.h> 58 #include <thread.h> 59 #include <synch.h> 60 #include <stdarg.h> 61 #ifdef PORTMAP 62 #include <netinet/in.h> 63 #endif 64 #include <arpa/inet.h> 65 #include <sys/termios.h> 66 #include "rpcbind.h" 67 #include <sys/syslog.h> 68 #include <sys/stat.h> 69 #include <syslog.h> 70 #include <string.h> 71 #include <sys/time.h> 72 #include <sys/resource.h> 73 #include <rpcsvc/daemon_utils.h> 74 #include <priv_utils.h> 75 #include <libscf.h> 76 #include <sys/ccompile.h> 77 78 #ifdef PORTMAP 79 extern void pmap_service(struct svc_req *, SVCXPRT *xprt); 80 #endif 81 extern void rpcb_service_3(struct svc_req *, SVCXPRT *xprt); 82 extern void rpcb_service_4(struct svc_req *, SVCXPRT *xprt); 83 extern void read_warmstart(void); 84 extern void write_warmstart(void); 85 extern int Is_ipv6present(void); 86 87 #define MAX_FILEDESC_LIMIT 1023 88 89 static void terminate(int); 90 static void note_refresh(int); 91 static void detachfromtty(void); 92 static void parseargs(int, char *[]); 93 static void rbllist_add(ulong_t, ulong_t, struct netconfig *, struct netbuf *); 94 static int init_transport(struct netconfig *); 95 static int check_netconfig(void); 96 97 static boolean_t check_hostserv(struct netconfig *, const char *, const char *); 98 static int setopt_reuseaddr(int); 99 static int setopt_anon_mlp(int); 100 static int setup_callit(int); 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 boolean_t local_only = B_FALSE; 120 121 volatile sig_atomic_t sigrefresh; 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) sigset(SIGHUP, note_refresh); 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, 336 dlerrstr ? dlerrstr : ""); 337 } 338 syslog(LOG_ERR, 339 "netid %s: dlopen of name-to-address library %s failed", 340 np->nc_netid, libname); 341 if (dlerrstr) 342 syslog(LOG_ERR, "%s", dlerrstr); 343 busted++; 344 } else { 345 if (debugging) 346 fprintf(stderr, 347 "\tdlopen of name-to-address library %s succeeded\n", libname); 348 (void) dlclose(dlcookie); 349 } 350 } 351 nconf = getnetconfigent(np->nc_netid); 352 353 if (!check_hostserv(nconf, HOST_SELF, "")) 354 busted++; 355 if (!check_hostserv(nconf, HOST_SELF_CONNECT, "")) 356 busted++; 357 if (!check_hostserv(nconf, HOST_SELF, "rpcbind")) 358 busted++; 359 if (!check_hostserv(nconf, HOST_SELF_CONNECT, "rpcbind")) 360 busted++; 361 362 freenetconfigent(nconf); 363 } 364 endnetconfig(nc); 365 366 if (lo_clts_found) { 367 if (debugging) 368 fprintf(stderr, "Found CLTS loopback transport\n"); 369 } else { 370 syslog(LOG_ALERT, "no CLTS loopback transport found\n"); 371 if (debugging) 372 fprintf(stderr, "no CLTS loopback transport found\n"); 373 } 374 if (lo_cots_found) { 375 if (debugging) 376 fprintf(stderr, "Found COTS loopback transport\n"); 377 } else { 378 syslog(LOG_ALERT, "no COTS loopback transport found\n"); 379 if (debugging) 380 fprintf(stderr, "no COTS loopback transport found\n"); 381 } 382 if (lo_cotsord_found) { 383 if (debugging) 384 fprintf(stderr, "Found COTS ORD loopback transport\n"); 385 } else { 386 syslog(LOG_ALERT, "no COTS ORD loopback transport found\n"); 387 if (debugging) 388 fprintf(stderr, 389 "no COTS ORD loopback transport found\n"); 390 } 391 392 return (busted); 393 } 394 395 /* 396 * Adds the entry into the rpcbind database. 397 * If PORTMAP, then for UDP and TCP, it adds the entries for version 2 also 398 * Returns 0 if succeeds, else fails 399 */ 400 static int 401 init_transport(struct netconfig *nconf) 402 { 403 int fd; 404 struct t_bind *taddr, *baddr; 405 SVCXPRT *my_xprt; 406 struct nd_addrlist *nas; 407 struct nd_hostserv hs; 408 int status; /* bound checking ? */ 409 static int msgprt = 0; 410 411 if ((nconf->nc_semantics != NC_TPI_CLTS) && 412 (nconf->nc_semantics != NC_TPI_COTS) && 413 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 414 return (1); /* not my type */ 415 416 if ((strcmp(nconf->nc_protofmly, NC_INET6) == 0) && !ipv6flag) { 417 if (!msgprt) 418 syslog(LOG_DEBUG, 419 "/etc/netconfig has IPv6 entries but IPv6 is not configured"); 420 msgprt++; 421 return (1); 422 } 423 #ifdef ND_DEBUG 424 { 425 int i; 426 char **s; 427 428 (void) fprintf(stderr, "%s: %d lookup routines :\n", 429 nconf->nc_netid, nconf->nc_nlookups); 430 for (i = 0, s = nconf->nc_lookups; i < nconf->nc_nlookups; i++, s++) 431 fprintf(stderr, "[%d] - %s\n", i, *s); 432 } 433 #endif 434 435 if ((fd = t_open(nconf->nc_device, O_RDWR, NULL)) < 0) { 436 syslog(LOG_ERR, "%s: cannot open connection: %s", 437 nconf->nc_netid, t_errlist[t_errno]); 438 return (1); 439 } 440 441 if (is_system_labeled() && 442 (strcmp(nconf->nc_protofmly, NC_INET) == 0 || 443 strcmp(nconf->nc_protofmly, NC_INET6) == 0) && 444 setopt_anon_mlp(fd) == -1) { 445 syslog(LOG_ERR, "%s: couldn't set SO_ANON_MLP option", 446 nconf->nc_netid); 447 } 448 449 /* 450 * Negotiate for returning the ucred of the caller. This should 451 * done before enabling the endpoint for service via 452 * t_bind() so that requests to rpcbind contain the uid. 453 */ 454 svc_fd_negotiate_ucred(fd); 455 456 taddr = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR); 457 baddr = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR); 458 if ((baddr == NULL) || (taddr == NULL)) { 459 syslog(LOG_ERR, "%s: cannot allocate netbuf: %s", 460 nconf->nc_netid, t_errlist[t_errno]); 461 exit(1); 462 } 463 464 /* Get rpcbind's address on this transport */ 465 hs.h_host = HOST_SELF; 466 hs.h_serv = servname; 467 if (netdir_getbyname(nconf, &hs, &nas)) 468 goto error; 469 470 /* Copy the address */ 471 taddr->addr.len = nas->n_addrs->len; 472 memcpy(taddr->addr.buf, nas->n_addrs->buf, (int)nas->n_addrs->len); 473 #ifdef ND_DEBUG 474 { 475 /* for debugging print out our universal address */ 476 char *uaddr; 477 478 uaddr = taddr2uaddr(nconf, nas->n_addrs); 479 (void) fprintf(stderr, "rpcbind : my address is %s\n", uaddr); 480 (void) free(uaddr); 481 } 482 #endif 483 netdir_free((char *)nas, ND_ADDRLIST); 484 485 if (nconf->nc_semantics == NC_TPI_CLTS) 486 taddr->qlen = 0; 487 else 488 taddr->qlen = listen_backlog; 489 490 if (strcmp(nconf->nc_proto, NC_TCP) == 0) { 491 /* 492 * Sm: If we are running then set SO_REUSEADDR option 493 * so that we can bind to our preferred address even if 494 * previous connections are in FIN_WAIT state 495 */ 496 #ifdef ND_DEBUG 497 fprintf(stdout, "Setting SO_REUSEADDR.\n"); 498 #endif 499 if (setopt_reuseaddr(fd) == -1) { 500 syslog(LOG_ERR, "Couldn't set SO_REUSEADDR option"); 501 } 502 } 503 504 if (t_bind(fd, taddr, baddr) != 0) { 505 syslog(LOG_ERR, "%s: cannot bind: %s", 506 nconf->nc_netid, t_errlist[t_errno]); 507 goto error; 508 } 509 510 511 if (memcmp(taddr->addr.buf, baddr->addr.buf, (int)baddr->addr.len)) { 512 syslog(LOG_ERR, "%s: address in use", nconf->nc_netid); 513 goto error; 514 } 515 516 my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, baddr, 0, 0); 517 if (my_xprt == (SVCXPRT *)NULL) { 518 syslog(LOG_ERR, "%s: could not create service", 519 nconf->nc_netid); 520 goto error; 521 } 522 523 /* set up multicast address for RPC CALL_IT, IPv6 */ 524 525 if ((strcmp(nconf->nc_protofmly, NC_INET6) == 0) && 526 (strcmp(nconf->nc_proto, NC_UDP) == 0)) { 527 if (setup_callit(fd) < 0) { 528 syslog(LOG_ERR, "Unable to join IPv6 multicast group \ 529 for rpc broadcast %s", RPCB_MULTICAST_ADDR); 530 } 531 } 532 533 if (strcmp(nconf->nc_proto, NC_TCP) == 0) { 534 svc_control(my_xprt, SVCSET_KEEPALIVE, (void *) TRUE); 535 } 536 537 #ifdef PORTMAP 538 /* 539 * Register both the versions for tcp/ip and udp/ip 540 */ 541 if ((strcmp(nconf->nc_protofmly, NC_INET) == 0) && 542 ((strcmp(nconf->nc_proto, NC_TCP) == 0) || 543 (strcmp(nconf->nc_proto, NC_UDP) == 0))) { 544 PMAPLIST *pml; 545 546 if (!svc_register(my_xprt, PMAPPROG, PMAPVERS, 547 pmap_service, NULL)) { 548 syslog(LOG_ERR, "could not register on %s", 549 nconf->nc_netid); 550 goto error; 551 } 552 pml = (PMAPLIST *)malloc((uint_t)sizeof (PMAPLIST)); 553 if (pml == (PMAPLIST *)NULL) { 554 syslog(LOG_ERR, "no memory!"); 555 exit(1); 556 } 557 pml->pml_map.pm_prog = PMAPPROG; 558 pml->pml_map.pm_vers = PMAPVERS; 559 pml->pml_map.pm_port = PMAPPORT; 560 if (strcmp(nconf->nc_proto, NC_TCP) == 0) { 561 if (tcptrans[0]) { 562 syslog(LOG_ERR, 563 "cannot have more than one TCP transport"); 564 goto error; 565 } 566 tcptrans = strdup(nconf->nc_netid); 567 pml->pml_map.pm_prot = IPPROTO_TCP; 568 569 /* Let's snarf the universal address */ 570 /* "h1.h2.h3.h4.p1.p2" */ 571 tcp_uaddr = taddr2uaddr(nconf, &baddr->addr); 572 } else { 573 if (udptrans[0]) { 574 syslog(LOG_ERR, 575 "cannot have more than one UDP transport"); 576 goto error; 577 } 578 udptrans = strdup(nconf->nc_netid); 579 pml->pml_map.pm_prot = IPPROTO_UDP; 580 581 /* Let's snarf the universal address */ 582 /* "h1.h2.h3.h4.p1.p2" */ 583 udp_uaddr = taddr2uaddr(nconf, &baddr->addr); 584 } 585 pml->pml_next = list_pml; 586 list_pml = pml; 587 588 /* Add version 3 information */ 589 pml = (PMAPLIST *)malloc((uint_t)sizeof (PMAPLIST)); 590 if (pml == (PMAPLIST *)NULL) { 591 syslog(LOG_ERR, "no memory!"); 592 exit(1); 593 } 594 pml->pml_map = list_pml->pml_map; 595 pml->pml_map.pm_vers = RPCBVERS; 596 pml->pml_next = list_pml; 597 list_pml = pml; 598 599 /* Add version 4 information */ 600 pml = (PMAPLIST *)malloc((uint_t)sizeof (PMAPLIST)); 601 if (pml == (PMAPLIST *)NULL) { 602 syslog(LOG_ERR, "no memory!"); 603 exit(1); 604 } 605 pml->pml_map = list_pml->pml_map; 606 pml->pml_map.pm_vers = RPCBVERS4; 607 pml->pml_next = list_pml; 608 list_pml = pml; 609 610 /* Also add version 2 stuff to rpcbind list */ 611 rbllist_add(PMAPPROG, PMAPVERS, nconf, &baddr->addr); 612 } 613 #endif 614 615 /* version 3 registration */ 616 if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS, rpcb_service_3, NULL)) { 617 syslog(LOG_ERR, "could not register %s version 3", 618 nconf->nc_netid); 619 goto error; 620 } 621 rbllist_add(RPCBPROG, RPCBVERS, nconf, &baddr->addr); 622 623 /* version 4 registration */ 624 if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS4, rpcb_service_4, NULL)) { 625 syslog(LOG_ERR, "could not register %s version 4", 626 nconf->nc_netid); 627 goto error; 628 } 629 rbllist_add(RPCBPROG, RPCBVERS4, nconf, &baddr->addr); 630 631 if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { 632 if (nconf->nc_semantics == NC_TPI_CLTS) 633 loopback_dg = strdup(nconf->nc_netid); 634 else if (nconf->nc_semantics == NC_TPI_COTS) 635 loopback_vc = strdup(nconf->nc_netid); 636 else if (nconf->nc_semantics == NC_TPI_COTS_ORD) 637 loopback_vc_ord = strdup(nconf->nc_netid); 638 } 639 640 /* decide if bound checking works for this transport */ 641 status = add_bndlist(nconf, taddr, baddr); 642 #ifdef BIND_DEBUG 643 if (status < 0) { 644 fprintf(stderr, "Error in finding bind status for %s\n", 645 nconf->nc_netid); 646 } else if (status == 0) { 647 fprintf(stderr, "check binding for %s\n", 648 nconf->nc_netid); 649 } else if (status > 0) { 650 fprintf(stderr, "No check binding for %s\n", 651 nconf->nc_netid); 652 } 653 #endif 654 /* 655 * rmtcall only supported on CLTS transports for now. 656 * only needed when we are allowing indirect calls 657 */ 658 if (allow_indirect && nconf->nc_semantics == NC_TPI_CLTS) { 659 status = create_rmtcall_fd(nconf); 660 661 #ifdef BIND_DEBUG 662 if (status < 0) { 663 fprintf(stderr, "Could not create rmtcall fd for %s\n", 664 nconf->nc_netid); 665 } else { 666 fprintf(stderr, "rmtcall fd for %s is %d\n", 667 nconf->nc_netid, status); 668 } 669 #endif 670 } 671 (void) t_free((char *)taddr, T_BIND); 672 (void) t_free((char *)baddr, T_BIND); 673 return (0); 674 error: 675 (void) t_free((char *)taddr, T_BIND); 676 (void) t_free((char *)baddr, T_BIND); 677 (void) t_close(fd); 678 return (1); 679 } 680 681 static void 682 rbllist_add(ulong_t prog, ulong_t vers, struct netconfig *nconf, 683 struct netbuf *addr) 684 { 685 rpcblist_ptr rbl; 686 687 rbl = (rpcblist_ptr)malloc((uint_t)sizeof (rpcblist)); 688 if (rbl == (rpcblist_ptr)NULL) { 689 syslog(LOG_ERR, "no memory!"); 690 exit(1); 691 } 692 693 rbl->rpcb_map.r_prog = prog; 694 rbl->rpcb_map.r_vers = vers; 695 rbl->rpcb_map.r_netid = strdup(nconf->nc_netid); 696 rbl->rpcb_map.r_addr = taddr2uaddr(nconf, addr); 697 rbl->rpcb_map.r_owner = strdup(superuser); 698 rbl->rpcb_next = list_rbl; /* Attach to global list */ 699 list_rbl = rbl; 700 } 701 702 /* 703 * Catch the signal and die 704 */ 705 /* ARGSUSED */ 706 static void 707 terminate(int sig) 708 { 709 syslog(LOG_ERR, "rpcbind terminating on signal."); 710 write_warmstart(); /* Dump yourself */ 711 exit(2); 712 } 713 714 /* ARGSUSED */ 715 static void 716 note_refresh(int sig) 717 { 718 sigrefresh = 1; 719 } 720 721 void 722 rpcbind_abort(void) 723 { 724 write_warmstart(); /* Dump yourself */ 725 abort(); 726 } 727 728 /* 729 * detach from tty 730 */ 731 static void 732 detachfromtty(void) 733 { 734 close(0); 735 close(1); 736 close(2); 737 switch (forkall()) { 738 case (pid_t)-1: 739 perror("fork"); 740 break; 741 case 0: 742 break; 743 default: 744 exit(0); 745 } 746 setsid(); 747 (void) open("/dev/null", O_RDWR, 0); 748 dup(0); 749 dup(0); 750 } 751 752 /* get command line options */ 753 static void 754 parseargs(int argc, char *argv[]) 755 { 756 int c; 757 int tmp; 758 759 while ((c = getopt(argc, argv, "dwal:")) != EOF) { 760 switch (c) { 761 case 'd': 762 debugging = 1; 763 break; 764 case 'a': 765 doabort = 1; /* when debugging, do an abort on */ 766 break; /* errors; for rpcbind developers */ 767 /* only! */ 768 case 'w': 769 warmstart = 1; 770 break; 771 772 case 'l': 773 if (sscanf(optarg, "%d", &tmp)) { 774 if (tmp > listen_backlog) { 775 listen_backlog = tmp; 776 } 777 } 778 break; 779 default: /* error */ 780 fprintf(stderr, 781 "usage: rpcbind [-d] [-w] [-l listen_backlog]\n"); 782 exit(1); 783 } 784 } 785 if (doabort && !debugging) { 786 fprintf(stderr, 787 "-a (abort) specified without -d " 788 "(debugging) -- ignored.\n"); 789 doabort = 0; 790 } 791 } 792 793 static int 794 setopt_int(int fd, int level, int name, int value) 795 { 796 struct t_optmgmt req, resp; 797 struct { 798 struct opthdr opt; 799 int value; 800 } optdata; 801 802 optdata.opt.level = level; 803 optdata.opt.name = name; 804 optdata.opt.len = sizeof (int); 805 806 optdata.value = value; 807 808 req.flags = T_NEGOTIATE; 809 req.opt.len = sizeof (optdata); 810 req.opt.buf = (char *)&optdata; 811 812 resp.flags = 0; 813 resp.opt.buf = (char *)&optdata; 814 resp.opt.maxlen = sizeof (optdata); 815 816 if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) { 817 t_error("t_optmgmt"); 818 return (-1); 819 } 820 return (0); 821 } 822 823 static int 824 setopt_reuseaddr(int fd) 825 { 826 return (setopt_int(fd, SOL_SOCKET, SO_REUSEADDR, 1)); 827 } 828 829 static int 830 setopt_anon_mlp(int fd) 831 { 832 return (setopt_int(fd, SOL_SOCKET, SO_ANON_MLP, 1)); 833 } 834 835 static int 836 setup_callit(int fd) 837 { 838 struct ipv6_mreq mreq; 839 struct t_optmgmt req, resp; 840 struct opthdr *opt; 841 char reqbuf[ sizeof (struct ipv6_mreq) + 24]; 842 struct ipv6_mreq *pmreq; 843 844 opt = (struct opthdr *)reqbuf; 845 846 opt->level = IPPROTO_IPV6; 847 opt->name = IPV6_ADD_MEMBERSHIP; 848 opt->len = sizeof (struct ipv6_mreq); 849 850 /* multicast address */ 851 (void) inet_pton(AF_INET6, RPCB_MULTICAST_ADDR, 852 mreq.ipv6mr_multiaddr.s6_addr); 853 mreq.ipv6mr_interface = 0; 854 855 /* insert it into opt */ 856 pmreq = (struct ipv6_mreq *)&reqbuf[sizeof (struct opthdr)]; 857 memcpy(pmreq, &mreq, sizeof (struct ipv6_mreq)); 858 859 req.flags = T_NEGOTIATE; 860 req.opt.len = sizeof (struct opthdr) + opt->len; 861 req.opt.buf = (char *)opt; 862 863 resp.flags = 0; 864 resp.opt.buf = reqbuf; 865 resp.opt.maxlen = sizeof (reqbuf); 866 867 if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) { 868 t_error("t_optmgmt"); 869 return (-1); 870 } 871 return (0); 872 } 873 874 static boolean_t 875 check_hostserv(struct netconfig *nconf, const char *host, const char *serv) 876 { 877 struct nd_hostserv nh; 878 struct nd_addrlist *na; 879 const char *hostname = host; 880 const char *servname = serv; 881 int retval; 882 883 if (strcmp(host, HOST_SELF) == 0) 884 hostname = "HOST_SELF"; 885 else if (strcmp(host, HOST_SELF_CONNECT) == 0) 886 hostname = "HOST_SELF_CONNECT"; 887 888 if (serv[0] == '\0') 889 servname = "<any>"; 890 891 nh.h_host = (char *)host; 892 nh.h_serv = (char *)serv; 893 894 retval = netdir_getbyname(nconf, &nh, &na); 895 if (retval != ND_OK || na->n_cnt == 0) { 896 if (retval == ND_OK) 897 netdir_free(na, ND_ADDRLIST); 898 899 syslog(LOG_ALERT, "netid %s: cannot find an address for host " 900 "%s, service \"%s\"", nconf->nc_netid, hostname, servname); 901 if (debugging) { 902 (void) fprintf(stderr, "\tnetdir_getbyname for %s, " 903 "service \"%s\" failed\n", hostname, servname); 904 } 905 return (B_FALSE); 906 } 907 netdir_free(na, ND_ADDRLIST); 908 909 if (debugging) { 910 (void) fprintf(stderr, "\tnetdir_getbyname for %s, service " 911 "service \"%s\" succeeded\n", hostname, servname); 912 } 913 return (B_TRUE); 914 } 915 916 /* Maximum outstanding syslog requests */ 917 #define MAXLOG 100 918 /* Maximum length: the messages generated are fairly short; no hostnames. */ 919 #define MAXMSG 128 920 921 typedef struct logmsg { 922 struct logmsg *log_next; 923 int log_pri; 924 char log_msg[MAXMSG]; 925 } logmsg; 926 927 static logmsg *loghead = NULL; 928 static logmsg **logtailp = &loghead; 929 static mutex_t logmutex = DEFAULTMUTEX; 930 static cond_t logcond = DEFAULTCV; 931 static int logcount = 0; 932 933 /*ARGSUSED*/ 934 static void * __NORETURN 935 logthread(void *arg) 936 { 937 while (1) { 938 logmsg *msg; 939 (void) mutex_lock(&logmutex); 940 while ((msg = loghead) == NULL) 941 (void) cond_wait(&logcond, &logmutex); 942 943 loghead = msg->log_next; 944 logcount--; 945 if (loghead == NULL) { 946 logtailp = &loghead; 947 logcount = 0; 948 } 949 (void) mutex_unlock(&logmutex); 950 syslog(msg->log_pri, "%s", msg->log_msg); 951 free(msg); 952 } 953 /* NOTREACHED */ 954 } 955 956 static boolean_t 957 get_smf_prop(const char *var, boolean_t def_val) 958 { 959 scf_simple_prop_t *prop; 960 uint8_t *val; 961 boolean_t res = def_val; 962 963 prop = scf_simple_prop_get(NULL, NULL, "config", var); 964 if (prop) { 965 if ((val = scf_simple_prop_next_boolean(prop)) != NULL) 966 res = (*val == 0) ? B_FALSE : B_TRUE; 967 scf_simple_prop_free(prop); 968 } 969 970 if (prop == NULL || val == NULL) { 971 syslog(LOG_ALERT, "no value for config/%s (%s). " 972 "Using default \"%s\"", var, scf_strerror(scf_error()), 973 def_val ? "true" : "false"); 974 } 975 976 return (res); 977 } 978 979 /* 980 * Initialize: read the configuration parameters from SMF. 981 * This function must be idempotent because it can be called from the 982 * main poll() loop in my_svc_run(). 983 */ 984 void 985 rpcb_check_init(void) 986 { 987 thread_t tid; 988 static int thr_running; 989 990 wrap_enabled = get_smf_prop("enable_tcpwrappers", B_FALSE); 991 verboselog = get_smf_prop("verbose_logging", B_FALSE); 992 allow_indirect = get_smf_prop("allow_indirect", B_TRUE); 993 local_only = get_smf_prop("local_only", B_FALSE); 994 995 if (wrap_enabled && !thr_running) { 996 (void) thr_create(NULL, 0, logthread, NULL, THR_DETACHED, &tid); 997 thr_running = 1; 998 } 999 } 1000 1001 /* 1002 * qsyslog() - queue a request for syslog(); if syslog blocks, the other 1003 * thread blocks; we make sure we don't run out of memory by allowing 1004 * only a limited number of outstandig syslog() requests. 1005 */ 1006 void 1007 qsyslog(int pri, const char *fmt, ...) 1008 { 1009 logmsg *msg = malloc(sizeof (*msg)); 1010 int oldcount; 1011 va_list ap; 1012 1013 if (msg == NULL) 1014 return; 1015 1016 msg->log_pri = pri; 1017 1018 va_start(ap, fmt); 1019 (void) vsnprintf(msg->log_msg, sizeof (msg->log_msg), fmt, ap); 1020 va_end(ap); 1021 1022 msg->log_next = NULL; 1023 1024 (void) mutex_lock(&logmutex); 1025 oldcount = logcount; 1026 if (logcount < MAXLOG) { 1027 logcount++; 1028 *logtailp = msg; 1029 logtailp = &msg->log_next; 1030 } else { 1031 free(msg); 1032 } 1033 (void) mutex_unlock(&logmutex); 1034 if (oldcount == 0) 1035 (void) cond_signal(&logcond); 1036 } 1037