128 lines
4.0 KiB
Diff
128 lines
4.0 KiB
Diff
|
From: Andreas Gruenbacher <agruen@suse.de>
|
||
|
Date: Fri, 11 Jun 2010 16:12:49 +0530
|
||
|
Subject: [PATCH 10/16] richacl: Create-time inheritance
|
||
|
Patch-mainline: not yet
|
||
|
|
||
|
When a new file is created, it can inherit an acl from its parent
|
||
|
directory; this is similar to how default acls work in POSIX (draft)
|
||
|
ACLs.
|
||
|
|
||
|
As with POSIX ACLs, if a file inherits an acl from its parent directory,
|
||
|
the intersection between the create mode and the permissions granted by
|
||
|
the inherited acl determines the file masks and file permission bits,
|
||
|
and the umask is ignored.
|
||
|
|
||
|
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||
|
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
|
||
|
---
|
||
|
fs/richacl_base.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
include/linux/richacl.h | 1
|
||
|
2 files changed, 91 insertions(+)
|
||
|
|
||
|
--- a/fs/richacl_base.c
|
||
|
+++ b/fs/richacl_base.c
|
||
|
@@ -454,3 +454,93 @@ is_everyone:
|
||
|
return denied ? -EACCES : 0;
|
||
|
}
|
||
|
EXPORT_SYMBOL_GPL(richacl_permission);
|
||
|
+
|
||
|
+/**
|
||
|
+ * richacl_inherit - compute the inherited acl of a new file
|
||
|
+ * @dir_acl: acl of the containing direcory
|
||
|
+ * @inode: inode of the new file (create mode in i_mode)
|
||
|
+ *
|
||
|
+ * A directory can have acl entries which files and/or directories created
|
||
|
+ * inside the directory will inherit. This function computes the acl for such
|
||
|
+ * a new file. If there is no inheritable acl, it will return %NULL.
|
||
|
+ *
|
||
|
+ * The file permission bits in inode->i_mode must be set to the create mode.
|
||
|
+ * If there is an inheritable acl, the maximum permissions that the acl grants
|
||
|
+ * will be computed and permissions not granted by the acl will be removed from
|
||
|
+ * inode->i_mode. If there is no inheritable acl, the umask will be applied
|
||
|
+ * instead.
|
||
|
+ */
|
||
|
+struct richacl *
|
||
|
+richacl_inherit(const struct richacl *dir_acl, struct inode *inode)
|
||
|
+{
|
||
|
+ const struct richace *dir_ace;
|
||
|
+ struct richacl *acl = NULL;
|
||
|
+ struct richace *ace;
|
||
|
+ int count = 0;
|
||
|
+ mode_t mask = ~current_umask();
|
||
|
+
|
||
|
+ if (S_ISDIR(inode->i_mode)) {
|
||
|
+ richacl_for_each_entry(dir_ace, dir_acl) {
|
||
|
+ if (!richace_is_inheritable(dir_ace))
|
||
|
+ continue;
|
||
|
+ count++;
|
||
|
+ }
|
||
|
+ if (!count)
|
||
|
+ goto mask;
|
||
|
+ acl = richacl_alloc(count);
|
||
|
+ if (!acl)
|
||
|
+ return ERR_PTR(-ENOMEM);
|
||
|
+ ace = acl->a_entries;
|
||
|
+ richacl_for_each_entry(dir_ace, dir_acl) {
|
||
|
+ if (!richace_is_inheritable(dir_ace))
|
||
|
+ continue;
|
||
|
+ memcpy(ace, dir_ace, sizeof(struct richace));
|
||
|
+ if (dir_ace->e_flags & ACE4_NO_PROPAGATE_INHERIT_ACE)
|
||
|
+ richace_clear_inheritance_flags(ace);
|
||
|
+ if ((dir_ace->e_flags & ACE4_FILE_INHERIT_ACE) &&
|
||
|
+ !(dir_ace->e_flags & ACE4_DIRECTORY_INHERIT_ACE))
|
||
|
+ ace->e_flags |= ACE4_INHERIT_ONLY_ACE;
|
||
|
+ ace++;
|
||
|
+ }
|
||
|
+ } else {
|
||
|
+ richacl_for_each_entry(dir_ace, dir_acl) {
|
||
|
+ if (!(dir_ace->e_flags & ACE4_FILE_INHERIT_ACE))
|
||
|
+ continue;
|
||
|
+ count++;
|
||
|
+ }
|
||
|
+ if (!count)
|
||
|
+ goto mask;
|
||
|
+ acl = richacl_alloc(count);
|
||
|
+ if (!acl)
|
||
|
+ return ERR_PTR(-ENOMEM);
|
||
|
+ ace = acl->a_entries;
|
||
|
+ richacl_for_each_entry(dir_ace, dir_acl) {
|
||
|
+ if (!(dir_ace->e_flags & ACE4_FILE_INHERIT_ACE))
|
||
|
+ continue;
|
||
|
+ memcpy(ace, dir_ace, sizeof(struct richace));
|
||
|
+ richace_clear_inheritance_flags(ace);
|
||
|
+ /*
|
||
|
+ * ACE4_DELETE_CHILD is meaningless for
|
||
|
+ * non-directories, so clear it.
|
||
|
+ */
|
||
|
+ ace->e_mask &= ~ACE4_DELETE_CHILD;
|
||
|
+ ace++;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ richacl_compute_max_masks(acl);
|
||
|
+
|
||
|
+ /*
|
||
|
+ * Ensure that the acl will not grant any permissions beyond the create
|
||
|
+ * mode.
|
||
|
+ */
|
||
|
+ acl->a_owner_mask &= richacl_mode_to_mask(inode->i_mode >> 6);
|
||
|
+ acl->a_group_mask &= richacl_mode_to_mask(inode->i_mode >> 3);
|
||
|
+ acl->a_other_mask &= richacl_mode_to_mask(inode->i_mode);
|
||
|
+ mask = ~S_IRWXUGO | richacl_masks_to_mode(acl);
|
||
|
+
|
||
|
+mask:
|
||
|
+ inode->i_mode &= mask;
|
||
|
+ return acl;
|
||
|
+}
|
||
|
+EXPORT_SYMBOL_GPL(richacl_inherit);
|
||
|
--- a/include/linux/richacl.h
|
||
|
+++ b/include/linux/richacl.h
|
||
|
@@ -272,6 +272,7 @@ extern void richacl_compute_max_masks(st
|
||
|
extern struct richacl *richacl_chmod(struct richacl *, mode_t);
|
||
|
extern int richacl_permission(struct inode *, const struct richacl *,
|
||
|
unsigned int);
|
||
|
+extern struct richacl *richacl_inherit(const struct richacl *, struct inode *);
|
||
|
|
||
|
/* richacl_inode.c */
|
||
|
|