Merge master.kernel.org:/home/rmk/linux-2.6-serial
[linux-2.6] / fs / reiserfs / xattr_acl.c
1 #include <linux/fs.h>
2 #include <linux/posix_acl.h>
3 #include <linux/reiserfs_fs.h>
4 #include <linux/errno.h>
5 #include <linux/pagemap.h>
6 #include <linux/xattr.h>
7 #include <linux/posix_acl_xattr.h>
8 #include <linux/reiserfs_xattr.h>
9 #include <linux/reiserfs_acl.h>
10 #include <asm/uaccess.h>
11
12 static int reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl);
13
14 static int
15 xattr_set_acl(struct inode *inode, int type, const void *value, size_t size)
16 {
17         struct posix_acl *acl;
18         int error;
19
20         if (!reiserfs_posixacl(inode->i_sb))
21                 return -EOPNOTSUPP;
22         if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
23                 return -EPERM;
24
25         if (value) {
26                 acl = posix_acl_from_xattr(value, size);
27                 if (IS_ERR(acl)) {
28                         return PTR_ERR(acl);
29                 } else if (acl) {
30                         error = posix_acl_valid(acl);
31                         if (error)
32                                 goto release_and_out;
33                 }
34         } else
35                 acl = NULL;
36
37         error = reiserfs_set_acl (inode, type, acl);
38
39 release_and_out:
40         posix_acl_release(acl);
41         return error;
42 }
43
44
45 static int
46 xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size)
47 {
48         struct posix_acl *acl;
49         int error;
50
51         if (!reiserfs_posixacl(inode->i_sb))
52                 return -EOPNOTSUPP;
53
54         acl = reiserfs_get_acl (inode, type);
55         if (IS_ERR(acl))
56                 return PTR_ERR(acl);
57         if (acl == NULL)
58                 return -ENODATA;
59         error = posix_acl_to_xattr(acl, buffer, size);
60         posix_acl_release(acl);
61
62         return error;
63 }
64
65
66 /*
67  * Convert from filesystem to in-memory representation.
68  */
69 static struct posix_acl *
70 posix_acl_from_disk(const void *value, size_t size)
71 {
72         const char *end = (char *)value + size;
73         int n, count;
74         struct posix_acl *acl;
75
76         if (!value)
77                 return NULL;
78         if (size < sizeof(reiserfs_acl_header))
79                  return ERR_PTR(-EINVAL);
80         if (((reiserfs_acl_header *)value)->a_version !=
81             cpu_to_le32(REISERFS_ACL_VERSION))
82                 return ERR_PTR(-EINVAL);
83         value = (char *)value + sizeof(reiserfs_acl_header);
84         count = reiserfs_acl_count(size);
85         if (count < 0)
86                 return ERR_PTR(-EINVAL);
87         if (count == 0)
88                 return NULL;
89         acl = posix_acl_alloc(count, GFP_NOFS);
90         if (!acl)
91                 return ERR_PTR(-ENOMEM);
92         for (n=0; n < count; n++) {
93                 reiserfs_acl_entry *entry =
94                         (reiserfs_acl_entry *)value;
95                 if ((char *)value + sizeof(reiserfs_acl_entry_short) > end)
96                         goto fail;
97                 acl->a_entries[n].e_tag  = le16_to_cpu(entry->e_tag);
98                 acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm);
99                 switch(acl->a_entries[n].e_tag) {
100                         case ACL_USER_OBJ:
101                         case ACL_GROUP_OBJ:
102                         case ACL_MASK:
103                         case ACL_OTHER:
104                                 value = (char *)value +
105                                         sizeof(reiserfs_acl_entry_short);
106                                 acl->a_entries[n].e_id = ACL_UNDEFINED_ID;
107                                 break;
108
109                         case ACL_USER:
110                         case ACL_GROUP:
111                                 value = (char *)value + sizeof(reiserfs_acl_entry);
112                                 if ((char *)value > end)
113                                         goto fail;
114                                 acl->a_entries[n].e_id =
115                                         le32_to_cpu(entry->e_id);
116                                 break;
117
118                         default:
119                                 goto fail;
120                 }
121         }
122         if (value != end)
123                 goto fail;
124         return acl;
125
126 fail:
127         posix_acl_release(acl);
128         return ERR_PTR(-EINVAL);
129 }
130
131 /*
132  * Convert from in-memory to filesystem representation.
133  */
134 static void *
135 posix_acl_to_disk(const struct posix_acl *acl, size_t *size)
136 {
137         reiserfs_acl_header *ext_acl;
138         char *e;
139         int n;
140
141         *size = reiserfs_acl_size(acl->a_count);
142         ext_acl = (reiserfs_acl_header *)kmalloc(sizeof(reiserfs_acl_header) +
143                 acl->a_count * sizeof(reiserfs_acl_entry), GFP_NOFS);
144         if (!ext_acl)
145                 return ERR_PTR(-ENOMEM);
146         ext_acl->a_version = cpu_to_le32(REISERFS_ACL_VERSION);
147         e = (char *)ext_acl + sizeof(reiserfs_acl_header);
148         for (n=0; n < acl->a_count; n++) {
149                 reiserfs_acl_entry *entry = (reiserfs_acl_entry *)e;
150                 entry->e_tag  = cpu_to_le16(acl->a_entries[n].e_tag);
151                 entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm);
152                 switch(acl->a_entries[n].e_tag) {
153                         case ACL_USER:
154                         case ACL_GROUP:
155                                 entry->e_id =
156                                         cpu_to_le32(acl->a_entries[n].e_id);
157                                 e += sizeof(reiserfs_acl_entry);
158                                 break;
159
160                         case ACL_USER_OBJ:
161                         case ACL_GROUP_OBJ:
162                         case ACL_MASK:
163                         case ACL_OTHER:
164                                 e += sizeof(reiserfs_acl_entry_short);
165                                 break;
166
167                         default:
168                                 goto fail;
169                 }
170         }
171         return (char *)ext_acl;
172
173 fail:
174         kfree(ext_acl);
175         return ERR_PTR(-EINVAL);
176 }
177
178 /*
179  * Inode operation get_posix_acl().
180  *
181  * inode->i_sem: down
182  * BKL held [before 2.5.x]
183  */
184 struct posix_acl *
185 reiserfs_get_acl(struct inode *inode, int type)
186 {
187         char *name, *value;
188         struct posix_acl *acl, **p_acl;
189         size_t size;
190         int retval;
191         struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
192
193         switch (type) {
194             case ACL_TYPE_ACCESS:
195                 name = POSIX_ACL_XATTR_ACCESS;
196                 p_acl = &reiserfs_i->i_acl_access;
197                 break;
198             case ACL_TYPE_DEFAULT:
199                 name = POSIX_ACL_XATTR_DEFAULT;
200                 p_acl = &reiserfs_i->i_acl_default;
201                 break;
202             default:
203                 return ERR_PTR (-EINVAL);
204         }
205
206         if (IS_ERR (*p_acl)) {
207             if (PTR_ERR (*p_acl) == -ENODATA)
208                 return NULL;
209         } else if (*p_acl != NULL)
210             return posix_acl_dup (*p_acl);
211
212         size = reiserfs_xattr_get (inode, name, NULL, 0);
213         if ((int)size < 0) {
214             if (size == -ENODATA || size == -ENOSYS) {
215                 *p_acl = ERR_PTR (-ENODATA);
216                 return NULL;
217             }
218             return ERR_PTR (size);
219         }
220
221         value = kmalloc (size, GFP_NOFS);
222         if (!value)
223             return ERR_PTR (-ENOMEM);
224
225         retval = reiserfs_xattr_get(inode, name, value, size);
226         if (retval == -ENODATA || retval == -ENOSYS) {
227                 /* This shouldn't actually happen as it should have
228                    been caught above.. but just in case */
229                 acl = NULL;
230                 *p_acl = ERR_PTR (-ENODATA);
231         } else if (retval < 0) {
232                 acl = ERR_PTR(retval);
233         } else {
234                 acl = posix_acl_from_disk(value, retval);
235                 *p_acl = posix_acl_dup (acl);
236         }
237
238         kfree(value);
239         return acl;
240 }
241
242 /*
243  * Inode operation set_posix_acl().
244  *
245  * inode->i_sem: down
246  * BKL held [before 2.5.x]
247  */
248 static int
249 reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
250 {
251         char *name;
252         void *value = NULL;
253         struct posix_acl **p_acl;
254         size_t size;
255         int error;
256         struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
257
258         if (S_ISLNK(inode->i_mode))
259                 return -EOPNOTSUPP;
260
261         switch (type) {
262             case ACL_TYPE_ACCESS:
263                 name = POSIX_ACL_XATTR_ACCESS;
264                 p_acl = &reiserfs_i->i_acl_access;
265                 if (acl) {
266                     mode_t mode = inode->i_mode;
267                     error = posix_acl_equiv_mode (acl, &mode);
268                     if (error < 0)
269                         return error;
270                     else {
271                         inode->i_mode = mode;
272                         if (error == 0)
273                             acl = NULL;
274                     }
275                 }
276                 break;
277             case ACL_TYPE_DEFAULT:
278                 name = POSIX_ACL_XATTR_DEFAULT;
279                 p_acl = &reiserfs_i->i_acl_default;
280                 if (!S_ISDIR (inode->i_mode))
281                     return acl ? -EACCES : 0;
282                 break;
283             default:
284                 return -EINVAL;
285         }
286
287         if (acl) {
288             value = posix_acl_to_disk(acl, &size);
289             if (IS_ERR(value))
290                 return (int)PTR_ERR(value);
291             error = reiserfs_xattr_set(inode, name, value, size, 0);
292         } else {
293             error = reiserfs_xattr_del (inode, name);
294             if (error == -ENODATA) {
295                 /* This may seem odd here, but it means that the ACL was set
296                  * with a value representable with mode bits. If there was
297                  * an ACL before, reiserfs_xattr_del already dirtied the inode.
298                  */
299                 mark_inode_dirty (inode);
300                 error = 0;
301             }
302         }
303
304         if (value)
305                 kfree(value);
306
307         if (!error) {
308             /* Release the old one */
309             if (!IS_ERR (*p_acl) && *p_acl)
310                 posix_acl_release (*p_acl);
311
312             if (acl == NULL)
313                 *p_acl = ERR_PTR (-ENODATA);
314             else
315                 *p_acl = posix_acl_dup (acl);
316         }
317
318         return error;
319 }
320
321 /* dir->i_sem: down,
322  * inode is new and not released into the wild yet */
323 int
324 reiserfs_inherit_default_acl (struct inode *dir, struct dentry *dentry, struct inode *inode)
325 {
326     struct posix_acl *acl;
327     int err = 0;
328
329     /* ACLs only get applied to files and directories */
330     if (S_ISLNK (inode->i_mode))
331         return 0;
332
333     /* ACLs can only be used on "new" objects, so if it's an old object
334      * there is nothing to inherit from */
335     if (get_inode_sd_version (dir) == STAT_DATA_V1)
336         goto apply_umask;
337
338     /* Don't apply ACLs to objects in the .reiserfs_priv tree.. This
339      * would be useless since permissions are ignored, and a pain because
340      * it introduces locking cycles */
341     if (is_reiserfs_priv_object (dir)) {
342         reiserfs_mark_inode_private (inode);
343         goto apply_umask;
344     }
345
346     acl = reiserfs_get_acl (dir, ACL_TYPE_DEFAULT);
347     if (IS_ERR (acl)) {
348         if (PTR_ERR (acl) == -ENODATA)
349             goto apply_umask;
350         return PTR_ERR (acl);
351     }
352
353     if (acl) {
354         struct posix_acl *acl_copy;
355         mode_t mode = inode->i_mode;
356         int need_acl;
357
358         /* Copy the default ACL to the default ACL of a new directory */
359         if (S_ISDIR (inode->i_mode)) {
360             err = reiserfs_set_acl (inode, ACL_TYPE_DEFAULT, acl);
361             if (err)
362                 goto cleanup;
363         }
364
365         /* Now we reconcile the new ACL and the mode,
366            potentially modifying both */
367         acl_copy = posix_acl_clone (acl, GFP_NOFS);
368         if (!acl_copy) {
369             err = -ENOMEM;
370             goto cleanup;
371         }
372
373
374         need_acl = posix_acl_create_masq (acl_copy, &mode);
375         if (need_acl >= 0) {
376             if (mode != inode->i_mode) {
377                 inode->i_mode = mode;
378             }
379
380             /* If we need an ACL.. */
381             if (need_acl > 0) {
382                 err = reiserfs_set_acl (inode, ACL_TYPE_ACCESS, acl_copy);
383                 if (err)
384                     goto cleanup_copy;
385             }
386         }
387 cleanup_copy:
388         posix_acl_release (acl_copy);
389 cleanup:
390         posix_acl_release (acl);
391     } else {
392 apply_umask:
393         /* no ACL, apply umask */
394         inode->i_mode &= ~current->fs->umask;
395     }
396
397     return err;
398 }
399
400 /* Looks up and caches the result of the default ACL.
401  * We do this so that we don't need to carry the xattr_sem into
402  * reiserfs_new_inode if we don't need to */
403 int
404 reiserfs_cache_default_acl (struct inode *inode)
405 {
406     int ret = 0;
407     if (reiserfs_posixacl (inode->i_sb) &&
408         !is_reiserfs_priv_object (inode)) {
409         struct posix_acl *acl;
410         reiserfs_read_lock_xattr_i (inode);
411         reiserfs_read_lock_xattrs (inode->i_sb);
412         acl = reiserfs_get_acl (inode, ACL_TYPE_DEFAULT);
413         reiserfs_read_unlock_xattrs (inode->i_sb);
414         reiserfs_read_unlock_xattr_i (inode);
415         ret = acl ? 1 : 0;
416         posix_acl_release (acl);
417     }
418
419     return ret;
420 }
421
422 int
423 reiserfs_acl_chmod (struct inode *inode)
424 {
425         struct posix_acl *acl, *clone;
426         int error;
427
428         if (S_ISLNK(inode->i_mode))
429                 return -EOPNOTSUPP;
430
431         if (get_inode_sd_version (inode) == STAT_DATA_V1 ||
432             !reiserfs_posixacl(inode->i_sb))
433         {
434             return 0;
435         }
436
437         reiserfs_read_lock_xattrs (inode->i_sb);
438         acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS);
439         reiserfs_read_unlock_xattrs (inode->i_sb);
440         if (!acl)
441                 return 0;
442         if (IS_ERR(acl))
443                 return PTR_ERR(acl);
444         clone = posix_acl_clone(acl, GFP_NOFS);
445         posix_acl_release(acl);
446         if (!clone)
447                 return -ENOMEM;
448         error = posix_acl_chmod_masq(clone, inode->i_mode);
449         if (!error) {
450                 int lock = !has_xattr_dir (inode);
451                 reiserfs_write_lock_xattr_i (inode);
452                 if (lock)
453                     reiserfs_write_lock_xattrs (inode->i_sb);
454                 else
455                     reiserfs_read_lock_xattrs (inode->i_sb);
456                 error = reiserfs_set_acl(inode, ACL_TYPE_ACCESS, clone);
457                 if (lock)
458                     reiserfs_write_unlock_xattrs (inode->i_sb);
459                 else
460                     reiserfs_read_unlock_xattrs (inode->i_sb);
461                 reiserfs_write_unlock_xattr_i (inode);
462         }
463         posix_acl_release(clone);
464         return error;
465 }
466
467 static int
468 posix_acl_access_get(struct inode *inode, const char *name,
469                           void *buffer, size_t size)
470 {
471         if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS)-1)
472                 return -EINVAL;
473         return xattr_get_acl(inode, ACL_TYPE_ACCESS, buffer, size);
474 }
475
476 static int
477 posix_acl_access_set(struct inode *inode, const char *name,
478                           const void *value, size_t size, int flags)
479 {
480         if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS)-1)
481                 return -EINVAL;
482         return xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size);
483 }
484
485 static int
486 posix_acl_access_del (struct inode *inode, const char *name)
487 {
488     struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
489     struct posix_acl **acl = &reiserfs_i->i_acl_access;
490     if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS)-1)
491         return -EINVAL;
492     if (!IS_ERR (*acl) && *acl) {
493         posix_acl_release (*acl);
494         *acl = ERR_PTR (-ENODATA);
495     }
496
497     return 0;
498 }
499
500 static int
501 posix_acl_access_list (struct inode *inode, const char *name, int namelen, char *out)
502 {
503     int len = namelen;
504     if (!reiserfs_posixacl (inode->i_sb))
505         return 0;
506     if (out)
507         memcpy (out, name, len);
508
509     return len;
510 }
511
512 struct reiserfs_xattr_handler posix_acl_access_handler = {
513         .prefix = POSIX_ACL_XATTR_ACCESS,
514         .get = posix_acl_access_get,
515         .set = posix_acl_access_set,
516         .del = posix_acl_access_del,
517         .list = posix_acl_access_list,
518 };
519
520 static int
521 posix_acl_default_get (struct inode *inode, const char *name,
522                            void *buffer, size_t size)
523 {
524         if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT)-1)
525                 return -EINVAL;
526         return xattr_get_acl(inode, ACL_TYPE_DEFAULT, buffer, size);
527 }
528
529 static int
530 posix_acl_default_set(struct inode *inode, const char *name,
531                            const void *value, size_t size, int flags)
532 {
533         if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT)-1)
534                 return -EINVAL;
535         return xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size);
536 }
537
538 static int
539 posix_acl_default_del (struct inode *inode, const char *name)
540 {
541     struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
542     struct posix_acl **acl = &reiserfs_i->i_acl_default;
543     if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT)-1)
544         return -EINVAL;
545     if (!IS_ERR (*acl) && *acl) {
546         posix_acl_release (*acl);
547         *acl = ERR_PTR (-ENODATA);
548     }
549
550     return 0;
551 }
552
553 static int
554 posix_acl_default_list (struct inode *inode, const char *name, int namelen, char *out)
555 {
556     int len = namelen;
557     if (!reiserfs_posixacl (inode->i_sb))
558         return 0;
559     if (out)
560         memcpy (out, name, len);
561
562     return len;
563 }
564
565 struct reiserfs_xattr_handler posix_acl_default_handler = {
566         .prefix = POSIX_ACL_XATTR_DEFAULT,
567         .get = posix_acl_default_get,
568         .set = posix_acl_default_set,
569         .del = posix_acl_default_del,
570         .list = posix_acl_default_list,
571 };