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