]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - src/patches/suse-2.6.27.25/patches.suse/nfs4acl-common.diff
Added missing SuSE-Xen-Patches.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.25 / patches.suse / nfs4acl-common.diff
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 */