1 /* $NetBSD: rpcbind.c,v 1.2 2001/01/11 02:45:31 lukem 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 118 parseargs(argc, argv); 119 120 getrlimit(RLIMIT_NOFILE, &rl); 121 if (rl.rlim_cur < 128) { 122 if (rl.rlim_max <= 128) 123 rl.rlim_cur = rl.rlim_max; 124 else 125 rl.rlim_cur = 128; 126 setrlimit(RLIMIT_NOFILE, &rl); 127 } 128 openlog("rpcbind", 0, LOG_DAEMON); 129 if (geteuid()) { /* This command allowed only to root */ 130 fprintf(stderr, "Sorry. You are not superuser\n"); 131 exit(1); 132 } 133 nc_handle = setnetconfig(); /* open netconfig file */ 134 if (nc_handle == NULL) { 135 syslog(LOG_ERR, "could not read /etc/netconfig"); 136 exit(1); 137 } 138 #ifdef PORTMAP 139 udptrans = ""; 140 tcptrans = ""; 141 #endif 142 143 nconf = getnetconfigent("local"); 144 if (nconf == NULL) { 145 syslog(LOG_ERR, "%s: can't find local transport\n", argv[0]); 146 exit(1); 147 } 148 init_transport(nconf); 149 150 while ((nconf = getnetconfig(nc_handle))) { 151 if (nconf->nc_flag & NC_VISIBLE) 152 init_transport(nconf); 153 } 154 endnetconfig(nc_handle); 155 156 /* catch the usual termination signals for graceful exit */ 157 (void) signal(SIGCHLD, reap); 158 (void) signal(SIGINT, terminate); 159 (void) signal(SIGTERM, terminate); 160 (void) signal(SIGQUIT, terminate); 161 /* ignore others that could get sent */ 162 (void) signal(SIGPIPE, SIG_IGN); 163 (void) signal(SIGHUP, SIG_IGN); 164 (void) signal(SIGUSR1, SIG_IGN); 165 (void) signal(SIGUSR2, SIG_IGN); 166 #ifdef WARMSTART 167 if (warmstart) { 168 read_warmstart(); 169 } 170 #endif 171 if (debugging) { 172 printf("rpcbind debugging enabled."); 173 if (doabort) { 174 printf(" Will abort on errors!\n"); 175 } else { 176 printf("\n"); 177 } 178 } else { 179 if (daemon(0, 0)) 180 err(1, "fork failed"); 181 } 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(1); 190 } 191 if (setuid(p->pw_uid) == -1) { 192 syslog(LOG_ERR, "setuid to daemon failed: %m"); 193 exit(1); 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 0; 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 226 if ((nconf->nc_semantics != NC_TPI_CLTS) && 227 (nconf->nc_semantics != NC_TPI_COTS) && 228 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 229 return (1); /* not my type */ 230 #ifdef ND_DEBUG 231 if (debugging) { 232 int i; 233 char **s; 234 235 (void) fprintf(stderr, "%s: %ld lookup routines :\n", 236 nconf->nc_netid, nconf->nc_nlookups); 237 for (i = 0, s = nconf->nc_lookups; i < nconf->nc_nlookups; 238 i++, s++) 239 fprintf(stderr, "[%d] - %s\n", i, *s); 240 } 241 #endif 242 243 /* 244 * XXX - using RPC library internal functions. 245 */ 246 if ((fd = __rpc_nconf2fd(nconf)) < 0) { 247 syslog(LOG_ERR, "cannot create socket for %s", nconf->nc_netid); 248 return (1); 249 } 250 251 if (!__rpc_nconf2sockinfo(nconf, &si)) { 252 syslog(LOG_ERR, "cannot get information for %s", 253 nconf->nc_netid); 254 return (1); 255 } 256 257 if (!strcmp(nconf->nc_netid, "local")) { 258 memset(&sun, 0, sizeof sun); 259 sun.sun_family = AF_LOCAL; 260 unlink(_PATH_RPCBINDSOCK); 261 strcpy(sun.sun_path, _PATH_RPCBINDSOCK); 262 sun.sun_len = SUN_LEN(&sun); 263 addrlen = sizeof (struct sockaddr_un); 264 sa = (struct sockaddr *)&sun; 265 } else { 266 /* Get rpcbind's address on this transport */ 267 268 memset(&hints, 0, sizeof hints); 269 hints.ai_flags = AI_PASSIVE; 270 hints.ai_family = si.si_af; 271 hints.ai_socktype = si.si_socktype; 272 hints.ai_protocol = si.si_proto; 273 if ((aicode = getaddrinfo(NULL, servname, &hints, &res)) != 0) { 274 syslog(LOG_ERR, "cannot get local address for %s: %s", 275 nconf->nc_netid, gai_strerror(aicode)); 276 return 1; 277 } 278 addrlen = res->ai_addrlen; 279 sa = (struct sockaddr *)res->ai_addr; 280 } 281 282 if (bind(fd, sa, addrlen) < 0) { 283 syslog(LOG_ERR, "cannot bind %s: %m", nconf->nc_netid); 284 if (res != NULL) 285 freeaddrinfo(res); 286 return 1; 287 } 288 289 /* Copy the address */ 290 taddr.addr.len = taddr.addr.maxlen = addrlen; 291 taddr.addr.buf = malloc(addrlen); 292 if (taddr.addr.buf == NULL) { 293 syslog(LOG_ERR, "cannot allocate memory for %s address", 294 nconf->nc_netid); 295 if (res != NULL) 296 freeaddrinfo(res); 297 return 1; 298 } 299 memcpy(taddr.addr.buf, sa, addrlen); 300 #ifdef ND_DEBUG 301 if (debugging) { 302 /* for debugging print out our universal address */ 303 char *uaddr; 304 struct netbuf nb; 305 306 nb.buf = sa; 307 nb.len = nb.maxlen = sa->sa_len; 308 uaddr = taddr2uaddr(nconf, &nb); 309 (void) fprintf(stderr, "rpcbind : my address is %s\n", uaddr); 310 (void) free(uaddr); 311 } 312 #endif 313 314 if (res != NULL) 315 freeaddrinfo(res); 316 317 if (nconf->nc_semantics != NC_TPI_CLTS) 318 listen(fd, SOMAXCONN); 319 320 my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr, 0, 0); 321 if (my_xprt == (SVCXPRT *)NULL) { 322 syslog(LOG_ERR, "%s: could not create service", 323 nconf->nc_netid); 324 goto error; 325 } 326 327 #ifdef PORTMAP 328 /* 329 * Register both the versions for tcp/ip, udp/ip and local. 330 */ 331 if ((strcmp(nconf->nc_protofmly, NC_INET) == 0 && 332 (strcmp(nconf->nc_proto, NC_TCP) == 0 || 333 strcmp(nconf->nc_proto, NC_UDP) == 0)) || 334 strcmp(nconf->nc_netid, "local") == 0) { 335 struct pmaplist *pml; 336 337 if (!svc_register(my_xprt, PMAPPROG, PMAPVERS, 338 pmap_service, NULL)) { 339 syslog(LOG_ERR, "could not register on %s", 340 nconf->nc_netid); 341 goto error; 342 } 343 pml = (struct pmaplist *)malloc((u_int)sizeof (struct pmaplist)); 344 if (pml == (struct pmaplist *)NULL) { 345 syslog(LOG_ERR, "no memory!"); 346 exit(1); 347 } 348 pml->pml_map.pm_prog = PMAPPROG; 349 pml->pml_map.pm_vers = PMAPVERS; 350 pml->pml_map.pm_port = PMAPPORT; 351 if (strcmp(nconf->nc_proto, NC_TCP) == 0) { 352 if (tcptrans[0]) { 353 syslog(LOG_ERR, 354 "cannot have more than one TCP transport"); 355 goto error; 356 } 357 tcptrans = strdup(nconf->nc_netid); 358 pml->pml_map.pm_prot = IPPROTO_TCP; 359 360 /* Let's snarf the universal address */ 361 /* "h1.h2.h3.h4.p1.p2" */ 362 tcp_uaddr = taddr2uaddr(nconf, &taddr.addr); 363 } else if (strcmp(nconf->nc_proto, NC_UDP) == 0) { 364 if (udptrans[0]) { 365 syslog(LOG_ERR, 366 "cannot have more than one UDP transport"); 367 goto error; 368 } 369 udptrans = strdup(nconf->nc_netid); 370 pml->pml_map.pm_prot = IPPROTO_UDP; 371 372 /* Let's snarf the universal address */ 373 /* "h1.h2.h3.h4.p1.p2" */ 374 udp_uaddr = taddr2uaddr(nconf, &taddr.addr); 375 } 376 pml->pml_next = list_pml; 377 list_pml = pml; 378 379 /* Add version 3 information */ 380 pml = (struct pmaplist *)malloc((u_int)sizeof (struct pmaplist)); 381 if (pml == (struct pmaplist *)NULL) { 382 syslog(LOG_ERR, "no memory!"); 383 exit(1); 384 } 385 pml->pml_map = list_pml->pml_map; 386 pml->pml_map.pm_vers = RPCBVERS; 387 pml->pml_next = list_pml; 388 list_pml = pml; 389 390 /* Add version 4 information */ 391 pml = (struct pmaplist *)malloc((u_int)sizeof (struct pmaplist)); 392 if (pml == (struct pmaplist *)NULL) { 393 syslog(LOG_ERR, "no memory!"); 394 exit(1); 395 } 396 pml->pml_map = list_pml->pml_map; 397 pml->pml_map.pm_vers = RPCBVERS4; 398 pml->pml_next = list_pml; 399 list_pml = pml; 400 401 /* Also add version 2 stuff to rpcbind list */ 402 rbllist_add(PMAPPROG, PMAPVERS, nconf, &taddr.addr); 403 } 404 #endif 405 406 /* version 3 registration */ 407 if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS, rpcb_service_3, NULL)) { 408 syslog(LOG_ERR, "could not register %s version 3", 409 nconf->nc_netid); 410 goto error; 411 } 412 rbllist_add(RPCBPROG, RPCBVERS, nconf, &taddr.addr); 413 414 /* version 4 registration */ 415 if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS4, rpcb_service_4, NULL)) { 416 syslog(LOG_ERR, "could not register %s version 4", 417 nconf->nc_netid); 418 goto error; 419 } 420 rbllist_add(RPCBPROG, RPCBVERS4, nconf, &taddr.addr); 421 422 /* decide if bound checking works for this transport */ 423 status = add_bndlist(nconf, &taddr.addr); 424 #ifdef BIND_DEBUG 425 if (debugging) { 426 if (status < 0) { 427 fprintf(stderr, "Error in finding bind status for %s\n", 428 nconf->nc_netid); 429 } else if (status == 0) { 430 fprintf(stderr, "check binding for %s\n", 431 nconf->nc_netid); 432 } else if (status > 0) { 433 fprintf(stderr, "No check binding for %s\n", 434 nconf->nc_netid); 435 } 436 } 437 #endif 438 /* 439 * rmtcall only supported on CLTS transports for now. 440 */ 441 if (nconf->nc_semantics == NC_TPI_CLTS) { 442 status = create_rmtcall_fd(nconf); 443 444 #ifdef BIND_DEBUG 445 if (debugging) { 446 if (status < 0) { 447 fprintf(stderr, 448 "Could not create rmtcall fd for %s\n", 449 nconf->nc_netid); 450 } else { 451 fprintf(stderr, "rmtcall fd for %s is %d\n", 452 nconf->nc_netid, status); 453 } 454 } 455 #endif 456 } 457 return (0); 458 error: 459 close(fd); 460 return (1); 461 } 462 463 static void 464 rbllist_add(rpcprog_t prog, rpcvers_t vers, struct netconfig *nconf, 465 struct netbuf *addr) 466 { 467 rpcblist_ptr rbl; 468 469 rbl = (rpcblist_ptr)malloc((u_int)sizeof (rpcblist)); 470 if (rbl == (rpcblist_ptr)NULL) { 471 syslog(LOG_ERR, "no memory!"); 472 exit(1); 473 } 474 475 rbl->rpcb_map.r_prog = prog; 476 rbl->rpcb_map.r_vers = vers; 477 rbl->rpcb_map.r_netid = strdup(nconf->nc_netid); 478 rbl->rpcb_map.r_addr = taddr2uaddr(nconf, addr); 479 rbl->rpcb_map.r_owner = strdup(superuser); 480 rbl->rpcb_next = list_rbl; /* Attach to global list */ 481 list_rbl = rbl; 482 } 483 484 /* 485 * Catch the signal and die 486 */ 487 static void 488 terminate(int dummy) 489 { 490 #ifdef WARMSTART 491 syslog(LOG_ERR, 492 "rpcbind terminating on signal. Restart with \"rpcbind -w\""); 493 write_warmstart(); /* Dump yourself */ 494 #endif 495 exit(2); 496 } 497 498 void 499 rpcbind_abort() 500 { 501 #ifdef WARMSTART 502 write_warmstart(); /* Dump yourself */ 503 #endif 504 abort(); 505 } 506 507 /* get command line options */ 508 static void 509 parseargs(int argc, char *argv[]) 510 { 511 int c; 512 513 while ((c = getopt(argc, argv, "dwailLs")) != -1) { 514 switch (c) { 515 case 'a': 516 doabort = 1; /* when debugging, do an abort on */ 517 break; /* errors; for rpcbind developers */ 518 /* only! */ 519 case 'd': 520 debugging = 1; 521 break; 522 case 'i': 523 insecure = 1; 524 break; 525 case 'L': 526 oldstyle_local = 1; 527 break; 528 case 'l': 529 verboselog = 1; 530 break; 531 case 's': 532 runasdaemon = 1; 533 break; 534 #ifdef WARMSTART 535 case 'w': 536 warmstart = 1; 537 break; 538 #endif 539 default: /* error */ 540 fprintf(stderr, "usage: rpcbind [-Idwils]\n"); 541 exit (1); 542 } 543 } 544 if (doabort && !debugging) { 545 fprintf(stderr, 546 "-a (abort) specified without -d (debugging) -- ignored.\n"); 547 doabort = 0; 548 } 549 } 550 551 void 552 reap(int dummy) 553 { 554 int save_errno = errno; 555 556 while (wait3(NULL, WNOHANG, NULL) > 0) 557 ; 558 errno = save_errno; 559 } 560 561 void 562 toggle_verboselog(int dummy) 563 { 564 verboselog = !verboselog; 565 } 566