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