diff options
Diffstat (limited to 'fs/nfsd/nfs4acl.c')
-rw-r--r-- | fs/nfsd/nfs4acl.c | 491 |
1 files changed, 238 insertions, 253 deletions
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c index 5d94555cdc83..832673b14587 100644 --- a/fs/nfsd/nfs4acl.c +++ b/fs/nfsd/nfs4acl.c | |||
@@ -61,9 +61,11 @@ | |||
61 | 61 | ||
62 | /* flags used to simulate posix default ACLs */ | 62 | /* flags used to simulate posix default ACLs */ |
63 | #define NFS4_INHERITANCE_FLAGS (NFS4_ACE_FILE_INHERIT_ACE \ | 63 | #define NFS4_INHERITANCE_FLAGS (NFS4_ACE_FILE_INHERIT_ACE \ |
64 | | NFS4_ACE_DIRECTORY_INHERIT_ACE | NFS4_ACE_INHERIT_ONLY_ACE) | 64 | | NFS4_ACE_DIRECTORY_INHERIT_ACE) |
65 | 65 | ||
66 | #define NFS4_SUPPORTED_FLAGS (NFS4_INHERITANCE_FLAGS | NFS4_ACE_IDENTIFIER_GROUP) | 66 | #define NFS4_SUPPORTED_FLAGS (NFS4_INHERITANCE_FLAGS \ |
67 | | NFS4_ACE_INHERIT_ONLY_ACE \ | ||
68 | | NFS4_ACE_IDENTIFIER_GROUP) | ||
67 | 69 | ||
68 | #define MASK_EQUAL(mask1, mask2) \ | 70 | #define MASK_EQUAL(mask1, mask2) \ |
69 | ( ((mask1) & NFS4_ACE_MASK_ALL) == ((mask2) & NFS4_ACE_MASK_ALL) ) | 71 | ( ((mask1) & NFS4_ACE_MASK_ALL) == ((mask2) & NFS4_ACE_MASK_ALL) ) |
@@ -87,12 +89,19 @@ mask_from_posix(unsigned short perm, unsigned int flags) | |||
87 | } | 89 | } |
88 | 90 | ||
89 | static u32 | 91 | static u32 |
90 | deny_mask(u32 allow_mask, unsigned int flags) | 92 | deny_mask_from_posix(unsigned short perm, u32 flags) |
91 | { | 93 | { |
92 | u32 ret = ~allow_mask & ~NFS4_MASK_UNSUPP; | 94 | u32 mask = 0; |
93 | if (!(flags & NFS4_ACL_DIR)) | 95 | |
94 | ret &= ~NFS4_ACE_DELETE_CHILD; | 96 | if (perm & ACL_READ) |
95 | return ret; | 97 | mask |= NFS4_READ_MODE; |
98 | if (perm & ACL_WRITE) | ||
99 | mask |= NFS4_WRITE_MODE; | ||
100 | if ((perm & ACL_WRITE) && (flags & NFS4_ACL_DIR)) | ||
101 | mask |= NFS4_ACE_DELETE_CHILD; | ||
102 | if (perm & ACL_EXECUTE) | ||
103 | mask |= NFS4_EXECUTE_MODE; | ||
104 | return mask; | ||
96 | } | 105 | } |
97 | 106 | ||
98 | /* XXX: modify functions to return NFS errors; they're only ever | 107 | /* XXX: modify functions to return NFS errors; they're only ever |
@@ -126,108 +135,151 @@ struct ace_container { | |||
126 | }; | 135 | }; |
127 | 136 | ||
128 | static short ace2type(struct nfs4_ace *); | 137 | static short ace2type(struct nfs4_ace *); |
129 | static int _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *, unsigned int); | 138 | static void _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *, |
130 | static struct posix_acl *_nfsv4_to_posix_one(struct nfs4_acl *, unsigned int); | 139 | unsigned int); |
131 | int nfs4_acl_add_ace(struct nfs4_acl *, u32, u32, u32, int, uid_t); | 140 | void nfs4_acl_add_ace(struct nfs4_acl *, u32, u32, u32, int, uid_t); |
132 | static int nfs4_acl_split(struct nfs4_acl *, struct nfs4_acl *); | ||
133 | 141 | ||
134 | struct nfs4_acl * | 142 | struct nfs4_acl * |
135 | nfs4_acl_posix_to_nfsv4(struct posix_acl *pacl, struct posix_acl *dpacl, | 143 | nfs4_acl_posix_to_nfsv4(struct posix_acl *pacl, struct posix_acl *dpacl, |
136 | unsigned int flags) | 144 | unsigned int flags) |
137 | { | 145 | { |
138 | struct nfs4_acl *acl; | 146 | struct nfs4_acl *acl; |
139 | int error = -EINVAL; | 147 | int size = 0; |
140 | 148 | ||
141 | if ((pacl != NULL && | 149 | if (pacl) { |
142 | (posix_acl_valid(pacl) < 0 || pacl->a_count == 0)) || | 150 | if (posix_acl_valid(pacl) < 0) |
143 | (dpacl != NULL && | 151 | return ERR_PTR(-EINVAL); |
144 | (posix_acl_valid(dpacl) < 0 || dpacl->a_count == 0))) | 152 | size += 2*pacl->a_count; |
145 | goto out_err; | ||
146 | |||
147 | acl = nfs4_acl_new(); | ||
148 | if (acl == NULL) { | ||
149 | error = -ENOMEM; | ||
150 | goto out_err; | ||
151 | } | 153 | } |
152 | 154 | if (dpacl) { | |
153 | if (pacl != NULL) { | 155 | if (posix_acl_valid(dpacl) < 0) |
154 | error = _posix_to_nfsv4_one(pacl, acl, | 156 | return ERR_PTR(-EINVAL); |
155 | flags & ~NFS4_ACL_TYPE_DEFAULT); | 157 | size += 2*dpacl->a_count; |
156 | if (error < 0) | ||
157 | goto out_acl; | ||
158 | } | 158 | } |
159 | 159 | ||
160 | if (dpacl != NULL) { | 160 | /* Allocate for worst case: one (deny, allow) pair each: */ |
161 | error = _posix_to_nfsv4_one(dpacl, acl, | 161 | acl = nfs4_acl_new(size); |
162 | flags | NFS4_ACL_TYPE_DEFAULT); | 162 | if (acl == NULL) |
163 | if (error < 0) | 163 | return ERR_PTR(-ENOMEM); |
164 | goto out_acl; | ||
165 | } | ||
166 | 164 | ||
167 | return acl; | 165 | if (pacl) |
166 | _posix_to_nfsv4_one(pacl, acl, flags & ~NFS4_ACL_TYPE_DEFAULT); | ||
168 | 167 | ||
169 | out_acl: | 168 | if (dpacl) |
170 | nfs4_acl_free(acl); | 169 | _posix_to_nfsv4_one(dpacl, acl, flags | NFS4_ACL_TYPE_DEFAULT); |
171 | out_err: | ||
172 | acl = ERR_PTR(error); | ||
173 | 170 | ||
174 | return acl; | 171 | return acl; |
175 | } | 172 | } |
176 | 173 | ||
177 | static int | 174 | struct posix_acl_summary { |
178 | nfs4_acl_add_pair(struct nfs4_acl *acl, int eflag, u32 mask, int whotype, | 175 | unsigned short owner; |
179 | uid_t owner, unsigned int flags) | 176 | unsigned short users; |
177 | unsigned short group; | ||
178 | unsigned short groups; | ||
179 | unsigned short other; | ||
180 | unsigned short mask; | ||
181 | }; | ||
182 | |||
183 | static void | ||
184 | summarize_posix_acl(struct posix_acl *acl, struct posix_acl_summary *pas) | ||
180 | { | 185 | { |
181 | int error; | 186 | struct posix_acl_entry *pa, *pe; |
182 | 187 | pas->users = 0; | |
183 | error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE, | 188 | pas->groups = 0; |
184 | eflag, mask, whotype, owner); | 189 | pas->mask = 07; |
185 | if (error < 0) | 190 | |
186 | return error; | 191 | pe = acl->a_entries + acl->a_count; |
187 | error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE, | 192 | |
188 | eflag, deny_mask(mask, flags), whotype, owner); | 193 | FOREACH_ACL_ENTRY(pa, acl, pe) { |
189 | return error; | 194 | switch (pa->e_tag) { |
195 | case ACL_USER_OBJ: | ||
196 | pas->owner = pa->e_perm; | ||
197 | break; | ||
198 | case ACL_GROUP_OBJ: | ||
199 | pas->group = pa->e_perm; | ||
200 | break; | ||
201 | case ACL_USER: | ||
202 | pas->users |= pa->e_perm; | ||
203 | break; | ||
204 | case ACL_GROUP: | ||
205 | pas->groups |= pa->e_perm; | ||
206 | break; | ||
207 | case ACL_OTHER: | ||
208 | pas->other = pa->e_perm; | ||
209 | break; | ||
210 | case ACL_MASK: | ||
211 | pas->mask = pa->e_perm; | ||
212 | break; | ||
213 | } | ||
214 | } | ||
215 | /* We'll only care about effective permissions: */ | ||
216 | pas->users &= pas->mask; | ||
217 | pas->group &= pas->mask; | ||
218 | pas->groups &= pas->mask; | ||
190 | } | 219 | } |
191 | 220 | ||
192 | /* We assume the acl has been verified with posix_acl_valid. */ | 221 | /* We assume the acl has been verified with posix_acl_valid. */ |
193 | static int | 222 | static void |
194 | _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, | 223 | _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, |
195 | unsigned int flags) | 224 | unsigned int flags) |
196 | { | 225 | { |
197 | struct posix_acl_entry *pa, *pe, *group_owner_entry; | 226 | struct posix_acl_entry *pa, *group_owner_entry; |
198 | int error = -EINVAL; | 227 | struct nfs4_ace *ace; |
199 | u32 mask, mask_mask; | 228 | struct posix_acl_summary pas; |
229 | unsigned short deny; | ||
200 | int eflag = ((flags & NFS4_ACL_TYPE_DEFAULT) ? | 230 | int eflag = ((flags & NFS4_ACL_TYPE_DEFAULT) ? |
201 | NFS4_INHERITANCE_FLAGS : 0); | 231 | NFS4_INHERITANCE_FLAGS : 0); |
202 | 232 | ||
203 | BUG_ON(pacl->a_count < 3); | 233 | BUG_ON(pacl->a_count < 3); |
204 | pe = pacl->a_entries + pacl->a_count; | 234 | summarize_posix_acl(pacl, &pas); |
205 | pa = pe - 2; /* if mask entry exists, it's second from the last. */ | ||
206 | if (pa->e_tag == ACL_MASK) | ||
207 | mask_mask = deny_mask(mask_from_posix(pa->e_perm, flags), flags); | ||
208 | else | ||
209 | mask_mask = 0; | ||
210 | 235 | ||
211 | pa = pacl->a_entries; | 236 | pa = pacl->a_entries; |
212 | BUG_ON(pa->e_tag != ACL_USER_OBJ); | 237 | ace = acl->aces + acl->naces; |
213 | mask = mask_from_posix(pa->e_perm, flags | NFS4_ACL_OWNER); | ||
214 | error = nfs4_acl_add_pair(acl, eflag, mask, NFS4_ACL_WHO_OWNER, 0, flags); | ||
215 | if (error < 0) | ||
216 | goto out; | ||
217 | pa++; | ||
218 | 238 | ||
219 | while (pa->e_tag == ACL_USER) { | 239 | /* We could deny everything not granted by the owner: */ |
220 | mask = mask_from_posix(pa->e_perm, flags); | 240 | deny = ~pas.owner; |
221 | error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE, | 241 | /* |
222 | eflag, mask_mask, NFS4_ACL_WHO_NAMED, pa->e_id); | 242 | * but it is equivalent (and simpler) to deny only what is not |
223 | if (error < 0) | 243 | * granted by later entries: |
224 | goto out; | 244 | */ |
245 | deny &= pas.users | pas.group | pas.groups | pas.other; | ||
246 | if (deny) { | ||
247 | ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE; | ||
248 | ace->flag = eflag; | ||
249 | ace->access_mask = deny_mask_from_posix(deny, flags); | ||
250 | ace->whotype = NFS4_ACL_WHO_OWNER; | ||
251 | ace++; | ||
252 | acl->naces++; | ||
253 | } | ||
225 | 254 | ||
255 | ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE; | ||
256 | ace->flag = eflag; | ||
257 | ace->access_mask = mask_from_posix(pa->e_perm, flags | NFS4_ACL_OWNER); | ||
258 | ace->whotype = NFS4_ACL_WHO_OWNER; | ||
259 | ace++; | ||
260 | acl->naces++; | ||
261 | pa++; | ||
226 | 262 | ||
227 | error = nfs4_acl_add_pair(acl, eflag, mask, | 263 | while (pa->e_tag == ACL_USER) { |
228 | NFS4_ACL_WHO_NAMED, pa->e_id, flags); | 264 | deny = ~(pa->e_perm & pas.mask); |
229 | if (error < 0) | 265 | deny &= pas.groups | pas.group | pas.other; |
230 | goto out; | 266 | if (deny) { |
267 | ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE; | ||
268 | ace->flag = eflag; | ||
269 | ace->access_mask = deny_mask_from_posix(deny, flags); | ||
270 | ace->whotype = NFS4_ACL_WHO_NAMED; | ||
271 | ace->who = pa->e_id; | ||
272 | ace++; | ||
273 | acl->naces++; | ||
274 | } | ||
275 | ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE; | ||
276 | ace->flag = eflag; | ||
277 | ace->access_mask = mask_from_posix(pa->e_perm & pas.mask, | ||
278 | flags); | ||
279 | ace->whotype = NFS4_ACL_WHO_NAMED; | ||
280 | ace->who = pa->e_id; | ||
281 | ace++; | ||
282 | acl->naces++; | ||
231 | pa++; | 283 | pa++; |
232 | } | 284 | } |
233 | 285 | ||
@@ -236,67 +288,65 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, | |||
236 | 288 | ||
237 | /* allow ACEs */ | 289 | /* allow ACEs */ |
238 | 290 | ||
239 | if (pacl->a_count > 3) { | ||
240 | BUG_ON(pa->e_tag != ACL_GROUP_OBJ); | ||
241 | error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE, | ||
242 | NFS4_ACE_IDENTIFIER_GROUP | eflag, mask_mask, | ||
243 | NFS4_ACL_WHO_GROUP, 0); | ||
244 | if (error < 0) | ||
245 | goto out; | ||
246 | } | ||
247 | group_owner_entry = pa; | 291 | group_owner_entry = pa; |
248 | mask = mask_from_posix(pa->e_perm, flags); | 292 | |
249 | error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE, | 293 | ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE; |
250 | NFS4_ACE_IDENTIFIER_GROUP | eflag, mask, | 294 | ace->flag = eflag; |
251 | NFS4_ACL_WHO_GROUP, 0); | 295 | ace->access_mask = mask_from_posix(pas.group, flags); |
252 | if (error < 0) | 296 | ace->whotype = NFS4_ACL_WHO_GROUP; |
253 | goto out; | 297 | ace++; |
298 | acl->naces++; | ||
254 | pa++; | 299 | pa++; |
255 | 300 | ||
256 | while (pa->e_tag == ACL_GROUP) { | 301 | while (pa->e_tag == ACL_GROUP) { |
257 | mask = mask_from_posix(pa->e_perm, flags); | 302 | ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE; |
258 | error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE, | 303 | ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP; |
259 | NFS4_ACE_IDENTIFIER_GROUP | eflag, mask_mask, | 304 | ace->access_mask = mask_from_posix(pa->e_perm & pas.mask, |
260 | NFS4_ACL_WHO_NAMED, pa->e_id); | 305 | flags); |
261 | if (error < 0) | 306 | ace->whotype = NFS4_ACL_WHO_NAMED; |
262 | goto out; | 307 | ace->who = pa->e_id; |
263 | 308 | ace++; | |
264 | error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE, | 309 | acl->naces++; |
265 | NFS4_ACE_IDENTIFIER_GROUP | eflag, mask, | ||
266 | NFS4_ACL_WHO_NAMED, pa->e_id); | ||
267 | if (error < 0) | ||
268 | goto out; | ||
269 | pa++; | 310 | pa++; |
270 | } | 311 | } |
271 | 312 | ||
272 | /* deny ACEs */ | 313 | /* deny ACEs */ |
273 | 314 | ||
274 | pa = group_owner_entry; | 315 | pa = group_owner_entry; |
275 | mask = mask_from_posix(pa->e_perm, flags); | 316 | |
276 | error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE, | 317 | deny = ~pas.group & pas.other; |
277 | NFS4_ACE_IDENTIFIER_GROUP | eflag, | 318 | if (deny) { |
278 | deny_mask(mask, flags), NFS4_ACL_WHO_GROUP, 0); | 319 | ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE; |
279 | if (error < 0) | 320 | ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP; |
280 | goto out; | 321 | ace->access_mask = deny_mask_from_posix(deny, flags); |
322 | ace->whotype = NFS4_ACL_WHO_GROUP; | ||
323 | ace++; | ||
324 | acl->naces++; | ||
325 | } | ||
281 | pa++; | 326 | pa++; |
327 | |||
282 | while (pa->e_tag == ACL_GROUP) { | 328 | while (pa->e_tag == ACL_GROUP) { |
283 | mask = mask_from_posix(pa->e_perm, flags); | 329 | deny = ~(pa->e_perm & pas.mask); |
284 | error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE, | 330 | deny &= pas.other; |
285 | NFS4_ACE_IDENTIFIER_GROUP | eflag, | 331 | if (deny) { |
286 | deny_mask(mask, flags), NFS4_ACL_WHO_NAMED, pa->e_id); | 332 | ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE; |
287 | if (error < 0) | 333 | ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP; |
288 | goto out; | 334 | ace->access_mask = mask_from_posix(deny, flags); |
335 | ace->whotype = NFS4_ACL_WHO_NAMED; | ||
336 | ace->who = pa->e_id; | ||
337 | ace++; | ||
338 | acl->naces++; | ||
339 | } | ||
289 | pa++; | 340 | pa++; |
290 | } | 341 | } |
291 | 342 | ||
292 | if (pa->e_tag == ACL_MASK) | 343 | if (pa->e_tag == ACL_MASK) |
293 | pa++; | 344 | pa++; |
294 | BUG_ON(pa->e_tag != ACL_OTHER); | 345 | ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE; |
295 | mask = mask_from_posix(pa->e_perm, flags); | 346 | ace->flag = eflag; |
296 | error = nfs4_acl_add_pair(acl, eflag, mask, NFS4_ACL_WHO_EVERYONE, 0, flags); | 347 | ace->access_mask = mask_from_posix(pa->e_perm, flags); |
297 | 348 | ace->whotype = NFS4_ACL_WHO_EVERYONE; | |
298 | out: | 349 | acl->naces++; |
299 | return error; | ||
300 | } | 350 | } |
301 | 351 | ||
302 | static void | 352 | static void |
@@ -342,46 +392,6 @@ sort_pacl(struct posix_acl *pacl) | |||
342 | return; | 392 | return; |
343 | } | 393 | } |
344 | 394 | ||
345 | int | ||
346 | nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl, | ||
347 | struct posix_acl **dpacl, unsigned int flags) | ||
348 | { | ||
349 | struct nfs4_acl *dacl; | ||
350 | int error = -ENOMEM; | ||
351 | |||
352 | *pacl = NULL; | ||
353 | *dpacl = NULL; | ||
354 | |||
355 | dacl = nfs4_acl_new(); | ||
356 | if (dacl == NULL) | ||
357 | goto out; | ||
358 | |||
359 | error = nfs4_acl_split(acl, dacl); | ||
360 | if (error) | ||
361 | goto out_acl; | ||
362 | |||
363 | *pacl = _nfsv4_to_posix_one(acl, flags); | ||
364 | if (IS_ERR(*pacl)) { | ||
365 | error = PTR_ERR(*pacl); | ||
366 | *pacl = NULL; | ||
367 | goto out_acl; | ||
368 | } | ||
369 | |||
370 | *dpacl = _nfsv4_to_posix_one(dacl, flags); | ||
371 | if (IS_ERR(*dpacl)) { | ||
372 | error = PTR_ERR(*dpacl); | ||
373 | *dpacl = NULL; | ||
374 | } | ||
375 | out_acl: | ||
376 | if (error) { | ||
377 | posix_acl_release(*pacl); | ||
378 | *pacl = NULL; | ||
379 | } | ||
380 | nfs4_acl_free(dacl); | ||
381 | out: | ||
382 | return error; | ||
383 | } | ||
384 | |||
385 | /* | 395 | /* |
386 | * While processing the NFSv4 ACE, this maintains bitmasks representing | 396 | * While processing the NFSv4 ACE, this maintains bitmasks representing |
387 | * which permission bits have been allowed and which denied to a given | 397 | * which permission bits have been allowed and which denied to a given |
@@ -406,6 +416,7 @@ struct posix_ace_state_array { | |||
406 | * calculated so far: */ | 416 | * calculated so far: */ |
407 | 417 | ||
408 | struct posix_acl_state { | 418 | struct posix_acl_state { |
419 | int empty; | ||
409 | struct posix_ace_state owner; | 420 | struct posix_ace_state owner; |
410 | struct posix_ace_state group; | 421 | struct posix_ace_state group; |
411 | struct posix_ace_state other; | 422 | struct posix_ace_state other; |
@@ -421,6 +432,7 @@ init_state(struct posix_acl_state *state, int cnt) | |||
421 | int alloc; | 432 | int alloc; |
422 | 433 | ||
423 | memset(state, 0, sizeof(struct posix_acl_state)); | 434 | memset(state, 0, sizeof(struct posix_acl_state)); |
435 | state->empty = 1; | ||
424 | /* | 436 | /* |
425 | * In the worst case, each individual acl could be for a distinct | 437 | * In the worst case, each individual acl could be for a distinct |
426 | * named user or group, but we don't no which, so we allocate | 438 | * named user or group, but we don't no which, so we allocate |
@@ -488,6 +500,20 @@ posix_state_to_acl(struct posix_acl_state *state, unsigned int flags) | |||
488 | int nace; | 500 | int nace; |
489 | int i, error = 0; | 501 | int i, error = 0; |
490 | 502 | ||
503 | /* | ||
504 | * ACLs with no ACEs are treated differently in the inheritable | ||
505 | * and effective cases: when there are no inheritable ACEs, we | ||
506 | * set a zero-length default posix acl: | ||
507 | */ | ||
508 | if (state->empty && (flags & NFS4_ACL_TYPE_DEFAULT)) { | ||
509 | pacl = posix_acl_alloc(0, GFP_KERNEL); | ||
510 | return pacl ? pacl : ERR_PTR(-ENOMEM); | ||
511 | } | ||
512 | /* | ||
513 | * When there are no effective ACEs, the following will end | ||
514 | * up setting a 3-element effective posix ACL with all | ||
515 | * permissions zero. | ||
516 | */ | ||
491 | nace = 4 + state->users->n + state->groups->n; | 517 | nace = 4 + state->users->n + state->groups->n; |
492 | pacl = posix_acl_alloc(nace, GFP_KERNEL); | 518 | pacl = posix_acl_alloc(nace, GFP_KERNEL); |
493 | if (!pacl) | 519 | if (!pacl) |
@@ -603,6 +629,8 @@ static void process_one_v4_ace(struct posix_acl_state *state, | |||
603 | u32 mask = ace->access_mask; | 629 | u32 mask = ace->access_mask; |
604 | int i; | 630 | int i; |
605 | 631 | ||
632 | state->empty = 0; | ||
633 | |||
606 | switch (ace2type(ace)) { | 634 | switch (ace2type(ace)) { |
607 | case ACL_USER_OBJ: | 635 | case ACL_USER_OBJ: |
608 | if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { | 636 | if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { |
@@ -666,75 +694,62 @@ static void process_one_v4_ace(struct posix_acl_state *state, | |||
666 | } | 694 | } |
667 | } | 695 | } |
668 | 696 | ||
669 | static struct posix_acl * | 697 | int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl, |
670 | _nfsv4_to_posix_one(struct nfs4_acl *n4acl, unsigned int flags) | 698 | struct posix_acl **dpacl, unsigned int flags) |
671 | { | 699 | { |
672 | struct posix_acl_state state; | 700 | struct posix_acl_state effective_acl_state, default_acl_state; |
673 | struct posix_acl *pacl; | ||
674 | struct nfs4_ace *ace; | 701 | struct nfs4_ace *ace; |
675 | int ret; | 702 | int ret; |
676 | 703 | ||
677 | ret = init_state(&state, n4acl->naces); | 704 | ret = init_state(&effective_acl_state, acl->naces); |
678 | if (ret) | 705 | if (ret) |
679 | return ERR_PTR(ret); | 706 | return ret; |
680 | 707 | ret = init_state(&default_acl_state, acl->naces); | |
681 | list_for_each_entry(ace, &n4acl->ace_head, l_ace) | 708 | if (ret) |
682 | process_one_v4_ace(&state, ace); | 709 | goto out_estate; |
683 | 710 | ret = -EINVAL; | |
684 | pacl = posix_state_to_acl(&state, flags); | 711 | for (ace = acl->aces; ace < acl->aces + acl->naces; ace++) { |
685 | |||
686 | free_state(&state); | ||
687 | |||
688 | if (!IS_ERR(pacl)) | ||
689 | sort_pacl(pacl); | ||
690 | return pacl; | ||
691 | } | ||
692 | |||
693 | static int | ||
694 | nfs4_acl_split(struct nfs4_acl *acl, struct nfs4_acl *dacl) | ||
695 | { | ||
696 | struct list_head *h, *n; | ||
697 | struct nfs4_ace *ace; | ||
698 | int error = 0; | ||
699 | |||
700 | list_for_each_safe(h, n, &acl->ace_head) { | ||
701 | ace = list_entry(h, struct nfs4_ace, l_ace); | ||
702 | |||
703 | if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE && | 712 | if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE && |
704 | ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE) | 713 | ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE) |
705 | return -EINVAL; | 714 | goto out_dstate; |
706 | |||
707 | if (ace->flag & ~NFS4_SUPPORTED_FLAGS) | 715 | if (ace->flag & ~NFS4_SUPPORTED_FLAGS) |
708 | return -EINVAL; | 716 | goto out_dstate; |
709 | 717 | if ((ace->flag & NFS4_INHERITANCE_FLAGS) == 0) { | |
710 | switch (ace->flag & NFS4_INHERITANCE_FLAGS) { | 718 | process_one_v4_ace(&effective_acl_state, ace); |
711 | case 0: | ||
712 | /* Leave this ace in the effective acl: */ | ||
713 | continue; | 719 | continue; |
714 | case NFS4_INHERITANCE_FLAGS: | ||
715 | /* Add this ace to the default acl and remove it | ||
716 | * from the effective acl: */ | ||
717 | error = nfs4_acl_add_ace(dacl, ace->type, ace->flag, | ||
718 | ace->access_mask, ace->whotype, ace->who); | ||
719 | if (error) | ||
720 | return error; | ||
721 | list_del(h); | ||
722 | kfree(ace); | ||
723 | acl->naces--; | ||
724 | break; | ||
725 | case NFS4_INHERITANCE_FLAGS & ~NFS4_ACE_INHERIT_ONLY_ACE: | ||
726 | /* Add this ace to the default, but leave it in | ||
727 | * the effective acl as well: */ | ||
728 | error = nfs4_acl_add_ace(dacl, ace->type, ace->flag, | ||
729 | ace->access_mask, ace->whotype, ace->who); | ||
730 | if (error) | ||
731 | return error; | ||
732 | break; | ||
733 | default: | ||
734 | return -EINVAL; | ||
735 | } | 720 | } |
721 | if (!(flags & NFS4_ACL_DIR)) | ||
722 | goto out_dstate; | ||
723 | /* | ||
724 | * Note that when only one of FILE_INHERIT or DIRECTORY_INHERIT | ||
725 | * is set, we're effectively turning on the other. That's OK, | ||
726 | * according to rfc 3530. | ||
727 | */ | ||
728 | process_one_v4_ace(&default_acl_state, ace); | ||
729 | |||
730 | if (!(ace->flag & NFS4_ACE_INHERIT_ONLY_ACE)) | ||
731 | process_one_v4_ace(&effective_acl_state, ace); | ||
736 | } | 732 | } |
737 | return 0; | 733 | *pacl = posix_state_to_acl(&effective_acl_state, flags); |
734 | if (IS_ERR(*pacl)) { | ||
735 | ret = PTR_ERR(*pacl); | ||
736 | goto out_dstate; | ||
737 | } | ||
738 | *dpacl = posix_state_to_acl(&default_acl_state, | ||
739 | flags | NFS4_ACL_TYPE_DEFAULT); | ||
740 | if (IS_ERR(*dpacl)) { | ||
741 | ret = PTR_ERR(*dpacl); | ||
742 | posix_acl_release(*pacl); | ||
743 | goto out_dstate; | ||
744 | } | ||
745 | sort_pacl(*pacl); | ||
746 | sort_pacl(*dpacl); | ||
747 | ret = 0; | ||
748 | out_dstate: | ||
749 | free_state(&default_acl_state); | ||
750 | out_estate: | ||
751 | free_state(&effective_acl_state); | ||
752 | return ret; | ||
738 | } | 753 | } |
739 | 754 | ||
740 | static short | 755 | static short |
@@ -759,48 +774,22 @@ EXPORT_SYMBOL(nfs4_acl_posix_to_nfsv4); | |||
759 | EXPORT_SYMBOL(nfs4_acl_nfsv4_to_posix); | 774 | EXPORT_SYMBOL(nfs4_acl_nfsv4_to_posix); |
760 | 775 | ||
761 | struct nfs4_acl * | 776 | struct nfs4_acl * |
762 | nfs4_acl_new(void) | 777 | nfs4_acl_new(int n) |
763 | { | 778 | { |
764 | struct nfs4_acl *acl; | 779 | struct nfs4_acl *acl; |
765 | 780 | ||
766 | if ((acl = kmalloc(sizeof(*acl), GFP_KERNEL)) == NULL) | 781 | acl = kmalloc(sizeof(*acl) + n*sizeof(struct nfs4_ace), GFP_KERNEL); |
782 | if (acl == NULL) | ||
767 | return NULL; | 783 | return NULL; |
768 | |||
769 | acl->naces = 0; | 784 | acl->naces = 0; |
770 | INIT_LIST_HEAD(&acl->ace_head); | ||
771 | |||
772 | return acl; | 785 | return acl; |
773 | } | 786 | } |
774 | 787 | ||
775 | void | 788 | void |
776 | nfs4_acl_free(struct nfs4_acl *acl) | ||
777 | { | ||
778 | struct list_head *h; | ||
779 | struct nfs4_ace *ace; | ||
780 | |||
781 | if (!acl) | ||
782 | return; | ||
783 | |||
784 | while (!list_empty(&acl->ace_head)) { | ||
785 | h = acl->ace_head.next; | ||
786 | list_del(h); | ||
787 | ace = list_entry(h, struct nfs4_ace, l_ace); | ||
788 | kfree(ace); | ||
789 | } | ||
790 | |||
791 | kfree(acl); | ||
792 | |||
793 | return; | ||
794 | } | ||
795 | |||
796 | int | ||
797 | nfs4_acl_add_ace(struct nfs4_acl *acl, u32 type, u32 flag, u32 access_mask, | 789 | nfs4_acl_add_ace(struct nfs4_acl *acl, u32 type, u32 flag, u32 access_mask, |
798 | int whotype, uid_t who) | 790 | int whotype, uid_t who) |
799 | { | 791 | { |
800 | struct nfs4_ace *ace; | 792 | struct nfs4_ace *ace = acl->aces + acl->naces; |
801 | |||
802 | if ((ace = kmalloc(sizeof(*ace), GFP_KERNEL)) == NULL) | ||
803 | return -ENOMEM; | ||
804 | 793 | ||
805 | ace->type = type; | 794 | ace->type = type; |
806 | ace->flag = flag; | 795 | ace->flag = flag; |
@@ -808,10 +797,7 @@ nfs4_acl_add_ace(struct nfs4_acl *acl, u32 type, u32 flag, u32 access_mask, | |||
808 | ace->whotype = whotype; | 797 | ace->whotype = whotype; |
809 | ace->who = who; | 798 | ace->who = who; |
810 | 799 | ||
811 | list_add_tail(&ace->l_ace, &acl->ace_head); | ||
812 | acl->naces++; | 800 | acl->naces++; |
813 | |||
814 | return 0; | ||
815 | } | 801 | } |
816 | 802 | ||
817 | static struct { | 803 | static struct { |
@@ -865,7 +851,6 @@ nfs4_acl_write_who(int who, char *p) | |||
865 | } | 851 | } |
866 | 852 | ||
867 | EXPORT_SYMBOL(nfs4_acl_new); | 853 | EXPORT_SYMBOL(nfs4_acl_new); |
868 | EXPORT_SYMBOL(nfs4_acl_free); | ||
869 | EXPORT_SYMBOL(nfs4_acl_add_ace); | 854 | EXPORT_SYMBOL(nfs4_acl_add_ace); |
870 | EXPORT_SYMBOL(nfs4_acl_get_whotype); | 855 | EXPORT_SYMBOL(nfs4_acl_get_whotype); |
871 | EXPORT_SYMBOL(nfs4_acl_write_who); | 856 | EXPORT_SYMBOL(nfs4_acl_write_who); |