1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
6 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 only,
10 * as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License version 2 for more details (a copy is included
16 * in the LICENSE file that accompanied this code).
18 * You should have received a copy of the GNU General Public License
19 * version 2 along with this program; If not, see
20 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
22 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23 * CA 95054 USA or visit www.sun.com if you need additional information or
29 * Copyright 2008 Sun Microsystems, Inc. All rights reserved
30 * Use is subject to license terms.
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>
44 # define EXPORT_SYMTAB
47 #define DEBUG_SUBSYSTEM S_SEC
49 #include <linux/lustre_acl.h>
50 #include <lustre_eacl.h>
51 #include <obd_support.h>
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);
100 * Check permission based on POSIX ACL.
102 int lustre_posix_acl_permission(struct md_ucred *mu, struct lu_attr *la,
103 int want, posix_acl_xattr_entry *entry,
106 posix_acl_xattr_entry *pa, *pe, *mask_obj;
107 posix_acl_xattr_entry ae, me;
113 for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
114 lustre_posix_acl_le_to_cpu(&ae, pa);
117 /* (May have been checked already) */
118 if (la->la_uid == mu->mu_fsuid)
122 if (ae.e_id == mu->mu_fsuid)
126 if (lustre_in_group_p(mu, la->la_gid)) {
128 if ((ae.e_perm & want) == want)
133 if (lustre_in_group_p(mu, ae.e_id)) {
135 if ((ae.e_perm & want) == want)
153 for (mask_obj = pa + 1; mask_obj <= pe; mask_obj++) {
154 lustre_posix_acl_le_to_cpu(&me, mask_obj);
155 if (me.e_tag == ACL_MASK) {
156 if ((ae.e_perm & me.e_perm & want) == want)
164 if ((ae.e_perm & want) == want)
169 EXPORT_SYMBOL(lustre_posix_acl_permission);
172 * Modify the ACL for the chmod.
174 int lustre_posix_acl_chmod_masq(posix_acl_xattr_entry *entry, __u32 mode,
177 posix_acl_xattr_entry *group_obj = NULL, *mask_obj = NULL, *pa, *pe;
179 for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
180 switch (le16_to_cpu(pa->e_tag)) {
182 pa->e_perm = cpu_to_le16((mode & S_IRWXU) >> 6);
194 pa->e_perm = cpu_to_le16(mode & S_IRWXO);
202 mask_obj->e_perm = cpu_to_le16((mode & S_IRWXG) >> 3);
206 group_obj->e_perm = cpu_to_le16((mode & S_IRWXG) >> 3);
211 EXPORT_SYMBOL(lustre_posix_acl_chmod_masq);
214 * Modify acl when creating a new object.
216 int lustre_posix_acl_create_masq(posix_acl_xattr_entry *entry, __u32 *pmode,
219 posix_acl_xattr_entry *group_obj = NULL, *mask_obj = NULL, *pa, *pe;
220 posix_acl_xattr_entry ae;
224 for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
225 lustre_posix_acl_le_to_cpu(&ae, pa);
228 ae.e_perm &= (mode >> 6) | ~S_IRWXO;
229 pa->e_perm = cpu_to_le16(ae.e_perm);
230 mode &= (ae.e_perm << 6) | ~S_IRWXU;
240 ae.e_perm &= mode | ~S_IRWXO;
241 pa->e_perm = cpu_to_le16(ae.e_perm);
242 mode &= ae.e_perm | ~S_IRWXO;
254 ae.e_perm = le16_to_cpu(mask_obj->e_perm) &
255 ((mode >> 3) | ~S_IRWXO);
256 mode &= (ae.e_perm << 3) | ~S_IRWXG;
257 mask_obj->e_perm = cpu_to_le16(ae.e_perm);
261 ae.e_perm = le16_to_cpu(group_obj->e_perm) &
262 ((mode >> 3) | ~S_IRWXO);
263 mode &= (ae.e_perm << 3) | ~S_IRWXG;
264 group_obj->e_perm = cpu_to_le16(ae.e_perm);
267 *pmode = (*pmode & ~S_IRWXUGO) | mode;
270 EXPORT_SYMBOL(lustre_posix_acl_create_masq);
272 /* if "new_count == 0", then "new = {a_version, NULL}", NOT NULL. */
273 static int lustre_posix_acl_xattr_reduce_space(posix_acl_xattr_header **header,
274 int old_count, int new_count)
276 int old_size = CFS_ACL_XATTR_SIZE(old_count, posix_acl_xattr);
277 int new_size = CFS_ACL_XATTR_SIZE(new_count, posix_acl_xattr);
278 posix_acl_xattr_header *new;
280 if (unlikely(old_count <= new_count))
283 OBD_ALLOC(new, new_size);
284 if (unlikely(new == NULL))
287 memcpy(new, *header, new_size);
288 OBD_FREE(*header, old_size);
293 /* if "new_count == 0", then "new = {0, NULL}", NOT NULL. */
294 static int lustre_ext_acl_xattr_reduce_space(ext_acl_xattr_header **header,
297 int ext_count = le32_to_cpu((*header)->a_count);
298 int ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr);
299 int old_size = CFS_ACL_XATTR_SIZE(old_count, ext_acl_xattr);
300 ext_acl_xattr_header *new;
302 if (unlikely(old_count <= ext_count))
305 OBD_ALLOC(new, ext_size);
306 if (unlikely(new == NULL))
309 memcpy(new, *header, ext_size);
310 OBD_FREE(*header, old_size);
316 * Generate new extended ACL based on the posix ACL.
318 ext_acl_xattr_header *
319 lustre_posix_acl_xattr_2ext(posix_acl_xattr_header *header, int size)
322 ext_acl_xattr_header *new;
325 if (unlikely(size < 0))
326 RETURN(ERR_PTR(-EINVAL));
330 count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
331 esize = CFS_ACL_XATTR_SIZE(count, ext_acl_xattr);
332 OBD_ALLOC(new, esize);
333 if (unlikely(new == NULL))
334 RETURN(ERR_PTR(-ENOMEM));
336 new->a_count = cpu_to_le32(count);
337 for (i = 0; i < count; i++) {
338 new->a_entries[i].e_tag = header->a_entries[i].e_tag;
339 new->a_entries[i].e_perm = header->a_entries[i].e_perm;
340 new->a_entries[i].e_id = header->a_entries[i].e_id;
341 new->a_entries[i].e_stat = cpu_to_le32(ES_UNK);
346 EXPORT_SYMBOL(lustre_posix_acl_xattr_2ext);
349 * Filter out the "nobody" entries in the posix ACL.
351 int lustre_posix_acl_xattr_filter(posix_acl_xattr_header *header, int size,
352 posix_acl_xattr_header **out)
354 int count, i, j, rc = 0;
356 posix_acl_xattr_header *new;
359 if (unlikely(size < 0))
364 OBD_ALLOC(new, size);
365 if (unlikely(new == NULL))
368 new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
369 count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
370 for (i = 0, j = 0; i < count; i++) {
371 id = le32_to_cpu(header->a_entries[i].e_id);
372 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
377 if (id != ACL_UNDEFINED_ID)
378 GOTO(_out, rc = -EIO);
380 memcpy(&new->a_entries[j++], &header->a_entries[i],
381 sizeof(posix_acl_xattr_entry));
384 if (id != NOBODY_UID)
385 memcpy(&new->a_entries[j++],
386 &header->a_entries[i],
387 sizeof(posix_acl_xattr_entry));
390 if (id != NOBODY_GID)
391 memcpy(&new->a_entries[j++],
392 &header->a_entries[i],
393 sizeof(posix_acl_xattr_entry));
396 GOTO(_out, rc = -EIO);
400 /* free unused space. */
401 rc = lustre_posix_acl_xattr_reduce_space(&new, count, j);
416 EXPORT_SYMBOL(lustre_posix_acl_xattr_filter);
419 * Convert server-side uid/gid in the posix ACL items to the client-side ones.
422 * nothing to be converted.
424 * mapped ids are converted to client-side ones,
425 * unmapped ones are converted to "nobody".
427 * only mapped ids are converted to "nobody".
429 * only unmapped ids are converted to "nobody".
431 int lustre_posix_acl_xattr_id2client(struct md_ucred *mu,
432 struct lustre_idmap_table *t,
433 posix_acl_xattr_header *header,
440 if (unlikely(size < 0))
445 if (unlikely(flags == CFS_IC_NOTHING))
448 count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
449 for (i = 0; i < count; i++) {
450 id = le32_to_cpu(header->a_entries[i].e_id);
451 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
456 if (id != ACL_UNDEFINED_ID)
460 id = lustre_idmap_lookup_uid(mu, t, 1, id);
461 if (flags == CFS_IC_ALL) {
462 if (id == CFS_IDMAP_NOTFOUND)
464 header->a_entries[i].e_id = cpu_to_le32(id);
465 } else if (flags == CFS_IC_MAPPED) {
466 if (id != CFS_IDMAP_NOTFOUND)
467 header->a_entries[i].e_id =
468 cpu_to_le32(NOBODY_UID);
469 } else if (flags == CFS_IC_UNMAPPED) {
470 if (id == CFS_IDMAP_NOTFOUND)
471 header->a_entries[i].e_id =
472 cpu_to_le32(NOBODY_UID);
476 id = lustre_idmap_lookup_gid(mu, t, 1, id);
477 if (flags == CFS_IC_ALL) {
478 if (id == CFS_IDMAP_NOTFOUND)
480 header->a_entries[i].e_id = cpu_to_le32(id);
481 } else if (flags == CFS_IC_MAPPED) {
482 if (id != CFS_IDMAP_NOTFOUND)
483 header->a_entries[i].e_id =
484 cpu_to_le32(NOBODY_GID);
485 } else if (flags == CFS_IC_UNMAPPED) {
486 if (id == CFS_IDMAP_NOTFOUND)
487 header->a_entries[i].e_id =
488 cpu_to_le32(NOBODY_GID);
497 EXPORT_SYMBOL(lustre_posix_acl_xattr_id2client);
500 * Release the posix ACL space.
502 void lustre_posix_acl_xattr_free(posix_acl_xattr_header *header, int size)
504 OBD_FREE(header, size);
506 EXPORT_SYMBOL(lustre_posix_acl_xattr_free);
509 * Converts client-side uid/gid in the extended ACL items to server-side ones.
511 * mapped ids are converted to server-side ones,
512 * unmapped ones cause "EPERM" error.
514 int lustre_ext_acl_xattr_id2server(struct md_ucred *mu,
515 struct lustre_idmap_table *t,
516 ext_acl_xattr_header *header)
519 int i, count = le32_to_cpu(header->a_count);
523 for (i = 0; i < count; i++) {
524 id = le32_to_cpu(header->a_entries[i].e_id);
525 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
530 if (id != ACL_UNDEFINED_ID)
534 id = lustre_idmap_lookup_uid(mu, t, 0, id);
535 if (id == CFS_IDMAP_NOTFOUND)
538 header->a_entries[i].e_id = cpu_to_le32(id);
541 id = lustre_idmap_lookup_gid(mu, t, 0, id);
542 if (id == CFS_IDMAP_NOTFOUND)
545 header->a_entries[i].e_id = cpu_to_le32(id);
553 EXPORT_SYMBOL(lustre_ext_acl_xattr_id2server);
556 * Release the extended ACL space.
558 void lustre_ext_acl_xattr_free(ext_acl_xattr_header *header)
560 OBD_FREE(header, CFS_ACL_XATTR_SIZE(le32_to_cpu(header->a_count), \
563 EXPORT_SYMBOL(lustre_ext_acl_xattr_free);
565 static ext_acl_xattr_entry *
566 lustre_ext_acl_xattr_search(ext_acl_xattr_header *header,
567 posix_acl_xattr_entry *entry, int *pos)
569 int once, start, end, i, j, count = le32_to_cpu(header->a_count);
576 for (i = start; i < end; i++) {
577 if (header->a_entries[i].e_tag == entry->e_tag &&
578 header->a_entries[i].e_id == entry->e_id) {
583 return &header->a_entries[j];
598 * Merge the posix ACL and the extended ACL into new posix ACL.
600 int lustre_acl_xattr_merge2posix(posix_acl_xattr_header *posix_header, int size,
601 ext_acl_xattr_header *ext_header,
602 posix_acl_xattr_header **out)
604 int posix_count, posix_size, i, j;
605 int ext_count = le32_to_cpu(ext_header->a_count), pos = 0, rc = 0;
606 posix_acl_xattr_entry pe = {ACL_MASK, 0, ACL_UNDEFINED_ID};
607 posix_acl_xattr_header *new;
608 ext_acl_xattr_entry *ee, ae;
611 lustre_posix_acl_cpu_to_le(&pe, &pe);
612 ee = lustre_ext_acl_xattr_search(ext_header, &pe, &pos);
613 if (ee == NULL || le32_to_cpu(ee->e_stat) == ES_DEL) {
614 /* there are only base ACL entries at most. */
616 posix_size = CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
617 OBD_ALLOC(new, posix_size);
618 if (unlikely(new == NULL))
621 new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
622 for (i = 0, j = 0; i < ext_count; i++) {
623 lustre_ext_acl_le_to_cpu(&ae,
624 &ext_header->a_entries[i]);
629 if (ae.e_id != ACL_UNDEFINED_ID)
630 GOTO(_out, rc = -EIO);
632 if (ae.e_stat != ES_DEL) {
633 new->a_entries[j].e_tag =
634 ext_header->a_entries[i].e_tag;
635 new->a_entries[j].e_perm =
636 ext_header->a_entries[i].e_perm;
637 new->a_entries[j++].e_id =
638 ext_header->a_entries[i].e_id;
644 if (ae.e_stat == ES_DEL)
647 GOTO(_out, rc = -EIO);
651 /* maybe there are valid ACL_USER or ACL_GROUP entries in the
652 * original server-side ACL, they are regarded as ES_UNC stat.*/
655 if (unlikely(size < 0))
661 CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
662 posix_count = ori_posix_count + ext_count;
664 CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
665 OBD_ALLOC(new, posix_size);
666 if (unlikely(new == NULL))
669 new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
670 /* 1. process the unchanged ACL entries
671 * in the original server-side ACL. */
673 for (i = 0, j = 0; i < ori_posix_count; i++) {
674 ee = lustre_ext_acl_xattr_search(ext_header,
675 &posix_header->a_entries[i], &pos);
677 memcpy(&new->a_entries[j++],
678 &posix_header->a_entries[i],
679 sizeof(posix_acl_xattr_entry));
682 /* 2. process the non-deleted entries
683 * from client-side extended ACL. */
684 for (i = 0; i < ext_count; i++) {
685 if (le16_to_cpu(ext_header->a_entries[i].e_stat) !=
687 new->a_entries[j].e_tag =
688 ext_header->a_entries[i].e_tag;
689 new->a_entries[j].e_perm =
690 ext_header->a_entries[i].e_perm;
691 new->a_entries[j++].e_id =
692 ext_header->a_entries[i].e_id;
697 /* free unused space. */
698 rc = lustre_posix_acl_xattr_reduce_space(&new, posix_count, j);
708 OBD_FREE(new, posix_size);
713 EXPORT_SYMBOL(lustre_acl_xattr_merge2posix);
716 * Merge the posix ACL and the extended ACL into new extended ACL.
718 ext_acl_xattr_header *
719 lustre_acl_xattr_merge2ext(posix_acl_xattr_header *posix_header, int size,
720 ext_acl_xattr_header *ext_header)
722 int ori_ext_count, posix_count, ext_count, ext_size;
723 int i, j, pos = 0, rc = 0;
724 posix_acl_xattr_entry pae;
725 ext_acl_xattr_header *new;
726 ext_acl_xattr_entry *ee, eae;
729 if (unlikely(size < 0))
730 RETURN(ERR_PTR(-EINVAL));
734 posix_count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
735 ori_ext_count = le32_to_cpu(ext_header->a_count);
736 ext_count = posix_count + ori_ext_count;
737 ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr);
739 OBD_ALLOC(new, ext_size);
740 if (unlikely(new == NULL))
741 RETURN(ERR_PTR(-ENOMEM));
743 for (i = 0, j = 0; i < posix_count; i++) {
744 lustre_posix_acl_le_to_cpu(&pae, &posix_header->a_entries[i]);
750 if (pae.e_id != ACL_UNDEFINED_ID)
751 GOTO(out, rc = -EIO);
753 /* ignore "nobody" entry. */
754 if (pae.e_id == NOBODY_UID)
757 new->a_entries[j].e_tag =
758 posix_header->a_entries[i].e_tag;
759 new->a_entries[j].e_perm =
760 posix_header->a_entries[i].e_perm;
761 new->a_entries[j].e_id =
762 posix_header->a_entries[i].e_id;
763 ee = lustre_ext_acl_xattr_search(ext_header,
764 &posix_header->a_entries[i], &pos);
766 if (posix_header->a_entries[i].e_perm !=
768 /* entry modified. */
770 new->a_entries[j++].e_stat =
773 /* entry unchanged. */
775 new->a_entries[j++].e_stat =
779 new->a_entries[j++].e_stat =
784 /* ignore "nobody" entry. */
785 if (pae.e_id == NOBODY_GID)
787 new->a_entries[j].e_tag =
788 posix_header->a_entries[i].e_tag;
789 new->a_entries[j].e_perm =
790 posix_header->a_entries[i].e_perm;
791 new->a_entries[j].e_id =
792 posix_header->a_entries[i].e_id;
793 ee = lustre_ext_acl_xattr_search(ext_header,
794 &posix_header->a_entries[i], &pos);
796 if (posix_header->a_entries[i].e_perm !=
798 /* entry modified. */
800 new->a_entries[j++].e_stat =
803 /* entry unchanged. */
805 new->a_entries[j++].e_stat =
809 new->a_entries[j++].e_stat =
814 GOTO(out, rc = -EIO);
818 /* process deleted entries. */
819 for (i = 0; i < ori_ext_count; i++) {
820 lustre_ext_acl_le_to_cpu(&eae, &ext_header->a_entries[i]);
821 if (eae.e_stat == ES_UNK) {
822 /* ignore "nobody" entry. */
823 if ((eae.e_tag == ACL_USER && eae.e_id == NOBODY_UID) ||
824 (eae.e_tag == ACL_GROUP && eae.e_id == NOBODY_GID))
827 new->a_entries[j].e_tag =
828 ext_header->a_entries[i].e_tag;
829 new->a_entries[j].e_perm =
830 ext_header->a_entries[i].e_perm;
831 new->a_entries[j].e_id = ext_header->a_entries[i].e_id;
832 new->a_entries[j++].e_stat = cpu_to_le32(ES_DEL);
836 new->a_count = cpu_to_le32(j);
837 /* free unused space. */
838 rc = lustre_ext_acl_xattr_reduce_space(&new, ext_count);
843 OBD_FREE(new, ext_size);
848 EXPORT_SYMBOL(lustre_acl_xattr_merge2ext);