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>
42 # define EXPORT_SYMTAB
45 #define DEBUG_SUBSYSTEM S_SEC
47 #include <lustre_acl.h>
48 #include <lustre_eacl.h>
49 #include <obd_support.h>
51 #ifdef CONFIG_FS_POSIX_ACL
53 #define CFS_ACL_XATTR_VERSION POSIX_ACL_XATTR_VERSION
56 ES_UNK = 0, /* unknown stat */
57 ES_UNC = 1, /* ACL entry is not changed */
58 ES_MOD = 2, /* ACL entry is modified */
59 ES_ADD = 3, /* ACL entry is added */
60 ES_DEL = 4 /* ACL entry is deleted */
63 static inline void lustre_ext_acl_le_to_cpu(ext_acl_xattr_entry *d,
64 ext_acl_xattr_entry *s)
66 d->e_tag = le16_to_cpu(s->e_tag);
67 d->e_perm = le16_to_cpu(s->e_perm);
68 d->e_id = le32_to_cpu(s->e_id);
69 d->e_stat = le32_to_cpu(s->e_stat);
72 static inline void lustre_ext_acl_cpu_to_le(ext_acl_xattr_entry *d,
73 ext_acl_xattr_entry *s)
75 d->e_tag = cpu_to_le16(s->e_tag);
76 d->e_perm = cpu_to_le16(s->e_perm);
77 d->e_id = cpu_to_le32(s->e_id);
78 d->e_stat = cpu_to_le32(s->e_stat);
81 static inline void lustre_posix_acl_le_to_cpu(posix_acl_xattr_entry *d,
82 posix_acl_xattr_entry *s)
84 d->e_tag = le16_to_cpu(s->e_tag);
85 d->e_perm = le16_to_cpu(s->e_perm);
86 d->e_id = le32_to_cpu(s->e_id);
89 static inline void lustre_posix_acl_cpu_to_le(posix_acl_xattr_entry *d,
90 posix_acl_xattr_entry *s)
92 d->e_tag = cpu_to_le16(s->e_tag);
93 d->e_perm = cpu_to_le16(s->e_perm);
94 d->e_id = cpu_to_le32(s->e_id);
98 * Check permission based on POSIX ACL.
100 int lustre_posix_acl_permission(struct md_ucred *mu, struct lu_attr *la,
101 int want, posix_acl_xattr_entry *entry,
104 posix_acl_xattr_entry *pa, *pe, *mask_obj;
105 posix_acl_xattr_entry ae, me;
111 for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
112 lustre_posix_acl_le_to_cpu(&ae, pa);
115 /* (May have been checked already) */
116 if (la->la_uid == mu->mu_fsuid)
120 if (ae.e_id == mu->mu_fsuid)
124 if (lustre_in_group_p(mu, la->la_gid)) {
126 if ((ae.e_perm & want) == want)
131 if (lustre_in_group_p(mu, ae.e_id)) {
133 if ((ae.e_perm & want) == want)
151 for (mask_obj = pa + 1; mask_obj <= pe; mask_obj++) {
152 lustre_posix_acl_le_to_cpu(&me, mask_obj);
153 if (me.e_tag == ACL_MASK) {
154 if ((ae.e_perm & me.e_perm & want) == want)
162 if ((ae.e_perm & want) == want)
167 EXPORT_SYMBOL(lustre_posix_acl_permission);
170 * Modify the ACL for the chmod.
172 int lustre_posix_acl_chmod_masq(posix_acl_xattr_entry *entry, __u32 mode,
175 posix_acl_xattr_entry *group_obj = NULL, *mask_obj = NULL, *pa, *pe;
177 for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
178 switch (le16_to_cpu(pa->e_tag)) {
180 pa->e_perm = cpu_to_le16((mode & S_IRWXU) >> 6);
192 pa->e_perm = cpu_to_le16(mode & S_IRWXO);
200 mask_obj->e_perm = cpu_to_le16((mode & S_IRWXG) >> 3);
204 group_obj->e_perm = cpu_to_le16((mode & S_IRWXG) >> 3);
209 EXPORT_SYMBOL(lustre_posix_acl_chmod_masq);
212 * Modify acl when creating a new object.
214 int lustre_posix_acl_create_masq(posix_acl_xattr_entry *entry, __u32 *pmode,
217 posix_acl_xattr_entry *group_obj = NULL, *mask_obj = NULL, *pa, *pe;
218 posix_acl_xattr_entry ae;
222 for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
223 lustre_posix_acl_le_to_cpu(&ae, pa);
226 ae.e_perm &= (mode >> 6) | ~S_IRWXO;
227 pa->e_perm = cpu_to_le16(ae.e_perm);
228 mode &= (ae.e_perm << 6) | ~S_IRWXU;
238 ae.e_perm &= mode | ~S_IRWXO;
239 pa->e_perm = cpu_to_le16(ae.e_perm);
240 mode &= ae.e_perm | ~S_IRWXO;
252 ae.e_perm = le16_to_cpu(mask_obj->e_perm) &
253 ((mode >> 3) | ~S_IRWXO);
254 mode &= (ae.e_perm << 3) | ~S_IRWXG;
255 mask_obj->e_perm = cpu_to_le16(ae.e_perm);
259 ae.e_perm = le16_to_cpu(group_obj->e_perm) &
260 ((mode >> 3) | ~S_IRWXO);
261 mode &= (ae.e_perm << 3) | ~S_IRWXG;
262 group_obj->e_perm = cpu_to_le16(ae.e_perm);
265 *pmode = (*pmode & ~S_IRWXUGO) | mode;
268 EXPORT_SYMBOL(lustre_posix_acl_create_masq);
270 /* if "new_count == 0", then "new = {a_version, NULL}", NOT NULL. */
271 static int lustre_posix_acl_xattr_reduce_space(posix_acl_xattr_header **header,
272 int old_count, int new_count)
274 int old_size = CFS_ACL_XATTR_SIZE(old_count, posix_acl_xattr);
275 int new_size = CFS_ACL_XATTR_SIZE(new_count, posix_acl_xattr);
276 posix_acl_xattr_header *new;
278 if (unlikely(old_count <= new_count))
281 OBD_ALLOC(new, new_size);
282 if (unlikely(new == NULL))
285 memcpy(new, *header, new_size);
286 OBD_FREE(*header, old_size);
291 /* if "new_count == 0", then "new = {0, NULL}", NOT NULL. */
292 static int lustre_ext_acl_xattr_reduce_space(ext_acl_xattr_header **header,
295 int ext_count = le32_to_cpu((*header)->a_count);
296 int ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr);
297 int old_size = CFS_ACL_XATTR_SIZE(old_count, ext_acl_xattr);
298 ext_acl_xattr_header *new;
300 if (unlikely(old_count <= ext_count))
303 OBD_ALLOC(new, ext_size);
304 if (unlikely(new == NULL))
307 memcpy(new, *header, ext_size);
308 OBD_FREE(*header, old_size);
314 * Generate new extended ACL based on the posix ACL.
316 ext_acl_xattr_header *
317 lustre_posix_acl_xattr_2ext(posix_acl_xattr_header *header, int size)
320 ext_acl_xattr_header *new;
323 if (unlikely(size < 0))
324 RETURN(ERR_PTR(-EINVAL));
328 count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
329 esize = CFS_ACL_XATTR_SIZE(count, ext_acl_xattr);
330 OBD_ALLOC(new, esize);
331 if (unlikely(new == NULL))
332 RETURN(ERR_PTR(-ENOMEM));
334 new->a_count = cpu_to_le32(count);
335 for (i = 0; i < count; i++) {
336 new->a_entries[i].e_tag = header->a_entries[i].e_tag;
337 new->a_entries[i].e_perm = header->a_entries[i].e_perm;
338 new->a_entries[i].e_id = header->a_entries[i].e_id;
339 new->a_entries[i].e_stat = cpu_to_le32(ES_UNK);
344 EXPORT_SYMBOL(lustre_posix_acl_xattr_2ext);
347 * Filter out the "nobody" entries in the posix ACL.
349 int lustre_posix_acl_xattr_filter(posix_acl_xattr_header *header, int size,
350 posix_acl_xattr_header **out)
352 int count, i, j, rc = 0;
354 posix_acl_xattr_header *new;
357 if (unlikely(size < 0))
362 OBD_ALLOC(new, size);
363 if (unlikely(new == NULL))
366 new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
367 count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
368 for (i = 0, j = 0; i < count; i++) {
369 id = le32_to_cpu(header->a_entries[i].e_id);
370 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
375 if (id != ACL_UNDEFINED_ID)
376 GOTO(_out, rc = -EIO);
378 memcpy(&new->a_entries[j++], &header->a_entries[i],
379 sizeof(posix_acl_xattr_entry));
382 if (id != NOBODY_UID)
383 memcpy(&new->a_entries[j++],
384 &header->a_entries[i],
385 sizeof(posix_acl_xattr_entry));
388 if (id != NOBODY_GID)
389 memcpy(&new->a_entries[j++],
390 &header->a_entries[i],
391 sizeof(posix_acl_xattr_entry));
394 GOTO(_out, rc = -EIO);
398 /* free unused space. */
399 rc = lustre_posix_acl_xattr_reduce_space(&new, count, j);
414 EXPORT_SYMBOL(lustre_posix_acl_xattr_filter);
417 * Convert server-side uid/gid in the posix ACL items to the client-side ones.
420 * nothing to be converted.
422 * mapped ids are converted to client-side ones,
423 * unmapped ones are converted to "nobody".
425 * only mapped ids are converted to "nobody".
427 * only unmapped ids are converted to "nobody".
429 int lustre_posix_acl_xattr_id2client(struct md_ucred *mu,
430 struct lustre_idmap_table *t,
431 posix_acl_xattr_header *header,
438 if (unlikely(size < 0))
443 if (unlikely(flags == CFS_IC_NOTHING))
446 count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
447 for (i = 0; i < count; i++) {
448 id = le32_to_cpu(header->a_entries[i].e_id);
449 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
454 if (id != ACL_UNDEFINED_ID)
458 id = lustre_idmap_lookup_uid(mu, t, 1, id);
459 if (flags == CFS_IC_ALL) {
460 if (id == CFS_IDMAP_NOTFOUND)
462 header->a_entries[i].e_id = cpu_to_le32(id);
463 } else if (flags == CFS_IC_MAPPED) {
464 if (id != CFS_IDMAP_NOTFOUND)
465 header->a_entries[i].e_id =
466 cpu_to_le32(NOBODY_UID);
467 } else if (flags == CFS_IC_UNMAPPED) {
468 if (id == CFS_IDMAP_NOTFOUND)
469 header->a_entries[i].e_id =
470 cpu_to_le32(NOBODY_UID);
474 id = lustre_idmap_lookup_gid(mu, t, 1, id);
475 if (flags == CFS_IC_ALL) {
476 if (id == CFS_IDMAP_NOTFOUND)
478 header->a_entries[i].e_id = cpu_to_le32(id);
479 } else if (flags == CFS_IC_MAPPED) {
480 if (id != CFS_IDMAP_NOTFOUND)
481 header->a_entries[i].e_id =
482 cpu_to_le32(NOBODY_GID);
483 } else if (flags == CFS_IC_UNMAPPED) {
484 if (id == CFS_IDMAP_NOTFOUND)
485 header->a_entries[i].e_id =
486 cpu_to_le32(NOBODY_GID);
495 EXPORT_SYMBOL(lustre_posix_acl_xattr_id2client);
498 * Release the posix ACL space.
500 void lustre_posix_acl_xattr_free(posix_acl_xattr_header *header, int size)
502 OBD_FREE(header, size);
504 EXPORT_SYMBOL(lustre_posix_acl_xattr_free);
507 * Converts client-side uid/gid in the extended ACL items to server-side ones.
509 * mapped ids are converted to server-side ones,
510 * unmapped ones cause "EPERM" error.
512 int lustre_ext_acl_xattr_id2server(struct md_ucred *mu,
513 struct lustre_idmap_table *t,
514 ext_acl_xattr_header *header)
517 int i, count = le32_to_cpu(header->a_count);
521 for (i = 0; i < count; i++) {
522 id = le32_to_cpu(header->a_entries[i].e_id);
523 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
528 if (id != ACL_UNDEFINED_ID)
532 id = lustre_idmap_lookup_uid(mu, t, 0, id);
533 if (id == CFS_IDMAP_NOTFOUND)
536 header->a_entries[i].e_id = cpu_to_le32(id);
539 id = lustre_idmap_lookup_gid(mu, t, 0, id);
540 if (id == CFS_IDMAP_NOTFOUND)
543 header->a_entries[i].e_id = cpu_to_le32(id);
551 EXPORT_SYMBOL(lustre_ext_acl_xattr_id2server);
554 * Release the extended ACL space.
556 void lustre_ext_acl_xattr_free(ext_acl_xattr_header *header)
558 OBD_FREE(header, CFS_ACL_XATTR_SIZE(le32_to_cpu(header->a_count), \
561 EXPORT_SYMBOL(lustre_ext_acl_xattr_free);
563 static ext_acl_xattr_entry *
564 lustre_ext_acl_xattr_search(ext_acl_xattr_header *header,
565 posix_acl_xattr_entry *entry, int *pos)
567 int once, start, end, i, j, count = le32_to_cpu(header->a_count);
574 for (i = start; i < end; i++) {
575 if (header->a_entries[i].e_tag == entry->e_tag &&
576 header->a_entries[i].e_id == entry->e_id) {
581 return &header->a_entries[j];
596 * Merge the posix ACL and the extended ACL into new posix ACL.
598 int lustre_acl_xattr_merge2posix(posix_acl_xattr_header *posix_header, int size,
599 ext_acl_xattr_header *ext_header,
600 posix_acl_xattr_header **out)
602 int posix_count, posix_size, i, j;
603 int ext_count = le32_to_cpu(ext_header->a_count), pos = 0, rc = 0;
604 posix_acl_xattr_entry pe = {ACL_MASK, 0, ACL_UNDEFINED_ID};
605 posix_acl_xattr_header *new;
606 ext_acl_xattr_entry *ee, ae;
609 lustre_posix_acl_cpu_to_le(&pe, &pe);
610 ee = lustre_ext_acl_xattr_search(ext_header, &pe, &pos);
611 if (ee == NULL || le32_to_cpu(ee->e_stat) == ES_DEL) {
612 /* there are only base ACL entries at most. */
614 posix_size = CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
615 OBD_ALLOC(new, posix_size);
616 if (unlikely(new == NULL))
619 new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
620 for (i = 0, j = 0; i < ext_count; i++) {
621 lustre_ext_acl_le_to_cpu(&ae,
622 &ext_header->a_entries[i]);
627 if (ae.e_id != ACL_UNDEFINED_ID)
628 GOTO(_out, rc = -EIO);
630 if (ae.e_stat != ES_DEL) {
631 new->a_entries[j].e_tag =
632 ext_header->a_entries[i].e_tag;
633 new->a_entries[j].e_perm =
634 ext_header->a_entries[i].e_perm;
635 new->a_entries[j++].e_id =
636 ext_header->a_entries[i].e_id;
642 if (ae.e_stat == ES_DEL)
645 GOTO(_out, rc = -EIO);
649 /* maybe there are valid ACL_USER or ACL_GROUP entries in the
650 * original server-side ACL, they are regarded as ES_UNC stat.*/
653 if (unlikely(size < 0))
659 CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
660 posix_count = ori_posix_count + ext_count;
662 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 /* 1. process the unchanged ACL entries
669 * in the original server-side ACL. */
671 for (i = 0, j = 0; i < ori_posix_count; i++) {
672 ee = lustre_ext_acl_xattr_search(ext_header,
673 &posix_header->a_entries[i], &pos);
675 memcpy(&new->a_entries[j++],
676 &posix_header->a_entries[i],
677 sizeof(posix_acl_xattr_entry));
680 /* 2. process the non-deleted entries
681 * from client-side extended ACL. */
682 for (i = 0; i < ext_count; i++) {
683 if (le16_to_cpu(ext_header->a_entries[i].e_stat) !=
685 new->a_entries[j].e_tag =
686 ext_header->a_entries[i].e_tag;
687 new->a_entries[j].e_perm =
688 ext_header->a_entries[i].e_perm;
689 new->a_entries[j++].e_id =
690 ext_header->a_entries[i].e_id;
695 /* free unused space. */
696 rc = lustre_posix_acl_xattr_reduce_space(&new, posix_count, j);
706 OBD_FREE(new, posix_size);
711 EXPORT_SYMBOL(lustre_acl_xattr_merge2posix);
714 * Merge the posix ACL and the extended ACL into new extended ACL.
716 ext_acl_xattr_header *
717 lustre_acl_xattr_merge2ext(posix_acl_xattr_header *posix_header, int size,
718 ext_acl_xattr_header *ext_header)
720 int ori_ext_count, posix_count, ext_count, ext_size;
721 int i, j, pos = 0, rc = 0;
722 posix_acl_xattr_entry pae;
723 ext_acl_xattr_header *new;
724 ext_acl_xattr_entry *ee, eae;
727 if (unlikely(size < 0))
728 RETURN(ERR_PTR(-EINVAL));
732 posix_count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
733 ori_ext_count = le32_to_cpu(ext_header->a_count);
734 ext_count = posix_count + ori_ext_count;
735 ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr);
737 OBD_ALLOC(new, ext_size);
738 if (unlikely(new == NULL))
739 RETURN(ERR_PTR(-ENOMEM));
741 for (i = 0, j = 0; i < posix_count; i++) {
742 lustre_posix_acl_le_to_cpu(&pae, &posix_header->a_entries[i]);
748 if (pae.e_id != ACL_UNDEFINED_ID)
749 GOTO(out, rc = -EIO);
751 /* ignore "nobody" entry. */
752 if (pae.e_id == NOBODY_UID)
755 new->a_entries[j].e_tag =
756 posix_header->a_entries[i].e_tag;
757 new->a_entries[j].e_perm =
758 posix_header->a_entries[i].e_perm;
759 new->a_entries[j].e_id =
760 posix_header->a_entries[i].e_id;
761 ee = lustre_ext_acl_xattr_search(ext_header,
762 &posix_header->a_entries[i], &pos);
764 if (posix_header->a_entries[i].e_perm !=
766 /* entry modified. */
768 new->a_entries[j++].e_stat =
771 /* entry unchanged. */
773 new->a_entries[j++].e_stat =
777 new->a_entries[j++].e_stat =
782 /* ignore "nobody" entry. */
783 if (pae.e_id == NOBODY_GID)
785 new->a_entries[j].e_tag =
786 posix_header->a_entries[i].e_tag;
787 new->a_entries[j].e_perm =
788 posix_header->a_entries[i].e_perm;
789 new->a_entries[j].e_id =
790 posix_header->a_entries[i].e_id;
791 ee = lustre_ext_acl_xattr_search(ext_header,
792 &posix_header->a_entries[i], &pos);
794 if (posix_header->a_entries[i].e_perm !=
796 /* entry modified. */
798 new->a_entries[j++].e_stat =
801 /* entry unchanged. */
803 new->a_entries[j++].e_stat =
807 new->a_entries[j++].e_stat =
812 GOTO(out, rc = -EIO);
816 /* process deleted entries. */
817 for (i = 0; i < ori_ext_count; i++) {
818 lustre_ext_acl_le_to_cpu(&eae, &ext_header->a_entries[i]);
819 if (eae.e_stat == ES_UNK) {
820 /* ignore "nobody" entry. */
821 if ((eae.e_tag == ACL_USER && eae.e_id == NOBODY_UID) ||
822 (eae.e_tag == ACL_GROUP && eae.e_id == NOBODY_GID))
825 new->a_entries[j].e_tag =
826 ext_header->a_entries[i].e_tag;
827 new->a_entries[j].e_perm =
828 ext_header->a_entries[i].e_perm;
829 new->a_entries[j].e_id = ext_header->a_entries[i].e_id;
830 new->a_entries[j++].e_stat = cpu_to_le32(ES_DEL);
834 new->a_count = cpu_to_le32(j);
835 /* free unused space. */
836 rc = lustre_ext_acl_xattr_reduce_space(&new, ext_count);
841 OBD_FREE(new, ext_size);
846 EXPORT_SYMBOL(lustre_acl_xattr_merge2ext);