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 <stdarg.h> 63 #ifdef PORTMAP 64 #include <netinet/in.h> 65 #endif 66 #include <arpa/inet.h> 67 #include <sys/termios.h> 68 #include "rpcbind.h" 69 #include <sys/syslog.h> 70 #include <sys/stat.h> 71 #include <syslog.h> 72 #include <string.h> 73 #include <sys/time.h> 74 #include <sys/resource.h> 75 #include <rpcsvc/daemon_utils.h> 76 #include <priv_utils.h> 77 #include <libscf.h> 78 79 #ifdef PORTMAP 80 extern void pmap_service(struct svc_req *, SVCXPRT *xprt); 81 #endif 82 extern void rpcb_service_3(struct svc_req *, SVCXPRT *xprt); 83 extern void rpcb_service_4(struct svc_req *, SVCXPRT *xprt); 84 extern void read_warmstart(void); 85 extern void write_warmstart(void); 86 extern int Is_ipv6present(void); 87 88 #define MAX_FILEDESC_LIMIT 1023 89 90 static void terminate(int); 91 static void note_refresh(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 int setopt_reuseaddr(int); 100 static int setopt_anon_mlp(int); 101 static int setup_callit(int); 102 103 /* Global variables */ 104 #ifdef ND_DEBUG 105 int debugging = 1; /* Tell me what's going on */ 106 #else 107 int debugging = 0; /* Tell me what's going on */ 108 #endif 109 static int ipv6flag = 0; 110 int doabort = 0; /* When debugging, do an abort on errors */ 111 static int listen_backlog = 64; 112 rpcblist_ptr list_rbl; /* A list of version 3/4 rpcbind services */ 113 char *loopback_dg; /* Datagram loopback transport, for set and unset */ 114 char *loopback_vc; /* COTS loopback transport, for set and unset */ 115 char *loopback_vc_ord; /* COTS_ORD loopback transport, for set and unset */ 116 117 boolean_t verboselog = B_FALSE; 118 boolean_t wrap_enabled = B_FALSE; 119 boolean_t allow_indirect = B_TRUE; 120 boolean_t local_only = B_FALSE; 121 122 volatile sig_atomic_t sigrefresh; 123 124 /* Local Variable */ 125 static int warmstart = 0; /* Grab a old copy of registrations */ 126 127 #ifdef PORTMAP 128 PMAPLIST *list_pml; /* A list of version 2 rpcbind services */ 129 char *udptrans; /* Name of UDP transport */ 130 char *tcptrans; /* Name of TCP transport */ 131 char *udp_uaddr; /* Universal UDP address */ 132 char *tcp_uaddr; /* Universal TCP address */ 133 #endif 134 static char servname[] = "rpcbind"; 135 static char superuser[] = "superuser"; 136 137 static const char daemon_dir[] = DAEMON_DIR; 138 139 int 140 main(int argc, char *argv[]) 141 { 142 struct netconfig *nconf; 143 void *nc_handle; /* Net config handle */ 144 struct rlimit rl; 145 int maxrecsz = RPC_MAXDATASIZE; 146 boolean_t can_do_mlp; 147 148 parseargs(argc, argv); 149 150 getrlimit(RLIMIT_NOFILE, &rl); 151 152 if (rl.rlim_cur < MAX_FILEDESC_LIMIT) { 153 if (rl.rlim_max <= MAX_FILEDESC_LIMIT) 154 rl.rlim_cur = rl.rlim_max; 155 else 156 rl.rlim_cur = MAX_FILEDESC_LIMIT; 157 setrlimit(RLIMIT_NOFILE, &rl); 158 } 159 (void) enable_extended_FILE_stdio(-1, -1); 160 161 openlog("rpcbind", LOG_CONS, LOG_DAEMON); 162 163 /* 164 * Create the daemon directory in /var/run 165 */ 166 if (mkdir(daemon_dir, DAEMON_DIR_MODE) == 0 || errno == EEXIST) { 167 chmod(daemon_dir, DAEMON_DIR_MODE); 168 chown(daemon_dir, DAEMON_UID, DAEMON_GID); 169 } else { 170 syslog(LOG_ERR, "failed to create \"%s\": %m", daemon_dir); 171 } 172 173 /* 174 * These privileges are required for the t_bind check rpcbind uses 175 * to determine whether a service is still live or not. 176 */ 177 can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP); 178 if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, DAEMON_UID, 179 DAEMON_GID, PRIV_NET_PRIVADDR, PRIV_SYS_NFS, 180 can_do_mlp ? PRIV_NET_BINDMLP : NULL, NULL) == -1) { 181 fprintf(stderr, "Insufficient privileges\n"); 182 exit(1); 183 } 184 185 /* 186 * Enable non-blocking mode and maximum record size checks for 187 * connection oriented transports. 188 */ 189 if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) { 190 syslog(LOG_INFO, "unable to set RPC max record size"); 191 } 192 193 nc_handle = setnetconfig(); /* open netconfig file */ 194 if (nc_handle == NULL) { 195 syslog(LOG_ERR, "could not read /etc/netconfig"); 196 exit(1); 197 } 198 loopback_dg = ""; 199 loopback_vc = ""; 200 loopback_vc_ord = ""; 201 #ifdef PORTMAP 202 udptrans = ""; 203 tcptrans = ""; 204 #endif 205 206 { 207 /* 208 * rpcbind is the first application to encounter the 209 * various netconfig files. check_netconfig() verifies 210 * that they are set up correctly and complains loudly 211 * if not. 212 */ 213 int trouble; 214 215 trouble = check_netconfig(); 216 if (trouble) { 217 syslog(LOG_ERR, 218 "%s: found %d errors with network configuration files. Exiting.", 219 argv[0], trouble); 220 fprintf(stderr, 221 "%s: found %d errors with network configuration files. Exiting.\n", 222 argv[0], trouble); 223 exit(1); 224 } 225 } 226 ipv6flag = Is_ipv6present(); 227 rpcb_check_init(); 228 while (nconf = getnetconfig(nc_handle)) { 229 if (nconf->nc_flag & NC_VISIBLE) 230 init_transport(nconf); 231 } 232 endnetconfig(nc_handle); 233 234 if ((loopback_dg[0] == NULL) && (loopback_vc[0] == NULL) && 235 (loopback_vc_ord[0] == NULL)) { 236 syslog(LOG_ERR, "could not find loopback transports"); 237 exit(1); 238 } 239 240 /* catch the usual termination signals for graceful exit */ 241 (void) signal(SIGINT, terminate); 242 (void) signal(SIGTERM, terminate); 243 (void) signal(SIGQUIT, terminate); 244 /* ignore others that could get sent */ 245 (void) sigset(SIGHUP, note_refresh); 246 (void) signal(SIGUSR1, SIG_IGN); 247 (void) signal(SIGUSR2, SIG_IGN); 248 if (warmstart) { 249 read_warmstart(); 250 } 251 if (debugging) { 252 printf("rpcbind debugging enabled."); 253 if (doabort) { 254 printf(" Will abort on errors!\n"); 255 } else { 256 printf("\n"); 257 } 258 } else { 259 detachfromtty(); 260 } 261 262 /* These are basic privileges we do not need */ 263 __fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_SESSION, 264 PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL); 265 266 my_svc_run(); 267 syslog(LOG_ERR, "svc_run returned unexpectedly"); 268 rpcbind_abort(); 269 /* NOTREACHED */ 270 } 271 272 /* 273 * Increments a counter each time a problem is found with the network 274 * configuration information. 275 */ 276 static int 277 check_netconfig(void) 278 { 279 void *nc; 280 void *dlcookie; 281 int busted = 0; 282 int i; 283 int lo_clts_found = 0, lo_cots_found = 0, lo_cotsord_found = 0; 284 struct netconfig *nconf, *np; 285 struct stat sb; 286 287 nc = setnetconfig(); 288 if (nc == NULL) { 289 if (debugging) 290 fprintf(stderr, 291 "setnetconfig() failed: %s\n", nc_sperror()); 292 syslog(LOG_ALERT, "setnetconfig() failed: %s", nc_sperror()); 293 return (1); 294 } 295 while (np = getnetconfig(nc)) { 296 if ((np->nc_flag & NC_VISIBLE) == 0) 297 continue; 298 if (debugging) 299 fprintf(stderr, "checking netid \"%s\"\n", 300 np->nc_netid); 301 if (strcmp(np->nc_protofmly, NC_LOOPBACK) == 0) 302 switch (np->nc_semantics) { 303 case NC_TPI_CLTS: 304 lo_clts_found = 1; 305 break; 306 307 case NC_TPI_COTS: 308 lo_cots_found = 1; 309 break; 310 311 case NC_TPI_COTS_ORD: 312 lo_cotsord_found = 1; 313 break; 314 } 315 if (stat(np->nc_device, &sb) == -1 && errno == ENOENT) { 316 if (debugging) 317 fprintf(stderr, "\tdevice %s does not exist\n", 318 np->nc_device); 319 syslog(LOG_ERR, "netid %s: device %s does not exist", 320 np->nc_netid, np->nc_device); 321 busted++; 322 } else 323 if (debugging) 324 fprintf(stderr, "\tdevice %s present\n", 325 np->nc_device); 326 for (i = 0; i < np->nc_nlookups; i++) { 327 char *libname = np->nc_lookups[i]; 328 329 if ((dlcookie = dlopen(libname, RTLD_LAZY)) == NULL) { 330 char *dlerrstr; 331 332 dlerrstr = dlerror(); 333 if (debugging) { 334 fprintf(stderr, 335 "\tnetid %s: dlopen of name-to-address library %s failed\ndlerror: %s", 336 np->nc_netid, libname, 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 (debugging) -- ignored.\n"); 788 doabort = 0; 789 } 790 } 791 792 static int 793 setopt_int(int fd, int level, int name, int value) 794 { 795 struct t_optmgmt req, resp; 796 struct { 797 struct opthdr opt; 798 int value; 799 } optdata; 800 801 optdata.opt.level = level; 802 optdata.opt.name = name; 803 optdata.opt.len = sizeof (int); 804 805 optdata.value = value; 806 807 req.flags = T_NEGOTIATE; 808 req.opt.len = sizeof (optdata); 809 req.opt.buf = (char *)&optdata; 810 811 resp.flags = 0; 812 resp.opt.buf = (char *)&optdata; 813 resp.opt.maxlen = sizeof (optdata); 814 815 if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) { 816 t_error("t_optmgmt"); 817 return (-1); 818 } 819 return (0); 820 } 821 822 static int 823 setopt_reuseaddr(int fd) 824 { 825 return (setopt_int(fd, SOL_SOCKET, SO_REUSEADDR, 1)); 826 } 827 828 static int 829 setopt_anon_mlp(int fd) 830 { 831 return (setopt_int(fd, SOL_SOCKET, SO_ANON_MLP, 1)); 832 } 833 834 static int 835 setup_callit(int fd) 836 { 837 struct ipv6_mreq mreq; 838 struct t_optmgmt req, resp; 839 struct opthdr *opt; 840 char reqbuf[ sizeof (struct ipv6_mreq) + 24]; 841 struct ipv6_mreq *pmreq; 842 843 opt = (struct opthdr *)reqbuf; 844 845 opt->level = IPPROTO_IPV6; 846 opt->name = IPV6_ADD_MEMBERSHIP; 847 opt->len = sizeof (struct ipv6_mreq); 848 849 /* multicast address */ 850 (void) inet_pton(AF_INET6, RPCB_MULTICAST_ADDR, 851 mreq.ipv6mr_multiaddr.s6_addr); 852 mreq.ipv6mr_interface = 0; 853 854 /* insert it into opt */ 855 pmreq = (struct ipv6_mreq *)&reqbuf[sizeof (struct opthdr)]; 856 memcpy(pmreq, &mreq, sizeof (struct ipv6_mreq)); 857 858 req.flags = T_NEGOTIATE; 859 req.opt.len = sizeof (struct opthdr) + opt->len; 860 req.opt.buf = (char *)opt; 861 862 resp.flags = 0; 863 resp.opt.buf = reqbuf; 864 resp.opt.maxlen = sizeof (reqbuf); 865 866 if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) { 867 t_error("t_optmgmt"); 868 return (-1); 869 } 870 return (0); 871 } 872 873 static boolean_t 874 check_hostserv(struct netconfig *nconf, const char *host, const char *serv) 875 { 876 struct nd_hostserv nh; 877 struct nd_addrlist *na; 878 const char *hostname = host; 879 const char *servname = serv; 880 int retval; 881 882 if (strcmp(host, HOST_SELF) == 0) 883 hostname = "HOST_SELF"; 884 else if (strcmp(host, HOST_SELF_CONNECT) == 0) 885 hostname = "HOST_SELF_CONNECT"; 886 887 if (serv[0] == '\0') 888 servname = "<any>"; 889 890 nh.h_host = (char *)host; 891 nh.h_serv = (char *)serv; 892 893 retval = netdir_getbyname(nconf, &nh, &na); 894 if (retval != ND_OK || na->n_cnt == 0) { 895 if (retval == ND_OK) 896 netdir_free(na, ND_ADDRLIST); 897 898 syslog(LOG_ALERT, "netid %s: cannot find an address for host " 899 "%s, service \"%s\"", nconf->nc_netid, hostname, servname); 900 if (debugging) { 901 (void) fprintf(stderr, "\tnetdir_getbyname for %s, " 902 "service \"%s\" failed\n", hostname, servname); 903 } 904 return (B_FALSE); 905 } 906 netdir_free(na, ND_ADDRLIST); 907 908 if (debugging) { 909 (void) fprintf(stderr, "\tnetdir_getbyname for %s, service " 910 "service \"%s\" succeeded\n", hostname, servname); 911 } 912 return (B_TRUE); 913 } 914 915 /* Maximum outstanding syslog requests */ 916 #define MAXLOG 100 917 /* Maximum length: the messages generated are fairly short; no hostnames. */ 918 #define MAXMSG 128 919 920 typedef struct logmsg { 921 struct logmsg *log_next; 922 int log_pri; 923 char log_msg[MAXMSG]; 924 } logmsg; 925 926 static logmsg *loghead = NULL; 927 static logmsg **logtailp = &loghead; 928 static mutex_t logmutex = DEFAULTMUTEX; 929 static cond_t logcond = DEFAULTCV; 930 static int logcount = 0; 931 932 /*ARGSUSED*/ 933 static void * 934 logthread(void *arg) 935 { 936 while (1) { 937 logmsg *msg; 938 (void) mutex_lock(&logmutex); 939 while ((msg = loghead) == NULL) 940 (void) cond_wait(&logcond, &logmutex); 941 942 loghead = msg->log_next; 943 logcount--; 944 if (loghead == NULL) { 945 logtailp = &loghead; 946 logcount = 0; 947 } 948 (void) mutex_unlock(&logmutex); 949 syslog(msg->log_pri, "%s", msg->log_msg); 950 free(msg); 951 } 952 /* NOTREACHED */ 953 } 954 955 static boolean_t 956 get_smf_prop(const char *var, boolean_t def_val) 957 { 958 scf_simple_prop_t *prop; 959 uint8_t *val; 960 boolean_t res = def_val; 961 962 prop = scf_simple_prop_get(NULL, NULL, "config", var); 963 if (prop) { 964 if ((val = scf_simple_prop_next_boolean(prop)) != NULL) 965 res = (*val == 0) ? B_FALSE : B_TRUE; 966 scf_simple_prop_free(prop); 967 } 968 969 if (prop == NULL || val == NULL) { 970 syslog(LOG_ALERT, "no value for config/%s (%s). " 971 "Using default \"%s\"", var, scf_strerror(scf_error()), 972 def_val ? "true" : "false"); 973 } 974 975 return (res); 976 } 977 978 /* 979 * Initialize: read the configuration parameters from SMF. 980 * This function must be idempotent because it can be called from the 981 * main poll() loop in my_svc_run(). 982 */ 983 void 984 rpcb_check_init(void) 985 { 986 thread_t tid; 987 static int thr_running; 988 989 wrap_enabled = get_smf_prop("enable_tcpwrappers", B_FALSE); 990 verboselog = get_smf_prop("verbose_logging", B_FALSE); 991 allow_indirect = get_smf_prop("allow_indirect", B_TRUE); 992 local_only = get_smf_prop("local_only", B_FALSE); 993 994 if (wrap_enabled && !thr_running) { 995 (void) thr_create(NULL, 0, logthread, NULL, THR_DETACHED, &tid); 996 thr_running = 1; 997 } 998 } 999 1000 /* 1001 * qsyslog() - queue a request for syslog(); if syslog blocks, the other 1002 * thread blocks; we make sure we don't run out of memory by allowing 1003 * only a limited number of outstandig syslog() requests. 1004 */ 1005 void 1006 qsyslog(int pri, const char *fmt, ...) 1007 { 1008 logmsg *msg = malloc(sizeof (*msg)); 1009 int oldcount; 1010 va_list ap; 1011 1012 if (msg == NULL) 1013 return; 1014 1015 msg->log_pri = pri; 1016 1017 va_start(ap, fmt); 1018 (void) vsnprintf(msg->log_msg, sizeof (msg->log_msg), fmt, ap); 1019 va_end(ap); 1020 1021 msg->log_next = NULL; 1022 1023 (void) mutex_lock(&logmutex); 1024 oldcount = logcount; 1025 if (logcount < MAXLOG) { 1026 logcount++; 1027 *logtailp = msg; 1028 logtailp = &msg->log_next; 1029 } else { 1030 free(msg); 1031 } 1032 (void) mutex_unlock(&logmutex); 1033 if (oldcount == 0) 1034 (void) cond_signal(&logcond); 1035 } 1036