xref: /freebsd/usr.sbin/rpc.statd/statd.c (revision f61a23adcc8e033780415050ab80169af5c510ff)
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>
421494289fSPeter Wemm #include <stdio.h>
43df82e9baSPhilippe Charnier #include <stdlib.h>
441494289fSPeter Wemm #include <rpc/rpc.h>
45bcb53b16SMartin Blapp #include <rpc/rpc_com.h>
4696e33c21SAlfred Perlstein #include <string.h>
471494289fSPeter Wemm #include <syslog.h>
481494289fSPeter Wemm #include <sys/types.h>
491494289fSPeter Wemm #include <sys/wait.h>
501494289fSPeter Wemm #include <signal.h>
511c38ed81SPhilippe Charnier #include <unistd.h>
521494289fSPeter Wemm #include "statd.h"
531494289fSPeter Wemm 
541494289fSPeter Wemm int debug = 0;		/* Controls syslog() calls for debug messages	*/
551494289fSPeter Wemm 
56bf117edaSAlfred Perlstein static void handle_sigchld(int sig);
57bf117edaSAlfred Perlstein static void usage(void);
581494289fSPeter Wemm 
5974e69f9eSMatteo Riondato const char *transports[] = { "udp", "tcp", "udp6", "tcp6" };
6074e69f9eSMatteo Riondato 
61df82e9baSPhilippe Charnier int
621494289fSPeter Wemm main(int argc, char **argv)
631494289fSPeter Wemm {
6474e69f9eSMatteo Riondato   SVCXPRT *transp;
651494289fSPeter Wemm   struct sigaction sa;
6674e69f9eSMatteo Riondato   struct netconfig *nconf;
6774e69f9eSMatteo Riondato   struct sockaddr_in sin;
6874e69f9eSMatteo Riondato   struct sockaddr_in6 sin6;
6974e69f9eSMatteo Riondato   int ch, i, maxindex, r, s, sock;
7074e69f9eSMatteo Riondato   char *endptr;
71bcb53b16SMartin Blapp   int maxrec = RPC_MAXDATASIZE;
7274e69f9eSMatteo Riondato   in_port_t svcport = 0;
731494289fSPeter Wemm 
7474e69f9eSMatteo Riondato   while ((ch = getopt(argc, argv, "dp:")) != -1)
751c38ed81SPhilippe Charnier     switch (ch) {
761c38ed81SPhilippe Charnier     case 'd':
771494289fSPeter Wemm       debug = 1;
781c38ed81SPhilippe Charnier       break;
7974e69f9eSMatteo Riondato     case 'p':
8074e69f9eSMatteo Riondato       endptr = NULL;
8174e69f9eSMatteo Riondato       svcport = (in_port_t)strtoul(optarg, &endptr, 10);
8274e69f9eSMatteo Riondato       if (endptr == NULL || *endptr != '\0' || svcport == 0 ||
8374e69f9eSMatteo Riondato           svcport >= IPPORT_MAX)
8474e69f9eSMatteo Riondato 	usage();
8574e69f9eSMatteo Riondato       break;
861c38ed81SPhilippe Charnier     default:
871c38ed81SPhilippe Charnier       usage();
881494289fSPeter Wemm     }
891c38ed81SPhilippe Charnier   argc -= optind;
901c38ed81SPhilippe Charnier   argv += optind;
911494289fSPeter Wemm 
92af37179bSAlfred Perlstein   (void)rpcb_unset(SM_PROG, SM_VERS, NULL);
931494289fSPeter Wemm 
9474e69f9eSMatteo Riondato   /*
9574e69f9eSMatteo Riondato    * Check if IPv6 support is present.
9674e69f9eSMatteo Riondato    */
9774e69f9eSMatteo Riondato   s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
9874e69f9eSMatteo Riondato   if (s < 0)
9974e69f9eSMatteo Riondato       maxindex = 2;
10074e69f9eSMatteo Riondato   else {
10174e69f9eSMatteo Riondato       close(s);
10274e69f9eSMatteo Riondato       maxindex = 4;
10374e69f9eSMatteo Riondato   }
10474e69f9eSMatteo Riondato 
10574e69f9eSMatteo Riondato   if (svcport != 0) {
10674e69f9eSMatteo Riondato       bzero(&sin, sizeof(struct sockaddr_in));
10774e69f9eSMatteo Riondato       sin.sin_len = sizeof(struct sockaddr_in);
10874e69f9eSMatteo Riondato       sin.sin_family = AF_INET;
10974e69f9eSMatteo Riondato       sin.sin_port = htons(svcport);
11074e69f9eSMatteo Riondato 
11174e69f9eSMatteo Riondato       bzero(&sin6, sizeof(struct sockaddr_in6));
11274e69f9eSMatteo Riondato       sin6.sin6_len = sizeof(struct sockaddr_in6);
11374e69f9eSMatteo Riondato       sin6.sin6_family = AF_INET6;
11474e69f9eSMatteo Riondato       sin6.sin6_port = htons(svcport);
11574e69f9eSMatteo Riondato   }
11674e69f9eSMatteo Riondato 
117bcb53b16SMartin Blapp   rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);
118bcb53b16SMartin Blapp 
11974e69f9eSMatteo Riondato   for (i = 0; i < maxindex; i++) {
12074e69f9eSMatteo Riondato       nconf = getnetconfigent(transports[i]);
12174e69f9eSMatteo Riondato       if (nconf == NULL)
12274e69f9eSMatteo Riondato     	  errx(1, "cannot get %s netconf: %s.", transports[i],
12374e69f9eSMatteo Riondato 		nc_sperror());
12474e69f9eSMatteo Riondato 
12574e69f9eSMatteo Riondato       if (svcport != 0) {
12674e69f9eSMatteo Riondato 	  if (strcmp(nconf->nc_netid, "udp6") == 0) {
12774e69f9eSMatteo Riondato 	      sock = socket(AF_INET6, SOCK_DGRAM,
12874e69f9eSMatteo Riondato 			    IPPROTO_UDP);
12974e69f9eSMatteo Riondato 	      if (sock != -1) {
13074e69f9eSMatteo Riondato 		  r = bindresvport_sa(sock,
13174e69f9eSMatteo Riondato 		        (struct sockaddr *)&sin6);
13274e69f9eSMatteo Riondato 		  if (r != 0) {
13374e69f9eSMatteo Riondato 		      syslog(LOG_ERR, "bindresvport: %m");
13474e69f9eSMatteo Riondato 		      exit(1);
13574e69f9eSMatteo Riondato 		  }
13674e69f9eSMatteo Riondato 	     }
13774e69f9eSMatteo Riondato 	  } else if (strcmp(nconf->nc_netid, "udp") == 0) {
13874e69f9eSMatteo Riondato 	      sock = socket(AF_INET, SOCK_DGRAM,
13974e69f9eSMatteo Riondato 			    IPPROTO_UDP);
14074e69f9eSMatteo Riondato 	      if (sock != -1) {
14174e69f9eSMatteo Riondato 		  r = bindresvport(sock, &sin);
14274e69f9eSMatteo Riondato 		  if (r != 0) {
14374e69f9eSMatteo Riondato 		      syslog(LOG_ERR, "bindresvport: %m");
14474e69f9eSMatteo Riondato 		      exit(1);
14574e69f9eSMatteo Riondato 		  }
14674e69f9eSMatteo Riondato 	      }
14774e69f9eSMatteo Riondato 	  } else if (strcmp(nconf->nc_netid, "tcp6") == 0) {
14874e69f9eSMatteo Riondato 	      sock = socket(AF_INET6, SOCK_STREAM,
14974e69f9eSMatteo Riondato 			    IPPROTO_TCP);
15074e69f9eSMatteo Riondato               if (sock != -1) {
15174e69f9eSMatteo Riondato 		  r = bindresvport_sa(sock,
15274e69f9eSMatteo Riondato 			(struct sockaddr *)&sin6);
15374e69f9eSMatteo Riondato 	      	  if (r != 0) {
15474e69f9eSMatteo Riondato 		      syslog(LOG_ERR, "bindresvport: %m");
15574e69f9eSMatteo Riondato 		      exit(1);
15674e69f9eSMatteo Riondato 	          }
15774e69f9eSMatteo Riondato 	      }
15874e69f9eSMatteo Riondato 	  } else if (strcmp(nconf->nc_netid, "tcp") == 0) {
15974e69f9eSMatteo Riondato 	      sock = socket(AF_INET, SOCK_STREAM,
16074e69f9eSMatteo Riondato 			    IPPROTO_TCP);
16174e69f9eSMatteo Riondato 	      if (sock != -1) {
16274e69f9eSMatteo Riondato 		  r = bindresvport(sock, &sin);
16374e69f9eSMatteo Riondato 		  if (r != 0) {
16474e69f9eSMatteo Riondato 		      syslog(LOG_ERR, "bindresvport: %m");
16574e69f9eSMatteo Riondato 		      exit(1);
16674e69f9eSMatteo Riondato 		  }
16774e69f9eSMatteo Riondato 	      }
16874e69f9eSMatteo Riondato 	  }
16974e69f9eSMatteo Riondato 
17074e69f9eSMatteo Riondato 	  transp = svc_tli_create(sock, nconf, NULL,
17174e69f9eSMatteo Riondato 	    	RPC_MAXDATASIZE, RPC_MAXDATASIZE);
17274e69f9eSMatteo Riondato       } else {
17374e69f9eSMatteo Riondato 	  transp = svc_tli_create(RPC_ANYFD, nconf, NULL,
17474e69f9eSMatteo Riondato 	    	RPC_MAXDATASIZE, RPC_MAXDATASIZE);
17574e69f9eSMatteo Riondato       }
17674e69f9eSMatteo Riondato 
17774e69f9eSMatteo Riondato       if (transp == NULL) {
17874e69f9eSMatteo Riondato 	  errx(1, "cannot create %s service.", transports[i]);
17974e69f9eSMatteo Riondato 	  /* NOTREACHED */
18074e69f9eSMatteo Riondato       }
18174e69f9eSMatteo Riondato       if (!svc_reg(transp, SM_PROG, SM_VERS, sm_prog_1, nconf)) {
18274e69f9eSMatteo Riondato 	  errx(1, "unable to register (SM_PROG, NLM_SM, %s)",
18374e69f9eSMatteo Riondato 		 transports[i]);
18474e69f9eSMatteo Riondato 	  /* NOTREACHED */
18574e69f9eSMatteo Riondato       }
18674e69f9eSMatteo Riondato       freenetconfigent(nconf);
18774e69f9eSMatteo Riondato   }
188f61a23adSDon Lewis   init_file("/var/db/statd.status");
1891494289fSPeter Wemm 
1901494289fSPeter Wemm   /* Note that it is NOT sensible to run this program from inetd - the 	*/
1911494289fSPeter Wemm   /* protocol assumes that it will run immediately at boot time.	*/
1921494289fSPeter Wemm   daemon(0, 0);
1931494289fSPeter Wemm   openlog("rpc.statd", 0, LOG_DAEMON);
1941494289fSPeter Wemm   if (debug) syslog(LOG_INFO, "Starting - debug enabled");
1951494289fSPeter Wemm   else syslog(LOG_INFO, "Starting");
1961494289fSPeter Wemm 
1971494289fSPeter Wemm   /* Install signal handler to collect exit status of child processes	*/
1981494289fSPeter Wemm   sa.sa_handler = handle_sigchld;
1991494289fSPeter Wemm   sigemptyset(&sa.sa_mask);
2001494289fSPeter Wemm   sigaddset(&sa.sa_mask, SIGCHLD);
2011494289fSPeter Wemm   sa.sa_flags = SA_RESTART;
2021494289fSPeter Wemm   sigaction(SIGCHLD, &sa, NULL);
2031494289fSPeter Wemm 
2041494289fSPeter Wemm   /* Initialisation now complete - start operating			*/
2051494289fSPeter Wemm   notify_hosts();	/* Forks a process (if necessary) to do the	*/
2061494289fSPeter Wemm 			/* SM_NOTIFY calls, which may be slow.		*/
2071494289fSPeter Wemm 
2081494289fSPeter Wemm   svc_run();	/* Should never return					*/
2091494289fSPeter Wemm   exit(1);
2101494289fSPeter Wemm }
2111494289fSPeter Wemm 
212df82e9baSPhilippe Charnier static void
213df82e9baSPhilippe Charnier usage()
214df82e9baSPhilippe Charnier {
21574e69f9eSMatteo Riondato       fprintf(stderr, "usage: rpc.statd [-d] [-p <port>]\n");
216df82e9baSPhilippe Charnier       exit(1);
217df82e9baSPhilippe Charnier }
2181494289fSPeter Wemm 
2191494289fSPeter Wemm /* handle_sigchld ---------------------------------------------------------- */
2201494289fSPeter Wemm /*
2211494289fSPeter Wemm    Purpose:	Catch SIGCHLD and collect process status
2221494289fSPeter Wemm    Retruns:	Nothing.
2231494289fSPeter Wemm    Notes:	No special action required, other than to collect the
2241494289fSPeter Wemm 		process status and hence allow the child to die:
2251494289fSPeter Wemm 		we only use child processes for asynchronous transmission
2261494289fSPeter Wemm 		of SM_NOTIFY to other systems, so it is normal for the
2271494289fSPeter Wemm 		children to exit when they have done their work.
2281494289fSPeter Wemm */
2291494289fSPeter Wemm 
230bf117edaSAlfred Perlstein static void handle_sigchld(int sig __unused)
2311494289fSPeter Wemm {
2321494289fSPeter Wemm   int pid, status;
2331494289fSPeter Wemm   pid = wait4(-1, &status, WNOHANG, (struct rusage*)0);
2341494289fSPeter Wemm   if (!pid) syslog(LOG_ERR, "Phantom SIGCHLD??");
2351494289fSPeter Wemm   else if (status == 0)
2361494289fSPeter Wemm   {
2371494289fSPeter Wemm     if (debug) syslog(LOG_DEBUG, "Child %d exited OK", pid);
2381494289fSPeter Wemm   }
2391494289fSPeter Wemm   else syslog(LOG_ERR, "Child %d failed with status %d", pid,
2401494289fSPeter Wemm     WEXITSTATUS(status));
2411494289fSPeter Wemm }
2421494289fSPeter Wemm 
243