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