rpcbind.c revision 107952
1/* $NetBSD: rpcbind.c,v 1.1 2000/06/02 23:15:42 fvdl Exp $ */ 2/* $FreeBSD: head/usr.sbin/rpcbind/rpcbind.c 107952 2002-12-16 22:24:26Z mbr $ */ 3 4/* 5 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 6 * unrestricted use provided that this legend is included on all tape 7 * media and as a part of the software program in whole or part. Users 8 * may copy or modify Sun RPC without charge, but are not authorized 9 * to license or distribute it to anyone else except as part of a product or 10 * program developed by the user. 11 * 12 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 13 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 14 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 15 * 16 * Sun RPC is provided with no support and without any obligation on the 17 * part of Sun Microsystems, Inc. to assist in its use, correction, 18 * modification or enhancement. 19 * 20 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 21 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 22 * OR ANY PART THEREOF. 23 * 24 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 25 * or profits or other special, indirect and consequential damages, even if 26 * Sun has been advised of the possibility of such damages. 27 * 28 * Sun Microsystems, Inc. 29 * 2550 Garcia Avenue 30 * Mountain View, California 94043 31 */ 32/* 33 * Copyright (c) 1984 - 1991 by Sun Microsystems, Inc. 34 */ 35 36/* #ident "@(#)rpcbind.c 1.19 94/04/25 SMI" */ 37 38#if 0 39#ifndef lint 40static char sccsid[] = "@(#)rpcbind.c 1.35 89/04/21 Copyr 1984 Sun Micro"; 41#endif 42#endif 43 44/* 45 * rpcbind.c 46 * Implements the program, version to address mapping for rpc. 47 * 48 */ 49 50#include <sys/types.h> 51#include <sys/stat.h> 52#include <sys/errno.h> 53#include <sys/time.h> 54#include <sys/resource.h> 55#include <sys/wait.h> 56#include <sys/signal.h> 57#include <sys/socket.h> 58#include <sys/un.h> 59#include <rpc/rpc.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 */ 79int debugging = 0; /* Tell me what's going on */ 80int doabort = 0; /* When debugging, do an abort on errors */ 81rpcblist_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 88int runasdaemon = 0; 89int insecure = 0; 90int oldstyle_local = 0; 91int verboselog = 0; 92 93char **hosts = NULL; 94int nhosts = 0; 95int on = 1; 96int rpcbindlockfd; 97 98#ifdef WARMSTART 99/* Local Variable */ 100static int warmstart = 0; /* Grab a old copy of registrations */ 101#endif 102 103#ifdef PORTMAP 104struct pmaplist *list_pml; /* A list of version 2 rpcbind services */ 105char *udptrans; /* Name of UDP transport */ 106char *tcptrans; /* Name of TCP transport */ 107char *udp_uaddr; /* Universal UDP address */ 108char *tcp_uaddr; /* Universal TCP address */ 109#endif 110static char servname[] = "rpcbind"; 111static char superuser[] = "superuser"; 112 113int main __P((int, char *[])); 114 115static int init_transport __P((struct netconfig *)); 116static void rbllist_add __P((rpcprog_t, rpcvers_t, struct netconfig *, 117 struct netbuf *)); 118static void terminate __P((int)); 119static void parseargs __P((int, char *[])); 120 121int 122main(int argc, char *argv[]) 123{ 124 struct netconfig *nconf; 125 void *nc_handle; /* Net config handle */ 126 struct rlimit rl; 127 128 parseargs(argc, argv); 129 130 /* Check that another rpcbind isn't already running. */ 131 if ((rpcbindlockfd = (open(RPCBINDDLOCK, 132 O_RDONLY|O_CREAT, 0444))) == -1) 133 err(1, "%s", RPCBINDDLOCK); 134 135 if(flock(rpcbindlockfd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK) 136 errx(1, "another rpcbind is already running. Aborting"); 137 138 getrlimit(RLIMIT_NOFILE, &rl); 139 if (rl.rlim_cur < 128) { 140 if (rl.rlim_max <= 128) 141 rl.rlim_cur = rl.rlim_max; 142 else 143 rl.rlim_cur = 128; 144 setrlimit(RLIMIT_NOFILE, &rl); 145 } 146 openlog("rpcbind", LOG_CONS, LOG_DAEMON); 147 if (geteuid()) { /* This command allowed only to root */ 148 fprintf(stderr, "Sorry. You are not superuser\n"); 149 exit(1); 150 } 151 nc_handle = setnetconfig(); /* open netconfig file */ 152 if (nc_handle == NULL) { 153 syslog(LOG_ERR, "could not read /etc/netconfig"); 154 exit(1); 155 } 156#ifdef PORTMAP 157 udptrans = ""; 158 tcptrans = ""; 159#endif 160 161 nconf = getnetconfigent("local"); 162 if (nconf == NULL) 163 nconf = getnetconfigent("unix"); 164 if (nconf == NULL) { 165 syslog(LOG_ERR, "%s: can't find local transport\n", argv[0]); 166 exit(1); 167 } 168 init_transport(nconf); 169 170 while ((nconf = getnetconfig(nc_handle))) { 171 if (nconf->nc_flag & NC_VISIBLE) 172 init_transport(nconf); 173 } 174 endnetconfig(nc_handle); 175 176 /* catch the usual termination signals for graceful exit */ 177 (void) signal(SIGCHLD, reap); 178 (void) signal(SIGINT, terminate); 179 (void) signal(SIGTERM, terminate); 180 (void) signal(SIGQUIT, terminate); 181 /* ignore others that could get sent */ 182 (void) signal(SIGPIPE, SIG_IGN); 183 (void) signal(SIGHUP, SIG_IGN); 184 (void) signal(SIGUSR1, SIG_IGN); 185 (void) signal(SIGUSR2, SIG_IGN); 186#ifdef WARMSTART 187 if (warmstart) { 188 read_warmstart(); 189 } 190#endif 191 if (debugging) { 192 printf("rpcbind debugging enabled."); 193 if (doabort) { 194 printf(" Will abort on errors!\n"); 195 } else { 196 printf("\n"); 197 } 198 } else { 199 if (daemon(0, 0)) 200 err(1, "fork failed"); 201 } 202 203 if (runasdaemon) { 204 struct passwd *p; 205 206 if((p = getpwnam(RUN_AS)) == NULL) { 207 syslog(LOG_ERR, "cannot get uid of daemon: %m"); 208 exit(1); 209 } 210 if (setuid(p->pw_uid) == -1) { 211 syslog(LOG_ERR, "setuid to daemon failed: %m"); 212 exit(1); 213 } 214 } 215 216 network_init(); 217 218 my_svc_run(); 219 syslog(LOG_ERR, "svc_run returned unexpectedly"); 220 rpcbind_abort(); 221 /* NOTREACHED */ 222 223 return 0; 224} 225 226/* 227 * Adds the entry into the rpcbind database. 228 * If PORTMAP, then for UDP and TCP, it adds the entries for version 2 also 229 * Returns 0 if succeeds, else fails 230 */ 231static int 232init_transport(struct netconfig *nconf) 233{ 234 int fd; 235 struct t_bind taddr; 236 struct addrinfo hints, *res = NULL; 237 struct __rpc_sockinfo si; 238 SVCXPRT *my_xprt; 239 int status; /* bound checking ? */ 240 int aicode; 241 int addrlen; 242 int nhostsbak; 243 int checkbind; 244 struct sockaddr *sa; 245 u_int32_t host_addr[4]; /* IPv4 or IPv6 */ 246 struct sockaddr_un sun; 247 mode_t oldmask; 248 249 if ((nconf->nc_semantics != NC_TPI_CLTS) && 250 (nconf->nc_semantics != NC_TPI_COTS) && 251 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 252 return (1); /* not my type */ 253#ifdef ND_DEBUG 254 if (debugging) { 255 int i; 256 char **s; 257 258 (void) fprintf(stderr, "%s: %ld lookup routines :\n", 259 nconf->nc_netid, nconf->nc_nlookups); 260 for (i = 0, s = nconf->nc_lookups; i < nconf->nc_nlookups; 261 i++, s++) 262 fprintf(stderr, "[%d] - %s\n", i, *s); 263 } 264#endif 265 266 /* 267 * XXX - using RPC library internal functions. For NC_TPI_CLTS 268 * we call this later, for each socket we like to bind. 269 */ 270 if (nconf->nc_semantics != NC_TPI_CLTS) { 271 if ((fd = __rpc_nconf2fd(nconf)) < 0) { 272 syslog(LOG_ERR, "cannot create socket for %s", 273 nconf->nc_netid); 274 return (1); 275 } 276 } 277 278 if (!__rpc_nconf2sockinfo(nconf, &si)) { 279 syslog(LOG_ERR, "cannot get information for %s", 280 nconf->nc_netid); 281 return (1); 282 } 283 284 if ((strcmp(nconf->nc_netid, "local") == 0) || 285 (strcmp(nconf->nc_netid, "unix") == 0)) { 286 memset(&sun, 0, sizeof sun); 287 sun.sun_family = AF_LOCAL; 288 unlink(_PATH_RPCBINDSOCK); 289 strcpy(sun.sun_path, _PATH_RPCBINDSOCK); 290 sun.sun_len = SUN_LEN(&sun); 291 addrlen = sizeof (struct sockaddr_un); 292 sa = (struct sockaddr *)&sun; 293 } else { 294 /* Get rpcbind's address on this transport */ 295 296 memset(&hints, 0, sizeof hints); 297 hints.ai_flags = AI_PASSIVE; 298 hints.ai_family = si.si_af; 299 hints.ai_socktype = si.si_socktype; 300 hints.ai_protocol = si.si_proto; 301 } 302 if (nconf->nc_semantics == NC_TPI_CLTS) { 303 /* 304 * If no hosts were specified, just bind to INADDR_ANY. Otherwise 305 * make sure 127.0.0.1 is added to the list. 306 */ 307 nhostsbak = nhosts; 308 nhostsbak++; 309 hosts = realloc(hosts, nhostsbak * sizeof(char *)); 310 if (nhostsbak == 1) 311 hosts[0] = "*"; 312 else { 313 if (hints.ai_family == AF_INET) { 314 hosts[nhostsbak - 1] = "127.0.0.1"; 315 } else if (hints.ai_family == AF_INET6) { 316 hosts[nhostsbak - 1] = "::1"; 317 } else 318 return 1; 319 } 320 321 /* 322 * Bind to specific IPs if asked to 323 */ 324 checkbind = 1; 325 while (nhostsbak > 0) { 326 --nhostsbak; 327 /* 328 * XXX - using RPC library internal functions. 329 */ 330 if ((fd = __rpc_nconf2fd(nconf)) < 0) { 331 syslog(LOG_ERR, "cannot create socket for %s", 332 nconf->nc_netid); 333 return (1); 334 } 335 switch (hints.ai_family) { 336 case AF_INET: 337 if (inet_pton(AF_INET, hosts[nhostsbak], 338 host_addr) == 1) { 339 hints.ai_flags &= AI_NUMERICHOST; 340 } else { 341 /* 342 * Skip if we have a AF_INET6 adress 343 */ 344 if (inet_pton(AF_INET6, 345 hosts[nhostsbak], host_addr) == 1) 346 continue; 347 } 348 break; 349 case AF_INET6: 350 if (inet_pton(AF_INET6, hosts[nhostsbak], 351 host_addr) == 1) { 352 hints.ai_flags &= AI_NUMERICHOST; 353 } else { 354 /* 355 * Skip if we have a AF_INET adress 356 */ 357 if (inet_pton(AF_INET, hosts[nhostsbak], 358 host_addr) == 1) 359 continue; 360 } 361 if (setsockopt(fd, IPPROTO_IPV6, 362 IPV6_V6ONLY, &on, sizeof on) < 0) { 363 syslog(LOG_ERR, 364 "can't set v6-only binding for " 365 "udp6 socket: %m"); 366 continue; 367 } 368 break; 369 default: 370 break; 371 } 372 373 /* 374 * If no hosts were specified, just bind to INADDR_ANY 375 */ 376 if (strcmp("*", hosts[nhostsbak]) == 0) 377 hosts[nhostsbak] = NULL; 378 379 if ((aicode = getaddrinfo(hosts[nhostsbak], 380 servname, &hints, &res)) != 0) { 381 syslog(LOG_ERR, 382 "cannot get local address for %s: %s", 383 nconf->nc_netid, gai_strerror(aicode)); 384 continue; 385 } 386 addrlen = res->ai_addrlen; 387 sa = (struct sockaddr *)res->ai_addr; 388 oldmask = umask(S_IXUSR|S_IXGRP|S_IXOTH); 389 if (bind(fd, sa, addrlen) != 0) { 390 syslog(LOG_ERR, "cannot bind %s on %s: %m", 391 (hosts[nhostsbak] == NULL) ? "*" : 392 hosts[nhostsbak], nconf->nc_netid); 393 if (res != NULL) 394 freeaddrinfo(res); 395 continue; 396 } else 397 checkbind++; 398 (void) umask(oldmask); 399 400 /* Copy the address */ 401 taddr.addr.len = taddr.addr.maxlen = addrlen; 402 taddr.addr.buf = malloc(addrlen); 403 if (taddr.addr.buf == NULL) { 404 syslog(LOG_ERR, 405 "cannot allocate memory for %s address", 406 nconf->nc_netid); 407 if (res != NULL) 408 freeaddrinfo(res); 409 return 1; 410 } 411 memcpy(taddr.addr.buf, sa, addrlen); 412#ifdef ND_DEBUG 413 if (debugging) { 414 /* 415 * for debugging print out our universal 416 * address 417 */ 418 char *uaddr; 419 struct netbuf nb; 420 421 nb.buf = sa; 422 nb.len = nb.maxlen = sa->sa_len; 423 uaddr = taddr2uaddr(nconf, &nb); 424 (void) fprintf(stderr, 425 "rpcbind : my address is %s\n", uaddr); 426 (void) free(uaddr); 427 } 428#endif 429 430 if (nconf->nc_semantics != NC_TPI_CLTS) 431 listen(fd, SOMAXCONN); 432 433 my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr, 434 0, 0); 435 if (my_xprt == (SVCXPRT *)NULL) { 436 syslog(LOG_ERR, "%s: could not create service", 437 nconf->nc_netid); 438 goto error; 439 } 440 } 441 if (!checkbind) 442 return 1; 443 } else { 444 if ((strcmp(nconf->nc_netid, "local") != 0) && 445 (strcmp(nconf->nc_netid, "unix") != 0)) { 446 if ((aicode = getaddrinfo(NULL, servname, &hints, &res)) 447 != 0) { 448 syslog(LOG_ERR, 449 "cannot get local address for %s: %s", 450 nconf->nc_netid, gai_strerror(aicode)); 451 return 1; 452 } 453 addrlen = res->ai_addrlen; 454 sa = (struct sockaddr *)res->ai_addr; 455 } 456 oldmask = umask(S_IXUSR|S_IXGRP|S_IXOTH); 457 if (bind(fd, sa, addrlen) < 0) { 458 syslog(LOG_ERR, "cannot bind %s: %m", nconf->nc_netid); 459 if (res != NULL) 460 freeaddrinfo(res); 461 return 1; 462 } 463 (void) umask(oldmask); 464 465 /* Copy the address */ 466 taddr.addr.len = taddr.addr.maxlen = addrlen; 467 taddr.addr.buf = malloc(addrlen); 468 if (taddr.addr.buf == NULL) { 469 syslog(LOG_ERR, "cannot allocate memory for %s address", 470 nconf->nc_netid); 471 if (res != NULL) 472 freeaddrinfo(res); 473 return 1; 474 } 475 memcpy(taddr.addr.buf, sa, addrlen); 476#ifdef ND_DEBUG 477 if (debugging) { 478 /* for debugging print out our universal address */ 479 char *uaddr; 480 struct netbuf nb; 481 482 nb.buf = sa; 483 nb.len = nb.maxlen = sa->sa_len; 484 uaddr = taddr2uaddr(nconf, &nb); 485 (void) fprintf(stderr, "rpcbind : my address is %s\n", 486 uaddr); 487 (void) free(uaddr); 488 } 489#endif 490 491 if (nconf->nc_semantics != NC_TPI_CLTS) 492 listen(fd, SOMAXCONN); 493 494 my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr, 0, 0); 495 if (my_xprt == (SVCXPRT *)NULL) { 496 syslog(LOG_ERR, "%s: could not create service", 497 nconf->nc_netid); 498 goto error; 499 } 500 } 501 502#ifdef PORTMAP 503 /* 504 * Register both the versions for tcp/ip, udp/ip and local. 505 */ 506 if ((strcmp(nconf->nc_protofmly, NC_INET) == 0 && 507 (strcmp(nconf->nc_proto, NC_TCP) == 0 || 508 strcmp(nconf->nc_proto, NC_UDP) == 0)) || 509 (strcmp(nconf->nc_netid, "unix") == 0) || 510 (strcmp(nconf->nc_netid, "local") == 0)) { 511 struct pmaplist *pml; 512 513 if (!svc_register(my_xprt, PMAPPROG, PMAPVERS, 514 pmap_service, NULL)) { 515 syslog(LOG_ERR, "could not register on %s", 516 nconf->nc_netid); 517 goto error; 518 } 519 pml = malloc(sizeof (struct pmaplist)); 520 if (pml == NULL) { 521 syslog(LOG_ERR, "no memory!"); 522 exit(1); 523 } 524 pml->pml_map.pm_prog = PMAPPROG; 525 pml->pml_map.pm_vers = PMAPVERS; 526 pml->pml_map.pm_port = PMAPPORT; 527 if (strcmp(nconf->nc_proto, NC_TCP) == 0) { 528 if (tcptrans[0]) { 529 syslog(LOG_ERR, 530 "cannot have more than one TCP transport"); 531 goto error; 532 } 533 tcptrans = strdup(nconf->nc_netid); 534 pml->pml_map.pm_prot = IPPROTO_TCP; 535 536 /* Let's snarf the universal address */ 537 /* "h1.h2.h3.h4.p1.p2" */ 538 tcp_uaddr = taddr2uaddr(nconf, &taddr.addr); 539 } else if (strcmp(nconf->nc_proto, NC_UDP) == 0) { 540 if (udptrans[0]) { 541 syslog(LOG_ERR, 542 "cannot have more than one UDP transport"); 543 goto error; 544 } 545 udptrans = strdup(nconf->nc_netid); 546 pml->pml_map.pm_prot = IPPROTO_UDP; 547 548 /* Let's snarf the universal address */ 549 /* "h1.h2.h3.h4.p1.p2" */ 550 udp_uaddr = taddr2uaddr(nconf, &taddr.addr); 551 } else if (strcmp(nconf->nc_netid, "local") == 0) 552 pml->pml_map.pm_prot = IPPROTO_ST; 553 else if (strcmp(nconf->nc_netid, "unix") == 0) 554 pml->pml_map.pm_prot = IPPROTO_ST; 555 pml->pml_next = list_pml; 556 list_pml = pml; 557 558 /* Add version 3 information */ 559 pml = malloc(sizeof (struct pmaplist)); 560 if (pml == NULL) { 561 syslog(LOG_ERR, "no memory!"); 562 exit(1); 563 } 564 pml->pml_map = list_pml->pml_map; 565 pml->pml_map.pm_vers = RPCBVERS; 566 pml->pml_next = list_pml; 567 list_pml = pml; 568 569 /* Add version 4 information */ 570 pml = malloc (sizeof (struct pmaplist)); 571 if (pml == NULL) { 572 syslog(LOG_ERR, "no memory!"); 573 exit(1); 574 } 575 pml->pml_map = list_pml->pml_map; 576 pml->pml_map.pm_vers = RPCBVERS4; 577 pml->pml_next = list_pml; 578 list_pml = pml; 579 580 /* Also add version 2 stuff to rpcbind list */ 581 rbllist_add(PMAPPROG, PMAPVERS, nconf, &taddr.addr); 582 } 583#endif 584 585 /* version 3 registration */ 586 if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS, rpcb_service_3, NULL)) { 587 syslog(LOG_ERR, "could not register %s version 3", 588 nconf->nc_netid); 589 goto error; 590 } 591 rbllist_add(RPCBPROG, RPCBVERS, nconf, &taddr.addr); 592 593 /* version 4 registration */ 594 if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS4, rpcb_service_4, NULL)) { 595 syslog(LOG_ERR, "could not register %s version 4", 596 nconf->nc_netid); 597 goto error; 598 } 599 rbllist_add(RPCBPROG, RPCBVERS4, nconf, &taddr.addr); 600 601 /* decide if bound checking works for this transport */ 602 status = add_bndlist(nconf, &taddr.addr); 603#ifdef BIND_DEBUG 604 if (debugging) { 605 if (status < 0) { 606 fprintf(stderr, "Error in finding bind status for %s\n", 607 nconf->nc_netid); 608 } else if (status == 0) { 609 fprintf(stderr, "check binding for %s\n", 610 nconf->nc_netid); 611 } else if (status > 0) { 612 fprintf(stderr, "No check binding for %s\n", 613 nconf->nc_netid); 614 } 615 } 616#endif 617 /* 618 * rmtcall only supported on CLTS transports for now. 619 */ 620 if (nconf->nc_semantics == NC_TPI_CLTS) { 621 status = create_rmtcall_fd(nconf); 622 623#ifdef BIND_DEBUG 624 if (debugging) { 625 if (status < 0) { 626 fprintf(stderr, 627 "Could not create rmtcall fd for %s\n", 628 nconf->nc_netid); 629 } else { 630 fprintf(stderr, "rmtcall fd for %s is %d\n", 631 nconf->nc_netid, status); 632 } 633 } 634#endif 635 } 636 return (0); 637error: 638 close(fd); 639 return (1); 640} 641 642static void 643rbllist_add(rpcprog_t prog, rpcvers_t vers, struct netconfig *nconf, 644 struct netbuf *addr) 645{ 646 rpcblist_ptr rbl; 647 648 rbl = malloc(sizeof (rpcblist)); 649 if (rbl == NULL) { 650 syslog(LOG_ERR, "no memory!"); 651 exit(1); 652 } 653 654 rbl->rpcb_map.r_prog = prog; 655 rbl->rpcb_map.r_vers = vers; 656 rbl->rpcb_map.r_netid = strdup(nconf->nc_netid); 657 rbl->rpcb_map.r_addr = taddr2uaddr(nconf, addr); 658 rbl->rpcb_map.r_owner = strdup(superuser); 659 rbl->rpcb_next = list_rbl; /* Attach to global list */ 660 list_rbl = rbl; 661} 662 663/* 664 * Catch the signal and die 665 */ 666static void 667terminate(int dummy __unused) 668{ 669 close(rpcbindlockfd); 670#ifdef WARMSTART 671 syslog(LOG_ERR, 672 "rpcbind terminating on signal. Restart with \"rpcbind -w\""); 673 write_warmstart(); /* Dump yourself */ 674#endif 675 exit(2); 676} 677 678void 679rpcbind_abort() 680{ 681#ifdef WARMSTART 682 write_warmstart(); /* Dump yourself */ 683#endif 684 abort(); 685} 686 687/* get command line options */ 688static void 689parseargs(int argc, char *argv[]) 690{ 691 int c; 692 693 while ((c = getopt(argc, argv, "dwah:ilLs")) != -1) { 694 switch (c) { 695 case 'a': 696 doabort = 1; /* when debugging, do an abort on */ 697 break; /* errors; for rpcbind developers */ 698 /* only! */ 699 case 'd': 700 debugging = 1; 701 break; 702 case 'h': 703 ++nhosts; 704 hosts = realloc(hosts, nhosts * sizeof(char *)); 705 if (hosts == NULL) 706 errx(1, "Out of memory"); 707 hosts[nhosts - 1] = strdup(optarg); 708 if (hosts[nhosts - 1] == NULL) 709 errx(1, "Out of memory"); 710 break; 711 case 'i': 712 insecure = 1; 713 break; 714 case 'L': 715 oldstyle_local = 1; 716 break; 717 case 'l': 718 verboselog = 1; 719 break; 720 case 's': 721 runasdaemon = 1; 722 break; 723#ifdef WARMSTART 724 case 'w': 725 warmstart = 1; 726 break; 727#endif 728 default: /* error */ 729 fprintf(stderr, "usage: rpcbind [-Idwils]\n"); 730 exit (1); 731 } 732 } 733 if (doabort && !debugging) { 734 fprintf(stderr, 735 "-a (abort) specified without -d (debugging) -- ignored.\n"); 736 doabort = 0; 737 } 738} 739 740void 741reap(int dummy __unused) 742{ 743 int save_errno = errno; 744 745 while (wait3(NULL, WNOHANG, NULL) > 0) 746 ; 747 errno = save_errno; 748} 749 750void 751toggle_verboselog(int dummy __unused) 752{ 753 verboselog = !verboselog; 754} 755