nfsd.c revision 1.9 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.9 1993/12/05 13:41:07 deraadt 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 bzero((char *)&saddr, sizeof saddr);
116 bzero((char *)&msk, sizeof msk);
117 bzero((char *)&mtch, sizeof mtch);
118
119 /*
120 * Save start and extent of argv for setproctitle.
121 */
122
123 Argv = argv;
124 if (envp == 0 || *envp == 0)
125 envp = argv;
126 while (*envp)
127 envp++;
128 LastArg = envp[-1] + strlen(envp[-1]);
129 while ((opt = getopt(argc, argv, "rt:u:")) != EOF)
130 switch (opt) {
131 case 'r':
132 reregister++;
133 break;
134 case 't':
135 tcpflag++;
136 if (cp = index(optarg, ',')) {
137 *cp++ = '\0';
138 msk.sin_addr.s_addr = inet_addr(optarg);
139 if (msk.sin_addr.s_addr == -1)
140 usage();
141 if (cp2 = index(cp, ','))
142 *cp2++ = '\0';
143 mtch.sin_addr.s_addr = inet_addr(cp);
144 if (mtch.sin_addr.s_addr == -1)
145 usage();
146 cp = cp2;
147 hphead.ha_next = (struct hadr *)0;
148 while (cp) {
149 if (cp2 = index(cp, ','))
150 *cp2++ = '\0';
151 hp = (struct hadr *)
152 malloc(sizeof (struct hadr));
153 hp->ha_sad = inet_addr(cp);
154 if (hp->ha_sad == -1)
155 usage();
156 hp->ha_next = hphead.ha_next;
157 hphead.ha_next = hp;
158 cp = cp2;
159 }
160 } else
161 usage();
162 break;
163 case 'u':
164 udpflag++;
165 if (cp = index(optarg, ',')) {
166 *cp++ = '\0';
167 msk.sin_addr.s_addr = inet_addr(optarg);
168 if (msk.sin_addr.s_addr == -1)
169 usage();
170 if (cp2 = index(cp, ','))
171 *cp2++ = '\0';
172 mtch.sin_addr.s_addr = inet_addr(cp);
173 if (mtch.sin_addr.s_addr == -1)
174 usage();
175 if (cp2)
176 udpcnt = atoi(cp2);
177 if (udpcnt < 1 || udpcnt > 20)
178 udpcnt = 1;
179 } else
180 usage();
181 break;
182 default:
183 case '?':
184 usage();
185 }
186
187 /*
188 * Default, if neither UDP nor TCP is specified,
189 * is to support UDP only; a numeric argument indicates
190 * the number of server daemons to run.
191 */
192 if (udpflag == 0 && tcpflag == 0) {
193 if (argc > 1)
194 udpcnt = atoi(*++argv);
195 if (udpcnt < 1 || udpcnt > 20)
196 udpcnt = 1;
197 msk.sin_addr.s_addr = mtch.sin_addr.s_addr = 0;
198 udpflag++;
199 }
200
201 if (debug == 0) {
202 daemon(0, 0);
203 signal(SIGINT, SIG_IGN);
204 signal(SIGQUIT, SIG_IGN);
205 signal(SIGTERM, SIG_IGN);
206 signal(SIGHUP, SIG_IGN);
207 }
208 signal(SIGCHLD, reapchild);
209 signal(SIGSYS, not_nfsserver);
210 if (nfssvc(-1, NULL, 0, NULL, 0) >= 0) {
211 syslog(LOG_ERR, "bad arguments didn't cause error");
212 exit(1);
213 }
214 if (reregister) {
215 if (udpflag && !pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP,
216 NFS_PORT)) {
217 fprintf(stderr,
218 "Can't register with portmap for UDP\n");
219 exit(1);
220 }
221 if (tcpflag && !pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP,
222 NFS_PORT)) {
223 fprintf(stderr,
224 "Can't register with portmap for TCP\n");
225 exit(1);
226 }
227 exit(0);
228 }
229 openlog("nfsd:", LOG_PID, LOG_DAEMON);
230 #ifdef notdef
231 /* why? unregisters both protocols even if we restart only one */
232 pmap_unset(RPCPROG_NFS, NFS_VER2);
233 #endif
234 if (udpflag) {
235 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
236 syslog(LOG_ERR, "Can't create socket");
237 exit(1);
238 }
239 saddr.sin_family = AF_INET;
240 saddr.sin_addr.s_addr = INADDR_ANY;
241 saddr.sin_port = htons(NFS_PORT);
242 if (bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
243 syslog(LOG_ERR, "Can't bind addr");
244 exit(1);
245 }
246 if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT)) {
247 syslog(LOG_ERR, "Can't register with portmap");
248 exit(1);
249 }
250
251 /*
252 * Send the nfs datagram servers
253 * right down into the kernel
254 */
255 for (i = 0; i < udpcnt; i++)
256 if (fork() == 0) {
257 setproctitle("nfsd-udp",
258 (struct sockaddr_in *)NULL);
259 ret = nfssvc(sock, &msk, sizeof(msk),
260 &mtch, sizeof(mtch));
261 if (ret < 0)
262 syslog(LOG_ERR, "nfssvc() failed %m");
263 exit(1);
264 }
265 close(sock);
266 }
267
268 /*
269 * Now set up the master STREAM server waiting for tcp connections.
270 */
271 if (tcpflag) {
272 int on = 1;
273
274 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
275 syslog(LOG_ERR, "Can't create socket");
276 exit(1);
277 }
278 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
279 (char *) &on, sizeof(on)) < 0)
280 syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
281 saddr.sin_family = AF_INET;
282 saddr.sin_addr.s_addr = INADDR_ANY;
283 saddr.sin_port = htons(NFS_PORT);
284 if (bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
285 syslog(LOG_ERR, "Can't bind addr");
286 exit(1);
287 }
288 if (listen(sock, 5) < 0) {
289 syslog(LOG_ERR, "Listen failed");
290 exit(1);
291 }
292 if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
293 syslog(LOG_ERR, "Can't register with portmap");
294 exit(1);
295 }
296 setproctitle("nfsd-listen", (struct sockaddr_in *)NULL);
297 /*
298 * Loop forever accepting connections and sending the children
299 * into the kernel to service the mounts.
300 */
301 for (;;) {
302 len = sizeof(peername);
303 if ((msgsock = accept(sock,
304 (struct sockaddr *)&peername, &len)) < 0) {
305 syslog(LOG_ERR, "Accept failed: %m");
306 exit(1);
307 }
308 if ((peername.sin_addr.s_addr & msk.sin_addr.s_addr) !=
309 mtch.sin_addr.s_addr) {
310 hp = hphead.ha_next;
311 while (hp) {
312 if (peername.sin_addr.s_addr ==
313 hp->ha_sad)
314 break;
315 hp = hp->ha_next;
316 }
317 if (hp == NULL) {
318 shutdown(msgsock, 2);
319 close(msgsock);
320 continue;
321 }
322 }
323 if (fork() == 0) {
324 close(sock);
325 setproctitle("nfsd-tcp", &peername);
326 if (setsockopt(msgsock, SOL_SOCKET,
327 SO_KEEPALIVE, (char *) &on, sizeof(on)) < 0)
328 syslog(LOG_ERR,
329 "setsockopt SO_KEEPALIVE: %m");
330 ret = nfssvc(msgsock, &msk, sizeof(msk),
331 &mtch, sizeof(mtch));
332 shutdown(msgsock, 2);
333 if (ret < 0)
334 syslog(LOG_NOTICE,
335 "Nfssvc STREAM Failed");
336 exit(1);
337 }
338 close(msgsock);
339 }
340 }
341 }
342
343 usage()
344 {
345 fprintf(stderr, "nfsd [-t msk,mtch[,addrs]] [-u msk,mtch,numprocs]\n");
346 exit(1);
347 }
348
349 void
350 reapchild()
351 {
352
353 while (wait3((int *) NULL, WNOHANG, (struct rusage *) NULL))
354 ;
355 }
356
357 setproctitle(a, sin)
358 char *a;
359 struct sockaddr_in *sin;
360 {
361 register char *cp;
362 static char buf[80];
363
364 if (sin)
365 (void) sprintf(buf, "%s [%s]", a, inet_ntoa(sin->sin_addr));
366 else
367 (void) sprintf(buf, "%s", a);
368 PS_STRINGS->ps_nargvstr = 1;
369 PS_STRINGS->ps_argvstr = buf;
370 }
371
372 void not_nfsserver()
373 {
374 syslog(LOG_ERR, "not configured as NFS server");
375 exit(1);
376 }
377