1 /* $NetBSD: rpcbind.c,v 1.3 2002/11/08 00:16:40 fvdl Exp $ */ 2 /* $FreeBSD$ */ 3 4 /*- 5 * Copyright (c) 2009, Sun Microsystems, Inc. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions are met: 10 * - Redistributions of source code must retain the above copyright notice, 11 * this list of conditions and the following disclaimer. 12 * - Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * - Neither the name of Sun Microsystems, Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 /* 32 * Copyright (c) 1984 - 1991 by Sun Microsystems, Inc. 33 */ 34 35 /* #ident "@(#)rpcbind.c 1.19 94/04/25 SMI" */ 36 37 #if 0 38 #ifndef lint 39 static char sccsid[] = "@(#)rpcbind.c 1.35 89/04/21 Copyr 1984 Sun Micro"; 40 #endif 41 #endif 42 43 /* 44 * rpcbind.c 45 * Implements the program, version to address mapping for rpc. 46 * 47 */ 48 49 #include <sys/types.h> 50 #include <sys/stat.h> 51 #include <sys/errno.h> 52 #include <sys/time.h> 53 #include <sys/resource.h> 54 #include <sys/wait.h> 55 #include <sys/signal.h> 56 #include <sys/socket.h> 57 #include <sys/un.h> 58 #include <rpc/rpc.h> 59 #include <rpc/rpc_com.h> 60 #ifdef PORTMAP 61 #include <netinet/in.h> 62 #endif 63 #include <arpa/inet.h> 64 #include <fcntl.h> 65 #include <netdb.h> 66 #include <stdio.h> 67 #include <netconfig.h> 68 #include <stdlib.h> 69 #include <unistd.h> 70 #include <syslog.h> 71 #include <err.h> 72 #include <libutil.h> 73 #include <pwd.h> 74 #include <string.h> 75 #include <errno.h> 76 #include "rpcbind.h" 77 78 /* Global variables */ 79 int debugging = 0; /* Tell me what's going on */ 80 int doabort = 0; /* When debugging, do an abort on errors */ 81 rpcblist_ptr list_rbl; /* A list of version 3/4 rpcbind services */ 82 83 /* who to suid to if -s is given */ 84 #define RUN_AS "daemon" 85 86 #define RPCBINDDLOCK "/var/run/rpcbind.lock" 87 88 int runasdaemon = 0; 89 int insecure = 0; 90 int oldstyle_local = 0; 91 #ifdef LIBWRAP 92 int libwrap = 0; 93 #endif 94 int verboselog = 0; 95 96 char **hosts = NULL; 97 struct sockaddr **bound_sa; 98 int ipv6_only = 0; 99 int nhosts = 0; 100 int on = 1; 101 int rpcbindlockfd; 102 103 #ifdef WARMSTART 104 /* Local Variable */ 105 static int warmstart = 0; /* Grab an old copy of registrations. */ 106 #endif 107 108 #ifdef PORTMAP 109 struct pmaplist *list_pml; /* A list of version 2 rpcbind services */ 110 char *udptrans; /* Name of UDP transport */ 111 char *tcptrans; /* Name of TCP transport */ 112 char *udp_uaddr; /* Universal UDP address */ 113 char *tcp_uaddr; /* Universal TCP address */ 114 #endif 115 static char servname[] = "rpcbind"; 116 static char superuser[] = "superuser"; 117 118 int main(int, char *[]); 119 120 static int init_transport(struct netconfig *); 121 static void rbllist_add(rpcprog_t, rpcvers_t, struct netconfig *, 122 struct netbuf *); 123 static void terminate(int); 124 static void parseargs(int, char *[]); 125 static void update_bound_sa(void); 126 127 int 128 main(int argc, char *argv[]) 129 { 130 struct netconfig *nconf; 131 void *nc_handle; /* Net config handle */ 132 struct rlimit rl; 133 int maxrec = RPC_MAXDATASIZE; 134 135 parseargs(argc, argv); 136 137 update_bound_sa(); 138 139 /* Check that another rpcbind isn't already running. */ 140 if ((rpcbindlockfd = (open(RPCBINDDLOCK, 141 O_RDONLY|O_CREAT, 0444))) == -1) 142 err(1, "%s", RPCBINDDLOCK); 143 144 if(flock(rpcbindlockfd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK) 145 errx(1, "another rpcbind is already running. Aborting"); 146 147 getrlimit(RLIMIT_NOFILE, &rl); 148 if (rl.rlim_cur < 128) { 149 if (rl.rlim_max <= 128) 150 rl.rlim_cur = rl.rlim_max; 151 else 152 rl.rlim_cur = 128; 153 setrlimit(RLIMIT_NOFILE, &rl); 154 } 155 openlog("rpcbind", LOG_CONS, LOG_DAEMON); 156 if (geteuid()) { /* This command allowed only to root */ 157 fprintf(stderr, "Sorry. You are not superuser\n"); 158 exit(1); 159 } 160 nc_handle = setnetconfig(); /* open netconfig file */ 161 if (nc_handle == NULL) { 162 syslog(LOG_ERR, "could not read /etc/netconfig"); 163 exit(1); 164 } 165 #ifdef PORTMAP 166 udptrans = ""; 167 tcptrans = ""; 168 #endif 169 170 nconf = getnetconfigent("local"); 171 if (nconf == NULL) 172 nconf = getnetconfigent("unix"); 173 if (nconf == NULL) { 174 syslog(LOG_ERR, "%s: can't find local transport\n", argv[0]); 175 exit(1); 176 } 177 178 rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 179 180 init_transport(nconf); 181 182 while ((nconf = getnetconfig(nc_handle))) { 183 if (nconf->nc_flag & NC_VISIBLE) { 184 if (ipv6_only == 1 && strcmp(nconf->nc_protofmly, 185 "inet") == 0) { 186 /* DO NOTHING */ 187 } else 188 init_transport(nconf); 189 } 190 } 191 endnetconfig(nc_handle); 192 193 /* catch the usual termination signals for graceful exit */ 194 (void) signal(SIGCHLD, reap); 195 (void) signal(SIGINT, terminate); 196 (void) signal(SIGTERM, terminate); 197 (void) signal(SIGQUIT, terminate); 198 /* ignore others that could get sent */ 199 (void) signal(SIGPIPE, SIG_IGN); 200 (void) signal(SIGHUP, SIG_IGN); 201 (void) signal(SIGUSR1, SIG_IGN); 202 (void) signal(SIGUSR2, SIG_IGN); 203 #ifdef WARMSTART 204 if (warmstart) { 205 read_warmstart(); 206 } 207 #endif 208 if (debugging) { 209 printf("rpcbind debugging enabled."); 210 if (doabort) { 211 printf(" Will abort on errors!\n"); 212 } else { 213 printf("\n"); 214 } 215 } else { 216 if (daemon(0, 0)) 217 err(1, "fork failed"); 218 } 219 220 if (runasdaemon) { 221 struct passwd *p; 222 223 if((p = getpwnam(RUN_AS)) == NULL) { 224 syslog(LOG_ERR, "cannot get uid of daemon: %m"); 225 exit(1); 226 } 227 if (setuid(p->pw_uid) == -1) { 228 syslog(LOG_ERR, "setuid to daemon failed: %m"); 229 exit(1); 230 } 231 } 232 233 network_init(); 234 235 my_svc_run(); 236 syslog(LOG_ERR, "svc_run returned unexpectedly"); 237 rpcbind_abort(); 238 /* NOTREACHED */ 239 240 return 0; 241 } 242 243 /* 244 * Adds the entry into the rpcbind database. 245 * If PORTMAP, then for UDP and TCP, it adds the entries for version 2 also 246 * Returns 0 if succeeds, else fails 247 */ 248 static int 249 init_transport(struct netconfig *nconf) 250 { 251 int fd; 252 struct t_bind taddr; 253 struct addrinfo hints, *res = NULL; 254 struct __rpc_sockinfo si; 255 SVCXPRT *my_xprt; 256 int status; /* bound checking ? */ 257 int aicode; 258 int addrlen; 259 int nhostsbak; 260 int bound; 261 struct sockaddr *sa; 262 u_int32_t host_addr[4]; /* IPv4 or IPv6 */ 263 struct sockaddr_un sun; 264 mode_t oldmask; 265 266 if ((nconf->nc_semantics != NC_TPI_CLTS) && 267 (nconf->nc_semantics != NC_TPI_COTS) && 268 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 269 return (1); /* not my type */ 270 #ifdef ND_DEBUG 271 if (debugging) { 272 int i; 273 char **s; 274 275 (void)fprintf(stderr, "%s: %ld lookup routines :\n", 276 nconf->nc_netid, nconf->nc_nlookups); 277 for (i = 0, s = nconf->nc_lookups; i < nconf->nc_nlookups; 278 i++, s++) 279 fprintf(stderr, "[%d] - %s\n", i, *s); 280 } 281 #endif 282 283 /* 284 * XXX - using RPC library internal functions. 285 */ 286 if ((strcmp(nconf->nc_netid, "local") == 0) || 287 (strcmp(nconf->nc_netid, "unix") == 0)) { 288 /* 289 * For other transports we call this later, for each socket we 290 * like to bind. 291 */ 292 if ((fd = __rpc_nconf2fd(nconf)) < 0) { 293 int non_fatal = 0; 294 if (errno == EAFNOSUPPORT) 295 non_fatal = 1; 296 syslog(non_fatal?LOG_DEBUG:LOG_ERR, "cannot create socket for %s", 297 nconf->nc_netid); 298 return (1); 299 } 300 } 301 302 if (!__rpc_nconf2sockinfo(nconf, &si)) { 303 syslog(LOG_ERR, "cannot get information for %s", 304 nconf->nc_netid); 305 return (1); 306 } 307 308 if ((strcmp(nconf->nc_netid, "local") == 0) || 309 (strcmp(nconf->nc_netid, "unix") == 0)) { 310 memset(&sun, 0, sizeof sun); 311 sun.sun_family = AF_LOCAL; 312 unlink(_PATH_RPCBINDSOCK); 313 strcpy(sun.sun_path, _PATH_RPCBINDSOCK); 314 sun.sun_len = SUN_LEN(&sun); 315 addrlen = sizeof (struct sockaddr_un); 316 sa = (struct sockaddr *)&sun; 317 } else { 318 /* Get rpcbind's address on this transport */ 319 320 memset(&hints, 0, sizeof hints); 321 hints.ai_flags = AI_PASSIVE; 322 hints.ai_family = si.si_af; 323 hints.ai_socktype = si.si_socktype; 324 hints.ai_protocol = si.si_proto; 325 } 326 327 if ((strcmp(nconf->nc_netid, "local") != 0) && 328 (strcmp(nconf->nc_netid, "unix") != 0)) { 329 /* 330 * If no hosts were specified, just bind to INADDR_ANY. 331 * Otherwise make sure 127.0.0.1 is added to the list. 332 */ 333 nhostsbak = nhosts + 1; 334 hosts = realloc(hosts, nhostsbak * sizeof(char *)); 335 if (nhostsbak == 1) 336 hosts[0] = "*"; 337 else { 338 if (hints.ai_family == AF_INET) { 339 hosts[nhostsbak - 1] = "127.0.0.1"; 340 } else if (hints.ai_family == AF_INET6) { 341 hosts[nhostsbak - 1] = "::1"; 342 } else 343 return 1; 344 } 345 346 /* 347 * Bind to specific IPs if asked to 348 */ 349 bound = 0; 350 while (nhostsbak > 0) { 351 --nhostsbak; 352 /* 353 * XXX - using RPC library internal functions. 354 */ 355 if ((fd = __rpc_nconf2fd(nconf)) < 0) { 356 int non_fatal = 0; 357 if (errno == EAFNOSUPPORT && 358 nconf->nc_semantics != NC_TPI_CLTS) 359 non_fatal = 1; 360 syslog(non_fatal ? LOG_DEBUG : LOG_ERR, 361 "cannot create socket for %s", nconf->nc_netid); 362 return (1); 363 } 364 switch (hints.ai_family) { 365 case AF_INET: 366 if (inet_pton(AF_INET, hosts[nhostsbak], 367 host_addr) == 1) { 368 hints.ai_flags &= AI_NUMERICHOST; 369 } else { 370 /* 371 * Skip if we have an AF_INET6 address. 372 */ 373 if (inet_pton(AF_INET6, 374 hosts[nhostsbak], host_addr) == 1) { 375 close(fd); 376 continue; 377 } 378 } 379 break; 380 case AF_INET6: 381 if (inet_pton(AF_INET6, hosts[nhostsbak], 382 host_addr) == 1) { 383 hints.ai_flags &= AI_NUMERICHOST; 384 } else { 385 /* 386 * Skip if we have an AF_INET address. 387 */ 388 if (inet_pton(AF_INET, hosts[nhostsbak], 389 host_addr) == 1) { 390 close(fd); 391 continue; 392 } 393 } 394 if (setsockopt(fd, IPPROTO_IPV6, 395 IPV6_V6ONLY, &on, sizeof on) < 0) { 396 syslog(LOG_ERR, 397 "can't set v6-only binding for " 398 "ipv6 socket: %m"); 399 continue; 400 } 401 break; 402 default: 403 break; 404 } 405 406 /* 407 * If no hosts were specified, just bind to INADDR_ANY 408 */ 409 if (strcmp("*", hosts[nhostsbak]) == 0) 410 hosts[nhostsbak] = NULL; 411 if ((strcmp(nconf->nc_netid, "local") != 0) && 412 (strcmp(nconf->nc_netid, "unix") != 0)) { 413 if ((aicode = getaddrinfo(hosts[nhostsbak], 414 servname, &hints, &res)) != 0) { 415 syslog(LOG_ERR, 416 "cannot get local address for %s: %s", 417 nconf->nc_netid, gai_strerror(aicode)); 418 continue; 419 } 420 addrlen = res->ai_addrlen; 421 sa = (struct sockaddr *)res->ai_addr; 422 } 423 oldmask = umask(S_IXUSR|S_IXGRP|S_IXOTH); 424 if (bind(fd, sa, addrlen) != 0) { 425 syslog(LOG_ERR, "cannot bind %s on %s: %m", 426 (hosts[nhostsbak] == NULL) ? "*" : 427 hosts[nhostsbak], nconf->nc_netid); 428 if (res != NULL) 429 freeaddrinfo(res); 430 continue; 431 } else 432 bound = 1; 433 (void)umask(oldmask); 434 435 /* Copy the address */ 436 taddr.addr.len = taddr.addr.maxlen = addrlen; 437 taddr.addr.buf = malloc(addrlen); 438 if (taddr.addr.buf == NULL) { 439 syslog(LOG_ERR, 440 "cannot allocate memory for %s address", 441 nconf->nc_netid); 442 if (res != NULL) 443 freeaddrinfo(res); 444 return 1; 445 } 446 memcpy(taddr.addr.buf, sa, addrlen); 447 #ifdef ND_DEBUG 448 if (debugging) { 449 /* 450 * for debugging print out our universal 451 * address 452 */ 453 char *uaddr; 454 struct netbuf nb; 455 456 nb.buf = sa; 457 nb.len = nb.maxlen = sa->sa_len; 458 uaddr = taddr2uaddr(nconf, &nb); 459 (void)fprintf(stderr, 460 "rpcbind : my address is %s\n", uaddr); 461 (void)free(uaddr); 462 } 463 #endif 464 465 if (nconf->nc_semantics != NC_TPI_CLTS) 466 listen(fd, SOMAXCONN); 467 468 my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr, 469 RPC_MAXDATASIZE, RPC_MAXDATASIZE); 470 if (my_xprt == (SVCXPRT *)NULL) { 471 syslog(LOG_ERR, "%s: could not create service", 472 nconf->nc_netid); 473 goto error; 474 } 475 } 476 if (!bound) 477 return 1; 478 } else { 479 oldmask = umask(S_IXUSR|S_IXGRP|S_IXOTH); 480 if (bind(fd, sa, addrlen) < 0) { 481 syslog(LOG_ERR, "cannot bind %s: %m", nconf->nc_netid); 482 if (res != NULL) 483 freeaddrinfo(res); 484 return 1; 485 } 486 (void) umask(oldmask); 487 488 /* Copy the address */ 489 taddr.addr.len = taddr.addr.maxlen = addrlen; 490 taddr.addr.buf = malloc(addrlen); 491 if (taddr.addr.buf == NULL) { 492 syslog(LOG_ERR, "cannot allocate memory for %s address", 493 nconf->nc_netid); 494 if (res != NULL) 495 freeaddrinfo(res); 496 return 1; 497 } 498 memcpy(taddr.addr.buf, sa, addrlen); 499 #ifdef ND_DEBUG 500 if (debugging) { 501 /* for debugging print out our universal address */ 502 char *uaddr; 503 struct netbuf nb; 504 505 nb.buf = sa; 506 nb.len = nb.maxlen = sa->sa_len; 507 uaddr = taddr2uaddr(nconf, &nb); 508 (void) fprintf(stderr, "rpcbind : my address is %s\n", 509 uaddr); 510 (void) free(uaddr); 511 } 512 #endif 513 514 if (nconf->nc_semantics != NC_TPI_CLTS) 515 listen(fd, SOMAXCONN); 516 517 my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr, 518 RPC_MAXDATASIZE, RPC_MAXDATASIZE); 519 if (my_xprt == (SVCXPRT *)NULL) { 520 syslog(LOG_ERR, "%s: could not create service", 521 nconf->nc_netid); 522 goto error; 523 } 524 } 525 526 #ifdef PORTMAP 527 /* 528 * Register both the versions for tcp/ip, udp/ip and local. 529 */ 530 if ((strcmp(nconf->nc_protofmly, NC_INET) == 0 && 531 (strcmp(nconf->nc_proto, NC_TCP) == 0 || 532 strcmp(nconf->nc_proto, NC_UDP) == 0)) || 533 (strcmp(nconf->nc_netid, "unix") == 0) || 534 (strcmp(nconf->nc_netid, "local") == 0)) { 535 struct pmaplist *pml; 536 537 if (!svc_register(my_xprt, PMAPPROG, PMAPVERS, 538 pmap_service, 0)) { 539 syslog(LOG_ERR, "could not register on %s", 540 nconf->nc_netid); 541 goto error; 542 } 543 pml = malloc(sizeof (struct pmaplist)); 544 if (pml == NULL) { 545 syslog(LOG_ERR, "no memory!"); 546 exit(1); 547 } 548 pml->pml_map.pm_prog = PMAPPROG; 549 pml->pml_map.pm_vers = PMAPVERS; 550 pml->pml_map.pm_port = PMAPPORT; 551 if (strcmp(nconf->nc_proto, NC_TCP) == 0) { 552 if (tcptrans[0]) { 553 syslog(LOG_ERR, 554 "cannot have more than one TCP transport"); 555 goto error; 556 } 557 tcptrans = strdup(nconf->nc_netid); 558 pml->pml_map.pm_prot = IPPROTO_TCP; 559 560 /* Let's snarf the universal address */ 561 /* "h1.h2.h3.h4.p1.p2" */ 562 tcp_uaddr = taddr2uaddr(nconf, &taddr.addr); 563 } else if (strcmp(nconf->nc_proto, NC_UDP) == 0) { 564 if (udptrans[0]) { 565 syslog(LOG_ERR, 566 "cannot have more than one UDP transport"); 567 goto error; 568 } 569 udptrans = strdup(nconf->nc_netid); 570 pml->pml_map.pm_prot = IPPROTO_UDP; 571 572 /* Let's snarf the universal address */ 573 /* "h1.h2.h3.h4.p1.p2" */ 574 udp_uaddr = taddr2uaddr(nconf, &taddr.addr); 575 } else if (strcmp(nconf->nc_netid, "local") == 0) 576 pml->pml_map.pm_prot = IPPROTO_ST; 577 else if (strcmp(nconf->nc_netid, "unix") == 0) 578 pml->pml_map.pm_prot = IPPROTO_ST; 579 pml->pml_next = list_pml; 580 list_pml = pml; 581 582 /* Add version 3 information */ 583 pml = malloc(sizeof (struct pmaplist)); 584 if (pml == NULL) { 585 syslog(LOG_ERR, "no memory!"); 586 exit(1); 587 } 588 pml->pml_map = list_pml->pml_map; 589 pml->pml_map.pm_vers = RPCBVERS; 590 pml->pml_next = list_pml; 591 list_pml = pml; 592 593 /* Add version 4 information */ 594 pml = malloc (sizeof (struct pmaplist)); 595 if (pml == NULL) { 596 syslog(LOG_ERR, "no memory!"); 597 exit(1); 598 } 599 pml->pml_map = list_pml->pml_map; 600 pml->pml_map.pm_vers = RPCBVERS4; 601 pml->pml_next = list_pml; 602 list_pml = pml; 603 604 /* Also add version 2 stuff to rpcbind list */ 605 rbllist_add(PMAPPROG, PMAPVERS, nconf, &taddr.addr); 606 } 607 #endif 608 609 /* version 3 registration */ 610 if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS, rpcb_service_3, NULL)) { 611 syslog(LOG_ERR, "could not register %s version 3", 612 nconf->nc_netid); 613 goto error; 614 } 615 rbllist_add(RPCBPROG, RPCBVERS, nconf, &taddr.addr); 616 617 /* version 4 registration */ 618 if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS4, rpcb_service_4, NULL)) { 619 syslog(LOG_ERR, "could not register %s version 4", 620 nconf->nc_netid); 621 goto error; 622 } 623 rbllist_add(RPCBPROG, RPCBVERS4, nconf, &taddr.addr); 624 625 /* decide if bound checking works for this transport */ 626 status = add_bndlist(nconf, &taddr.addr); 627 #ifdef BIND_DEBUG 628 if (debugging) { 629 if (status < 0) { 630 fprintf(stderr, "Error in finding bind status for %s\n", 631 nconf->nc_netid); 632 } else if (status == 0) { 633 fprintf(stderr, "check binding for %s\n", 634 nconf->nc_netid); 635 } else if (status > 0) { 636 fprintf(stderr, "No check binding for %s\n", 637 nconf->nc_netid); 638 } 639 } 640 #endif 641 /* 642 * rmtcall only supported on CLTS transports for now. 643 */ 644 if (nconf->nc_semantics == NC_TPI_CLTS) { 645 status = create_rmtcall_fd(nconf); 646 647 #ifdef BIND_DEBUG 648 if (debugging) { 649 if (status < 0) { 650 fprintf(stderr, 651 "Could not create rmtcall fd for %s\n", 652 nconf->nc_netid); 653 } else { 654 fprintf(stderr, "rmtcall fd for %s is %d\n", 655 nconf->nc_netid, status); 656 } 657 } 658 #endif 659 } 660 return (0); 661 error: 662 close(fd); 663 return (1); 664 } 665 666 /* 667 * Create the list of addresses that we're bound to. Normally, this 668 * list is empty because we're listening on the wildcard address 669 * (nhost == 0). If -h is specified on the command line, then 670 * bound_sa will have a list of the addresses that the program binds 671 * to specifically. This function takes that list and converts them to 672 * struct sockaddr * and stores them in bound_sa. 673 */ 674 static void 675 update_bound_sa(void) 676 { 677 struct addrinfo hints, *res = NULL; 678 int i; 679 680 if (nhosts == 0) 681 return; 682 bound_sa = malloc(sizeof(*bound_sa) * nhosts); 683 memset(&hints, 0, sizeof(hints)); 684 hints.ai_family = PF_UNSPEC; 685 for (i = 0; i < nhosts; i++) { 686 if (getaddrinfo(hosts[i], NULL, &hints, &res) != 0) 687 continue; 688 bound_sa[i] = malloc(res->ai_addrlen); 689 memcpy(bound_sa[i], res->ai_addr, res->ai_addrlen); 690 } 691 } 692 693 /* 694 * Match the sa against the list of addresses we've bound to. If 695 * we've not specifically bound to anything, we match everything. 696 * Otherwise, if the IPv4 or IPv6 address matches one of the addresses 697 * in bound_sa, we return true. If not, we return false. 698 */ 699 int 700 listen_addr(const struct sockaddr *sa) 701 { 702 int i; 703 704 /* 705 * If nhosts == 0, then there were no -h options on the 706 * command line, so all addresses are addresses we're 707 * listening to. 708 */ 709 if (nhosts == 0) 710 return 1; 711 for (i = 0; i < nhosts; i++) { 712 if (bound_sa[i] == NULL || 713 sa->sa_family != bound_sa[i]->sa_family) 714 continue; 715 switch (sa->sa_family) { 716 case AF_INET: 717 if (memcmp(&SA2SINADDR(sa), &SA2SINADDR(bound_sa[i]), 718 sizeof(struct in_addr)) == 0) 719 return (1); 720 break; 721 #ifdef INET6 722 case AF_INET6: 723 if (memcmp(&SA2SIN6ADDR(sa), &SA2SIN6ADDR(bound_sa[i]), 724 sizeof(struct in6_addr)) == 0) 725 return (1); 726 break; 727 #endif 728 default: 729 break; 730 } 731 } 732 return (0); 733 } 734 735 static void 736 rbllist_add(rpcprog_t prog, rpcvers_t vers, struct netconfig *nconf, 737 struct netbuf *addr) 738 { 739 rpcblist_ptr rbl; 740 741 rbl = malloc(sizeof (rpcblist)); 742 if (rbl == NULL) { 743 syslog(LOG_ERR, "no memory!"); 744 exit(1); 745 } 746 747 rbl->rpcb_map.r_prog = prog; 748 rbl->rpcb_map.r_vers = vers; 749 rbl->rpcb_map.r_netid = strdup(nconf->nc_netid); 750 rbl->rpcb_map.r_addr = taddr2uaddr(nconf, addr); 751 rbl->rpcb_map.r_owner = strdup(superuser); 752 rbl->rpcb_next = list_rbl; /* Attach to global list */ 753 list_rbl = rbl; 754 } 755 756 /* 757 * Catch the signal and die 758 */ 759 static void 760 terminate(int dummy __unused) 761 { 762 close(rpcbindlockfd); 763 #ifdef WARMSTART 764 syslog(LOG_ERR, 765 "rpcbind terminating on signal. Restart with \"rpcbind -w\""); 766 write_warmstart(); /* Dump yourself */ 767 #endif 768 exit(2); 769 } 770 771 void 772 rpcbind_abort(void) 773 { 774 #ifdef WARMSTART 775 write_warmstart(); /* Dump yourself */ 776 #endif 777 abort(); 778 } 779 780 /* get command line options */ 781 static void 782 parseargs(int argc, char *argv[]) 783 { 784 int c; 785 786 #ifdef WARMSTART 787 #define WSOP "w" 788 #else 789 #define WSOP "" 790 #endif 791 #ifdef LIBWRAP 792 #define WRAPOP "W" 793 #else 794 #define WRAPOP "" 795 #endif 796 while ((c = getopt(argc, argv, "6adh:iLls" WRAPOP WSOP)) != -1) { 797 switch (c) { 798 case '6': 799 ipv6_only = 1; 800 break; 801 case 'a': 802 doabort = 1; /* when debugging, do an abort on */ 803 break; /* errors; for rpcbind developers */ 804 /* only! */ 805 case 'd': 806 debugging = 1; 807 break; 808 case 'h': 809 ++nhosts; 810 hosts = realloc(hosts, nhosts * sizeof(char *)); 811 if (hosts == NULL) 812 errx(1, "Out of memory"); 813 hosts[nhosts - 1] = strdup(optarg); 814 if (hosts[nhosts - 1] == NULL) 815 errx(1, "Out of memory"); 816 break; 817 case 'i': 818 insecure = 1; 819 break; 820 case 'L': 821 oldstyle_local = 1; 822 break; 823 case 'l': 824 verboselog = 1; 825 break; 826 case 's': 827 runasdaemon = 1; 828 break; 829 #ifdef LIBWRAP 830 case 'W': 831 libwrap = 1; 832 break; 833 #endif 834 #ifdef WARMSTART 835 case 'w': 836 warmstart = 1; 837 break; 838 #endif 839 default: /* error */ 840 fprintf(stderr, 841 "usage: rpcbind [-6adiLls%s%s] [-h bindip]\n", 842 WRAPOP, WSOP); 843 exit (1); 844 } 845 } 846 if (doabort && !debugging) { 847 fprintf(stderr, 848 "-a (abort) specified without -d (debugging) -- ignored.\n"); 849 doabort = 0; 850 } 851 #undef WSOP 852 } 853 854 void 855 reap(int dummy __unused) 856 { 857 int save_errno = errno; 858 859 while (wait3(NULL, WNOHANG, NULL) > 0) 860 ; 861 errno = save_errno; 862 } 863 864 void 865 toggle_verboselog(int dummy __unused) 866 { 867 verboselog = !verboselog; 868 } 869