| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* user_defined.c: user defined key type | 
 | 2 |  * | 
 | 3 |  * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | 
 | 4 |  * Written by David Howells (dhowells@redhat.com) | 
 | 5 |  * | 
 | 6 |  * This program is free software; you can redistribute it and/or | 
 | 7 |  * modify it under the terms of the GNU General Public License | 
 | 8 |  * as published by the Free Software Foundation; either version | 
 | 9 |  * 2 of the License, or (at your option) any later version. | 
 | 10 |  */ | 
 | 11 |  | 
 | 12 | #include <linux/module.h> | 
 | 13 | #include <linux/init.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 14 | #include <linux/slab.h> | 
 | 15 | #include <linux/seq_file.h> | 
 | 16 | #include <linux/err.h> | 
| David Howells | 2aa349f | 2005-10-30 15:02:42 -0800 | [diff] [blame] | 17 | #include <keys/user-type.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 18 | #include <asm/uaccess.h> | 
 | 19 | #include "internal.h" | 
 | 20 |  | 
| Jeff Layton | 9f6ed2c | 2012-01-17 16:09:11 -0500 | [diff] [blame] | 21 | static int logon_vet_description(const char *desc); | 
 | 22 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 23 | /* | 
 | 24 |  * user defined keys take an arbitrary string as the description and an | 
 | 25 |  * arbitrary blob of data as the payload | 
 | 26 |  */ | 
 | 27 | struct key_type key_type_user = { | 
 | 28 | 	.name		= "user", | 
 | 29 | 	.instantiate	= user_instantiate, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 30 | 	.update		= user_update, | 
 | 31 | 	.match		= user_match, | 
| David Howells | 31204ed | 2006-06-26 00:24:51 -0700 | [diff] [blame] | 32 | 	.revoke		= user_revoke, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 33 | 	.destroy	= user_destroy, | 
 | 34 | 	.describe	= user_describe, | 
 | 35 | 	.read		= user_read, | 
 | 36 | }; | 
 | 37 |  | 
| Michael Halcrow | 16c29b6 | 2005-06-23 22:00:58 -0700 | [diff] [blame] | 38 | EXPORT_SYMBOL_GPL(key_type_user); | 
 | 39 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 40 | /* | 
| Jeff Layton | 9f6ed2c | 2012-01-17 16:09:11 -0500 | [diff] [blame] | 41 |  * This key type is essentially the same as key_type_user, but it does | 
 | 42 |  * not define a .read op. This is suitable for storing username and | 
 | 43 |  * password pairs in the keyring that you do not want to be readable | 
 | 44 |  * from userspace. | 
 | 45 |  */ | 
 | 46 | struct key_type key_type_logon = { | 
 | 47 | 	.name			= "logon", | 
 | 48 | 	.instantiate		= user_instantiate, | 
 | 49 | 	.update			= user_update, | 
 | 50 | 	.match			= user_match, | 
 | 51 | 	.revoke			= user_revoke, | 
 | 52 | 	.destroy		= user_destroy, | 
 | 53 | 	.describe		= user_describe, | 
 | 54 | 	.vet_description	= logon_vet_description, | 
 | 55 | }; | 
 | 56 | EXPORT_SYMBOL_GPL(key_type_logon); | 
 | 57 |  | 
 | 58 | /* | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 59 |  * instantiate a user defined key | 
 | 60 |  */ | 
| David Howells | 2aa349f | 2005-10-30 15:02:42 -0800 | [diff] [blame] | 61 | int user_instantiate(struct key *key, const void *data, size_t datalen) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 62 | { | 
| David Howells | 76d8aea | 2005-06-23 22:00:49 -0700 | [diff] [blame] | 63 | 	struct user_key_payload *upayload; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 64 | 	int ret; | 
 | 65 |  | 
 | 66 | 	ret = -EINVAL; | 
 | 67 | 	if (datalen <= 0 || datalen > 32767 || !data) | 
 | 68 | 		goto error; | 
 | 69 |  | 
 | 70 | 	ret = key_payload_reserve(key, datalen); | 
 | 71 | 	if (ret < 0) | 
 | 72 | 		goto error; | 
 | 73 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 74 | 	ret = -ENOMEM; | 
| David Howells | 76d8aea | 2005-06-23 22:00:49 -0700 | [diff] [blame] | 75 | 	upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL); | 
 | 76 | 	if (!upayload) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 77 | 		goto error; | 
 | 78 |  | 
| David Howells | 76d8aea | 2005-06-23 22:00:49 -0700 | [diff] [blame] | 79 | 	/* attach the data */ | 
 | 80 | 	upayload->datalen = datalen; | 
 | 81 | 	memcpy(upayload->data, data, datalen); | 
| Mimi Zohar | f6b2457 | 2012-01-18 10:03:14 +0000 | [diff] [blame] | 82 | 	rcu_assign_keypointer(key, upayload); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 83 | 	ret = 0; | 
 | 84 |  | 
| David Howells | 2aa349f | 2005-10-30 15:02:42 -0800 | [diff] [blame] | 85 | error: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 86 | 	return ret; | 
| David Howells | a8b17ed | 2011-01-20 16:38:27 +0000 | [diff] [blame] | 87 | } | 
| David Howells | 31204ed | 2006-06-26 00:24:51 -0700 | [diff] [blame] | 88 |  | 
| David Howells | 2aa349f | 2005-10-30 15:02:42 -0800 | [diff] [blame] | 89 | EXPORT_SYMBOL_GPL(user_instantiate); | 
 | 90 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 91 | /* | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 92 |  * update a user defined key | 
| David Howells | 76d8aea | 2005-06-23 22:00:49 -0700 | [diff] [blame] | 93 |  * - the key's semaphore is write-locked | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 94 |  */ | 
| David Howells | 2aa349f | 2005-10-30 15:02:42 -0800 | [diff] [blame] | 95 | int user_update(struct key *key, const void *data, size_t datalen) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 96 | { | 
| David Howells | 76d8aea | 2005-06-23 22:00:49 -0700 | [diff] [blame] | 97 | 	struct user_key_payload *upayload, *zap; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 98 | 	int ret; | 
 | 99 |  | 
 | 100 | 	ret = -EINVAL; | 
 | 101 | 	if (datalen <= 0 || datalen > 32767 || !data) | 
 | 102 | 		goto error; | 
 | 103 |  | 
| David Howells | 76d8aea | 2005-06-23 22:00:49 -0700 | [diff] [blame] | 104 | 	/* construct a replacement payload */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 105 | 	ret = -ENOMEM; | 
| David Howells | 76d8aea | 2005-06-23 22:00:49 -0700 | [diff] [blame] | 106 | 	upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL); | 
 | 107 | 	if (!upayload) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 108 | 		goto error; | 
 | 109 |  | 
| David Howells | 76d8aea | 2005-06-23 22:00:49 -0700 | [diff] [blame] | 110 | 	upayload->datalen = datalen; | 
 | 111 | 	memcpy(upayload->data, data, datalen); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 112 |  | 
 | 113 | 	/* check the quota and attach the new data */ | 
| David Howells | 76d8aea | 2005-06-23 22:00:49 -0700 | [diff] [blame] | 114 | 	zap = upayload; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 115 |  | 
 | 116 | 	ret = key_payload_reserve(key, datalen); | 
 | 117 |  | 
 | 118 | 	if (ret == 0) { | 
 | 119 | 		/* attach the new data, displacing the old */ | 
 | 120 | 		zap = key->payload.data; | 
| Mimi Zohar | f6b2457 | 2012-01-18 10:03:14 +0000 | [diff] [blame] | 121 | 		rcu_assign_keypointer(key, upayload); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 122 | 		key->expiry = 0; | 
 | 123 | 	} | 
 | 124 |  | 
| David Howells | 9f35a33 | 2011-11-15 22:09:45 +0000 | [diff] [blame] | 125 | 	if (zap) | 
 | 126 | 		kfree_rcu(zap, rcu); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 127 |  | 
| David Howells | 2aa349f | 2005-10-30 15:02:42 -0800 | [diff] [blame] | 128 | error: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 129 | 	return ret; | 
| David Howells | a8b17ed | 2011-01-20 16:38:27 +0000 | [diff] [blame] | 130 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 131 |  | 
| David Howells | 2aa349f | 2005-10-30 15:02:42 -0800 | [diff] [blame] | 132 | EXPORT_SYMBOL_GPL(user_update); | 
 | 133 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 134 | /* | 
 | 135 |  * match users on their name | 
 | 136 |  */ | 
| David Howells | 2aa349f | 2005-10-30 15:02:42 -0800 | [diff] [blame] | 137 | int user_match(const struct key *key, const void *description) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 138 | { | 
 | 139 | 	return strcmp(key->description, description) == 0; | 
| David Howells | a8b17ed | 2011-01-20 16:38:27 +0000 | [diff] [blame] | 140 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 141 |  | 
| David Howells | 2aa349f | 2005-10-30 15:02:42 -0800 | [diff] [blame] | 142 | EXPORT_SYMBOL_GPL(user_match); | 
 | 143 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 144 | /* | 
| David Howells | 31204ed | 2006-06-26 00:24:51 -0700 | [diff] [blame] | 145 |  * dispose of the links from a revoked keyring | 
 | 146 |  * - called with the key sem write-locked | 
 | 147 |  */ | 
 | 148 | void user_revoke(struct key *key) | 
 | 149 | { | 
 | 150 | 	struct user_key_payload *upayload = key->payload.data; | 
 | 151 |  | 
 | 152 | 	/* clear the quota */ | 
 | 153 | 	key_payload_reserve(key, 0); | 
 | 154 |  | 
 | 155 | 	if (upayload) { | 
| Mimi Zohar | f6b2457 | 2012-01-18 10:03:14 +0000 | [diff] [blame] | 156 | 		rcu_assign_keypointer(key, NULL); | 
| Lai Jiangshan | 3acb458 | 2011-03-18 12:11:07 +0800 | [diff] [blame] | 157 | 		kfree_rcu(upayload, rcu); | 
| David Howells | 31204ed | 2006-06-26 00:24:51 -0700 | [diff] [blame] | 158 | 	} | 
| David Howells | a8b17ed | 2011-01-20 16:38:27 +0000 | [diff] [blame] | 159 | } | 
| David Howells | 31204ed | 2006-06-26 00:24:51 -0700 | [diff] [blame] | 160 |  | 
 | 161 | EXPORT_SYMBOL(user_revoke); | 
 | 162 |  | 
| David Howells | 31204ed | 2006-06-26 00:24:51 -0700 | [diff] [blame] | 163 | /* | 
 | 164 |  * dispose of the data dangling from the corpse of a user key | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 165 |  */ | 
| David Howells | 2aa349f | 2005-10-30 15:02:42 -0800 | [diff] [blame] | 166 | void user_destroy(struct key *key) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 167 | { | 
| David Howells | 76d8aea | 2005-06-23 22:00:49 -0700 | [diff] [blame] | 168 | 	struct user_key_payload *upayload = key->payload.data; | 
 | 169 |  | 
 | 170 | 	kfree(upayload); | 
| David Howells | a8b17ed | 2011-01-20 16:38:27 +0000 | [diff] [blame] | 171 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 172 |  | 
| David Howells | 2aa349f | 2005-10-30 15:02:42 -0800 | [diff] [blame] | 173 | EXPORT_SYMBOL_GPL(user_destroy); | 
 | 174 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 175 | /* | 
| David Howells | 76d8aea | 2005-06-23 22:00:49 -0700 | [diff] [blame] | 176 |  * describe the user key | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 177 |  */ | 
| David Howells | 2aa349f | 2005-10-30 15:02:42 -0800 | [diff] [blame] | 178 | void user_describe(const struct key *key, struct seq_file *m) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 179 | { | 
 | 180 | 	seq_puts(m, key->description); | 
| David Howells | 78b7280 | 2011-03-11 17:57:23 +0000 | [diff] [blame] | 181 | 	if (key_is_instantiated(key)) | 
 | 182 | 		seq_printf(m, ": %u", key->datalen); | 
| David Howells | a8b17ed | 2011-01-20 16:38:27 +0000 | [diff] [blame] | 183 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 184 |  | 
| David Howells | 2aa349f | 2005-10-30 15:02:42 -0800 | [diff] [blame] | 185 | EXPORT_SYMBOL_GPL(user_describe); | 
 | 186 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 187 | /* | 
 | 188 |  * read the key data | 
| David Howells | 76d8aea | 2005-06-23 22:00:49 -0700 | [diff] [blame] | 189 |  * - the key's semaphore is read-locked | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 190 |  */ | 
| David Howells | 2aa349f | 2005-10-30 15:02:42 -0800 | [diff] [blame] | 191 | long user_read(const struct key *key, char __user *buffer, size_t buflen) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 192 | { | 
| David Howells | 76d8aea | 2005-06-23 22:00:49 -0700 | [diff] [blame] | 193 | 	struct user_key_payload *upayload; | 
 | 194 | 	long ret; | 
 | 195 |  | 
| David Howells | 633e804 | 2011-03-07 15:05:51 +0000 | [diff] [blame] | 196 | 	upayload = rcu_dereference_key(key); | 
| David Howells | 76d8aea | 2005-06-23 22:00:49 -0700 | [diff] [blame] | 197 | 	ret = upayload->datalen; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 198 |  | 
 | 199 | 	/* we can return the data as is */ | 
 | 200 | 	if (buffer && buflen > 0) { | 
| David Howells | 76d8aea | 2005-06-23 22:00:49 -0700 | [diff] [blame] | 201 | 		if (buflen > upayload->datalen) | 
 | 202 | 			buflen = upayload->datalen; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 203 |  | 
| David Howells | 76d8aea | 2005-06-23 22:00:49 -0700 | [diff] [blame] | 204 | 		if (copy_to_user(buffer, upayload->data, buflen) != 0) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 205 | 			ret = -EFAULT; | 
 | 206 | 	} | 
 | 207 |  | 
 | 208 | 	return ret; | 
| David Howells | a8b17ed | 2011-01-20 16:38:27 +0000 | [diff] [blame] | 209 | } | 
| David Howells | 2aa349f | 2005-10-30 15:02:42 -0800 | [diff] [blame] | 210 |  | 
 | 211 | EXPORT_SYMBOL_GPL(user_read); | 
| Jeff Layton | 9f6ed2c | 2012-01-17 16:09:11 -0500 | [diff] [blame] | 212 |  | 
 | 213 | /* Vet the description for a "logon" key */ | 
 | 214 | static int logon_vet_description(const char *desc) | 
 | 215 | { | 
 | 216 | 	char *p; | 
 | 217 |  | 
 | 218 | 	/* require a "qualified" description string */ | 
 | 219 | 	p = strchr(desc, ':'); | 
 | 220 | 	if (!p) | 
 | 221 | 		return -EINVAL; | 
 | 222 |  | 
 | 223 | 	/* also reject description with ':' as first char */ | 
 | 224 | 	if (p == desc) | 
 | 225 | 		return -EINVAL; | 
 | 226 |  | 
 | 227 | 	return 0; | 
 | 228 | } |