nfsd.c revision 9336
11558Srgrimes/*
21558Srgrimes * Copyright (c) 1989, 1993, 1994
31558Srgrimes *	The Regents of the University of California.  All rights reserved.
41558Srgrimes *
51558Srgrimes * This code is derived from software contributed to Berkeley by
61558Srgrimes * Rick Macklem at The University of Guelph.
71558Srgrimes *
81558Srgrimes * Redistribution and use in source and binary forms, with or without
91558Srgrimes * modification, are permitted provided that the following conditions
101558Srgrimes * are met:
111558Srgrimes * 1. Redistributions of source code must retain the above copyright
121558Srgrimes *    notice, this list of conditions and the following disclaimer.
131558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141558Srgrimes *    notice, this list of conditions and the following disclaimer in the
151558Srgrimes *    documentation and/or other materials provided with the distribution.
161558Srgrimes * 3. All advertising materials mentioning features or use of this software
171558Srgrimes *    must display the following acknowledgement:
181558Srgrimes *	This product includes software developed by the University of
191558Srgrimes *	California, Berkeley and its contributors.
201558Srgrimes * 4. Neither the name of the University nor the names of its contributors
211558Srgrimes *    may be used to endorse or promote products derived from this software
221558Srgrimes *    without specific prior written permission.
231558Srgrimes *
241558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271558Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341558Srgrimes * SUCH DAMAGE.
351558Srgrimes */
361558Srgrimes
371558Srgrimes#ifndef lint
381558Srgrimesstatic char copyright[] =
391558Srgrimes"@(#) Copyright (c) 1989, 1993, 1994\n\
401558Srgrimes	The Regents of the University of California.  All rights reserved.\n";
411558Srgrimes#endif not lint
421558Srgrimes
431558Srgrimes#ifndef lint
441558Srgrimesstatic char sccsid[] = "@(#)nfsd.c	8.7 (Berkeley) 2/22/94";
451558Srgrimes#endif not lint
461558Srgrimes
471558Srgrimes#include <sys/param.h>
481558Srgrimes#include <sys/syslog.h>
491558Srgrimes#include <sys/ioctl.h>
501558Srgrimes#include <sys/stat.h>
511558Srgrimes#include <sys/wait.h>
521558Srgrimes#include <sys/uio.h>
531558Srgrimes#include <sys/ucred.h>
541558Srgrimes#include <sys/mount.h>
551558Srgrimes#include <sys/socket.h>
561558Srgrimes#include <sys/socketvar.h>
571558Srgrimes
581558Srgrimes#include <rpc/rpc.h>
591558Srgrimes#include <rpc/pmap_clnt.h>
601558Srgrimes#include <rpc/pmap_prot.h>
611558Srgrimes
621558Srgrimes#ifdef ISO
631558Srgrimes#include <netiso/iso.h>
641558Srgrimes#endif
651558Srgrimes#include <nfs/rpcv2.h>
669336Sdfr#include <nfs/nfsproto.h>
671558Srgrimes#include <nfs/nfs.h>
681558Srgrimes
699336Sdfr#ifdef NFSKERB
701558Srgrimes#include <kerberosIV/des.h>
711558Srgrimes#include <kerberosIV/krb.h>
721558Srgrimes#endif
731558Srgrimes
741558Srgrimes#include <err.h>
751558Srgrimes#include <errno.h>
761558Srgrimes#include <fcntl.h>
771558Srgrimes#include <grp.h>
781558Srgrimes#include <pwd.h>
791558Srgrimes#include <signal.h>
801558Srgrimes#include <stdio.h>
811558Srgrimes#include <stdlib.h>
821558Srgrimes#include <strings.h>
831558Srgrimes#include <unistd.h>
841558Srgrimes
851558Srgrimes/* Global defs */
861558Srgrimes#ifdef DEBUG
871558Srgrimes#define	syslog(e, s)	fprintf(stderr,(s))
881558Srgrimesint	debug = 1;
891558Srgrimes#else
901558Srgrimesint	debug = 0;
911558Srgrimes#endif
921558Srgrimes
931558Srgrimesstruct	nfsd_srvargs nsd;
941558Srgrimeschar	**Argv = NULL;		/* pointer to argument vector */
951558Srgrimeschar	*LastArg = NULL;	/* end of argv */
961558Srgrimes
979336Sdfr#ifdef NFSKERB
981558Srgrimeschar		lnam[ANAME_SZ];
991558SrgrimesKTEXT_ST	kt;
1009336SdfrAUTH_DAT	kauth;
1011558Srgrimeschar		inst[INST_SZ];
1029336Sdfrstruct nfsrpc_fullblock kin, kout;
1039336Sdfrstruct nfsrpc_fullverf kverf;
1049336SdfrNFSKERBKEY_T	kivec;
1059336Sdfrstruct timeval	ktv;
1069336SdfrNFSKERBKEYSCHED_T kerb_keysched;
1071558Srgrimes#endif
1081558Srgrimes
1091558Srgrimesvoid	nonfs __P((int));
1101558Srgrimesvoid	reapchild __P((int));
1119336Sdfr#ifdef __FreeBSD__
1121558Srgrimesvoid	setproctitle __P((char *));
1139336Sdfr#endif
1141558Srgrimesvoid	usage __P((void));
1151558Srgrimes
1161558Srgrimes/*
1171558Srgrimes * Nfs server daemon mostly just a user context for nfssvc()
1181558Srgrimes *
1191558Srgrimes * 1 - do file descriptor and signal cleanup
1201558Srgrimes * 2 - fork the nfsd(s)
1211558Srgrimes * 3 - create server socket(s)
1221558Srgrimes * 4 - register socket with portmap
1231558Srgrimes *
1241558Srgrimes * For connectionless protocols, just pass the socket into the kernel via.
1251558Srgrimes * nfssvc().
1261558Srgrimes * For connection based sockets, loop doing accepts. When you get a new
1271558Srgrimes * socket from accept, pass the msgsock into the kernel via. nfssvc().
1281558Srgrimes * The arguments are:
1291558Srgrimes *	-c - support iso cltp clients
1301558Srgrimes *	-r - reregister with portmapper
1311558Srgrimes *	-t - support tcp nfs clients
1321558Srgrimes *	-u - support udp nfs clients
1331558Srgrimes * followed by "n" which is the number of nfsds' to fork off
1341558Srgrimes */
1351558Srgrimesint
1361558Srgrimesmain(argc, argv, envp)
1371558Srgrimes	int argc;
1381558Srgrimes	char *argv[], *envp[];
1391558Srgrimes{
1401558Srgrimes	extern int optind;
1411558Srgrimes	struct group *grp;
1421558Srgrimes	struct nfsd_args nfsdargs;
1431558Srgrimes	struct passwd *pwd;
1441558Srgrimes	struct ucred *cr;
1451558Srgrimes	struct sockaddr_in inetaddr, inetpeer;
1461558Srgrimes#ifdef ISO
1471558Srgrimes	struct sockaddr_iso isoaddr, isopeer;
1481558Srgrimes#endif
1499336Sdfr	struct timeval ktv;
1501558Srgrimes	fd_set ready, sockbits;
1511558Srgrimes	int ch, cltpflag, connect_type_cnt, i, len, maxsock, msgsock;
1521558Srgrimes	int nfsdcnt, nfssvc_flag, on, reregister, sock, tcpflag, tcpsock;
1531558Srgrimes	int tp4cnt, tp4flag, tp4sock, tpipcnt, tpipflag, tpipsock, udpflag;
1541558Srgrimes	char *cp, **cpp;
1559336Sdfr#ifdef __FreeBSD__
1562999Swollman	struct vfsconf *vfc;
1571558Srgrimes
1582999Swollman	vfc = getvfsbyname("nfs");
1592999Swollman	if(!vfc && vfsisloadable("nfs")) {
1602999Swollman		if(vfsload("nfs"))
1612999Swollman			err(1, "vfsload(nfs)");
1622999Swollman		endvfsent();	/* flush cache */
1632999Swollman		vfc = getvfsbyname("nfs"); /* probably unnecessary */
1642999Swollman	}
1652999Swollman	if(!vfc) {
1662999Swollman		errx(1, "NFS is not available in the running kernel");
1672999Swollman	}
1689336Sdfr#endif
1692999Swollman
1701558Srgrimes	/* Save start and extent of argv for setproctitle. */
1711558Srgrimes	Argv = argv;
1721558Srgrimes	if (envp == 0 || *envp == 0)
1731558Srgrimes		envp = argv;
1741558Srgrimes	while (*envp)
1751558Srgrimes		envp++;
1761558Srgrimes	LastArg = envp[-1] + strlen(envp[-1]);
1771558Srgrimes
1781558Srgrimes#define	MAXNFSDCNT	20
1791558Srgrimes#define	DEFNFSDCNT	 4
1801558Srgrimes	nfsdcnt = DEFNFSDCNT;
1811558Srgrimes	cltpflag = reregister = tcpflag = tp4cnt = tp4flag = tpipcnt = 0;
1821558Srgrimes	tpipflag = udpflag = 0;
1831558Srgrimes#ifdef ISO
1841558Srgrimes#define	GETOPT	"cn:rtu"
1851558Srgrimes#define	USAGE	"[-crtu] [-n num_servers]"
1861558Srgrimes#else
1871558Srgrimes#define	GETOPT	"n:rtu"
1881558Srgrimes#define	USAGE	"[-rtu] [-n num_servers]"
1891558Srgrimes#endif
1901558Srgrimes	while ((ch = getopt(argc, argv, GETOPT)) != EOF)
1911558Srgrimes		switch (ch) {
1921558Srgrimes		case 'n':
1931558Srgrimes			nfsdcnt = atoi(optarg);
1941558Srgrimes			if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) {
1951558Srgrimes				warnx("nfsd count %d; reset to %d", DEFNFSDCNT);
1961558Srgrimes				nfsdcnt = DEFNFSDCNT;
1971558Srgrimes			}
1981558Srgrimes			break;
1991558Srgrimes		case 'r':
2001558Srgrimes			reregister = 1;
2011558Srgrimes			break;
2021558Srgrimes		case 't':
2031558Srgrimes			tcpflag = 1;
2041558Srgrimes			break;
2051558Srgrimes		case 'u':
2061558Srgrimes			udpflag = 1;
2071558Srgrimes			break;
2081558Srgrimes#ifdef ISO
2091558Srgrimes		case 'c':
2101558Srgrimes			cltpflag = 1;
2111558Srgrimes			break;
2121558Srgrimes#ifdef notyet
2131558Srgrimes		case 'i':
2141558Srgrimes			tp4cnt = 1;
2151558Srgrimes			break;
2161558Srgrimes		case 'p':
2171558Srgrimes			tpipcnt = 1;
2181558Srgrimes			break;
2191558Srgrimes#endif /* notyet */
2201558Srgrimes#endif /* ISO */
2211558Srgrimes		default:
2221558Srgrimes		case '?':
2231558Srgrimes			usage();
2241558Srgrimes		};
2251558Srgrimes	argv += optind;
2261558Srgrimes	argc -= optind;
2271558Srgrimes
2281558Srgrimes	/*
2291558Srgrimes	 * XXX
2301558Srgrimes	 * Backward compatibility, trailing number is the count of daemons.
2311558Srgrimes	 */
2321558Srgrimes	if (argc > 1)
2331558Srgrimes		usage();
2341558Srgrimes	if (argc == 1) {
2351558Srgrimes		nfsdcnt = atoi(argv[0]);
2361558Srgrimes		if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) {
2371558Srgrimes			warnx("nfsd count %d; reset to %d", DEFNFSDCNT);
2381558Srgrimes			nfsdcnt = DEFNFSDCNT;
2391558Srgrimes		}
2401558Srgrimes	}
2411558Srgrimes
2421558Srgrimes	if (debug == 0) {
2431558Srgrimes		daemon(0, 0);
2441558Srgrimes		(void)signal(SIGHUP, SIG_IGN);
2451558Srgrimes		(void)signal(SIGINT, SIG_IGN);
2461558Srgrimes		(void)signal(SIGQUIT, SIG_IGN);
2471558Srgrimes		(void)signal(SIGSYS, nonfs);
2481558Srgrimes		(void)signal(SIGTERM, SIG_IGN);
2491558Srgrimes	}
2501558Srgrimes	(void)signal(SIGCHLD, reapchild);
2511558Srgrimes
2521558Srgrimes	if (reregister) {
2531558Srgrimes		if (udpflag &&
2549336Sdfr		    (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) ||
2559336Sdfr		     !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT)))
2561558Srgrimes			err(1, "can't register with portmap for UDP.");
2571558Srgrimes		if (tcpflag &&
2589336Sdfr		    (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) ||
2599336Sdfr		     !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT)))
2601558Srgrimes			err(1, "can't register with portmap for TCP.");
2611558Srgrimes		exit(0);
2621558Srgrimes	}
2631558Srgrimes	openlog("nfsd:", LOG_PID, LOG_DAEMON);
2641558Srgrimes
2651558Srgrimes	for (i = 0; i < nfsdcnt; i++) {
2661558Srgrimes		switch (fork()) {
2671558Srgrimes		case -1:
2681558Srgrimes			syslog(LOG_ERR, "fork: %m");
2691558Srgrimes			exit (1);
2701558Srgrimes		case 0:
2711558Srgrimes			break;
2721558Srgrimes		default:
2731558Srgrimes			continue;
2741558Srgrimes		}
2751558Srgrimes
2769336Sdfr		setproctitle("server");
2771558Srgrimes		nfssvc_flag = NFSSVC_NFSD;
2781558Srgrimes		nsd.nsd_nfsd = NULL;
2799336Sdfr#ifdef NFSKERB
2809336Sdfr		if (sizeof (struct nfsrpc_fullverf) != RPCX_FULLVERF ||
2819336Sdfr		    sizeof (struct nfsrpc_fullblock) != RPCX_FULLBLOCK)
2829336Sdfr		    syslog(LOG_ERR, "Yikes NFSKERB structs not packed!");
2839336Sdfr		nsd.nsd_authstr = (u_char *)&kt;
2849336Sdfr		nsd.nsd_authlen = sizeof (kt);
2859336Sdfr		nsd.nsd_verfstr = (u_char *)&kverf;
2869336Sdfr		nsd.nsd_verflen = sizeof (kverf);
2871558Srgrimes#endif
2881558Srgrimes		while (nfssvc(nfssvc_flag, &nsd) < 0) {
2891558Srgrimes			if (errno != ENEEDAUTH) {
2901558Srgrimes				syslog(LOG_ERR, "nfssvc: %m");
2911558Srgrimes				exit(1);
2921558Srgrimes			}
2931558Srgrimes			nfssvc_flag = NFSSVC_NFSD | NFSSVC_AUTHINFAIL;
2949336Sdfr#ifdef NFSKERB
2959336Sdfr			/*
2969336Sdfr			 * Get the Kerberos ticket out of the authenticator
2979336Sdfr			 * verify it and convert the principal name to a user
2989336Sdfr			 * name. The user name is then converted to a set of
2999336Sdfr			 * user credentials via the password and group file.
3009336Sdfr			 * Finally, decrypt the timestamp and validate it.
3019336Sdfr			 * For more info see the IETF Draft "Authentication
3029336Sdfr			 * in ONC RPC".
3039336Sdfr			 */
3049336Sdfr			kt.length = ntohl(kt.length);
3059336Sdfr			if (gettimeofday(&ktv, (struct timezone *)0) == 0 &&
3069336Sdfr			    kt.length > 0 && kt.length <=
3079336Sdfr			    (RPCAUTH_MAXSIZ - 3 * NFSX_UNSIGNED)) {
3089336Sdfr			    kin.w1 = NFS_KERBW1(kt);
3099336Sdfr			    kt.mbz = 0;
3109336Sdfr			    (void)strcpy(inst, "*");
3119336Sdfr			    if (krb_rd_req(&kt, NFS_KERBSRV,
3129336Sdfr				inst, nsd.nsd_haddr, &kauth, "") == RD_AP_OK &&
3139336Sdfr				krb_kntoln(&kauth, lnam) == KSUCCESS &&
3149336Sdfr				(pwd = getpwnam(lnam)) != NULL) {
3151558Srgrimes				cr = &nsd.nsd_cr;
3161558Srgrimes				cr->cr_uid = pwd->pw_uid;
3171558Srgrimes				cr->cr_groups[0] = pwd->pw_gid;
3181558Srgrimes				cr->cr_ngroups = 1;
3191558Srgrimes				setgrent();
3201558Srgrimes				while ((grp = getgrent()) != NULL) {
3211558Srgrimes					if (grp->gr_gid == cr->cr_groups[0])
3221558Srgrimes						continue;
3231558Srgrimes					for (cpp = grp->gr_mem;
3241558Srgrimes					    *cpp != NULL; ++cpp)
3251558Srgrimes						if (!strcmp(*cpp, lnam))
3261558Srgrimes							break;
3271558Srgrimes					if (*cpp == NULL)
3281558Srgrimes						continue;
3291558Srgrimes					cr->cr_groups[cr->cr_ngroups++]
3301558Srgrimes					    = grp->gr_gid;
3311558Srgrimes					if (cr->cr_ngroups == NGROUPS)
3321558Srgrimes						break;
3331558Srgrimes				}
3341558Srgrimes				endgrent();
3359336Sdfr
3369336Sdfr				/*
3379336Sdfr				 * Get the timestamp verifier out of the
3389336Sdfr				 * authenticator and verifier strings.
3399336Sdfr				 */
3409336Sdfr				kin.t1 = kverf.t1;
3419336Sdfr				kin.t2 = kverf.t2;
3429336Sdfr				kin.w2 = kverf.w2;
3439336Sdfr				bzero((caddr_t)kivec, sizeof (kivec));
3449336Sdfr				bcopy((caddr_t)kauth.session,
3459336Sdfr				    (caddr_t)nsd.nsd_key,sizeof(kauth.session));
3469336Sdfr
3479336Sdfr				/*
3489336Sdfr				 * Decrypt the timestamp verifier in CBC mode.
3499336Sdfr				 */
3509336Sdfr				XXX
3519336Sdfr
3529336Sdfr				/*
3539336Sdfr				 * Validate the timestamp verifier, to
3549336Sdfr				 * check that the session key is ok.
3559336Sdfr				 */
3569336Sdfr				nsd.nsd_timestamp.tv_sec = ntohl(kout.t1);
3579336Sdfr				nsd.nsd_timestamp.tv_usec = ntohl(kout.t2);
3589336Sdfr				nsd.nsd_ttl = ntohl(kout.w1);
3599336Sdfr				if ((nsd.nsd_ttl - 1) == ntohl(kout.w2))
3609336Sdfr				    nfssvc_flag = NFSSVC_NFSD | NFSSVC_AUTHIN;
3611558Srgrimes			}
3629336Sdfr#endif /* NFSKERB */
3631558Srgrimes		}
3641558Srgrimes		exit(0);
3651558Srgrimes	}
3661558Srgrimes
3671558Srgrimes	/* If we are serving udp, set up the socket. */
3681558Srgrimes	if (udpflag) {
3691558Srgrimes		if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
3701558Srgrimes			syslog(LOG_ERR, "can't create udp socket");
3711558Srgrimes			exit(1);
3721558Srgrimes		}
3731558Srgrimes		inetaddr.sin_family = AF_INET;
3741558Srgrimes		inetaddr.sin_addr.s_addr = INADDR_ANY;
3751558Srgrimes		inetaddr.sin_port = htons(NFS_PORT);
3761558Srgrimes		inetaddr.sin_len = sizeof(inetaddr);
3771558Srgrimes		if (bind(sock,
3781558Srgrimes		    (struct sockaddr *)&inetaddr, sizeof(inetaddr)) < 0) {
3791558Srgrimes			syslog(LOG_ERR, "can't bind udp addr");
3801558Srgrimes			exit(1);
3811558Srgrimes		}
3829336Sdfr		if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) ||
3839336Sdfr		    !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT)) {
3841558Srgrimes			syslog(LOG_ERR, "can't register with udp portmap");
3851558Srgrimes			exit(1);
3861558Srgrimes		}
3871558Srgrimes		nfsdargs.sock = sock;
3881558Srgrimes		nfsdargs.name = NULL;
3891558Srgrimes		nfsdargs.namelen = 0;
3901558Srgrimes		if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
3911558Srgrimes			syslog(LOG_ERR, "can't Add UDP socket");
3921558Srgrimes			exit(1);
3931558Srgrimes		}
3941558Srgrimes		(void)close(sock);
3951558Srgrimes	}
3961558Srgrimes
3971558Srgrimes#ifdef ISO
3981558Srgrimes	/* If we are serving cltp, set up the socket. */
3991558Srgrimes	if (cltpflag) {
4001558Srgrimes		if ((sock = socket(AF_ISO, SOCK_DGRAM, 0)) < 0) {
4011558Srgrimes			syslog(LOG_ERR, "can't create cltp socket");
4021558Srgrimes			exit(1);
4031558Srgrimes		}
4041558Srgrimes		memset(&isoaddr, 0, sizeof(isoaddr));
4051558Srgrimes		isoaddr.siso_family = AF_ISO;
4061558Srgrimes		isoaddr.siso_tlen = 2;
4071558Srgrimes		cp = TSEL(&isoaddr);
4081558Srgrimes		*cp++ = (NFS_PORT >> 8);
4091558Srgrimes		*cp = (NFS_PORT & 0xff);
4101558Srgrimes		isoaddr.siso_len = sizeof(isoaddr);
4111558Srgrimes		if (bind(sock,
4121558Srgrimes		    (struct sockaddr *)&isoaddr, sizeof(isoaddr)) < 0) {
4131558Srgrimes			syslog(LOG_ERR, "can't bind cltp addr");
4141558Srgrimes			exit(1);
4151558Srgrimes		}
4161558Srgrimes#ifdef notyet
4171558Srgrimes		/*
4181558Srgrimes		 * XXX
4191558Srgrimes		 * Someday this should probably use "rpcbind", the son of
4201558Srgrimes		 * portmap.
4211558Srgrimes		 */
4221558Srgrimes		if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT)) {
4231558Srgrimes			syslog(LOG_ERR, "can't register with udp portmap");
4241558Srgrimes			exit(1);
4251558Srgrimes		}
4261558Srgrimes#endif /* notyet */
4271558Srgrimes		nfsdargs.sock = sock;
4281558Srgrimes		nfsdargs.name = NULL;
4291558Srgrimes		nfsdargs.namelen = 0;
4301558Srgrimes		if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
4311558Srgrimes			syslog(LOG_ERR, "can't add UDP socket");
4321558Srgrimes			exit(1);
4331558Srgrimes		}
4341558Srgrimes		close(sock);
4351558Srgrimes	}
4361558Srgrimes#endif /* ISO */
4371558Srgrimes
4381558Srgrimes	/* Now set up the master server socket waiting for tcp connections. */
4391558Srgrimes	on = 1;
4401558Srgrimes	FD_ZERO(&sockbits);
4411558Srgrimes	connect_type_cnt = 0;
4421558Srgrimes	if (tcpflag) {
4431558Srgrimes		if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
4441558Srgrimes			syslog(LOG_ERR, "can't create tcp socket");
4451558Srgrimes			exit(1);
4461558Srgrimes		}
4471558Srgrimes		if (setsockopt(tcpsock,
4481558Srgrimes		    SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
4491558Srgrimes			syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
4501558Srgrimes		inetaddr.sin_family = AF_INET;
4511558Srgrimes		inetaddr.sin_addr.s_addr = INADDR_ANY;
4521558Srgrimes		inetaddr.sin_port = htons(NFS_PORT);
4531558Srgrimes		inetaddr.sin_len = sizeof(inetaddr);
4541558Srgrimes		if (bind(tcpsock,
4551558Srgrimes		    (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) {
4561558Srgrimes			syslog(LOG_ERR, "can't bind tcp addr");
4571558Srgrimes			exit(1);
4581558Srgrimes		}
4591558Srgrimes		if (listen(tcpsock, 5) < 0) {
4601558Srgrimes			syslog(LOG_ERR, "listen failed");
4611558Srgrimes			exit(1);
4621558Srgrimes		}
4639336Sdfr		if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) ||
4649336Sdfr		    !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT)) {
4651558Srgrimes			syslog(LOG_ERR, "can't register tcp with portmap");
4661558Srgrimes			exit(1);
4671558Srgrimes		}
4681558Srgrimes		FD_SET(tcpsock, &sockbits);
4691558Srgrimes		maxsock = tcpsock;
4701558Srgrimes		connect_type_cnt++;
4711558Srgrimes	}
4721558Srgrimes
4731558Srgrimes#ifdef notyet
4741558Srgrimes	/* Now set up the master server socket waiting for tp4 connections. */
4751558Srgrimes	if (tp4flag) {
4761558Srgrimes		if ((tp4sock = socket(AF_ISO, SOCK_SEQPACKET, 0)) < 0) {
4771558Srgrimes			syslog(LOG_ERR, "can't create tp4 socket");
4781558Srgrimes			exit(1);
4791558Srgrimes		}
4801558Srgrimes		if (setsockopt(tp4sock,
4811558Srgrimes		    SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
4821558Srgrimes			syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
4831558Srgrimes		memset(&isoaddr, 0, sizeof(isoaddr));
4841558Srgrimes		isoaddr.siso_family = AF_ISO;
4851558Srgrimes		isoaddr.siso_tlen = 2;
4861558Srgrimes		cp = TSEL(&isoaddr);
4871558Srgrimes		*cp++ = (NFS_PORT >> 8);
4881558Srgrimes		*cp = (NFS_PORT & 0xff);
4891558Srgrimes		isoaddr.siso_len = sizeof(isoaddr);
4901558Srgrimes		if (bind(tp4sock,
4911558Srgrimes		    (struct sockaddr *)&isoaddr, sizeof (isoaddr)) < 0) {
4921558Srgrimes			syslog(LOG_ERR, "can't bind tp4 addr");
4931558Srgrimes			exit(1);
4941558Srgrimes		}
4951558Srgrimes		if (listen(tp4sock, 5) < 0) {
4961558Srgrimes			syslog(LOG_ERR, "listen failed");
4971558Srgrimes			exit(1);
4981558Srgrimes		}
4991558Srgrimes		/*
5001558Srgrimes		 * XXX
5011558Srgrimes		 * Someday this should probably use "rpcbind", the son of
5021558Srgrimes		 * portmap.
5031558Srgrimes		 */
5041558Srgrimes		if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
5051558Srgrimes			syslog(LOG_ERR, "can't register tcp with portmap");
5061558Srgrimes			exit(1);
5071558Srgrimes		}
5081558Srgrimes		FD_SET(tp4sock, &sockbits);
5091558Srgrimes		maxsock = tp4sock;
5101558Srgrimes		connect_type_cnt++;
5111558Srgrimes	}
5121558Srgrimes
5131558Srgrimes	/* Now set up the master server socket waiting for tpip connections. */
5141558Srgrimes	if (tpipflag) {
5151558Srgrimes		if ((tpipsock = socket(AF_INET, SOCK_SEQPACKET, 0)) < 0) {
5161558Srgrimes			syslog(LOG_ERR, "can't create tpip socket");
5171558Srgrimes			exit(1);
5181558Srgrimes		}
5191558Srgrimes		if (setsockopt(tpipsock,
5201558Srgrimes		    SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
5211558Srgrimes			syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
5221558Srgrimes		inetaddr.sin_family = AF_INET;
5231558Srgrimes		inetaddr.sin_addr.s_addr = INADDR_ANY;
5241558Srgrimes		inetaddr.sin_port = htons(NFS_PORT);
5251558Srgrimes		inetaddr.sin_len = sizeof(inetaddr);
5261558Srgrimes		if (bind(tpipsock,
5271558Srgrimes		    (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) {
5281558Srgrimes			syslog(LOG_ERR, "can't bind tcp addr");
5291558Srgrimes			exit(1);
5301558Srgrimes		}
5311558Srgrimes		if (listen(tpipsock, 5) < 0) {
5321558Srgrimes			syslog(LOG_ERR, "listen failed");
5331558Srgrimes			exit(1);
5341558Srgrimes		}
5351558Srgrimes		/*
5361558Srgrimes		 * XXX
5371558Srgrimes		 * Someday this should probably use "rpcbind", the son of
5381558Srgrimes		 * portmap.
5391558Srgrimes		 */
5401558Srgrimes		if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
5411558Srgrimes			syslog(LOG_ERR, "can't register tcp with portmap");
5421558Srgrimes			exit(1);
5431558Srgrimes		}
5441558Srgrimes		FD_SET(tpipsock, &sockbits);
5451558Srgrimes		maxsock = tpipsock;
5461558Srgrimes		connect_type_cnt++;
5471558Srgrimes	}
5481558Srgrimes#endif /* notyet */
5491558Srgrimes
5501558Srgrimes	if (connect_type_cnt == 0)
5511558Srgrimes		exit(0);
5521558Srgrimes
5539336Sdfr	setproctitle("master");
5541558Srgrimes
5551558Srgrimes	/*
5561558Srgrimes	 * Loop forever accepting connections and passing the sockets
5571558Srgrimes	 * into the kernel for the mounts.
5581558Srgrimes	 */
5591558Srgrimes	for (;;) {
5601558Srgrimes		ready = sockbits;
5611558Srgrimes		if (connect_type_cnt > 1) {
5621558Srgrimes			if (select(maxsock + 1,
5631558Srgrimes			    &ready, NULL, NULL, NULL) < 1) {
5641558Srgrimes				syslog(LOG_ERR, "select failed: %m");
5651558Srgrimes				exit(1);
5661558Srgrimes			}
5671558Srgrimes		}
5681558Srgrimes		if (tcpflag && FD_ISSET(tcpsock, &ready)) {
5691558Srgrimes			len = sizeof(inetpeer);
5701558Srgrimes			if ((msgsock = accept(tcpsock,
5711558Srgrimes			    (struct sockaddr *)&inetpeer, &len)) < 0) {
5721558Srgrimes				syslog(LOG_ERR, "accept failed: %m");
5731558Srgrimes				exit(1);
5741558Srgrimes			}
5751558Srgrimes			memset(inetpeer.sin_zero, 0, sizeof(inetpeer.sin_zero));
5761558Srgrimes			if (setsockopt(msgsock, SOL_SOCKET,
5771558Srgrimes			    SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
5781558Srgrimes				syslog(LOG_ERR,
5791558Srgrimes				    "setsockopt SO_KEEPALIVE: %m");
5801558Srgrimes			nfsdargs.sock = msgsock;
5811558Srgrimes			nfsdargs.name = (caddr_t)&inetpeer;
5821558Srgrimes			nfsdargs.namelen = sizeof(inetpeer);
5831558Srgrimes			nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
5841558Srgrimes			(void)close(msgsock);
5851558Srgrimes		}
5861558Srgrimes#ifdef notyet
5871558Srgrimes		if (tp4flag && FD_ISSET(tp4sock, &ready)) {
5881558Srgrimes			len = sizeof(isopeer);
5891558Srgrimes			if ((msgsock = accept(tp4sock,
5901558Srgrimes			    (struct sockaddr *)&isopeer, &len)) < 0) {
5911558Srgrimes				syslog(LOG_ERR, "accept failed: %m");
5921558Srgrimes				exit(1);
5931558Srgrimes			}
5941558Srgrimes			if (setsockopt(msgsock, SOL_SOCKET,
5951558Srgrimes			    SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
5961558Srgrimes				syslog(LOG_ERR,
5971558Srgrimes				    "setsockopt SO_KEEPALIVE: %m");
5981558Srgrimes			nfsdargs.sock = msgsock;
5991558Srgrimes			nfsdargs.name = (caddr_t)&isopeer;
6001558Srgrimes			nfsdargs.namelen = len;
6011558Srgrimes			nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
6021558Srgrimes			(void)close(msgsock);
6031558Srgrimes		}
6041558Srgrimes		if (tpipflag && FD_ISSET(tpipsock, &ready)) {
6051558Srgrimes			len = sizeof(inetpeer);
6061558Srgrimes			if ((msgsock = accept(tpipsock,
6071558Srgrimes			    (struct sockaddr *)&inetpeer, &len)) < 0) {
6081558Srgrimes				syslog(LOG_ERR, "Accept failed: %m");
6091558Srgrimes				exit(1);
6101558Srgrimes			}
6111558Srgrimes			if (setsockopt(msgsock, SOL_SOCKET,
6121558Srgrimes			    SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
6131558Srgrimes				syslog(LOG_ERR, "setsockopt SO_KEEPALIVE: %m");
6141558Srgrimes			nfsdargs.sock = msgsock;
6151558Srgrimes			nfsdargs.name = (caddr_t)&inetpeer;
6161558Srgrimes			nfsdargs.namelen = len;
6171558Srgrimes			nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
6181558Srgrimes			(void)close(msgsock);
6191558Srgrimes		}
6201558Srgrimes#endif /* notyet */
6211558Srgrimes	}
6221558Srgrimes}
6231558Srgrimes
6241558Srgrimesvoid
6251558Srgrimesusage()
6261558Srgrimes{
6279336Sdfr	(void)fprintf(stderr, "usage: nfsd %s\n", USAGE);
6281558Srgrimes	exit(1);
6291558Srgrimes}
6301558Srgrimes
6311558Srgrimesvoid
6321558Srgrimesnonfs(signo)
6331558Srgrimes	int signo;
6341558Srgrimes{
6351558Srgrimes	syslog(LOG_ERR, "missing system call: NFS not available.");
6361558Srgrimes}
6371558Srgrimes
6381558Srgrimesvoid
6391558Srgrimesreapchild(signo)
6401558Srgrimes	int signo;
6411558Srgrimes{
6421558Srgrimes
6439336Sdfr	while (wait3(NULL, WNOHANG, NULL) > 0);
6441558Srgrimes}
6451558Srgrimes
6469336Sdfr#ifdef __FreeBSD__
6471558Srgrimesvoid
6481558Srgrimessetproctitle(a)
6491558Srgrimes	char *a;
6501558Srgrimes{
6511558Srgrimes	register char *cp;
6521558Srgrimes	char buf[80];
6531558Srgrimes
6541558Srgrimes	cp = Argv[0];
6559336Sdfr	(void)snprintf(buf, sizeof(buf), "nfsd-%s", a);
6561558Srgrimes	(void)strncpy(cp, buf, LastArg - cp);
6571558Srgrimes	cp += strlen(cp);
6581558Srgrimes	while (cp < LastArg)
6592030Sdg		*cp++ = '\0';
6601558Srgrimes}
6619336Sdfr#endif	/* __FreeBSD__ */
662