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 DEFUSERMAX 200
80 #define DEFUSERTIMEOUT (1 * 60)
84 char name[MAXNAME + 1];
87 u_char *dnsname = "default.domain";
88 u_char *defaultuser = "nobody";
89 uid_t defaultuid = (uid_t)32767;
90 u_char *defaultgroup = "nogroup";
91 gid_t defaultgid = (gid_t)32767;
92 int verbose = 0, im_a_slave = 0, nfsuserdcnt = -1, forcestart = 0;
93 int defusertimeout = DEFUSERTIMEOUT;
94 pid_t slaves[MAXNFSUSERD];
97 main(int argc, char *argv[])
100 int error, len, mustfreeai = 0;
101 struct nfsd_idargs nid;
108 char hostname[MAXHOSTNAMELEN + 1], *cp;
109 struct addrinfo *aip, hints;
111 if (modfind("nfscommon") < 0) {
112 /* Not present in kernel, try loading it */
113 if (kldload("nfscommon") < 0 ||
114 modfind("nfscommon") < 0)
115 errx(1, "Experimental nfs subsystem is not available");
119 * First, figure out what our domain name and Kerberos Realm
120 * seem to be. Command line args may override these later.
122 if (gethostname(hostname, MAXHOSTNAMELEN) == 0) {
123 if ((cp = strchr(hostname, '.')) != NULL &&
127 memset((void *)&hints, 0, sizeof (hints));
128 hints.ai_flags = AI_CANONNAME;
129 error = getaddrinfo(hostname, NULL, &hints, &aip);
131 if (aip->ai_canonname != NULL &&
132 (cp = strchr(aip->ai_canonname, '.')) != NULL
133 && *(cp + 1) != '\0') {
142 nid.nid_usermax = DEFUSERMAX;
143 nid.nid_usertimeout = defusertimeout;
148 if (!strcmp(*argv, "-domain")) {
153 strncpy(hostname, *argv, MAXHOSTNAMELEN);
154 hostname[MAXHOSTNAMELEN] = '\0';
156 } else if (!strcmp(*argv, "-verbose")) {
158 } else if (!strcmp(*argv, "-force")) {
160 } else if (!strcmp(*argv, "-usermax")) {
166 if (i < 10 || i > 100000) {
168 "usermax %d out of range 10<->100000\n", i);
172 } else if (!strcmp(*argv, "-usertimeout")) {
178 if (i < 0 || i > 100000) {
180 "usertimeout %d out of range 0<->100000\n",
184 nid.nid_usertimeout = defusertimeout = i * 60;
185 } else if (nfsuserdcnt == -1) {
186 nfsuserdcnt = atoi(*argv);
189 if (nfsuserdcnt > MAXNFSUSERD) {
190 warnx("nfsuserd count %d; reset to %d",
191 nfsuserdcnt, DEFNFSUSERD);
192 nfsuserdcnt = DEFNFSUSERD;
201 nfsuserdcnt = DEFNFSUSERD;
204 * Strip off leading and trailing '.'s in domain name and map
205 * alphabetics to lower case.
207 while (*dnsname == '.')
209 if (*dnsname == '\0')
210 errx(1, "Domain name all '.'");
211 len = strlen(dnsname);
212 cp = dnsname + len - 1;
218 for (i = 0; i < len; i++) {
219 if (!isascii(dnsname[i]))
220 errx(1, "Domain name has non-ascii char");
221 if (isupper(dnsname[i]))
222 dnsname[i] = tolower(dnsname[i]);
226 * If the nfsuserd died off ungracefully, this is necessary to
227 * get them to start again.
229 if (forcestart && nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0)
230 errx(1, "Can't do nfssvc() to delete the port");
234 "nfsuserd: domain=%s usermax=%d usertimeout=%d\n",
235 dnsname, nid.nid_usermax, nid.nid_usertimeout);
237 for (i = 0; i < nfsuserdcnt; i++)
238 slaves[i] = (pid_t)-1;
241 * Set up the service port to accept requests via UDP from
242 * localhost (127.0.0.1).
244 if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
245 err(1, "cannot create udp socket");
248 * Not sure what this does, so I'll leave it here for now.
250 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
252 if ((udptransp = svcudp_create(sock)) == NULL)
253 err(1, "Can't set up socket");
256 * By not specifying a protocol, it is linked into the
257 * dispatch queue, but not registered with portmapper,
258 * which is just what I want.
260 if (!svc_register(udptransp, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS,
262 err(1, "Can't register nfsuserd");
265 * Tell the kernel what my port# is.
267 portnum = htons(udptransp->xp_port);
269 printf("portnum=0x%x\n", portnum);
271 if (nfssvc(NFSSVC_NFSUSERDPORT, (caddr_t)&portnum) < 0) {
272 if (errno == EPERM) {
274 "Can't start nfsuserd when already running");
276 " If not running, use the -force option.\n");
278 fprintf(stderr, "Can't do nfssvc() to add port\n");
284 pwd = getpwnam(defaultuser);
286 nid.nid_uid = pwd->pw_uid;
288 nid.nid_uid = defaultuid;
289 grp = getgrnam(defaultgroup);
291 nid.nid_gid = grp->gr_gid;
293 nid.nid_gid = defaultgid;
294 nid.nid_name = dnsname;
295 nid.nid_namelen = strlen(nid.nid_name);
296 nid.nid_flag = NFSID_INITIALIZE;
298 printf("Initialize uid=%d gid=%d dns=%s\n", nid.nid_uid, nid.nid_gid,
301 error = nfssvc(NFSSVC_IDNAME, &nid);
303 errx(1, "Can't initialize nfs user/groups");
308 * Loop around adding all groups.
311 while (i < nid.nid_usermax && (grp = getgrent())) {
312 nid.nid_gid = grp->gr_gid;
313 nid.nid_name = grp->gr_name;
314 nid.nid_namelen = strlen(grp->gr_name);
315 nid.nid_flag = NFSID_ADDGID;
317 printf("add gid=%d name=%s\n", nid.nid_gid, nid.nid_name);
319 error = nfssvc(NFSSVC_IDNAME, &nid);
321 errx(1, "Can't add group %s", grp->gr_name);
327 * Loop around adding all users.
330 while (i < nid.nid_usermax && (pwd = getpwent())) {
331 nid.nid_uid = pwd->pw_uid;
332 nid.nid_name = pwd->pw_name;
333 nid.nid_namelen = strlen(pwd->pw_name);
334 nid.nid_flag = NFSID_ADDUID;
336 printf("add uid=%d name=%s\n", nid.nid_uid, nid.nid_name);
338 error = nfssvc(NFSSVC_IDNAME, &nid);
340 errx(1, "Can't add user %s", pwd->pw_name);
346 * I should feel guilty for not calling this for all the above exit()
347 * upon error cases, but I don't.
356 * Temporarily block SIGUSR1 and SIGCHLD, so slaves[] can't
359 sigemptyset(&signew);
360 sigaddset(&signew, SIGUSR1);
361 sigaddset(&signew, SIGCHLD);
362 sigprocmask(SIG_BLOCK, &signew, NULL);
365 (void)signal(SIGHUP, SIG_IGN);
366 (void)signal(SIGINT, SIG_IGN);
367 (void)signal(SIGQUIT, SIG_IGN);
368 (void)signal(SIGTERM, SIG_IGN);
369 (void)signal(SIGUSR1, cleanup_term);
370 (void)signal(SIGCHLD, cleanup_term);
372 openlog("nfsuserd:", LOG_PID, LOG_DAEMON);
375 * Fork off the slave daemons that do the work. All the master
376 * does is kill them off and cleanup.
378 for (i = 0; i < nfsuserdcnt; i++) {
380 if (slaves[i] == 0) {
382 setproctitle("slave");
383 sigemptyset(&signew);
384 sigaddset(&signew, SIGUSR1);
385 sigprocmask(SIG_UNBLOCK, &signew, NULL);
391 syslog(LOG_ERR, "nfsuserd died: %m");
393 } else if (slaves[i] < 0) {
394 syslog(LOG_ERR, "fork: %m");
399 * Just wait for SIGUSR1 or a child to die and then...
400 * As the Governor of California would say, "Terminate them".
402 setproctitle("master");
403 sigemptyset(&signew);
409 * The nfsuserd rpc service
412 nfsuserdsrv(struct svc_req *rqstp, SVCXPRT *transp)
419 struct nfsd_idargs nid;
423 * Only handle requests from 127.0.0.1 on a reserved port number.
424 * (Since a reserved port # at localhost implies a client with
425 * local root, there won't be a security breach. This is about
426 * the only case I can think of where a reserved port # means
429 sport = ntohs(transp->xp_raddr.sin_port);
430 saddr = ntohl(transp->xp_raddr.sin_addr.s_addr);
431 if ((rqstp->rq_proc != NULLPROC && sport >= IPPORT_RESERVED) ||
432 saddr != 0x7f000001) {
433 syslog(LOG_ERR, "req from ip=0x%x port=%d\n", saddr, sport);
434 svcerr_weakauth(transp);
437 switch (rqstp->rq_proc) {
439 if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL))
440 syslog(LOG_ERR, "Can't send reply");
442 case RPCNFSUSERD_GETUID:
443 if (!svc_getargs(transp, (xdrproc_t)xdr_getid,
445 svcerr_decode(transp);
448 pwd = getpwuid((uid_t)info.id);
451 nid.nid_usertimeout = defusertimeout;
452 nid.nid_uid = pwd->pw_uid;
453 nid.nid_name = pwd->pw_name;
455 nid.nid_usertimeout = 5;
456 nid.nid_uid = (uid_t)info.id;
457 nid.nid_name = defaultuser;
459 nid.nid_namelen = strlen(nid.nid_name);
460 nid.nid_flag = NFSID_ADDUID;
461 error = nfssvc(NFSSVC_IDNAME, &nid);
464 syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name);
465 } else if (verbose) {
466 syslog(LOG_ERR,"Added uid=%d name=%s\n",
467 nid.nid_uid, nid.nid_name);
469 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
471 syslog(LOG_ERR, "Can't send reply");
473 case RPCNFSUSERD_GETGID:
474 if (!svc_getargs(transp, (xdrproc_t)xdr_getid,
476 svcerr_decode(transp);
479 grp = getgrgid((gid_t)info.id);
482 nid.nid_usertimeout = defusertimeout;
483 nid.nid_gid = grp->gr_gid;
484 nid.nid_name = grp->gr_name;
486 nid.nid_usertimeout = 5;
487 nid.nid_gid = (gid_t)info.id;
488 nid.nid_name = defaultgroup;
490 nid.nid_namelen = strlen(nid.nid_name);
491 nid.nid_flag = NFSID_ADDGID;
492 error = nfssvc(NFSSVC_IDNAME, &nid);
495 syslog(LOG_ERR, "Can't add group %s\n",
497 } else if (verbose) {
498 syslog(LOG_ERR,"Added gid=%d name=%s\n",
499 nid.nid_gid, nid.nid_name);
501 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
503 syslog(LOG_ERR, "Can't send reply");
505 case RPCNFSUSERD_GETUSER:
506 if (!svc_getargs(transp, (xdrproc_t)xdr_getname,
508 svcerr_decode(transp);
511 pwd = getpwnam(info.name);
514 nid.nid_usertimeout = defusertimeout;
515 nid.nid_uid = pwd->pw_uid;
516 nid.nid_name = pwd->pw_name;
518 nid.nid_usertimeout = 5;
519 nid.nid_uid = defaultuid;
520 nid.nid_name = info.name;
522 nid.nid_namelen = strlen(nid.nid_name);
523 nid.nid_flag = NFSID_ADDUSERNAME;
524 error = nfssvc(NFSSVC_IDNAME, &nid);
527 syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name);
528 } else if (verbose) {
529 syslog(LOG_ERR,"Added uid=%d name=%s\n",
530 nid.nid_uid, nid.nid_name);
532 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
534 syslog(LOG_ERR, "Can't send reply");
536 case RPCNFSUSERD_GETGROUP:
537 if (!svc_getargs(transp, (xdrproc_t)xdr_getname,
539 svcerr_decode(transp);
542 grp = getgrnam(info.name);
545 nid.nid_usertimeout = defusertimeout;
546 nid.nid_gid = grp->gr_gid;
547 nid.nid_name = grp->gr_name;
549 nid.nid_usertimeout = 5;
550 nid.nid_gid = defaultgid;
551 nid.nid_name = info.name;
553 nid.nid_namelen = strlen(nid.nid_name);
554 nid.nid_flag = NFSID_ADDGROUPNAME;
555 error = nfssvc(NFSSVC_IDNAME, &nid);
558 syslog(LOG_ERR, "Can't add group %s\n",
560 } else if (verbose) {
561 syslog(LOG_ERR,"Added gid=%d name=%s\n",
562 nid.nid_gid, nid.nid_name);
564 if (!svc_sendreply(transp, (xdrproc_t)xdr_retval,
566 syslog(LOG_ERR, "Can't send reply");
569 svcerr_noproc(transp);
575 * Xdr routine to get an id number
578 xdr_getid(XDR *xdrsp, caddr_t cp)
580 struct info *ifp = (struct info *)cp;
582 return (xdr_long(xdrsp, &ifp->id));
586 * Xdr routine to get a user name
589 xdr_getname(XDR *xdrsp, caddr_t cp)
591 struct info *ifp = (struct info *)cp;
594 if (!xdr_long(xdrsp, &len))
598 if (!xdr_opaque(xdrsp, ifp->name, len))
600 ifp->name[len] = '\0';
605 * Xdr routine to return the value.
608 xdr_retval(XDR *xdrsp, caddr_t cp)
610 struct info *ifp = (struct info *)cp;
614 return (xdr_long(xdrsp, &val));
618 * cleanup_term() called via SIGUSR1.
621 cleanup_term(int signo __unused)
629 * Ok, so I'm the master.
630 * As the Governor of California might say, "Terminate them".
633 for (i = 0; i < nfsuserdcnt; i++) {
634 if (slaves[i] != (pid_t)-1) {
636 kill(slaves[i], SIGUSR1);
641 * and wait for them to die
643 for (i = 0; i < cnt; i++)
644 wait3(NULL, 0, NULL);
647 * Finally, get rid of the socket
649 if (nfssvc(NFSSVC_NFSUSERDDELPORT, NULL) < 0) {
650 syslog(LOG_ERR, "Can't do nfssvc() to delete the port\n");
661 "usage: nfsuserd [-usermax cache_size] [-usertimeout minutes] [-verbose] [-domain domain_name] [n]");