diff --git a/configure.ac b/configure.ac index 80fb39d..f101b86 100644 --- a/configure.ac +++ b/configure.ac @@ -265,6 +265,12 @@ if test "$enable_nfsv4" = yes; then AC_RPCSEC_VERSION fi fi + +if test "$enable_nfsv41" = yes; then + AC_CHECK_LIB([devmapper], [dm_task_create], [LIBDEVMAPPER="-ldevmapper"], AC_MSG_ERROR([libdevmapper needed])) + AC_CHECK_HEADER(libdevmapper.h, , AC_MSG_ERROR([Cannot find devmapper header file libdevmapper.h])) +fi + dnl enable nfsidmap when its support by libnfsidmap AM_CONDITIONAL(CONFIG_NFSIDMAP, [test "$ac_cv_header_keyutils_h$ac_cv_lib_nfsidmap_nfs4_owner_to_uid" = "yesyes"]) diff --git a/support/include/nfs/debug.h b/support/include/nfs/debug.h index d391e91..dbec5ba 100644 --- a/support/include/nfs/debug.h +++ b/support/include/nfs/debug.h @@ -76,6 +76,9 @@ enum { #define NFSDBG_CALLBACK 0x0100 #define NFSDBG_CLIENT 0x0200 #define NFSDBG_MOUNT 0x0400 +#define NFSDBG_FSCACHE 0x0800 +#define NFSDBG_PNFS 0x1000 +#define NFSDBG_PNFS_LD 0x2000 #define NFSDBG_ALL 0xFFFF #endif /* _NFS_DEBUG_H */ diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c index fa0dc6b..3990578 100644 --- a/support/nfs/conffile.c +++ b/support/nfs/conffile.c @@ -256,13 +256,14 @@ conf_parse_line(int trans, char *line, size_t sz) val++, j++; if (*val) i = j; - section = malloc(i); + section = malloc(i+1); if (!section) { xlog_warn("conf_parse_line: %d: malloc (%lu) failed", ln, (unsigned long)i); return; } strncpy(section, line, i); + section[i] = '\0'; if (arg) free(arg); diff --git a/tools/rpcdebug/rpcdebug.c b/tools/rpcdebug/rpcdebug.c index 275a491..444616d 100644 --- a/tools/rpcdebug/rpcdebug.c +++ b/tools/rpcdebug/rpcdebug.c @@ -167,6 +167,9 @@ static struct flagmap { FLAG(NFS, CALLBACK), FLAG(NFS, CLIENT), FLAG(NFS, MOUNT), + FLAG(NFS, FSCACHE), + FLAG(NFS, PNFS), + FLAG(NFS, PNFS_LD), FLAG(NFS, ALL), /* nfsd */ diff --git a/utils/blkmapd/device-process.c b/utils/blkmapd/device-process.c index 27ff374..652a7a8 100644 --- a/utils/blkmapd/device-process.c +++ b/utils/blkmapd/device-process.c @@ -296,7 +296,7 @@ decode_blk_volume(uint32_t **pp, uint32_t *end, struct bl_volume *vols, int voln off_t stripe_unit = vol->param.bv_stripe_unit; /* Check limitations imposed by device-mapper */ if ((stripe_unit & (stripe_unit - 1)) != 0 - || stripe_unit < (off_t) (PAGE_SIZE >> 9)) + || stripe_unit < (off_t) (sysconf(_SC_PAGE_SIZE) >> 9)) return -EIO; BLK_READBUF(p, end, 4); READ32(vol->bv_vol_n); diff --git a/utils/exportfs/exportfs.man b/utils/exportfs/exportfs.man index 364f247..8853486 100644 --- a/utils/exportfs/exportfs.man +++ b/utils/exportfs/exportfs.man @@ -177,7 +177,7 @@ In this way .B exportfs can be used to modify the export options of an already exported directory. .SS Unexporting Directories -The third synopsis shows how to unexported a currently exported directory. +The third synopsis shows how to unexport a currently exported directory. When using .BR "exportfs -ua" , all entries listed in diff --git a/utils/exportfs/nfsd.man b/utils/exportfs/nfsd.man index 7365a1b..47b73be 100644 --- a/utils/exportfs/nfsd.man +++ b/utils/exportfs/nfsd.man @@ -12,7 +12,7 @@ nfsd \- special filesystem for controlling Linux NFS server .SH DESCRIPTION The .B nfsd -filesytem is a special filesystem which provides access to the Linux +filesystem is a special filesystem which provides access to the Linux NFS server. The filesystem consists of a single directory which contains a number of files. These files are actually gateways into the NFS server. Writing to them can affect the server. Reading from @@ -86,7 +86,7 @@ should be followed by a newline, with white-space separating the fields, and octal quoting of special characters. On writing this, the program will be able to read back a filehandle -for that path as exported to the given client. The filehandles length +for that path as exported to the given client. The filehandle's length will be at most the number of bytes given. The filehandle will be represented in hex with a leading '\ex'. @@ -165,7 +165,7 @@ file. The user-space program might then write .ti +5 nfsd 127.0.0.1 1057206953 localhost .br -to indicate that 127.0.0.1 should map to localhost, atleast for now. +to indicate that 127.0.0.1 should map to localhost, at least for now. If the program uses select(2) or poll(2) to discover if it can read from the diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c index 19d9114..e80efb4 100644 --- a/utils/idmapd/idmapd.c +++ b/utils/idmapd/idmapd.c @@ -778,8 +778,8 @@ nfsopen(struct idmap_client *ic) } else { event_set(&ic->ic_event, ic->ic_fd, EV_READ, nfscb, ic); event_add(&ic->ic_event, NULL); - fcntl(ic->ic_dirfd, F_SETSIG, 0); fcntl(ic->ic_dirfd, F_NOTIFY, 0); + fcntl(ic->ic_dirfd, F_SETSIG, 0); if (verbose > 0) xlog_warn("Opened %s", ic->ic_path); } diff --git a/utils/mount/nfs.man b/utils/mount/nfs.man index ce40933..2ad92d1 100644 --- a/utils/mount/nfs.man +++ b/utils/mount/nfs.man @@ -1561,10 +1561,10 @@ To ensure that the saved mount options are not erased during a remount, specify either the local mount directory, or the server hostname and export pathname, but not both, during a remount. For example, .P -.NF -.TA 2.5i +.nf +.ta 8n mount -o remount,ro /mnt -.FI +.fi .P merges the mount option .B ro diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c index 314a806..d52e21a 100644 --- a/utils/mount/stropts.c +++ b/utils/mount/stropts.c @@ -540,6 +540,8 @@ nfs_rewrite_pmap_mount_options(struct mount_options *options) errno = EOPNOTSUPP; else if (rpc_createerr.cf_stat == RPC_AUTHERROR) errno = EACCES; + else if (rpc_createerr.cf_stat == RPC_TIMEDOUT) + errno = ETIMEDOUT; else if (rpc_createerr.cf_error.re_errno != 0) errno = rpc_createerr.cf_error.re_errno; return 0; @@ -665,9 +667,10 @@ static int nfs_try_mount_v3v2(struct nfsmount_info *mi) case EHOSTUNREACH: continue; default: - break; + goto out; } } +out: return ret; } @@ -751,9 +754,10 @@ static int nfs_try_mount_v4(struct nfsmount_info *mi) case EHOSTUNREACH: continue; default: - break; + goto out; } } +out: return ret; } diff --git a/utils/nfsd/nfsd.man b/utils/nfsd/nfsd.man index d8988d2..1cf9296 100644 --- a/utils/nfsd/nfsd.man +++ b/utils/nfsd/nfsd.man @@ -38,7 +38,7 @@ request on all known network addresses. This may change in future releases of the Linux Kernel. .TP .B \-p " or " \-\-port port -specify a diferent port to listen on for NFS requests. By default, +specify a different port to listen on for NFS requests. By default, .B rpc.nfsd will listen on port 2049. .TP diff --git a/utils/nfsidmap/Makefile.am b/utils/nfsidmap/Makefile.am index f837b91..037aa79 100644 --- a/utils/nfsidmap/Makefile.am +++ b/utils/nfsidmap/Makefile.am @@ -4,6 +4,6 @@ man8_MANS = nfsidmap.man sbin_PROGRAMS = nfsidmap nfsidmap_SOURCES = nfsidmap.c -nfsidmap_LDADD = -lnfsidmap -lkeyutils +nfsidmap_LDADD = -lnfsidmap -lkeyutils ../../support/nfs/libnfs.a MAINTAINERCLEANFILES = Makefile.in diff --git a/utils/nfsidmap/nfsidmap.c b/utils/nfsidmap/nfsidmap.c index 2d87381..ce8cf3e 100644 --- a/utils/nfsidmap/nfsidmap.c +++ b/utils/nfsidmap/nfsidmap.c @@ -9,15 +9,25 @@ #include #include -#include +#include +#include "xlog.h" -/* gcc nfsidmap.c -o nfsidmap -l nfsidmap -l keyutils */ +int verbose = 0; +char *usage="Usage: %s [-v] [-c || [-u|-g|-r key] || [-t timeout] key desc]"; #define MAX_ID_LEN 11 #define IDMAP_NAMESZ 128 #define USER 1 #define GROUP 0 +#define PROCKEYS "/proc/keys" +#ifndef DEFAULT_KEYRING +#define DEFAULT_KEYRING "id_resolver" +#endif + + +#define UIDKEYS 0x1 +#define GIDKEYS 0x2 /* * Find either a user or group id based on the name@domain string @@ -36,9 +46,15 @@ int id_lookup(char *name_at_domain, key_serial_t key, int type) rc = nfs4_group_owner_to_gid(name_at_domain, &gid); sprintf(id, "%u", gid); } + if (rc < 0) + xlog_err("id_lookup: %s: failed: %m", + (type == USER ? "nfs4_owner_to_uid" : "nfs4_group_owner_to_gid")); - if (rc == 0) + if (rc == 0) { rc = keyctl_instantiate(key, id, strlen(id) + 1, 0); + if (rc < 0) + xlog_err("id_lookup: keyctl_instantiate failed: %m"); + } return rc; } @@ -57,6 +73,7 @@ int name_lookup(char *id, key_serial_t key, int type) rc = nfs4_get_default_domain(NULL, domain, NFS4_MAX_DOMAIN_LEN); if (rc != 0) { rc = -1; + xlog_err("name_lookup: nfs4_get_default_domain failed: %m"); goto out; } @@ -67,39 +84,206 @@ int name_lookup(char *id, key_serial_t key, int type) gid = atoi(id); rc = nfs4_gid_to_name(gid, domain, name, IDMAP_NAMESZ); } + if (rc < 0) + xlog_err("name_lookup: %s: failed: %m", + (type == USER ? "nfs4_uid_to_name" : "nfs4_gid_to_name")); - if (rc == 0) + if (rc == 0) { rc = keyctl_instantiate(key, &name, strlen(name), 0); - + if (rc < 0) + xlog_err("name_lookup: keyctl_instantiate failed: %m"); + } out: return rc; } +/* + * Clear all the keys on the given keyring + */ +static int keyring_clear(char *keyring) +{ + FILE *fp; + char buf[BUFSIZ]; + key_serial_t key; + + xlog_syslog(0); + if (keyring == NULL) + keyring = DEFAULT_KEYRING; + + if ((fp = fopen(PROCKEYS, "r")) == NULL) { + xlog_err("fopen(%s) failed: %m", PROCKEYS); + return 1; + } + + while(fgets(buf, BUFSIZ, fp) != NULL) { + if (strstr(buf, "keyring") == NULL) + continue; + if (strstr(buf, keyring) == NULL) + continue; + if (verbose) { + *(strchr(buf, '\n')) = '\0'; + xlog_warn("clearing '%s'", buf); + } + /* + * The key is the first arugment in the string + */ + *(strchr(buf, ' ')) = '\0'; + sscanf(buf, "%x", &key); + if (keyctl_clear(key) < 0) { + xlog_err("keyctl_clear(0x%x) failed: %m", key); + fclose(fp); + return 1; + } + fclose(fp); + return 0; + } + xlog_err("'%s' keyring was not found.", keyring); + fclose(fp); + return 1; +} +/* + * Revoke a key + */ +static int key_revoke(char *keystr, int keymask) +{ + FILE *fp; + char buf[BUFSIZ], *ptr; + key_serial_t key; + int mask; + + xlog_syslog(0); + + if ((fp = fopen(PROCKEYS, "r")) == NULL) { + xlog_err("fopen(%s) failed: %m", PROCKEYS); + return 1; + } + + while(fgets(buf, BUFSIZ, fp) != NULL) { + if (strstr(buf, "keyring") != NULL) + continue; + + mask = 0; + if ((ptr = strstr(buf, "uid:")) != NULL) + mask = UIDKEYS; + else if ((ptr = strstr(buf, "gid:")) != NULL) + mask = GIDKEYS; + else + continue; + + if ((keymask & mask) == 0) + continue; + + if (strncmp(ptr+4, keystr, strlen(keystr)) != NULL) + continue; + + if (verbose) { + *(strchr(buf, '\n')) = '\0'; + xlog_warn("revoking '%s'", buf); + } + /* + * The key is the first arugment in the string + */ + *(strchr(buf, ' ')) = '\0'; + sscanf(buf, "%x", &key); + + if (keyctl_revoke(key) < 0) { + xlog_err("keyctl_revoke(0x%x) failed: %m", key); + fclose(fp); + return 1; + } + + keymask &= ~mask; + if (keymask == 0) { + fclose(fp); + return 0; + } + } + xlog_err("'%s' key was not found.", keystr); + fclose(fp); + return 1; +} int main(int argc, char **argv) { char *arg; char *value; char *type; - int rc = 1; + int rc = 1, opt; int timeout = 600; key_serial_t key; + char *progname, *keystr = NULL; + int clearing = 0, keymask = 0; + + /* Set the basename */ + if ((progname = strrchr(argv[0], '/')) != NULL) + progname++; + else + progname = argv[0]; - if (argc < 3) + xlog_open(progname); + + while ((opt = getopt(argc, argv, "u:g:r:ct:v")) != -1) { + switch (opt) { + case 'u': + keymask = UIDKEYS; + keystr = strdup(optarg); + break; + case 'g': + keymask = GIDKEYS; + keystr = strdup(optarg); + break; + case 'r': + keymask = GIDKEYS|UIDKEYS; + keystr = strdup(optarg); + break; + case 'c': + clearing++; + break; + case 'v': + verbose++; + break; + case 't': + timeout = atoi(optarg); + break; + default: + xlog_warn(usage, progname); + break; + } + } + + if (keystr) { + rc = key_revoke(keystr, keymask); + return rc; + } + if (clearing) { + rc = keyring_clear(DEFAULT_KEYRING); + return rc; + } + + xlog_stderr(0); + if ((argc - optind) != 2) { + xlog_err("Bad arg count. Check /etc/request-key.conf"); + xlog_warn(usage, progname); return 1; + } + + if (verbose) + nfs4_set_debug(verbose, NULL); + + key = strtol(argv[optind++], NULL, 10); - arg = malloc(sizeof(char) * strlen(argv[2]) + 1); - strcpy(arg, argv[2]); + arg = strdup(argv[optind]); + if (arg == NULL) { + xlog_err("strdup failed: %m"); + return 1; + } type = strtok(arg, ":"); value = strtok(NULL, ":"); - if (argc == 4) { - timeout = atoi(argv[3]); - if (timeout < 0) - timeout = 0; + if (verbose) { + xlog_warn("key: %ld type: %s value: %s timeout %ld", + key, type, value, timeout); } - key = strtol(argv[1], NULL, 10); - if (strcmp(type, "uid") == 0) rc = id_lookup(value, key, USER); else if (strcmp(type, "gid") == 0) @@ -109,7 +293,7 @@ int main(int argc, char **argv) else if (strcmp(type, "group") == 0) rc = name_lookup(value, key, GROUP); - /* Set timeout to 5 (600 seconds) minutes */ + /* Set timeout to 10 (600 seconds) minutes */ if (rc == 0) keyctl_set_timeout(key, timeout); diff --git a/utils/nfsidmap/nfsidmap.man b/utils/nfsidmap/nfsidmap.man index 2381908..3a3a523 100644 --- a/utils/nfsidmap/nfsidmap.man +++ b/utils/nfsidmap/nfsidmap.man @@ -5,6 +5,12 @@ .TH nfsidmap 5 "1 October 2010" .SH NAME nfsidmap \- The NFS idmapper upcall program +.SH SYNOPSIS +.B "nfsidmap [-v] [-t timeout] key desc" +.br +.B "nfsidmap [-v] [-c]" +.br +.B "nfsidmap [-v] [-u|-g|-r user]" .SH DESCRIPTION The file .I /usr/sbin/nfsidmap @@ -12,11 +18,36 @@ is used by the NFS idmapper to translate user and group ids into names, and to translate user and group names into ids. Idmapper uses request-key to perform the upcall and cache the result. .I /usr/sbin/nfsidmap -should only be called by request-key, and will perform the translation and +is called by /sbin/request-key, and will perform the translation and initialize a key with the resulting information. .PP -NFS_USE_NEW_IDMAPPER must be selected when configuring the kernel to use this -feature. +.I nfsidmap +can also used to clear the keyring of all the keys or +revoke one particular key. +This is useful when the id mappings have failed to due +to a lookup error resulting in all the cached uids/gids to be set +to the user id nobody. +.SH OPTIONS +.TP +.B -c +Clear the keyring of all the keys. +.TP +.B -g user +Revoke the gid key of the given user. +.TP +.B -r user +Revoke both the uid and gid key of the given user. +.TP +.B -t timeout +Set the expiration timer, in seconds, on the key. +The default is 600 seconds (10 mins). +.TP +.B -u user +Revoke the uid key of the given user. +.TP +.B -v +Increases the verbosity of the output to syslog +(can be specified multiple times). .SH CONFIGURING The file .I /etc/request-key.conf @@ -25,11 +56,13 @@ will need to be modified so can properly direct the upcall. The following line should be added before a call to keyctl negate: .PP -create id_resolver * * /usr/sbin/nfsidmap %k %d 600 +create id_resolver * * /usr/sbin/nfsidmap -t 600 %k %d .PP This will direct all id_resolver requests to the program -.I /usr/sbin/nfsidmap -The last parameter, 600, defines how many seconds into the future the key will +.I /usr/sbin/nfsidmap. +The +.B -t 600 +defines how many seconds into the future the key will expire. This is an optional parameter for .I /usr/sbin/nfsidmap and will default to 600 seconds when not specified. @@ -48,9 +81,9 @@ You can choose to handle any of these individually, rather than using the generic upcall program. If you would like to use your own program for a uid lookup then you would edit your request-key.conf so it looks similar to this: .PP -create id_resolver uid:* * /some/other/program %k %d 600 +create id_resolver uid:* * /some/other/program %k %d .br -create id_resolver * * /usr/sbin/nfsidmap %k %d 600 +create id_resolver * * /usr/sbin/nfsidmap %k %d .PP Notice that the new line was added above the line for the generic program. request-key will find the first matching line and run the corresponding program.