2 * Copyright (c) 2009 Rick Macklem, University of Guelph
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
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>
39 #include <sys/ucred.h>
40 #include <sys/vnode.h>
43 #include <nfs/nfssvc.h>
47 #include <fs/nfs/rpcv2.h>
48 #include <fs/nfs/nfsproto.h>
49 #include <fs/nfs/nfskpiport.h>
50 #include <fs/nfs/nfs.h>
65 * This program loads the password and group databases into the kernel
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);
77 #define MAXNFSUSERD 20
79 #define MAXUSERMAX 100000
81 #define DEFUSERMAX 200
82 #define DEFUSERTIMEOUT (1 * 60)
86 char name[MAXNAME + 1];
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, manage_gids = 0;
96 pid_t slaves[MAXNFSUSERD];
99 main(int argc, char *argv[])
102 int error, fnd_dup, len, mustfreeai = 0, start_uidpos;
103 struct nfsd_idargs nid;
110 char hostname[MAXHOSTNAMELEN + 1], *cp;
111 struct addrinfo *aip, hints;
112 static uid_t check_dups[MAXUSERMAX];
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");
124 * First, figure out what our domain name and Kerberos Realm
125 * seem to be. Command line args may override these later.
127 if (gethostname(hostname, MAXHOSTNAMELEN) == 0) {
128 if ((cp = strchr(hostname, '.')) != NULL &&
132 memset((void *)&hints, 0, sizeof (hints));
133 hints.ai_flags = AI_CANONNAME;
134 error = getaddrinfo(hostname, NULL, &hints, &aip);
136 if (aip->ai_canonname != NULL &&
137 (cp = strchr(aip->ai_canonname, '.')) != NULL
138 && *(cp + 1) != '\0') {
147 nid.nid_usermax = DEFUSERMAX;
148 nid.nid_usertimeout = defusertimeout;
153 if (!strcmp(*argv, "-domain")) {
158 strncpy(hostname, *argv, MAXHOSTNAMELEN);
159 hostname[MAXHOSTNAMELEN] = '\0';
161 } else if (!strcmp(*argv, "-verbose")) {
163 } else if (!strcmp(*argv, "-force")) {
165 } else if (!strcmp(*argv, "-manage-gids")) {
167 } else if (!strcmp(*argv, "-usermax")) {
173 if (i < MINUSERMAX || i > MAXUSERMAX) {
175 "usermax %d out of range %d<->%d\n", i,
176 MINUSERMAX, MAXUSERMAX);
180 } else if (!strcmp(*argv, "-usertimeout")) {
186 if (i < 0 || i > 100000) {
188 "usertimeout %d out of range 0<->100000\n",
192 nid.nid_usertimeout = defusertimeout = i * 60;
193 } else if (nfsuserdcnt == -1) {
194 nfsuserdcnt = atoi(*argv);
197 if (nfsuserdcnt > MAXNFSUSERD) {
198 warnx("nfsuserd count %d; reset to %d",
199 nfsuserdcnt, DEFNFSUSERD);
200 nfsuserdcnt = DEFNFSUSERD;
209 nfsuserdcnt = DEFNFSUSERD;
212 * Strip off leading and trailing '.'s in domain name and map
213 * alphabetics to lower case.
215 while (*dnsname == '.')
217 if (*dnsname == '\0')
218 errx(1, "Domain name all '.'");
219 len = strlen(dnsname);
220 cp = dnsname + len - 1;
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]);
234 * If the nfsuserd died off ungracefully, this is necessary to
235 * get them to start again.
237 if (forcestart && nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0)
238 errx(1, "Can't do nfssvc() to delete the port");
242 "nfsuserd: domain=%s usermax=%d usertimeout=%d\n",
243 dnsname, nid.nid_usermax, nid.nid_usertimeout);
245 for (i = 0; i < nfsuserdcnt; i++)
246 slaves[i] = (pid_t)-1;
249 * Set up the service port to accept requests via UDP from
250 * localhost (127.0.0.1).
252 if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
253 err(1, "cannot create udp socket");
256 * Not sure what this does, so I'll leave it here for now.
258 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
260 if ((udptransp = svcudp_create(sock)) == NULL)
261 err(1, "Can't set up socket");
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.
268 if (!svc_register(udptransp, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS,
270 err(1, "Can't register nfsuserd");
273 * Tell the kernel what my port# is.
275 portnum = htons(udptransp->xp_port);
277 printf("portnum=0x%x\n", portnum);
279 if (nfssvc(NFSSVC_NFSUSERDPORT, (caddr_t)&portnum) < 0) {
280 if (errno == EPERM) {
282 "Can't start nfsuserd when already running");
284 " If not running, use the -force option.\n");
286 fprintf(stderr, "Can't do nfssvc() to add port\n");
292 pwd = getpwnam(defaultuser);
294 nid.nid_uid = pwd->pw_uid;
296 nid.nid_uid = defaultuid;
297 grp = getgrnam(defaultgroup);
299 nid.nid_gid = grp->gr_gid;
301 nid.nid_gid = defaultgid;
302 nid.nid_name = dnsname;
303 nid.nid_namelen = strlen(nid.nid_name);
306 nid.nid_flag = NFSID_INITIALIZE;
308 printf("Initialize uid=%d gid=%d dns=%s\n", nid.nid_uid, nid.nid_gid,
311 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
313 errx(1, "Can't initialize nfs user/groups");
318 * Loop around adding all groups.
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);
327 nid.nid_flag = NFSID_ADDGID;
329 printf("add gid=%d name=%s\n", nid.nid_gid, nid.nid_name);
331 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
333 errx(1, "Can't add group %s", grp->gr_name);
339 * Loop around adding all users.
343 while (i < nid.nid_usermax && (pwd = getpwent())) {
346 * Yes, this is inefficient, but it is only done once when
347 * the daemon is started and will run in a fraction of a second
348 * for nid_usermax at 10000. If nid_usermax is cranked up to
349 * 100000, it will take several seconds, depending on the CPU.
351 for (j = 0; j < (i - start_uidpos); j++)
352 if (check_dups[j] == pwd->pw_uid) {
353 /* Found another entry for uid, so skip it */
359 check_dups[i - start_uidpos] = pwd->pw_uid;
360 nid.nid_uid = pwd->pw_uid;
361 nid.nid_name = pwd->pw_name;
362 nid.nid_namelen = strlen(pwd->pw_name);
363 if (manage_gids != 0) {
364 /* Get the group list for this user. */
366 if (getgrouplist(pwd->pw_name, pwd->pw_gid, grps,
368 syslog(LOG_ERR, "Group list too small");
369 nid.nid_ngroup = ngroup;
375 nid.nid_flag = NFSID_ADDUID;
377 printf("add uid=%d name=%s\n", nid.nid_uid, nid.nid_name);
379 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
381 errx(1, "Can't add user %s", pwd->pw_name);
387 * I should feel guilty for not calling this for all the above exit()
388 * upon error cases, but I don't.
397 * Temporarily block SIGUSR1 and SIGCHLD, so slaves[] can't
400 sigemptyset(&signew);
401 sigaddset(&signew, SIGUSR1);
402 sigaddset(&signew, SIGCHLD);
403 sigprocmask(SIG_BLOCK, &signew, NULL);
406 (void)signal(SIGHUP, SIG_IGN);
407 (void)signal(SIGINT, SIG_IGN);
408 (void)signal(SIGQUIT, SIG_IGN);
409 (void)signal(SIGTERM, SIG_IGN);
410 (void)signal(SIGUSR1, cleanup_term);
411 (void)signal(SIGCHLD, cleanup_term);
413 openlog("nfsuserd:", LOG_PID, LOG_DAEMON);
416 * Fork off the slave daemons that do the work. All the master
417 * does is kill them off and cleanup.
419 for (i = 0; i < nfsuserdcnt; i++) {
421 if (slaves[i] == 0) {
423 setproctitle("slave");
424 sigemptyset(&signew);
425 sigaddset(&signew, SIGUSR1);
426 sigprocmask(SIG_UNBLOCK, &signew, NULL);
432 syslog(LOG_ERR, "nfsuserd died: %m");
434 } else if (slaves[i] < 0) {
435 syslog(LOG_ERR, "fork: %m");
440 * Just wait for SIGUSR1 or a child to die and then...
441 * As the Governor of California would say, "Terminate them".
443 setproctitle("master");
444 sigemptyset(&signew);
450 * The nfsuserd rpc service
453 nfsuserdsrv(struct svc_req *rqstp, SVCXPRT *transp)
460 struct nfsd_idargs nid;
466 * Only handle requests from 127.0.0.1 on a reserved port number.
467 * (Since a reserved port # at localhost implies a client with
468 * local root, there won't be a security breach. This is about
469 * the only case I can think of where a reserved port # means
472 sport = ntohs(transp->xp_raddr.sin_port);
473 saddr = ntohl(transp->xp_raddr.sin_addr.s_addr);
474 if ((rqstp->rq_proc != NULLPROC && sport >= IPPORT_RESERVED) ||
475 saddr != 0x7f000001) {
476 syslog(LOG_ERR, "req from ip=0x%x port=%d\n", saddr, sport);
477 svcerr_weakauth(transp);
480 switch (rqstp->rq_proc) {
482 if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL))
483 syslog(LOG_ERR, "Can't send reply");
485 case RPCNFSUSERD_GETUID:
486 if (!svc_getargs(transp, (xdrproc_t)xdr_getid,
488 svcerr_decode(transp);
491 pwd = getpwuid((uid_t)info.id);
494 nid.nid_usertimeout = defusertimeout;
495 nid.nid_uid = pwd->pw_uid;
496 nid.nid_name = pwd->pw_name;
497 if (manage_gids != 0) {
498 /* Get the group list for this user. */
500 if (getgrouplist(pwd->pw_name, pwd->pw_gid,
502 syslog(LOG_ERR, "Group list too small");
503 nid.nid_ngroup = ngroup;
510 nid.nid_usertimeout = 5;
511 nid.nid_uid = (uid_t)info.id;
512 nid.nid_name = defaultuser;
516 nid.nid_namelen = strlen(nid.nid_name);
517 nid.nid_flag = NFSID_ADDUID;
518 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
521 syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name);
522 } else if (verbose) {
523 syslog(LOG_ERR,"Added uid=%d name=%s\n",
524 nid.nid_uid, nid.nid_name);
526 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
528 syslog(LOG_ERR, "Can't send reply");
530 case RPCNFSUSERD_GETGID:
531 if (!svc_getargs(transp, (xdrproc_t)xdr_getid,
533 svcerr_decode(transp);
536 grp = getgrgid((gid_t)info.id);
539 nid.nid_usertimeout = defusertimeout;
540 nid.nid_gid = grp->gr_gid;
541 nid.nid_name = grp->gr_name;
543 nid.nid_usertimeout = 5;
544 nid.nid_gid = (gid_t)info.id;
545 nid.nid_name = defaultgroup;
547 nid.nid_namelen = strlen(nid.nid_name);
550 nid.nid_flag = NFSID_ADDGID;
551 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
554 syslog(LOG_ERR, "Can't add group %s\n",
556 } else if (verbose) {
557 syslog(LOG_ERR,"Added gid=%d name=%s\n",
558 nid.nid_gid, nid.nid_name);
560 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
562 syslog(LOG_ERR, "Can't send reply");
564 case RPCNFSUSERD_GETUSER:
565 if (!svc_getargs(transp, (xdrproc_t)xdr_getname,
567 svcerr_decode(transp);
570 pwd = getpwnam(info.name);
573 nid.nid_usertimeout = defusertimeout;
574 nid.nid_uid = pwd->pw_uid;
575 nid.nid_name = pwd->pw_name;
577 nid.nid_usertimeout = 5;
578 nid.nid_uid = defaultuid;
579 nid.nid_name = info.name;
581 nid.nid_namelen = strlen(nid.nid_name);
584 nid.nid_flag = NFSID_ADDUSERNAME;
585 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
588 syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name);
589 } else if (verbose) {
590 syslog(LOG_ERR,"Added uid=%d name=%s\n",
591 nid.nid_uid, nid.nid_name);
593 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
595 syslog(LOG_ERR, "Can't send reply");
597 case RPCNFSUSERD_GETGROUP:
598 if (!svc_getargs(transp, (xdrproc_t)xdr_getname,
600 svcerr_decode(transp);
603 grp = getgrnam(info.name);
606 nid.nid_usertimeout = defusertimeout;
607 nid.nid_gid = grp->gr_gid;
608 nid.nid_name = grp->gr_name;
610 nid.nid_usertimeout = 5;
611 nid.nid_gid = defaultgid;
612 nid.nid_name = info.name;
614 nid.nid_namelen = strlen(nid.nid_name);
617 nid.nid_flag = NFSID_ADDGROUPNAME;
618 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
621 syslog(LOG_ERR, "Can't add group %s\n",
623 } else if (verbose) {
624 syslog(LOG_ERR,"Added gid=%d name=%s\n",
625 nid.nid_gid, nid.nid_name);
627 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
629 syslog(LOG_ERR, "Can't send reply");
632 svcerr_noproc(transp);
638 * Xdr routine to get an id number
641 xdr_getid(XDR *xdrsp, caddr_t cp)
643 struct info *ifp = (struct info *)cp;
645 return (xdr_long(xdrsp, &ifp->id));
649 * Xdr routine to get a user name
652 xdr_getname(XDR *xdrsp, caddr_t cp)
654 struct info *ifp = (struct info *)cp;
657 if (!xdr_long(xdrsp, &len))
661 if (!xdr_opaque(xdrsp, ifp->name, len))
663 ifp->name[len] = '\0';
668 * Xdr routine to return the value.
671 xdr_retval(XDR *xdrsp, caddr_t cp)
673 struct info *ifp = (struct info *)cp;
677 return (xdr_long(xdrsp, &val));
681 * cleanup_term() called via SIGUSR1.
684 cleanup_term(int signo __unused)
692 * Ok, so I'm the master.
693 * As the Governor of California might say, "Terminate them".
696 for (i = 0; i < nfsuserdcnt; i++) {
697 if (slaves[i] != (pid_t)-1) {
699 kill(slaves[i], SIGUSR1);
704 * and wait for them to die
706 for (i = 0; i < cnt; i++)
707 wait3(NULL, 0, NULL);
710 * Finally, get rid of the socket
712 if (nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0) {
713 syslog(LOG_ERR, "Can't do nfssvc() to delete the port\n");
724 "usage: nfsuserd [-usermax cache_size] [-usertimeout minutes] [-verbose] [-manage-gids] [-domain domain_name] [n]");