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: stable/10/usr.sbin/nfsuserd/nfsuserd.c 346467 2019-04-21 01:25:27Z rmacklem $");
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
386	/*
387	 * Loop around adding all users.
388	 */
389	start_uidpos = i;
390	setpwent();
391	while (i < nid.nid_usermax && (pwd = getpwent())) {
392		fnd_dup = 0;
393		/*
394		 * Yes, this is inefficient, but it is only done once when
395		 * the daemon is started and will run in a fraction of a second
396		 * for nid_usermax at 10000. If nid_usermax is cranked up to
397		 * 100000, it will take several seconds, depending on the CPU.
398		 */
399		for (j = 0; j < (i - start_uidpos); j++)
400			if (check_dups[j] == pwd->pw_uid) {
401				/* Found another entry for uid, so skip it */
402				fnd_dup = 1;
403				break;
404			}
405		if (fnd_dup != 0)
406			continue;
407		check_dups[i - start_uidpos] = pwd->pw_uid;
408		nid.nid_uid = pwd->pw_uid;
409		nid.nid_name = pwd->pw_name;
410		nid.nid_namelen = strlen(pwd->pw_name);
411		if (manage_gids != 0) {
412			/* Get the group list for this user. */
413			ngroup = NGROUPS;
414			if (getgrouplist(pwd->pw_name, pwd->pw_gid, grps,
415			    &ngroup) < 0)
416				syslog(LOG_ERR, "Group list too small");
417			nid.nid_ngroup = ngroup;
418			nid.nid_grps = grps;
419		} else {
420			nid.nid_ngroup = 0;
421			nid.nid_grps = NULL;
422		}
423		nid.nid_flag = NFSID_ADDUID;
424#ifdef DEBUG
425		printf("add uid=%d name=%s\n", nid.nid_uid, nid.nid_name);
426#else
427		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
428		if (error)
429			errx(1, "Can't add user %s", pwd->pw_name);
430#endif
431		i++;
432	}
433
434	/*
435	 * I should feel guilty for not calling this for all the above exit()
436	 * upon error cases, but I don't.
437	 */
438	if (mustfreeai)
439		freeaddrinfo(aip);
440
441#ifdef DEBUG
442	exit(0);
443#endif
444	/*
445	 * Temporarily block SIGUSR1 and SIGCHLD, so slaves[] can't
446	 * end up bogus.
447	 */
448	sigemptyset(&signew);
449	sigaddset(&signew, SIGUSR1);
450	sigaddset(&signew, SIGCHLD);
451	sigprocmask(SIG_BLOCK, &signew, NULL);
452
453	daemon(0, 0);
454	(void)signal(SIGHUP, SIG_IGN);
455	(void)signal(SIGINT, SIG_IGN);
456	(void)signal(SIGQUIT, SIG_IGN);
457	(void)signal(SIGTERM, SIG_IGN);
458	(void)signal(SIGUSR1, cleanup_term);
459	(void)signal(SIGCHLD, cleanup_term);
460
461	openlog("nfsuserd:", LOG_PID, LOG_DAEMON);
462
463	/*
464	 * Fork off the slave daemons that do the work. All the master
465	 * does is kill them off and cleanup.
466	 */
467	for (i = 0; i < nfsuserdcnt; i++) {
468		slaves[i] = fork();
469		if (slaves[i] == 0) {
470			im_a_slave = 1;
471			setproctitle("slave");
472			sigemptyset(&signew);
473			sigaddset(&signew, SIGUSR1);
474			sigprocmask(SIG_UNBLOCK, &signew, NULL);
475
476			/*
477			 * and away we go.
478			 */
479			svc_run();
480			syslog(LOG_ERR, "nfsuserd died: %m");
481			exit(1);
482		} else if (slaves[i] < 0) {
483			syslog(LOG_ERR, "fork: %m");
484		}
485	}
486
487	/*
488	 * Just wait for SIGUSR1 or a child to die and then...
489	 * As the Governor of California would say, "Terminate them".
490	 */
491	setproctitle("master");
492	sigemptyset(&signew);
493	while (1)
494		sigsuspend(&signew);
495}
496
497/*
498 * The nfsuserd rpc service
499 */
500static void
501nfsuserdsrv(struct svc_req *rqstp, SVCXPRT *transp)
502{
503	struct passwd *pwd;
504	struct group *grp;
505	int error;
506#if defined(INET) || defined(INET6)
507	u_short sport;
508	int ret;
509#endif
510	struct info info;
511	struct nfsd_idargs nid;
512	gid_t grps[NGROUPS];
513	int ngroup;
514#ifdef INET
515	struct sockaddr_in *fromsin, *sin;
516#endif
517#ifdef INET6
518	struct sockaddr_in6 *fromsin6, *sin6;
519	char buf[INET6_ADDRSTRLEN];
520#endif
521
522	/*
523	 * Only handle requests from localhost on a reserved port number.
524	 * If the upcall is from a different address, call nfsbind_localhost()
525	 * to check for a remapping of localhost, due to jails.
526	 * (Since a reserved port # at localhost implies a client with
527	 *  local root, there won't be a security breach. This is about
528	 *  the only case I can think of where a reserved port # means
529	 *  something.)
530	 */
531	if (rqstp->rq_proc != NULLPROC) {
532		switch (fromip.ss_family) {
533#ifdef INET
534		case AF_INET:
535			if (transp->xp_rtaddr.len < sizeof(*sin)) {
536				syslog(LOG_ERR, "xp_rtaddr too small");
537				svcerr_weakauth(transp);
538				return;
539			}
540			sin = (struct sockaddr_in *)transp->xp_rtaddr.buf;
541			fromsin = (struct sockaddr_in *)&fromip;
542			sport = ntohs(sin->sin_port);
543			if (sport >= IPPORT_RESERVED) {
544				syslog(LOG_ERR, "not a reserved port#");
545				svcerr_weakauth(transp);
546				return;
547			}
548			ret = 1;
549			if (sin->sin_addr.s_addr != fromsin->sin_addr.s_addr)
550				ret = nfsbind_localhost();
551			if (ret == 0 || sin->sin_addr.s_addr !=
552			    fromsin->sin_addr.s_addr) {
553				syslog(LOG_ERR, "bad from ip %s",
554				    inet_ntoa(sin->sin_addr));
555				svcerr_weakauth(transp);
556				return;
557			}
558			break;
559#endif	/* INET */
560#ifdef INET6
561		case AF_INET6:
562			if (transp->xp_rtaddr.len < sizeof(*sin6)) {
563				syslog(LOG_ERR, "xp_rtaddr too small");
564				svcerr_weakauth(transp);
565				return;
566			}
567			sin6 = (struct sockaddr_in6 *)transp->xp_rtaddr.buf;
568			fromsin6 = (struct sockaddr_in6 *)&fromip;
569			sport = ntohs(sin6->sin6_port);
570			if (sport >= IPV6PORT_RESERVED) {
571				syslog(LOG_ERR, "not a reserved port#");
572				svcerr_weakauth(transp);
573				return;
574			}
575			ret = 1;
576			if (!IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
577			    &fromsin6->sin6_addr))
578				ret = nfsbind_localhost();
579			if (ret == 0 || !IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
580			    &fromsin6->sin6_addr)) {
581				if (inet_ntop(AF_INET6, &sin6->sin6_addr, buf,
582				    INET6_ADDRSTRLEN) != NULL)
583					syslog(LOG_ERR, "bad from ip %s", buf);
584				else
585					syslog(LOG_ERR, "bad from ip6 addr");
586				svcerr_weakauth(transp);
587				return;
588			}
589			break;
590#endif	/* INET6 */
591		}
592	}
593	switch (rqstp->rq_proc) {
594	case NULLPROC:
595		if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL))
596			syslog(LOG_ERR, "Can't send reply");
597		return;
598	case RPCNFSUSERD_GETUID:
599		if (!svc_getargs(transp, (xdrproc_t)xdr_getid,
600		    (caddr_t)&info)) {
601			svcerr_decode(transp);
602			return;
603		}
604		pwd = getpwuid((uid_t)info.id);
605		info.retval = 0;
606		if (pwd != NULL) {
607			nid.nid_usertimeout = defusertimeout;
608			nid.nid_uid = pwd->pw_uid;
609			nid.nid_name = pwd->pw_name;
610			if (manage_gids != 0) {
611				/* Get the group list for this user. */
612				ngroup = NGROUPS;
613				if (getgrouplist(pwd->pw_name, pwd->pw_gid,
614				    grps, &ngroup) < 0)
615					syslog(LOG_ERR, "Group list too small");
616				nid.nid_ngroup = ngroup;
617				nid.nid_grps = grps;
618			} else {
619				nid.nid_ngroup = 0;
620				nid.nid_grps = NULL;
621			}
622		} else {
623			nid.nid_usertimeout = 5;
624			nid.nid_uid = (uid_t)info.id;
625			nid.nid_name = defaultuser;
626			nid.nid_ngroup = 0;
627			nid.nid_grps = NULL;
628		}
629		nid.nid_namelen = strlen(nid.nid_name);
630		nid.nid_flag = NFSID_ADDUID;
631		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
632		if (error) {
633			info.retval = error;
634			syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name);
635		} else if (verbose) {
636			syslog(LOG_ERR,"Added uid=%d name=%s\n",
637			    nid.nid_uid, nid.nid_name);
638		}
639		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
640		    (caddr_t)&info))
641			syslog(LOG_ERR, "Can't send reply");
642		return;
643	case RPCNFSUSERD_GETGID:
644		if (!svc_getargs(transp, (xdrproc_t)xdr_getid,
645		    (caddr_t)&info)) {
646			svcerr_decode(transp);
647			return;
648		}
649		grp = getgrgid((gid_t)info.id);
650		info.retval = 0;
651		if (grp != NULL) {
652			nid.nid_usertimeout = defusertimeout;
653			nid.nid_gid = grp->gr_gid;
654			nid.nid_name = grp->gr_name;
655		} else {
656			nid.nid_usertimeout = 5;
657			nid.nid_gid = (gid_t)info.id;
658			nid.nid_name = defaultgroup;
659		}
660		nid.nid_namelen = strlen(nid.nid_name);
661		nid.nid_ngroup = 0;
662		nid.nid_grps = NULL;
663		nid.nid_flag = NFSID_ADDGID;
664		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
665		if (error) {
666			info.retval = error;
667			syslog(LOG_ERR, "Can't add group %s\n",
668			    grp->gr_name);
669		} else if (verbose) {
670			syslog(LOG_ERR,"Added gid=%d name=%s\n",
671			    nid.nid_gid, nid.nid_name);
672		}
673		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
674		    (caddr_t)&info))
675			syslog(LOG_ERR, "Can't send reply");
676		return;
677	case RPCNFSUSERD_GETUSER:
678		if (!svc_getargs(transp, (xdrproc_t)xdr_getname,
679		    (caddr_t)&info)) {
680			svcerr_decode(transp);
681			return;
682		}
683		pwd = getpwnam(info.name);
684		info.retval = 0;
685		if (pwd != NULL) {
686			nid.nid_usertimeout = defusertimeout;
687			nid.nid_uid = pwd->pw_uid;
688			nid.nid_name = pwd->pw_name;
689		} else {
690			nid.nid_usertimeout = 5;
691			nid.nid_uid = defaultuid;
692			nid.nid_name = info.name;
693		}
694		nid.nid_namelen = strlen(nid.nid_name);
695		nid.nid_ngroup = 0;
696		nid.nid_grps = NULL;
697		nid.nid_flag = NFSID_ADDUSERNAME;
698		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
699		if (error) {
700			info.retval = error;
701			syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name);
702		} else if (verbose) {
703			syslog(LOG_ERR,"Added uid=%d name=%s\n",
704			    nid.nid_uid, nid.nid_name);
705		}
706		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
707		    (caddr_t)&info))
708			syslog(LOG_ERR, "Can't send reply");
709		return;
710	case RPCNFSUSERD_GETGROUP:
711		if (!svc_getargs(transp, (xdrproc_t)xdr_getname,
712		    (caddr_t)&info)) {
713			svcerr_decode(transp);
714			return;
715		}
716		grp = getgrnam(info.name);
717		info.retval = 0;
718		if (grp != NULL) {
719			nid.nid_usertimeout = defusertimeout;
720			nid.nid_gid = grp->gr_gid;
721			nid.nid_name = grp->gr_name;
722		} else {
723			nid.nid_usertimeout = 5;
724			nid.nid_gid = defaultgid;
725			nid.nid_name = info.name;
726		}
727		nid.nid_namelen = strlen(nid.nid_name);
728		nid.nid_ngroup = 0;
729		nid.nid_grps = NULL;
730		nid.nid_flag = NFSID_ADDGROUPNAME;
731		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
732		if (error) {
733			info.retval = error;
734			syslog(LOG_ERR, "Can't add group %s\n",
735			    grp->gr_name);
736		} else if (verbose) {
737			syslog(LOG_ERR,"Added gid=%d name=%s\n",
738			    nid.nid_gid, nid.nid_name);
739		}
740		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
741		    (caddr_t)&info))
742			syslog(LOG_ERR, "Can't send reply");
743		return;
744	default:
745		svcerr_noproc(transp);
746		return;
747	};
748}
749
750/*
751 * Xdr routine to get an id number
752 */
753static bool_t
754xdr_getid(XDR *xdrsp, caddr_t cp)
755{
756	struct info *ifp = (struct info *)cp;
757
758	return (xdr_long(xdrsp, &ifp->id));
759}
760
761/*
762 * Xdr routine to get a user name
763 */
764static bool_t
765xdr_getname(XDR *xdrsp, caddr_t cp)
766{
767	struct info *ifp = (struct info *)cp;
768	long len;
769
770	if (!xdr_long(xdrsp, &len))
771		return (0);
772	if (len > MAXNAME)
773		return (0);
774	if (!xdr_opaque(xdrsp, ifp->name, len))
775		return (0);
776	ifp->name[len] = '\0';
777	return (1);
778}
779
780/*
781 * Xdr routine to return the value.
782 */
783static bool_t
784xdr_retval(XDR *xdrsp, caddr_t cp)
785{
786	struct info *ifp = (struct info *)cp;
787	long val;
788
789	val = ifp->retval;
790	return (xdr_long(xdrsp, &val));
791}
792
793/*
794 * cleanup_term() called via SIGUSR1.
795 */
796static void
797cleanup_term(int signo __unused)
798{
799	int i, cnt;
800
801	if (im_a_slave)
802		exit(0);
803
804	/*
805	 * Ok, so I'm the master.
806	 * As the Governor of California might say, "Terminate them".
807	 */
808	cnt = 0;
809	for (i = 0; i < nfsuserdcnt; i++) {
810		if (slaves[i] != (pid_t)-1) {
811			cnt++;
812			kill(slaves[i], SIGUSR1);
813		}
814	}
815
816	/*
817	 * and wait for them to die
818	 */
819	for (i = 0; i < cnt; i++)
820		wait3(NULL, 0, NULL);
821
822	/*
823	 * Finally, get rid of the socket
824	 */
825	if (nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0) {
826		syslog(LOG_ERR, "Can't do nfssvc() to delete the port\n");
827		exit(1);
828	}
829	exit(0);
830}
831
832/*
833 * Get the IP address that the localhost address maps to.
834 * This is needed when jails map localhost to another IP address.
835 */
836static int
837nfsbind_localhost(void)
838{
839#ifdef INET
840	struct sockaddr_in sin;
841#endif
842#ifdef INET6
843	struct sockaddr_in6 sin6;
844#endif
845	socklen_t slen;
846	int ret, s;
847
848	switch (fromip.ss_family) {
849#ifdef INET6
850	case AF_INET6:
851		s = socket(PF_INET6, SOCK_DGRAM, 0);
852		if (s < 0)
853			return (0);
854		memset(&sin6, 0, sizeof(sin6));
855		sin6.sin6_len = sizeof(sin6);
856		sin6.sin6_family = AF_INET6;
857		sin6.sin6_addr = in6loopback;
858		sin6.sin6_port = 0;
859		ret = bind(s, (struct sockaddr *)&sin6, sizeof(sin6));
860		if (ret < 0) {
861			close(s);
862			return (0);
863		}
864		break;
865#endif	/* INET6 */
866#ifdef INET
867	case AF_INET:
868		s = socket(PF_INET, SOCK_DGRAM, 0);
869		if (s < 0)
870			return (0);
871		memset(&sin, 0, sizeof(sin));
872		sin.sin_len = sizeof(sin);
873		sin.sin_family = AF_INET;
874		sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
875		sin.sin_port = 0;
876		ret = bind(s, (struct sockaddr *)&sin, sizeof(sin));
877		if (ret < 0) {
878			close(s);
879			return (0);
880		}
881		break;
882#endif	/* INET */
883	}
884	memset(&fromip, 0, sizeof(fromip));
885	slen = sizeof(fromip);
886	ret = getsockname(s, (struct sockaddr *)&fromip, &slen);
887	close(s);
888	if (ret < 0)
889		return (0);
890	return (1);
891}
892
893static void
894usage(void)
895{
896
897	errx(1,
898	    "usage: nfsuserd [-usermax cache_size] [-usertimeout minutes] [-verbose] [-manage-gids] [-domain domain_name] [n]");
899}
900