VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[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 NULL;
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                 int retries = 0;
432
433         retry:
434                 handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS);
435                 if (IS_ERR(handle)) {
436                         error = PTR_ERR(handle);
437                         ext3_std_error(inode->i_sb, error);
438                         goto out;
439                 }
440                 error = ext3_set_acl(handle, inode, ACL_TYPE_ACCESS, clone);
441                 ext3_journal_stop(handle);
442                 if (error == -ENOSPC &&
443                     ext3_should_retry_alloc(inode->i_sb, &retries))
444                         goto retry;
445         }
446 out:
447         posix_acl_release(clone);
448         return error;
449 }
450
451 /*
452  * Extended attribute handlers
453  */
454 static size_t
455 ext3_xattr_list_acl_access(char *list, struct inode *inode,
456                            const char *name, int name_len)
457 {
458         const size_t size = sizeof(XATTR_NAME_ACL_ACCESS);
459
460         if (!test_opt(inode->i_sb, POSIX_ACL))
461                 return 0;
462         if (list)
463                 memcpy(list, XATTR_NAME_ACL_ACCESS, size);
464         return size;
465 }
466
467 static size_t
468 ext3_xattr_list_acl_default(char *list, struct inode *inode,
469                             const char *name, int name_len)
470 {
471         const size_t size = sizeof(XATTR_NAME_ACL_DEFAULT);
472
473         if (!test_opt(inode->i_sb, POSIX_ACL))
474                 return 0;
475         if (list)
476                 memcpy(list, XATTR_NAME_ACL_DEFAULT, size);
477         return size;
478 }
479
480 static int
481 ext3_xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size)
482 {
483         struct posix_acl *acl;
484         int error;
485
486         if (!test_opt(inode->i_sb, POSIX_ACL))
487                 return -EOPNOTSUPP;
488
489         acl = ext3_get_acl(inode, type);
490         if (IS_ERR(acl))
491                 return PTR_ERR(acl);
492         if (acl == NULL)
493                 return -ENODATA;
494         error = posix_acl_to_xattr(acl, buffer, size);
495         posix_acl_release(acl);
496
497         return error;
498 }
499
500 static int
501 ext3_xattr_get_acl_access(struct inode *inode, const char *name,
502                           void *buffer, size_t size)
503 {
504         if (strcmp(name, "") != 0)
505                 return -EINVAL;
506         return ext3_xattr_get_acl(inode, ACL_TYPE_ACCESS, buffer, size);
507 }
508
509 static int
510 ext3_xattr_get_acl_default(struct inode *inode, const char *name,
511                            void *buffer, size_t size)
512 {
513         if (strcmp(name, "") != 0)
514                 return -EINVAL;
515         return ext3_xattr_get_acl(inode, ACL_TYPE_DEFAULT, buffer, size);
516 }
517
518 static int
519 ext3_xattr_set_acl(struct inode *inode, int type, const void *value,
520                    size_t size)
521 {
522         handle_t *handle;
523         struct posix_acl *acl;
524         int error, retries = 0;
525
526         if (!test_opt(inode->i_sb, POSIX_ACL))
527                 return -EOPNOTSUPP;
528         if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
529                 return -EPERM;
530
531         if (value) {
532                 acl = posix_acl_from_xattr(value, size);
533                 if (IS_ERR(acl))
534                         return PTR_ERR(acl);
535                 else if (acl) {
536                         error = posix_acl_valid(acl);
537                         if (error)
538                                 goto release_and_out;
539                 }
540         } else
541                 acl = NULL;
542
543 retry:
544         handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS);
545         if (IS_ERR(handle))
546                 return PTR_ERR(handle);
547         error = ext3_set_acl(handle, inode, type, acl);
548         ext3_journal_stop(handle);
549         if (error == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries))
550                 goto retry;
551
552 release_and_out:
553         posix_acl_release(acl);
554         return error;
555 }
556
557 static int
558 ext3_xattr_set_acl_access(struct inode *inode, const char *name,
559                           const void *value, size_t size, int flags)
560 {
561         if (strcmp(name, "") != 0)
562                 return -EINVAL;
563         return ext3_xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size);
564 }
565
566 static int
567 ext3_xattr_set_acl_default(struct inode *inode, const char *name,
568                            const void *value, size_t size, int flags)
569 {
570         if (strcmp(name, "") != 0)
571                 return -EINVAL;
572         return ext3_xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size);
573 }
574
575 struct ext3_xattr_handler ext3_xattr_acl_access_handler = {
576         .prefix = XATTR_NAME_ACL_ACCESS,
577         .list   = ext3_xattr_list_acl_access,
578         .get    = ext3_xattr_get_acl_access,
579         .set    = ext3_xattr_set_acl_access,
580 };
581
582 struct ext3_xattr_handler ext3_xattr_acl_default_handler = {
583         .prefix = XATTR_NAME_ACL_DEFAULT,
584         .list   = ext3_xattr_list_acl_default,
585         .get    = ext3_xattr_get_acl_default,
586         .set    = ext3_xattr_set_acl_default,
587 };
588
589 void
590 exit_ext3_acl(void)
591 {
592         ext3_xattr_unregister(EXT3_XATTR_INDEX_POSIX_ACL_ACCESS,
593                               &ext3_xattr_acl_access_handler);
594         ext3_xattr_unregister(EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT,
595                               &ext3_xattr_acl_default_handler);
596 }
597
598 int __init
599 init_ext3_acl(void)
600 {
601         int error;
602
603         error = ext3_xattr_register(EXT3_XATTR_INDEX_POSIX_ACL_ACCESS,
604                                     &ext3_xattr_acl_access_handler);
605         if (error)
606                 goto fail;
607         error = ext3_xattr_register(EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT,
608                                     &ext3_xattr_acl_default_handler);
609         if (error)
610                 goto fail;
611         return 0;
612
613 fail:
614         exit_ext3_acl();
615         return error;
616 }