[PATCH] nfsidmap: use multiple child keyrings

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The kernel keyring has a max of ~508 entries on 64-bit systems.
For installations with more distict users than this limit, create
a specified number of child keyrings and fill them evenly.
---
 utils/nfsidmap/nfsidmap.c   |   76 +++++++++++++++++++++++++++++++++---------
 utils/nfsidmap/nfsidmap.man |    5 ++-
 2 files changed, 63 insertions(+), 18 deletions(-)

diff --git a/utils/nfsidmap/nfsidmap.c b/utils/nfsidmap/nfsidmap.c
index 2518ed6..41abede 100644
--- a/utils/nfsidmap/nfsidmap.c
+++ b/utils/nfsidmap/nfsidmap.c
@@ -15,7 +15,7 @@
 #include "conffile.h"
 
 int verbose = 0;
-char *usage="Usage: %s [-v] [-c || [-u|-g|-r key] || [-t timeout] key desc]";
+char *usage="Usage: %s [-v] [-c || [-u|-g|-r key] || [-t timeout] [-n count] key desc]";
 
 #define MAX_ID_LEN   11
 #define IDMAP_NAMESZ 128
@@ -24,7 +24,7 @@ char *usage="Usage: %s [-v] [-c || [-u|-g|-r key] || [-t timeout] key desc]";
 
 #define PROCKEYS "/proc/keys"
 #ifndef DEFAULT_KEYRING
-#define DEFAULT_KEYRING "id_resolver"
+#define DEFAULT_KEYRING ".id_resolver"
 #endif
 
 #ifndef PATH_IDMAPDCONF
@@ -39,7 +39,7 @@ static int keyring_clear(char *keyring);
 /*
  * Find either a user or group id based on the name@domain string
  */
-int id_lookup(char *name_at_domain, key_serial_t key, int type)
+int id_lookup(char *name_at_domain, key_serial_t key, int type, key_serial_t dest_keyring)
 {
 	char id[MAX_ID_LEN];
 	uid_t uid = 0;
@@ -58,7 +58,7 @@ int id_lookup(char *name_at_domain, key_serial_t key, int type)
 			(type == USER ? "nfs4_owner_to_uid" : "nfs4_group_owner_to_gid"));
 
 	if (rc == 0) {
-		rc = keyctl_instantiate(key, id, strlen(id) + 1, 0);
+		rc = keyctl_instantiate(key, id, strlen(id) + 1, dest_keyring);
 		if (rc < 0) {
 			switch(rc) {
 			case -EDQUOT:
@@ -67,9 +67,9 @@ int id_lookup(char *name_at_domain, key_serial_t key, int type)
 				/*
 			 	 * The keyring is full. Clear the keyring and try again
 			 	 */
-				rc = keyring_clear(DEFAULT_KEYRING);
+				rc = keyctl_clear(dest_keyring);
 				if (rc == 0)
-					rc = keyctl_instantiate(key, id, strlen(id) + 1, 0);
+					rc = keyctl_instantiate(key, id, strlen(id) + 1, dest_keyring);
 				break;
 			default:
 				break;
@@ -85,7 +85,7 @@ int id_lookup(char *name_at_domain, key_serial_t key, int type)
 /*
  * Find the name@domain string from either a user or group id
  */
-int name_lookup(char *id, key_serial_t key, int type)
+int name_lookup(char *id, key_serial_t key, int type, key_serial_t dest_keyring)
 {
 	char name[IDMAP_NAMESZ];
 	char domain[NFS4_MAX_DOMAIN_LEN];
@@ -113,7 +113,7 @@ int name_lookup(char *id, key_serial_t key, int type)
 			(type == USER ? "nfs4_uid_to_name" : "nfs4_gid_to_name"));
 
 	if (rc == 0) {
-		rc = keyctl_instantiate(key, &name, strlen(name), 0);
+		rc = keyctl_instantiate(key, &name, strlen(name), dest_keyring);
 		if (rc < 0)
 			xlog_err("name_lookup: keyctl_instantiate failed: %m");
 	}
@@ -127,7 +127,7 @@ static int keyring_clear(char *keyring)
 {
 	FILE *fp;
 	char buf[BUFSIZ];
-	key_serial_t key;
+	key_serial_t key, child_key;
 
 	if (keyring == NULL)
 		keyring = DEFAULT_KEYRING;
@@ -151,6 +151,7 @@ static int keyring_clear(char *keyring)
 		 */
 		*(strchr(buf, ' ')) = '\0';
 		sscanf(buf, "%x", &key);
+
 		if (keyctl_clear(key) < 0) {
 			xlog_err("keyctl_clear(0x%x) failed: %m", key);
 			fclose(fp);
@@ -159,7 +160,8 @@ static int keyring_clear(char *keyring)
 		fclose(fp);
 		return 0;
 	}
-	xlog_err("'%s' keyring was not found.", keyring);
+	if (strstr(keyring, DEFAULT_KEYRING":"))
+		xlog_err("'%s' keyring was not found.", keyring);
 	fclose(fp);
 	return 1;
 }
@@ -232,8 +234,10 @@ int main(int argc, char **argv)
 	char *type;
 	int rc = 1, opt;
 	int timeout = 600;
-	key_serial_t key;
+	int childrings = 0;
+	key_serial_t key, parent_keyring, dest_keyring;
 	char *progname, *keystr = NULL;
+	char child_name[BUFSIZ];
 	int clearing = 0, keymask = 0;
 
 	/* Set the basename */
@@ -244,7 +248,7 @@ int main(int argc, char **argv)
 
 	xlog_open(progname);
 
-	while ((opt = getopt(argc, argv, "u:g:r:ct:v")) != -1) {
+	while ((opt = getopt(argc, argv, "u:g:r:ct:vn:d:")) != -1) {
 		switch (opt) {
 		case 'u':
 			keymask = UIDKEYS;
@@ -267,6 +271,9 @@ int main(int argc, char **argv)
 		case 't':
 			timeout = atoi(optarg);
 			break;
+		case 'n':
+			childrings = atoi(optarg);
+			break;
 		default:
 			xlog_warn(usage, progname);
 			break;
@@ -284,9 +291,16 @@ int main(int argc, char **argv)
 		rc = key_revoke(keystr, keymask);
 		return rc;		
 	}
+
 	if (clearing) {
 		xlog_syslog(0);
-		rc = keyring_clear(DEFAULT_KEYRING);
+		int i = 1;
+		for(rc = 0; rc == 0; i++) {
+			snprintf(child_name, sizeof(child_name), DEFAULT_KEYRING "_child_%d", i);
+			rc = keyring_clear(child_name);
+		}
+
+		rc = keyring_clear(DEFAULT_KEYRING ":");
 		return rc;		
 	}
 
@@ -315,14 +329,42 @@ int main(int argc, char **argv)
 			key, type, value, timeout);
 	}
 
+	if (childrings) {
+		int i;
+		long child_size, smallest_size = 2032;
+		parent_keyring = request_key("keyring", DEFAULT_KEYRING, NULL, KEY_SPEC_THREAD_KEYRING);
+
+		for (i = 1; i <= childrings; i++) {
+			key_serial_t child_keyring;
+
+			snprintf(child_name, sizeof(child_name), DEFAULT_KEYRING "_child_%d", i);
+
+			child_keyring = keyctl_search(parent_keyring, "keyring", child_name, 0);
+			if (child_keyring < 0) {
+				child_keyring = add_key("keyring", child_name, NULL, 0, parent_keyring);
+				xlog_warn("added new child %s: %m", child_name);
+			}
+
+			child_size = keyctl_read(child_keyring, NULL, 0);
+			if (child_size < smallest_size) {
+				dest_keyring = child_keyring;
+				smallest_size = child_size;
+			}
+		}
+	}
+
 	if (strcmp(type, "uid") == 0)
-		rc = id_lookup(value, key, USER);
+		rc = id_lookup(value, key, USER, dest_keyring);
 	else if (strcmp(type, "gid") == 0)
-		rc = id_lookup(value, key, GROUP);
+		rc = id_lookup(value, key, GROUP, dest_keyring);
 	else if (strcmp(type, "user") == 0)
-		rc = name_lookup(value, key, USER);
+		rc = name_lookup(value, key, USER, dest_keyring);
 	else if (strcmp(type, "group") == 0)
-		rc = name_lookup(value, key, GROUP);
+		rc = name_lookup(value, key, GROUP, dest_keyring);
+
+	/* if we hung this off a child, unlink from the parent */
+	if (dest_keyring)
+		keyctl_unlink(key, parent_keyring);
 
 	/* Set timeout to 10 (600 seconds) minutes */
 	if (rc == 0)
diff --git a/utils/nfsidmap/nfsidmap.man b/utils/nfsidmap/nfsidmap.man
index 3a3a523..04f0014 100644
--- a/utils/nfsidmap/nfsidmap.man
+++ b/utils/nfsidmap/nfsidmap.man
@@ -6,7 +6,7 @@
 .SH NAME
 nfsidmap \- The NFS idmapper upcall program
 .SH SYNOPSIS
-.B "nfsidmap [-v] [-t timeout] key desc"
+.B "nfsidmap [-v] [-t timeout] [-n count] key desc"
 .br
 .B "nfsidmap [-v] [-c]"
 .br
@@ -42,6 +42,9 @@ Revoke both the uid and gid key of the given user.
 Set the expiration timer, in seconds, on the key.
 The default is 600 seconds (10 mins).
 .TP
+.B -n count
+Set the the number of child keyrings to create.
+.TP
 .B -u user
 Revoke the uid key of the given user.
 .TP
-- 
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux