xref: /freebsd/usr.sbin/nfsuserd/nfsuserd.c (revision 7c1b51d6dc2e165ae7333373513b080f17cf79bd)
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/stat.h>
39 #include <sys/time.h>
40 #include <sys/ucred.h>
41 #include <sys/vnode.h>
42 #include <sys/wait.h>
43 
44 #include <nfs/nfssvc.h>
45 
46 #include <rpc/rpc.h>
47 #include <rpc/rpc_com.h>
48 
49 #include <fs/nfs/rpcv2.h>
50 #include <fs/nfs/nfsproto.h>
51 #include <fs/nfs/nfskpiport.h>
52 #include <fs/nfs/nfs.h>
53 
54 #include <ctype.h>
55 #include <err.h>
56 #include <grp.h>
57 #include <netdb.h>
58 #include <pwd.h>
59 #include <signal.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <syslog.h>
64 #include <unistd.h>
65 
66 /*
67  * This program loads the password and group databases into the kernel
68  * for NFS V4.
69  */
70 
71 static void	cleanup_term(int);
72 static void	usage(void);
73 static void	nfsuserdsrv(struct svc_req *, SVCXPRT *);
74 static bool_t	xdr_getid(XDR *, caddr_t);
75 static bool_t	xdr_getname(XDR *, caddr_t);
76 static bool_t	xdr_retval(XDR *, caddr_t);
77 
78 #ifndef _PATH_NFSUSERDSOCK
79 #define _PATH_NFSUSERDSOCK	"/var/run/nfsuserd.sock"
80 #endif
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)
88 struct info {
89 	long	id;
90 	long	retval;
91 	char	name[MAXNAME + 1];
92 };
93 
94 u_char *dnsname = "default.domain";
95 u_char *defaultuser = "nobody";
96 uid_t defaultuid = 65534;
97 u_char *defaultgroup = "nogroup";
98 gid_t defaultgid = 65533;
99 int verbose = 0, im_a_slave = 0, nfsuserdcnt = -1, forcestart = 0;
100 int use_udpsock = 0;
101 int defusertimeout = DEFUSERTIMEOUT, manage_gids = 0;
102 pid_t slaves[MAXNFSUSERD];
103 
104 int
105 main(int argc, char *argv[])
106 {
107 	int i, j;
108 	int error, fnd_dup, len, mustfreeai = 0, start_uidpos;
109 	struct nfsd_idargs nid;
110 	struct passwd *pwd;
111 	struct group *grp;
112 	int oldmask, one = 1, sock;
113 	SVCXPRT *udptransp;
114 	u_short portnum;
115 	SVCXPRT *xprt;
116 	sigset_t signew;
117 	char hostname[MAXHOSTNAMELEN + 1], *cp;
118 	struct addrinfo *aip, hints;
119 	static uid_t check_dups[MAXUSERMAX];
120 	gid_t grps[NGROUPS];
121 	int ngroup;
122 	struct sockaddr_un sun;
123 
124 	if (modfind("nfscommon") < 0) {
125 		/* Not present in kernel, try loading it */
126 		if (kldload("nfscommon") < 0 ||
127 		    modfind("nfscommon") < 0)
128 			errx(1, "Experimental nfs subsystem is not available");
129 	}
130 
131 	/*
132 	 * First, figure out what our domain name and Kerberos Realm
133 	 * seem to be. Command line args may override these later.
134 	 */
135 	if (gethostname(hostname, MAXHOSTNAMELEN) == 0) {
136 		if ((cp = strchr(hostname, '.')) != NULL &&
137 		    *(cp + 1) != '\0') {
138 			dnsname = cp + 1;
139 		} else {
140 			memset((void *)&hints, 0, sizeof (hints));
141 			hints.ai_flags = AI_CANONNAME;
142 			error = getaddrinfo(hostname, NULL, &hints, &aip);
143 			if (error == 0) {
144 			    if (aip->ai_canonname != NULL &&
145 				(cp = strchr(aip->ai_canonname, '.')) != NULL
146 				&& *(cp + 1) != '\0') {
147 					dnsname = cp + 1;
148 					mustfreeai = 1;
149 				} else {
150 					freeaddrinfo(aip);
151 				}
152 			}
153 		}
154 	}
155 	nid.nid_usermax = DEFUSERMAX;
156 	nid.nid_usertimeout = defusertimeout;
157 
158 	argc--;
159 	argv++;
160 	while (argc >= 1) {
161 		if (!strcmp(*argv, "-domain")) {
162 			if (argc == 1)
163 				usage();
164 			argc--;
165 			argv++;
166 			strncpy(hostname, *argv, MAXHOSTNAMELEN);
167 			hostname[MAXHOSTNAMELEN] = '\0';
168 			dnsname = hostname;
169 		} else if (!strcmp(*argv, "-verbose")) {
170 			verbose = 1;
171 		} else if (!strcmp(*argv, "-force")) {
172 			forcestart = 1;
173 		} else if (!strcmp(*argv, "-manage-gids")) {
174 			manage_gids = 1;
175 		} else if (!strcmp(*argv, "-use-udpsock")) {
176 			use_udpsock = 1;
177 		} else if (!strcmp(*argv, "-usermax")) {
178 			if (argc == 1)
179 				usage();
180 			argc--;
181 			argv++;
182 			i = atoi(*argv);
183 			if (i < MINUSERMAX || i > MAXUSERMAX) {
184 				fprintf(stderr,
185 				    "usermax %d out of range %d<->%d\n", i,
186 				    MINUSERMAX, MAXUSERMAX);
187 				usage();
188 			}
189 			nid.nid_usermax = i;
190 		} else if (!strcmp(*argv, "-usertimeout")) {
191 			if (argc == 1)
192 				usage();
193 			argc--;
194 			argv++;
195 			i = atoi(*argv);
196 			if (i < 0 || i > 100000) {
197 				fprintf(stderr,
198 				    "usertimeout %d out of range 0<->100000\n",
199 				    i);
200 				usage();
201 			}
202 			nid.nid_usertimeout = defusertimeout = i * 60;
203 		} else if (nfsuserdcnt == -1) {
204 			nfsuserdcnt = atoi(*argv);
205 			if (nfsuserdcnt < 1)
206 				usage();
207 			if (nfsuserdcnt > MAXNFSUSERD) {
208 				warnx("nfsuserd count %d; reset to %d",
209 				    nfsuserdcnt, DEFNFSUSERD);
210 				nfsuserdcnt = DEFNFSUSERD;
211 			}
212 		} else {
213 			usage();
214 		}
215 		argc--;
216 		argv++;
217 	}
218 	if (nfsuserdcnt < 1)
219 		nfsuserdcnt = DEFNFSUSERD;
220 	if (use_udpsock == 0)
221 		/* For AF_LOCAL socket, only allow one server daemon. */
222 		nfsuserdcnt = 1;
223 
224 	/*
225 	 * Strip off leading and trailing '.'s in domain name and map
226 	 * alphabetics to lower case.
227 	 */
228 	while (*dnsname == '.')
229 		dnsname++;
230 	if (*dnsname == '\0')
231 		errx(1, "Domain name all '.'");
232 	len = strlen(dnsname);
233 	cp = dnsname + len - 1;
234 	while (*cp == '.') {
235 		*cp = '\0';
236 		len--;
237 		cp--;
238 	}
239 	for (i = 0; i < len; i++) {
240 		if (!isascii(dnsname[i]))
241 			errx(1, "Domain name has non-ascii char");
242 		if (isupper(dnsname[i]))
243 			dnsname[i] = tolower(dnsname[i]);
244 	}
245 
246 	/*
247 	 * If the nfsuserd died off ungracefully, this is necessary to
248 	 * get them to start again.
249 	 */
250 	if (forcestart && nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0)
251 		errx(1, "Can't do nfssvc() to delete the port");
252 
253 	if (verbose)
254 		fprintf(stderr,
255 		    "nfsuserd: domain=%s usermax=%d usertimeout=%d\n",
256 		    dnsname, nid.nid_usermax, nid.nid_usertimeout);
257 
258 	for (i = 0; i < nfsuserdcnt; i++)
259 		slaves[i] = (pid_t)-1;
260 
261 	if (use_udpsock != 0) {
262 		/*
263 		 * Set up the service port to accept requests via UDP from
264 		 * localhost (127.0.0.1).
265 		 */
266 		if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
267 			err(1, "cannot create udp socket");
268 
269 		/*
270 		 * Not sure what this does, so I'll leave it here for now.
271 		 */
272 		setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
273 
274 		if ((udptransp = svcudp_create(sock)) == NULL)
275 			err(1, "Can't set up socket");
276 
277 		/*
278 		 * By not specifying a protocol, it is linked into the
279 		 * dispatch queue, but not registered with portmapper,
280 		 * which is just what I want.
281 		 */
282 		if (!svc_register(udptransp, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS,
283 		    nfsuserdsrv, 0))
284 			err(1, "Can't register nfsuserd");
285 
286 		/*
287 		 * Tell the kernel what my port# is.
288 		 */
289 		portnum = htons(udptransp->xp_port);
290 #ifdef DEBUG
291 		printf("portnum=0x%x\n", portnum);
292 #else
293 		if (nfssvc(NFSSVC_NFSUSERDPORT, (caddr_t)&portnum) < 0) {
294 			if (errno == EPERM)
295 				fprintf(stderr, "Can't start nfsuserd when"
296 				    " already running\nIf not running,"
297 				    " use the -force option.\n");
298 			else
299 				fprintf(stderr,
300 				    "Can't do nfssvc() to add socket\n");
301 			exit(1);
302 		}
303 #endif
304 	} else {
305 		/* Use the AF_LOCAL socket. */
306 		memset(&sun, 0, sizeof sun);
307 		sun.sun_family = AF_LOCAL;
308 		unlink(_PATH_NFSUSERDSOCK);
309 		strcpy(sun.sun_path, _PATH_NFSUSERDSOCK);
310 		sun.sun_len = SUN_LEN(&sun);
311 		sock = socket(AF_LOCAL, SOCK_STREAM, 0);
312 		if (sock < 0)
313 			err(1, "Can't create local nfsuserd socket");
314 		oldmask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
315 		if (bind(sock, (struct sockaddr *)&sun, sun.sun_len) < 0)
316 			err(1, "Can't bind local nfsuserd socket");
317 		umask(oldmask);
318 		if (listen(sock, SOMAXCONN) < 0)
319 			err(1, "Can't listen on local nfsuserd socket");
320 		xprt = svc_vc_create(sock, RPC_MAXDATASIZE, RPC_MAXDATASIZE);
321 		if (xprt == NULL)
322 			err(1,
323 			    "Can't create transport for local nfsuserd socket");
324 		if (!svc_reg(xprt, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS,
325 		    nfsuserdsrv, NULL))
326 			err(1,
327 			    "Can't register service for local nfsuserd socket");
328 
329 		/*
330 		 * Tell the kernel what the socket's path is.
331 		 */
332 #ifdef DEBUG
333 		printf("sockpath=%s\n", _PATH_NFSUSERDSOCK);
334 #else
335 		if (nfssvc(NFSSVC_NFSUSERDPORT | NFSSVC_NEWSTRUCT,
336 		    _PATH_NFSUSERDSOCK) < 0) {
337 			if (errno == EPERM)
338 				fprintf(stderr, "Can't start nfsuserd when"
339 				    " already running\nIf not running,"
340 				    " use the -force option.\n");
341 			else
342 				fprintf(stderr,
343 				    "Can't do nfssvc() to add socket\n");
344 			exit(1);
345 		}
346 #endif
347 	}
348 
349 	pwd = getpwnam(defaultuser);
350 	if (pwd)
351 		nid.nid_uid = pwd->pw_uid;
352 	else
353 		nid.nid_uid = defaultuid;
354 	grp = getgrnam(defaultgroup);
355 	if (grp)
356 		nid.nid_gid = grp->gr_gid;
357 	else
358 		nid.nid_gid = defaultgid;
359 	nid.nid_name = dnsname;
360 	nid.nid_namelen = strlen(nid.nid_name);
361 	nid.nid_ngroup = 0;
362 	nid.nid_grps = NULL;
363 	nid.nid_flag = NFSID_INITIALIZE;
364 #ifdef DEBUG
365 	printf("Initialize uid=%d gid=%d dns=%s\n", nid.nid_uid, nid.nid_gid,
366 	    nid.nid_name);
367 #else
368 	error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
369 	if (error)
370 		errx(1, "Can't initialize nfs user/groups");
371 #endif
372 
373 	i = 0;
374 	/*
375 	 * Loop around adding all groups.
376 	 */
377 	setgrent();
378 	while (i < nid.nid_usermax && (grp = getgrent())) {
379 		nid.nid_gid = grp->gr_gid;
380 		nid.nid_name = grp->gr_name;
381 		nid.nid_namelen = strlen(grp->gr_name);
382 		nid.nid_ngroup = 0;
383 		nid.nid_grps = NULL;
384 		nid.nid_flag = NFSID_ADDGID;
385 #ifdef DEBUG
386 		printf("add gid=%d name=%s\n", nid.nid_gid, nid.nid_name);
387 #else
388 		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
389 		if (error)
390 			errx(1, "Can't add group %s", grp->gr_name);
391 #endif
392 		i++;
393 	}
394 
395 	/*
396 	 * Loop around adding all users.
397 	 */
398 	start_uidpos = i;
399 	setpwent();
400 	while (i < nid.nid_usermax && (pwd = getpwent())) {
401 		fnd_dup = 0;
402 		/*
403 		 * Yes, this is inefficient, but it is only done once when
404 		 * the daemon is started and will run in a fraction of a second
405 		 * for nid_usermax at 10000. If nid_usermax is cranked up to
406 		 * 100000, it will take several seconds, depending on the CPU.
407 		 */
408 		for (j = 0; j < (i - start_uidpos); j++)
409 			if (check_dups[j] == pwd->pw_uid) {
410 				/* Found another entry for uid, so skip it */
411 				fnd_dup = 1;
412 				break;
413 			}
414 		if (fnd_dup != 0)
415 			continue;
416 		check_dups[i - start_uidpos] = pwd->pw_uid;
417 		nid.nid_uid = pwd->pw_uid;
418 		nid.nid_name = pwd->pw_name;
419 		nid.nid_namelen = strlen(pwd->pw_name);
420 		if (manage_gids != 0) {
421 			/* Get the group list for this user. */
422 			ngroup = NGROUPS;
423 			if (getgrouplist(pwd->pw_name, pwd->pw_gid, grps,
424 			    &ngroup) < 0)
425 				syslog(LOG_ERR, "Group list too small");
426 			nid.nid_ngroup = ngroup;
427 			nid.nid_grps = grps;
428 		} else {
429 			nid.nid_ngroup = 0;
430 			nid.nid_grps = NULL;
431 		}
432 		nid.nid_flag = NFSID_ADDUID;
433 #ifdef DEBUG
434 		printf("add uid=%d name=%s\n", nid.nid_uid, nid.nid_name);
435 #else
436 		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
437 		if (error)
438 			errx(1, "Can't add user %s", pwd->pw_name);
439 #endif
440 		i++;
441 	}
442 
443 	/*
444 	 * I should feel guilty for not calling this for all the above exit()
445 	 * upon error cases, but I don't.
446 	 */
447 	if (mustfreeai)
448 		freeaddrinfo(aip);
449 
450 #ifdef DEBUG
451 	exit(0);
452 #endif
453 	/*
454 	 * Temporarily block SIGUSR1 and SIGCHLD, so slaves[] can't
455 	 * end up bogus.
456 	 */
457 	sigemptyset(&signew);
458 	sigaddset(&signew, SIGUSR1);
459 	sigaddset(&signew, SIGCHLD);
460 	sigprocmask(SIG_BLOCK, &signew, NULL);
461 
462 	daemon(0, 0);
463 	(void)signal(SIGHUP, SIG_IGN);
464 	(void)signal(SIGINT, SIG_IGN);
465 	(void)signal(SIGQUIT, SIG_IGN);
466 	(void)signal(SIGTERM, SIG_IGN);
467 	(void)signal(SIGUSR1, cleanup_term);
468 	(void)signal(SIGCHLD, cleanup_term);
469 
470 	openlog("nfsuserd:", LOG_PID, LOG_DAEMON);
471 
472 	/*
473 	 * Fork off the slave daemons that do the work. All the master
474 	 * does is kill them off and cleanup.
475 	 */
476 	for (i = 0; i < nfsuserdcnt; i++) {
477 		slaves[i] = fork();
478 		if (slaves[i] == 0) {
479 			im_a_slave = 1;
480 			setproctitle("slave");
481 			sigemptyset(&signew);
482 			sigaddset(&signew, SIGUSR1);
483 			sigprocmask(SIG_UNBLOCK, &signew, NULL);
484 
485 			/*
486 			 * and away we go.
487 			 */
488 			svc_run();
489 			syslog(LOG_ERR, "nfsuserd died: %m");
490 			exit(1);
491 		} else if (slaves[i] < 0) {
492 			syslog(LOG_ERR, "fork: %m");
493 		}
494 	}
495 
496 	/*
497 	 * Just wait for SIGUSR1 or a child to die and then...
498 	 * As the Governor of California would say, "Terminate them".
499 	 */
500 	setproctitle("master");
501 	sigemptyset(&signew);
502 	while (1)
503 		sigsuspend(&signew);
504 }
505 
506 /*
507  * The nfsuserd rpc service
508  */
509 static void
510 nfsuserdsrv(struct svc_req *rqstp, SVCXPRT *transp)
511 {
512 	struct passwd *pwd;
513 	struct group *grp;
514 	int error;
515 	u_short sport;
516 	struct info info;
517 	struct nfsd_idargs nid;
518 	u_int32_t saddr;
519 	gid_t grps[NGROUPS];
520 	int ngroup;
521 
522 	if (use_udpsock != 0) {
523 		/*
524 		 * Only handle requests from 127.0.0.1 on a reserved port
525 		 * number.  (Since a reserved port # at localhost implies a
526 		 * client with local root, there won't be a security breach.
527 		 * This is about the only case I can think of where a reserved
528 		 * port # means something.)
529 		 */
530 		sport = ntohs(transp->xp_raddr.sin_port);
531 		saddr = ntohl(transp->xp_raddr.sin_addr.s_addr);
532 		if ((rqstp->rq_proc != NULLPROC && sport >= IPPORT_RESERVED) ||
533 		    saddr != 0x7f000001) {
534 			syslog(LOG_ERR, "req from ip=0x%x port=%d, consider"
535 			    " using an AF_LOCAL socket\n", saddr, sport);
536 			svcerr_weakauth(transp);
537 			return;
538 		}
539 	}
540 
541 	switch (rqstp->rq_proc) {
542 	case NULLPROC:
543 		if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL))
544 			syslog(LOG_ERR, "Can't send reply");
545 		return;
546 	case RPCNFSUSERD_GETUID:
547 		if (!svc_getargs(transp, (xdrproc_t)xdr_getid,
548 		    (caddr_t)&info)) {
549 			svcerr_decode(transp);
550 			return;
551 		}
552 		pwd = getpwuid((uid_t)info.id);
553 		info.retval = 0;
554 		if (pwd != NULL) {
555 			nid.nid_usertimeout = defusertimeout;
556 			nid.nid_uid = pwd->pw_uid;
557 			nid.nid_name = pwd->pw_name;
558 			if (manage_gids != 0) {
559 				/* Get the group list for this user. */
560 				ngroup = NGROUPS;
561 				if (getgrouplist(pwd->pw_name, pwd->pw_gid,
562 				    grps, &ngroup) < 0)
563 					syslog(LOG_ERR, "Group list too small");
564 				nid.nid_ngroup = ngroup;
565 				nid.nid_grps = grps;
566 			} else {
567 				nid.nid_ngroup = 0;
568 				nid.nid_grps = NULL;
569 			}
570 		} else {
571 			nid.nid_usertimeout = 5;
572 			nid.nid_uid = (uid_t)info.id;
573 			nid.nid_name = defaultuser;
574 			nid.nid_ngroup = 0;
575 			nid.nid_grps = NULL;
576 		}
577 		nid.nid_namelen = strlen(nid.nid_name);
578 		nid.nid_flag = NFSID_ADDUID;
579 		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
580 		if (error) {
581 			info.retval = error;
582 			syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name);
583 		} else if (verbose) {
584 			syslog(LOG_ERR,"Added uid=%d name=%s\n",
585 			    nid.nid_uid, nid.nid_name);
586 		}
587 		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
588 		    (caddr_t)&info))
589 			syslog(LOG_ERR, "Can't send reply");
590 		return;
591 	case RPCNFSUSERD_GETGID:
592 		if (!svc_getargs(transp, (xdrproc_t)xdr_getid,
593 		    (caddr_t)&info)) {
594 			svcerr_decode(transp);
595 			return;
596 		}
597 		grp = getgrgid((gid_t)info.id);
598 		info.retval = 0;
599 		if (grp != NULL) {
600 			nid.nid_usertimeout = defusertimeout;
601 			nid.nid_gid = grp->gr_gid;
602 			nid.nid_name = grp->gr_name;
603 		} else {
604 			nid.nid_usertimeout = 5;
605 			nid.nid_gid = (gid_t)info.id;
606 			nid.nid_name = defaultgroup;
607 		}
608 		nid.nid_namelen = strlen(nid.nid_name);
609 		nid.nid_ngroup = 0;
610 		nid.nid_grps = NULL;
611 		nid.nid_flag = NFSID_ADDGID;
612 		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
613 		if (error) {
614 			info.retval = error;
615 			syslog(LOG_ERR, "Can't add group %s\n",
616 			    grp->gr_name);
617 		} else if (verbose) {
618 			syslog(LOG_ERR,"Added gid=%d name=%s\n",
619 			    nid.nid_gid, nid.nid_name);
620 		}
621 		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
622 		    (caddr_t)&info))
623 			syslog(LOG_ERR, "Can't send reply");
624 		return;
625 	case RPCNFSUSERD_GETUSER:
626 		if (!svc_getargs(transp, (xdrproc_t)xdr_getname,
627 		    (caddr_t)&info)) {
628 			svcerr_decode(transp);
629 			return;
630 		}
631 		pwd = getpwnam(info.name);
632 		info.retval = 0;
633 		if (pwd != NULL) {
634 			nid.nid_usertimeout = defusertimeout;
635 			nid.nid_uid = pwd->pw_uid;
636 			nid.nid_name = pwd->pw_name;
637 		} else {
638 			nid.nid_usertimeout = 5;
639 			nid.nid_uid = defaultuid;
640 			nid.nid_name = info.name;
641 		}
642 		nid.nid_namelen = strlen(nid.nid_name);
643 		nid.nid_ngroup = 0;
644 		nid.nid_grps = NULL;
645 		nid.nid_flag = NFSID_ADDUSERNAME;
646 		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
647 		if (error) {
648 			info.retval = error;
649 			syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name);
650 		} else if (verbose) {
651 			syslog(LOG_ERR,"Added uid=%d name=%s\n",
652 			    nid.nid_uid, nid.nid_name);
653 		}
654 		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
655 		    (caddr_t)&info))
656 			syslog(LOG_ERR, "Can't send reply");
657 		return;
658 	case RPCNFSUSERD_GETGROUP:
659 		if (!svc_getargs(transp, (xdrproc_t)xdr_getname,
660 		    (caddr_t)&info)) {
661 			svcerr_decode(transp);
662 			return;
663 		}
664 		grp = getgrnam(info.name);
665 		info.retval = 0;
666 		if (grp != NULL) {
667 			nid.nid_usertimeout = defusertimeout;
668 			nid.nid_gid = grp->gr_gid;
669 			nid.nid_name = grp->gr_name;
670 		} else {
671 			nid.nid_usertimeout = 5;
672 			nid.nid_gid = defaultgid;
673 			nid.nid_name = info.name;
674 		}
675 		nid.nid_namelen = strlen(nid.nid_name);
676 		nid.nid_ngroup = 0;
677 		nid.nid_grps = NULL;
678 		nid.nid_flag = NFSID_ADDGROUPNAME;
679 		error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
680 		if (error) {
681 			info.retval = error;
682 			syslog(LOG_ERR, "Can't add group %s\n",
683 			    grp->gr_name);
684 		} else if (verbose) {
685 			syslog(LOG_ERR,"Added gid=%d name=%s\n",
686 			    nid.nid_gid, nid.nid_name);
687 		}
688 		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
689 		    (caddr_t)&info))
690 			syslog(LOG_ERR, "Can't send reply");
691 		return;
692 	default:
693 		svcerr_noproc(transp);
694 		return;
695 	};
696 }
697 
698 /*
699  * Xdr routine to get an id number
700  */
701 static bool_t
702 xdr_getid(XDR *xdrsp, caddr_t cp)
703 {
704 	struct info *ifp = (struct info *)cp;
705 
706 	return (xdr_long(xdrsp, &ifp->id));
707 }
708 
709 /*
710  * Xdr routine to get a user name
711  */
712 static bool_t
713 xdr_getname(XDR *xdrsp, caddr_t cp)
714 {
715 	struct info *ifp = (struct info *)cp;
716 	long len;
717 
718 	if (!xdr_long(xdrsp, &len))
719 		return (0);
720 	if (len > MAXNAME)
721 		return (0);
722 	if (!xdr_opaque(xdrsp, ifp->name, len))
723 		return (0);
724 	ifp->name[len] = '\0';
725 	return (1);
726 }
727 
728 /*
729  * Xdr routine to return the value.
730  */
731 static bool_t
732 xdr_retval(XDR *xdrsp, caddr_t cp)
733 {
734 	struct info *ifp = (struct info *)cp;
735 	long val;
736 
737 	val = ifp->retval;
738 	return (xdr_long(xdrsp, &val));
739 }
740 
741 /*
742  * cleanup_term() called via SIGUSR1.
743  */
744 static void
745 cleanup_term(int signo __unused)
746 {
747 	int i, cnt;
748 
749 	if (im_a_slave)
750 		exit(0);
751 
752 	/*
753 	 * Ok, so I'm the master.
754 	 * As the Governor of California might say, "Terminate them".
755 	 */
756 	cnt = 0;
757 	for (i = 0; i < nfsuserdcnt; i++) {
758 		if (slaves[i] != (pid_t)-1) {
759 			cnt++;
760 			kill(slaves[i], SIGUSR1);
761 		}
762 	}
763 
764 	/*
765 	 * and wait for them to die
766 	 */
767 	for (i = 0; i < cnt; i++)
768 		wait3(NULL, 0, NULL);
769 
770 	/*
771 	 * Finally, get rid of the socket
772 	 */
773 	if (nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0) {
774 		syslog(LOG_ERR, "Can't do nfssvc() to delete the port\n");
775 		exit(1);
776 	}
777 	exit(0);
778 }
779 
780 static void
781 usage(void)
782 {
783 
784 	errx(1, "usage: nfsuserd [-usermax cache_size] [-usertimeout minutes]"
785 	    " [-verbose] [-manage-gids] [-use-udpsock] [-domain domain_name]"
786 	    " [n]");
787 }
788