X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=utils%2Fidmapd%2Fidmapd.c;h=b76607a4d8fa437eea010e8638bc3c31f2b93778;hp=e965563ac045df75d25735c7b5ea67edb063e067;hb=706bfd7c94d48659a1411fdef2a3a61d4719f1aa;hpb=2aa84c3f3e9fd8e5732045c48bbaa633250f25ee diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c index e965563..b76607a 100644 --- a/utils/idmapd/idmapd.c +++ b/utils/idmapd/idmapd.c @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include @@ -64,7 +65,8 @@ #include "config.h" #endif /* HAVE_CONFIG_H */ -#include "cfg.h" +#include "xlog.h" +#include "conffile.h" #include "queue.h" #include "nfslib.h" @@ -76,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 @@ -91,19 +97,45 @@ (w) = p; \ } while (0) -#define IC_IDNAME 1 -#define IC_NAMEID 2 +#define IC_IDNAME 0 +#define IC_IDNAME_CHAN NFSD_DIR "/nfs4.idtoname/channel" +#define IC_IDNAME_FLUSH NFSD_DIR "/nfs4.idtoname/flush" + +#define IC_NAMEID 1 +#define IC_NAMEID_CHAN NFSD_DIR "/nfs4.nametoid/channel" +#define IC_NAMEID_FLUSH NFSD_DIR "/nfs4.nametoid/flush" + struct idmap_client { - int ic_fd; - int ic_dirfd; + short ic_which; char ic_clid[30]; + char *ic_id; char ic_path[PATH_MAX]; + int ic_fd; + int ic_dirfd; int ic_scanned; struct event ic_event; - char *ic_id; - short ic_which; TAILQ_ENTRY(idmap_client) ic_next; }; +static struct idmap_client nfsd_ic[2] = { +{ + .ic_which = IC_IDNAME, + .ic_clid = "", + .ic_id = "Server", + .ic_path = IC_IDNAME_CHAN, + .ic_fd = -1, + .ic_dirfd = -1, + .ic_scanned = 0 +}, +{ + .ic_which = IC_NAMEID, + .ic_clid = "", + .ic_id = "Server", + .ic_path = IC_NAMEID_CHAN, + .ic_fd = -1, + .ic_dirfd = -1, + .ic_scanned = 0 +}, +}; TAILQ_HEAD(idmap_clientq, idmap_client); @@ -121,26 +153,60 @@ static void imconv(struct idmap_client *, struct idmap_msg *); static void idtonameres(struct idmap_msg *); static void nametoidres(struct idmap_msg *); -static int nfsdopen(char *); -static int nfsdopenone(struct idmap_client *, short, char *); +static int nfsdopen(void); +static int nfsdopenone(struct idmap_client *); +static void nfsdreopen_one(struct idmap_client *); 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); +ssize_t atomicio(ssize_t (*f) (int, void*, size_t), + int, void *, size_t); +void mydaemon(int, int); +void release_parent(void); static int verbose = 0; -static char domain[512]; +#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; static gid_t nobodygid; -static struct idmap_client nfsd_ic[2]; -/* Used by cfg.c */ +/* Used by conffile.c in libnfs.a */ 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; + if (write(fd, stime, strlen(stime)) != (ssize_t)strlen(stime)) { + errx(1, "Flushing nfsd cache failed: errno %d (%s)", + errno, strerror(errno)); + } + close(fd); + return 0; +} + +static int +flush_nfsd_idmap_cache(void) +{ + time_t now = time(NULL); + int ret; + + ret = flush_nfsd_cache(IC_IDNAME_FLUSH, now); + if (ret) + return ret; + ret = flush_nfsd_cache(IC_NAMEID_FLUSH, now); + return ret; +} + int main(int argc, char **argv) { @@ -152,14 +218,21 @@ main(int argc, char **argv) struct group *gr; struct stat sb; char *xpipefsdir = NULL; - char *xdomain = NULL; int serverstart = 1, clientstart = 1; + int ret; + char *progname; conf_path = _PATH_IDMAPDCONF; nobodyuser = NFS4NOBODY_USER; nobodygroup = NFS4NOBODY_GROUP; strlcpy(pipefsdir, PIPEFS_DIR, sizeof(pipefsdir)); + if ((progname = strrchr(argv[0], '/'))) + progname++; + else + progname = argv[0]; + xlog_open(progname); + #define GETOPTSTR "vfd:p:U:G:c:CS" opterr=0; /* Turn off error messages */ while ((opt = getopt(argc, argv, GETOPTSTR)) != -1) { @@ -176,15 +249,15 @@ main(int argc, char **argv) if (stat(conf_path, &sb) == -1 && (errno == ENOENT || errno == EACCES)) { warn("Skipping configuration file \"%s\"", conf_path); + conf_path = NULL; } 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")); - 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")); } @@ -220,23 +293,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; @@ -245,19 +301,30 @@ 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); +#ifdef HAVE_NFS4_SET_DEBUG + nfs4_set_debug(verbose, xlog_warn); +#endif + if (conf_path == NULL) + conf_path = _PATH_IDMAPDCONF; + if (nfs4_init_name_mapping(conf_path)) + errx(1, "Unable to create name to user id mappings."); if (!fg) - daemon(0, 0); + mydaemon(0, 0); event_init(); - if (serverstart) - nfsdret = nfsdopen(NFSD_DIR); + if (verbose > 0) + xlog_warn("Expiration time is %d seconds.", + cache_entry_expiration); + if (serverstart) { + nfsdret = nfsdopen(); + if (nfsdret == 0) { + ret = flush_nfsd_idmap_cache(); + if (ret) + xlog_err("main: Failed to flush nfsd idmap cache\n: %s", strerror(errno)); + } + } if (clientstart) { struct timeval now = { @@ -265,15 +332,41 @@ 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) { + xlog_warn("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) + xlog_warn("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) - err(1, "open(%s)", pipefsdir); + xlog_err("main: open(%s): %s", pipefsdir, strerror(errno)); if (fcntl(fd, F_SETSIG, SIGUSR1) == -1) - err(1, "fcntl(%s)", pipefsdir); - if (fcntl(fd, F_NOTIFY, - DN_CREATE | DN_DELETE | DN_MODIFY | DN_MULTISHOT) == -1) - err(1, "fcntl(%s)", pipefsdir); + xlog_err("main: fcntl(%s): %s", pipefsdir, strerror(errno)); + if (fcntl(fd, F_NOTIFY, + DN_CREATE | DN_DELETE | DN_MODIFY | DN_MULTISHOT) == -1) { + xlog_err("main: fcntl(%s): %s", pipefsdir, strerror(errno)); + if (errno == EINVAL) + xlog_err("main: Possibly no Dnotify support in kernel."); + } TAILQ_INIT(&icq); /* These events are persistent */ @@ -292,26 +385,29 @@ main(int argc, char **argv) } if (nfsdret != 0 && fd == 0) - errx(1, "Neither NFS client nor NFSd found"); + xlog_err("main: Neither NFS client nor NFSd found"); + + release_parent(); if (event_dispatch() < 0) - errx(1, "event_dispatch: returns errno %d (%s)", errno, strerror(errno)); + xlog_err("main: event_dispatch returns errno %d (%s)", + errno, strerror(errno)); /* NOTREACHED */ return 1; } static void -dirscancb(int fd, short which, void *data) +dirscancb(int UNUSED(fd), short UNUSED(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; nent = scandir(pipefsdir, &ents, NULL, alphasort); if (nent == -1) { - warn("scandir(%s)", pipefsdir); + xlog_warn("dirscancb: scandir(%s): %s", pipefsdir, strerror(errno)); return; } @@ -325,7 +421,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'; @@ -333,21 +429,21 @@ dirscancb(int fd, short which, void *data) pipefsdir, ents[i]->d_name); if ((ic->ic_dirfd = open(path, O_RDONLY, 0)) == -1) { - warn("open(%s)", path); + xlog_warn("dirscancb: open(%s): %s", path, strerror(errno)); free(ic); - return; + goto out; } strlcat(path, "/idmap", sizeof(path)); strlcpy(ic->ic_path, path, sizeof(ic->ic_path)); if (verbose > 0) - warnx("New client: %s", ic->ic_clid); + xlog_warn("New client: %s", ic->ic_clid); if (nfsopen(ic) == -1) { close(ic->ic_dirfd); free(ic); - return; + goto out; } ic->ic_id = "Client"; @@ -359,31 +455,39 @@ 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); close(ic->ic_dirfd); TAILQ_REMOVE(icq, ic, ic_next); if (verbose > 0) { - warnx("Stale client: %s", ic->ic_clid); - warnx("\t-> closed %s", ic->ic_path); + xlog_warn("Stale client: %s", ic->ic_clid); + xlog_warn("\t-> closed %s", ic->ic_path); } free(ic); } else ic->ic_scanned = 0; + ic = nextic; } + +out: + for (i = 0; i < nent; i++) + free(ents[i]); + free(ents); return; } static void -svrreopen(int fd, short which, void *data) +svrreopen(int UNUSED(fd), short UNUSED(which), void *UNUSED(data)) { nfsdreopen(); } static void -clntscancb(int fd, short which, void *data) +clntscancb(int UNUSED(fd), short UNUSED(which), void *data) { struct idmap_clientq *icq = data; struct idmap_client *ic; @@ -397,41 +501,46 @@ clntscancb(int fd, short which, void *data) } static void -nfsdcb(int fd, short which, void *data) +nfsdcb(int UNUSED(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; if (which != EV_READ) goto out; - if ((len = read(ic->ic_fd, buf, sizeof(buf))) == -1) { - warnx("nfsdcb: read(%s) failed: errno %d (%s)", - ic->ic_path, errno, strerror(errno)); - goto out; + if ((len = read(ic->ic_fd, buf, sizeof(buf))) <= 0) { + xlog_warn("nfsdcb: read(%s) failed: errno %d (%s)", + ic->ic_path, len?errno:0, + len?strerror(errno):"End of File"); + nfsdreopen_one(ic); + return; } /* Get rid of newline and terminate buffer*/ buf[len - 1] = '\0'; - bp = buf; + bp = (char *)buf; memset(&im, 0, sizeof(im)); /* Authentication name -- ignored for now*/ if (getfield(&bp, authbuf, sizeof(authbuf)) == -1) { - warnx("nfsdcb: bad authentication name in upcall\n"); - return; + xlog_warn("nfsdcb: bad authentication name in upcall\n"); + goto out; } if (getfield(&bp, typebuf, sizeof(typebuf)) == -1) { - warnx("nfsdcb: bad type in upcall\n"); - return; + xlog_warn("nfsdcb: bad type in upcall\n"); + goto out; } if (verbose > 0) - warnx("nfsdcb: authbuf=%s authtype=%s", authbuf, typebuf); + xlog_warn("nfsdcb: authbuf=%s authtype=%s", + authbuf, typebuf); im.im_type = strcmp(typebuf, "user") == 0 ? IDMAP_TYPE_USER : IDMAP_TYPE_GROUP; @@ -440,32 +549,33 @@ nfsdcb(int fd, short which, void *data) case IC_NAMEID: im.im_conv = IDMAP_CONV_NAMETOID; if (getfield(&bp, im.im_name, sizeof(im.im_name)) == -1) { - warnx("nfsdcb: bad name in upcall\n"); - return; + xlog_warn("nfsdcb: bad name in upcall\n"); + goto out; } break; case IC_IDNAME: im.im_conv = IDMAP_CONV_IDTONAME; if (getfield(&bp, buf1, sizeof(buf1)) == -1) { - warnx("nfsdcb: bad id in upcall\n"); - return; + xlog_warn("nfsdcb: bad id in upcall\n"); + goto out; } - if ((im.im_id = strtoul(buf1, (char **)NULL, 10)) == ULONG_MAX && - errno == ERANGE) { - warnx("nfsdcb: id '%s' too big!\n", buf1); - return; + tmp = strtoul(buf1, (char **)NULL, 10); + im.im_id = (u_int32_t)tmp; + if ((tmp == ULONG_MAX && errno == ERANGE) + || (unsigned long)im.im_id != tmp) { + xlog_warn("nfsdcb: id '%s' too big!\n", buf1); + goto out; } - break; default: - warnx("Unknown which type %d", ic->ic_which); - return; + xlog_warn("nfsdcb: Unknown which type %d", ic->ic_which); + goto out; } imconv(ic, &im); buf[0] = '\0'; - bp = buf; + bp = (char *)buf; bsiz = sizeof(buf); /* Authentication name */ @@ -478,14 +588,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'; @@ -499,8 +617,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); @@ -508,15 +629,15 @@ nfsdcb(int fd, short which, void *data) break; default: - warnx("Unknown which type %d", ic->ic_which); - return; + xlog_warn("nfsdcb: Unknown which type %d", ic->ic_which); + goto out; } bsiz = sizeof(buf) - bsiz; - if (atomicio(write, ic->ic_fd, buf, bsiz) != bsiz) - warnx("nfsdcb: write(%s) failed: errno %d (%s)", - ic->ic_path, errno, strerror(errno)); + if (atomicio((void*)write, ic->ic_fd, buf, bsiz) != bsiz) + xlog_warn("nfsdcb: write(%s) failed: errno %d (%s)", + ic->ic_path, errno, strerror(errno)); out: event_add(&ic->ic_event, NULL); @@ -529,7 +650,7 @@ imconv(struct idmap_client *ic, struct idmap_msg *im) case IDMAP_CONV_IDTONAME: idtonameres(im); if (verbose > 1) - warnx("%s %s: (%s) id \"%d\" -> name \"%s\"", + xlog_warn("%s %s: (%s) id \"%d\" -> name \"%s\"", ic->ic_id, ic->ic_clid, im->im_type == IDMAP_TYPE_USER ? "user" : "group", im->im_id, im->im_name); @@ -541,20 +662,21 @@ imconv(struct idmap_client *ic, struct idmap_msg *im) } nametoidres(im); if (verbose > 1) - warnx("%s %s: (%s) name \"%s\" -> id \"%d\"", + xlog_warn("%s %s: (%s) name \"%s\" -> id \"%d\"", ic->ic_id, ic->ic_clid, im->im_type == IDMAP_TYPE_USER ? "user" : "group", im->im_name, im->im_id); break; default: - warnx("Invalid conversion type (%d) in message", im->im_conv); + xlog_warn("imconv: Invalid conversion type (%d) in message", + im->im_conv); im->im_status |= IDMAP_STATUS_INVALIDMSG; break; } } static void -nfscb(int fd, short which, void *data) +nfscb(int UNUSED(fd), short which, void *data) { struct idmap_client *ic = data; struct idmap_msg im; @@ -564,7 +686,7 @@ nfscb(int fd, short which, void *data) if (atomicio(read, ic->ic_fd, &im, sizeof(im)) != sizeof(im)) { if (verbose > 0) - warn("read(%s)", ic->ic_path); + xlog_warn("nfscb: read(%s): %s", ic->ic_path, strerror(errno)); if (errno == EPIPE) return; goto out; @@ -572,8 +694,15 @@ nfscb(int fd, short which, void *data) imconv(ic, &im); - if (atomicio(write, ic->ic_fd, &im, sizeof(im)) != sizeof(im)) - warn("write(%s)", ic->ic_path); + /* 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((void*)write, ic->ic_fd, &im, sizeof(im)) != sizeof(im)) + xlog_warn("nfscb: write(%s): %s", ic->ic_path, strerror(errno)); out: event_add(&ic->ic_event, NULL); } @@ -584,24 +713,23 @@ nfsdreopen_one(struct idmap_client *ic) int fd; if (verbose > 0) - warnx("ReOpening %s", ic->ic_path); + xlog_warn("ReOpening %s", ic->ic_path); + if ((fd = open(ic->ic_path, O_RDWR, 0)) != -1) { + if ((ic->ic_event.ev_flags & EVLIST_INIT)) + event_del(&ic->ic_event); if (ic->ic_fd != -1) close(ic->ic_fd); + ic->ic_event.ev_fd = ic->ic_fd = fd; - if ((ic->ic_event.ev_flags & EVLIST_INIT) == 0) { - event_set(&ic->ic_event, ic->ic_fd, EV_READ, nfsdcb, ic); - event_add(&ic->ic_event, NULL); - } + 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)", + xlog_warn("nfsdreopen: Opening '%s' failed: errno %d (%s)", ic->ic_path, errno, strerror(errno)); } } -/* - * Note: nfsdreopen assumes nfsdopen has already been called - */ static void nfsdreopen() { @@ -611,23 +739,19 @@ nfsdreopen() } static int -nfsdopen(char *path) +nfsdopen(void) { - 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]) == 0 && + nfsdopenone(&nfsd_ic[IC_IDNAME]) == 0) ? 0 : -1); } static int -nfsdopenone(struct idmap_client *ic, short which, char *path) +nfsdopenone(struct idmap_client *ic) { - char *whichstr; - - whichstr = which == IC_IDNAME ? "idtoname" : "nametoid"; - 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) { if (verbose > 0) - warnx("Opening %s failed: errno %d (%s)", + xlog_warn("nfsdopenone: Opening %s failed: " + "errno %d (%s)", ic->ic_path, errno, strerror(errno)); return (-1); } @@ -635,12 +759,8 @@ nfsdopenone(struct idmap_client *ic, short which, char *path) event_set(&ic->ic_event, ic->ic_fd, EV_READ, nfsdcb, ic); event_add(&ic->ic_event, NULL); - ic->ic_which = which; - ic->ic_id = "Server"; - strlcpy(ic->ic_clid, domain, sizeof(ic->ic_clid)); - if (verbose > 0) - warnx("Opened %s", ic->ic_path); + xlog_warn("Opened %s", ic->ic_path); return (0); } @@ -656,7 +776,7 @@ nfsopen(struct idmap_client *ic) DN_CREATE | DN_DELETE | DN_MULTISHOT); break; default: - warn("open(%s)", ic->ic_path); + xlog_warn("nfsopen: open(%s): %s", ic->ic_path, strerror(errno)); return (-1); } } else { @@ -665,77 +785,83 @@ nfsopen(struct idmap_client *ic) fcntl(ic->ic_dirfd, F_SETSIG, 0); fcntl(ic->ic_dirfd, F_NOTIFY, 0); if (verbose > 0) - warnx("Opened %s", ic->ic_path); + xlog_warn("Opened %s", ic->ic_path); } return (0); } -static int write_name(char *dest, char *localname, char *domain, size_t len) -{ - if (strlen(localname) + 1 + strlen(domain) + 1 > len) { - return -ENOMEM; /* XXX: Is there an -ETOOLONG? */ - } - strcpy(dest, localname); - strcat(dest, "@"); - strcat(dest, domain); - return 0; -} - 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, sizeof(im->im_name)); - if (ret) - write_name(im->im_name, nobodyuser, domain, - sizeof(im->im_name)); + if (ret) { + if (strlen(nobodyuser) < sizeof(im->im_name)) + strcpy(im->im_name, nobodyuser); + else + strcpy(im->im_name, NFS4NOBODY_USER); + } break; case IDMAP_TYPE_GROUP: ret = nfs4_gid_to_name(im->im_id, domain, im->im_name, sizeof(im->im_name)); - if (ret) - write_name(im->im_name, nobodygroup, domain, - sizeof(im->im_name)); + if (ret) { + if (strlen(nobodygroup) < sizeof(im->im_name)) + strcpy(im->im_name, nobodygroup); + else + strcpy(im->im_name, NFS4NOBODY_GROUP); + } 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. */ - im->im_status = IDMAP_STATUS_SUCCESS; + if (ret) + im->im_status = IDMAP_STATUS_LOOKUPFAIL; + else + im->im_status = IDMAP_STATUS_SUCCESS; } static void nametoidres(struct idmap_msg *im) { + uid_t uid; + gid_t gid; int ret = 0; + /* XXX: move nobody stuff to library calls + * (nfs4_get_nobody_user(domain), nfs4_get_nobody_group(domain)) */ + + im->im_status = IDMAP_STATUS_SUCCESS; + switch (im->im_type) { case IDMAP_TYPE_USER: - ret = nfs4_name_to_uid(im->im_name, &im->im_id); - if (ret) + ret = nfs4_name_to_uid(im->im_name, &uid); + im->im_id = (u_int32_t) uid; + 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, &im->im_id); - if (ret) + ret = nfs4_name_to_gid(im->im_name, &gid); + im->im_id = (u_int32_t) gid; + if (ret) { + im->im_status = IDMAP_STATUS_LOOKUPFAIL; im->im_id = nobodygid; - break; + } + return; } - /* 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. */ - im->im_status = IDMAP_STATUS_SUCCESS; } static int validateascii(char *string, u_int32_t len) { - int i; + u_int32_t i; for (i = 0; i < len; i++) { if (string[i] == '\0') @@ -745,7 +871,7 @@ validateascii(char *string, u_int32_t len) return (-1); } - if (string[i] != '\0') + if ((i >= len) || string[i] != '\0') return (-1); return (i + 1); @@ -791,7 +917,7 @@ static int getfield(char **bpp, char *fld, size_t fldsz) { char *bp; - u_int val, n; + int val, n; while ((bp = strsep(bpp, " ")) != NULL && bp[0] == '\0') ; @@ -820,3 +946,77 @@ 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", errno); + + if ((pid = fork ()) < 0) + err(1, "mydaemon: fork() failed: errno %d", 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", errno); + } + + while (pipefds[1] <= 2) { + pipefds[1] = dup(pipefds[1]); + if (pipefds[1] < 0) + err(1, "mydaemon: dup() failed: errno %d", errno); + } + + if (noclose == 0) { + tempfd = open("/dev/null", O_RDWR); + if (tempfd < 0) + tempfd = open("/", O_RDONLY); + if (tempfd >= 0) { + dup2(tempfd, 0); + dup2(tempfd, 1); + dup2(tempfd, 2); + close(tempfd); + } else { + err(1, "mydaemon: can't open /dev/null: errno %d", + errno); + exit(1); + } + } + + return; +} +void +release_parent(void) +{ + int status; + + if (pipefds[1] > 0) { + if (write(pipefds[1], &status, 1) != 1) { + err(1, "Writing to parent pipe failed: errno %d (%s)\n", + errno, strerror(errno)); + } + close(pipefds[1]); + pipefds[1] = -1; + } +}