]>
Commit | Line | Data |
---|---|---|
4d1e5b62 AF |
1 | From: Andreas Gruenbacher <agruen@suse.de> |
2 | Subject: NFSv4 ACL in-memory representation and manipulation | |
3 | ||
4 | * In-memory representation (struct nfs4acl). | |
5 | * Functionality a filesystem needs such as permission checking, | |
6 | apply mode to acl, compute mode from acl, inheritance upon file | |
7 | create. | |
8 | * Compute a mask-less acl from struct nfs4acl that grants the same | |
9 | permissions. Protocols which don't understand the masks need | |
10 | this. | |
11 | * Convert to/from xattrs. | |
12 | ||
13 | Signed-off-by: Andreas Gruenbacher <agruen@suse.de> | |
14 | ||
15 | --- | |
16 | fs/Kconfig | 4 | |
17 | fs/Makefile | 4 | |
18 | fs/nfs4acl_base.c | 565 +++++++++++++++++++++++++++++++ | |
19 | fs/nfs4acl_compat.c | 757 ++++++++++++++++++++++++++++++++++++++++++ | |
20 | fs/nfs4acl_xattr.c | 146 ++++++++ | |
21 | include/linux/nfs4acl.h | 205 +++++++++++ | |
22 | include/linux/nfs4acl_xattr.h | 32 + | |
23 | 7 files changed, 1713 insertions(+) | |
24 | ||
25 | --- a/fs/Kconfig | |
26 | +++ b/fs/Kconfig | |
27 | @@ -419,6 +419,10 @@ config FS_POSIX_ACL | |
28 | bool | |
29 | default n | |
30 | ||
31 | +config FS_NFS4ACL | |
32 | + bool | |
33 | + default n | |
34 | + | |
35 | source "fs/xfs/Kconfig" | |
36 | source "fs/gfs2/Kconfig" | |
37 | ||
38 | --- a/fs/Makefile | |
39 | +++ b/fs/Makefile | |
40 | @@ -50,6 +50,10 @@ obj-$(CONFIG_FS_POSIX_ACL) += posix_acl. | |
41 | obj-$(CONFIG_NFS_COMMON) += nfs_common/ | |
42 | obj-$(CONFIG_GENERIC_ACL) += generic_acl.o | |
43 | ||
44 | +obj-$(CONFIG_FS_NFS4ACL) += nfs4acl.o | |
45 | +nfs4acl-y := nfs4acl_base.o nfs4acl_xattr.o \ | |
46 | + nfs4acl_compat.o | |
47 | + | |
48 | obj-$(CONFIG_QUOTA) += dquot.o | |
49 | obj-$(CONFIG_QFMT_V1) += quota_v1.o | |
50 | obj-$(CONFIG_QFMT_V2) += quota_v2.o | |
51 | --- /dev/null | |
52 | +++ b/fs/nfs4acl_base.c | |
53 | @@ -0,0 +1,565 @@ | |
54 | +/* | |
55 | + * Copyright (C) 2006 Andreas Gruenbacher <a.gruenbacher@computer.org> | |
56 | + * | |
57 | + * This program is free software; you can redistribute it and/or modify it | |
58 | + * under the terms of the GNU General Public License as published by the | |
59 | + * Free Software Foundation; either version 2, or (at your option) any | |
60 | + * later version. | |
61 | + * | |
62 | + * This program is distributed in the hope that it will be useful, but | |
63 | + * WITHOUT ANY WARRANTY; without even the implied warranty of | |
64 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
65 | + * General Public License for more details. | |
66 | + */ | |
67 | + | |
68 | +#include <linux/sched.h> | |
69 | +#include <linux/module.h> | |
70 | +#include <linux/fs.h> | |
71 | +#include <linux/nfs4acl.h> | |
72 | + | |
73 | +MODULE_LICENSE("GPL"); | |
74 | + | |
75 | +/* | |
76 | + * ACL entries that have ACE4_SPECIAL_WHO set in ace->e_flags use the | |
77 | + * pointer values of these constants in ace->u.e_who to avoid massive | |
78 | + * amounts of string comparisons. | |
79 | + */ | |
80 | + | |
81 | +const char nfs4ace_owner_who[] = "OWNER@"; | |
82 | +const char nfs4ace_group_who[] = "GROUP@"; | |
83 | +const char nfs4ace_everyone_who[] = "EVERYONE@"; | |
84 | + | |
85 | +EXPORT_SYMBOL(nfs4ace_owner_who); | |
86 | +EXPORT_SYMBOL(nfs4ace_group_who); | |
87 | +EXPORT_SYMBOL(nfs4ace_everyone_who); | |
88 | + | |
89 | +/** | |
90 | + * nfs4acl_alloc - allocate an acl | |
91 | + * @count: number of entries | |
92 | + */ | |
93 | +struct nfs4acl * | |
94 | +nfs4acl_alloc(int count) | |
95 | +{ | |
96 | + size_t size = sizeof(struct nfs4acl) + count * sizeof(struct nfs4ace); | |
97 | + struct nfs4acl *acl = kmalloc(size, GFP_KERNEL); | |
98 | + | |
99 | + if (acl) { | |
100 | + memset(acl, 0, size); | |
101 | + atomic_set(&acl->a_refcount, 1); | |
102 | + acl->a_count = count; | |
103 | + } | |
104 | + return acl; | |
105 | +} | |
106 | +EXPORT_SYMBOL(nfs4acl_alloc); | |
107 | + | |
108 | +/** | |
109 | + * nfs4acl_clone - create a copy of an acl | |
110 | + */ | |
111 | +struct nfs4acl * | |
112 | +nfs4acl_clone(const struct nfs4acl *acl) | |
113 | +{ | |
114 | + int count = acl->a_count; | |
115 | + size_t size = sizeof(struct nfs4acl) + count * sizeof(struct nfs4ace); | |
116 | + struct nfs4acl *dup = kmalloc(size, GFP_KERNEL); | |
117 | + | |
118 | + if (dup) { | |
119 | + memcpy(dup, acl, size); | |
120 | + atomic_set(&dup->a_refcount, 1); | |
121 | + } | |
122 | + return dup; | |
123 | +} | |
124 | + | |
125 | +/* | |
126 | + * The POSIX permissions are supersets of the below mask flags. | |
127 | + * | |
128 | + * The ACE4_READ_ATTRIBUTES and ACE4_READ_ACL flags are always granted | |
129 | + * in POSIX. The ACE4_SYNCHRONIZE flag has no meaning under POSIX. We | |
130 | + * make sure that we do not mask them if they are set, so that users who | |
131 | + * rely on these flags won't get confused. | |
132 | + */ | |
133 | +#define ACE4_POSIX_MODE_READ ( \ | |
134 | + ACE4_READ_DATA | ACE4_LIST_DIRECTORY ) | |
135 | +#define ACE4_POSIX_MODE_WRITE ( \ | |
136 | + ACE4_WRITE_DATA | ACE4_ADD_FILE | \ | |
137 | + ACE4_APPEND_DATA | ACE4_ADD_SUBDIRECTORY | \ | |
138 | + ACE4_DELETE_CHILD ) | |
139 | +#define ACE4_POSIX_MODE_EXEC ( \ | |
140 | + ACE4_EXECUTE) | |
141 | + | |
142 | +static int | |
143 | +nfs4acl_mask_to_mode(unsigned int mask) | |
144 | +{ | |
145 | + int mode = 0; | |
146 | + | |
147 | + if (mask & ACE4_POSIX_MODE_READ) | |
148 | + mode |= MAY_READ; | |
149 | + if (mask & ACE4_POSIX_MODE_WRITE) | |
150 | + mode |= MAY_WRITE; | |
151 | + if (mask & ACE4_POSIX_MODE_EXEC) | |
152 | + mode |= MAY_EXEC; | |
153 | + | |
154 | + return mode; | |
155 | +} | |
156 | + | |
157 | +/** | |
158 | + * nfs4acl_masks_to_mode - compute file mode permission bits from file masks | |
159 | + * | |
160 | + * Compute the file mode permission bits from the file masks in the acl. | |
161 | + */ | |
162 | +int | |
163 | +nfs4acl_masks_to_mode(const struct nfs4acl *acl) | |
164 | +{ | |
165 | + return nfs4acl_mask_to_mode(acl->a_owner_mask) << 6 | | |
166 | + nfs4acl_mask_to_mode(acl->a_group_mask) << 3 | | |
167 | + nfs4acl_mask_to_mode(acl->a_other_mask); | |
168 | +} | |
169 | +EXPORT_SYMBOL(nfs4acl_masks_to_mode); | |
170 | + | |
171 | +static unsigned int | |
172 | +nfs4acl_mode_to_mask(mode_t mode) | |
173 | +{ | |
174 | + unsigned int mask = ACE4_POSIX_ALWAYS_ALLOWED; | |
175 | + | |
176 | + if (mode & MAY_READ) | |
177 | + mask |= ACE4_POSIX_MODE_READ; | |
178 | + if (mode & MAY_WRITE) | |
179 | + mask |= ACE4_POSIX_MODE_WRITE; | |
180 | + if (mode & MAY_EXEC) | |
181 | + mask |= ACE4_POSIX_MODE_EXEC; | |
182 | + | |
183 | + return mask; | |
184 | +} | |
185 | + | |
186 | +/** | |
187 | + * nfs4acl_chmod - update the file masks to reflect the new mode | |
188 | + * @mode: file mode permission bits to apply to the @acl | |
189 | + * | |
190 | + * Converts the mask flags corresponding to the owner, group, and other file | |
191 | + * permissions and computes the file masks. Returns @acl if it already has the | |
192 | + * appropriate file masks, or updates the flags in a copy of @acl. Takes over | |
193 | + * @acl. | |
194 | + */ | |
195 | +struct nfs4acl * | |
196 | +nfs4acl_chmod(struct nfs4acl *acl, mode_t mode) | |
197 | +{ | |
198 | + unsigned int owner_mask, group_mask, other_mask; | |
199 | + struct nfs4acl *clone; | |
200 | + | |
201 | + owner_mask = nfs4acl_mode_to_mask(mode >> 6); | |
202 | + group_mask = nfs4acl_mode_to_mask(mode >> 3); | |
203 | + other_mask = nfs4acl_mode_to_mask(mode); | |
204 | + | |
205 | + if (acl->a_owner_mask == owner_mask && | |
206 | + acl->a_group_mask == group_mask && | |
207 | + acl->a_other_mask == other_mask) | |
208 | + return acl; | |
209 | + | |
210 | + clone = nfs4acl_clone(acl); | |
211 | + nfs4acl_put(acl); | |
212 | + if (!clone) | |
213 | + return ERR_PTR(-ENOMEM); | |
214 | + | |
215 | + clone->a_owner_mask = owner_mask; | |
216 | + clone->a_group_mask = group_mask; | |
217 | + clone->a_other_mask = other_mask; | |
218 | + | |
219 | + if (nfs4acl_write_through(&clone)) { | |
220 | + nfs4acl_put(clone); | |
221 | + clone = ERR_PTR(-ENOMEM); | |
222 | + } | |
223 | + return clone; | |
224 | +} | |
225 | +EXPORT_SYMBOL(nfs4acl_chmod); | |
226 | + | |
227 | +/** | |
228 | + * nfs4acl_want_to_mask - convert permission want argument to a mask | |
229 | + * @want: @want argument of the permission inode operation | |
230 | + * | |
231 | + * When checking for append, @want is (MAY_WRITE | MAY_APPEND). | |
232 | + */ | |
233 | +unsigned int | |
234 | +nfs4acl_want_to_mask(int want) | |
235 | +{ | |
236 | + unsigned int mask = 0; | |
237 | + | |
238 | + if (want & MAY_READ) | |
239 | + mask |= ACE4_READ_DATA; | |
240 | + if (want & MAY_APPEND) | |
241 | + mask |= ACE4_APPEND_DATA; | |
242 | + else if (want & MAY_WRITE) | |
243 | + mask |= ACE4_WRITE_DATA; | |
244 | + if (want & MAY_EXEC) | |
245 | + mask |= ACE4_EXECUTE; | |
246 | + | |
247 | + return mask; | |
248 | +} | |
249 | +EXPORT_SYMBOL(nfs4acl_want_to_mask); | |
250 | + | |
251 | +/** | |
252 | + * nfs4acl_capability_check - check for capabilities overriding read/write access | |
253 | + * @inode: inode to check | |
254 | + * @mask: requested access (ACE4_* bitmask) | |
255 | + * | |
256 | + * Capabilities other than CAP_DAC_OVERRIDE and CAP_DAC_READ_SEARCH must be checked | |
257 | + * separately. | |
258 | + */ | |
259 | +static inline int nfs4acl_capability_check(struct inode *inode, unsigned int mask) | |
260 | +{ | |
261 | + /* | |
262 | + * Read/write DACs are always overridable. | |
263 | + * Executable DACs are overridable if at least one exec bit is set. | |
264 | + */ | |
265 | + if (!(mask & (ACE4_WRITE_ACL | ACE4_WRITE_OWNER)) && | |
266 | + (!(mask & ACE4_EXECUTE) || | |
267 | + (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode))) | |
268 | + if (capable(CAP_DAC_OVERRIDE)) | |
269 | + return 0; | |
270 | + | |
271 | + /* | |
272 | + * Searching includes executable on directories, else just read. | |
273 | + */ | |
274 | + if (!(mask & ~(ACE4_READ_DATA | ACE4_EXECUTE)) && | |
275 | + (S_ISDIR(inode->i_mode) || !(mask & ACE4_EXECUTE))) | |
276 | + if (capable(CAP_DAC_READ_SEARCH)) | |
277 | + return 0; | |
278 | + | |
279 | + return -EACCES; | |
280 | +} | |
281 | + | |
282 | +/** | |
283 | + * nfs4acl_permission - permission check algorithm with masking | |
284 | + * @inode: inode to check | |
285 | + * @acl: nfs4 acl of the inode | |
286 | + * @mask: requested access (ACE4_* bitmask) | |
287 | + * | |
288 | + * Checks if the current process is granted @mask flags in @acl. With | |
289 | + * write-through, the OWNER@ is always granted the owner file mask, the | |
290 | + * GROUP@ is always granted the group file mask, and EVERYONE@ is always | |
291 | + * granted the other file mask. Otherwise, processes are only granted | |
292 | + * @mask flags which they are granted in the @acl as well as in their | |
293 | + * file mask. | |
294 | + */ | |
295 | +int nfs4acl_permission(struct inode *inode, const struct nfs4acl *acl, | |
296 | + unsigned int mask) | |
297 | +{ | |
298 | + const struct nfs4ace *ace; | |
299 | + unsigned int file_mask, requested = mask, denied = 0; | |
300 | + int in_owning_group = in_group_p(inode->i_gid); | |
301 | + int owner_or_group_class = in_owning_group; | |
302 | + | |
303 | + /* | |
304 | + * A process is in the | |
305 | + * - owner file class if it owns the file, in the | |
306 | + * - group file class if it is in the file's owning group or | |
307 | + * it matches any of the user or group entries, and in the | |
308 | + * - other file class otherwise. | |
309 | + */ | |
310 | + | |
311 | + nfs4acl_for_each_entry(ace, acl) { | |
312 | + unsigned int ace_mask = ace->e_mask; | |
313 | + | |
314 | + if (nfs4ace_is_inherit_only(ace)) | |
315 | + continue; | |
316 | + if (nfs4ace_is_owner(ace)) { | |
317 | + if (current->fsuid != inode->i_uid) | |
318 | + continue; | |
319 | + goto is_owner; | |
320 | + } else if (nfs4ace_is_group(ace)) { | |
321 | + if (!in_owning_group) | |
322 | + continue; | |
323 | + } else if (nfs4ace_is_unix_id(ace)) { | |
324 | + if (ace->e_flags & ACE4_IDENTIFIER_GROUP) { | |
325 | + if (!in_group_p(ace->u.e_id)) | |
326 | + continue; | |
327 | + } else { | |
328 | + if (current->fsuid != ace->u.e_id) | |
329 | + continue; | |
330 | + } | |
331 | + } else | |
332 | + goto is_everyone; | |
333 | + | |
334 | + /* | |
335 | + * Apply the group file mask to entries other than OWNER@ and | |
336 | + * EVERYONE@. This is not required for correct access checking | |
337 | + * but ensures that we grant the same permissions as the acl | |
338 | + * computed by nfs4acl_apply_masks(). | |
339 | + * | |
340 | + * For example, without this restriction, 'group@:rw::allow' | |
341 | + * with mode 0600 would grant rw access to owner processes | |
342 | + * which are also in the owning group. This cannot be expressed | |
343 | + * in an acl. | |
344 | + */ | |
345 | + if (nfs4ace_is_allow(ace)) | |
346 | + ace_mask &= acl->a_group_mask; | |
347 | + | |
348 | + is_owner: | |
349 | + /* The process is in the owner or group file class. */ | |
350 | + owner_or_group_class = 1; | |
351 | + | |
352 | + is_everyone: | |
353 | + /* Check which mask flags the ACE allows or denies. */ | |
354 | + if (nfs4ace_is_deny(ace)) | |
355 | + denied |= ace_mask & mask; | |
356 | + mask &= ~ace_mask; | |
357 | + | |
358 | + /* Keep going until we know which file class the process is in. */ | |
359 | + if (!mask && owner_or_group_class) | |
360 | + break; | |
361 | + } | |
362 | + denied |= mask; | |
363 | + | |
364 | + /* | |
365 | + * Figure out which file mask applies. | |
366 | + * Clear write-through if the process is in the file group class but | |
367 | + * not in the owning group, and so the denied permissions apply. | |
368 | + */ | |
369 | + if (current->fsuid == inode->i_uid) | |
370 | + file_mask = acl->a_owner_mask; | |
371 | + else if (in_owning_group || owner_or_group_class) | |
372 | + file_mask = acl->a_group_mask; | |
373 | + else | |
374 | + file_mask = acl->a_other_mask; | |
375 | + | |
376 | + denied |= requested & ~file_mask; | |
377 | + if (!denied) | |
378 | + return 0; | |
379 | + return nfs4acl_capability_check(inode, requested); | |
380 | +} | |
381 | +EXPORT_SYMBOL(nfs4acl_permission); | |
382 | + | |
383 | +/** | |
384 | + * nfs4acl_generic_permission - permission check algorithm without explicit acl | |
385 | + * @inode: inode to check permissions for | |
386 | + * @mask: requested access (ACE4_* bitmask) | |
387 | + * | |
388 | + * The file mode of a file without ACL corresponds to an ACL with a single | |
389 | + * "EVERYONE:~0::ALLOW" entry, with file masks that correspond to the file mode | |
390 | + * permissions. Instead of constructing a temporary ACL and applying | |
391 | + * nfs4acl_permission() to it, compute the identical result directly from the file | |
392 | + * mode. | |
393 | + */ | |
394 | +int nfs4acl_generic_permission(struct inode *inode, unsigned int mask) | |
395 | +{ | |
396 | + int mode = inode->i_mode; | |
397 | + | |
398 | + if (current->fsuid == inode->i_uid) | |
399 | + mode >>= 6; | |
400 | + else if (in_group_p(inode->i_gid)) | |
401 | + mode >>= 3; | |
402 | + if (!(mask & ~nfs4acl_mode_to_mask(mode))) | |
403 | + return 0; | |
404 | + return nfs4acl_capability_check(inode, mask); | |
405 | +} | |
406 | +EXPORT_SYMBOL(nfs4acl_generic_permission); | |
407 | + | |
408 | +/* | |
409 | + * nfs4ace_is_same_who - do both acl entries refer to the same identifier? | |
410 | + */ | |
411 | +int | |
412 | +nfs4ace_is_same_who(const struct nfs4ace *a, const struct nfs4ace *b) | |
413 | +{ | |
414 | +#define WHO_FLAGS (ACE4_SPECIAL_WHO | ACE4_IDENTIFIER_GROUP) | |
415 | + if ((a->e_flags & WHO_FLAGS) != (b->e_flags & WHO_FLAGS)) | |
416 | + return 0; | |
417 | + if (a->e_flags & ACE4_SPECIAL_WHO) | |
418 | + return a->u.e_who == b->u.e_who; | |
419 | + else | |
420 | + return a->u.e_id == b->u.e_id; | |
421 | +#undef WHO_FLAGS | |
422 | +} | |
423 | + | |
424 | +/** | |
425 | + * nfs4acl_set_who - set a special who value | |
426 | + * @ace: acl entry | |
427 | + * @who: who value to use | |
428 | + */ | |
429 | +int | |
430 | +nfs4ace_set_who(struct nfs4ace *ace, const char *who) | |
431 | +{ | |
432 | + if (!strcmp(who, nfs4ace_owner_who)) | |
433 | + who = nfs4ace_owner_who; | |
434 | + else if (!strcmp(who, nfs4ace_group_who)) | |
435 | + who = nfs4ace_group_who; | |
436 | + else if (!strcmp(who, nfs4ace_everyone_who)) | |
437 | + who = nfs4ace_everyone_who; | |
438 | + else | |
439 | + return -EINVAL; | |
440 | + | |
441 | + ace->u.e_who = who; | |
442 | + ace->e_flags |= ACE4_SPECIAL_WHO; | |
443 | + ace->e_flags &= ~ACE4_IDENTIFIER_GROUP; | |
444 | + return 0; | |
445 | +} | |
446 | +EXPORT_SYMBOL(nfs4ace_set_who); | |
447 | + | |
448 | +/** | |
449 | + * nfs4acl_allowed_to_who - mask flags allowed to a specific who value | |
450 | + * | |
451 | + * Computes the mask values allowed to a specific who value, taking | |
452 | + * EVERYONE@ entries into account. | |
453 | + */ | |
454 | +static unsigned int | |
455 | +nfs4acl_allowed_to_who(struct nfs4acl *acl, struct nfs4ace *who) | |
456 | +{ | |
457 | + struct nfs4ace *ace; | |
458 | + unsigned int allowed = 0; | |
459 | + | |
460 | + nfs4acl_for_each_entry_reverse(ace, acl) { | |
461 | + if (nfs4ace_is_inherit_only(ace)) | |
462 | + continue; | |
463 | + if (nfs4ace_is_same_who(ace, who) || | |
464 | + nfs4ace_is_everyone(ace)) { | |
465 | + if (nfs4ace_is_allow(ace)) | |
466 | + allowed |= ace->e_mask; | |
467 | + else if (nfs4ace_is_deny(ace)) | |
468 | + allowed &= ~ace->e_mask; | |
469 | + } | |
470 | + } | |
471 | + return allowed; | |
472 | +} | |
473 | + | |
474 | +/** | |
475 | + * nfs4acl_compute_max_masks - compute upper bound masks | |
476 | + * | |
477 | + * Computes upper bound owner, group, and other masks so that none of | |
478 | + * the mask flags allowed by the acl are disabled (for any choice of the | |
479 | + * file owner or group membership). | |
480 | + */ | |
481 | +static void | |
482 | +nfs4acl_compute_max_masks(struct nfs4acl *acl) | |
483 | +{ | |
484 | + struct nfs4ace *ace; | |
485 | + | |
486 | + acl->a_owner_mask = 0; | |
487 | + acl->a_group_mask = 0; | |
488 | + acl->a_other_mask = 0; | |
489 | + | |
490 | + nfs4acl_for_each_entry_reverse(ace, acl) { | |
491 | + if (nfs4ace_is_inherit_only(ace)) | |
492 | + continue; | |
493 | + | |
494 | + if (nfs4ace_is_owner(ace)) { | |
495 | + if (nfs4ace_is_allow(ace)) | |
496 | + acl->a_owner_mask |= ace->e_mask; | |
497 | + else if (nfs4ace_is_deny(ace)) | |
498 | + acl->a_owner_mask &= ~ace->e_mask; | |
499 | + } else if (nfs4ace_is_everyone(ace)) { | |
500 | + if (nfs4ace_is_allow(ace)) { | |
501 | + struct nfs4ace who = { | |
502 | + .e_flags = ACE4_SPECIAL_WHO, | |
503 | + .u.e_who = nfs4ace_group_who, | |
504 | + }; | |
505 | + | |
506 | + acl->a_other_mask |= ace->e_mask; | |
507 | + acl->a_group_mask |= | |
508 | + nfs4acl_allowed_to_who(acl, &who); | |
509 | + acl->a_owner_mask |= ace->e_mask; | |
510 | + } else if (nfs4ace_is_deny(ace)) { | |
511 | + acl->a_other_mask &= ~ace->e_mask; | |
512 | + acl->a_group_mask &= ~ace->e_mask; | |
513 | + acl->a_owner_mask &= ~ace->e_mask; | |
514 | + } | |
515 | + } else { | |
516 | + if (nfs4ace_is_allow(ace)) { | |
517 | + unsigned int mask = | |
518 | + nfs4acl_allowed_to_who(acl, ace); | |
519 | + | |
520 | + acl->a_group_mask |= mask; | |
521 | + acl->a_owner_mask |= mask; | |
522 | + } | |
523 | + } | |
524 | + } | |
525 | +} | |
526 | + | |
527 | +/** | |
528 | + * nfs4acl_inherit - compute the acl a new file will inherit | |
529 | + * @dir_acl: acl of the containing direcory | |
530 | + * @mode: file type and create mode of the new file | |
531 | + * | |
532 | + * Given the containing directory's acl, this function will compute the | |
533 | + * acl that new files in that directory will inherit, or %NULL if | |
534 | + * @dir_acl does not contain acl entries inheritable by this file. | |
535 | + * | |
536 | + * Without write-through, the file masks in the returned acl are set to | |
537 | + * the intersection of the create mode and the maximum permissions | |
538 | + * allowed to each file class. With write-through, the file masks are | |
539 | + * set to the create mode. | |
540 | + */ | |
541 | +struct nfs4acl * | |
542 | +nfs4acl_inherit(const struct nfs4acl *dir_acl, mode_t mode) | |
543 | +{ | |
544 | + const struct nfs4ace *dir_ace; | |
545 | + struct nfs4acl *acl; | |
546 | + struct nfs4ace *ace; | |
547 | + int count = 0; | |
548 | + | |
549 | + if (S_ISDIR(mode)) { | |
550 | + nfs4acl_for_each_entry(dir_ace, dir_acl) { | |
551 | + if (!nfs4ace_is_inheritable(dir_ace)) | |
552 | + continue; | |
553 | + count++; | |
554 | + } | |
555 | + if (!count) | |
556 | + return NULL; | |
557 | + acl = nfs4acl_alloc(count); | |
558 | + if (!acl) | |
559 | + return ERR_PTR(-ENOMEM); | |
560 | + ace = acl->a_entries; | |
561 | + nfs4acl_for_each_entry(dir_ace, dir_acl) { | |
562 | + if (!nfs4ace_is_inheritable(dir_ace)) | |
563 | + continue; | |
564 | + memcpy(ace, dir_ace, sizeof(struct nfs4ace)); | |
565 | + if (dir_ace->e_flags & ACE4_NO_PROPAGATE_INHERIT_ACE) | |
566 | + nfs4ace_clear_inheritance_flags(ace); | |
567 | + if ((dir_ace->e_flags & ACE4_FILE_INHERIT_ACE) && | |
568 | + !(dir_ace->e_flags & ACE4_DIRECTORY_INHERIT_ACE)) | |
569 | + ace->e_flags |= ACE4_INHERIT_ONLY_ACE; | |
570 | + ace++; | |
571 | + } | |
572 | + } else { | |
573 | + nfs4acl_for_each_entry(dir_ace, dir_acl) { | |
574 | + if (!(dir_ace->e_flags & ACE4_FILE_INHERIT_ACE)) | |
575 | + continue; | |
576 | + count++; | |
577 | + } | |
578 | + if (!count) | |
579 | + return NULL; | |
580 | + acl = nfs4acl_alloc(count); | |
581 | + if (!acl) | |
582 | + return ERR_PTR(-ENOMEM); | |
583 | + ace = acl->a_entries; | |
584 | + nfs4acl_for_each_entry(dir_ace, dir_acl) { | |
585 | + if (!(dir_ace->e_flags & ACE4_FILE_INHERIT_ACE)) | |
586 | + continue; | |
587 | + memcpy(ace, dir_ace, sizeof(struct nfs4ace)); | |
588 | + nfs4ace_clear_inheritance_flags(ace); | |
589 | + ace++; | |
590 | + } | |
591 | + } | |
592 | + | |
593 | + /* The maximum max flags that the owner, group, and other classes | |
594 | + are allowed. */ | |
595 | + if (dir_acl->a_flags & ACL4_WRITE_THROUGH) { | |
596 | + acl->a_owner_mask = ACE4_VALID_MASK; | |
597 | + acl->a_group_mask = ACE4_VALID_MASK; | |
598 | + acl->a_other_mask = ACE4_VALID_MASK; | |
599 | + | |
600 | + mode &= ~current->fs->umask; | |
601 | + } else | |
602 | + nfs4acl_compute_max_masks(acl); | |
603 | + | |
604 | + /* Apply the create mode. */ | |
605 | + acl->a_owner_mask &= nfs4acl_mode_to_mask(mode >> 6); | |
606 | + acl->a_group_mask &= nfs4acl_mode_to_mask(mode >> 3); | |
607 | + acl->a_other_mask &= nfs4acl_mode_to_mask(mode); | |
608 | + | |
609 | + if (nfs4acl_write_through(&acl)) { | |
610 | + nfs4acl_put(acl); | |
611 | + return ERR_PTR(-ENOMEM); | |
612 | + } | |
613 | + | |
614 | + acl->a_flags = (dir_acl->a_flags & ACL4_WRITE_THROUGH); | |
615 | + | |
616 | + return acl; | |
617 | +} | |
618 | +EXPORT_SYMBOL(nfs4acl_inherit); | |
619 | --- /dev/null | |
620 | +++ b/fs/nfs4acl_compat.c | |
621 | @@ -0,0 +1,757 @@ | |
622 | +/* | |
623 | + * Copyright (C) 2006 Andreas Gruenbacher <a.gruenbacher@computer.org> | |
624 | + * | |
625 | + * This program is free software; you can redistribute it and/or modify it | |
626 | + * under the terms of the GNU General Public License as published by the | |
627 | + * Free Software Foundation; either version 2, or (at your option) any | |
628 | + * later version. | |
629 | + * | |
630 | + * This program is distributed in the hope that it will be useful, but | |
631 | + * WITHOUT ANY WARRANTY; without even the implied warranty of | |
632 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
633 | + * General Public License for more details. | |
634 | + */ | |
635 | + | |
636 | +#include <linux/module.h> | |
637 | +#include <linux/fs.h> | |
638 | +#include <linux/nfs4acl.h> | |
639 | + | |
640 | +/** | |
641 | + * struct nfs4acl_alloc - remember how many entries are actually allocated | |
642 | + * @acl: acl with a_count <= @count | |
643 | + * @count: the actual number of entries allocated in @acl | |
644 | + * | |
645 | + * We pass around this structure while modifying an acl, so that we do | |
646 | + * not have to reallocate when we remove existing entries followed by | |
647 | + * adding new entries. | |
648 | + */ | |
649 | +struct nfs4acl_alloc { | |
650 | + struct nfs4acl *acl; | |
651 | + unsigned int count; | |
652 | +}; | |
653 | + | |
654 | +/** | |
655 | + * nfs4acl_delete_entry - delete an entry in an acl | |
656 | + * @x: acl and number of allocated entries | |
657 | + * @ace: an entry in @x->acl | |
658 | + * | |
659 | + * Updates @ace so that it points to the entry before the deleted entry | |
660 | + * on return. (When deleting the first entry, @ace will point to the | |
661 | + * (non-existant) entry before the first entry). This behavior is the | |
662 | + * expected behavior when deleting entries while forward iterating over | |
663 | + * an acl. | |
664 | + */ | |
665 | +static void | |
666 | +nfs4acl_delete_entry(struct nfs4acl_alloc *x, struct nfs4ace **ace) | |
667 | +{ | |
668 | + void *end = x->acl->a_entries + x->acl->a_count; | |
669 | + | |
670 | + memmove(*ace, *ace + 1, end - (void *)(*ace + 1)); | |
671 | + (*ace)--; | |
672 | + x->acl->a_count--; | |
673 | +} | |
674 | + | |
675 | +/** | |
676 | + * nfs4acl_insert_entry - insert an entry in an acl | |
677 | + * @x: acl and number of allocated entries | |
678 | + * @ace: entry before which the new entry shall be inserted | |
679 | + * | |
680 | + * Insert a new entry in @x->acl at position @ace, and zero-initialize | |
681 | + * it. This may require reallocating @x->acl. | |
682 | + */ | |
683 | +static int | |
684 | +nfs4acl_insert_entry(struct nfs4acl_alloc *x, struct nfs4ace **ace) | |
685 | +{ | |
686 | + if (x->count == x->acl->a_count) { | |
687 | + int n = *ace - x->acl->a_entries; | |
688 | + struct nfs4acl *acl2; | |
689 | + | |
690 | + acl2 = nfs4acl_alloc(x->acl->a_count + 1); | |
691 | + if (!acl2) | |
692 | + return -1; | |
693 | + acl2->a_flags = x->acl->a_flags; | |
694 | + acl2->a_owner_mask = x->acl->a_owner_mask; | |
695 | + acl2->a_group_mask = x->acl->a_group_mask; | |
696 | + acl2->a_other_mask = x->acl->a_other_mask; | |
697 | + memcpy(acl2->a_entries, x->acl->a_entries, | |
698 | + n * sizeof(struct nfs4ace)); | |
699 | + memcpy(acl2->a_entries + n + 1, *ace, | |
700 | + (x->acl->a_count - n) * sizeof(struct nfs4ace)); | |
701 | + kfree(x->acl); | |
702 | + x->acl = acl2; | |
703 | + x->count = acl2->a_count; | |
704 | + *ace = acl2->a_entries + n; | |
705 | + } else { | |
706 | + void *end = x->acl->a_entries + x->acl->a_count; | |
707 | + | |
708 | + memmove(*ace + 1, *ace, end - (void *)*ace); | |
709 | + x->acl->a_count++; | |
710 | + } | |
711 | + memset(*ace, 0, sizeof(struct nfs4ace)); | |
712 | + return 0; | |
713 | +} | |
714 | + | |
715 | +/** | |
716 | + * nfs4ace_change_mask - change the mask in @ace to @mask | |
717 | + * @x: acl and number of allocated entries | |
718 | + * @ace: entry to modify | |
719 | + * @mask: new mask for @ace | |
720 | + * | |
721 | + * Set the effective mask of @ace to @mask. This will require splitting | |
722 | + * off a separate acl entry if @ace is inheritable. In that case, the | |
723 | + * effective- only acl entry is inserted after the inheritable acl | |
724 | + * entry, end the inheritable acl entry is set to inheritable-only. If | |
725 | + * @mode is 0, either set the original acl entry to inheritable-only if | |
726 | + * it was inheritable, or remove it otherwise. The returned @ace points | |
727 | + * to the modified or inserted effective-only acl entry if that entry | |
728 | + * exists, to the entry that has become inheritable-only, or else to the | |
729 | + * previous entry in the acl. This is the expected behavior when | |
730 | + * modifying masks while forward iterating over an acl. | |
731 | + */ | |
732 | +static int | |
733 | +nfs4ace_change_mask(struct nfs4acl_alloc *x, struct nfs4ace **ace, | |
734 | + unsigned int mask) | |
735 | +{ | |
736 | + if (mask && (*ace)->e_mask == mask) | |
737 | + return 0; | |
738 | + if (mask & ~ACE4_POSIX_ALWAYS_ALLOWED) { | |
739 | + if (nfs4ace_is_inheritable(*ace)) { | |
740 | + if (nfs4acl_insert_entry(x, ace)) | |
741 | + return -1; | |
742 | + memcpy(*ace, *ace + 1, sizeof(struct nfs4ace)); | |
743 | + (*ace)->e_flags |= ACE4_INHERIT_ONLY_ACE; | |
744 | + (*ace)++; | |
745 | + nfs4ace_clear_inheritance_flags(*ace); | |
746 | + } | |
747 | + (*ace)->e_mask = mask; | |
748 | + } else { | |
749 | + if (nfs4ace_is_inheritable(*ace)) | |
750 | + (*ace)->e_flags |= ACE4_INHERIT_ONLY_ACE; | |
751 | + else | |
752 | + nfs4acl_delete_entry(x, ace); | |
753 | + } | |
754 | + return 0; | |
755 | +} | |
756 | + | |
757 | +/** | |
758 | + * nfs4acl_move_everyone_aces_down - move everyone@ acl entries to the end | |
759 | + * @x: acl and number of allocated entries | |
760 | + * | |
761 | + * Move all everyone acl entries to the bottom of the acl so that only a | |
762 | + * single everyone@ allow acl entry remains at the end, and update the | |
763 | + * mask fields of all acl entries on the way. If everyone@ is not | |
764 | + * granted any permissions, no empty everyone@ acl entry is inserted. | |
765 | + * | |
766 | + * This transformation does not modify the permissions that the acl | |
767 | + * grants, but we need it to simplify successive transformations. | |
768 | + */ | |
769 | +static int | |
770 | +nfs4acl_move_everyone_aces_down(struct nfs4acl_alloc *x) | |
771 | +{ | |
772 | + struct nfs4ace *ace; | |
773 | + unsigned int allowed = 0, denied = 0; | |
774 | + | |
775 | + nfs4acl_for_each_entry(ace, x->acl) { | |
776 | + if (nfs4ace_is_inherit_only(ace)) | |
777 | + continue; | |
778 | + if (nfs4ace_is_everyone(ace)) { | |
779 | + if (nfs4ace_is_allow(ace)) | |
780 | + allowed |= (ace->e_mask & ~denied); | |
781 | + else if (nfs4ace_is_deny(ace)) | |
782 | + denied |= (ace->e_mask & ~allowed); | |
783 | + else | |
784 | + continue; | |
785 | + if (nfs4ace_change_mask(x, &ace, 0)) | |
786 | + return -1; | |
787 | + } else { | |
788 | + if (nfs4ace_is_allow(ace)) { | |
789 | + if (nfs4ace_change_mask(x, &ace, allowed | | |
790 | + (ace->e_mask & ~denied))) | |
791 | + return -1; | |
792 | + } else if (nfs4ace_is_deny(ace)) { | |
793 | + if (nfs4ace_change_mask(x, &ace, denied | | |
794 | + (ace->e_mask & ~allowed))) | |
795 | + return -1; | |
796 | + } | |
797 | + } | |
798 | + } | |
799 | + if (allowed & ~ACE4_POSIX_ALWAYS_ALLOWED) { | |
800 | + struct nfs4ace *last_ace = ace - 1; | |
801 | + | |
802 | + if (nfs4ace_is_everyone(last_ace) && | |
803 | + nfs4ace_is_allow(last_ace) && | |
804 | + nfs4ace_is_inherit_only(last_ace) && | |
805 | + last_ace->e_mask == allowed) | |
806 | + last_ace->e_flags &= ~ACE4_INHERIT_ONLY_ACE; | |
807 | + else { | |
808 | + if (nfs4acl_insert_entry(x, &ace)) | |
809 | + return -1; | |
810 | + ace->e_type = ACE4_ACCESS_ALLOWED_ACE_TYPE; | |
811 | + ace->e_flags = ACE4_SPECIAL_WHO; | |
812 | + ace->e_mask = allowed; | |
813 | + ace->u.e_who = nfs4ace_everyone_who; | |
814 | + } | |
815 | + } | |
816 | + return 0; | |
817 | +} | |
818 | + | |
819 | +/** | |
820 | + * __nfs4acl_propagate_everyone - propagate everyone@ mask flags up for @who | |
821 | + * @x: acl and number of allocated entries | |
822 | + * @who: identifier to propagate mask flags for | |
823 | + * @allow: mask flags to propagate up | |
824 | + * | |
825 | + * Propagate mask flags from the trailing everyone@ allow acl entry up | |
826 | + * for the specified @who. | |
827 | + * | |
828 | + * The idea here is to precede the trailing EVERYONE@ ALLOW entry by an | |
829 | + * additional @who ALLOW entry, but with the following optimizations: | |
830 | + * (1) we don't bother setting any flags in the new @who ALLOW entry | |
831 | + * that has already been allowed or denied by a previous @who entry, (2) | |
832 | + * we merge the new @who entry with a previous @who entry if there is | |
833 | + * such a previous @who entry and there are no intervening DENY entries | |
834 | + * with mask flags that overlap the flags we care about. | |
835 | + */ | |
836 | +static int | |
837 | +__nfs4acl_propagate_everyone(struct nfs4acl_alloc *x, struct nfs4ace *who, | |
838 | + unsigned int allow) | |
839 | +{ | |
840 | + struct nfs4ace *allow_last = NULL, *ace; | |
841 | + | |
842 | + /* Remove the mask flags from allow that are already determined for | |
843 | + this who value, and figure out if there is an ALLOW entry for | |
844 | + this who value that is "reachable" from the trailing EVERYONE@ | |
845 | + ALLOW ACE. */ | |
846 | + nfs4acl_for_each_entry(ace, x->acl) { | |
847 | + if (nfs4ace_is_inherit_only(ace)) | |
848 | + continue; | |
849 | + if (nfs4ace_is_allow(ace)) { | |
850 | + if (nfs4ace_is_same_who(ace, who)) { | |
851 | + allow &= ~ace->e_mask; | |
852 | + allow_last = ace; | |
853 | + } | |
854 | + } else if (nfs4ace_is_deny(ace)) { | |
855 | + if (nfs4ace_is_same_who(ace, who)) | |
856 | + allow &= ~ace->e_mask; | |
857 | + if (allow & ace->e_mask) | |
858 | + allow_last = NULL; | |
859 | + } | |
860 | + } | |
861 | + | |
862 | + if (allow) { | |
863 | + if (allow_last) | |
864 | + return nfs4ace_change_mask(x, &allow_last, | |
865 | + allow_last->e_mask | allow); | |
866 | + else { | |
867 | + struct nfs4ace who_copy; | |
868 | + | |
869 | + ace = x->acl->a_entries + x->acl->a_count - 1; | |
870 | + memcpy(&who_copy, who, sizeof(struct nfs4ace)); | |
871 | + if (nfs4acl_insert_entry(x, &ace)) | |
872 | + return -1; | |
873 | + memcpy(ace, &who_copy, sizeof(struct nfs4ace)); | |
874 | + ace->e_type = ACE4_ACCESS_ALLOWED_ACE_TYPE; | |
875 | + nfs4ace_clear_inheritance_flags(ace); | |
876 | + ace->e_mask = allow; | |
877 | + } | |
878 | + } | |
879 | + return 0; | |
880 | +} | |
881 | + | |
882 | +/** | |
883 | + * nfs4acl_propagate_everyone - propagate everyone@ mask flags up the acl | |
884 | + * @x: acl and number of allocated entries | |
885 | + * | |
886 | + * Make sure for owner@, group@, and all other users, groups, and | |
887 | + * special identifiers that they are allowed or denied all permissions | |
888 | + * that are granted be the trailing everyone@ acl entry. If they are | |
889 | + * not, try to add the missing permissions to existing allow acl entries | |
890 | + * for those users, or introduce additional acl entries if that is not | |
891 | + * possible. | |
892 | + * | |
893 | + * We do this so that no mask flags will get lost when finally applying | |
894 | + * the file masks to the acl entries: otherwise, with an other file mask | |
895 | + * that is more restrictive than the owner and/or group file mask, mask | |
896 | + * flags that were allowed to processes in the owner and group classes | |
897 | + * and that the other mask denies would be lost. For example, the | |
898 | + * following two acls show the problem when mode 0664 is applied to | |
899 | + * them: | |
900 | + * | |
901 | + * masking without propagation (wrong) | |
902 | + * =========================================================== | |
903 | + * joe:r::allow => joe:r::allow | |
904 | + * everyone@:rwx::allow => everyone@:r::allow | |
905 | + * ----------------------------------------------------------- | |
906 | + * joe:w::deny => joe:w::deny | |
907 | + * everyone@:rwx::allow everyone@:r::allow | |
908 | + * | |
909 | + * Note that the permissions of joe end up being more restrictive than | |
910 | + * what the acl would allow when first computing the allowed flags and | |
911 | + * then applying the respective mask. With propagation of permissions, | |
912 | + * we get: | |
913 | + * | |
914 | + * masking after propagation (correct) | |
915 | + * =========================================================== | |
916 | + * joe:r::allow => joe:rw::allow | |
917 | + * owner@:rw::allow | |
918 | + * group@:rw::allow | |
919 | + * everyone@:rwx::allow everyone@:r::allow | |
920 | + * ----------------------------------------------------------- | |
921 | + * joe:w::deny => owner@:x::deny | |
922 | + * joe:w::deny | |
923 | + * owner@:rw::allow | |
924 | + * owner@:rw::allow | |
925 | + * joe:r::allow | |
926 | + * everyone@:rwx::allow everyone@:r::allow | |
927 | + * | |
928 | + * The examples show the acls that would result from propagation with no | |
929 | + * masking performed. In fact, we do apply the respective mask to the | |
930 | + * acl entries before computing the propagation because this will save | |
931 | + * us from adding acl entries that would end up with empty mask fields | |
932 | + * after applying the masks. | |
933 | + * | |
934 | + * It is ensured that no more than one entry will be inserted for each | |
935 | + * who value, no matter how many entries each who value has already. | |
936 | + */ | |
937 | +static int | |
938 | +nfs4acl_propagate_everyone(struct nfs4acl_alloc *x) | |
939 | +{ | |
940 | + int write_through = (x->acl->a_flags & ACL4_WRITE_THROUGH); | |
941 | + struct nfs4ace who = { .e_flags = ACE4_SPECIAL_WHO }; | |
942 | + struct nfs4ace *ace; | |
943 | + unsigned int owner_allow, group_allow; | |
944 | + int retval; | |
945 | + | |
946 | + if (!((x->acl->a_owner_mask | x->acl->a_group_mask) & | |
947 | + ~x->acl->a_other_mask)) | |
948 | + return 0; | |
949 | + if (!x->acl->a_count) | |
950 | + return 0; | |
951 | + ace = x->acl->a_entries + x->acl->a_count - 1; | |
952 | + if (nfs4ace_is_inherit_only(ace) || !nfs4ace_is_everyone(ace)) | |
953 | + return 0; | |
954 | + if (!(ace->e_mask & ~x->acl->a_other_mask)) { | |
955 | + /* None of the allowed permissions will get masked. */ | |
956 | + return 0; | |
957 | + } | |
958 | + owner_allow = ace->e_mask & x->acl->a_owner_mask; | |
959 | + group_allow = ace->e_mask & x->acl->a_group_mask; | |
960 | + | |
961 | + /* Propagate everyone@ permissions through to owner@. */ | |
962 | + if (owner_allow && !write_through && | |
963 | + (x->acl->a_owner_mask & ~x->acl->a_other_mask)) { | |
964 | + who.u.e_who = nfs4ace_owner_who; | |
965 | + retval = __nfs4acl_propagate_everyone(x, &who, owner_allow); | |
966 | + if (retval) | |
967 | + return -1; | |
968 | + } | |
969 | + | |
970 | + if (group_allow && (x->acl->a_group_mask & ~x->acl->a_other_mask)) { | |
971 | + int n; | |
972 | + | |
973 | + if (!write_through) { | |
974 | + /* Propagate everyone@ permissions through to group@. */ | |
975 | + who.u.e_who = nfs4ace_group_who; | |
976 | + retval = __nfs4acl_propagate_everyone(x, &who, | |
977 | + group_allow); | |
978 | + if (retval) | |
979 | + return -1; | |
980 | + } | |
981 | + | |
982 | + /* Start from the entry before the trailing EVERYONE@ ALLOW | |
983 | + entry. We will not hit EVERYONE@ entries in the loop. */ | |
984 | + for (n = x->acl->a_count - 2; n != -1; n--) { | |
985 | + ace = x->acl->a_entries + n; | |
986 | + | |
987 | + if (nfs4ace_is_inherit_only(ace) || | |
988 | + nfs4ace_is_owner(ace) || | |
989 | + nfs4ace_is_group(ace)) | |
990 | + continue; | |
991 | + if (nfs4ace_is_allow(ace) || nfs4ace_is_deny(ace)) { | |
992 | + /* Any inserted entry will end up below the | |
993 | + current entry. */ | |
994 | + retval = __nfs4acl_propagate_everyone(x, ace, | |
995 | + group_allow); | |
996 | + if (retval) | |
997 | + return -1; | |
998 | + } | |
999 | + } | |
1000 | + } | |
1001 | + return 0; | |
1002 | +} | |
1003 | + | |
1004 | +/** | |
1005 | + * __nfs4acl_apply_masks - apply the masks to the acl entries | |
1006 | + * @x: acl and number of allocated entries | |
1007 | + * | |
1008 | + * Apply the owner file mask to owner@ entries, the intersection of the | |
1009 | + * group and other file masks to everyone@ entries, and the group file | |
1010 | + * mask to all other entries. | |
1011 | + */ | |
1012 | +static int | |
1013 | +__nfs4acl_apply_masks(struct nfs4acl_alloc *x) | |
1014 | +{ | |
1015 | + struct nfs4ace *ace; | |
1016 | + | |
1017 | + nfs4acl_for_each_entry(ace, x->acl) { | |
1018 | + unsigned int mask; | |
1019 | + | |
1020 | + if (nfs4ace_is_inherit_only(ace) || !nfs4ace_is_allow(ace)) | |
1021 | + continue; | |
1022 | + if (nfs4ace_is_owner(ace)) | |
1023 | + mask = x->acl->a_owner_mask; | |
1024 | + else if (nfs4ace_is_everyone(ace)) | |
1025 | + mask = x->acl->a_other_mask; | |
1026 | + else | |
1027 | + mask = x->acl->a_group_mask; | |
1028 | + if (nfs4ace_change_mask(x, &ace, ace->e_mask & mask)) | |
1029 | + return -1; | |
1030 | + } | |
1031 | + return 0; | |
1032 | +} | |
1033 | + | |
1034 | +/** | |
1035 | + * nfs4acl_max_allowed - maximum mask flags that anybody is allowed | |
1036 | + */ | |
1037 | +static unsigned int | |
1038 | +nfs4acl_max_allowed(struct nfs4acl *acl) | |
1039 | +{ | |
1040 | + struct nfs4ace *ace; | |
1041 | + unsigned int allowed = 0; | |
1042 | + | |
1043 | + nfs4acl_for_each_entry_reverse(ace, acl) { | |
1044 | + if (nfs4ace_is_inherit_only(ace)) | |
1045 | + continue; | |
1046 | + if (nfs4ace_is_allow(ace)) | |
1047 | + allowed |= ace->e_mask; | |
1048 | + else if (nfs4ace_is_deny(ace)) { | |
1049 | + if (nfs4ace_is_everyone(ace)) | |
1050 | + allowed &= ~ace->e_mask; | |
1051 | + } | |
1052 | + } | |
1053 | + return allowed; | |
1054 | +} | |
1055 | + | |
1056 | +/** | |
1057 | + * nfs4acl_isolate_owner_class - limit the owner class to the owner file mask | |
1058 | + * @x: acl and number of allocated entries | |
1059 | + * | |
1060 | + * Make sure the owner class (owner@) is granted no more than the owner | |
1061 | + * mask by first checking which permissions anyone is granted, and then | |
1062 | + * denying owner@ all permissions beyond that. | |
1063 | + */ | |
1064 | +static int | |
1065 | +nfs4acl_isolate_owner_class(struct nfs4acl_alloc *x) | |
1066 | +{ | |
1067 | + struct nfs4ace *ace; | |
1068 | + unsigned int allowed = 0; | |
1069 | + | |
1070 | + allowed = nfs4acl_max_allowed(x->acl); | |
1071 | + if (allowed & ~x->acl->a_owner_mask) { | |
1072 | + /* Figure out if we can update an existig OWNER@ DENY entry. */ | |
1073 | + nfs4acl_for_each_entry(ace, x->acl) { | |
1074 | + if (nfs4ace_is_inherit_only(ace)) | |
1075 | + continue; | |
1076 | + if (nfs4ace_is_deny(ace)) { | |
1077 | + if (nfs4ace_is_owner(ace)) | |
1078 | + break; | |
1079 | + } else if (nfs4ace_is_allow(ace)) { | |
1080 | + ace = x->acl->a_entries + x->acl->a_count; | |
1081 | + break; | |
1082 | + } | |
1083 | + } | |
1084 | + if (ace != x->acl->a_entries + x->acl->a_count) { | |
1085 | + if (nfs4ace_change_mask(x, &ace, ace->e_mask | | |
1086 | + (allowed & ~x->acl->a_owner_mask))) | |
1087 | + return -1; | |
1088 | + } else { | |
1089 | + /* Insert an owner@ deny entry at the front. */ | |
1090 | + ace = x->acl->a_entries; | |
1091 | + if (nfs4acl_insert_entry(x, &ace)) | |
1092 | + return -1; | |
1093 | + ace->e_type = ACE4_ACCESS_DENIED_ACE_TYPE; | |
1094 | + ace->e_flags = ACE4_SPECIAL_WHO; | |
1095 | + ace->e_mask = allowed & ~x->acl->a_owner_mask; | |
1096 | + ace->u.e_who = nfs4ace_owner_who; | |
1097 | + } | |
1098 | + } | |
1099 | + return 0; | |
1100 | +} | |
1101 | + | |
1102 | +/** | |
1103 | + * __nfs4acl_isolate_who - isolate entry from EVERYONE@ ALLOW entry | |
1104 | + * @x: acl and number of allocated entries | |
1105 | + * @who: identifier to isolate | |
1106 | + * @deny: mask flags this identifier should not be allowed | |
1107 | + * | |
1108 | + * Make sure that @who is not allowed any mask flags in @deny by checking | |
1109 | + * which mask flags this identifier is allowed, and adding excess allowed | |
1110 | + * mask flags to an existing DENY entry before the trailing EVERYONE@ ALLOW | |
1111 | + * entry, or inserting such an entry. | |
1112 | + */ | |
1113 | +static int | |
1114 | +__nfs4acl_isolate_who(struct nfs4acl_alloc *x, struct nfs4ace *who, | |
1115 | + unsigned int deny) | |
1116 | +{ | |
1117 | + struct nfs4ace *ace; | |
1118 | + unsigned int allowed = 0, n; | |
1119 | + | |
1120 | + /* Compute the mask flags granted to this who value. */ | |
1121 | + nfs4acl_for_each_entry_reverse(ace, x->acl) { | |
1122 | + if (nfs4ace_is_inherit_only(ace)) | |
1123 | + continue; | |
1124 | + if (nfs4ace_is_same_who(ace, who)) { | |
1125 | + if (nfs4ace_is_allow(ace)) | |
1126 | + allowed |= ace->e_mask; | |
1127 | + else if (nfs4ace_is_deny(ace)) | |
1128 | + allowed &= ~ace->e_mask; | |
1129 | + deny &= ~ace->e_mask; | |
1130 | + } | |
1131 | + } | |
1132 | + if (!deny) | |
1133 | + return 0; | |
1134 | + | |
1135 | + /* Figure out if we can update an existig DENY entry. Start | |
1136 | + from the entry before the trailing EVERYONE@ ALLOW entry. We | |
1137 | + will not hit EVERYONE@ entries in the loop. */ | |
1138 | + for (n = x->acl->a_count - 2; n != -1; n--) { | |
1139 | + ace = x->acl->a_entries + n; | |
1140 | + if (nfs4ace_is_inherit_only(ace)) | |
1141 | + continue; | |
1142 | + if (nfs4ace_is_deny(ace)) { | |
1143 | + if (nfs4ace_is_same_who(ace, who)) | |
1144 | + break; | |
1145 | + } else if (nfs4ace_is_allow(ace) && | |
1146 | + (ace->e_mask & deny)) { | |
1147 | + n = -1; | |
1148 | + break; | |
1149 | + } | |
1150 | + } | |
1151 | + if (n != -1) { | |
1152 | + if (nfs4ace_change_mask(x, &ace, ace->e_mask | deny)) | |
1153 | + return -1; | |
1154 | + } else { | |
1155 | + /* Insert a eny entry before the trailing EVERYONE@ DENY | |
1156 | + entry. */ | |
1157 | + struct nfs4ace who_copy; | |
1158 | + | |
1159 | + ace = x->acl->a_entries + x->acl->a_count - 1; | |
1160 | + memcpy(&who_copy, who, sizeof(struct nfs4ace)); | |
1161 | + if (nfs4acl_insert_entry(x, &ace)) | |
1162 | + return -1; | |
1163 | + memcpy(ace, &who_copy, sizeof(struct nfs4ace)); | |
1164 | + ace->e_type = ACE4_ACCESS_DENIED_ACE_TYPE; | |
1165 | + nfs4ace_clear_inheritance_flags(ace); | |
1166 | + ace->e_mask = deny; | |
1167 | + } | |
1168 | + return 0; | |
1169 | +} | |
1170 | + | |
1171 | +/** | |
1172 | + * nfs4acl_isolate_group_class - limit the group class to the group file mask | |
1173 | + * @x: acl and number of allocated entries | |
1174 | + * | |
1175 | + * Make sure the group class (all entries except owner@ and everyone@) is | |
1176 | + * granted no more than the group mask by inserting DENY entries for group | |
1177 | + * class entries where necessary. | |
1178 | + */ | |
1179 | +static int | |
1180 | +nfs4acl_isolate_group_class(struct nfs4acl_alloc *x) | |
1181 | +{ | |
1182 | + struct nfs4ace who = { | |
1183 | + .e_flags = ACE4_SPECIAL_WHO, | |
1184 | + .u.e_who = nfs4ace_group_who, | |
1185 | + }; | |
1186 | + struct nfs4ace *ace; | |
1187 | + unsigned int deny; | |
1188 | + | |
1189 | + if (!x->acl->a_count) | |
1190 | + return 0; | |
1191 | + ace = x->acl->a_entries + x->acl->a_count - 1; | |
1192 | + if (nfs4ace_is_inherit_only(ace) || !nfs4ace_is_everyone(ace)) | |
1193 | + return 0; | |
1194 | + deny = ace->e_mask & ~x->acl->a_group_mask; | |
1195 | + | |
1196 | + if (deny) { | |
1197 | + unsigned int n; | |
1198 | + | |
1199 | + if (__nfs4acl_isolate_who(x, &who, deny)) | |
1200 | + return -1; | |
1201 | + | |
1202 | + /* Start from the entry before the trailing EVERYONE@ ALLOW | |
1203 | + entry. We will not hit EVERYONE@ entries in the loop. */ | |
1204 | + for (n = x->acl->a_count - 2; n != -1; n--) { | |
1205 | + ace = x->acl->a_entries + n; | |
1206 | + | |
1207 | + if (nfs4ace_is_inherit_only(ace) || | |
1208 | + nfs4ace_is_owner(ace) || | |
1209 | + nfs4ace_is_group(ace)) | |
1210 | + continue; | |
1211 | + if (__nfs4acl_isolate_who(x, ace, deny)) | |
1212 | + return -1; | |
1213 | + } | |
1214 | + } | |
1215 | + return 0; | |
1216 | +} | |
1217 | + | |
1218 | +/** | |
1219 | + * __nfs4acl_write_through - grant the full masks to owner@, group@, everyone@ | |
1220 | + * | |
1221 | + * Make sure that owner, group@, and everyone@ are allowed the full mask | |
1222 | + * permissions, and not only the permissions granted both by the acl and | |
1223 | + * the masks. | |
1224 | + */ | |
1225 | +static int | |
1226 | +__nfs4acl_write_through(struct nfs4acl_alloc *x) | |
1227 | +{ | |
1228 | + struct nfs4ace *ace; | |
1229 | + unsigned int allowed; | |
1230 | + | |
1231 | + /* Remove all owner@ and group@ ACEs: we re-insert them at the | |
1232 | + top. */ | |
1233 | + nfs4acl_for_each_entry(ace, x->acl) { | |
1234 | + if (nfs4ace_is_inherit_only(ace)) | |
1235 | + continue; | |
1236 | + if ((nfs4ace_is_owner(ace) || nfs4ace_is_group(ace)) && | |
1237 | + nfs4ace_change_mask(x, &ace, 0)) | |
1238 | + return -1; | |
1239 | + } | |
1240 | + | |
1241 | + /* Insert the everyone@ allow entry at the end, or update the | |
1242 | + existing entry. */ | |
1243 | + allowed = x->acl->a_other_mask; | |
1244 | + if (allowed & ~ACE4_POSIX_ALWAYS_ALLOWED) { | |
1245 | + ace = x->acl->a_entries + x->acl->a_count - 1; | |
1246 | + if (x->acl->a_count && nfs4ace_is_everyone(ace) && | |
1247 | + !nfs4ace_is_inherit_only(ace)) { | |
1248 | + if (nfs4ace_change_mask(x, &ace, allowed)) | |
1249 | + return -1; | |
1250 | + } else { | |
1251 | + ace = x->acl->a_entries + x->acl->a_count; | |
1252 | + if (nfs4acl_insert_entry(x, &ace)) | |
1253 | + return -1; | |
1254 | + ace->e_type = ACE4_ACCESS_ALLOWED_ACE_TYPE; | |
1255 | + ace->e_flags = ACE4_SPECIAL_WHO; | |
1256 | + ace->e_mask = allowed; | |
1257 | + ace->u.e_who = nfs4ace_everyone_who; | |
1258 | + } | |
1259 | + } | |
1260 | + | |
1261 | + /* Compute the permissions that owner@ and group@ are already granted | |
1262 | + though the everyone@ allow entry at the end. Note that the acl | |
1263 | + contains no owner@ or group@ entries at this point. */ | |
1264 | + allowed = 0; | |
1265 | + nfs4acl_for_each_entry_reverse(ace, x->acl) { | |
1266 | + if (nfs4ace_is_inherit_only(ace)) | |
1267 | + continue; | |
1268 | + if (nfs4ace_is_allow(ace)) { | |
1269 | + if (nfs4ace_is_everyone(ace)) | |
1270 | + allowed |= ace->e_mask; | |
1271 | + } else if (nfs4ace_is_deny(ace)) | |
1272 | + allowed &= ~ace->e_mask; | |
1273 | + } | |
1274 | + | |
1275 | + /* Insert the appropriate group@ allow entry at the front. */ | |
1276 | + if (x->acl->a_group_mask & ~allowed) { | |
1277 | + ace = x->acl->a_entries; | |
1278 | + if (nfs4acl_insert_entry(x, &ace)) | |
1279 | + return -1; | |
1280 | + ace->e_type = ACE4_ACCESS_ALLOWED_ACE_TYPE; | |
1281 | + ace->e_flags = ACE4_SPECIAL_WHO; | |
1282 | + ace->e_mask = x->acl->a_group_mask /*& ~allowed*/; | |
1283 | + ace->u.e_who = nfs4ace_group_who; | |
1284 | + } | |
1285 | + | |
1286 | + /* Insert the appropriate owner@ allow entry at the front. */ | |
1287 | + if (x->acl->a_owner_mask & ~allowed) { | |
1288 | + ace = x->acl->a_entries; | |
1289 | + if (nfs4acl_insert_entry(x, &ace)) | |
1290 | + return -1; | |
1291 | + ace->e_type = ACE4_ACCESS_ALLOWED_ACE_TYPE; | |
1292 | + ace->e_flags = ACE4_SPECIAL_WHO; | |
1293 | + ace->e_mask = x->acl->a_owner_mask /*& ~allowed*/; | |
1294 | + ace->u.e_who = nfs4ace_owner_who; | |
1295 | + } | |
1296 | + | |
1297 | + /* Insert the appropriate owner@ deny entry at the front. */ | |
1298 | + allowed = nfs4acl_max_allowed(x->acl); | |
1299 | + if (allowed & ~x->acl->a_owner_mask) { | |
1300 | + nfs4acl_for_each_entry(ace, x->acl) { | |
1301 | + if (nfs4ace_is_inherit_only(ace)) | |
1302 | + continue; | |
1303 | + if (nfs4ace_is_allow(ace)) { | |
1304 | + ace = x->acl->a_entries + x->acl->a_count; | |
1305 | + break; | |
1306 | + } | |
1307 | + if (nfs4ace_is_deny(ace) && nfs4ace_is_owner(ace)) | |
1308 | + break; | |
1309 | + } | |
1310 | + if (ace != x->acl->a_entries + x->acl->a_count) { | |
1311 | + if (nfs4ace_change_mask(x, &ace, ace->e_mask | | |
1312 | + (allowed & ~x->acl->a_owner_mask))) | |
1313 | + return -1; | |
1314 | + } else { | |
1315 | + ace = x->acl->a_entries; | |
1316 | + if (nfs4acl_insert_entry(x, &ace)) | |
1317 | + return -1; | |
1318 | + ace->e_type = ACE4_ACCESS_DENIED_ACE_TYPE; | |
1319 | + ace->e_flags = ACE4_SPECIAL_WHO; | |
1320 | + ace->e_mask = allowed & ~x->acl->a_owner_mask; | |
1321 | + ace->u.e_who = nfs4ace_owner_who; | |
1322 | + } | |
1323 | + } | |
1324 | + | |
1325 | + return 0; | |
1326 | +} | |
1327 | + | |
1328 | +/** | |
1329 | + * nfs4acl_apply_masks - apply the masks to the acl | |
1330 | + * | |
1331 | + * Apply the masks so that the acl allows no more flags than the | |
1332 | + * intersection between the flags that the original acl allows and the | |
1333 | + * mask matching the process. | |
1334 | + * | |
1335 | + * Note: this algorithm may push the number of entries in the acl above | |
1336 | + * ACL4_XATTR_MAX_COUNT, so a read-modify-write cycle would fail. | |
1337 | + */ | |
1338 | +int | |
1339 | +nfs4acl_apply_masks(struct nfs4acl **acl) | |
1340 | +{ | |
1341 | + struct nfs4acl_alloc x = { | |
1342 | + .acl = *acl, | |
1343 | + .count = (*acl)->a_count, | |
1344 | + }; | |
1345 | + int retval = 0; | |
1346 | + | |
1347 | + if (nfs4acl_move_everyone_aces_down(&x) || | |
1348 | + nfs4acl_propagate_everyone(&x) || | |
1349 | + __nfs4acl_apply_masks(&x) || | |
1350 | + nfs4acl_isolate_owner_class(&x) || | |
1351 | + nfs4acl_isolate_group_class(&x)) | |
1352 | + retval = -ENOMEM; | |
1353 | + | |
1354 | + *acl = x.acl; | |
1355 | + return retval; | |
1356 | +} | |
1357 | +EXPORT_SYMBOL(nfs4acl_apply_masks); | |
1358 | + | |
1359 | +int nfs4acl_write_through(struct nfs4acl **acl) | |
1360 | +{ | |
1361 | + struct nfs4acl_alloc x = { | |
1362 | + .acl = *acl, | |
1363 | + .count = (*acl)->a_count, | |
1364 | + }; | |
1365 | + int retval = 0; | |
1366 | + | |
1367 | + if (!((*acl)->a_flags & ACL4_WRITE_THROUGH)) | |
1368 | + goto out; | |
1369 | + | |
1370 | + if (nfs4acl_move_everyone_aces_down(&x) || | |
1371 | + nfs4acl_propagate_everyone(&x) || | |
1372 | + __nfs4acl_write_through(&x)) | |
1373 | + retval = -ENOMEM; | |
1374 | + | |
1375 | + *acl = x.acl; | |
1376 | +out: | |
1377 | + return retval; | |
1378 | +} | |
1379 | --- /dev/null | |
1380 | +++ b/fs/nfs4acl_xattr.c | |
1381 | @@ -0,0 +1,146 @@ | |
1382 | +/* | |
1383 | + * Copyright (C) 2006 Andreas Gruenbacher <a.gruenbacher@computer.org> | |
1384 | + * | |
1385 | + * This program is free software; you can redistribute it and/or modify it | |
1386 | + * under the terms of the GNU General Public License as published by the | |
1387 | + * Free Software Foundation; either version 2, or (at your option) any | |
1388 | + * later version. | |
1389 | + * | |
1390 | + * This program is distributed in the hope that it will be useful, but | |
1391 | + * WITHOUT ANY WARRANTY; without even the implied warranty of | |
1392 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
1393 | + * General Public License for more details. | |
1394 | + */ | |
1395 | + | |
1396 | +#include <linux/kernel.h> | |
1397 | +#include <linux/fs.h> | |
1398 | +#include <linux/slab.h> | |
1399 | +#include <linux/module.h> | |
1400 | +#include <linux/nfs4acl_xattr.h> | |
1401 | + | |
1402 | +MODULE_LICENSE("GPL"); | |
1403 | + | |
1404 | +struct nfs4acl * | |
1405 | +nfs4acl_from_xattr(const void *value, size_t size) | |
1406 | +{ | |
1407 | + const struct nfs4acl_xattr *xattr_acl = value; | |
1408 | + const struct nfs4ace_xattr *xattr_ace = (void *)(xattr_acl + 1); | |
1409 | + struct nfs4acl *acl; | |
1410 | + struct nfs4ace *ace; | |
1411 | + int count; | |
1412 | + | |
1413 | + if (size < sizeof(struct nfs4acl_xattr) || | |
1414 | + xattr_acl->a_version != ACL4_XATTR_VERSION || | |
1415 | + (xattr_acl->a_flags & ~ACL4_VALID_FLAGS)) | |
1416 | + return ERR_PTR(-EINVAL); | |
1417 | + | |
1418 | + count = be16_to_cpu(xattr_acl->a_count); | |
1419 | + if (count > ACL4_XATTR_MAX_COUNT) | |
1420 | + return ERR_PTR(-EINVAL); | |
1421 | + | |
1422 | + acl = nfs4acl_alloc(count); | |
1423 | + if (!acl) | |
1424 | + return ERR_PTR(-ENOMEM); | |
1425 | + | |
1426 | + acl->a_flags = xattr_acl->a_flags; | |
1427 | + acl->a_owner_mask = be32_to_cpu(xattr_acl->a_owner_mask); | |
1428 | + if (acl->a_owner_mask & ~ACE4_VALID_MASK) | |
1429 | + goto fail_einval; | |
1430 | + acl->a_group_mask = be32_to_cpu(xattr_acl->a_group_mask); | |
1431 | + if (acl->a_group_mask & ~ACE4_VALID_MASK) | |
1432 | + goto fail_einval; | |
1433 | + acl->a_other_mask = be32_to_cpu(xattr_acl->a_other_mask); | |
1434 | + if (acl->a_other_mask & ~ACE4_VALID_MASK) | |
1435 | + goto fail_einval; | |
1436 | + | |
1437 | + nfs4acl_for_each_entry(ace, acl) { | |
1438 | + const char *who = (void *)(xattr_ace + 1), *end; | |
1439 | + ssize_t used = (void *)who - value; | |
1440 | + | |
1441 | + if (used > size) | |
1442 | + goto fail_einval; | |
1443 | + end = memchr(who, 0, size - used); | |
1444 | + if (!end) | |
1445 | + goto fail_einval; | |
1446 | + | |
1447 | + ace->e_type = be16_to_cpu(xattr_ace->e_type); | |
1448 | + ace->e_flags = be16_to_cpu(xattr_ace->e_flags); | |
1449 | + ace->e_mask = be32_to_cpu(xattr_ace->e_mask); | |
1450 | + ace->u.e_id = be32_to_cpu(xattr_ace->e_id); | |
1451 | + | |
1452 | + if (ace->e_flags & ~ACE4_VALID_FLAGS) { | |
1453 | + memset(ace, 0, sizeof(struct nfs4ace)); | |
1454 | + goto fail_einval; | |
1455 | + } | |
1456 | + if (ace->e_type > ACE4_ACCESS_DENIED_ACE_TYPE || | |
1457 | + (ace->e_mask & ~ACE4_VALID_MASK)) | |
1458 | + goto fail_einval; | |
1459 | + | |
1460 | + if (who == end) { | |
1461 | + if (ace->u.e_id == -1) | |
1462 | + goto fail_einval; /* uid/gid needed */ | |
1463 | + } else if (nfs4ace_set_who(ace, who)) | |
1464 | + goto fail_einval; | |
1465 | + | |
1466 | + xattr_ace = (void *)who + ALIGN(end - who + 1, 4); | |
1467 | + } | |
1468 | + | |
1469 | + return acl; | |
1470 | + | |
1471 | +fail_einval: | |
1472 | + nfs4acl_put(acl); | |
1473 | + return ERR_PTR(-EINVAL); | |
1474 | +} | |
1475 | +EXPORT_SYMBOL(nfs4acl_from_xattr); | |
1476 | + | |
1477 | +size_t | |
1478 | +nfs4acl_xattr_size(const struct nfs4acl *acl) | |
1479 | +{ | |
1480 | + size_t size = sizeof(struct nfs4acl_xattr); | |
1481 | + const struct nfs4ace *ace; | |
1482 | + | |
1483 | + nfs4acl_for_each_entry(ace, acl) { | |
1484 | + size += sizeof(struct nfs4ace_xattr) + | |
1485 | + (nfs4ace_is_unix_id(ace) ? 4 : | |
1486 | + ALIGN(strlen(ace->u.e_who) + 1, 4)); | |
1487 | + } | |
1488 | + return size; | |
1489 | +} | |
1490 | +EXPORT_SYMBOL(nfs4acl_xattr_size); | |
1491 | + | |
1492 | +void | |
1493 | +nfs4acl_to_xattr(const struct nfs4acl *acl, void *buffer) | |
1494 | +{ | |
1495 | + struct nfs4acl_xattr *xattr_acl = buffer; | |
1496 | + struct nfs4ace_xattr *xattr_ace; | |
1497 | + const struct nfs4ace *ace; | |
1498 | + | |
1499 | + xattr_acl->a_version = ACL4_XATTR_VERSION; | |
1500 | + xattr_acl->a_flags = acl->a_flags; | |
1501 | + xattr_acl->a_count = cpu_to_be16(acl->a_count); | |
1502 | + | |
1503 | + xattr_acl->a_owner_mask = cpu_to_be32(acl->a_owner_mask); | |
1504 | + xattr_acl->a_group_mask = cpu_to_be32(acl->a_group_mask); | |
1505 | + xattr_acl->a_other_mask = cpu_to_be32(acl->a_other_mask); | |
1506 | + | |
1507 | + xattr_ace = (void *)(xattr_acl + 1); | |
1508 | + nfs4acl_for_each_entry(ace, acl) { | |
1509 | + xattr_ace->e_type = cpu_to_be16(ace->e_type); | |
1510 | + xattr_ace->e_flags = cpu_to_be16(ace->e_flags & | |
1511 | + ACE4_VALID_FLAGS); | |
1512 | + xattr_ace->e_mask = cpu_to_be32(ace->e_mask); | |
1513 | + if (nfs4ace_is_unix_id(ace)) { | |
1514 | + xattr_ace->e_id = cpu_to_be32(ace->u.e_id); | |
1515 | + memset(xattr_ace->e_who, 0, 4); | |
1516 | + xattr_ace = (void *)xattr_ace->e_who + 4; | |
1517 | + } else { | |
1518 | + int sz = ALIGN(strlen(ace->u.e_who) + 1, 4); | |
1519 | + | |
1520 | + xattr_ace->e_id = cpu_to_be32(-1); | |
1521 | + memset(xattr_ace->e_who + sz - 4, 0, 4); | |
1522 | + strcpy(xattr_ace->e_who, ace->u.e_who); | |
1523 | + xattr_ace = (void *)xattr_ace->e_who + sz; | |
1524 | + } | |
1525 | + } | |
1526 | +} | |
1527 | +EXPORT_SYMBOL(nfs4acl_to_xattr); | |
1528 | --- /dev/null | |
1529 | +++ b/include/linux/nfs4acl.h | |
1530 | @@ -0,0 +1,205 @@ | |
1531 | +#ifndef __NFS4ACL_H | |
1532 | +#define __NFS4ACL_H | |
1533 | + | |
1534 | +struct nfs4ace { | |
1535 | + unsigned short e_type; | |
1536 | + unsigned short e_flags; | |
1537 | + unsigned int e_mask; | |
1538 | + union { | |
1539 | + unsigned int e_id; | |
1540 | + const char *e_who; | |
1541 | + } u; | |
1542 | +}; | |
1543 | + | |
1544 | +struct nfs4acl { | |
1545 | + atomic_t a_refcount; | |
1546 | + unsigned int a_owner_mask; | |
1547 | + unsigned int a_group_mask; | |
1548 | + unsigned int a_other_mask; | |
1549 | + unsigned short a_count; | |
1550 | + unsigned short a_flags; | |
1551 | + struct nfs4ace a_entries[0]; | |
1552 | +}; | |
1553 | + | |
1554 | +#define nfs4acl_for_each_entry(_ace, _acl) \ | |
1555 | + for (_ace = _acl->a_entries; \ | |
1556 | + _ace != _acl->a_entries + _acl->a_count; \ | |
1557 | + _ace++) | |
1558 | + | |
1559 | +#define nfs4acl_for_each_entry_reverse(_ace, _acl) \ | |
1560 | + for (_ace = _acl->a_entries + _acl->a_count - 1; \ | |
1561 | + _ace != _acl->a_entries - 1; \ | |
1562 | + _ace--) | |
1563 | + | |
1564 | +/* a_flags values */ | |
1565 | +#define ACL4_WRITE_THROUGH 0x40 | |
1566 | + | |
1567 | +#define ACL4_VALID_FLAGS \ | |
1568 | + ACL4_WRITE_THROUGH | |
1569 | + | |
1570 | +/* e_type values */ | |
1571 | +#define ACE4_ACCESS_ALLOWED_ACE_TYPE 0x0000 | |
1572 | +#define ACE4_ACCESS_DENIED_ACE_TYPE 0x0001 | |
1573 | +/*#define ACE4_SYSTEM_AUDIT_ACE_TYPE 0x0002*/ | |
1574 | +/*#define ACE4_SYSTEM_ALARM_ACE_TYPE 0x0003*/ | |
1575 | + | |
1576 | +/* e_flags bitflags */ | |
1577 | +#define ACE4_FILE_INHERIT_ACE 0x0001 | |
1578 | +#define ACE4_DIRECTORY_INHERIT_ACE 0x0002 | |
1579 | +#define ACE4_NO_PROPAGATE_INHERIT_ACE 0x0004 | |
1580 | +#define ACE4_INHERIT_ONLY_ACE 0x0008 | |
1581 | +/*#define ACE4_SUCCESSFUL_ACCESS_ACE_FLAG 0x0010*/ | |
1582 | +/*#define ACE4_FAILED_ACCESS_ACE_FLAG 0x0020*/ | |
1583 | +#define ACE4_IDENTIFIER_GROUP 0x0040 | |
1584 | +#define ACE4_SPECIAL_WHO 0x4000 /* in-memory representation only */ | |
1585 | + | |
1586 | +#define ACE4_VALID_FLAGS ( \ | |
1587 | + ACE4_FILE_INHERIT_ACE | \ | |
1588 | + ACE4_DIRECTORY_INHERIT_ACE | \ | |
1589 | + ACE4_NO_PROPAGATE_INHERIT_ACE | \ | |
1590 | + ACE4_INHERIT_ONLY_ACE | \ | |
1591 | + ACE4_IDENTIFIER_GROUP ) | |
1592 | + | |
1593 | +/* e_mask bitflags */ | |
1594 | +#define ACE4_READ_DATA 0x00000001 | |
1595 | +#define ACE4_LIST_DIRECTORY 0x00000001 | |
1596 | +#define ACE4_WRITE_DATA 0x00000002 | |
1597 | +#define ACE4_ADD_FILE 0x00000002 | |
1598 | +#define ACE4_APPEND_DATA 0x00000004 | |
1599 | +#define ACE4_ADD_SUBDIRECTORY 0x00000004 | |
1600 | +#define ACE4_READ_NAMED_ATTRS 0x00000008 | |
1601 | +#define ACE4_WRITE_NAMED_ATTRS 0x00000010 | |
1602 | +#define ACE4_EXECUTE 0x00000020 | |
1603 | +#define ACE4_DELETE_CHILD 0x00000040 | |
1604 | +#define ACE4_READ_ATTRIBUTES 0x00000080 | |
1605 | +#define ACE4_WRITE_ATTRIBUTES 0x00000100 | |
1606 | +#define ACE4_DELETE 0x00010000 | |
1607 | +#define ACE4_READ_ACL 0x00020000 | |
1608 | +#define ACE4_WRITE_ACL 0x00040000 | |
1609 | +#define ACE4_WRITE_OWNER 0x00080000 | |
1610 | +#define ACE4_SYNCHRONIZE 0x00100000 | |
1611 | + | |
1612 | +#define ACE4_VALID_MASK ( \ | |
1613 | + ACE4_READ_DATA | ACE4_LIST_DIRECTORY | \ | |
1614 | + ACE4_WRITE_DATA | ACE4_ADD_FILE | \ | |
1615 | + ACE4_APPEND_DATA | ACE4_ADD_SUBDIRECTORY | \ | |
1616 | + ACE4_READ_NAMED_ATTRS | \ | |
1617 | + ACE4_WRITE_NAMED_ATTRS | \ | |
1618 | + ACE4_EXECUTE | \ | |
1619 | + ACE4_DELETE_CHILD | \ | |
1620 | + ACE4_READ_ATTRIBUTES | \ | |
1621 | + ACE4_WRITE_ATTRIBUTES | \ | |
1622 | + ACE4_DELETE | \ | |
1623 | + ACE4_READ_ACL | \ | |
1624 | + ACE4_WRITE_ACL | \ | |
1625 | + ACE4_WRITE_OWNER | \ | |
1626 | + ACE4_SYNCHRONIZE ) | |
1627 | + | |
1628 | +#define ACE4_POSIX_ALWAYS_ALLOWED ( \ | |
1629 | + ACE4_SYNCHRONIZE | \ | |
1630 | + ACE4_READ_ATTRIBUTES | \ | |
1631 | + ACE4_READ_ACL ) | |
1632 | +/* | |
1633 | + * Duplicate an NFS4ACL handle. | |
1634 | + */ | |
1635 | +static inline struct nfs4acl * | |
1636 | +nfs4acl_get(struct nfs4acl *acl) | |
1637 | +{ | |
1638 | + if (acl) | |
1639 | + atomic_inc(&acl->a_refcount); | |
1640 | + return acl; | |
1641 | +} | |
1642 | + | |
1643 | +/* | |
1644 | + * Free an NFS4ACL handle | |
1645 | + */ | |
1646 | +static inline void | |
1647 | +nfs4acl_put(struct nfs4acl *acl) | |
1648 | +{ | |
1649 | + if (acl && atomic_dec_and_test(&acl->a_refcount)) | |
1650 | + kfree(acl); | |
1651 | +} | |
1652 | + | |
1653 | +/* Special e_who identifiers: we use these pointer values in comparisons | |
1654 | + instead of strcmp for efficiency. */ | |
1655 | + | |
1656 | +extern const char nfs4ace_owner_who[]; | |
1657 | +extern const char nfs4ace_group_who[]; | |
1658 | +extern const char nfs4ace_everyone_who[]; | |
1659 | + | |
1660 | +static inline int | |
1661 | +nfs4ace_is_owner(const struct nfs4ace *ace) | |
1662 | +{ | |
1663 | + return (ace->e_flags & ACE4_SPECIAL_WHO) && | |
1664 | + ace->u.e_who == nfs4ace_owner_who; | |
1665 | +} | |
1666 | + | |
1667 | +static inline int | |
1668 | +nfs4ace_is_group(const struct nfs4ace *ace) | |
1669 | +{ | |
1670 | + return (ace->e_flags & ACE4_SPECIAL_WHO) && | |
1671 | + ace->u.e_who == nfs4ace_group_who; | |
1672 | +} | |
1673 | + | |
1674 | +static inline int | |
1675 | +nfs4ace_is_everyone(const struct nfs4ace *ace) | |
1676 | +{ | |
1677 | + return (ace->e_flags & ACE4_SPECIAL_WHO) && | |
1678 | + ace->u.e_who == nfs4ace_everyone_who; | |
1679 | +} | |
1680 | + | |
1681 | +static inline int | |
1682 | +nfs4ace_is_unix_id(const struct nfs4ace *ace) | |
1683 | +{ | |
1684 | + return !(ace->e_flags & ACE4_SPECIAL_WHO); | |
1685 | +} | |
1686 | + | |
1687 | +static inline int | |
1688 | +nfs4ace_is_inherit_only(const struct nfs4ace *ace) | |
1689 | +{ | |
1690 | + return ace->e_flags & ACE4_INHERIT_ONLY_ACE; | |
1691 | +} | |
1692 | + | |
1693 | +static inline int | |
1694 | +nfs4ace_is_inheritable(const struct nfs4ace *ace) | |
1695 | +{ | |
1696 | + return ace->e_flags & (ACE4_FILE_INHERIT_ACE | | |
1697 | + ACE4_DIRECTORY_INHERIT_ACE); | |
1698 | +} | |
1699 | + | |
1700 | +static inline void | |
1701 | +nfs4ace_clear_inheritance_flags(struct nfs4ace *ace) | |
1702 | +{ | |
1703 | + ace->e_flags &= ~(ACE4_FILE_INHERIT_ACE | | |
1704 | + ACE4_DIRECTORY_INHERIT_ACE | | |
1705 | + ACE4_NO_PROPAGATE_INHERIT_ACE | | |
1706 | + ACE4_INHERIT_ONLY_ACE); | |
1707 | +} | |
1708 | + | |
1709 | +static inline int | |
1710 | +nfs4ace_is_allow(const struct nfs4ace *ace) | |
1711 | +{ | |
1712 | + return ace->e_type == ACE4_ACCESS_ALLOWED_ACE_TYPE; | |
1713 | +} | |
1714 | + | |
1715 | +static inline int | |
1716 | +nfs4ace_is_deny(const struct nfs4ace *ace) | |
1717 | +{ | |
1718 | + return ace->e_type == ACE4_ACCESS_DENIED_ACE_TYPE; | |
1719 | +} | |
1720 | + | |
1721 | +extern struct nfs4acl *nfs4acl_alloc(int count); | |
1722 | +extern struct nfs4acl *nfs4acl_clone(const struct nfs4acl *acl); | |
1723 | + | |
1724 | +extern unsigned int nfs4acl_want_to_mask(int want); | |
1725 | +extern int nfs4acl_permission(struct inode *, const struct nfs4acl *, unsigned int); | |
1726 | +extern int nfs4acl_generic_permission(struct inode *, unsigned int); | |
1727 | +extern int nfs4ace_is_same_who(const struct nfs4ace *, const struct nfs4ace *); | |
1728 | +extern int nfs4ace_set_who(struct nfs4ace *ace, const char *who); | |
1729 | +extern struct nfs4acl *nfs4acl_inherit(const struct nfs4acl *, mode_t); | |
1730 | +extern int nfs4acl_masks_to_mode(const struct nfs4acl *); | |
1731 | +extern struct nfs4acl *nfs4acl_chmod(struct nfs4acl *, mode_t); | |
1732 | +extern int nfs4acl_apply_masks(struct nfs4acl **acl); | |
1733 | +extern int nfs4acl_write_through(struct nfs4acl **acl); | |
1734 | + | |
1735 | +#endif /* __NFS4ACL_H */ | |
1736 | --- /dev/null | |
1737 | +++ b/include/linux/nfs4acl_xattr.h | |
1738 | @@ -0,0 +1,32 @@ | |
1739 | +#ifndef __NFS4ACL_XATTR_H | |
1740 | +#define __NFS4ACL_XATTR_H | |
1741 | + | |
1742 | +#include <linux/nfs4acl.h> | |
1743 | + | |
1744 | +#define NFS4ACL_XATTR "system.nfs4acl" | |
1745 | + | |
1746 | +struct nfs4ace_xattr { | |
1747 | + __be16 e_type; | |
1748 | + __be16 e_flags; | |
1749 | + __be32 e_mask; | |
1750 | + __be32 e_id; | |
1751 | + char e_who[0]; | |
1752 | +}; | |
1753 | + | |
1754 | +struct nfs4acl_xattr { | |
1755 | + unsigned char a_version; | |
1756 | + unsigned char a_flags; | |
1757 | + __be16 a_count; | |
1758 | + __be32 a_owner_mask; | |
1759 | + __be32 a_group_mask; | |
1760 | + __be32 a_other_mask; | |
1761 | +}; | |
1762 | + | |
1763 | +#define ACL4_XATTR_VERSION 0 | |
1764 | +#define ACL4_XATTR_MAX_COUNT 1024 | |
1765 | + | |
1766 | +extern struct nfs4acl *nfs4acl_from_xattr(const void *, size_t); | |
1767 | +extern size_t nfs4acl_xattr_size(const struct nfs4acl *acl); | |
1768 | +extern void nfs4acl_to_xattr(const struct nfs4acl *, void *); | |
1769 | + | |
1770 | +#endif /* __NFS4ACL_XATTR_H */ |