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