1 /*- 2 * SPDX-License-Identifier: BSD-4-Clause 3 * 4 * Copyright (c) 1995 5 * A.R. Gordon (andrew.gordon@net-tel.co.uk). All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed for the FreeBSD project 18 * 4. Neither the name of the author nor the names of any co-contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 */ 35 36 /* main() function for status monitor daemon. Some of the code in this */ 37 /* file was generated by running rpcgen /usr/include/rpcsvc/sm_inter.x */ 38 /* The actual program logic is in the file procs.c */ 39 40 #include <sys/cdefs.h> 41 __FBSDID("$FreeBSD$"); 42 43 #include <err.h> 44 #include <errno.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <rpc/rpc.h> 48 #include <rpc/rpc_com.h> 49 #include <string.h> 50 #include <syslog.h> 51 #include <sys/types.h> 52 #include <sys/socket.h> 53 #include <sys/wait.h> 54 #include <netinet/in.h> 55 #include <arpa/inet.h> 56 #include <netdb.h> 57 #include <signal.h> 58 #include <unistd.h> 59 #include "statd.h" 60 61 #define GETPORT_MAXTRY 20 /* Max tries to get a port # */ 62 63 int debug = 0; /* Controls syslog() calls for debug messages */ 64 65 char **hosts, *svcport_str = NULL; 66 int nhosts = 0; 67 int xcreated = 0; 68 static int mallocd_svcport = 0; 69 static int *sock_fd; 70 static int sock_fdcnt; 71 static int sock_fdpos; 72 73 static int create_service(struct netconfig *nconf); 74 static void complete_service(struct netconfig *nconf, char *port_str); 75 static void clearout_service(void); 76 static void handle_sigchld(int sig); 77 void out_of_mem(void) __dead2; 78 79 static void usage(void) __dead2; 80 81 int 82 main(int argc, char **argv) 83 { 84 struct sigaction sa; 85 struct netconfig *nconf; 86 void *nc_handle; 87 in_port_t svcport; 88 int ch, i, s; 89 char *endptr, **hosts_bak; 90 int have_v6 = 1; 91 int maxrec = RPC_MAXDATASIZE; 92 int attempt_cnt, port_len, port_pos, ret; 93 char **port_list; 94 95 while ((ch = getopt(argc, argv, "dh:p:")) != -1) 96 switch (ch) { 97 case 'd': 98 debug = 1; 99 break; 100 case 'h': 101 ++nhosts; 102 hosts_bak = hosts; 103 hosts_bak = realloc(hosts, nhosts * sizeof(char *)); 104 if (hosts_bak == NULL) { 105 if (hosts != NULL) { 106 for (i = 0; i < nhosts; i++) 107 free(hosts[i]); 108 free(hosts); 109 out_of_mem(); 110 } 111 } 112 hosts = hosts_bak; 113 hosts[nhosts - 1] = strdup(optarg); 114 if (hosts[nhosts - 1] == NULL) { 115 for (i = 0; i < (nhosts - 1); i++) 116 free(hosts[i]); 117 free(hosts); 118 out_of_mem(); 119 } 120 break; 121 case 'p': 122 endptr = NULL; 123 svcport = (in_port_t)strtoul(optarg, &endptr, 10); 124 if (endptr == NULL || *endptr != '\0' || svcport == 0 || 125 svcport >= IPPORT_MAX) 126 usage(); 127 128 svcport_str = strdup(optarg); 129 break; 130 default: 131 usage(); 132 } 133 argc -= optind; 134 argv += optind; 135 136 (void)rpcb_unset(SM_PROG, SM_VERS, NULL); 137 138 /* 139 * Check if IPv6 support is present. 140 */ 141 s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 142 if (s < 0) 143 have_v6 = 0; 144 else 145 close(s); 146 147 rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 148 149 /* 150 * If no hosts were specified, add a wildcard entry to bind to 151 * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the 152 * list. 153 */ 154 if (nhosts == 0) { 155 hosts = malloc(sizeof(char *)); 156 if (hosts == NULL) 157 out_of_mem(); 158 159 hosts[0] = "*"; 160 nhosts = 1; 161 } else { 162 hosts_bak = hosts; 163 if (have_v6) { 164 hosts_bak = realloc(hosts, (nhosts + 2) * 165 sizeof(char *)); 166 if (hosts_bak == NULL) { 167 for (i = 0; i < nhosts; i++) 168 free(hosts[i]); 169 free(hosts); 170 out_of_mem(); 171 } else 172 hosts = hosts_bak; 173 174 nhosts += 2; 175 hosts[nhosts - 2] = "::1"; 176 } else { 177 hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *)); 178 if (hosts_bak == NULL) { 179 for (i = 0; i < nhosts; i++) 180 free(hosts[i]); 181 182 free(hosts); 183 out_of_mem(); 184 } else { 185 nhosts += 1; 186 hosts = hosts_bak; 187 } 188 } 189 hosts[nhosts - 1] = "127.0.0.1"; 190 } 191 192 attempt_cnt = 1; 193 sock_fdcnt = 0; 194 sock_fd = NULL; 195 port_list = NULL; 196 port_len = 0; 197 nc_handle = setnetconfig(); 198 while ((nconf = getnetconfig(nc_handle))) { 199 /* We want to listen only on udp6, tcp6, udp, tcp transports */ 200 if (nconf->nc_flag & NC_VISIBLE) { 201 /* Skip if there's no IPv6 support */ 202 if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) { 203 /* DO NOTHING */ 204 } else { 205 ret = create_service(nconf); 206 if (ret == 1) 207 /* Ignore this call */ 208 continue; 209 if (ret < 0) { 210 /* 211 * Failed to bind port, so close off 212 * all sockets created and try again 213 * if the port# was dynamically 214 * assigned via bind(2). 215 */ 216 clearout_service(); 217 if (mallocd_svcport != 0 && 218 attempt_cnt < GETPORT_MAXTRY) { 219 free(svcport_str); 220 svcport_str = NULL; 221 mallocd_svcport = 0; 222 } else { 223 errno = EADDRINUSE; 224 syslog(LOG_ERR, 225 "bindresvport_sa: %m"); 226 exit(1); 227 } 228 229 /* Start over at the first service. */ 230 free(sock_fd); 231 sock_fdcnt = 0; 232 sock_fd = NULL; 233 nc_handle = setnetconfig(); 234 attempt_cnt++; 235 } else if (mallocd_svcport != 0 && 236 attempt_cnt == GETPORT_MAXTRY) { 237 /* 238 * For the last attempt, allow 239 * different port #s for each nconf 240 * by saving the svcport_str and 241 * setting it back to NULL. 242 */ 243 port_list = realloc(port_list, 244 (port_len + 1) * sizeof(char *)); 245 if (port_list == NULL) 246 out_of_mem(); 247 port_list[port_len++] = svcport_str; 248 svcport_str = NULL; 249 mallocd_svcport = 0; 250 } 251 } 252 } 253 } 254 255 /* 256 * Successfully bound the ports, so call complete_service() to 257 * do the rest of the setup on the service(s). 258 */ 259 sock_fdpos = 0; 260 port_pos = 0; 261 nc_handle = setnetconfig(); 262 while ((nconf = getnetconfig(nc_handle))) { 263 /* We want to listen only on udp6, tcp6, udp, tcp transports */ 264 if (nconf->nc_flag & NC_VISIBLE) { 265 /* Skip if there's no IPv6 support */ 266 if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) { 267 /* DO NOTHING */ 268 } else if (port_list != NULL) { 269 if (port_pos >= port_len) { 270 syslog(LOG_ERR, "too many port#s"); 271 exit(1); 272 } 273 complete_service(nconf, port_list[port_pos++]); 274 } else 275 complete_service(nconf, svcport_str); 276 } 277 } 278 endnetconfig(nc_handle); 279 free(sock_fd); 280 if (port_list != NULL) { 281 for (port_pos = 0; port_pos < port_len; port_pos++) 282 free(port_list[port_pos]); 283 free(port_list); 284 } 285 286 init_file("/var/db/statd.status"); 287 288 /* Note that it is NOT sensible to run this program from inetd - the */ 289 /* protocol assumes that it will run immediately at boot time. */ 290 daemon(0, 0); 291 openlog("rpc.statd", 0, LOG_DAEMON); 292 if (debug) syslog(LOG_INFO, "Starting - debug enabled"); 293 else syslog(LOG_INFO, "Starting"); 294 295 /* Install signal handler to collect exit status of child processes */ 296 sa.sa_handler = handle_sigchld; 297 sigemptyset(&sa.sa_mask); 298 sigaddset(&sa.sa_mask, SIGCHLD); 299 sa.sa_flags = SA_RESTART; 300 sigaction(SIGCHLD, &sa, NULL); 301 302 /* Initialisation now complete - start operating */ 303 notify_hosts(); /* Forks a process (if necessary) to do the */ 304 /* SM_NOTIFY calls, which may be slow. */ 305 306 svc_run(); /* Should never return */ 307 exit(1); 308 } 309 310 /* 311 * This routine creates and binds sockets on the appropriate 312 * addresses. It gets called one time for each transport. 313 * It returns 0 upon success, 1 for ingore the call and -1 to indicate 314 * bind failed with EADDRINUSE. 315 * Any file descriptors that have been created are stored in sock_fd and 316 * the total count of them is maintained in sock_fdcnt. 317 */ 318 static int 319 create_service(struct netconfig *nconf) 320 { 321 struct addrinfo hints, *res = NULL; 322 struct sockaddr_in *sin; 323 struct sockaddr_in6 *sin6; 324 struct __rpc_sockinfo si; 325 int aicode; 326 int fd; 327 int nhostsbak; 328 int r; 329 u_int32_t host_addr[4]; /* IPv4 or IPv6 */ 330 int mallocd_res; 331 332 if ((nconf->nc_semantics != NC_TPI_CLTS) && 333 (nconf->nc_semantics != NC_TPI_COTS) && 334 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 335 return (1); /* not my type */ 336 337 /* 338 * XXX - using RPC library internal functions. 339 */ 340 if (!__rpc_nconf2sockinfo(nconf, &si)) { 341 syslog(LOG_ERR, "cannot get information for %s", 342 nconf->nc_netid); 343 return (1); 344 } 345 346 /* Get rpc.statd's address on this transport */ 347 memset(&hints, 0, sizeof hints); 348 hints.ai_family = si.si_af; 349 hints.ai_socktype = si.si_socktype; 350 hints.ai_protocol = si.si_proto; 351 352 /* 353 * Bind to specific IPs if asked to 354 */ 355 nhostsbak = nhosts; 356 while (nhostsbak > 0) { 357 --nhostsbak; 358 sock_fd = realloc(sock_fd, (sock_fdcnt + 1) * sizeof(int)); 359 if (sock_fd == NULL) 360 out_of_mem(); 361 sock_fd[sock_fdcnt++] = -1; /* Set invalid for now. */ 362 mallocd_res = 0; 363 hints.ai_flags = AI_PASSIVE; 364 365 /* 366 * XXX - using RPC library internal functions. 367 */ 368 if ((fd = __rpc_nconf2fd(nconf)) < 0) { 369 syslog(LOG_ERR, "cannot create socket for %s", 370 nconf->nc_netid); 371 continue; 372 } 373 switch (hints.ai_family) { 374 case AF_INET: 375 if (inet_pton(AF_INET, hosts[nhostsbak], 376 host_addr) == 1) { 377 hints.ai_flags |= AI_NUMERICHOST; 378 } else { 379 /* 380 * Skip if we have an AF_INET6 address. 381 */ 382 if (inet_pton(AF_INET6, hosts[nhostsbak], 383 host_addr) == 1) { 384 close(fd); 385 continue; 386 } 387 } 388 break; 389 case AF_INET6: 390 if (inet_pton(AF_INET6, hosts[nhostsbak], 391 host_addr) == 1) { 392 hints.ai_flags |= AI_NUMERICHOST; 393 } else { 394 /* 395 * Skip if we have an AF_INET address. 396 */ 397 if (inet_pton(AF_INET, hosts[nhostsbak], 398 host_addr) == 1) { 399 close(fd); 400 continue; 401 } 402 } 403 break; 404 default: 405 break; 406 } 407 408 /* 409 * If no hosts were specified, just bind to INADDR_ANY 410 */ 411 if (strcmp("*", hosts[nhostsbak]) == 0) { 412 if (svcport_str == NULL) { 413 res = malloc(sizeof(struct addrinfo)); 414 if (res == NULL) 415 out_of_mem(); 416 mallocd_res = 1; 417 res->ai_flags = hints.ai_flags; 418 res->ai_family = hints.ai_family; 419 res->ai_protocol = hints.ai_protocol; 420 switch (res->ai_family) { 421 case AF_INET: 422 sin = malloc(sizeof(struct sockaddr_in)); 423 if (sin == NULL) 424 out_of_mem(); 425 sin->sin_family = AF_INET; 426 sin->sin_port = htons(0); 427 sin->sin_addr.s_addr = htonl(INADDR_ANY); 428 res->ai_addr = (struct sockaddr*) sin; 429 res->ai_addrlen = (socklen_t) 430 sizeof(struct sockaddr_in); 431 break; 432 case AF_INET6: 433 sin6 = malloc(sizeof(struct sockaddr_in6)); 434 if (sin6 == NULL) 435 out_of_mem(); 436 sin6->sin6_family = AF_INET6; 437 sin6->sin6_port = htons(0); 438 sin6->sin6_addr = in6addr_any; 439 res->ai_addr = (struct sockaddr*) sin6; 440 res->ai_addrlen = (socklen_t) 441 sizeof(struct sockaddr_in6); 442 break; 443 default: 444 syslog(LOG_ERR, "bad addr fam %d", 445 res->ai_family); 446 exit(1); 447 } 448 } else { 449 if ((aicode = getaddrinfo(NULL, svcport_str, 450 &hints, &res)) != 0) { 451 syslog(LOG_ERR, 452 "cannot get local address for %s: %s", 453 nconf->nc_netid, 454 gai_strerror(aicode)); 455 close(fd); 456 continue; 457 } 458 } 459 } else { 460 if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str, 461 &hints, &res)) != 0) { 462 syslog(LOG_ERR, 463 "cannot get local address for %s: %s", 464 nconf->nc_netid, gai_strerror(aicode)); 465 close(fd); 466 continue; 467 } 468 } 469 470 /* Store the fd. */ 471 sock_fd[sock_fdcnt - 1] = fd; 472 473 /* Now, attempt the bind. */ 474 r = bindresvport_sa(fd, res->ai_addr); 475 if (r != 0) { 476 if (errno == EADDRINUSE && mallocd_svcport != 0) { 477 if (mallocd_res != 0) { 478 free(res->ai_addr); 479 free(res); 480 } else 481 freeaddrinfo(res); 482 return (-1); 483 } 484 syslog(LOG_ERR, "bindresvport_sa: %m"); 485 exit(1); 486 } 487 488 if (svcport_str == NULL) { 489 svcport_str = malloc(NI_MAXSERV * sizeof(char)); 490 if (svcport_str == NULL) 491 out_of_mem(); 492 mallocd_svcport = 1; 493 494 if (getnameinfo(res->ai_addr, 495 res->ai_addr->sa_len, NULL, NI_MAXHOST, 496 svcport_str, NI_MAXSERV * sizeof(char), 497 NI_NUMERICHOST | NI_NUMERICSERV)) 498 errx(1, "Cannot get port number"); 499 } 500 if (mallocd_res != 0) { 501 free(res->ai_addr); 502 free(res); 503 } else 504 freeaddrinfo(res); 505 res = NULL; 506 } 507 return (0); 508 } 509 510 /* 511 * Called after all the create_service() calls have succeeded, to complete 512 * the setup and registration. 513 */ 514 static void 515 complete_service(struct netconfig *nconf, char *port_str) 516 { 517 struct addrinfo hints, *res = NULL; 518 struct __rpc_sockinfo si; 519 struct netbuf servaddr; 520 SVCXPRT *transp = NULL; 521 int aicode, fd, nhostsbak; 522 int registered = 0; 523 524 if ((nconf->nc_semantics != NC_TPI_CLTS) && 525 (nconf->nc_semantics != NC_TPI_COTS) && 526 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 527 return; /* not my type */ 528 529 /* 530 * XXX - using RPC library internal functions. 531 */ 532 if (!__rpc_nconf2sockinfo(nconf, &si)) { 533 syslog(LOG_ERR, "cannot get information for %s", 534 nconf->nc_netid); 535 return; 536 } 537 538 nhostsbak = nhosts; 539 while (nhostsbak > 0) { 540 --nhostsbak; 541 if (sock_fdpos >= sock_fdcnt) { 542 /* Should never happen. */ 543 syslog(LOG_ERR, "Ran out of socket fd's"); 544 return; 545 } 546 fd = sock_fd[sock_fdpos++]; 547 if (fd < 0) 548 continue; 549 550 if (nconf->nc_semantics != NC_TPI_CLTS) 551 listen(fd, SOMAXCONN); 552 553 transp = svc_tli_create(fd, nconf, NULL, 554 RPC_MAXDATASIZE, RPC_MAXDATASIZE); 555 556 if (transp != (SVCXPRT *) NULL) { 557 if (!svc_register(transp, SM_PROG, SM_VERS, 558 sm_prog_1, 0)) { 559 syslog(LOG_ERR, "can't register on %s", 560 nconf->nc_netid); 561 } else { 562 if (!svc_reg(transp, SM_PROG, SM_VERS, 563 sm_prog_1, NULL)) 564 syslog(LOG_ERR, 565 "can't register %s SM_PROG service", 566 nconf->nc_netid); 567 } 568 } else 569 syslog(LOG_WARNING, "can't create %s services", 570 nconf->nc_netid); 571 572 if (registered == 0) { 573 registered = 1; 574 memset(&hints, 0, sizeof hints); 575 hints.ai_flags = AI_PASSIVE; 576 hints.ai_family = si.si_af; 577 hints.ai_socktype = si.si_socktype; 578 hints.ai_protocol = si.si_proto; 579 580 581 if ((aicode = getaddrinfo(NULL, port_str, &hints, 582 &res)) != 0) { 583 syslog(LOG_ERR, "cannot get local address: %s", 584 gai_strerror(aicode)); 585 exit(1); 586 } 587 588 servaddr.buf = malloc(res->ai_addrlen); 589 memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen); 590 servaddr.len = res->ai_addrlen; 591 592 rpcb_set(SM_PROG, SM_VERS, nconf, &servaddr); 593 594 xcreated++; 595 freeaddrinfo(res); 596 } 597 } /* end while */ 598 } 599 600 /* 601 * Clear out sockets after a failure to bind one of them, so that the 602 * cycle of socket creation/binding can start anew. 603 */ 604 static void 605 clearout_service(void) 606 { 607 int i; 608 609 for (i = 0; i < sock_fdcnt; i++) { 610 if (sock_fd[i] >= 0) { 611 shutdown(sock_fd[i], SHUT_RDWR); 612 close(sock_fd[i]); 613 } 614 } 615 } 616 617 static void 618 usage(void) 619 { 620 fprintf(stderr, "usage: rpc.statd [-d] [-h <bindip>] [-p <port>]\n"); 621 exit(1); 622 } 623 624 /* handle_sigchld ---------------------------------------------------------- */ 625 /* 626 Purpose: Catch SIGCHLD and collect process status 627 Retruns: Nothing. 628 Notes: No special action required, other than to collect the 629 process status and hence allow the child to die: 630 we only use child processes for asynchronous transmission 631 of SM_NOTIFY to other systems, so it is normal for the 632 children to exit when they have done their work. 633 */ 634 635 static void handle_sigchld(int sig __unused) 636 { 637 int pid, status; 638 pid = wait4(-1, &status, WNOHANG, (struct rusage*)0); 639 if (!pid) syslog(LOG_ERR, "Phantom SIGCHLD??"); 640 else if (status == 0) 641 { 642 if (debug) syslog(LOG_DEBUG, "Child %d exited OK", pid); 643 } 644 else syslog(LOG_ERR, "Child %d failed with status %d", pid, 645 WEXITSTATUS(status)); 646 } 647 648 /* 649 * Out of memory, fatal 650 */ 651 void 652 out_of_mem(void) 653 { 654 655 syslog(LOG_ERR, "out of memory"); 656 exit(2); 657 } 658