Staging: p9auth: remove unneeded header file
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / staging / p9auth / p9auth.c
blob5824c7f88ccae144dc76dc9e4984fdc8e40052e8
1 /*
2 * Plan 9 style capability device implementation for the Linux Kernel
4 * Copyright 2008, 2009 Ashwin Ganti <ashwin.ganti@gmail.com>
6 * Released under the GPLv2
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 <linux/sched.h>
35 #include <linux/cred.h>
37 #ifndef CAP_MAJOR
38 #define CAP_MAJOR 0
39 #endif
41 #ifndef CAP_NR_DEVS
42 #define CAP_NR_DEVS 2 /* caphash and capuse */
43 #endif
45 #ifndef CAP_NODE_SIZE
46 #define CAP_NODE_SIZE 20
47 #endif
49 #define MAX_DIGEST_SIZE 20
51 struct cap_node {
52 char data[CAP_NODE_SIZE];
53 struct list_head list;
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;
64 int cap_trim(struct cap_dev *);
65 ssize_t cap_write(struct file *, const char __user *, size_t, loff_t *);
66 char *cap_hash(char *plain_text, unsigned int plain_text_size, char *key, unsigned int key_size);
67 void hex_dump(unsigned char * buf, unsigned int len);
69 int cap_major = CAP_MAJOR;
70 int cap_minor = 0;
71 int cap_nr_devs = CAP_NR_DEVS;
72 int cap_node_size = CAP_NODE_SIZE;
74 module_param(cap_major, int, S_IRUGO);
75 module_param(cap_minor, int, S_IRUGO);
76 module_param(cap_nr_devs, int, S_IRUGO);
78 MODULE_AUTHOR("Ashwin Ganti");
79 MODULE_LICENSE("GPL");
81 struct cap_dev *cap_devices;
83 void hexdump(unsigned char *buf, unsigned int len)
85 while (len--)
86 printk("%02x", *buf++);
87 printk("\n");
90 int cap_trim(struct cap_dev *dev)
92 struct cap_node *tmp;
93 struct list_head *pos, *q;
94 if (dev->head != NULL) {
95 list_for_each_safe(pos, q, &(dev->head->list)) {
96 tmp = list_entry(pos, struct cap_node, list);
97 list_del(pos);
98 kfree(tmp);
101 return 0;
104 int cap_open(struct inode *inode, struct file *filp)
106 struct cap_dev *dev;
107 dev = container_of(inode->i_cdev, struct cap_dev, cdev);
108 filp->private_data = dev;
110 /* trim to 0 the length of the device if open was write-only */
111 if ((filp->f_flags & O_ACCMODE) == O_WRONLY) {
112 if (down_interruptible(&dev->sem))
113 return -ERESTARTSYS;
114 cap_trim(dev);
115 up(&dev->sem);
117 /* initialise the head if it is NULL */
118 if (dev->head == NULL) {
119 dev->head =
120 (struct cap_node *) kmalloc(sizeof(struct cap_node),
121 GFP_KERNEL);
122 INIT_LIST_HEAD(&(dev->head->list));
124 return 0;
127 int cap_release(struct inode *inode, struct file *filp)
129 return 0;
132 ssize_t
133 cap_write(struct file * filp, const char __user * buf,
134 size_t count, loff_t * f_pos)
136 struct cap_node *node_ptr, *tmp;
137 struct list_head *pos;
138 struct cap_dev *dev = filp->private_data;
139 ssize_t retval = -ENOMEM;
140 struct cred *new;
141 int len, target_int, source_int, flag = 0;
142 char *user_buf, *user_buf_running, *source_user, *target_user,
143 *rand_str, *hash_str, *result;
145 if (down_interruptible(&dev->sem))
146 return -ERESTARTSYS;
148 node_ptr =
149 (struct cap_node *) kmalloc(sizeof(struct cap_node),
150 GFP_KERNEL);
151 user_buf = (char *) kmalloc(count, GFP_KERNEL);
152 memset(user_buf, 0, count);
154 if (copy_from_user(user_buf, buf, count)) {
155 retval = -EFAULT;
156 goto out;
159 /* If the minor number is 0 ( /dev/caphash ) then simply add the
160 * hashed capability supplied by the user to the list of hashes
162 if (0 == iminor(filp->f_dentry->d_inode)) {
163 printk(KERN_INFO "Capability being written to /dev/caphash : \n");
164 hexdump(user_buf, count);
165 memcpy(node_ptr->data, user_buf, count);
166 list_add(&(node_ptr->list), &(dev->head->list));
167 } else {
168 /* break the supplied string into tokens with @ as the delimiter
169 If the string is "user1@user2@randomstring" we need to split it
170 and hash 'user1@user2' using 'randomstring' as the key
172 user_buf_running = kstrdup(user_buf, GFP_KERNEL);
173 source_user = strsep(&user_buf_running, "@");
174 target_user = strsep(&user_buf_running, "@");
175 rand_str = strsep(&user_buf_running, "@");
177 /* hash the string user1@user2 with rand_str as the key */
178 len = strlen(source_user) + strlen(target_user) + 1;
179 hash_str = (char *) kmalloc(len, GFP_KERNEL);
180 memset(hash_str, 0, len);
181 strcat(hash_str, source_user);
182 strcat(hash_str, "@");
183 strcat(hash_str, target_user);
185 printk(KERN_ALERT "the source user is %s \n", source_user);
186 printk(KERN_ALERT "the target user is %s \n", target_user);
188 result =
189 cap_hash(hash_str, len, rand_str, strlen(rand_str));
190 if (NULL == result) {
191 retval = -EFAULT;
192 goto out;
194 memcpy(node_ptr->data, result, CAP_NODE_SIZE);
195 /* Change the process's uid if the hash is present in the
196 * list of hashes
198 list_for_each(pos, &(cap_devices->head->list)) {
199 /* Change the user id of the process if the hashes match */
200 if (0 ==
201 memcmp(result,
202 list_entry(pos, struct cap_node,
203 list)->data,
204 CAP_NODE_SIZE)) {
205 target_int = (unsigned int)
206 simple_strtol(target_user, NULL, 0);
207 source_int = (unsigned int)
208 simple_strtol(source_user, NULL, 0);
209 flag = 1;
211 /* Check whether the process writing to capuse is actually owned by
212 * the source owner
214 if (source_int != current_uid()) {
215 printk(KERN_ALERT
216 "Process is not owned by the source user of the capability.\n");
217 retval = -EFAULT;
218 goto out;
220 /* What all id's need to be changed here? uid, euid, fsid, savedids ??
221 * Currently I am changing the effective user id
222 * since most of the authorisation decisions are based on it
224 new = prepare_creds();
225 if (!new) {
226 retval = -ENOMEM;
227 goto out;
229 new->uid = (uid_t) target_int;
230 new->euid = (uid_t) target_int;
231 retval = commit_creds(new);
232 if (retval)
233 goto out;
235 /* Remove the capability from the list and break */
236 tmp =
237 list_entry(pos, struct cap_node, list);
238 list_del(pos);
239 kfree(tmp);
240 break;
243 if (0 == flag) {
244 /* The capability is not present in the list of the hashes stored, hence return failure */
245 printk(KERN_ALERT
246 "Invalid capabiliy written to /dev/capuse \n");
247 retval = -EFAULT;
248 goto out;
251 *f_pos += count;
252 retval = count;
253 /* update the size */
254 if (dev->size < *f_pos)
255 dev->size = *f_pos;
257 out:
258 up(&dev->sem);
259 return retval;
262 struct file_operations cap_fops = {
263 .owner = THIS_MODULE,
264 .write = cap_write,
265 .open = cap_open,
266 .release = cap_release,
270 void cap_cleanup_module(void)
272 int i;
273 dev_t devno = MKDEV(cap_major, cap_minor);
274 if (cap_devices) {
275 for (i = 0; i < cap_nr_devs; i++) {
276 cap_trim(cap_devices + i);
277 cdev_del(&cap_devices[i].cdev);
279 kfree(cap_devices);
281 unregister_chrdev_region(devno, cap_nr_devs);
286 static void cap_setup_cdev(struct cap_dev *dev, int index)
288 int err, devno = MKDEV(cap_major, cap_minor + index);
289 cdev_init(&dev->cdev, &cap_fops);
290 dev->cdev.owner = THIS_MODULE;
291 dev->cdev.ops = &cap_fops;
292 err = cdev_add(&dev->cdev, devno, 1);
293 if (err)
294 printk(KERN_NOTICE "Error %d adding cap%d", err, index);
298 int cap_init_module(void)
300 int result, i;
301 dev_t dev = 0;
303 if (cap_major) {
304 dev = MKDEV(cap_major, cap_minor);
305 result = register_chrdev_region(dev, cap_nr_devs, "cap");
306 } else {
307 result = alloc_chrdev_region(&dev, cap_minor, cap_nr_devs,
308 "cap");
309 cap_major = MAJOR(dev);
312 if (result < 0) {
313 printk(KERN_WARNING "cap: can't get major %d\n",
314 cap_major);
315 return result;
318 cap_devices =
319 kmalloc(cap_nr_devs * sizeof(struct cap_dev), GFP_KERNEL);
320 if (!cap_devices) {
321 result = -ENOMEM;
322 goto fail;
324 memset(cap_devices, 0, cap_nr_devs * sizeof(struct cap_dev));
326 /* Initialize each device. */
327 for (i = 0; i < cap_nr_devs; i++) {
328 cap_devices[i].node_size = cap_node_size;
329 init_MUTEX(&cap_devices[i].sem);
330 cap_setup_cdev(&cap_devices[i], i);
333 return 0;
335 fail:
336 cap_cleanup_module();
337 return result;
340 module_init(cap_init_module);
341 module_exit(cap_cleanup_module);
343 char *cap_hash(char *plain_text, unsigned int plain_text_size,
344 char *key, unsigned int key_size)
346 struct scatterlist sg;
347 char *result = (char *) kmalloc(MAX_DIGEST_SIZE, GFP_KERNEL);
348 struct crypto_hash *tfm;
349 struct hash_desc desc;
350 int ret;
352 tfm = crypto_alloc_hash("hmac(sha1)", 0, CRYPTO_ALG_ASYNC);
353 if (IS_ERR(tfm)) {
354 printk("failed to load transform for hmac(sha1): %ld\n",
355 PTR_ERR(tfm));
356 kfree(result);
357 return NULL;
360 desc.tfm = tfm;
361 desc.flags = 0;
363 memset(result, 0, MAX_DIGEST_SIZE);
364 sg_set_buf(&sg, plain_text, plain_text_size);
366 ret = crypto_hash_setkey(tfm, key, key_size);
367 if (ret) {
368 printk("setkey() failed ret=%d\n", ret);
369 kfree(result);
370 result = NULL;
371 goto out;
374 ret = crypto_hash_digest(&desc, &sg, plain_text_size, result);
375 if (ret) {
376 printk("digest () failed ret=%d\n", ret);
377 kfree(result);
378 result = NULL;
379 goto out;
382 printk("crypto hash digest size %d\n",
383 crypto_hash_digestsize(tfm));
384 hexdump(result, MAX_DIGEST_SIZE);
386 out:
387 crypto_free_hash(tfm);
388 return result;