1 /*-
2  * SPDX-License-Identifier: BSD-4-Clause
3  *
4  * Copyright (c) 1995
5  *	A.R. Gordon (andrew.gordon@net-tel.co.uk).  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed for the FreeBSD project
18  * 4. Neither the name of the author nor the names of any co-contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  */
35 
36 /* main() function for status monitor daemon.  Some of the code in this	*/
37 /* file was generated by running rpcgen /usr/include/rpcsvc/sm_inter.x	*/
38 /* The actual program logic is in the file procs.c			*/
39 
40 #include <sys/cdefs.h>
41 __FBSDID("$FreeBSD: stable/12/usr.sbin/rpc.statd/statd.c 372865 2023-01-22 09:12:28Z gbe $");
42 
43 #include <err.h>
44 #include <errno.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <rpc/rpc.h>
48 #include <rpc/rpc_com.h>
49 #include <string.h>
50 #include <syslog.h>
51 #include <sys/types.h>
52 #include <sys/socket.h>
53 #include <sys/wait.h>
54 #include <netinet/in.h>
55 #include <arpa/inet.h>
56 #include <netdb.h>
57 #include <signal.h>
58 #include <unistd.h>
59 #include "statd.h"
60 
61 #define	GETPORT_MAXTRY	20	/* Max tries to get a port # */
62 
63 int debug = 0;		/* Controls syslog() calls for debug messages	*/
64 
65 char **hosts, *svcport_str = NULL;
66 int nhosts = 0;
67 int xcreated = 0;
68 static int	mallocd_svcport = 0;
69 static int	*sock_fd;
70 static int	sock_fdcnt;
71 static int	sock_fdpos;
72 
73 static int	create_service(struct netconfig *nconf);
74 static void	complete_service(struct netconfig *nconf, char *port_str);
75 static void	clearout_service(void);
76 static void handle_sigchld(int sig);
77 void out_of_mem(void) __dead2;
78 
79 static void usage(void) __dead2;
80 
81 int
main(int argc,char ** argv)82 main(int argc, char **argv)
83 {
84   struct sigaction sa;
85   struct netconfig *nconf;
86   void *nc_handle;
87   in_port_t svcport;
88   int ch, i, s;
89   char *endptr, **hosts_bak;
90   int have_v6 = 1;
91   int foreground = 0;
92   int maxrec = RPC_MAXDATASIZE;
93   int attempt_cnt, port_len, port_pos, ret;
94   char **port_list;
95 
96   while ((ch = getopt(argc, argv, "dFh:p:")) != -1)
97     switch (ch) {
98     case 'd':
99       debug = 1;
100       break;
101     case 'F':
102       foreground = 1;
103       break;
104     case 'h':
105       ++nhosts;
106       hosts_bak = hosts;
107       hosts_bak = realloc(hosts, nhosts * sizeof(char *));
108       if (hosts_bak == NULL) {
109 	      if (hosts != NULL) {
110 		      for (i = 0; i < nhosts; i++)
111 			      free(hosts[i]);
112 		      free(hosts);
113 		      out_of_mem();
114 	      }
115       }
116       hosts = hosts_bak;
117       hosts[nhosts - 1] = strdup(optarg);
118       if (hosts[nhosts - 1] == NULL) {
119 	      for (i = 0; i < (nhosts - 1); i++)
120 		      free(hosts[i]);
121 	      free(hosts);
122 	      out_of_mem();
123       }
124       break;
125     case 'p':
126       endptr = NULL;
127       svcport = (in_port_t)strtoul(optarg, &endptr, 10);
128       if (endptr == NULL || *endptr != '\0' || svcport == 0 ||
129           svcport >= IPPORT_MAX)
130 	usage();
131 
132       svcport_str = strdup(optarg);
133       break;
134     default:
135       usage();
136     }
137   argc -= optind;
138   argv += optind;
139 
140   (void)rpcb_unset(SM_PROG, SM_VERS, NULL);
141 
142   /*
143    * Check if IPv6 support is present.
144    */
145   s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
146   if (s < 0)
147       have_v6 = 0;
148   else
149       close(s);
150 
151   rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);
152 
153   /*
154    * If no hosts were specified, add a wildcard entry to bind to
155    * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the
156    * list.
157    */
158   if (nhosts == 0) {
159 	  hosts = malloc(sizeof(char *));
160 	  if (hosts == NULL)
161 		  out_of_mem();
162 
163 	  hosts[0] = "*";
164 	  nhosts = 1;
165   } else {
166 	  hosts_bak = hosts;
167 	  if (have_v6) {
168 		  hosts_bak = realloc(hosts, (nhosts + 2) *
169 		      sizeof(char *));
170 		  if (hosts_bak == NULL) {
171 			  for (i = 0; i < nhosts; i++)
172 				  free(hosts[i]);
173 			  free(hosts);
174 			  out_of_mem();
175 		  } else
176 			  hosts = hosts_bak;
177 
178 		  nhosts += 2;
179 		  hosts[nhosts - 2] = "::1";
180 	  } else {
181 		  hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *));
182 		  if (hosts_bak == NULL) {
183 			  for (i = 0; i < nhosts; i++)
184 				  free(hosts[i]);
185 
186 			  free(hosts);
187 			  out_of_mem();
188 		  } else {
189 			  nhosts += 1;
190 			  hosts = hosts_bak;
191 		  }
192 	  }
193 	  hosts[nhosts - 1] = "127.0.0.1";
194   }
195 
196   attempt_cnt = 1;
197   sock_fdcnt = 0;
198   sock_fd = NULL;
199   port_list = NULL;
200   port_len = 0;
201   nc_handle = setnetconfig();
202   while ((nconf = getnetconfig(nc_handle))) {
203 	  /* We want to listen only on udp6, tcp6, udp, tcp transports */
204 	  if (nconf->nc_flag & NC_VISIBLE) {
205 		  /* Skip if there's no IPv6 support */
206 		  if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
207 	      /* DO NOTHING */
208 		  } else {
209 			ret = create_service(nconf);
210 			if (ret == 1)
211 				/* Ignore this call */
212 				continue;
213 			if (ret < 0) {
214 				/*
215 				 * Failed to bind port, so close off
216 				 * all sockets created and try again
217 				 * if the port# was dynamically
218 				 * assigned via bind(2).
219 				 */
220 				clearout_service();
221 				if (mallocd_svcport != 0 &&
222 				    attempt_cnt < GETPORT_MAXTRY) {
223 					free(svcport_str);
224 					svcport_str = NULL;
225 					mallocd_svcport = 0;
226 				} else {
227 					errno = EADDRINUSE;
228 					syslog(LOG_ERR,
229 					    "bindresvport_sa: %m");
230 					exit(1);
231 				}
232 
233 				/* Start over at the first service. */
234 				free(sock_fd);
235 				sock_fdcnt = 0;
236 				sock_fd = NULL;
237 				nc_handle = setnetconfig();
238 				attempt_cnt++;
239 			} else if (mallocd_svcport != 0 &&
240 			    attempt_cnt == GETPORT_MAXTRY) {
241 				/*
242 				 * For the last attempt, allow
243 				 * different port #s for each nconf
244 				 * by saving the svcport_str and
245 				 * setting it back to NULL.
246 				 */
247 				port_list = realloc(port_list,
248 				    (port_len + 1) * sizeof(char *));
249 				if (port_list == NULL)
250 					out_of_mem();
251 				port_list[port_len++] = svcport_str;
252 				svcport_str = NULL;
253 				mallocd_svcport = 0;
254 			}
255 		  }
256 	  }
257   }
258 
259   /*
260    * Successfully bound the ports, so call complete_service() to
261    * do the rest of the setup on the service(s).
262    */
263   sock_fdpos = 0;
264   port_pos = 0;
265   nc_handle = setnetconfig();
266   while ((nconf = getnetconfig(nc_handle))) {
267 	  /* We want to listen only on udp6, tcp6, udp, tcp transports */
268 	  if (nconf->nc_flag & NC_VISIBLE) {
269 		  /* Skip if there's no IPv6 support */
270 		  if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
271 	      /* DO NOTHING */
272 		  } else if (port_list != NULL) {
273 			if (port_pos >= port_len) {
274 				syslog(LOG_ERR, "too many port#s");
275 				exit(1);
276 			}
277 			complete_service(nconf, port_list[port_pos++]);
278 		  } else
279 			complete_service(nconf, svcport_str);
280 	  }
281   }
282   endnetconfig(nc_handle);
283   free(sock_fd);
284   if (port_list != NULL) {
285   	for (port_pos = 0; port_pos < port_len; port_pos++)
286   		free(port_list[port_pos]);
287   	free(port_list);
288   }
289 
290   init_file("/var/db/statd.status");
291 
292   /* Note that it is NOT sensible to run this program from inetd - the 	*/
293   /* protocol assumes that it will run immediately at boot time.	*/
294   if ((foreground == 0) && daemon(0, 0) < 0) {
295   	err(1, "cannot fork");
296   	/* NOTREACHED */
297   }
298 
299   openlog("rpc.statd", 0, LOG_DAEMON);
300   if (debug) syslog(LOG_INFO, "Starting - debug enabled");
301   else syslog(LOG_INFO, "Starting");
302 
303   /* Install signal handler to collect exit status of child processes	*/
304   sa.sa_handler = handle_sigchld;
305   sigemptyset(&sa.sa_mask);
306   sigaddset(&sa.sa_mask, SIGCHLD);
307   sa.sa_flags = SA_RESTART;
308   sigaction(SIGCHLD, &sa, NULL);
309 
310   /* Initialisation now complete - start operating			*/
311   notify_hosts();	/* Forks a process (if necessary) to do the	*/
312 			/* SM_NOTIFY calls, which may be slow.		*/
313 
314   svc_run();	/* Should never return					*/
315   exit(1);
316 }
317 
318 /*
319  * This routine creates and binds sockets on the appropriate
320  * addresses. It gets called one time for each transport.
321  * It returns 0 upon success, 1 for ignore the call and -1 to indicate
322  * bind failed with EADDRINUSE.
323  * Any file descriptors that have been created are stored in sock_fd and
324  * the total count of them is maintained in sock_fdcnt.
325  */
326 static int
create_service(struct netconfig * nconf)327 create_service(struct netconfig *nconf)
328 {
329 	struct addrinfo hints, *res = NULL;
330 	struct sockaddr_in *sin;
331 	struct sockaddr_in6 *sin6;
332 	struct __rpc_sockinfo si;
333 	int aicode;
334 	int fd;
335 	int nhostsbak;
336 	int r;
337 	u_int32_t host_addr[4];  /* IPv4 or IPv6 */
338 	int mallocd_res;
339 
340 	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
341 	    (nconf->nc_semantics != NC_TPI_COTS) &&
342 	    (nconf->nc_semantics != NC_TPI_COTS_ORD))
343 		return (1);	/* not my type */
344 
345 	/*
346 	 * XXX - using RPC library internal functions.
347 	 */
348 	if (!__rpc_nconf2sockinfo(nconf, &si)) {
349 		syslog(LOG_ERR, "cannot get information for %s",
350 		    nconf->nc_netid);
351 		return (1);
352 	}
353 
354 	/* Get rpc.statd's address on this transport */
355 	memset(&hints, 0, sizeof hints);
356 	hints.ai_family = si.si_af;
357 	hints.ai_socktype = si.si_socktype;
358 	hints.ai_protocol = si.si_proto;
359 
360 	/*
361 	 * Bind to specific IPs if asked to
362 	 */
363 	nhostsbak = nhosts;
364 	while (nhostsbak > 0) {
365 		--nhostsbak;
366 		sock_fd = realloc(sock_fd, (sock_fdcnt + 1) * sizeof(int));
367 		if (sock_fd == NULL)
368 			out_of_mem();
369 		sock_fd[sock_fdcnt++] = -1;	/* Set invalid for now. */
370 		mallocd_res = 0;
371 		hints.ai_flags = AI_PASSIVE;
372 
373 		/*
374 		 * XXX - using RPC library internal functions.
375 		 */
376 		if ((fd = __rpc_nconf2fd(nconf)) < 0) {
377 			syslog(LOG_ERR, "cannot create socket for %s",
378 			    nconf->nc_netid);
379 			continue;
380 		}
381 		switch (hints.ai_family) {
382 		case AF_INET:
383 			if (inet_pton(AF_INET, hosts[nhostsbak],
384 			    host_addr) == 1) {
385 				hints.ai_flags |= AI_NUMERICHOST;
386 			} else {
387 				/*
388 				 * Skip if we have an AF_INET6 address.
389 				 */
390 				if (inet_pton(AF_INET6, hosts[nhostsbak],
391 				    host_addr) == 1) {
392 					close(fd);
393 					continue;
394 				}
395 			}
396 			break;
397 		case AF_INET6:
398 			if (inet_pton(AF_INET6, hosts[nhostsbak],
399 			    host_addr) == 1) {
400 				hints.ai_flags |= AI_NUMERICHOST;
401 			} else {
402 				/*
403 				 * Skip if we have an AF_INET address.
404 				 */
405 				if (inet_pton(AF_INET, hosts[nhostsbak],
406 				    host_addr) == 1) {
407 					close(fd);
408 					continue;
409 				}
410 			}
411 			break;
412 		default:
413 			break;
414 		}
415 
416 		/*
417 		 * If no hosts were specified, just bind to INADDR_ANY
418 		 */
419 		if (strcmp("*", hosts[nhostsbak]) == 0) {
420 			if (svcport_str == NULL) {
421 				res = malloc(sizeof(struct addrinfo));
422 				if (res == NULL)
423 					out_of_mem();
424 				mallocd_res = 1;
425 				res->ai_flags = hints.ai_flags;
426 				res->ai_family = hints.ai_family;
427 				res->ai_protocol = hints.ai_protocol;
428 				switch (res->ai_family) {
429 				case AF_INET:
430 					sin = malloc(sizeof(struct sockaddr_in));
431 					if (sin == NULL)
432 						out_of_mem();
433 					sin->sin_family = AF_INET;
434 					sin->sin_port = htons(0);
435 					sin->sin_addr.s_addr = htonl(INADDR_ANY);
436 					res->ai_addr = (struct sockaddr*) sin;
437 					res->ai_addrlen = (socklen_t)
438 					    sizeof(struct sockaddr_in);
439 					break;
440 				case AF_INET6:
441 					sin6 = malloc(sizeof(struct sockaddr_in6));
442 					if (sin6 == NULL)
443 						out_of_mem();
444 					sin6->sin6_family = AF_INET6;
445 					sin6->sin6_port = htons(0);
446 					sin6->sin6_addr = in6addr_any;
447 					res->ai_addr = (struct sockaddr*) sin6;
448 					res->ai_addrlen = (socklen_t)
449 					    sizeof(struct sockaddr_in6);
450 					break;
451 				default:
452 					syslog(LOG_ERR, "bad addr fam %d",
453 					    res->ai_family);
454 					exit(1);
455 				}
456 			} else {
457 				if ((aicode = getaddrinfo(NULL, svcport_str,
458 				    &hints, &res)) != 0) {
459 					syslog(LOG_ERR,
460 					    "cannot get local address for %s: %s",
461 					    nconf->nc_netid,
462 					    gai_strerror(aicode));
463 					close(fd);
464 					continue;
465 				}
466 			}
467 		} else {
468 			if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str,
469 			    &hints, &res)) != 0) {
470 				syslog(LOG_ERR,
471 				    "cannot get local address for %s: %s",
472 				    nconf->nc_netid, gai_strerror(aicode));
473 				close(fd);
474 				continue;
475 			}
476 		}
477 
478 		/* Store the fd. */
479 		sock_fd[sock_fdcnt - 1] = fd;
480 
481 		/* Now, attempt the bind. */
482 		r = bindresvport_sa(fd, res->ai_addr);
483 		if (r != 0) {
484 			if (errno == EADDRINUSE && mallocd_svcport != 0) {
485 				if (mallocd_res != 0) {
486 					free(res->ai_addr);
487 					free(res);
488 				} else
489 					freeaddrinfo(res);
490 				return (-1);
491 			}
492 			syslog(LOG_ERR, "bindresvport_sa: %m");
493 			exit(1);
494 		}
495 
496 		if (svcport_str == NULL) {
497 			svcport_str = malloc(NI_MAXSERV * sizeof(char));
498 			if (svcport_str == NULL)
499 				out_of_mem();
500 			mallocd_svcport = 1;
501 
502 			if (getnameinfo(res->ai_addr,
503 			    res->ai_addr->sa_len, NULL, NI_MAXHOST,
504 			    svcport_str, NI_MAXSERV * sizeof(char),
505 			    NI_NUMERICHOST | NI_NUMERICSERV))
506 				errx(1, "Cannot get port number");
507 		}
508 		if (mallocd_res != 0) {
509 			free(res->ai_addr);
510 			free(res);
511 		} else
512 			freeaddrinfo(res);
513 		res = NULL;
514 	}
515 	return (0);
516 }
517 
518 /*
519  * Called after all the create_service() calls have succeeded, to complete
520  * the setup and registration.
521  */
522 static void
complete_service(struct netconfig * nconf,char * port_str)523 complete_service(struct netconfig *nconf, char *port_str)
524 {
525 	struct addrinfo hints, *res = NULL;
526 	struct __rpc_sockinfo si;
527 	struct netbuf servaddr;
528 	SVCXPRT	*transp = NULL;
529 	int aicode, fd, nhostsbak;
530 	int registered = 0;
531 
532 	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
533 	    (nconf->nc_semantics != NC_TPI_COTS) &&
534 	    (nconf->nc_semantics != NC_TPI_COTS_ORD))
535 		return;	/* not my type */
536 
537 	/*
538 	 * XXX - using RPC library internal functions.
539 	 */
540 	if (!__rpc_nconf2sockinfo(nconf, &si)) {
541 		syslog(LOG_ERR, "cannot get information for %s",
542 		    nconf->nc_netid);
543 		return;
544 	}
545 
546 	nhostsbak = nhosts;
547 	while (nhostsbak > 0) {
548 		--nhostsbak;
549 		if (sock_fdpos >= sock_fdcnt) {
550 			/* Should never happen. */
551 			syslog(LOG_ERR, "Ran out of socket fd's");
552 			return;
553 		}
554 		fd = sock_fd[sock_fdpos++];
555 		if (fd < 0)
556 			continue;
557 
558 		if (nconf->nc_semantics != NC_TPI_CLTS)
559 			listen(fd, SOMAXCONN);
560 
561 		transp = svc_tli_create(fd, nconf, NULL,
562 		RPC_MAXDATASIZE, RPC_MAXDATASIZE);
563 
564 		if (transp != (SVCXPRT *) NULL) {
565 			if (!svc_register(transp, SM_PROG, SM_VERS,
566 			    sm_prog_1, 0)) {
567 				syslog(LOG_ERR, "can't register on %s",
568 				    nconf->nc_netid);
569 			} else {
570 				if (!svc_reg(transp, SM_PROG, SM_VERS,
571 				    sm_prog_1, NULL))
572 					syslog(LOG_ERR,
573 					    "can't register %s SM_PROG service",
574 					    nconf->nc_netid);
575 			}
576 		} else
577 			syslog(LOG_WARNING, "can't create %s services",
578 			    nconf->nc_netid);
579 
580 		if (registered == 0) {
581 			registered = 1;
582 			memset(&hints, 0, sizeof hints);
583 			hints.ai_flags = AI_PASSIVE;
584 			hints.ai_family = si.si_af;
585 			hints.ai_socktype = si.si_socktype;
586 			hints.ai_protocol = si.si_proto;
587 
588 
589 			if ((aicode = getaddrinfo(NULL, port_str, &hints,
590 			    &res)) != 0) {
591 				syslog(LOG_ERR, "cannot get local address: %s",
592 				    gai_strerror(aicode));
593 				exit(1);
594 			}
595 
596 			servaddr.buf = malloc(res->ai_addrlen);
597 			memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen);
598 			servaddr.len = res->ai_addrlen;
599 
600 			rpcb_set(SM_PROG, SM_VERS, nconf, &servaddr);
601 
602 			xcreated++;
603 			freeaddrinfo(res);
604 		}
605 	} /* end while */
606 }
607 
608 /*
609  * Clear out sockets after a failure to bind one of them, so that the
610  * cycle of socket creation/binding can start anew.
611  */
612 static void
clearout_service(void)613 clearout_service(void)
614 {
615 	int i;
616 
617 	for (i = 0; i < sock_fdcnt; i++) {
618 		if (sock_fd[i] >= 0) {
619 			shutdown(sock_fd[i], SHUT_RDWR);
620 			close(sock_fd[i]);
621 		}
622 	}
623 }
624 
625 static void
usage(void)626 usage(void)
627 {
628       fprintf(stderr, "usage: rpc.statd [-d] [-F] [-h <bindip>] [-p <port>]\n");
629       exit(1);
630 }
631 
632 /* handle_sigchld ---------------------------------------------------------- */
633 /*
634    Purpose:	Catch SIGCHLD and collect process status
635    Retruns:	Nothing.
636    Notes:	No special action required, other than to collect the
637 		process status and hence allow the child to die:
638 		we only use child processes for asynchronous transmission
639 		of SM_NOTIFY to other systems, so it is normal for the
640 		children to exit when they have done their work.
641 */
642 
handle_sigchld(int sig __unused)643 static void handle_sigchld(int sig __unused)
644 {
645   int pid, status;
646   pid = wait4(-1, &status, WNOHANG, (struct rusage*)0);
647   if (!pid) syslog(LOG_ERR, "Phantom SIGCHLD??");
648   else if (status == 0)
649   {
650     if (debug) syslog(LOG_DEBUG, "Child %d exited OK", pid);
651   }
652   else syslog(LOG_ERR, "Child %d failed with status %d", pid,
653     WEXITSTATUS(status));
654 }
655 
656 /*
657  * Out of memory, fatal
658  */
659 void
out_of_mem(void)660 out_of_mem(void)
661 {
662 
663 	syslog(LOG_ERR, "out of memory");
664 	exit(2);
665 }
666