2 * Copyright (C) 2006, 2010 Novell, Inc.
3 * Written by Andreas Gruenbacher <agruen@suse.de>
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2, or (at your option) any
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
16 #include <linux/kernel.h>
18 #include <linux/slab.h>
19 #include <linux/module.h>
20 #include <linux/richacl_xattr.h>
22 MODULE_LICENSE("GPL");
25 * richacl_from_xattr - convert a richacl xattr into the in-memory representation
28 richacl_from_xattr(const void *value, size_t size)
30 const struct richacl_xattr *xattr_acl = value;
31 const struct richace_xattr *xattr_ace = (void *)(xattr_acl + 1);
36 if (size < sizeof(struct richacl_xattr) ||
37 xattr_acl->a_version != ACL4_XATTR_VERSION ||
38 (xattr_acl->a_flags & ~ACL4_VALID_FLAGS))
39 return ERR_PTR(-EINVAL);
41 count = le16_to_cpu(xattr_acl->a_count);
42 if (count > ACL4_XATTR_MAX_COUNT)
43 return ERR_PTR(-EINVAL);
45 acl = richacl_alloc(count);
47 return ERR_PTR(-ENOMEM);
49 acl->a_flags = xattr_acl->a_flags;
50 acl->a_owner_mask = le32_to_cpu(xattr_acl->a_owner_mask);
51 if (acl->a_owner_mask & ~ACE4_VALID_MASK)
53 acl->a_group_mask = le32_to_cpu(xattr_acl->a_group_mask);
54 if (acl->a_group_mask & ~ACE4_VALID_MASK)
56 acl->a_other_mask = le32_to_cpu(xattr_acl->a_other_mask);
57 if (acl->a_other_mask & ~ACE4_VALID_MASK)
60 richacl_for_each_entry(ace, acl) {
61 const char *who = (void *)(xattr_ace + 1), *end;
62 ssize_t used = (void *)who - value;
66 end = memchr(who, 0, size - used);
70 ace->e_type = le16_to_cpu(xattr_ace->e_type);
71 ace->e_flags = le16_to_cpu(xattr_ace->e_flags);
72 ace->e_mask = le32_to_cpu(xattr_ace->e_mask);
73 ace->u.e_id = le32_to_cpu(xattr_ace->e_id);
75 if (ace->e_flags & ~ACE4_VALID_FLAGS)
77 if (ace->e_type > ACE4_ACCESS_DENIED_ACE_TYPE ||
78 (ace->e_mask & ~ACE4_VALID_MASK))
82 if (ace->u.e_id == -1)
83 goto fail_einval; /* uid/gid needed */
84 } else if (richace_set_who(ace, who))
87 xattr_ace = (void *)who + ALIGN(end - who + 1, 4);
94 return ERR_PTR(-EINVAL);
96 EXPORT_SYMBOL_GPL(richacl_from_xattr);
99 * richacl_xattr_size - compute the size of the xattr representation of @acl
102 richacl_xattr_size(const struct richacl *acl)
104 size_t size = sizeof(struct richacl_xattr);
105 const struct richace *ace;
107 richacl_for_each_entry(ace, acl) {
108 size += sizeof(struct richace_xattr) +
109 (richace_is_unix_id(ace) ? 4 :
110 ALIGN(strlen(ace->u.e_who) + 1, 4));
114 EXPORT_SYMBOL_GPL(richacl_xattr_size);
117 * richacl_to_xattr - convert @acl into its xattr representation
118 * @acl: the richacl to convert
119 * @buffer: buffer of size richacl_xattr_size(@acl) for the result
122 richacl_to_xattr(const struct richacl *acl, void *buffer)
124 struct richacl_xattr *xattr_acl = buffer;
125 struct richace_xattr *xattr_ace;
126 const struct richace *ace;
128 xattr_acl->a_version = ACL4_XATTR_VERSION;
129 xattr_acl->a_flags = acl->a_flags;
130 xattr_acl->a_count = cpu_to_le16(acl->a_count);
132 xattr_acl->a_owner_mask = cpu_to_le32(acl->a_owner_mask);
133 xattr_acl->a_group_mask = cpu_to_le32(acl->a_group_mask);
134 xattr_acl->a_other_mask = cpu_to_le32(acl->a_other_mask);
136 xattr_ace = (void *)(xattr_acl + 1);
137 richacl_for_each_entry(ace, acl) {
138 xattr_ace->e_type = cpu_to_le16(ace->e_type);
139 xattr_ace->e_flags = cpu_to_le16(ace->e_flags &
141 xattr_ace->e_mask = cpu_to_le32(ace->e_mask);
142 if (richace_is_unix_id(ace)) {
143 xattr_ace->e_id = cpu_to_le32(ace->u.e_id);
144 memset(xattr_ace->e_who, 0, 4);
145 xattr_ace = (void *)xattr_ace->e_who + 4;
147 int sz = ALIGN(strlen(ace->u.e_who) + 1, 4);
149 xattr_ace->e_id = cpu_to_le32(-1);
150 memset(xattr_ace->e_who + sz - 4, 0, 4);
151 strcpy(xattr_ace->e_who, ace->u.e_who);
152 xattr_ace = (void *)xattr_ace->e_who + sz;
156 EXPORT_SYMBOL_GPL(richacl_to_xattr);