1 /* $NetBSD: rpcbind.c,v 1.23 2015/11/08 16:36:28 christos Exp $ */ 2 3 /* 4 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 5 * unrestricted use provided that this legend is included on all tape 6 * media and as a part of the software program in whole or part. Users 7 * may copy or modify Sun RPC without charge, but are not authorized 8 * to license or distribute it to anyone else except as part of a product or 9 * program developed by the user. 10 * 11 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 12 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 13 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 14 * 15 * Sun RPC is provided with no support and without any obligation on the 16 * part of Sun Microsystems, Inc. to assist in its use, correction, 17 * modification or enhancement. 18 * 19 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 20 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 21 * OR ANY PART THEREOF. 22 * 23 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 24 * or profits or other special, indirect and consequential damages, even if 25 * Sun has been advised of the possibility of such damages. 26 * 27 * Sun Microsystems, Inc. 28 * 2550 Garcia Avenue 29 * Mountain View, California 94043 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 #ifdef PORTMAP 60 #include <netinet/in.h> 61 #endif 62 #include <netdb.h> 63 #include <stdio.h> 64 #include <netconfig.h> 65 #include <stdlib.h> 66 #include <unistd.h> 67 #include <syslog.h> 68 #include <err.h> 69 #include <util.h> 70 #include <pwd.h> 71 #include <string.h> 72 #include <errno.h> 73 #include "rpcbind.h" 74 75 #ifdef RPCBIND_RUMP 76 #include <semaphore.h> 77 78 #include <rump/rump.h> 79 #include <rump/rump_syscalls.h> 80 81 #include "svc_fdset.h" 82 83 extern sem_t gensem; 84 #define DEBUGGING 1 85 #else 86 #define DEBUGGING 0 87 #endif 88 89 /* Global variables */ 90 int debugging = DEBUGGING; /* Tell me what's going on */ 91 int doabort = 0; /* When debugging, do an abort on errors */ 92 rpcblist_ptr list_rbl; /* A list of version 3/4 rpcbind services */ 93 94 /* who to suid to if -s is given */ 95 #define RUN_AS "daemon" 96 97 int runasdaemon = 0; 98 int insecure = 0; 99 int oldstyle_local = 0; 100 int verboselog = 0; 101 102 #ifdef WARMSTART 103 /* Local Variable */ 104 static int warmstart = 0; /* Grab a old copy of registrations */ 105 #endif 106 107 #ifdef PORTMAP 108 struct pmaplist *list_pml; /* A list of version 2 rpcbind services */ 109 const char *udptrans; /* Name of UDP transport */ 110 const char *tcptrans; /* Name of TCP transport */ 111 const char *udp_uaddr; /* Universal UDP address */ 112 const char *tcp_uaddr; /* Universal TCP address */ 113 #endif 114 static const char servname[] = "sunrpc"; 115 116 const char rpcbind_superuser[] = "superuser"; 117 const char rpcbind_unknown[] = "unknown"; 118 119 static int init_transport(struct netconfig *); 120 static void rbllist_add(rpcprog_t, rpcvers_t, struct netconfig *, 121 struct netbuf *); 122 __dead static void terminate(int); 123 #ifndef RPCBIND_RUMP 124 static void parseargs(int, char *[]); 125 126 int 127 main(int argc, char *argv[]) 128 #else 129 int rpcbind_main(void *); 130 int 131 rpcbind_main(void *arg) 132 #endif 133 { 134 struct netconfig *nconf; 135 void *nc_handle; /* Net config handle */ 136 struct rlimit rl; 137 int maxrec = RPC_MAXDATASIZE; 138 139 #ifdef RPCBIND_RUMP 140 svc_fdset_init(SVC_FDSET_MT); 141 #else 142 parseargs(argc, argv); 143 #endif 144 145 if (getrlimit(RLIMIT_NOFILE, &rl) == -1) 146 err(EXIT_FAILURE, "getrlimit(RLIMIT_NOFILE)"); 147 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 if (setrlimit(RLIMIT_NOFILE, &rl) < 0) 154 err(EXIT_FAILURE, "setrlimit(RLIMIT_NOFILE)"); 155 } 156 nc_handle = setnetconfig(); /* open netconfig file */ 157 if (nc_handle == NULL) 158 errx(EXIT_FAILURE, "could not read /etc/netconfig"); 159 #ifdef PORTMAP 160 udptrans = ""; 161 tcptrans = ""; 162 #endif 163 164 nconf = getnetconfigent("local"); 165 if (nconf == NULL) 166 errx(EXIT_FAILURE, "can't find local transport"); 167 168 rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 169 170 init_transport(nconf); 171 172 while ((nconf = getnetconfig(nc_handle))) { 173 if (nconf->nc_flag & NC_VISIBLE) 174 init_transport(nconf); 175 } 176 endnetconfig(nc_handle); 177 178 /* catch the usual termination signals for graceful exit */ 179 (void) signal(SIGCHLD, reap); 180 (void) signal(SIGINT, terminate); 181 (void) signal(SIGTERM, terminate); 182 (void) signal(SIGQUIT, terminate); 183 /* ignore others that could get sent */ 184 (void) signal(SIGPIPE, SIG_IGN); 185 #ifndef RPCBIND_RUMP 186 (void) signal(SIGHUP, SIG_IGN); 187 #endif 188 (void) signal(SIGUSR1, SIG_IGN); 189 (void) signal(SIGUSR2, SIG_IGN); 190 #ifdef WARMSTART 191 if (warmstart) { 192 read_warmstart(); 193 } 194 #endif 195 if (debugging) { 196 printf("rpcbind debugging enabled."); 197 if (doabort) { 198 printf(" Will abort on errors!\n"); 199 } else { 200 printf("\n"); 201 } 202 } else { 203 if (daemon(0, 0)) 204 err(EXIT_FAILURE, "fork failed"); 205 } 206 207 openlog("rpcbind", 0, LOG_DAEMON); 208 pidfile(NULL); 209 210 if (runasdaemon) { 211 struct passwd *p; 212 213 if((p = getpwnam(RUN_AS)) == NULL) { 214 syslog(LOG_ERR, "cannot get uid of daemon: %m"); 215 exit(EXIT_FAILURE); 216 } 217 if (setuid(p->pw_uid) == -1) { 218 syslog(LOG_ERR, "setuid to daemon failed: %m"); 219 exit(EXIT_FAILURE); 220 } 221 } 222 223 network_init(); 224 225 #ifdef RPCBIND_RUMP 226 sem_post(&gensem); 227 #endif 228 my_svc_run(); 229 syslog(LOG_ERR, "svc_run returned unexpectedly"); 230 rpcbind_abort(); 231 /* NOTREACHED */ 232 233 return EXIT_SUCCESS; 234 } 235 236 /* 237 * Adds the entry into the rpcbind database. 238 * If PORTMAP, then for UDP and TCP, it adds the entries for version 2 also 239 * Returns 0 if succeeds, else fails 240 */ 241 static int 242 init_transport(struct netconfig *nconf) 243 { 244 int fd; 245 struct t_bind taddr; 246 struct addrinfo hints, *res = NULL; 247 struct __rpc_sockinfo si; 248 SVCXPRT *my_xprt; 249 int status; /* bound checking ? */ 250 int aicode; 251 int addrlen; 252 struct sockaddr *sa; 253 struct sockaddr_un sun; 254 const int one = 1; 255 256 if ((nconf->nc_semantics != NC_TPI_CLTS) && 257 (nconf->nc_semantics != NC_TPI_COTS) && 258 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 259 return 1; /* not my type */ 260 #ifdef RPCBIND_DEBUG 261 if (debugging) { 262 int i; 263 char **s; 264 265 (void)fprintf(stderr, "%s: %ld lookup routines :\n", 266 nconf->nc_netid, nconf->nc_nlookups); 267 for (i = 0, s = nconf->nc_lookups; i < nconf->nc_nlookups; 268 i++, s++) 269 (void)fprintf(stderr, "[%d] - %s\n", i, *s); 270 } 271 #endif 272 273 /* 274 * XXX - using RPC library internal functions. 275 */ 276 if ((fd = __rpc_nconf2fd(nconf)) < 0) { 277 if (errno == EAFNOSUPPORT) 278 return 1; 279 warn("Cannot create socket for `%s'", nconf->nc_netid); 280 return 1; 281 } 282 283 if (!__rpc_nconf2sockinfo(nconf, &si)) { 284 warnx("Cannot get information for `%s'", nconf->nc_netid); 285 return 1; 286 } 287 288 if (si.si_af == AF_INET6) { 289 /* 290 * We're doing host-based access checks here, so don't allow 291 * v4-in-v6 to confuse things. 292 */ 293 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, 294 sizeof one) < 0) { 295 warn("Can't make socket ipv6 only"); 296 return 1; 297 } 298 } 299 300 301 if (!strcmp(nconf->nc_netid, "local")) { 302 (void)memset(&sun, 0, sizeof sun); 303 sun.sun_family = AF_LOCAL; 304 #ifdef RPCBIND_RUMP 305 (void)rump_sys_unlink(_PATH_RPCBINDSOCK); 306 #else 307 (void)unlink(_PATH_RPCBINDSOCK); 308 #endif 309 (void)strlcpy(sun.sun_path, _PATH_RPCBINDSOCK, 310 sizeof(sun.sun_path)); 311 sun.sun_len = SUN_LEN(&sun); 312 addrlen = sizeof(struct sockaddr_un); 313 sa = (struct sockaddr *)&sun; 314 } else { 315 /* Get rpcbind's address on this transport */ 316 317 (void)memset(&hints, 0, sizeof hints); 318 hints.ai_flags = AI_PASSIVE; 319 hints.ai_family = si.si_af; 320 hints.ai_socktype = si.si_socktype; 321 hints.ai_protocol = si.si_proto; 322 if ((aicode = getaddrinfo(NULL, servname, &hints, &res)) != 0) { 323 warnx("Cannot get local address for `%s' (%s)", 324 nconf->nc_netid, gai_strerror(aicode)); 325 return 1; 326 } 327 addrlen = res->ai_addrlen; 328 sa = (struct sockaddr *)res->ai_addr; 329 } 330 331 if (bind(fd, sa, addrlen) < 0) { 332 warn("Cannot bind `%s'", nconf->nc_netid); 333 if (res != NULL) 334 freeaddrinfo(res); 335 return 1; 336 } 337 #ifndef RPCBIND_RUMP 338 if (sa->sa_family == AF_LOCAL) 339 if (chmod(sun.sun_path, S_IRWXU|S_IRWXG|S_IRWXO) == -1) 340 warn("Cannot chmod `%s'", sun.sun_path); 341 #endif 342 343 /* Copy the address */ 344 taddr.addr.len = taddr.addr.maxlen = addrlen; 345 taddr.addr.buf = malloc(addrlen); 346 if (taddr.addr.buf == NULL) { 347 warn("Cannot allocate memory for `%s' address", 348 nconf->nc_netid); 349 if (res != NULL) 350 freeaddrinfo(res); 351 return 1; 352 } 353 (void)memcpy(taddr.addr.buf, sa, addrlen); 354 #ifdef RPCBIND_DEBUG 355 if (debugging) { 356 /* for debugging print out our universal address */ 357 char *uaddr; 358 struct netbuf nb; 359 360 nb.buf = sa; 361 nb.len = nb.maxlen = sa->sa_len; 362 uaddr = taddr2uaddr(nconf, &nb); 363 (void)fprintf(stderr, "rpcbind: my address is %s fd=%d\n", 364 uaddr, fd); 365 (void)free(uaddr); 366 } 367 #endif 368 369 if (res != NULL) 370 freeaddrinfo(res); 371 372 if (nconf->nc_semantics != NC_TPI_CLTS) 373 listen(fd, SOMAXCONN); 374 375 my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr, RPC_MAXDATASIZE, 376 RPC_MAXDATASIZE); 377 if (my_xprt == NULL) { 378 warnx("Could not create service for `%s'", nconf->nc_netid); 379 goto error; 380 } 381 382 #ifdef PORTMAP 383 /* 384 * Register both the versions for tcp/ip, udp/ip and local. 385 */ 386 if ((strcmp(nconf->nc_protofmly, NC_INET) == 0 && 387 (strcmp(nconf->nc_proto, NC_TCP) == 0 || 388 strcmp(nconf->nc_proto, NC_UDP) == 0)) || 389 strcmp(nconf->nc_netid, "local") == 0) { 390 struct pmaplist *pml; 391 392 if (!svc_register(my_xprt, PMAPPROG, PMAPVERS, 393 pmap_service, 0)) { 394 warn("Could not register on `%s'", nconf->nc_netid); 395 goto error; 396 } 397 pml = malloc(sizeof (struct pmaplist)); 398 if (pml == NULL) { 399 warn("Cannot allocate memory"); 400 goto error; 401 } 402 pml->pml_map.pm_prog = PMAPPROG; 403 pml->pml_map.pm_vers = PMAPVERS; 404 pml->pml_map.pm_port = PMAPPORT; 405 if (strcmp(nconf->nc_proto, NC_TCP) == 0) { 406 if (tcptrans[0]) { 407 warnx( 408 "Cannot have more than one TCP transport"); 409 free(pml); 410 goto error; 411 } 412 tcptrans = strdup(nconf->nc_netid); 413 if (tcptrans == NULL) { 414 free(pml); 415 warn("Cannot allocate memory"); 416 goto error; 417 } 418 pml->pml_map.pm_prot = IPPROTO_TCP; 419 420 /* Let's snarf the universal address */ 421 /* "h1.h2.h3.h4.p1.p2" */ 422 tcp_uaddr = taddr2uaddr(nconf, &taddr.addr); 423 } else if (strcmp(nconf->nc_proto, NC_UDP) == 0) { 424 if (udptrans[0]) { 425 free(pml); 426 warnx( 427 "Cannot have more than one UDP transport"); 428 goto error; 429 } 430 udptrans = strdup(nconf->nc_netid); 431 if (udptrans == NULL) { 432 free(pml); 433 warn("Cannot allocate memory"); 434 goto error; 435 } 436 pml->pml_map.pm_prot = IPPROTO_UDP; 437 438 /* Let's snarf the universal address */ 439 /* "h1.h2.h3.h4.p1.p2" */ 440 udp_uaddr = taddr2uaddr(nconf, &taddr.addr); 441 } 442 pml->pml_next = list_pml; 443 list_pml = pml; 444 445 /* Add version 3 information */ 446 pml = malloc(sizeof (struct pmaplist)); 447 if (pml == NULL) { 448 warn("Cannot allocate memory"); 449 goto error; 450 } 451 pml->pml_map = list_pml->pml_map; 452 pml->pml_map.pm_vers = RPCBVERS; 453 pml->pml_next = list_pml; 454 list_pml = pml; 455 456 /* Add version 4 information */ 457 pml = malloc(sizeof (struct pmaplist)); 458 if (pml == NULL) { 459 warn("Cannot allocate memory"); 460 goto error; 461 } 462 pml->pml_map = list_pml->pml_map; 463 pml->pml_map.pm_vers = RPCBVERS4; 464 pml->pml_next = list_pml; 465 list_pml = pml; 466 467 /* Also add version 2 stuff to rpcbind list */ 468 rbllist_add(PMAPPROG, PMAPVERS, nconf, &taddr.addr); 469 } 470 #endif 471 472 /* version 3 registration */ 473 if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS, rpcb_service_3, NULL)) { 474 warn("Could not register %s version 3", nconf->nc_netid); 475 goto error; 476 } 477 rbllist_add(RPCBPROG, RPCBVERS, nconf, &taddr.addr); 478 479 /* version 4 registration */ 480 if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS4, rpcb_service_4, NULL)) { 481 warn("Could not register %s version 4", nconf->nc_netid); 482 goto error; 483 } 484 rbllist_add(RPCBPROG, RPCBVERS4, nconf, &taddr.addr); 485 486 /* decide if bound checking works for this transport */ 487 status = add_bndlist(nconf, &taddr.addr); 488 #ifdef RPCBIND_DEBUG 489 if (debugging) { 490 if (status < 0) { 491 fprintf(stderr, "Error in finding bind status for %s\n", 492 nconf->nc_netid); 493 } else if (status == 0) { 494 fprintf(stderr, "check binding for %s\n", 495 nconf->nc_netid); 496 } else if (status > 0) { 497 fprintf(stderr, "No check binding for %s\n", 498 nconf->nc_netid); 499 } 500 } 501 #else 502 __USE(status); 503 #endif 504 /* 505 * rmtcall only supported on CLTS transports for now. 506 */ 507 if (nconf->nc_semantics == NC_TPI_CLTS) { 508 status = create_rmtcall_fd(nconf); 509 510 #ifdef RPCBIND_DEBUG 511 if (debugging) { 512 if (status < 0) { 513 fprintf(stderr, 514 "Could not create rmtcall fd for %s\n", 515 nconf->nc_netid); 516 } else { 517 fprintf(stderr, "rmtcall fd for %s is %d\n", 518 nconf->nc_netid, status); 519 } 520 } 521 #endif 522 } 523 return (0); 524 error: 525 #ifdef RPCBIND_RUMP 526 (void)rump_sys_close(fd); 527 #else 528 (void)close(fd); 529 #endif 530 return (1); 531 } 532 533 static void 534 rbllist_add(rpcprog_t prog, rpcvers_t vers, struct netconfig *nconf, 535 struct netbuf *addr) 536 { 537 rpcblist_ptr rbl; 538 539 rbl = malloc(sizeof(rpcblist)); 540 if (rbl == NULL) { 541 warn("Out of memory"); 542 return; 543 } 544 545 rbl->rpcb_map.r_prog = prog; 546 rbl->rpcb_map.r_vers = vers; 547 rbl->rpcb_map.r_netid = strdup(nconf->nc_netid); 548 rbl->rpcb_map.r_addr = taddr2uaddr(nconf, addr); 549 rbl->rpcb_map.r_owner = strdup(rpcbind_superuser); 550 rbl->rpcb_next = list_rbl; /* Attach to global list */ 551 list_rbl = rbl; 552 } 553 554 /* 555 * Catch the signal and die 556 */ 557 static void 558 terminate(int dummy) 559 { 560 #ifdef WARMSTART 561 syslog(LOG_ERR, 562 "rpcbind terminating on signal. Restart with \"rpcbind -w\""); 563 write_warmstart(); /* Dump yourself */ 564 #endif 565 #ifdef RPCBIND_RUMP 566 exit(2); 567 #else 568 exit(EXIT_FAILURE); 569 #endif 570 } 571 572 void 573 rpcbind_abort() 574 { 575 #ifdef WARMSTART 576 write_warmstart(); /* Dump yourself */ 577 #endif 578 abort(); 579 } 580 581 #ifndef RPCBIND_RUMP 582 /* get command line options */ 583 static void 584 parseargs(int argc, char *argv[]) 585 { 586 int c; 587 588 while ((c = getopt(argc, argv, "dwailLs")) != -1) { 589 switch (c) { 590 case 'a': 591 doabort = 1; /* when debugging, do an abort on */ 592 break; /* errors; for rpcbind developers */ 593 /* only! */ 594 case 'd': 595 debugging = 1; 596 break; 597 case 'i': 598 insecure = 1; 599 break; 600 case 'L': 601 oldstyle_local = 1; 602 break; 603 case 'l': 604 verboselog = 1; 605 break; 606 case 's': 607 runasdaemon = 1; 608 break; 609 #ifdef WARMSTART 610 case 'w': 611 warmstart = 1; 612 break; 613 #endif 614 default: /* error */ 615 fprintf(stderr, "usage: rpcbind [-Idwils]\n"); 616 exit(EXIT_FAILURE); 617 } 618 } 619 if (doabort && !debugging) { 620 fprintf(stderr, 621 "-a (abort) specified without -d (debugging) -- ignored.\n"); 622 doabort = 0; 623 } 624 } 625 #endif 626 627 void 628 reap(int dummy) 629 { 630 int save_errno = errno; 631 632 while (wait3(NULL, WNOHANG, NULL) > 0) 633 ; 634 errno = save_errno; 635 } 636 637 void 638 toggle_verboselog(int dummy) 639 { 640 verboselog = !verboselog; 641 } 642