1192811Srmacklem/*-
2192811Srmacklem * Copyright (c) 2009 Rick Macklem, University of Guelph
3192811Srmacklem * All rights reserved.
4192811Srmacklem *
5192811Srmacklem * Redistribution and use in source and binary forms, with or without
6192811Srmacklem * modification, are permitted provided that the following conditions
7192811Srmacklem * are met:
8192811Srmacklem * 1. Redistributions of source code must retain the above copyright
9192811Srmacklem *    notice, this list of conditions and the following disclaimer.
10192811Srmacklem * 2. Redistributions in binary form must reproduce the above copyright
11192811Srmacklem *    notice, this list of conditions and the following disclaimer in the
12192811Srmacklem *    documentation and/or other materials provided with the distribution.
13192811Srmacklem *
14192811Srmacklem * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15192811Srmacklem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16192811Srmacklem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17192811Srmacklem * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18192811Srmacklem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19192811Srmacklem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20192811Srmacklem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21192811Srmacklem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22192811Srmacklem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23192811Srmacklem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24192811Srmacklem * SUCH DAMAGE.
25192811Srmacklem *
26192811Srmacklem */
27192811Srmacklem
28192811Srmacklem#include <sys/cdefs.h>
29192811Srmacklem__FBSDID("$FreeBSD$");
30192811Srmacklem
31192811Srmacklem#include <sys/param.h>
32192811Srmacklem#include <sys/errno.h>
33192811Srmacklem#include <sys/linker.h>
34192811Srmacklem#include <sys/module.h>
35192811Srmacklem#include <sys/mount.h>
36192811Srmacklem#include <sys/socket.h>
37192811Srmacklem#include <sys/socketvar.h>
38192811Srmacklem#include <sys/time.h>
39192811Srmacklem#include <sys/ucred.h>
40192811Srmacklem#include <sys/vnode.h>
41192811Srmacklem#include <sys/wait.h>
42192811Srmacklem
43192811Srmacklem#include <nfs/nfssvc.h>
44192811Srmacklem
45192811Srmacklem#include <rpc/rpc.h>
46192811Srmacklem
47192811Srmacklem#include <fs/nfs/rpcv2.h>
48192811Srmacklem#include <fs/nfs/nfsproto.h>
49192811Srmacklem#include <fs/nfs/nfskpiport.h>
50192811Srmacklem#include <fs/nfs/nfs.h>
51192811Srmacklem
52192811Srmacklem#include <ctype.h>
53192811Srmacklem#include <err.h>
54192811Srmacklem#include <grp.h>
55192811Srmacklem#include <netdb.h>
56192811Srmacklem#include <pwd.h>
57192811Srmacklem#include <signal.h>
58192811Srmacklem#include <stdio.h>
59192811Srmacklem#include <stdlib.h>
60192811Srmacklem#include <string.h>
61192811Srmacklem#include <syslog.h>
62192811Srmacklem#include <unistd.h>
63192811Srmacklem
64192811Srmacklem/*
65192811Srmacklem * This program loads the password and group databases into the kernel
66192811Srmacklem * for NFS V4.
67192811Srmacklem */
68192811Srmacklem
69193070Sdelphijstatic void	cleanup_term(int);
70193070Sdelphijstatic void	usage(void);
71193070Sdelphijstatic void	nfsuserdsrv(struct svc_req *, SVCXPRT *);
72193070Sdelphijstatic bool_t	xdr_getid(XDR *, caddr_t);
73193070Sdelphijstatic bool_t	xdr_getname(XDR *, caddr_t);
74193070Sdelphijstatic bool_t	xdr_retval(XDR *, caddr_t);
75192811Srmacklem
76192811Srmacklem#define	MAXNAME		1024
77192811Srmacklem#define	MAXNFSUSERD	20
78192811Srmacklem#define	DEFNFSUSERD	4
79223382Srmacklem#define	MAXUSERMAX	100000
80223382Srmacklem#define	MINUSERMAX	10
81192811Srmacklem#define	DEFUSERMAX	200
82192811Srmacklem#define	DEFUSERTIMEOUT	(1 * 60)
83192811Srmacklemstruct info {
84192811Srmacklem	long	id;
85192811Srmacklem	long	retval;
86192811Srmacklem	char	name[MAXNAME + 1];
87192811Srmacklem};
88192811Srmacklem
89192811Srmacklemu_char *dnsname = "default.domain";
90192811Srmacklemu_char *defaultuser = "nobody";
91192811Srmacklemuid_t defaultuid = (uid_t)32767;
92192811Srmacklemu_char *defaultgroup = "nogroup";
93192811Srmacklemgid_t defaultgid = (gid_t)32767;
94192811Srmacklemint verbose = 0, im_a_slave = 0, nfsuserdcnt = -1, forcestart = 0;
95192811Srmacklemint defusertimeout = DEFUSERTIMEOUT;
96192811Srmacklempid_t slaves[MAXNFSUSERD];
97192811Srmacklem
98192811Srmacklemint
99193070Sdelphijmain(int argc, char *argv[])
100192811Srmacklem{
101223382Srmacklem	int i, j;
102223382Srmacklem	int error, fnd_dup, len, mustfreeai = 0, start_uidpos;
103192811Srmacklem	struct nfsd_idargs nid;
104192811Srmacklem	struct passwd *pwd;
105192811Srmacklem	struct group *grp;
106192811Srmacklem	int sock, one = 1;
107193070Sdelphij	SVCXPRT *udptransp;
108192811Srmacklem	u_short portnum;
109192811Srmacklem	sigset_t signew;
110193070Sdelphij	char hostname[MAXHOSTNAMELEN + 1], *cp;
111192811Srmacklem	struct addrinfo *aip, hints;
112223382Srmacklem	static uid_t check_dups[MAXUSERMAX];
113192811Srmacklem
114192811Srmacklem	if (modfind("nfscommon") < 0) {
115192811Srmacklem		/* Not present in kernel, try loading it */
116192811Srmacklem		if (kldload("nfscommon") < 0 ||
117192811Srmacklem		    modfind("nfscommon") < 0)
118192811Srmacklem			errx(1, "Experimental nfs subsystem is not available");
119192811Srmacklem	}
120192811Srmacklem
121192811Srmacklem	/*
122192811Srmacklem	 * First, figure out what our domain name and Kerberos Realm
123192811Srmacklem	 * seem to be. Command line args may override these later.
124192811Srmacklem	 */
125192811Srmacklem	if (gethostname(hostname, MAXHOSTNAMELEN) == 0) {
126192811Srmacklem		if ((cp = strchr(hostname, '.')) != NULL &&
127192811Srmacklem		    *(cp + 1) != '\0') {
128192811Srmacklem			dnsname = cp + 1;
129192811Srmacklem		} else {
130192811Srmacklem			memset((void *)&hints, 0, sizeof (hints));
131192811Srmacklem			hints.ai_flags = AI_CANONNAME;
132192811Srmacklem			error = getaddrinfo(hostname, NULL, &hints, &aip);
133192811Srmacklem			if (error == 0) {
134192811Srmacklem			    if (aip->ai_canonname != NULL &&
135192811Srmacklem				(cp = strchr(aip->ai_canonname, '.')) != NULL
136192811Srmacklem				&& *(cp + 1) != '\0') {
137192811Srmacklem					dnsname = cp + 1;
138192811Srmacklem					mustfreeai = 1;
139192811Srmacklem				} else {
140192811Srmacklem					freeaddrinfo(aip);
141192811Srmacklem				}
142192811Srmacklem			}
143192811Srmacklem		}
144192811Srmacklem	}
145192811Srmacklem	nid.nid_usermax = DEFUSERMAX;
146192811Srmacklem	nid.nid_usertimeout = defusertimeout;
147192811Srmacklem
148192811Srmacklem	argc--;
149192811Srmacklem	argv++;
150192811Srmacklem	while (argc >= 1) {
151192811Srmacklem		if (!strcmp(*argv, "-domain")) {
152192811Srmacklem			if (argc == 1)
153192811Srmacklem				usage();
154192811Srmacklem			argc--;
155192811Srmacklem			argv++;
156192811Srmacklem			strncpy(hostname, *argv, MAXHOSTNAMELEN);
157192811Srmacklem			hostname[MAXHOSTNAMELEN] = '\0';
158192811Srmacklem			dnsname = hostname;
159192811Srmacklem		} else if (!strcmp(*argv, "-verbose")) {
160192811Srmacklem			verbose = 1;
161192811Srmacklem		} else if (!strcmp(*argv, "-force")) {
162192811Srmacklem			forcestart = 1;
163192811Srmacklem		} else if (!strcmp(*argv, "-usermax")) {
164192811Srmacklem			if (argc == 1)
165192811Srmacklem				usage();
166192811Srmacklem			argc--;
167192811Srmacklem			argv++;
168192811Srmacklem			i = atoi(*argv);
169223382Srmacklem			if (i < MINUSERMAX || i > MAXUSERMAX) {
170192811Srmacklem				fprintf(stderr,
171223382Srmacklem				    "usermax %d out of range %d<->%d\n", i,
172223382Srmacklem				    MINUSERMAX, MAXUSERMAX);
173192811Srmacklem				usage();
174192811Srmacklem			}
175192811Srmacklem			nid.nid_usermax = i;
176192811Srmacklem		} else if (!strcmp(*argv, "-usertimeout")) {
177192811Srmacklem			if (argc == 1)
178192811Srmacklem				usage();
179192811Srmacklem			argc--;
180192811Srmacklem			argv++;
181192811Srmacklem			i = atoi(*argv);
182192811Srmacklem			if (i < 0 || i > 100000) {
183192811Srmacklem				fprintf(stderr,
184193070Sdelphij				    "usertimeout %d out of range 0<->100000\n",
185192811Srmacklem				    i);
186192811Srmacklem				usage();
187192811Srmacklem			}
188192811Srmacklem			nid.nid_usertimeout = defusertimeout = i * 60;
189192811Srmacklem		} else if (nfsuserdcnt == -1) {
190192811Srmacklem			nfsuserdcnt = atoi(*argv);
191192811Srmacklem			if (nfsuserdcnt < 1)
192192811Srmacklem				usage();
193192811Srmacklem			if (nfsuserdcnt > MAXNFSUSERD) {
194192811Srmacklem				warnx("nfsuserd count %d; reset to %d",
195192811Srmacklem				    nfsuserdcnt, DEFNFSUSERD);
196192811Srmacklem				nfsuserdcnt = DEFNFSUSERD;
197192811Srmacklem			}
198192811Srmacklem		} else {
199192811Srmacklem			usage();
200192811Srmacklem		}
201192811Srmacklem		argc--;
202192811Srmacklem		argv++;
203192811Srmacklem	}
204192811Srmacklem	if (nfsuserdcnt < 1)
205192811Srmacklem		nfsuserdcnt = DEFNFSUSERD;
206192811Srmacklem
207192811Srmacklem	/*
208192811Srmacklem	 * Strip off leading and trailing '.'s in domain name and map
209192811Srmacklem	 * alphabetics to lower case.
210192811Srmacklem	 */
211192811Srmacklem	while (*dnsname == '.')
212192811Srmacklem		dnsname++;
213192811Srmacklem	if (*dnsname == '\0')
214192811Srmacklem		errx(1, "Domain name all '.'");
215192811Srmacklem	len = strlen(dnsname);
216192811Srmacklem	cp = dnsname + len - 1;
217192811Srmacklem	while (*cp == '.') {
218192811Srmacklem		*cp = '\0';
219192811Srmacklem		len--;
220192811Srmacklem		cp--;
221192811Srmacklem	}
222192811Srmacklem	for (i = 0; i < len; i++) {
223192811Srmacklem		if (!isascii(dnsname[i]))
224192811Srmacklem			errx(1, "Domain name has non-ascii char");
225192811Srmacklem		if (isupper(dnsname[i]))
226192811Srmacklem			dnsname[i] = tolower(dnsname[i]);
227192811Srmacklem	}
228192811Srmacklem
229192811Srmacklem	/*
230192811Srmacklem	 * If the nfsuserd died off ungracefully, this is necessary to
231192811Srmacklem	 * get them to start again.
232192811Srmacklem	 */
233192811Srmacklem	if (forcestart && nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0)
234192811Srmacklem		errx(1, "Can't do nfssvc() to delete the port");
235192811Srmacklem
236192811Srmacklem	if (verbose)
237192811Srmacklem		fprintf(stderr,
238192811Srmacklem		    "nfsuserd: domain=%s usermax=%d usertimeout=%d\n",
239192811Srmacklem		    dnsname, nid.nid_usermax, nid.nid_usertimeout);
240192811Srmacklem
241192811Srmacklem	for (i = 0; i < nfsuserdcnt; i++)
242192811Srmacklem		slaves[i] = (pid_t)-1;
243192811Srmacklem
244192811Srmacklem	/*
245192811Srmacklem	 * Set up the service port to accept requests via UDP from
246192811Srmacklem	 * localhost (127.0.0.1).
247192811Srmacklem	 */
248192811Srmacklem	if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
249192811Srmacklem		err(1, "cannot create udp socket");
250192811Srmacklem
251192811Srmacklem	/*
252192811Srmacklem	 * Not sure what this does, so I'll leave it here for now.
253192811Srmacklem	 */
254192811Srmacklem	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
255192811Srmacklem
256192811Srmacklem	if ((udptransp = svcudp_create(sock)) == NULL)
257192811Srmacklem		err(1, "Can't set up socket");
258192811Srmacklem
259192811Srmacklem	/*
260192811Srmacklem	 * By not specifying a protocol, it is linked into the
261192811Srmacklem	 * dispatch queue, but not registered with portmapper,
262192811Srmacklem	 * which is just what I want.
263192811Srmacklem	 */
264192811Srmacklem	if (!svc_register(udptransp, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS,
265192811Srmacklem	    nfsuserdsrv, 0))
266192811Srmacklem		err(1, "Can't register nfsuserd");
267192811Srmacklem
268192811Srmacklem	/*
269192811Srmacklem	 * Tell the kernel what my port# is.
270192811Srmacklem	 */
271192811Srmacklem	portnum = htons(udptransp->xp_port);
272192811Srmacklem#ifdef DEBUG
273192811Srmacklem	printf("portnum=0x%x\n", portnum);
274192811Srmacklem#else
275192811Srmacklem	if (nfssvc(NFSSVC_NFSUSERDPORT, (caddr_t)&portnum) < 0) {
276192811Srmacklem		if (errno == EPERM) {
277192811Srmacklem			fprintf(stderr,
278192811Srmacklem			    "Can't start nfsuserd when already running");
279192811Srmacklem			fprintf(stderr,
280192811Srmacklem			    " If not running, use the -force option.\n");
281192811Srmacklem		} else {
282192811Srmacklem			fprintf(stderr, "Can't do nfssvc() to add port\n");
283192811Srmacklem		}
284192811Srmacklem		exit(1);
285192811Srmacklem	}
286192811Srmacklem#endif
287192811Srmacklem
288192811Srmacklem	pwd = getpwnam(defaultuser);
289192811Srmacklem	if (pwd)
290192811Srmacklem		nid.nid_uid = pwd->pw_uid;
291192811Srmacklem	else
292192811Srmacklem		nid.nid_uid = defaultuid;
293192811Srmacklem	grp = getgrnam(defaultgroup);
294192811Srmacklem	if (grp)
295192811Srmacklem		nid.nid_gid = grp->gr_gid;
296192811Srmacklem	else
297192811Srmacklem		nid.nid_gid = defaultgid;
298192811Srmacklem	nid.nid_name = dnsname;
299192811Srmacklem	nid.nid_namelen = strlen(nid.nid_name);
300192811Srmacklem	nid.nid_flag = NFSID_INITIALIZE;
301192811Srmacklem#ifdef DEBUG
302192811Srmacklem	printf("Initialize uid=%d gid=%d dns=%s\n", nid.nid_uid, nid.nid_gid,
303192811Srmacklem	    nid.nid_name);
304192811Srmacklem#else
305192811Srmacklem	error = nfssvc(NFSSVC_IDNAME, &nid);
306192811Srmacklem	if (error)
307192811Srmacklem		errx(1, "Can't initialize nfs user/groups");
308192811Srmacklem#endif
309192811Srmacklem
310192811Srmacklem	i = 0;
311192811Srmacklem	/*
312192811Srmacklem	 * Loop around adding all groups.
313192811Srmacklem	 */
314192811Srmacklem	setgrent();
315192811Srmacklem	while (i < nid.nid_usermax && (grp = getgrent())) {
316192811Srmacklem		nid.nid_gid = grp->gr_gid;
317192811Srmacklem		nid.nid_name = grp->gr_name;
318192811Srmacklem		nid.nid_namelen = strlen(grp->gr_name);
319192811Srmacklem		nid.nid_flag = NFSID_ADDGID;
320192811Srmacklem#ifdef DEBUG
321192811Srmacklem		printf("add gid=%d name=%s\n", nid.nid_gid, nid.nid_name);
322192811Srmacklem#else
323192811Srmacklem		error = nfssvc(NFSSVC_IDNAME, &nid);
324192811Srmacklem		if (error)
325192811Srmacklem			errx(1, "Can't add group %s", grp->gr_name);
326192811Srmacklem#endif
327192811Srmacklem		i++;
328192811Srmacklem	}
329192811Srmacklem
330192811Srmacklem	/*
331192811Srmacklem	 * Loop around adding all users.
332192811Srmacklem	 */
333223382Srmacklem	start_uidpos = i;
334192811Srmacklem	setpwent();
335192811Srmacklem	while (i < nid.nid_usermax && (pwd = getpwent())) {
336223382Srmacklem		fnd_dup = 0;
337223382Srmacklem		/*
338223382Srmacklem		 * Yes, this is inefficient, but it is only done once when
339223382Srmacklem		 * the daemon is started and will run in a fraction of a second
340223382Srmacklem		 * for nid_usermax at 10000. If nid_usermax is cranked up to
341223382Srmacklem		 * 100000, it will take several seconds, depending on the CPU.
342223382Srmacklem		 */
343223382Srmacklem		for (j = 0; j < (i - start_uidpos); j++)
344223382Srmacklem			if (check_dups[j] == pwd->pw_uid) {
345223382Srmacklem				/* Found another entry for uid, so skip it */
346223382Srmacklem				fnd_dup = 1;
347223382Srmacklem				break;
348223382Srmacklem			}
349223382Srmacklem		if (fnd_dup != 0)
350223382Srmacklem			continue;
351223382Srmacklem		check_dups[i - start_uidpos] = pwd->pw_uid;
352192811Srmacklem		nid.nid_uid = pwd->pw_uid;
353192811Srmacklem		nid.nid_name = pwd->pw_name;
354192811Srmacklem		nid.nid_namelen = strlen(pwd->pw_name);
355192811Srmacklem		nid.nid_flag = NFSID_ADDUID;
356192811Srmacklem#ifdef DEBUG
357192811Srmacklem		printf("add uid=%d name=%s\n", nid.nid_uid, nid.nid_name);
358192811Srmacklem#else
359192811Srmacklem		error = nfssvc(NFSSVC_IDNAME, &nid);
360192811Srmacklem		if (error)
361192811Srmacklem			errx(1, "Can't add user %s", pwd->pw_name);
362192811Srmacklem#endif
363192811Srmacklem		i++;
364192811Srmacklem	}
365192811Srmacklem
366192811Srmacklem	/*
367192811Srmacklem	 * I should feel guilty for not calling this for all the above exit()
368192811Srmacklem	 * upon error cases, but I don't.
369192811Srmacklem	 */
370192811Srmacklem	if (mustfreeai)
371192811Srmacklem		freeaddrinfo(aip);
372192811Srmacklem
373192811Srmacklem#ifdef DEBUG
374192811Srmacklem	exit(0);
375192811Srmacklem#endif
376192811Srmacklem	/*
377192811Srmacklem	 * Temporarily block SIGUSR1 and SIGCHLD, so slaves[] can't
378192811Srmacklem	 * end up bogus.
379192811Srmacklem	 */
380192811Srmacklem	sigemptyset(&signew);
381192811Srmacklem	sigaddset(&signew, SIGUSR1);
382192811Srmacklem	sigaddset(&signew, SIGCHLD);
383192811Srmacklem	sigprocmask(SIG_BLOCK, &signew, NULL);
384192811Srmacklem
385192811Srmacklem	daemon(0, 0);
386192811Srmacklem	(void)signal(SIGHUP, SIG_IGN);
387192811Srmacklem	(void)signal(SIGINT, SIG_IGN);
388192811Srmacklem	(void)signal(SIGQUIT, SIG_IGN);
389192811Srmacklem	(void)signal(SIGTERM, SIG_IGN);
390192811Srmacklem	(void)signal(SIGUSR1, cleanup_term);
391192811Srmacklem	(void)signal(SIGCHLD, cleanup_term);
392192811Srmacklem
393192811Srmacklem	openlog("nfsuserd:", LOG_PID, LOG_DAEMON);
394192811Srmacklem
395192811Srmacklem	/*
396192811Srmacklem	 * Fork off the slave daemons that do the work. All the master
397192811Srmacklem	 * does is kill them off and cleanup.
398192811Srmacklem	 */
399192811Srmacklem	for (i = 0; i < nfsuserdcnt; i++) {
400192811Srmacklem		slaves[i] = fork();
401192811Srmacklem		if (slaves[i] == 0) {
402192811Srmacklem			im_a_slave = 1;
403192811Srmacklem			setproctitle("slave");
404192811Srmacklem			sigemptyset(&signew);
405192811Srmacklem			sigaddset(&signew, SIGUSR1);
406192811Srmacklem			sigprocmask(SIG_UNBLOCK, &signew, NULL);
407192811Srmacklem
408192811Srmacklem			/*
409192811Srmacklem			 * and away we go.
410192811Srmacklem			 */
411192811Srmacklem			svc_run();
412192811Srmacklem			syslog(LOG_ERR, "nfsuserd died: %m");
413192811Srmacklem			exit(1);
414192811Srmacklem		} else if (slaves[i] < 0) {
415192811Srmacklem			syslog(LOG_ERR, "fork: %m");
416192811Srmacklem		}
417192811Srmacklem	}
418192811Srmacklem
419192811Srmacklem	/*
420192811Srmacklem	 * Just wait for SIGUSR1 or a child to die and then...
421192811Srmacklem	 * As the Governor of California would say, "Terminate them".
422192811Srmacklem	 */
423192811Srmacklem	setproctitle("master");
424192811Srmacklem	sigemptyset(&signew);
425192811Srmacklem	while (1)
426192811Srmacklem		sigsuspend(&signew);
427192811Srmacklem}
428192811Srmacklem
429192811Srmacklem/*
430192811Srmacklem * The nfsuserd rpc service
431192811Srmacklem */
432193070Sdelphijstatic void
433192811Srmacklemnfsuserdsrv(struct svc_req *rqstp, SVCXPRT *transp)
434192811Srmacklem{
435192811Srmacklem	struct passwd *pwd;
436192811Srmacklem	struct group *grp;
437192811Srmacklem	int error;
438192811Srmacklem	u_short sport;
439192811Srmacklem	struct info info;
440192811Srmacklem	struct nfsd_idargs nid;
441192811Srmacklem	u_int32_t saddr;
442192811Srmacklem
443192811Srmacklem	/*
444192811Srmacklem	 * Only handle requests from 127.0.0.1 on a reserved port number.
445192811Srmacklem	 * (Since a reserved port # at localhost implies a client with
446192811Srmacklem	 *  local root, there won't be a security breach. This is about
447192811Srmacklem	 *  the only case I can think of where a reserved port # means
448192811Srmacklem	 *  something.)
449192811Srmacklem	 */
450192811Srmacklem	sport = ntohs(transp->xp_raddr.sin_port);
451192811Srmacklem	saddr = ntohl(transp->xp_raddr.sin_addr.s_addr);
452192811Srmacklem	if ((rqstp->rq_proc != NULLPROC && sport >= IPPORT_RESERVED) ||
453192811Srmacklem	    saddr != 0x7f000001) {
454192811Srmacklem		syslog(LOG_ERR, "req from ip=0x%x port=%d\n", saddr, sport);
455192811Srmacklem		svcerr_weakauth(transp);
456192811Srmacklem		return;
457192811Srmacklem	}
458192811Srmacklem	switch (rqstp->rq_proc) {
459192811Srmacklem	case NULLPROC:
460192811Srmacklem		if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL))
461192811Srmacklem			syslog(LOG_ERR, "Can't send reply");
462192811Srmacklem		return;
463192811Srmacklem	case RPCNFSUSERD_GETUID:
464192811Srmacklem		if (!svc_getargs(transp, (xdrproc_t)xdr_getid,
465192811Srmacklem		    (caddr_t)&info)) {
466192811Srmacklem			svcerr_decode(transp);
467192811Srmacklem			return;
468192811Srmacklem		}
469192811Srmacklem		pwd = getpwuid((uid_t)info.id);
470192811Srmacklem		info.retval = 0;
471192811Srmacklem		if (pwd != NULL) {
472192811Srmacklem			nid.nid_usertimeout = defusertimeout;
473192811Srmacklem			nid.nid_uid = pwd->pw_uid;
474192811Srmacklem			nid.nid_name = pwd->pw_name;
475192811Srmacklem		} else {
476192811Srmacklem			nid.nid_usertimeout = 5;
477192811Srmacklem			nid.nid_uid = (uid_t)info.id;
478192811Srmacklem			nid.nid_name = defaultuser;
479192811Srmacklem		}
480192811Srmacklem		nid.nid_namelen = strlen(nid.nid_name);
481192811Srmacklem		nid.nid_flag = NFSID_ADDUID;
482192811Srmacklem		error = nfssvc(NFSSVC_IDNAME, &nid);
483192811Srmacklem		if (error) {
484192811Srmacklem			info.retval = error;
485192811Srmacklem			syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name);
486192811Srmacklem		} else if (verbose) {
487192811Srmacklem			syslog(LOG_ERR,"Added uid=%d name=%s\n",
488192811Srmacklem			    nid.nid_uid, nid.nid_name);
489192811Srmacklem		}
490192811Srmacklem		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
491192811Srmacklem		    (caddr_t)&info))
492192811Srmacklem			syslog(LOG_ERR, "Can't send reply");
493192811Srmacklem		return;
494192811Srmacklem	case RPCNFSUSERD_GETGID:
495192811Srmacklem		if (!svc_getargs(transp, (xdrproc_t)xdr_getid,
496192811Srmacklem		    (caddr_t)&info)) {
497192811Srmacklem			svcerr_decode(transp);
498192811Srmacklem			return;
499192811Srmacklem		}
500192811Srmacklem		grp = getgrgid((gid_t)info.id);
501192811Srmacklem		info.retval = 0;
502192811Srmacklem		if (grp != NULL) {
503192811Srmacklem			nid.nid_usertimeout = defusertimeout;
504192811Srmacklem			nid.nid_gid = grp->gr_gid;
505192811Srmacklem			nid.nid_name = grp->gr_name;
506192811Srmacklem		} else {
507192811Srmacklem			nid.nid_usertimeout = 5;
508192811Srmacklem			nid.nid_gid = (gid_t)info.id;
509192811Srmacklem			nid.nid_name = defaultgroup;
510192811Srmacklem		}
511192811Srmacklem		nid.nid_namelen = strlen(nid.nid_name);
512192811Srmacklem		nid.nid_flag = NFSID_ADDGID;
513192811Srmacklem		error = nfssvc(NFSSVC_IDNAME, &nid);
514192811Srmacklem		if (error) {
515192811Srmacklem			info.retval = error;
516192811Srmacklem			syslog(LOG_ERR, "Can't add group %s\n",
517192811Srmacklem			    grp->gr_name);
518192811Srmacklem		} else if (verbose) {
519192811Srmacklem			syslog(LOG_ERR,"Added gid=%d name=%s\n",
520192811Srmacklem			    nid.nid_gid, nid.nid_name);
521192811Srmacklem		}
522192811Srmacklem		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
523192811Srmacklem		    (caddr_t)&info))
524192811Srmacklem			syslog(LOG_ERR, "Can't send reply");
525192811Srmacklem		return;
526192811Srmacklem	case RPCNFSUSERD_GETUSER:
527192811Srmacklem		if (!svc_getargs(transp, (xdrproc_t)xdr_getname,
528192811Srmacklem		    (caddr_t)&info)) {
529192811Srmacklem			svcerr_decode(transp);
530192811Srmacklem			return;
531192811Srmacklem		}
532192811Srmacklem		pwd = getpwnam(info.name);
533192811Srmacklem		info.retval = 0;
534192811Srmacklem		if (pwd != NULL) {
535192811Srmacklem			nid.nid_usertimeout = defusertimeout;
536192811Srmacklem			nid.nid_uid = pwd->pw_uid;
537192811Srmacklem			nid.nid_name = pwd->pw_name;
538192811Srmacklem		} else {
539192811Srmacklem			nid.nid_usertimeout = 5;
540192811Srmacklem			nid.nid_uid = defaultuid;
541192811Srmacklem			nid.nid_name = info.name;
542192811Srmacklem		}
543192811Srmacklem		nid.nid_namelen = strlen(nid.nid_name);
544192811Srmacklem		nid.nid_flag = NFSID_ADDUSERNAME;
545192811Srmacklem		error = nfssvc(NFSSVC_IDNAME, &nid);
546192811Srmacklem		if (error) {
547192811Srmacklem			info.retval = error;
548192811Srmacklem			syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name);
549192811Srmacklem		} else if (verbose) {
550192811Srmacklem			syslog(LOG_ERR,"Added uid=%d name=%s\n",
551192811Srmacklem			    nid.nid_uid, nid.nid_name);
552192811Srmacklem		}
553192811Srmacklem		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
554192811Srmacklem		    (caddr_t)&info))
555192811Srmacklem			syslog(LOG_ERR, "Can't send reply");
556192811Srmacklem		return;
557192811Srmacklem	case RPCNFSUSERD_GETGROUP:
558192811Srmacklem		if (!svc_getargs(transp, (xdrproc_t)xdr_getname,
559192811Srmacklem		    (caddr_t)&info)) {
560192811Srmacklem			svcerr_decode(transp);
561192811Srmacklem			return;
562192811Srmacklem		}
563192811Srmacklem		grp = getgrnam(info.name);
564192811Srmacklem		info.retval = 0;
565192811Srmacklem		if (grp != NULL) {
566192811Srmacklem			nid.nid_usertimeout = defusertimeout;
567192811Srmacklem			nid.nid_gid = grp->gr_gid;
568192811Srmacklem			nid.nid_name = grp->gr_name;
569192811Srmacklem		} else {
570192811Srmacklem			nid.nid_usertimeout = 5;
571192811Srmacklem			nid.nid_gid = defaultgid;
572192811Srmacklem			nid.nid_name = info.name;
573192811Srmacklem		}
574192811Srmacklem		nid.nid_namelen = strlen(nid.nid_name);
575192811Srmacklem		nid.nid_flag = NFSID_ADDGROUPNAME;
576192811Srmacklem		error = nfssvc(NFSSVC_IDNAME, &nid);
577192811Srmacklem		if (error) {
578192811Srmacklem			info.retval = error;
579192811Srmacklem			syslog(LOG_ERR, "Can't add group %s\n",
580192811Srmacklem			    grp->gr_name);
581192811Srmacklem		} else if (verbose) {
582192811Srmacklem			syslog(LOG_ERR,"Added gid=%d name=%s\n",
583192811Srmacklem			    nid.nid_gid, nid.nid_name);
584192811Srmacklem		}
585192811Srmacklem		if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
586192811Srmacklem		    (caddr_t)&info))
587192811Srmacklem			syslog(LOG_ERR, "Can't send reply");
588192811Srmacklem		return;
589192811Srmacklem	default:
590192811Srmacklem		svcerr_noproc(transp);
591192811Srmacklem		return;
592192811Srmacklem	};
593192811Srmacklem}
594192811Srmacklem
595192811Srmacklem/*
596192811Srmacklem * Xdr routine to get an id number
597192811Srmacklem */
598193070Sdelphijstatic bool_t
599192811Srmacklemxdr_getid(XDR *xdrsp, caddr_t cp)
600192811Srmacklem{
601192811Srmacklem	struct info *ifp = (struct info *)cp;
602192811Srmacklem
603192811Srmacklem	return (xdr_long(xdrsp, &ifp->id));
604192811Srmacklem}
605192811Srmacklem
606192811Srmacklem/*
607192811Srmacklem * Xdr routine to get a user name
608192811Srmacklem */
609193070Sdelphijstatic bool_t
610192811Srmacklemxdr_getname(XDR *xdrsp, caddr_t cp)
611192811Srmacklem{
612192811Srmacklem	struct info *ifp = (struct info *)cp;
613192811Srmacklem	long len;
614192811Srmacklem
615192811Srmacklem	if (!xdr_long(xdrsp, &len))
616192811Srmacklem		return (0);
617192811Srmacklem	if (len > MAXNAME)
618192811Srmacklem		return (0);
619192811Srmacklem	if (!xdr_opaque(xdrsp, ifp->name, len))
620192811Srmacklem		return (0);
621192811Srmacklem	ifp->name[len] = '\0';
622192811Srmacklem	return (1);
623192811Srmacklem}
624192811Srmacklem
625192811Srmacklem/*
626192811Srmacklem * Xdr routine to return the value.
627192811Srmacklem */
628193070Sdelphijstatic bool_t
629192811Srmacklemxdr_retval(XDR *xdrsp, caddr_t cp)
630192811Srmacklem{
631192811Srmacklem	struct info *ifp = (struct info *)cp;
632192811Srmacklem	long val;
633192811Srmacklem
634192811Srmacklem	val = ifp->retval;
635192811Srmacklem	return (xdr_long(xdrsp, &val));
636192811Srmacklem}
637192811Srmacklem
638192811Srmacklem/*
639192811Srmacklem * cleanup_term() called via SIGUSR1.
640192811Srmacklem */
641193070Sdelphijstatic void
642193070Sdelphijcleanup_term(int signo __unused)
643192811Srmacklem{
644192811Srmacklem	int i, cnt;
645192811Srmacklem
646192811Srmacklem	if (im_a_slave)
647192811Srmacklem		exit(0);
648192811Srmacklem
649192811Srmacklem	/*
650192811Srmacklem	 * Ok, so I'm the master.
651192811Srmacklem	 * As the Governor of California might say, "Terminate them".
652192811Srmacklem	 */
653192811Srmacklem	cnt = 0;
654192811Srmacklem	for (i = 0; i < nfsuserdcnt; i++) {
655192811Srmacklem		if (slaves[i] != (pid_t)-1) {
656192811Srmacklem			cnt++;
657192811Srmacklem			kill(slaves[i], SIGUSR1);
658192811Srmacklem		}
659192811Srmacklem	}
660192811Srmacklem
661192811Srmacklem	/*
662192811Srmacklem	 * and wait for them to die
663192811Srmacklem	 */
664192811Srmacklem	for (i = 0; i < cnt; i++)
665192811Srmacklem		wait3(NULL, 0, NULL);
666192811Srmacklem
667192811Srmacklem	/*
668192811Srmacklem	 * Finally, get rid of the socket
669192811Srmacklem	 */
670192811Srmacklem	if (nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0) {
671192811Srmacklem		syslog(LOG_ERR, "Can't do nfssvc() to delete the port\n");
672192811Srmacklem		exit(1);
673192811Srmacklem	}
674192811Srmacklem	exit(0);
675192811Srmacklem}
676192811Srmacklem
677193070Sdelphijstatic void
678192811Srmacklemusage(void)
679192811Srmacklem{
680192811Srmacklem
681192811Srmacklem	errx(1,
682192811Srmacklem	    "usage: nfsuserd [-usermax cache_size] [-usertimeout minutes] [-verbose] [-domain domain_name] [n]");
683192811Srmacklem}
684