11494289fSPeter Wemm /* 21494289fSPeter Wemm * Copyright (c) 1995 31494289fSPeter Wemm * A.R. Gordon (andrew.gordon@net-tel.co.uk). All rights reserved. 41494289fSPeter Wemm * 51494289fSPeter Wemm * Redistribution and use in source and binary forms, with or without 61494289fSPeter Wemm * modification, are permitted provided that the following conditions 71494289fSPeter Wemm * are met: 81494289fSPeter Wemm * 1. Redistributions of source code must retain the above copyright 91494289fSPeter Wemm * notice, this list of conditions and the following disclaimer. 101494289fSPeter Wemm * 2. Redistributions in binary form must reproduce the above copyright 111494289fSPeter Wemm * notice, this list of conditions and the following disclaimer in the 121494289fSPeter Wemm * documentation and/or other materials provided with the distribution. 131494289fSPeter Wemm * 3. All advertising materials mentioning features or use of this software 141494289fSPeter Wemm * must display the following acknowledgement: 151494289fSPeter Wemm * This product includes software developed for the FreeBSD project 161494289fSPeter Wemm * 4. Neither the name of the author nor the names of any co-contributors 171494289fSPeter Wemm * may be used to endorse or promote products derived from this software 181494289fSPeter Wemm * without specific prior written permission. 191494289fSPeter Wemm * 201494289fSPeter Wemm * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND 211494289fSPeter Wemm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221494289fSPeter Wemm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231494289fSPeter Wemm * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 241494289fSPeter Wemm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251494289fSPeter Wemm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261494289fSPeter Wemm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271494289fSPeter Wemm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281494289fSPeter Wemm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291494289fSPeter Wemm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301494289fSPeter Wemm * SUCH DAMAGE. 311494289fSPeter Wemm * 321494289fSPeter Wemm */ 331494289fSPeter Wemm 341494289fSPeter Wemm /* main() function for status monitor daemon. Some of the code in this */ 351494289fSPeter Wemm /* file was generated by running rpcgen /usr/include/rpcsvc/sm_inter.x */ 361494289fSPeter Wemm /* The actual program logic is in the file procs.c */ 371494289fSPeter Wemm 381c38ed81SPhilippe Charnier #include <sys/cdefs.h> 391c38ed81SPhilippe Charnier __FBSDID("$FreeBSD$"); 401c38ed81SPhilippe Charnier 41df82e9baSPhilippe Charnier #include <err.h> 426924e68eSRick Macklem #include <errno.h> 431494289fSPeter Wemm #include <stdio.h> 44df82e9baSPhilippe Charnier #include <stdlib.h> 451494289fSPeter Wemm #include <rpc/rpc.h> 46bcb53b16SMartin Blapp #include <rpc/rpc_com.h> 4796e33c21SAlfred Perlstein #include <string.h> 481494289fSPeter Wemm #include <syslog.h> 491494289fSPeter Wemm #include <sys/types.h> 503c2ff3b0SMatteo Riondato #include <sys/socket.h> 511494289fSPeter Wemm #include <sys/wait.h> 523c2ff3b0SMatteo Riondato #include <netinet/in.h> 533c2ff3b0SMatteo Riondato #include <arpa/inet.h> 543c2ff3b0SMatteo Riondato #include <netdb.h> 551494289fSPeter Wemm #include <signal.h> 561c38ed81SPhilippe Charnier #include <unistd.h> 571494289fSPeter Wemm #include "statd.h" 581494289fSPeter Wemm 596924e68eSRick Macklem #define GETPORT_MAXTRY 20 /* Max tries to get a port # */ 606924e68eSRick Macklem 611494289fSPeter Wemm int debug = 0; /* Controls syslog() calls for debug messages */ 621494289fSPeter Wemm 633c2ff3b0SMatteo Riondato char **hosts, *svcport_str = NULL; 643c2ff3b0SMatteo Riondato int nhosts = 0; 653c2ff3b0SMatteo Riondato int xcreated = 0; 666924e68eSRick Macklem static int mallocd_svcport = 0; 676924e68eSRick Macklem static int *sock_fd; 686924e68eSRick Macklem static int sock_fdcnt; 696924e68eSRick Macklem static int sock_fdpos; 701494289fSPeter Wemm 716924e68eSRick Macklem static int create_service(struct netconfig *nconf); 726924e68eSRick Macklem static void complete_service(struct netconfig *nconf, char *port_str); 736924e68eSRick Macklem static void clearout_service(void); 743c2ff3b0SMatteo Riondato static void handle_sigchld(int sig); 75*06eae2c1SEnji Cooper void out_of_mem(void) __dead2; 763c2ff3b0SMatteo Riondato 77*06eae2c1SEnji Cooper static void usage(void) __dead2; 7874e69f9eSMatteo Riondato 79df82e9baSPhilippe Charnier int 801494289fSPeter Wemm main(int argc, char **argv) 811494289fSPeter Wemm { 821494289fSPeter Wemm struct sigaction sa; 8374e69f9eSMatteo Riondato struct netconfig *nconf; 843c2ff3b0SMatteo Riondato void *nc_handle; 853c2ff3b0SMatteo Riondato in_port_t svcport; 863c2ff3b0SMatteo Riondato int ch, i, s; 873c2ff3b0SMatteo Riondato char *endptr, **hosts_bak; 883c2ff3b0SMatteo Riondato int have_v6 = 1; 89bcb53b16SMartin Blapp int maxrec = RPC_MAXDATASIZE; 906924e68eSRick Macklem int attempt_cnt, port_len, port_pos, ret; 916924e68eSRick Macklem char **port_list; 921494289fSPeter Wemm 933c2ff3b0SMatteo Riondato while ((ch = getopt(argc, argv, "dh:p:")) != -1) 941c38ed81SPhilippe Charnier switch (ch) { 951c38ed81SPhilippe Charnier case 'd': 961494289fSPeter Wemm debug = 1; 971c38ed81SPhilippe Charnier break; 983c2ff3b0SMatteo Riondato case 'h': 993c2ff3b0SMatteo Riondato ++nhosts; 1003c2ff3b0SMatteo Riondato hosts_bak = hosts; 1013c2ff3b0SMatteo Riondato hosts_bak = realloc(hosts, nhosts * sizeof(char *)); 1023c2ff3b0SMatteo Riondato if (hosts_bak == NULL) { 1033c2ff3b0SMatteo Riondato if (hosts != NULL) { 1043c2ff3b0SMatteo Riondato for (i = 0; i < nhosts; i++) 1053c2ff3b0SMatteo Riondato free(hosts[i]); 1063c2ff3b0SMatteo Riondato free(hosts); 1073c2ff3b0SMatteo Riondato out_of_mem(); 1083c2ff3b0SMatteo Riondato } 1093c2ff3b0SMatteo Riondato } 1103c2ff3b0SMatteo Riondato hosts = hosts_bak; 1113c2ff3b0SMatteo Riondato hosts[nhosts - 1] = strdup(optarg); 1123c2ff3b0SMatteo Riondato if (hosts[nhosts - 1] == NULL) { 1133c2ff3b0SMatteo Riondato for (i = 0; i < (nhosts - 1); i++) 1143c2ff3b0SMatteo Riondato free(hosts[i]); 1153c2ff3b0SMatteo Riondato free(hosts); 1163c2ff3b0SMatteo Riondato out_of_mem(); 1173c2ff3b0SMatteo Riondato } 1183c2ff3b0SMatteo Riondato break; 11974e69f9eSMatteo Riondato case 'p': 12074e69f9eSMatteo Riondato endptr = NULL; 12174e69f9eSMatteo Riondato svcport = (in_port_t)strtoul(optarg, &endptr, 10); 12274e69f9eSMatteo Riondato if (endptr == NULL || *endptr != '\0' || svcport == 0 || 12374e69f9eSMatteo Riondato svcport >= IPPORT_MAX) 12474e69f9eSMatteo Riondato usage(); 1253c2ff3b0SMatteo Riondato 1263c2ff3b0SMatteo Riondato svcport_str = strdup(optarg); 12774e69f9eSMatteo Riondato break; 1281c38ed81SPhilippe Charnier default: 1291c38ed81SPhilippe Charnier usage(); 1301494289fSPeter Wemm } 1311c38ed81SPhilippe Charnier argc -= optind; 1321c38ed81SPhilippe Charnier argv += optind; 1331494289fSPeter Wemm 134af37179bSAlfred Perlstein (void)rpcb_unset(SM_PROG, SM_VERS, NULL); 1351494289fSPeter Wemm 13674e69f9eSMatteo Riondato /* 13774e69f9eSMatteo Riondato * Check if IPv6 support is present. 13874e69f9eSMatteo Riondato */ 13974e69f9eSMatteo Riondato s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 14074e69f9eSMatteo Riondato if (s < 0) 1413c2ff3b0SMatteo Riondato have_v6 = 0; 1423c2ff3b0SMatteo Riondato else 14374e69f9eSMatteo Riondato close(s); 14474e69f9eSMatteo Riondato 145bcb53b16SMartin Blapp rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 146bcb53b16SMartin Blapp 1473c2ff3b0SMatteo Riondato /* 1483c2ff3b0SMatteo Riondato * If no hosts were specified, add a wildcard entry to bind to 1493c2ff3b0SMatteo Riondato * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the 1503c2ff3b0SMatteo Riondato * list. 1513c2ff3b0SMatteo Riondato */ 1523c2ff3b0SMatteo Riondato if (nhosts == 0) { 153c9e1c304SUlrich Spörlein hosts = malloc(sizeof(char *)); 1543c2ff3b0SMatteo Riondato if (hosts == NULL) 1553c2ff3b0SMatteo Riondato out_of_mem(); 15674e69f9eSMatteo Riondato 1573c2ff3b0SMatteo Riondato hosts[0] = "*"; 1583c2ff3b0SMatteo Riondato nhosts = 1; 15974e69f9eSMatteo Riondato } else { 1603c2ff3b0SMatteo Riondato hosts_bak = hosts; 1613c2ff3b0SMatteo Riondato if (have_v6) { 1623c2ff3b0SMatteo Riondato hosts_bak = realloc(hosts, (nhosts + 2) * 1633c2ff3b0SMatteo Riondato sizeof(char *)); 1643c2ff3b0SMatteo Riondato if (hosts_bak == NULL) { 1653c2ff3b0SMatteo Riondato for (i = 0; i < nhosts; i++) 1663c2ff3b0SMatteo Riondato free(hosts[i]); 1673c2ff3b0SMatteo Riondato free(hosts); 1683c2ff3b0SMatteo Riondato out_of_mem(); 1693c2ff3b0SMatteo Riondato } else 1703c2ff3b0SMatteo Riondato hosts = hosts_bak; 1713c2ff3b0SMatteo Riondato 1723c2ff3b0SMatteo Riondato nhosts += 2; 1733c2ff3b0SMatteo Riondato hosts[nhosts - 2] = "::1"; 1743c2ff3b0SMatteo Riondato } else { 1753c2ff3b0SMatteo Riondato hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *)); 1763c2ff3b0SMatteo Riondato if (hosts_bak == NULL) { 1773c2ff3b0SMatteo Riondato for (i = 0; i < nhosts; i++) 1783c2ff3b0SMatteo Riondato free(hosts[i]); 1793c2ff3b0SMatteo Riondato 1803c2ff3b0SMatteo Riondato free(hosts); 1813c2ff3b0SMatteo Riondato out_of_mem(); 1823c2ff3b0SMatteo Riondato } else { 1833c2ff3b0SMatteo Riondato nhosts += 1; 1843c2ff3b0SMatteo Riondato hosts = hosts_bak; 1853c2ff3b0SMatteo Riondato } 1863c2ff3b0SMatteo Riondato } 1873c2ff3b0SMatteo Riondato hosts[nhosts - 1] = "127.0.0.1"; 18874e69f9eSMatteo Riondato } 18974e69f9eSMatteo Riondato 1906924e68eSRick Macklem attempt_cnt = 1; 1916924e68eSRick Macklem sock_fdcnt = 0; 1926924e68eSRick Macklem sock_fd = NULL; 1936924e68eSRick Macklem port_list = NULL; 1946924e68eSRick Macklem port_len = 0; 1953c2ff3b0SMatteo Riondato nc_handle = setnetconfig(); 1963c2ff3b0SMatteo Riondato while ((nconf = getnetconfig(nc_handle))) { 1973c2ff3b0SMatteo Riondato /* We want to listen only on udp6, tcp6, udp, tcp transports */ 1983c2ff3b0SMatteo Riondato if (nconf->nc_flag & NC_VISIBLE) { 1993c2ff3b0SMatteo Riondato /* Skip if there's no IPv6 support */ 2003c2ff3b0SMatteo Riondato if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) { 2013c2ff3b0SMatteo Riondato /* DO NOTHING */ 2023c2ff3b0SMatteo Riondato } else { 2036924e68eSRick Macklem ret = create_service(nconf); 2046924e68eSRick Macklem if (ret == 1) 2056924e68eSRick Macklem /* Ignore this call */ 2066924e68eSRick Macklem continue; 2076924e68eSRick Macklem if (ret < 0) { 2086924e68eSRick Macklem /* 2096924e68eSRick Macklem * Failed to bind port, so close off 2106924e68eSRick Macklem * all sockets created and try again 2116924e68eSRick Macklem * if the port# was dynamically 2126924e68eSRick Macklem * assigned via bind(2). 2136924e68eSRick Macklem */ 2146924e68eSRick Macklem clearout_service(); 2156924e68eSRick Macklem if (mallocd_svcport != 0 && 2166924e68eSRick Macklem attempt_cnt < GETPORT_MAXTRY) { 2176924e68eSRick Macklem free(svcport_str); 2186924e68eSRick Macklem svcport_str = NULL; 2196924e68eSRick Macklem mallocd_svcport = 0; 2206924e68eSRick Macklem } else { 2216924e68eSRick Macklem errno = EADDRINUSE; 2226924e68eSRick Macklem syslog(LOG_ERR, 2236924e68eSRick Macklem "bindresvport_sa: %m"); 2246924e68eSRick Macklem exit(1); 22574e69f9eSMatteo Riondato } 2266924e68eSRick Macklem 2276924e68eSRick Macklem /* Start over at the first service. */ 2286924e68eSRick Macklem free(sock_fd); 2296924e68eSRick Macklem sock_fdcnt = 0; 2306924e68eSRick Macklem sock_fd = NULL; 2316924e68eSRick Macklem nc_handle = setnetconfig(); 2326924e68eSRick Macklem attempt_cnt++; 2336924e68eSRick Macklem } else if (mallocd_svcport != 0 && 2346924e68eSRick Macklem attempt_cnt == GETPORT_MAXTRY) { 2356924e68eSRick Macklem /* 2366924e68eSRick Macklem * For the last attempt, allow 2376924e68eSRick Macklem * different port #s for each nconf 2386924e68eSRick Macklem * by saving the svcport_str and 2396924e68eSRick Macklem * setting it back to NULL. 2406924e68eSRick Macklem */ 2416924e68eSRick Macklem port_list = realloc(port_list, 2426924e68eSRick Macklem (port_len + 1) * sizeof(char *)); 2436924e68eSRick Macklem if (port_list == NULL) 2446924e68eSRick Macklem out_of_mem(); 2456924e68eSRick Macklem port_list[port_len++] = svcport_str; 2466924e68eSRick Macklem svcport_str = NULL; 2476924e68eSRick Macklem mallocd_svcport = 0; 2486924e68eSRick Macklem } 2496924e68eSRick Macklem } 2506924e68eSRick Macklem } 2516924e68eSRick Macklem } 2526924e68eSRick Macklem 2536924e68eSRick Macklem /* 2546924e68eSRick Macklem * Successfully bound the ports, so call complete_service() to 2556924e68eSRick Macklem * do the rest of the setup on the service(s). 2566924e68eSRick Macklem */ 2576924e68eSRick Macklem sock_fdpos = 0; 2586924e68eSRick Macklem port_pos = 0; 2596924e68eSRick Macklem nc_handle = setnetconfig(); 2606924e68eSRick Macklem while ((nconf = getnetconfig(nc_handle))) { 2616924e68eSRick Macklem /* We want to listen only on udp6, tcp6, udp, tcp transports */ 2626924e68eSRick Macklem if (nconf->nc_flag & NC_VISIBLE) { 2636924e68eSRick Macklem /* Skip if there's no IPv6 support */ 2646924e68eSRick Macklem if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) { 2656924e68eSRick Macklem /* DO NOTHING */ 2666924e68eSRick Macklem } else if (port_list != NULL) { 2676924e68eSRick Macklem if (port_pos >= port_len) { 2686924e68eSRick Macklem syslog(LOG_ERR, "too many port#s"); 2696924e68eSRick Macklem exit(1); 2706924e68eSRick Macklem } 2716924e68eSRick Macklem complete_service(nconf, port_list[port_pos++]); 2726924e68eSRick Macklem } else 2736924e68eSRick Macklem complete_service(nconf, svcport_str); 27474e69f9eSMatteo Riondato } 27574e69f9eSMatteo Riondato } 2763c2ff3b0SMatteo Riondato endnetconfig(nc_handle); 2776924e68eSRick Macklem free(sock_fd); 2786924e68eSRick Macklem if (port_list != NULL) { 2796924e68eSRick Macklem for (port_pos = 0; port_pos < port_len; port_pos++) 2806924e68eSRick Macklem free(port_list[port_pos]); 2816924e68eSRick Macklem free(port_list); 2826924e68eSRick Macklem } 2836924e68eSRick Macklem 284f61a23adSDon Lewis init_file("/var/db/statd.status"); 2851494289fSPeter Wemm 2861494289fSPeter Wemm /* Note that it is NOT sensible to run this program from inetd - the */ 2871494289fSPeter Wemm /* protocol assumes that it will run immediately at boot time. */ 2881494289fSPeter Wemm daemon(0, 0); 2891494289fSPeter Wemm openlog("rpc.statd", 0, LOG_DAEMON); 2901494289fSPeter Wemm if (debug) syslog(LOG_INFO, "Starting - debug enabled"); 2911494289fSPeter Wemm else syslog(LOG_INFO, "Starting"); 2921494289fSPeter Wemm 2931494289fSPeter Wemm /* Install signal handler to collect exit status of child processes */ 2941494289fSPeter Wemm sa.sa_handler = handle_sigchld; 2951494289fSPeter Wemm sigemptyset(&sa.sa_mask); 2961494289fSPeter Wemm sigaddset(&sa.sa_mask, SIGCHLD); 2971494289fSPeter Wemm sa.sa_flags = SA_RESTART; 2981494289fSPeter Wemm sigaction(SIGCHLD, &sa, NULL); 2991494289fSPeter Wemm 3001494289fSPeter Wemm /* Initialisation now complete - start operating */ 3011494289fSPeter Wemm notify_hosts(); /* Forks a process (if necessary) to do the */ 3021494289fSPeter Wemm /* SM_NOTIFY calls, which may be slow. */ 3031494289fSPeter Wemm 3041494289fSPeter Wemm svc_run(); /* Should never return */ 3051494289fSPeter Wemm exit(1); 3061494289fSPeter Wemm } 3071494289fSPeter Wemm 3083c2ff3b0SMatteo Riondato /* 3093c2ff3b0SMatteo Riondato * This routine creates and binds sockets on the appropriate 3106924e68eSRick Macklem * addresses. It gets called one time for each transport. 3116924e68eSRick Macklem * It returns 0 upon success, 1 for ingore the call and -1 to indicate 3126924e68eSRick Macklem * bind failed with EADDRINUSE. 3136924e68eSRick Macklem * Any file descriptors that have been created are stored in sock_fd and 3146924e68eSRick Macklem * the total count of them is maintained in sock_fdcnt. 3153c2ff3b0SMatteo Riondato */ 3166924e68eSRick Macklem static int 3173c2ff3b0SMatteo Riondato create_service(struct netconfig *nconf) 3183c2ff3b0SMatteo Riondato { 3193c2ff3b0SMatteo Riondato struct addrinfo hints, *res = NULL; 3203c2ff3b0SMatteo Riondato struct sockaddr_in *sin; 3213c2ff3b0SMatteo Riondato struct sockaddr_in6 *sin6; 3223c2ff3b0SMatteo Riondato struct __rpc_sockinfo si; 3233c2ff3b0SMatteo Riondato int aicode; 3243c2ff3b0SMatteo Riondato int fd; 3253c2ff3b0SMatteo Riondato int nhostsbak; 3263c2ff3b0SMatteo Riondato int r; 3273c2ff3b0SMatteo Riondato u_int32_t host_addr[4]; /* IPv4 or IPv6 */ 3286924e68eSRick Macklem int mallocd_res; 3293c2ff3b0SMatteo Riondato 3303c2ff3b0SMatteo Riondato if ((nconf->nc_semantics != NC_TPI_CLTS) && 3313c2ff3b0SMatteo Riondato (nconf->nc_semantics != NC_TPI_COTS) && 3323c2ff3b0SMatteo Riondato (nconf->nc_semantics != NC_TPI_COTS_ORD)) 3336924e68eSRick Macklem return (1); /* not my type */ 3343c2ff3b0SMatteo Riondato 3353c2ff3b0SMatteo Riondato /* 3363c2ff3b0SMatteo Riondato * XXX - using RPC library internal functions. 3373c2ff3b0SMatteo Riondato */ 3383c2ff3b0SMatteo Riondato if (!__rpc_nconf2sockinfo(nconf, &si)) { 3393c2ff3b0SMatteo Riondato syslog(LOG_ERR, "cannot get information for %s", 3403c2ff3b0SMatteo Riondato nconf->nc_netid); 3416924e68eSRick Macklem return (1); 3423c2ff3b0SMatteo Riondato } 3433c2ff3b0SMatteo Riondato 3443c2ff3b0SMatteo Riondato /* Get rpc.statd's address on this transport */ 3453c2ff3b0SMatteo Riondato memset(&hints, 0, sizeof hints); 3463c2ff3b0SMatteo Riondato hints.ai_family = si.si_af; 3473c2ff3b0SMatteo Riondato hints.ai_socktype = si.si_socktype; 3483c2ff3b0SMatteo Riondato hints.ai_protocol = si.si_proto; 3493c2ff3b0SMatteo Riondato 3503c2ff3b0SMatteo Riondato /* 3513c2ff3b0SMatteo Riondato * Bind to specific IPs if asked to 3523c2ff3b0SMatteo Riondato */ 3533c2ff3b0SMatteo Riondato nhostsbak = nhosts; 3543c2ff3b0SMatteo Riondato while (nhostsbak > 0) { 3553c2ff3b0SMatteo Riondato --nhostsbak; 3566924e68eSRick Macklem sock_fd = realloc(sock_fd, (sock_fdcnt + 1) * sizeof(int)); 3576924e68eSRick Macklem if (sock_fd == NULL) 3586924e68eSRick Macklem out_of_mem(); 3596924e68eSRick Macklem sock_fd[sock_fdcnt++] = -1; /* Set invalid for now. */ 3606924e68eSRick Macklem mallocd_res = 0; 3619745de4cSRyan Stone hints.ai_flags = AI_PASSIVE; 3623c2ff3b0SMatteo Riondato 3633c2ff3b0SMatteo Riondato /* 3643c2ff3b0SMatteo Riondato * XXX - using RPC library internal functions. 3653c2ff3b0SMatteo Riondato */ 3663c2ff3b0SMatteo Riondato if ((fd = __rpc_nconf2fd(nconf)) < 0) { 3673c2ff3b0SMatteo Riondato syslog(LOG_ERR, "cannot create socket for %s", 3683c2ff3b0SMatteo Riondato nconf->nc_netid); 3693c2ff3b0SMatteo Riondato continue; 3703c2ff3b0SMatteo Riondato } 3713c2ff3b0SMatteo Riondato switch (hints.ai_family) { 3723c2ff3b0SMatteo Riondato case AF_INET: 3733c2ff3b0SMatteo Riondato if (inet_pton(AF_INET, hosts[nhostsbak], 3743c2ff3b0SMatteo Riondato host_addr) == 1) { 3756924e68eSRick Macklem hints.ai_flags |= AI_NUMERICHOST; 3763c2ff3b0SMatteo Riondato } else { 3773c2ff3b0SMatteo Riondato /* 3783c2ff3b0SMatteo Riondato * Skip if we have an AF_INET6 address. 3793c2ff3b0SMatteo Riondato */ 3803c2ff3b0SMatteo Riondato if (inet_pton(AF_INET6, hosts[nhostsbak], 3813c2ff3b0SMatteo Riondato host_addr) == 1) { 3823c2ff3b0SMatteo Riondato close(fd); 3833c2ff3b0SMatteo Riondato continue; 3843c2ff3b0SMatteo Riondato } 3853c2ff3b0SMatteo Riondato } 3863c2ff3b0SMatteo Riondato break; 3873c2ff3b0SMatteo Riondato case AF_INET6: 3883c2ff3b0SMatteo Riondato if (inet_pton(AF_INET6, hosts[nhostsbak], 3893c2ff3b0SMatteo Riondato host_addr) == 1) { 3906924e68eSRick Macklem hints.ai_flags |= AI_NUMERICHOST; 3913c2ff3b0SMatteo Riondato } else { 3923c2ff3b0SMatteo Riondato /* 3933c2ff3b0SMatteo Riondato * Skip if we have an AF_INET address. 3943c2ff3b0SMatteo Riondato */ 3953c2ff3b0SMatteo Riondato if (inet_pton(AF_INET, hosts[nhostsbak], 3963c2ff3b0SMatteo Riondato host_addr) == 1) { 3973c2ff3b0SMatteo Riondato close(fd); 3983c2ff3b0SMatteo Riondato continue; 3993c2ff3b0SMatteo Riondato } 4003c2ff3b0SMatteo Riondato } 4013c2ff3b0SMatteo Riondato break; 4023c2ff3b0SMatteo Riondato default: 4033c2ff3b0SMatteo Riondato break; 4043c2ff3b0SMatteo Riondato } 4053c2ff3b0SMatteo Riondato 4063c2ff3b0SMatteo Riondato /* 4073c2ff3b0SMatteo Riondato * If no hosts were specified, just bind to INADDR_ANY 4083c2ff3b0SMatteo Riondato */ 4093c2ff3b0SMatteo Riondato if (strcmp("*", hosts[nhostsbak]) == 0) { 4103c2ff3b0SMatteo Riondato if (svcport_str == NULL) { 4113c2ff3b0SMatteo Riondato res = malloc(sizeof(struct addrinfo)); 4123c2ff3b0SMatteo Riondato if (res == NULL) 4133c2ff3b0SMatteo Riondato out_of_mem(); 4146924e68eSRick Macklem mallocd_res = 1; 4153c2ff3b0SMatteo Riondato res->ai_flags = hints.ai_flags; 4163c2ff3b0SMatteo Riondato res->ai_family = hints.ai_family; 4173c2ff3b0SMatteo Riondato res->ai_protocol = hints.ai_protocol; 4183c2ff3b0SMatteo Riondato switch (res->ai_family) { 4193c2ff3b0SMatteo Riondato case AF_INET: 4203c2ff3b0SMatteo Riondato sin = malloc(sizeof(struct sockaddr_in)); 4213c2ff3b0SMatteo Riondato if (sin == NULL) 4223c2ff3b0SMatteo Riondato out_of_mem(); 4233c2ff3b0SMatteo Riondato sin->sin_family = AF_INET; 4243c2ff3b0SMatteo Riondato sin->sin_port = htons(0); 4253c2ff3b0SMatteo Riondato sin->sin_addr.s_addr = htonl(INADDR_ANY); 4263c2ff3b0SMatteo Riondato res->ai_addr = (struct sockaddr*) sin; 4273c2ff3b0SMatteo Riondato res->ai_addrlen = (socklen_t) 4286924e68eSRick Macklem sizeof(struct sockaddr_in); 4293c2ff3b0SMatteo Riondato break; 4303c2ff3b0SMatteo Riondato case AF_INET6: 4313c2ff3b0SMatteo Riondato sin6 = malloc(sizeof(struct sockaddr_in6)); 43296e460ecSMatteo Riondato if (sin6 == NULL) 4333c2ff3b0SMatteo Riondato out_of_mem(); 4343c2ff3b0SMatteo Riondato sin6->sin6_family = AF_INET6; 4353c2ff3b0SMatteo Riondato sin6->sin6_port = htons(0); 4363c2ff3b0SMatteo Riondato sin6->sin6_addr = in6addr_any; 4373c2ff3b0SMatteo Riondato res->ai_addr = (struct sockaddr*) sin6; 4386924e68eSRick Macklem res->ai_addrlen = (socklen_t) 4396924e68eSRick Macklem sizeof(struct sockaddr_in6); 4403c2ff3b0SMatteo Riondato break; 4413c2ff3b0SMatteo Riondato default: 4426924e68eSRick Macklem syslog(LOG_ERR, "bad addr fam %d", 4436924e68eSRick Macklem res->ai_family); 4446924e68eSRick Macklem exit(1); 4453c2ff3b0SMatteo Riondato } 4463c2ff3b0SMatteo Riondato } else { 4473c2ff3b0SMatteo Riondato if ((aicode = getaddrinfo(NULL, svcport_str, 4483c2ff3b0SMatteo Riondato &hints, &res)) != 0) { 4493c2ff3b0SMatteo Riondato syslog(LOG_ERR, 4503c2ff3b0SMatteo Riondato "cannot get local address for %s: %s", 4513c2ff3b0SMatteo Riondato nconf->nc_netid, 4523c2ff3b0SMatteo Riondato gai_strerror(aicode)); 4536924e68eSRick Macklem close(fd); 4543c2ff3b0SMatteo Riondato continue; 4553c2ff3b0SMatteo Riondato } 4563c2ff3b0SMatteo Riondato } 4573c2ff3b0SMatteo Riondato } else { 4583c2ff3b0SMatteo Riondato if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str, 4593c2ff3b0SMatteo Riondato &hints, &res)) != 0) { 4603c2ff3b0SMatteo Riondato syslog(LOG_ERR, 4613c2ff3b0SMatteo Riondato "cannot get local address for %s: %s", 4623c2ff3b0SMatteo Riondato nconf->nc_netid, gai_strerror(aicode)); 4636924e68eSRick Macklem close(fd); 4643c2ff3b0SMatteo Riondato continue; 4653c2ff3b0SMatteo Riondato } 4663c2ff3b0SMatteo Riondato } 4673c2ff3b0SMatteo Riondato 4686924e68eSRick Macklem /* Store the fd. */ 4696924e68eSRick Macklem sock_fd[sock_fdcnt - 1] = fd; 4706924e68eSRick Macklem 4716924e68eSRick Macklem /* Now, attempt the bind. */ 4723c2ff3b0SMatteo Riondato r = bindresvport_sa(fd, res->ai_addr); 4733c2ff3b0SMatteo Riondato if (r != 0) { 4746924e68eSRick Macklem if (errno == EADDRINUSE && mallocd_svcport != 0) { 4756924e68eSRick Macklem if (mallocd_res != 0) { 4766924e68eSRick Macklem free(res->ai_addr); 4776924e68eSRick Macklem free(res); 4786924e68eSRick Macklem } else 4796924e68eSRick Macklem freeaddrinfo(res); 4806924e68eSRick Macklem return (-1); 4816924e68eSRick Macklem } 4823c2ff3b0SMatteo Riondato syslog(LOG_ERR, "bindresvport_sa: %m"); 4833c2ff3b0SMatteo Riondato exit(1); 4843c2ff3b0SMatteo Riondato } 4853c2ff3b0SMatteo Riondato 4866924e68eSRick Macklem if (svcport_str == NULL) { 4876924e68eSRick Macklem svcport_str = malloc(NI_MAXSERV * sizeof(char)); 4886924e68eSRick Macklem if (svcport_str == NULL) 4896924e68eSRick Macklem out_of_mem(); 4906924e68eSRick Macklem mallocd_svcport = 1; 4916924e68eSRick Macklem 4926924e68eSRick Macklem if (getnameinfo(res->ai_addr, 4936924e68eSRick Macklem res->ai_addr->sa_len, NULL, NI_MAXHOST, 4946924e68eSRick Macklem svcport_str, NI_MAXSERV * sizeof(char), 4956924e68eSRick Macklem NI_NUMERICHOST | NI_NUMERICSERV)) 4966924e68eSRick Macklem errx(1, "Cannot get port number"); 4976924e68eSRick Macklem } 4986924e68eSRick Macklem if (mallocd_res != 0) { 4996924e68eSRick Macklem free(res->ai_addr); 5006924e68eSRick Macklem free(res); 5016924e68eSRick Macklem } else 5026924e68eSRick Macklem freeaddrinfo(res); 5036924e68eSRick Macklem res = NULL; 5046924e68eSRick Macklem } 5056924e68eSRick Macklem return (0); 5066924e68eSRick Macklem } 5076924e68eSRick Macklem 5086924e68eSRick Macklem /* 5096924e68eSRick Macklem * Called after all the create_service() calls have succeeded, to complete 5106924e68eSRick Macklem * the setup and registration. 5116924e68eSRick Macklem */ 5126924e68eSRick Macklem static void 5136924e68eSRick Macklem complete_service(struct netconfig *nconf, char *port_str) 5146924e68eSRick Macklem { 5156924e68eSRick Macklem struct addrinfo hints, *res = NULL; 5166924e68eSRick Macklem struct __rpc_sockinfo si; 5176924e68eSRick Macklem struct netbuf servaddr; 5186924e68eSRick Macklem SVCXPRT *transp = NULL; 5196924e68eSRick Macklem int aicode, fd, nhostsbak; 5206924e68eSRick Macklem int registered = 0; 5216924e68eSRick Macklem 5226924e68eSRick Macklem if ((nconf->nc_semantics != NC_TPI_CLTS) && 5236924e68eSRick Macklem (nconf->nc_semantics != NC_TPI_COTS) && 5246924e68eSRick Macklem (nconf->nc_semantics != NC_TPI_COTS_ORD)) 5256924e68eSRick Macklem return; /* not my type */ 5266924e68eSRick Macklem 5276924e68eSRick Macklem /* 5286924e68eSRick Macklem * XXX - using RPC library internal functions. 5296924e68eSRick Macklem */ 5306924e68eSRick Macklem if (!__rpc_nconf2sockinfo(nconf, &si)) { 5316924e68eSRick Macklem syslog(LOG_ERR, "cannot get information for %s", 5326924e68eSRick Macklem nconf->nc_netid); 5336924e68eSRick Macklem return; 5346924e68eSRick Macklem } 5356924e68eSRick Macklem 5366924e68eSRick Macklem nhostsbak = nhosts; 5376924e68eSRick Macklem while (nhostsbak > 0) { 5386924e68eSRick Macklem --nhostsbak; 5396924e68eSRick Macklem if (sock_fdpos >= sock_fdcnt) { 5406924e68eSRick Macklem /* Should never happen. */ 5416924e68eSRick Macklem syslog(LOG_ERR, "Ran out of socket fd's"); 5426924e68eSRick Macklem return; 5436924e68eSRick Macklem } 5446924e68eSRick Macklem fd = sock_fd[sock_fdpos++]; 5456924e68eSRick Macklem if (fd < 0) 5466924e68eSRick Macklem continue; 5476924e68eSRick Macklem 5480e7cce13SDoug Rabson if (nconf->nc_semantics != NC_TPI_CLTS) 5494760d2acSAlexander Kabaev listen(fd, SOMAXCONN); 5500e7cce13SDoug Rabson 5513c2ff3b0SMatteo Riondato transp = svc_tli_create(fd, nconf, NULL, 5523c2ff3b0SMatteo Riondato RPC_MAXDATASIZE, RPC_MAXDATASIZE); 5533c2ff3b0SMatteo Riondato 5543c2ff3b0SMatteo Riondato if (transp != (SVCXPRT *) NULL) { 5553c2ff3b0SMatteo Riondato if (!svc_register(transp, SM_PROG, SM_VERS, 5563c2ff3b0SMatteo Riondato sm_prog_1, 0)) { 5573c2ff3b0SMatteo Riondato syslog(LOG_ERR, "can't register on %s", 5583c2ff3b0SMatteo Riondato nconf->nc_netid); 5593c2ff3b0SMatteo Riondato } else { 5603c2ff3b0SMatteo Riondato if (!svc_reg(transp, SM_PROG, SM_VERS, 5613c2ff3b0SMatteo Riondato sm_prog_1, NULL)) 5623c2ff3b0SMatteo Riondato syslog(LOG_ERR, 5633c2ff3b0SMatteo Riondato "can't register %s SM_PROG service", 5643c2ff3b0SMatteo Riondato nconf->nc_netid); 5653c2ff3b0SMatteo Riondato } 5663c2ff3b0SMatteo Riondato } else 5673c2ff3b0SMatteo Riondato syslog(LOG_WARNING, "can't create %s services", 5683c2ff3b0SMatteo Riondato nconf->nc_netid); 5693c2ff3b0SMatteo Riondato 5703c2ff3b0SMatteo Riondato if (registered == 0) { 5713c2ff3b0SMatteo Riondato registered = 1; 5723c2ff3b0SMatteo Riondato memset(&hints, 0, sizeof hints); 5733c2ff3b0SMatteo Riondato hints.ai_flags = AI_PASSIVE; 5743c2ff3b0SMatteo Riondato hints.ai_family = si.si_af; 5753c2ff3b0SMatteo Riondato hints.ai_socktype = si.si_socktype; 5763c2ff3b0SMatteo Riondato hints.ai_protocol = si.si_proto; 5773c2ff3b0SMatteo Riondato 5783c2ff3b0SMatteo Riondato 5796924e68eSRick Macklem if ((aicode = getaddrinfo(NULL, port_str, &hints, 5803c2ff3b0SMatteo Riondato &res)) != 0) { 5813c2ff3b0SMatteo Riondato syslog(LOG_ERR, "cannot get local address: %s", 5823c2ff3b0SMatteo Riondato gai_strerror(aicode)); 5833c2ff3b0SMatteo Riondato exit(1); 5843c2ff3b0SMatteo Riondato } 5853c2ff3b0SMatteo Riondato 5863c2ff3b0SMatteo Riondato servaddr.buf = malloc(res->ai_addrlen); 5873c2ff3b0SMatteo Riondato memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen); 5883c2ff3b0SMatteo Riondato servaddr.len = res->ai_addrlen; 5893c2ff3b0SMatteo Riondato 5903c2ff3b0SMatteo Riondato rpcb_set(SM_PROG, SM_VERS, nconf, &servaddr); 5913c2ff3b0SMatteo Riondato 5923c2ff3b0SMatteo Riondato xcreated++; 5933c2ff3b0SMatteo Riondato freeaddrinfo(res); 5943c2ff3b0SMatteo Riondato } 5953c2ff3b0SMatteo Riondato } /* end while */ 5963c2ff3b0SMatteo Riondato } 5973c2ff3b0SMatteo Riondato 5986924e68eSRick Macklem /* 5996924e68eSRick Macklem * Clear out sockets after a failure to bind one of them, so that the 6006924e68eSRick Macklem * cycle of socket creation/binding can start anew. 6016924e68eSRick Macklem */ 6026924e68eSRick Macklem static void 6036924e68eSRick Macklem clearout_service(void) 6046924e68eSRick Macklem { 6056924e68eSRick Macklem int i; 6066924e68eSRick Macklem 6076924e68eSRick Macklem for (i = 0; i < sock_fdcnt; i++) { 6086924e68eSRick Macklem if (sock_fd[i] >= 0) { 6096924e68eSRick Macklem shutdown(sock_fd[i], SHUT_RDWR); 6106924e68eSRick Macklem close(sock_fd[i]); 6116924e68eSRick Macklem } 6126924e68eSRick Macklem } 6136924e68eSRick Macklem } 6146924e68eSRick Macklem 615df82e9baSPhilippe Charnier static void 616*06eae2c1SEnji Cooper usage(void) 617df82e9baSPhilippe Charnier { 6183c2ff3b0SMatteo Riondato fprintf(stderr, "usage: rpc.statd [-d] [-h <bindip>] [-p <port>]\n"); 619df82e9baSPhilippe Charnier exit(1); 620df82e9baSPhilippe Charnier } 6211494289fSPeter Wemm 6221494289fSPeter Wemm /* handle_sigchld ---------------------------------------------------------- */ 6231494289fSPeter Wemm /* 6241494289fSPeter Wemm Purpose: Catch SIGCHLD and collect process status 6251494289fSPeter Wemm Retruns: Nothing. 6261494289fSPeter Wemm Notes: No special action required, other than to collect the 6271494289fSPeter Wemm process status and hence allow the child to die: 6281494289fSPeter Wemm we only use child processes for asynchronous transmission 6291494289fSPeter Wemm of SM_NOTIFY to other systems, so it is normal for the 6301494289fSPeter Wemm children to exit when they have done their work. 6311494289fSPeter Wemm */ 6321494289fSPeter Wemm 633bf117edaSAlfred Perlstein static void handle_sigchld(int sig __unused) 6341494289fSPeter Wemm { 6351494289fSPeter Wemm int pid, status; 6361494289fSPeter Wemm pid = wait4(-1, &status, WNOHANG, (struct rusage*)0); 6371494289fSPeter Wemm if (!pid) syslog(LOG_ERR, "Phantom SIGCHLD??"); 6381494289fSPeter Wemm else if (status == 0) 6391494289fSPeter Wemm { 6401494289fSPeter Wemm if (debug) syslog(LOG_DEBUG, "Child %d exited OK", pid); 6411494289fSPeter Wemm } 6421494289fSPeter Wemm else syslog(LOG_ERR, "Child %d failed with status %d", pid, 6431494289fSPeter Wemm WEXITSTATUS(status)); 6441494289fSPeter Wemm } 6451494289fSPeter Wemm 6463c2ff3b0SMatteo Riondato /* 6473c2ff3b0SMatteo Riondato * Out of memory, fatal 6483c2ff3b0SMatteo Riondato */ 6493c2ff3b0SMatteo Riondato void 650*06eae2c1SEnji Cooper out_of_mem(void) 6513c2ff3b0SMatteo Riondato { 6523c2ff3b0SMatteo Riondato 6533c2ff3b0SMatteo Riondato syslog(LOG_ERR, "out of memory"); 6543c2ff3b0SMatteo Riondato exit(2); 6553c2ff3b0SMatteo Riondato } 656