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