xref: /openbsd-src/sbin/nfsd/nfsd.c (revision c2a2da96ebbcbfbd0804bf8303a9cb85b0cf2695)
1*c2a2da96Skn /*	$OpenBSD: nfsd.c,v 1.45 2025/01/16 12:46:03 kn Exp $	*/
2be0fe854Sniklas /*	$NetBSD: nfsd.c,v 1.19 1996/02/18 23:18:56 mycroft Exp $	*/
3df930be7Sderaadt 
4df930be7Sderaadt /*
5df930be7Sderaadt  * Copyright (c) 1989, 1993, 1994
6df930be7Sderaadt  *	The Regents of the University of California.  All rights reserved.
7df930be7Sderaadt  *
8df930be7Sderaadt  * This code is derived from software contributed to Berkeley by
9df930be7Sderaadt  * Rick Macklem at The University of Guelph.
10df930be7Sderaadt  *
11df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
12df930be7Sderaadt  * modification, are permitted provided that the following conditions
13df930be7Sderaadt  * are met:
14df930be7Sderaadt  * 1. Redistributions of source code must retain the above copyright
15df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer.
16df930be7Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
17df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer in the
18df930be7Sderaadt  *    documentation and/or other materials provided with the distribution.
191ef0d710Smillert  * 3. Neither the name of the University nor the names of its contributors
20df930be7Sderaadt  *    may be used to endorse or promote products derived from this software
21df930be7Sderaadt  *    without specific prior written permission.
22df930be7Sderaadt  *
23df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24df930be7Sderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25df930be7Sderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26df930be7Sderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27df930be7Sderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28df930be7Sderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29df930be7Sderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30df930be7Sderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31df930be7Sderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32df930be7Sderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33df930be7Sderaadt  * SUCH DAMAGE.
34df930be7Sderaadt  */
35df930be7Sderaadt 
36df930be7Sderaadt #include <sys/ioctl.h>
37df930be7Sderaadt #include <sys/stat.h>
38df930be7Sderaadt #include <sys/wait.h>
39df930be7Sderaadt #include <sys/uio.h>
40df930be7Sderaadt #include <sys/ucred.h>
41df930be7Sderaadt #include <sys/mount.h>
42df930be7Sderaadt #include <sys/socket.h>
43df930be7Sderaadt 
44df930be7Sderaadt #include <rpc/rpc.h>
45df930be7Sderaadt #include <rpc/pmap_clnt.h>
46df930be7Sderaadt #include <rpc/pmap_prot.h>
47df930be7Sderaadt 
48df930be7Sderaadt #include <nfs/rpcv2.h>
49be0fe854Sniklas #include <nfs/nfsproto.h>
50df930be7Sderaadt #include <nfs/nfs.h>
51df930be7Sderaadt 
52df930be7Sderaadt #include <err.h>
53df930be7Sderaadt #include <errno.h>
54df930be7Sderaadt #include <fcntl.h>
55df930be7Sderaadt #include <grp.h>
56df930be7Sderaadt #include <pwd.h>
57df930be7Sderaadt #include <signal.h>
58df930be7Sderaadt #include <stdio.h>
59df930be7Sderaadt #include <stdlib.h>
601d1da20fSmillert #include <string.h>
61be0fe854Sniklas #include <syslog.h>
62df930be7Sderaadt #include <unistd.h>
63df930be7Sderaadt 
64df930be7Sderaadt /* Global defs */
65df930be7Sderaadt #ifdef DEBUG
66c77ed605Smestre #define	syslog(e, s, ...)			\
67c77ed605Smestre do {						\
68c77ed605Smestre 	fprintf(stderr, (s), ##__VA_ARGS__);	\
69c77ed605Smestre 	fprintf(stderr, "\n");			\
70c77ed605Smestre } while (0)
71df930be7Sderaadt int	debug = 1;
72df930be7Sderaadt #else
73df930be7Sderaadt int	debug = 0;
74df930be7Sderaadt #endif
75df930be7Sderaadt 
76df930be7Sderaadt struct	nfsd_srvargs nsd;
77df930be7Sderaadt 
78c72b5b24Smillert void	nonfs(int);
79c72b5b24Smillert void	reapchild(int);
80c72b5b24Smillert void	usage(void);
81df930be7Sderaadt 
821b85ea92Sderaadt #define	MAXNFSDCNT	20
831b85ea92Sderaadt #define	DEFNFSDCNT	 4
841b85ea92Sderaadt 
85df930be7Sderaadt /*
86df930be7Sderaadt  * Nfs server daemon mostly just a user context for nfssvc()
87df930be7Sderaadt  *
88df930be7Sderaadt  * 1 - do file descriptor and signal cleanup
89df930be7Sderaadt  * 2 - fork the nfsd(s)
90df930be7Sderaadt  * 3 - create server socket(s)
91df930be7Sderaadt  * 4 - register socket with portmap
92df930be7Sderaadt  *
93df930be7Sderaadt  * For connectionless protocols, just pass the socket into the kernel via.
94df930be7Sderaadt  * nfssvc().
95df930be7Sderaadt  * For connection based sockets, loop doing accepts. When you get a new
96df930be7Sderaadt  * socket from accept, pass the msgsock into the kernel via. nfssvc().
97df930be7Sderaadt  * The arguments are:
98df930be7Sderaadt  *	-r - reregister with portmapper
99df930be7Sderaadt  *	-t - support tcp nfs clients
100df930be7Sderaadt  *	-u - support udp nfs clients
101df930be7Sderaadt  * followed by "n" which is the number of nfsds' to fork off
102df930be7Sderaadt  */
103df930be7Sderaadt int
104bc52e260Sderaadt main(int argc, char *argv[])
105df930be7Sderaadt {
106df930be7Sderaadt 	struct nfsd_args nfsdargs;
107ec38e1feSchl 	struct sockaddr_in inetaddr;
1085ea00adcSkn 	int ch, i;
10909b20ce0Sthib 	int nfsdcnt = DEFNFSDCNT, on, reregister = 0, sock;
1101b85ea92Sderaadt 	int udpflag = 0, tcpflag = 0, tcpsock;
1111b85ea92Sderaadt 	const char *errstr = NULL;
112df930be7Sderaadt 
1135dae5719Skrw 	/* Start by writing to both console and log. */
1145dae5719Skrw 	openlog("nfsd", LOG_PID | LOG_PERROR, LOG_DAEMON);
1155dae5719Skrw 
116*c2a2da96Skn 	if (unveil("/", "") == -1) {
117*c2a2da96Skn 		syslog(LOG_ERR, "unveil /: %s", strerror(errno));
118*c2a2da96Skn 		return (1);
119*c2a2da96Skn 	}
120*c2a2da96Skn 	if (unveil(NULL, NULL) == -1) {
121*c2a2da96Skn 		syslog(LOG_ERR, "unveil: %s", strerror(errno));
122*c2a2da96Skn 		return (1);
123*c2a2da96Skn 	}
124*c2a2da96Skn 
1251b85ea92Sderaadt 	while ((ch = getopt(argc, argv, "n:rtu")) != -1)
126df930be7Sderaadt 		switch (ch) {
127df930be7Sderaadt 		case 'n':
1281b85ea92Sderaadt 			nfsdcnt = strtonum(optarg, 1, MAXNFSDCNT, &errstr);
1295dae5719Skrw 			if (errstr) {
1305dae5719Skrw 				syslog(LOG_ERR, "nfsd count is %s: %s", errstr, optarg);
1315dae5719Skrw 				return(1);
1325dae5719Skrw 			}
133df930be7Sderaadt 			break;
134df930be7Sderaadt 		case 'r':
135df930be7Sderaadt 			reregister = 1;
136df930be7Sderaadt 			break;
137df930be7Sderaadt 		case 't':
138df930be7Sderaadt 			tcpflag = 1;
139df930be7Sderaadt 			break;
140df930be7Sderaadt 		case 'u':
141df930be7Sderaadt 			udpflag = 1;
142df930be7Sderaadt 			break;
143df930be7Sderaadt 		default:
144df930be7Sderaadt 			usage();
145478f2fecStedu 		}
146df930be7Sderaadt 	argv += optind;
147df930be7Sderaadt 	argc -= optind;
148df930be7Sderaadt 
1499a5c1bb0Skn 	if (!(tcpflag || udpflag))
1509a5c1bb0Skn 		udpflag = 1;
1519a5c1bb0Skn 
152df930be7Sderaadt 	/*
153df930be7Sderaadt 	 * XXX
154df930be7Sderaadt 	 * Backward compatibility, trailing number is the count of daemons.
155df930be7Sderaadt 	 */
156df930be7Sderaadt 	if (argc > 1)
157df930be7Sderaadt 		usage();
158df930be7Sderaadt 	if (argc == 1) {
1591b85ea92Sderaadt 		nfsdcnt = strtonum(argv[0], 1, MAXNFSDCNT, &errstr);
1605dae5719Skrw 		if (errstr) {
1615dae5719Skrw 			syslog(LOG_ERR, "nfsd count is %s: %s", errstr, optarg);
1625dae5719Skrw 			return(1);
1635dae5719Skrw 		}
164df930be7Sderaadt 	}
165df930be7Sderaadt 
166df930be7Sderaadt 	if (debug == 0) {
167df930be7Sderaadt 		daemon(0, 0);
168df930be7Sderaadt 		(void)signal(SIGHUP, SIG_IGN);
169df930be7Sderaadt 		(void)signal(SIGINT, SIG_IGN);
170df930be7Sderaadt 		(void)signal(SIGQUIT, SIG_IGN);
171df930be7Sderaadt 		(void)signal(SIGSYS, nonfs);
172df930be7Sderaadt 	}
173df930be7Sderaadt 	(void)signal(SIGCHLD, reapchild);
174df930be7Sderaadt 
175df930be7Sderaadt 	if (reregister) {
176df930be7Sderaadt 		if (udpflag &&
177be0fe854Sniklas 		    (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) ||
1785dae5719Skrw 		     !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT))) {
179c77ed605Smestre 			syslog(LOG_ERR, "can't register with portmap for UDP (%s).",
180c77ed605Smestre 			    strerror(errno));
1815dae5719Skrw 			return (1);
1825dae5719Skrw 		}
183df930be7Sderaadt 		if (tcpflag &&
184be0fe854Sniklas 		    (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) ||
1855dae5719Skrw 		     !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT))) {
186c77ed605Smestre 			syslog(LOG_ERR, "can't register with portmap for TCP (%s).",
187c77ed605Smestre 			    strerror(errno));
1885dae5719Skrw 			return (1);
1895dae5719Skrw 		}
19066420897Smickey 		return (0);
191df930be7Sderaadt 	}
1925dae5719Skrw 
1935dae5719Skrw 	/* Cut back to writing to log only. */
1945dae5719Skrw 	closelog();
195ae9ae5acSderaadt 	openlog("nfsd", LOG_PID, LOG_DAEMON);
196df930be7Sderaadt 
197df930be7Sderaadt 	for (i = 0; i < nfsdcnt; i++) {
198df930be7Sderaadt 		switch (fork()) {
199df930be7Sderaadt 		case -1:
200c77ed605Smestre 			syslog(LOG_ERR, "fork: %s", strerror(errno));
20166420897Smickey 			return (1);
202df930be7Sderaadt 		case 0:
203df930be7Sderaadt 			break;
204df930be7Sderaadt 		default:
205df930be7Sderaadt 			continue;
206df930be7Sderaadt 		}
207df930be7Sderaadt 
208df930be7Sderaadt 		setproctitle("server");
209df930be7Sderaadt 		nsd.nsd_nfsd = NULL;
210df69c215Sderaadt 		if (nfssvc(NFSSVC_NFSD, &nsd) == -1) {
211c77ed605Smestre 			syslog(LOG_ERR, "nfssvc: %s", strerror(errno));
21266420897Smickey 			return (1);
213df930be7Sderaadt 		}
21466420897Smickey 		return (0);
215df930be7Sderaadt 	}
216df930be7Sderaadt 
217df930be7Sderaadt 	/* If we are serving udp, set up the socket. */
218df930be7Sderaadt 	if (udpflag) {
219df69c215Sderaadt 		if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
220df930be7Sderaadt 			syslog(LOG_ERR, "can't create udp socket");
22166420897Smickey 			return (1);
222df930be7Sderaadt 		}
22384b6bffdSderaadt 		memset(&inetaddr, 0, sizeof inetaddr);
224df930be7Sderaadt 		inetaddr.sin_family = AF_INET;
225df930be7Sderaadt 		inetaddr.sin_addr.s_addr = INADDR_ANY;
226df930be7Sderaadt 		inetaddr.sin_port = htons(NFS_PORT);
227df930be7Sderaadt 		inetaddr.sin_len = sizeof(inetaddr);
2281b85ea92Sderaadt 		if (bind(sock, (struct sockaddr *)&inetaddr,
229df69c215Sderaadt 		    sizeof(inetaddr)) == -1) {
230df930be7Sderaadt 			syslog(LOG_ERR, "can't bind udp addr");
23166420897Smickey 			return (1);
232df930be7Sderaadt 		}
233be0fe854Sniklas 		if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) ||
234be0fe854Sniklas 		    !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT)) {
235df930be7Sderaadt 			syslog(LOG_ERR, "can't register with udp portmap");
23666420897Smickey 			return (1);
237df930be7Sderaadt 		}
238df930be7Sderaadt 		nfsdargs.sock = sock;
239df930be7Sderaadt 		nfsdargs.name = NULL;
240df930be7Sderaadt 		nfsdargs.namelen = 0;
241df69c215Sderaadt 		if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) == -1) {
242df930be7Sderaadt 			syslog(LOG_ERR, "can't Add UDP socket");
24366420897Smickey 			return (1);
244df930be7Sderaadt 		}
245df930be7Sderaadt 		(void)close(sock);
246df930be7Sderaadt 	}
247df930be7Sderaadt 
248df930be7Sderaadt 	/* Now set up the master server socket waiting for tcp connections. */
249df930be7Sderaadt 	on = 1;
2505ea00adcSkn 	if (!tcpflag)
2515ea00adcSkn 		return (0);
2525ea00adcSkn 
253df69c215Sderaadt 	if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
254df930be7Sderaadt 		syslog(LOG_ERR, "can't create tcp socket");
25566420897Smickey 		return (1);
256df930be7Sderaadt 	}
257df930be7Sderaadt 	if (setsockopt(tcpsock,
258df69c215Sderaadt 	    SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)
259c77ed605Smestre 		syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %s", strerror(errno));
26084b6bffdSderaadt 	memset(&inetaddr, 0, sizeof inetaddr);
261df930be7Sderaadt 	inetaddr.sin_family = AF_INET;
262df930be7Sderaadt 	inetaddr.sin_addr.s_addr = INADDR_ANY;
263df930be7Sderaadt 	inetaddr.sin_port = htons(NFS_PORT);
264df930be7Sderaadt 	inetaddr.sin_len = sizeof(inetaddr);
2651b85ea92Sderaadt 	if (bind(tcpsock, (struct sockaddr *)&inetaddr,
266df69c215Sderaadt 	    sizeof (inetaddr)) == -1) {
267df930be7Sderaadt 		syslog(LOG_ERR, "can't bind tcp addr");
26866420897Smickey 		return (1);
269df930be7Sderaadt 	}
270df69c215Sderaadt 	if (listen(tcpsock, 5) == -1) {
271df930be7Sderaadt 		syslog(LOG_ERR, "listen failed");
27266420897Smickey 		return (1);
273df930be7Sderaadt 	}
274be0fe854Sniklas 	if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) ||
275be0fe854Sniklas 	    !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT)) {
276df930be7Sderaadt 		syslog(LOG_ERR, "can't register tcp with portmap");
27766420897Smickey 		return (1);
278df930be7Sderaadt 	}
279df930be7Sderaadt 
280df930be7Sderaadt 	setproctitle("master");
281df930be7Sderaadt 
282df930be7Sderaadt 	/*
283df930be7Sderaadt 	 * Loop forever accepting connections and passing the sockets
284df930be7Sderaadt 	 * into the kernel for the mounts.
285df930be7Sderaadt 	 */
286df930be7Sderaadt 	for (;;) {
287df0b39aaStedu 		struct sockaddr_in	inetpeer;
288df0b39aaStedu 		int ret, msgsock;
2895ea00adcSkn 		socklen_t len = sizeof(inetpeer);
290df0b39aaStedu 
291df930be7Sderaadt 		if ((msgsock = accept(tcpsock,
292df69c215Sderaadt 		    (struct sockaddr *)&inetpeer, &len)) == -1) {
29362e3c252Sderaadt 			if (errno == EWOULDBLOCK || errno == EINTR ||
29462e3c252Sderaadt 			    errno == ECONNABORTED)
29562e3c252Sderaadt 				continue;
296c77ed605Smestre 			syslog(LOG_ERR, "accept failed: %s", strerror(errno));
29766420897Smickey 			return (1);
298df930be7Sderaadt 		}
299df930be7Sderaadt 		memset(inetpeer.sin_zero, 0, sizeof(inetpeer.sin_zero));
300df930be7Sderaadt 		if (setsockopt(msgsock, SOL_SOCKET,
301df69c215Sderaadt 		    SO_KEEPALIVE, &on, sizeof(on)) == -1)
302df930be7Sderaadt 			syslog(LOG_ERR,
303c77ed605Smestre 			    "setsockopt SO_KEEPALIVE: %s", strerror(errno));
304df930be7Sderaadt 		nfsdargs.sock = msgsock;
305df930be7Sderaadt 		nfsdargs.name = (caddr_t)&inetpeer;
3065ea00adcSkn 		nfsdargs.namelen = len;
307df69c215Sderaadt 		if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) == -1) {
30809b20ce0Sthib 			syslog(LOG_ERR, "can't Add TCP socket");
30909b20ce0Sthib 		}
310df930be7Sderaadt 		(void)close(msgsock);
311df930be7Sderaadt 	}
312df930be7Sderaadt }
313df930be7Sderaadt 
314df930be7Sderaadt void
315bc52e260Sderaadt usage(void)
316df930be7Sderaadt {
3171b85ea92Sderaadt 	(void)fprintf(stderr, "usage: nfsd [-rtu] [-n num_servers]\n");
318df930be7Sderaadt 	exit(1);
319df930be7Sderaadt }
320df930be7Sderaadt 
321df930be7Sderaadt void
322bc52e260Sderaadt nonfs(int signo)
323df930be7Sderaadt {
324bc52e260Sderaadt 	int save_errno = errno;
325bc52e260Sderaadt 	struct syslog_data sdata = SYSLOG_DATA_INIT;
326bc52e260Sderaadt 
327bc52e260Sderaadt 	syslog_r(LOG_ERR, &sdata, "missing system call: NFS not available.");
328bc52e260Sderaadt 	errno = save_errno;
329df930be7Sderaadt }
330df930be7Sderaadt 
331df930be7Sderaadt void
332bc52e260Sderaadt reapchild(int signo)
333df930be7Sderaadt {
3346dccf94eSderaadt 	int save_errno = errno;
335df930be7Sderaadt 
3366dccf94eSderaadt 	while (wait3(NULL, WNOHANG, NULL) > 0)
337252fb110Stedu 		continue;
3386dccf94eSderaadt 	errno = save_errno;
339df930be7Sderaadt }
340