X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=utils%2Fidmapd%2Fidmapd.c;h=b30b69eb72fb04b7555c5086be2adb5f84f72501;hp=ca52c2c497a8a03ffa3f9f3ffc17a5bbf2d13944;hb=1bcf67703e5606837853666763c739db91f08fee;hpb=3adabc36875e73fead1b15c7c5eb8f357ad039f7 diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c index ca52c2c..b30b69e 100644 --- a/utils/idmapd/idmapd.c +++ b/utils/idmapd/idmapd.c @@ -78,6 +78,10 @@ #define NFSD_DIR "/proc/net/rpc" #endif +#ifndef CLIENT_CACHE_TIMEOUT_FILE +#define CLIENT_CACHE_TIMEOUT_FILE "/proc/sys/fs/nfs/idmap_cache_timeout" +#endif + #ifndef NFS4NOBODY_USER #define NFS4NOBODY_USER "nobody" #endif @@ -144,6 +148,8 @@ void mydaemon(int, int); void release_parent(); static int verbose = 0; +#define DEFAULT_IDMAP_CACHE_EXPIRY 600 /* seconds */ +static int cache_entry_expiration = 0; static char pipefsdir[PATH_MAX]; static char *nobodyuser, *nobodygroup; static uid_t nobodyuid; @@ -291,6 +297,8 @@ main(int argc, char **argv) } else { conf_init(); verbose = conf_get_num("General", "Verbosity", 0); + cache_entry_expiration = conf_get_num("General", + "Cache-Expiration", DEFAULT_IDMAP_CACHE_EXPIRY); CONF_SAVE(xpipefsdir, conf_get_str("General", "Pipefs-Directory")); if (xpipefsdir != NULL) strlcpy(pipefsdir, xpipefsdir, sizeof(pipefsdir)); @@ -337,7 +345,9 @@ main(int argc, char **argv) errx(1, "Could not find group \"%s\"", nobodygroup); nobodygid = gr->gr_gid; +#ifdef HAVE_NFS4_SET_DEBUG nfs4_set_debug(verbose, idmapd_warnx); +#endif if (conf_path == NULL) conf_path = _PATH_IDMAPDCONF; if (nfs4_init_name_mapping(conf_path)) @@ -348,6 +358,9 @@ main(int argc, char **argv) event_init(); + if (verbose > 0) + idmapd_warnx("Expiration time is %d seconds.", + cache_entry_expiration); if (serverstart) { nfsdret = nfsdopen(); if (nfsdret == 0) { @@ -364,6 +377,29 @@ main(int argc, char **argv) .tv_usec = 0, }; + if (cache_entry_expiration != DEFAULT_IDMAP_CACHE_EXPIRY) { + int timeout_fd, len; + char timeout_buf[12]; + if ((timeout_fd = open(CLIENT_CACHE_TIMEOUT_FILE, + O_RDWR)) == -1) { + idmapd_warnx("Unable to open '%s' to set " + "client cache expiration time " + "to %d seconds\n", + CLIENT_CACHE_TIMEOUT_FILE, + cache_entry_expiration); + } else { + len = snprintf(timeout_buf, sizeof(timeout_buf), + "%d", cache_entry_expiration); + if ((write(timeout_fd, timeout_buf, len)) != len) + idmapd_warnx("Error writing '%s' to " + "'%s' to set client " + "cache expiration time\n", + timeout_buf, + CLIENT_CACHE_TIMEOUT_FILE); + close(timeout_fd); + } + } + if ((fd = open(pipefsdir, O_RDONLY)) == -1) idmapd_err(1, "main: open(%s)", pipefsdir); @@ -408,7 +444,7 @@ dirscancb(int fd, short which, void *data) { int nent, i; struct dirent **ents; - struct idmap_client *ic; + struct idmap_client *ic, *nextic; char path[PATH_MAX]; struct idmap_clientq *icq = data; @@ -428,7 +464,7 @@ dirscancb(int fd, short which, void *data) goto next; if ((ic = calloc(1, sizeof(*ic))) == NULL) - return; + goto out; strlcpy(ic->ic_clid, ents[i]->d_name + 4, sizeof(ic->ic_clid)); path[0] = '\0'; @@ -438,7 +474,7 @@ dirscancb(int fd, short which, void *data) if ((ic->ic_dirfd = open(path, O_RDONLY, 0)) == -1) { idmapd_warn("dirscancb: open(%s)", path); free(ic); - return; + goto out; } strlcat(path, "/idmap", sizeof(path)); @@ -450,7 +486,7 @@ dirscancb(int fd, short which, void *data) if (nfsopen(ic) == -1) { close(ic->ic_dirfd); free(ic); - return; + goto out; } ic->ic_id = "Client"; @@ -462,7 +498,9 @@ dirscancb(int fd, short which, void *data) } } - TAILQ_FOREACH(ic, icq, ic_next) { + ic = TAILQ_FIRST(icq); + while(ic != NULL) { + nextic=TAILQ_NEXT(ic, ic_next); if (!ic->ic_scanned) { event_del(&ic->ic_event); close(ic->ic_fd); @@ -475,7 +513,13 @@ dirscancb(int fd, short which, void *data) free(ic); } else ic->ic_scanned = 0; + ic = nextic; } + +out: + for (i = 0; i < nent; i++) + free(ents[i]); + free(ents); return; } @@ -505,7 +549,8 @@ nfsdcb(int fd, short which, void *data) struct idmap_client *ic = data; struct idmap_msg im; u_char buf[IDMAP_MAXMSGSZ + 1]; - size_t len, bsiz; + size_t len; + ssize_t bsiz; char *bp, typebuf[IDMAP_MAXMSGSZ], buf1[IDMAP_MAXMSGSZ], authbuf[IDMAP_MAXMSGSZ], *p; unsigned long tmp; @@ -513,15 +558,16 @@ nfsdcb(int fd, short which, void *data) if (which != EV_READ) goto out; - if ((len = read(ic->ic_fd, buf, sizeof(buf))) == -1) { + if ((len = read(ic->ic_fd, buf, sizeof(buf))) <= 0) { idmapd_warnx("nfsdcb: read(%s) failed: errno %d (%s)", - ic->ic_path, errno, strerror(errno)); + ic->ic_path, len?errno:0, + len?strerror(errno):"End of File"); goto out; } /* Get rid of newline and terminate buffer*/ buf[len - 1] = '\0'; - bp = buf; + bp = (char *)buf; memset(&im, 0, sizeof(im)); @@ -571,7 +617,7 @@ nfsdcb(int fd, short which, void *data) imconv(ic, &im); buf[0] = '\0'; - bp = buf; + bp = (char *)buf; bsiz = sizeof(buf); /* Authentication name */ @@ -584,14 +630,22 @@ nfsdcb(int fd, short which, void *data) addfield(&bp, &bsiz, p); /* Name */ addfield(&bp, &bsiz, im.im_name); -#define NFSD_EXPIRY 300 /* seconds */ /* expiry */ - snprintf(buf1, sizeof(buf1), "%lu", time(NULL) + NFSD_EXPIRY); - addfield(&bp, &bsiz, buf1); - /* ID */ - snprintf(buf1, sizeof(buf1), "%u", im.im_id); + snprintf(buf1, sizeof(buf1), "%lu", + time(NULL) + cache_entry_expiration); addfield(&bp, &bsiz, buf1); + /* Note that we don't want to write the id if the mapping + * failed; instead, by leaving it off, we write a negative + * cache entry which will result in an error returned to + * the client. We don't want a chown or setacl referring + * to an unknown user to result in giving permissions to + * "nobody"! */ + if (im.im_status == IDMAP_STATUS_SUCCESS) { + /* ID */ + snprintf(buf1, sizeof(buf1), "%u", im.im_id); + addfield(&bp, &bsiz, buf1); + } //if (bsiz == sizeof(buf)) /* XXX */ bp[-1] = '\n'; @@ -605,8 +659,11 @@ nfsdcb(int fd, short which, void *data) snprintf(buf1, sizeof(buf1), "%u", im.im_id); addfield(&bp, &bsiz, buf1); /* expiry */ - snprintf(buf1, sizeof(buf1), "%lu", time(NULL) + NFSD_EXPIRY); + snprintf(buf1, sizeof(buf1), "%lu", + time(NULL) + cache_entry_expiration); addfield(&bp, &bsiz, buf1); + /* Note we're ignoring the status field in this case; we'll + * just map to nobody instead. */ /* Name */ addfield(&bp, &bsiz, im.im_name); @@ -679,6 +736,13 @@ nfscb(int fd, short which, void *data) imconv(ic, &im); + /* XXX: I don't like ignoring this error in the id->name case, + * but we've never returned it, and I need to check that the client + * can handle it gracefully before starting to return it now. */ + + if (im.im_status == IDMAP_STATUS_LOOKUPFAIL) + im.im_status = IDMAP_STATUS_SUCCESS; + if (atomicio(write, ic->ic_fd, &im, sizeof(im)) != sizeof(im)) idmapd_warn("nfscb: write(%s)", ic->ic_path); out: @@ -798,8 +862,10 @@ idtonameres(struct idmap_msg *im) } break; } - /* XXX Hack? */ - im->im_status = IDMAP_STATUS_SUCCESS; + if (ret) + im->im_status = IDMAP_STATUS_LOOKUPFAIL; + else + im->im_status = IDMAP_STATUS_SUCCESS; } static void @@ -809,30 +875,29 @@ nametoidres(struct idmap_msg *im) gid_t gid; 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. */ + + im->im_status = IDMAP_STATUS_SUCCESS; + switch (im->im_type) { case IDMAP_TYPE_USER: ret = nfs4_name_to_uid(im->im_name, &uid); im->im_id = (u_int32_t) uid; - if (ret) + if (ret) { + im->im_status = IDMAP_STATUS_LOOKUPFAIL; im->im_id = nobodyuid; - break; + } + return; case IDMAP_TYPE_GROUP: ret = nfs4_name_to_gid(im->im_name, &gid); im->im_id = (u_int32_t) gid; - if (ret) + if (ret) { + im->im_status = IDMAP_STATUS_LOOKUPFAIL; im->im_id = nobodygid; - break; + } + return; } - /* XXX? */ - im->im_status = IDMAP_STATUS_SUCCESS; } static int @@ -967,10 +1032,15 @@ mydaemon(int nochdir, int noclose) if (noclose == 0) { tempfd = open("/dev/null", O_RDWR); - dup2(tempfd, 0); - dup2(tempfd, 1); - dup2(tempfd, 2); - closeall(3); + if (tempfd < 0) + tempfd = open("/", O_RDONLY); + if (tempfd >= 0) { + dup2(tempfd, 0); + dup2(tempfd, 1); + dup2(tempfd, 2); + closeall(3); + } else + closeall(0); } return;