1/*	$NetBSD: nfsd.c,v 1.2 2010/07/27 14:04:47 macallan 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.2 2010/07/27 14:04:47 macallan 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 <pwd.h>
73#include <pthread.h>
74#include <signal.h>
75#include <stdio.h>
76#include <stdlib.h>
77#include <string.h>
78#include <syslog.h>
79#include <unistd.h>
80#include <netdb.h>
81
82#include <rump/rump.h>
83#include <rump/rump_syscalls.h>
84
85/* Global defs */
86#ifdef DEBUG
87#define	syslog(e, s, args...)						\
88do {									\
89    fprintf(stderr,(s), ## args); 					\
90    fprintf(stderr, "\n");						\
91} while (/*CONSTCOND*/0)
92int	debug = 1;
93#else
94int	debug = 0;
95#endif
96
97int	main __P((int, char **));
98void	nonfs __P((int));
99void	usage __P((void));
100
101static void *
102child(void *arg)
103{
104	struct	nfsd_srvargs nsd;
105	int nfssvc_flag;
106
107	nfssvc_flag = NFSSVC_NFSD;
108	memset(&nsd, 0, sizeof(nsd));
109	while (rump_sys_nfssvc(nfssvc_flag, &nsd) < 0) {
110		if (errno != ENEEDAUTH) {
111			syslog(LOG_ERR, "nfssvc: %m %d", errno);
112			exit(1);
113		}
114		nfssvc_flag = NFSSVC_NFSD | NFSSVC_AUTHINFAIL;
115	}
116
117	return NULL;
118}
119
120/*
121 * Nfs server daemon mostly just a user context for nfssvc()
122 *
123 * 1 - do file descriptor and signal cleanup
124 * 2 - create the nfsd thread(s)
125 * 3 - create server socket(s)
126 * 4 - register socket with portmap
127 *
128 * For connectionless protocols, just pass the socket into the kernel via
129 * nfssvc().
130 * For connection based sockets, loop doing accepts. When you get a new
131 * socket from accept, pass the msgsock into the kernel via nfssvc().
132 * The arguments are:
133 *	-c - support iso cltp clients
134 *	-r - reregister with portmapper
135 *	-t - support tcp nfs clients
136 *	-u - support udp nfs clients
137 * followed by "n" which is the number of nfsd threads to create
138 */
139int nfsd_main(int, char**);
140int
141nfsd_main(argc, argv)
142	int argc;
143	char *argv[];
144{
145	struct nfsd_args nfsdargs;
146	struct addrinfo *ai_udp, *ai_tcp, *ai_udp6, *ai_tcp6, hints;
147	struct netconfig *nconf_udp, *nconf_tcp, *nconf_udp6, *nconf_tcp6;
148	struct netbuf nb_udp, nb_tcp, nb_udp6, nb_tcp6;
149	struct sockaddr_in inetpeer;
150	struct pollfd set[4];
151	socklen_t len;
152	int ch, cltpflag, connect_type_cnt, i, maxsock, msgsock;
153	int nfsdcnt, on = 1, reregister, sock, tcpflag, tcpsock;
154	int tcp6sock, ip6flag;
155	int tp4cnt, tp4flag, tpipcnt, tpipflag, udpflag, ecode, s;
156	int error = 0;
157
158#define	DEFNFSDCNT	 4
159	nfsdcnt = DEFNFSDCNT;
160	cltpflag = reregister = tcpflag = tp4cnt = tp4flag = tpipcnt = 0;
161	tpipflag = udpflag = ip6flag = 0;
162	nconf_udp = nconf_tcp = nconf_udp6 = nconf_tcp6 = NULL;
163	maxsock = 0;
164	tcpsock = tcp6sock = -1;
165#define	GETOPT	"6n:rtu"
166#define	USAGE	"[-rtu] [-n num_servers]"
167	while ((ch = getopt(argc, argv, GETOPT)) != -1) {
168		switch (ch) {
169		case '6':
170			ip6flag = 1;
171			s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
172			if (s < 0 && (errno == EPROTONOSUPPORT ||
173			    errno == EPFNOSUPPORT || errno == EAFNOSUPPORT))
174				ip6flag = 0;
175			else
176				close(s);
177			break;
178		case 'n':
179			nfsdcnt = atoi(optarg);
180			if (nfsdcnt < 1) {
181				warnx("nfsd count %d; reset to %d", nfsdcnt, DEFNFSDCNT);
182				nfsdcnt = DEFNFSDCNT;
183			}
184			break;
185		case 'r':
186			reregister = 1;
187			break;
188		case 't':
189			tcpflag = 1;
190			break;
191		case 'u':
192			udpflag = 1;
193			break;
194		default:
195		case '?':
196			usage();
197		};
198	}
199	argv += optind;
200	argc -= optind;
201
202	/*
203	 * XXX
204	 * Backward compatibility, trailing number is the count of daemons.
205	 */
206	if (argc > 1)
207		usage();
208	if (argc == 1) {
209		nfsdcnt = atoi(argv[0]);
210		if (nfsdcnt < 1) {
211			warnx("nfsd count %d; reset to %d", nfsdcnt, DEFNFSDCNT);
212			nfsdcnt = DEFNFSDCNT;
213		}
214	}
215
216	/*
217	 * If none of TCP or UDP are specified, default to UDP only.
218	 */
219	if (tcpflag == 0 && udpflag == 0)
220		udpflag = 1;
221
222	if (debug == 0) {
223		fprintf(stderr, "non-debug not supported here\n");
224		exit(1);
225
226#ifdef not_the_debug_man
227		daemon(0, 0);
228		(void)signal(SIGHUP, SIG_IGN);
229		(void)signal(SIGINT, SIG_IGN);
230		(void)signal(SIGQUIT, SIG_IGN);
231		(void)signal(SIGSYS, nonfs);
232#endif
233	}
234
235	if (udpflag) {
236		memset(&hints, 0, sizeof hints);
237		hints.ai_flags = AI_PASSIVE;
238		hints.ai_family = PF_INET;
239		hints.ai_socktype = SOCK_DGRAM;
240		hints.ai_protocol = IPPROTO_UDP;
241
242		ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp);
243		if (ecode != 0) {
244			syslog(LOG_ERR, "getaddrinfo udp: %s",
245			    gai_strerror(ecode));
246			exit(1);
247		}
248
249		nconf_udp = getnetconfigent("udp");
250
251		if (nconf_udp == NULL)
252			err(1, "getnetconfigent udp failed");
253
254		nb_udp.buf = ai_udp->ai_addr;
255		nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen;
256		if (reregister)
257			if (!rpcb_set(RPCPROG_NFS, 2, nconf_udp, &nb_udp))
258				err(1, "rpcb_set udp failed");
259	}
260
261	if (tcpflag) {
262		memset(&hints, 0, sizeof hints);
263		hints.ai_flags = AI_PASSIVE;
264		hints.ai_family = PF_INET;
265		hints.ai_socktype = SOCK_STREAM;
266		hints.ai_protocol = IPPROTO_TCP;
267
268		ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp);
269		if (ecode != 0) {
270			syslog(LOG_ERR, "getaddrinfo tcp: %s",
271			    gai_strerror(ecode));
272			exit(1);
273		}
274
275		nconf_tcp = getnetconfigent("tcp");
276
277		if (nconf_tcp == NULL)
278			err(1, "getnetconfigent tcp failed");
279
280		nb_tcp.buf = ai_tcp->ai_addr;
281		nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen;
282		if (reregister)
283			if (!rpcb_set(RPCPROG_NFS, 2, nconf_tcp, &nb_tcp))
284				err(1, "rpcb_set tcp failed");
285	}
286
287	if (udpflag && ip6flag) {
288		memset(&hints, 0, sizeof hints);
289		hints.ai_flags = AI_PASSIVE;
290		hints.ai_family = PF_INET6;
291		hints.ai_socktype = SOCK_DGRAM;
292		hints.ai_protocol = IPPROTO_UDP;
293
294		ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6);
295		if (ecode != 0) {
296			syslog(LOG_ERR, "getaddrinfo udp: %s",
297			    gai_strerror(ecode));
298			exit(1);
299		}
300
301		nconf_udp6 = getnetconfigent("udp6");
302
303		if (nconf_udp6 == NULL)
304			err(1, "getnetconfigent udp6 failed");
305
306		nb_udp6.buf = ai_udp6->ai_addr;
307		nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen;
308		if (reregister)
309			if (!rpcb_set(RPCPROG_NFS, 2, nconf_udp6, &nb_udp6))
310				err(1, "rpcb_set udp6 failed");
311	}
312
313	if (tcpflag && ip6flag) {
314		memset(&hints, 0, sizeof hints);
315		hints.ai_flags = AI_PASSIVE;
316		hints.ai_family = PF_INET6;
317		hints.ai_socktype = SOCK_STREAM;
318		hints.ai_protocol = IPPROTO_TCP;
319
320		ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6);
321		if (ecode != 0) {
322			syslog(LOG_ERR, "getaddrinfo tcp: %s",
323			    gai_strerror(ecode));
324			exit(1);
325		}
326
327		nconf_tcp6 = getnetconfigent("tcp6");
328
329		if (nconf_tcp6 == NULL)
330			err(1, "getnetconfigent tcp6 failed");
331
332		nb_tcp6.buf = ai_tcp6->ai_addr;
333		nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen;
334		if (reregister)
335			if (!rpcb_set(RPCPROG_NFS, 2, nconf_tcp6, &nb_tcp6))
336				err(1, "rpcb_set tcp6 failed");
337	}
338
339	openlog("nfsd", LOG_PID, LOG_DAEMON);
340
341	for (i = 0; i < nfsdcnt; i++) {
342		pthread_t t;
343		pthread_create(&t, NULL, child, NULL);
344	}
345
346	/* If we are serving udp, set up the socket. */
347	if (udpflag) {
348		if ((sock = rump_sys_socket(ai_udp->ai_family, ai_udp->ai_socktype,
349		    ai_udp->ai_protocol)) < 0) {
350			syslog(LOG_ERR, "can't create udp socket");
351			exit(1);
352		}
353		if (bind(sock, ai_udp->ai_addr, ai_udp->ai_addrlen) < 0) {
354			syslog(LOG_ERR, "can't bind udp addr");
355			exit(1);
356		}
357		if (!rpcb_set(RPCPROG_NFS, 2, nconf_udp, &nb_udp) ||
358		    !rpcb_set(RPCPROG_NFS, 3, nconf_udp, &nb_udp)) {
359			syslog(LOG_ERR, "can't register with udp portmap");
360			exit(1);
361		}
362		nfsdargs.sock = sock;
363		nfsdargs.name = NULL;
364		nfsdargs.namelen = 0;
365		if (rump_sys_nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
366			syslog(LOG_ERR, "can't add UDP socket");
367			exit(1);
368		}
369		(void)rump_sys_close(sock);
370	}
371
372	if (udpflag &&ip6flag) {
373		if ((sock = rump_sys_socket(ai_udp6->ai_family, ai_udp6->ai_socktype,
374		    ai_udp6->ai_protocol)) < 0) {
375			syslog(LOG_ERR, "can't create udp socket");
376			exit(1);
377		}
378		if (rump_sys_setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
379		    &on, sizeof on) < 0) {
380			syslog(LOG_ERR, "can't set v6-only binding for udp6 "
381					"socket: %m");
382			exit(1);
383		}
384		if (rump_sys_bind(sock, ai_udp6->ai_addr, ai_udp6->ai_addrlen) < 0) {
385			syslog(LOG_ERR, "can't bind udp addr");
386			exit(1);
387		}
388		if (!rpcb_set(RPCPROG_NFS, 2, nconf_udp6, &nb_udp6) ||
389		    !rpcb_set(RPCPROG_NFS, 3, nconf_udp6, &nb_udp6)) {
390			syslog(LOG_ERR, "can't register with udp portmap");
391			exit(1);
392		}
393		nfsdargs.sock = sock;
394		nfsdargs.name = NULL;
395		nfsdargs.namelen = 0;
396		if (rump_sys_nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
397			syslog(LOG_ERR, "can't add UDP6 socket");
398			exit(1);
399		}
400		(void)rump_sys_close(sock);
401	}
402
403	/* Now set up the master server socket waiting for tcp connections. */
404	on = 1;
405	connect_type_cnt = 0;
406	if (tcpflag) {
407		if ((tcpsock = rump_sys_socket(ai_tcp->ai_family, ai_tcp->ai_socktype,
408		    ai_tcp->ai_protocol)) < 0) {
409			syslog(LOG_ERR, "can't create tcp socket");
410			exit(1);
411		}
412		if (setsockopt(tcpsock,
413		    SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
414			syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
415		if (bind(tcpsock, ai_tcp->ai_addr, ai_tcp->ai_addrlen) < 0) {
416			syslog(LOG_ERR, "can't bind tcp addr");
417			exit(1);
418		}
419		if (rump_sys_listen(tcpsock, 5) < 0) {
420			syslog(LOG_ERR, "listen failed");
421			exit(1);
422		}
423		if (!rpcb_set(RPCPROG_NFS, 2, nconf_tcp, &nb_tcp) ||
424		    !rpcb_set(RPCPROG_NFS, 3, nconf_tcp, &nb_tcp)) {
425			syslog(LOG_ERR, "can't register tcp with rpcbind");
426			exit(1);
427		}
428		set[0].fd = tcpsock;
429		set[0].events = POLLIN;
430		connect_type_cnt++;
431	} else
432		set[0].fd = -1;
433
434	if (tcpflag && ip6flag) {
435		if ((tcp6sock = socket(ai_tcp6->ai_family, ai_tcp6->ai_socktype,
436		    ai_tcp6->ai_protocol)) < 0) {
437			syslog(LOG_ERR, "can't create tcp socket");
438			exit(1);
439		}
440		if (setsockopt(tcp6sock,
441		    SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
442			syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
443		if (setsockopt(tcp6sock, IPPROTO_IPV6, IPV6_V6ONLY,
444		    &on, sizeof on) < 0) {
445			syslog(LOG_ERR, "can't set v6-only binding for tcp6 "
446					"socket: %m");
447			exit(1);
448		}
449		if (bind(tcp6sock, ai_tcp6->ai_addr, ai_tcp6->ai_addrlen) < 0) {
450			syslog(LOG_ERR, "can't bind tcp6 addr");
451			exit(1);
452		}
453		if (listen(tcp6sock, 5) < 0) {
454			syslog(LOG_ERR, "listen failed");
455			exit(1);
456		}
457		if (!rpcb_set(RPCPROG_NFS, 2, nconf_tcp6, &nb_tcp6) ||
458		    !rpcb_set(RPCPROG_NFS, 3, nconf_tcp6, &nb_tcp6)) {
459			syslog(LOG_ERR, "can't register tcp6 with rpcbind");
460			exit(1);
461		}
462		set[1].fd = tcp6sock;
463		set[1].events = POLLIN;
464		connect_type_cnt++;
465	} else
466		set[1].fd = -1;
467
468	set[2].fd = -1;
469	set[3].fd = -1;
470
471	if (connect_type_cnt == 0) {
472		pause();
473		exit(0);
474	}
475
476	/*
477	 * Loop forever accepting connections and passing the sockets
478	 * into the kernel for the mounts.
479	 */
480	for (;;) {
481		if (rump_sys_poll(set, 4, INFTIM) < 1) {
482			syslog(LOG_ERR, "poll failed: %m");
483			exit(1);
484		}
485
486			len = sizeof(inetpeer);
487			if ((msgsock = accept(tcpsock,
488			    (struct sockaddr *)&inetpeer, &len)) < 0) {
489				syslog(LOG_ERR, "accept failed: %d", error);
490				exit(1);
491			}
492			memset(inetpeer.sin_zero, 0, sizeof(inetpeer.sin_zero));
493			if (setsockopt(msgsock, SOL_SOCKET,
494			    SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
495				syslog(LOG_ERR,
496				    "setsockopt SO_KEEPALIVE: %m");
497			nfsdargs.sock = msgsock;
498			nfsdargs.name = (caddr_t)&inetpeer;
499			nfsdargs.namelen = sizeof(inetpeer);
500			rump_sys_nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
501			(void)rump_sys_close(msgsock);
502
503#ifdef notyet
504		if (set[1].revents & POLLIN) {
505			len = sizeof(inet6peer);
506			if ((msgsock = rump_sys_accept(tcp6sock,
507			    (struct sockaddr *)&inet6peer, &len, &error)) < 0) {
508				syslog(LOG_ERR, "accept failed: %m");
509				exit(1);
510			}
511			if (rump_sys_setsockopt(msgsock, SOL_SOCKET,
512			    SO_KEEPALIVE, (char *)&on, sizeof(on), &error) < 0)
513				syslog(LOG_ERR,
514				    "setsockopt SO_KEEPALIVE: %m");
515			nfsdargs.sock = msgsock;
516			nfsdargs.name = (caddr_t)&inet6peer;
517			nfsdargs.namelen = sizeof(inet6peer);
518			rump_sys_nfssvc(NFSSVC_ADDSOCK, &nfsdargs, &error);
519			(void)rump_sys_close(msgsock, &error);
520		}
521
522		if (set[2].revents & POLLIN) {
523			len = sizeof(isopeer);
524			if ((msgsock = rump_sys_accept(tp4sock,
525			    (struct sockaddr *)&isopeer, &len, &error)) < 0) {
526				syslog(LOG_ERR, "accept failed: %m");
527				exit(1);
528			}
529			if (rump_sys_setsockopt(msgsock, SOL_SOCKET,
530			    SO_KEEPALIVE, (char *)&on, sizeof(on), &error) < 0)
531				syslog(LOG_ERR,
532				    "setsockopt SO_KEEPALIVE: %m");
533			nfsdargs.sock = msgsock;
534			nfsdargs.name = (caddr_t)&isopeer;
535			nfsdargs.namelen = len;
536			rump_sys_nfssvc(NFSSVC_ADDSOCK, &nfsdargs, &error);
537			(void)rump_sys_close(msgsock, &error);
538		}
539
540		if (set[3].revents & POLLIN) {
541			len = sizeof(inetpeer);
542			if ((msgsock = rump_sys_accept(tpipsock,
543			    (struct sockaddr *)&inetpeer, &len)) < 0) {
544				syslog(LOG_ERR, "accept failed: %m");
545				exit(1);
546			}
547			if (setsockopt(msgsock, SOL_SOCKET,
548			    SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
549				syslog(LOG_ERR, "setsockopt SO_KEEPALIVE: %m");
550			nfsdargs.sock = msgsock;
551			nfsdargs.name = (caddr_t)&inetpeer;
552			nfsdargs.namelen = len;
553			rump_sys_nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
554			(void)rump_sys_close(msgsock);
555		}
556#endif /* notyet */
557	}
558}
559
560void
561usage()
562{
563	(void)fprintf(stderr, "usage: nfsd %s\n", USAGE);
564	exit(1);
565}
566
567void
568nonfs(signo)
569	int signo;
570{
571	syslog(LOG_ERR, "missing system call: NFS not available.");
572}
573