1/*	$NetBSD: nfsd.c,v 1.74 2021/11/27 22:30:25 rillig Exp $	*/
2
3/*
4 * Copyright (c) 1989, 1993, 1994
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Rick Macklem at The University of Guelph.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its 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 THE REGENTS 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 REGENTS 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#include <sys/cdefs.h>
36#ifndef lint
37__COPYRIGHT("@(#) Copyright (c) 1989, 1993, 1994\
38 The Regents of the University of California.  All rights reserved.");
39#endif /* not lint */
40
41#ifndef lint
42#if 0
43static char sccsid[] = "@(#)nfsd.c	8.9 (Berkeley) 3/29/95";
44#else
45__RCSID("$NetBSD: nfsd.c,v 1.74 2021/11/27 22:30:25 rillig Exp $");
46#endif
47#endif /* not lint */
48
49#include <sys/param.h>
50#include <sys/ioctl.h>
51#include <sys/stat.h>
52#include <sys/wait.h>
53#include <sys/uio.h>
54#include <sys/ucred.h>
55#include <sys/mount.h>
56#include <sys/socket.h>
57#include <sys/socketvar.h>
58#include <poll.h>
59
60#include <rpc/rpc.h>
61#include <rpc/pmap_clnt.h>
62#include <rpc/pmap_prot.h>
63
64#include <nfs/rpcv2.h>
65#include <nfs/nfsproto.h>
66#include <nfs/nfs.h>
67
68#include <err.h>
69#include <errno.h>
70#include <fcntl.h>
71#include <grp.h>
72#include <paths.h>
73#include <pwd.h>
74#include <pthread.h>
75#include <signal.h>
76#include <stdio.h>
77#include <stdlib.h>
78#include <string.h>
79#include <syslog.h>
80#include <unistd.h>
81#include <netdb.h>
82
83#ifdef NFSD_RUMP
84#include <rump/rump.h>
85#include <rump/rump_syscallshotgun.h>
86#include <rump/rump_syscalls.h>
87
88#define nfssvc(a, b) rump_sys_nfssvc((a), (b))
89#define close(a)	rump_sys_close(a)
90#define poll(a, b, c) rump_sys_poll((a), (b), (c))
91#if 0
92#define socket(a, b, c) rump_sys_socket((a), (b), (c))
93#define setsockopt(a, b, c, d, e) rump_sys_setsockopt((a), (b), (c), (d), (e))
94#define bind(a, b, c) rump_sys_bind((a), (b), (c))
95#define listen(a, b) rump_sys_listen((a), (b))
96#define accept(a, b, c) rump_sys_accept((a), (b), (c))
97#endif
98#define main nfsd_main
99int nfsd_main(int, char *[]);
100#endif
101
102/* Global defs */
103#if defined(DEBUG) || defined(NFSD_RUMP)
104static int	debug = 1;
105#else
106static int	debug = 0;
107#endif
108
109#define	logit(e, s, args...)						\
110do {									\
111	if (debug) {							\
112		fprintf(stderr,(s), ## args);				\
113		fprintf(stderr, "\n");					\
114	} else {							\
115		syslog(e, s, ## args);					\
116	}								\
117} while (0)
118
119static void	nonfs(int);
120__dead static void	usage(void);
121
122static void *
123worker(void *dummy)
124{
125	struct	nfsd_srvargs nsd;
126	int nfssvc_flag;
127
128	pthread_setname_np(pthread_self(), "slave", NULL);
129	nfssvc_flag = NFSSVC_NFSD;
130	memset(&nsd, 0, sizeof(nsd));
131	while (nfssvc(nfssvc_flag, &nsd) == -1) {
132		if (errno != ENEEDAUTH) {
133			logit(LOG_ERR, "nfssvc: %s", strerror(errno));
134			exit(EXIT_FAILURE);
135		}
136		nfssvc_flag = NFSSVC_NFSD | NFSSVC_AUTHINFAIL;
137	}
138
139	return NULL;
140}
141
142struct conf {
143	struct addrinfo *ai;
144	struct netconfig *nc;
145	struct netbuf nb;
146	struct pollfd pfd;
147};
148
149#define NFS_UDP4	0
150#define NFS_TCP4	1
151#define NFS_UDP6	2
152#define NFS_TCP6	3
153
154static int cfg_family[] = { PF_INET, PF_INET, PF_INET6, PF_INET6 };
155static const char *cfg_netconf[] = { "udp", "tcp", "udp6", "tcp6" };
156static int cfg_socktype[] = {
157    SOCK_DGRAM, SOCK_STREAM, SOCK_DGRAM, SOCK_STREAM };
158static int cfg_protocol[] = {
159    IPPROTO_UDP, IPPROTO_TCP, IPPROTO_UDP, IPPROTO_TCP };
160
161static int
162tryconf(struct conf *cfg, int t, int reregister)
163{
164	struct addrinfo hints;
165	int ecode;
166
167	memset(&hints, 0, sizeof hints);
168	hints.ai_flags = AI_PASSIVE;
169	hints.ai_family = cfg_family[t];
170	hints.ai_socktype = cfg_socktype[t];
171	hints.ai_protocol = cfg_protocol[t];
172
173	ecode = getaddrinfo(NULL, "nfs", &hints, &cfg->ai);
174	if (ecode != 0) {
175		logit(LOG_ERR, "getaddrinfo %s: %s", cfg_netconf[t],
176		    gai_strerror(ecode));
177		return -1;
178	}
179
180	cfg->nc = getnetconfigent(cfg_netconf[t]);
181
182	if (cfg->nc == NULL) {
183		logit(LOG_ERR, "getnetconfigent %s failed: %s",
184		    cfg_netconf[t], strerror(errno));
185		goto out;
186	}
187
188	cfg->nb.buf = cfg->ai->ai_addr;
189	cfg->nb.len = cfg->nb.maxlen = cfg->ai->ai_addrlen;
190	if (reregister)
191		if (!rpcb_set(RPCPROG_NFS, 2, cfg->nc, &cfg->nb)) {
192			logit(LOG_ERR, "rpcb_set %s failed", cfg_netconf[t]);
193			goto out1;
194		}
195	return 0;
196out1:
197	freenetconfigent(cfg->nc);
198	cfg->nc = NULL;
199out:
200	freeaddrinfo(cfg->ai);
201	cfg->ai = NULL;
202	return -1;
203}
204
205static int
206setupsock(struct conf *cfg, struct pollfd *set, int p)
207{
208	int sock;
209	struct nfsd_args nfsdargs;
210	struct addrinfo *ai = cfg->ai;
211	int on = 1;
212
213	sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
214
215	if (sock == -1) {
216		logit(LOG_ERR, "can't create %s socket: %s", cfg_netconf[p],
217		    strerror(errno));
218		return -1;
219	}
220	if (cfg_family[p] == PF_INET6) {
221		if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on,
222		    sizeof(on)) == -1) {
223			logit(LOG_ERR, "can't set v6-only binding for %s "
224			    "socket: %s", cfg_netconf[p], strerror(errno));
225			goto out;
226		}
227	}
228
229	if (cfg_protocol[p] == IPPROTO_TCP) {
230		if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on,
231		    sizeof(on)) == -1) {
232			logit(LOG_ERR, "setsockopt SO_REUSEADDR for %s: %s",
233			    cfg_netconf[p], strerror(errno));
234			goto out;
235		}
236	}
237
238	if (bind(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
239		logit(LOG_ERR, "can't bind %s addr: %s", cfg_netconf[p],
240		    strerror(errno));
241		goto out;
242	}
243
244	if (cfg_protocol[p] == IPPROTO_TCP) {
245		if (listen(sock, 5) == -1) {
246			logit(LOG_ERR, "listen failed");
247			goto out;
248		}
249	}
250
251	if (!rpcb_set(RPCPROG_NFS, 2, cfg->nc, &cfg->nb) ||
252	    !rpcb_set(RPCPROG_NFS, 3, cfg->nc, &cfg->nb)) {
253		logit(LOG_ERR, "can't register with %s portmap",
254		    cfg_netconf[p]);
255		goto out;
256	}
257
258
259	if (cfg_protocol[p] == IPPROTO_TCP)
260		set->fd = sock;
261	else {
262		nfsdargs.sock = sock;
263		nfsdargs.name = NULL;
264		nfsdargs.namelen = 0;
265		if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) == -1) {
266			logit(LOG_ERR, "can't add %s socket: %s",
267			    cfg_netconf[p], strerror(errno));
268			goto out;
269		}
270		(void)close(sock);
271	}
272	return 0;
273out:
274	(void)close(sock);
275	return -1;
276}
277
278/*
279 * The functions daemon2_fork() and daemon2_detach() below provide
280 * functionality similar to daemon(3) but split into two phases.
281 * daemon2_fork() is called early, before creating resources that
282 * cannot be inherited across a fork, such as threads or kqueues.
283 * When the daemon is ready to provide service, daemon2_detach()
284 * is called to complete the daemonization and signal the parent
285 * process to exit.
286 *
287 * These functions could potentially be moved to a library and
288 * shared by other daemons.
289 *
290 * The return value from daemon2_fork() is a file descriptor to
291 * be passed as the first argument to daemon2_detach().
292 */
293
294static int
295daemon2_fork(void)
296{
297	 int i;
298	 int fd;
299	 int r;
300	 pid_t pid;
301	 int detach_msg_pipe[2];
302
303	 /*
304	  * Set up a pipe for signalling the parent, making sure the
305	  * write end does not get allocated one of the file
306	  * descriptors that may be closed in daemon2_detach().  The
307	  * read end does not need such protection.
308	  */
309	 for (i = 0; i < 3; i++) {
310		 r = pipe2(detach_msg_pipe, O_CLOEXEC|O_NOSIGPIPE);
311		 if (r == -1)
312			 return -1;
313		 if (detach_msg_pipe[1] <= STDERR_FILENO &&
314		     (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
315			 (void)dup2(fd, detach_msg_pipe[0]);
316			 (void)dup2(fd, detach_msg_pipe[1]);
317			 if (fd > STDERR_FILENO)
318				 (void)close(fd);
319			 continue;
320		 }
321		 break;
322	 }
323
324	 pid = fork();
325	 switch (pid) {
326	 case -1:
327		return -1;
328	 case 0:
329		/* child */
330		(void)close(detach_msg_pipe[0]);
331		return detach_msg_pipe[1];
332	 default:
333		break;
334	}
335
336	/* Parent */
337	(void)close(detach_msg_pipe[1]);
338
339	for (;;) {
340		ssize_t nread;
341		char dummy;
342		nread = read(detach_msg_pipe[0], &dummy, 1);
343		if (nread == -1) {
344			if (errno == EINTR)
345				continue;
346			_exit(EXIT_FAILURE);
347		} else if (nread == 0) {
348			_exit(EXIT_FAILURE);
349		} else { /* nread > 0 */
350			_exit(EXIT_SUCCESS);
351		}
352	}
353}
354
355static int
356daemon2_detach(int parentfd, int nochdir, int noclose)
357{
358	int fd;
359
360	if (setsid() == -1)
361		return -1;
362
363	if (!nochdir)
364		(void)chdir("/");
365
366	if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
367		(void)dup2(fd, STDIN_FILENO);
368		(void)dup2(fd, STDOUT_FILENO);
369		(void)dup2(fd, STDERR_FILENO);
370		if (fd > STDERR_FILENO)
371			(void)close(fd);
372	}
373
374	while (1) {
375		ssize_t r = write(parentfd, "", 1);
376		if (r == -1) {
377			if (errno == EINTR)
378				continue;
379			else if (errno == EPIPE)
380				break;
381			else
382				return -1;
383		} else if (r == 0) {
384			/* Should not happen */
385			return -1;
386		} else {
387			break;
388		}
389	}
390
391	(void)close(parentfd);
392
393	return 0;
394}
395
396/*
397 * Nfs server daemon mostly just a user context for nfssvc()
398 *
399 * 1 - do file descriptor and signal cleanup
400 * 2 - create the nfsd thread(s)
401 * 3 - create server socket(s)
402 * 4 - register socket with portmap
403 *
404 * For connectionless protocols, just pass the socket into the kernel via
405 * nfssvc().
406 * For connection based sockets, loop doing accepts. When you get a new
407 * socket from accept, pass the msgsock into the kernel via nfssvc().
408 * The arguments are:
409 *	-r - reregister with portmapper
410 *	-t - support only tcp nfs clients
411 *	-u - support only udp nfs clients
412 *	-n num how many threads to create.
413 *	-4 - use only ipv4
414 *	-6 - use only ipv6
415 */
416int
417main(int argc, char *argv[])
418{
419	struct conf cfg[4];
420	struct pollfd set[__arraycount(cfg)];
421	int ch, connect_type_cnt;
422	size_t i, nfsdcnt;
423	int reregister;
424	int tcpflag, udpflag;
425	int ip6flag, ip4flag;
426	int s, compat;
427	int parent_fd = -1;
428	pthread_t *workers;
429
430#define	DEFNFSDCNT	 4
431	nfsdcnt = DEFNFSDCNT;
432	compat = reregister = 0;
433	tcpflag = udpflag = 1;
434	ip6flag = ip4flag = 1;
435#define	GETOPT	"46dn:rtu"
436#define	USAGE	"[-46drtu] [-n num_servers]"
437	while ((ch = getopt(argc, argv, GETOPT)) != -1) {
438		switch (ch) {
439		case '6':
440			ip6flag = 1;
441			ip4flag = 0;
442			s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
443			if (s == -1 && (errno == EPROTONOSUPPORT ||
444			    errno == EPFNOSUPPORT || errno == EAFNOSUPPORT))
445				ip6flag = 0;
446			else
447				close(s);
448			break;
449		case '4':
450			ip6flag = 0;
451			ip4flag = 1;
452			s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
453			if (s == -1 && (errno == EPROTONOSUPPORT ||
454			    errno == EPFNOSUPPORT || errno == EAFNOSUPPORT))
455				ip4flag = 0;
456			else
457				close(s);
458			break;
459		case 'd':
460			debug++;
461			break;
462		case 'n':
463			nfsdcnt = atoi(optarg);
464			if (nfsdcnt < 1) {
465				warnx("nfsd count %zu; reset to %d", nfsdcnt,
466				    DEFNFSDCNT);
467				nfsdcnt = DEFNFSDCNT;
468			}
469			break;
470		case 'r':
471			reregister = 1;
472			break;
473		case 't':
474			compat |= 2;
475			tcpflag = 1;
476			udpflag = 0;
477			break;
478		case 'u':
479			compat |= 1;
480			tcpflag = 0;
481			udpflag = 1;
482			break;
483		default:
484		case '?':
485			usage();
486		}
487	}
488	argv += optind;
489	argc -= optind;
490
491	if (compat == 3) {
492		warnx("Old -tu options detected; enabling both udp and tcp.");
493		warnx("This is the default behavior now and you can remove");
494		warnx("all options.");
495		tcpflag = udpflag = 1;
496		if (ip6flag == 1 && ip4flag == 0)
497			ip4flag = 1;
498	}
499
500	if (debug == 0) {
501		parent_fd = daemon2_fork();
502		if (parent_fd == -1)
503			logit(LOG_ERR, "daemon2_fork failed");
504		openlog("nfsd", LOG_PID, LOG_DAEMON);
505	}
506
507
508	memset(cfg, 0, sizeof(cfg));
509	for (i = 0; i < __arraycount(cfg); i++) {
510		if (ip4flag == 0 && cfg_family[i] == PF_INET)
511			continue;
512		if (ip6flag == 0 && cfg_family[i] == PF_INET6)
513			continue;
514		if (tcpflag == 0 && cfg_protocol[i] == IPPROTO_TCP)
515			continue;
516		if (udpflag == 0 && cfg_protocol[i] == IPPROTO_UDP)
517			continue;
518		tryconf(&cfg[i], i, reregister);
519	}
520
521	workers = calloc(nfsdcnt, sizeof(*workers));
522	if (workers == NULL) {
523		logit(LOG_ERR, "thread alloc %s", strerror(errno));
524		exit(EXIT_FAILURE);
525	}
526
527	for (i = 0; i < nfsdcnt; i++) {
528		int error;
529
530		error = pthread_create(&workers[i], NULL, worker, NULL);
531		if (error) {
532			errno = error;
533			logit(LOG_ERR, "pthread_create: %s", strerror(errno));
534			exit(EXIT_FAILURE);
535		}
536	}
537
538	connect_type_cnt = 0;
539	for (i = 0; i < __arraycount(cfg); i++) {
540		set[i].fd = -1;
541		set[i].events = POLLIN;
542		set[i].revents = 0;
543
544		if (cfg[i].nc == NULL)
545			continue;
546
547		setupsock(&cfg[i], &set[i], i);
548		if (set[i].fd != -1)
549			connect_type_cnt++;
550	}
551
552	pthread_setname_np(pthread_self(), "master", NULL);
553
554	if (debug == 0) {
555		daemon2_detach(parent_fd, 0, 0);
556		(void)signal(SIGHUP, SIG_IGN);
557		(void)signal(SIGINT, SIG_IGN);
558		(void)signal(SIGQUIT, SIG_IGN);
559		(void)signal(SIGSYS, nonfs);
560	}
561
562	if (connect_type_cnt == 0) {
563		for (i = 0; i < nfsdcnt; i++)
564			    pthread_join(workers[i], NULL);
565		exit(EXIT_SUCCESS);
566	}
567
568	/*
569	 * Loop forever accepting connections and passing the sockets
570	 * into the kernel for the mounts.
571	 */
572	for (;;) {
573		if (poll(set, __arraycount(set), INFTIM) == -1) {
574			logit(LOG_ERR, "poll failed: %s", strerror(errno));
575			exit(EXIT_FAILURE);
576		}
577
578		for (i = 0; i < __arraycount(set); i++) {
579			struct nfsd_args nfsdargs;
580			struct sockaddr_storage ss;
581			socklen_t len;
582			int msgsock;
583			int on = 1;
584
585			if ((set[i].revents & POLLIN) == 0)
586				continue;
587			len = sizeof(ss);
588			if ((msgsock = accept(set[i].fd,
589			    (struct sockaddr *)&ss, &len)) == -1) {
590				int serrno = errno;
591				logit(LOG_ERR, "accept failed: %s",
592				    strerror(errno));
593				if (serrno == EINTR || serrno == ECONNABORTED)
594					continue;
595				exit(EXIT_FAILURE);
596			}
597			if (setsockopt(msgsock, SOL_SOCKET, SO_KEEPALIVE, &on,
598			    sizeof(on)) == -1)
599				logit(LOG_ERR, "setsockopt SO_KEEPALIVE: %s",
600				    strerror(errno));
601			nfsdargs.sock = msgsock;
602			nfsdargs.name = (void *)&ss;
603			nfsdargs.namelen = len;
604			nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
605			(void)close(msgsock);
606		}
607	}
608}
609
610static void
611usage(void)
612{
613	(void)fprintf(stderr, "Usage: %s %s\n", getprogname(), USAGE);
614	exit(EXIT_FAILURE);
615}
616
617static void
618nonfs(int signo)
619{
620	logit(LOG_ERR, "missing system call: NFS not available.");
621}
622