xref: /freebsd/usr.sbin/nfsuserd/nfsuserd.c (revision 9a14aa017b21c292740c00ee098195cd46642730)
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 = (uid_t)32767;
92 u_char *defaultgroup = "nogroup";
93 gid_t defaultgid = (gid_t)32767;
94 int verbose = 0, im_a_slave = 0, nfsuserdcnt = -1, forcestart = 0;
95 int defusertimeout = DEFUSERTIMEOUT;
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 
114 	if (modfind("nfscommon") < 0) {
115 		/* Not present in kernel, try loading it */
116 		if (kldload("nfscommon") < 0 ||
117 		    modfind("nfscommon") < 0)
118 			errx(1, "Experimental nfs subsystem is not available");
119 	}
120 
121 	/*
122 	 * First, figure out what our domain name and Kerberos Realm
123 	 * seem to be. Command line args may override these later.
124 	 */
125 	if (gethostname(hostname, MAXHOSTNAMELEN) == 0) {
126 		if ((cp = strchr(hostname, '.')) != NULL &&
127 		    *(cp + 1) != '\0') {
128 			dnsname = cp + 1;
129 		} else {
130 			memset((void *)&hints, 0, sizeof (hints));
131 			hints.ai_flags = AI_CANONNAME;
132 			error = getaddrinfo(hostname, NULL, &hints, &aip);
133 			if (error == 0) {
134 			    if (aip->ai_canonname != NULL &&
135 				(cp = strchr(aip->ai_canonname, '.')) != NULL
136 				&& *(cp + 1) != '\0') {
137 					dnsname = cp + 1;
138 					mustfreeai = 1;
139 				} else {
140 					freeaddrinfo(aip);
141 				}
142 			}
143 		}
144 	}
145 	nid.nid_usermax = DEFUSERMAX;
146 	nid.nid_usertimeout = defusertimeout;
147 
148 	argc--;
149 	argv++;
150 	while (argc >= 1) {
151 		if (!strcmp(*argv, "-domain")) {
152 			if (argc == 1)
153 				usage();
154 			argc--;
155 			argv++;
156 			strncpy(hostname, *argv, MAXHOSTNAMELEN);
157 			hostname[MAXHOSTNAMELEN] = '\0';
158 			dnsname = hostname;
159 		} else if (!strcmp(*argv, "-verbose")) {
160 			verbose = 1;
161 		} else if (!strcmp(*argv, "-force")) {
162 			forcestart = 1;
163 		} else if (!strcmp(*argv, "-usermax")) {
164 			if (argc == 1)
165 				usage();
166 			argc--;
167 			argv++;
168 			i = atoi(*argv);
169 			if (i < MINUSERMAX || i > MAXUSERMAX) {
170 				fprintf(stderr,
171 				    "usermax %d out of range %d<->%d\n", i,
172 				    MINUSERMAX, MAXUSERMAX);
173 				usage();
174 			}
175 			nid.nid_usermax = i;
176 		} else if (!strcmp(*argv, "-usertimeout")) {
177 			if (argc == 1)
178 				usage();
179 			argc--;
180 			argv++;
181 			i = atoi(*argv);
182 			if (i < 0 || i > 100000) {
183 				fprintf(stderr,
184 				    "usertimeout %d out of range 0<->100000\n",
185 				    i);
186 				usage();
187 			}
188 			nid.nid_usertimeout = defusertimeout = i * 60;
189 		} else if (nfsuserdcnt == -1) {
190 			nfsuserdcnt = atoi(*argv);
191 			if (nfsuserdcnt < 1)
192 				usage();
193 			if (nfsuserdcnt > MAXNFSUSERD) {
194 				warnx("nfsuserd count %d; reset to %d",
195 				    nfsuserdcnt, DEFNFSUSERD);
196 				nfsuserdcnt = DEFNFSUSERD;
197 			}
198 		} else {
199 			usage();
200 		}
201 		argc--;
202 		argv++;
203 	}
204 	if (nfsuserdcnt < 1)
205 		nfsuserdcnt = DEFNFSUSERD;
206 
207 	/*
208 	 * Strip off leading and trailing '.'s in domain name and map
209 	 * alphabetics to lower case.
210 	 */
211 	while (*dnsname == '.')
212 		dnsname++;
213 	if (*dnsname == '\0')
214 		errx(1, "Domain name all '.'");
215 	len = strlen(dnsname);
216 	cp = dnsname + len - 1;
217 	while (*cp == '.') {
218 		*cp = '\0';
219 		len--;
220 		cp--;
221 	}
222 	for (i = 0; i < len; i++) {
223 		if (!isascii(dnsname[i]))
224 			errx(1, "Domain name has non-ascii char");
225 		if (isupper(dnsname[i]))
226 			dnsname[i] = tolower(dnsname[i]);
227 	}
228 
229 	/*
230 	 * If the nfsuserd died off ungracefully, this is necessary to
231 	 * get them to start again.
232 	 */
233 	if (forcestart && nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0)
234 		errx(1, "Can't do nfssvc() to delete the port");
235 
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  */
432 static void
433 nfsuserdsrv(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  */
598 static bool_t
599 xdr_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  */
609 static bool_t
610 xdr_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  */
628 static bool_t
629 xdr_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  */
641 static void
642 cleanup_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 
677 static void
678 usage(void)
679 {
680 
681 	errx(1,
682 	    "usage: nfsuserd [-usermax cache_size] [-usertimeout minutes] [-verbose] [-domain domain_name] [n]");
683 }
684