Blame SOURCES/nfs-utils-1.3.0-nfsidmap-update.patch

851484
diff --git a/aclocal/keyutils.m4 b/aclocal/keyutils.m4
851484
index a392c0e..16b225d 100644
851484
--- a/aclocal/keyutils.m4
851484
+++ b/aclocal/keyutils.m4
851484
@@ -8,4 +8,8 @@ AC_DEFUN([AC_KEYUTILS], [
851484
 
851484
   AC_CHECK_HEADERS([keyutils.h])
851484
 
851484
+  AC_CHECK_LIB([keyutils], [find_key_by_type_and_desc],
851484
+		[AC_DEFINE([HAVE_FIND_KEY_BY_TYPE_AND_DESC], [1],
851484
+			[Define to 1 if you have the `find_key_by_type_and_desc' function.])],)
851484
+
851484
 ])dnl
851484
diff --git a/utils/nfsidmap/nfsidmap.c b/utils/nfsidmap/nfsidmap.c
851484
index 10f69f9..9c49d42 100644
851484
--- a/utils/nfsidmap/nfsidmap.c
851484
+++ b/utils/nfsidmap/nfsidmap.c
851484
@@ -1,3 +1,4 @@
851484
+#include "config.h"
851484
 
851484
 #include <stdarg.h>
851484
 #include <stdio.h>
851484
@@ -15,7 +16,7 @@
851484
 #include "conffile.h"
851484
 
851484
 int verbose = 0;
851484
-char *usage="Usage: %s [-v] [-c || [-u|-g|-r key] || [-t timeout] key desc]";
851484
+char *usage = "Usage: %s [-v] [-c || [-u|-g|-r key] || -d || -l || [-t timeout] key desc]";
851484
 
851484
 #define MAX_ID_LEN   11
851484
 #define IDMAP_NAMESZ 128
851484
@@ -31,15 +32,163 @@ char *usage="Usage: %s [-v] [-c || [-u|-g|-r key] || [-t timeout] key desc]";
851484
 #define PATH_IDMAPDCONF "/etc/idmapd.conf"
851484
 #endif
851484
 
851484
-static int keyring_clear(char *keyring);
851484
-
851484
 #define UIDKEYS 0x1
851484
 #define GIDKEYS 0x2
851484
 
851484
+#ifndef HAVE_FIND_KEY_BY_TYPE_AND_DESC
851484
+static key_serial_t find_key_by_type_and_desc(const char *type,
851484
+		const char *desc, key_serial_t destringid)
851484
+{
851484
+	char buf[BUFSIZ];
851484
+	key_serial_t key;
851484
+	FILE *fp;
851484
+
851484
+	if ((fp = fopen(PROCKEYS, "r")) == NULL) {
851484
+		xlog_err("fopen(%s) failed: %m", PROCKEYS);
851484
+		return -1;
851484
+	}
851484
+
851484
+	key = -1;
851484
+	while(fgets(buf, BUFSIZ, fp) != NULL) {
851484
+		unsigned int id;
851484
+
851484
+		if (strstr(buf, type) == NULL)
851484
+			continue;
851484
+		if (strstr(buf, desc) == NULL)
851484
+			continue;
851484
+		if (sscanf(buf, "%x %*s", &id) != 1) {
851484
+			xlog_err("Unparsable keyring entry in %s", PROCKEYS);
851484
+			continue;
851484
+		}
851484
+
851484
+		key = (key_serial_t)id;
851484
+		break;
851484
+	}
851484
+
851484
+	fclose(fp);
851484
+	return key;
851484
+}
851484
+#endif
851484
+
851484
+/*
851484
+ * Clear all the keys on the given keyring
851484
+ */
851484
+static int keyring_clear(const char *keyring)
851484
+{
851484
+	key_serial_t key;
851484
+
851484
+	key = find_key_by_type_and_desc("keyring", keyring, 0);
851484
+	if (key == -1) {
851484
+		if (verbose)
851484
+			xlog_warn("'%s' keyring was not found.", keyring);
851484
+		return EXIT_SUCCESS;
851484
+	}
851484
+
851484
+	if (keyctl_clear(key) < 0) {
851484
+		xlog_err("keyctl_clear(0x%x) failed: %m",
851484
+				(unsigned int)key);
851484
+		return EXIT_FAILURE;
851484
+	}
851484
+
851484
+	if (verbose)
851484
+		xlog_warn("'%s' cleared", keyring);
851484
+	return EXIT_SUCCESS;
851484
+}
851484
+
851484
+static int display_default_domain(void)
851484
+{
851484
+	char domain[NFS4_MAX_DOMAIN_LEN];
851484
+	int rc;
851484
+
851484
+	rc = nfs4_get_default_domain(NULL, domain, NFS4_MAX_DOMAIN_LEN);
851484
+	if (rc) {
851484
+		xlog_errno(rc, "nfs4_get_default_domain failed: %m");
851484
+		return EXIT_FAILURE;
851484
+	}
851484
+
851484
+	printf("%s\n", domain);
851484
+	return EXIT_SUCCESS;
851484
+}
851484
+
851484
+static void list_key(key_serial_t key)
851484
+{
851484
+	char *buffer, *c;
851484
+	int rc;
851484
+
851484
+	rc = keyctl_describe_alloc(key, &buffer);
851484
+	if (rc < 0) {
851484
+		switch (errno) {
851484
+		case EKEYEXPIRED:
851484
+			printf("Expired key not displayed\n");
851484
+			break;
851484
+		default:
851484
+			xlog_err("Failed to describe key: %m");
851484
+		}
851484
+		return;
851484
+	}
851484
+
851484
+	c = strrchr(buffer, ';');
851484
+	if (!c) {
851484
+		xlog_err("Unparsable key not displayed\n");
851484
+		goto out_free;
851484
+	}
851484
+	printf("  %s\n", ++c);
851484
+
851484
+out_free:
851484
+	free(buffer);
851484
+}
851484
+
851484
+static void list_keys(const char *ring_name, key_serial_t ring_id)
851484
+{
851484
+	key_serial_t *key;
851484
+	void *keylist;
851484
+	int count;
851484
+
851484
+	count = keyctl_read_alloc(ring_id, &keylist);
851484
+	if (count < 0) {
851484
+		xlog_err("Failed to read keyring %s: %m", ring_name);
851484
+		return;
851484
+	}
851484
+	count /= (int)sizeof(*key);
851484
+
851484
+	switch (count) {
851484
+	case 0:
851484
+		printf("No %s keys found.\n", ring_name);
851484
+		break;
851484
+	case 1:
851484
+		printf("1 %s key found:\n", ring_name);
851484
+		break;
851484
+	default:
851484
+		printf("%u %s keys found:\n", count, ring_name);
851484
+	}
851484
+
851484
+	for (key = keylist; count--; key++)
851484
+		list_key(*key);
851484
+
851484
+	free(keylist);
851484
+}
851484
+
851484
+/*
851484
+ * List all keys on a keyring
851484
+ */
851484
+static int list_keyring(const char *keyring)
851484
+{
851484
+	key_serial_t key;
851484
+
851484
+	key = find_key_by_type_and_desc("keyring", keyring, 0);
851484
+	if (key == -1) {
851484
+		xlog_err("'%s' keyring was not found.", keyring);
851484
+		return EXIT_FAILURE;
851484
+	}
851484
+
851484
+	list_keys(keyring, key);
851484
+	return EXIT_SUCCESS;
851484
+}
851484
+
851484
 /*
851484
  * Find either a user or group id based on the name@domain string
851484
  */
851484
-int id_lookup(char *name_at_domain, key_serial_t key, int type)
851484
+static int id_lookup(char *name_at_domain, key_serial_t key, int type)
851484
 {
851484
 	char id[MAX_ID_LEN];
851484
 	uid_t uid = 0;
851484
@@ -53,30 +202,33 @@ int id_lookup(char *name_at_domain, key_serial_t key, int type)
851484
 		rc = nfs4_group_owner_to_gid(name_at_domain, &gid;;
851484
 		sprintf(id, "%u", gid);
851484
 	}
851484
-	if (rc < 0)
851484
+	if (rc < 0) {
851484
 		xlog_errno(rc, "id_lookup: %s: failed: %m",
851484
 			(type == USER ? "nfs4_owner_to_uid" : "nfs4_group_owner_to_gid"));
851484
+		return EXIT_FAILURE;
851484
+	}
851484
 
851484
-	if (rc == 0) {
851484
-		rc = keyctl_instantiate(key, id, strlen(id) + 1, 0);
851484
-		if (rc < 0) {
851484
-			switch(rc) {
851484
-			case -EDQUOT:
851484
-			case -ENFILE:
851484
-			case -ENOMEM:
851484
-				/*
851484
-			 	 * The keyring is full. Clear the keyring and try again
851484
-			 	 */
851484
-				rc = keyring_clear(DEFAULT_KEYRING);
851484
-				if (rc == 0)
851484
-					rc = keyctl_instantiate(key, id, strlen(id) + 1, 0);
851484
-				break;
851484
-			default:
851484
+	rc = EXIT_SUCCESS;
851484
+	if (keyctl_instantiate(key, id, strlen(id) + 1, 0)) {
851484
+		switch (errno) {
851484
+		case EDQUOT:
851484
+		case ENFILE:
851484
+		case ENOMEM:
851484
+			/*
851484
+			 * The keyring is full. Clear the keyring and try again
851484
+			 */
851484
+			rc = keyring_clear(DEFAULT_KEYRING);
851484
+			if (rc)
851484
 				break;
851484
+			if (keyctl_instantiate(key, id, strlen(id) + 1, 0)) {
851484
+				rc = EXIT_FAILURE;
851484
+				xlog_err("id_lookup: keyctl_instantiate failed: %m");
851484
 			}
851484
+			break;
851484
+		default:
851484
+			rc = EXIT_FAILURE;
851484
+			break;
851484
 		}
851484
-		if (rc < 0)
851484
-			xlog_err("id_lookup: keyctl_instantiate failed: %m");
851484
 	}
851484
 
851484
 	return rc;
851484
@@ -85,7 +237,7 @@ int id_lookup(char *name_at_domain, key_serial_t key, int type)
851484
 /*
851484
  * Find the name@domain string from either a user or group id
851484
  */
851484
-int name_lookup(char *id, key_serial_t key, int type)
851484
+static int name_lookup(char *id, key_serial_t key, int type)
851484
 {
851484
 	char name[IDMAP_NAMESZ];
851484
 	char domain[NFS4_MAX_DOMAIN_LEN];
851484
@@ -94,11 +246,10 @@ int name_lookup(char *id, key_serial_t key, int type)
851484
 	int rc;
851484
 
851484
 	rc = nfs4_get_default_domain(NULL, domain, NFS4_MAX_DOMAIN_LEN);
851484
-	if (rc != 0) {
851484
+	if (rc) {
851484
 		xlog_errno(rc,
851484
 			"name_lookup: nfs4_get_default_domain failed: %m");
851484
-		rc = -1;
851484
-		goto out;
851484
+		return EXIT_FAILURE;
851484
 	}
851484
 
851484
 	if (type == USER) {
851484
@@ -108,61 +259,21 @@ int name_lookup(char *id, key_serial_t key, int type)
851484
 		gid = atoi(id);
851484
 		rc = nfs4_gid_to_name(gid, domain, name, IDMAP_NAMESZ);
851484
 	}
851484
-	if (rc < 0)
851484
+	if (rc) {
851484
 		xlog_errno(rc, "name_lookup: %s: failed: %m",
851484
 			(type == USER ? "nfs4_uid_to_name" : "nfs4_gid_to_name"));
851484
-
851484
-	if (rc == 0) {
851484
-		rc = keyctl_instantiate(key, &name, strlen(name), 0);
851484
-		if (rc < 0)
851484
-			xlog_err("name_lookup: keyctl_instantiate failed: %m");
851484
+		return EXIT_FAILURE;
851484
 	}
851484
-out:
851484
-	return rc;
851484
-}
851484
-/*
851484
- * Clear all the keys on the given keyring
851484
- */
851484
-static int keyring_clear(char *keyring)
851484
-{
851484
-	FILE *fp;
851484
-	char buf[BUFSIZ];
851484
-	key_serial_t key;
851484
 
851484
-	if (keyring == NULL)
851484
-		keyring = DEFAULT_KEYRING;
851484
-
851484
-	if ((fp = fopen(PROCKEYS, "r")) == NULL) {
851484
-		xlog_err("fopen(%s) failed: %m", PROCKEYS);
851484
-		return 1;
851484
+	rc = EXIT_SUCCESS;
851484
+	if (keyctl_instantiate(key, &name, strlen(name), 0)) {
851484
+		rc = EXIT_FAILURE;
851484
+		xlog_err("name_lookup: keyctl_instantiate failed: %m");
851484
 	}
851484
 
851484
-	while(fgets(buf, BUFSIZ, fp) != NULL) {
851484
-		if (strstr(buf, "keyring") == NULL)
851484
-			continue;
851484
-		if (strstr(buf, keyring) == NULL)
851484
-			continue;
851484
-		if (verbose) {
851484
-			*(strchr(buf, '\n')) = '\0';
851484
-			xlog_warn("clearing '%s'", buf);
851484
-		}
851484
-		/*
851484
-		 * The key is the first arugment in the string
851484
-		 */
851484
-		*(strchr(buf, ' ')) = '\0';
851484
-		sscanf(buf, "%x", &key);
851484
-		if (keyctl_clear(key) < 0) {
851484
-			xlog_err("keyctl_clear(0x%x) failed: %m", key);
851484
-			fclose(fp);
851484
-			return 1;
851484
-		}
851484
-		fclose(fp);
851484
-		return 0;
851484
-	}
851484
-	xlog_err("'%s' keyring was not found.", keyring);
851484
-	fclose(fp);
851484
-	return 1;
851484
+	return rc;
851484
 }
851484
+
851484
 /*
851484
  * Revoke a key 
851484
  */
851484
@@ -177,7 +288,7 @@ static int key_invalidate(char *keystr, int keymask)
851484
 
851484
 	if ((fp = fopen(PROCKEYS, "r")) == NULL) {
851484
 		xlog_err("fopen(%s) failed: %m", PROCKEYS);
851484
-		return 1;
851484
+		return EXIT_FAILURE;
851484
 	}
851484
 
851484
 	while(fgets(buf, BUFSIZ, fp) != NULL) {
851484
@@ -211,18 +322,18 @@ static int key_invalidate(char *keystr, int keymask)
851484
 		if (keyctl_invalidate(key) < 0) {
851484
 			xlog_err("keyctl_invalidate(0x%x) failed: %m", key);
851484
 			fclose(fp);
851484
-			return 1;
851484
+			return EXIT_FAILURE;
851484
 		}
851484
 
851484
 		keymask &= ~mask;
851484
 		if (keymask == 0) {
851484
 			fclose(fp);
851484
-			return 0;
851484
+			return EXIT_SUCCESS;
851484
 		}
851484
 	}
851484
 	xlog_err("'%s' key was not found.", keystr);
851484
 	fclose(fp);
851484
-	return 1;
851484
+	return EXIT_FAILURE;
851484
 }
851484
 
851484
 int main(int argc, char **argv)
851484
@@ -234,7 +345,7 @@ int main(int argc, char **argv)
851484
 	int timeout = 600;
851484
 	key_serial_t key;
851484
 	char *progname, *keystr = NULL;
851484
-	int clearing = 0, keymask = 0;
851484
+	int clearing = 0, keymask = 0, display = 0, list = 0;
851484
 
851484
 	/* Set the basename */
851484
 	if ((progname = strrchr(argv[0], '/')) != NULL)
851484
@@ -244,8 +355,14 @@ int main(int argc, char **argv)
851484
 
851484
 	xlog_open(progname);
851484
 
851484
-	while ((opt = getopt(argc, argv, "u:g:r:ct:v")) != -1) {
851484
+	while ((opt = getopt(argc, argv, "du:g:r:ct:vl")) != -1) {
851484
 		switch (opt) {
851484
+		case 'd':
851484
+			display++;
851484
+			break;
851484
+		case 'l':
851484
+			list++;
851484
+			break;
851484
 		case 'u':
851484
 			keymask = UIDKEYS;
851484
 			keystr = strdup(optarg);
851484
@@ -273,28 +390,35 @@ int main(int argc, char **argv)
851484
 		}
851484
 	}
851484
 
851484
+	if (geteuid() != 0) {
851484
+		xlog_err("Must be run as root.");
851484
+		return EXIT_FAILURE;
851484
+	}
851484
+
851484
 	if ((rc = nfs4_init_name_mapping(PATH_IDMAPDCONF)))  {
851484
 		xlog_errno(rc, "Unable to create name to user id mappings.");
851484
-		return 1;
851484
+		return EXIT_FAILURE;
851484
 	}
851484
 	if (!verbose)
851484
 		verbose = conf_get_num("General", "Verbosity", 0);
851484
 
851484
+	if (display)
851484
+		return display_default_domain();
851484
+	if (list)
851484
+		return list_keyring(DEFAULT_KEYRING);
851484
 	if (keystr) {
851484
-		rc = key_invalidate(keystr, keymask);
851484
-		return rc;		
851484
+		return key_invalidate(keystr, keymask);
851484
 	}
851484
 	if (clearing) {
851484
 		xlog_syslog(0);
851484
-		rc = keyring_clear(DEFAULT_KEYRING);
851484
-		return rc;		
851484
+		return keyring_clear(DEFAULT_KEYRING);
851484
 	}
851484
 
851484
-	xlog_stderr(0);
851484
+	xlog_stderr(verbose);
851484
 	if ((argc - optind) != 2) {
851484
-		xlog_err("Bad arg count. Check /etc/request-key.conf");
851484
+		xlog_warn("Bad arg count. Check /etc/request-key.conf");
851484
 		xlog_warn(usage, progname);
851484
-		return 1;
851484
+		return EXIT_FAILURE;
851484
 	}
851484
 
851484
 	if (verbose)
851484
@@ -305,11 +429,15 @@ int main(int argc, char **argv)
851484
 	arg = strdup(argv[optind]);
851484
 	if (arg == NULL) {
851484
 		xlog_err("strdup failed: %m");
851484
-		return 1;
851484
+		return EXIT_FAILURE;
851484
 	}
851484
 	type = strtok(arg, ":");
851484
 	value = strtok(NULL, ":");
851484
-
851484
+	if (value == NULL) {
851484
+		free(arg);
851484
+		xlog_err("Error: Null uid/gid value.");
851484
+		return EXIT_FAILURE;
851484
+	}
851484
 	if (verbose) {
851484
 		xlog_warn("key: 0x%lx type: %s value: %s timeout %ld",
851484
 			key, type, value, timeout);
851484
@@ -328,7 +456,7 @@ int main(int argc, char **argv)
851484
 		rc = name_lookup(value, key, GROUP);
851484
 
851484
 	/* Set timeout to 10 (600 seconds) minutes */
851484
-	if (rc == 0)
851484
+	if (rc == EXIT_SUCCESS)
851484
 		keyctl_set_timeout(key, timeout);
851484
 
851484
 	free(arg);
851484
diff --git a/utils/nfsidmap/nfsidmap.man b/utils/nfsidmap/nfsidmap.man
851484
index 3a3a523..0275bdf 100644
851484
--- a/utils/nfsidmap/nfsidmap.man
851484
+++ b/utils/nfsidmap/nfsidmap.man
851484
@@ -11,30 +11,72 @@ nfsidmap \- The NFS idmapper upcall program
851484
 .B "nfsidmap [-v] [-c]"
851484
 .br
851484
 .B "nfsidmap [-v] [-u|-g|-r user]"
851484
+.br
851484
+.B "nfsidmap -d"
851484
+.br
851484
+.B "nfsidmap -l"
851484
 .SH DESCRIPTION
851484
-The file
851484
+The NFSv4 protocol represents the local system's UID and GID values
851484
+on the wire as strings of the form
851484
+.IR user@domain .
851484
+The process of translating from UID to string and string to UID is
851484
+referred to as "ID mapping."
851484
+.PP
851484
+The system derives the
851484
+.I user
851484
+part of the string by performing a password or group lookup.
851484
+The lookup mechanism is configured in
851484
+.IR /etc/idmapd.conf .
851484
+.PP
851484
+By default, the
851484
+.I domain
851484
+part of the string is the system's DNS domain name.
851484
+It can also be specified in
851484
+.I /etc/idmapd.conf
851484
+if the system is multi-homed,
851484
+or if the system's DNS domain name does
851484
+not match the name of the system's Kerberos realm.
851484
+.PP
851484
+The
851484
 .I /usr/sbin/nfsidmap
851484
-is used by the NFS idmapper to translate user and group ids into names, and to
851484
-translate user and group names into ids. Idmapper uses request-key to perform
851484
-the upcall and cache the result.
851484
+program performs translations on behalf of the kernel.
851484
+The kernel uses the request-key mechanism to perform
851484
+an upcall.
851484
 .I /usr/sbin/nfsidmap
851484
-is called by /sbin/request-key, and will perform the translation and
851484
-initialize a key with the resulting information.
851484
+is invoked by /sbin/request-key, performs the translation,
851484
+and initializes a key with the resulting information.
851484
+The kernel then caches the translation results in the key.
851484
 .PP
851484
 .I nfsidmap
851484
-can also used to clear the keyring of all the keys or 
851484
-revoke one particular key.  
851484
-This is useful when the id mappings have failed to due 
851484
-to a lookup error resulting in all the cached uids/gids to be set 
851484
-to the user id nobody.
851484
+can also clear cached ID map results in the kernel,
851484
+or revoke one particular key.
851484
+An incorrect cached key can result in file and directory ownership
851484
+reverting to "nobody" on NFSv4 mount points.
851484
+.PP
851484
+In addition, the
851484
+.B -d
851484
+and
851484
+.B -l
851484
+options are available to help diagnose misconfigurations.
851484
+They have no effect on the keyring containing ID mapping results.
851484
 .SH OPTIONS
851484
 .TP
851484
 .B -c 
851484
 Clear the keyring of all the keys.
851484
 .TP
851484
+.B -d
851484
+Display the system's effective NFSv4 domain name on
851484
+.IR stdout .
851484
+.TP
851484
 .B -g user
851484
 Revoke the gid key of the given user.
851484
 .TP
851484
+.B -l
851484
+Display on
851484
+.I stdout
851484
+all keys currently in the keyring used to cache ID mapping results.
851484
+These keys are visible only to the superuser.
851484
+.TP
851484
 .B -r user
851484
 Revoke both the uid and gid key of the given user.
851484
 .TP
851484
@@ -89,5 +131,15 @@ Notice that the new line was added above the line for the generic program.
851484
 request-key will find the first matching line and run the corresponding program.
851484
 In this case, /some/other/program will handle all uid lookups, and
851484
 /usr/sbin/nfsidmap will handle gid, user, and group lookups.
851484
+.SH FILES
851484
+.TP
851484
+.I /etc/idmapd.conf
851484
+ID mapping configuration file
851484
+.TP
851484
+.I /etc/request-key.conf
851484
+Request key configuration file
851484
+.SH "SEE ALSO"
851484
+.BR idmapd.conf (5),
851484
+.BR request-key (8)
851484
 .SH AUTHOR
851484
 Bryan Schumaker, <bjschuma@netapp.com>