416 lines
11 KiB
Diff
416 lines
11 KiB
Diff
From: Andreas Gruenbacher <agruen@suse.de>
|
|
Date: Fri, 11 Jun 2010 16:12:46 +0530
|
|
Subject: [PATCH 04/16] richacl: In-memory representation and helper functions
|
|
Patch-mainline: not yet
|
|
|
|
A richacl consists of an NFSv4 acl and an owner, group, and other mask.
|
|
These three masks correspond to the owner, group, and other file
|
|
permission bits, but they contain NFSv4 permissions instead of POSIX
|
|
permissions.
|
|
|
|
Each entry in the NFSv4 acl applies to the file owner (OWNER@), the
|
|
owning group (GROUP@), literally everyone (EVERYONE@), or to a specific
|
|
uid or gid.
|
|
|
|
As in the standard POSIX file permission model, each process is the
|
|
owner, group, or other file class. A richacl grants a requested access
|
|
only if the NFSv4 acl in the richacl grants the access (according to the
|
|
NFSv4 permission check algorithm), and the file mask that applies to the
|
|
process includes the requested permissions.
|
|
|
|
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
|
|
---
|
|
fs/Kconfig | 4
|
|
fs/Makefile | 3
|
|
fs/richacl_base.c | 109 +++++++++++++++++++++
|
|
include/linux/richacl.h | 245 ++++++++++++++++++++++++++++++++++++++++++++++++
|
|
4 files changed, 361 insertions(+)
|
|
create mode 100644 fs/richacl_base.c
|
|
create mode 100644 include/linux/richacl.h
|
|
|
|
--- a/fs/Kconfig
|
|
+++ b/fs/Kconfig
|
|
@@ -39,6 +39,9 @@ config FS_POSIX_ACL
|
|
source "fs/reiserfs/Kconfig"
|
|
source "fs/jfs/Kconfig"
|
|
|
|
+config FS_RICHACL
|
|
+ bool
|
|
+
|
|
source "fs/xfs/Kconfig"
|
|
source "fs/gfs2/Kconfig"
|
|
source "fs/ocfs2/Kconfig"
|
|
--- a/fs/Makefile
|
|
+++ b/fs/Makefile
|
|
@@ -51,6 +51,9 @@ obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.
|
|
obj-$(CONFIG_NFS_COMMON) += nfs_common/
|
|
obj-$(CONFIG_GENERIC_ACL) += generic_acl.o
|
|
|
|
+obj-$(CONFIG_FS_RICHACL) += richacl.o
|
|
+richacl-y := richacl_base.o
|
|
+
|
|
obj-y += quota/
|
|
|
|
obj-$(CONFIG_PROC_FS) += proc/
|
|
--- /dev/null
|
|
+++ b/fs/richacl_base.c
|
|
@@ -0,0 +1,109 @@
|
|
+/*
|
|
+ * Copyright (C) 2006, 2010 Novell, Inc.
|
|
+ * Written by Andreas Gruenbacher <agruen@suse.de>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License as published by the
|
|
+ * Free Software Foundation; either version 2, or (at your option) any
|
|
+ * later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful, but
|
|
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
+ * General Public License for more details.
|
|
+ */
|
|
+
|
|
+#include <linux/sched.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/fs.h>
|
|
+#include <linux/richacl.h>
|
|
+
|
|
+MODULE_LICENSE("GPL");
|
|
+
|
|
+/*
|
|
+ * Special e_who identifiers: ACEs which have ACE4_SPECIAL_WHO set in
|
|
+ * ace->e_flags use these constants in ace->u.e_who.
|
|
+ *
|
|
+ * For efficiency, we compare pointers instead of comparing strings.
|
|
+ */
|
|
+const char richace_owner_who[] = "OWNER@";
|
|
+EXPORT_SYMBOL_GPL(richace_owner_who);
|
|
+const char richace_group_who[] = "GROUP@";
|
|
+EXPORT_SYMBOL_GPL(richace_group_who);
|
|
+const char richace_everyone_who[] = "EVERYONE@";
|
|
+EXPORT_SYMBOL_GPL(richace_everyone_who);
|
|
+
|
|
+/**
|
|
+ * richacl_alloc - allocate a richacl
|
|
+ * @count: number of entries
|
|
+ */
|
|
+struct richacl *
|
|
+richacl_alloc(int count)
|
|
+{
|
|
+ size_t size = sizeof(struct richacl) + count * sizeof(struct richace);
|
|
+ struct richacl *acl = kzalloc(size, GFP_KERNEL);
|
|
+
|
|
+ if (acl) {
|
|
+ atomic_set(&acl->a_refcount, 1);
|
|
+ acl->a_count = count;
|
|
+ }
|
|
+ return acl;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(richacl_alloc);
|
|
+
|
|
+/**
|
|
+ * richacl_clone - create a copy of a richacl
|
|
+ */
|
|
+static struct richacl *
|
|
+richacl_clone(const struct richacl *acl)
|
|
+{
|
|
+ int count = acl->a_count;
|
|
+ size_t size = sizeof(struct richacl) + count * sizeof(struct richace);
|
|
+ struct richacl *dup = kmalloc(size, GFP_KERNEL);
|
|
+
|
|
+ if (dup) {
|
|
+ memcpy(dup, acl, size);
|
|
+ atomic_set(&dup->a_refcount, 1);
|
|
+ }
|
|
+ return dup;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * richace_is_same_identifier - are both identifiers the same?
|
|
+ */
|
|
+int
|
|
+richace_is_same_identifier(const struct richace *a, const struct richace *b)
|
|
+{
|
|
+#define WHO_FLAGS (ACE4_SPECIAL_WHO | ACE4_IDENTIFIER_GROUP)
|
|
+ if ((a->e_flags & WHO_FLAGS) != (b->e_flags & WHO_FLAGS))
|
|
+ return 0;
|
|
+ if (a->e_flags & ACE4_SPECIAL_WHO)
|
|
+ return a->u.e_who == b->u.e_who;
|
|
+ else
|
|
+ return a->u.e_id == b->u.e_id;
|
|
+#undef WHO_FLAGS
|
|
+}
|
|
+
|
|
+/**
|
|
+ * richacl_set_who - set a special who value
|
|
+ * @ace: acl entry
|
|
+ * @who: who value to use
|
|
+ */
|
|
+int
|
|
+richace_set_who(struct richace *ace, const char *who)
|
|
+{
|
|
+ if (!strcmp(who, richace_owner_who))
|
|
+ who = richace_owner_who;
|
|
+ else if (!strcmp(who, richace_group_who))
|
|
+ who = richace_group_who;
|
|
+ else if (!strcmp(who, richace_everyone_who))
|
|
+ who = richace_everyone_who;
|
|
+ else
|
|
+ return -EINVAL;
|
|
+
|
|
+ ace->u.e_who = who;
|
|
+ ace->e_flags |= ACE4_SPECIAL_WHO;
|
|
+ ace->e_flags &= ~ACE4_IDENTIFIER_GROUP;
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(richace_set_who);
|
|
--- /dev/null
|
|
+++ b/include/linux/richacl.h
|
|
@@ -0,0 +1,245 @@
|
|
+/*
|
|
+ * Copyright (C) 2006, 2010 Novell, Inc.
|
|
+ * Written by Andreas Gruenbacher <agruen@suse.de>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License as published by the
|
|
+ * Free Software Foundation; either version 2, or (at your option) any
|
|
+ * later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful, but
|
|
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
+ * General Public License for more details.
|
|
+ */
|
|
+
|
|
+#ifndef __RICHACL_H
|
|
+#define __RICHACL_H
|
|
+#include <linux/slab.h>
|
|
+
|
|
+struct richace {
|
|
+ unsigned short e_type;
|
|
+ unsigned short e_flags;
|
|
+ unsigned int e_mask;
|
|
+ union {
|
|
+ unsigned int e_id;
|
|
+ const char *e_who;
|
|
+ } u;
|
|
+};
|
|
+
|
|
+struct richacl {
|
|
+ atomic_t a_refcount;
|
|
+ unsigned int a_owner_mask;
|
|
+ unsigned int a_group_mask;
|
|
+ unsigned int a_other_mask;
|
|
+ unsigned short a_count;
|
|
+ unsigned short a_flags;
|
|
+ struct richace a_entries[0];
|
|
+};
|
|
+
|
|
+#define richacl_for_each_entry(_ace, _acl) \
|
|
+ for (_ace = _acl->a_entries; \
|
|
+ _ace != _acl->a_entries + _acl->a_count; \
|
|
+ _ace++)
|
|
+
|
|
+#define richacl_for_each_entry_reverse(_ace, _acl) \
|
|
+ for (_ace = _acl->a_entries + _acl->a_count - 1; \
|
|
+ _ace != _acl->a_entries - 1; \
|
|
+ _ace--)
|
|
+
|
|
+/* e_type values */
|
|
+#define ACE4_ACCESS_ALLOWED_ACE_TYPE 0x0000
|
|
+#define ACE4_ACCESS_DENIED_ACE_TYPE 0x0001
|
|
+/*#define ACE4_SYSTEM_AUDIT_ACE_TYPE 0x0002*/
|
|
+/*#define ACE4_SYSTEM_ALARM_ACE_TYPE 0x0003*/
|
|
+
|
|
+/* e_flags bitflags */
|
|
+#define ACE4_FILE_INHERIT_ACE 0x0001
|
|
+#define ACE4_DIRECTORY_INHERIT_ACE 0x0002
|
|
+#define ACE4_NO_PROPAGATE_INHERIT_ACE 0x0004
|
|
+#define ACE4_INHERIT_ONLY_ACE 0x0008
|
|
+/*#define ACE4_SUCCESSFUL_ACCESS_ACE_FLAG 0x0010*/
|
|
+/*#define ACE4_FAILED_ACCESS_ACE_FLAG 0x0020*/
|
|
+#define ACE4_IDENTIFIER_GROUP 0x0040
|
|
+/* in-memory representation only */
|
|
+#define ACE4_SPECIAL_WHO 0x4000
|
|
+
|
|
+#define ACE4_VALID_FLAGS ( \
|
|
+ ACE4_FILE_INHERIT_ACE | \
|
|
+ ACE4_DIRECTORY_INHERIT_ACE | \
|
|
+ ACE4_NO_PROPAGATE_INHERIT_ACE | \
|
|
+ ACE4_INHERIT_ONLY_ACE | \
|
|
+ ACE4_IDENTIFIER_GROUP)
|
|
+
|
|
+/* e_mask bitflags */
|
|
+#define ACE4_READ_DATA 0x00000001
|
|
+#define ACE4_LIST_DIRECTORY 0x00000001
|
|
+#define ACE4_WRITE_DATA 0x00000002
|
|
+#define ACE4_ADD_FILE 0x00000002
|
|
+#define ACE4_APPEND_DATA 0x00000004
|
|
+#define ACE4_ADD_SUBDIRECTORY 0x00000004
|
|
+#define ACE4_READ_NAMED_ATTRS 0x00000008
|
|
+#define ACE4_WRITE_NAMED_ATTRS 0x00000010
|
|
+#define ACE4_EXECUTE 0x00000020
|
|
+#define ACE4_DELETE_CHILD 0x00000040
|
|
+#define ACE4_READ_ATTRIBUTES 0x00000080
|
|
+#define ACE4_WRITE_ATTRIBUTES 0x00000100
|
|
+#define ACE4_WRITE_RETENTION 0x00000200
|
|
+#define ACE4_WRITE_RETENTION_HOLD 0x00000400
|
|
+#define ACE4_DELETE 0x00010000
|
|
+#define ACE4_READ_ACL 0x00020000
|
|
+#define ACE4_WRITE_ACL 0x00040000
|
|
+#define ACE4_WRITE_OWNER 0x00080000
|
|
+#define ACE4_SYNCHRONIZE 0x00100000
|
|
+
|
|
+/* Valid ACE4_* flags for directories and non-directories */
|
|
+#define ACE4_VALID_MASK ( \
|
|
+ ACE4_READ_DATA | ACE4_LIST_DIRECTORY | \
|
|
+ ACE4_WRITE_DATA | ACE4_ADD_FILE | \
|
|
+ ACE4_APPEND_DATA | ACE4_ADD_SUBDIRECTORY | \
|
|
+ ACE4_READ_NAMED_ATTRS | \
|
|
+ ACE4_WRITE_NAMED_ATTRS | \
|
|
+ ACE4_EXECUTE | \
|
|
+ ACE4_DELETE_CHILD | \
|
|
+ ACE4_READ_ATTRIBUTES | \
|
|
+ ACE4_WRITE_ATTRIBUTES | \
|
|
+ ACE4_WRITE_RETENTION | \
|
|
+ ACE4_WRITE_RETENTION_HOLD | \
|
|
+ ACE4_DELETE | \
|
|
+ ACE4_READ_ACL | \
|
|
+ ACE4_WRITE_ACL | \
|
|
+ ACE4_WRITE_OWNER | \
|
|
+ ACE4_SYNCHRONIZE)
|
|
+
|
|
+/* These permissions are always allowed no matter what the acl says. */
|
|
+#define ACE4_POSIX_ALWAYS_ALLOWED ( \
|
|
+ ACE4_SYNCHRONIZE | \
|
|
+ ACE4_READ_ATTRIBUTES | \
|
|
+ ACE4_READ_ACL)
|
|
+
|
|
+/**
|
|
+ * richacl_get - grab another reference to a richacl handle
|
|
+ */
|
|
+static inline struct richacl *
|
|
+richacl_get(struct richacl *acl)
|
|
+{
|
|
+ if (acl)
|
|
+ atomic_inc(&acl->a_refcount);
|
|
+ return acl;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * richacl_put - free a richacl handle
|
|
+ */
|
|
+static inline void
|
|
+richacl_put(struct richacl *acl)
|
|
+{
|
|
+ if (acl && atomic_dec_and_test(&acl->a_refcount))
|
|
+ kfree(acl);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Special e_who identifiers: we use these pointer values in comparisons
|
|
+ * instead of doing a strcmp.
|
|
+ */
|
|
+extern const char richace_owner_who[];
|
|
+extern const char richace_group_who[];
|
|
+extern const char richace_everyone_who[];
|
|
+
|
|
+/**
|
|
+ * richace_is_owner - check if @ace is an OWNER@ entry
|
|
+ */
|
|
+static inline int
|
|
+richace_is_owner(const struct richace *ace)
|
|
+{
|
|
+ return (ace->e_flags & ACE4_SPECIAL_WHO) &&
|
|
+ ace->u.e_who == richace_owner_who;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * richace_is_group - check if @ace is a GROUP@ entry
|
|
+ */
|
|
+static inline int
|
|
+richace_is_group(const struct richace *ace)
|
|
+{
|
|
+ return (ace->e_flags & ACE4_SPECIAL_WHO) &&
|
|
+ ace->u.e_who == richace_group_who;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * richace_is_everyone - check if @ace is an EVERYONE@ entry
|
|
+ */
|
|
+static inline int
|
|
+richace_is_everyone(const struct richace *ace)
|
|
+{
|
|
+ return (ace->e_flags & ACE4_SPECIAL_WHO) &&
|
|
+ ace->u.e_who == richace_everyone_who;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * richace_is_unix_id - check if @ace applies to a specific uid or gid
|
|
+ */
|
|
+static inline int
|
|
+richace_is_unix_id(const struct richace *ace)
|
|
+{
|
|
+ return !(ace->e_flags & ACE4_SPECIAL_WHO);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * richace_is_inherit_only - check if @ace is for inheritance only
|
|
+ *
|
|
+ * ACEs with the %ACE4_INHERIT_ONLY_ACE flag set have no effect during
|
|
+ * permission checking.
|
|
+ */
|
|
+static inline int
|
|
+richace_is_inherit_only(const struct richace *ace)
|
|
+{
|
|
+ return ace->e_flags & ACE4_INHERIT_ONLY_ACE;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * richace_is_inheritable - check if @ace is inheritable
|
|
+ */
|
|
+static inline int
|
|
+richace_is_inheritable(const struct richace *ace)
|
|
+{
|
|
+ return ace->e_flags & (ACE4_FILE_INHERIT_ACE |
|
|
+ ACE4_DIRECTORY_INHERIT_ACE);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * richace_clear_inheritance_flags - clear all inheritance flags in @ace
|
|
+ */
|
|
+static inline void
|
|
+richace_clear_inheritance_flags(struct richace *ace)
|
|
+{
|
|
+ ace->e_flags &= ~(ACE4_FILE_INHERIT_ACE |
|
|
+ ACE4_DIRECTORY_INHERIT_ACE |
|
|
+ ACE4_NO_PROPAGATE_INHERIT_ACE |
|
|
+ ACE4_INHERIT_ONLY_ACE);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * richace_is_allow - check if @ace is an %ALLOW type entry
|
|
+ */
|
|
+static inline int
|
|
+richace_is_allow(const struct richace *ace)
|
|
+{
|
|
+ return ace->e_type == ACE4_ACCESS_ALLOWED_ACE_TYPE;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * richace_is_deny - check if @ace is a %DENY type entry
|
|
+ */
|
|
+static inline int
|
|
+richace_is_deny(const struct richace *ace)
|
|
+{
|
|
+ return ace->e_type == ACE4_ACCESS_DENIED_ACE_TYPE;
|
|
+}
|
|
+
|
|
+extern struct richacl *richacl_alloc(int);
|
|
+extern int richace_is_same_identifier(const struct richace *,
|
|
+ const struct richace *);
|
|
+extern int richace_set_who(struct richace *, const char *);
|
|
+
|
|
+#endif /* __RICHACL_H */
|