xref: /netbsd-src/usr.sbin/nfsd/nfsd.c (revision 0b9f50897e9a9c6709320fafb4c3787fddcc0a45)
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[] = "from: @(#)nfsd.c	5.10 (Berkeley) 4/24/91";*/
45 static char rcsid[] = "$Id: nfsd.c,v 1.8 1993/10/05 00:36:28 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 
67 #include <machine/vmparam.h>	/* these are for PS_STRINGS */
68 #include <sys/exec.h>
69 
70 /* Global defs */
71 #ifdef DEBUG
72 #define	syslog(e, s)	fprintf(stderr,(s))
73 int	debug = 1;
74 #else
75 int	debug = 0;
76 #endif
77 struct hadr {
78 	u_long	ha_sad;
79 	struct hadr *ha_next;
80 };
81 struct	hadr hphead;
82 char	**Argv = NULL;		/* pointer to argument vector */
83 char	*LastArg = NULL;	/* end of argv */
84 void	reapchild(),not_nfsserver();;
85 
86 /*
87  * Nfs server daemon mostly just a user context for nfssvc()
88  * 1 - do file descriptor and signal cleanup
89  * 2 - create server socket
90  * 3 - register socket with portmap
91  * For SOCK_DGRAM, just fork children and send them into the kernel
92  * by calling nfssvc()
93  * For connection based sockets, loop doing accepts. When you get a new socket
94  * from accept, fork a child that drops into the kernel via. nfssvc.
95  * This child will return from nfssvc when the connection is closed, so
96  * just shutdown() and exit().
97  * The arguments are:
98  * -t - support tcp nfs clients
99  * -u - support udp nfs clients
100  */
101 main(argc, argv, envp)
102 	int argc;
103 	char *argv[], *envp[];
104 {
105 	register int i;
106 	register char *cp, *cp2;
107 	register struct hadr *hp;
108 	int udpcnt, sock, msgsock, tcpflag = 0, udpflag = 0, ret, len;
109 	int reregister = 0;
110 	char opt;
111 	extern int optind;
112 	extern char *optarg;
113 	struct sockaddr_in saddr, msk, mtch, peername;
114 
115 
116 	/*
117 	 *  Save start and extent of argv for setproctitle.
118 	 */
119 
120 	Argv = argv;
121 	if (envp == 0 || *envp == 0)
122 		envp = argv;
123 	while (*envp)
124 		envp++;
125 	LastArg = envp[-1] + strlen(envp[-1]);
126 	while ((opt = getopt(argc, argv, "rt:u:")) != EOF)
127 		switch (opt) {
128 		case 'r':
129 			reregister++;
130 			break;
131 		case 't':
132 			tcpflag++;
133 			if (cp = index(optarg, ',')) {
134 				*cp++ = '\0';
135 				msk.sin_addr.s_addr = inet_addr(optarg);
136 				if (msk.sin_addr.s_addr == -1)
137 					usage();
138 				if (cp2 = index(cp, ','))
139 					*cp2++ = '\0';
140 				mtch.sin_addr.s_addr = inet_addr(cp);
141 				if (mtch.sin_addr.s_addr == -1)
142 					usage();
143 				cp = cp2;
144 				hphead.ha_next = (struct hadr *)0;
145 				while (cp) {
146 					if (cp2 = index(cp, ','))
147 						*cp2++ = '\0';
148 					hp = (struct hadr *)
149 						malloc(sizeof (struct hadr));
150 					hp->ha_sad = inet_addr(cp);
151 					if (hp->ha_sad == -1)
152 						usage();
153 					hp->ha_next = hphead.ha_next;
154 					hphead.ha_next = hp;
155 					cp = cp2;
156 				}
157 			} else
158 				usage();
159 			break;
160 		case 'u':
161 			udpflag++;
162 			if (cp = index(optarg, ',')) {
163 				*cp++ = '\0';
164 				msk.sin_addr.s_addr = inet_addr(optarg);
165 				if (msk.sin_addr.s_addr == -1)
166 					usage();
167 				if (cp2 = index(cp, ','))
168 					*cp2++ = '\0';
169 				mtch.sin_addr.s_addr = inet_addr(cp);
170 				if (mtch.sin_addr.s_addr == -1)
171 					usage();
172 				if (cp2)
173 					udpcnt = atoi(cp2);
174 				if (udpcnt < 1 || udpcnt > 20)
175 					udpcnt = 1;
176 			} else
177 				usage();
178 			break;
179 		default:
180 		case '?':
181 			usage();
182 		}
183 
184 	/*
185 	 * Default, if neither UDP nor TCP is specified,
186 	 * is to support UDP only; a numeric argument indicates
187 	 * the number of server daemons to run.
188 	 */
189 	if (udpflag == 0 && tcpflag == 0) {
190 		if (argc > 1)
191 			udpcnt = atoi(*++argv);
192 		if (udpcnt < 1 || udpcnt > 20)
193 			udpcnt = 1;
194 		msk.sin_addr.s_addr = mtch.sin_addr.s_addr = 0;
195 		udpflag++;
196 	}
197 
198 	if (debug == 0) {
199 		daemon(0, 0);
200 		signal(SIGINT, SIG_IGN);
201 		signal(SIGQUIT, SIG_IGN);
202 		signal(SIGTERM, SIG_IGN);
203 		signal(SIGHUP, SIG_IGN);
204 	}
205 	signal(SIGCHLD, reapchild);
206 	signal(SIGSYS, not_nfsserver);
207 	if (nfssvc(-1, NULL, 0, NULL, 0) >= 0) {
208 		syslog(LOG_ERR, "bad arguments didn't cause error");
209 		exit(1);
210 	}
211 	if (reregister) {
212 		if (udpflag && !pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP,
213 		    NFS_PORT)) {
214 			fprintf(stderr,
215 			    "Can't register with portmap for UDP\n");
216 			exit(1);
217 		}
218 		if (tcpflag && !pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP,
219 		    NFS_PORT)) {
220 			fprintf(stderr,
221 			    "Can't register with portmap for TCP\n");
222 			exit(1);
223 		}
224 		exit(0);
225 	}
226 	openlog("nfsd:", LOG_PID, LOG_DAEMON);
227 #ifdef notdef
228 	/* why? unregisters both protocols even if we restart only one */
229 	pmap_unset(RPCPROG_NFS, NFS_VER2);
230 #endif
231 	if (udpflag) {
232 		if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
233 			syslog(LOG_ERR, "Can't create socket");
234 			exit(1);
235 		}
236 		saddr.sin_family = AF_INET;
237 		saddr.sin_addr.s_addr = INADDR_ANY;
238 		saddr.sin_port = htons(NFS_PORT);
239 		if (bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
240 			syslog(LOG_ERR, "Can't bind addr");
241 			exit(1);
242 		}
243 		if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT)) {
244 			syslog(LOG_ERR, "Can't register with portmap");
245 			exit(1);
246 		}
247 
248 		/*
249 		 * Send the nfs datagram servers
250 		 * right down into the kernel
251 		 */
252 		for (i = 0; i < udpcnt; i++)
253 			if (fork() == 0) {
254 				setproctitle("nfsd-udp",
255 				    (struct sockaddr_in *)NULL);
256 				ret = nfssvc(sock, &msk, sizeof(msk),
257 						&mtch, sizeof(mtch));
258 				if (ret < 0)
259 					syslog(LOG_ERR, "nfssvc() failed %m");
260 				exit(1);
261 			}
262 		close(sock);
263 	}
264 
265 	/*
266 	 * Now set up the master STREAM server waiting for tcp connections.
267 	 */
268 	if (tcpflag) {
269 		int on = 1;
270 
271 		if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
272 			syslog(LOG_ERR, "Can't create socket");
273 			exit(1);
274 		}
275 		if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
276 		    (char *) &on, sizeof(on)) < 0)
277 			syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
278 		saddr.sin_family = AF_INET;
279 		saddr.sin_addr.s_addr = INADDR_ANY;
280 		saddr.sin_port = htons(NFS_PORT);
281 		if (bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
282 			syslog(LOG_ERR, "Can't bind addr");
283 			exit(1);
284 		}
285 		if (listen(sock, 5) < 0) {
286 			syslog(LOG_ERR, "Listen failed");
287 			exit(1);
288 		}
289 		if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
290 			syslog(LOG_ERR, "Can't register with portmap");
291 			exit(1);
292 		}
293 		setproctitle("nfsd-listen", (struct sockaddr_in *)NULL);
294 		/*
295 		 * Loop forever accepting connections and sending the children
296 		 * into the kernel to service the mounts.
297 		 */
298 		for (;;) {
299 			len = sizeof(peername);
300 			if ((msgsock = accept(sock,
301 			    (struct sockaddr *)&peername, &len)) < 0) {
302 				syslog(LOG_ERR, "Accept failed: %m");
303 				exit(1);
304 			}
305 			if ((peername.sin_addr.s_addr & msk.sin_addr.s_addr) !=
306 			   mtch.sin_addr.s_addr) {
307 				hp = hphead.ha_next;
308 				while (hp) {
309 					if (peername.sin_addr.s_addr ==
310 						hp->ha_sad)
311 						break;
312 					hp = hp->ha_next;
313 				}
314 				if (hp == NULL) {
315 					shutdown(msgsock, 2);
316 					close(msgsock);
317 					continue;
318 				}
319 			}
320 			if (fork() == 0) {
321 				close(sock);
322 				setproctitle("nfsd-tcp", &peername);
323 				if (setsockopt(msgsock, SOL_SOCKET,
324 				    SO_KEEPALIVE, (char *) &on, sizeof(on)) < 0)
325 					syslog(LOG_ERR,
326 					    "setsockopt SO_KEEPALIVE: %m");
327 				ret = nfssvc(msgsock, &msk, sizeof(msk),
328 						&mtch, sizeof(mtch));
329 				shutdown(msgsock, 2);
330 				if (ret < 0)
331 					syslog(LOG_NOTICE,
332 					    "Nfssvc STREAM Failed");
333 				exit(1);
334 			}
335 			close(msgsock);
336 		}
337 	}
338 }
339 
340 usage()
341 {
342 	fprintf(stderr, "nfsd [-t msk,mtch[,addrs]] [-u msk,mtch,numprocs]\n");
343 	exit(1);
344 }
345 
346 void
347 reapchild()
348 {
349 
350 	while (wait3((int *) NULL, WNOHANG, (struct rusage *) NULL))
351 		;
352 }
353 
354 setproctitle(a, sin)
355 	char *a;
356 	struct sockaddr_in *sin;
357 {
358 	register char *cp;
359 	static char buf[80];
360 
361 	if (sin)
362 		(void) sprintf(buf, "%s [%s]", a, inet_ntoa(sin->sin_addr));
363 	else
364 		(void) sprintf(buf, "%s", a);
365 	PS_STRINGS->ps_nargvstr = 1;
366 	PS_STRINGS->ps_argvstr = buf;
367 }
368 
369 void not_nfsserver()
370 {
371 	syslog(LOG_ERR, "not configured as NFS server");
372 	exit(1);
373 }
374