]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/cifs/cifs_spnego.c
cifs: Create dedicated keyring for spnego operations
[karo-tx-linux.git] / fs / cifs / cifs_spnego.c
index 6908080e9b6d889f323d21da24892046f7fd16a0..b611fc2e8984e0fce26c08367b1306764685054a 100644 (file)
 #include <linux/string.h>
 #include <keys/user-type.h>
 #include <linux/key-type.h>
+#include <linux/keyctl.h>
 #include <linux/inet.h>
 #include "cifsglob.h"
 #include "cifs_spnego.h"
 #include "cifs_debug.h"
+#include "cifsproto.h"
+static const struct cred *spnego_cred;
 
 /* create a new cifs key */
 static int
@@ -102,6 +105,7 @@ cifs_get_spnego_key(struct cifs_ses *sesInfo)
        size_t desc_len;
        struct key *spnego_key;
        const char *hostname = server->hostname;
+       const struct cred *saved_cred;
 
        /* length of fields (with semicolons): ver=0xyz ip4=ipaddress
           host=hostname sec=mechanism uid=0xFF user=username */
@@ -163,7 +167,9 @@ cifs_get_spnego_key(struct cifs_ses *sesInfo)
        sprintf(dp, ";pid=0x%x", current->pid);
 
        cifs_dbg(FYI, "key description = %s\n", description);
+       saved_cred = override_creds(spnego_cred);
        spnego_key = request_key(&cifs_spnego_key_type, description, "");
+       revert_creds(saved_cred);
 
 #ifdef CONFIG_CIFS_DEBUG2
        if (cifsFYI && !IS_ERR(spnego_key)) {
@@ -177,3 +183,64 @@ out:
        kfree(description);
        return spnego_key;
 }
+
+int
+init_cifs_spnego(void)
+{
+       struct cred *cred;
+       struct key *keyring;
+       int ret;
+
+       cifs_dbg(FYI, "Registering the %s key type\n",
+                cifs_spnego_key_type.name);
+
+       /*
+        * Create an override credential set with special thread keyring for
+        * spnego upcalls.
+        */
+
+       cred = prepare_kernel_cred(NULL);
+       if (!cred)
+               return -ENOMEM;
+
+       keyring = keyring_alloc(".cifs_spnego",
+                               GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
+                               (KEY_POS_ALL & ~KEY_POS_SETATTR) |
+                               KEY_USR_VIEW | KEY_USR_READ,
+                               KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
+       if (IS_ERR(keyring)) {
+               ret = PTR_ERR(keyring);
+               goto failed_put_cred;
+       }
+
+       ret = register_key_type(&cifs_spnego_key_type);
+       if (ret < 0)
+               goto failed_put_key;
+
+       /*
+        * instruct request_key() to use this special keyring as a cache for
+        * the results it looks up
+        */
+       set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
+       cred->thread_keyring = keyring;
+       cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
+       spnego_cred = cred;
+
+       cifs_dbg(FYI, "cifs spnego keyring: %d\n", key_serial(keyring));
+       return 0;
+
+failed_put_key:
+       key_put(keyring);
+failed_put_cred:
+       put_cred(cred);
+       return ret;
+}
+
+void
+exit_cifs_spnego(void)
+{
+       key_revoke(spnego_cred->thread_keyring);
+       unregister_key_type(&cifs_spnego_key_type);
+       put_cred(spnego_cred);
+       cifs_dbg(FYI, "Unregistered %s key type\n", cifs_spnego_key_type.name);
+}