1 /*
2 * access.c -- the files with access control on open
3 *
4 * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
5 * Copyright (C) 2001 O'Reilly & Associates
6 * Modified for warning-free compilation under Linux 2.6.31 by baker@cs.fsu.edu.
7 *
8 * The source code in this file can be freely used, adapted,
9 * and redistributed in source or binary form, so long as an
10 * acknowledgment appears in derived source files. The citation
11 * should list that the code comes from the book "Linux Device
12 * Drivers" by Alessandro Rubini and Jonathan Corbet, published
13 * by O'Reilly & Associates. No warranty is attached;
14 * we cannot take responsibility for errors or fitness for use.
15 *
16 * $Id: access.c,v 1.2 2010/05/19 20:40:00 baker Exp baker $
17 */
18
19 /* FIXME: cloned devices as a use for kobjects? */
20
21 /* Uid, etc. moved from struct task_struct to struct cred. */ //tpb
22
23 #include <linux/kernel.h> /* printk() */
24 #include <linux/module.h>
25 #include <linux/slab.h> /* kmalloc() */
26 #include <linux/fs.h> /* everything... */
27 #include <linux/errno.h> /* error codes */
28 #include <linux/types.h> /* size_t */
29 #include <linux/fcntl.h>
30 #include <linux/cdev.h>
31 #include <linux/tty.h>
32 #include <asm/atomic.h>
33 #include <linux/list.h>
34 #include <linux/sched.h>
35
36 #include "scull.h" /* local definitions */
37
38 static dev_t scull_a_firstdev; /* Where our range begins */
39
40 /*
41 * These devices fall back on the main scull operations. They only
42 * differ in the implementation of open() and close()
43 */
44
45
46
47 /************************************************************************
48 *
49 * The first device is the single-open one,
50 * it has an hw structure and an open count
51 */
52
53 static struct scull_dev scull_s_device;
54 static atomic_t scull_s_available = ATOMIC_INIT(1);
55
56 static int scull_s_open(struct inode *inode, struct file *filp)
57 {
58 struct scull_dev *dev = &scull_s_device; /* device information */
59
60 if (! atomic_dec_and_test (&scull_s_available)) {
61 atomic_inc(&scull_s_available);
62 return -EBUSY; /* already open */
63 }
64
65 /* then, everything else is copied from the bare scull device */
66 if ( (filp->f_flags & O_ACCMODE) == O_WRONLY)
67 scull_trim(dev);
68 filp->private_data = dev;
69 return 0; /* success */
70 }
71
72 static int scull_s_release(struct inode *inode, struct file *filp)
73 {
74 atomic_inc(&scull_s_available); /* release the device */
75 return 0;
76 }
77
78
79 /*
80 * The other operations for the single-open device come from the bare device
81 */
82 struct file_operations scull_sngl_fops = {
83 .owner = THIS_MODULE,
84 .llseek = scull_llseek,
85 .read = scull_read,
86 .write = scull_write,
87 .ioctl = scull_ioctl,
88 .open = scull_s_open,
89 .release = scull_s_release,
90 };
91
92
93 /************************************************************************
94 *
95 * Next, the "uid" device. It can be opened multiple times by the
96 * same user, but access is denied to other users if the device is open
97 */
98
99 static struct scull_dev scull_u_device;
100 static int scull_u_count; /* initialized to 0 by default */
101 static uid_t scull_u_owner; /* initialized to 0 by default */
102 static spinlock_t scull_u_lock = SPIN_LOCK_UNLOCKED;
103
104 static int scull_u_open(struct inode *inode, struct file *filp)
105 {
106 struct scull_dev *dev = &scull_u_device; /* device information */
107
108 spin_lock(&scull_u_lock);
109 if (scull_u_count &&
110 (scull_u_owner != current->cred->uid) && /* allow user */
111 (scull_u_owner != current->cred->euid) && /* allow whoever did su */
112 !capable(CAP_DAC_OVERRIDE)) { /* still allow root */
113 spin_unlock(&scull_u_lock);
114 return -EBUSY; /* -EPERM would confuse the user */
115 }
116
117 if (scull_u_count == 0)
118 scull_u_owner = current->cred->uid; /* grab it */
119
120 scull_u_count++;
121 spin_unlock(&scull_u_lock);
122
123 /* then, everything else is copied from the bare scull device */
124
125 if ((filp->f_flags & O_ACCMODE) == O_WRONLY)
126 scull_trim(dev);
127 filp->private_data = dev;
128 return 0; /* success */
129 }
130
131 static int scull_u_release(struct inode *inode, struct file *filp)
132 {
133 spin_lock(&scull_u_lock);
134 scull_u_count--; /* nothing else */
135 spin_unlock(&scull_u_lock);
136 return 0;
137 }
138
139
140
141 /*
142 * The other operations for the device come from the bare device
143 */
144 struct file_operations scull_user_fops = {
145 .owner = THIS_MODULE,
146 .llseek = scull_llseek,
147 .read = scull_read,
148 .write = scull_write,
149 .ioctl = scull_ioctl,
150 .open = scull_u_open,
151 .release = scull_u_release,
152 };
153
154
155 /************************************************************************
156 *
157 * Next, the device with blocking-open based on uid
158 */
159
160 static struct scull_dev scull_w_device;
161 static int scull_w_count; /* initialized to 0 by default */
162 static uid_t scull_w_owner; /* initialized to 0 by default */
163 static DECLARE_WAIT_QUEUE_HEAD(scull_w_wait);
164 static spinlock_t scull_w_lock = SPIN_LOCK_UNLOCKED;
165
166 static inline int scull_w_available(void)
167 {
168 return scull_w_count == 0 ||
169 scull_w_owner == current->cred->uid ||
170 scull_w_owner == current->cred->euid ||
171 capable(CAP_DAC_OVERRIDE);
172 }
173
174
175 static int scull_w_open(struct inode *inode, struct file *filp)
176 {
177 struct scull_dev *dev = &scull_w_device; /* device information */
178
179 spin_lock(&scull_w_lock);
180 while (! scull_w_available()) {
181 spin_unlock(&scull_w_lock);
182 if (filp->f_flags & O_NONBLOCK) return -EAGAIN;
183 if (wait_event_interruptible (scull_w_wait, scull_w_available()))
184 return -ERESTARTSYS; /* tell the fs layer to handle it */
185 spin_lock(&scull_w_lock);
186 }
187 if (scull_w_count == 0)
188 scull_w_owner = current->cred->uid; /* grab it */
189 scull_w_count++;
190 spin_unlock(&scull_w_lock);
191
192 /* then, everything else is copied from the bare scull device */
193 if ((filp->f_flags & O_ACCMODE) == O_WRONLY)
194 scull_trim(dev);
195 filp->private_data = dev;
196 return 0; /* success */
197 }
198
199 static int scull_w_release(struct inode *inode, struct file *filp)
200 {
201 int temp;
202
203 spin_lock(&scull_w_lock);
204 scull_w_count--;
205 temp = scull_w_count;
206 spin_unlock(&scull_w_lock);
207
208 if (temp == 0)
209 wake_up_interruptible_sync(&scull_w_wait); /* awake other uid's */
210 return 0;
211 }
212
213
214 /*
215 * The other operations for the device come from the bare device
216 */
217 struct file_operations scull_wusr_fops = {
218 .owner = THIS_MODULE,
219 .llseek = scull_llseek,
220 .read = scull_read,
221 .write = scull_write,
222 .ioctl = scull_ioctl,
223 .open = scull_w_open,
224 .release = scull_w_release,
225 };
226
227 /************************************************************************
228 *
229 * Finally the `cloned' private device. This is trickier because it
230 * involves list management, and dynamic allocation.
231 */
232
233 /* The clone-specific data structure includes a key field */
234
235 struct scull_listitem {
236 struct scull_dev device;
237 dev_t key;
238 struct list_head list;
239
240 };
241
242 /* The list of devices, and a lock to protect it */
243 static LIST_HEAD(scull_c_list);
244 static spinlock_t scull_c_lock = SPIN_LOCK_UNLOCKED;
245
246 /* A placeholder scull_dev which really just holds the cdev stuff. */
247 static struct scull_dev scull_c_device;
248
249 /* Look for a device or create one if missing */
250 static struct scull_dev *scull_c_lookfor_device(dev_t key)
251 {
252 struct scull_listitem *lptr;
253
254 list_for_each_entry(lptr, &scull_c_list, list) {
255 if (lptr->key == key)
256 return &(lptr->device);
257 }
258
259 /* not found */
260 lptr = kmalloc(sizeof(struct scull_listitem), GFP_KERNEL);
261 if (!lptr)
262 return NULL;
263
264 /* initialize the device */
265 memset(lptr, 0, sizeof(struct scull_listitem));
266 lptr->key = key;
267 scull_trim(&(lptr->device)); /* initialize it */
268 init_MUTEX(&(lptr->device.sem));
269
270 /* place it in the list */
271 list_add(&lptr->list, &scull_c_list);
272
273 return &(lptr->device);
274 }
275
276 static int scull_c_open(struct inode *inode, struct file *filp)
277 {
278 struct scull_dev *dev;
279 dev_t key;
280
281 if (!current->signal->tty) {
282 PDEBUG("Process \"%s\" has no ctl tty\n", current->comm);
283 return -EINVAL;
284 }
285 key = tty_devnum(current->signal->tty);
286
287 /* look for a scullc device in the list */
288 spin_lock(&scull_c_lock);
289 dev = scull_c_lookfor_device(key);
290 spin_unlock(&scull_c_lock);
291
292 if (!dev)
293 return -ENOMEM;
294
295 /* then, everything else is copied from the bare scull device */
296 if ( (filp->f_flags & O_ACCMODE) == O_WRONLY)
297 scull_trim(dev);
298 filp->private_data = dev;
299 return 0; /* success */
300 }
301
302 static int scull_c_release(struct inode *inode, struct file *filp)
303 {
304 /*
305 * Nothing to do, because the device is persistent.
306 * A `real' cloned device should be freed on last close
307 */
308 return 0;
309 }
310
311
312
313 /*
314 * The other operations for the device come from the bare device
315 */
316 struct file_operations scull_priv_fops = {
317 .owner = THIS_MODULE,
318 .llseek = scull_llseek,
319 .read = scull_read,
320 .write = scull_write,
321 .ioctl = scull_ioctl,
322 .open = scull_c_open,
323 .release = scull_c_release,
324 };
325
326 /************************************************************************
327 *
328 * And the init and cleanup functions come last
329 */
330
331 static struct scull_adev_info {
332 char *name;
333 struct scull_dev *sculldev;
334 struct file_operations *fops;
335 } scull_access_devs[] = {
336 { "scullsingle", &scull_s_device, &scull_sngl_fops },
337 { "sculluid", &scull_u_device, &scull_user_fops },
338 { "scullwuid", &scull_w_device, &scull_wusr_fops },
339 { "sullpriv", &scull_c_device, &scull_priv_fops }
340 };
341 #define SCULL_N_ADEVS 4
342
343 /*
344 * Set up a single device.
345 */
346 static void scull_access_setup (dev_t devno, struct scull_adev_info *devinfo)
347 {
348 struct scull_dev *dev = devinfo->sculldev;
349 int err;
350
351 /* Initialize the device structure */
352 dev->quantum = scull_quantum;
353 dev->qset = scull_qset;
354 init_MUTEX(&dev->sem);
355
356 /* Do the cdev stuff. */
357 cdev_init(&dev->cdev, devinfo->fops);
358 kobject_set_name(&dev->cdev.kobj, devinfo->name);
359 dev->cdev.owner = THIS_MODULE;
360 err = cdev_add (&dev->cdev, devno, 1);
361 /* Fail gracefully if need be */
362 if (err) {
363 printk(KERN_NOTICE "Error %d adding %s\n", err, devinfo->name);
364 kobject_put(&dev->cdev.kobj);
365 } else
366 printk(KERN_NOTICE "%s registered at %x\n", devinfo->name, devno);
367 }
368
369
370 int scull_access_init(dev_t firstdev)
371 {
372 int result, i;
373
374 /* Get our number space */
375 result = register_chrdev_region (firstdev, SCULL_N_ADEVS, "sculla");
376 if (result < 0) {
377 printk(KERN_WARNING "sculla: device number registration failed\n");
378 return 0;
379 }
380 scull_a_firstdev = firstdev;
381
382 /* Set up each device. */
383 for (i = 0; i < SCULL_N_ADEVS; i++)
384 scull_access_setup (firstdev + i, scull_access_devs + i);
385 return SCULL_N_ADEVS;
386 }
387
388 /*
389 * This is called by cleanup_module or on failure.
390 * It is required to never fail, even if nothing was initialized first
391 */
392 void scull_access_cleanup(void)
393 {
394 struct scull_listitem *lptr, *next;
395 int i;
396
397 /* Clean up the static devs */
398 for (i = 0; i < SCULL_N_ADEVS; i++) {
399 struct scull_dev *dev = scull_access_devs[i].sculldev;
400 cdev_del(&dev->cdev);
401 scull_trim(scull_access_devs[i].sculldev);
402 }
403
404 /* And all the cloned devices */
405 list_for_each_entry_safe(lptr, next, &scull_c_list, list) {
406 list_del(&lptr->list);
407 scull_trim(&(lptr->device));
408 kfree(lptr);
409 }
410
411 /* Free up our number space */
412 unregister_chrdev_region(scull_a_firstdev, SCULL_N_ADEVS);
413 return;
414 }
415
|
This page was automatically generated by the
LXR engine.
|