Fix 1.25 ND sources
[tomato.git] / release / src / linux / linux / fs / nfsacl.c
bloba666959c9a1e92bbad7e3807983da9a74ae681a6
1 /*
2 * linux/fs/nfsacl.c
4 * Copyright (C) 2002 by Andreas Gruenbacher <a.gruenbacher@computer.org>
5 */
7 /*
8 * The Solaris nfsacl protocol represents some ACLs slightly differently
9 * than POSIX 1003.1e draft 17 does (and we do):
11 * - Minimal ACLs always have an ACL_MASK entry, so they have
12 * four instead of three entries.
13 * - The ACL_MASK entry in such minimal ACLs always has the same
14 * permissions as the ACL_GROUP_OBJ entry. (In extended ACLs
15 * the ACL_MASK and ACL_GROUP_OBJ entries may differ.)
16 * - The identifier fields of the ACL_USER_OBJ and ACL_GROUP_OBJ
17 * entries contain the identifiers of the owner and owning group.
18 * (In POSIX ACLs we always set them to ACL_UNDEFINED_ID).
19 * - ACL entries in the kernel are kept sorted in ascending order
20 * of (e_tag, e_id). Solaris ACLs are unsorted.
23 #include <linux/module.h>
24 #include <linux/nfsacl.h>
25 #include <linux/nfs3.h>
27 EXPORT_SYMBOL(nfsacl_encode);
28 EXPORT_SYMBOL(nfsacl_decode);
30 u32 *
31 nfsacl_encode(u32 *p, u32 *end, struct inode *inode, struct posix_acl *acl,
32 int encode_entries, int typeflag)
34 int entries = acl ? acl->a_count : 0;
36 if (entries == 3)
37 entries++; /* need to fake up ACL_MASK entry */
38 if (entries > NFS3_ACL_MAX_ENTRIES ||
39 p + 2 + (encode_entries ? (3 * entries) : 0) > end)
40 return NULL;
41 *p++ = htonl(entries);
42 if (acl && encode_entries) {
43 struct posix_acl_entry *pa, *pe;
44 int group_obj_perm = ACL_READ|ACL_WRITE|ACL_EXECUTE;
46 *p++ = htonl(entries);
47 FOREACH_ACL_ENTRY(pa, acl, pe) {
48 *p++ = htonl(pa->e_tag | typeflag);
49 switch(pa->e_tag) {
50 case ACL_USER_OBJ:
51 *p++ = htonl(inode->i_uid);
52 break;
53 case ACL_GROUP_OBJ:
54 *p++ = htonl(inode->i_gid);
55 group_obj_perm = pa->e_perm;
56 break;
57 case ACL_USER:
58 case ACL_GROUP:
59 *p++ = htonl(pa->e_id);
60 break;
61 default: /* Solaris depends on that! */
62 *p++ = 0;
63 break;
65 *p++ = htonl(pa->e_perm & S_IRWXO);
67 if (acl->a_count < entries) {
68 /* fake up ACL_MASK entry */
69 *p++ = htonl(ACL_MASK | typeflag);
70 *p++ = htonl(ACL_UNDEFINED_ID);
71 *p++ = htonl(group_obj_perm & S_IRWXO);
73 } else
74 *p++ = 0;
76 return p;
79 static int
80 cmp_acl_entry(const struct posix_acl_entry *a, const struct posix_acl_entry *b)
82 if (a->e_tag != b->e_tag)
83 return a->e_tag - b->e_tag;
84 else if (a->e_id > b->e_id)
85 return 1;
86 else if (a->e_id < b->e_id)
87 return -1;
88 else
89 return 0;
93 * Convert from a Solaris ACL to a POSIX 1003.1e draft 17 ACL.
95 static int
96 posix_acl_from_nfsacl(struct posix_acl *acl)
98 struct posix_acl_entry *pa, *pe,
99 *group_obj = NULL, *mask = NULL;
101 if (!acl)
102 return 0;
104 qsort(acl->a_entries, acl->a_count, sizeof(struct posix_acl_entry),
105 (int(*)(const void *,const void *))cmp_acl_entry);
107 /* Clear undefined identifier fields and find the ACL_GROUP_OBJ
108 and ACL_MASK entries. */
109 FOREACH_ACL_ENTRY(pa, acl, pe) {
110 switch(pa->e_tag) {
111 case ACL_USER_OBJ:
112 pa->e_id = ACL_UNDEFINED_ID;
113 break;
114 case ACL_GROUP_OBJ:
115 pa->e_id = ACL_UNDEFINED_ID;
116 group_obj = pa;
117 break;
118 case ACL_MASK:
119 mask = pa;
120 /* fall through */
121 case ACL_OTHER:
122 pa->e_id = ACL_UNDEFINED_ID;
123 break;
126 if (acl->a_count == 4 && group_obj && mask &&
127 mask->e_perm == group_obj->e_perm) {
128 /* remove bogus ACL_MASK entry */
129 memmove(mask, mask+1, (acl->a_entries + 4 - mask) *
130 sizeof(struct posix_acl_entry));
131 acl->a_count = 3;
133 return 0;
136 static u32 *
137 nfsacl_decode_entry(u32 *p, struct posix_acl_entry *entry)
139 entry->e_tag = ntohl(*p++) & ~NFS3_ACL_DEFAULT;
140 entry->e_id = ntohl(*p++);
141 entry->e_perm = ntohl(*p++);
143 switch(entry->e_tag) {
144 case ACL_USER_OBJ:
145 case ACL_USER:
146 case ACL_GROUP_OBJ:
147 case ACL_GROUP:
148 case ACL_OTHER:
149 if (entry->e_perm & ~S_IRWXO)
150 return NULL;
151 break;
152 case ACL_MASK:
153 /* Solaris sometimes sets additonal bits in the mask */
154 entry->e_perm &= S_IRWXO;
155 break;
156 default:
157 return NULL;
159 return p;
162 u32 *
163 nfsacl_decode(u32 *p, u32 *end, unsigned int *aclcnt, struct posix_acl **pacl)
165 struct posix_acl_entry *pa, *pe;
166 unsigned int entries, array_len;
168 if (p + 2 > end)
169 return NULL;
170 entries = ntohl(*p++);
171 array_len = ntohl(*p++);
172 if (entries > NFS3_ACL_MAX_ENTRIES || (pacl && entries != array_len))
173 return NULL;
174 if (p + 3 * array_len > end)
175 return NULL;
176 if (pacl) {
177 *pacl = NULL;
178 if (entries) {
179 struct posix_acl *acl;
181 if (!(acl = posix_acl_alloc(array_len, GFP_KERNEL)))
182 return NULL;
183 FOREACH_ACL_ENTRY(pa, acl, pe) {
184 if (!(p = nfsacl_decode_entry(p, pa))) {
185 posix_acl_release(acl);
186 return NULL;
189 if (posix_acl_from_nfsacl(acl) != 0) {
190 posix_acl_release(acl);
191 return NULL;
193 *pacl = acl;
195 } else
196 p += 3 * array_len;
198 if (aclcnt)
199 *aclcnt = entries;
200 return p;