Remove kerberosIV from the build.
[dragonfly.git] / sbin / nfsd / nfsd.c
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. 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  * @(#) Copyright (c) 1989, 1993, 1994 The Regents of the University of California.  All rights reserved.
37  * @(#)nfsd.c   8.9 (Berkeley) 3/29/95
38  * $FreeBSD: src/sbin/nfsd/nfsd.c,v 1.15.2.1 2000/09/16 22:52:23 brian Exp $
39  * $DragonFly: src/sbin/nfsd/nfsd.c,v 1.3 2003/08/05 07:45:42 asmodai Exp $
40  */
41
42 #include <sys/param.h>
43 #include <sys/syslog.h>
44 #include <sys/wait.h>
45 #include <sys/mount.h>
46
47 #include <rpc/rpc.h>
48 #include <rpc/pmap_clnt.h>
49
50 #include <netdb.h>
51 #include <arpa/inet.h>
52 #ifdef ISO
53 #include <netiso/iso.h>
54 #endif
55 #include <nfs/rpcv2.h>
56 #include <nfs/nfsproto.h>
57 #include <nfs/nfs.h>
58
59 #include <err.h>
60 #include <errno.h>
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <strings.h>
64 #include <unistd.h>
65
66 /* Global defs */
67 #ifdef DEBUG
68 #define syslog(e, s)    fprintf(stderr,(s))
69 int     debug = 1;
70 #else
71 int     debug = 0;
72 #endif
73
74 struct  nfsd_srvargs nsd;
75 #ifdef OLD_SETPROCTITLE
76 char    **Argv = NULL;          /* pointer to argument vector */
77 char    *LastArg = NULL;        /* end of argv */
78 #endif
79
80 #ifdef NFSKERB
81 char            lnam[ANAME_SZ];
82 KTEXT_ST        kt;
83 AUTH_DAT        kauth;
84 char            inst[INST_SZ];
85 struct nfsrpc_fullblock kin, kout;
86 struct nfsrpc_fullverf kverf;
87 NFSKERBKEY_T    kivec;
88 struct timeval  ktv;
89 NFSKERBKEYSCHED_T kerb_keysched;
90 #endif
91
92 void    nonfs __P((int));
93 void    reapchild __P((int));
94 void    setbindhost __P((struct sockaddr_in *ia, const char *bindhost));
95 #ifdef OLD_SETPROCTITLE
96 #ifdef __FreeBSD__
97 void    setproctitle __P((char *));
98 #endif
99 #endif
100 void    usage __P((void));
101
102 /*
103  * Nfs server daemon mostly just a user context for nfssvc()
104  *
105  * 1 - do file descriptor and signal cleanup
106  * 2 - fork the nfsd(s)
107  * 3 - create server socket(s)
108  * 4 - register socket with portmap
109  *
110  * For connectionless protocols, just pass the socket into the kernel via.
111  * nfssvc().
112  * For connection based sockets, loop doing accepts. When you get a new
113  * socket from accept, pass the msgsock into the kernel via. nfssvc().
114  * The arguments are:
115  *      -c - support iso cltp clients
116  *      -r - reregister with portmapper
117  *      -t - support tcp nfs clients
118  *      -u - support udp nfs clients
119  * followed by "n" which is the number of nfsds' to fork off
120  */
121 int
122 main(argc, argv, envp)
123         int argc;
124         char *argv[], *envp[];
125 {
126         struct nfsd_args nfsdargs;
127         struct sockaddr_in inetaddr, inetpeer;
128 #ifdef ISO
129         struct sockaddr_iso isoaddr, isopeer;
130         char *cp;
131 #endif
132         fd_set ready, sockbits;
133         int ch, cltpflag, connect_type_cnt, i, len, maxsock, msgsock;
134         int nfsdcnt, nfssvc_flag, on, reregister, sock, tcpflag, tcpsock;
135         int tp4cnt, tp4flag, tpipcnt, tpipflag, udpflag;
136         int bindhostc = 0, bindanyflag;
137         char **bindhost = NULL;
138 #ifdef notyet
139         int tp4sock, tpipsock;
140 #endif
141 #ifdef NFSKERB
142         struct group *grp;
143         struct passwd *pwd;
144         struct ucred *cr;
145         struct timeval ktv;
146         char **cpp;
147 #endif
148 #ifdef __FreeBSD__
149         struct vfsconf vfc;
150         int error;
151
152         error = getvfsbyname("nfs", &vfc);
153         if (error && vfsisloadable("nfs")) {
154                 if (vfsload("nfs"))
155                         err(1, "vfsload(nfs)");
156                 endvfsent();    /* flush cache */
157                 error = getvfsbyname("nfs", &vfc);
158         }
159         if (error)
160                 errx(1, "NFS is not available in the running kernel");
161 #endif
162
163 #ifdef OLD_SETPROCTITLE
164         /* Save start and extent of argv for setproctitle. */
165         Argv = argv;
166         if (envp == 0 || *envp == 0)
167                 envp = argv;
168         while (*envp)
169                 envp++;
170         LastArg = envp[-1] + strlen(envp[-1]);
171 #endif
172
173 #define MAXNFSDCNT      20
174 #define DEFNFSDCNT       4
175         nfsdcnt = DEFNFSDCNT;
176         cltpflag = reregister = tcpflag = tp4cnt = tp4flag = tpipcnt = 0;
177         bindanyflag = tpipflag = udpflag = 0;
178 #ifdef ISO
179 #define GETOPT  "ach:n:rtu"
180 #define USAGE   "[-acrtu] [-n num_servers] [-h bindip]"
181 #else
182 #define GETOPT  "ah:n:rtu"
183 #define USAGE   "[-artu] [-n num_servers] [-h bindip]"
184 #endif
185         while ((ch = getopt(argc, argv, GETOPT)) != -1)
186                 switch (ch) {
187                 case 'a':
188                         bindanyflag = 1;
189                         break;
190                 case 'n':
191                         nfsdcnt = atoi(optarg);
192                         if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) {
193                                 warnx("nfsd count %d; reset to %d", nfsdcnt,
194                                     DEFNFSDCNT);
195                                 nfsdcnt = DEFNFSDCNT;
196                         }
197                         break;
198                 case 'h':
199                         bindhostc++;
200                         bindhost = realloc(bindhost,sizeof(char *)*bindhostc);
201                         if (bindhost == NULL) 
202                                 errx(1, "Out of memory");
203                         bindhost[bindhostc-1] = strdup(optarg);
204                         if (bindhost[bindhostc-1] == NULL)
205                                 errx(1, "Out of memory");
206                         break;
207                 case 'r':
208                         reregister = 1;
209                         break;
210                 case 't':
211                         tcpflag = 1;
212                         break;
213                 case 'u':
214                         udpflag = 1;
215                         break;
216 #ifdef ISO
217                 case 'c':
218                         cltpflag = 1;
219                         break;
220 #ifdef notyet
221                 case 'i':
222                         tp4cnt = 1;
223                         break;
224                 case 'p':
225                         tpipcnt = 1;
226                         break;
227 #endif /* notyet */
228 #endif /* ISO */
229                 default:
230                 case '?':
231                         usage();
232                 };
233         if (!tcpflag && !udpflag)
234                 udpflag = 1;
235         argv += optind;
236         argc -= optind;
237
238         /*
239          * XXX
240          * Backward compatibility, trailing number is the count of daemons.
241          */
242         if (argc > 1)
243                 usage();
244         if (argc == 1) {
245                 nfsdcnt = atoi(argv[0]);
246                 if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) {
247                         warnx("nfsd count %d; reset to %d", nfsdcnt,
248                             DEFNFSDCNT);
249                         nfsdcnt = DEFNFSDCNT;
250                 }
251         }
252
253         if (bindhostc == 0 || bindanyflag) {
254                 bindhostc++;
255                 bindhost = realloc(bindhost,sizeof(char *)*bindhostc);
256                 if (bindhost == NULL) 
257                         errx(1, "Out of memory");
258                 bindhost[bindhostc-1] = strdup("*");
259                 if (bindhost[bindhostc-1] == NULL) 
260                         errx(1, "Out of memory");
261         }
262
263         if (debug == 0) {
264                 daemon(0, 0);
265                 (void)signal(SIGHUP, SIG_IGN);
266                 (void)signal(SIGINT, SIG_IGN);
267                 (void)signal(SIGQUIT, SIG_IGN);
268                 (void)signal(SIGSYS, nonfs);
269                 (void)signal(SIGTERM, SIG_IGN);
270         }
271         (void)signal(SIGCHLD, reapchild);
272
273         if (reregister) {
274                 if (udpflag &&
275                     (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) ||
276                      !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT)))
277                         err(1, "can't register with portmap for UDP");
278                 if (tcpflag &&
279                     (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) ||
280                      !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT)))
281                         err(1, "can't register with portmap for TCP");
282                 exit(0);
283         }
284         openlog("nfsd:", LOG_PID, LOG_DAEMON);
285
286         for (i = 0; i < nfsdcnt; i++) {
287                 switch (fork()) {
288                 case -1:
289                         syslog(LOG_ERR, "fork: %m");
290                         exit (1);
291                 case 0:
292                         break;
293                 default:
294                         continue;
295                 }
296
297                 setproctitle("server");
298                 nfssvc_flag = NFSSVC_NFSD;
299                 nsd.nsd_nfsd = NULL;
300 #ifdef NFSKERB
301                 if (sizeof (struct nfsrpc_fullverf) != RPCX_FULLVERF ||
302                     sizeof (struct nfsrpc_fullblock) != RPCX_FULLBLOCK)
303                     syslog(LOG_ERR, "Yikes NFSKERB structs not packed!");
304                 nsd.nsd_authstr = (u_char *)&kt;
305                 nsd.nsd_authlen = sizeof (kt);
306                 nsd.nsd_verfstr = (u_char *)&kverf;
307                 nsd.nsd_verflen = sizeof (kverf);
308 #endif
309                 while (nfssvc(nfssvc_flag, &nsd) < 0) {
310                         if (errno != ENEEDAUTH) {
311                                 syslog(LOG_ERR, "nfssvc: %m");
312                                 exit(1);
313                         }
314                         nfssvc_flag = NFSSVC_NFSD | NFSSVC_AUTHINFAIL;
315 #ifdef NFSKERB
316                         /*
317                          * Get the Kerberos ticket out of the authenticator
318                          * verify it and convert the principal name to a user
319                          * name. The user name is then converted to a set of
320                          * user credentials via the password and group file.
321                          * Finally, decrypt the timestamp and validate it.
322                          * For more info see the IETF Draft "Authentication
323                          * in ONC RPC".
324                          */
325                         kt.length = ntohl(kt.length);
326                         if (gettimeofday(&ktv, (struct timezone *)0) == 0 &&
327                             kt.length > 0 && kt.length <=
328                             (RPCAUTH_MAXSIZ - 3 * NFSX_UNSIGNED)) {
329                             kin.w1 = NFS_KERBW1(kt);
330                             kt.mbz = 0;
331                             (void)strcpy(inst, "*");
332                             if (krb_rd_req(&kt, NFS_KERBSRV,
333                                 inst, nsd.nsd_haddr, &kauth, "") == RD_AP_OK &&
334                                 krb_kntoln(&kauth, lnam) == KSUCCESS &&
335                                 (pwd = getpwnam(lnam)) != NULL) {
336                                 cr = &nsd.nsd_cr;
337                                 cr->cr_uid = pwd->pw_uid;
338                                 cr->cr_groups[0] = pwd->pw_gid;
339                                 cr->cr_ngroups = 1;
340                                 setgrent();
341                                 while ((grp = getgrent()) != NULL) {
342                                         if (grp->gr_gid == cr->cr_groups[0])
343                                                 continue;
344                                         for (cpp = grp->gr_mem;
345                                             *cpp != NULL; ++cpp)
346                                                 if (!strcmp(*cpp, lnam))
347                                                         break;
348                                         if (*cpp == NULL)
349                                                 continue;
350                                         cr->cr_groups[cr->cr_ngroups++]
351                                             = grp->gr_gid;
352                                         if (cr->cr_ngroups == NGROUPS)
353                                                 break;
354                                 }
355                                 endgrent();
356
357                                 /*
358                                  * Get the timestamp verifier out of the
359                                  * authenticator and verifier strings.
360                                  */
361                                 kin.t1 = kverf.t1;
362                                 kin.t2 = kverf.t2;
363                                 kin.w2 = kverf.w2;
364                                 bzero((caddr_t)kivec, sizeof (kivec));
365                                 bcopy((caddr_t)kauth.session,
366                                     (caddr_t)nsd.nsd_key,sizeof(kauth.session));
367
368                                 /*
369                                  * Decrypt the timestamp verifier in CBC mode.
370                                  */
371                                 XXX
372
373                                 /*
374                                  * Validate the timestamp verifier, to
375                                  * check that the session key is ok.
376                                  */
377                                 nsd.nsd_timestamp.tv_sec = ntohl(kout.t1);
378                                 nsd.nsd_timestamp.tv_usec = ntohl(kout.t2);
379                                 nsd.nsd_ttl = ntohl(kout.w1);
380                                 if ((nsd.nsd_ttl - 1) == ntohl(kout.w2))
381                                     nfssvc_flag = NFSSVC_NFSD | NFSSVC_AUTHIN;
382                         }
383 #endif /* NFSKERB */
384                 }
385                 exit(0);
386         }
387
388         /* If we are serving udp, set up the socket. */
389         for (i = 0; udpflag && i < bindhostc; i++) {
390                 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
391                         syslog(LOG_ERR, "can't create udp socket");
392                         exit(1);
393                 }
394                 setbindhost(&inetaddr, bindhost[i]);
395                 if (bind(sock,
396                     (struct sockaddr *)&inetaddr, sizeof(inetaddr)) < 0) {
397                         syslog(LOG_ERR, "can't bind udp addr %s: %m", bindhost[i]);
398                         exit(1);
399                 }
400                 if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) ||
401                     !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT)) {
402                         syslog(LOG_ERR, "can't register with udp portmap");
403                         exit(1);
404                 }
405                 nfsdargs.sock = sock;
406                 nfsdargs.name = NULL;
407                 nfsdargs.namelen = 0;
408                 if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
409                         syslog(LOG_ERR, "can't Add UDP socket");
410                         exit(1);
411                 }
412                 (void)close(sock);
413         }
414
415 #ifdef ISO
416         /* If we are serving cltp, set up the socket. */
417         if (cltpflag) {
418                 if ((sock = socket(AF_ISO, SOCK_DGRAM, 0)) < 0) {
419                         syslog(LOG_ERR, "can't create cltp socket");
420                         exit(1);
421                 }
422                 memset(&isoaddr, 0, sizeof(isoaddr));
423                 isoaddr.siso_family = AF_ISO;
424                 isoaddr.siso_tlen = 2;
425                 cp = TSEL(&isoaddr);
426                 *cp++ = (NFS_PORT >> 8);
427                 *cp = (NFS_PORT & 0xff);
428                 isoaddr.siso_len = sizeof(isoaddr);
429                 if (bind(sock,
430                     (struct sockaddr *)&isoaddr, sizeof(isoaddr)) < 0) {
431                         syslog(LOG_ERR, "can't bind cltp addr");
432                         exit(1);
433                 }
434 #ifdef notyet
435                 /*
436                  * XXX
437                  * Someday this should probably use "rpcbind", the son of
438                  * portmap.
439                  */
440                 if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT)) {
441                         syslog(LOG_ERR, "can't register with udp portmap");
442                         exit(1);
443                 }
444 #endif /* notyet */
445                 nfsdargs.sock = sock;
446                 nfsdargs.name = NULL;
447                 nfsdargs.namelen = 0;
448                 if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
449                         syslog(LOG_ERR, "can't add UDP socket");
450                         exit(1);
451                 }
452                 close(sock);
453         }
454 #endif /* ISO */
455
456         /* Now set up the master server socket waiting for tcp connections. */
457         on = 1;
458         FD_ZERO(&sockbits);
459         connect_type_cnt = 0;
460         for (i = 0; tcpflag && i < bindhostc; i++) {
461                 if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
462                         syslog(LOG_ERR, "can't create tcp socket");
463                         exit(1);
464                 }
465                 if (setsockopt(tcpsock,
466                     SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
467                         syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
468                 setbindhost(&inetaddr, bindhost[i]);
469                 if (bind(tcpsock,
470                     (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) {
471                         syslog(LOG_ERR, "can't bind tcp addr %s: %m", bindhost[i]);
472                         exit(1);
473                 }
474                 if (listen(tcpsock, 5) < 0) {
475                         syslog(LOG_ERR, "listen failed");
476                         exit(1);
477                 }
478                 if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) ||
479                     !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT)) {
480                         syslog(LOG_ERR, "can't register tcp with portmap");
481                         exit(1);
482                 }
483                 FD_SET(tcpsock, &sockbits);
484                 maxsock = tcpsock;
485                 connect_type_cnt++;
486         }
487
488 #ifdef notyet
489         /* Now set up the master server socket waiting for tp4 connections. */
490         if (tp4flag) {
491                 if ((tp4sock = socket(AF_ISO, SOCK_SEQPACKET, 0)) < 0) {
492                         syslog(LOG_ERR, "can't create tp4 socket");
493                         exit(1);
494                 }
495                 if (setsockopt(tp4sock,
496                     SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
497                         syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
498                 memset(&isoaddr, 0, sizeof(isoaddr));
499                 isoaddr.siso_family = AF_ISO;
500                 isoaddr.siso_tlen = 2;
501                 cp = TSEL(&isoaddr);
502                 *cp++ = (NFS_PORT >> 8);
503                 *cp = (NFS_PORT & 0xff);
504                 isoaddr.siso_len = sizeof(isoaddr);
505                 if (bind(tp4sock,
506                     (struct sockaddr *)&isoaddr, sizeof (isoaddr)) < 0) {
507                         syslog(LOG_ERR, "can't bind tp4 addr");
508                         exit(1);
509                 }
510                 if (listen(tp4sock, 5) < 0) {
511                         syslog(LOG_ERR, "listen failed");
512                         exit(1);
513                 }
514                 /*
515                  * XXX
516                  * Someday this should probably use "rpcbind", the son of
517                  * portmap.
518                  */
519                 if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
520                         syslog(LOG_ERR, "can't register tcp with portmap");
521                         exit(1);
522                 }
523                 FD_SET(tp4sock, &sockbits);
524                 maxsock = tp4sock;
525                 connect_type_cnt++;
526         }
527
528         /* Now set up the master server socket waiting for tpip connections. */
529         for (i = 0; tpipflag && i < bindhostc; i++) {
530                 if ((tpipsock = socket(AF_INET, SOCK_SEQPACKET, 0)) < 0) {
531                         syslog(LOG_ERR, "can't create tpip socket");
532                         exit(1);
533                 }
534                 if (setsockopt(tpipsock,
535                     SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
536                         syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
537                 setbindhost(&inetaddr, bindhost[i]);
538                 if (bind(tpipsock,
539                     (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) {
540                         syslog(LOG_ERR, "can't bind tcp addr %s: %m", bindhost[i]);
541                         exit(1);
542                 }
543                 if (listen(tpipsock, 5) < 0) {
544                         syslog(LOG_ERR, "listen failed");
545                         exit(1);
546                 }
547                 /*
548                  * XXX
549                  * Someday this should probably use "rpcbind", the son of
550                  * portmap.
551                  */
552                 if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
553                         syslog(LOG_ERR, "can't register tcp with portmap");
554                         exit(1);
555                 }
556                 FD_SET(tpipsock, &sockbits);
557                 maxsock = tpipsock;
558                 connect_type_cnt++;
559         }
560 #endif /* notyet */
561
562         if (connect_type_cnt == 0)
563                 exit(0);
564
565         setproctitle("master");
566
567         /*
568          * Loop forever accepting connections and passing the sockets
569          * into the kernel for the mounts.
570          */
571         for (;;) {
572                 ready = sockbits;
573                 if (connect_type_cnt > 1) {
574                         if (select(maxsock + 1,
575                             &ready, NULL, NULL, NULL) < 1) {
576                                 syslog(LOG_ERR, "select failed: %m");
577                                 exit(1);
578                         }
579                 }
580                 if (tcpflag && FD_ISSET(tcpsock, &ready)) {
581                         len = sizeof(inetpeer);
582                         if ((msgsock = accept(tcpsock,
583                             (struct sockaddr *)&inetpeer, &len)) < 0) {
584                                 syslog(LOG_ERR, "accept failed: %m");
585                                 exit(1);
586                         }
587                         memset(inetpeer.sin_zero, 0, sizeof(inetpeer.sin_zero));
588                         if (setsockopt(msgsock, SOL_SOCKET,
589                             SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
590                                 syslog(LOG_ERR,
591                                     "setsockopt SO_KEEPALIVE: %m");
592                         nfsdargs.sock = msgsock;
593                         nfsdargs.name = (caddr_t)&inetpeer;
594                         nfsdargs.namelen = sizeof(inetpeer);
595                         nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
596                         (void)close(msgsock);
597                 }
598 #ifdef notyet
599                 if (tp4flag && FD_ISSET(tp4sock, &ready)) {
600                         len = sizeof(isopeer);
601                         if ((msgsock = accept(tp4sock,
602                             (struct sockaddr *)&isopeer, &len)) < 0) {
603                                 syslog(LOG_ERR, "accept failed: %m");
604                                 exit(1);
605                         }
606                         if (setsockopt(msgsock, SOL_SOCKET,
607                             SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
608                                 syslog(LOG_ERR,
609                                     "setsockopt SO_KEEPALIVE: %m");
610                         nfsdargs.sock = msgsock;
611                         nfsdargs.name = (caddr_t)&isopeer;
612                         nfsdargs.namelen = len;
613                         nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
614                         (void)close(msgsock);
615                 }
616                 if (tpipflag && FD_ISSET(tpipsock, &ready)) {
617                         len = sizeof(inetpeer);
618                         if ((msgsock = accept(tpipsock,
619                             (struct sockaddr *)&inetpeer, &len)) < 0) {
620                                 syslog(LOG_ERR, "accept failed: %m");
621                                 exit(1);
622                         }
623                         if (setsockopt(msgsock, SOL_SOCKET,
624                             SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
625                                 syslog(LOG_ERR, "setsockopt SO_KEEPALIVE: %m");
626                         nfsdargs.sock = msgsock;
627                         nfsdargs.name = (caddr_t)&inetpeer;
628                         nfsdargs.namelen = len;
629                         nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
630                         (void)close(msgsock);
631                 }
632 #endif /* notyet */
633         }
634 }
635
636 void
637 setbindhost(struct sockaddr_in *ia, const char *bindhost)
638 {
639         ia->sin_family = AF_INET;
640         ia->sin_port = htons(NFS_PORT);
641         ia->sin_len = sizeof(*ia);
642         if (bindhost == NULL || strcmp(bindhost,"*") == 0) {
643                 ia->sin_addr.s_addr = INADDR_ANY;
644         } else {
645                 if (inet_aton(bindhost, &ia->sin_addr) == 0) {
646                         struct hostent *he;
647
648                         he = gethostbyname2(bindhost, ia->sin_family);
649                         if (he == NULL) {
650                                 syslog(LOG_ERR, "gethostbyname of %s failed", bindhost);
651                                 exit(1);
652                         }
653                         bcopy(he->h_addr, &ia->sin_addr, he->h_length);
654                 }
655         }
656 }
657
658 void
659 usage()
660 {
661         (void)fprintf(stderr, "usage: nfsd %s\n", USAGE);
662         exit(1);
663 }
664
665 void
666 nonfs(signo)
667         int signo;
668 {
669         syslog(LOG_ERR, "missing system call: NFS not available");
670 }
671
672 void
673 reapchild(signo)
674         int signo;
675 {
676
677         while (wait3(NULL, WNOHANG, NULL) > 0);
678 }
679
680 #ifdef OLD_SETPROCTITLE
681 #ifdef __FreeBSD__
682 void
683 setproctitle(a)
684         char *a;
685 {
686         register char *cp;
687         char buf[80];
688
689         cp = Argv[0];
690         (void)snprintf(buf, sizeof(buf), "nfsd-%s", a);
691         (void)strncpy(cp, buf, LastArg - cp);
692         cp += strlen(cp);
693         while (cp < LastArg)
694                 *cp++ = '\0';
695         Argv[1] = NULL;
696 }
697 #endif  /* __FreeBSD__ */
698 #endif