Deleted Added
full compact
nfsd.c (140679) nfsd.c (153590)
1/*
2 * Copyright (c) 1989, 1993, 1994
3 * The Regents of the University of California. 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 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#ifndef lint
34static const char copyright[] =
35"@(#) Copyright (c) 1989, 1993, 1994\n\
36 The Regents of the University of California. All rights reserved.\n";
37#endif /* not lint */
38
39#ifndef lint
40#if 0
41static char sccsid[] = "@(#)nfsd.c 8.9 (Berkeley) 3/29/95";
42#endif
43static const char rcsid[] =
1/*
2 * Copyright (c) 1989, 1993, 1994
3 * The Regents of the University of California. 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 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#ifndef lint
34static const char copyright[] =
35"@(#) Copyright (c) 1989, 1993, 1994\n\
36 The Regents of the University of California. All rights reserved.\n";
37#endif /* not lint */
38
39#ifndef lint
40#if 0
41static char sccsid[] = "@(#)nfsd.c 8.9 (Berkeley) 3/29/95";
42#endif
43static const char rcsid[] =
44 "$FreeBSD: head/usr.sbin/nfsd/nfsd.c 140679 2005-01-23 21:34:00Z rwatson $";
44 "$FreeBSD: head/usr.sbin/nfsd/nfsd.c 153590 2005-12-21 02:25:59Z delphij $";
45#endif /* not lint */
46
47#include <sys/param.h>
48#include <sys/syslog.h>
49#include <sys/wait.h>
50#include <sys/mount.h>
51#include <sys/linker.h>
52#include <sys/module.h>
53
54#include <rpc/rpc.h>
55#include <rpc/pmap_clnt.h>
56
57#include <netdb.h>
58#include <arpa/inet.h>
59#include <nfs/rpcv2.h>
60#include <nfs/nfsproto.h>
61#include <nfsserver/nfs.h>
62
63#include <err.h>
64#include <errno.h>
65#include <signal.h>
66#include <stdio.h>
67#include <stdlib.h>
68#include <string.h>
69#include <unistd.h>
70#include <netdb.h>
71
72/* Global defs */
73#ifdef DEBUG
74#define syslog(e, s...) fprintf(stderr,s)
75int debug = 1;
76#else
77int debug = 0;
78#endif
79
80#define MAXNFSDCNT 256
81#define DEFNFSDCNT 4
82pid_t children[MAXNFSDCNT]; /* PIDs of children */
83int nfsdcnt; /* number of children */
84
85void cleanup(int);
86void child_cleanup(int);
87void killchildren(void);
88void nfsd_exit(int);
89void nonfs(int);
90void reapchild(int);
91int setbindhost(struct addrinfo **ia, const char *bindhost,
92 struct addrinfo hints);
93void start_server(int);
94void unregistration(void);
95void usage(void);
96
97/*
98 * Nfs server daemon mostly just a user context for nfssvc()
99 *
100 * 1 - do file descriptor and signal cleanup
101 * 2 - fork the nfsd(s)
102 * 3 - create server socket(s)
103 * 4 - register socket with rpcbind
104 *
105 * For connectionless protocols, just pass the socket into the kernel via.
106 * nfssvc().
107 * For connection based sockets, loop doing accepts. When you get a new
108 * socket from accept, pass the msgsock into the kernel via. nfssvc().
109 * The arguments are:
110 * -r - reregister with rpcbind
111 * -d - unregister with rpcbind
112 * -t - support tcp nfs clients
113 * -u - support udp nfs clients
114 * followed by "n" which is the number of nfsds' to fork off
115 */
116int
117main(int argc, char **argv)
118{
119 struct nfsd_args nfsdargs;
120 struct addrinfo *ai_udp, *ai_tcp, *ai_udp6, *ai_tcp6, hints;
121 struct netconfig *nconf_udp, *nconf_tcp, *nconf_udp6, *nconf_tcp6;
122 struct netbuf nb_udp, nb_tcp, nb_udp6, nb_tcp6;
123 struct sockaddr_in inetpeer;
124 struct sockaddr_in6 inet6peer;
125 fd_set ready, sockbits;
126 fd_set v4bits, v6bits;
45#endif /* not lint */
46
47#include <sys/param.h>
48#include <sys/syslog.h>
49#include <sys/wait.h>
50#include <sys/mount.h>
51#include <sys/linker.h>
52#include <sys/module.h>
53
54#include <rpc/rpc.h>
55#include <rpc/pmap_clnt.h>
56
57#include <netdb.h>
58#include <arpa/inet.h>
59#include <nfs/rpcv2.h>
60#include <nfs/nfsproto.h>
61#include <nfsserver/nfs.h>
62
63#include <err.h>
64#include <errno.h>
65#include <signal.h>
66#include <stdio.h>
67#include <stdlib.h>
68#include <string.h>
69#include <unistd.h>
70#include <netdb.h>
71
72/* Global defs */
73#ifdef DEBUG
74#define syslog(e, s...) fprintf(stderr,s)
75int debug = 1;
76#else
77int debug = 0;
78#endif
79
80#define MAXNFSDCNT 256
81#define DEFNFSDCNT 4
82pid_t children[MAXNFSDCNT]; /* PIDs of children */
83int nfsdcnt; /* number of children */
84
85void cleanup(int);
86void child_cleanup(int);
87void killchildren(void);
88void nfsd_exit(int);
89void nonfs(int);
90void reapchild(int);
91int setbindhost(struct addrinfo **ia, const char *bindhost,
92 struct addrinfo hints);
93void start_server(int);
94void unregistration(void);
95void usage(void);
96
97/*
98 * Nfs server daemon mostly just a user context for nfssvc()
99 *
100 * 1 - do file descriptor and signal cleanup
101 * 2 - fork the nfsd(s)
102 * 3 - create server socket(s)
103 * 4 - register socket with rpcbind
104 *
105 * For connectionless protocols, just pass the socket into the kernel via.
106 * nfssvc().
107 * For connection based sockets, loop doing accepts. When you get a new
108 * socket from accept, pass the msgsock into the kernel via. nfssvc().
109 * The arguments are:
110 * -r - reregister with rpcbind
111 * -d - unregister with rpcbind
112 * -t - support tcp nfs clients
113 * -u - support udp nfs clients
114 * followed by "n" which is the number of nfsds' to fork off
115 */
116int
117main(int argc, char **argv)
118{
119 struct nfsd_args nfsdargs;
120 struct addrinfo *ai_udp, *ai_tcp, *ai_udp6, *ai_tcp6, hints;
121 struct netconfig *nconf_udp, *nconf_tcp, *nconf_udp6, *nconf_tcp6;
122 struct netbuf nb_udp, nb_tcp, nb_udp6, nb_tcp6;
123 struct sockaddr_in inetpeer;
124 struct sockaddr_in6 inet6peer;
125 fd_set ready, sockbits;
126 fd_set v4bits, v6bits;
127 int ch, connect_type_cnt, i, len, maxsock, msgsock;
127 int ch, connect_type_cnt, i, maxsock, msgsock;
128 size_t len;
128 int on = 1, unregister, reregister, sock;
129 int tcp6sock, ip6flag, tcpflag, tcpsock;
130 int udpflag, ecode, s, srvcnt;
131 int bindhostc, bindanyflag, rpcbreg, rpcbregcnt;
132 char **bindhost = NULL;
133 pid_t pid;
134
135 if (modfind("nfsserver") < 0) {
136 /* Not present in kernel, try loading it */
137 if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0)
138 errx(1, "NFS server is not available");
139 }
140
141 nfsdcnt = DEFNFSDCNT;
142 unregister = reregister = tcpflag = maxsock = 0;
143 bindanyflag = udpflag = connect_type_cnt = bindhostc = 0;
144#define GETOPT "ah:n:rdtu"
145#define USAGE "[-ardtu] [-n num_servers] [-h bindip]"
146 while ((ch = getopt(argc, argv, GETOPT)) != -1)
147 switch (ch) {
148 case 'a':
149 bindanyflag = 1;
150 break;
151 case 'n':
152 nfsdcnt = atoi(optarg);
153 if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) {
154 warnx("nfsd count %d; reset to %d", nfsdcnt,
155 DEFNFSDCNT);
156 nfsdcnt = DEFNFSDCNT;
157 }
158 break;
159 case 'h':
160 bindhostc++;
161 bindhost = realloc(bindhost,sizeof(char *)*bindhostc);
162 if (bindhost == NULL)
163 errx(1, "Out of memory");
164 bindhost[bindhostc-1] = strdup(optarg);
165 if (bindhost[bindhostc-1] == NULL)
166 errx(1, "Out of memory");
167 break;
168 case 'r':
169 reregister = 1;
170 break;
171 case 'd':
172 unregister = 1;
173 break;
174 case 't':
175 tcpflag = 1;
176 break;
177 case 'u':
178 udpflag = 1;
179 break;
180 default:
181 case '?':
182 usage();
183 };
184 if (!tcpflag && !udpflag)
185 udpflag = 1;
186 argv += optind;
187 argc -= optind;
188
189 /*
190 * XXX
191 * Backward compatibility, trailing number is the count of daemons.
192 */
193 if (argc > 1)
194 usage();
195 if (argc == 1) {
196 nfsdcnt = atoi(argv[0]);
197 if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) {
198 warnx("nfsd count %d; reset to %d", nfsdcnt,
199 DEFNFSDCNT);
200 nfsdcnt = DEFNFSDCNT;
201 }
202 }
203
204 ip6flag = 1;
205 s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
206 if (s == -1) {
207 if (errno != EPROTONOSUPPORT)
208 err(1, "socket");
209 ip6flag = 0;
210 } else if (getnetconfigent("udp6") == NULL ||
211 getnetconfigent("tcp6") == NULL) {
212 ip6flag = 0;
213 }
214 if (s != -1)
215 close(s);
216
217 if (bindhostc == 0 || bindanyflag) {
218 bindhostc++;
219 bindhost = realloc(bindhost,sizeof(char *)*bindhostc);
220 if (bindhost == NULL)
221 errx(1, "Out of memory");
222 bindhost[bindhostc-1] = strdup("*");
223 if (bindhost[bindhostc-1] == NULL)
224 errx(1, "Out of memory");
225 }
226
227 if (unregister) {
228 unregistration();
229 exit (0);
230 }
231 if (reregister) {
232 if (udpflag) {
233 memset(&hints, 0, sizeof hints);
234 hints.ai_flags = AI_PASSIVE;
235 hints.ai_family = AF_INET;
236 hints.ai_socktype = SOCK_DGRAM;
237 hints.ai_protocol = IPPROTO_UDP;
238 ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp);
239 if (ecode != 0)
240 err(1, "getaddrinfo udp: %s", gai_strerror(ecode));
241 nconf_udp = getnetconfigent("udp");
242 if (nconf_udp == NULL)
243 err(1, "getnetconfigent udp failed");
244 nb_udp.buf = ai_udp->ai_addr;
245 nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen;
246 if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp, &nb_udp)) ||
247 (!rpcb_set(RPCPROG_NFS, 3, nconf_udp, &nb_udp)))
248 err(1, "rpcb_set udp failed");
249 freeaddrinfo(ai_udp);
250 }
251 if (udpflag && ip6flag) {
252 memset(&hints, 0, sizeof hints);
253 hints.ai_flags = AI_PASSIVE;
254 hints.ai_family = AF_INET6;
255 hints.ai_socktype = SOCK_DGRAM;
256 hints.ai_protocol = IPPROTO_UDP;
257 ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6);
258 if (ecode != 0)
259 err(1, "getaddrinfo udp6: %s", gai_strerror(ecode));
260 nconf_udp6 = getnetconfigent("udp6");
261 if (nconf_udp6 == NULL)
262 err(1, "getnetconfigent udp6 failed");
263 nb_udp6.buf = ai_udp6->ai_addr;
264 nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen;
265 if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp6, &nb_udp6)) ||
266 (!rpcb_set(RPCPROG_NFS, 3, nconf_udp6, &nb_udp6)))
267 err(1, "rpcb_set udp6 failed");
268 freeaddrinfo(ai_udp6);
269 }
270 if (tcpflag) {
271 memset(&hints, 0, sizeof hints);
272 hints.ai_flags = AI_PASSIVE;
273 hints.ai_family = AF_INET;
274 hints.ai_socktype = SOCK_STREAM;
275 hints.ai_protocol = IPPROTO_TCP;
276 ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp);
277 if (ecode != 0)
278 err(1, "getaddrinfo tcp: %s", gai_strerror(ecode));
279 nconf_tcp = getnetconfigent("tcp");
280 if (nconf_tcp == NULL)
281 err(1, "getnetconfigent tcp failed");
282 nb_tcp.buf = ai_tcp->ai_addr;
283 nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen;
284 if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp, &nb_tcp)) ||
285 (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp, &nb_tcp)))
286 err(1, "rpcb_set tcp failed");
287 freeaddrinfo(ai_tcp);
288 }
289 if (tcpflag && ip6flag) {
290 memset(&hints, 0, sizeof hints);
291 hints.ai_flags = AI_PASSIVE;
292 hints.ai_family = AF_INET6;
293 hints.ai_socktype = SOCK_STREAM;
294 hints.ai_protocol = IPPROTO_TCP;
295 ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6);
296 if (ecode != 0)
297 err(1, "getaddrinfo tcp6: %s", gai_strerror(ecode));
298 nconf_tcp6 = getnetconfigent("tcp6");
299 if (nconf_tcp6 == NULL)
300 err(1, "getnetconfigent tcp6 failed");
301 nb_tcp6.buf = ai_tcp6->ai_addr;
302 nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen;
303 if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp6, &nb_tcp6)) ||
304 (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp6, &nb_tcp6)))
305 err(1, "rpcb_set tcp6 failed");
306 freeaddrinfo(ai_tcp6);
307 }
308 exit (0);
309 }
310 if (debug == 0) {
311 daemon(0, 0);
312 (void)signal(SIGHUP, SIG_IGN);
313 (void)signal(SIGINT, SIG_IGN);
314 /*
315 * nfsd sits in the kernel most of the time. It needs
316 * to ignore SIGTERM/SIGQUIT in order to stay alive as long
317 * as possible during a shutdown, otherwise loopback
318 * mounts will not be able to unmount.
319 */
320 (void)signal(SIGTERM, SIG_IGN);
321 (void)signal(SIGQUIT, SIG_IGN);
322 }
323 (void)signal(SIGSYS, nonfs);
324 (void)signal(SIGCHLD, reapchild);
325
326 openlog("nfsd", LOG_PID, LOG_DAEMON);
327
328 /* If we use UDP only, we start the last server below. */
329 srvcnt = tcpflag ? nfsdcnt : nfsdcnt - 1;
330 for (i = 0; i < srvcnt; i++) {
331 switch ((pid = fork())) {
332 case -1:
333 syslog(LOG_ERR, "fork: %m");
334 nfsd_exit(1);
335 case 0:
336 break;
337 default:
338 children[i] = pid;
339 continue;
340 }
341 (void)signal(SIGUSR1, child_cleanup);
342 setproctitle("server");
343
344 start_server(0);
345 }
346
347 (void)signal(SIGUSR1, cleanup);
348 FD_ZERO(&v4bits);
349 FD_ZERO(&v6bits);
350 FD_ZERO(&sockbits);
351
352 rpcbregcnt = 0;
353 /* Set up the socket for udp and rpcb register it. */
354 if (udpflag) {
355 rpcbreg = 0;
356 for (i = 0; i < bindhostc; i++) {
357 memset(&hints, 0, sizeof hints);
358 hints.ai_flags = AI_PASSIVE;
359 hints.ai_family = AF_INET;
360 hints.ai_socktype = SOCK_DGRAM;
361 hints.ai_protocol = IPPROTO_UDP;
362 if (setbindhost(&ai_udp, bindhost[i], hints) == 0) {
363 rpcbreg = 1;
364 rpcbregcnt++;
365 if ((sock = socket(ai_udp->ai_family,
366 ai_udp->ai_socktype,
367 ai_udp->ai_protocol)) < 0) {
368 syslog(LOG_ERR,
369 "can't create udp socket");
370 nfsd_exit(1);
371 }
372 if (bind(sock, ai_udp->ai_addr,
373 ai_udp->ai_addrlen) < 0) {
374 syslog(LOG_ERR,
375 "can't bind udp addr %s: %m",
376 bindhost[i]);
377 nfsd_exit(1);
378 }
379 freeaddrinfo(ai_udp);
380 nfsdargs.sock = sock;
381 nfsdargs.name = NULL;
382 nfsdargs.namelen = 0;
383 if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
384 syslog(LOG_ERR, "can't Add UDP socket");
385 nfsd_exit(1);
386 }
387 (void)close(sock);
388 }
389 }
390 if (rpcbreg == 1) {
391 memset(&hints, 0, sizeof hints);
392 hints.ai_flags = AI_PASSIVE;
393 hints.ai_family = AF_INET;
394 hints.ai_socktype = SOCK_DGRAM;
395 hints.ai_protocol = IPPROTO_UDP;
396 ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp);
397 if (ecode != 0) {
398 syslog(LOG_ERR, "getaddrinfo udp: %s",
399 gai_strerror(ecode));
400 nfsd_exit(1);
401 }
402 nconf_udp = getnetconfigent("udp");
403 if (nconf_udp == NULL)
404 err(1, "getnetconfigent udp failed");
405 nb_udp.buf = ai_udp->ai_addr;
406 nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen;
407 if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp, &nb_udp)) ||
408 (!rpcb_set(RPCPROG_NFS, 3, nconf_udp, &nb_udp)))
409 err(1, "rpcb_set udp failed");
410 freeaddrinfo(ai_udp);
411 }
412 }
413
414 /* Set up the socket for udp6 and rpcb register it. */
415 if (udpflag && ip6flag) {
416 rpcbreg = 0;
417 for (i = 0; i < bindhostc; i++) {
418 memset(&hints, 0, sizeof hints);
419 hints.ai_flags = AI_PASSIVE;
420 hints.ai_family = AF_INET6;
421 hints.ai_socktype = SOCK_DGRAM;
422 hints.ai_protocol = IPPROTO_UDP;
423 if (setbindhost(&ai_udp6, bindhost[i], hints) == 0) {
424 rpcbreg = 1;
425 rpcbregcnt++;
426 if ((sock = socket(ai_udp6->ai_family,
427 ai_udp6->ai_socktype,
428 ai_udp6->ai_protocol)) < 0) {
429 syslog(LOG_ERR,
430 "can't create udp6 socket");
431 nfsd_exit(1);
432 }
433 if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
434 &on, sizeof on) < 0) {
435 syslog(LOG_ERR,
436 "can't set v6-only binding for "
437 "udp6 socket: %m");
438 nfsd_exit(1);
439 }
440 if (bind(sock, ai_udp6->ai_addr,
441 ai_udp6->ai_addrlen) < 0) {
442 syslog(LOG_ERR,
443 "can't bind udp6 addr %s: %m",
444 bindhost[i]);
445 nfsd_exit(1);
446 }
447 freeaddrinfo(ai_udp6);
448 nfsdargs.sock = sock;
449 nfsdargs.name = NULL;
450 nfsdargs.namelen = 0;
451 if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
452 syslog(LOG_ERR,
453 "can't add UDP6 socket");
454 nfsd_exit(1);
455 }
456 (void)close(sock);
457 }
458 }
459 if (rpcbreg == 1) {
460 memset(&hints, 0, sizeof hints);
461 hints.ai_flags = AI_PASSIVE;
462 hints.ai_family = AF_INET6;
463 hints.ai_socktype = SOCK_DGRAM;
464 hints.ai_protocol = IPPROTO_UDP;
465 ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6);
466 if (ecode != 0) {
467 syslog(LOG_ERR, "getaddrinfo udp6: %s",
468 gai_strerror(ecode));
469 nfsd_exit(1);
470 }
471 nconf_udp6 = getnetconfigent("udp6");
472 if (nconf_udp6 == NULL)
473 err(1, "getnetconfigent udp6 failed");
474 nb_udp6.buf = ai_udp6->ai_addr;
475 nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen;
476 if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp6, &nb_udp6)) ||
477 (!rpcb_set(RPCPROG_NFS, 3, nconf_udp6, &nb_udp6)))
478 err(1, "rpcb_set udp6 failed");
479 freeaddrinfo(ai_udp6);
480 }
481 }
482
483 /* Set up the socket for tcp and rpcb register it. */
484 if (tcpflag) {
485 rpcbreg = 0;
486 for (i = 0; i < bindhostc; i++) {
487 memset(&hints, 0, sizeof hints);
488 hints.ai_flags = AI_PASSIVE;
489 hints.ai_family = AF_INET;
490 hints.ai_socktype = SOCK_STREAM;
491 hints.ai_protocol = IPPROTO_TCP;
492 if (setbindhost(&ai_tcp, bindhost[i], hints) == 0) {
493 rpcbreg = 1;
494 rpcbregcnt++;
495 if ((tcpsock = socket(AF_INET, SOCK_STREAM,
496 0)) < 0) {
497 syslog(LOG_ERR,
498 "can't create tpc socket");
499 nfsd_exit(1);
500 }
501 if (setsockopt(tcpsock, SOL_SOCKET,
502 SO_REUSEADDR,
503 (char *)&on, sizeof(on)) < 0)
504 syslog(LOG_ERR,
505 "setsockopt SO_REUSEADDR: %m");
506 if (bind(tcpsock, ai_tcp->ai_addr,
507 ai_tcp->ai_addrlen) < 0) {
508 syslog(LOG_ERR,
509 "can't bind tcp addr %s: %m",
510 bindhost[i]);
511 nfsd_exit(1);
512 }
513 if (listen(tcpsock, 5) < 0) {
514 syslog(LOG_ERR, "listen failed");
515 nfsd_exit(1);
516 }
517 freeaddrinfo(ai_tcp);
518 FD_SET(tcpsock, &sockbits);
519 FD_SET(tcpsock, &v4bits);
520 maxsock = tcpsock;
521 connect_type_cnt++;
522 }
523 }
524 if (rpcbreg == 1) {
525 memset(&hints, 0, sizeof hints);
526 hints.ai_flags = AI_PASSIVE;
527 hints.ai_family = AF_INET;
528 hints.ai_socktype = SOCK_STREAM;
529 hints.ai_protocol = IPPROTO_TCP;
530 ecode = getaddrinfo(NULL, "nfs", &hints,
531 &ai_tcp);
532 if (ecode != 0) {
533 syslog(LOG_ERR, "getaddrinfo tcp: %s",
534 gai_strerror(ecode));
535 nfsd_exit(1);
536 }
537 nconf_tcp = getnetconfigent("tcp");
538 if (nconf_tcp == NULL)
539 err(1, "getnetconfigent tcp failed");
540 nb_tcp.buf = ai_tcp->ai_addr;
541 nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen;
542 if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp,
543 &nb_tcp)) || (!rpcb_set(RPCPROG_NFS, 3,
544 nconf_tcp, &nb_tcp)))
545 err(1, "rpcb_set tcp failed");
546 freeaddrinfo(ai_tcp);
547 }
548 }
549
550 /* Set up the socket for tcp6 and rpcb register it. */
551 if (tcpflag && ip6flag) {
552 rpcbreg = 0;
553 for (i = 0; i < bindhostc; i++) {
554 memset(&hints, 0, sizeof hints);
555 hints.ai_flags = AI_PASSIVE;
556 hints.ai_family = AF_INET6;
557 hints.ai_socktype = SOCK_STREAM;
558 hints.ai_protocol = IPPROTO_TCP;
559 if (setbindhost(&ai_tcp6, bindhost[i], hints) == 0) {
560 rpcbreg = 1;
561 rpcbregcnt++;
562 if ((tcp6sock = socket(ai_tcp6->ai_family,
563 ai_tcp6->ai_socktype,
564 ai_tcp6->ai_protocol)) < 0) {
565 syslog(LOG_ERR,
566 "can't create tcp6 socket");
567 nfsd_exit(1);
568 }
569 if (setsockopt(tcp6sock, SOL_SOCKET,
570 SO_REUSEADDR,
571 (char *)&on, sizeof(on)) < 0)
572 syslog(LOG_ERR,
573 "setsockopt SO_REUSEADDR: %m");
574 if (setsockopt(tcp6sock, IPPROTO_IPV6,
575 IPV6_V6ONLY, &on, sizeof on) < 0) {
576 syslog(LOG_ERR,
577 "can't set v6-only binding for tcp6 "
578 "socket: %m");
579 nfsd_exit(1);
580 }
581 if (bind(tcp6sock, ai_tcp6->ai_addr,
582 ai_tcp6->ai_addrlen) < 0) {
583 syslog(LOG_ERR,
584 "can't bind tcp6 addr %s: %m",
585 bindhost[i]);
586 nfsd_exit(1);
587 }
588 if (listen(tcp6sock, 5) < 0) {
589 syslog(LOG_ERR, "listen failed");
590 nfsd_exit(1);
591 }
592 freeaddrinfo(ai_tcp6);
593 FD_SET(tcp6sock, &sockbits);
594 FD_SET(tcp6sock, &v6bits);
595 if (maxsock < tcp6sock)
596 maxsock = tcp6sock;
597 connect_type_cnt++;
598 }
599 }
600 if (rpcbreg == 1) {
601 memset(&hints, 0, sizeof hints);
602 hints.ai_flags = AI_PASSIVE;
603 hints.ai_family = AF_INET6;
604 hints.ai_socktype = SOCK_STREAM;
605 hints.ai_protocol = IPPROTO_TCP;
606 ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6);
607 if (ecode != 0) {
608 syslog(LOG_ERR, "getaddrinfo tcp6: %s",
609 gai_strerror(ecode));
610 nfsd_exit(1);
611 }
612 nconf_tcp6 = getnetconfigent("tcp6");
613 if (nconf_tcp6 == NULL)
614 err(1, "getnetconfigent tcp6 failed");
615 nb_tcp6.buf = ai_tcp6->ai_addr;
616 nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen;
617 if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp6, &nb_tcp6)) ||
618 (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp6, &nb_tcp6)))
619 err(1, "rpcb_set tcp6 failed");
620 freeaddrinfo(ai_tcp6);
621 }
622 }
623
624 if (rpcbregcnt == 0) {
625 syslog(LOG_ERR, "rpcb_set() failed, nothing to do: %m");
626 nfsd_exit(1);
627 }
628
629 if (tcpflag && connect_type_cnt == 0) {
630 syslog(LOG_ERR, "tcp connects == 0, nothing to do: %m");
631 nfsd_exit(1);
632 }
633
634 setproctitle("master");
635 /*
636 * We always want a master to have a clean way to to shut nfsd down
637 * (with unregistration): if the master is killed, it unregisters and
638 * kills all children. If we run for UDP only (and so do not have to
639 * loop waiting waiting for accept), we instead make the parent
640 * a "server" too. start_server will not return.
641 */
642 if (!tcpflag)
643 start_server(1);
644
645 /*
646 * Loop forever accepting connections and passing the sockets
647 * into the kernel for the mounts.
648 */
649 for (;;) {
650 ready = sockbits;
651 if (connect_type_cnt > 1) {
652 if (select(maxsock + 1,
653 &ready, NULL, NULL, NULL) < 1) {
654 syslog(LOG_ERR, "select failed: %m");
655 if (errno == EINTR)
656 continue;
657 nfsd_exit(1);
658 }
659 }
660 for (tcpsock = 0; tcpsock <= maxsock; tcpsock++) {
661 if (FD_ISSET(tcpsock, &ready)) {
662 if (FD_ISSET(tcpsock, &v4bits)) {
663 len = sizeof(inetpeer);
664 if ((msgsock = accept(tcpsock,
665 (struct sockaddr *)&inetpeer, &len)) < 0) {
666 syslog(LOG_ERR, "accept failed: %m");
667 if (errno == ECONNABORTED ||
668 errno == EINTR)
669 continue;
670 nfsd_exit(1);
671 }
672 memset(inetpeer.sin_zero, 0,
673 sizeof(inetpeer.sin_zero));
674 if (setsockopt(msgsock, SOL_SOCKET,
675 SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
676 syslog(LOG_ERR,
677 "setsockopt SO_KEEPALIVE: %m");
678 nfsdargs.sock = msgsock;
679 nfsdargs.name = (caddr_t)&inetpeer;
680 nfsdargs.namelen = len;
681 nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
682 (void)close(msgsock);
683 } else if (FD_ISSET(tcpsock, &v6bits)) {
684 len = sizeof(inet6peer);
685 if ((msgsock = accept(tcpsock,
686 (struct sockaddr *)&inet6peer,
687 &len)) < 0) {
688 syslog(LOG_ERR,
689 "accept failed: %m");
690 if (errno == ECONNABORTED ||
691 errno == EINTR)
692 continue;
693 nfsd_exit(1);
694 }
695 if (setsockopt(msgsock, SOL_SOCKET,
696 SO_KEEPALIVE, (char *)&on,
697 sizeof(on)) < 0)
698 syslog(LOG_ERR, "setsockopt "
699 "SO_KEEPALIVE: %m");
700 nfsdargs.sock = msgsock;
701 nfsdargs.name = (caddr_t)&inet6peer;
702 nfsdargs.namelen = len;
703 nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
704 (void)close(msgsock);
705 }
706 }
707 }
708 }
709}
710
711int
712setbindhost(struct addrinfo **ai, const char *bindhost, struct addrinfo hints)
713{
714 int ecode;
715 u_int32_t host_addr[4]; /* IPv4 or IPv6 */
716 const char *hostptr;
717
718 if (bindhost == NULL || strcmp("*", bindhost) == 0)
719 hostptr = NULL;
720 else
721 hostptr = bindhost;
722
723 if (hostptr != NULL) {
724 switch (hints.ai_family) {
725 case AF_INET:
726 if (inet_pton(AF_INET, hostptr, host_addr) == 1) {
727 hints.ai_flags = AI_NUMERICHOST;
728 } else {
729 if (inet_pton(AF_INET6, hostptr,
730 host_addr) == 1)
731 return (1);
732 }
733 break;
734 case AF_INET6:
735 if (inet_pton(AF_INET6, hostptr, host_addr) == 1) {
736 hints.ai_flags = AI_NUMERICHOST;
737 } else {
738 if (inet_pton(AF_INET, hostptr,
739 host_addr) == 1)
740 return (1);
741 }
742 break;
743 default:
744 break;
745 }
746 }
747
748 ecode = getaddrinfo(hostptr, "nfs", &hints, ai);
749 if (ecode != 0) {
750 syslog(LOG_ERR, "getaddrinfo %s: %s", bindhost,
751 gai_strerror(ecode));
752 return (1);
753 }
754 return (0);
755}
756
757void
758usage()
759{
760 (void)fprintf(stderr, "usage: nfsd %s\n", USAGE);
761 exit(1);
762}
763
764void
765nonfs(__unused int signo)
766{
767 syslog(LOG_ERR, "missing system call: NFS not available");
768}
769
770void
771reapchild(__unused int signo)
772{
773 pid_t pid;
774 int i;
775
776 while ((pid = wait3(NULL, WNOHANG, NULL)) > 0) {
777 for (i = 0; i < nfsdcnt; i++)
778 if (pid == children[i])
779 children[i] = -1;
780 }
781}
782
783void
784unregistration()
785{
786 if ((!rpcb_unset(RPCPROG_NFS, 2, NULL)) ||
787 (!rpcb_unset(RPCPROG_NFS, 3, NULL)))
788 syslog(LOG_ERR, "rpcb_unset failed");
789}
790
791void
792killchildren()
793{
794 int i;
795
796 for (i = 0; i < nfsdcnt; i++) {
797 if (children[i] > 0)
798 kill(children[i], SIGKILL);
799 }
800}
801
802/*
803 * Cleanup master after SIGUSR1.
804 */
805void
806cleanup(__unused int signo)
807{
808 nfsd_exit(0);
809}
810
811/*
812 * Cleanup child after SIGUSR1.
813 */
814void
815child_cleanup(__unused int signo)
816{
817 exit(0);
818}
819
820void
821nfsd_exit(int status)
822{
823 killchildren();
824 unregistration();
825 exit(status);
826}
827
828void
829start_server(int master)
830{
831 int status;
832
833 status = 0;
834 if (nfssvc(NFSSVC_NFSD, NULL) < 0) {
835 syslog(LOG_ERR, "nfssvc: %m");
836 status = 1;
837 }
838 if (master)
839 nfsd_exit(status);
840 else
841 exit(status);
842}
129 int on = 1, unregister, reregister, sock;
130 int tcp6sock, ip6flag, tcpflag, tcpsock;
131 int udpflag, ecode, s, srvcnt;
132 int bindhostc, bindanyflag, rpcbreg, rpcbregcnt;
133 char **bindhost = NULL;
134 pid_t pid;
135
136 if (modfind("nfsserver") < 0) {
137 /* Not present in kernel, try loading it */
138 if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0)
139 errx(1, "NFS server is not available");
140 }
141
142 nfsdcnt = DEFNFSDCNT;
143 unregister = reregister = tcpflag = maxsock = 0;
144 bindanyflag = udpflag = connect_type_cnt = bindhostc = 0;
145#define GETOPT "ah:n:rdtu"
146#define USAGE "[-ardtu] [-n num_servers] [-h bindip]"
147 while ((ch = getopt(argc, argv, GETOPT)) != -1)
148 switch (ch) {
149 case 'a':
150 bindanyflag = 1;
151 break;
152 case 'n':
153 nfsdcnt = atoi(optarg);
154 if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) {
155 warnx("nfsd count %d; reset to %d", nfsdcnt,
156 DEFNFSDCNT);
157 nfsdcnt = DEFNFSDCNT;
158 }
159 break;
160 case 'h':
161 bindhostc++;
162 bindhost = realloc(bindhost,sizeof(char *)*bindhostc);
163 if (bindhost == NULL)
164 errx(1, "Out of memory");
165 bindhost[bindhostc-1] = strdup(optarg);
166 if (bindhost[bindhostc-1] == NULL)
167 errx(1, "Out of memory");
168 break;
169 case 'r':
170 reregister = 1;
171 break;
172 case 'd':
173 unregister = 1;
174 break;
175 case 't':
176 tcpflag = 1;
177 break;
178 case 'u':
179 udpflag = 1;
180 break;
181 default:
182 case '?':
183 usage();
184 };
185 if (!tcpflag && !udpflag)
186 udpflag = 1;
187 argv += optind;
188 argc -= optind;
189
190 /*
191 * XXX
192 * Backward compatibility, trailing number is the count of daemons.
193 */
194 if (argc > 1)
195 usage();
196 if (argc == 1) {
197 nfsdcnt = atoi(argv[0]);
198 if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) {
199 warnx("nfsd count %d; reset to %d", nfsdcnt,
200 DEFNFSDCNT);
201 nfsdcnt = DEFNFSDCNT;
202 }
203 }
204
205 ip6flag = 1;
206 s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
207 if (s == -1) {
208 if (errno != EPROTONOSUPPORT)
209 err(1, "socket");
210 ip6flag = 0;
211 } else if (getnetconfigent("udp6") == NULL ||
212 getnetconfigent("tcp6") == NULL) {
213 ip6flag = 0;
214 }
215 if (s != -1)
216 close(s);
217
218 if (bindhostc == 0 || bindanyflag) {
219 bindhostc++;
220 bindhost = realloc(bindhost,sizeof(char *)*bindhostc);
221 if (bindhost == NULL)
222 errx(1, "Out of memory");
223 bindhost[bindhostc-1] = strdup("*");
224 if (bindhost[bindhostc-1] == NULL)
225 errx(1, "Out of memory");
226 }
227
228 if (unregister) {
229 unregistration();
230 exit (0);
231 }
232 if (reregister) {
233 if (udpflag) {
234 memset(&hints, 0, sizeof hints);
235 hints.ai_flags = AI_PASSIVE;
236 hints.ai_family = AF_INET;
237 hints.ai_socktype = SOCK_DGRAM;
238 hints.ai_protocol = IPPROTO_UDP;
239 ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp);
240 if (ecode != 0)
241 err(1, "getaddrinfo udp: %s", gai_strerror(ecode));
242 nconf_udp = getnetconfigent("udp");
243 if (nconf_udp == NULL)
244 err(1, "getnetconfigent udp failed");
245 nb_udp.buf = ai_udp->ai_addr;
246 nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen;
247 if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp, &nb_udp)) ||
248 (!rpcb_set(RPCPROG_NFS, 3, nconf_udp, &nb_udp)))
249 err(1, "rpcb_set udp failed");
250 freeaddrinfo(ai_udp);
251 }
252 if (udpflag && ip6flag) {
253 memset(&hints, 0, sizeof hints);
254 hints.ai_flags = AI_PASSIVE;
255 hints.ai_family = AF_INET6;
256 hints.ai_socktype = SOCK_DGRAM;
257 hints.ai_protocol = IPPROTO_UDP;
258 ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6);
259 if (ecode != 0)
260 err(1, "getaddrinfo udp6: %s", gai_strerror(ecode));
261 nconf_udp6 = getnetconfigent("udp6");
262 if (nconf_udp6 == NULL)
263 err(1, "getnetconfigent udp6 failed");
264 nb_udp6.buf = ai_udp6->ai_addr;
265 nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen;
266 if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp6, &nb_udp6)) ||
267 (!rpcb_set(RPCPROG_NFS, 3, nconf_udp6, &nb_udp6)))
268 err(1, "rpcb_set udp6 failed");
269 freeaddrinfo(ai_udp6);
270 }
271 if (tcpflag) {
272 memset(&hints, 0, sizeof hints);
273 hints.ai_flags = AI_PASSIVE;
274 hints.ai_family = AF_INET;
275 hints.ai_socktype = SOCK_STREAM;
276 hints.ai_protocol = IPPROTO_TCP;
277 ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp);
278 if (ecode != 0)
279 err(1, "getaddrinfo tcp: %s", gai_strerror(ecode));
280 nconf_tcp = getnetconfigent("tcp");
281 if (nconf_tcp == NULL)
282 err(1, "getnetconfigent tcp failed");
283 nb_tcp.buf = ai_tcp->ai_addr;
284 nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen;
285 if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp, &nb_tcp)) ||
286 (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp, &nb_tcp)))
287 err(1, "rpcb_set tcp failed");
288 freeaddrinfo(ai_tcp);
289 }
290 if (tcpflag && ip6flag) {
291 memset(&hints, 0, sizeof hints);
292 hints.ai_flags = AI_PASSIVE;
293 hints.ai_family = AF_INET6;
294 hints.ai_socktype = SOCK_STREAM;
295 hints.ai_protocol = IPPROTO_TCP;
296 ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6);
297 if (ecode != 0)
298 err(1, "getaddrinfo tcp6: %s", gai_strerror(ecode));
299 nconf_tcp6 = getnetconfigent("tcp6");
300 if (nconf_tcp6 == NULL)
301 err(1, "getnetconfigent tcp6 failed");
302 nb_tcp6.buf = ai_tcp6->ai_addr;
303 nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen;
304 if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp6, &nb_tcp6)) ||
305 (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp6, &nb_tcp6)))
306 err(1, "rpcb_set tcp6 failed");
307 freeaddrinfo(ai_tcp6);
308 }
309 exit (0);
310 }
311 if (debug == 0) {
312 daemon(0, 0);
313 (void)signal(SIGHUP, SIG_IGN);
314 (void)signal(SIGINT, SIG_IGN);
315 /*
316 * nfsd sits in the kernel most of the time. It needs
317 * to ignore SIGTERM/SIGQUIT in order to stay alive as long
318 * as possible during a shutdown, otherwise loopback
319 * mounts will not be able to unmount.
320 */
321 (void)signal(SIGTERM, SIG_IGN);
322 (void)signal(SIGQUIT, SIG_IGN);
323 }
324 (void)signal(SIGSYS, nonfs);
325 (void)signal(SIGCHLD, reapchild);
326
327 openlog("nfsd", LOG_PID, LOG_DAEMON);
328
329 /* If we use UDP only, we start the last server below. */
330 srvcnt = tcpflag ? nfsdcnt : nfsdcnt - 1;
331 for (i = 0; i < srvcnt; i++) {
332 switch ((pid = fork())) {
333 case -1:
334 syslog(LOG_ERR, "fork: %m");
335 nfsd_exit(1);
336 case 0:
337 break;
338 default:
339 children[i] = pid;
340 continue;
341 }
342 (void)signal(SIGUSR1, child_cleanup);
343 setproctitle("server");
344
345 start_server(0);
346 }
347
348 (void)signal(SIGUSR1, cleanup);
349 FD_ZERO(&v4bits);
350 FD_ZERO(&v6bits);
351 FD_ZERO(&sockbits);
352
353 rpcbregcnt = 0;
354 /* Set up the socket for udp and rpcb register it. */
355 if (udpflag) {
356 rpcbreg = 0;
357 for (i = 0; i < bindhostc; i++) {
358 memset(&hints, 0, sizeof hints);
359 hints.ai_flags = AI_PASSIVE;
360 hints.ai_family = AF_INET;
361 hints.ai_socktype = SOCK_DGRAM;
362 hints.ai_protocol = IPPROTO_UDP;
363 if (setbindhost(&ai_udp, bindhost[i], hints) == 0) {
364 rpcbreg = 1;
365 rpcbregcnt++;
366 if ((sock = socket(ai_udp->ai_family,
367 ai_udp->ai_socktype,
368 ai_udp->ai_protocol)) < 0) {
369 syslog(LOG_ERR,
370 "can't create udp socket");
371 nfsd_exit(1);
372 }
373 if (bind(sock, ai_udp->ai_addr,
374 ai_udp->ai_addrlen) < 0) {
375 syslog(LOG_ERR,
376 "can't bind udp addr %s: %m",
377 bindhost[i]);
378 nfsd_exit(1);
379 }
380 freeaddrinfo(ai_udp);
381 nfsdargs.sock = sock;
382 nfsdargs.name = NULL;
383 nfsdargs.namelen = 0;
384 if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
385 syslog(LOG_ERR, "can't Add UDP socket");
386 nfsd_exit(1);
387 }
388 (void)close(sock);
389 }
390 }
391 if (rpcbreg == 1) {
392 memset(&hints, 0, sizeof hints);
393 hints.ai_flags = AI_PASSIVE;
394 hints.ai_family = AF_INET;
395 hints.ai_socktype = SOCK_DGRAM;
396 hints.ai_protocol = IPPROTO_UDP;
397 ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp);
398 if (ecode != 0) {
399 syslog(LOG_ERR, "getaddrinfo udp: %s",
400 gai_strerror(ecode));
401 nfsd_exit(1);
402 }
403 nconf_udp = getnetconfigent("udp");
404 if (nconf_udp == NULL)
405 err(1, "getnetconfigent udp failed");
406 nb_udp.buf = ai_udp->ai_addr;
407 nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen;
408 if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp, &nb_udp)) ||
409 (!rpcb_set(RPCPROG_NFS, 3, nconf_udp, &nb_udp)))
410 err(1, "rpcb_set udp failed");
411 freeaddrinfo(ai_udp);
412 }
413 }
414
415 /* Set up the socket for udp6 and rpcb register it. */
416 if (udpflag && ip6flag) {
417 rpcbreg = 0;
418 for (i = 0; i < bindhostc; i++) {
419 memset(&hints, 0, sizeof hints);
420 hints.ai_flags = AI_PASSIVE;
421 hints.ai_family = AF_INET6;
422 hints.ai_socktype = SOCK_DGRAM;
423 hints.ai_protocol = IPPROTO_UDP;
424 if (setbindhost(&ai_udp6, bindhost[i], hints) == 0) {
425 rpcbreg = 1;
426 rpcbregcnt++;
427 if ((sock = socket(ai_udp6->ai_family,
428 ai_udp6->ai_socktype,
429 ai_udp6->ai_protocol)) < 0) {
430 syslog(LOG_ERR,
431 "can't create udp6 socket");
432 nfsd_exit(1);
433 }
434 if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
435 &on, sizeof on) < 0) {
436 syslog(LOG_ERR,
437 "can't set v6-only binding for "
438 "udp6 socket: %m");
439 nfsd_exit(1);
440 }
441 if (bind(sock, ai_udp6->ai_addr,
442 ai_udp6->ai_addrlen) < 0) {
443 syslog(LOG_ERR,
444 "can't bind udp6 addr %s: %m",
445 bindhost[i]);
446 nfsd_exit(1);
447 }
448 freeaddrinfo(ai_udp6);
449 nfsdargs.sock = sock;
450 nfsdargs.name = NULL;
451 nfsdargs.namelen = 0;
452 if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
453 syslog(LOG_ERR,
454 "can't add UDP6 socket");
455 nfsd_exit(1);
456 }
457 (void)close(sock);
458 }
459 }
460 if (rpcbreg == 1) {
461 memset(&hints, 0, sizeof hints);
462 hints.ai_flags = AI_PASSIVE;
463 hints.ai_family = AF_INET6;
464 hints.ai_socktype = SOCK_DGRAM;
465 hints.ai_protocol = IPPROTO_UDP;
466 ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6);
467 if (ecode != 0) {
468 syslog(LOG_ERR, "getaddrinfo udp6: %s",
469 gai_strerror(ecode));
470 nfsd_exit(1);
471 }
472 nconf_udp6 = getnetconfigent("udp6");
473 if (nconf_udp6 == NULL)
474 err(1, "getnetconfigent udp6 failed");
475 nb_udp6.buf = ai_udp6->ai_addr;
476 nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen;
477 if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp6, &nb_udp6)) ||
478 (!rpcb_set(RPCPROG_NFS, 3, nconf_udp6, &nb_udp6)))
479 err(1, "rpcb_set udp6 failed");
480 freeaddrinfo(ai_udp6);
481 }
482 }
483
484 /* Set up the socket for tcp and rpcb register it. */
485 if (tcpflag) {
486 rpcbreg = 0;
487 for (i = 0; i < bindhostc; i++) {
488 memset(&hints, 0, sizeof hints);
489 hints.ai_flags = AI_PASSIVE;
490 hints.ai_family = AF_INET;
491 hints.ai_socktype = SOCK_STREAM;
492 hints.ai_protocol = IPPROTO_TCP;
493 if (setbindhost(&ai_tcp, bindhost[i], hints) == 0) {
494 rpcbreg = 1;
495 rpcbregcnt++;
496 if ((tcpsock = socket(AF_INET, SOCK_STREAM,
497 0)) < 0) {
498 syslog(LOG_ERR,
499 "can't create tpc socket");
500 nfsd_exit(1);
501 }
502 if (setsockopt(tcpsock, SOL_SOCKET,
503 SO_REUSEADDR,
504 (char *)&on, sizeof(on)) < 0)
505 syslog(LOG_ERR,
506 "setsockopt SO_REUSEADDR: %m");
507 if (bind(tcpsock, ai_tcp->ai_addr,
508 ai_tcp->ai_addrlen) < 0) {
509 syslog(LOG_ERR,
510 "can't bind tcp addr %s: %m",
511 bindhost[i]);
512 nfsd_exit(1);
513 }
514 if (listen(tcpsock, 5) < 0) {
515 syslog(LOG_ERR, "listen failed");
516 nfsd_exit(1);
517 }
518 freeaddrinfo(ai_tcp);
519 FD_SET(tcpsock, &sockbits);
520 FD_SET(tcpsock, &v4bits);
521 maxsock = tcpsock;
522 connect_type_cnt++;
523 }
524 }
525 if (rpcbreg == 1) {
526 memset(&hints, 0, sizeof hints);
527 hints.ai_flags = AI_PASSIVE;
528 hints.ai_family = AF_INET;
529 hints.ai_socktype = SOCK_STREAM;
530 hints.ai_protocol = IPPROTO_TCP;
531 ecode = getaddrinfo(NULL, "nfs", &hints,
532 &ai_tcp);
533 if (ecode != 0) {
534 syslog(LOG_ERR, "getaddrinfo tcp: %s",
535 gai_strerror(ecode));
536 nfsd_exit(1);
537 }
538 nconf_tcp = getnetconfigent("tcp");
539 if (nconf_tcp == NULL)
540 err(1, "getnetconfigent tcp failed");
541 nb_tcp.buf = ai_tcp->ai_addr;
542 nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen;
543 if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp,
544 &nb_tcp)) || (!rpcb_set(RPCPROG_NFS, 3,
545 nconf_tcp, &nb_tcp)))
546 err(1, "rpcb_set tcp failed");
547 freeaddrinfo(ai_tcp);
548 }
549 }
550
551 /* Set up the socket for tcp6 and rpcb register it. */
552 if (tcpflag && ip6flag) {
553 rpcbreg = 0;
554 for (i = 0; i < bindhostc; i++) {
555 memset(&hints, 0, sizeof hints);
556 hints.ai_flags = AI_PASSIVE;
557 hints.ai_family = AF_INET6;
558 hints.ai_socktype = SOCK_STREAM;
559 hints.ai_protocol = IPPROTO_TCP;
560 if (setbindhost(&ai_tcp6, bindhost[i], hints) == 0) {
561 rpcbreg = 1;
562 rpcbregcnt++;
563 if ((tcp6sock = socket(ai_tcp6->ai_family,
564 ai_tcp6->ai_socktype,
565 ai_tcp6->ai_protocol)) < 0) {
566 syslog(LOG_ERR,
567 "can't create tcp6 socket");
568 nfsd_exit(1);
569 }
570 if (setsockopt(tcp6sock, SOL_SOCKET,
571 SO_REUSEADDR,
572 (char *)&on, sizeof(on)) < 0)
573 syslog(LOG_ERR,
574 "setsockopt SO_REUSEADDR: %m");
575 if (setsockopt(tcp6sock, IPPROTO_IPV6,
576 IPV6_V6ONLY, &on, sizeof on) < 0) {
577 syslog(LOG_ERR,
578 "can't set v6-only binding for tcp6 "
579 "socket: %m");
580 nfsd_exit(1);
581 }
582 if (bind(tcp6sock, ai_tcp6->ai_addr,
583 ai_tcp6->ai_addrlen) < 0) {
584 syslog(LOG_ERR,
585 "can't bind tcp6 addr %s: %m",
586 bindhost[i]);
587 nfsd_exit(1);
588 }
589 if (listen(tcp6sock, 5) < 0) {
590 syslog(LOG_ERR, "listen failed");
591 nfsd_exit(1);
592 }
593 freeaddrinfo(ai_tcp6);
594 FD_SET(tcp6sock, &sockbits);
595 FD_SET(tcp6sock, &v6bits);
596 if (maxsock < tcp6sock)
597 maxsock = tcp6sock;
598 connect_type_cnt++;
599 }
600 }
601 if (rpcbreg == 1) {
602 memset(&hints, 0, sizeof hints);
603 hints.ai_flags = AI_PASSIVE;
604 hints.ai_family = AF_INET6;
605 hints.ai_socktype = SOCK_STREAM;
606 hints.ai_protocol = IPPROTO_TCP;
607 ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6);
608 if (ecode != 0) {
609 syslog(LOG_ERR, "getaddrinfo tcp6: %s",
610 gai_strerror(ecode));
611 nfsd_exit(1);
612 }
613 nconf_tcp6 = getnetconfigent("tcp6");
614 if (nconf_tcp6 == NULL)
615 err(1, "getnetconfigent tcp6 failed");
616 nb_tcp6.buf = ai_tcp6->ai_addr;
617 nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen;
618 if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp6, &nb_tcp6)) ||
619 (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp6, &nb_tcp6)))
620 err(1, "rpcb_set tcp6 failed");
621 freeaddrinfo(ai_tcp6);
622 }
623 }
624
625 if (rpcbregcnt == 0) {
626 syslog(LOG_ERR, "rpcb_set() failed, nothing to do: %m");
627 nfsd_exit(1);
628 }
629
630 if (tcpflag && connect_type_cnt == 0) {
631 syslog(LOG_ERR, "tcp connects == 0, nothing to do: %m");
632 nfsd_exit(1);
633 }
634
635 setproctitle("master");
636 /*
637 * We always want a master to have a clean way to to shut nfsd down
638 * (with unregistration): if the master is killed, it unregisters and
639 * kills all children. If we run for UDP only (and so do not have to
640 * loop waiting waiting for accept), we instead make the parent
641 * a "server" too. start_server will not return.
642 */
643 if (!tcpflag)
644 start_server(1);
645
646 /*
647 * Loop forever accepting connections and passing the sockets
648 * into the kernel for the mounts.
649 */
650 for (;;) {
651 ready = sockbits;
652 if (connect_type_cnt > 1) {
653 if (select(maxsock + 1,
654 &ready, NULL, NULL, NULL) < 1) {
655 syslog(LOG_ERR, "select failed: %m");
656 if (errno == EINTR)
657 continue;
658 nfsd_exit(1);
659 }
660 }
661 for (tcpsock = 0; tcpsock <= maxsock; tcpsock++) {
662 if (FD_ISSET(tcpsock, &ready)) {
663 if (FD_ISSET(tcpsock, &v4bits)) {
664 len = sizeof(inetpeer);
665 if ((msgsock = accept(tcpsock,
666 (struct sockaddr *)&inetpeer, &len)) < 0) {
667 syslog(LOG_ERR, "accept failed: %m");
668 if (errno == ECONNABORTED ||
669 errno == EINTR)
670 continue;
671 nfsd_exit(1);
672 }
673 memset(inetpeer.sin_zero, 0,
674 sizeof(inetpeer.sin_zero));
675 if (setsockopt(msgsock, SOL_SOCKET,
676 SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
677 syslog(LOG_ERR,
678 "setsockopt SO_KEEPALIVE: %m");
679 nfsdargs.sock = msgsock;
680 nfsdargs.name = (caddr_t)&inetpeer;
681 nfsdargs.namelen = len;
682 nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
683 (void)close(msgsock);
684 } else if (FD_ISSET(tcpsock, &v6bits)) {
685 len = sizeof(inet6peer);
686 if ((msgsock = accept(tcpsock,
687 (struct sockaddr *)&inet6peer,
688 &len)) < 0) {
689 syslog(LOG_ERR,
690 "accept failed: %m");
691 if (errno == ECONNABORTED ||
692 errno == EINTR)
693 continue;
694 nfsd_exit(1);
695 }
696 if (setsockopt(msgsock, SOL_SOCKET,
697 SO_KEEPALIVE, (char *)&on,
698 sizeof(on)) < 0)
699 syslog(LOG_ERR, "setsockopt "
700 "SO_KEEPALIVE: %m");
701 nfsdargs.sock = msgsock;
702 nfsdargs.name = (caddr_t)&inet6peer;
703 nfsdargs.namelen = len;
704 nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
705 (void)close(msgsock);
706 }
707 }
708 }
709 }
710}
711
712int
713setbindhost(struct addrinfo **ai, const char *bindhost, struct addrinfo hints)
714{
715 int ecode;
716 u_int32_t host_addr[4]; /* IPv4 or IPv6 */
717 const char *hostptr;
718
719 if (bindhost == NULL || strcmp("*", bindhost) == 0)
720 hostptr = NULL;
721 else
722 hostptr = bindhost;
723
724 if (hostptr != NULL) {
725 switch (hints.ai_family) {
726 case AF_INET:
727 if (inet_pton(AF_INET, hostptr, host_addr) == 1) {
728 hints.ai_flags = AI_NUMERICHOST;
729 } else {
730 if (inet_pton(AF_INET6, hostptr,
731 host_addr) == 1)
732 return (1);
733 }
734 break;
735 case AF_INET6:
736 if (inet_pton(AF_INET6, hostptr, host_addr) == 1) {
737 hints.ai_flags = AI_NUMERICHOST;
738 } else {
739 if (inet_pton(AF_INET, hostptr,
740 host_addr) == 1)
741 return (1);
742 }
743 break;
744 default:
745 break;
746 }
747 }
748
749 ecode = getaddrinfo(hostptr, "nfs", &hints, ai);
750 if (ecode != 0) {
751 syslog(LOG_ERR, "getaddrinfo %s: %s", bindhost,
752 gai_strerror(ecode));
753 return (1);
754 }
755 return (0);
756}
757
758void
759usage()
760{
761 (void)fprintf(stderr, "usage: nfsd %s\n", USAGE);
762 exit(1);
763}
764
765void
766nonfs(__unused int signo)
767{
768 syslog(LOG_ERR, "missing system call: NFS not available");
769}
770
771void
772reapchild(__unused int signo)
773{
774 pid_t pid;
775 int i;
776
777 while ((pid = wait3(NULL, WNOHANG, NULL)) > 0) {
778 for (i = 0; i < nfsdcnt; i++)
779 if (pid == children[i])
780 children[i] = -1;
781 }
782}
783
784void
785unregistration()
786{
787 if ((!rpcb_unset(RPCPROG_NFS, 2, NULL)) ||
788 (!rpcb_unset(RPCPROG_NFS, 3, NULL)))
789 syslog(LOG_ERR, "rpcb_unset failed");
790}
791
792void
793killchildren()
794{
795 int i;
796
797 for (i = 0; i < nfsdcnt; i++) {
798 if (children[i] > 0)
799 kill(children[i], SIGKILL);
800 }
801}
802
803/*
804 * Cleanup master after SIGUSR1.
805 */
806void
807cleanup(__unused int signo)
808{
809 nfsd_exit(0);
810}
811
812/*
813 * Cleanup child after SIGUSR1.
814 */
815void
816child_cleanup(__unused int signo)
817{
818 exit(0);
819}
820
821void
822nfsd_exit(int status)
823{
824 killchildren();
825 unregistration();
826 exit(status);
827}
828
829void
830start_server(int master)
831{
832 int status;
833
834 status = 0;
835 if (nfssvc(NFSSVC_NFSD, NULL) < 0) {
836 syslog(LOG_ERR, "nfssvc: %m");
837 status = 1;
838 }
839 if (master)
840 nfsd_exit(status);
841 else
842 exit(status);
843}