nfsuserd.c revision 223382
159191Skris/*-
2296465Sdelphij * Copyright (c) 2009 Rick Macklem, University of Guelph
3296465Sdelphij * All rights reserved.
4296465Sdelphij *
559191Skris * Redistribution and use in source and binary forms, with or without
659191Skris * modification, are permitted provided that the following conditions
759191Skris * are met:
859191Skris * 1. Redistributions of source code must retain the above copyright
959191Skris *    notice, this list of conditions and the following disclaimer.
1059191Skris * 2. Redistributions in binary form must reproduce the above copyright
1159191Skris *    notice, this list of conditions and the following disclaimer in the
1259191Skris *    documentation and/or other materials provided with the distribution.
1359191Skris *
14296465Sdelphij * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1559191Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1659191Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1759191Skris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1859191Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1959191Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2059191Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2159191Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2259191Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2359191Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2459191Skris * SUCH DAMAGE.
2559191Skris *
2659191Skris */
2759191Skris
2859191Skris#include <sys/cdefs.h>
2959191Skris__FBSDID("$FreeBSD: head/usr.sbin/nfsuserd/nfsuserd.c 223382 2011-06-21 21:07:33Z rmacklem $");
3059191Skris
3159191Skris#include <sys/param.h>
3259191Skris#include <sys/errno.h>
3359191Skris#include <sys/linker.h>
3459191Skris#include <sys/module.h>
3559191Skris#include <sys/mount.h>
3659191Skris#include <sys/socket.h>
3759191Skris#include <sys/socketvar.h>
3859191Skris#include <sys/time.h>
3959191Skris#include <sys/ucred.h>
4059191Skris#include <sys/vnode.h>
4159191Skris#include <sys/wait.h>
4259191Skris
4359191Skris#include <nfs/nfssvc.h>
4459191Skris
4559191Skris#include <rpc/rpc.h>
4659191Skris
4759191Skris#include <fs/nfs/rpcv2.h>
4859191Skris#include <fs/nfs/nfsproto.h>
4959191Skris#include <fs/nfs/nfskpiport.h>
5059191Skris#include <fs/nfs/nfs.h>
5159191Skris
5259191Skris#include <ctype.h>
5359191Skris#include <err.h>
5459191Skris#include <grp.h>
5559191Skris#include <netdb.h>
5659191Skris#include <pwd.h>
5759191Skris#include <signal.h>
5859191Skris#include <stdio.h>
5959191Skris#include <stdlib.h>
6059191Skris#include <string.h>
6159191Skris#include <syslog.h>
6259191Skris#include <unistd.h>
6359191Skris
6459191Skris/*
6559191Skris * This program loads the password and group databases into the kernel
6659191Skris * for NFS V4.
6759191Skris */
6859191Skris
6959191Skrisstatic void	cleanup_term(int);
7068651Skrisstatic void	usage(void);
71296465Sdelphijstatic void	nfsuserdsrv(struct svc_req *, SVCXPRT *);
7259191Skrisstatic bool_t	xdr_getid(XDR *, caddr_t);
7359191Skrisstatic bool_t	xdr_getname(XDR *, caddr_t);
7459191Skrisstatic bool_t	xdr_retval(XDR *, caddr_t);
75296465Sdelphij
7659191Skris#define	MAXNAME		1024
7759191Skris#define	MAXNFSUSERD	20
7859191Skris#define	DEFNFSUSERD	4
7959191Skris#define	MAXUSERMAX	100000
8059191Skris#define	MINUSERMAX	10
81296465Sdelphij#define	DEFUSERMAX	200
8259191Skris#define	DEFUSERTIMEOUT	(1 * 60)
83296465Sdelphijstruct info {
84296465Sdelphij	long	id;
85296465Sdelphij	long	retval;
86296465Sdelphij	char	name[MAXNAME + 1];
87296465Sdelphij};
8859191Skris
89296465Sdelphiju_char *dnsname = "default.domain";
9059191Skrisu_char *defaultuser = "nobody";
91296465Sdelphijuid_t defaultuid = (uid_t)32767;
92296465Sdelphiju_char *defaultgroup = "nogroup";
93296465Sdelphijgid_t defaultgid = (gid_t)32767;
94296465Sdelphijint verbose = 0, im_a_slave = 0, nfsuserdcnt = -1, forcestart = 0;
9559191Skrisint defusertimeout = DEFUSERTIMEOUT;
96296465Sdelphijpid_t slaves[MAXNFSUSERD];
97296465Sdelphij
98296465Sdelphijint
99296465Sdelphijmain(int argc, char *argv[])
100296465Sdelphij{
101296465Sdelphij	int i, j;
10259191Skris	int error, fnd_dup, len, mustfreeai = 0, start_uidpos;
10359191Skris	struct nfsd_idargs nid;
10459191Skris	struct passwd *pwd;
10559191Skris	struct group *grp;
10659191Skris	int sock, one = 1;
10759191Skris	SVCXPRT *udptransp;
108296465Sdelphij	u_short portnum;
109296465Sdelphij	sigset_t signew;
110296465Sdelphij	char hostname[MAXHOSTNAMELEN + 1], *cp;
111296465Sdelphij	struct addrinfo *aip, hints;
112296465Sdelphij	static uid_t check_dups[MAXUSERMAX];
113296465Sdelphij
114296465Sdelphij	if (modfind("nfscommon") < 0) {
11568651Skris		/* Not present in kernel, try loading it */
116296465Sdelphij		if (kldload("nfscommon") < 0 ||
117296465Sdelphij		    modfind("nfscommon") < 0)
118296465Sdelphij			errx(1, "Experimental nfs subsystem is not available");
119296465Sdelphij	}
120296465Sdelphij
121296465Sdelphij	/*
122296465Sdelphij	 * First, figure out what our domain name and Kerberos Realm
123296465Sdelphij	 * seem to be. Command line args may override these later.
124296465Sdelphij	 */
125296465Sdelphij	if (gethostname(hostname, MAXHOSTNAMELEN) == 0) {
126296465Sdelphij		if ((cp = strchr(hostname, '.')) != NULL &&
127296465Sdelphij		    *(cp + 1) != '\0') {
128296465Sdelphij			dnsname = cp + 1;
129296465Sdelphij		} else {
130296465Sdelphij			memset((void *)&hints, 0, sizeof (hints));
131296465Sdelphij			hints.ai_flags = AI_CANONNAME;
132296465Sdelphij			error = getaddrinfo(hostname, NULL, &hints, &aip);
133296465Sdelphij			if (error == 0) {
134296465Sdelphij			    if (aip->ai_canonname != NULL &&
135296465Sdelphij				(cp = strchr(aip->ai_canonname, '.')) != NULL
136296465Sdelphij				&& *(cp + 1) != '\0') {
137296465Sdelphij					dnsname = cp + 1;
138296465Sdelphij					mustfreeai = 1;
139296465Sdelphij				} else {
140296465Sdelphij					freeaddrinfo(aip);
141296465Sdelphij				}
142296465Sdelphij			}
143296465Sdelphij		}
144296465Sdelphij	}
145296465Sdelphij	nid.nid_usermax = DEFUSERMAX;
146296465Sdelphij	nid.nid_usertimeout = defusertimeout;
147296465Sdelphij
148296465Sdelphij	argc--;
149296465Sdelphij	argv++;
150296465Sdelphij	while (argc >= 1) {
151296465Sdelphij		if (!strcmp(*argv, "-domain")) {
152296465Sdelphij			if (argc == 1)
153296465Sdelphij				usage();
154296465Sdelphij			argc--;
155296465Sdelphij			argv++;
156296465Sdelphij			strncpy(hostname, *argv, MAXHOSTNAMELEN);
15759191Skris			hostname[MAXHOSTNAMELEN] = '\0';
158296465Sdelphij			dnsname = hostname;
15959191Skris		} else if (!strcmp(*argv, "-verbose")) {
160296465Sdelphij			verbose = 1;
161296465Sdelphij		} else if (!strcmp(*argv, "-force")) {
162296465Sdelphij			forcestart = 1;
163296465Sdelphij		} else if (!strcmp(*argv, "-usermax")) {
164296465Sdelphij			if (argc == 1)
16559191Skris				usage();
166296465Sdelphij			argc--;
167296465Sdelphij			argv++;
168296465Sdelphij			i = atoi(*argv);
169296465Sdelphij			if (i < MINUSERMAX || i > MAXUSERMAX) {
170296465Sdelphij				fprintf(stderr,
171296465Sdelphij				    "usermax %d out of range %d<->%d\n", i,
172296465Sdelphij				    MINUSERMAX, MAXUSERMAX);
173296465Sdelphij				usage();
174296465Sdelphij			}
17559191Skris			nid.nid_usermax = i;
176296465Sdelphij		} else if (!strcmp(*argv, "-usertimeout")) {
17759191Skris			if (argc == 1)
178296465Sdelphij				usage();
179296465Sdelphij			argc--;
180296465Sdelphij			argv++;
181296465Sdelphij			i = atoi(*argv);
182296465Sdelphij			if (i < 0 || i > 100000) {
183296465Sdelphij				fprintf(stderr,
18459191Skris				    "usertimeout %d out of range 0<->100000\n",
18559191Skris				    i);
18659191Skris				usage();
18768651Skris			}
188296465Sdelphij			nid.nid_usertimeout = defusertimeout = i * 60;
18959191Skris		} else if (nfsuserdcnt == -1) {
190296465Sdelphij			nfsuserdcnt = atoi(*argv);
191296465Sdelphij			if (nfsuserdcnt < 1)
192296465Sdelphij				usage();
193296465Sdelphij			if (nfsuserdcnt > MAXNFSUSERD) {
194296465Sdelphij				warnx("nfsuserd count %d; reset to %d",
195296465Sdelphij				    nfsuserdcnt, DEFNFSUSERD);
19659191Skris				nfsuserdcnt = DEFNFSUSERD;
19759191Skris			}
19859191Skris		} else {
19959191Skris			usage();
20059191Skris		}
20159191Skris		argc--;
202296465Sdelphij		argv++;
203296465Sdelphij	}
204296465Sdelphij	if (nfsuserdcnt < 1)
20559191Skris		nfsuserdcnt = DEFNFSUSERD;
206296465Sdelphij
207296465Sdelphij	/*
20859191Skris	 * Strip off leading and trailing '.'s in domain name and map
209296465Sdelphij	 * alphabetics to lower case.
210296465Sdelphij	 */
211296465Sdelphij	while (*dnsname == '.')
212296465Sdelphij		dnsname++;
213296465Sdelphij	if (*dnsname == '\0')
214296465Sdelphij		errx(1, "Domain name all '.'");
215296465Sdelphij	len = strlen(dnsname);
216296465Sdelphij	cp = dnsname + len - 1;
217296465Sdelphij	while (*cp == '.') {
218296465Sdelphij		*cp = '\0';
21959191Skris		len--;
22059191Skris		cp--;
22159191Skris	}
22259191Skris	for (i = 0; i < len; i++) {
223296465Sdelphij		if (!isascii(dnsname[i]))
224296465Sdelphij			errx(1, "Domain name has non-ascii char");
225160814Ssimon		if (isupper(dnsname[i]))
226296465Sdelphij			dnsname[i] = tolower(dnsname[i]);
227296465Sdelphij	}
228296465Sdelphij
229296465Sdelphij	/*
230296465Sdelphij	 * If the nfsuserd died off ungracefully, this is necessary to
231296465Sdelphij	 * get them to start again.
232296465Sdelphij	 */
233296465Sdelphij	if (forcestart && nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0)
234296465Sdelphij		errx(1, "Can't do nfssvc() to delete the port");
23559191Skris
236	if (verbose)
237		fprintf(stderr,
238		    "nfsuserd: domain=%s usermax=%d usertimeout=%d\n",
239		    dnsname, nid.nid_usermax, nid.nid_usertimeout);
240
241	for (i = 0; i < nfsuserdcnt; i++)
242		slaves[i] = (pid_t)-1;
243
244	/*
245	 * Set up the service port to accept requests via UDP from
246	 * localhost (127.0.0.1).
247	 */
248	if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
249		err(1, "cannot create udp socket");
250
251	/*
252	 * Not sure what this does, so I'll leave it here for now.
253	 */
254	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
255
256	if ((udptransp = svcudp_create(sock)) == NULL)
257		err(1, "Can't set up socket");
258
259	/*
260	 * By not specifying a protocol, it is linked into the
261	 * dispatch queue, but not registered with portmapper,
262	 * which is just what I want.
263	 */
264	if (!svc_register(udptransp, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS,
265	    nfsuserdsrv, 0))
266		err(1, "Can't register nfsuserd");
267
268	/*
269	 * Tell the kernel what my port# is.
270	 */
271	portnum = htons(udptransp->xp_port);
272#ifdef DEBUG
273	printf("portnum=0x%x\n", portnum);
274#else
275	if (nfssvc(NFSSVC_NFSUSERDPORT, (caddr_t)&portnum) < 0) {
276		if (errno == EPERM) {
277			fprintf(stderr,
278			    "Can't start nfsuserd when already running");
279			fprintf(stderr,
280			    " If not running, use the -force option.\n");
281		} else {
282			fprintf(stderr, "Can't do nfssvc() to add port\n");
283		}
284		exit(1);
285	}
286#endif
287
288	pwd = getpwnam(defaultuser);
289	if (pwd)
290		nid.nid_uid = pwd->pw_uid;
291	else
292		nid.nid_uid = defaultuid;
293	grp = getgrnam(defaultgroup);
294	if (grp)
295		nid.nid_gid = grp->gr_gid;
296	else
297		nid.nid_gid = defaultgid;
298	nid.nid_name = dnsname;
299	nid.nid_namelen = strlen(nid.nid_name);
300	nid.nid_flag = NFSID_INITIALIZE;
301#ifdef DEBUG
302	printf("Initialize uid=%d gid=%d dns=%s\n", nid.nid_uid, nid.nid_gid,
303	    nid.nid_name);
304#else
305	error = nfssvc(NFSSVC_IDNAME, &nid);
306	if (error)
307		errx(1, "Can't initialize nfs user/groups");
308#endif
309
310	i = 0;
311	/*
312	 * Loop around adding all groups.
313	 */
314	setgrent();
315	while (i < nid.nid_usermax && (grp = getgrent())) {
316		nid.nid_gid = grp->gr_gid;
317		nid.nid_name = grp->gr_name;
318		nid.nid_namelen = strlen(grp->gr_name);
319		nid.nid_flag = NFSID_ADDGID;
320#ifdef DEBUG
321		printf("add gid=%d name=%s\n", nid.nid_gid, nid.nid_name);
322#else
323		error = nfssvc(NFSSVC_IDNAME, &nid);
324		if (error)
325			errx(1, "Can't add group %s", grp->gr_name);
326#endif
327		i++;
328	}
329
330	/*
331	 * Loop around adding all users.
332	 */
333	start_uidpos = i;
334	setpwent();
335	while (i < nid.nid_usermax && (pwd = getpwent())) {
336		fnd_dup = 0;
337		/*
338		 * Yes, this is inefficient, but it is only done once when
339		 * the daemon is started and will run in a fraction of a second
340		 * for nid_usermax at 10000. If nid_usermax is cranked up to
341		 * 100000, it will take several seconds, depending on the CPU.
342		 */
343		for (j = 0; j < (i - start_uidpos); j++)
344			if (check_dups[j] == pwd->pw_uid) {
345				/* Found another entry for uid, so skip it */
346				fnd_dup = 1;
347				break;
348			}
349		if (fnd_dup != 0)
350			continue;
351		check_dups[i - start_uidpos] = pwd->pw_uid;
352		nid.nid_uid = pwd->pw_uid;
353		nid.nid_name = pwd->pw_name;
354		nid.nid_namelen = strlen(pwd->pw_name);
355		nid.nid_flag = NFSID_ADDUID;
356#ifdef DEBUG
357		printf("add uid=%d name=%s\n", nid.nid_uid, nid.nid_name);
358#else
359		error = nfssvc(NFSSVC_IDNAME, &nid);
360		if (error)
361			errx(1, "Can't add user %s", pwd->pw_name);
362#endif
363		i++;
364	}
365
366	/*
367	 * I should feel guilty for not calling this for all the above exit()
368	 * upon error cases, but I don't.
369	 */
370	if (mustfreeai)
371		freeaddrinfo(aip);
372
373#ifdef DEBUG
374	exit(0);
375#endif
376	/*
377	 * Temporarily block SIGUSR1 and SIGCHLD, so slaves[] can't
378	 * end up bogus.
379	 */
380	sigemptyset(&signew);
381	sigaddset(&signew, SIGUSR1);
382	sigaddset(&signew, SIGCHLD);
383	sigprocmask(SIG_BLOCK, &signew, NULL);
384
385	daemon(0, 0);
386	(void)signal(SIGHUP, SIG_IGN);
387	(void)signal(SIGINT, SIG_IGN);
388	(void)signal(SIGQUIT, SIG_IGN);
389	(void)signal(SIGTERM, SIG_IGN);
390	(void)signal(SIGUSR1, cleanup_term);
391	(void)signal(SIGCHLD, cleanup_term);
392
393	openlog("nfsuserd:", LOG_PID, LOG_DAEMON);
394
395	/*
396	 * Fork off the slave daemons that do the work. All the master
397	 * does is kill them off and cleanup.
398	 */
399	for (i = 0; i < nfsuserdcnt; i++) {
400		slaves[i] = fork();
401		if (slaves[i] == 0) {
402			im_a_slave = 1;
403			setproctitle("slave");
404			sigemptyset(&signew);
405			sigaddset(&signew, SIGUSR1);
406			sigprocmask(SIG_UNBLOCK, &signew, NULL);
407
408			/*
409			 * and away we go.
410			 */
411			svc_run();
412			syslog(LOG_ERR, "nfsuserd died: %m");
413			exit(1);
414		} else if (slaves[i] < 0) {
415			syslog(LOG_ERR, "fork: %m");
416		}
417	}
418
419	/*
420	 * Just wait for SIGUSR1 or a child to die and then...
421	 * As the Governor of California would say, "Terminate them".
422	 */
423	setproctitle("master");
424	sigemptyset(&signew);
425	while (1)
426		sigsuspend(&signew);
427}
428
429/*
430 * The nfsuserd rpc service
431 */
432static void
433nfsuserdsrv(struct svc_req *rqstp, SVCXPRT *transp)
434{
435	struct passwd *pwd;
436	struct group *grp;
437	int error;
438	u_short sport;
439	struct info info;
440	struct nfsd_idargs nid;
441	u_int32_t saddr;
442
443	/*
444	 * Only handle requests from 127.0.0.1 on a reserved port number.
445	 * (Since a reserved port # at localhost implies a client with
446	 *  local root, there won't be a security breach. This is about
447	 *  the only case I can think of where a reserved port # means
448	 *  something.)
449	 */
450	sport = ntohs(transp->xp_raddr.sin_port);
451	saddr = ntohl(transp->xp_raddr.sin_addr.s_addr);
452	if ((rqstp->rq_proc != NULLPROC && sport >= IPPORT_RESERVED) ||
453	    saddr != 0x7f000001) {
454		syslog(LOG_ERR, "req from ip=0x%x port=%d\n", saddr, sport);
455		svcerr_weakauth(transp);
456		return;
457	}
458	switch (rqstp->rq_proc) {
459	case NULLPROC:
460		if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL))
461			syslog(LOG_ERR, "Can't send reply");
462		return;
463	case RPCNFSUSERD_GETUID:
464		if (!svc_getargs(transp, (xdrproc_t)xdr_getid,
465		    (caddr_t)&info)) {
466			svcerr_decode(transp);
467			return;
468		}
469		pwd = getpwuid((uid_t)info.id);
470		info.retval = 0;
471		if (pwd != NULL) {
472			nid.nid_usertimeout = defusertimeout;
473			nid.nid_uid = pwd->pw_uid;
474			nid.nid_name = pwd->pw_name;
475		} else {
476			nid.nid_usertimeout = 5;
477			nid.nid_uid = (uid_t)info.id;
478			nid.nid_name = defaultuser;
479		}
480		nid.nid_namelen = strlen(nid.nid_name);
481		nid.nid_flag = NFSID_ADDUID;
482		error = nfssvc(NFSSVC_IDNAME, &nid);
483		if (error) {
484			info.retval = error;
485			syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name);
486		} else if (verbose) {
487			syslog(LOG_ERR,"Added uid=%d name=%s\n",
488			    nid.nid_uid, nid.nid_name);
489		}
490		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
491		    (caddr_t)&info))
492			syslog(LOG_ERR, "Can't send reply");
493		return;
494	case RPCNFSUSERD_GETGID:
495		if (!svc_getargs(transp, (xdrproc_t)xdr_getid,
496		    (caddr_t)&info)) {
497			svcerr_decode(transp);
498			return;
499		}
500		grp = getgrgid((gid_t)info.id);
501		info.retval = 0;
502		if (grp != NULL) {
503			nid.nid_usertimeout = defusertimeout;
504			nid.nid_gid = grp->gr_gid;
505			nid.nid_name = grp->gr_name;
506		} else {
507			nid.nid_usertimeout = 5;
508			nid.nid_gid = (gid_t)info.id;
509			nid.nid_name = defaultgroup;
510		}
511		nid.nid_namelen = strlen(nid.nid_name);
512		nid.nid_flag = NFSID_ADDGID;
513		error = nfssvc(NFSSVC_IDNAME, &nid);
514		if (error) {
515			info.retval = error;
516			syslog(LOG_ERR, "Can't add group %s\n",
517			    grp->gr_name);
518		} else if (verbose) {
519			syslog(LOG_ERR,"Added gid=%d name=%s\n",
520			    nid.nid_gid, nid.nid_name);
521		}
522		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
523		    (caddr_t)&info))
524			syslog(LOG_ERR, "Can't send reply");
525		return;
526	case RPCNFSUSERD_GETUSER:
527		if (!svc_getargs(transp, (xdrproc_t)xdr_getname,
528		    (caddr_t)&info)) {
529			svcerr_decode(transp);
530			return;
531		}
532		pwd = getpwnam(info.name);
533		info.retval = 0;
534		if (pwd != NULL) {
535			nid.nid_usertimeout = defusertimeout;
536			nid.nid_uid = pwd->pw_uid;
537			nid.nid_name = pwd->pw_name;
538		} else {
539			nid.nid_usertimeout = 5;
540			nid.nid_uid = defaultuid;
541			nid.nid_name = info.name;
542		}
543		nid.nid_namelen = strlen(nid.nid_name);
544		nid.nid_flag = NFSID_ADDUSERNAME;
545		error = nfssvc(NFSSVC_IDNAME, &nid);
546		if (error) {
547			info.retval = error;
548			syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name);
549		} else if (verbose) {
550			syslog(LOG_ERR,"Added uid=%d name=%s\n",
551			    nid.nid_uid, nid.nid_name);
552		}
553		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
554		    (caddr_t)&info))
555			syslog(LOG_ERR, "Can't send reply");
556		return;
557	case RPCNFSUSERD_GETGROUP:
558		if (!svc_getargs(transp, (xdrproc_t)xdr_getname,
559		    (caddr_t)&info)) {
560			svcerr_decode(transp);
561			return;
562		}
563		grp = getgrnam(info.name);
564		info.retval = 0;
565		if (grp != NULL) {
566			nid.nid_usertimeout = defusertimeout;
567			nid.nid_gid = grp->gr_gid;
568			nid.nid_name = grp->gr_name;
569		} else {
570			nid.nid_usertimeout = 5;
571			nid.nid_gid = defaultgid;
572			nid.nid_name = info.name;
573		}
574		nid.nid_namelen = strlen(nid.nid_name);
575		nid.nid_flag = NFSID_ADDGROUPNAME;
576		error = nfssvc(NFSSVC_IDNAME, &nid);
577		if (error) {
578			info.retval = error;
579			syslog(LOG_ERR, "Can't add group %s\n",
580			    grp->gr_name);
581		} else if (verbose) {
582			syslog(LOG_ERR,"Added gid=%d name=%s\n",
583			    nid.nid_gid, nid.nid_name);
584		}
585		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
586		    (caddr_t)&info))
587			syslog(LOG_ERR, "Can't send reply");
588		return;
589	default:
590		svcerr_noproc(transp);
591		return;
592	};
593}
594
595/*
596 * Xdr routine to get an id number
597 */
598static bool_t
599xdr_getid(XDR *xdrsp, caddr_t cp)
600{
601	struct info *ifp = (struct info *)cp;
602
603	return (xdr_long(xdrsp, &ifp->id));
604}
605
606/*
607 * Xdr routine to get a user name
608 */
609static bool_t
610xdr_getname(XDR *xdrsp, caddr_t cp)
611{
612	struct info *ifp = (struct info *)cp;
613	long len;
614
615	if (!xdr_long(xdrsp, &len))
616		return (0);
617	if (len > MAXNAME)
618		return (0);
619	if (!xdr_opaque(xdrsp, ifp->name, len))
620		return (0);
621	ifp->name[len] = '\0';
622	return (1);
623}
624
625/*
626 * Xdr routine to return the value.
627 */
628static bool_t
629xdr_retval(XDR *xdrsp, caddr_t cp)
630{
631	struct info *ifp = (struct info *)cp;
632	long val;
633
634	val = ifp->retval;
635	return (xdr_long(xdrsp, &val));
636}
637
638/*
639 * cleanup_term() called via SIGUSR1.
640 */
641static void
642cleanup_term(int signo __unused)
643{
644	int i, cnt;
645
646	if (im_a_slave)
647		exit(0);
648
649	/*
650	 * Ok, so I'm the master.
651	 * As the Governor of California might say, "Terminate them".
652	 */
653	cnt = 0;
654	for (i = 0; i < nfsuserdcnt; i++) {
655		if (slaves[i] != (pid_t)-1) {
656			cnt++;
657			kill(slaves[i], SIGUSR1);
658		}
659	}
660
661	/*
662	 * and wait for them to die
663	 */
664	for (i = 0; i < cnt; i++)
665		wait3(NULL, 0, NULL);
666
667	/*
668	 * Finally, get rid of the socket
669	 */
670	if (nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0) {
671		syslog(LOG_ERR, "Can't do nfssvc() to delete the port\n");
672		exit(1);
673	}
674	exit(0);
675}
676
677static void
678usage(void)
679{
680
681	errx(1,
682	    "usage: nfsuserd [-usermax cache_size] [-usertimeout minutes] [-verbose] [-domain domain_name] [n]");
683}
684