summary refs log tree commit diff
path: root/net
diff options
context:
space:
mode:
authorTommi Virtanen <tommi.virtanen@dreamhost.com>2011-03-25 16:40:48 -0700
committerSage Weil <sage@newdream.net>2011-03-29 12:11:19 -0700
commite2c3d29b4295c3eec18294bc34f0c99a7b9ae413 (patch)
tree29fbffeeed7e2774a4f87883ae01798079d85ed2 /net
parent8323c3aa74cd92465350294567142d12ffdcc963 (diff)
downloadlinux-e2c3d29b4295c3eec18294bc34f0c99a7b9ae413.tar.gz
libceph: Get secret from the kernel keys api when mounting with key=NAME.
Signed-off-by: Tommi Virtanen <tommi.virtanen@dreamhost.com>
Signed-off-by: Sage Weil <sage@newdream.net>
Diffstat (limited to 'net')
-rw-r--r--net/ceph/Kconfig1
-rw-r--r--net/ceph/ceph_common.c58
2 files changed, 59 insertions, 0 deletions
diff --git a/net/ceph/Kconfig b/net/ceph/Kconfig
index ad424049b0cf..be683f2d401f 100644
--- a/net/ceph/Kconfig
+++ b/net/ceph/Kconfig
@@ -4,6 +4,7 @@ config CEPH_LIB
 	select LIBCRC32C
 	select CRYPTO_AES
 	select CRYPTO
+	select KEYS
 	default n
 	help
 	  Choose Y or M here to include cephlib, which provides the
diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c
index 02e084f29d24..c92bc8d50597 100644
--- a/net/ceph/ceph_common.c
+++ b/net/ceph/ceph_common.c
@@ -5,6 +5,8 @@
 #include <linux/fs.h>
 #include <linux/inet.h>
 #include <linux/in6.h>
+#include <linux/key.h>
+#include <keys/user-type.h>
 #include <linux/module.h>
 #include <linux/mount.h>
 #include <linux/parser.h>
@@ -197,6 +199,7 @@ enum {
 	Opt_fsid,
 	Opt_name,
 	Opt_secret,
+	Opt_key,
 	Opt_ip,
 	Opt_last_string,
 	/* string args above */
@@ -213,6 +216,7 @@ static match_table_t opt_tokens = {
 	{Opt_fsid, "fsid=%s"},
 	{Opt_name, "name=%s"},
 	{Opt_secret, "secret=%s"},
+	{Opt_key, "key=%s"},
 	{Opt_ip, "ip=%s"},
 	/* string args above */
 	{Opt_noshare, "noshare"},
@@ -232,6 +236,50 @@ void ceph_destroy_options(struct ceph_options *opt)
 }
 EXPORT_SYMBOL(ceph_destroy_options);
 
+/* get secret from key store */
+static int get_secret(struct ceph_crypto_key *dst, const char *name) {
+	struct key *ukey;
+	int key_err;
+	int err = 0;
+	struct user_key_payload *payload;
+	void *p;
+
+	ukey = request_key(&key_type_user, name, NULL);
+	if (!ukey || IS_ERR(ukey)) {
+		/* request_key errors don't map nicely to mount(2)
+		   errors; don't even try, but still printk */
+		key_err = PTR_ERR(ukey);
+		switch (key_err) {
+		case -ENOKEY:
+			pr_warning("ceph: Mount failed due to key not found: %s\n", name);
+			break;
+		case -EKEYEXPIRED:
+			pr_warning("ceph: Mount failed due to expired key: %s\n", name);
+			break;
+		case -EKEYREVOKED:
+			pr_warning("ceph: Mount failed due to revoked key: %s\n", name);
+			break;
+		default:
+			pr_warning("ceph: Mount failed due to unknown key error"
+			       " %d: %s\n", key_err, name);
+		}
+		err = -EPERM;
+		goto out;
+	}
+
+	payload = ukey->payload.data;
+	p = payload->data;
+	err = ceph_crypto_key_decode(dst, &p, p + payload->datalen);
+	if (err)
+		goto out_key;
+	/* pass through, err is 0 */
+
+out_key:
+	key_put(ukey);
+out:
+	return err;
+}
+
 int ceph_parse_options(struct ceph_options **popt, char *options,
 		       const char *dev_name, const char *dev_name_end,
 		       int (*parse_extra_token)(char *c, void *private),
@@ -328,6 +376,16 @@ int ceph_parse_options(struct ceph_options **popt, char *options,
 			if (err < 0)
 				goto out;
 			break;
+		case Opt_key:
+		        opt->key = kzalloc(sizeof(*opt->key), GFP_KERNEL);
+			if (!opt->key) {
+				err = -ENOMEM;
+				goto out;
+			}
+			err = get_secret(opt->key, argstr[0].from);
+			if (err < 0)
+				goto out;
+			break;
 
 			/* misc */
 		case Opt_osdtimeout: