xref: /netbsd-src/usr.sbin/nfsd/nfsd.c (revision cda4f8f6ee55684e8d311b86c99ea59191e6b74f)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Rick Macklem at The University of Guelph.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #ifndef lint
38 char copyright[] =
39 "@(#) Copyright (c) 1989 Regents of the University of California.\n\
40  All rights reserved.\n";
41 #endif not lint
42 
43 #ifndef lint
44 static char sccsid[] = "@(#)nfsd.c	5.10 (Berkeley) 4/24/91";
45 static char rcsid[] = "$Header: /cvsroot/src/usr.sbin/nfsd/nfsd.c,v 1.6 1993/06/02 05:01:49 cgd Exp $";
46 #endif not lint
47 
48 #include <sys/types.h>
49 #include <sys/signal.h>
50 #include <sys/ioctl.h>
51 #include <sys/stat.h>
52 #include <sys/wait.h>
53 #include <sys/mount.h>
54 #include <sys/socket.h>
55 #include <sys/socketvar.h>
56 #include <stdio.h>
57 #include <syslog.h>
58 #include <fcntl.h>
59 #include <string.h>
60 #include <netdb.h>
61 #include <rpc/rpc.h>
62 #include <rpc/pmap_clnt.h>
63 #include <rpc/pmap_prot.h>
64 #include <nfs/rpcv2.h>
65 #include <nfs/nfsv2.h>
66 #include <err.h>
67 
68 #include <machine/vmparam.h>	/* these are for PS_STRINGS */
69 #include <sys/exec.h>
70 
71 /* Global defs */
72 #ifdef DEBUG
73 #define	syslog(e, s)	fprintf(stderr,(s))
74 int	debug = 1;
75 #else
76 int	debug = 0;
77 #endif
78 struct hadr {
79 	u_long	ha_sad;
80 	struct hadr *ha_next;
81 };
82 struct	hadr hphead;
83 char	**Argv = NULL;		/* pointer to argument vector */
84 char	*LastArg = NULL;	/* end of argv */
85 void	reapchild(),not_nfsserver();;
86 
87 /*
88  * Nfs server daemon mostly just a user context for nfssvc()
89  * 1 - do file descriptor and signal cleanup
90  * 2 - create server socket
91  * 3 - register socket with portmap
92  * For SOCK_DGRAM, just fork children and send them into the kernel
93  * by calling nfssvc()
94  * For connection based sockets, loop doing accepts. When you get a new socket
95  * from accept, fork a child that drops into the kernel via. nfssvc.
96  * This child will return from nfssvc when the connection is closed, so
97  * just shutdown() and exit().
98  * The arguments are:
99  * -t - support tcp nfs clients
100  * -u - support udp nfs clients
101  */
102 main(argc, argv, envp)
103 	int argc;
104 	char *argv[], *envp[];
105 {
106 	register int i;
107 	register char *cp, *cp2;
108 	register struct hadr *hp;
109 	int udpcnt, sock, msgsock, tcpflag = 0, udpflag = 0, ret, len;
110 	int reregister = 0;
111 	char opt;
112 	extern int optind;
113 	extern char *optarg;
114 	struct sockaddr_in saddr, msk, mtch, peername;
115 
116 
117 	/*
118 	 *  Save start and extent of argv for setproctitle.
119 	 */
120 
121 	Argv = argv;
122 	if (envp == 0 || *envp == 0)
123 		envp = argv;
124 	while (*envp)
125 		envp++;
126 	LastArg = envp[-1] + strlen(envp[-1]);
127 	while ((opt = getopt(argc, argv, "rt:u:")) != EOF)
128 		switch (opt) {
129 		case 'r':
130 			reregister++;
131 			break;
132 		case 't':
133 			tcpflag++;
134 			if (cp = index(optarg, ',')) {
135 				*cp++ = '\0';
136 				msk.sin_addr.s_addr = inet_addr(optarg);
137 				if (msk.sin_addr.s_addr == -1)
138 					usage();
139 				if (cp2 = index(cp, ','))
140 					*cp2++ = '\0';
141 				mtch.sin_addr.s_addr = inet_addr(cp);
142 				if (mtch.sin_addr.s_addr == -1)
143 					usage();
144 				cp = cp2;
145 				hphead.ha_next = (struct hadr *)0;
146 				while (cp) {
147 					if (cp2 = index(cp, ','))
148 						*cp2++ = '\0';
149 					hp = (struct hadr *)
150 						malloc(sizeof (struct hadr));
151 					hp->ha_sad = inet_addr(cp);
152 					if (hp->ha_sad == -1)
153 						usage();
154 					hp->ha_next = hphead.ha_next;
155 					hphead.ha_next = hp;
156 					cp = cp2;
157 				}
158 			} else
159 				usage();
160 			break;
161 		case 'u':
162 			udpflag++;
163 			if (cp = index(optarg, ',')) {
164 				*cp++ = '\0';
165 				msk.sin_addr.s_addr = inet_addr(optarg);
166 				if (msk.sin_addr.s_addr == -1)
167 					usage();
168 				if (cp2 = index(cp, ','))
169 					*cp2++ = '\0';
170 				mtch.sin_addr.s_addr = inet_addr(cp);
171 				if (mtch.sin_addr.s_addr == -1)
172 					usage();
173 				if (cp2)
174 					udpcnt = atoi(cp2);
175 				if (udpcnt < 1 || udpcnt > 20)
176 					udpcnt = 1;
177 			} else
178 				usage();
179 			break;
180 		default:
181 		case '?':
182 			usage();
183 		}
184 
185 	/*
186 	 * Default, if neither UDP nor TCP is specified,
187 	 * is to support UDP only; a numeric argument indicates
188 	 * the number of server daemons to run.
189 	 */
190 	if (udpflag == 0 && tcpflag == 0) {
191 		if (argc > 1)
192 			udpcnt = atoi(*++argv);
193 		if (udpcnt < 1 || udpcnt > 20)
194 			udpcnt = 1;
195 		msk.sin_addr.s_addr = mtch.sin_addr.s_addr = 0;
196 		udpflag++;
197 	}
198 
199 	if (debug == 0) {
200 		daemon(0, 0);
201 		signal(SIGINT, SIG_IGN);
202 		signal(SIGQUIT, SIG_IGN);
203 		signal(SIGTERM, SIG_IGN);
204 		signal(SIGHUP, SIG_IGN);
205 	}
206 	signal(SIGCHLD, reapchild);
207 	signal(SIGSYS, not_nfsserver);
208 	if (nfssvc(-1, NULL, 0, NULL, 0) >= 0)
209 	    err(1, "bad arguments didn't cause error");
210 	if (reregister) {
211 		if (udpflag && !pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP,
212 		    NFS_PORT)) {
213 			fprintf(stderr,
214 			    "Can't register with portmap for UDP\n");
215 			exit(1);
216 		}
217 		if (tcpflag && !pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP,
218 		    NFS_PORT)) {
219 			fprintf(stderr,
220 			    "Can't register with portmap for TCP\n");
221 			exit(1);
222 		}
223 		exit(0);
224 	}
225 	openlog("nfsd:", LOG_PID, LOG_DAEMON);
226 #ifdef notdef
227 	/* why? unregisters both protocols even if we restart only one */
228 	pmap_unset(RPCPROG_NFS, NFS_VER2);
229 #endif
230 	if (udpflag) {
231 		if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
232 			syslog(LOG_ERR, "Can't create socket");
233 			exit(1);
234 		}
235 		saddr.sin_family = AF_INET;
236 		saddr.sin_addr.s_addr = INADDR_ANY;
237 		saddr.sin_port = htons(NFS_PORT);
238 		if (bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
239 			syslog(LOG_ERR, "Can't bind addr");
240 			exit(1);
241 		}
242 		if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT)) {
243 			syslog(LOG_ERR, "Can't register with portmap");
244 			exit(1);
245 		}
246 
247 		/*
248 		 * Send the nfs datagram servers
249 		 * right down into the kernel
250 		 */
251 		for (i = 0; i < udpcnt; i++)
252 			if (fork() == 0) {
253 				setproctitle("nfsd-udp",
254 				    (struct sockaddr_in *)NULL);
255 				ret = nfssvc(sock, &msk, sizeof(msk),
256 						&mtch, sizeof(mtch));
257 				if (ret < 0)
258 					syslog(LOG_ERR, "nfssvc() failed %m");
259 				exit(1);
260 			}
261 		close(sock);
262 	}
263 
264 	/*
265 	 * Now set up the master STREAM server waiting for tcp connections.
266 	 */
267 	if (tcpflag) {
268 		int on = 1;
269 
270 		if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
271 			syslog(LOG_ERR, "Can't create socket");
272 			exit(1);
273 		}
274 		if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
275 		    (char *) &on, sizeof(on)) < 0)
276 			syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
277 		saddr.sin_family = AF_INET;
278 		saddr.sin_addr.s_addr = INADDR_ANY;
279 		saddr.sin_port = htons(NFS_PORT);
280 		if (bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
281 			syslog(LOG_ERR, "Can't bind addr");
282 			exit(1);
283 		}
284 		if (listen(sock, 5) < 0) {
285 			syslog(LOG_ERR, "Listen failed");
286 			exit(1);
287 		}
288 		if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
289 			syslog(LOG_ERR, "Can't register with portmap");
290 			exit(1);
291 		}
292 		setproctitle("nfsd-listen", (struct sockaddr_in *)NULL);
293 		/*
294 		 * Loop forever accepting connections and sending the children
295 		 * into the kernel to service the mounts.
296 		 */
297 		for (;;) {
298 			len = sizeof(peername);
299 			if ((msgsock = accept(sock,
300 			    (struct sockaddr *)&peername, &len)) < 0) {
301 				syslog(LOG_ERR, "Accept failed: %m");
302 				exit(1);
303 			}
304 			if ((peername.sin_addr.s_addr & msk.sin_addr.s_addr) !=
305 			   mtch.sin_addr.s_addr) {
306 				hp = hphead.ha_next;
307 				while (hp) {
308 					if (peername.sin_addr.s_addr ==
309 						hp->ha_sad)
310 						break;
311 					hp = hp->ha_next;
312 				}
313 				if (hp == NULL) {
314 					shutdown(msgsock, 2);
315 					close(msgsock);
316 					continue;
317 				}
318 			}
319 			if (fork() == 0) {
320 				close(sock);
321 				setproctitle("nfsd-tcp", &peername);
322 				if (setsockopt(msgsock, SOL_SOCKET,
323 				    SO_KEEPALIVE, (char *) &on, sizeof(on)) < 0)
324 					syslog(LOG_ERR,
325 					    "setsockopt SO_KEEPALIVE: %m");
326 				ret = nfssvc(msgsock, &msk, sizeof(msk),
327 						&mtch, sizeof(mtch));
328 				shutdown(msgsock, 2);
329 				if (ret < 0)
330 					syslog(LOG_NOTICE,
331 					    "Nfssvc STREAM Failed");
332 				exit(1);
333 			}
334 			close(msgsock);
335 		}
336 	}
337 }
338 
339 usage()
340 {
341 	fprintf(stderr, "nfsd [-t msk,mtch[,addrs]] [-u msk,mtch,numprocs]\n");
342 	exit(1);
343 }
344 
345 void
346 reapchild()
347 {
348 
349 	while (wait3((int *) NULL, WNOHANG, (struct rusage *) NULL))
350 		;
351 }
352 
353 setproctitle(a, sin)
354 	char *a;
355 	struct sockaddr_in *sin;
356 {
357 	register char *cp;
358 	static char buf[80];
359 
360 	if (sin)
361 		(void) sprintf(buf, "%s [%s]", a, inet_ntoa(sin->sin_addr));
362 	else
363 		(void) sprintf(buf, "%s", a);
364 	PS_STRINGS->ps_nargvstr = 1;
365 	PS_STRINGS->ps_argvstr = buf;
366 }
367 
368 void not_nfsserver()
369 {
370     err(1, "not configured as NFS server\n");
371 }
372