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 * Modify acl when creating a new object.
210 int lustre_posix_acl_create_masq(posix_acl_xattr_entry *entry, __u32 *pmode,
213 posix_acl_xattr_entry *group_obj = NULL, *mask_obj = NULL, *pa, *pe;
214 posix_acl_xattr_entry ae;
218 for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
219 lustre_posix_acl_le_to_cpu(&ae, pa);
222 ae.e_perm &= (mode >> 6) | ~S_IRWXO;
223 pa->e_perm = cpu_to_le16(ae.e_perm);
224 mode &= (ae.e_perm << 6) | ~S_IRWXU;
234 ae.e_perm &= mode | ~S_IRWXO;
235 pa->e_perm = cpu_to_le16(ae.e_perm);
236 mode &= ae.e_perm | ~S_IRWXO;
248 ae.e_perm = le16_to_cpu(mask_obj->e_perm) &
249 ((mode >> 3) | ~S_IRWXO);
250 mode &= (ae.e_perm << 3) | ~S_IRWXG;
251 mask_obj->e_perm = cpu_to_le16(ae.e_perm);
255 ae.e_perm = le16_to_cpu(group_obj->e_perm) &
256 ((mode >> 3) | ~S_IRWXO);
257 mode &= (ae.e_perm << 3) | ~S_IRWXG;
258 group_obj->e_perm = cpu_to_le16(ae.e_perm);
261 *pmode = (*pmode & ~S_IRWXUGO) | mode;
264 EXPORT_SYMBOL(lustre_posix_acl_create_masq);
266 /* if "new_count == 0", then "new = {a_version, NULL}", NOT NULL. */
267 static int lustre_posix_acl_xattr_reduce_space(posix_acl_xattr_header **header,
268 int old_count, int new_count)
270 int old_size = CFS_ACL_XATTR_SIZE(old_count, posix_acl_xattr);
271 int new_size = CFS_ACL_XATTR_SIZE(new_count, posix_acl_xattr);
272 posix_acl_xattr_header *new;
274 if (unlikely(old_count <= new_count))
277 OBD_ALLOC(new, new_size);
278 if (unlikely(new == NULL))
281 memcpy(new, *header, new_size);
282 OBD_FREE(*header, old_size);
287 /* if "new_count == 0", then "new = {0, NULL}", NOT NULL. */
288 static int lustre_ext_acl_xattr_reduce_space(ext_acl_xattr_header **header,
291 int ext_count = le32_to_cpu((*header)->a_count);
292 int ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr);
293 int old_size = CFS_ACL_XATTR_SIZE(old_count, ext_acl_xattr);
294 ext_acl_xattr_header *new;
296 if (unlikely(old_count <= ext_count))
299 OBD_ALLOC(new, ext_size);
300 if (unlikely(new == NULL))
303 memcpy(new, *header, ext_size);
304 OBD_FREE(*header, old_size);
310 * Generate new extended ACL based on the posix ACL.
312 ext_acl_xattr_header *
313 lustre_posix_acl_xattr_2ext(posix_acl_xattr_header *header, int size)
316 ext_acl_xattr_header *new;
319 if (unlikely(size < 0))
320 RETURN(ERR_PTR(-EINVAL));
324 count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
325 esize = CFS_ACL_XATTR_SIZE(count, ext_acl_xattr);
326 OBD_ALLOC(new, esize);
327 if (unlikely(new == NULL))
328 RETURN(ERR_PTR(-ENOMEM));
330 new->a_count = cpu_to_le32(count);
331 for (i = 0; i < count; i++) {
332 new->a_entries[i].e_tag = header->a_entries[i].e_tag;
333 new->a_entries[i].e_perm = header->a_entries[i].e_perm;
334 new->a_entries[i].e_id = header->a_entries[i].e_id;
335 new->a_entries[i].e_stat = cpu_to_le32(ES_UNK);
340 EXPORT_SYMBOL(lustre_posix_acl_xattr_2ext);
343 * Filter out the "nobody" entries in the posix ACL.
345 int lustre_posix_acl_xattr_filter(posix_acl_xattr_header *header, int size,
346 posix_acl_xattr_header **out)
348 int count, i, j, rc = 0;
350 posix_acl_xattr_header *new;
353 if (unlikely(size < 0))
358 OBD_ALLOC(new, size);
359 if (unlikely(new == NULL))
362 new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
363 count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
364 for (i = 0, j = 0; i < count; i++) {
365 id = le32_to_cpu(header->a_entries[i].e_id);
366 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
371 if (id != ACL_UNDEFINED_ID)
372 GOTO(_out, rc = -EIO);
374 memcpy(&new->a_entries[j++], &header->a_entries[i],
375 sizeof(posix_acl_xattr_entry));
378 if (id != NOBODY_UID)
379 memcpy(&new->a_entries[j++],
380 &header->a_entries[i],
381 sizeof(posix_acl_xattr_entry));
384 if (id != NOBODY_GID)
385 memcpy(&new->a_entries[j++],
386 &header->a_entries[i],
387 sizeof(posix_acl_xattr_entry));
390 GOTO(_out, rc = -EIO);
394 /* free unused space. */
395 rc = lustre_posix_acl_xattr_reduce_space(&new, count, j);
410 EXPORT_SYMBOL(lustre_posix_acl_xattr_filter);
413 * Convert server-side uid/gid in the posix ACL items to the client-side ones.
416 * nothing to be converted.
418 * mapped ids are converted to client-side ones,
419 * unmapped ones are converted to "nobody".
421 * only mapped ids are converted to "nobody".
423 * only unmapped ids are converted to "nobody".
425 int lustre_posix_acl_xattr_id2client(struct md_ucred *mu,
426 struct lustre_idmap_table *t,
427 posix_acl_xattr_header *header,
434 if (unlikely(size < 0))
439 if (unlikely(flags == CFS_IC_NOTHING))
442 count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
443 for (i = 0; i < count; i++) {
444 id = le32_to_cpu(header->a_entries[i].e_id);
445 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
450 if (id != ACL_UNDEFINED_ID)
454 id = lustre_idmap_lookup_uid(mu, t, 1, id);
455 if (flags == CFS_IC_ALL) {
456 if (id == CFS_IDMAP_NOTFOUND)
458 header->a_entries[i].e_id = cpu_to_le32(id);
459 } else if (flags == CFS_IC_MAPPED) {
460 if (id != CFS_IDMAP_NOTFOUND)
461 header->a_entries[i].e_id =
462 cpu_to_le32(NOBODY_UID);
463 } else if (flags == CFS_IC_UNMAPPED) {
464 if (id == CFS_IDMAP_NOTFOUND)
465 header->a_entries[i].e_id =
466 cpu_to_le32(NOBODY_UID);
470 id = lustre_idmap_lookup_gid(mu, t, 1, id);
471 if (flags == CFS_IC_ALL) {
472 if (id == CFS_IDMAP_NOTFOUND)
474 header->a_entries[i].e_id = cpu_to_le32(id);
475 } else if (flags == CFS_IC_MAPPED) {
476 if (id != CFS_IDMAP_NOTFOUND)
477 header->a_entries[i].e_id =
478 cpu_to_le32(NOBODY_GID);
479 } else if (flags == CFS_IC_UNMAPPED) {
480 if (id == CFS_IDMAP_NOTFOUND)
481 header->a_entries[i].e_id =
482 cpu_to_le32(NOBODY_GID);
491 EXPORT_SYMBOL(lustre_posix_acl_xattr_id2client);
494 * Release the posix ACL space.
496 void lustre_posix_acl_xattr_free(posix_acl_xattr_header *header, int size)
498 OBD_FREE(header, size);
500 EXPORT_SYMBOL(lustre_posix_acl_xattr_free);
503 * Converts client-side uid/gid in the extended ACL items to server-side ones.
505 * mapped ids are converted to server-side ones,
506 * unmapped ones cause "EPERM" error.
508 int lustre_ext_acl_xattr_id2server(struct md_ucred *mu,
509 struct lustre_idmap_table *t,
510 ext_acl_xattr_header *header)
513 int i, count = le32_to_cpu(header->a_count);
517 for (i = 0; i < count; i++) {
518 id = le32_to_cpu(header->a_entries[i].e_id);
519 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
524 if (id != ACL_UNDEFINED_ID)
528 id = lustre_idmap_lookup_uid(mu, t, 0, id);
529 if (id == CFS_IDMAP_NOTFOUND)
532 header->a_entries[i].e_id = cpu_to_le32(id);
535 id = lustre_idmap_lookup_gid(mu, t, 0, id);
536 if (id == CFS_IDMAP_NOTFOUND)
539 header->a_entries[i].e_id = cpu_to_le32(id);
547 EXPORT_SYMBOL(lustre_ext_acl_xattr_id2server);
550 * Release the extended ACL space.
552 void lustre_ext_acl_xattr_free(ext_acl_xattr_header *header)
554 OBD_FREE(header, CFS_ACL_XATTR_SIZE(le32_to_cpu(header->a_count), \
557 EXPORT_SYMBOL(lustre_ext_acl_xattr_free);
559 static ext_acl_xattr_entry *
560 lustre_ext_acl_xattr_search(ext_acl_xattr_header *header,
561 posix_acl_xattr_entry *entry, int *pos)
563 int once, start, end, i, j, count = le32_to_cpu(header->a_count);
570 for (i = start; i < end; i++) {
571 if (header->a_entries[i].e_tag == entry->e_tag &&
572 header->a_entries[i].e_id == entry->e_id) {
577 return &header->a_entries[j];
592 * Merge the posix ACL and the extended ACL into new posix ACL.
594 int lustre_acl_xattr_merge2posix(posix_acl_xattr_header *posix_header, int size,
595 ext_acl_xattr_header *ext_header,
596 posix_acl_xattr_header **out)
598 int posix_count, posix_size, i, j;
599 int ext_count = le32_to_cpu(ext_header->a_count), pos = 0, rc = 0;
600 posix_acl_xattr_entry pe = {ACL_MASK, 0, ACL_UNDEFINED_ID};
601 posix_acl_xattr_header *new;
602 ext_acl_xattr_entry *ee, ae;
605 lustre_posix_acl_cpu_to_le(&pe, &pe);
606 ee = lustre_ext_acl_xattr_search(ext_header, &pe, &pos);
607 if (ee == NULL || le32_to_cpu(ee->e_stat) == ES_DEL) {
608 /* there are only base ACL entries at most. */
610 posix_size = CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
611 OBD_ALLOC(new, posix_size);
612 if (unlikely(new == NULL))
615 new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
616 for (i = 0, j = 0; i < ext_count; i++) {
617 lustre_ext_acl_le_to_cpu(&ae,
618 &ext_header->a_entries[i]);
623 if (ae.e_id != ACL_UNDEFINED_ID)
624 GOTO(_out, rc = -EIO);
626 if (ae.e_stat != ES_DEL) {
627 new->a_entries[j].e_tag =
628 ext_header->a_entries[i].e_tag;
629 new->a_entries[j].e_perm =
630 ext_header->a_entries[i].e_perm;
631 new->a_entries[j++].e_id =
632 ext_header->a_entries[i].e_id;
638 if (ae.e_stat == ES_DEL)
641 GOTO(_out, rc = -EIO);
645 /* maybe there are valid ACL_USER or ACL_GROUP entries in the
646 * original server-side ACL, they are regarded as ES_UNC stat.*/
649 if (unlikely(size < 0))
655 CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
656 posix_count = ori_posix_count + ext_count;
658 CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
659 OBD_ALLOC(new, posix_size);
660 if (unlikely(new == NULL))
663 new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
664 /* 1. process the unchanged ACL entries
665 * in the original server-side ACL. */
667 for (i = 0, j = 0; i < ori_posix_count; i++) {
668 ee = lustre_ext_acl_xattr_search(ext_header,
669 &posix_header->a_entries[i], &pos);
671 memcpy(&new->a_entries[j++],
672 &posix_header->a_entries[i],
673 sizeof(posix_acl_xattr_entry));
676 /* 2. process the non-deleted entries
677 * from client-side extended ACL. */
678 for (i = 0; i < ext_count; i++) {
679 if (le16_to_cpu(ext_header->a_entries[i].e_stat) !=
681 new->a_entries[j].e_tag =
682 ext_header->a_entries[i].e_tag;
683 new->a_entries[j].e_perm =
684 ext_header->a_entries[i].e_perm;
685 new->a_entries[j++].e_id =
686 ext_header->a_entries[i].e_id;
691 /* free unused space. */
692 rc = lustre_posix_acl_xattr_reduce_space(&new, posix_count, j);
702 OBD_FREE(new, posix_size);
707 EXPORT_SYMBOL(lustre_acl_xattr_merge2posix);
710 * Merge the posix ACL and the extended ACL into new extended ACL.
712 ext_acl_xattr_header *
713 lustre_acl_xattr_merge2ext(posix_acl_xattr_header *posix_header, int size,
714 ext_acl_xattr_header *ext_header)
716 int ori_ext_count, posix_count, ext_count, ext_size;
717 int i, j, pos = 0, rc = 0;
718 posix_acl_xattr_entry pae;
719 ext_acl_xattr_header *new;
720 ext_acl_xattr_entry *ee, eae;
723 if (unlikely(size < 0))
724 RETURN(ERR_PTR(-EINVAL));
728 posix_count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
729 ori_ext_count = le32_to_cpu(ext_header->a_count);
730 ext_count = posix_count + ori_ext_count;
731 ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr);
733 OBD_ALLOC(new, ext_size);
734 if (unlikely(new == NULL))
735 RETURN(ERR_PTR(-ENOMEM));
737 for (i = 0, j = 0; i < posix_count; i++) {
738 lustre_posix_acl_le_to_cpu(&pae, &posix_header->a_entries[i]);
744 if (pae.e_id != ACL_UNDEFINED_ID)
745 GOTO(out, rc = -EIO);
747 /* ignore "nobody" entry. */
748 if (pae.e_id == NOBODY_UID)
751 new->a_entries[j].e_tag =
752 posix_header->a_entries[i].e_tag;
753 new->a_entries[j].e_perm =
754 posix_header->a_entries[i].e_perm;
755 new->a_entries[j].e_id =
756 posix_header->a_entries[i].e_id;
757 ee = lustre_ext_acl_xattr_search(ext_header,
758 &posix_header->a_entries[i], &pos);
760 if (posix_header->a_entries[i].e_perm !=
762 /* entry modified. */
764 new->a_entries[j++].e_stat =
767 /* entry unchanged. */
769 new->a_entries[j++].e_stat =
773 new->a_entries[j++].e_stat =
778 /* ignore "nobody" entry. */
779 if (pae.e_id == NOBODY_GID)
781 new->a_entries[j].e_tag =
782 posix_header->a_entries[i].e_tag;
783 new->a_entries[j].e_perm =
784 posix_header->a_entries[i].e_perm;
785 new->a_entries[j].e_id =
786 posix_header->a_entries[i].e_id;
787 ee = lustre_ext_acl_xattr_search(ext_header,
788 &posix_header->a_entries[i], &pos);
790 if (posix_header->a_entries[i].e_perm !=
792 /* entry modified. */
794 new->a_entries[j++].e_stat =
797 /* entry unchanged. */
799 new->a_entries[j++].e_stat =
803 new->a_entries[j++].e_stat =
808 GOTO(out, rc = -EIO);
812 /* process deleted entries. */
813 for (i = 0; i < ori_ext_count; i++) {
814 lustre_ext_acl_le_to_cpu(&eae, &ext_header->a_entries[i]);
815 if (eae.e_stat == ES_UNK) {
816 /* ignore "nobody" entry. */
817 if ((eae.e_tag == ACL_USER && eae.e_id == NOBODY_UID) ||
818 (eae.e_tag == ACL_GROUP && eae.e_id == NOBODY_GID))
821 new->a_entries[j].e_tag =
822 ext_header->a_entries[i].e_tag;
823 new->a_entries[j].e_perm =
824 ext_header->a_entries[i].e_perm;
825 new->a_entries[j].e_id = ext_header->a_entries[i].e_id;
826 new->a_entries[j++].e_stat = cpu_to_le32(ES_DEL);
830 new->a_count = cpu_to_le32(j);
831 /* free unused space. */
832 rc = lustre_ext_acl_xattr_reduce_space(&new, ext_count);
837 OBD_FREE(new, ext_size);
842 EXPORT_SYMBOL(lustre_acl_xattr_merge2ext);