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