From: NeilBrown <neilb@cse.unsw.edu.au>

Basic v4 acl definitions, to be used by server ACL implementation

Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/fs/nfsd/Makefile         |    3 
 25-akpm/fs/nfsd/nfs4acl.c        |  203 +++++++++++++++++++++++++++++++++++++++
 25-akpm/include/linux/nfs4.h     |   57 ++++++++++
 25-akpm/include/linux/nfs4_acl.h |   50 +++++++++
 4 files changed, 312 insertions(+), 1 deletion(-)

diff -puN fs/nfsd/Makefile~nfsd-basic-v4-acl-definitions fs/nfsd/Makefile
--- 25/fs/nfsd/Makefile~nfsd-basic-v4-acl-definitions	2004-08-01 21:10:04.099262264 -0700
+++ 25-akpm/fs/nfsd/Makefile	2004-08-01 21:10:04.108260896 -0700
@@ -7,5 +7,6 @@ obj-$(CONFIG_NFSD)	+= nfsd.o
 nfsd-y 			:= nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \
 			   export.o auth.o lockd.o nfscache.o nfsxdr.o stats.o
 nfsd-$(CONFIG_NFSD_V3)	+= nfs3proc.o nfs3xdr.o
-nfsd-$(CONFIG_NFSD_V4)	+= nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o
+nfsd-$(CONFIG_NFSD_V4)	+= nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \
+			   nfs4acl.o
 nfsd-objs		:= $(nfsd-y)
diff -puN fs/nfsd/nfs4acl.c~nfsd-basic-v4-acl-definitions fs/nfsd/nfs4acl.c
--- 25/fs/nfsd/nfs4acl.c~nfsd-basic-v4-acl-definitions	2004-08-01 21:10:04.100262112 -0700
+++ 25-akpm/fs/nfsd/nfs4acl.c	2004-08-01 21:10:04.109260744 -0700
@@ -0,0 +1,203 @@
+/*
+ *  fs/nfs4acl/acl.c
+ *
+ *  Common NFSv4 ACL handling code.
+ *
+ *  Copyright (c) 2002, 2003 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Marius Aamodt Eriksen <marius@umich.edu>
+ *  Jeff Sedlak <jsedlak@umich.edu>
+ *  J. Bruce Fields <bfields@umich.edu>
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the University nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/nfs_fs.h>
+#include <linux/nfs4.h>
+#include <linux/nfs4_acl.h>
+
+struct nfs4_acl *
+nfs4_acl_new(void)
+{
+	struct nfs4_acl *acl;
+
+	if ((acl = kmalloc(sizeof(*acl), GFP_KERNEL)) == NULL)
+		return NULL;
+
+	acl->naces = 0;
+	INIT_LIST_HEAD(&acl->ace_head);
+
+	return acl;
+}
+
+void
+nfs4_acl_free(struct nfs4_acl *acl)
+{
+	struct list_head *h;
+	struct nfs4_ace *ace;
+
+	if (!acl)
+		return;
+
+	while (!list_empty(&acl->ace_head)) {
+		h = acl->ace_head.next;
+		list_del(h);
+		ace = list_entry(h, struct nfs4_ace, l_ace);
+		kfree(ace);
+	}
+
+	kfree(acl);
+
+	return;
+}
+
+int
+nfs4_acl_add_ace(struct nfs4_acl *acl, u32 type, u32 flag, u32 access_mask,
+		int whotype, uid_t who)
+{
+	struct nfs4_ace *ace;
+
+	if ((ace = kmalloc(sizeof(*ace), GFP_KERNEL)) == NULL)
+		return -1;
+
+	ace->type = type;
+	ace->flag = flag;
+	ace->access_mask = access_mask;
+	ace->whotype = whotype;
+	ace->who = who;
+
+	list_add_tail(&ace->l_ace, &acl->ace_head);
+	acl->naces++;
+
+	return 0;
+}
+
+static struct {
+	char *string;
+	int   stringlen;
+	int type;
+} s2t_map[] = {
+	{
+		.string    = "OWNER@",
+		.stringlen = sizeof("OWNER@") - 1,
+		.type      = NFS4_ACL_WHO_OWNER,
+	},
+	{
+		.string    = "GROUP@",
+		.stringlen = sizeof("GROUP@") - 1,
+		.type      = NFS4_ACL_WHO_GROUP,
+	},
+	{
+		.string    = "EVERYONE@",
+		.stringlen = sizeof("EVERYONE@") - 1,
+		.type      = NFS4_ACL_WHO_EVERYONE,
+	},
+};
+
+int
+nfs4_acl_get_whotype(char *p, u32 len)
+{
+	int i;
+
+	for (i=0; i < sizeof(s2t_map) / sizeof(*s2t_map); i++) {
+		if (s2t_map[i].stringlen == len &&
+				0 == memcmp(s2t_map[i].string, p, len))
+			return s2t_map[i].type;
+	}
+	return NFS4_ACL_WHO_NAMED;
+}
+
+int
+nfs4_acl_write_who(int who, char *p)
+{
+	int i;
+
+	for (i=0; i < sizeof(s2t_map) / sizeof(*s2t_map); i++) {
+		if (s2t_map[i].type == who) {
+			memcpy(p, s2t_map[i].string, s2t_map[i].stringlen);
+			return s2t_map[i].stringlen;
+		}
+	}
+	BUG();
+	return -1;
+}
+
+static inline int
+match_who(struct nfs4_ace *ace, uid_t owner, gid_t group, uid_t who)
+{
+	switch (ace->whotype) {
+		case NFS4_ACL_WHO_NAMED:
+			return who == ace->who;
+		case NFS4_ACL_WHO_OWNER:
+			return who == owner;
+		case NFS4_ACL_WHO_GROUP:
+			return who == group;
+		case NFS4_ACL_WHO_EVERYONE:
+			return 1;
+		default:
+			return 0;
+	}
+}
+
+/* 0 = granted, -EACCES = denied; mask is an nfsv4 mask, not mode bits */
+int
+nfs4_acl_permission(struct nfs4_acl *acl, uid_t owner, gid_t group,
+			uid_t who, u32 mask)
+{
+	struct nfs4_ace *ace;
+	u32 allowed = 0;
+
+	list_for_each_entry(ace, &acl->ace_head, l_ace) {
+		if (!match_who(ace, group, owner, who))
+			continue;
+		switch (ace->type) {
+			case NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE:
+				allowed |= ace->access_mask;
+				if ((allowed & mask) == mask)
+					return 0;
+				break;
+			case NFS4_ACE_ACCESS_DENIED_ACE_TYPE:
+				if (ace->access_mask & mask)
+					return -EACCES;
+				break;
+		}
+	}
+	return -EACCES;
+}
+
+EXPORT_SYMBOL(nfs4_acl_new);
+EXPORT_SYMBOL(nfs4_acl_free);
+EXPORT_SYMBOL(nfs4_acl_add_ace);
+EXPORT_SYMBOL(nfs4_acl_get_whotype);
+EXPORT_SYMBOL(nfs4_acl_write_who);
+EXPORT_SYMBOL(nfs4_acl_permission);
diff -puN include/linux/nfs4_acl.h~nfsd-basic-v4-acl-definitions include/linux/nfs4_acl.h
--- 25/include/linux/nfs4_acl.h~nfsd-basic-v4-acl-definitions	2004-08-01 21:10:04.102261808 -0700
+++ 25-akpm/include/linux/nfs4_acl.h	2004-08-01 21:10:04.110260592 -0700
@@ -0,0 +1,50 @@
+/*
+ *  include/linux/nfs4_acl.c
+ *
+ *  Common NFSv4 ACL handling definitions.
+ *
+ *  Copyright (c) 2002 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Marius Aamodt Eriksen <marius@umich.edu>
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the University nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LINUX_NFS4_ACL_H
+#define LINUX_NFS4_ACL_H
+
+#include <linux/posix_acl.h>
+
+struct nfs4_acl *nfs4_acl_new(void);
+void nfs4_acl_free(struct nfs4_acl *);
+int nfs4_acl_add_ace(struct nfs4_acl *, u32, u32, u32, int, uid_t);
+int nfs4_acl_get_whotype(char *, u32);
+int nfs4_acl_write_who(int who, char *p);
+int nfs4_acl_permission(struct nfs4_acl *acl, uid_t owner, gid_t group,
+		                        uid_t who, u32 mask);
+
+#endif /* LINUX_NFS4_ACL_H */
diff -puN include/linux/nfs4.h~nfsd-basic-v4-acl-definitions include/linux/nfs4.h
--- 25/include/linux/nfs4.h~nfsd-basic-v4-acl-definitions	2004-08-01 21:10:04.104261504 -0700
+++ 25-akpm/include/linux/nfs4.h	2004-08-01 21:10:04.109260744 -0700
@@ -13,6 +13,9 @@
 #ifndef _LINUX_NFS4_H
 #define _LINUX_NFS4_H
 
+#include <linux/types.h>
+#include <linux/list.h>
+
 #define NFS4_VERIFIER_SIZE	8
 #define NFS4_FHSIZE		128
 #define NFS4_MAXNAMLEN		NAME_MAX
@@ -52,6 +55,60 @@
 #define ACL4_SUPPORT_AUDIT_ACL 0x04
 #define ACL4_SUPPORT_ALARM_ACL 0x08
 
+#define NFS4_ACE_FILE_INHERIT_ACE             0x00000001
+#define NFS4_ACE_DIRECTORY_INHERIT_ACE        0x00000002
+#define NFS4_ACE_NO_PROPAGATE_INHERIT_ACE     0x00000004
+#define NFS4_ACE_INHERIT_ONLY_ACE             0x00000008
+#define NFS4_ACE_SUCCESSFUL_ACCESS_ACE_FLAG   0x00000010
+#define NFS4_ACE_FAILED_ACCESS_ACE_FLAG       0x00000020
+#define NFS4_ACE_IDENTIFIER_GROUP             0x00000040
+#define NFS4_ACE_OWNER                        0x00000080
+#define NFS4_ACE_GROUP                        0x00000100
+#define NFS4_ACE_EVERYONE                     0x00000200
+
+#define NFS4_ACE_READ_DATA                    0x00000001
+#define NFS4_ACE_LIST_DIRECTORY               0x00000001
+#define NFS4_ACE_WRITE_DATA                   0x00000002
+#define NFS4_ACE_ADD_FILE                     0x00000002
+#define NFS4_ACE_APPEND_DATA                  0x00000004
+#define NFS4_ACE_ADD_SUBDIRECTORY             0x00000004
+#define NFS4_ACE_READ_NAMED_ATTRS             0x00000008
+#define NFS4_ACE_WRITE_NAMED_ATTRS            0x00000010
+#define NFS4_ACE_EXECUTE                      0x00000020
+#define NFS4_ACE_DELETE_CHILD                 0x00000040
+#define NFS4_ACE_READ_ATTRIBUTES              0x00000080
+#define NFS4_ACE_WRITE_ATTRIBUTES             0x00000100
+#define NFS4_ACE_DELETE                       0x00010000
+#define NFS4_ACE_READ_ACL                     0x00020000
+#define NFS4_ACE_WRITE_ACL                    0x00040000
+#define NFS4_ACE_WRITE_OWNER                  0x00080000
+#define NFS4_ACE_SYNCHRONIZE                  0x00100000
+#define NFS4_ACE_GENERIC_READ                 0x00120081
+#define NFS4_ACE_GENERIC_WRITE                0x00160106
+#define NFS4_ACE_GENERIC_EXECUTE              0x001200A0
+#define NFS4_ACE_MASK_ALL                     0x001F01FF
+
+enum nfs4_acl_whotype {
+	NFS4_ACL_WHO_NAMED = 0,
+	NFS4_ACL_WHO_OWNER,
+	NFS4_ACL_WHO_GROUP,
+	NFS4_ACL_WHO_EVERYONE,
+};
+
+struct nfs4_ace {
+	uint32_t	type;
+	uint32_t	flag;
+	uint32_t	access_mask;
+	int		whotype;
+	uid_t		who;
+	struct list_head l_ace;
+};
+
+struct nfs4_acl {
+	uint32_t	naces;
+	struct list_head ace_head;
+};
+
 typedef struct { char data[NFS4_VERIFIER_SIZE]; } nfs4_verifier;
 typedef struct { char data[16]; } nfs4_stateid;
 
_