X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=utils%2Fidmapd%2Fidmapd.c;h=3be8148e537eeb35e88e0e28dd94df4f75609a17;hp=ee117b6d632b91b9162691822c4dbff192c4f8db;hb=f73e7b9f69835d483cee95e6a20b6307b9d16b77;hpb=021751e2e70c0d629bf196065816949e38b158d9 diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c index ee117b6..3be8148 100644 --- a/utils/idmapd/idmapd.c +++ b/utils/idmapd/idmapd.c @@ -91,8 +91,8 @@ (w) = p; \ } while (0) -#define IC_IDNAME 1 -#define IC_NAMEID 2 +#define IC_IDNAME 0 +#define IC_NAMEID 1 struct idmap_client { int ic_fd; int ic_dirfd; @@ -109,6 +109,7 @@ TAILQ_HEAD(idmap_clientq, idmap_client); static void dirscancb(int, short, void *); static void clntscancb(int, short, void *); +static void svrreopen(int, short, void *); static int nfsopen(struct idmap_client *); static void nfscb(int, short, void *); static void nfsdcb(int, short, void *); @@ -122,14 +123,15 @@ static void nametoidres(struct idmap_msg *); static int nfsdopen(char *); static int nfsdopenone(struct idmap_client *, short, char *); +static void nfsdreopen(void); size_t strlcat(char *, const char *, size_t); size_t strlcpy(char *, const char *, size_t); ssize_t atomicio(ssize_t (*)(), int, void *, size_t); -int daemon(int, int); +void mydaemon(int, int); +void release_parent(); static int verbose = 0; -static char domain[512]; static char pipefsdir[PATH_MAX]; static char *nobodyuser, *nobodygroup; static uid_t nobodyuid; @@ -139,19 +141,47 @@ static struct idmap_client nfsd_ic[2]; /* Used by cfg.c */ char *conf_path; +static int +flush_nfsd_cache(char *path, time_t now) +{ + int fd; + char stime[20]; + + sprintf(stime, "%ld\n", now); + fd = open(path, O_RDWR); + if (fd == -1) + return -1; + write(fd, stime, strlen(stime)); + close(fd); + return 0; +} + +static int +flush_nfsd_idmap_cache(void) +{ + time_t now = time(NULL); + int ret; + + ret = flush_nfsd_cache("/proc/net/rpc/nfs4.idtoname/flush", now); + if (ret) + return ret; + ret = flush_nfsd_cache("/proc/net/rpc/nfs4.nametoid/flush", now); + return ret; +} + int main(int argc, char **argv) { int fd = 0, opt, fg = 0, nfsdret = -1; struct idmap_clientq icq; - struct event rootdirev, clntdirev; + struct event rootdirev, clntdirev, svrdirev; struct event initialize; struct passwd *pw; struct group *gr; struct stat sb; char *xpipefsdir = NULL; - char *xdomain = NULL; int serverstart = 1, clientstart = 1; + int ret; conf_path = _PATH_IDMAPDCONF; nobodyuser = NFS4NOBODY_USER; @@ -178,13 +208,11 @@ main(int argc, char **argv) conf_init(); verbose = conf_get_num("General", "Verbosity", 0); CONF_SAVE(xpipefsdir, conf_get_str("General", "Pipefs-Directory")); - CONF_SAVE(xdomain, conf_get_str("General", "Domain")); if (xpipefsdir != NULL) strlcpy(pipefsdir, xpipefsdir, sizeof(pipefsdir)); - if (xdomain != NULL) - strlcpy(domain, xdomain, sizeof(domain)); CONF_SAVE(nobodyuser, conf_get_str("Mapping", "Nobody-User")); CONF_SAVE(nobodygroup, conf_get_str("Mapping", "Nobody-Group")); + nfs4_init_name_mapping(conf_path); } while ((opt = getopt(argc, argv, GETOPTSTR)) != -1) @@ -195,18 +223,14 @@ main(int argc, char **argv) case 'f': fg = 1; break; - case 'd': - strlcpy(domain, optarg, sizeof(domain)); - break; case 'p': strlcpy(pipefsdir, optarg, sizeof(pipefsdir)); break; + case 'd': case 'U': - nobodyuser = optarg; - break; case 'G': - nobodygroup = optarg; - break; + errx(1, "the -d, -U, and -G options have been removed;" + " please use the configuration file instead."); case 'C': serverstart = 0; break; @@ -222,23 +246,6 @@ main(int argc, char **argv) strncat(pipefsdir, "/nfs", sizeof(pipefsdir)); - if (domain[0] == '\0') { - struct hostent *he; - char hname[64], *c; - - if (gethostname(hname, sizeof(hname)) == -1) - errx(1, "Error getting hostname"); - - if ((he = gethostbyname(hname)) == NULL) - errx(1, "Error resolving hostname: %s", hname); - - if ((c = strchr(he->h_name, '.')) == NULL || *++c == '\0') - errx(1, "Error resolving domain, " - "please use the -d switch"); - - strlcpy(domain, c, sizeof(domain)); - } - if ((pw = getpwnam(nobodyuser)) == NULL) errx(1, "Could not find user \"%s\"", nobodyuser); nobodyuid = pw->pw_uid; @@ -247,19 +254,19 @@ main(int argc, char **argv) errx(1, "Could not find group \"%s\"", nobodygroup); nobodygid = gr->gr_gid; - if (strlen(domain) == 0) - errx(1, "Invalid domain; please specify with -d switch"); - - if (verbose > 2) - warnx("Using domain \"%s\"", domain); - if (!fg) - daemon(0, 0); + mydaemon(0, 0); event_init(); - if (serverstart) + if (serverstart) { nfsdret = nfsdopen(NFSD_DIR); + if (nfsdret == 0) { + ret = flush_nfsd_idmap_cache(); + if (ret) + errx(1, "Failed to flush nfsd idmap cache\n"); + } + } if (clientstart) { struct timeval now = { @@ -283,6 +290,8 @@ main(int argc, char **argv) signal_add(&rootdirev, NULL); signal_set(&clntdirev, SIGUSR2, clntscancb, &icq); signal_add(&clntdirev, NULL); + signal_set(&svrdirev, SIGHUP, svrreopen, NULL); + signal_add(&svrdirev, NULL); /* Fetch current state */ /* (Delay till start of event_dispatch to avoid possibly losing @@ -294,7 +303,10 @@ main(int argc, char **argv) if (nfsdret != 0 && fd == 0) errx(1, "Neither NFS client nor NFSd found"); - event_dispatch(); + release_parent(); + + if (event_dispatch() < 0) + errx(1, "event_dispatch: returns errno %d (%s)", errno, strerror(errno)); /* NOTREACHED */ return 1; } @@ -375,6 +387,12 @@ dirscancb(int fd, short which, void *data) return; } +static void +svrreopen(int fd, short which, void *data) +{ + nfsdreopen(); +} + static void clntscancb(int fd, short which, void *data) { @@ -403,8 +421,8 @@ nfsdcb(int fd, short which, void *data) goto out; if ((len = read(ic->ic_fd, buf, sizeof(buf))) == -1) { - if (verbose > 0) - warn("read(%s)", ic->ic_path); + warnx("nfsdcb: read(%s) failed: errno %d (%s)", + ic->ic_path, errno, strerror(errno)); goto out; } @@ -415,11 +433,16 @@ nfsdcb(int fd, short which, void *data) memset(&im, 0, sizeof(im)); /* Authentication name -- ignored for now*/ - if (getfield(&bp, authbuf, sizeof(authbuf)) == -1) + if (getfield(&bp, authbuf, sizeof(authbuf)) == -1) { + warnx("nfsdcb: bad authentication name in upcall\n"); return; - - if (getfield(&bp, typebuf, sizeof(typebuf)) == -1) + } + if (getfield(&bp, typebuf, sizeof(typebuf)) == -1) { + warnx("nfsdcb: bad type in upcall\n"); return; + } + if (verbose > 0) + warnx("nfsdcb: authbuf=%s authtype=%s", authbuf, typebuf); im.im_type = strcmp(typebuf, "user") == 0 ? IDMAP_TYPE_USER : IDMAP_TYPE_GROUP; @@ -427,16 +450,22 @@ nfsdcb(int fd, short which, void *data) switch (ic->ic_which) { case IC_NAMEID: im.im_conv = IDMAP_CONV_NAMETOID; - if (getfield(&bp, im.im_name, sizeof(im.im_name)) == -1) + if (getfield(&bp, im.im_name, sizeof(im.im_name)) == -1) { + warnx("nfsdcb: bad name in upcall\n"); return; + } break; case IC_IDNAME: im.im_conv = IDMAP_CONV_IDTONAME; - if (getfield(&bp, buf1, sizeof(buf1)) == -1) + if (getfield(&bp, buf1, sizeof(buf1)) == -1) { + warnx("nfsdcb: bad id in upcall\n"); return; + } if ((im.im_id = strtoul(buf1, (char **)NULL, 10)) == ULONG_MAX && - errno == ERANGE) + errno == ERANGE) { + warnx("nfsdcb: id '%s' too big!\n", buf1); return; + } break; default: @@ -496,8 +525,9 @@ nfsdcb(int fd, short which, void *data) bsiz = sizeof(buf) - bsiz; - if (atomicio(write, ic->ic_fd, buf, bsiz) != bsiz && verbose > 0) - warn("write(%s)", ic->ic_path); + if (atomicio(write, ic->ic_fd, buf, bsiz) != bsiz) + warnx("nfsdcb: write(%s) failed: errno %d (%s)", + ic->ic_path, errno, strerror(errno)); out: event_add(&ic->ic_event, NULL); @@ -559,11 +589,41 @@ out: event_add(&ic->ic_event, NULL); } +static void +nfsdreopen_one(struct idmap_client *ic) +{ + int fd; + + if (verbose > 0) + warnx("ReOpening %s", ic->ic_path); + if ((fd = open(ic->ic_path, O_RDWR, 0)) != -1) { + if (ic->ic_fd != -1) + close(ic->ic_fd); + ic->ic_event.ev_fd = ic->ic_fd = fd; + event_set(&ic->ic_event, ic->ic_fd, EV_READ, nfsdcb, ic); + event_add(&ic->ic_event, NULL); + } else { + warnx("nfsdreopen: Opening '%s' failed: errno %d (%s)", + ic->ic_path, errno, strerror(errno)); + } +} + +/* + * Note: nfsdreopen assumes nfsdopen has already been called + */ +static void +nfsdreopen() +{ + nfsdreopen_one(&nfsd_ic[IC_NAMEID]); + nfsdreopen_one(&nfsd_ic[IC_IDNAME]); + return; +} + static int nfsdopen(char *path) { - return ((nfsdopenone(&nfsd_ic[0], IC_NAMEID, path) == 0 && - nfsdopenone(&nfsd_ic[1], IC_IDNAME, path) == 0) ? 0 : -1); + return ((nfsdopenone(&nfsd_ic[IC_NAMEID], IC_NAMEID, path) == 0 && + nfsdopenone(&nfsd_ic[IC_IDNAME], IC_IDNAME, path) == 0) ? 0 : -1); } static int @@ -575,7 +635,9 @@ nfsdopenone(struct idmap_client *ic, short which, char *path) snprintf(ic->ic_path, sizeof(ic->ic_path), "%s/nfs4.%s/channel", path, whichstr); if ((ic->ic_fd = open(ic->ic_path, O_RDWR, 0)) == -1) { - warn("%s", ic->ic_path); + if (verbose > 0) + warnx("Opening %s failed: errno %d (%s)", + ic->ic_path, errno, strerror(errno)); return (-1); } @@ -584,7 +646,7 @@ nfsdopenone(struct idmap_client *ic, short which, char *path) ic->ic_which = which; ic->ic_id = "Server"; - strlcpy(ic->ic_clid, domain, sizeof(ic->ic_clid)); + strlcpy(ic->ic_clid, "Server", strlen("Server")); if (verbose > 0) warnx("Opened %s", ic->ic_path); @@ -632,8 +694,10 @@ static int write_name(char *dest, char *localname, char *domain, size_t len) static void idtonameres(struct idmap_msg *im) { + char domain[NFS4_MAX_DOMAIN_LEN]; int ret = 0; + ret = nfs4_get_default_domain(NULL, domain, sizeof(domain)); switch (im->im_type) { case IDMAP_TYPE_USER: ret = nfs4_uid_to_name(im->im_id, domain, im->im_name, @@ -650,9 +714,7 @@ idtonameres(struct idmap_msg *im) sizeof(im->im_name)); break; } - /* XXX Hack? would rather return failure instead of writing nobody - * as above, but kernel seems not to deal well with that as of - * 2.6.8-rc3. */ + /* XXX Hack? */ im->im_status = IDMAP_STATUS_SUCCESS; } @@ -661,6 +723,14 @@ nametoidres(struct idmap_msg *im) { int ret = 0; + /* XXX: nobody fallbacks shouldn't always happen: + * server id -> name should be OK + * client name -> id should be OK + * but not otherwise */ + /* XXX: move nobody stuff to library calls + * (nfs4_get_nobody_user(domain), nfs4_get_nobody_group(domain)) */ + /* XXX: should make this call higher up in the call chain (so we'd + * have a chance on looking up server/whatever. */ switch (im->im_type) { case IDMAP_TYPE_USER: ret = nfs4_name_to_uid(im->im_name, &im->im_id); @@ -673,9 +743,7 @@ nametoidres(struct idmap_msg *im) im->im_id = nobodygid; break; } - /* XXX Hack? would rather return failure instead of writing nobody - * as above, but kernel seems not to deal well with that as of - * 2.6.8-rc3. */ + /* XXX? */ im->im_status = IDMAP_STATUS_SUCCESS; } @@ -767,3 +835,66 @@ getfield(char **bpp, char *fld, size_t fldsz) return (0); } +/* + * mydaemon creates a pipe between the partent and child + * process. The parent process will wait until the + * child dies or writes a '1' on the pipe signaling + * that it started successfully. + */ +int pipefds[2] = { -1, -1}; + +void +mydaemon(int nochdir, int noclose) +{ + int pid, status, tempfd; + + if (pipe(pipefds) < 0) + err(1, "mydaemon: pipe() failed: errno %d (%s)\n", errno, strerror(errno)); + + if ((pid = fork ()) < 0) + err(1, "mydaemon: fork() failed: errno %d (%s)\n", errno, strerror(errno)); + + if (pid != 0) { + /* + * Parent. Wait for status from child. + */ + close(pipefds[1]); + if (read(pipefds[0], &status, 1) != 1) + exit(1); + exit (0); + } + /* Child. */ + close(pipefds[0]); + setsid (); + if (nochdir == 0) { + if (chdir ("/") == -1) + err(1, "mydaemon: chdir() failed: errno %d (%s)\n", errno, strerror(errno)); + } + + while (pipefds[1] <= 2) { + pipefds[1] = dup(pipefds[1]); + if (pipefds[1] < 0) + err(1, "mydaemon: dup() failed: errno %d (%s)\n", errno, strerror(errno)); + } + + if (noclose == 0) { + tempfd = open("/dev/null", O_RDWR); + dup2(tempfd, 0); + dup2(tempfd, 1); + dup2(tempfd, 2); + closeall(3); + } + + return; +} +void +release_parent() +{ + int status; + + if (pipefds[1] > 0) { + write(pipefds[1], &status, 1); + close(pipefds[1]); + pipefds[1] = -1; + } +}