1/* $NetBSD: rpcbind.c,v 1.2 2010/07/28 15:11:30 pooka 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 39static 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 */ 80int debugging = 1; /* Tell me what's going on */ 81int doabort = 0; /* When debugging, do an abort on errors */ 82rpcblist_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 89int runasdaemon = 0; 90int insecure = 0; 91int oldstyle_local = 0; 92int verboselog = 0; 93 94#ifdef WARMSTART 95/* Local Variable */ 96static int warmstart = 0; /* Grab a old copy of registrations */ 97#endif 98 99#ifdef PORTMAP 100struct pmaplist *list_pml; /* A list of version 2 rpcbind services */ 101const char *udptrans; /* Name of UDP transport */ 102const char *tcptrans; /* Name of TCP transport */ 103const char *udp_uaddr; /* Universal UDP address */ 104const char *tcp_uaddr; /* Universal TCP address */ 105#endif 106static const char servname[] = "sunrpc"; 107 108const char rpcbind_superuser[] = "superuser"; 109const char rpcbind_unknown[] = "unknown"; 110 111static int init_transport(struct netconfig *); 112static void rbllist_add(rpcprog_t, rpcvers_t, struct netconfig *, 113 struct netbuf *); 114static void terminate(int); 115#if 0 116static void parseargs(int, char *[]); 117#endif 118 119int rpcbind_main(void *); 120int 121rpcbind_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 */ 228static int 229init_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 status; /* bound checking ? */ 237 int aicode; 238 int addrlen; 239 struct sockaddr *sa; 240 struct sockaddr_un sun; 241 const int one = 1; 242 243 if ((nconf->nc_semantics != NC_TPI_CLTS) && 244 (nconf->nc_semantics != NC_TPI_COTS) && 245 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 246 return 1; /* not my type */ 247#ifdef RPCBIND_DEBUG 248 if (debugging) { 249 int i; 250 char **s; 251 252 (void)fprintf(stderr, "%s: %ld lookup routines :\n", 253 nconf->nc_netid, nconf->nc_nlookups); 254 for (i = 0, s = nconf->nc_lookups; i < nconf->nc_nlookups; 255 i++, s++) 256 (void)fprintf(stderr, "[%d] - %s\n", i, *s); 257 } 258#endif 259 260 /* 261 * XXX - using RPC library internal functions. 262 */ 263 if ((fd = __rpc_nconf2fd(nconf)) < 0) { 264 if (errno == EAFNOSUPPORT) 265 return 1; 266 warn("Cannot create socket for `%s'", nconf->nc_netid); 267 return 1; 268 } 269 270 if (!__rpc_nconf2sockinfo(nconf, &si)) { 271 warnx("Cannot get information for `%s'", nconf->nc_netid); 272 return 1; 273 } 274 275 if (si.si_af == AF_INET6) { 276 /* 277 * We're doing host-based access checks here, so don't allow 278 * v4-in-v6 to confuse things. 279 */ 280 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, 281 sizeof one) < 0) { 282 warn("Can't make socket ipv6 only"); 283 return 1; 284 } 285 } 286 287 288 if (!strcmp(nconf->nc_netid, "local")) { 289 (void)memset(&sun, 0, sizeof sun); 290 sun.sun_family = AF_LOCAL; 291 (void)rump_sys_unlink(_PATH_RPCBINDSOCK); 292 (void)strlcpy(sun.sun_path, _PATH_RPCBINDSOCK, 293 sizeof(sun.sun_path)); 294 sun.sun_len = SUN_LEN(&sun); 295 addrlen = sizeof(struct sockaddr_un); 296 sa = (struct sockaddr *)&sun; 297 } else { 298 /* Get rpcbind's address on this transport */ 299 300 (void)memset(&hints, 0, sizeof hints); 301 hints.ai_flags = AI_PASSIVE; 302 hints.ai_family = si.si_af; 303 hints.ai_socktype = si.si_socktype; 304 hints.ai_protocol = si.si_proto; 305 if ((aicode = getaddrinfo(NULL, servname, &hints, &res)) != 0) { 306 warnx("Cannot get local address for `%s' (%s)", 307 nconf->nc_netid, gai_strerror(aicode)); 308 return 1; 309 } 310 addrlen = res->ai_addrlen; 311 sa = (struct sockaddr *)res->ai_addr; 312 } 313 314 if (bind(fd, sa, addrlen) < 0) { 315 warn("Cannot bind `%s'", nconf->nc_netid); 316 if (res != NULL) 317 freeaddrinfo(res); 318 return 1; 319 } 320#if 0 321 if (sa->sa_family == AF_LOCAL) 322 if (rump_sys_chmod(sun.sun_path, S_IRWXU|S_IRWXG|S_IRWXO) == -1) 323 warn("Cannot chmod `%s'", sun.sun_path); 324#endif 325 326 /* Copy the address */ 327 taddr.addr.len = taddr.addr.maxlen = addrlen; 328 taddr.addr.buf = malloc(addrlen); 329 if (taddr.addr.buf == NULL) { 330 warn("Cannot allocate memory for `%s' address", 331 nconf->nc_netid); 332 if (res != NULL) 333 freeaddrinfo(res); 334 return 1; 335 } 336 (void)memcpy(taddr.addr.buf, sa, addrlen); 337#ifdef RPCBIND_DEBUG 338 if (debugging) { 339 /* for debugging print out our universal address */ 340 char *uaddr; 341 struct netbuf nb; 342 343 nb.buf = sa; 344 nb.len = nb.maxlen = sa->sa_len; 345 uaddr = taddr2uaddr(nconf, &nb); 346 (void)fprintf(stderr, "rpcbind: my address is %s\n", uaddr); 347 (void)free(uaddr); 348 } 349#endif 350 351 if (res != NULL) 352 freeaddrinfo(res); 353 354 if (nconf->nc_semantics != NC_TPI_CLTS) 355 listen(fd, SOMAXCONN); 356 357 my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr, RPC_MAXDATASIZE, 358 RPC_MAXDATASIZE); 359 if (my_xprt == NULL) { 360 warnx("Could not create service for `%s'", nconf->nc_netid); 361 goto error; 362 } 363 364#ifdef PORTMAP 365 /* 366 * Register both the versions for tcp/ip, udp/ip and local. 367 */ 368 if ((strcmp(nconf->nc_protofmly, NC_INET) == 0 && 369 (strcmp(nconf->nc_proto, NC_TCP) == 0 || 370 strcmp(nconf->nc_proto, NC_UDP) == 0)) || 371 strcmp(nconf->nc_netid, "local") == 0) { 372 struct pmaplist *pml; 373 374 if (!svc_register(my_xprt, PMAPPROG, PMAPVERS, 375 pmap_service, 0)) { 376 warn("Could not register on `%s'", nconf->nc_netid); 377 goto error; 378 } 379 pml = malloc(sizeof (struct pmaplist)); 380 if (pml == NULL) { 381 warn("Cannot allocate memory"); 382 goto error; 383 } 384 pml->pml_map.pm_prog = PMAPPROG; 385 pml->pml_map.pm_vers = PMAPVERS; 386 pml->pml_map.pm_port = PMAPPORT; 387 if (strcmp(nconf->nc_proto, NC_TCP) == 0) { 388 if (tcptrans[0]) { 389 warnx( 390 "Cannot have more than one TCP transport"); 391 free(pml); 392 goto error; 393 } 394 tcptrans = strdup(nconf->nc_netid); 395 if (tcptrans == NULL) { 396 free(pml); 397 warn("Cannot allocate memory"); 398 goto error; 399 } 400 pml->pml_map.pm_prot = IPPROTO_TCP; 401 402 /* Let's snarf the universal address */ 403 /* "h1.h2.h3.h4.p1.p2" */ 404 tcp_uaddr = taddr2uaddr(nconf, &taddr.addr); 405 } else if (strcmp(nconf->nc_proto, NC_UDP) == 0) { 406 if (udptrans[0]) { 407 free(pml); 408 warnx( 409 "Cannot have more than one UDP transport"); 410 goto error; 411 } 412 udptrans = strdup(nconf->nc_netid); 413 if (udptrans == NULL) { 414 free(pml); 415 warn("Cannot allocate memory"); 416 goto error; 417 } 418 pml->pml_map.pm_prot = IPPROTO_UDP; 419 420 /* Let's snarf the universal address */ 421 /* "h1.h2.h3.h4.p1.p2" */ 422 udp_uaddr = taddr2uaddr(nconf, &taddr.addr); 423 } 424 pml->pml_next = list_pml; 425 list_pml = pml; 426 427 /* Add version 3 information */ 428 pml = malloc(sizeof (struct pmaplist)); 429 if (pml == NULL) { 430 warn("Cannot allocate memory"); 431 goto error; 432 } 433 pml->pml_map = list_pml->pml_map; 434 pml->pml_map.pm_vers = RPCBVERS; 435 pml->pml_next = list_pml; 436 list_pml = pml; 437 438 /* Add version 4 information */ 439 pml = malloc(sizeof (struct pmaplist)); 440 if (pml == NULL) { 441 warn("Cannot allocate memory"); 442 goto error; 443 } 444 pml->pml_map = list_pml->pml_map; 445 pml->pml_map.pm_vers = RPCBVERS4; 446 pml->pml_next = list_pml; 447 list_pml = pml; 448 449 /* Also add version 2 stuff to rpcbind list */ 450 rbllist_add(PMAPPROG, PMAPVERS, nconf, &taddr.addr); 451 } 452#endif 453 454 /* version 3 registration */ 455 if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS, rpcb_service_3, NULL)) { 456 warn("Could not register %s version 3", nconf->nc_netid); 457 goto error; 458 } 459 rbllist_add(RPCBPROG, RPCBVERS, nconf, &taddr.addr); 460 461 /* version 4 registration */ 462 if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS4, rpcb_service_4, NULL)) { 463 warn("Could not register %s version 4", nconf->nc_netid); 464 goto error; 465 } 466 rbllist_add(RPCBPROG, RPCBVERS4, nconf, &taddr.addr); 467 468 /* decide if bound checking works for this transport */ 469 status = add_bndlist(nconf, &taddr.addr); 470#ifdef RPCBIND_DEBUG 471 if (debugging) { 472 if (status < 0) { 473 fprintf(stderr, "Error in finding bind status for %s\n", 474 nconf->nc_netid); 475 } else if (status == 0) { 476 fprintf(stderr, "check binding for %s\n", 477 nconf->nc_netid); 478 } else if (status > 0) { 479 fprintf(stderr, "No check binding for %s\n", 480 nconf->nc_netid); 481 } 482 } 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); 504error: 505 (void)rump_sys_close(fd); 506 return (1); 507} 508 509static void 510rbllist_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 */ 533static void 534terminate(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 544void 545rpcbind_abort() 546{ 547#ifdef WARMSTART 548 write_warmstart(); /* Dump yourself */ 549#endif 550 abort(); 551} 552 553#if 0 554/* get command line options */ 555static void 556parseargs(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 599void 600reap(int dummy) 601{ 602 int save_errno = errno; 603 604 while (wait3(NULL, WNOHANG, NULL) > 0) 605 ; 606 errno = save_errno; 607} 608 609void 610toggle_verboselog(int dummy) 611{ 612 verboselog = !verboselog; 613} 614