Root/
1 | /* |
2 | * fs/nfs_common/nfsacl.c |
3 | * |
4 | * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de> |
5 | */ |
6 | |
7 | /* |
8 | * The Solaris nfsacl protocol represents some ACLs slightly differently |
9 | * than POSIX 1003.1e draft 17 does (and we do): |
10 | * |
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. |
21 | */ |
22 | |
23 | #include <linux/module.h> |
24 | #include <linux/fs.h> |
25 | #include <linux/gfp.h> |
26 | #include <linux/sunrpc/xdr.h> |
27 | #include <linux/nfsacl.h> |
28 | #include <linux/nfs3.h> |
29 | #include <linux/sort.h> |
30 | |
31 | MODULE_LICENSE("GPL"); |
32 | |
33 | EXPORT_SYMBOL_GPL(nfsacl_encode); |
34 | EXPORT_SYMBOL_GPL(nfsacl_decode); |
35 | |
36 | struct nfsacl_encode_desc { |
37 | struct xdr_array2_desc desc; |
38 | unsigned int count; |
39 | struct posix_acl *acl; |
40 | int typeflag; |
41 | uid_t uid; |
42 | gid_t gid; |
43 | }; |
44 | |
45 | static int |
46 | xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem) |
47 | { |
48 | struct nfsacl_encode_desc *nfsacl_desc = |
49 | (struct nfsacl_encode_desc *) desc; |
50 | __be32 *p = elem; |
51 | |
52 | struct posix_acl_entry *entry = |
53 | &nfsacl_desc->acl->a_entries[nfsacl_desc->count++]; |
54 | |
55 | *p++ = htonl(entry->e_tag | nfsacl_desc->typeflag); |
56 | switch(entry->e_tag) { |
57 | case ACL_USER_OBJ: |
58 | *p++ = htonl(nfsacl_desc->uid); |
59 | break; |
60 | case ACL_GROUP_OBJ: |
61 | *p++ = htonl(nfsacl_desc->gid); |
62 | break; |
63 | case ACL_USER: |
64 | case ACL_GROUP: |
65 | *p++ = htonl(entry->e_id); |
66 | break; |
67 | default: /* Solaris depends on that! */ |
68 | *p++ = 0; |
69 | break; |
70 | } |
71 | *p++ = htonl(entry->e_perm & S_IRWXO); |
72 | return 0; |
73 | } |
74 | |
75 | unsigned int |
76 | nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode, |
77 | struct posix_acl *acl, int encode_entries, int typeflag) |
78 | { |
79 | int entries = (acl && acl->a_count) ? max_t(int, acl->a_count, 4) : 0; |
80 | struct nfsacl_encode_desc nfsacl_desc = { |
81 | .desc = { |
82 | .elem_size = 12, |
83 | .array_len = encode_entries ? entries : 0, |
84 | .xcode = xdr_nfsace_encode, |
85 | }, |
86 | .acl = acl, |
87 | .typeflag = typeflag, |
88 | .uid = inode->i_uid, |
89 | .gid = inode->i_gid, |
90 | }; |
91 | int err; |
92 | struct posix_acl *acl2 = NULL; |
93 | |
94 | if (entries > NFS_ACL_MAX_ENTRIES || |
95 | xdr_encode_word(buf, base, entries)) |
96 | return -EINVAL; |
97 | if (encode_entries && acl && acl->a_count == 3) { |
98 | /* Fake up an ACL_MASK entry. */ |
99 | acl2 = posix_acl_alloc(4, GFP_KERNEL); |
100 | if (!acl2) |
101 | return -ENOMEM; |
102 | /* Insert entries in canonical order: other orders seem |
103 | to confuse Solaris VxFS. */ |
104 | acl2->a_entries[0] = acl->a_entries[0]; /* ACL_USER_OBJ */ |
105 | acl2->a_entries[1] = acl->a_entries[1]; /* ACL_GROUP_OBJ */ |
106 | acl2->a_entries[2] = acl->a_entries[1]; /* ACL_MASK */ |
107 | acl2->a_entries[2].e_tag = ACL_MASK; |
108 | acl2->a_entries[3] = acl->a_entries[2]; /* ACL_OTHER */ |
109 | nfsacl_desc.acl = acl2; |
110 | } |
111 | err = xdr_encode_array2(buf, base + 4, &nfsacl_desc.desc); |
112 | if (acl2) |
113 | posix_acl_release(acl2); |
114 | if (!err) |
115 | err = 8 + nfsacl_desc.desc.elem_size * |
116 | nfsacl_desc.desc.array_len; |
117 | return err; |
118 | } |
119 | |
120 | struct nfsacl_decode_desc { |
121 | struct xdr_array2_desc desc; |
122 | unsigned int count; |
123 | struct posix_acl *acl; |
124 | }; |
125 | |
126 | static int |
127 | xdr_nfsace_decode(struct xdr_array2_desc *desc, void *elem) |
128 | { |
129 | struct nfsacl_decode_desc *nfsacl_desc = |
130 | (struct nfsacl_decode_desc *) desc; |
131 | __be32 *p = elem; |
132 | struct posix_acl_entry *entry; |
133 | |
134 | if (!nfsacl_desc->acl) { |
135 | if (desc->array_len > NFS_ACL_MAX_ENTRIES) |
136 | return -EINVAL; |
137 | nfsacl_desc->acl = posix_acl_alloc(desc->array_len, GFP_KERNEL); |
138 | if (!nfsacl_desc->acl) |
139 | return -ENOMEM; |
140 | nfsacl_desc->count = 0; |
141 | } |
142 | |
143 | entry = &nfsacl_desc->acl->a_entries[nfsacl_desc->count++]; |
144 | entry->e_tag = ntohl(*p++) & ~NFS_ACL_DEFAULT; |
145 | entry->e_id = ntohl(*p++); |
146 | entry->e_perm = ntohl(*p++); |
147 | |
148 | switch(entry->e_tag) { |
149 | case ACL_USER_OBJ: |
150 | case ACL_USER: |
151 | case ACL_GROUP_OBJ: |
152 | case ACL_GROUP: |
153 | case ACL_OTHER: |
154 | if (entry->e_perm & ~S_IRWXO) |
155 | return -EINVAL; |
156 | break; |
157 | case ACL_MASK: |
158 | /* Solaris sometimes sets additonal bits in the mask */ |
159 | entry->e_perm &= S_IRWXO; |
160 | break; |
161 | default: |
162 | return -EINVAL; |
163 | } |
164 | |
165 | return 0; |
166 | } |
167 | |
168 | static int |
169 | cmp_acl_entry(const void *x, const void *y) |
170 | { |
171 | const struct posix_acl_entry *a = x, *b = y; |
172 | |
173 | if (a->e_tag != b->e_tag) |
174 | return a->e_tag - b->e_tag; |
175 | else if (a->e_id > b->e_id) |
176 | return 1; |
177 | else if (a->e_id < b->e_id) |
178 | return -1; |
179 | else |
180 | return 0; |
181 | } |
182 | |
183 | /* |
184 | * Convert from a Solaris ACL to a POSIX 1003.1e draft 17 ACL. |
185 | */ |
186 | static int |
187 | posix_acl_from_nfsacl(struct posix_acl *acl) |
188 | { |
189 | struct posix_acl_entry *pa, *pe, |
190 | *group_obj = NULL, *mask = NULL; |
191 | |
192 | if (!acl) |
193 | return 0; |
194 | |
195 | sort(acl->a_entries, acl->a_count, sizeof(struct posix_acl_entry), |
196 | cmp_acl_entry, NULL); |
197 | |
198 | /* Clear undefined identifier fields and find the ACL_GROUP_OBJ |
199 | and ACL_MASK entries. */ |
200 | FOREACH_ACL_ENTRY(pa, acl, pe) { |
201 | switch(pa->e_tag) { |
202 | case ACL_USER_OBJ: |
203 | pa->e_id = ACL_UNDEFINED_ID; |
204 | break; |
205 | case ACL_GROUP_OBJ: |
206 | pa->e_id = ACL_UNDEFINED_ID; |
207 | group_obj = pa; |
208 | break; |
209 | case ACL_MASK: |
210 | mask = pa; |
211 | /* fall through */ |
212 | case ACL_OTHER: |
213 | pa->e_id = ACL_UNDEFINED_ID; |
214 | break; |
215 | } |
216 | } |
217 | if (acl->a_count == 4 && group_obj && mask && |
218 | mask->e_perm == group_obj->e_perm) { |
219 | /* remove bogus ACL_MASK entry */ |
220 | memmove(mask, mask+1, (3 - (mask - acl->a_entries)) * |
221 | sizeof(struct posix_acl_entry)); |
222 | acl->a_count = 3; |
223 | } |
224 | return 0; |
225 | } |
226 | |
227 | unsigned int |
228 | nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt, |
229 | struct posix_acl **pacl) |
230 | { |
231 | struct nfsacl_decode_desc nfsacl_desc = { |
232 | .desc = { |
233 | .elem_size = 12, |
234 | .xcode = pacl ? xdr_nfsace_decode : NULL, |
235 | }, |
236 | }; |
237 | u32 entries; |
238 | int err; |
239 | |
240 | if (xdr_decode_word(buf, base, &entries) || |
241 | entries > NFS_ACL_MAX_ENTRIES) |
242 | return -EINVAL; |
243 | nfsacl_desc.desc.array_maxlen = entries; |
244 | err = xdr_decode_array2(buf, base + 4, &nfsacl_desc.desc); |
245 | if (err) |
246 | return err; |
247 | if (pacl) { |
248 | if (entries != nfsacl_desc.desc.array_len || |
249 | posix_acl_from_nfsacl(nfsacl_desc.acl) != 0) { |
250 | posix_acl_release(nfsacl_desc.acl); |
251 | return -EINVAL; |
252 | } |
253 | *pacl = nfsacl_desc.acl; |
254 | } |
255 | if (aclcnt) |
256 | *aclcnt = entries; |
257 | return 8 + nfsacl_desc.desc.elem_size * |
258 | nfsacl_desc.desc.array_len; |
259 | } |
260 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9