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>
40 #include <sys/ucred.h>
41 #include <sys/vnode.h>
44 #include <nfs/nfssvc.h>
47 #include <rpc/rpc_com.h>
49 #include <fs/nfs/rpcv2.h>
50 #include <fs/nfs/nfsproto.h>
51 #include <fs/nfs/nfskpiport.h>
52 #include <fs/nfs/nfs.h>
67 * This program loads the password and group databases into the kernel
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);
78 #ifndef _PATH_NFSUSERDSOCK
79 #define _PATH_NFSUSERDSOCK "/var/run/nfsuserd.sock"
82 #define MAXNFSUSERD 20
84 #define MAXUSERMAX 100000
86 #define DEFUSERMAX 200
87 #define DEFUSERTIMEOUT (1 * 60)
91 char name[MAXNAME + 1];
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;
101 int defusertimeout = DEFUSERTIMEOUT, manage_gids = 0;
102 pid_t slaves[MAXNFSUSERD];
105 main(int argc, char *argv[])
108 int error, fnd_dup, len, mustfreeai = 0, start_uidpos;
109 struct nfsd_idargs nid;
112 int oldmask, one = 1, sock;
117 char hostname[MAXHOSTNAMELEN + 1], *cp;
118 struct addrinfo *aip, hints;
119 static uid_t check_dups[MAXUSERMAX];
122 struct sockaddr_un sun;
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");
132 * First, figure out what our domain name and Kerberos Realm
133 * seem to be. Command line args may override these later.
135 if (gethostname(hostname, MAXHOSTNAMELEN) == 0) {
136 if ((cp = strchr(hostname, '.')) != NULL &&
140 memset((void *)&hints, 0, sizeof (hints));
141 hints.ai_flags = AI_CANONNAME;
142 error = getaddrinfo(hostname, NULL, &hints, &aip);
144 if (aip->ai_canonname != NULL &&
145 (cp = strchr(aip->ai_canonname, '.')) != NULL
146 && *(cp + 1) != '\0') {
155 nid.nid_usermax = DEFUSERMAX;
156 nid.nid_usertimeout = defusertimeout;
161 if (!strcmp(*argv, "-domain")) {
166 strncpy(hostname, *argv, MAXHOSTNAMELEN);
167 hostname[MAXHOSTNAMELEN] = '\0';
169 } else if (!strcmp(*argv, "-verbose")) {
171 } else if (!strcmp(*argv, "-force")) {
173 } else if (!strcmp(*argv, "-manage-gids")) {
175 } else if (!strcmp(*argv, "-use-udpsock")) {
177 } else if (!strcmp(*argv, "-usermax")) {
183 if (i < MINUSERMAX || i > MAXUSERMAX) {
185 "usermax %d out of range %d<->%d\n", i,
186 MINUSERMAX, MAXUSERMAX);
190 } else if (!strcmp(*argv, "-usertimeout")) {
196 if (i < 0 || i > 100000) {
198 "usertimeout %d out of range 0<->100000\n",
202 nid.nid_usertimeout = defusertimeout = i * 60;
203 } else if (nfsuserdcnt == -1) {
204 nfsuserdcnt = atoi(*argv);
207 if (nfsuserdcnt > MAXNFSUSERD) {
208 warnx("nfsuserd count %d; reset to %d",
209 nfsuserdcnt, DEFNFSUSERD);
210 nfsuserdcnt = DEFNFSUSERD;
219 nfsuserdcnt = DEFNFSUSERD;
220 if (use_udpsock == 0)
221 /* For AF_LOCAL socket, only allow one server daemon. */
225 * Strip off leading and trailing '.'s in domain name and map
226 * alphabetics to lower case.
228 while (*dnsname == '.')
230 if (*dnsname == '\0')
231 errx(1, "Domain name all '.'");
232 len = strlen(dnsname);
233 cp = dnsname + len - 1;
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]);
247 * If the nfsuserd died off ungracefully, this is necessary to
248 * get them to start again.
250 if (forcestart && nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0)
251 errx(1, "Can't do nfssvc() to delete the port");
255 "nfsuserd: domain=%s usermax=%d usertimeout=%d\n",
256 dnsname, nid.nid_usermax, nid.nid_usertimeout);
258 for (i = 0; i < nfsuserdcnt; i++)
259 slaves[i] = (pid_t)-1;
261 if (use_udpsock != 0) {
263 * Set up the service port to accept requests via UDP from
264 * localhost (127.0.0.1).
266 if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
267 err(1, "cannot create udp socket");
270 * Not sure what this does, so I'll leave it here for now.
272 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
274 if ((udptransp = svcudp_create(sock)) == NULL)
275 err(1, "Can't set up socket");
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.
282 if (!svc_register(udptransp, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS,
284 err(1, "Can't register nfsuserd");
287 * Tell the kernel what my port# is.
289 portnum = htons(udptransp->xp_port);
291 printf("portnum=0x%x\n", portnum);
293 if (nfssvc(NFSSVC_NFSUSERDPORT, (caddr_t)&portnum) < 0) {
295 fprintf(stderr, "Can't start nfsuserd when"
296 " already running\nIf not running,"
297 " use the -force option.\n");
300 "Can't do nfssvc() to add socket\n");
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);
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");
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);
323 "Can't create transport for local nfsuserd socket");
324 if (!svc_reg(xprt, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS,
327 "Can't register service for local nfsuserd socket");
330 * Tell the kernel what the socket's path is.
333 printf("sockpath=%s\n", _PATH_NFSUSERDSOCK);
335 if (nfssvc(NFSSVC_NFSUSERDPORT | NFSSVC_NEWSTRUCT,
336 _PATH_NFSUSERDSOCK) < 0) {
338 fprintf(stderr, "Can't start nfsuserd when"
339 " already running\nIf not running,"
340 " use the -force option.\n");
343 "Can't do nfssvc() to add socket\n");
349 pwd = getpwnam(defaultuser);
351 nid.nid_uid = pwd->pw_uid;
353 nid.nid_uid = defaultuid;
354 grp = getgrnam(defaultgroup);
356 nid.nid_gid = grp->gr_gid;
358 nid.nid_gid = defaultgid;
359 nid.nid_name = dnsname;
360 nid.nid_namelen = strlen(nid.nid_name);
363 nid.nid_flag = NFSID_INITIALIZE;
365 printf("Initialize uid=%d gid=%d dns=%s\n", nid.nid_uid, nid.nid_gid,
368 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
370 errx(1, "Can't initialize nfs user/groups");
375 * Loop around adding all groups.
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);
384 nid.nid_flag = NFSID_ADDGID;
386 printf("add gid=%d name=%s\n", nid.nid_gid, nid.nid_name);
388 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
390 errx(1, "Can't add group %s", grp->gr_name);
396 * Loop around adding all users.
400 while (i < nid.nid_usermax && (pwd = getpwent())) {
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.
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 */
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. */
423 if (getgrouplist(pwd->pw_name, pwd->pw_gid, grps,
425 syslog(LOG_ERR, "Group list too small");
426 nid.nid_ngroup = ngroup;
432 nid.nid_flag = NFSID_ADDUID;
434 printf("add uid=%d name=%s\n", nid.nid_uid, nid.nid_name);
436 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
438 errx(1, "Can't add user %s", pwd->pw_name);
444 * I should feel guilty for not calling this for all the above exit()
445 * upon error cases, but I don't.
454 * Temporarily block SIGUSR1 and SIGCHLD, so slaves[] can't
457 sigemptyset(&signew);
458 sigaddset(&signew, SIGUSR1);
459 sigaddset(&signew, SIGCHLD);
460 sigprocmask(SIG_BLOCK, &signew, NULL);
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);
470 openlog("nfsuserd:", LOG_PID, LOG_DAEMON);
473 * Fork off the slave daemons that do the work. All the master
474 * does is kill them off and cleanup.
476 for (i = 0; i < nfsuserdcnt; i++) {
478 if (slaves[i] == 0) {
480 setproctitle("slave");
481 sigemptyset(&signew);
482 sigaddset(&signew, SIGUSR1);
483 sigprocmask(SIG_UNBLOCK, &signew, NULL);
489 syslog(LOG_ERR, "nfsuserd died: %m");
491 } else if (slaves[i] < 0) {
492 syslog(LOG_ERR, "fork: %m");
497 * Just wait for SIGUSR1 or a child to die and then...
498 * As the Governor of California would say, "Terminate them".
500 setproctitle("master");
501 sigemptyset(&signew);
507 * The nfsuserd rpc service
510 nfsuserdsrv(struct svc_req *rqstp, SVCXPRT *transp)
517 struct nfsd_idargs nid;
522 if (use_udpsock != 0) {
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.)
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);
541 switch (rqstp->rq_proc) {
543 if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL))
544 syslog(LOG_ERR, "Can't send reply");
546 case RPCNFSUSERD_GETUID:
547 if (!svc_getargs(transp, (xdrproc_t)xdr_getid,
549 svcerr_decode(transp);
552 pwd = getpwuid((uid_t)info.id);
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. */
561 if (getgrouplist(pwd->pw_name, pwd->pw_gid,
563 syslog(LOG_ERR, "Group list too small");
564 nid.nid_ngroup = ngroup;
571 nid.nid_usertimeout = 5;
572 nid.nid_uid = (uid_t)info.id;
573 nid.nid_name = defaultuser;
577 nid.nid_namelen = strlen(nid.nid_name);
578 nid.nid_flag = NFSID_ADDUID;
579 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
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);
587 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
589 syslog(LOG_ERR, "Can't send reply");
591 case RPCNFSUSERD_GETGID:
592 if (!svc_getargs(transp, (xdrproc_t)xdr_getid,
594 svcerr_decode(transp);
597 grp = getgrgid((gid_t)info.id);
600 nid.nid_usertimeout = defusertimeout;
601 nid.nid_gid = grp->gr_gid;
602 nid.nid_name = grp->gr_name;
604 nid.nid_usertimeout = 5;
605 nid.nid_gid = (gid_t)info.id;
606 nid.nid_name = defaultgroup;
608 nid.nid_namelen = strlen(nid.nid_name);
611 nid.nid_flag = NFSID_ADDGID;
612 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
615 syslog(LOG_ERR, "Can't add group %s\n",
617 } else if (verbose) {
618 syslog(LOG_ERR,"Added gid=%d name=%s\n",
619 nid.nid_gid, nid.nid_name);
621 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
623 syslog(LOG_ERR, "Can't send reply");
625 case RPCNFSUSERD_GETUSER:
626 if (!svc_getargs(transp, (xdrproc_t)xdr_getname,
628 svcerr_decode(transp);
631 pwd = getpwnam(info.name);
634 nid.nid_usertimeout = defusertimeout;
635 nid.nid_uid = pwd->pw_uid;
636 nid.nid_name = pwd->pw_name;
638 nid.nid_usertimeout = 5;
639 nid.nid_uid = defaultuid;
640 nid.nid_name = info.name;
642 nid.nid_namelen = strlen(nid.nid_name);
645 nid.nid_flag = NFSID_ADDUSERNAME;
646 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
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);
654 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
656 syslog(LOG_ERR, "Can't send reply");
658 case RPCNFSUSERD_GETGROUP:
659 if (!svc_getargs(transp, (xdrproc_t)xdr_getname,
661 svcerr_decode(transp);
664 grp = getgrnam(info.name);
667 nid.nid_usertimeout = defusertimeout;
668 nid.nid_gid = grp->gr_gid;
669 nid.nid_name = grp->gr_name;
671 nid.nid_usertimeout = 5;
672 nid.nid_gid = defaultgid;
673 nid.nid_name = info.name;
675 nid.nid_namelen = strlen(nid.nid_name);
678 nid.nid_flag = NFSID_ADDGROUPNAME;
679 error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
682 syslog(LOG_ERR, "Can't add group %s\n",
684 } else if (verbose) {
685 syslog(LOG_ERR,"Added gid=%d name=%s\n",
686 nid.nid_gid, nid.nid_name);
688 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
690 syslog(LOG_ERR, "Can't send reply");
693 svcerr_noproc(transp);
699 * Xdr routine to get an id number
702 xdr_getid(XDR *xdrsp, caddr_t cp)
704 struct info *ifp = (struct info *)cp;
706 return (xdr_long(xdrsp, &ifp->id));
710 * Xdr routine to get a user name
713 xdr_getname(XDR *xdrsp, caddr_t cp)
715 struct info *ifp = (struct info *)cp;
718 if (!xdr_long(xdrsp, &len))
722 if (!xdr_opaque(xdrsp, ifp->name, len))
724 ifp->name[len] = '\0';
729 * Xdr routine to return the value.
732 xdr_retval(XDR *xdrsp, caddr_t cp)
734 struct info *ifp = (struct info *)cp;
738 return (xdr_long(xdrsp, &val));
742 * cleanup_term() called via SIGUSR1.
745 cleanup_term(int signo __unused)
753 * Ok, so I'm the master.
754 * As the Governor of California might say, "Terminate them".
757 for (i = 0; i < nfsuserdcnt; i++) {
758 if (slaves[i] != (pid_t)-1) {
760 kill(slaves[i], SIGUSR1);
765 * and wait for them to die
767 for (i = 0; i < cnt; i++)
768 wait3(NULL, 0, NULL);
771 * Finally, get rid of the socket
773 if (nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0) {
774 syslog(LOG_ERR, "Can't do nfssvc() to delete the port\n");
784 errx(1, "usage: nfsuserd [-usermax cache_size] [-usertimeout minutes]"
785 " [-verbose] [-manage-gids] [-use-udpsock] [-domain domain_name]"