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