aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/p9auth
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/p9auth')
-rw-r--r--drivers/staging/p9auth/p9auth.c347
-rw-r--r--drivers/staging/p9auth/p9auth.h35
2 files changed, 382 insertions, 0 deletions
diff --git a/drivers/staging/p9auth/p9auth.c b/drivers/staging/p9auth/p9auth.c
new file mode 100644
index 00000000000..6704d97194a
--- /dev/null
+++ b/drivers/staging/p9auth/p9auth.c
@@ -0,0 +1,347 @@
1/*
2 * Plan 9 style capability device implementation for the Linux Kernel
3 *
4 * Copyright 2008, 2009 Ashwin Ganti <ashwin.ganti@gmail.com>
5 *
6 * Released under the GPLv2
7 *
8 */
9#include <linux/module.h>
10#include <linux/moduleparam.h>
11#include <linux/init.h>
12#include <linux/kernel.h>
13#include <linux/slab.h>
14#include <linux/fs.h>
15#include <linux/errno.h>
16#include <linux/types.h>
17#include <linux/proc_fs.h>
18#include <linux/fcntl.h>
19#include <linux/cdev.h>
20#include <linux/syscalls.h>
21#include <asm/system.h>
22#include <asm/uaccess.h>
23#include <linux/list.h>
24#include <linux/err.h>
25#include <linux/mm.h>
26#include <linux/string.h>
27#include <linux/crypto.h>
28#include <linux/highmem.h>
29#include <linux/jiffies.h>
30#include <linux/timex.h>
31#include <linux/interrupt.h>
32#include <linux/scatterlist.h>
33#include <linux/crypto.h>
34#include "p9auth.h"
35
36int cap_major = CAP_MAJOR;
37int cap_minor = 0;
38int cap_nr_devs = CAP_NR_DEVS;
39int cap_node_size = CAP_NODE_SIZE;
40
41module_param(cap_major, int, S_IRUGO);
42module_param(cap_minor, int, S_IRUGO);
43module_param(cap_nr_devs, int, S_IRUGO);
44
45MODULE_AUTHOR("Ashwin Ganti");
46MODULE_LICENSE("GPL");
47
48struct cap_dev *cap_devices;
49
50void hexdump(unsigned char *buf, unsigned int len)
51{
52 while (len--)
53 printk("%02x", *buf++);
54 printk("\n");
55}
56
57int cap_trim(struct cap_dev *dev)
58{
59 struct cap_node *tmp;
60 struct list_head *pos, *q;
61 if (dev->head != NULL) {
62 list_for_each_safe(pos, q, &(dev->head->list)) {
63 tmp = list_entry(pos, struct cap_node, list);
64 list_del(pos);
65 kfree(tmp);
66 }
67 }
68 return 0;
69}
70
71int cap_open(struct inode *inode, struct file *filp)
72{
73 struct cap_dev *dev;
74 dev = container_of(inode->i_cdev, struct cap_dev, cdev);
75 filp->private_data = dev;
76
77 /* trim to 0 the length of the device if open was write-only */
78 if ((filp->f_flags & O_ACCMODE) == O_WRONLY) {
79 if (down_interruptible(&dev->sem))
80 return -ERESTARTSYS;
81 cap_trim(dev);
82 up(&dev->sem);
83 }
84 /* initialise the head if it is NULL */
85 if (dev->head == NULL) {
86 dev->head =
87 (struct cap_node *) kmalloc(sizeof(struct cap_node),
88 GFP_KERNEL);
89 INIT_LIST_HEAD(&(dev->head->list));
90 }
91 return 0;
92}
93
94int cap_release(struct inode *inode, struct file *filp)
95{
96 return 0;
97}
98
99ssize_t
100cap_write(struct file * filp, const char __user * buf,
101 size_t count, loff_t * f_pos)
102{
103 struct cap_node *node_ptr, *tmp;
104 struct list_head *pos;
105 struct cap_dev *dev = filp->private_data;
106 ssize_t retval = -ENOMEM;
107 int len, target_int, source_int, flag = 0;
108 char *user_buf, *user_buf_running, *source_user, *target_user,
109 *rand_str, *hash_str, *result;
110
111 if (down_interruptible(&dev->sem))
112 return -ERESTARTSYS;
113
114 node_ptr =
115 (struct cap_node *) kmalloc(sizeof(struct cap_node),
116 GFP_KERNEL);
117 user_buf = (char *) kmalloc(count, GFP_KERNEL);
118 memset(user_buf, 0, count);
119
120 if (copy_from_user(user_buf, buf, count)) {
121 retval = -EFAULT;
122 goto out;
123 }
124
125 /* If the minor number is 0 ( /dev/caphash ) then simply add the
126 * hashed capability supplied by the user to the list of hashes
127 */
128 if (0 == iminor(filp->f_dentry->d_inode)) {
129 printk(KERN_INFO "Capability being written to /dev/caphash : \n");
130 hexdump(user_buf, count);
131 memcpy(node_ptr->data, user_buf, count);
132 list_add(&(node_ptr->list), &(dev->head->list));
133 } else {
134 /* break the supplied string into tokens with @ as the delimiter
135 If the string is "user1@user2@randomstring" we need to split it
136 and hash 'user1@user2' using 'randomstring' as the key
137 */
138 user_buf_running = kstrdup(user_buf, GFP_KERNEL);
139 source_user = strsep(&user_buf_running, "@");
140 target_user = strsep(&user_buf_running, "@");
141 rand_str = strsep(&user_buf_running, "@");
142
143 /* hash the string user1@user2 with rand_str as the key */
144 len = strlen(source_user) + strlen(target_user) + 1;
145 hash_str = (char *) kmalloc(len, GFP_KERNEL);
146 memset(hash_str, 0, len);
147 strcat(hash_str, source_user);
148 strcat(hash_str, "@");
149 strcat(hash_str, target_user);
150
151 printk(KERN_ALERT "the source user is %s \n", source_user);
152 printk(KERN_ALERT "the target user is %s \n", target_user);
153
154 result =
155 cap_hash(hash_str, len, rand_str, strlen(rand_str));
156 if (NULL == result) {
157 retval = -EFAULT;
158 goto out;
159 }
160 memcpy(node_ptr->data, result, CAP_NODE_SIZE);
161 /* Change the process's uid if the hash is present in the
162 * list of hashes
163 */
164 list_for_each(pos, &(cap_devices->head->list)) {
165 /* Change the user id of the process if the hashes match */
166 if (0 ==
167 memcmp(result,
168 list_entry(pos, struct cap_node,
169 list)->data,
170 CAP_NODE_SIZE)) {
171 target_int = (unsigned int)
172 simple_strtol(target_user, NULL, 0);
173 source_int = (unsigned int)
174 simple_strtol(source_user, NULL, 0);
175 flag = 1;
176
177 /* Check whether the process writing to capuse is actually owned by
178 * the source owner
179 */
180 if (source_int != current->uid) {
181 printk(KERN_ALERT
182 "Process is not owned by the source user of the capability.\n");
183 retval = -EFAULT;
184 goto out;
185 }
186 /* What all id's need to be changed here? uid, euid, fsid, savedids ??
187 * Currently I am changing the effective user id
188 * since most of the authorisation decisions are based on it
189 */
190 current->uid = (uid_t) target_int;
191 current->euid = (uid_t) target_int;
192
193 /* Remove the capability from the list and break */
194 tmp =
195 list_entry(pos, struct cap_node, list);
196 list_del(pos);
197 kfree(tmp);
198 break;
199 }
200 }
201 if (0 == flag) {
202 /* The capability is not present in the list of the hashes stored, hence return failure */
203 printk(KERN_ALERT
204 "Invalid capabiliy written to /dev/capuse \n");
205 retval = -EFAULT;
206 goto out;
207 }
208 }
209 *f_pos += count;
210 retval = count;
211 /* update the size */
212 if (dev->size < *f_pos)
213 dev->size = *f_pos;
214
215 out:
216 up(&dev->sem);
217 return retval;
218}
219
220struct file_operations cap_fops = {
221 .owner = THIS_MODULE,
222 .write = cap_write,
223 .open = cap_open,
224 .release = cap_release,
225};
226
227
228void cap_cleanup_module(void)
229{
230 int i;
231 dev_t devno = MKDEV(cap_major, cap_minor);
232 if (cap_devices) {
233 for (i = 0; i < cap_nr_devs; i++) {
234 cap_trim(cap_devices + i);
235 cdev_del(&cap_devices[i].cdev);
236 }
237 kfree(cap_devices);
238 }
239 unregister_chrdev_region(devno, cap_nr_devs);
240
241}
242
243
244static void cap_setup_cdev(struct cap_dev *dev, int index)
245{
246 int err, devno = MKDEV(cap_major, cap_minor + index);
247 cdev_init(&dev->cdev, &cap_fops);
248 dev->cdev.owner = THIS_MODULE;
249 dev->cdev.ops = &cap_fops;
250 err = cdev_add(&dev->cdev, devno, 1);
251 if (err)
252 printk(KERN_NOTICE "Error %d adding cap%d", err, index);
253}
254
255
256int cap_init_module(void)
257{
258 int result, i;
259 dev_t dev = 0;
260
261 if (cap_major) {
262 dev = MKDEV(cap_major, cap_minor);
263 result = register_chrdev_region(dev, cap_nr_devs, "cap");
264 } else {
265 result = alloc_chrdev_region(&dev, cap_minor, cap_nr_devs,
266 "cap");
267 cap_major = MAJOR(dev);
268 }
269
270 if (result < 0) {
271 printk(KERN_WARNING "cap: can't get major %d\n",
272 cap_major);
273 return result;
274 }
275
276 cap_devices =
277 kmalloc(cap_nr_devs * sizeof(struct cap_dev), GFP_KERNEL);
278 if (!cap_devices) {
279 result = -ENOMEM;
280 goto fail;
281 }
282 memset(cap_devices, 0, cap_nr_devs * sizeof(struct cap_dev));
283
284 /* Initialize each device. */
285 for (i = 0; i < cap_nr_devs; i++) {
286 cap_devices[i].node_size = cap_node_size;
287 init_MUTEX(&cap_devices[i].sem);
288 cap_setup_cdev(&cap_devices[i], i);
289 }
290
291 return 0;
292
293 fail:
294 cap_cleanup_module();
295 return result;
296}
297
298module_init(cap_init_module);
299module_exit(cap_cleanup_module);
300
301char *cap_hash(char *plain_text, unsigned int plain_text_size,
302 char *key, unsigned int key_size)
303{
304 struct scatterlist sg;
305 char *result = (char *) kmalloc(MAX_DIGEST_SIZE, GFP_KERNEL);
306 struct crypto_hash *tfm;
307 struct hash_desc desc;
308 int ret;
309
310 tfm = crypto_alloc_hash("hmac(sha1)", 0, CRYPTO_ALG_ASYNC);
311 if (IS_ERR(tfm)) {
312 printk("failed to load transform for hmac(sha1): %ld\n",
313 PTR_ERR(tfm));
314 kfree(result);
315 return NULL;
316 }
317
318 desc.tfm = tfm;
319 desc.flags = 0;
320
321 memset(result, 0, MAX_DIGEST_SIZE);
322 sg_set_buf(&sg, plain_text, plain_text_size);
323
324 ret = crypto_hash_setkey(tfm, key, key_size);
325 if (ret) {
326 printk("setkey() failed ret=%d\n", ret);
327 kfree(result);
328 result = NULL;
329 goto out;
330 }
331
332 ret = crypto_hash_digest(&desc, &sg, plain_text_size, result);
333 if (ret) {
334 printk("digest () failed ret=%d\n", ret);
335 kfree(result);
336 result = NULL;
337 goto out;
338 }
339
340 printk("crypto hash digest size %d\n",
341 crypto_hash_digestsize(tfm));
342 hexdump(result, MAX_DIGEST_SIZE);
343
344 out:
345 crypto_free_hash(tfm);
346 return result;
347}
diff --git a/drivers/staging/p9auth/p9auth.h b/drivers/staging/p9auth/p9auth.h
new file mode 100644
index 00000000000..285d1d8c917
--- /dev/null
+++ b/drivers/staging/p9auth/p9auth.h
@@ -0,0 +1,35 @@
1#ifndef CAP_MAJOR
2#define CAP_MAJOR 0
3#endif
4
5#ifndef CAP_NR_DEVS
6#define CAP_NR_DEVS 2 /* caphash and capuse */
7#endif
8
9#ifndef CAP_NODE_SIZE
10#define CAP_NODE_SIZE 20
11#endif
12
13#define MAX_DIGEST_SIZE 20
14
15struct cap_node {
16 char data[CAP_NODE_SIZE];
17 struct list_head list;
18};
19
20struct cap_dev {
21 struct cap_node *head;
22 int node_size;
23 unsigned long size;
24 struct semaphore sem;
25 struct cdev cdev;
26};
27
28extern int cap_major;
29extern int cap_nr_devs;
30extern int cap_node_size;
31
32int cap_trim(struct cap_dev *);
33ssize_t cap_write(struct file *, const char __user *, size_t, loff_t *);
34char *cap_hash(char *plain_text, unsigned int plain_text_size, char *key, unsigned int key_size);
35void hex_dump(unsigned char * buf, unsigned int len);