1 From: Andreas Gruenbacher <agruen@suse.de>
2 Subject: NFSv4 ACL in-memory representation and manipulation
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
8 * Compute a mask-less acl from struct nfs4acl that grants the same
9 permissions. Protocols which don't understand the masks need
11 * Convert to/from xattrs.
13 Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
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(+)
27 @@ -419,6 +419,10 @@ config FS_POSIX_ACL
35 source "fs/xfs/Kconfig"
36 source "fs/gfs2/Kconfig"
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
44 +obj-$(CONFIG_FS_NFS4ACL) += nfs4acl.o
45 +nfs4acl-y := nfs4acl_base.o nfs4acl_xattr.o \
48 obj-$(CONFIG_QUOTA) += dquot.o
49 obj-$(CONFIG_QFMT_V1) += quota_v1.o
50 obj-$(CONFIG_QFMT_V2) += quota_v2.o
52 +++ b/fs/nfs4acl_base.c
55 + * Copyright (C) 2006 Andreas Gruenbacher <a.gruenbacher@computer.org>
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
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.
68 +#include <linux/sched.h>
69 +#include <linux/module.h>
70 +#include <linux/fs.h>
71 +#include <linux/nfs4acl.h>
73 +MODULE_LICENSE("GPL");
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.
81 +const char nfs4ace_owner_who[] = "OWNER@";
82 +const char nfs4ace_group_who[] = "GROUP@";
83 +const char nfs4ace_everyone_who[] = "EVERYONE@";
85 +EXPORT_SYMBOL(nfs4ace_owner_who);
86 +EXPORT_SYMBOL(nfs4ace_group_who);
87 +EXPORT_SYMBOL(nfs4ace_everyone_who);
90 + * nfs4acl_alloc - allocate an acl
91 + * @count: number of entries
94 +nfs4acl_alloc(int count)
96 + size_t size = sizeof(struct nfs4acl) + count * sizeof(struct nfs4ace);
97 + struct nfs4acl *acl = kmalloc(size, GFP_KERNEL);
100 + memset(acl, 0, size);
101 + atomic_set(&acl->a_refcount, 1);
102 + acl->a_count = count;
106 +EXPORT_SYMBOL(nfs4acl_alloc);
109 + * nfs4acl_clone - create a copy of an acl
112 +nfs4acl_clone(const struct nfs4acl *acl)
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);
119 + memcpy(dup, acl, size);
120 + atomic_set(&dup->a_refcount, 1);
126 + * The POSIX permissions are supersets of the below mask flags.
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.
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 ( \
143 +nfs4acl_mask_to_mode(unsigned int mask)
147 + if (mask & ACE4_POSIX_MODE_READ)
149 + if (mask & ACE4_POSIX_MODE_WRITE)
151 + if (mask & ACE4_POSIX_MODE_EXEC)
158 + * nfs4acl_masks_to_mode - compute file mode permission bits from file masks
160 + * Compute the file mode permission bits from the file masks in the acl.
163 +nfs4acl_masks_to_mode(const struct nfs4acl *acl)
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);
169 +EXPORT_SYMBOL(nfs4acl_masks_to_mode);
172 +nfs4acl_mode_to_mask(mode_t mode)
174 + unsigned int mask = ACE4_POSIX_ALWAYS_ALLOWED;
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;
187 + * nfs4acl_chmod - update the file masks to reflect the new mode
188 + * @mode: file mode permission bits to apply to the @acl
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
196 +nfs4acl_chmod(struct nfs4acl *acl, mode_t mode)
198 + unsigned int owner_mask, group_mask, other_mask;
199 + struct nfs4acl *clone;
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);
205 + if (acl->a_owner_mask == owner_mask &&
206 + acl->a_group_mask == group_mask &&
207 + acl->a_other_mask == other_mask)
210 + clone = nfs4acl_clone(acl);
213 + return ERR_PTR(-ENOMEM);
215 + clone->a_owner_mask = owner_mask;
216 + clone->a_group_mask = group_mask;
217 + clone->a_other_mask = other_mask;
219 + if (nfs4acl_write_through(&clone)) {
220 + nfs4acl_put(clone);
221 + clone = ERR_PTR(-ENOMEM);
225 +EXPORT_SYMBOL(nfs4acl_chmod);
228 + * nfs4acl_want_to_mask - convert permission want argument to a mask
229 + * @want: @want argument of the permission inode operation
231 + * When checking for append, @want is (MAY_WRITE | MAY_APPEND).
234 +nfs4acl_want_to_mask(int want)
236 + unsigned int mask = 0;
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;
249 +EXPORT_SYMBOL(nfs4acl_want_to_mask);
252 + * nfs4acl_capability_check - check for capabilities overriding read/write access
253 + * @inode: inode to check
254 + * @mask: requested access (ACE4_* bitmask)
256 + * Capabilities other than CAP_DAC_OVERRIDE and CAP_DAC_READ_SEARCH must be checked
259 +static inline int nfs4acl_capability_check(struct inode *inode, unsigned int mask)
262 + * Read/write DACs are always overridable.
263 + * Executable DACs are overridable if at least one exec bit is set.
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))
272 + * Searching includes executable on directories, else just read.
274 + if (!(mask & ~(ACE4_READ_DATA | ACE4_EXECUTE)) &&
275 + (S_ISDIR(inode->i_mode) || !(mask & ACE4_EXECUTE)))
276 + if (capable(CAP_DAC_READ_SEARCH))
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)
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
295 +int nfs4acl_permission(struct inode *inode, const struct nfs4acl *acl,
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;
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.
311 + nfs4acl_for_each_entry(ace, acl) {
312 + unsigned int ace_mask = ace->e_mask;
314 + if (nfs4ace_is_inherit_only(ace))
316 + if (nfs4ace_is_owner(ace)) {
317 + if (current->fsuid != inode->i_uid)
320 + } else if (nfs4ace_is_group(ace)) {
321 + if (!in_owning_group)
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))
328 + if (current->fsuid != ace->u.e_id)
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().
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
345 + if (nfs4ace_is_allow(ace))
346 + ace_mask &= acl->a_group_mask;
349 + /* The process is in the owner or group file class. */
350 + owner_or_group_class = 1;
353 + /* Check which mask flags the ACE allows or denies. */
354 + if (nfs4ace_is_deny(ace))
355 + denied |= ace_mask & mask;
358 + /* Keep going until we know which file class the process is in. */
359 + if (!mask && owner_or_group_class)
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.
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;
374 + file_mask = acl->a_other_mask;
376 + denied |= requested & ~file_mask;
379 + return nfs4acl_capability_check(inode, requested);
381 +EXPORT_SYMBOL(nfs4acl_permission);
384 + * nfs4acl_generic_permission - permission check algorithm without explicit acl
385 + * @inode: inode to check permissions for
386 + * @mask: requested access (ACE4_* bitmask)
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
394 +int nfs4acl_generic_permission(struct inode *inode, unsigned int mask)
396 + int mode = inode->i_mode;
398 + if (current->fsuid == inode->i_uid)
400 + else if (in_group_p(inode->i_gid))
402 + if (!(mask & ~nfs4acl_mode_to_mask(mode)))
404 + return nfs4acl_capability_check(inode, mask);
406 +EXPORT_SYMBOL(nfs4acl_generic_permission);
409 + * nfs4ace_is_same_who - do both acl entries refer to the same identifier?
412 +nfs4ace_is_same_who(const struct nfs4ace *a, const struct nfs4ace *b)
414 +#define WHO_FLAGS (ACE4_SPECIAL_WHO | ACE4_IDENTIFIER_GROUP)
415 + if ((a->e_flags & WHO_FLAGS) != (b->e_flags & WHO_FLAGS))
417 + if (a->e_flags & ACE4_SPECIAL_WHO)
418 + return a->u.e_who == b->u.e_who;
420 + return a->u.e_id == b->u.e_id;
425 + * nfs4acl_set_who - set a special who value
427 + * @who: who value to use
430 +nfs4ace_set_who(struct nfs4ace *ace, const char *who)
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;
441 + ace->u.e_who = who;
442 + ace->e_flags |= ACE4_SPECIAL_WHO;
443 + ace->e_flags &= ~ACE4_IDENTIFIER_GROUP;
446 +EXPORT_SYMBOL(nfs4ace_set_who);
449 + * nfs4acl_allowed_to_who - mask flags allowed to a specific who value
451 + * Computes the mask values allowed to a specific who value, taking
452 + * EVERYONE@ entries into account.
455 +nfs4acl_allowed_to_who(struct nfs4acl *acl, struct nfs4ace *who)
457 + struct nfs4ace *ace;
458 + unsigned int allowed = 0;
460 + nfs4acl_for_each_entry_reverse(ace, acl) {
461 + if (nfs4ace_is_inherit_only(ace))
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;
475 + * nfs4acl_compute_max_masks - compute upper bound masks
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).
482 +nfs4acl_compute_max_masks(struct nfs4acl *acl)
484 + struct nfs4ace *ace;
486 + acl->a_owner_mask = 0;
487 + acl->a_group_mask = 0;
488 + acl->a_other_mask = 0;
490 + nfs4acl_for_each_entry_reverse(ace, acl) {
491 + if (nfs4ace_is_inherit_only(ace))
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,
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;
516 + if (nfs4ace_is_allow(ace)) {
517 + unsigned int mask =
518 + nfs4acl_allowed_to_who(acl, ace);
520 + acl->a_group_mask |= mask;
521 + acl->a_owner_mask |= mask;
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
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.
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.
542 +nfs4acl_inherit(const struct nfs4acl *dir_acl, mode_t mode)
544 + const struct nfs4ace *dir_ace;
545 + struct nfs4acl *acl;
546 + struct nfs4ace *ace;
549 + if (S_ISDIR(mode)) {
550 + nfs4acl_for_each_entry(dir_ace, dir_acl) {
551 + if (!nfs4ace_is_inheritable(dir_ace))
557 + acl = nfs4acl_alloc(count);
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))
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;
573 + nfs4acl_for_each_entry(dir_ace, dir_acl) {
574 + if (!(dir_ace->e_flags & ACE4_FILE_INHERIT_ACE))
580 + acl = nfs4acl_alloc(count);
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))
587 + memcpy(ace, dir_ace, sizeof(struct nfs4ace));
588 + nfs4ace_clear_inheritance_flags(ace);
593 + /* The maximum max flags that the owner, group, and other classes
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;
600 + mode &= ~current->fs->umask;
602 + nfs4acl_compute_max_masks(acl);
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);
609 + if (nfs4acl_write_through(&acl)) {
611 + return ERR_PTR(-ENOMEM);
614 + acl->a_flags = (dir_acl->a_flags & ACL4_WRITE_THROUGH);
618 +EXPORT_SYMBOL(nfs4acl_inherit);
620 +++ b/fs/nfs4acl_compat.c
623 + * Copyright (C) 2006 Andreas Gruenbacher <a.gruenbacher@computer.org>
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
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.
636 +#include <linux/module.h>
637 +#include <linux/fs.h>
638 +#include <linux/nfs4acl.h>
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
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.
649 +struct nfs4acl_alloc {
650 + struct nfs4acl *acl;
651 + unsigned int count;
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
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
666 +nfs4acl_delete_entry(struct nfs4acl_alloc *x, struct nfs4ace **ace)
668 + void *end = x->acl->a_entries + x->acl->a_count;
670 + memmove(*ace, *ace + 1, end - (void *)(*ace + 1));
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
680 + * Insert a new entry in @x->acl at position @ace, and zero-initialize
681 + * it. This may require reallocating @x->acl.
684 +nfs4acl_insert_entry(struct nfs4acl_alloc *x, struct nfs4ace **ace)
686 + if (x->count == x->acl->a_count) {
687 + int n = *ace - x->acl->a_entries;
688 + struct nfs4acl *acl2;
690 + acl2 = nfs4acl_alloc(x->acl->a_count + 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));
703 + x->count = acl2->a_count;
704 + *ace = acl2->a_entries + n;
706 + void *end = x->acl->a_entries + x->acl->a_count;
708 + memmove(*ace + 1, *ace, end - (void *)*ace);
711 + memset(*ace, 0, sizeof(struct nfs4ace));
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
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.
733 +nfs4ace_change_mask(struct nfs4acl_alloc *x, struct nfs4ace **ace,
736 + if (mask && (*ace)->e_mask == mask)
738 + if (mask & ~ACE4_POSIX_ALWAYS_ALLOWED) {
739 + if (nfs4ace_is_inheritable(*ace)) {
740 + if (nfs4acl_insert_entry(x, ace))
742 + memcpy(*ace, *ace + 1, sizeof(struct nfs4ace));
743 + (*ace)->e_flags |= ACE4_INHERIT_ONLY_ACE;
745 + nfs4ace_clear_inheritance_flags(*ace);
747 + (*ace)->e_mask = mask;
749 + if (nfs4ace_is_inheritable(*ace))
750 + (*ace)->e_flags |= ACE4_INHERIT_ONLY_ACE;
752 + nfs4acl_delete_entry(x, ace);
758 + * nfs4acl_move_everyone_aces_down - move everyone@ acl entries to the end
759 + * @x: acl and number of allocated entries
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.
766 + * This transformation does not modify the permissions that the acl
767 + * grants, but we need it to simplify successive transformations.
770 +nfs4acl_move_everyone_aces_down(struct nfs4acl_alloc *x)
772 + struct nfs4ace *ace;
773 + unsigned int allowed = 0, denied = 0;
775 + nfs4acl_for_each_entry(ace, x->acl) {
776 + if (nfs4ace_is_inherit_only(ace))
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);
785 + if (nfs4ace_change_mask(x, &ace, 0))
788 + if (nfs4ace_is_allow(ace)) {
789 + if (nfs4ace_change_mask(x, &ace, allowed |
790 + (ace->e_mask & ~denied)))
792 + } else if (nfs4ace_is_deny(ace)) {
793 + if (nfs4ace_change_mask(x, &ace, denied |
794 + (ace->e_mask & ~allowed)))
799 + if (allowed & ~ACE4_POSIX_ALWAYS_ALLOWED) {
800 + struct nfs4ace *last_ace = ace - 1;
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;
808 + if (nfs4acl_insert_entry(x, &ace))
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;
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
825 + * Propagate mask flags from the trailing everyone@ allow acl entry up
826 + * for the specified @who.
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.
837 +__nfs4acl_propagate_everyone(struct nfs4acl_alloc *x, struct nfs4ace *who,
838 + unsigned int allow)
840 + struct nfs4ace *allow_last = NULL, *ace;
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@
846 + nfs4acl_for_each_entry(ace, x->acl) {
847 + if (nfs4ace_is_inherit_only(ace))
849 + if (nfs4ace_is_allow(ace)) {
850 + if (nfs4ace_is_same_who(ace, who)) {
851 + allow &= ~ace->e_mask;
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)
864 + return nfs4ace_change_mask(x, &allow_last,
865 + allow_last->e_mask | allow);
867 + struct nfs4ace who_copy;
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))
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;
883 + * nfs4acl_propagate_everyone - propagate everyone@ mask flags up the acl
884 + * @x: acl and number of allocated entries
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
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
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
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,
914 + * masking after propagation (correct)
915 + * ===========================================================
916 + * joe:r::allow => joe:rw::allow
919 + * everyone@:rwx::allow everyone@:r::allow
920 + * -----------------------------------------------------------
921 + * joe:w::deny => owner@:x::deny
926 + * everyone@:rwx::allow everyone@:r::allow
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.
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.
938 +nfs4acl_propagate_everyone(struct nfs4acl_alloc *x)
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;
946 + if (!((x->acl->a_owner_mask | x->acl->a_group_mask) &
947 + ~x->acl->a_other_mask))
949 + if (!x->acl->a_count)
951 + ace = x->acl->a_entries + x->acl->a_count - 1;
952 + if (nfs4ace_is_inherit_only(ace) || !nfs4ace_is_everyone(ace))
954 + if (!(ace->e_mask & ~x->acl->a_other_mask)) {
955 + /* None of the allowed permissions will get masked. */
958 + owner_allow = ace->e_mask & x->acl->a_owner_mask;
959 + group_allow = ace->e_mask & x->acl->a_group_mask;
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);
970 + if (group_allow && (x->acl->a_group_mask & ~x->acl->a_other_mask)) {
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,
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;
987 + if (nfs4ace_is_inherit_only(ace) ||
988 + nfs4ace_is_owner(ace) ||
989 + nfs4ace_is_group(ace))
991 + if (nfs4ace_is_allow(ace) || nfs4ace_is_deny(ace)) {
992 + /* Any inserted entry will end up below the
994 + retval = __nfs4acl_propagate_everyone(x, ace,
1005 + * __nfs4acl_apply_masks - apply the masks to the acl entries
1006 + * @x: acl and number of allocated entries
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.
1013 +__nfs4acl_apply_masks(struct nfs4acl_alloc *x)
1015 + struct nfs4ace *ace;
1017 + nfs4acl_for_each_entry(ace, x->acl) {
1018 + unsigned int mask;
1020 + if (nfs4ace_is_inherit_only(ace) || !nfs4ace_is_allow(ace))
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;
1027 + mask = x->acl->a_group_mask;
1028 + if (nfs4ace_change_mask(x, &ace, ace->e_mask & mask))
1035 + * nfs4acl_max_allowed - maximum mask flags that anybody is allowed
1037 +static unsigned int
1038 +nfs4acl_max_allowed(struct nfs4acl *acl)
1040 + struct nfs4ace *ace;
1041 + unsigned int allowed = 0;
1043 + nfs4acl_for_each_entry_reverse(ace, acl) {
1044 + if (nfs4ace_is_inherit_only(ace))
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;
1057 + * nfs4acl_isolate_owner_class - limit the owner class to the owner file mask
1058 + * @x: acl and number of allocated entries
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.
1065 +nfs4acl_isolate_owner_class(struct nfs4acl_alloc *x)
1067 + struct nfs4ace *ace;
1068 + unsigned int allowed = 0;
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))
1076 + if (nfs4ace_is_deny(ace)) {
1077 + if (nfs4ace_is_owner(ace))
1079 + } else if (nfs4ace_is_allow(ace)) {
1080 + ace = x->acl->a_entries + x->acl->a_count;
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)))
1089 + /* Insert an owner@ deny entry at the front. */
1090 + ace = x->acl->a_entries;
1091 + if (nfs4acl_insert_entry(x, &ace))
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;
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
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.
1114 +__nfs4acl_isolate_who(struct nfs4acl_alloc *x, struct nfs4ace *who,
1115 + unsigned int deny)
1117 + struct nfs4ace *ace;
1118 + unsigned int allowed = 0, n;
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))
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;
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))
1142 + if (nfs4ace_is_deny(ace)) {
1143 + if (nfs4ace_is_same_who(ace, who))
1145 + } else if (nfs4ace_is_allow(ace) &&
1146 + (ace->e_mask & deny)) {
1152 + if (nfs4ace_change_mask(x, &ace, ace->e_mask | deny))
1155 + /* Insert a eny entry before the trailing EVERYONE@ DENY
1157 + struct nfs4ace who_copy;
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))
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;
1172 + * nfs4acl_isolate_group_class - limit the group class to the group file mask
1173 + * @x: acl and number of allocated entries
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.
1180 +nfs4acl_isolate_group_class(struct nfs4acl_alloc *x)
1182 + struct nfs4ace who = {
1183 + .e_flags = ACE4_SPECIAL_WHO,
1184 + .u.e_who = nfs4ace_group_who,
1186 + struct nfs4ace *ace;
1187 + unsigned int deny;
1189 + if (!x->acl->a_count)
1191 + ace = x->acl->a_entries + x->acl->a_count - 1;
1192 + if (nfs4ace_is_inherit_only(ace) || !nfs4ace_is_everyone(ace))
1194 + deny = ace->e_mask & ~x->acl->a_group_mask;
1199 + if (__nfs4acl_isolate_who(x, &who, deny))
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;
1207 + if (nfs4ace_is_inherit_only(ace) ||
1208 + nfs4ace_is_owner(ace) ||
1209 + nfs4ace_is_group(ace))
1211 + if (__nfs4acl_isolate_who(x, ace, deny))
1219 + * __nfs4acl_write_through - grant the full masks to owner@, group@, everyone@
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
1226 +__nfs4acl_write_through(struct nfs4acl_alloc *x)
1228 + struct nfs4ace *ace;
1229 + unsigned int allowed;
1231 + /* Remove all owner@ and group@ ACEs: we re-insert them at the
1233 + nfs4acl_for_each_entry(ace, x->acl) {
1234 + if (nfs4ace_is_inherit_only(ace))
1236 + if ((nfs4ace_is_owner(ace) || nfs4ace_is_group(ace)) &&
1237 + nfs4ace_change_mask(x, &ace, 0))
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))
1251 + ace = x->acl->a_entries + x->acl->a_count;
1252 + if (nfs4acl_insert_entry(x, &ace))
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;
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. */
1265 + nfs4acl_for_each_entry_reverse(ace, x->acl) {
1266 + if (nfs4ace_is_inherit_only(ace))
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;
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))
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;
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))
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;
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))
1303 + if (nfs4ace_is_allow(ace)) {
1304 + ace = x->acl->a_entries + x->acl->a_count;
1307 + if (nfs4ace_is_deny(ace) && nfs4ace_is_owner(ace))
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)))
1315 + ace = x->acl->a_entries;
1316 + if (nfs4acl_insert_entry(x, &ace))
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;
1329 + * nfs4acl_apply_masks - apply the masks to the acl
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.
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.
1339 +nfs4acl_apply_masks(struct nfs4acl **acl)
1341 + struct nfs4acl_alloc x = {
1343 + .count = (*acl)->a_count,
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))
1357 +EXPORT_SYMBOL(nfs4acl_apply_masks);
1359 +int nfs4acl_write_through(struct nfs4acl **acl)
1361 + struct nfs4acl_alloc x = {
1363 + .count = (*acl)->a_count,
1367 + if (!((*acl)->a_flags & ACL4_WRITE_THROUGH))
1370 + if (nfs4acl_move_everyone_aces_down(&x) ||
1371 + nfs4acl_propagate_everyone(&x) ||
1372 + __nfs4acl_write_through(&x))
1380 +++ b/fs/nfs4acl_xattr.c
1383 + * Copyright (C) 2006 Andreas Gruenbacher <a.gruenbacher@computer.org>
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
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.
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>
1402 +MODULE_LICENSE("GPL");
1405 +nfs4acl_from_xattr(const void *value, size_t size)
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;
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);
1418 + count = be16_to_cpu(xattr_acl->a_count);
1419 + if (count > ACL4_XATTR_MAX_COUNT)
1420 + return ERR_PTR(-EINVAL);
1422 + acl = nfs4acl_alloc(count);
1424 + return ERR_PTR(-ENOMEM);
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)
1430 + acl->a_group_mask = be32_to_cpu(xattr_acl->a_group_mask);
1431 + if (acl->a_group_mask & ~ACE4_VALID_MASK)
1433 + acl->a_other_mask = be32_to_cpu(xattr_acl->a_other_mask);
1434 + if (acl->a_other_mask & ~ACE4_VALID_MASK)
1437 + nfs4acl_for_each_entry(ace, acl) {
1438 + const char *who = (void *)(xattr_ace + 1), *end;
1439 + ssize_t used = (void *)who - value;
1443 + end = memchr(who, 0, size - used);
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);
1452 + if (ace->e_flags & ~ACE4_VALID_FLAGS) {
1453 + memset(ace, 0, sizeof(struct nfs4ace));
1456 + if (ace->e_type > ACE4_ACCESS_DENIED_ACE_TYPE ||
1457 + (ace->e_mask & ~ACE4_VALID_MASK))
1461 + if (ace->u.e_id == -1)
1462 + goto fail_einval; /* uid/gid needed */
1463 + } else if (nfs4ace_set_who(ace, who))
1466 + xattr_ace = (void *)who + ALIGN(end - who + 1, 4);
1473 + return ERR_PTR(-EINVAL);
1475 +EXPORT_SYMBOL(nfs4acl_from_xattr);
1478 +nfs4acl_xattr_size(const struct nfs4acl *acl)
1480 + size_t size = sizeof(struct nfs4acl_xattr);
1481 + const struct nfs4ace *ace;
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));
1490 +EXPORT_SYMBOL(nfs4acl_xattr_size);
1493 +nfs4acl_to_xattr(const struct nfs4acl *acl, void *buffer)
1495 + struct nfs4acl_xattr *xattr_acl = buffer;
1496 + struct nfs4ace_xattr *xattr_ace;
1497 + const struct nfs4ace *ace;
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);
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);
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;
1518 + int sz = ALIGN(strlen(ace->u.e_who) + 1, 4);
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;
1527 +EXPORT_SYMBOL(nfs4acl_to_xattr);
1529 +++ b/include/linux/nfs4acl.h
1531 +#ifndef __NFS4ACL_H
1532 +#define __NFS4ACL_H
1535 + unsigned short e_type;
1536 + unsigned short e_flags;
1537 + unsigned int e_mask;
1539 + unsigned int e_id;
1540 + const char *e_who;
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];
1554 +#define nfs4acl_for_each_entry(_ace, _acl) \
1555 + for (_ace = _acl->a_entries; \
1556 + _ace != _acl->a_entries + _acl->a_count; \
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; \
1564 +/* a_flags values */
1565 +#define ACL4_WRITE_THROUGH 0x40
1567 +#define ACL4_VALID_FLAGS \
1568 + ACL4_WRITE_THROUGH
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*/
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 */
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 )
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
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 | \
1619 + ACE4_DELETE_CHILD | \
1620 + ACE4_READ_ATTRIBUTES | \
1621 + ACE4_WRITE_ATTRIBUTES | \
1624 + ACE4_WRITE_ACL | \
1625 + ACE4_WRITE_OWNER | \
1626 + ACE4_SYNCHRONIZE )
1628 +#define ACE4_POSIX_ALWAYS_ALLOWED ( \
1629 + ACE4_SYNCHRONIZE | \
1630 + ACE4_READ_ATTRIBUTES | \
1633 + * Duplicate an NFS4ACL handle.
1635 +static inline struct nfs4acl *
1636 +nfs4acl_get(struct nfs4acl *acl)
1639 + atomic_inc(&acl->a_refcount);
1644 + * Free an NFS4ACL handle
1647 +nfs4acl_put(struct nfs4acl *acl)
1649 + if (acl && atomic_dec_and_test(&acl->a_refcount))
1653 +/* Special e_who identifiers: we use these pointer values in comparisons
1654 + instead of strcmp for efficiency. */
1656 +extern const char nfs4ace_owner_who[];
1657 +extern const char nfs4ace_group_who[];
1658 +extern const char nfs4ace_everyone_who[];
1661 +nfs4ace_is_owner(const struct nfs4ace *ace)
1663 + return (ace->e_flags & ACE4_SPECIAL_WHO) &&
1664 + ace->u.e_who == nfs4ace_owner_who;
1668 +nfs4ace_is_group(const struct nfs4ace *ace)
1670 + return (ace->e_flags & ACE4_SPECIAL_WHO) &&
1671 + ace->u.e_who == nfs4ace_group_who;
1675 +nfs4ace_is_everyone(const struct nfs4ace *ace)
1677 + return (ace->e_flags & ACE4_SPECIAL_WHO) &&
1678 + ace->u.e_who == nfs4ace_everyone_who;
1682 +nfs4ace_is_unix_id(const struct nfs4ace *ace)
1684 + return !(ace->e_flags & ACE4_SPECIAL_WHO);
1688 +nfs4ace_is_inherit_only(const struct nfs4ace *ace)
1690 + return ace->e_flags & ACE4_INHERIT_ONLY_ACE;
1694 +nfs4ace_is_inheritable(const struct nfs4ace *ace)
1696 + return ace->e_flags & (ACE4_FILE_INHERIT_ACE |
1697 + ACE4_DIRECTORY_INHERIT_ACE);
1701 +nfs4ace_clear_inheritance_flags(struct nfs4ace *ace)
1703 + ace->e_flags &= ~(ACE4_FILE_INHERIT_ACE |
1704 + ACE4_DIRECTORY_INHERIT_ACE |
1705 + ACE4_NO_PROPAGATE_INHERIT_ACE |
1706 + ACE4_INHERIT_ONLY_ACE);
1710 +nfs4ace_is_allow(const struct nfs4ace *ace)
1712 + return ace->e_type == ACE4_ACCESS_ALLOWED_ACE_TYPE;
1716 +nfs4ace_is_deny(const struct nfs4ace *ace)
1718 + return ace->e_type == ACE4_ACCESS_DENIED_ACE_TYPE;
1721 +extern struct nfs4acl *nfs4acl_alloc(int count);
1722 +extern struct nfs4acl *nfs4acl_clone(const struct nfs4acl *acl);
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);
1735 +#endif /* __NFS4ACL_H */
1737 +++ b/include/linux/nfs4acl_xattr.h
1739 +#ifndef __NFS4ACL_XATTR_H
1740 +#define __NFS4ACL_XATTR_H
1742 +#include <linux/nfs4acl.h>
1744 +#define NFS4ACL_XATTR "system.nfs4acl"
1746 +struct nfs4ace_xattr {
1754 +struct nfs4acl_xattr {
1755 + unsigned char a_version;
1756 + unsigned char a_flags;
1758 + __be32 a_owner_mask;
1759 + __be32 a_group_mask;
1760 + __be32 a_other_mask;
1763 +#define ACL4_XATTR_VERSION 0
1764 +#define ACL4_XATTR_MAX_COUNT 1024
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 *);
1770 +#endif /* __NFS4ACL_XATTR_H */