xref: /freebsd/usr.sbin/nfsuserd/nfsuserd.c (revision 0957b409)
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 	endgrent();
338 
339 	/*
340 	 * Loop around adding all users.
341 	 */
342 	start_uidpos = i;
343 	setpwent();
344 	while (i < nid.nid_usermax && (pwd = getpwent())) {
345 		fnd_dup = 0;
346 		/*
347 		 * Yes, this is inefficient, but it is only done once when
348 		 * the daemon is started and will run in a fraction of a second
349 		 * for nid_usermax at 10000. If nid_usermax is cranked up to
350 		 * 100000, it will take several seconds, depending on the CPU.
351 		 */
352 		for (j = 0; j < (i - start_uidpos); j++)
353 			if (check_dups[j] == pwd->pw_uid) {
354 				/* Found another entry for uid, so skip it */
355 				fnd_dup = 1;
356 				break;
357 			}
358 		if (fnd_dup != 0)
359 			continue;
360 		check_dups[i - start_uidpos] = pwd->pw_uid;
361 		nid.nid_uid = pwd->pw_uid;
362 		nid.nid_name = pwd->pw_name;
363 		nid.nid_namelen = strlen(pwd->pw_name);
364 		if (manage_gids != 0) {
365 			/* Get the group list for this user. */
366 			ngroup = NGROUPS;
367 			if (getgrouplist(pwd->pw_name, pwd->pw_gid, grps,
368 			    &ngroup) < 0)
369 				syslog(LOG_ERR, "Group list too small");
370 			nid.nid_ngroup = ngroup;
371 			nid.nid_grps = grps;
372 		} else {
373 			nid.nid_ngroup = 0;
374 			nid.nid_grps = NULL;
375 		}
376 		nid.nid_flag = NFSID_ADDUID;
377 #ifdef DEBUG
378 		printf("add uid=%d name=%s\n", nid.nid_uid, nid.nid_name);
379 #else
380 		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
381 		if (error)
382 			errx(1, "Can't add user %s", pwd->pw_name);
383 #endif
384 		i++;
385 	}
386 	endpwent();
387 
388 	/*
389 	 * I should feel guilty for not calling this for all the above exit()
390 	 * upon error cases, but I don't.
391 	 */
392 	if (mustfreeai)
393 		freeaddrinfo(aip);
394 
395 #ifdef DEBUG
396 	exit(0);
397 #endif
398 	/*
399 	 * Temporarily block SIGUSR1 and SIGCHLD, so slaves[] can't
400 	 * end up bogus.
401 	 */
402 	sigemptyset(&signew);
403 	sigaddset(&signew, SIGUSR1);
404 	sigaddset(&signew, SIGCHLD);
405 	sigprocmask(SIG_BLOCK, &signew, NULL);
406 
407 	daemon(0, 0);
408 	(void)signal(SIGHUP, SIG_IGN);
409 	(void)signal(SIGINT, SIG_IGN);
410 	(void)signal(SIGQUIT, SIG_IGN);
411 	(void)signal(SIGTERM, SIG_IGN);
412 	(void)signal(SIGUSR1, cleanup_term);
413 	(void)signal(SIGCHLD, cleanup_term);
414 
415 	openlog("nfsuserd:", LOG_PID, LOG_DAEMON);
416 
417 	/*
418 	 * Fork off the slave daemons that do the work. All the master
419 	 * does is kill them off and cleanup.
420 	 */
421 	for (i = 0; i < nfsuserdcnt; i++) {
422 		slaves[i] = fork();
423 		if (slaves[i] == 0) {
424 			im_a_slave = 1;
425 			setproctitle("slave");
426 			sigemptyset(&signew);
427 			sigaddset(&signew, SIGUSR1);
428 			sigprocmask(SIG_UNBLOCK, &signew, NULL);
429 
430 			/*
431 			 * and away we go.
432 			 */
433 			svc_run();
434 			syslog(LOG_ERR, "nfsuserd died: %m");
435 			exit(1);
436 		} else if (slaves[i] < 0) {
437 			syslog(LOG_ERR, "fork: %m");
438 		}
439 	}
440 
441 	/*
442 	 * Just wait for SIGUSR1 or a child to die and then...
443 	 * As the Governor of California would say, "Terminate them".
444 	 */
445 	setproctitle("master");
446 	sigemptyset(&signew);
447 	while (1)
448 		sigsuspend(&signew);
449 }
450 
451 /*
452  * The nfsuserd rpc service
453  */
454 static void
455 nfsuserdsrv(struct svc_req *rqstp, SVCXPRT *transp)
456 {
457 	struct passwd *pwd;
458 	struct group *grp;
459 	int error;
460 	u_short sport;
461 	struct info info;
462 	struct nfsd_idargs nid;
463 	u_int32_t saddr;
464 	gid_t grps[NGROUPS];
465 	int ngroup;
466 
467 	/*
468 	 * Only handle requests from 127.0.0.1 on a reserved port number.
469 	 * (Since a reserved port # at localhost implies a client with
470 	 *  local root, there won't be a security breach. This is about
471 	 *  the only case I can think of where a reserved port # means
472 	 *  something.)
473 	 */
474 	sport = ntohs(transp->xp_raddr.sin_port);
475 	saddr = ntohl(transp->xp_raddr.sin_addr.s_addr);
476 	if ((rqstp->rq_proc != NULLPROC && sport >= IPPORT_RESERVED) ||
477 	    saddr != 0x7f000001) {
478 		syslog(LOG_ERR, "req from ip=0x%x port=%d\n", saddr, sport);
479 		svcerr_weakauth(transp);
480 		return;
481 	}
482 	switch (rqstp->rq_proc) {
483 	case NULLPROC:
484 		if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL))
485 			syslog(LOG_ERR, "Can't send reply");
486 		return;
487 	case RPCNFSUSERD_GETUID:
488 		if (!svc_getargs(transp, (xdrproc_t)xdr_getid,
489 		    (caddr_t)&info)) {
490 			svcerr_decode(transp);
491 			return;
492 		}
493 		pwd = getpwuid((uid_t)info.id);
494 		info.retval = 0;
495 		if (pwd != NULL) {
496 			nid.nid_usertimeout = defusertimeout;
497 			nid.nid_uid = pwd->pw_uid;
498 			nid.nid_name = pwd->pw_name;
499 			if (manage_gids != 0) {
500 				/* Get the group list for this user. */
501 				ngroup = NGROUPS;
502 				if (getgrouplist(pwd->pw_name, pwd->pw_gid,
503 				    grps, &ngroup) < 0)
504 					syslog(LOG_ERR, "Group list too small");
505 				nid.nid_ngroup = ngroup;
506 				nid.nid_grps = grps;
507 			} else {
508 				nid.nid_ngroup = 0;
509 				nid.nid_grps = NULL;
510 			}
511 		} else {
512 			nid.nid_usertimeout = 5;
513 			nid.nid_uid = (uid_t)info.id;
514 			nid.nid_name = defaultuser;
515 			nid.nid_ngroup = 0;
516 			nid.nid_grps = NULL;
517 		}
518 		nid.nid_namelen = strlen(nid.nid_name);
519 		nid.nid_flag = NFSID_ADDUID;
520 		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
521 		if (error) {
522 			info.retval = error;
523 			syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name);
524 		} else if (verbose) {
525 			syslog(LOG_ERR,"Added uid=%d name=%s\n",
526 			    nid.nid_uid, nid.nid_name);
527 		}
528 		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
529 		    (caddr_t)&info))
530 			syslog(LOG_ERR, "Can't send reply");
531 		return;
532 	case RPCNFSUSERD_GETGID:
533 		if (!svc_getargs(transp, (xdrproc_t)xdr_getid,
534 		    (caddr_t)&info)) {
535 			svcerr_decode(transp);
536 			return;
537 		}
538 		grp = getgrgid((gid_t)info.id);
539 		info.retval = 0;
540 		if (grp != NULL) {
541 			nid.nid_usertimeout = defusertimeout;
542 			nid.nid_gid = grp->gr_gid;
543 			nid.nid_name = grp->gr_name;
544 		} else {
545 			nid.nid_usertimeout = 5;
546 			nid.nid_gid = (gid_t)info.id;
547 			nid.nid_name = defaultgroup;
548 		}
549 		nid.nid_namelen = strlen(nid.nid_name);
550 		nid.nid_ngroup = 0;
551 		nid.nid_grps = NULL;
552 		nid.nid_flag = NFSID_ADDGID;
553 		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
554 		if (error) {
555 			info.retval = error;
556 			syslog(LOG_ERR, "Can't add group %s\n",
557 			    grp->gr_name);
558 		} else if (verbose) {
559 			syslog(LOG_ERR,"Added gid=%d name=%s\n",
560 			    nid.nid_gid, nid.nid_name);
561 		}
562 		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
563 		    (caddr_t)&info))
564 			syslog(LOG_ERR, "Can't send reply");
565 		return;
566 	case RPCNFSUSERD_GETUSER:
567 		if (!svc_getargs(transp, (xdrproc_t)xdr_getname,
568 		    (caddr_t)&info)) {
569 			svcerr_decode(transp);
570 			return;
571 		}
572 		pwd = getpwnam(info.name);
573 		info.retval = 0;
574 		if (pwd != NULL) {
575 			nid.nid_usertimeout = defusertimeout;
576 			nid.nid_uid = pwd->pw_uid;
577 			nid.nid_name = pwd->pw_name;
578 		} else {
579 			nid.nid_usertimeout = 5;
580 			nid.nid_uid = defaultuid;
581 			nid.nid_name = info.name;
582 		}
583 		nid.nid_namelen = strlen(nid.nid_name);
584 		nid.nid_ngroup = 0;
585 		nid.nid_grps = NULL;
586 		nid.nid_flag = NFSID_ADDUSERNAME;
587 		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
588 		if (error) {
589 			info.retval = error;
590 			syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name);
591 		} else if (verbose) {
592 			syslog(LOG_ERR,"Added uid=%d name=%s\n",
593 			    nid.nid_uid, nid.nid_name);
594 		}
595 		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
596 		    (caddr_t)&info))
597 			syslog(LOG_ERR, "Can't send reply");
598 		return;
599 	case RPCNFSUSERD_GETGROUP:
600 		if (!svc_getargs(transp, (xdrproc_t)xdr_getname,
601 		    (caddr_t)&info)) {
602 			svcerr_decode(transp);
603 			return;
604 		}
605 		grp = getgrnam(info.name);
606 		info.retval = 0;
607 		if (grp != NULL) {
608 			nid.nid_usertimeout = defusertimeout;
609 			nid.nid_gid = grp->gr_gid;
610 			nid.nid_name = grp->gr_name;
611 		} else {
612 			nid.nid_usertimeout = 5;
613 			nid.nid_gid = defaultgid;
614 			nid.nid_name = info.name;
615 		}
616 		nid.nid_namelen = strlen(nid.nid_name);
617 		nid.nid_ngroup = 0;
618 		nid.nid_grps = NULL;
619 		nid.nid_flag = NFSID_ADDGROUPNAME;
620 		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
621 		if (error) {
622 			info.retval = error;
623 			syslog(LOG_ERR, "Can't add group %s\n",
624 			    grp->gr_name);
625 		} else if (verbose) {
626 			syslog(LOG_ERR,"Added gid=%d name=%s\n",
627 			    nid.nid_gid, nid.nid_name);
628 		}
629 		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
630 		    (caddr_t)&info))
631 			syslog(LOG_ERR, "Can't send reply");
632 		return;
633 	default:
634 		svcerr_noproc(transp);
635 		return;
636 	};
637 }
638 
639 /*
640  * Xdr routine to get an id number
641  */
642 static bool_t
643 xdr_getid(XDR *xdrsp, caddr_t cp)
644 {
645 	struct info *ifp = (struct info *)cp;
646 
647 	return (xdr_long(xdrsp, &ifp->id));
648 }
649 
650 /*
651  * Xdr routine to get a user name
652  */
653 static bool_t
654 xdr_getname(XDR *xdrsp, caddr_t cp)
655 {
656 	struct info *ifp = (struct info *)cp;
657 	long len;
658 
659 	if (!xdr_long(xdrsp, &len))
660 		return (0);
661 	if (len > MAXNAME)
662 		return (0);
663 	if (!xdr_opaque(xdrsp, ifp->name, len))
664 		return (0);
665 	ifp->name[len] = '\0';
666 	return (1);
667 }
668 
669 /*
670  * Xdr routine to return the value.
671  */
672 static bool_t
673 xdr_retval(XDR *xdrsp, caddr_t cp)
674 {
675 	struct info *ifp = (struct info *)cp;
676 	long val;
677 
678 	val = ifp->retval;
679 	return (xdr_long(xdrsp, &val));
680 }
681 
682 /*
683  * cleanup_term() called via SIGUSR1.
684  */
685 static void
686 cleanup_term(int signo __unused)
687 {
688 	int i, cnt;
689 
690 	if (im_a_slave)
691 		exit(0);
692 
693 	/*
694 	 * Ok, so I'm the master.
695 	 * As the Governor of California might say, "Terminate them".
696 	 */
697 	cnt = 0;
698 	for (i = 0; i < nfsuserdcnt; i++) {
699 		if (slaves[i] != (pid_t)-1) {
700 			cnt++;
701 			kill(slaves[i], SIGUSR1);
702 		}
703 	}
704 
705 	/*
706 	 * and wait for them to die
707 	 */
708 	for (i = 0; i < cnt; i++)
709 		wait3(NULL, 0, NULL);
710 
711 	/*
712 	 * Finally, get rid of the socket
713 	 */
714 	if (nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0) {
715 		syslog(LOG_ERR, "Can't do nfssvc() to delete the port\n");
716 		exit(1);
717 	}
718 	exit(0);
719 }
720 
721 static void
722 usage(void)
723 {
724 
725 	errx(1,
726 	    "usage: nfsuserd [-usermax cache_size] [-usertimeout minutes] [-verbose] [-manage-gids] [-domain domain_name] [n]");
727 }
728