1 /* $NetBSD: rpcbind.c,v 1.1 2000/06/02 23:15:42 fvdl Exp $ */ 2 /* $FreeBSD$ */ 3 4 /* 5 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 6 * unrestricted use provided that this legend is included on all tape 7 * media and as a part of the software program in whole or part. Users 8 * may copy or modify Sun RPC without charge, but are not authorized 9 * to license or distribute it to anyone else except as part of a product or 10 * program developed by the user. 11 * 12 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 13 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 14 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 15 * 16 * Sun RPC is provided with no support and without any obligation on the 17 * part of Sun Microsystems, Inc. to assist in its use, correction, 18 * modification or enhancement. 19 * 20 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 21 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 22 * OR ANY PART THEREOF. 23 * 24 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 25 * or profits or other special, indirect and consequential damages, even if 26 * Sun has been advised of the possibility of such damages. 27 * 28 * Sun Microsystems, Inc. 29 * 2550 Garcia Avenue 30 * Mountain View, California 94043 31 */ 32 /* 33 * Copyright (c) 1984 - 1991 by Sun Microsystems, Inc. 34 */ 35 36 /* #ident "@(#)rpcbind.c 1.19 94/04/25 SMI" */ 37 38 #if 0 39 #ifndef lint 40 static char sccsid[] = "@(#)rpcbind.c 1.35 89/04/21 Copyr 1984 Sun Micro"; 41 #endif 42 #endif 43 44 /* 45 * rpcbind.c 46 * Implements the program, version to address mapping for rpc. 47 * 48 */ 49 50 #include <sys/types.h> 51 #include <sys/stat.h> 52 #include <sys/errno.h> 53 #include <sys/time.h> 54 #include <sys/resource.h> 55 #include <sys/wait.h> 56 #include <sys/signal.h> 57 #include <sys/socket.h> 58 #include <sys/un.h> 59 #include <rpc/rpc.h> 60 #ifdef PORTMAP 61 #include <netinet/in.h> 62 #endif 63 #include <netdb.h> 64 #include <stdio.h> 65 #include <netconfig.h> 66 #include <stdlib.h> 67 #include <unistd.h> 68 #include <syslog.h> 69 #include <err.h> 70 #include <libutil.h> 71 #include <pwd.h> 72 #include <string.h> 73 #include <errno.h> 74 #include "rpcbind.h" 75 76 /* Global variables */ 77 int debugging = 0; /* Tell me what's going on */ 78 int doabort = 0; /* When debugging, do an abort on errors */ 79 rpcblist_ptr list_rbl; /* A list of version 3/4 rpcbind services */ 80 81 /* who to suid to if -s is given */ 82 #define RUN_AS "daemon" 83 84 int runasdaemon = 0; 85 int insecure = 0; 86 int oldstyle_local = 0; 87 int verboselog = 0; 88 89 #ifdef WARMSTART 90 /* Local Variable */ 91 static int warmstart = 0; /* Grab a old copy of registrations */ 92 #endif 93 94 #ifdef PORTMAP 95 struct pmaplist *list_pml; /* A list of version 2 rpcbind services */ 96 char *udptrans; /* Name of UDP transport */ 97 char *tcptrans; /* Name of TCP transport */ 98 char *udp_uaddr; /* Universal UDP address */ 99 char *tcp_uaddr; /* Universal TCP address */ 100 #endif 101 static char servname[] = "rpcbind"; 102 static char superuser[] = "superuser"; 103 104 int main __P((int, char *[])); 105 106 static int init_transport __P((struct netconfig *)); 107 static void rbllist_add __P((rpcprog_t, rpcvers_t, struct netconfig *, 108 struct netbuf *)); 109 static void terminate __P((int)); 110 static void parseargs __P((int, char *[])); 111 112 int 113 main(int argc, char *argv[]) 114 { 115 struct netconfig *nconf; 116 void *nc_handle; /* Net config handle */ 117 struct rlimit rl; 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", LOG_CONS, 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("unix"); 145 if (nconf == NULL) { 146 syslog(LOG_ERR, "%s: can't find local transport\n", argv[0]); 147 exit(1); 148 } 149 init_transport(nconf); 150 151 while ((nconf = getnetconfig(nc_handle))) { 152 if (nconf->nc_flag & NC_VISIBLE) 153 init_transport(nconf); 154 } 155 endnetconfig(nc_handle); 156 157 /* catch the usual termination signals for graceful exit */ 158 (void) signal(SIGCHLD, reap); 159 (void) signal(SIGINT, terminate); 160 (void) signal(SIGTERM, terminate); 161 (void) signal(SIGQUIT, terminate); 162 /* ignore others that could get sent */ 163 (void) signal(SIGPIPE, SIG_IGN); 164 (void) signal(SIGHUP, SIG_IGN); 165 (void) signal(SIGUSR1, SIG_IGN); 166 (void) signal(SIGUSR2, SIG_IGN); 167 #ifdef WARMSTART 168 if (warmstart) { 169 read_warmstart(); 170 } 171 #endif 172 if (debugging) { 173 printf("rpcbind debugging enabled."); 174 if (doabort) { 175 printf(" Will abort on errors!\n"); 176 } else { 177 printf("\n"); 178 } 179 } else { 180 if (daemon(0, 0)) 181 err(1, "fork failed"); 182 } 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 mode_t oldmask; 226 227 if ((nconf->nc_semantics != NC_TPI_CLTS) && 228 (nconf->nc_semantics != NC_TPI_COTS) && 229 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 230 return (1); /* not my type */ 231 #ifdef ND_DEBUG 232 if (debugging) { 233 int i; 234 char **s; 235 236 (void) fprintf(stderr, "%s: %ld lookup routines :\n", 237 nconf->nc_netid, nconf->nc_nlookups); 238 for (i = 0, s = nconf->nc_lookups; i < nconf->nc_nlookups; 239 i++, s++) 240 fprintf(stderr, "[%d] - %s\n", i, *s); 241 } 242 #endif 243 244 /* 245 * XXX - using RPC library internal functions. 246 */ 247 if ((fd = __rpc_nconf2fd(nconf)) < 0) { 248 syslog(LOG_ERR, "cannot create socket for %s", nconf->nc_netid); 249 return (1); 250 } 251 252 if (!__rpc_nconf2sockinfo(nconf, &si)) { 253 syslog(LOG_ERR, "cannot get information for %s", 254 nconf->nc_netid); 255 return (1); 256 } 257 258 if (!strcmp(nconf->nc_netid, "unix")) { 259 memset(&sun, 0, sizeof sun); 260 sun.sun_family = AF_LOCAL; 261 unlink(_PATH_RPCBINDSOCK); 262 strcpy(sun.sun_path, _PATH_RPCBINDSOCK); 263 sun.sun_len = SUN_LEN(&sun); 264 addrlen = sizeof (struct sockaddr_un); 265 sa = (struct sockaddr *)&sun; 266 } else { 267 /* Get rpcbind's address on this transport */ 268 269 memset(&hints, 0, sizeof hints); 270 hints.ai_flags = AI_PASSIVE; 271 hints.ai_family = si.si_af; 272 hints.ai_socktype = si.si_socktype; 273 hints.ai_protocol = si.si_proto; 274 if ((aicode = getaddrinfo(NULL, servname, &hints, &res)) != 0) { 275 syslog(LOG_ERR, "cannot get local address for %s: %s", 276 nconf->nc_netid, gai_strerror(aicode)); 277 return 1; 278 } 279 addrlen = res->ai_addrlen; 280 sa = (struct sockaddr *)res->ai_addr; 281 } 282 oldmask = umask(S_IXUSR|S_IXGRP|S_IXOTH); 283 if (bind(fd, sa, addrlen) < 0) { 284 syslog(LOG_ERR, "cannot bind %s: %m", nconf->nc_netid); 285 if (res != NULL) 286 freeaddrinfo(res); 287 return 1; 288 } 289 (void) umask(oldmask); 290 291 /* Copy the address */ 292 taddr.addr.len = taddr.addr.maxlen = addrlen; 293 taddr.addr.buf = malloc(addrlen); 294 if (taddr.addr.buf == NULL) { 295 syslog(LOG_ERR, "cannot allocate memory for %s address", 296 nconf->nc_netid); 297 if (res != NULL) 298 freeaddrinfo(res); 299 return 1; 300 } 301 memcpy(taddr.addr.buf, sa, addrlen); 302 #ifdef ND_DEBUG 303 if (debugging) { 304 /* for debugging print out our universal address */ 305 char *uaddr; 306 struct netbuf nb; 307 308 nb.buf = sa; 309 nb.len = nb.maxlen = sa->sa_len; 310 uaddr = taddr2uaddr(nconf, &nb); 311 (void) fprintf(stderr, "rpcbind : my address is %s\n", uaddr); 312 (void) free(uaddr); 313 } 314 #endif 315 316 if (res != NULL) 317 freeaddrinfo(res); 318 319 if (nconf->nc_semantics != NC_TPI_CLTS) 320 listen(fd, SOMAXCONN); 321 322 my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr, 0, 0); 323 if (my_xprt == (SVCXPRT *)NULL) { 324 syslog(LOG_ERR, "%s: could not create service", 325 nconf->nc_netid); 326 goto error; 327 } 328 329 #ifdef PORTMAP 330 /* 331 * Register both the versions for tcp/ip, udp/ip and local. 332 */ 333 if ((strcmp(nconf->nc_protofmly, NC_INET) == 0 && 334 (strcmp(nconf->nc_proto, NC_TCP) == 0 || 335 strcmp(nconf->nc_proto, NC_UDP) == 0)) || 336 strcmp(nconf->nc_netid, "unix") == 0) { 337 struct pmaplist *pml; 338 339 if (!svc_register(my_xprt, PMAPPROG, PMAPVERS, 340 pmap_service, NULL)) { 341 syslog(LOG_ERR, "could not register on %s", 342 nconf->nc_netid); 343 goto error; 344 } 345 pml = (struct pmaplist *)malloc((u_int)sizeof (struct pmaplist)); 346 if (pml == (struct pmaplist *)NULL) { 347 syslog(LOG_ERR, "no memory!"); 348 exit(1); 349 } 350 pml->pml_map.pm_prog = PMAPPROG; 351 pml->pml_map.pm_vers = PMAPVERS; 352 pml->pml_map.pm_port = PMAPPORT; 353 if (strcmp(nconf->nc_proto, NC_TCP) == 0) { 354 if (tcptrans[0]) { 355 syslog(LOG_ERR, 356 "cannot have more than one TCP transport"); 357 goto error; 358 } 359 tcptrans = strdup(nconf->nc_netid); 360 pml->pml_map.pm_prot = IPPROTO_TCP; 361 362 /* Let's snarf the universal address */ 363 /* "h1.h2.h3.h4.p1.p2" */ 364 tcp_uaddr = taddr2uaddr(nconf, &taddr.addr); 365 } else if (strcmp(nconf->nc_proto, NC_UDP) == 0) { 366 if (udptrans[0]) { 367 syslog(LOG_ERR, 368 "cannot have more than one UDP transport"); 369 goto error; 370 } 371 udptrans = strdup(nconf->nc_netid); 372 pml->pml_map.pm_prot = IPPROTO_UDP; 373 374 /* Let's snarf the universal address */ 375 /* "h1.h2.h3.h4.p1.p2" */ 376 udp_uaddr = taddr2uaddr(nconf, &taddr.addr); 377 } else if (strcmp(nconf->nc_netid, "unix") == 0) 378 pml->pml_map.pm_prot = IPPROTO_ST; 379 pml->pml_next = list_pml; 380 list_pml = pml; 381 382 /* Add version 3 information */ 383 pml = (struct pmaplist *)malloc((u_int)sizeof (struct pmaplist)); 384 if (pml == (struct pmaplist *)NULL) { 385 syslog(LOG_ERR, "no memory!"); 386 exit(1); 387 } 388 pml->pml_map = list_pml->pml_map; 389 pml->pml_map.pm_vers = RPCBVERS; 390 pml->pml_next = list_pml; 391 list_pml = pml; 392 393 /* Add version 4 information */ 394 pml = (struct pmaplist *)malloc((u_int)sizeof (struct pmaplist)); 395 if (pml == (struct pmaplist *)NULL) { 396 syslog(LOG_ERR, "no memory!"); 397 exit(1); 398 } 399 pml->pml_map = list_pml->pml_map; 400 pml->pml_map.pm_vers = RPCBVERS4; 401 pml->pml_next = list_pml; 402 list_pml = pml; 403 404 /* Also add version 2 stuff to rpcbind list */ 405 rbllist_add(PMAPPROG, PMAPVERS, nconf, &taddr.addr); 406 } 407 #endif 408 409 /* version 3 registration */ 410 if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS, rpcb_service_3, NULL)) { 411 syslog(LOG_ERR, "could not register %s version 3", 412 nconf->nc_netid); 413 goto error; 414 } 415 rbllist_add(RPCBPROG, RPCBVERS, nconf, &taddr.addr); 416 417 /* version 4 registration */ 418 if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS4, rpcb_service_4, NULL)) { 419 syslog(LOG_ERR, "could not register %s version 4", 420 nconf->nc_netid); 421 goto error; 422 } 423 rbllist_add(RPCBPROG, RPCBVERS4, nconf, &taddr.addr); 424 425 /* decide if bound checking works for this transport */ 426 status = add_bndlist(nconf, &taddr.addr); 427 #ifdef BIND_DEBUG 428 if (debugging) { 429 if (status < 0) { 430 fprintf(stderr, "Error in finding bind status for %s\n", 431 nconf->nc_netid); 432 } else if (status == 0) { 433 fprintf(stderr, "check binding for %s\n", 434 nconf->nc_netid); 435 } else if (status > 0) { 436 fprintf(stderr, "No check binding for %s\n", 437 nconf->nc_netid); 438 } 439 } 440 #endif 441 /* 442 * rmtcall only supported on CLTS transports for now. 443 */ 444 if (nconf->nc_semantics == NC_TPI_CLTS) { 445 status = create_rmtcall_fd(nconf); 446 447 #ifdef BIND_DEBUG 448 if (debugging) { 449 if (status < 0) { 450 fprintf(stderr, 451 "Could not create rmtcall fd for %s\n", 452 nconf->nc_netid); 453 } else { 454 fprintf(stderr, "rmtcall fd for %s is %d\n", 455 nconf->nc_netid, status); 456 } 457 } 458 #endif 459 } 460 return (0); 461 error: 462 close(fd); 463 return (1); 464 } 465 466 static void 467 rbllist_add(rpcprog_t prog, rpcvers_t vers, struct netconfig *nconf, 468 struct netbuf *addr) 469 { 470 rpcblist_ptr rbl; 471 472 rbl = (rpcblist_ptr)malloc((u_int)sizeof (rpcblist)); 473 if (rbl == (rpcblist_ptr)NULL) { 474 syslog(LOG_ERR, "no memory!"); 475 exit(1); 476 } 477 478 rbl->rpcb_map.r_prog = prog; 479 rbl->rpcb_map.r_vers = vers; 480 rbl->rpcb_map.r_netid = strdup(nconf->nc_netid); 481 rbl->rpcb_map.r_addr = taddr2uaddr(nconf, addr); 482 rbl->rpcb_map.r_owner = strdup(superuser); 483 rbl->rpcb_next = list_rbl; /* Attach to global list */ 484 list_rbl = rbl; 485 } 486 487 /* 488 * Catch the signal and die 489 */ 490 static void 491 terminate(int dummy) 492 { 493 #ifdef WARMSTART 494 syslog(LOG_ERR, 495 "rpcbind terminating on signal. Restart with \"rpcbind -w\""); 496 write_warmstart(); /* Dump yourself */ 497 #endif 498 exit(2); 499 } 500 501 void 502 rpcbind_abort() 503 { 504 #ifdef WARMSTART 505 write_warmstart(); /* Dump yourself */ 506 #endif 507 abort(); 508 } 509 510 /* get command line options */ 511 static void 512 parseargs(int argc, char *argv[]) 513 { 514 int c; 515 516 while ((c = getopt(argc, argv, "dwailLs")) != -1) { 517 switch (c) { 518 case 'a': 519 doabort = 1; /* when debugging, do an abort on */ 520 break; /* errors; for rpcbind developers */ 521 /* only! */ 522 case 'd': 523 debugging = 1; 524 break; 525 case 'i': 526 insecure = 1; 527 break; 528 case 'L': 529 oldstyle_local = 1; 530 break; 531 case 'l': 532 verboselog = 1; 533 break; 534 case 's': 535 runasdaemon = 1; 536 break; 537 #ifdef WARMSTART 538 case 'w': 539 warmstart = 1; 540 break; 541 #endif 542 default: /* error */ 543 fprintf(stderr, "usage: rpcbind [-Idwils]\n"); 544 exit (1); 545 } 546 } 547 if (doabort && !debugging) { 548 fprintf(stderr, 549 "-a (abort) specified without -d (debugging) -- ignored.\n"); 550 doabort = 0; 551 } 552 } 553 554 void 555 reap(int dummy) 556 { 557 int save_errno = errno; 558 559 while (wait3(NULL, WNOHANG, NULL) > 0) 560 ; 561 errno = save_errno; 562 } 563 564 void 565 toggle_verboselog(int dummy) 566 { 567 verboselog = !verboselog; 568 } 569