nfsd.c revision 31206
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
4423684Speterstatic char sccsid[] = "@(#)nfsd.c	8.9 (Berkeley) 3/29/95";
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
7023684Speter#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>
8413141Speter#include <libutil.h>
851558Srgrimes
861558Srgrimes/* Global defs */
871558Srgrimes#ifdef DEBUG
881558Srgrimes#define	syslog(e, s)	fprintf(stderr,(s))
891558Srgrimesint	debug = 1;
901558Srgrimes#else
911558Srgrimesint	debug = 0;
921558Srgrimes#endif
931558Srgrimes
941558Srgrimesstruct	nfsd_srvargs nsd;
9513141Speter#ifdef OLD_SETPROCTITLE
961558Srgrimeschar	**Argv = NULL;		/* pointer to argument vector */
971558Srgrimeschar	*LastArg = NULL;	/* end of argv */
9813141Speter#endif
991558Srgrimes
1009336Sdfr#ifdef NFSKERB
1011558Srgrimeschar		lnam[ANAME_SZ];
1021558SrgrimesKTEXT_ST	kt;
1039336SdfrAUTH_DAT	kauth;
1041558Srgrimeschar		inst[INST_SZ];
1059336Sdfrstruct nfsrpc_fullblock kin, kout;
1069336Sdfrstruct nfsrpc_fullverf kverf;
1079336SdfrNFSKERBKEY_T	kivec;
1089336Sdfrstruct timeval	ktv;
1099336SdfrNFSKERBKEYSCHED_T kerb_keysched;
1101558Srgrimes#endif
1111558Srgrimes
1121558Srgrimesvoid	nonfs __P((int));
1131558Srgrimesvoid	reapchild __P((int));
11413141Speter#ifdef OLD_SETPROCTITLE
1159336Sdfr#ifdef __FreeBSD__
1161558Srgrimesvoid	setproctitle __P((char *));
1179336Sdfr#endif
11813141Speter#endif
1191558Srgrimesvoid	usage __P((void));
1201558Srgrimes
1211558Srgrimes/*
1221558Srgrimes * Nfs server daemon mostly just a user context for nfssvc()
1231558Srgrimes *
1241558Srgrimes * 1 - do file descriptor and signal cleanup
1251558Srgrimes * 2 - fork the nfsd(s)
1261558Srgrimes * 3 - create server socket(s)
1271558Srgrimes * 4 - register socket with portmap
1281558Srgrimes *
1291558Srgrimes * For connectionless protocols, just pass the socket into the kernel via.
1301558Srgrimes * nfssvc().
1311558Srgrimes * For connection based sockets, loop doing accepts. When you get a new
1321558Srgrimes * socket from accept, pass the msgsock into the kernel via. nfssvc().
1331558Srgrimes * The arguments are:
1341558Srgrimes *	-c - support iso cltp clients
1351558Srgrimes *	-r - reregister with portmapper
1361558Srgrimes *	-t - support tcp nfs clients
1371558Srgrimes *	-u - support udp nfs clients
1381558Srgrimes * followed by "n" which is the number of nfsds' to fork off
1391558Srgrimes */
1401558Srgrimesint
1411558Srgrimesmain(argc, argv, envp)
1421558Srgrimes	int argc;
1431558Srgrimes	char *argv[], *envp[];
1441558Srgrimes{
1451558Srgrimes	extern int optind;
1461558Srgrimes	struct group *grp;
1471558Srgrimes	struct nfsd_args nfsdargs;
1481558Srgrimes	struct passwd *pwd;
1491558Srgrimes	struct ucred *cr;
1501558Srgrimes	struct sockaddr_in inetaddr, inetpeer;
1511558Srgrimes#ifdef ISO
1521558Srgrimes	struct sockaddr_iso isoaddr, isopeer;
1531558Srgrimes#endif
1549336Sdfr	struct timeval ktv;
1551558Srgrimes	fd_set ready, sockbits;
1561558Srgrimes	int ch, cltpflag, connect_type_cnt, i, len, maxsock, msgsock;
1571558Srgrimes	int nfsdcnt, nfssvc_flag, on, reregister, sock, tcpflag, tcpsock;
1581558Srgrimes	int tp4cnt, tp4flag, tp4sock, tpipcnt, tpipflag, tpipsock, udpflag;
1591558Srgrimes	char *cp, **cpp;
1609336Sdfr#ifdef __FreeBSD__
16123684Speter	struct vfsconf vfc;
16223684Speter	int error;
1631558Srgrimes
16423684Speter	error = getvfsbyname("nfs", &vfc);
16523684Speter	if (error && vfsisloadable("nfs")) {
16623684Speter		if (vfsload("nfs"))
1672999Swollman			err(1, "vfsload(nfs)");
1682999Swollman		endvfsent();	/* flush cache */
16923684Speter		error = getvfsbyname("nfs", &vfc);
1702999Swollman	}
17123684Speter	if (error)
1722999Swollman		errx(1, "NFS is not available in the running kernel");
1739336Sdfr#endif
1742999Swollman
17513141Speter#ifdef OLD_SETPROCTITLE
1761558Srgrimes	/* Save start and extent of argv for setproctitle. */
1771558Srgrimes	Argv = argv;
1781558Srgrimes	if (envp == 0 || *envp == 0)
1791558Srgrimes		envp = argv;
1801558Srgrimes	while (*envp)
1811558Srgrimes		envp++;
1821558Srgrimes	LastArg = envp[-1] + strlen(envp[-1]);
18313141Speter#endif
1841558Srgrimes
1851558Srgrimes#define	MAXNFSDCNT	20
1861558Srgrimes#define	DEFNFSDCNT	 4
1871558Srgrimes	nfsdcnt = DEFNFSDCNT;
1881558Srgrimes	cltpflag = reregister = tcpflag = tp4cnt = tp4flag = tpipcnt = 0;
1891558Srgrimes	tpipflag = udpflag = 0;
1901558Srgrimes#ifdef ISO
1911558Srgrimes#define	GETOPT	"cn:rtu"
1921558Srgrimes#define	USAGE	"[-crtu] [-n num_servers]"
1931558Srgrimes#else
1941558Srgrimes#define	GETOPT	"n:rtu"
1951558Srgrimes#define	USAGE	"[-rtu] [-n num_servers]"
1961558Srgrimes#endif
19724359Simp	while ((ch = getopt(argc, argv, GETOPT)) != -1)
1981558Srgrimes		switch (ch) {
1991558Srgrimes		case 'n':
2001558Srgrimes			nfsdcnt = atoi(optarg);
2011558Srgrimes			if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) {
20231206Sjdp				warnx("nfsd count %d; reset to %d", nfsdcnt,
20331206Sjdp				    DEFNFSDCNT);
2041558Srgrimes				nfsdcnt = DEFNFSDCNT;
2051558Srgrimes			}
2061558Srgrimes			break;
2071558Srgrimes		case 'r':
2081558Srgrimes			reregister = 1;
2091558Srgrimes			break;
2101558Srgrimes		case 't':
2111558Srgrimes			tcpflag = 1;
2121558Srgrimes			break;
2131558Srgrimes		case 'u':
2141558Srgrimes			udpflag = 1;
2151558Srgrimes			break;
2161558Srgrimes#ifdef ISO
2171558Srgrimes		case 'c':
2181558Srgrimes			cltpflag = 1;
2191558Srgrimes			break;
2201558Srgrimes#ifdef notyet
2211558Srgrimes		case 'i':
2221558Srgrimes			tp4cnt = 1;
2231558Srgrimes			break;
2241558Srgrimes		case 'p':
2251558Srgrimes			tpipcnt = 1;
2261558Srgrimes			break;
2271558Srgrimes#endif /* notyet */
2281558Srgrimes#endif /* ISO */
2291558Srgrimes		default:
2301558Srgrimes		case '?':
2311558Srgrimes			usage();
2321558Srgrimes		};
23315496Sbde	if (!tcpflag && !udpflag)
23415496Sbde		udpflag = 1;
2351558Srgrimes	argv += optind;
2361558Srgrimes	argc -= optind;
2371558Srgrimes
2381558Srgrimes	/*
2391558Srgrimes	 * XXX
2401558Srgrimes	 * Backward compatibility, trailing number is the count of daemons.
2411558Srgrimes	 */
2421558Srgrimes	if (argc > 1)
2431558Srgrimes		usage();
2441558Srgrimes	if (argc == 1) {
2451558Srgrimes		nfsdcnt = atoi(argv[0]);
2461558Srgrimes		if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) {
24731206Sjdp			warnx("nfsd count %d; reset to %d", nfsdcnt,
24831206Sjdp			    DEFNFSDCNT);
2491558Srgrimes			nfsdcnt = DEFNFSDCNT;
2501558Srgrimes		}
2511558Srgrimes	}
2521558Srgrimes
2531558Srgrimes	if (debug == 0) {
2541558Srgrimes		daemon(0, 0);
2551558Srgrimes		(void)signal(SIGHUP, SIG_IGN);
2561558Srgrimes		(void)signal(SIGINT, SIG_IGN);
2571558Srgrimes		(void)signal(SIGQUIT, SIG_IGN);
2581558Srgrimes		(void)signal(SIGSYS, nonfs);
2591558Srgrimes		(void)signal(SIGTERM, SIG_IGN);
2601558Srgrimes	}
2611558Srgrimes	(void)signal(SIGCHLD, reapchild);
2621558Srgrimes
2631558Srgrimes	if (reregister) {
2641558Srgrimes		if (udpflag &&
2659336Sdfr		    (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) ||
2669336Sdfr		     !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT)))
2671558Srgrimes			err(1, "can't register with portmap for UDP.");
2681558Srgrimes		if (tcpflag &&
2699336Sdfr		    (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) ||
2709336Sdfr		     !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT)))
2711558Srgrimes			err(1, "can't register with portmap for TCP.");
2721558Srgrimes		exit(0);
2731558Srgrimes	}
2741558Srgrimes	openlog("nfsd:", LOG_PID, LOG_DAEMON);
2751558Srgrimes
2761558Srgrimes	for (i = 0; i < nfsdcnt; i++) {
2771558Srgrimes		switch (fork()) {
2781558Srgrimes		case -1:
2791558Srgrimes			syslog(LOG_ERR, "fork: %m");
2801558Srgrimes			exit (1);
2811558Srgrimes		case 0:
2821558Srgrimes			break;
2831558Srgrimes		default:
2841558Srgrimes			continue;
2851558Srgrimes		}
2861558Srgrimes
2879336Sdfr		setproctitle("server");
2881558Srgrimes		nfssvc_flag = NFSSVC_NFSD;
2891558Srgrimes		nsd.nsd_nfsd = NULL;
2909336Sdfr#ifdef NFSKERB
2919336Sdfr		if (sizeof (struct nfsrpc_fullverf) != RPCX_FULLVERF ||
2929336Sdfr		    sizeof (struct nfsrpc_fullblock) != RPCX_FULLBLOCK)
2939336Sdfr		    syslog(LOG_ERR, "Yikes NFSKERB structs not packed!");
2949336Sdfr		nsd.nsd_authstr = (u_char *)&kt;
2959336Sdfr		nsd.nsd_authlen = sizeof (kt);
2969336Sdfr		nsd.nsd_verfstr = (u_char *)&kverf;
2979336Sdfr		nsd.nsd_verflen = sizeof (kverf);
2981558Srgrimes#endif
2991558Srgrimes		while (nfssvc(nfssvc_flag, &nsd) < 0) {
3001558Srgrimes			if (errno != ENEEDAUTH) {
3011558Srgrimes				syslog(LOG_ERR, "nfssvc: %m");
3021558Srgrimes				exit(1);
3031558Srgrimes			}
3041558Srgrimes			nfssvc_flag = NFSSVC_NFSD | NFSSVC_AUTHINFAIL;
3059336Sdfr#ifdef NFSKERB
3069336Sdfr			/*
3079336Sdfr			 * Get the Kerberos ticket out of the authenticator
3089336Sdfr			 * verify it and convert the principal name to a user
3099336Sdfr			 * name. The user name is then converted to a set of
3109336Sdfr			 * user credentials via the password and group file.
3119336Sdfr			 * Finally, decrypt the timestamp and validate it.
3129336Sdfr			 * For more info see the IETF Draft "Authentication
3139336Sdfr			 * in ONC RPC".
3149336Sdfr			 */
3159336Sdfr			kt.length = ntohl(kt.length);
3169336Sdfr			if (gettimeofday(&ktv, (struct timezone *)0) == 0 &&
3179336Sdfr			    kt.length > 0 && kt.length <=
3189336Sdfr			    (RPCAUTH_MAXSIZ - 3 * NFSX_UNSIGNED)) {
3199336Sdfr			    kin.w1 = NFS_KERBW1(kt);
3209336Sdfr			    kt.mbz = 0;
3219336Sdfr			    (void)strcpy(inst, "*");
3229336Sdfr			    if (krb_rd_req(&kt, NFS_KERBSRV,
3239336Sdfr				inst, nsd.nsd_haddr, &kauth, "") == RD_AP_OK &&
3249336Sdfr				krb_kntoln(&kauth, lnam) == KSUCCESS &&
3259336Sdfr				(pwd = getpwnam(lnam)) != NULL) {
3261558Srgrimes				cr = &nsd.nsd_cr;
3271558Srgrimes				cr->cr_uid = pwd->pw_uid;
3281558Srgrimes				cr->cr_groups[0] = pwd->pw_gid;
3291558Srgrimes				cr->cr_ngroups = 1;
3301558Srgrimes				setgrent();
3311558Srgrimes				while ((grp = getgrent()) != NULL) {
3321558Srgrimes					if (grp->gr_gid == cr->cr_groups[0])
3331558Srgrimes						continue;
3341558Srgrimes					for (cpp = grp->gr_mem;
3351558Srgrimes					    *cpp != NULL; ++cpp)
3361558Srgrimes						if (!strcmp(*cpp, lnam))
3371558Srgrimes							break;
3381558Srgrimes					if (*cpp == NULL)
3391558Srgrimes						continue;
3401558Srgrimes					cr->cr_groups[cr->cr_ngroups++]
3411558Srgrimes					    = grp->gr_gid;
3421558Srgrimes					if (cr->cr_ngroups == NGROUPS)
3431558Srgrimes						break;
3441558Srgrimes				}
3451558Srgrimes				endgrent();
3469336Sdfr
3479336Sdfr				/*
3489336Sdfr				 * Get the timestamp verifier out of the
3499336Sdfr				 * authenticator and verifier strings.
3509336Sdfr				 */
3519336Sdfr				kin.t1 = kverf.t1;
3529336Sdfr				kin.t2 = kverf.t2;
3539336Sdfr				kin.w2 = kverf.w2;
3549336Sdfr				bzero((caddr_t)kivec, sizeof (kivec));
3559336Sdfr				bcopy((caddr_t)kauth.session,
3569336Sdfr				    (caddr_t)nsd.nsd_key,sizeof(kauth.session));
3579336Sdfr
3589336Sdfr				/*
3599336Sdfr				 * Decrypt the timestamp verifier in CBC mode.
3609336Sdfr				 */
3619336Sdfr				XXX
3629336Sdfr
3639336Sdfr				/*
3649336Sdfr				 * Validate the timestamp verifier, to
3659336Sdfr				 * check that the session key is ok.
3669336Sdfr				 */
3679336Sdfr				nsd.nsd_timestamp.tv_sec = ntohl(kout.t1);
3689336Sdfr				nsd.nsd_timestamp.tv_usec = ntohl(kout.t2);
3699336Sdfr				nsd.nsd_ttl = ntohl(kout.w1);
3709336Sdfr				if ((nsd.nsd_ttl - 1) == ntohl(kout.w2))
3719336Sdfr				    nfssvc_flag = NFSSVC_NFSD | NFSSVC_AUTHIN;
3721558Srgrimes			}
3739336Sdfr#endif /* NFSKERB */
3741558Srgrimes		}
3751558Srgrimes		exit(0);
3761558Srgrimes	}
3771558Srgrimes
3781558Srgrimes	/* If we are serving udp, set up the socket. */
3791558Srgrimes	if (udpflag) {
3801558Srgrimes		if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
3811558Srgrimes			syslog(LOG_ERR, "can't create udp socket");
3821558Srgrimes			exit(1);
3831558Srgrimes		}
3841558Srgrimes		inetaddr.sin_family = AF_INET;
3851558Srgrimes		inetaddr.sin_addr.s_addr = INADDR_ANY;
3861558Srgrimes		inetaddr.sin_port = htons(NFS_PORT);
3871558Srgrimes		inetaddr.sin_len = sizeof(inetaddr);
3881558Srgrimes		if (bind(sock,
3891558Srgrimes		    (struct sockaddr *)&inetaddr, sizeof(inetaddr)) < 0) {
3901558Srgrimes			syslog(LOG_ERR, "can't bind udp addr");
3911558Srgrimes			exit(1);
3921558Srgrimes		}
3939336Sdfr		if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) ||
3949336Sdfr		    !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT)) {
3951558Srgrimes			syslog(LOG_ERR, "can't register with udp portmap");
3961558Srgrimes			exit(1);
3971558Srgrimes		}
3981558Srgrimes		nfsdargs.sock = sock;
3991558Srgrimes		nfsdargs.name = NULL;
4001558Srgrimes		nfsdargs.namelen = 0;
4011558Srgrimes		if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
4021558Srgrimes			syslog(LOG_ERR, "can't Add UDP socket");
4031558Srgrimes			exit(1);
4041558Srgrimes		}
4051558Srgrimes		(void)close(sock);
4061558Srgrimes	}
4071558Srgrimes
4081558Srgrimes#ifdef ISO
4091558Srgrimes	/* If we are serving cltp, set up the socket. */
4101558Srgrimes	if (cltpflag) {
4111558Srgrimes		if ((sock = socket(AF_ISO, SOCK_DGRAM, 0)) < 0) {
4121558Srgrimes			syslog(LOG_ERR, "can't create cltp socket");
4131558Srgrimes			exit(1);
4141558Srgrimes		}
4151558Srgrimes		memset(&isoaddr, 0, sizeof(isoaddr));
4161558Srgrimes		isoaddr.siso_family = AF_ISO;
4171558Srgrimes		isoaddr.siso_tlen = 2;
4181558Srgrimes		cp = TSEL(&isoaddr);
4191558Srgrimes		*cp++ = (NFS_PORT >> 8);
4201558Srgrimes		*cp = (NFS_PORT & 0xff);
4211558Srgrimes		isoaddr.siso_len = sizeof(isoaddr);
4221558Srgrimes		if (bind(sock,
4231558Srgrimes		    (struct sockaddr *)&isoaddr, sizeof(isoaddr)) < 0) {
4241558Srgrimes			syslog(LOG_ERR, "can't bind cltp addr");
4251558Srgrimes			exit(1);
4261558Srgrimes		}
4271558Srgrimes#ifdef notyet
4281558Srgrimes		/*
4291558Srgrimes		 * XXX
4301558Srgrimes		 * Someday this should probably use "rpcbind", the son of
4311558Srgrimes		 * portmap.
4321558Srgrimes		 */
4331558Srgrimes		if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT)) {
4341558Srgrimes			syslog(LOG_ERR, "can't register with udp portmap");
4351558Srgrimes			exit(1);
4361558Srgrimes		}
4371558Srgrimes#endif /* notyet */
4381558Srgrimes		nfsdargs.sock = sock;
4391558Srgrimes		nfsdargs.name = NULL;
4401558Srgrimes		nfsdargs.namelen = 0;
4411558Srgrimes		if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
4421558Srgrimes			syslog(LOG_ERR, "can't add UDP socket");
4431558Srgrimes			exit(1);
4441558Srgrimes		}
4451558Srgrimes		close(sock);
4461558Srgrimes	}
4471558Srgrimes#endif /* ISO */
4481558Srgrimes
4491558Srgrimes	/* Now set up the master server socket waiting for tcp connections. */
4501558Srgrimes	on = 1;
4511558Srgrimes	FD_ZERO(&sockbits);
4521558Srgrimes	connect_type_cnt = 0;
4531558Srgrimes	if (tcpflag) {
4541558Srgrimes		if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
4551558Srgrimes			syslog(LOG_ERR, "can't create tcp socket");
4561558Srgrimes			exit(1);
4571558Srgrimes		}
4581558Srgrimes		if (setsockopt(tcpsock,
4591558Srgrimes		    SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
4601558Srgrimes			syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
4611558Srgrimes		inetaddr.sin_family = AF_INET;
4621558Srgrimes		inetaddr.sin_addr.s_addr = INADDR_ANY;
4631558Srgrimes		inetaddr.sin_port = htons(NFS_PORT);
4641558Srgrimes		inetaddr.sin_len = sizeof(inetaddr);
4651558Srgrimes		if (bind(tcpsock,
4661558Srgrimes		    (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) {
4671558Srgrimes			syslog(LOG_ERR, "can't bind tcp addr");
4681558Srgrimes			exit(1);
4691558Srgrimes		}
4701558Srgrimes		if (listen(tcpsock, 5) < 0) {
4711558Srgrimes			syslog(LOG_ERR, "listen failed");
4721558Srgrimes			exit(1);
4731558Srgrimes		}
4749336Sdfr		if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) ||
4759336Sdfr		    !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT)) {
4761558Srgrimes			syslog(LOG_ERR, "can't register tcp with portmap");
4771558Srgrimes			exit(1);
4781558Srgrimes		}
4791558Srgrimes		FD_SET(tcpsock, &sockbits);
4801558Srgrimes		maxsock = tcpsock;
4811558Srgrimes		connect_type_cnt++;
4821558Srgrimes	}
4831558Srgrimes
4841558Srgrimes#ifdef notyet
4851558Srgrimes	/* Now set up the master server socket waiting for tp4 connections. */
4861558Srgrimes	if (tp4flag) {
4871558Srgrimes		if ((tp4sock = socket(AF_ISO, SOCK_SEQPACKET, 0)) < 0) {
4881558Srgrimes			syslog(LOG_ERR, "can't create tp4 socket");
4891558Srgrimes			exit(1);
4901558Srgrimes		}
4911558Srgrimes		if (setsockopt(tp4sock,
4921558Srgrimes		    SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
4931558Srgrimes			syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
4941558Srgrimes		memset(&isoaddr, 0, sizeof(isoaddr));
4951558Srgrimes		isoaddr.siso_family = AF_ISO;
4961558Srgrimes		isoaddr.siso_tlen = 2;
4971558Srgrimes		cp = TSEL(&isoaddr);
4981558Srgrimes		*cp++ = (NFS_PORT >> 8);
4991558Srgrimes		*cp = (NFS_PORT & 0xff);
5001558Srgrimes		isoaddr.siso_len = sizeof(isoaddr);
5011558Srgrimes		if (bind(tp4sock,
5021558Srgrimes		    (struct sockaddr *)&isoaddr, sizeof (isoaddr)) < 0) {
5031558Srgrimes			syslog(LOG_ERR, "can't bind tp4 addr");
5041558Srgrimes			exit(1);
5051558Srgrimes		}
5061558Srgrimes		if (listen(tp4sock, 5) < 0) {
5071558Srgrimes			syslog(LOG_ERR, "listen failed");
5081558Srgrimes			exit(1);
5091558Srgrimes		}
5101558Srgrimes		/*
5111558Srgrimes		 * XXX
5121558Srgrimes		 * Someday this should probably use "rpcbind", the son of
5131558Srgrimes		 * portmap.
5141558Srgrimes		 */
5151558Srgrimes		if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
5161558Srgrimes			syslog(LOG_ERR, "can't register tcp with portmap");
5171558Srgrimes			exit(1);
5181558Srgrimes		}
5191558Srgrimes		FD_SET(tp4sock, &sockbits);
5201558Srgrimes		maxsock = tp4sock;
5211558Srgrimes		connect_type_cnt++;
5221558Srgrimes	}
5231558Srgrimes
5241558Srgrimes	/* Now set up the master server socket waiting for tpip connections. */
5251558Srgrimes	if (tpipflag) {
5261558Srgrimes		if ((tpipsock = socket(AF_INET, SOCK_SEQPACKET, 0)) < 0) {
5271558Srgrimes			syslog(LOG_ERR, "can't create tpip socket");
5281558Srgrimes			exit(1);
5291558Srgrimes		}
5301558Srgrimes		if (setsockopt(tpipsock,
5311558Srgrimes		    SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
5321558Srgrimes			syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
5331558Srgrimes		inetaddr.sin_family = AF_INET;
5341558Srgrimes		inetaddr.sin_addr.s_addr = INADDR_ANY;
5351558Srgrimes		inetaddr.sin_port = htons(NFS_PORT);
5361558Srgrimes		inetaddr.sin_len = sizeof(inetaddr);
5371558Srgrimes		if (bind(tpipsock,
5381558Srgrimes		    (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) {
5391558Srgrimes			syslog(LOG_ERR, "can't bind tcp addr");
5401558Srgrimes			exit(1);
5411558Srgrimes		}
5421558Srgrimes		if (listen(tpipsock, 5) < 0) {
5431558Srgrimes			syslog(LOG_ERR, "listen failed");
5441558Srgrimes			exit(1);
5451558Srgrimes		}
5461558Srgrimes		/*
5471558Srgrimes		 * XXX
5481558Srgrimes		 * Someday this should probably use "rpcbind", the son of
5491558Srgrimes		 * portmap.
5501558Srgrimes		 */
5511558Srgrimes		if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
5521558Srgrimes			syslog(LOG_ERR, "can't register tcp with portmap");
5531558Srgrimes			exit(1);
5541558Srgrimes		}
5551558Srgrimes		FD_SET(tpipsock, &sockbits);
5561558Srgrimes		maxsock = tpipsock;
5571558Srgrimes		connect_type_cnt++;
5581558Srgrimes	}
5591558Srgrimes#endif /* notyet */
5601558Srgrimes
5611558Srgrimes	if (connect_type_cnt == 0)
5621558Srgrimes		exit(0);
5631558Srgrimes
5649336Sdfr	setproctitle("master");
5651558Srgrimes
5661558Srgrimes	/*
5671558Srgrimes	 * Loop forever accepting connections and passing the sockets
5681558Srgrimes	 * into the kernel for the mounts.
5691558Srgrimes	 */
5701558Srgrimes	for (;;) {
5711558Srgrimes		ready = sockbits;
5721558Srgrimes		if (connect_type_cnt > 1) {
5731558Srgrimes			if (select(maxsock + 1,
5741558Srgrimes			    &ready, NULL, NULL, NULL) < 1) {
5751558Srgrimes				syslog(LOG_ERR, "select failed: %m");
5761558Srgrimes				exit(1);
5771558Srgrimes			}
5781558Srgrimes		}
5791558Srgrimes		if (tcpflag && FD_ISSET(tcpsock, &ready)) {
5801558Srgrimes			len = sizeof(inetpeer);
5811558Srgrimes			if ((msgsock = accept(tcpsock,
5821558Srgrimes			    (struct sockaddr *)&inetpeer, &len)) < 0) {
5831558Srgrimes				syslog(LOG_ERR, "accept failed: %m");
5841558Srgrimes				exit(1);
5851558Srgrimes			}
5861558Srgrimes			memset(inetpeer.sin_zero, 0, sizeof(inetpeer.sin_zero));
5871558Srgrimes			if (setsockopt(msgsock, SOL_SOCKET,
5881558Srgrimes			    SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
5891558Srgrimes				syslog(LOG_ERR,
5901558Srgrimes				    "setsockopt SO_KEEPALIVE: %m");
5911558Srgrimes			nfsdargs.sock = msgsock;
5921558Srgrimes			nfsdargs.name = (caddr_t)&inetpeer;
5931558Srgrimes			nfsdargs.namelen = sizeof(inetpeer);
5941558Srgrimes			nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
5951558Srgrimes			(void)close(msgsock);
5961558Srgrimes		}
5971558Srgrimes#ifdef notyet
5981558Srgrimes		if (tp4flag && FD_ISSET(tp4sock, &ready)) {
5991558Srgrimes			len = sizeof(isopeer);
6001558Srgrimes			if ((msgsock = accept(tp4sock,
6011558Srgrimes			    (struct sockaddr *)&isopeer, &len)) < 0) {
6021558Srgrimes				syslog(LOG_ERR, "accept failed: %m");
6031558Srgrimes				exit(1);
6041558Srgrimes			}
6051558Srgrimes			if (setsockopt(msgsock, SOL_SOCKET,
6061558Srgrimes			    SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
6071558Srgrimes				syslog(LOG_ERR,
6081558Srgrimes				    "setsockopt SO_KEEPALIVE: %m");
6091558Srgrimes			nfsdargs.sock = msgsock;
6101558Srgrimes			nfsdargs.name = (caddr_t)&isopeer;
6111558Srgrimes			nfsdargs.namelen = len;
6121558Srgrimes			nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
6131558Srgrimes			(void)close(msgsock);
6141558Srgrimes		}
6151558Srgrimes		if (tpipflag && FD_ISSET(tpipsock, &ready)) {
6161558Srgrimes			len = sizeof(inetpeer);
6171558Srgrimes			if ((msgsock = accept(tpipsock,
6181558Srgrimes			    (struct sockaddr *)&inetpeer, &len)) < 0) {
6191558Srgrimes				syslog(LOG_ERR, "Accept failed: %m");
6201558Srgrimes				exit(1);
6211558Srgrimes			}
6221558Srgrimes			if (setsockopt(msgsock, SOL_SOCKET,
6231558Srgrimes			    SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
6241558Srgrimes				syslog(LOG_ERR, "setsockopt SO_KEEPALIVE: %m");
6251558Srgrimes			nfsdargs.sock = msgsock;
6261558Srgrimes			nfsdargs.name = (caddr_t)&inetpeer;
6271558Srgrimes			nfsdargs.namelen = len;
6281558Srgrimes			nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
6291558Srgrimes			(void)close(msgsock);
6301558Srgrimes		}
6311558Srgrimes#endif /* notyet */
6321558Srgrimes	}
6331558Srgrimes}
6341558Srgrimes
6351558Srgrimesvoid
6361558Srgrimesusage()
6371558Srgrimes{
6389336Sdfr	(void)fprintf(stderr, "usage: nfsd %s\n", USAGE);
6391558Srgrimes	exit(1);
6401558Srgrimes}
6411558Srgrimes
6421558Srgrimesvoid
6431558Srgrimesnonfs(signo)
6441558Srgrimes	int signo;
6451558Srgrimes{
6461558Srgrimes	syslog(LOG_ERR, "missing system call: NFS not available.");
6471558Srgrimes}
6481558Srgrimes
6491558Srgrimesvoid
6501558Srgrimesreapchild(signo)
6511558Srgrimes	int signo;
6521558Srgrimes{
6531558Srgrimes
6549336Sdfr	while (wait3(NULL, WNOHANG, NULL) > 0);
6551558Srgrimes}
6561558Srgrimes
65713141Speter#ifdef OLD_SETPROCTITLE
6589336Sdfr#ifdef __FreeBSD__
6591558Srgrimesvoid
6601558Srgrimessetproctitle(a)
6611558Srgrimes	char *a;
6621558Srgrimes{
6631558Srgrimes	register char *cp;
6641558Srgrimes	char buf[80];
6651558Srgrimes
6661558Srgrimes	cp = Argv[0];
6679336Sdfr	(void)snprintf(buf, sizeof(buf), "nfsd-%s", a);
6681558Srgrimes	(void)strncpy(cp, buf, LastArg - cp);
6691558Srgrimes	cp += strlen(cp);
6701558Srgrimes	while (cp < LastArg)
6712030Sdg		*cp++ = '\0';
67212869Speter	Argv[1] = NULL;
6731558Srgrimes}
6749336Sdfr#endif	/* __FreeBSD__ */
67513141Speter#endif
676