[PATCH] Keys: Allow in-kernel key requestor to pass auxiliary data to upcaller

The proposed NFS key type uses its own method of passing key requests to
userspace (upcalling) rather than invoking /sbin/request-key.  This is
because the responsible userspace daemon should already be running and will
be contacted through rpc_pipefs.

This patch permits the NFS filesystem to pass auxiliary data to the upcall
operation (struct key_type::request_key) so that the upcaller can use a
pre-existing communications channel more easily.

Signed-off-by: David Howells <dhowells@redhat.com>
Acked-By: Kevin Coffman <kwc@citi.umich.edu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
diff --git a/security/keys/internal.h b/security/keys/internal.h
index 3c2877f..1bb416f 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -99,6 +99,7 @@
 extern struct key *request_key_and_link(struct key_type *type,
 					const char *description,
 					const char *callout_info,
+					void *aux,
 					struct key *dest_keyring,
 					unsigned long flags);
 
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 329411c..d9ca15c 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -183,7 +183,7 @@
 	}
 
 	/* do the search */
-	key = request_key_and_link(ktype, description, callout_info,
+	key = request_key_and_link(ktype, description, callout_info, NULL,
 				   key_ref_to_ptr(dest_ref),
 				   KEY_ALLOC_IN_QUOTA);
 	if (IS_ERR(key)) {
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index 58d1efd..f573ac1 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -1,6 +1,6 @@
 /* request_key.c: request a key from userspace
  *
- * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-6 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -33,7 +33,8 @@
  */
 static int call_sbin_request_key(struct key *key,
 				 struct key *authkey,
-				 const char *op)
+				 const char *op,
+				 void *aux)
 {
 	struct task_struct *tsk = current;
 	key_serial_t prkey, sskey;
@@ -127,6 +128,7 @@
 static struct key *__request_key_construction(struct key_type *type,
 					      const char *description,
 					      const char *callout_info,
+					      void *aux,
 					      unsigned long flags)
 {
 	request_key_actor_t actor;
@@ -164,7 +166,7 @@
 	actor = call_sbin_request_key;
 	if (type->request_key)
 		actor = type->request_key;
-	ret = actor(key, authkey, "create");
+	ret = actor(key, authkey, "create", aux);
 	if (ret < 0)
 		goto request_failed;
 
@@ -258,8 +260,9 @@
  */
 static struct key *request_key_construction(struct key_type *type,
 					    const char *description,
-					    struct key_user *user,
 					    const char *callout_info,
+					    void *aux,
+					    struct key_user *user,
 					    unsigned long flags)
 {
 	struct key_construction *pcons;
@@ -284,7 +287,7 @@
 	}
 
 	/* see about getting userspace to construct the key */
-	key = __request_key_construction(type, description, callout_info,
+	key = __request_key_construction(type, description, callout_info, aux,
 					 flags);
  error:
 	kleave(" = %p", key);
@@ -392,6 +395,7 @@
 struct key *request_key_and_link(struct key_type *type,
 				 const char *description,
 				 const char *callout_info,
+				 void *aux,
 				 struct key *dest_keyring,
 				 unsigned long flags)
 {
@@ -399,8 +403,9 @@
 	struct key *key;
 	key_ref_t key_ref;
 
-	kenter("%s,%s,%s,%p,%lx",
-	       type->name, description, callout_info, dest_keyring, flags);
+	kenter("%s,%s,%s,%p,%p,%lx",
+	       type->name, description, callout_info, aux,
+	       dest_keyring, flags);
 
 	/* search all the process keyrings for a key */
 	key_ref = search_process_keyrings(type, description, type->match,
@@ -433,8 +438,8 @@
 			/* ask userspace (returns NULL if it waited on a key
 			 * being constructed) */
 			key = request_key_construction(type, description,
-						       user, callout_info,
-						       flags);
+						       callout_info, aux,
+						       user, flags);
 			if (key)
 				break;
 
@@ -491,8 +496,27 @@
 			const char *callout_info)
 {
 	return request_key_and_link(type, description, callout_info, NULL,
-				    KEY_ALLOC_IN_QUOTA);
+				    NULL, KEY_ALLOC_IN_QUOTA);
 
 } /* end request_key() */
 
 EXPORT_SYMBOL(request_key);
+
+/*****************************************************************************/
+/*
+ * request a key with auxiliary data for the upcaller
+ * - search the process's keyrings
+ * - check the list of keys being created or updated
+ * - call out to userspace for a key if supplementary info was provided
+ */
+struct key *request_key_with_auxdata(struct key_type *type,
+				     const char *description,
+				     const char *callout_info,
+				     void *aux)
+{
+	return request_key_and_link(type, description, callout_info, aux,
+				    NULL, KEY_ALLOC_IN_QUOTA);
+
+} /* end request_key_with_auxdata() */
+
+EXPORT_SYMBOL(request_key_with_auxdata);