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.
30 * Copyright (c) 2012, Intel Corporation.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
36 * lustre/obdclass/acl.c
38 * Lustre Access Control List.
40 * Author: Fan Yong <fanyong@clusterfs.com>
43 #define DEBUG_SUBSYSTEM S_SEC
44 #include <lu_object.h>
45 #include <lustre_acl.h>
46 #include <lustre_eacl.h>
47 #include <obd_support.h>
48 #ifdef HAVE_SERVER_SUPPORT
49 # include <lustre_idmap.h>
50 # include <md_object.h>
51 #endif /* HAVE_SERVER_SUPPORT */
53 #ifdef CONFIG_FS_POSIX_ACL
55 #define CFS_ACL_XATTR_VERSION POSIX_ACL_XATTR_VERSION
58 ES_UNK = 0, /* unknown stat */
59 ES_UNC = 1, /* ACL entry is not changed */
60 ES_MOD = 2, /* ACL entry is modified */
61 ES_ADD = 3, /* ACL entry is added */
62 ES_DEL = 4 /* ACL entry is deleted */
65 static inline void lustre_ext_acl_le_to_cpu(ext_acl_xattr_entry *d,
66 ext_acl_xattr_entry *s)
68 d->e_tag = le16_to_cpu(s->e_tag);
69 d->e_perm = le16_to_cpu(s->e_perm);
70 d->e_id = le32_to_cpu(s->e_id);
71 d->e_stat = le32_to_cpu(s->e_stat);
74 static inline void lustre_ext_acl_cpu_to_le(ext_acl_xattr_entry *d,
75 ext_acl_xattr_entry *s)
77 d->e_tag = cpu_to_le16(s->e_tag);
78 d->e_perm = cpu_to_le16(s->e_perm);
79 d->e_id = cpu_to_le32(s->e_id);
80 d->e_stat = cpu_to_le32(s->e_stat);
83 static inline void lustre_posix_acl_le_to_cpu(posix_acl_xattr_entry *d,
84 posix_acl_xattr_entry *s)
86 d->e_tag = le16_to_cpu(s->e_tag);
87 d->e_perm = le16_to_cpu(s->e_perm);
88 d->e_id = le32_to_cpu(s->e_id);
91 static inline void lustre_posix_acl_cpu_to_le(posix_acl_xattr_entry *d,
92 posix_acl_xattr_entry *s)
94 d->e_tag = cpu_to_le16(s->e_tag);
95 d->e_perm = cpu_to_le16(s->e_perm);
96 d->e_id = cpu_to_le32(s->e_id);
99 #ifdef HAVE_SERVER_SUPPORT
101 * Check permission based on POSIX ACL.
103 int lustre_posix_acl_permission(struct lu_ucred *mu, struct lu_attr *la,
104 int want, posix_acl_xattr_entry *entry,
107 posix_acl_xattr_entry *pa, *pe, *mask_obj;
108 posix_acl_xattr_entry ae, me;
114 for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
115 lustre_posix_acl_le_to_cpu(&ae, pa);
118 /* (May have been checked already) */
119 if (la->la_uid == mu->uc_fsuid)
123 if (ae.e_id == mu->uc_fsuid)
127 if (lustre_in_group_p(mu, la->la_gid)) {
129 if ((ae.e_perm & want) == want)
134 if (lustre_in_group_p(mu, ae.e_id)) {
136 if ((ae.e_perm & want) == want)
154 for (mask_obj = pa + 1; mask_obj <= pe; mask_obj++) {
155 lustre_posix_acl_le_to_cpu(&me, mask_obj);
156 if (me.e_tag == ACL_MASK) {
157 if ((ae.e_perm & me.e_perm & want) == want)
165 if ((ae.e_perm & want) == want)
170 EXPORT_SYMBOL(lustre_posix_acl_permission);
173 * Modify the ACL for the chmod.
175 int lustre_posix_acl_chmod_masq(posix_acl_xattr_entry *entry, __u32 mode,
178 posix_acl_xattr_entry *group_obj = NULL, *mask_obj = NULL, *pa, *pe;
180 for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
181 switch (le16_to_cpu(pa->e_tag)) {
183 pa->e_perm = cpu_to_le16((mode & S_IRWXU) >> 6);
195 pa->e_perm = cpu_to_le16(mode & S_IRWXO);
203 mask_obj->e_perm = cpu_to_le16((mode & S_IRWXG) >> 3);
207 group_obj->e_perm = cpu_to_le16((mode & S_IRWXG) >> 3);
212 EXPORT_SYMBOL(lustre_posix_acl_chmod_masq);
215 * Returns 0 if the acl can be exactly represented in the traditional
216 * file mode permission bits, or else 1. Returns -E... on error.
219 lustre_posix_acl_equiv_mode(posix_acl_xattr_entry *entry, mode_t *mode_p,
222 posix_acl_xattr_entry *pa, *pe;
226 for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
227 __u16 perm = le16_to_cpu(pa->e_perm);
228 switch (le16_to_cpu(pa->e_tag)) {
230 mode |= (perm & S_IRWXO) << 6;
233 mode |= (perm & S_IRWXO) << 3;
236 mode |= perm & S_IRWXO;
239 mode = (mode & ~S_IRWXG) |
240 ((perm & S_IRWXO) << 3);
252 *mode_p = (*mode_p & ~S_IRWXUGO) | mode;
255 EXPORT_SYMBOL(lustre_posix_acl_equiv_mode);
258 * Modify acl when creating a new object.
260 int lustre_posix_acl_create_masq(posix_acl_xattr_entry *entry, __u32 *pmode,
263 posix_acl_xattr_entry *group_obj = NULL, *mask_obj = NULL, *pa, *pe;
264 posix_acl_xattr_entry ae;
268 for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
269 lustre_posix_acl_le_to_cpu(&ae, pa);
272 ae.e_perm &= (mode >> 6) | ~S_IRWXO;
273 pa->e_perm = cpu_to_le16(ae.e_perm);
274 mode &= (ae.e_perm << 6) | ~S_IRWXU;
284 ae.e_perm &= mode | ~S_IRWXO;
285 pa->e_perm = cpu_to_le16(ae.e_perm);
286 mode &= ae.e_perm | ~S_IRWXO;
298 ae.e_perm = le16_to_cpu(mask_obj->e_perm) &
299 ((mode >> 3) | ~S_IRWXO);
300 mode &= (ae.e_perm << 3) | ~S_IRWXG;
301 mask_obj->e_perm = cpu_to_le16(ae.e_perm);
305 ae.e_perm = le16_to_cpu(group_obj->e_perm) &
306 ((mode >> 3) | ~S_IRWXO);
307 mode &= (ae.e_perm << 3) | ~S_IRWXG;
308 group_obj->e_perm = cpu_to_le16(ae.e_perm);
311 *pmode = (*pmode & ~S_IRWXUGO) | mode;
314 EXPORT_SYMBOL(lustre_posix_acl_create_masq);
317 * Convert server-side uid/gid in the posix ACL items to the client-side ones.
320 * nothing to be converted.
322 * mapped ids are converted to client-side ones,
323 * unmapped ones are converted to "nobody".
325 * only mapped ids are converted to "nobody".
327 * only unmapped ids are converted to "nobody".
329 int lustre_posix_acl_xattr_id2client(struct lu_ucred *mu,
330 struct lustre_idmap_table *t,
331 posix_acl_xattr_header *header,
338 if (unlikely(size < 0))
343 if (unlikely(flags == CFS_IC_NOTHING))
346 count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
347 for (i = 0; i < count; i++) {
348 id = le32_to_cpu(header->a_entries[i].e_id);
349 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
354 if (id != ACL_UNDEFINED_ID)
358 id = lustre_idmap_lookup_uid(mu, t, 1, id);
359 if (flags == CFS_IC_ALL) {
360 if (id == CFS_IDMAP_NOTFOUND)
362 header->a_entries[i].e_id = cpu_to_le32(id);
363 } else if (flags == CFS_IC_MAPPED) {
364 if (id != CFS_IDMAP_NOTFOUND)
365 header->a_entries[i].e_id =
366 cpu_to_le32(NOBODY_UID);
367 } else if (flags == CFS_IC_UNMAPPED) {
368 if (id == CFS_IDMAP_NOTFOUND)
369 header->a_entries[i].e_id =
370 cpu_to_le32(NOBODY_UID);
374 id = lustre_idmap_lookup_gid(mu, t, 1, id);
375 if (flags == CFS_IC_ALL) {
376 if (id == CFS_IDMAP_NOTFOUND)
378 header->a_entries[i].e_id = cpu_to_le32(id);
379 } else if (flags == CFS_IC_MAPPED) {
380 if (id != CFS_IDMAP_NOTFOUND)
381 header->a_entries[i].e_id =
382 cpu_to_le32(NOBODY_GID);
383 } else if (flags == CFS_IC_UNMAPPED) {
384 if (id == CFS_IDMAP_NOTFOUND)
385 header->a_entries[i].e_id =
386 cpu_to_le32(NOBODY_GID);
396 EXPORT_SYMBOL(lustre_posix_acl_xattr_id2client);
399 * Converts client-side uid/gid in the extended ACL items to server-side ones.
401 * mapped ids are converted to server-side ones,
402 * unmapped ones cause "EPERM" error.
404 int lustre_ext_acl_xattr_id2server(struct lu_ucred *mu,
405 struct lustre_idmap_table *t,
406 ext_acl_xattr_header *header)
408 int i, count = le32_to_cpu(header->a_count);
412 for (i = 0; i < count; i++) {
413 id = le32_to_cpu(header->a_entries[i].e_id);
414 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
419 if (id != ACL_UNDEFINED_ID)
423 id = lustre_idmap_lookup_uid(mu, t, 0, id);
424 if (id == CFS_IDMAP_NOTFOUND)
427 header->a_entries[i].e_id = cpu_to_le32(id);
430 id = lustre_idmap_lookup_gid(mu, t, 0, id);
431 if (id == CFS_IDMAP_NOTFOUND)
434 header->a_entries[i].e_id = cpu_to_le32(id);
443 EXPORT_SYMBOL(lustre_ext_acl_xattr_id2server);
444 #endif /* HAVE_SERVER_SUPPORT */
446 /* if "new_count == 0", then "new = {a_version, NULL}", NOT NULL. */
447 static int lustre_posix_acl_xattr_reduce_space(posix_acl_xattr_header **header,
448 int old_count, int new_count)
450 int old_size = CFS_ACL_XATTR_SIZE(old_count, posix_acl_xattr);
451 int new_size = CFS_ACL_XATTR_SIZE(new_count, posix_acl_xattr);
452 posix_acl_xattr_header *new;
454 if (unlikely(old_count <= new_count))
457 OBD_ALLOC(new, new_size);
458 if (unlikely(new == NULL))
461 memcpy(new, *header, new_size);
462 OBD_FREE(*header, old_size);
467 /* if "new_count == 0", then "new = {0, NULL}", NOT NULL. */
468 static int lustre_ext_acl_xattr_reduce_space(ext_acl_xattr_header **header,
471 int ext_count = le32_to_cpu((*header)->a_count);
472 int ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr);
473 int old_size = CFS_ACL_XATTR_SIZE(old_count, ext_acl_xattr);
474 ext_acl_xattr_header *new;
476 if (unlikely(old_count <= ext_count))
479 OBD_ALLOC(new, ext_size);
480 if (unlikely(new == NULL))
483 memcpy(new, *header, ext_size);
484 OBD_FREE(*header, old_size);
490 * Generate new extended ACL based on the posix ACL.
492 ext_acl_xattr_header *
493 lustre_posix_acl_xattr_2ext(posix_acl_xattr_header *header, int size)
496 ext_acl_xattr_header *new;
499 if (unlikely(size < 0))
500 RETURN(ERR_PTR(-EINVAL));
504 count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
505 esize = CFS_ACL_XATTR_SIZE(count, ext_acl_xattr);
506 OBD_ALLOC(new, esize);
507 if (unlikely(new == NULL))
508 RETURN(ERR_PTR(-ENOMEM));
510 new->a_count = cpu_to_le32(count);
511 for (i = 0; i < count; i++) {
512 new->a_entries[i].e_tag = header->a_entries[i].e_tag;
513 new->a_entries[i].e_perm = header->a_entries[i].e_perm;
514 new->a_entries[i].e_id = header->a_entries[i].e_id;
515 new->a_entries[i].e_stat = cpu_to_le32(ES_UNK);
520 EXPORT_SYMBOL(lustre_posix_acl_xattr_2ext);
523 * Filter out the "nobody" entries in the posix ACL.
525 int lustre_posix_acl_xattr_filter(posix_acl_xattr_header *header, int size,
526 posix_acl_xattr_header **out)
528 int count, i, j, rc = 0;
530 posix_acl_xattr_header *new;
533 if (unlikely(size < 0))
538 OBD_ALLOC(new, size);
539 if (unlikely(new == NULL))
542 new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
543 count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
544 for (i = 0, j = 0; i < count; i++) {
545 id = le32_to_cpu(header->a_entries[i].e_id);
546 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
551 if (id != ACL_UNDEFINED_ID)
552 GOTO(_out, rc = -EIO);
554 memcpy(&new->a_entries[j++], &header->a_entries[i],
555 sizeof(posix_acl_xattr_entry));
558 if (id != NOBODY_UID)
559 memcpy(&new->a_entries[j++],
560 &header->a_entries[i],
561 sizeof(posix_acl_xattr_entry));
564 if (id != NOBODY_GID)
565 memcpy(&new->a_entries[j++],
566 &header->a_entries[i],
567 sizeof(posix_acl_xattr_entry));
570 GOTO(_out, rc = -EIO);
574 /* free unused space. */
575 rc = lustre_posix_acl_xattr_reduce_space(&new, count, j);
590 EXPORT_SYMBOL(lustre_posix_acl_xattr_filter);
593 * Release the posix ACL space.
595 void lustre_posix_acl_xattr_free(posix_acl_xattr_header *header, int size)
597 OBD_FREE(header, size);
599 EXPORT_SYMBOL(lustre_posix_acl_xattr_free);
602 * Release the extended ACL space.
604 void lustre_ext_acl_xattr_free(ext_acl_xattr_header *header)
606 OBD_FREE(header, CFS_ACL_XATTR_SIZE(le32_to_cpu(header->a_count), \
609 EXPORT_SYMBOL(lustre_ext_acl_xattr_free);
611 static ext_acl_xattr_entry *
612 lustre_ext_acl_xattr_search(ext_acl_xattr_header *header,
613 posix_acl_xattr_entry *entry, int *pos)
615 int once, start, end, i, j, count = le32_to_cpu(header->a_count);
622 for (i = start; i < end; i++) {
623 if (header->a_entries[i].e_tag == entry->e_tag &&
624 header->a_entries[i].e_id == entry->e_id) {
629 return &header->a_entries[j];
644 * Merge the posix ACL and the extended ACL into new posix ACL.
646 int lustre_acl_xattr_merge2posix(posix_acl_xattr_header *posix_header, int size,
647 ext_acl_xattr_header *ext_header,
648 posix_acl_xattr_header **out)
650 int posix_count, posix_size, i, j;
651 int ext_count = le32_to_cpu(ext_header->a_count), pos = 0, rc = 0;
652 posix_acl_xattr_entry pe = {ACL_MASK, 0, ACL_UNDEFINED_ID};
653 posix_acl_xattr_header *new;
654 ext_acl_xattr_entry *ee, ae;
657 lustre_posix_acl_cpu_to_le(&pe, &pe);
658 ee = lustre_ext_acl_xattr_search(ext_header, &pe, &pos);
659 if (ee == NULL || le32_to_cpu(ee->e_stat) == ES_DEL) {
660 /* there are only base ACL entries at most. */
662 posix_size = CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
663 OBD_ALLOC(new, posix_size);
664 if (unlikely(new == NULL))
667 new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
668 for (i = 0, j = 0; i < ext_count; i++) {
669 lustre_ext_acl_le_to_cpu(&ae,
670 &ext_header->a_entries[i]);
675 if (ae.e_id != ACL_UNDEFINED_ID)
676 GOTO(_out, rc = -EIO);
678 if (ae.e_stat != ES_DEL) {
679 new->a_entries[j].e_tag =
680 ext_header->a_entries[i].e_tag;
681 new->a_entries[j].e_perm =
682 ext_header->a_entries[i].e_perm;
683 new->a_entries[j++].e_id =
684 ext_header->a_entries[i].e_id;
690 if (ae.e_stat == ES_DEL)
693 GOTO(_out, rc = -EIO);
697 /* maybe there are valid ACL_USER or ACL_GROUP entries in the
698 * original server-side ACL, they are regarded as ES_UNC stat.*/
701 if (unlikely(size < 0))
707 CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
708 posix_count = ori_posix_count + ext_count;
710 CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
711 OBD_ALLOC(new, posix_size);
712 if (unlikely(new == NULL))
715 new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
716 /* 1. process the unchanged ACL entries
717 * in the original server-side ACL. */
719 for (i = 0, j = 0; i < ori_posix_count; i++) {
720 ee = lustre_ext_acl_xattr_search(ext_header,
721 &posix_header->a_entries[i], &pos);
723 memcpy(&new->a_entries[j++],
724 &posix_header->a_entries[i],
725 sizeof(posix_acl_xattr_entry));
728 /* 2. process the non-deleted entries
729 * from client-side extended ACL. */
730 for (i = 0; i < ext_count; i++) {
731 if (le16_to_cpu(ext_header->a_entries[i].e_stat) !=
733 new->a_entries[j].e_tag =
734 ext_header->a_entries[i].e_tag;
735 new->a_entries[j].e_perm =
736 ext_header->a_entries[i].e_perm;
737 new->a_entries[j++].e_id =
738 ext_header->a_entries[i].e_id;
743 /* free unused space. */
744 rc = lustre_posix_acl_xattr_reduce_space(&new, posix_count, j);
754 OBD_FREE(new, posix_size);
759 EXPORT_SYMBOL(lustre_acl_xattr_merge2posix);
762 * Merge the posix ACL and the extended ACL into new extended ACL.
764 ext_acl_xattr_header *
765 lustre_acl_xattr_merge2ext(posix_acl_xattr_header *posix_header, int size,
766 ext_acl_xattr_header *ext_header)
768 int ori_ext_count, posix_count, ext_count, ext_size;
769 int i, j, pos = 0, rc = 0;
770 posix_acl_xattr_entry pae;
771 ext_acl_xattr_header *new;
772 ext_acl_xattr_entry *ee, eae;
775 if (unlikely(size < 0))
776 RETURN(ERR_PTR(-EINVAL));
780 posix_count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
781 ori_ext_count = le32_to_cpu(ext_header->a_count);
782 ext_count = posix_count + ori_ext_count;
783 ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr);
785 OBD_ALLOC(new, ext_size);
786 if (unlikely(new == NULL))
787 RETURN(ERR_PTR(-ENOMEM));
789 for (i = 0, j = 0; i < posix_count; i++) {
790 lustre_posix_acl_le_to_cpu(&pae, &posix_header->a_entries[i]);
796 if (pae.e_id != ACL_UNDEFINED_ID)
797 GOTO(out, rc = -EIO);
799 /* ignore "nobody" entry. */
800 if (pae.e_id == NOBODY_UID)
803 new->a_entries[j].e_tag =
804 posix_header->a_entries[i].e_tag;
805 new->a_entries[j].e_perm =
806 posix_header->a_entries[i].e_perm;
807 new->a_entries[j].e_id =
808 posix_header->a_entries[i].e_id;
809 ee = lustre_ext_acl_xattr_search(ext_header,
810 &posix_header->a_entries[i], &pos);
812 if (posix_header->a_entries[i].e_perm !=
814 /* entry modified. */
816 new->a_entries[j++].e_stat =
819 /* entry unchanged. */
821 new->a_entries[j++].e_stat =
825 new->a_entries[j++].e_stat =
830 /* ignore "nobody" entry. */
831 if (pae.e_id == NOBODY_GID)
833 new->a_entries[j].e_tag =
834 posix_header->a_entries[i].e_tag;
835 new->a_entries[j].e_perm =
836 posix_header->a_entries[i].e_perm;
837 new->a_entries[j].e_id =
838 posix_header->a_entries[i].e_id;
839 ee = lustre_ext_acl_xattr_search(ext_header,
840 &posix_header->a_entries[i], &pos);
842 if (posix_header->a_entries[i].e_perm !=
844 /* entry modified. */
846 new->a_entries[j++].e_stat =
849 /* entry unchanged. */
851 new->a_entries[j++].e_stat =
855 new->a_entries[j++].e_stat =
860 GOTO(out, rc = -EIO);
864 /* process deleted entries. */
865 for (i = 0; i < ori_ext_count; i++) {
866 lustre_ext_acl_le_to_cpu(&eae, &ext_header->a_entries[i]);
867 if (eae.e_stat == ES_UNK) {
868 /* ignore "nobody" entry. */
869 if ((eae.e_tag == ACL_USER && eae.e_id == NOBODY_UID) ||
870 (eae.e_tag == ACL_GROUP && eae.e_id == NOBODY_GID))
873 new->a_entries[j].e_tag =
874 ext_header->a_entries[i].e_tag;
875 new->a_entries[j].e_perm =
876 ext_header->a_entries[i].e_perm;
877 new->a_entries[j].e_id = ext_header->a_entries[i].e_id;
878 new->a_entries[j++].e_stat = cpu_to_le32(ES_DEL);
882 new->a_count = cpu_to_le32(j);
883 /* free unused space. */
884 rc = lustre_ext_acl_xattr_reduce_space(&new, ext_count);
889 OBD_FREE(new, ext_size);
894 EXPORT_SYMBOL(lustre_acl_xattr_merge2ext);