nfsuserd.c revision 317920
12864Swollman/*-
250471Speter * Copyright (c) 2009 Rick Macklem, University of Guelph
31556Srgrimes * All rights reserved.
438652Sgpalmer *
538652Sgpalmer * Redistribution and use in source and binary forms, with or without
638652Sgpalmer * modification, are permitted provided that the following conditions
738652Sgpalmer * are met:
838652Sgpalmer * 1. Redistributions of source code must retain the above copyright
938652Sgpalmer *    notice, this list of conditions and the following disclaimer.
1038652Sgpalmer * 2. Redistributions in binary form must reproduce the above copyright
1138652Sgpalmer *    notice, this list of conditions and the following disclaimer in the
1238652Sgpalmer *    documentation and/or other materials provided with the distribution.
1338652Sgpalmer *
1438652Sgpalmer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1574466Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1638652Sgpalmer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1738652Sgpalmer * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1838652Sgpalmer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1938652Sgpalmer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2038652Sgpalmer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2138652Sgpalmer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2238652Sgpalmer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2338652Sgpalmer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2438652Sgpalmer * SUCH DAMAGE.
2590535Smike *
2638652Sgpalmer */
2738652Sgpalmer
2874466Srwatson#include <sys/cdefs.h>
2938652Sgpalmer__FBSDID("$FreeBSD: stable/10/usr.sbin/nfsuserd/nfsuserd.c 317920 2017-05-07 20:50:32Z rmacklem $");
3038652Sgpalmer
3138652Sgpalmer#include <sys/param.h>
3238652Sgpalmer#include <sys/errno.h>
3338652Sgpalmer#include <sys/linker.h>
341556Srgrimes#include <sys/module.h>
3594297Sbmilekic#include <sys/mount.h>
3694297Sbmilekic#include <sys/socket.h>
3794297Sbmilekic#include <sys/socketvar.h>
3894297Sbmilekic#include <sys/time.h>
3959337Sobrien#include <sys/ucred.h>
4059337Sobrien#include <sys/vnode.h>
4159337Sobrien#include <sys/wait.h>
4259337Sobrien
4367849Sdougb#include <nfs/nfssvc.h>
4436410Sphk
4536410Sphk#include <rpc/rpc.h>
4636410Sphk
471556Srgrimes#include <fs/nfs/rpcv2.h>
48#include <fs/nfs/nfsproto.h>
49#include <fs/nfs/nfskpiport.h>
50#include <fs/nfs/nfs.h>
51
52#include <ctype.h>
53#include <err.h>
54#include <grp.h>
55#include <netdb.h>
56#include <pwd.h>
57#include <signal.h>
58#include <stdio.h>
59#include <stdlib.h>
60#include <string.h>
61#include <syslog.h>
62#include <unistd.h>
63
64/*
65 * This program loads the password and group databases into the kernel
66 * for NFS V4.
67 */
68
69static void	cleanup_term(int);
70static void	usage(void);
71static void	nfsuserdsrv(struct svc_req *, SVCXPRT *);
72static bool_t	xdr_getid(XDR *, caddr_t);
73static bool_t	xdr_getname(XDR *, caddr_t);
74static bool_t	xdr_retval(XDR *, caddr_t);
75
76#define	MAXNAME		1024
77#define	MAXNFSUSERD	20
78#define	DEFNFSUSERD	4
79#define	MAXUSERMAX	100000
80#define	MINUSERMAX	10
81#define	DEFUSERMAX	200
82#define	DEFUSERTIMEOUT	(1 * 60)
83struct info {
84	long	id;
85	long	retval;
86	char	name[MAXNAME + 1];
87};
88
89u_char *dnsname = "default.domain";
90u_char *defaultuser = "nobody";
91uid_t defaultuid = 65534;
92u_char *defaultgroup = "nogroup";
93gid_t defaultgid = 65533;
94int verbose = 0, im_a_slave = 0, nfsuserdcnt = -1, forcestart = 0;
95int defusertimeout = DEFUSERTIMEOUT, manage_gids = 0;
96pid_t slaves[MAXNFSUSERD];
97
98int
99main(int argc, char *argv[])
100{
101	int i, j;
102	int error, fnd_dup, len, mustfreeai = 0, start_uidpos;
103	struct nfsd_idargs nid;
104	struct passwd *pwd;
105	struct group *grp;
106	int sock, one = 1;
107	SVCXPRT *udptransp;
108	u_short portnum;
109	sigset_t signew;
110	char hostname[MAXHOSTNAMELEN + 1], *cp;
111	struct addrinfo *aip, hints;
112	static uid_t check_dups[MAXUSERMAX];
113	gid_t grps[NGROUPS];
114	int ngroup;
115
116	if (modfind("nfscommon") < 0) {
117		/* Not present in kernel, try loading it */
118		if (kldload("nfscommon") < 0 ||
119		    modfind("nfscommon") < 0)
120			errx(1, "Experimental nfs subsystem is not available");
121	}
122
123	/*
124	 * First, figure out what our domain name and Kerberos Realm
125	 * seem to be. Command line args may override these later.
126	 */
127	if (gethostname(hostname, MAXHOSTNAMELEN) == 0) {
128		if ((cp = strchr(hostname, '.')) != NULL &&
129		    *(cp + 1) != '\0') {
130			dnsname = cp + 1;
131		} else {
132			memset((void *)&hints, 0, sizeof (hints));
133			hints.ai_flags = AI_CANONNAME;
134			error = getaddrinfo(hostname, NULL, &hints, &aip);
135			if (error == 0) {
136			    if (aip->ai_canonname != NULL &&
137				(cp = strchr(aip->ai_canonname, '.')) != NULL
138				&& *(cp + 1) != '\0') {
139					dnsname = cp + 1;
140					mustfreeai = 1;
141				} else {
142					freeaddrinfo(aip);
143				}
144			}
145		}
146	}
147	nid.nid_usermax = DEFUSERMAX;
148	nid.nid_usertimeout = defusertimeout;
149
150	argc--;
151	argv++;
152	while (argc >= 1) {
153		if (!strcmp(*argv, "-domain")) {
154			if (argc == 1)
155				usage();
156			argc--;
157			argv++;
158			strncpy(hostname, *argv, MAXHOSTNAMELEN);
159			hostname[MAXHOSTNAMELEN] = '\0';
160			dnsname = hostname;
161		} else if (!strcmp(*argv, "-verbose")) {
162			verbose = 1;
163		} else if (!strcmp(*argv, "-force")) {
164			forcestart = 1;
165		} else if (!strcmp(*argv, "-manage-gids")) {
166			manage_gids = 1;
167		} else if (!strcmp(*argv, "-usermax")) {
168			if (argc == 1)
169				usage();
170			argc--;
171			argv++;
172			i = atoi(*argv);
173			if (i < MINUSERMAX || i > MAXUSERMAX) {
174				fprintf(stderr,
175				    "usermax %d out of range %d<->%d\n", i,
176				    MINUSERMAX, MAXUSERMAX);
177				usage();
178			}
179			nid.nid_usermax = i;
180		} else if (!strcmp(*argv, "-usertimeout")) {
181			if (argc == 1)
182				usage();
183			argc--;
184			argv++;
185			i = atoi(*argv);
186			if (i < 0 || i > 100000) {
187				fprintf(stderr,
188				    "usertimeout %d out of range 0<->100000\n",
189				    i);
190				usage();
191			}
192			nid.nid_usertimeout = defusertimeout = i * 60;
193		} else if (nfsuserdcnt == -1) {
194			nfsuserdcnt = atoi(*argv);
195			if (nfsuserdcnt < 1)
196				usage();
197			if (nfsuserdcnt > MAXNFSUSERD) {
198				warnx("nfsuserd count %d; reset to %d",
199				    nfsuserdcnt, DEFNFSUSERD);
200				nfsuserdcnt = DEFNFSUSERD;
201			}
202		} else {
203			usage();
204		}
205		argc--;
206		argv++;
207	}
208	if (nfsuserdcnt < 1)
209		nfsuserdcnt = DEFNFSUSERD;
210
211	/*
212	 * Strip off leading and trailing '.'s in domain name and map
213	 * alphabetics to lower case.
214	 */
215	while (*dnsname == '.')
216		dnsname++;
217	if (*dnsname == '\0')
218		errx(1, "Domain name all '.'");
219	len = strlen(dnsname);
220	cp = dnsname + len - 1;
221	while (*cp == '.') {
222		*cp = '\0';
223		len--;
224		cp--;
225	}
226	for (i = 0; i < len; i++) {
227		if (!isascii(dnsname[i]))
228			errx(1, "Domain name has non-ascii char");
229		if (isupper(dnsname[i]))
230			dnsname[i] = tolower(dnsname[i]);
231	}
232
233	/*
234	 * If the nfsuserd died off ungracefully, this is necessary to
235	 * get them to start again.
236	 */
237	if (forcestart && nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0)
238		errx(1, "Can't do nfssvc() to delete the port");
239
240	if (verbose)
241		fprintf(stderr,
242		    "nfsuserd: domain=%s usermax=%d usertimeout=%d\n",
243		    dnsname, nid.nid_usermax, nid.nid_usertimeout);
244
245	for (i = 0; i < nfsuserdcnt; i++)
246		slaves[i] = (pid_t)-1;
247
248	/*
249	 * Set up the service port to accept requests via UDP from
250	 * localhost (127.0.0.1).
251	 */
252	if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
253		err(1, "cannot create udp socket");
254
255	/*
256	 * Not sure what this does, so I'll leave it here for now.
257	 */
258	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
259
260	if ((udptransp = svcudp_create(sock)) == NULL)
261		err(1, "Can't set up socket");
262
263	/*
264	 * By not specifying a protocol, it is linked into the
265	 * dispatch queue, but not registered with portmapper,
266	 * which is just what I want.
267	 */
268	if (!svc_register(udptransp, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS,
269	    nfsuserdsrv, 0))
270		err(1, "Can't register nfsuserd");
271
272	/*
273	 * Tell the kernel what my port# is.
274	 */
275	portnum = htons(udptransp->xp_port);
276#ifdef DEBUG
277	printf("portnum=0x%x\n", portnum);
278#else
279	if (nfssvc(NFSSVC_NFSUSERDPORT, (caddr_t)&portnum) < 0) {
280		if (errno == EPERM) {
281			fprintf(stderr,
282			    "Can't start nfsuserd when already running");
283			fprintf(stderr,
284			    " If not running, use the -force option.\n");
285		} else {
286			fprintf(stderr, "Can't do nfssvc() to add port\n");
287		}
288		exit(1);
289	}
290#endif
291
292	pwd = getpwnam(defaultuser);
293	if (pwd)
294		nid.nid_uid = pwd->pw_uid;
295	else
296		nid.nid_uid = defaultuid;
297	grp = getgrnam(defaultgroup);
298	if (grp)
299		nid.nid_gid = grp->gr_gid;
300	else
301		nid.nid_gid = defaultgid;
302	nid.nid_name = dnsname;
303	nid.nid_namelen = strlen(nid.nid_name);
304	nid.nid_ngroup = 0;
305	nid.nid_grps = NULL;
306	nid.nid_flag = NFSID_INITIALIZE;
307#ifdef DEBUG
308	printf("Initialize uid=%d gid=%d dns=%s\n", nid.nid_uid, nid.nid_gid,
309	    nid.nid_name);
310#else
311	error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
312	if (error)
313		errx(1, "Can't initialize nfs user/groups");
314#endif
315
316	i = 0;
317	/*
318	 * Loop around adding all groups.
319	 */
320	setgrent();
321	while (i < nid.nid_usermax && (grp = getgrent())) {
322		nid.nid_gid = grp->gr_gid;
323		nid.nid_name = grp->gr_name;
324		nid.nid_namelen = strlen(grp->gr_name);
325		nid.nid_ngroup = 0;
326		nid.nid_grps = NULL;
327		nid.nid_flag = NFSID_ADDGID;
328#ifdef DEBUG
329		printf("add gid=%d name=%s\n", nid.nid_gid, nid.nid_name);
330#else
331		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
332		if (error)
333			errx(1, "Can't add group %s", grp->gr_name);
334#endif
335		i++;
336	}
337
338	/*
339	 * Loop around adding all users.
340	 */
341	start_uidpos = i;
342	setpwent();
343	while (i < nid.nid_usermax && (pwd = getpwent())) {
344		fnd_dup = 0;
345		/*
346		 * Yes, this is inefficient, but it is only done once when
347		 * the daemon is started and will run in a fraction of a second
348		 * for nid_usermax at 10000. If nid_usermax is cranked up to
349		 * 100000, it will take several seconds, depending on the CPU.
350		 */
351		for (j = 0; j < (i - start_uidpos); j++)
352			if (check_dups[j] == pwd->pw_uid) {
353				/* Found another entry for uid, so skip it */
354				fnd_dup = 1;
355				break;
356			}
357		if (fnd_dup != 0)
358			continue;
359		check_dups[i - start_uidpos] = pwd->pw_uid;
360		nid.nid_uid = pwd->pw_uid;
361		nid.nid_name = pwd->pw_name;
362		nid.nid_namelen = strlen(pwd->pw_name);
363		if (manage_gids != 0) {
364			/* Get the group list for this user. */
365			ngroup = NGROUPS;
366			if (getgrouplist(pwd->pw_name, pwd->pw_gid, grps,
367			    &ngroup) < 0)
368				syslog(LOG_ERR, "Group list too small");
369			nid.nid_ngroup = ngroup;
370			nid.nid_grps = grps;
371		} else {
372			nid.nid_ngroup = 0;
373			nid.nid_grps = NULL;
374		}
375		nid.nid_flag = NFSID_ADDUID;
376#ifdef DEBUG
377		printf("add uid=%d name=%s\n", nid.nid_uid, nid.nid_name);
378#else
379		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
380		if (error)
381			errx(1, "Can't add user %s", pwd->pw_name);
382#endif
383		i++;
384	}
385
386	/*
387	 * I should feel guilty for not calling this for all the above exit()
388	 * upon error cases, but I don't.
389	 */
390	if (mustfreeai)
391		freeaddrinfo(aip);
392
393#ifdef DEBUG
394	exit(0);
395#endif
396	/*
397	 * Temporarily block SIGUSR1 and SIGCHLD, so slaves[] can't
398	 * end up bogus.
399	 */
400	sigemptyset(&signew);
401	sigaddset(&signew, SIGUSR1);
402	sigaddset(&signew, SIGCHLD);
403	sigprocmask(SIG_BLOCK, &signew, NULL);
404
405	daemon(0, 0);
406	(void)signal(SIGHUP, SIG_IGN);
407	(void)signal(SIGINT, SIG_IGN);
408	(void)signal(SIGQUIT, SIG_IGN);
409	(void)signal(SIGTERM, SIG_IGN);
410	(void)signal(SIGUSR1, cleanup_term);
411	(void)signal(SIGCHLD, cleanup_term);
412
413	openlog("nfsuserd:", LOG_PID, LOG_DAEMON);
414
415	/*
416	 * Fork off the slave daemons that do the work. All the master
417	 * does is kill them off and cleanup.
418	 */
419	for (i = 0; i < nfsuserdcnt; i++) {
420		slaves[i] = fork();
421		if (slaves[i] == 0) {
422			im_a_slave = 1;
423			setproctitle("slave");
424			sigemptyset(&signew);
425			sigaddset(&signew, SIGUSR1);
426			sigprocmask(SIG_UNBLOCK, &signew, NULL);
427
428			/*
429			 * and away we go.
430			 */
431			svc_run();
432			syslog(LOG_ERR, "nfsuserd died: %m");
433			exit(1);
434		} else if (slaves[i] < 0) {
435			syslog(LOG_ERR, "fork: %m");
436		}
437	}
438
439	/*
440	 * Just wait for SIGUSR1 or a child to die and then...
441	 * As the Governor of California would say, "Terminate them".
442	 */
443	setproctitle("master");
444	sigemptyset(&signew);
445	while (1)
446		sigsuspend(&signew);
447}
448
449/*
450 * The nfsuserd rpc service
451 */
452static void
453nfsuserdsrv(struct svc_req *rqstp, SVCXPRT *transp)
454{
455	struct passwd *pwd;
456	struct group *grp;
457	int error;
458	u_short sport;
459	struct info info;
460	struct nfsd_idargs nid;
461	u_int32_t saddr;
462	gid_t grps[NGROUPS];
463	int ngroup;
464
465	/*
466	 * Only handle requests from 127.0.0.1 on a reserved port number.
467	 * (Since a reserved port # at localhost implies a client with
468	 *  local root, there won't be a security breach. This is about
469	 *  the only case I can think of where a reserved port # means
470	 *  something.)
471	 */
472	sport = ntohs(transp->xp_raddr.sin_port);
473	saddr = ntohl(transp->xp_raddr.sin_addr.s_addr);
474	if ((rqstp->rq_proc != NULLPROC && sport >= IPPORT_RESERVED) ||
475	    saddr != 0x7f000001) {
476		syslog(LOG_ERR, "req from ip=0x%x port=%d\n", saddr, sport);
477		svcerr_weakauth(transp);
478		return;
479	}
480	switch (rqstp->rq_proc) {
481	case NULLPROC:
482		if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL))
483			syslog(LOG_ERR, "Can't send reply");
484		return;
485	case RPCNFSUSERD_GETUID:
486		if (!svc_getargs(transp, (xdrproc_t)xdr_getid,
487		    (caddr_t)&info)) {
488			svcerr_decode(transp);
489			return;
490		}
491		pwd = getpwuid((uid_t)info.id);
492		info.retval = 0;
493		if (pwd != NULL) {
494			nid.nid_usertimeout = defusertimeout;
495			nid.nid_uid = pwd->pw_uid;
496			nid.nid_name = pwd->pw_name;
497			if (manage_gids != 0) {
498				/* Get the group list for this user. */
499				ngroup = NGROUPS;
500				if (getgrouplist(pwd->pw_name, pwd->pw_gid,
501				    grps, &ngroup) < 0)
502					syslog(LOG_ERR, "Group list too small");
503				nid.nid_ngroup = ngroup;
504				nid.nid_grps = grps;
505			} else {
506				nid.nid_ngroup = 0;
507				nid.nid_grps = NULL;
508			}
509		} else {
510			nid.nid_usertimeout = 5;
511			nid.nid_uid = (uid_t)info.id;
512			nid.nid_name = defaultuser;
513			nid.nid_ngroup = 0;
514			nid.nid_grps = NULL;
515		}
516		nid.nid_namelen = strlen(nid.nid_name);
517		nid.nid_flag = NFSID_ADDUID;
518		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
519		if (error) {
520			info.retval = error;
521			syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name);
522		} else if (verbose) {
523			syslog(LOG_ERR,"Added uid=%d name=%s\n",
524			    nid.nid_uid, nid.nid_name);
525		}
526		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
527		    (caddr_t)&info))
528			syslog(LOG_ERR, "Can't send reply");
529		return;
530	case RPCNFSUSERD_GETGID:
531		if (!svc_getargs(transp, (xdrproc_t)xdr_getid,
532		    (caddr_t)&info)) {
533			svcerr_decode(transp);
534			return;
535		}
536		grp = getgrgid((gid_t)info.id);
537		info.retval = 0;
538		if (grp != NULL) {
539			nid.nid_usertimeout = defusertimeout;
540			nid.nid_gid = grp->gr_gid;
541			nid.nid_name = grp->gr_name;
542		} else {
543			nid.nid_usertimeout = 5;
544			nid.nid_gid = (gid_t)info.id;
545			nid.nid_name = defaultgroup;
546		}
547		nid.nid_namelen = strlen(nid.nid_name);
548		nid.nid_ngroup = 0;
549		nid.nid_grps = NULL;
550		nid.nid_flag = NFSID_ADDGID;
551		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
552		if (error) {
553			info.retval = error;
554			syslog(LOG_ERR, "Can't add group %s\n",
555			    grp->gr_name);
556		} else if (verbose) {
557			syslog(LOG_ERR,"Added gid=%d name=%s\n",
558			    nid.nid_gid, nid.nid_name);
559		}
560		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
561		    (caddr_t)&info))
562			syslog(LOG_ERR, "Can't send reply");
563		return;
564	case RPCNFSUSERD_GETUSER:
565		if (!svc_getargs(transp, (xdrproc_t)xdr_getname,
566		    (caddr_t)&info)) {
567			svcerr_decode(transp);
568			return;
569		}
570		pwd = getpwnam(info.name);
571		info.retval = 0;
572		if (pwd != NULL) {
573			nid.nid_usertimeout = defusertimeout;
574			nid.nid_uid = pwd->pw_uid;
575			nid.nid_name = pwd->pw_name;
576		} else {
577			nid.nid_usertimeout = 5;
578			nid.nid_uid = defaultuid;
579			nid.nid_name = info.name;
580		}
581		nid.nid_namelen = strlen(nid.nid_name);
582		nid.nid_ngroup = 0;
583		nid.nid_grps = NULL;
584		nid.nid_flag = NFSID_ADDUSERNAME;
585		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
586		if (error) {
587			info.retval = error;
588			syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name);
589		} else if (verbose) {
590			syslog(LOG_ERR,"Added uid=%d name=%s\n",
591			    nid.nid_uid, nid.nid_name);
592		}
593		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
594		    (caddr_t)&info))
595			syslog(LOG_ERR, "Can't send reply");
596		return;
597	case RPCNFSUSERD_GETGROUP:
598		if (!svc_getargs(transp, (xdrproc_t)xdr_getname,
599		    (caddr_t)&info)) {
600			svcerr_decode(transp);
601			return;
602		}
603		grp = getgrnam(info.name);
604		info.retval = 0;
605		if (grp != NULL) {
606			nid.nid_usertimeout = defusertimeout;
607			nid.nid_gid = grp->gr_gid;
608			nid.nid_name = grp->gr_name;
609		} else {
610			nid.nid_usertimeout = 5;
611			nid.nid_gid = defaultgid;
612			nid.nid_name = info.name;
613		}
614		nid.nid_namelen = strlen(nid.nid_name);
615		nid.nid_ngroup = 0;
616		nid.nid_grps = NULL;
617		nid.nid_flag = NFSID_ADDGROUPNAME;
618		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
619		if (error) {
620			info.retval = error;
621			syslog(LOG_ERR, "Can't add group %s\n",
622			    grp->gr_name);
623		} else if (verbose) {
624			syslog(LOG_ERR,"Added gid=%d name=%s\n",
625			    nid.nid_gid, nid.nid_name);
626		}
627		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
628		    (caddr_t)&info))
629			syslog(LOG_ERR, "Can't send reply");
630		return;
631	default:
632		svcerr_noproc(transp);
633		return;
634	};
635}
636
637/*
638 * Xdr routine to get an id number
639 */
640static bool_t
641xdr_getid(XDR *xdrsp, caddr_t cp)
642{
643	struct info *ifp = (struct info *)cp;
644
645	return (xdr_long(xdrsp, &ifp->id));
646}
647
648/*
649 * Xdr routine to get a user name
650 */
651static bool_t
652xdr_getname(XDR *xdrsp, caddr_t cp)
653{
654	struct info *ifp = (struct info *)cp;
655	long len;
656
657	if (!xdr_long(xdrsp, &len))
658		return (0);
659	if (len > MAXNAME)
660		return (0);
661	if (!xdr_opaque(xdrsp, ifp->name, len))
662		return (0);
663	ifp->name[len] = '\0';
664	return (1);
665}
666
667/*
668 * Xdr routine to return the value.
669 */
670static bool_t
671xdr_retval(XDR *xdrsp, caddr_t cp)
672{
673	struct info *ifp = (struct info *)cp;
674	long val;
675
676	val = ifp->retval;
677	return (xdr_long(xdrsp, &val));
678}
679
680/*
681 * cleanup_term() called via SIGUSR1.
682 */
683static void
684cleanup_term(int signo __unused)
685{
686	int i, cnt;
687
688	if (im_a_slave)
689		exit(0);
690
691	/*
692	 * Ok, so I'm the master.
693	 * As the Governor of California might say, "Terminate them".
694	 */
695	cnt = 0;
696	for (i = 0; i < nfsuserdcnt; i++) {
697		if (slaves[i] != (pid_t)-1) {
698			cnt++;
699			kill(slaves[i], SIGUSR1);
700		}
701	}
702
703	/*
704	 * and wait for them to die
705	 */
706	for (i = 0; i < cnt; i++)
707		wait3(NULL, 0, NULL);
708
709	/*
710	 * Finally, get rid of the socket
711	 */
712	if (nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0) {
713		syslog(LOG_ERR, "Can't do nfssvc() to delete the port\n");
714		exit(1);
715	}
716	exit(0);
717}
718
719static void
720usage(void)
721{
722
723	errx(1,
724	    "usage: nfsuserd [-usermax cache_size] [-usertimeout minutes] [-verbose] [-manage-gids] [-domain domain_name] [n]");
725}
726