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