xref: /freebsd/usr.sbin/nfsuserd/nfsuserd.c (revision 3416500aef140042c64bc149cb1ec6620483bc44)
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 <nfs/nfssvc.h>
44 
45 #include <rpc/rpc.h>
46 
47 #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 
69 static void	cleanup_term(int);
70 static void	usage(void);
71 static void	nfsuserdsrv(struct svc_req *, SVCXPRT *);
72 static bool_t	xdr_getid(XDR *, caddr_t);
73 static bool_t	xdr_getname(XDR *, caddr_t);
74 static 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)
83 struct info {
84 	long	id;
85 	long	retval;
86 	char	name[MAXNAME + 1];
87 };
88 
89 u_char *dnsname = "default.domain";
90 u_char *defaultuser = "nobody";
91 uid_t defaultuid = 65534;
92 u_char *defaultgroup = "nogroup";
93 gid_t defaultgid = 65533;
94 int verbose = 0, im_a_slave = 0, nfsuserdcnt = -1, forcestart = 0;
95 int defusertimeout = DEFUSERTIMEOUT, manage_gids = 0;
96 pid_t slaves[MAXNFSUSERD];
97 
98 int
99 main(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  */
452 static void
453 nfsuserdsrv(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  */
640 static bool_t
641 xdr_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  */
651 static bool_t
652 xdr_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  */
670 static bool_t
671 xdr_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  */
683 static void
684 cleanup_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 
719 static void
720 usage(void)
721 {
722 
723 	errx(1,
724 	    "usage: nfsuserd [-usermax cache_size] [-usertimeout minutes] [-verbose] [-manage-gids] [-domain domain_name] [n]");
725 }
726