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