1/*-
2 * Copyright (c) 2009 Rick Macklem, University of Guelph
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD$");
30
31#include <sys/param.h>
32#include <sys/errno.h>
33#include <sys/linker.h>
34#include <sys/module.h>
35#include <sys/mount.h>
36#include <sys/socket.h>
37#include <sys/socketvar.h>
38#include <sys/time.h>
39#include <sys/ucred.h>
40#include <sys/vnode.h>
41#include <sys/wait.h>
42
43#include <netinet/in.h>
44
45#include <arpa/inet.h>
46
47#include <nfs/nfssvc.h>
48
49#include <rpc/rpc.h>
50
51#include <fs/nfs/rpcv2.h>
52#include <fs/nfs/nfsproto.h>
53#include <fs/nfs/nfskpiport.h>
54#include <fs/nfs/nfs.h>
55
56#include <ctype.h>
57#include <err.h>
58#include <grp.h>
59#include <netdb.h>
60#include <pwd.h>
61#include <signal.h>
62#include <stdio.h>
63#include <stdlib.h>
64#include <string.h>
65#include <syslog.h>
66#include <unistd.h>
67
68/*
69 * This program loads the password and group databases into the kernel
70 * for NFS V4.
71 */
72
73static void	cleanup_term(int);
74static void	usage(void);
75static void	nfsuserdsrv(struct svc_req *, SVCXPRT *);
76static bool_t	xdr_getid(XDR *, caddr_t);
77static bool_t	xdr_getname(XDR *, caddr_t);
78static bool_t	xdr_retval(XDR *, caddr_t);
79static int	nfsbind_localhost(void);
80
81#define	MAXNAME		1024
82#define	MAXNFSUSERD	20
83#define	DEFNFSUSERD	4
84#define	MAXUSERMAX	100000
85#define	MINUSERMAX	10
86#define	DEFUSERMAX	200
87#define	DEFUSERTIMEOUT	(1 * 60)
88struct info {
89	long	id;
90	long	retval;
91	char	name[MAXNAME + 1];
92};
93
94u_char *dnsname = "default.domain";
95u_char *defaultuser = "nobody";
96uid_t defaultuid = 65534;
97u_char *defaultgroup = "nogroup";
98gid_t defaultgid = 65533;
99int verbose = 0, im_a_slave = 0, nfsuserdcnt = -1, forcestart = 0;
100int defusertimeout = DEFUSERTIMEOUT, manage_gids = 0;
101pid_t slaves[MAXNFSUSERD];
102static struct sockaddr_storage fromip;
103#ifdef INET6
104static struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT;
105#endif
106
107int
108main(int argc, char *argv[])
109{
110	int i, j;
111	int error, fnd_dup, len, mustfreeai = 0, start_uidpos;
112	struct nfsd_idargs nid;
113	struct passwd *pwd;
114	struct group *grp;
115	int sock, one = 1;
116	SVCXPRT *udptransp;
117	struct nfsuserd_args nargs;
118	sigset_t signew;
119	char hostname[MAXHOSTNAMELEN + 1], *cp;
120	struct addrinfo *aip, hints;
121	static uid_t check_dups[MAXUSERMAX];
122	gid_t grps[NGROUPS];
123	int ngroup;
124#ifdef INET
125	struct sockaddr_in *sin;
126#endif
127#ifdef INET6
128	struct sockaddr_in6 *sin6;
129#endif
130	int s;
131
132	if (modfind("nfscommon") < 0) {
133		/* Not present in kernel, try loading it */
134		if (kldload("nfscommon") < 0 ||
135		    modfind("nfscommon") < 0)
136			errx(1, "Experimental nfs subsystem is not available");
137	}
138
139	/*
140	 * First, figure out what our domain name and Kerberos Realm
141	 * seem to be. Command line args may override these later.
142	 */
143	if (gethostname(hostname, MAXHOSTNAMELEN) == 0) {
144		if ((cp = strchr(hostname, '.')) != NULL &&
145		    *(cp + 1) != '\0') {
146			dnsname = cp + 1;
147		} else {
148			memset((void *)&hints, 0, sizeof (hints));
149			hints.ai_flags = AI_CANONNAME;
150			error = getaddrinfo(hostname, NULL, &hints, &aip);
151			if (error == 0) {
152			    if (aip->ai_canonname != NULL &&
153				(cp = strchr(aip->ai_canonname, '.')) != NULL
154				&& *(cp + 1) != '\0') {
155					dnsname = cp + 1;
156					mustfreeai = 1;
157				} else {
158					freeaddrinfo(aip);
159				}
160			}
161		}
162	}
163
164	/*
165	 * See if this server handles IPv4 or IPv6 and set up the default
166	 * localhost address.
167	 */
168	s = -1;
169#ifdef INET6
170	s = socket(PF_INET6, SOCK_DGRAM, 0);
171	if (s >= 0) {
172		fromip.ss_family = AF_INET6;
173		fromip.ss_len = sizeof(struct sockaddr_in6);
174		sin6 = (struct sockaddr_in6 *)&fromip;
175		sin6->sin6_addr = in6loopback;
176		close(s);
177	}
178#endif	/* INET6 */
179#ifdef INET
180	if (s < 0) {
181		s = socket(PF_INET, SOCK_DGRAM, 0);
182		if (s >= 0) {
183			fromip.ss_family = AF_INET;
184			fromip.ss_len = sizeof(struct sockaddr_in);
185			sin = (struct sockaddr_in *)&fromip;
186			sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
187			close(s);
188		}
189	}
190#endif	/* INET */
191	if (s < 0)
192		err(1, "Can't create a inet/inet6 socket");
193
194	nid.nid_usermax = DEFUSERMAX;
195	nid.nid_usertimeout = defusertimeout;
196
197	argc--;
198	argv++;
199	while (argc >= 1) {
200		if (!strcmp(*argv, "-domain")) {
201			if (argc == 1)
202				usage();
203			argc--;
204			argv++;
205			strncpy(hostname, *argv, MAXHOSTNAMELEN);
206			hostname[MAXHOSTNAMELEN] = '\0';
207			dnsname = hostname;
208		} else if (!strcmp(*argv, "-verbose")) {
209			verbose = 1;
210		} else if (!strcmp(*argv, "-force")) {
211			forcestart = 1;
212		} else if (!strcmp(*argv, "-manage-gids")) {
213			manage_gids = 1;
214		} else if (!strcmp(*argv, "-usermax")) {
215			if (argc == 1)
216				usage();
217			argc--;
218			argv++;
219			i = atoi(*argv);
220			if (i < MINUSERMAX || i > MAXUSERMAX) {
221				fprintf(stderr,
222				    "usermax %d out of range %d<->%d\n", i,
223				    MINUSERMAX, MAXUSERMAX);
224				usage();
225			}
226			nid.nid_usermax = i;
227		} else if (!strcmp(*argv, "-usertimeout")) {
228			if (argc == 1)
229				usage();
230			argc--;
231			argv++;
232			i = atoi(*argv);
233			if (i < 0 || i > 100000) {
234				fprintf(stderr,
235				    "usertimeout %d out of range 0<->100000\n",
236				    i);
237				usage();
238			}
239			nid.nid_usertimeout = defusertimeout = i * 60;
240		} else if (nfsuserdcnt == -1) {
241			nfsuserdcnt = atoi(*argv);
242			if (nfsuserdcnt < 1)
243				usage();
244			if (nfsuserdcnt > MAXNFSUSERD) {
245				warnx("nfsuserd count %d; reset to %d",
246				    nfsuserdcnt, DEFNFSUSERD);
247				nfsuserdcnt = DEFNFSUSERD;
248			}
249		} else {
250			usage();
251		}
252		argc--;
253		argv++;
254	}
255	if (nfsuserdcnt < 1)
256		nfsuserdcnt = DEFNFSUSERD;
257
258	/*
259	 * Strip off leading and trailing '.'s in domain name and map
260	 * alphabetics to lower case.
261	 */
262	while (*dnsname == '.')
263		dnsname++;
264	if (*dnsname == '\0')
265		errx(1, "Domain name all '.'");
266	len = strlen(dnsname);
267	cp = dnsname + len - 1;
268	while (*cp == '.') {
269		*cp = '\0';
270		len--;
271		cp--;
272	}
273	for (i = 0; i < len; i++) {
274		if (!isascii(dnsname[i]))
275			errx(1, "Domain name has non-ascii char");
276		if (isupper(dnsname[i]))
277			dnsname[i] = tolower(dnsname[i]);
278	}
279
280	/*
281	 * If the nfsuserd died off ungracefully, this is necessary to
282	 * get them to start again.
283	 */
284	if (forcestart && nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0)
285		errx(1, "Can't do nfssvc() to delete the port");
286
287	if (verbose)
288		fprintf(stderr,
289		    "nfsuserd: domain=%s usermax=%d usertimeout=%d\n",
290		    dnsname, nid.nid_usermax, nid.nid_usertimeout);
291
292	for (i = 0; i < nfsuserdcnt; i++)
293		slaves[i] = (pid_t)-1;
294
295	nargs.nuserd_family = fromip.ss_family;
296	/*
297	 * Set up the service port to accept requests via UDP from
298	 * localhost (INADDR_LOOPBACK or IN6ADDR_LOOPBACK_INIT).
299	 */
300	if ((sock = socket(nargs.nuserd_family, SOCK_DGRAM, IPPROTO_UDP)) < 0)
301		err(1, "cannot create udp socket");
302
303	/*
304	 * Not sure what this does, so I'll leave it here for now.
305	 */
306	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
307
308	if ((udptransp = svcudp_create(sock)) == NULL)
309		err(1, "Can't set up socket");
310
311	/*
312	 * By not specifying a protocol, it is linked into the
313	 * dispatch queue, but not registered with portmapper,
314	 * which is just what I want.
315	 */
316	if (!svc_register(udptransp, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS,
317	    nfsuserdsrv, 0))
318		err(1, "Can't register nfsuserd");
319
320	/*
321	 * Tell the kernel what my port# is.
322	 */
323	nargs.nuserd_port = htons(udptransp->xp_port);
324#ifdef DEBUG
325	printf("portnum=0x%x\n", nargs.nuserd_port);
326#else
327	if (nfssvc(NFSSVC_NFSUSERDPORT | NFSSVC_NEWSTRUCT, &nargs) < 0) {
328		if (errno == EPERM) {
329			fprintf(stderr,
330			    "Can't start nfsuserd when already running");
331			fprintf(stderr,
332			    " If not running, use the -force option.\n");
333		} else {
334			fprintf(stderr, "Can't do nfssvc() to add port\n");
335		}
336		exit(1);
337	}
338#endif
339
340	pwd = getpwnam(defaultuser);
341	if (pwd)
342		nid.nid_uid = pwd->pw_uid;
343	else
344		nid.nid_uid = defaultuid;
345	grp = getgrnam(defaultgroup);
346	if (grp)
347		nid.nid_gid = grp->gr_gid;
348	else
349		nid.nid_gid = defaultgid;
350	nid.nid_name = dnsname;
351	nid.nid_namelen = strlen(nid.nid_name);
352	nid.nid_ngroup = 0;
353	nid.nid_grps = NULL;
354	nid.nid_flag = NFSID_INITIALIZE;
355#ifdef DEBUG
356	printf("Initialize uid=%d gid=%d dns=%s\n", nid.nid_uid, nid.nid_gid,
357	    nid.nid_name);
358#else
359	error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
360	if (error)
361		errx(1, "Can't initialize nfs user/groups");
362#endif
363
364	i = 0;
365	/*
366	 * Loop around adding all groups.
367	 */
368	setgrent();
369	while (i < nid.nid_usermax && (grp = getgrent())) {
370		nid.nid_gid = grp->gr_gid;
371		nid.nid_name = grp->gr_name;
372		nid.nid_namelen = strlen(grp->gr_name);
373		nid.nid_ngroup = 0;
374		nid.nid_grps = NULL;
375		nid.nid_flag = NFSID_ADDGID;
376#ifdef DEBUG
377		printf("add gid=%d name=%s\n", nid.nid_gid, nid.nid_name);
378#else
379		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
380		if (error)
381			errx(1, "Can't add group %s", grp->gr_name);
382#endif
383		i++;
384	}
385	endgrent();
386
387	/*
388	 * Loop around adding all users.
389	 */
390	start_uidpos = i;
391	setpwent();
392	while (i < nid.nid_usermax && (pwd = getpwent())) {
393		fnd_dup = 0;
394		/*
395		 * Yes, this is inefficient, but it is only done once when
396		 * the daemon is started and will run in a fraction of a second
397		 * for nid_usermax at 10000. If nid_usermax is cranked up to
398		 * 100000, it will take several seconds, depending on the CPU.
399		 */
400		for (j = 0; j < (i - start_uidpos); j++)
401			if (check_dups[j] == pwd->pw_uid) {
402				/* Found another entry for uid, so skip it */
403				fnd_dup = 1;
404				break;
405			}
406		if (fnd_dup != 0)
407			continue;
408		check_dups[i - start_uidpos] = pwd->pw_uid;
409		nid.nid_uid = pwd->pw_uid;
410		nid.nid_name = pwd->pw_name;
411		nid.nid_namelen = strlen(pwd->pw_name);
412		if (manage_gids != 0) {
413			/* Get the group list for this user. */
414			ngroup = NGROUPS;
415			if (getgrouplist(pwd->pw_name, pwd->pw_gid, grps,
416			    &ngroup) < 0)
417				syslog(LOG_ERR, "Group list too small");
418			nid.nid_ngroup = ngroup;
419			nid.nid_grps = grps;
420		} else {
421			nid.nid_ngroup = 0;
422			nid.nid_grps = NULL;
423		}
424		nid.nid_flag = NFSID_ADDUID;
425#ifdef DEBUG
426		printf("add uid=%d name=%s\n", nid.nid_uid, nid.nid_name);
427#else
428		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
429		if (error)
430			errx(1, "Can't add user %s", pwd->pw_name);
431#endif
432		i++;
433	}
434	endpwent();
435
436	/*
437	 * I should feel guilty for not calling this for all the above exit()
438	 * upon error cases, but I don't.
439	 */
440	if (mustfreeai)
441		freeaddrinfo(aip);
442
443#ifdef DEBUG
444	exit(0);
445#endif
446	/*
447	 * Temporarily block SIGUSR1 and SIGCHLD, so slaves[] can't
448	 * end up bogus.
449	 */
450	sigemptyset(&signew);
451	sigaddset(&signew, SIGUSR1);
452	sigaddset(&signew, SIGCHLD);
453	sigprocmask(SIG_BLOCK, &signew, NULL);
454
455	daemon(0, 0);
456	(void)signal(SIGHUP, SIG_IGN);
457	(void)signal(SIGINT, SIG_IGN);
458	(void)signal(SIGQUIT, SIG_IGN);
459	(void)signal(SIGTERM, SIG_IGN);
460	(void)signal(SIGUSR1, cleanup_term);
461	(void)signal(SIGCHLD, cleanup_term);
462
463	openlog("nfsuserd:", LOG_PID, LOG_DAEMON);
464
465	/*
466	 * Fork off the slave daemons that do the work. All the master
467	 * does is kill them off and cleanup.
468	 */
469	for (i = 0; i < nfsuserdcnt; i++) {
470		slaves[i] = fork();
471		if (slaves[i] == 0) {
472			im_a_slave = 1;
473			setproctitle("slave");
474			sigemptyset(&signew);
475			sigaddset(&signew, SIGUSR1);
476			sigprocmask(SIG_UNBLOCK, &signew, NULL);
477
478			/*
479			 * and away we go.
480			 */
481			svc_run();
482			syslog(LOG_ERR, "nfsuserd died: %m");
483			exit(1);
484		} else if (slaves[i] < 0) {
485			syslog(LOG_ERR, "fork: %m");
486		}
487	}
488
489	/*
490	 * Just wait for SIGUSR1 or a child to die and then...
491	 * As the Governor of California would say, "Terminate them".
492	 */
493	setproctitle("master");
494	sigemptyset(&signew);
495	while (1)
496		sigsuspend(&signew);
497}
498
499/*
500 * The nfsuserd rpc service
501 */
502static void
503nfsuserdsrv(struct svc_req *rqstp, SVCXPRT *transp)
504{
505	struct passwd *pwd;
506	struct group *grp;
507	int error;
508#if defined(INET) || defined(INET6)
509	u_short sport;
510	int ret;
511#endif
512	struct info info;
513	struct nfsd_idargs nid;
514	gid_t grps[NGROUPS];
515	int ngroup;
516#ifdef INET
517	struct sockaddr_in *fromsin, *sin;
518#endif
519#ifdef INET6
520	struct sockaddr_in6 *fromsin6, *sin6;
521	char buf[INET6_ADDRSTRLEN];
522#endif
523
524	/*
525	 * Only handle requests from localhost on a reserved port number.
526	 * If the upcall is from a different address, call nfsbind_localhost()
527	 * to check for a remapping of localhost, due to jails.
528	 * (Since a reserved port # at localhost implies a client with
529	 *  local root, there won't be a security breach. This is about
530	 *  the only case I can think of where a reserved port # means
531	 *  something.)
532	 */
533	if (rqstp->rq_proc != NULLPROC) {
534		switch (fromip.ss_family) {
535#ifdef INET
536		case AF_INET:
537			if (transp->xp_rtaddr.len < sizeof(*sin)) {
538				syslog(LOG_ERR, "xp_rtaddr too small");
539				svcerr_weakauth(transp);
540				return;
541			}
542			sin = (struct sockaddr_in *)transp->xp_rtaddr.buf;
543			fromsin = (struct sockaddr_in *)&fromip;
544			sport = ntohs(sin->sin_port);
545			if (sport >= IPPORT_RESERVED) {
546				syslog(LOG_ERR, "not a reserved port#");
547				svcerr_weakauth(transp);
548				return;
549			}
550			ret = 1;
551			if (sin->sin_addr.s_addr != fromsin->sin_addr.s_addr)
552				ret = nfsbind_localhost();
553			if (ret == 0 || sin->sin_addr.s_addr !=
554			    fromsin->sin_addr.s_addr) {
555				syslog(LOG_ERR, "bad from ip %s",
556				    inet_ntoa(sin->sin_addr));
557				svcerr_weakauth(transp);
558				return;
559			}
560			break;
561#endif	/* INET */
562#ifdef INET6
563		case AF_INET6:
564			if (transp->xp_rtaddr.len < sizeof(*sin6)) {
565				syslog(LOG_ERR, "xp_rtaddr too small");
566				svcerr_weakauth(transp);
567				return;
568			}
569			sin6 = (struct sockaddr_in6 *)transp->xp_rtaddr.buf;
570			fromsin6 = (struct sockaddr_in6 *)&fromip;
571			sport = ntohs(sin6->sin6_port);
572			if (sport >= IPV6PORT_RESERVED) {
573				syslog(LOG_ERR, "not a reserved port#");
574				svcerr_weakauth(transp);
575				return;
576			}
577			ret = 1;
578			if (!IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
579			    &fromsin6->sin6_addr))
580				ret = nfsbind_localhost();
581			if (ret == 0 || !IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
582			    &fromsin6->sin6_addr)) {
583				if (inet_ntop(AF_INET6, &sin6->sin6_addr, buf,
584				    INET6_ADDRSTRLEN) != NULL)
585					syslog(LOG_ERR, "bad from ip %s", buf);
586				else
587					syslog(LOG_ERR, "bad from ip6 addr");
588				svcerr_weakauth(transp);
589				return;
590			}
591			break;
592#endif	/* INET6 */
593		}
594	}
595	switch (rqstp->rq_proc) {
596	case NULLPROC:
597		if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL))
598			syslog(LOG_ERR, "Can't send reply");
599		return;
600	case RPCNFSUSERD_GETUID:
601		if (!svc_getargs(transp, (xdrproc_t)xdr_getid,
602		    (caddr_t)&info)) {
603			svcerr_decode(transp);
604			return;
605		}
606		pwd = getpwuid((uid_t)info.id);
607		info.retval = 0;
608		if (pwd != NULL) {
609			nid.nid_usertimeout = defusertimeout;
610			nid.nid_uid = pwd->pw_uid;
611			nid.nid_name = pwd->pw_name;
612			if (manage_gids != 0) {
613				/* Get the group list for this user. */
614				ngroup = NGROUPS;
615				if (getgrouplist(pwd->pw_name, pwd->pw_gid,
616				    grps, &ngroup) < 0)
617					syslog(LOG_ERR, "Group list too small");
618				nid.nid_ngroup = ngroup;
619				nid.nid_grps = grps;
620			} else {
621				nid.nid_ngroup = 0;
622				nid.nid_grps = NULL;
623			}
624		} else {
625			nid.nid_usertimeout = 5;
626			nid.nid_uid = (uid_t)info.id;
627			nid.nid_name = defaultuser;
628			nid.nid_ngroup = 0;
629			nid.nid_grps = NULL;
630		}
631		nid.nid_namelen = strlen(nid.nid_name);
632		nid.nid_flag = NFSID_ADDUID;
633		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
634		if (error) {
635			info.retval = error;
636			syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name);
637		} else if (verbose) {
638			syslog(LOG_ERR,"Added uid=%d name=%s\n",
639			    nid.nid_uid, nid.nid_name);
640		}
641		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
642		    (caddr_t)&info))
643			syslog(LOG_ERR, "Can't send reply");
644		return;
645	case RPCNFSUSERD_GETGID:
646		if (!svc_getargs(transp, (xdrproc_t)xdr_getid,
647		    (caddr_t)&info)) {
648			svcerr_decode(transp);
649			return;
650		}
651		grp = getgrgid((gid_t)info.id);
652		info.retval = 0;
653		if (grp != NULL) {
654			nid.nid_usertimeout = defusertimeout;
655			nid.nid_gid = grp->gr_gid;
656			nid.nid_name = grp->gr_name;
657		} else {
658			nid.nid_usertimeout = 5;
659			nid.nid_gid = (gid_t)info.id;
660			nid.nid_name = defaultgroup;
661		}
662		nid.nid_namelen = strlen(nid.nid_name);
663		nid.nid_ngroup = 0;
664		nid.nid_grps = NULL;
665		nid.nid_flag = NFSID_ADDGID;
666		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
667		if (error) {
668			info.retval = error;
669			syslog(LOG_ERR, "Can't add group %s\n",
670			    grp->gr_name);
671		} else if (verbose) {
672			syslog(LOG_ERR,"Added gid=%d name=%s\n",
673			    nid.nid_gid, nid.nid_name);
674		}
675		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
676		    (caddr_t)&info))
677			syslog(LOG_ERR, "Can't send reply");
678		return;
679	case RPCNFSUSERD_GETUSER:
680		if (!svc_getargs(transp, (xdrproc_t)xdr_getname,
681		    (caddr_t)&info)) {
682			svcerr_decode(transp);
683			return;
684		}
685		pwd = getpwnam(info.name);
686		info.retval = 0;
687		if (pwd != NULL) {
688			nid.nid_usertimeout = defusertimeout;
689			nid.nid_uid = pwd->pw_uid;
690			nid.nid_name = pwd->pw_name;
691		} else {
692			nid.nid_usertimeout = 5;
693			nid.nid_uid = defaultuid;
694			nid.nid_name = info.name;
695		}
696		nid.nid_namelen = strlen(nid.nid_name);
697		nid.nid_ngroup = 0;
698		nid.nid_grps = NULL;
699		nid.nid_flag = NFSID_ADDUSERNAME;
700		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
701		if (error) {
702			info.retval = error;
703			syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name);
704		} else if (verbose) {
705			syslog(LOG_ERR,"Added uid=%d name=%s\n",
706			    nid.nid_uid, nid.nid_name);
707		}
708		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
709		    (caddr_t)&info))
710			syslog(LOG_ERR, "Can't send reply");
711		return;
712	case RPCNFSUSERD_GETGROUP:
713		if (!svc_getargs(transp, (xdrproc_t)xdr_getname,
714		    (caddr_t)&info)) {
715			svcerr_decode(transp);
716			return;
717		}
718		grp = getgrnam(info.name);
719		info.retval = 0;
720		if (grp != NULL) {
721			nid.nid_usertimeout = defusertimeout;
722			nid.nid_gid = grp->gr_gid;
723			nid.nid_name = grp->gr_name;
724		} else {
725			nid.nid_usertimeout = 5;
726			nid.nid_gid = defaultgid;
727			nid.nid_name = info.name;
728		}
729		nid.nid_namelen = strlen(nid.nid_name);
730		nid.nid_ngroup = 0;
731		nid.nid_grps = NULL;
732		nid.nid_flag = NFSID_ADDGROUPNAME;
733		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
734		if (error) {
735			info.retval = error;
736			syslog(LOG_ERR, "Can't add group %s\n",
737			    grp->gr_name);
738		} else if (verbose) {
739			syslog(LOG_ERR,"Added gid=%d name=%s\n",
740			    nid.nid_gid, nid.nid_name);
741		}
742		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
743		    (caddr_t)&info))
744			syslog(LOG_ERR, "Can't send reply");
745		return;
746	default:
747		svcerr_noproc(transp);
748		return;
749	};
750}
751
752/*
753 * Xdr routine to get an id number
754 */
755static bool_t
756xdr_getid(XDR *xdrsp, caddr_t cp)
757{
758	struct info *ifp = (struct info *)cp;
759
760	return (xdr_long(xdrsp, &ifp->id));
761}
762
763/*
764 * Xdr routine to get a user name
765 */
766static bool_t
767xdr_getname(XDR *xdrsp, caddr_t cp)
768{
769	struct info *ifp = (struct info *)cp;
770	long len;
771
772	if (!xdr_long(xdrsp, &len))
773		return (0);
774	if (len > MAXNAME)
775		return (0);
776	if (!xdr_opaque(xdrsp, ifp->name, len))
777		return (0);
778	ifp->name[len] = '\0';
779	return (1);
780}
781
782/*
783 * Xdr routine to return the value.
784 */
785static bool_t
786xdr_retval(XDR *xdrsp, caddr_t cp)
787{
788	struct info *ifp = (struct info *)cp;
789	long val;
790
791	val = ifp->retval;
792	return (xdr_long(xdrsp, &val));
793}
794
795/*
796 * cleanup_term() called via SIGUSR1.
797 */
798static void
799cleanup_term(int signo __unused)
800{
801	int i, cnt;
802
803	if (im_a_slave)
804		exit(0);
805
806	/*
807	 * Ok, so I'm the master.
808	 * As the Governor of California might say, "Terminate them".
809	 */
810	cnt = 0;
811	for (i = 0; i < nfsuserdcnt; i++) {
812		if (slaves[i] != (pid_t)-1) {
813			cnt++;
814			kill(slaves[i], SIGUSR1);
815		}
816	}
817
818	/*
819	 * and wait for them to die
820	 */
821	for (i = 0; i < cnt; i++)
822		wait3(NULL, 0, NULL);
823
824	/*
825	 * Finally, get rid of the socket
826	 */
827	if (nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0) {
828		syslog(LOG_ERR, "Can't do nfssvc() to delete the port\n");
829		exit(1);
830	}
831	exit(0);
832}
833
834/*
835 * Get the IP address that the localhost address maps to.
836 * This is needed when jails map localhost to another IP address.
837 */
838static int
839nfsbind_localhost(void)
840{
841#ifdef INET
842	struct sockaddr_in sin;
843#endif
844#ifdef INET6
845	struct sockaddr_in6 sin6;
846#endif
847	socklen_t slen;
848	int ret, s;
849
850	switch (fromip.ss_family) {
851#ifdef INET6
852	case AF_INET6:
853		s = socket(PF_INET6, SOCK_DGRAM, 0);
854		if (s < 0)
855			return (0);
856		memset(&sin6, 0, sizeof(sin6));
857		sin6.sin6_len = sizeof(sin6);
858		sin6.sin6_family = AF_INET6;
859		sin6.sin6_addr = in6loopback;
860		sin6.sin6_port = 0;
861		ret = bind(s, (struct sockaddr *)&sin6, sizeof(sin6));
862		if (ret < 0) {
863			close(s);
864			return (0);
865		}
866		break;
867#endif	/* INET6 */
868#ifdef INET
869	case AF_INET:
870		s = socket(PF_INET, SOCK_DGRAM, 0);
871		if (s < 0)
872			return (0);
873		memset(&sin, 0, sizeof(sin));
874		sin.sin_len = sizeof(sin);
875		sin.sin_family = AF_INET;
876		sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
877		sin.sin_port = 0;
878		ret = bind(s, (struct sockaddr *)&sin, sizeof(sin));
879		if (ret < 0) {
880			close(s);
881			return (0);
882		}
883		break;
884#endif	/* INET */
885	}
886	memset(&fromip, 0, sizeof(fromip));
887	slen = sizeof(fromip);
888	ret = getsockname(s, (struct sockaddr *)&fromip, &slen);
889	close(s);
890	if (ret < 0)
891		return (0);
892	return (1);
893}
894
895static void
896usage(void)
897{
898
899	errx(1,
900	    "usage: nfsuserd [-usermax cache_size] [-usertimeout minutes] [-verbose] [-manage-gids] [-domain domain_name] [n]");
901}
902