xref: /freebsd/usr.sbin/nfsd/nfsd.c (revision a62dc4065454b3af8bde3af9f005db2c4d802fec)
18fae3551SRodney W. Grimes /*
28fae3551SRodney W. Grimes  * Copyright (c) 1989, 1993, 1994
38fae3551SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
48fae3551SRodney W. Grimes  *
58fae3551SRodney W. Grimes  * This code is derived from software contributed to Berkeley by
68fae3551SRodney W. Grimes  * Rick Macklem at The University of Guelph.
78fae3551SRodney W. Grimes  *
88fae3551SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
98fae3551SRodney W. Grimes  * modification, are permitted provided that the following conditions
108fae3551SRodney W. Grimes  * are met:
118fae3551SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
128fae3551SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
138fae3551SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
148fae3551SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
158fae3551SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
168fae3551SRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
178fae3551SRodney W. Grimes  *    must display the following acknowledgement:
188fae3551SRodney W. Grimes  *	This product includes software developed by the University of
198fae3551SRodney W. Grimes  *	California, Berkeley and its contributors.
208fae3551SRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
218fae3551SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
228fae3551SRodney W. Grimes  *    without specific prior written permission.
238fae3551SRodney W. Grimes  *
248fae3551SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
258fae3551SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
268fae3551SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
278fae3551SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
288fae3551SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
298fae3551SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
308fae3551SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
318fae3551SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
328fae3551SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
338fae3551SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
348fae3551SRodney W. Grimes  * SUCH DAMAGE.
358fae3551SRodney W. Grimes  */
368fae3551SRodney W. Grimes 
378fae3551SRodney W. Grimes #ifndef lint
388fae3551SRodney W. Grimes static char copyright[] =
398fae3551SRodney W. Grimes "@(#) Copyright (c) 1989, 1993, 1994\n\
408fae3551SRodney W. Grimes 	The Regents of the University of California.  All rights reserved.\n";
418fae3551SRodney W. Grimes #endif not lint
428fae3551SRodney W. Grimes 
438fae3551SRodney W. Grimes #ifndef lint
448fae3551SRodney W. Grimes static char sccsid[] = "@(#)nfsd.c	8.7 (Berkeley) 2/22/94";
458fae3551SRodney W. Grimes #endif not lint
468fae3551SRodney W. Grimes 
478fae3551SRodney W. Grimes #include <sys/param.h>
488fae3551SRodney W. Grimes #include <sys/syslog.h>
498fae3551SRodney W. Grimes #include <sys/ioctl.h>
508fae3551SRodney W. Grimes #include <sys/stat.h>
518fae3551SRodney W. Grimes #include <sys/wait.h>
528fae3551SRodney W. Grimes #include <sys/uio.h>
538fae3551SRodney W. Grimes #include <sys/ucred.h>
548fae3551SRodney W. Grimes #include <sys/mount.h>
558fae3551SRodney W. Grimes #include <sys/socket.h>
568fae3551SRodney W. Grimes #include <sys/socketvar.h>
578fae3551SRodney W. Grimes 
588fae3551SRodney W. Grimes #include <rpc/rpc.h>
598fae3551SRodney W. Grimes #include <rpc/pmap_clnt.h>
608fae3551SRodney W. Grimes #include <rpc/pmap_prot.h>
618fae3551SRodney W. Grimes 
628fae3551SRodney W. Grimes #ifdef ISO
638fae3551SRodney W. Grimes #include <netiso/iso.h>
648fae3551SRodney W. Grimes #endif
658fae3551SRodney W. Grimes #include <nfs/rpcv2.h>
66a62dc406SDoug Rabson #include <nfs/nfsproto.h>
678fae3551SRodney W. Grimes #include <nfs/nfs.h>
688fae3551SRodney W. Grimes 
69a62dc406SDoug Rabson #ifdef NFSKERB
708fae3551SRodney W. Grimes #include <kerberosIV/des.h>
718fae3551SRodney W. Grimes #include <kerberosIV/krb.h>
728fae3551SRodney W. Grimes #endif
738fae3551SRodney W. Grimes 
748fae3551SRodney W. Grimes #include <err.h>
758fae3551SRodney W. Grimes #include <errno.h>
768fae3551SRodney W. Grimes #include <fcntl.h>
778fae3551SRodney W. Grimes #include <grp.h>
788fae3551SRodney W. Grimes #include <pwd.h>
798fae3551SRodney W. Grimes #include <signal.h>
808fae3551SRodney W. Grimes #include <stdio.h>
818fae3551SRodney W. Grimes #include <stdlib.h>
828fae3551SRodney W. Grimes #include <strings.h>
838fae3551SRodney W. Grimes #include <unistd.h>
848fae3551SRodney W. Grimes 
858fae3551SRodney W. Grimes /* Global defs */
868fae3551SRodney W. Grimes #ifdef DEBUG
878fae3551SRodney W. Grimes #define	syslog(e, s)	fprintf(stderr,(s))
888fae3551SRodney W. Grimes int	debug = 1;
898fae3551SRodney W. Grimes #else
908fae3551SRodney W. Grimes int	debug = 0;
918fae3551SRodney W. Grimes #endif
928fae3551SRodney W. Grimes 
938fae3551SRodney W. Grimes struct	nfsd_srvargs nsd;
948fae3551SRodney W. Grimes char	**Argv = NULL;		/* pointer to argument vector */
958fae3551SRodney W. Grimes char	*LastArg = NULL;	/* end of argv */
968fae3551SRodney W. Grimes 
97a62dc406SDoug Rabson #ifdef NFSKERB
988fae3551SRodney W. Grimes char		lnam[ANAME_SZ];
998fae3551SRodney W. Grimes KTEXT_ST	kt;
100a62dc406SDoug Rabson AUTH_DAT	kauth;
1018fae3551SRodney W. Grimes char		inst[INST_SZ];
102a62dc406SDoug Rabson struct nfsrpc_fullblock kin, kout;
103a62dc406SDoug Rabson struct nfsrpc_fullverf kverf;
104a62dc406SDoug Rabson NFSKERBKEY_T	kivec;
105a62dc406SDoug Rabson struct timeval	ktv;
106a62dc406SDoug Rabson NFSKERBKEYSCHED_T kerb_keysched;
1078fae3551SRodney W. Grimes #endif
1088fae3551SRodney W. Grimes 
1098fae3551SRodney W. Grimes void	nonfs __P((int));
1108fae3551SRodney W. Grimes void	reapchild __P((int));
111a62dc406SDoug Rabson #ifdef __FreeBSD__
1128fae3551SRodney W. Grimes void	setproctitle __P((char *));
113a62dc406SDoug Rabson #endif
1148fae3551SRodney W. Grimes void	usage __P((void));
1158fae3551SRodney W. Grimes 
1168fae3551SRodney W. Grimes /*
1178fae3551SRodney W. Grimes  * Nfs server daemon mostly just a user context for nfssvc()
1188fae3551SRodney W. Grimes  *
1198fae3551SRodney W. Grimes  * 1 - do file descriptor and signal cleanup
1208fae3551SRodney W. Grimes  * 2 - fork the nfsd(s)
1218fae3551SRodney W. Grimes  * 3 - create server socket(s)
1228fae3551SRodney W. Grimes  * 4 - register socket with portmap
1238fae3551SRodney W. Grimes  *
1248fae3551SRodney W. Grimes  * For connectionless protocols, just pass the socket into the kernel via.
1258fae3551SRodney W. Grimes  * nfssvc().
1268fae3551SRodney W. Grimes  * For connection based sockets, loop doing accepts. When you get a new
1278fae3551SRodney W. Grimes  * socket from accept, pass the msgsock into the kernel via. nfssvc().
1288fae3551SRodney W. Grimes  * The arguments are:
1298fae3551SRodney W. Grimes  *	-c - support iso cltp clients
1308fae3551SRodney W. Grimes  *	-r - reregister with portmapper
1318fae3551SRodney W. Grimes  *	-t - support tcp nfs clients
1328fae3551SRodney W. Grimes  *	-u - support udp nfs clients
1338fae3551SRodney W. Grimes  * followed by "n" which is the number of nfsds' to fork off
1348fae3551SRodney W. Grimes  */
1358fae3551SRodney W. Grimes int
1368fae3551SRodney W. Grimes main(argc, argv, envp)
1378fae3551SRodney W. Grimes 	int argc;
1388fae3551SRodney W. Grimes 	char *argv[], *envp[];
1398fae3551SRodney W. Grimes {
1408fae3551SRodney W. Grimes 	extern int optind;
1418fae3551SRodney W. Grimes 	struct group *grp;
1428fae3551SRodney W. Grimes 	struct nfsd_args nfsdargs;
1438fae3551SRodney W. Grimes 	struct passwd *pwd;
1448fae3551SRodney W. Grimes 	struct ucred *cr;
1458fae3551SRodney W. Grimes 	struct sockaddr_in inetaddr, inetpeer;
1468fae3551SRodney W. Grimes #ifdef ISO
1478fae3551SRodney W. Grimes 	struct sockaddr_iso isoaddr, isopeer;
1488fae3551SRodney W. Grimes #endif
149a62dc406SDoug Rabson 	struct timeval ktv;
1508fae3551SRodney W. Grimes 	fd_set ready, sockbits;
1518fae3551SRodney W. Grimes 	int ch, cltpflag, connect_type_cnt, i, len, maxsock, msgsock;
1528fae3551SRodney W. Grimes 	int nfsdcnt, nfssvc_flag, on, reregister, sock, tcpflag, tcpsock;
1538fae3551SRodney W. Grimes 	int tp4cnt, tp4flag, tp4sock, tpipcnt, tpipflag, tpipsock, udpflag;
1548fae3551SRodney W. Grimes 	char *cp, **cpp;
155a62dc406SDoug Rabson #ifdef __FreeBSD__
156d599144dSGarrett Wollman 	struct vfsconf *vfc;
157d599144dSGarrett Wollman 
158d599144dSGarrett Wollman 	vfc = getvfsbyname("nfs");
159d599144dSGarrett Wollman 	if(!vfc && vfsisloadable("nfs")) {
160d599144dSGarrett Wollman 		if(vfsload("nfs"))
161d599144dSGarrett Wollman 			err(1, "vfsload(nfs)");
162d599144dSGarrett Wollman 		endvfsent();	/* flush cache */
163d599144dSGarrett Wollman 		vfc = getvfsbyname("nfs"); /* probably unnecessary */
164d599144dSGarrett Wollman 	}
165d599144dSGarrett Wollman 	if(!vfc) {
166d599144dSGarrett Wollman 		errx(1, "NFS is not available in the running kernel");
167d599144dSGarrett Wollman 	}
168a62dc406SDoug Rabson #endif
1698fae3551SRodney W. Grimes 
1708fae3551SRodney W. Grimes 	/* Save start and extent of argv for setproctitle. */
1718fae3551SRodney W. Grimes 	Argv = argv;
1728fae3551SRodney W. Grimes 	if (envp == 0 || *envp == 0)
1738fae3551SRodney W. Grimes 		envp = argv;
1748fae3551SRodney W. Grimes 	while (*envp)
1758fae3551SRodney W. Grimes 		envp++;
1768fae3551SRodney W. Grimes 	LastArg = envp[-1] + strlen(envp[-1]);
1778fae3551SRodney W. Grimes 
1788fae3551SRodney W. Grimes #define	MAXNFSDCNT	20
1798fae3551SRodney W. Grimes #define	DEFNFSDCNT	 4
1808fae3551SRodney W. Grimes 	nfsdcnt = DEFNFSDCNT;
1818fae3551SRodney W. Grimes 	cltpflag = reregister = tcpflag = tp4cnt = tp4flag = tpipcnt = 0;
1828fae3551SRodney W. Grimes 	tpipflag = udpflag = 0;
1838fae3551SRodney W. Grimes #ifdef ISO
1848fae3551SRodney W. Grimes #define	GETOPT	"cn:rtu"
1858fae3551SRodney W. Grimes #define	USAGE	"[-crtu] [-n num_servers]"
1868fae3551SRodney W. Grimes #else
1878fae3551SRodney W. Grimes #define	GETOPT	"n:rtu"
1888fae3551SRodney W. Grimes #define	USAGE	"[-rtu] [-n num_servers]"
1898fae3551SRodney W. Grimes #endif
1908fae3551SRodney W. Grimes 	while ((ch = getopt(argc, argv, GETOPT)) != EOF)
1918fae3551SRodney W. Grimes 		switch (ch) {
1928fae3551SRodney W. Grimes 		case 'n':
1938fae3551SRodney W. Grimes 			nfsdcnt = atoi(optarg);
1948fae3551SRodney W. Grimes 			if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) {
1958fae3551SRodney W. Grimes 				warnx("nfsd count %d; reset to %d", DEFNFSDCNT);
1968fae3551SRodney W. Grimes 				nfsdcnt = DEFNFSDCNT;
1978fae3551SRodney W. Grimes 			}
1988fae3551SRodney W. Grimes 			break;
1998fae3551SRodney W. Grimes 		case 'r':
2008fae3551SRodney W. Grimes 			reregister = 1;
2018fae3551SRodney W. Grimes 			break;
2028fae3551SRodney W. Grimes 		case 't':
2038fae3551SRodney W. Grimes 			tcpflag = 1;
2048fae3551SRodney W. Grimes 			break;
2058fae3551SRodney W. Grimes 		case 'u':
2068fae3551SRodney W. Grimes 			udpflag = 1;
2078fae3551SRodney W. Grimes 			break;
2088fae3551SRodney W. Grimes #ifdef ISO
2098fae3551SRodney W. Grimes 		case 'c':
2108fae3551SRodney W. Grimes 			cltpflag = 1;
2118fae3551SRodney W. Grimes 			break;
2128fae3551SRodney W. Grimes #ifdef notyet
2138fae3551SRodney W. Grimes 		case 'i':
2148fae3551SRodney W. Grimes 			tp4cnt = 1;
2158fae3551SRodney W. Grimes 			break;
2168fae3551SRodney W. Grimes 		case 'p':
2178fae3551SRodney W. Grimes 			tpipcnt = 1;
2188fae3551SRodney W. Grimes 			break;
2198fae3551SRodney W. Grimes #endif /* notyet */
2208fae3551SRodney W. Grimes #endif /* ISO */
2218fae3551SRodney W. Grimes 		default:
2228fae3551SRodney W. Grimes 		case '?':
2238fae3551SRodney W. Grimes 			usage();
2248fae3551SRodney W. Grimes 		};
2258fae3551SRodney W. Grimes 	argv += optind;
2268fae3551SRodney W. Grimes 	argc -= optind;
2278fae3551SRodney W. Grimes 
2288fae3551SRodney W. Grimes 	/*
2298fae3551SRodney W. Grimes 	 * XXX
2308fae3551SRodney W. Grimes 	 * Backward compatibility, trailing number is the count of daemons.
2318fae3551SRodney W. Grimes 	 */
2328fae3551SRodney W. Grimes 	if (argc > 1)
2338fae3551SRodney W. Grimes 		usage();
2348fae3551SRodney W. Grimes 	if (argc == 1) {
2358fae3551SRodney W. Grimes 		nfsdcnt = atoi(argv[0]);
2368fae3551SRodney W. Grimes 		if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) {
2378fae3551SRodney W. Grimes 			warnx("nfsd count %d; reset to %d", DEFNFSDCNT);
2388fae3551SRodney W. Grimes 			nfsdcnt = DEFNFSDCNT;
2398fae3551SRodney W. Grimes 		}
2408fae3551SRodney W. Grimes 	}
2418fae3551SRodney W. Grimes 
2428fae3551SRodney W. Grimes 	if (debug == 0) {
2438fae3551SRodney W. Grimes 		daemon(0, 0);
2448fae3551SRodney W. Grimes 		(void)signal(SIGHUP, SIG_IGN);
2458fae3551SRodney W. Grimes 		(void)signal(SIGINT, SIG_IGN);
2468fae3551SRodney W. Grimes 		(void)signal(SIGQUIT, SIG_IGN);
2478fae3551SRodney W. Grimes 		(void)signal(SIGSYS, nonfs);
2488fae3551SRodney W. Grimes 		(void)signal(SIGTERM, SIG_IGN);
2498fae3551SRodney W. Grimes 	}
2508fae3551SRodney W. Grimes 	(void)signal(SIGCHLD, reapchild);
2518fae3551SRodney W. Grimes 
2528fae3551SRodney W. Grimes 	if (reregister) {
2538fae3551SRodney W. Grimes 		if (udpflag &&
254a62dc406SDoug Rabson 		    (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) ||
255a62dc406SDoug Rabson 		     !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT)))
2568fae3551SRodney W. Grimes 			err(1, "can't register with portmap for UDP.");
2578fae3551SRodney W. Grimes 		if (tcpflag &&
258a62dc406SDoug Rabson 		    (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) ||
259a62dc406SDoug Rabson 		     !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT)))
2608fae3551SRodney W. Grimes 			err(1, "can't register with portmap for TCP.");
2618fae3551SRodney W. Grimes 		exit(0);
2628fae3551SRodney W. Grimes 	}
2638fae3551SRodney W. Grimes 	openlog("nfsd:", LOG_PID, LOG_DAEMON);
2648fae3551SRodney W. Grimes 
2658fae3551SRodney W. Grimes 	for (i = 0; i < nfsdcnt; i++) {
2668fae3551SRodney W. Grimes 		switch (fork()) {
2678fae3551SRodney W. Grimes 		case -1:
2688fae3551SRodney W. Grimes 			syslog(LOG_ERR, "fork: %m");
2698fae3551SRodney W. Grimes 			exit (1);
2708fae3551SRodney W. Grimes 		case 0:
2718fae3551SRodney W. Grimes 			break;
2728fae3551SRodney W. Grimes 		default:
2738fae3551SRodney W. Grimes 			continue;
2748fae3551SRodney W. Grimes 		}
2758fae3551SRodney W. Grimes 
276a62dc406SDoug Rabson 		setproctitle("server");
2778fae3551SRodney W. Grimes 		nfssvc_flag = NFSSVC_NFSD;
2788fae3551SRodney W. Grimes 		nsd.nsd_nfsd = NULL;
279a62dc406SDoug Rabson #ifdef NFSKERB
280a62dc406SDoug Rabson 		if (sizeof (struct nfsrpc_fullverf) != RPCX_FULLVERF ||
281a62dc406SDoug Rabson 		    sizeof (struct nfsrpc_fullblock) != RPCX_FULLBLOCK)
282a62dc406SDoug Rabson 		    syslog(LOG_ERR, "Yikes NFSKERB structs not packed!");
283a62dc406SDoug Rabson 		nsd.nsd_authstr = (u_char *)&kt;
284a62dc406SDoug Rabson 		nsd.nsd_authlen = sizeof (kt);
285a62dc406SDoug Rabson 		nsd.nsd_verfstr = (u_char *)&kverf;
286a62dc406SDoug Rabson 		nsd.nsd_verflen = sizeof (kverf);
2878fae3551SRodney W. Grimes #endif
2888fae3551SRodney W. Grimes 		while (nfssvc(nfssvc_flag, &nsd) < 0) {
2898fae3551SRodney W. Grimes 			if (errno != ENEEDAUTH) {
2908fae3551SRodney W. Grimes 				syslog(LOG_ERR, "nfssvc: %m");
2918fae3551SRodney W. Grimes 				exit(1);
2928fae3551SRodney W. Grimes 			}
2938fae3551SRodney W. Grimes 			nfssvc_flag = NFSSVC_NFSD | NFSSVC_AUTHINFAIL;
294a62dc406SDoug Rabson #ifdef NFSKERB
295a62dc406SDoug Rabson 			/*
296a62dc406SDoug Rabson 			 * Get the Kerberos ticket out of the authenticator
297a62dc406SDoug Rabson 			 * verify it and convert the principal name to a user
298a62dc406SDoug Rabson 			 * name. The user name is then converted to a set of
299a62dc406SDoug Rabson 			 * user credentials via the password and group file.
300a62dc406SDoug Rabson 			 * Finally, decrypt the timestamp and validate it.
301a62dc406SDoug Rabson 			 * For more info see the IETF Draft "Authentication
302a62dc406SDoug Rabson 			 * in ONC RPC".
303a62dc406SDoug Rabson 			 */
304a62dc406SDoug Rabson 			kt.length = ntohl(kt.length);
305a62dc406SDoug Rabson 			if (gettimeofday(&ktv, (struct timezone *)0) == 0 &&
306a62dc406SDoug Rabson 			    kt.length > 0 && kt.length <=
307a62dc406SDoug Rabson 			    (RPCAUTH_MAXSIZ - 3 * NFSX_UNSIGNED)) {
308a62dc406SDoug Rabson 			    kin.w1 = NFS_KERBW1(kt);
3098fae3551SRodney W. Grimes 			    kt.mbz = 0;
3108fae3551SRodney W. Grimes 			    (void)strcpy(inst, "*");
311a62dc406SDoug Rabson 			    if (krb_rd_req(&kt, NFS_KERBSRV,
312a62dc406SDoug Rabson 				inst, nsd.nsd_haddr, &kauth, "") == RD_AP_OK &&
313a62dc406SDoug Rabson 				krb_kntoln(&kauth, lnam) == KSUCCESS &&
3148fae3551SRodney W. Grimes 				(pwd = getpwnam(lnam)) != NULL) {
3158fae3551SRodney W. Grimes 				cr = &nsd.nsd_cr;
3168fae3551SRodney W. Grimes 				cr->cr_uid = pwd->pw_uid;
3178fae3551SRodney W. Grimes 				cr->cr_groups[0] = pwd->pw_gid;
3188fae3551SRodney W. Grimes 				cr->cr_ngroups = 1;
3198fae3551SRodney W. Grimes 				setgrent();
3208fae3551SRodney W. Grimes 				while ((grp = getgrent()) != NULL) {
3218fae3551SRodney W. Grimes 					if (grp->gr_gid == cr->cr_groups[0])
3228fae3551SRodney W. Grimes 						continue;
3238fae3551SRodney W. Grimes 					for (cpp = grp->gr_mem;
3248fae3551SRodney W. Grimes 					    *cpp != NULL; ++cpp)
3258fae3551SRodney W. Grimes 						if (!strcmp(*cpp, lnam))
3268fae3551SRodney W. Grimes 							break;
3278fae3551SRodney W. Grimes 					if (*cpp == NULL)
3288fae3551SRodney W. Grimes 						continue;
3298fae3551SRodney W. Grimes 					cr->cr_groups[cr->cr_ngroups++]
3308fae3551SRodney W. Grimes 					    = grp->gr_gid;
3318fae3551SRodney W. Grimes 					if (cr->cr_ngroups == NGROUPS)
3328fae3551SRodney W. Grimes 						break;
3338fae3551SRodney W. Grimes 				}
3348fae3551SRodney W. Grimes 				endgrent();
335a62dc406SDoug Rabson 
336a62dc406SDoug Rabson 				/*
337a62dc406SDoug Rabson 				 * Get the timestamp verifier out of the
338a62dc406SDoug Rabson 				 * authenticator and verifier strings.
339a62dc406SDoug Rabson 				 */
340a62dc406SDoug Rabson 				kin.t1 = kverf.t1;
341a62dc406SDoug Rabson 				kin.t2 = kverf.t2;
342a62dc406SDoug Rabson 				kin.w2 = kverf.w2;
343a62dc406SDoug Rabson 				bzero((caddr_t)kivec, sizeof (kivec));
344a62dc406SDoug Rabson 				bcopy((caddr_t)kauth.session,
345a62dc406SDoug Rabson 				    (caddr_t)nsd.nsd_key,sizeof(kauth.session));
346a62dc406SDoug Rabson 
347a62dc406SDoug Rabson 				/*
348a62dc406SDoug Rabson 				 * Decrypt the timestamp verifier in CBC mode.
349a62dc406SDoug Rabson 				 */
350a62dc406SDoug Rabson 				XXX
351a62dc406SDoug Rabson 
352a62dc406SDoug Rabson 				/*
353a62dc406SDoug Rabson 				 * Validate the timestamp verifier, to
354a62dc406SDoug Rabson 				 * check that the session key is ok.
355a62dc406SDoug Rabson 				 */
356a62dc406SDoug Rabson 				nsd.nsd_timestamp.tv_sec = ntohl(kout.t1);
357a62dc406SDoug Rabson 				nsd.nsd_timestamp.tv_usec = ntohl(kout.t2);
358a62dc406SDoug Rabson 				nsd.nsd_ttl = ntohl(kout.w1);
359a62dc406SDoug Rabson 				if ((nsd.nsd_ttl - 1) == ntohl(kout.w2))
3608fae3551SRodney W. Grimes 				    nfssvc_flag = NFSSVC_NFSD | NFSSVC_AUTHIN;
3618fae3551SRodney W. Grimes 			}
362a62dc406SDoug Rabson #endif /* NFSKERB */
3638fae3551SRodney W. Grimes 		}
3648fae3551SRodney W. Grimes 		exit(0);
3658fae3551SRodney W. Grimes 	}
3668fae3551SRodney W. Grimes 
3678fae3551SRodney W. Grimes 	/* If we are serving udp, set up the socket. */
3688fae3551SRodney W. Grimes 	if (udpflag) {
3698fae3551SRodney W. Grimes 		if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
3708fae3551SRodney W. Grimes 			syslog(LOG_ERR, "can't create udp socket");
3718fae3551SRodney W. Grimes 			exit(1);
3728fae3551SRodney W. Grimes 		}
3738fae3551SRodney W. Grimes 		inetaddr.sin_family = AF_INET;
3748fae3551SRodney W. Grimes 		inetaddr.sin_addr.s_addr = INADDR_ANY;
3758fae3551SRodney W. Grimes 		inetaddr.sin_port = htons(NFS_PORT);
3768fae3551SRodney W. Grimes 		inetaddr.sin_len = sizeof(inetaddr);
3778fae3551SRodney W. Grimes 		if (bind(sock,
3788fae3551SRodney W. Grimes 		    (struct sockaddr *)&inetaddr, sizeof(inetaddr)) < 0) {
3798fae3551SRodney W. Grimes 			syslog(LOG_ERR, "can't bind udp addr");
3808fae3551SRodney W. Grimes 			exit(1);
3818fae3551SRodney W. Grimes 		}
382a62dc406SDoug Rabson 		if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) ||
383a62dc406SDoug Rabson 		    !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT)) {
3848fae3551SRodney W. Grimes 			syslog(LOG_ERR, "can't register with udp portmap");
3858fae3551SRodney W. Grimes 			exit(1);
3868fae3551SRodney W. Grimes 		}
3878fae3551SRodney W. Grimes 		nfsdargs.sock = sock;
3888fae3551SRodney W. Grimes 		nfsdargs.name = NULL;
3898fae3551SRodney W. Grimes 		nfsdargs.namelen = 0;
3908fae3551SRodney W. Grimes 		if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
3918fae3551SRodney W. Grimes 			syslog(LOG_ERR, "can't Add UDP socket");
3928fae3551SRodney W. Grimes 			exit(1);
3938fae3551SRodney W. Grimes 		}
3948fae3551SRodney W. Grimes 		(void)close(sock);
3958fae3551SRodney W. Grimes 	}
3968fae3551SRodney W. Grimes 
3978fae3551SRodney W. Grimes #ifdef ISO
3988fae3551SRodney W. Grimes 	/* If we are serving cltp, set up the socket. */
3998fae3551SRodney W. Grimes 	if (cltpflag) {
4008fae3551SRodney W. Grimes 		if ((sock = socket(AF_ISO, SOCK_DGRAM, 0)) < 0) {
4018fae3551SRodney W. Grimes 			syslog(LOG_ERR, "can't create cltp socket");
4028fae3551SRodney W. Grimes 			exit(1);
4038fae3551SRodney W. Grimes 		}
4048fae3551SRodney W. Grimes 		memset(&isoaddr, 0, sizeof(isoaddr));
4058fae3551SRodney W. Grimes 		isoaddr.siso_family = AF_ISO;
4068fae3551SRodney W. Grimes 		isoaddr.siso_tlen = 2;
4078fae3551SRodney W. Grimes 		cp = TSEL(&isoaddr);
4088fae3551SRodney W. Grimes 		*cp++ = (NFS_PORT >> 8);
4098fae3551SRodney W. Grimes 		*cp = (NFS_PORT & 0xff);
4108fae3551SRodney W. Grimes 		isoaddr.siso_len = sizeof(isoaddr);
4118fae3551SRodney W. Grimes 		if (bind(sock,
4128fae3551SRodney W. Grimes 		    (struct sockaddr *)&isoaddr, sizeof(isoaddr)) < 0) {
4138fae3551SRodney W. Grimes 			syslog(LOG_ERR, "can't bind cltp addr");
4148fae3551SRodney W. Grimes 			exit(1);
4158fae3551SRodney W. Grimes 		}
4168fae3551SRodney W. Grimes #ifdef notyet
4178fae3551SRodney W. Grimes 		/*
4188fae3551SRodney W. Grimes 		 * XXX
4198fae3551SRodney W. Grimes 		 * Someday this should probably use "rpcbind", the son of
4208fae3551SRodney W. Grimes 		 * portmap.
4218fae3551SRodney W. Grimes 		 */
4228fae3551SRodney W. Grimes 		if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT)) {
4238fae3551SRodney W. Grimes 			syslog(LOG_ERR, "can't register with udp portmap");
4248fae3551SRodney W. Grimes 			exit(1);
4258fae3551SRodney W. Grimes 		}
4268fae3551SRodney W. Grimes #endif /* notyet */
4278fae3551SRodney W. Grimes 		nfsdargs.sock = sock;
4288fae3551SRodney W. Grimes 		nfsdargs.name = NULL;
4298fae3551SRodney W. Grimes 		nfsdargs.namelen = 0;
4308fae3551SRodney W. Grimes 		if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
4318fae3551SRodney W. Grimes 			syslog(LOG_ERR, "can't add UDP socket");
4328fae3551SRodney W. Grimes 			exit(1);
4338fae3551SRodney W. Grimes 		}
4348fae3551SRodney W. Grimes 		close(sock);
4358fae3551SRodney W. Grimes 	}
4368fae3551SRodney W. Grimes #endif /* ISO */
4378fae3551SRodney W. Grimes 
4388fae3551SRodney W. Grimes 	/* Now set up the master server socket waiting for tcp connections. */
4398fae3551SRodney W. Grimes 	on = 1;
4408fae3551SRodney W. Grimes 	FD_ZERO(&sockbits);
4418fae3551SRodney W. Grimes 	connect_type_cnt = 0;
4428fae3551SRodney W. Grimes 	if (tcpflag) {
4438fae3551SRodney W. Grimes 		if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
4448fae3551SRodney W. Grimes 			syslog(LOG_ERR, "can't create tcp socket");
4458fae3551SRodney W. Grimes 			exit(1);
4468fae3551SRodney W. Grimes 		}
4478fae3551SRodney W. Grimes 		if (setsockopt(tcpsock,
4488fae3551SRodney W. Grimes 		    SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
4498fae3551SRodney W. Grimes 			syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
4508fae3551SRodney W. Grimes 		inetaddr.sin_family = AF_INET;
4518fae3551SRodney W. Grimes 		inetaddr.sin_addr.s_addr = INADDR_ANY;
4528fae3551SRodney W. Grimes 		inetaddr.sin_port = htons(NFS_PORT);
4538fae3551SRodney W. Grimes 		inetaddr.sin_len = sizeof(inetaddr);
4548fae3551SRodney W. Grimes 		if (bind(tcpsock,
4558fae3551SRodney W. Grimes 		    (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) {
4568fae3551SRodney W. Grimes 			syslog(LOG_ERR, "can't bind tcp addr");
4578fae3551SRodney W. Grimes 			exit(1);
4588fae3551SRodney W. Grimes 		}
4598fae3551SRodney W. Grimes 		if (listen(tcpsock, 5) < 0) {
4608fae3551SRodney W. Grimes 			syslog(LOG_ERR, "listen failed");
4618fae3551SRodney W. Grimes 			exit(1);
4628fae3551SRodney W. Grimes 		}
463a62dc406SDoug Rabson 		if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) ||
464a62dc406SDoug Rabson 		    !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT)) {
4658fae3551SRodney W. Grimes 			syslog(LOG_ERR, "can't register tcp with portmap");
4668fae3551SRodney W. Grimes 			exit(1);
4678fae3551SRodney W. Grimes 		}
4688fae3551SRodney W. Grimes 		FD_SET(tcpsock, &sockbits);
4698fae3551SRodney W. Grimes 		maxsock = tcpsock;
4708fae3551SRodney W. Grimes 		connect_type_cnt++;
4718fae3551SRodney W. Grimes 	}
4728fae3551SRodney W. Grimes 
4738fae3551SRodney W. Grimes #ifdef notyet
4748fae3551SRodney W. Grimes 	/* Now set up the master server socket waiting for tp4 connections. */
4758fae3551SRodney W. Grimes 	if (tp4flag) {
4768fae3551SRodney W. Grimes 		if ((tp4sock = socket(AF_ISO, SOCK_SEQPACKET, 0)) < 0) {
4778fae3551SRodney W. Grimes 			syslog(LOG_ERR, "can't create tp4 socket");
4788fae3551SRodney W. Grimes 			exit(1);
4798fae3551SRodney W. Grimes 		}
4808fae3551SRodney W. Grimes 		if (setsockopt(tp4sock,
4818fae3551SRodney W. Grimes 		    SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
4828fae3551SRodney W. Grimes 			syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
4838fae3551SRodney W. Grimes 		memset(&isoaddr, 0, sizeof(isoaddr));
4848fae3551SRodney W. Grimes 		isoaddr.siso_family = AF_ISO;
4858fae3551SRodney W. Grimes 		isoaddr.siso_tlen = 2;
4868fae3551SRodney W. Grimes 		cp = TSEL(&isoaddr);
4878fae3551SRodney W. Grimes 		*cp++ = (NFS_PORT >> 8);
4888fae3551SRodney W. Grimes 		*cp = (NFS_PORT & 0xff);
4898fae3551SRodney W. Grimes 		isoaddr.siso_len = sizeof(isoaddr);
4908fae3551SRodney W. Grimes 		if (bind(tp4sock,
4918fae3551SRodney W. Grimes 		    (struct sockaddr *)&isoaddr, sizeof (isoaddr)) < 0) {
4928fae3551SRodney W. Grimes 			syslog(LOG_ERR, "can't bind tp4 addr");
4938fae3551SRodney W. Grimes 			exit(1);
4948fae3551SRodney W. Grimes 		}
4958fae3551SRodney W. Grimes 		if (listen(tp4sock, 5) < 0) {
4968fae3551SRodney W. Grimes 			syslog(LOG_ERR, "listen failed");
4978fae3551SRodney W. Grimes 			exit(1);
4988fae3551SRodney W. Grimes 		}
4998fae3551SRodney W. Grimes 		/*
5008fae3551SRodney W. Grimes 		 * XXX
5018fae3551SRodney W. Grimes 		 * Someday this should probably use "rpcbind", the son of
5028fae3551SRodney W. Grimes 		 * portmap.
5038fae3551SRodney W. Grimes 		 */
5048fae3551SRodney W. Grimes 		if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
5058fae3551SRodney W. Grimes 			syslog(LOG_ERR, "can't register tcp with portmap");
5068fae3551SRodney W. Grimes 			exit(1);
5078fae3551SRodney W. Grimes 		}
5088fae3551SRodney W. Grimes 		FD_SET(tp4sock, &sockbits);
5098fae3551SRodney W. Grimes 		maxsock = tp4sock;
5108fae3551SRodney W. Grimes 		connect_type_cnt++;
5118fae3551SRodney W. Grimes 	}
5128fae3551SRodney W. Grimes 
5138fae3551SRodney W. Grimes 	/* Now set up the master server socket waiting for tpip connections. */
5148fae3551SRodney W. Grimes 	if (tpipflag) {
5158fae3551SRodney W. Grimes 		if ((tpipsock = socket(AF_INET, SOCK_SEQPACKET, 0)) < 0) {
5168fae3551SRodney W. Grimes 			syslog(LOG_ERR, "can't create tpip socket");
5178fae3551SRodney W. Grimes 			exit(1);
5188fae3551SRodney W. Grimes 		}
5198fae3551SRodney W. Grimes 		if (setsockopt(tpipsock,
5208fae3551SRodney W. Grimes 		    SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
5218fae3551SRodney W. Grimes 			syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
5228fae3551SRodney W. Grimes 		inetaddr.sin_family = AF_INET;
5238fae3551SRodney W. Grimes 		inetaddr.sin_addr.s_addr = INADDR_ANY;
5248fae3551SRodney W. Grimes 		inetaddr.sin_port = htons(NFS_PORT);
5258fae3551SRodney W. Grimes 		inetaddr.sin_len = sizeof(inetaddr);
5268fae3551SRodney W. Grimes 		if (bind(tpipsock,
5278fae3551SRodney W. Grimes 		    (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) {
5288fae3551SRodney W. Grimes 			syslog(LOG_ERR, "can't bind tcp addr");
5298fae3551SRodney W. Grimes 			exit(1);
5308fae3551SRodney W. Grimes 		}
5318fae3551SRodney W. Grimes 		if (listen(tpipsock, 5) < 0) {
5328fae3551SRodney W. Grimes 			syslog(LOG_ERR, "listen failed");
5338fae3551SRodney W. Grimes 			exit(1);
5348fae3551SRodney W. Grimes 		}
5358fae3551SRodney W. Grimes 		/*
5368fae3551SRodney W. Grimes 		 * XXX
5378fae3551SRodney W. Grimes 		 * Someday this should probably use "rpcbind", the son of
5388fae3551SRodney W. Grimes 		 * portmap.
5398fae3551SRodney W. Grimes 		 */
5408fae3551SRodney W. Grimes 		if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
5418fae3551SRodney W. Grimes 			syslog(LOG_ERR, "can't register tcp with portmap");
5428fae3551SRodney W. Grimes 			exit(1);
5438fae3551SRodney W. Grimes 		}
5448fae3551SRodney W. Grimes 		FD_SET(tpipsock, &sockbits);
5458fae3551SRodney W. Grimes 		maxsock = tpipsock;
5468fae3551SRodney W. Grimes 		connect_type_cnt++;
5478fae3551SRodney W. Grimes 	}
5488fae3551SRodney W. Grimes #endif /* notyet */
5498fae3551SRodney W. Grimes 
5508fae3551SRodney W. Grimes 	if (connect_type_cnt == 0)
5518fae3551SRodney W. Grimes 		exit(0);
5528fae3551SRodney W. Grimes 
553a62dc406SDoug Rabson 	setproctitle("master");
5548fae3551SRodney W. Grimes 
5558fae3551SRodney W. Grimes 	/*
5568fae3551SRodney W. Grimes 	 * Loop forever accepting connections and passing the sockets
5578fae3551SRodney W. Grimes 	 * into the kernel for the mounts.
5588fae3551SRodney W. Grimes 	 */
5598fae3551SRodney W. Grimes 	for (;;) {
5608fae3551SRodney W. Grimes 		ready = sockbits;
5618fae3551SRodney W. Grimes 		if (connect_type_cnt > 1) {
5628fae3551SRodney W. Grimes 			if (select(maxsock + 1,
5638fae3551SRodney W. Grimes 			    &ready, NULL, NULL, NULL) < 1) {
5648fae3551SRodney W. Grimes 				syslog(LOG_ERR, "select failed: %m");
5658fae3551SRodney W. Grimes 				exit(1);
5668fae3551SRodney W. Grimes 			}
5678fae3551SRodney W. Grimes 		}
5688fae3551SRodney W. Grimes 		if (tcpflag && FD_ISSET(tcpsock, &ready)) {
5698fae3551SRodney W. Grimes 			len = sizeof(inetpeer);
5708fae3551SRodney W. Grimes 			if ((msgsock = accept(tcpsock,
5718fae3551SRodney W. Grimes 			    (struct sockaddr *)&inetpeer, &len)) < 0) {
5728fae3551SRodney W. Grimes 				syslog(LOG_ERR, "accept failed: %m");
5738fae3551SRodney W. Grimes 				exit(1);
5748fae3551SRodney W. Grimes 			}
5758fae3551SRodney W. Grimes 			memset(inetpeer.sin_zero, 0, sizeof(inetpeer.sin_zero));
5768fae3551SRodney W. Grimes 			if (setsockopt(msgsock, SOL_SOCKET,
5778fae3551SRodney W. Grimes 			    SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
5788fae3551SRodney W. Grimes 				syslog(LOG_ERR,
5798fae3551SRodney W. Grimes 				    "setsockopt SO_KEEPALIVE: %m");
5808fae3551SRodney W. Grimes 			nfsdargs.sock = msgsock;
5818fae3551SRodney W. Grimes 			nfsdargs.name = (caddr_t)&inetpeer;
5828fae3551SRodney W. Grimes 			nfsdargs.namelen = sizeof(inetpeer);
5838fae3551SRodney W. Grimes 			nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
5848fae3551SRodney W. Grimes 			(void)close(msgsock);
5858fae3551SRodney W. Grimes 		}
5868fae3551SRodney W. Grimes #ifdef notyet
5878fae3551SRodney W. Grimes 		if (tp4flag && FD_ISSET(tp4sock, &ready)) {
5888fae3551SRodney W. Grimes 			len = sizeof(isopeer);
5898fae3551SRodney W. Grimes 			if ((msgsock = accept(tp4sock,
5908fae3551SRodney W. Grimes 			    (struct sockaddr *)&isopeer, &len)) < 0) {
5918fae3551SRodney W. Grimes 				syslog(LOG_ERR, "accept failed: %m");
5928fae3551SRodney W. Grimes 				exit(1);
5938fae3551SRodney W. Grimes 			}
5948fae3551SRodney W. Grimes 			if (setsockopt(msgsock, SOL_SOCKET,
5958fae3551SRodney W. Grimes 			    SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
5968fae3551SRodney W. Grimes 				syslog(LOG_ERR,
5978fae3551SRodney W. Grimes 				    "setsockopt SO_KEEPALIVE: %m");
5988fae3551SRodney W. Grimes 			nfsdargs.sock = msgsock;
5998fae3551SRodney W. Grimes 			nfsdargs.name = (caddr_t)&isopeer;
6008fae3551SRodney W. Grimes 			nfsdargs.namelen = len;
6018fae3551SRodney W. Grimes 			nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
6028fae3551SRodney W. Grimes 			(void)close(msgsock);
6038fae3551SRodney W. Grimes 		}
6048fae3551SRodney W. Grimes 		if (tpipflag && FD_ISSET(tpipsock, &ready)) {
6058fae3551SRodney W. Grimes 			len = sizeof(inetpeer);
6068fae3551SRodney W. Grimes 			if ((msgsock = accept(tpipsock,
6078fae3551SRodney W. Grimes 			    (struct sockaddr *)&inetpeer, &len)) < 0) {
6088fae3551SRodney W. Grimes 				syslog(LOG_ERR, "Accept failed: %m");
6098fae3551SRodney W. Grimes 				exit(1);
6108fae3551SRodney W. Grimes 			}
6118fae3551SRodney W. Grimes 			if (setsockopt(msgsock, SOL_SOCKET,
6128fae3551SRodney W. Grimes 			    SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
6138fae3551SRodney W. Grimes 				syslog(LOG_ERR, "setsockopt SO_KEEPALIVE: %m");
6148fae3551SRodney W. Grimes 			nfsdargs.sock = msgsock;
6158fae3551SRodney W. Grimes 			nfsdargs.name = (caddr_t)&inetpeer;
6168fae3551SRodney W. Grimes 			nfsdargs.namelen = len;
6178fae3551SRodney W. Grimes 			nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
6188fae3551SRodney W. Grimes 			(void)close(msgsock);
6198fae3551SRodney W. Grimes 		}
6208fae3551SRodney W. Grimes #endif /* notyet */
6218fae3551SRodney W. Grimes 	}
6228fae3551SRodney W. Grimes }
6238fae3551SRodney W. Grimes 
6248fae3551SRodney W. Grimes void
6258fae3551SRodney W. Grimes usage()
6268fae3551SRodney W. Grimes {
627a62dc406SDoug Rabson 	(void)fprintf(stderr, "usage: nfsd %s\n", USAGE);
6288fae3551SRodney W. Grimes 	exit(1);
6298fae3551SRodney W. Grimes }
6308fae3551SRodney W. Grimes 
6318fae3551SRodney W. Grimes void
6328fae3551SRodney W. Grimes nonfs(signo)
6338fae3551SRodney W. Grimes 	int signo;
6348fae3551SRodney W. Grimes {
6358fae3551SRodney W. Grimes 	syslog(LOG_ERR, "missing system call: NFS not available.");
6368fae3551SRodney W. Grimes }
6378fae3551SRodney W. Grimes 
6388fae3551SRodney W. Grimes void
6398fae3551SRodney W. Grimes reapchild(signo)
6408fae3551SRodney W. Grimes 	int signo;
6418fae3551SRodney W. Grimes {
6428fae3551SRodney W. Grimes 
643a62dc406SDoug Rabson 	while (wait3(NULL, WNOHANG, NULL) > 0);
6448fae3551SRodney W. Grimes }
6458fae3551SRodney W. Grimes 
646a62dc406SDoug Rabson #ifdef __FreeBSD__
6478fae3551SRodney W. Grimes void
6488fae3551SRodney W. Grimes setproctitle(a)
6498fae3551SRodney W. Grimes 	char *a;
6508fae3551SRodney W. Grimes {
6518fae3551SRodney W. Grimes 	register char *cp;
6528fae3551SRodney W. Grimes 	char buf[80];
6538fae3551SRodney W. Grimes 
6548fae3551SRodney W. Grimes 	cp = Argv[0];
655a62dc406SDoug Rabson 	(void)snprintf(buf, sizeof(buf), "nfsd-%s", a);
6568fae3551SRodney W. Grimes 	(void)strncpy(cp, buf, LastArg - cp);
6578fae3551SRodney W. Grimes 	cp += strlen(cp);
6588fae3551SRodney W. Grimes 	while (cp < LastArg)
6596aab3b5aSDavid Greenman 		*cp++ = '\0';
6608fae3551SRodney W. Grimes }
661a62dc406SDoug Rabson #endif	/* __FreeBSD__ */
662