4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21 * CA 95054 USA or visit www.sun.com if you need additional information or
27 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28 * Use is subject to license terms.
31 * This file is part of Lustre, http://www.lustre.org/
32 * Lustre is a trademark of Sun Microsystems, Inc.
34 * lustre/obdclass/acl.c
36 * Lustre Access Control List.
38 * Author: Fan Yong <fanyong@clusterfs.com>
41 #define DEBUG_SUBSYSTEM S_SEC
43 #include <lustre_acl.h>
44 #include <lustre_eacl.h>
45 #include <obd_support.h>
47 #ifdef CONFIG_FS_POSIX_ACL
49 #define CFS_ACL_XATTR_VERSION POSIX_ACL_XATTR_VERSION
52 ES_UNK = 0, /* unknown stat */
53 ES_UNC = 1, /* ACL entry is not changed */
54 ES_MOD = 2, /* ACL entry is modified */
55 ES_ADD = 3, /* ACL entry is added */
56 ES_DEL = 4 /* ACL entry is deleted */
59 static inline void lustre_ext_acl_le_to_cpu(ext_acl_xattr_entry *d,
60 ext_acl_xattr_entry *s)
62 d->e_tag = le16_to_cpu(s->e_tag);
63 d->e_perm = le16_to_cpu(s->e_perm);
64 d->e_id = le32_to_cpu(s->e_id);
65 d->e_stat = le32_to_cpu(s->e_stat);
68 static inline void lustre_ext_acl_cpu_to_le(ext_acl_xattr_entry *d,
69 ext_acl_xattr_entry *s)
71 d->e_tag = cpu_to_le16(s->e_tag);
72 d->e_perm = cpu_to_le16(s->e_perm);
73 d->e_id = cpu_to_le32(s->e_id);
74 d->e_stat = cpu_to_le32(s->e_stat);
77 static inline void lustre_posix_acl_le_to_cpu(posix_acl_xattr_entry *d,
78 posix_acl_xattr_entry *s)
80 d->e_tag = le16_to_cpu(s->e_tag);
81 d->e_perm = le16_to_cpu(s->e_perm);
82 d->e_id = le32_to_cpu(s->e_id);
85 static inline void lustre_posix_acl_cpu_to_le(posix_acl_xattr_entry *d,
86 posix_acl_xattr_entry *s)
88 d->e_tag = cpu_to_le16(s->e_tag);
89 d->e_perm = cpu_to_le16(s->e_perm);
90 d->e_id = cpu_to_le32(s->e_id);
94 * Check permission based on POSIX ACL.
96 int lustre_posix_acl_permission(struct md_ucred *mu, struct lu_attr *la,
97 int want, posix_acl_xattr_entry *entry,
100 posix_acl_xattr_entry *pa, *pe, *mask_obj;
101 posix_acl_xattr_entry ae, me;
107 for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
108 lustre_posix_acl_le_to_cpu(&ae, pa);
111 /* (May have been checked already) */
112 if (la->la_uid == mu->mu_fsuid)
116 if (ae.e_id == mu->mu_fsuid)
120 if (lustre_in_group_p(mu, la->la_gid)) {
122 if ((ae.e_perm & want) == want)
127 if (lustre_in_group_p(mu, ae.e_id)) {
129 if ((ae.e_perm & want) == want)
147 for (mask_obj = pa + 1; mask_obj <= pe; mask_obj++) {
148 lustre_posix_acl_le_to_cpu(&me, mask_obj);
149 if (me.e_tag == ACL_MASK) {
150 if ((ae.e_perm & me.e_perm & want) == want)
158 if ((ae.e_perm & want) == want)
163 EXPORT_SYMBOL(lustre_posix_acl_permission);
166 * Modify the ACL for the chmod.
168 int lustre_posix_acl_chmod_masq(posix_acl_xattr_entry *entry, __u32 mode,
171 posix_acl_xattr_entry *group_obj = NULL, *mask_obj = NULL, *pa, *pe;
173 for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
174 switch (le16_to_cpu(pa->e_tag)) {
176 pa->e_perm = cpu_to_le16((mode & S_IRWXU) >> 6);
188 pa->e_perm = cpu_to_le16(mode & S_IRWXO);
196 mask_obj->e_perm = cpu_to_le16((mode & S_IRWXG) >> 3);
200 group_obj->e_perm = cpu_to_le16((mode & S_IRWXG) >> 3);
205 EXPORT_SYMBOL(lustre_posix_acl_chmod_masq);
208 * Returns 0 if the acl can be exactly represented in the traditional
209 * file mode permission bits, or else 1. Returns -E... on error.
212 lustre_posix_acl_equiv_mode(posix_acl_xattr_entry *entry, mode_t *mode_p,
215 posix_acl_xattr_entry *pa, *pe;
219 for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
220 __u16 perm = le16_to_cpu(pa->e_perm);
221 switch (le16_to_cpu(pa->e_tag)) {
223 mode |= (perm & S_IRWXO) << 6;
226 mode |= (perm & S_IRWXO) << 3;
229 mode |= perm & S_IRWXO;
232 mode = (mode & ~S_IRWXG) |
233 ((perm & S_IRWXO) << 3);
245 *mode_p = (*mode_p & ~S_IRWXUGO) | mode;
248 EXPORT_SYMBOL(lustre_posix_acl_equiv_mode);
251 * Modify acl when creating a new object.
253 int lustre_posix_acl_create_masq(posix_acl_xattr_entry *entry, __u32 *pmode,
256 posix_acl_xattr_entry *group_obj = NULL, *mask_obj = NULL, *pa, *pe;
257 posix_acl_xattr_entry ae;
261 for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
262 lustre_posix_acl_le_to_cpu(&ae, pa);
265 ae.e_perm &= (mode >> 6) | ~S_IRWXO;
266 pa->e_perm = cpu_to_le16(ae.e_perm);
267 mode &= (ae.e_perm << 6) | ~S_IRWXU;
277 ae.e_perm &= mode | ~S_IRWXO;
278 pa->e_perm = cpu_to_le16(ae.e_perm);
279 mode &= ae.e_perm | ~S_IRWXO;
291 ae.e_perm = le16_to_cpu(mask_obj->e_perm) &
292 ((mode >> 3) | ~S_IRWXO);
293 mode &= (ae.e_perm << 3) | ~S_IRWXG;
294 mask_obj->e_perm = cpu_to_le16(ae.e_perm);
298 ae.e_perm = le16_to_cpu(group_obj->e_perm) &
299 ((mode >> 3) | ~S_IRWXO);
300 mode &= (ae.e_perm << 3) | ~S_IRWXG;
301 group_obj->e_perm = cpu_to_le16(ae.e_perm);
304 *pmode = (*pmode & ~S_IRWXUGO) | mode;
307 EXPORT_SYMBOL(lustre_posix_acl_create_masq);
309 /* if "new_count == 0", then "new = {a_version, NULL}", NOT NULL. */
310 static int lustre_posix_acl_xattr_reduce_space(posix_acl_xattr_header **header,
311 int old_count, int new_count)
313 int old_size = CFS_ACL_XATTR_SIZE(old_count, posix_acl_xattr);
314 int new_size = CFS_ACL_XATTR_SIZE(new_count, posix_acl_xattr);
315 posix_acl_xattr_header *new;
317 if (unlikely(old_count <= new_count))
320 OBD_ALLOC(new, new_size);
321 if (unlikely(new == NULL))
324 memcpy(new, *header, new_size);
325 OBD_FREE(*header, old_size);
330 /* if "new_count == 0", then "new = {0, NULL}", NOT NULL. */
331 static int lustre_ext_acl_xattr_reduce_space(ext_acl_xattr_header **header,
334 int ext_count = le32_to_cpu((*header)->a_count);
335 int ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr);
336 int old_size = CFS_ACL_XATTR_SIZE(old_count, ext_acl_xattr);
337 ext_acl_xattr_header *new;
339 if (unlikely(old_count <= ext_count))
342 OBD_ALLOC(new, ext_size);
343 if (unlikely(new == NULL))
346 memcpy(new, *header, ext_size);
347 OBD_FREE(*header, old_size);
353 * Generate new extended ACL based on the posix ACL.
355 ext_acl_xattr_header *
356 lustre_posix_acl_xattr_2ext(posix_acl_xattr_header *header, int size)
359 ext_acl_xattr_header *new;
362 if (unlikely(size < 0))
363 RETURN(ERR_PTR(-EINVAL));
367 count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
368 esize = CFS_ACL_XATTR_SIZE(count, ext_acl_xattr);
369 OBD_ALLOC(new, esize);
370 if (unlikely(new == NULL))
371 RETURN(ERR_PTR(-ENOMEM));
373 new->a_count = cpu_to_le32(count);
374 for (i = 0; i < count; i++) {
375 new->a_entries[i].e_tag = header->a_entries[i].e_tag;
376 new->a_entries[i].e_perm = header->a_entries[i].e_perm;
377 new->a_entries[i].e_id = header->a_entries[i].e_id;
378 new->a_entries[i].e_stat = cpu_to_le32(ES_UNK);
383 EXPORT_SYMBOL(lustre_posix_acl_xattr_2ext);
386 * Filter out the "nobody" entries in the posix ACL.
388 int lustre_posix_acl_xattr_filter(posix_acl_xattr_header *header, int size,
389 posix_acl_xattr_header **out)
391 int count, i, j, rc = 0;
393 posix_acl_xattr_header *new;
396 if (unlikely(size < 0))
401 OBD_ALLOC(new, size);
402 if (unlikely(new == NULL))
405 new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
406 count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
407 for (i = 0, j = 0; i < count; i++) {
408 id = le32_to_cpu(header->a_entries[i].e_id);
409 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
414 if (id != ACL_UNDEFINED_ID)
415 GOTO(_out, rc = -EIO);
417 memcpy(&new->a_entries[j++], &header->a_entries[i],
418 sizeof(posix_acl_xattr_entry));
421 if (id != NOBODY_UID)
422 memcpy(&new->a_entries[j++],
423 &header->a_entries[i],
424 sizeof(posix_acl_xattr_entry));
427 if (id != NOBODY_GID)
428 memcpy(&new->a_entries[j++],
429 &header->a_entries[i],
430 sizeof(posix_acl_xattr_entry));
433 GOTO(_out, rc = -EIO);
437 /* free unused space. */
438 rc = lustre_posix_acl_xattr_reduce_space(&new, count, j);
453 EXPORT_SYMBOL(lustre_posix_acl_xattr_filter);
456 * Convert server-side uid/gid in the posix ACL items to the client-side ones.
459 * nothing to be converted.
461 * mapped ids are converted to client-side ones,
462 * unmapped ones are converted to "nobody".
464 * only mapped ids are converted to "nobody".
466 * only unmapped ids are converted to "nobody".
468 int lustre_posix_acl_xattr_id2client(struct md_ucred *mu,
469 struct lustre_idmap_table *t,
470 posix_acl_xattr_header *header,
477 if (unlikely(size < 0))
482 if (unlikely(flags == CFS_IC_NOTHING))
485 count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
486 for (i = 0; i < count; i++) {
487 id = le32_to_cpu(header->a_entries[i].e_id);
488 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
493 if (id != ACL_UNDEFINED_ID)
497 id = lustre_idmap_lookup_uid(mu, t, 1, id);
498 if (flags == CFS_IC_ALL) {
499 if (id == CFS_IDMAP_NOTFOUND)
501 header->a_entries[i].e_id = cpu_to_le32(id);
502 } else if (flags == CFS_IC_MAPPED) {
503 if (id != CFS_IDMAP_NOTFOUND)
504 header->a_entries[i].e_id =
505 cpu_to_le32(NOBODY_UID);
506 } else if (flags == CFS_IC_UNMAPPED) {
507 if (id == CFS_IDMAP_NOTFOUND)
508 header->a_entries[i].e_id =
509 cpu_to_le32(NOBODY_UID);
513 id = lustre_idmap_lookup_gid(mu, t, 1, id);
514 if (flags == CFS_IC_ALL) {
515 if (id == CFS_IDMAP_NOTFOUND)
517 header->a_entries[i].e_id = cpu_to_le32(id);
518 } else if (flags == CFS_IC_MAPPED) {
519 if (id != CFS_IDMAP_NOTFOUND)
520 header->a_entries[i].e_id =
521 cpu_to_le32(NOBODY_GID);
522 } else if (flags == CFS_IC_UNMAPPED) {
523 if (id == CFS_IDMAP_NOTFOUND)
524 header->a_entries[i].e_id =
525 cpu_to_le32(NOBODY_GID);
534 EXPORT_SYMBOL(lustre_posix_acl_xattr_id2client);
537 * Release the posix ACL space.
539 void lustre_posix_acl_xattr_free(posix_acl_xattr_header *header, int size)
541 OBD_FREE(header, size);
543 EXPORT_SYMBOL(lustre_posix_acl_xattr_free);
546 * Converts client-side uid/gid in the extended ACL items to server-side ones.
548 * mapped ids are converted to server-side ones,
549 * unmapped ones cause "EPERM" error.
551 int lustre_ext_acl_xattr_id2server(struct md_ucred *mu,
552 struct lustre_idmap_table *t,
553 ext_acl_xattr_header *header)
556 int i, count = le32_to_cpu(header->a_count);
560 for (i = 0; i < count; i++) {
561 id = le32_to_cpu(header->a_entries[i].e_id);
562 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
567 if (id != ACL_UNDEFINED_ID)
571 id = lustre_idmap_lookup_uid(mu, t, 0, id);
572 if (id == CFS_IDMAP_NOTFOUND)
575 header->a_entries[i].e_id = cpu_to_le32(id);
578 id = lustre_idmap_lookup_gid(mu, t, 0, id);
579 if (id == CFS_IDMAP_NOTFOUND)
582 header->a_entries[i].e_id = cpu_to_le32(id);
590 EXPORT_SYMBOL(lustre_ext_acl_xattr_id2server);
593 * Release the extended ACL space.
595 void lustre_ext_acl_xattr_free(ext_acl_xattr_header *header)
597 OBD_FREE(header, CFS_ACL_XATTR_SIZE(le32_to_cpu(header->a_count), \
600 EXPORT_SYMBOL(lustre_ext_acl_xattr_free);
602 static ext_acl_xattr_entry *
603 lustre_ext_acl_xattr_search(ext_acl_xattr_header *header,
604 posix_acl_xattr_entry *entry, int *pos)
606 int once, start, end, i, j, count = le32_to_cpu(header->a_count);
613 for (i = start; i < end; i++) {
614 if (header->a_entries[i].e_tag == entry->e_tag &&
615 header->a_entries[i].e_id == entry->e_id) {
620 return &header->a_entries[j];
635 * Merge the posix ACL and the extended ACL into new posix ACL.
637 int lustre_acl_xattr_merge2posix(posix_acl_xattr_header *posix_header, int size,
638 ext_acl_xattr_header *ext_header,
639 posix_acl_xattr_header **out)
641 int posix_count, posix_size, i, j;
642 int ext_count = le32_to_cpu(ext_header->a_count), pos = 0, rc = 0;
643 posix_acl_xattr_entry pe = {ACL_MASK, 0, ACL_UNDEFINED_ID};
644 posix_acl_xattr_header *new;
645 ext_acl_xattr_entry *ee, ae;
648 lustre_posix_acl_cpu_to_le(&pe, &pe);
649 ee = lustre_ext_acl_xattr_search(ext_header, &pe, &pos);
650 if (ee == NULL || le32_to_cpu(ee->e_stat) == ES_DEL) {
651 /* there are only base ACL entries at most. */
653 posix_size = CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
654 OBD_ALLOC(new, posix_size);
655 if (unlikely(new == NULL))
658 new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
659 for (i = 0, j = 0; i < ext_count; i++) {
660 lustre_ext_acl_le_to_cpu(&ae,
661 &ext_header->a_entries[i]);
666 if (ae.e_id != ACL_UNDEFINED_ID)
667 GOTO(_out, rc = -EIO);
669 if (ae.e_stat != ES_DEL) {
670 new->a_entries[j].e_tag =
671 ext_header->a_entries[i].e_tag;
672 new->a_entries[j].e_perm =
673 ext_header->a_entries[i].e_perm;
674 new->a_entries[j++].e_id =
675 ext_header->a_entries[i].e_id;
681 if (ae.e_stat == ES_DEL)
684 GOTO(_out, rc = -EIO);
688 /* maybe there are valid ACL_USER or ACL_GROUP entries in the
689 * original server-side ACL, they are regarded as ES_UNC stat.*/
692 if (unlikely(size < 0))
698 CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
699 posix_count = ori_posix_count + ext_count;
701 CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
702 OBD_ALLOC(new, posix_size);
703 if (unlikely(new == NULL))
706 new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
707 /* 1. process the unchanged ACL entries
708 * in the original server-side ACL. */
710 for (i = 0, j = 0; i < ori_posix_count; i++) {
711 ee = lustre_ext_acl_xattr_search(ext_header,
712 &posix_header->a_entries[i], &pos);
714 memcpy(&new->a_entries[j++],
715 &posix_header->a_entries[i],
716 sizeof(posix_acl_xattr_entry));
719 /* 2. process the non-deleted entries
720 * from client-side extended ACL. */
721 for (i = 0; i < ext_count; i++) {
722 if (le16_to_cpu(ext_header->a_entries[i].e_stat) !=
724 new->a_entries[j].e_tag =
725 ext_header->a_entries[i].e_tag;
726 new->a_entries[j].e_perm =
727 ext_header->a_entries[i].e_perm;
728 new->a_entries[j++].e_id =
729 ext_header->a_entries[i].e_id;
734 /* free unused space. */
735 rc = lustre_posix_acl_xattr_reduce_space(&new, posix_count, j);
745 OBD_FREE(new, posix_size);
750 EXPORT_SYMBOL(lustre_acl_xattr_merge2posix);
753 * Merge the posix ACL and the extended ACL into new extended ACL.
755 ext_acl_xattr_header *
756 lustre_acl_xattr_merge2ext(posix_acl_xattr_header *posix_header, int size,
757 ext_acl_xattr_header *ext_header)
759 int ori_ext_count, posix_count, ext_count, ext_size;
760 int i, j, pos = 0, rc = 0;
761 posix_acl_xattr_entry pae;
762 ext_acl_xattr_header *new;
763 ext_acl_xattr_entry *ee, eae;
766 if (unlikely(size < 0))
767 RETURN(ERR_PTR(-EINVAL));
771 posix_count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
772 ori_ext_count = le32_to_cpu(ext_header->a_count);
773 ext_count = posix_count + ori_ext_count;
774 ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr);
776 OBD_ALLOC(new, ext_size);
777 if (unlikely(new == NULL))
778 RETURN(ERR_PTR(-ENOMEM));
780 for (i = 0, j = 0; i < posix_count; i++) {
781 lustre_posix_acl_le_to_cpu(&pae, &posix_header->a_entries[i]);
787 if (pae.e_id != ACL_UNDEFINED_ID)
788 GOTO(out, rc = -EIO);
790 /* ignore "nobody" entry. */
791 if (pae.e_id == NOBODY_UID)
794 new->a_entries[j].e_tag =
795 posix_header->a_entries[i].e_tag;
796 new->a_entries[j].e_perm =
797 posix_header->a_entries[i].e_perm;
798 new->a_entries[j].e_id =
799 posix_header->a_entries[i].e_id;
800 ee = lustre_ext_acl_xattr_search(ext_header,
801 &posix_header->a_entries[i], &pos);
803 if (posix_header->a_entries[i].e_perm !=
805 /* entry modified. */
807 new->a_entries[j++].e_stat =
810 /* entry unchanged. */
812 new->a_entries[j++].e_stat =
816 new->a_entries[j++].e_stat =
821 /* ignore "nobody" entry. */
822 if (pae.e_id == NOBODY_GID)
824 new->a_entries[j].e_tag =
825 posix_header->a_entries[i].e_tag;
826 new->a_entries[j].e_perm =
827 posix_header->a_entries[i].e_perm;
828 new->a_entries[j].e_id =
829 posix_header->a_entries[i].e_id;
830 ee = lustre_ext_acl_xattr_search(ext_header,
831 &posix_header->a_entries[i], &pos);
833 if (posix_header->a_entries[i].e_perm !=
835 /* entry modified. */
837 new->a_entries[j++].e_stat =
840 /* entry unchanged. */
842 new->a_entries[j++].e_stat =
846 new->a_entries[j++].e_stat =
851 GOTO(out, rc = -EIO);
855 /* process deleted entries. */
856 for (i = 0; i < ori_ext_count; i++) {
857 lustre_ext_acl_le_to_cpu(&eae, &ext_header->a_entries[i]);
858 if (eae.e_stat == ES_UNK) {
859 /* ignore "nobody" entry. */
860 if ((eae.e_tag == ACL_USER && eae.e_id == NOBODY_UID) ||
861 (eae.e_tag == ACL_GROUP && eae.e_id == NOBODY_GID))
864 new->a_entries[j].e_tag =
865 ext_header->a_entries[i].e_tag;
866 new->a_entries[j].e_perm =
867 ext_header->a_entries[i].e_perm;
868 new->a_entries[j].e_id = ext_header->a_entries[i].e_id;
869 new->a_entries[j++].e_stat = cpu_to_le32(ES_DEL);
873 new->a_count = cpu_to_le32(j);
874 /* free unused space. */
875 rc = lustre_ext_acl_xattr_reduce_space(&new, ext_count);
880 OBD_FREE(new, ext_size);
885 EXPORT_SYMBOL(lustre_acl_xattr_merge2ext);