xref: /freebsd/usr.sbin/rpc.statd/statd.c (revision 06eae2c1e06266b251883f7eeff0db129ed1ade5)
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