1df57947fSPedro F. Giffuni /*-
2df57947fSPedro F. Giffuni * SPDX-License-Identifier: BSD-4-Clause
3df57947fSPedro F. Giffuni *
41494289fSPeter Wemm * Copyright (c) 1995
51494289fSPeter Wemm * A.R. Gordon (andrew.gordon@net-tel.co.uk). All rights reserved.
61494289fSPeter Wemm *
71494289fSPeter Wemm * Redistribution and use in source and binary forms, with or without
81494289fSPeter Wemm * modification, are permitted provided that the following conditions
91494289fSPeter Wemm * are met:
101494289fSPeter Wemm * 1. Redistributions of source code must retain the above copyright
111494289fSPeter Wemm * notice, this list of conditions and the following disclaimer.
121494289fSPeter Wemm * 2. Redistributions in binary form must reproduce the above copyright
131494289fSPeter Wemm * notice, this list of conditions and the following disclaimer in the
141494289fSPeter Wemm * documentation and/or other materials provided with the distribution.
151494289fSPeter Wemm * 3. All advertising materials mentioning features or use of this software
161494289fSPeter Wemm * must display the following acknowledgement:
171494289fSPeter Wemm * This product includes software developed for the FreeBSD project
181494289fSPeter Wemm * 4. Neither the name of the author nor the names of any co-contributors
191494289fSPeter Wemm * may be used to endorse or promote products derived from this software
201494289fSPeter Wemm * without specific prior written permission.
211494289fSPeter Wemm *
221494289fSPeter Wemm * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND
231494289fSPeter Wemm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
241494289fSPeter Wemm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
251494289fSPeter Wemm * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
261494289fSPeter Wemm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
271494289fSPeter Wemm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
281494289fSPeter Wemm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
291494289fSPeter Wemm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
301494289fSPeter Wemm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
311494289fSPeter Wemm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
321494289fSPeter Wemm * SUCH DAMAGE.
331494289fSPeter Wemm *
341494289fSPeter Wemm */
351494289fSPeter Wemm
361494289fSPeter Wemm /* main() function for status monitor daemon. Some of the code in this */
371494289fSPeter Wemm /* file was generated by running rpcgen /usr/include/rpcsvc/sm_inter.x */
381494289fSPeter Wemm /* The actual program logic is in the file procs.c */
391494289fSPeter Wemm
401c38ed81SPhilippe Charnier #include <sys/cdefs.h>
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
63aec74e0cSHiroki Sato static char **hosts, *svcport_str = NULL;
64aec74e0cSHiroki Sato static int nhosts = 0;
65aec74e0cSHiroki Sato static 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);
7506eae2c1SEnji Cooper void out_of_mem(void) __dead2;
763c2ff3b0SMatteo Riondato
7706eae2c1SEnji Cooper static void usage(void) __dead2;
7874e69f9eSMatteo Riondato
79df82e9baSPhilippe Charnier int
main(int argc,char ** argv)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;
87aec74e0cSHiroki Sato char *endptr;
88aec74e0cSHiroki Sato char **hosts_bak;
893c2ff3b0SMatteo Riondato int have_v6 = 1;
9090e43b44SRavi Pokala int foreground = 0;
91bcb53b16SMartin Blapp int maxrec = RPC_MAXDATASIZE;
926924e68eSRick Macklem int attempt_cnt, port_len, port_pos, ret;
936924e68eSRick Macklem char **port_list;
941494289fSPeter Wemm
9590e43b44SRavi Pokala while ((ch = getopt(argc, argv, "dFh:p:")) != -1)
961c38ed81SPhilippe Charnier switch (ch) {
971c38ed81SPhilippe Charnier case 'd':
981494289fSPeter Wemm debug = 1;
991c38ed81SPhilippe Charnier break;
10090e43b44SRavi Pokala case 'F':
10190e43b44SRavi Pokala foreground = 1;
10290e43b44SRavi Pokala break;
1033c2ff3b0SMatteo Riondato case 'h':
1043c2ff3b0SMatteo Riondato ++nhosts;
1053c2ff3b0SMatteo Riondato hosts_bak = hosts;
1063c2ff3b0SMatteo Riondato hosts_bak = realloc(hosts, nhosts * sizeof(char *));
1073c2ff3b0SMatteo Riondato if (hosts_bak == NULL) {
1083c2ff3b0SMatteo Riondato if (hosts != NULL) {
1093c2ff3b0SMatteo Riondato for (i = 0; i < nhosts; i++)
1103c2ff3b0SMatteo Riondato free(hosts[i]);
1113c2ff3b0SMatteo Riondato free(hosts);
1123c2ff3b0SMatteo Riondato out_of_mem();
1133c2ff3b0SMatteo Riondato }
1143c2ff3b0SMatteo Riondato }
1153c2ff3b0SMatteo Riondato hosts = hosts_bak;
1163c2ff3b0SMatteo Riondato hosts[nhosts - 1] = strdup(optarg);
1173c2ff3b0SMatteo Riondato if (hosts[nhosts - 1] == NULL) {
1183c2ff3b0SMatteo Riondato for (i = 0; i < (nhosts - 1); i++)
1193c2ff3b0SMatteo Riondato free(hosts[i]);
1203c2ff3b0SMatteo Riondato free(hosts);
1213c2ff3b0SMatteo Riondato out_of_mem();
1223c2ff3b0SMatteo Riondato }
1233c2ff3b0SMatteo Riondato break;
12474e69f9eSMatteo Riondato case 'p':
12574e69f9eSMatteo Riondato endptr = NULL;
12674e69f9eSMatteo Riondato svcport = (in_port_t)strtoul(optarg, &endptr, 10);
12774e69f9eSMatteo Riondato if (endptr == NULL || *endptr != '\0' || svcport == 0 ||
12874e69f9eSMatteo Riondato svcport >= IPPORT_MAX)
12974e69f9eSMatteo Riondato usage();
1303c2ff3b0SMatteo Riondato
1313c2ff3b0SMatteo Riondato svcport_str = strdup(optarg);
13274e69f9eSMatteo Riondato break;
1331c38ed81SPhilippe Charnier default:
1341c38ed81SPhilippe Charnier usage();
1351494289fSPeter Wemm }
1361c38ed81SPhilippe Charnier argc -= optind;
1371c38ed81SPhilippe Charnier argv += optind;
1381494289fSPeter Wemm
139af37179bSAlfred Perlstein (void)rpcb_unset(SM_PROG, SM_VERS, NULL);
1401494289fSPeter Wemm
14174e69f9eSMatteo Riondato /*
14274e69f9eSMatteo Riondato * Check if IPv6 support is present.
14374e69f9eSMatteo Riondato */
14474e69f9eSMatteo Riondato s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
14574e69f9eSMatteo Riondato if (s < 0)
1463c2ff3b0SMatteo Riondato have_v6 = 0;
1473c2ff3b0SMatteo Riondato else
14874e69f9eSMatteo Riondato close(s);
14974e69f9eSMatteo Riondato
150bcb53b16SMartin Blapp rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);
151bcb53b16SMartin Blapp
1523c2ff3b0SMatteo Riondato /*
1533c2ff3b0SMatteo Riondato * If no hosts were specified, add a wildcard entry to bind to
1543c2ff3b0SMatteo Riondato * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the
1553c2ff3b0SMatteo Riondato * list.
1563c2ff3b0SMatteo Riondato */
1573c2ff3b0SMatteo Riondato if (nhosts == 0) {
158c9e1c304SUlrich Spörlein hosts = malloc(sizeof(char *));
1593c2ff3b0SMatteo Riondato if (hosts == NULL)
1603c2ff3b0SMatteo Riondato out_of_mem();
16174e69f9eSMatteo Riondato
162aec74e0cSHiroki Sato hosts[0] = strdup("*");
1633c2ff3b0SMatteo Riondato nhosts = 1;
16474e69f9eSMatteo Riondato } else {
1653c2ff3b0SMatteo Riondato hosts_bak = hosts;
1663c2ff3b0SMatteo Riondato if (have_v6) {
1673c2ff3b0SMatteo Riondato hosts_bak = realloc(hosts, (nhosts + 2) *
1683c2ff3b0SMatteo Riondato sizeof(char *));
1693c2ff3b0SMatteo Riondato if (hosts_bak == NULL) {
1703c2ff3b0SMatteo Riondato for (i = 0; i < nhosts; i++)
1713c2ff3b0SMatteo Riondato free(hosts[i]);
1723c2ff3b0SMatteo Riondato free(hosts);
1733c2ff3b0SMatteo Riondato out_of_mem();
1743c2ff3b0SMatteo Riondato } else
1753c2ff3b0SMatteo Riondato hosts = hosts_bak;
1763c2ff3b0SMatteo Riondato
1773c2ff3b0SMatteo Riondato nhosts += 2;
178aec74e0cSHiroki Sato hosts[nhosts - 2] = strdup("::1");
1793c2ff3b0SMatteo Riondato } else {
1803c2ff3b0SMatteo Riondato hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *));
1813c2ff3b0SMatteo Riondato if (hosts_bak == NULL) {
1823c2ff3b0SMatteo Riondato for (i = 0; i < nhosts; i++)
1833c2ff3b0SMatteo Riondato free(hosts[i]);
1843c2ff3b0SMatteo Riondato
1853c2ff3b0SMatteo Riondato free(hosts);
1863c2ff3b0SMatteo Riondato out_of_mem();
1873c2ff3b0SMatteo Riondato } else {
1883c2ff3b0SMatteo Riondato nhosts += 1;
1893c2ff3b0SMatteo Riondato hosts = hosts_bak;
1903c2ff3b0SMatteo Riondato }
1913c2ff3b0SMatteo Riondato }
192aec74e0cSHiroki Sato hosts[nhosts - 1] = strdup("127.0.0.1");
19374e69f9eSMatteo Riondato }
19474e69f9eSMatteo Riondato
1956924e68eSRick Macklem attempt_cnt = 1;
1966924e68eSRick Macklem sock_fdcnt = 0;
1976924e68eSRick Macklem sock_fd = NULL;
1986924e68eSRick Macklem port_list = NULL;
1996924e68eSRick Macklem port_len = 0;
2003c2ff3b0SMatteo Riondato nc_handle = setnetconfig();
2013c2ff3b0SMatteo Riondato while ((nconf = getnetconfig(nc_handle))) {
2023c2ff3b0SMatteo Riondato /* We want to listen only on udp6, tcp6, udp, tcp transports */
2033c2ff3b0SMatteo Riondato if (nconf->nc_flag & NC_VISIBLE) {
2043c2ff3b0SMatteo Riondato /* Skip if there's no IPv6 support */
2053c2ff3b0SMatteo Riondato if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
2063c2ff3b0SMatteo Riondato /* DO NOTHING */
2073c2ff3b0SMatteo Riondato } else {
2086924e68eSRick Macklem ret = create_service(nconf);
2096924e68eSRick Macklem if (ret == 1)
2106924e68eSRick Macklem /* Ignore this call */
2116924e68eSRick Macklem continue;
2126924e68eSRick Macklem if (ret < 0) {
2136924e68eSRick Macklem /*
2146924e68eSRick Macklem * Failed to bind port, so close off
2156924e68eSRick Macklem * all sockets created and try again
2166924e68eSRick Macklem * if the port# was dynamically
2176924e68eSRick Macklem * assigned via bind(2).
2186924e68eSRick Macklem */
2196924e68eSRick Macklem clearout_service();
2206924e68eSRick Macklem if (mallocd_svcport != 0 &&
2216924e68eSRick Macklem attempt_cnt < GETPORT_MAXTRY) {
2226924e68eSRick Macklem free(svcport_str);
2236924e68eSRick Macklem svcport_str = NULL;
2246924e68eSRick Macklem mallocd_svcport = 0;
2256924e68eSRick Macklem } else {
2266924e68eSRick Macklem errno = EADDRINUSE;
2276924e68eSRick Macklem syslog(LOG_ERR,
2286924e68eSRick Macklem "bindresvport_sa: %m");
2296924e68eSRick Macklem exit(1);
23074e69f9eSMatteo Riondato }
2316924e68eSRick Macklem
2326924e68eSRick Macklem /* Start over at the first service. */
2336924e68eSRick Macklem free(sock_fd);
2346924e68eSRick Macklem sock_fdcnt = 0;
2356924e68eSRick Macklem sock_fd = NULL;
2366924e68eSRick Macklem nc_handle = setnetconfig();
2376924e68eSRick Macklem attempt_cnt++;
2386924e68eSRick Macklem } else if (mallocd_svcport != 0 &&
2396924e68eSRick Macklem attempt_cnt == GETPORT_MAXTRY) {
2406924e68eSRick Macklem /*
2416924e68eSRick Macklem * For the last attempt, allow
2426924e68eSRick Macklem * different port #s for each nconf
2436924e68eSRick Macklem * by saving the svcport_str and
2446924e68eSRick Macklem * setting it back to NULL.
2456924e68eSRick Macklem */
2466924e68eSRick Macklem port_list = realloc(port_list,
2476924e68eSRick Macklem (port_len + 1) * sizeof(char *));
2486924e68eSRick Macklem if (port_list == NULL)
2496924e68eSRick Macklem out_of_mem();
2506924e68eSRick Macklem port_list[port_len++] = svcport_str;
2516924e68eSRick Macklem svcport_str = NULL;
2526924e68eSRick Macklem mallocd_svcport = 0;
2536924e68eSRick Macklem }
2546924e68eSRick Macklem }
2556924e68eSRick Macklem }
2566924e68eSRick Macklem }
2576924e68eSRick Macklem
2586924e68eSRick Macklem /*
2596924e68eSRick Macklem * Successfully bound the ports, so call complete_service() to
2606924e68eSRick Macklem * do the rest of the setup on the service(s).
2616924e68eSRick Macklem */
2626924e68eSRick Macklem sock_fdpos = 0;
2636924e68eSRick Macklem port_pos = 0;
2646924e68eSRick Macklem nc_handle = setnetconfig();
2656924e68eSRick Macklem while ((nconf = getnetconfig(nc_handle))) {
2666924e68eSRick Macklem /* We want to listen only on udp6, tcp6, udp, tcp transports */
2676924e68eSRick Macklem if (nconf->nc_flag & NC_VISIBLE) {
2686924e68eSRick Macklem /* Skip if there's no IPv6 support */
2696924e68eSRick Macklem if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
2706924e68eSRick Macklem /* DO NOTHING */
2716924e68eSRick Macklem } else if (port_list != NULL) {
2726924e68eSRick Macklem if (port_pos >= port_len) {
2736924e68eSRick Macklem syslog(LOG_ERR, "too many port#s");
2746924e68eSRick Macklem exit(1);
2756924e68eSRick Macklem }
2766924e68eSRick Macklem complete_service(nconf, port_list[port_pos++]);
2776924e68eSRick Macklem } else
2786924e68eSRick Macklem complete_service(nconf, svcport_str);
27974e69f9eSMatteo Riondato }
28074e69f9eSMatteo Riondato }
2813c2ff3b0SMatteo Riondato endnetconfig(nc_handle);
2826924e68eSRick Macklem free(sock_fd);
2836924e68eSRick Macklem if (port_list != NULL) {
2846924e68eSRick Macklem for (port_pos = 0; port_pos < port_len; port_pos++)
2856924e68eSRick Macklem free(port_list[port_pos]);
2866924e68eSRick Macklem free(port_list);
2876924e68eSRick Macklem }
2886924e68eSRick Macklem
289f61a23adSDon Lewis init_file("/var/db/statd.status");
2901494289fSPeter Wemm
2911494289fSPeter Wemm /* Note that it is NOT sensible to run this program from inetd - the */
2921494289fSPeter Wemm /* protocol assumes that it will run immediately at boot time. */
29390e43b44SRavi Pokala if ((foreground == 0) && daemon(0, 0) < 0) {
29490e43b44SRavi Pokala err(1, "cannot fork");
29590e43b44SRavi Pokala /* NOTREACHED */
29690e43b44SRavi Pokala }
29790e43b44SRavi Pokala
2981494289fSPeter Wemm openlog("rpc.statd", 0, LOG_DAEMON);
2991494289fSPeter Wemm if (debug) syslog(LOG_INFO, "Starting - debug enabled");
3001494289fSPeter Wemm else syslog(LOG_INFO, "Starting");
3011494289fSPeter Wemm
3021494289fSPeter Wemm /* Install signal handler to collect exit status of child processes */
3031494289fSPeter Wemm sa.sa_handler = handle_sigchld;
3041494289fSPeter Wemm sigemptyset(&sa.sa_mask);
3051494289fSPeter Wemm sigaddset(&sa.sa_mask, SIGCHLD);
3061494289fSPeter Wemm sa.sa_flags = SA_RESTART;
3071494289fSPeter Wemm sigaction(SIGCHLD, &sa, NULL);
3081494289fSPeter Wemm
3091494289fSPeter Wemm /* Initialisation now complete - start operating */
3101494289fSPeter Wemm notify_hosts(); /* Forks a process (if necessary) to do the */
3111494289fSPeter Wemm /* SM_NOTIFY calls, which may be slow. */
3121494289fSPeter Wemm
3131494289fSPeter Wemm svc_run(); /* Should never return */
3141494289fSPeter Wemm exit(1);
3151494289fSPeter Wemm }
3161494289fSPeter Wemm
3173c2ff3b0SMatteo Riondato /*
3183c2ff3b0SMatteo Riondato * This routine creates and binds sockets on the appropriate
3196924e68eSRick Macklem * addresses. It gets called one time for each transport.
320*72e70904SGordon Bergling * It returns 0 upon success, 1 for ignore the call and -1 to indicate
3216924e68eSRick Macklem * bind failed with EADDRINUSE.
3226924e68eSRick Macklem * Any file descriptors that have been created are stored in sock_fd and
3236924e68eSRick Macklem * the total count of them is maintained in sock_fdcnt.
3243c2ff3b0SMatteo Riondato */
3256924e68eSRick Macklem static int
create_service(struct netconfig * nconf)3263c2ff3b0SMatteo Riondato create_service(struct netconfig *nconf)
3273c2ff3b0SMatteo Riondato {
3283c2ff3b0SMatteo Riondato struct addrinfo hints, *res = NULL;
3293c2ff3b0SMatteo Riondato struct sockaddr_in *sin;
3303c2ff3b0SMatteo Riondato struct sockaddr_in6 *sin6;
3313c2ff3b0SMatteo Riondato struct __rpc_sockinfo si;
3323c2ff3b0SMatteo Riondato int aicode;
3333c2ff3b0SMatteo Riondato int fd;
3343c2ff3b0SMatteo Riondato int nhostsbak;
3353c2ff3b0SMatteo Riondato int r;
3363c2ff3b0SMatteo Riondato u_int32_t host_addr[4]; /* IPv4 or IPv6 */
3376924e68eSRick Macklem int mallocd_res;
3383c2ff3b0SMatteo Riondato
3393c2ff3b0SMatteo Riondato if ((nconf->nc_semantics != NC_TPI_CLTS) &&
3403c2ff3b0SMatteo Riondato (nconf->nc_semantics != NC_TPI_COTS) &&
3413c2ff3b0SMatteo Riondato (nconf->nc_semantics != NC_TPI_COTS_ORD))
3426924e68eSRick Macklem return (1); /* not my type */
3433c2ff3b0SMatteo Riondato
3443c2ff3b0SMatteo Riondato /*
3453c2ff3b0SMatteo Riondato * XXX - using RPC library internal functions.
3463c2ff3b0SMatteo Riondato */
3473c2ff3b0SMatteo Riondato if (!__rpc_nconf2sockinfo(nconf, &si)) {
3483c2ff3b0SMatteo Riondato syslog(LOG_ERR, "cannot get information for %s",
3493c2ff3b0SMatteo Riondato nconf->nc_netid);
3506924e68eSRick Macklem return (1);
3513c2ff3b0SMatteo Riondato }
3523c2ff3b0SMatteo Riondato
3533c2ff3b0SMatteo Riondato /* Get rpc.statd's address on this transport */
3543c2ff3b0SMatteo Riondato memset(&hints, 0, sizeof hints);
3553c2ff3b0SMatteo Riondato hints.ai_family = si.si_af;
3563c2ff3b0SMatteo Riondato hints.ai_socktype = si.si_socktype;
3573c2ff3b0SMatteo Riondato hints.ai_protocol = si.si_proto;
3583c2ff3b0SMatteo Riondato
3593c2ff3b0SMatteo Riondato /*
3603c2ff3b0SMatteo Riondato * Bind to specific IPs if asked to
3613c2ff3b0SMatteo Riondato */
3623c2ff3b0SMatteo Riondato nhostsbak = nhosts;
3633c2ff3b0SMatteo Riondato while (nhostsbak > 0) {
3643c2ff3b0SMatteo Riondato --nhostsbak;
3656924e68eSRick Macklem sock_fd = realloc(sock_fd, (sock_fdcnt + 1) * sizeof(int));
3666924e68eSRick Macklem if (sock_fd == NULL)
3676924e68eSRick Macklem out_of_mem();
3686924e68eSRick Macklem sock_fd[sock_fdcnt++] = -1; /* Set invalid for now. */
3696924e68eSRick Macklem mallocd_res = 0;
3709745de4cSRyan Stone hints.ai_flags = AI_PASSIVE;
3713c2ff3b0SMatteo Riondato
3723c2ff3b0SMatteo Riondato /*
3733c2ff3b0SMatteo Riondato * XXX - using RPC library internal functions.
3743c2ff3b0SMatteo Riondato */
3753c2ff3b0SMatteo Riondato if ((fd = __rpc_nconf2fd(nconf)) < 0) {
3763c2ff3b0SMatteo Riondato syslog(LOG_ERR, "cannot create socket for %s",
3773c2ff3b0SMatteo Riondato nconf->nc_netid);
3783c2ff3b0SMatteo Riondato continue;
3793c2ff3b0SMatteo Riondato }
3803c2ff3b0SMatteo Riondato switch (hints.ai_family) {
3813c2ff3b0SMatteo Riondato case AF_INET:
3823c2ff3b0SMatteo Riondato if (inet_pton(AF_INET, hosts[nhostsbak],
3833c2ff3b0SMatteo Riondato host_addr) == 1) {
3846924e68eSRick Macklem hints.ai_flags |= AI_NUMERICHOST;
3853c2ff3b0SMatteo Riondato } else {
3863c2ff3b0SMatteo Riondato /*
3873c2ff3b0SMatteo Riondato * Skip if we have an AF_INET6 address.
3883c2ff3b0SMatteo Riondato */
3893c2ff3b0SMatteo Riondato if (inet_pton(AF_INET6, hosts[nhostsbak],
3903c2ff3b0SMatteo Riondato host_addr) == 1) {
3913c2ff3b0SMatteo Riondato close(fd);
3923c2ff3b0SMatteo Riondato continue;
3933c2ff3b0SMatteo Riondato }
3943c2ff3b0SMatteo Riondato }
3953c2ff3b0SMatteo Riondato break;
3963c2ff3b0SMatteo Riondato case AF_INET6:
3973c2ff3b0SMatteo Riondato if (inet_pton(AF_INET6, hosts[nhostsbak],
3983c2ff3b0SMatteo Riondato host_addr) == 1) {
3996924e68eSRick Macklem hints.ai_flags |= AI_NUMERICHOST;
4003c2ff3b0SMatteo Riondato } else {
4013c2ff3b0SMatteo Riondato /*
4023c2ff3b0SMatteo Riondato * Skip if we have an AF_INET address.
4033c2ff3b0SMatteo Riondato */
4043c2ff3b0SMatteo Riondato if (inet_pton(AF_INET, hosts[nhostsbak],
4053c2ff3b0SMatteo Riondato host_addr) == 1) {
4063c2ff3b0SMatteo Riondato close(fd);
4073c2ff3b0SMatteo Riondato continue;
4083c2ff3b0SMatteo Riondato }
4093c2ff3b0SMatteo Riondato }
4103c2ff3b0SMatteo Riondato break;
4113c2ff3b0SMatteo Riondato default:
4123c2ff3b0SMatteo Riondato break;
4133c2ff3b0SMatteo Riondato }
4143c2ff3b0SMatteo Riondato
4153c2ff3b0SMatteo Riondato /*
4163c2ff3b0SMatteo Riondato * If no hosts were specified, just bind to INADDR_ANY
4173c2ff3b0SMatteo Riondato */
4183c2ff3b0SMatteo Riondato if (strcmp("*", hosts[nhostsbak]) == 0) {
4193c2ff3b0SMatteo Riondato if (svcport_str == NULL) {
4203c2ff3b0SMatteo Riondato res = malloc(sizeof(struct addrinfo));
4213c2ff3b0SMatteo Riondato if (res == NULL)
4223c2ff3b0SMatteo Riondato out_of_mem();
4236924e68eSRick Macklem mallocd_res = 1;
4243c2ff3b0SMatteo Riondato res->ai_flags = hints.ai_flags;
4253c2ff3b0SMatteo Riondato res->ai_family = hints.ai_family;
4263c2ff3b0SMatteo Riondato res->ai_protocol = hints.ai_protocol;
4273c2ff3b0SMatteo Riondato switch (res->ai_family) {
4283c2ff3b0SMatteo Riondato case AF_INET:
4293c2ff3b0SMatteo Riondato sin = malloc(sizeof(struct sockaddr_in));
4303c2ff3b0SMatteo Riondato if (sin == NULL)
4313c2ff3b0SMatteo Riondato out_of_mem();
4323c2ff3b0SMatteo Riondato sin->sin_family = AF_INET;
4333c2ff3b0SMatteo Riondato sin->sin_port = htons(0);
4343c2ff3b0SMatteo Riondato sin->sin_addr.s_addr = htonl(INADDR_ANY);
4353c2ff3b0SMatteo Riondato res->ai_addr = (struct sockaddr*) sin;
4363c2ff3b0SMatteo Riondato res->ai_addrlen = (socklen_t)
4376924e68eSRick Macklem sizeof(struct sockaddr_in);
4383c2ff3b0SMatteo Riondato break;
4393c2ff3b0SMatteo Riondato case AF_INET6:
4403c2ff3b0SMatteo Riondato sin6 = malloc(sizeof(struct sockaddr_in6));
44196e460ecSMatteo Riondato if (sin6 == NULL)
4423c2ff3b0SMatteo Riondato out_of_mem();
4433c2ff3b0SMatteo Riondato sin6->sin6_family = AF_INET6;
4443c2ff3b0SMatteo Riondato sin6->sin6_port = htons(0);
4453c2ff3b0SMatteo Riondato sin6->sin6_addr = in6addr_any;
4463c2ff3b0SMatteo Riondato res->ai_addr = (struct sockaddr*) sin6;
4476924e68eSRick Macklem res->ai_addrlen = (socklen_t)
4486924e68eSRick Macklem sizeof(struct sockaddr_in6);
4493c2ff3b0SMatteo Riondato break;
4503c2ff3b0SMatteo Riondato default:
4516924e68eSRick Macklem syslog(LOG_ERR, "bad addr fam %d",
4526924e68eSRick Macklem res->ai_family);
4536924e68eSRick Macklem exit(1);
4543c2ff3b0SMatteo Riondato }
4553c2ff3b0SMatteo Riondato } else {
4563c2ff3b0SMatteo Riondato if ((aicode = getaddrinfo(NULL, svcport_str,
4573c2ff3b0SMatteo Riondato &hints, &res)) != 0) {
4583c2ff3b0SMatteo Riondato syslog(LOG_ERR,
4593c2ff3b0SMatteo Riondato "cannot get local address for %s: %s",
4603c2ff3b0SMatteo Riondato nconf->nc_netid,
4613c2ff3b0SMatteo Riondato gai_strerror(aicode));
4626924e68eSRick Macklem close(fd);
4633c2ff3b0SMatteo Riondato continue;
4643c2ff3b0SMatteo Riondato }
4653c2ff3b0SMatteo Riondato }
4663c2ff3b0SMatteo Riondato } else {
4673c2ff3b0SMatteo Riondato if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str,
4683c2ff3b0SMatteo Riondato &hints, &res)) != 0) {
4693c2ff3b0SMatteo Riondato syslog(LOG_ERR,
4703c2ff3b0SMatteo Riondato "cannot get local address for %s: %s",
4713c2ff3b0SMatteo Riondato nconf->nc_netid, gai_strerror(aicode));
4726924e68eSRick Macklem close(fd);
4733c2ff3b0SMatteo Riondato continue;
4743c2ff3b0SMatteo Riondato }
4753c2ff3b0SMatteo Riondato }
4763c2ff3b0SMatteo Riondato
4776924e68eSRick Macklem /* Store the fd. */
4786924e68eSRick Macklem sock_fd[sock_fdcnt - 1] = fd;
4796924e68eSRick Macklem
4806924e68eSRick Macklem /* Now, attempt the bind. */
4813c2ff3b0SMatteo Riondato r = bindresvport_sa(fd, res->ai_addr);
4823c2ff3b0SMatteo Riondato if (r != 0) {
4836924e68eSRick Macklem if (errno == EADDRINUSE && mallocd_svcport != 0) {
4846924e68eSRick Macklem if (mallocd_res != 0) {
4856924e68eSRick Macklem free(res->ai_addr);
4866924e68eSRick Macklem free(res);
4876924e68eSRick Macklem } else
4886924e68eSRick Macklem freeaddrinfo(res);
4896924e68eSRick Macklem return (-1);
4906924e68eSRick Macklem }
4913c2ff3b0SMatteo Riondato syslog(LOG_ERR, "bindresvport_sa: %m");
4923c2ff3b0SMatteo Riondato exit(1);
4933c2ff3b0SMatteo Riondato }
4943c2ff3b0SMatteo Riondato
4956924e68eSRick Macklem if (svcport_str == NULL) {
4966924e68eSRick Macklem svcport_str = malloc(NI_MAXSERV * sizeof(char));
4976924e68eSRick Macklem if (svcport_str == NULL)
4986924e68eSRick Macklem out_of_mem();
4996924e68eSRick Macklem mallocd_svcport = 1;
5006924e68eSRick Macklem
5016924e68eSRick Macklem if (getnameinfo(res->ai_addr,
5026924e68eSRick Macklem res->ai_addr->sa_len, NULL, NI_MAXHOST,
5036924e68eSRick Macklem svcport_str, NI_MAXSERV * sizeof(char),
5046924e68eSRick Macklem NI_NUMERICHOST | NI_NUMERICSERV))
5056924e68eSRick Macklem errx(1, "Cannot get port number");
5066924e68eSRick Macklem }
5076924e68eSRick Macklem if (mallocd_res != 0) {
5086924e68eSRick Macklem free(res->ai_addr);
5096924e68eSRick Macklem free(res);
5106924e68eSRick Macklem } else
5116924e68eSRick Macklem freeaddrinfo(res);
5126924e68eSRick Macklem res = NULL;
5136924e68eSRick Macklem }
5146924e68eSRick Macklem return (0);
5156924e68eSRick Macklem }
5166924e68eSRick Macklem
5176924e68eSRick Macklem /*
5186924e68eSRick Macklem * Called after all the create_service() calls have succeeded, to complete
5196924e68eSRick Macklem * the setup and registration.
5206924e68eSRick Macklem */
5216924e68eSRick Macklem static void
complete_service(struct netconfig * nconf,char * port_str)5226924e68eSRick Macklem complete_service(struct netconfig *nconf, char *port_str)
5236924e68eSRick Macklem {
5246924e68eSRick Macklem struct addrinfo hints, *res = NULL;
5256924e68eSRick Macklem struct __rpc_sockinfo si;
5266924e68eSRick Macklem struct netbuf servaddr;
5276924e68eSRick Macklem SVCXPRT *transp = NULL;
5286924e68eSRick Macklem int aicode, fd, nhostsbak;
5296924e68eSRick Macklem int registered = 0;
5306924e68eSRick Macklem
5316924e68eSRick Macklem if ((nconf->nc_semantics != NC_TPI_CLTS) &&
5326924e68eSRick Macklem (nconf->nc_semantics != NC_TPI_COTS) &&
5336924e68eSRick Macklem (nconf->nc_semantics != NC_TPI_COTS_ORD))
5346924e68eSRick Macklem return; /* not my type */
5356924e68eSRick Macklem
5366924e68eSRick Macklem /*
5376924e68eSRick Macklem * XXX - using RPC library internal functions.
5386924e68eSRick Macklem */
5396924e68eSRick Macklem if (!__rpc_nconf2sockinfo(nconf, &si)) {
5406924e68eSRick Macklem syslog(LOG_ERR, "cannot get information for %s",
5416924e68eSRick Macklem nconf->nc_netid);
5426924e68eSRick Macklem return;
5436924e68eSRick Macklem }
5446924e68eSRick Macklem
5456924e68eSRick Macklem nhostsbak = nhosts;
5466924e68eSRick Macklem while (nhostsbak > 0) {
5476924e68eSRick Macklem --nhostsbak;
5486924e68eSRick Macklem if (sock_fdpos >= sock_fdcnt) {
5496924e68eSRick Macklem /* Should never happen. */
5506924e68eSRick Macklem syslog(LOG_ERR, "Ran out of socket fd's");
5516924e68eSRick Macklem return;
5526924e68eSRick Macklem }
5536924e68eSRick Macklem fd = sock_fd[sock_fdpos++];
5546924e68eSRick Macklem if (fd < 0)
5556924e68eSRick Macklem continue;
5566924e68eSRick Macklem
5570e7cce13SDoug Rabson if (nconf->nc_semantics != NC_TPI_CLTS)
5584760d2acSAlexander Kabaev listen(fd, SOMAXCONN);
5590e7cce13SDoug Rabson
5603c2ff3b0SMatteo Riondato transp = svc_tli_create(fd, nconf, NULL,
5613c2ff3b0SMatteo Riondato RPC_MAXDATASIZE, RPC_MAXDATASIZE);
5623c2ff3b0SMatteo Riondato
5633c2ff3b0SMatteo Riondato if (transp != (SVCXPRT *) NULL) {
5643c2ff3b0SMatteo Riondato if (!svc_register(transp, SM_PROG, SM_VERS,
5653c2ff3b0SMatteo Riondato sm_prog_1, 0)) {
5663c2ff3b0SMatteo Riondato syslog(LOG_ERR, "can't register on %s",
5673c2ff3b0SMatteo Riondato nconf->nc_netid);
5683c2ff3b0SMatteo Riondato } else {
5693c2ff3b0SMatteo Riondato if (!svc_reg(transp, SM_PROG, SM_VERS,
5703c2ff3b0SMatteo Riondato sm_prog_1, NULL))
5713c2ff3b0SMatteo Riondato syslog(LOG_ERR,
5723c2ff3b0SMatteo Riondato "can't register %s SM_PROG service",
5733c2ff3b0SMatteo Riondato nconf->nc_netid);
5743c2ff3b0SMatteo Riondato }
5753c2ff3b0SMatteo Riondato } else
5763c2ff3b0SMatteo Riondato syslog(LOG_WARNING, "can't create %s services",
5773c2ff3b0SMatteo Riondato nconf->nc_netid);
5783c2ff3b0SMatteo Riondato
5793c2ff3b0SMatteo Riondato if (registered == 0) {
5803c2ff3b0SMatteo Riondato registered = 1;
5813c2ff3b0SMatteo Riondato memset(&hints, 0, sizeof hints);
5823c2ff3b0SMatteo Riondato hints.ai_flags = AI_PASSIVE;
5833c2ff3b0SMatteo Riondato hints.ai_family = si.si_af;
5843c2ff3b0SMatteo Riondato hints.ai_socktype = si.si_socktype;
5853c2ff3b0SMatteo Riondato hints.ai_protocol = si.si_proto;
5863c2ff3b0SMatteo Riondato
5873c2ff3b0SMatteo Riondato
5886924e68eSRick Macklem if ((aicode = getaddrinfo(NULL, port_str, &hints,
5893c2ff3b0SMatteo Riondato &res)) != 0) {
5903c2ff3b0SMatteo Riondato syslog(LOG_ERR, "cannot get local address: %s",
5913c2ff3b0SMatteo Riondato gai_strerror(aicode));
5923c2ff3b0SMatteo Riondato exit(1);
5933c2ff3b0SMatteo Riondato }
5943c2ff3b0SMatteo Riondato
5953c2ff3b0SMatteo Riondato servaddr.buf = malloc(res->ai_addrlen);
5963c2ff3b0SMatteo Riondato memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen);
5973c2ff3b0SMatteo Riondato servaddr.len = res->ai_addrlen;
5983c2ff3b0SMatteo Riondato
5993c2ff3b0SMatteo Riondato rpcb_set(SM_PROG, SM_VERS, nconf, &servaddr);
6003c2ff3b0SMatteo Riondato
6013c2ff3b0SMatteo Riondato xcreated++;
6023c2ff3b0SMatteo Riondato freeaddrinfo(res);
6033c2ff3b0SMatteo Riondato }
6043c2ff3b0SMatteo Riondato } /* end while */
6053c2ff3b0SMatteo Riondato }
6063c2ff3b0SMatteo Riondato
6076924e68eSRick Macklem /*
6086924e68eSRick Macklem * Clear out sockets after a failure to bind one of them, so that the
6096924e68eSRick Macklem * cycle of socket creation/binding can start anew.
6106924e68eSRick Macklem */
6116924e68eSRick Macklem static void
clearout_service(void)6126924e68eSRick Macklem clearout_service(void)
6136924e68eSRick Macklem {
6146924e68eSRick Macklem int i;
6156924e68eSRick Macklem
6166924e68eSRick Macklem for (i = 0; i < sock_fdcnt; i++) {
6176924e68eSRick Macklem if (sock_fd[i] >= 0) {
6186924e68eSRick Macklem shutdown(sock_fd[i], SHUT_RDWR);
6196924e68eSRick Macklem close(sock_fd[i]);
6206924e68eSRick Macklem }
6216924e68eSRick Macklem }
6226924e68eSRick Macklem }
6236924e68eSRick Macklem
624df82e9baSPhilippe Charnier static void
usage(void)62506eae2c1SEnji Cooper usage(void)
626df82e9baSPhilippe Charnier {
62790e43b44SRavi Pokala fprintf(stderr, "usage: rpc.statd [-d] [-F] [-h <bindip>] [-p <port>]\n");
628df82e9baSPhilippe Charnier exit(1);
629df82e9baSPhilippe Charnier }
6301494289fSPeter Wemm
6311494289fSPeter Wemm /* handle_sigchld ---------------------------------------------------------- */
6321494289fSPeter Wemm /*
6331494289fSPeter Wemm Purpose: Catch SIGCHLD and collect process status
6341494289fSPeter Wemm Retruns: Nothing.
6351494289fSPeter Wemm Notes: No special action required, other than to collect the
6361494289fSPeter Wemm process status and hence allow the child to die:
6371494289fSPeter Wemm we only use child processes for asynchronous transmission
6381494289fSPeter Wemm of SM_NOTIFY to other systems, so it is normal for the
6391494289fSPeter Wemm children to exit when they have done their work.
6401494289fSPeter Wemm */
6411494289fSPeter Wemm
handle_sigchld(int sig __unused)642bf117edaSAlfred Perlstein static void handle_sigchld(int sig __unused)
6431494289fSPeter Wemm {
6441494289fSPeter Wemm int pid, status;
6451494289fSPeter Wemm pid = wait4(-1, &status, WNOHANG, (struct rusage*)0);
6461494289fSPeter Wemm if (!pid) syslog(LOG_ERR, "Phantom SIGCHLD??");
6471494289fSPeter Wemm else if (status == 0)
6481494289fSPeter Wemm {
6491494289fSPeter Wemm if (debug) syslog(LOG_DEBUG, "Child %d exited OK", pid);
6501494289fSPeter Wemm }
6511494289fSPeter Wemm else syslog(LOG_ERR, "Child %d failed with status %d", pid,
6521494289fSPeter Wemm WEXITSTATUS(status));
6531494289fSPeter Wemm }
6541494289fSPeter Wemm
6553c2ff3b0SMatteo Riondato /*
6563c2ff3b0SMatteo Riondato * Out of memory, fatal
6573c2ff3b0SMatteo Riondato */
6583c2ff3b0SMatteo Riondato void
out_of_mem(void)65906eae2c1SEnji Cooper out_of_mem(void)
6603c2ff3b0SMatteo Riondato {
6613c2ff3b0SMatteo Riondato
6623c2ff3b0SMatteo Riondato syslog(LOG_ERR, "out of memory");
6633c2ff3b0SMatteo Riondato exit(2);
6643c2ff3b0SMatteo Riondato }
665