ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / fs / ext3 / acl.c
1 /*
2  * linux/fs/ext3/acl.c
3  *
4  * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
5  */
6
7 #include <linux/init.h>
8 #include <linux/sched.h>
9 #include <linux/slab.h>
10 #include <linux/fs.h>
11 #include <linux/ext3_jbd.h>
12 #include <linux/ext3_fs.h>
13 #include "xattr.h"
14 #include "acl.h"
15
16 /*
17  * Convert from filesystem to in-memory representation.
18  */
19 static struct posix_acl *
20 ext3_acl_from_disk(const void *value, size_t size)
21 {
22         const char *end = (char *)value + size;
23         int n, count;
24         struct posix_acl *acl;
25
26         if (!value)
27                 return NULL;
28         if (size < sizeof(ext3_acl_header))
29                  return ERR_PTR(-EINVAL);
30         if (((ext3_acl_header *)value)->a_version !=
31             cpu_to_le32(EXT3_ACL_VERSION))
32                 return ERR_PTR(-EINVAL);
33         value = (char *)value + sizeof(ext3_acl_header);
34         count = ext3_acl_count(size);
35         if (count < 0)
36                 return ERR_PTR(-EINVAL);
37         if (count == 0)
38                 return NULL;
39         acl = posix_acl_alloc(count, GFP_KERNEL);
40         if (!acl)
41                 return ERR_PTR(-ENOMEM);
42         for (n=0; n < count; n++) {
43                 ext3_acl_entry *entry =
44                         (ext3_acl_entry *)value;
45                 if ((char *)value + sizeof(ext3_acl_entry_short) > end)
46                         goto fail;
47                 acl->a_entries[n].e_tag  = le16_to_cpu(entry->e_tag);
48                 acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm);
49                 switch(acl->a_entries[n].e_tag) {
50                         case ACL_USER_OBJ:
51                         case ACL_GROUP_OBJ:
52                         case ACL_MASK:
53                         case ACL_OTHER:
54                                 value = (char *)value +
55                                         sizeof(ext3_acl_entry_short);
56                                 acl->a_entries[n].e_id = ACL_UNDEFINED_ID;
57                                 break;
58
59                         case ACL_USER:
60                         case ACL_GROUP:
61                                 value = (char *)value + sizeof(ext3_acl_entry);
62                                 if ((char *)value > end)
63                                         goto fail;
64                                 acl->a_entries[n].e_id =
65                                         le32_to_cpu(entry->e_id);
66                                 break;
67
68                         default:
69                                 goto fail;
70                 }
71         }
72         if (value != end)
73                 goto fail;
74         return acl;
75
76 fail:
77         posix_acl_release(acl);
78         return ERR_PTR(-EINVAL);
79 }
80
81 /*
82  * Convert from in-memory to filesystem representation.
83  */
84 static void *
85 ext3_acl_to_disk(const struct posix_acl *acl, size_t *size)
86 {
87         ext3_acl_header *ext_acl;
88         char *e;
89         size_t n;
90
91         *size = ext3_acl_size(acl->a_count);
92         ext_acl = (ext3_acl_header *)kmalloc(sizeof(ext3_acl_header) +
93                 acl->a_count * sizeof(ext3_acl_entry), GFP_KERNEL);
94         if (!ext_acl)
95                 return ERR_PTR(-ENOMEM);
96         ext_acl->a_version = cpu_to_le32(EXT3_ACL_VERSION);
97         e = (char *)ext_acl + sizeof(ext3_acl_header);
98         for (n=0; n < acl->a_count; n++) {
99                 ext3_acl_entry *entry = (ext3_acl_entry *)e;
100                 entry->e_tag  = cpu_to_le16(acl->a_entries[n].e_tag);
101                 entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm);
102                 switch(acl->a_entries[n].e_tag) {
103                         case ACL_USER:
104                         case ACL_GROUP:
105                                 entry->e_id =
106                                         cpu_to_le32(acl->a_entries[n].e_id);
107                                 e += sizeof(ext3_acl_entry);
108                                 break;
109
110                         case ACL_USER_OBJ:
111                         case ACL_GROUP_OBJ:
112                         case ACL_MASK:
113                         case ACL_OTHER:
114                                 e += sizeof(ext3_acl_entry_short);
115                                 break;
116
117                         default:
118                                 goto fail;
119                 }
120         }
121         return (char *)ext_acl;
122
123 fail:
124         kfree(ext_acl);
125         return ERR_PTR(-EINVAL);
126 }
127
128 static inline struct posix_acl *
129 ext3_iget_acl(struct inode *inode, struct posix_acl **i_acl)
130 {
131         struct posix_acl *acl = EXT3_ACL_NOT_CACHED;
132
133         spin_lock(&inode->i_lock);
134         if (*i_acl != EXT3_ACL_NOT_CACHED)
135                 acl = posix_acl_dup(*i_acl);
136         spin_unlock(&inode->i_lock);
137
138         return acl;
139 }
140
141 static inline void
142 ext3_iset_acl(struct inode *inode, struct posix_acl **i_acl,
143                   struct posix_acl *acl)
144 {
145         spin_lock(&inode->i_lock);
146         if (*i_acl != EXT3_ACL_NOT_CACHED)
147                 posix_acl_release(*i_acl);
148         *i_acl = posix_acl_dup(acl);
149         spin_unlock(&inode->i_lock);
150 }
151
152 /*
153  * Inode operation get_posix_acl().
154  *
155  * inode->i_sem: don't care
156  */
157 static struct posix_acl *
158 ext3_get_acl(struct inode *inode, int type)
159 {
160         struct ext3_inode_info *ei = EXT3_I(inode);
161         int name_index;
162         char *value = NULL;
163         struct posix_acl *acl;
164         int retval;
165
166         if (!test_opt(inode->i_sb, POSIX_ACL))
167                 return 0;
168
169         switch(type) {
170                 case ACL_TYPE_ACCESS:
171                         acl = ext3_iget_acl(inode, &ei->i_acl);
172                         if (acl != EXT3_ACL_NOT_CACHED)
173                                 return acl;
174                         name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS;
175                         break;
176
177                 case ACL_TYPE_DEFAULT:
178                         acl = ext3_iget_acl(inode, &ei->i_default_acl);
179                         if (acl != EXT3_ACL_NOT_CACHED)
180                                 return acl;
181                         name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT;
182                         break;
183
184                 default:
185                         return ERR_PTR(-EINVAL);
186         }
187         retval = ext3_xattr_get(inode, name_index, "", NULL, 0);
188         if (retval > 0) {
189                 value = kmalloc(retval, GFP_KERNEL);
190                 if (!value)
191                         return ERR_PTR(-ENOMEM);
192                 retval = ext3_xattr_get(inode, name_index, "", value, retval);
193         }
194         if (retval > 0)
195                 acl = ext3_acl_from_disk(value, retval);
196         else if (retval == -ENODATA || retval == -ENOSYS)
197                 acl = NULL;
198         else
199                 acl = ERR_PTR(retval);
200         if (value)
201                 kfree(value);
202
203         if (!IS_ERR(acl)) {
204                 switch(type) {
205                         case ACL_TYPE_ACCESS:
206                                 ext3_iset_acl(inode, &ei->i_acl, acl);
207                                 break;
208
209                         case ACL_TYPE_DEFAULT:
210                                 ext3_iset_acl(inode, &ei->i_default_acl, acl);
211                                 break;
212                 }
213         }
214         return acl;
215 }
216
217 /*
218  * Set the access or default ACL of an inode.
219  *
220  * inode->i_sem: down unless called from ext3_new_inode
221  */
222 static int
223 ext3_set_acl(handle_t *handle, struct inode *inode, int type,
224              struct posix_acl *acl)
225 {
226         struct ext3_inode_info *ei = EXT3_I(inode);
227         int name_index;
228         void *value = NULL;
229         size_t size;
230         int error;
231
232         if (S_ISLNK(inode->i_mode))
233                 return -EOPNOTSUPP;
234
235         switch(type) {
236                 case ACL_TYPE_ACCESS:
237                         name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS;
238                         if (acl) {
239                                 mode_t mode = inode->i_mode;
240                                 error = posix_acl_equiv_mode(acl, &mode);
241                                 if (error < 0)
242                                         return error;
243                                 else {
244                                         inode->i_mode = mode;
245                                         ext3_mark_inode_dirty(handle, inode);
246                                         if (error == 0)
247                                                 acl = NULL;
248                                 }
249                         }
250                         break;
251
252                 case ACL_TYPE_DEFAULT:
253                         name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT;
254                         if (!S_ISDIR(inode->i_mode))
255                                 return acl ? -EACCES : 0;
256                         break;
257
258                 default:
259                         return -EINVAL;
260         }
261         if (acl) {
262                 if (acl->a_count > EXT3_ACL_MAX_ENTRIES)
263                         return -EINVAL;
264                 value = ext3_acl_to_disk(acl, &size);
265                 if (IS_ERR(value))
266                         return (int)PTR_ERR(value);
267         }
268
269         error = ext3_xattr_set_handle(handle, inode, name_index, "",
270                                       value, size, 0);
271
272         if (value)
273                 kfree(value);
274         if (!error) {
275                 switch(type) {
276                         case ACL_TYPE_ACCESS:
277                                 ext3_iset_acl(inode, &ei->i_acl, acl);
278                                 break;
279
280                         case ACL_TYPE_DEFAULT:
281                                 ext3_iset_acl(inode, &ei->i_default_acl, acl);
282                                 break;
283                 }
284         }
285         return error;
286 }
287
288 /*
289  * Inode operation permission().
290  *
291  * inode->i_sem: don't care
292  */
293 int
294 ext3_permission(struct inode *inode, int mask, struct nameidata *nd)
295 {
296         int mode = inode->i_mode;
297
298         /* Nobody gets write access to a read-only fs */
299         if ((mask & MAY_WRITE) && IS_RDONLY(inode) &&
300             (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
301                 return -EROFS;
302         /* Nobody gets write access to an immutable file */
303         if ((mask & MAY_WRITE) && IS_IMMUTABLE(inode))
304             return -EACCES;
305         if (current->fsuid == inode->i_uid) {
306                 mode >>= 6;
307         } else if (test_opt(inode->i_sb, POSIX_ACL)) {
308                 struct posix_acl *acl;
309
310                 /* The access ACL cannot grant access if the group class
311                    permission bits don't contain all requested permissions. */
312                 if (((mode >> 3) & mask & S_IRWXO) != mask)
313                         goto check_groups;
314                 acl = ext3_get_acl(inode, ACL_TYPE_ACCESS);
315                 if (acl) {
316                         int error = posix_acl_permission(inode, acl, mask);
317                         posix_acl_release(acl);
318                         if (error == -EACCES)
319                                 goto check_capabilities;
320                         return error;
321                 } else
322                         goto check_groups;
323         } else {
324 check_groups:
325                 if (in_group_p(inode->i_gid))
326                         mode >>= 3;
327         }
328         if ((mode & mask & S_IRWXO) == mask)
329                 return 0;
330
331 check_capabilities:
332         /* Allowed to override Discretionary Access Control? */
333         if (!(mask & MAY_EXEC) ||
334             (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode))
335                 if (capable(CAP_DAC_OVERRIDE))
336                         return 0;
337         /* Read and search granted if capable(CAP_DAC_READ_SEARCH) */
338         if (capable(CAP_DAC_READ_SEARCH) && ((mask == MAY_READ) ||
339             (S_ISDIR(inode->i_mode) && !(mask & MAY_WRITE))))
340                 return 0;
341         return -EACCES;
342 }
343
344 /*
345  * Initialize the ACLs of a new inode. Called from ext3_new_inode.
346  *
347  * dir->i_sem: down
348  * inode->i_sem: up (access to inode is still exclusive)
349  */
350 int
351 ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
352 {
353         struct posix_acl *acl = NULL;
354         int error = 0;
355
356         if (!S_ISLNK(inode->i_mode)) {
357                 if (test_opt(dir->i_sb, POSIX_ACL)) {
358                         acl = ext3_get_acl(dir, ACL_TYPE_DEFAULT);
359                         if (IS_ERR(acl))
360                                 return PTR_ERR(acl);
361                 }
362                 if (!acl)
363                         inode->i_mode &= ~current->fs->umask;
364         }
365         if (test_opt(inode->i_sb, POSIX_ACL) && acl) {
366                 struct posix_acl *clone;
367                 mode_t mode;
368
369                 if (S_ISDIR(inode->i_mode)) {
370                         error = ext3_set_acl(handle, inode,
371                                              ACL_TYPE_DEFAULT, acl);
372                         if (error)
373                                 goto cleanup;
374                 }
375                 clone = posix_acl_clone(acl, GFP_KERNEL);
376                 error = -ENOMEM;
377                 if (!clone)
378                         goto cleanup;
379
380                 mode = inode->i_mode;
381                 error = posix_acl_create_masq(clone, &mode);
382                 if (error >= 0) {
383                         inode->i_mode = mode;
384                         if (error > 0) {
385                                 /* This is an extended ACL */
386                                 error = ext3_set_acl(handle, inode,
387                                                      ACL_TYPE_ACCESS, clone);
388                         }
389                 }
390                 posix_acl_release(clone);
391         }
392 cleanup:
393         posix_acl_release(acl);
394         return error;
395 }
396
397 /*
398  * Does chmod for an inode that may have an Access Control List. The
399  * inode->i_mode field must be updated to the desired value by the caller
400  * before calling this function.
401  * Returns 0 on success, or a negative error number.
402  *
403  * We change the ACL rather than storing some ACL entries in the file
404  * mode permission bits (which would be more efficient), because that
405  * would break once additional permissions (like  ACL_APPEND, ACL_DELETE
406  * for directories) are added. There are no more bits available in the
407  * file mode.
408  *
409  * inode->i_sem: down
410  */
411 int
412 ext3_acl_chmod(struct inode *inode)
413 {
414         struct posix_acl *acl, *clone;
415         int error;
416
417         if (S_ISLNK(inode->i_mode))
418                 return -EOPNOTSUPP;
419         if (!test_opt(inode->i_sb, POSIX_ACL))
420                 return 0;
421         acl = ext3_get_acl(inode, ACL_TYPE_ACCESS);
422         if (IS_ERR(acl) || !acl)
423                 return PTR_ERR(acl);
424         clone = posix_acl_clone(acl, GFP_KERNEL);
425         posix_acl_release(acl);
426         if (!clone)
427                 return -ENOMEM;
428         error = posix_acl_chmod_masq(clone, inode->i_mode);
429         if (!error) {
430                 handle_t *handle;
431
432                 handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS);
433                 if (IS_ERR(handle)) {
434                         error = PTR_ERR(handle);
435                         ext3_std_error(inode->i_sb, error);
436                         goto out;
437                 }
438                 error = ext3_set_acl(handle, inode, ACL_TYPE_ACCESS, clone);
439                 ext3_journal_stop(handle);
440         }
441 out:
442         posix_acl_release(clone);
443         return error;
444 }
445
446 /*
447  * Extended attribute handlers
448  */
449 static size_t
450 ext3_xattr_list_acl_access(char *list, struct inode *inode,
451                            const char *name, int name_len)
452 {
453         const size_t size = sizeof(XATTR_NAME_ACL_ACCESS);
454
455         if (!test_opt(inode->i_sb, POSIX_ACL))
456                 return 0;
457         if (list)
458                 memcpy(list, XATTR_NAME_ACL_ACCESS, size);
459         return size;
460 }
461
462 static size_t
463 ext3_xattr_list_acl_default(char *list, struct inode *inode,
464                             const char *name, int name_len)
465 {
466         const size_t size = sizeof(XATTR_NAME_ACL_DEFAULT);
467
468         if (!test_opt(inode->i_sb, POSIX_ACL))
469                 return 0;
470         if (list)
471                 memcpy(list, XATTR_NAME_ACL_DEFAULT, size);
472         return size;
473 }
474
475 static int
476 ext3_xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size)
477 {
478         struct posix_acl *acl;
479         int error;
480
481         if (!test_opt(inode->i_sb, POSIX_ACL))
482                 return -EOPNOTSUPP;
483
484         acl = ext3_get_acl(inode, type);
485         if (IS_ERR(acl))
486                 return PTR_ERR(acl);
487         if (acl == NULL)
488                 return -ENODATA;
489         error = posix_acl_to_xattr(acl, buffer, size);
490         posix_acl_release(acl);
491
492         return error;
493 }
494
495 static int
496 ext3_xattr_get_acl_access(struct inode *inode, const char *name,
497                           void *buffer, size_t size)
498 {
499         if (strcmp(name, "") != 0)
500                 return -EINVAL;
501         return ext3_xattr_get_acl(inode, ACL_TYPE_ACCESS, buffer, size);
502 }
503
504 static int
505 ext3_xattr_get_acl_default(struct inode *inode, const char *name,
506                            void *buffer, size_t size)
507 {
508         if (strcmp(name, "") != 0)
509                 return -EINVAL;
510         return ext3_xattr_get_acl(inode, ACL_TYPE_DEFAULT, buffer, size);
511 }
512
513 static int
514 ext3_xattr_set_acl(struct inode *inode, int type, const void *value,
515                    size_t size)
516 {
517         handle_t *handle;
518         struct posix_acl *acl;
519         int error;
520
521         if (!test_opt(inode->i_sb, POSIX_ACL))
522                 return -EOPNOTSUPP;
523         if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
524                 return -EPERM;
525
526         if (value) {
527                 acl = posix_acl_from_xattr(value, size);
528                 if (IS_ERR(acl))
529                         return PTR_ERR(acl);
530                 else if (acl) {
531                         error = posix_acl_valid(acl);
532                         if (error)
533                                 goto release_and_out;
534                 }
535         } else
536                 acl = NULL;
537
538         handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS);
539         if (IS_ERR(handle))
540                 return PTR_ERR(handle);
541         error = ext3_set_acl(handle, inode, type, acl);
542         ext3_journal_stop(handle);
543
544 release_and_out:
545         posix_acl_release(acl);
546         return error;
547 }
548
549 static int
550 ext3_xattr_set_acl_access(struct inode *inode, const char *name,
551                           const void *value, size_t size, int flags)
552 {
553         if (strcmp(name, "") != 0)
554                 return -EINVAL;
555         return ext3_xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size);
556 }
557
558 static int
559 ext3_xattr_set_acl_default(struct inode *inode, const char *name,
560                            const void *value, size_t size, int flags)
561 {
562         if (strcmp(name, "") != 0)
563                 return -EINVAL;
564         return ext3_xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size);
565 }
566
567 struct ext3_xattr_handler ext3_xattr_acl_access_handler = {
568         .prefix = XATTR_NAME_ACL_ACCESS,
569         .list   = ext3_xattr_list_acl_access,
570         .get    = ext3_xattr_get_acl_access,
571         .set    = ext3_xattr_set_acl_access,
572 };
573
574 struct ext3_xattr_handler ext3_xattr_acl_default_handler = {
575         .prefix = XATTR_NAME_ACL_DEFAULT,
576         .list   = ext3_xattr_list_acl_default,
577         .get    = ext3_xattr_get_acl_default,
578         .set    = ext3_xattr_set_acl_default,
579 };
580
581 void
582 exit_ext3_acl(void)
583 {
584         ext3_xattr_unregister(EXT3_XATTR_INDEX_POSIX_ACL_ACCESS,
585                               &ext3_xattr_acl_access_handler);
586         ext3_xattr_unregister(EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT,
587                               &ext3_xattr_acl_default_handler);
588 }
589
590 int __init
591 init_ext3_acl(void)
592 {
593         int error;
594
595         error = ext3_xattr_register(EXT3_XATTR_INDEX_POSIX_ACL_ACCESS,
596                                     &ext3_xattr_acl_access_handler);
597         if (error)
598                 goto fail;
599         error = ext3_xattr_register(EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT,
600                                     &ext3_xattr_acl_default_handler);
601         if (error)
602                 goto fail;
603         return 0;
604
605 fail:
606         exit_ext3_acl();
607         return error;
608 }