xref: /freebsd/usr.sbin/nfsuserd/nfsuserd.c (revision 4d65a7c6951cea0333f1a0c1b32c38489cdfa6c5)
103914b0bSRick Macklem /*-
203914b0bSRick Macklem  * Copyright (c) 2009 Rick Macklem, University of Guelph
303914b0bSRick Macklem  * All rights reserved.
403914b0bSRick Macklem  *
503914b0bSRick Macklem  * Redistribution and use in source and binary forms, with or without
603914b0bSRick Macklem  * modification, are permitted provided that the following conditions
703914b0bSRick Macklem  * are met:
803914b0bSRick Macklem  * 1. Redistributions of source code must retain the above copyright
903914b0bSRick Macklem  *    notice, this list of conditions and the following disclaimer.
1003914b0bSRick Macklem  * 2. Redistributions in binary form must reproduce the above copyright
1103914b0bSRick Macklem  *    notice, this list of conditions and the following disclaimer in the
1203914b0bSRick Macklem  *    documentation and/or other materials provided with the distribution.
1303914b0bSRick Macklem  *
1403914b0bSRick Macklem  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1503914b0bSRick Macklem  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1603914b0bSRick Macklem  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1703914b0bSRick Macklem  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1803914b0bSRick Macklem  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1903914b0bSRick Macklem  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2003914b0bSRick Macklem  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2103914b0bSRick Macklem  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2203914b0bSRick Macklem  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2303914b0bSRick Macklem  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2403914b0bSRick Macklem  * SUCH DAMAGE.
2503914b0bSRick Macklem  *
2603914b0bSRick Macklem  */
2703914b0bSRick Macklem 
2803914b0bSRick Macklem #include <sys/param.h>
2903914b0bSRick Macklem #include <sys/errno.h>
3003914b0bSRick Macklem #include <sys/linker.h>
3103914b0bSRick Macklem #include <sys/module.h>
3203914b0bSRick Macklem #include <sys/mount.h>
3303914b0bSRick Macklem #include <sys/socket.h>
3403914b0bSRick Macklem #include <sys/socketvar.h>
35*a94018e2SRick Macklem #include <sys/sysctl.h>
3603914b0bSRick Macklem #include <sys/time.h>
3703914b0bSRick Macklem #include <sys/ucred.h>
3803914b0bSRick Macklem #include <sys/vnode.h>
3903914b0bSRick Macklem #include <sys/wait.h>
4003914b0bSRick Macklem 
41ce78460aSRick Macklem #include <netinet/in.h>
42ce78460aSRick Macklem 
43ce78460aSRick Macklem #include <arpa/inet.h>
44ce78460aSRick Macklem 
4503914b0bSRick Macklem #include <nfs/nfssvc.h>
4603914b0bSRick Macklem 
4703914b0bSRick Macklem #include <rpc/rpc.h>
4803914b0bSRick Macklem 
4903914b0bSRick Macklem #include <fs/nfs/rpcv2.h>
5003914b0bSRick Macklem #include <fs/nfs/nfsproto.h>
5103914b0bSRick Macklem #include <fs/nfs/nfskpiport.h>
5203914b0bSRick Macklem #include <fs/nfs/nfs.h>
5303914b0bSRick Macklem 
5403914b0bSRick Macklem #include <ctype.h>
5503914b0bSRick Macklem #include <err.h>
5603914b0bSRick Macklem #include <grp.h>
5703914b0bSRick Macklem #include <netdb.h>
5803914b0bSRick Macklem #include <pwd.h>
5903914b0bSRick Macklem #include <signal.h>
6003914b0bSRick Macklem #include <stdio.h>
6103914b0bSRick Macklem #include <stdlib.h>
6203914b0bSRick Macklem #include <string.h>
6303914b0bSRick Macklem #include <syslog.h>
6403914b0bSRick Macklem #include <unistd.h>
6503914b0bSRick Macklem 
6603914b0bSRick Macklem /*
6703914b0bSRick Macklem  * This program loads the password and group databases into the kernel
6803914b0bSRick Macklem  * for NFS V4.
6903914b0bSRick Macklem  */
7003914b0bSRick Macklem 
719964058eSXin LI static void	cleanup_term(int);
729964058eSXin LI static void	usage(void);
739964058eSXin LI static void	nfsuserdsrv(struct svc_req *, SVCXPRT *);
749964058eSXin LI static bool_t	xdr_getid(XDR *, caddr_t);
759964058eSXin LI static bool_t	xdr_getname(XDR *, caddr_t);
769964058eSXin LI static bool_t	xdr_retval(XDR *, caddr_t);
77ce78460aSRick Macklem static int	nfsbind_localhost(void);
7803914b0bSRick Macklem 
7903914b0bSRick Macklem #define	MAXNAME		1024
8003914b0bSRick Macklem #define	MAXNFSUSERD	20
8103914b0bSRick Macklem #define	DEFNFSUSERD	4
82eb75badeSRick Macklem #define	MAXUSERMAX	100000
83eb75badeSRick Macklem #define	MINUSERMAX	10
8403914b0bSRick Macklem #define	DEFUSERMAX	200
8503914b0bSRick Macklem #define	DEFUSERTIMEOUT	(1 * 60)
8603914b0bSRick Macklem struct info {
8703914b0bSRick Macklem 	long	id;
8803914b0bSRick Macklem 	long	retval;
8903914b0bSRick Macklem 	char	name[MAXNAME + 1];
9003914b0bSRick Macklem };
9103914b0bSRick Macklem 
9203914b0bSRick Macklem u_char *dnsname = "default.domain";
9303914b0bSRick Macklem u_char *defaultuser = "nobody";
94c1c63967SRick Macklem uid_t defaultuid = 65534;
9503914b0bSRick Macklem u_char *defaultgroup = "nogroup";
96c1c63967SRick Macklem gid_t defaultgid = 65533;
9733906122SRick Macklem int verbose = 0, im_a_server = 0, nfsuserdcnt = -1, forcestart = 0;
98e6c623c8SRick Macklem int defusertimeout = DEFUSERTIMEOUT, manage_gids = 0;
9933906122SRick Macklem pid_t servers[MAXNFSUSERD];
100ce78460aSRick Macklem static struct sockaddr_storage fromip;
101ce78460aSRick Macklem #ifdef INET6
102ce78460aSRick Macklem static struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT;
103ce78460aSRick Macklem #endif
10403914b0bSRick Macklem 
10503914b0bSRick Macklem int
main(int argc,char * argv[])1069964058eSXin LI main(int argc, char *argv[])
10703914b0bSRick Macklem {
108eb75badeSRick Macklem 	int i, j;
109eb75badeSRick Macklem 	int error, fnd_dup, len, mustfreeai = 0, start_uidpos;
11003914b0bSRick Macklem 	struct nfsd_idargs nid;
11103914b0bSRick Macklem 	struct passwd *pwd;
11203914b0bSRick Macklem 	struct group *grp;
1137897d2a5SRick Macklem 	int sock, one = 1;
1149964058eSXin LI 	SVCXPRT *udptransp;
115ce78460aSRick Macklem 	struct nfsuserd_args nargs;
11603914b0bSRick Macklem 	sigset_t signew;
1179964058eSXin LI 	char hostname[MAXHOSTNAMELEN + 1], *cp;
11803914b0bSRick Macklem 	struct addrinfo *aip, hints;
119eb75badeSRick Macklem 	static uid_t check_dups[MAXUSERMAX];
120e6c623c8SRick Macklem 	gid_t grps[NGROUPS];
121e6c623c8SRick Macklem 	int ngroup;
122ce78460aSRick Macklem #ifdef INET
123ce78460aSRick Macklem 	struct sockaddr_in *sin;
124ce78460aSRick Macklem #endif
125ce78460aSRick Macklem #ifdef INET6
126ce78460aSRick Macklem 	struct sockaddr_in6 *sin6;
127ce78460aSRick Macklem #endif
128*a94018e2SRick Macklem 	int jailed, s;
129*a94018e2SRick Macklem 	size_t jailed_size;
13003914b0bSRick Macklem 
13103914b0bSRick Macklem 	if (modfind("nfscommon") < 0) {
13203914b0bSRick Macklem 		/* Not present in kernel, try loading it */
13303914b0bSRick Macklem 		if (kldload("nfscommon") < 0 ||
13403914b0bSRick Macklem 		    modfind("nfscommon") < 0)
13503914b0bSRick Macklem 			errx(1, "Experimental nfs subsystem is not available");
13603914b0bSRick Macklem 	}
13703914b0bSRick Macklem 
13803914b0bSRick Macklem 	/*
13903914b0bSRick Macklem 	 * First, figure out what our domain name and Kerberos Realm
14003914b0bSRick Macklem 	 * seem to be. Command line args may override these later.
14103914b0bSRick Macklem 	 */
14203914b0bSRick Macklem 	if (gethostname(hostname, MAXHOSTNAMELEN) == 0) {
14303914b0bSRick Macklem 		if ((cp = strchr(hostname, '.')) != NULL &&
14403914b0bSRick Macklem 		    *(cp + 1) != '\0') {
14503914b0bSRick Macklem 			dnsname = cp + 1;
14603914b0bSRick Macklem 		} else {
14703914b0bSRick Macklem 			memset((void *)&hints, 0, sizeof (hints));
14803914b0bSRick Macklem 			hints.ai_flags = AI_CANONNAME;
14903914b0bSRick Macklem 			error = getaddrinfo(hostname, NULL, &hints, &aip);
15003914b0bSRick Macklem 			if (error == 0) {
15103914b0bSRick Macklem 			    if (aip->ai_canonname != NULL &&
15203914b0bSRick Macklem 				(cp = strchr(aip->ai_canonname, '.')) != NULL
15303914b0bSRick Macklem 				&& *(cp + 1) != '\0') {
15403914b0bSRick Macklem 					dnsname = cp + 1;
15503914b0bSRick Macklem 					mustfreeai = 1;
15603914b0bSRick Macklem 				} else {
15703914b0bSRick Macklem 					freeaddrinfo(aip);
15803914b0bSRick Macklem 				}
15903914b0bSRick Macklem 			}
16003914b0bSRick Macklem 		}
16103914b0bSRick Macklem 	}
162ce78460aSRick Macklem 
163ce78460aSRick Macklem 	/*
164ce78460aSRick Macklem 	 * See if this server handles IPv4 or IPv6 and set up the default
165ce78460aSRick Macklem 	 * localhost address.
166ce78460aSRick Macklem 	 */
167ce78460aSRick Macklem 	s = -1;
168ce78460aSRick Macklem #ifdef INET6
169ce78460aSRick Macklem 	s = socket(PF_INET6, SOCK_DGRAM, 0);
170ce78460aSRick Macklem 	if (s >= 0) {
171ce78460aSRick Macklem 		fromip.ss_family = AF_INET6;
172ce78460aSRick Macklem 		fromip.ss_len = sizeof(struct sockaddr_in6);
173ce78460aSRick Macklem 		sin6 = (struct sockaddr_in6 *)&fromip;
174ce78460aSRick Macklem 		sin6->sin6_addr = in6loopback;
175ce78460aSRick Macklem 		close(s);
176ce78460aSRick Macklem 	}
177ce78460aSRick Macklem #endif	/* INET6 */
178ce78460aSRick Macklem #ifdef INET
179ce78460aSRick Macklem 	if (s < 0) {
180ce78460aSRick Macklem 		s = socket(PF_INET, SOCK_DGRAM, 0);
181ce78460aSRick Macklem 		if (s >= 0) {
182ce78460aSRick Macklem 			fromip.ss_family = AF_INET;
183ce78460aSRick Macklem 			fromip.ss_len = sizeof(struct sockaddr_in);
184ce78460aSRick Macklem 			sin = (struct sockaddr_in *)&fromip;
185ce78460aSRick Macklem 			sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
186ce78460aSRick Macklem 			close(s);
187ce78460aSRick Macklem 		}
188ce78460aSRick Macklem 	}
189ce78460aSRick Macklem #endif	/* INET */
190ce78460aSRick Macklem 	if (s < 0)
191ce78460aSRick Macklem 		err(1, "Can't create a inet/inet6 socket");
192ce78460aSRick Macklem 
19303914b0bSRick Macklem 	nid.nid_usermax = DEFUSERMAX;
19403914b0bSRick Macklem 	nid.nid_usertimeout = defusertimeout;
19503914b0bSRick Macklem 
19603914b0bSRick Macklem 	argc--;
19703914b0bSRick Macklem 	argv++;
19803914b0bSRick Macklem 	while (argc >= 1) {
19903914b0bSRick Macklem 		if (!strcmp(*argv, "-domain")) {
20003914b0bSRick Macklem 			if (argc == 1)
20103914b0bSRick Macklem 				usage();
20203914b0bSRick Macklem 			argc--;
20303914b0bSRick Macklem 			argv++;
20403914b0bSRick Macklem 			strncpy(hostname, *argv, MAXHOSTNAMELEN);
20503914b0bSRick Macklem 			hostname[MAXHOSTNAMELEN] = '\0';
20603914b0bSRick Macklem 			dnsname = hostname;
20703914b0bSRick Macklem 		} else if (!strcmp(*argv, "-verbose")) {
20803914b0bSRick Macklem 			verbose = 1;
20903914b0bSRick Macklem 		} else if (!strcmp(*argv, "-force")) {
21003914b0bSRick Macklem 			forcestart = 1;
211e6c623c8SRick Macklem 		} else if (!strcmp(*argv, "-manage-gids")) {
212e6c623c8SRick Macklem 			manage_gids = 1;
21303914b0bSRick Macklem 		} else if (!strcmp(*argv, "-usermax")) {
21403914b0bSRick Macklem 			if (argc == 1)
21503914b0bSRick Macklem 				usage();
21603914b0bSRick Macklem 			argc--;
21703914b0bSRick Macklem 			argv++;
21803914b0bSRick Macklem 			i = atoi(*argv);
219eb75badeSRick Macklem 			if (i < MINUSERMAX || i > MAXUSERMAX) {
22003914b0bSRick Macklem 				fprintf(stderr,
221eb75badeSRick Macklem 				    "usermax %d out of range %d<->%d\n", i,
222eb75badeSRick Macklem 				    MINUSERMAX, MAXUSERMAX);
22303914b0bSRick Macklem 				usage();
22403914b0bSRick Macklem 			}
22503914b0bSRick Macklem 			nid.nid_usermax = i;
22603914b0bSRick Macklem 		} else if (!strcmp(*argv, "-usertimeout")) {
22703914b0bSRick Macklem 			if (argc == 1)
22803914b0bSRick Macklem 				usage();
22903914b0bSRick Macklem 			argc--;
23003914b0bSRick Macklem 			argv++;
23103914b0bSRick Macklem 			i = atoi(*argv);
23203914b0bSRick Macklem 			if (i < 0 || i > 100000) {
23303914b0bSRick Macklem 				fprintf(stderr,
2349964058eSXin LI 				    "usertimeout %d out of range 0<->100000\n",
23503914b0bSRick Macklem 				    i);
23603914b0bSRick Macklem 				usage();
23703914b0bSRick Macklem 			}
23803914b0bSRick Macklem 			nid.nid_usertimeout = defusertimeout = i * 60;
23903914b0bSRick Macklem 		} else if (nfsuserdcnt == -1) {
24003914b0bSRick Macklem 			nfsuserdcnt = atoi(*argv);
24103914b0bSRick Macklem 			if (nfsuserdcnt < 1)
24203914b0bSRick Macklem 				usage();
24303914b0bSRick Macklem 			if (nfsuserdcnt > MAXNFSUSERD) {
24403914b0bSRick Macklem 				warnx("nfsuserd count %d; reset to %d",
24503914b0bSRick Macklem 				    nfsuserdcnt, DEFNFSUSERD);
24603914b0bSRick Macklem 				nfsuserdcnt = DEFNFSUSERD;
24703914b0bSRick Macklem 			}
24803914b0bSRick Macklem 		} else {
24903914b0bSRick Macklem 			usage();
25003914b0bSRick Macklem 		}
25103914b0bSRick Macklem 		argc--;
25203914b0bSRick Macklem 		argv++;
25303914b0bSRick Macklem 	}
25403914b0bSRick Macklem 	if (nfsuserdcnt < 1)
25503914b0bSRick Macklem 		nfsuserdcnt = DEFNFSUSERD;
25603914b0bSRick Macklem 
25703914b0bSRick Macklem 	/*
25803914b0bSRick Macklem 	 * Strip off leading and trailing '.'s in domain name and map
25903914b0bSRick Macklem 	 * alphabetics to lower case.
26003914b0bSRick Macklem 	 */
26103914b0bSRick Macklem 	while (*dnsname == '.')
26203914b0bSRick Macklem 		dnsname++;
26303914b0bSRick Macklem 	if (*dnsname == '\0')
26403914b0bSRick Macklem 		errx(1, "Domain name all '.'");
26503914b0bSRick Macklem 	len = strlen(dnsname);
26603914b0bSRick Macklem 	cp = dnsname + len - 1;
26703914b0bSRick Macklem 	while (*cp == '.') {
26803914b0bSRick Macklem 		*cp = '\0';
26903914b0bSRick Macklem 		len--;
27003914b0bSRick Macklem 		cp--;
27103914b0bSRick Macklem 	}
27203914b0bSRick Macklem 	for (i = 0; i < len; i++) {
27303914b0bSRick Macklem 		if (!isascii(dnsname[i]))
27403914b0bSRick Macklem 			errx(1, "Domain name has non-ascii char");
27503914b0bSRick Macklem 		if (isupper(dnsname[i]))
27603914b0bSRick Macklem 			dnsname[i] = tolower(dnsname[i]);
27703914b0bSRick Macklem 	}
27803914b0bSRick Macklem 
27903914b0bSRick Macklem 	/*
28003914b0bSRick Macklem 	 * If the nfsuserd died off ungracefully, this is necessary to
28103914b0bSRick Macklem 	 * get them to start again.
28203914b0bSRick Macklem 	 */
28303914b0bSRick Macklem 	if (forcestart && nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0)
28403914b0bSRick Macklem 		errx(1, "Can't do nfssvc() to delete the port");
28503914b0bSRick Macklem 
28603914b0bSRick Macklem 	if (verbose)
28703914b0bSRick Macklem 		fprintf(stderr,
28803914b0bSRick Macklem 		    "nfsuserd: domain=%s usermax=%d usertimeout=%d\n",
28903914b0bSRick Macklem 		    dnsname, nid.nid_usermax, nid.nid_usertimeout);
29003914b0bSRick Macklem 
29103914b0bSRick Macklem 	for (i = 0; i < nfsuserdcnt; i++)
29233906122SRick Macklem 		servers[i] = (pid_t)-1;
29303914b0bSRick Macklem 
294ce78460aSRick Macklem 	nargs.nuserd_family = fromip.ss_family;
29503914b0bSRick Macklem 	/*
29603914b0bSRick Macklem 	 * Set up the service port to accept requests via UDP from
297ce78460aSRick Macklem 	 * localhost (INADDR_LOOPBACK or IN6ADDR_LOOPBACK_INIT).
29803914b0bSRick Macklem 	 */
299ce78460aSRick Macklem 	if ((sock = socket(nargs.nuserd_family, SOCK_DGRAM, IPPROTO_UDP)) < 0)
30003914b0bSRick Macklem 		err(1, "cannot create udp socket");
30103914b0bSRick Macklem 
30203914b0bSRick Macklem 	/*
30303914b0bSRick Macklem 	 * Not sure what this does, so I'll leave it here for now.
30403914b0bSRick Macklem 	 */
30503914b0bSRick Macklem 	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
30603914b0bSRick Macklem 
30703914b0bSRick Macklem 	if ((udptransp = svcudp_create(sock)) == NULL)
30803914b0bSRick Macklem 		err(1, "Can't set up socket");
30903914b0bSRick Macklem 
31003914b0bSRick Macklem 	/*
31103914b0bSRick Macklem 	 * By not specifying a protocol, it is linked into the
31203914b0bSRick Macklem 	 * dispatch queue, but not registered with portmapper,
31303914b0bSRick Macklem 	 * which is just what I want.
31403914b0bSRick Macklem 	 */
31503914b0bSRick Macklem 	if (!svc_register(udptransp, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS,
31603914b0bSRick Macklem 	    nfsuserdsrv, 0))
31703914b0bSRick Macklem 		err(1, "Can't register nfsuserd");
31803914b0bSRick Macklem 
31903914b0bSRick Macklem 	/*
32003914b0bSRick Macklem 	 * Tell the kernel what my port# is.
32103914b0bSRick Macklem 	 */
322ce78460aSRick Macklem 	nargs.nuserd_port = htons(udptransp->xp_port);
32303914b0bSRick Macklem #ifdef DEBUG
324ce78460aSRick Macklem 	printf("portnum=0x%x\n", nargs.nuserd_port);
32503914b0bSRick Macklem #else
326ce78460aSRick Macklem 	if (nfssvc(NFSSVC_NFSUSERDPORT | NFSSVC_NEWSTRUCT, &nargs) < 0) {
3277897d2a5SRick Macklem 		if (errno == EPERM) {
328*a94018e2SRick Macklem 			jailed = 0;
329*a94018e2SRick Macklem 			jailed_size = sizeof(jailed);
330*a94018e2SRick Macklem 			sysctlbyname("security.jail.jailed", &jailed,
331*a94018e2SRick Macklem 			    &jailed_size, NULL, 0);
332*a94018e2SRick Macklem 			if (jailed != 0) {
333*a94018e2SRick Macklem 				fprintf(stderr, "Cannot start nfsuserd. "
334*a94018e2SRick Macklem 				    "allow.nfsd might not be configured\n");
335*a94018e2SRick Macklem 			} else {
336*a94018e2SRick Macklem 				fprintf(stderr, "Cannot start nfsuserd "
337*a94018e2SRick Macklem 				    "when already running.");
338*a94018e2SRick Macklem 				fprintf(stderr, " If not running, "
339*a94018e2SRick Macklem 				    "use the -force option.\n");
340*a94018e2SRick Macklem 			}
34177193c05SRick Macklem 		} else {
3427897d2a5SRick Macklem 			fprintf(stderr, "Can't do nfssvc() to add port\n");
3437897d2a5SRick Macklem 		}
34477193c05SRick Macklem 		exit(1);
34577193c05SRick Macklem 	}
34677193c05SRick Macklem #endif
34703914b0bSRick Macklem 
34803914b0bSRick Macklem 	pwd = getpwnam(defaultuser);
34903914b0bSRick Macklem 	if (pwd)
35003914b0bSRick Macklem 		nid.nid_uid = pwd->pw_uid;
35103914b0bSRick Macklem 	else
35203914b0bSRick Macklem 		nid.nid_uid = defaultuid;
35303914b0bSRick Macklem 	grp = getgrnam(defaultgroup);
35403914b0bSRick Macklem 	if (grp)
35503914b0bSRick Macklem 		nid.nid_gid = grp->gr_gid;
35603914b0bSRick Macklem 	else
35703914b0bSRick Macklem 		nid.nid_gid = defaultgid;
35803914b0bSRick Macklem 	nid.nid_name = dnsname;
35903914b0bSRick Macklem 	nid.nid_namelen = strlen(nid.nid_name);
360e6c623c8SRick Macklem 	nid.nid_ngroup = 0;
361e6c623c8SRick Macklem 	nid.nid_grps = NULL;
36203914b0bSRick Macklem 	nid.nid_flag = NFSID_INITIALIZE;
36303914b0bSRick Macklem #ifdef DEBUG
36403914b0bSRick Macklem 	printf("Initialize uid=%d gid=%d dns=%s\n", nid.nid_uid, nid.nid_gid,
36503914b0bSRick Macklem 	    nid.nid_name);
36603914b0bSRick Macklem #else
367e6c623c8SRick Macklem 	error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
36803914b0bSRick Macklem 	if (error)
36903914b0bSRick Macklem 		errx(1, "Can't initialize nfs user/groups");
37003914b0bSRick Macklem #endif
37103914b0bSRick Macklem 
37203914b0bSRick Macklem 	i = 0;
37303914b0bSRick Macklem 	/*
37403914b0bSRick Macklem 	 * Loop around adding all groups.
37503914b0bSRick Macklem 	 */
37603914b0bSRick Macklem 	setgrent();
37703914b0bSRick Macklem 	while (i < nid.nid_usermax && (grp = getgrent())) {
37803914b0bSRick Macklem 		nid.nid_gid = grp->gr_gid;
37903914b0bSRick Macklem 		nid.nid_name = grp->gr_name;
38003914b0bSRick Macklem 		nid.nid_namelen = strlen(grp->gr_name);
381e6c623c8SRick Macklem 		nid.nid_ngroup = 0;
382e6c623c8SRick Macklem 		nid.nid_grps = NULL;
38303914b0bSRick Macklem 		nid.nid_flag = NFSID_ADDGID;
38403914b0bSRick Macklem #ifdef DEBUG
38503914b0bSRick Macklem 		printf("add gid=%d name=%s\n", nid.nid_gid, nid.nid_name);
38603914b0bSRick Macklem #else
387e6c623c8SRick Macklem 		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
38803914b0bSRick Macklem 		if (error)
38903914b0bSRick Macklem 			errx(1, "Can't add group %s", grp->gr_name);
39003914b0bSRick Macklem #endif
39103914b0bSRick Macklem 		i++;
39203914b0bSRick Macklem 	}
393670c1e4bSMark Johnston 	endgrent();
39403914b0bSRick Macklem 
39503914b0bSRick Macklem 	/*
39603914b0bSRick Macklem 	 * Loop around adding all users.
39703914b0bSRick Macklem 	 */
398eb75badeSRick Macklem 	start_uidpos = i;
39903914b0bSRick Macklem 	setpwent();
40003914b0bSRick Macklem 	while (i < nid.nid_usermax && (pwd = getpwent())) {
401eb75badeSRick Macklem 		fnd_dup = 0;
402eb75badeSRick Macklem 		/*
403eb75badeSRick Macklem 		 * Yes, this is inefficient, but it is only done once when
404eb75badeSRick Macklem 		 * the daemon is started and will run in a fraction of a second
405eb75badeSRick Macklem 		 * for nid_usermax at 10000. If nid_usermax is cranked up to
406eb75badeSRick Macklem 		 * 100000, it will take several seconds, depending on the CPU.
407eb75badeSRick Macklem 		 */
408eb75badeSRick Macklem 		for (j = 0; j < (i - start_uidpos); j++)
409eb75badeSRick Macklem 			if (check_dups[j] == pwd->pw_uid) {
410eb75badeSRick Macklem 				/* Found another entry for uid, so skip it */
411eb75badeSRick Macklem 				fnd_dup = 1;
412eb75badeSRick Macklem 				break;
413eb75badeSRick Macklem 			}
414eb75badeSRick Macklem 		if (fnd_dup != 0)
415eb75badeSRick Macklem 			continue;
416eb75badeSRick Macklem 		check_dups[i - start_uidpos] = pwd->pw_uid;
41703914b0bSRick Macklem 		nid.nid_uid = pwd->pw_uid;
41803914b0bSRick Macklem 		nid.nid_name = pwd->pw_name;
41903914b0bSRick Macklem 		nid.nid_namelen = strlen(pwd->pw_name);
420e6c623c8SRick Macklem 		if (manage_gids != 0) {
421e6c623c8SRick Macklem 			/* Get the group list for this user. */
422e6c623c8SRick Macklem 			ngroup = NGROUPS;
423e6c623c8SRick Macklem 			if (getgrouplist(pwd->pw_name, pwd->pw_gid, grps,
424e6c623c8SRick Macklem 			    &ngroup) < 0)
425e6c623c8SRick Macklem 				syslog(LOG_ERR, "Group list too small");
426e6c623c8SRick Macklem 			nid.nid_ngroup = ngroup;
427e6c623c8SRick Macklem 			nid.nid_grps = grps;
428e6c623c8SRick Macklem 		} else {
429e6c623c8SRick Macklem 			nid.nid_ngroup = 0;
430e6c623c8SRick Macklem 			nid.nid_grps = NULL;
431e6c623c8SRick Macklem 		}
43203914b0bSRick Macklem 		nid.nid_flag = NFSID_ADDUID;
43303914b0bSRick Macklem #ifdef DEBUG
43403914b0bSRick Macklem 		printf("add uid=%d name=%s\n", nid.nid_uid, nid.nid_name);
43503914b0bSRick Macklem #else
436e6c623c8SRick Macklem 		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
43703914b0bSRick Macklem 		if (error)
43803914b0bSRick Macklem 			errx(1, "Can't add user %s", pwd->pw_name);
43903914b0bSRick Macklem #endif
44003914b0bSRick Macklem 		i++;
44103914b0bSRick Macklem 	}
442670c1e4bSMark Johnston 	endpwent();
44303914b0bSRick Macklem 
44403914b0bSRick Macklem 	/*
44503914b0bSRick Macklem 	 * I should feel guilty for not calling this for all the above exit()
44603914b0bSRick Macklem 	 * upon error cases, but I don't.
44703914b0bSRick Macklem 	 */
44803914b0bSRick Macklem 	if (mustfreeai)
44903914b0bSRick Macklem 		freeaddrinfo(aip);
45003914b0bSRick Macklem 
45103914b0bSRick Macklem #ifdef DEBUG
45203914b0bSRick Macklem 	exit(0);
45303914b0bSRick Macklem #endif
45403914b0bSRick Macklem 	/*
45533906122SRick Macklem 	 * Temporarily block SIGUSR1 and SIGCHLD, so servers[] can't
45603914b0bSRick Macklem 	 * end up bogus.
45703914b0bSRick Macklem 	 */
45803914b0bSRick Macklem 	sigemptyset(&signew);
45903914b0bSRick Macklem 	sigaddset(&signew, SIGUSR1);
46003914b0bSRick Macklem 	sigaddset(&signew, SIGCHLD);
46103914b0bSRick Macklem 	sigprocmask(SIG_BLOCK, &signew, NULL);
46203914b0bSRick Macklem 
46303914b0bSRick Macklem 	daemon(0, 0);
46403914b0bSRick Macklem 	(void)signal(SIGHUP, SIG_IGN);
46503914b0bSRick Macklem 	(void)signal(SIGINT, SIG_IGN);
46603914b0bSRick Macklem 	(void)signal(SIGQUIT, SIG_IGN);
46703914b0bSRick Macklem 	(void)signal(SIGTERM, SIG_IGN);
46803914b0bSRick Macklem 	(void)signal(SIGUSR1, cleanup_term);
46903914b0bSRick Macklem 	(void)signal(SIGCHLD, cleanup_term);
47003914b0bSRick Macklem 
47103914b0bSRick Macklem 	openlog("nfsuserd:", LOG_PID, LOG_DAEMON);
47203914b0bSRick Macklem 
47303914b0bSRick Macklem 	/*
47433906122SRick Macklem 	 * Fork off the server daemons that do the work. All the master
47533906122SRick Macklem 	 * does is terminate them and cleanup.
47603914b0bSRick Macklem 	 */
47703914b0bSRick Macklem 	for (i = 0; i < nfsuserdcnt; i++) {
47833906122SRick Macklem 		servers[i] = fork();
47933906122SRick Macklem 		if (servers[i] == 0) {
48033906122SRick Macklem 			im_a_server = 1;
48133906122SRick Macklem 			setproctitle("server");
48203914b0bSRick Macklem 			sigemptyset(&signew);
48303914b0bSRick Macklem 			sigaddset(&signew, SIGUSR1);
48403914b0bSRick Macklem 			sigprocmask(SIG_UNBLOCK, &signew, NULL);
48503914b0bSRick Macklem 
48603914b0bSRick Macklem 			/*
48703914b0bSRick Macklem 			 * and away we go.
48803914b0bSRick Macklem 			 */
48903914b0bSRick Macklem 			svc_run();
49003914b0bSRick Macklem 			syslog(LOG_ERR, "nfsuserd died: %m");
49103914b0bSRick Macklem 			exit(1);
49233906122SRick Macklem 		} else if (servers[i] < 0) {
49303914b0bSRick Macklem 			syslog(LOG_ERR, "fork: %m");
49403914b0bSRick Macklem 		}
49503914b0bSRick Macklem 	}
49603914b0bSRick Macklem 
49703914b0bSRick Macklem 	/*
49803914b0bSRick Macklem 	 * Just wait for SIGUSR1 or a child to die and then...
49903914b0bSRick Macklem 	 * As the Governor of California would say, "Terminate them".
50003914b0bSRick Macklem 	 */
50103914b0bSRick Macklem 	setproctitle("master");
50203914b0bSRick Macklem 	sigemptyset(&signew);
50303914b0bSRick Macklem 	while (1)
50403914b0bSRick Macklem 		sigsuspend(&signew);
50503914b0bSRick Macklem }
50603914b0bSRick Macklem 
50703914b0bSRick Macklem /*
50803914b0bSRick Macklem  * The nfsuserd rpc service
50903914b0bSRick Macklem  */
5109964058eSXin LI static void
nfsuserdsrv(struct svc_req * rqstp,SVCXPRT * transp)51103914b0bSRick Macklem nfsuserdsrv(struct svc_req *rqstp, SVCXPRT *transp)
51203914b0bSRick Macklem {
51303914b0bSRick Macklem 	struct passwd *pwd;
51403914b0bSRick Macklem 	struct group *grp;
51503914b0bSRick Macklem 	int error;
516ce78460aSRick Macklem #if defined(INET) || defined(INET6)
51703914b0bSRick Macklem 	u_short sport;
518ce78460aSRick Macklem 	int ret;
519ce78460aSRick Macklem #endif
52003914b0bSRick Macklem 	struct info info;
52103914b0bSRick Macklem 	struct nfsd_idargs nid;
522e6c623c8SRick Macklem 	gid_t grps[NGROUPS];
523e6c623c8SRick Macklem 	int ngroup;
524ce78460aSRick Macklem #ifdef INET
525ce78460aSRick Macklem 	struct sockaddr_in *fromsin, *sin;
526ce78460aSRick Macklem #endif
527ce78460aSRick Macklem #ifdef INET6
528ce78460aSRick Macklem 	struct sockaddr_in6 *fromsin6, *sin6;
529ce78460aSRick Macklem 	char buf[INET6_ADDRSTRLEN];
530ce78460aSRick Macklem #endif
53103914b0bSRick Macklem 
53203914b0bSRick Macklem 	/*
533ce78460aSRick Macklem 	 * Only handle requests from localhost on a reserved port number.
534ce78460aSRick Macklem 	 * If the upcall is from a different address, call nfsbind_localhost()
535ce78460aSRick Macklem 	 * to check for a remapping of localhost, due to jails.
5367897d2a5SRick Macklem 	 * (Since a reserved port # at localhost implies a client with
5377897d2a5SRick Macklem 	 *  local root, there won't be a security breach. This is about
5387897d2a5SRick Macklem 	 *  the only case I can think of where a reserved port # means
5397897d2a5SRick Macklem 	 *  something.)
54003914b0bSRick Macklem 	 */
541ce78460aSRick Macklem 	if (rqstp->rq_proc != NULLPROC) {
542ce78460aSRick Macklem 		switch (fromip.ss_family) {
543ce78460aSRick Macklem #ifdef INET
544ce78460aSRick Macklem 		case AF_INET:
545ce78460aSRick Macklem 			if (transp->xp_rtaddr.len < sizeof(*sin)) {
546ce78460aSRick Macklem 				syslog(LOG_ERR, "xp_rtaddr too small");
54703914b0bSRick Macklem 				svcerr_weakauth(transp);
54803914b0bSRick Macklem 				return;
54903914b0bSRick Macklem 			}
550ce78460aSRick Macklem 			sin = (struct sockaddr_in *)transp->xp_rtaddr.buf;
551ce78460aSRick Macklem 			fromsin = (struct sockaddr_in *)&fromip;
552ce78460aSRick Macklem 			sport = ntohs(sin->sin_port);
553ce78460aSRick Macklem 			if (sport >= IPPORT_RESERVED) {
554ce78460aSRick Macklem 				syslog(LOG_ERR, "not a reserved port#");
555ce78460aSRick Macklem 				svcerr_weakauth(transp);
556ce78460aSRick Macklem 				return;
557ce78460aSRick Macklem 			}
558ce78460aSRick Macklem 			ret = 1;
559ce78460aSRick Macklem 			if (sin->sin_addr.s_addr != fromsin->sin_addr.s_addr)
560ce78460aSRick Macklem 				ret = nfsbind_localhost();
561ce78460aSRick Macklem 			if (ret == 0 || sin->sin_addr.s_addr !=
562ce78460aSRick Macklem 			    fromsin->sin_addr.s_addr) {
563ce78460aSRick Macklem 				syslog(LOG_ERR, "bad from ip %s",
564ce78460aSRick Macklem 				    inet_ntoa(sin->sin_addr));
565ce78460aSRick Macklem 				svcerr_weakauth(transp);
566ce78460aSRick Macklem 				return;
567ce78460aSRick Macklem 			}
568ce78460aSRick Macklem 			break;
569ce78460aSRick Macklem #endif	/* INET */
570ce78460aSRick Macklem #ifdef INET6
571ce78460aSRick Macklem 		case AF_INET6:
572ce78460aSRick Macklem 			if (transp->xp_rtaddr.len < sizeof(*sin6)) {
573ce78460aSRick Macklem 				syslog(LOG_ERR, "xp_rtaddr too small");
574ce78460aSRick Macklem 				svcerr_weakauth(transp);
575ce78460aSRick Macklem 				return;
576ce78460aSRick Macklem 			}
577ce78460aSRick Macklem 			sin6 = (struct sockaddr_in6 *)transp->xp_rtaddr.buf;
578ce78460aSRick Macklem 			fromsin6 = (struct sockaddr_in6 *)&fromip;
579ce78460aSRick Macklem 			sport = ntohs(sin6->sin6_port);
580ce78460aSRick Macklem 			if (sport >= IPV6PORT_RESERVED) {
581ce78460aSRick Macklem 				syslog(LOG_ERR, "not a reserved port#");
582ce78460aSRick Macklem 				svcerr_weakauth(transp);
583ce78460aSRick Macklem 				return;
584ce78460aSRick Macklem 			}
585ce78460aSRick Macklem 			ret = 1;
586ce78460aSRick Macklem 			if (!IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
587ce78460aSRick Macklem 			    &fromsin6->sin6_addr))
588ce78460aSRick Macklem 				ret = nfsbind_localhost();
589ce78460aSRick Macklem 			if (ret == 0 || !IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
590ce78460aSRick Macklem 			    &fromsin6->sin6_addr)) {
591ce78460aSRick Macklem 				if (inet_ntop(AF_INET6, &sin6->sin6_addr, buf,
592ce78460aSRick Macklem 				    INET6_ADDRSTRLEN) != NULL)
593ce78460aSRick Macklem 					syslog(LOG_ERR, "bad from ip %s", buf);
594ce78460aSRick Macklem 				else
595ce78460aSRick Macklem 					syslog(LOG_ERR, "bad from ip6 addr");
596ce78460aSRick Macklem 				svcerr_weakauth(transp);
597ce78460aSRick Macklem 				return;
598ce78460aSRick Macklem 			}
599ce78460aSRick Macklem 			break;
600ce78460aSRick Macklem #endif	/* INET6 */
601ce78460aSRick Macklem 		}
602ce78460aSRick Macklem 	}
60303914b0bSRick Macklem 	switch (rqstp->rq_proc) {
60403914b0bSRick Macklem 	case NULLPROC:
60503914b0bSRick Macklem 		if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL))
60603914b0bSRick Macklem 			syslog(LOG_ERR, "Can't send reply");
60703914b0bSRick Macklem 		return;
60803914b0bSRick Macklem 	case RPCNFSUSERD_GETUID:
60903914b0bSRick Macklem 		if (!svc_getargs(transp, (xdrproc_t)xdr_getid,
61003914b0bSRick Macklem 		    (caddr_t)&info)) {
61103914b0bSRick Macklem 			svcerr_decode(transp);
61203914b0bSRick Macklem 			return;
61303914b0bSRick Macklem 		}
61403914b0bSRick Macklem 		pwd = getpwuid((uid_t)info.id);
61503914b0bSRick Macklem 		info.retval = 0;
61603914b0bSRick Macklem 		if (pwd != NULL) {
61703914b0bSRick Macklem 			nid.nid_usertimeout = defusertimeout;
61803914b0bSRick Macklem 			nid.nid_uid = pwd->pw_uid;
61903914b0bSRick Macklem 			nid.nid_name = pwd->pw_name;
620e6c623c8SRick Macklem 			if (manage_gids != 0) {
621e6c623c8SRick Macklem 				/* Get the group list for this user. */
622e6c623c8SRick Macklem 				ngroup = NGROUPS;
623e6c623c8SRick Macklem 				if (getgrouplist(pwd->pw_name, pwd->pw_gid,
624e6c623c8SRick Macklem 				    grps, &ngroup) < 0)
625e6c623c8SRick Macklem 					syslog(LOG_ERR, "Group list too small");
626e6c623c8SRick Macklem 				nid.nid_ngroup = ngroup;
627e6c623c8SRick Macklem 				nid.nid_grps = grps;
628e6c623c8SRick Macklem 			} else {
629e6c623c8SRick Macklem 				nid.nid_ngroup = 0;
630e6c623c8SRick Macklem 				nid.nid_grps = NULL;
631e6c623c8SRick Macklem 			}
63203914b0bSRick Macklem 		} else {
63303914b0bSRick Macklem 			nid.nid_usertimeout = 5;
63403914b0bSRick Macklem 			nid.nid_uid = (uid_t)info.id;
63503914b0bSRick Macklem 			nid.nid_name = defaultuser;
636e6c623c8SRick Macklem 			nid.nid_ngroup = 0;
637e6c623c8SRick Macklem 			nid.nid_grps = NULL;
63803914b0bSRick Macklem 		}
63903914b0bSRick Macklem 		nid.nid_namelen = strlen(nid.nid_name);
64003914b0bSRick Macklem 		nid.nid_flag = NFSID_ADDUID;
641e6c623c8SRick Macklem 		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
64203914b0bSRick Macklem 		if (error) {
64303914b0bSRick Macklem 			info.retval = error;
64403914b0bSRick Macklem 			syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name);
64503914b0bSRick Macklem 		} else if (verbose) {
64603914b0bSRick Macklem 			syslog(LOG_ERR,"Added uid=%d name=%s\n",
64703914b0bSRick Macklem 			    nid.nid_uid, nid.nid_name);
64803914b0bSRick Macklem 		}
64903914b0bSRick Macklem 		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
65003914b0bSRick Macklem 		    (caddr_t)&info))
65103914b0bSRick Macklem 			syslog(LOG_ERR, "Can't send reply");
65203914b0bSRick Macklem 		return;
65303914b0bSRick Macklem 	case RPCNFSUSERD_GETGID:
65403914b0bSRick Macklem 		if (!svc_getargs(transp, (xdrproc_t)xdr_getid,
65503914b0bSRick Macklem 		    (caddr_t)&info)) {
65603914b0bSRick Macklem 			svcerr_decode(transp);
65703914b0bSRick Macklem 			return;
65803914b0bSRick Macklem 		}
65903914b0bSRick Macklem 		grp = getgrgid((gid_t)info.id);
66003914b0bSRick Macklem 		info.retval = 0;
66103914b0bSRick Macklem 		if (grp != NULL) {
66203914b0bSRick Macklem 			nid.nid_usertimeout = defusertimeout;
66303914b0bSRick Macklem 			nid.nid_gid = grp->gr_gid;
66403914b0bSRick Macklem 			nid.nid_name = grp->gr_name;
66503914b0bSRick Macklem 		} else {
66603914b0bSRick Macklem 			nid.nid_usertimeout = 5;
66703914b0bSRick Macklem 			nid.nid_gid = (gid_t)info.id;
66803914b0bSRick Macklem 			nid.nid_name = defaultgroup;
66903914b0bSRick Macklem 		}
67003914b0bSRick Macklem 		nid.nid_namelen = strlen(nid.nid_name);
671e6c623c8SRick Macklem 		nid.nid_ngroup = 0;
672e6c623c8SRick Macklem 		nid.nid_grps = NULL;
67303914b0bSRick Macklem 		nid.nid_flag = NFSID_ADDGID;
674e6c623c8SRick Macklem 		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
67503914b0bSRick Macklem 		if (error) {
67603914b0bSRick Macklem 			info.retval = error;
67703914b0bSRick Macklem 			syslog(LOG_ERR, "Can't add group %s\n",
67803914b0bSRick Macklem 			    grp->gr_name);
67903914b0bSRick Macklem 		} else if (verbose) {
68003914b0bSRick Macklem 			syslog(LOG_ERR,"Added gid=%d name=%s\n",
68103914b0bSRick Macklem 			    nid.nid_gid, nid.nid_name);
68203914b0bSRick Macklem 		}
68303914b0bSRick Macklem 		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
68403914b0bSRick Macklem 		    (caddr_t)&info))
68503914b0bSRick Macklem 			syslog(LOG_ERR, "Can't send reply");
68603914b0bSRick Macklem 		return;
68703914b0bSRick Macklem 	case RPCNFSUSERD_GETUSER:
68803914b0bSRick Macklem 		if (!svc_getargs(transp, (xdrproc_t)xdr_getname,
68903914b0bSRick Macklem 		    (caddr_t)&info)) {
69003914b0bSRick Macklem 			svcerr_decode(transp);
69103914b0bSRick Macklem 			return;
69203914b0bSRick Macklem 		}
69303914b0bSRick Macklem 		pwd = getpwnam(info.name);
69403914b0bSRick Macklem 		info.retval = 0;
69503914b0bSRick Macklem 		if (pwd != NULL) {
69603914b0bSRick Macklem 			nid.nid_usertimeout = defusertimeout;
69703914b0bSRick Macklem 			nid.nid_uid = pwd->pw_uid;
69803914b0bSRick Macklem 			nid.nid_name = pwd->pw_name;
69903914b0bSRick Macklem 		} else {
70003914b0bSRick Macklem 			nid.nid_usertimeout = 5;
70103914b0bSRick Macklem 			nid.nid_uid = defaultuid;
70203914b0bSRick Macklem 			nid.nid_name = info.name;
70303914b0bSRick Macklem 		}
70403914b0bSRick Macklem 		nid.nid_namelen = strlen(nid.nid_name);
705e6c623c8SRick Macklem 		nid.nid_ngroup = 0;
706e6c623c8SRick Macklem 		nid.nid_grps = NULL;
70703914b0bSRick Macklem 		nid.nid_flag = NFSID_ADDUSERNAME;
708e6c623c8SRick Macklem 		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
70903914b0bSRick Macklem 		if (error) {
71003914b0bSRick Macklem 			info.retval = error;
71103914b0bSRick Macklem 			syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name);
71203914b0bSRick Macklem 		} else if (verbose) {
71303914b0bSRick Macklem 			syslog(LOG_ERR,"Added uid=%d name=%s\n",
71403914b0bSRick Macklem 			    nid.nid_uid, nid.nid_name);
71503914b0bSRick Macklem 		}
71603914b0bSRick Macklem 		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
71703914b0bSRick Macklem 		    (caddr_t)&info))
71803914b0bSRick Macklem 			syslog(LOG_ERR, "Can't send reply");
71903914b0bSRick Macklem 		return;
72003914b0bSRick Macklem 	case RPCNFSUSERD_GETGROUP:
72103914b0bSRick Macklem 		if (!svc_getargs(transp, (xdrproc_t)xdr_getname,
72203914b0bSRick Macklem 		    (caddr_t)&info)) {
72303914b0bSRick Macklem 			svcerr_decode(transp);
72403914b0bSRick Macklem 			return;
72503914b0bSRick Macklem 		}
72603914b0bSRick Macklem 		grp = getgrnam(info.name);
72703914b0bSRick Macklem 		info.retval = 0;
72803914b0bSRick Macklem 		if (grp != NULL) {
72903914b0bSRick Macklem 			nid.nid_usertimeout = defusertimeout;
73003914b0bSRick Macklem 			nid.nid_gid = grp->gr_gid;
73103914b0bSRick Macklem 			nid.nid_name = grp->gr_name;
73203914b0bSRick Macklem 		} else {
73303914b0bSRick Macklem 			nid.nid_usertimeout = 5;
73403914b0bSRick Macklem 			nid.nid_gid = defaultgid;
73503914b0bSRick Macklem 			nid.nid_name = info.name;
73603914b0bSRick Macklem 		}
73703914b0bSRick Macklem 		nid.nid_namelen = strlen(nid.nid_name);
738e6c623c8SRick Macklem 		nid.nid_ngroup = 0;
739e6c623c8SRick Macklem 		nid.nid_grps = NULL;
74003914b0bSRick Macklem 		nid.nid_flag = NFSID_ADDGROUPNAME;
741e6c623c8SRick Macklem 		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
74203914b0bSRick Macklem 		if (error) {
74303914b0bSRick Macklem 			info.retval = error;
74403914b0bSRick Macklem 			syslog(LOG_ERR, "Can't add group %s\n",
74503914b0bSRick Macklem 			    grp->gr_name);
74603914b0bSRick Macklem 		} else if (verbose) {
74703914b0bSRick Macklem 			syslog(LOG_ERR,"Added gid=%d name=%s\n",
74803914b0bSRick Macklem 			    nid.nid_gid, nid.nid_name);
74903914b0bSRick Macklem 		}
75003914b0bSRick Macklem 		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
75103914b0bSRick Macklem 		    (caddr_t)&info))
75203914b0bSRick Macklem 			syslog(LOG_ERR, "Can't send reply");
75303914b0bSRick Macklem 		return;
75403914b0bSRick Macklem 	default:
75503914b0bSRick Macklem 		svcerr_noproc(transp);
75603914b0bSRick Macklem 		return;
75703914b0bSRick Macklem 	};
75803914b0bSRick Macklem }
75903914b0bSRick Macklem 
76003914b0bSRick Macklem /*
76103914b0bSRick Macklem  * Xdr routine to get an id number
76203914b0bSRick Macklem  */
7639964058eSXin LI static bool_t
xdr_getid(XDR * xdrsp,caddr_t cp)76403914b0bSRick Macklem xdr_getid(XDR *xdrsp, caddr_t cp)
76503914b0bSRick Macklem {
76603914b0bSRick Macklem 	struct info *ifp = (struct info *)cp;
76703914b0bSRick Macklem 
76803914b0bSRick Macklem 	return (xdr_long(xdrsp, &ifp->id));
76903914b0bSRick Macklem }
77003914b0bSRick Macklem 
77103914b0bSRick Macklem /*
77203914b0bSRick Macklem  * Xdr routine to get a user name
77303914b0bSRick Macklem  */
7749964058eSXin LI static bool_t
xdr_getname(XDR * xdrsp,caddr_t cp)77503914b0bSRick Macklem xdr_getname(XDR *xdrsp, caddr_t cp)
77603914b0bSRick Macklem {
77703914b0bSRick Macklem 	struct info *ifp = (struct info *)cp;
77803914b0bSRick Macklem 	long len;
77903914b0bSRick Macklem 
78003914b0bSRick Macklem 	if (!xdr_long(xdrsp, &len))
78103914b0bSRick Macklem 		return (0);
78203914b0bSRick Macklem 	if (len > MAXNAME)
78303914b0bSRick Macklem 		return (0);
78403914b0bSRick Macklem 	if (!xdr_opaque(xdrsp, ifp->name, len))
78503914b0bSRick Macklem 		return (0);
78603914b0bSRick Macklem 	ifp->name[len] = '\0';
78703914b0bSRick Macklem 	return (1);
78803914b0bSRick Macklem }
78903914b0bSRick Macklem 
79003914b0bSRick Macklem /*
79103914b0bSRick Macklem  * Xdr routine to return the value.
79203914b0bSRick Macklem  */
7939964058eSXin LI static bool_t
xdr_retval(XDR * xdrsp,caddr_t cp)79403914b0bSRick Macklem xdr_retval(XDR *xdrsp, caddr_t cp)
79503914b0bSRick Macklem {
79603914b0bSRick Macklem 	struct info *ifp = (struct info *)cp;
79703914b0bSRick Macklem 	long val;
79803914b0bSRick Macklem 
79903914b0bSRick Macklem 	val = ifp->retval;
80003914b0bSRick Macklem 	return (xdr_long(xdrsp, &val));
80103914b0bSRick Macklem }
80203914b0bSRick Macklem 
80303914b0bSRick Macklem /*
80403914b0bSRick Macklem  * cleanup_term() called via SIGUSR1.
80503914b0bSRick Macklem  */
8069964058eSXin LI static void
cleanup_term(int signo __unused)8079964058eSXin LI cleanup_term(int signo __unused)
80803914b0bSRick Macklem {
80903914b0bSRick Macklem 	int i, cnt;
81003914b0bSRick Macklem 
81133906122SRick Macklem 	if (im_a_server)
81203914b0bSRick Macklem 		exit(0);
81303914b0bSRick Macklem 
81403914b0bSRick Macklem 	/*
81503914b0bSRick Macklem 	 * Ok, so I'm the master.
81603914b0bSRick Macklem 	 * As the Governor of California might say, "Terminate them".
81703914b0bSRick Macklem 	 */
81803914b0bSRick Macklem 	cnt = 0;
81903914b0bSRick Macklem 	for (i = 0; i < nfsuserdcnt; i++) {
82033906122SRick Macklem 		if (servers[i] != (pid_t)-1) {
82103914b0bSRick Macklem 			cnt++;
82233906122SRick Macklem 			kill(servers[i], SIGUSR1);
82303914b0bSRick Macklem 		}
82403914b0bSRick Macklem 	}
82503914b0bSRick Macklem 
82603914b0bSRick Macklem 	/*
82703914b0bSRick Macklem 	 * and wait for them to die
82803914b0bSRick Macklem 	 */
82903914b0bSRick Macklem 	for (i = 0; i < cnt; i++)
83003914b0bSRick Macklem 		wait3(NULL, 0, NULL);
83103914b0bSRick Macklem 
83203914b0bSRick Macklem 	/*
83303914b0bSRick Macklem 	 * Finally, get rid of the socket
83403914b0bSRick Macklem 	 */
83503914b0bSRick Macklem 	if (nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0) {
83603914b0bSRick Macklem 		syslog(LOG_ERR, "Can't do nfssvc() to delete the port\n");
83703914b0bSRick Macklem 		exit(1);
83803914b0bSRick Macklem 	}
83903914b0bSRick Macklem 	exit(0);
84003914b0bSRick Macklem }
84103914b0bSRick Macklem 
842ce78460aSRick Macklem /*
843ce78460aSRick Macklem  * Get the IP address that the localhost address maps to.
844ce78460aSRick Macklem  * This is needed when jails map localhost to another IP address.
845ce78460aSRick Macklem  */
846ce78460aSRick Macklem static int
nfsbind_localhost(void)847ce78460aSRick Macklem nfsbind_localhost(void)
848ce78460aSRick Macklem {
849ce78460aSRick Macklem #ifdef INET
850ce78460aSRick Macklem 	struct sockaddr_in sin;
851ce78460aSRick Macklem #endif
852ce78460aSRick Macklem #ifdef INET6
853ce78460aSRick Macklem 	struct sockaddr_in6 sin6;
854ce78460aSRick Macklem #endif
855ce78460aSRick Macklem 	socklen_t slen;
856ce78460aSRick Macklem 	int ret, s;
857ce78460aSRick Macklem 
858ce78460aSRick Macklem 	switch (fromip.ss_family) {
859ce78460aSRick Macklem #ifdef INET6
860ce78460aSRick Macklem 	case AF_INET6:
861ce78460aSRick Macklem 		s = socket(PF_INET6, SOCK_DGRAM, 0);
862ce78460aSRick Macklem 		if (s < 0)
863ce78460aSRick Macklem 			return (0);
864ce78460aSRick Macklem 		memset(&sin6, 0, sizeof(sin6));
865ce78460aSRick Macklem 		sin6.sin6_len = sizeof(sin6);
866ce78460aSRick Macklem 		sin6.sin6_family = AF_INET6;
867ce78460aSRick Macklem 		sin6.sin6_addr = in6loopback;
868ce78460aSRick Macklem 		sin6.sin6_port = 0;
869ce78460aSRick Macklem 		ret = bind(s, (struct sockaddr *)&sin6, sizeof(sin6));
870ce78460aSRick Macklem 		if (ret < 0) {
871ce78460aSRick Macklem 			close(s);
872ce78460aSRick Macklem 			return (0);
873ce78460aSRick Macklem 		}
874ce78460aSRick Macklem 		break;
875ce78460aSRick Macklem #endif	/* INET6 */
876ce78460aSRick Macklem #ifdef INET
877ce78460aSRick Macklem 	case AF_INET:
878ce78460aSRick Macklem 		s = socket(PF_INET, SOCK_DGRAM, 0);
879ce78460aSRick Macklem 		if (s < 0)
880ce78460aSRick Macklem 			return (0);
881ce78460aSRick Macklem 		memset(&sin, 0, sizeof(sin));
882ce78460aSRick Macklem 		sin.sin_len = sizeof(sin);
883ce78460aSRick Macklem 		sin.sin_family = AF_INET;
884ce78460aSRick Macklem 		sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
885ce78460aSRick Macklem 		sin.sin_port = 0;
886ce78460aSRick Macklem 		ret = bind(s, (struct sockaddr *)&sin, sizeof(sin));
887ce78460aSRick Macklem 		if (ret < 0) {
888ce78460aSRick Macklem 			close(s);
889ce78460aSRick Macklem 			return (0);
890ce78460aSRick Macklem 		}
891ce78460aSRick Macklem 		break;
892ce78460aSRick Macklem #endif	/* INET */
893ce78460aSRick Macklem 	}
894ce78460aSRick Macklem 	memset(&fromip, 0, sizeof(fromip));
895ce78460aSRick Macklem 	slen = sizeof(fromip);
896ce78460aSRick Macklem 	ret = getsockname(s, (struct sockaddr *)&fromip, &slen);
897ce78460aSRick Macklem 	close(s);
898ce78460aSRick Macklem 	if (ret < 0)
899ce78460aSRick Macklem 		return (0);
900ce78460aSRick Macklem 	return (1);
901ce78460aSRick Macklem }
902ce78460aSRick Macklem 
9039964058eSXin LI static void
usage(void)90403914b0bSRick Macklem usage(void)
90503914b0bSRick Macklem {
90603914b0bSRick Macklem 
9077897d2a5SRick Macklem 	errx(1,
9087897d2a5SRick Macklem 	    "usage: nfsuserd [-usermax cache_size] [-usertimeout minutes] [-verbose] [-manage-gids] [-domain domain_name] [n]");
90903914b0bSRick Macklem }
910