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 "../include/lu_object.h"
45 #include "../include/lustre_acl.h"
46 #include "../include/lustre_eacl.h"
47 #include "../include/obd_support.h"
49 #ifdef CONFIG_FS_POSIX_ACL
51 #define CFS_ACL_XATTR_VERSION POSIX_ACL_XATTR_VERSION
54 ES_UNK
= 0, /* unknown stat */
55 ES_UNC
= 1, /* ACL entry is not changed */
56 ES_MOD
= 2, /* ACL entry is modified */
57 ES_ADD
= 3, /* ACL entry is added */
58 ES_DEL
= 4 /* ACL entry is deleted */
61 static inline void lustre_ext_acl_le_to_cpu(ext_acl_xattr_entry
*d
,
62 ext_acl_xattr_entry
*s
)
64 d
->e_tag
= le16_to_cpu(s
->e_tag
);
65 d
->e_perm
= le16_to_cpu(s
->e_perm
);
66 d
->e_id
= le32_to_cpu(s
->e_id
);
67 d
->e_stat
= le32_to_cpu(s
->e_stat
);
70 static inline void lustre_ext_acl_cpu_to_le(ext_acl_xattr_entry
*d
,
71 ext_acl_xattr_entry
*s
)
73 d
->e_tag
= cpu_to_le16(s
->e_tag
);
74 d
->e_perm
= cpu_to_le16(s
->e_perm
);
75 d
->e_id
= cpu_to_le32(s
->e_id
);
76 d
->e_stat
= cpu_to_le32(s
->e_stat
);
79 static inline void lustre_posix_acl_le_to_cpu(posix_acl_xattr_entry
*d
,
80 posix_acl_xattr_entry
*s
)
82 d
->e_tag
= le16_to_cpu(s
->e_tag
);
83 d
->e_perm
= le16_to_cpu(s
->e_perm
);
84 d
->e_id
= le32_to_cpu(s
->e_id
);
87 static inline void lustre_posix_acl_cpu_to_le(posix_acl_xattr_entry
*d
,
88 posix_acl_xattr_entry
*s
)
90 d
->e_tag
= cpu_to_le16(s
->e_tag
);
91 d
->e_perm
= cpu_to_le16(s
->e_perm
);
92 d
->e_id
= cpu_to_le32(s
->e_id
);
96 /* if "new_count == 0", then "new = {a_version, NULL}", NOT NULL. */
97 static int lustre_posix_acl_xattr_reduce_space(posix_acl_xattr_header
**header
,
98 int old_count
, int new_count
)
100 int old_size
= CFS_ACL_XATTR_SIZE(old_count
, posix_acl_xattr
);
101 int new_size
= CFS_ACL_XATTR_SIZE(new_count
, posix_acl_xattr
);
102 posix_acl_xattr_header
*new;
104 if (unlikely(old_count
<= new_count
))
107 new = kzalloc(new_size
, GFP_NOFS
);
108 if (unlikely(new == NULL
))
111 memcpy(new, *header
, new_size
);
117 /* if "new_count == 0", then "new = {0, NULL}", NOT NULL. */
118 static int lustre_ext_acl_xattr_reduce_space(ext_acl_xattr_header
**header
,
121 int ext_count
= le32_to_cpu((*header
)->a_count
);
122 int ext_size
= CFS_ACL_XATTR_SIZE(ext_count
, ext_acl_xattr
);
123 ext_acl_xattr_header
*new;
125 if (unlikely(old_count
<= ext_count
))
128 new = kzalloc(ext_size
, GFP_NOFS
);
129 if (unlikely(new == NULL
))
132 memcpy(new, *header
, ext_size
);
139 * Generate new extended ACL based on the posix ACL.
141 ext_acl_xattr_header
*
142 lustre_posix_acl_xattr_2ext(posix_acl_xattr_header
*header
, int size
)
145 ext_acl_xattr_header
*new;
147 if (unlikely(size
< 0))
148 return ERR_PTR(-EINVAL
);
152 count
= CFS_ACL_XATTR_COUNT(size
, posix_acl_xattr
);
153 esize
= CFS_ACL_XATTR_SIZE(count
, ext_acl_xattr
);
154 new = kzalloc(esize
, GFP_NOFS
);
155 if (unlikely(new == NULL
))
156 return ERR_PTR(-ENOMEM
);
158 new->a_count
= cpu_to_le32(count
);
159 for (i
= 0; i
< count
; i
++) {
160 new->a_entries
[i
].e_tag
= header
->a_entries
[i
].e_tag
;
161 new->a_entries
[i
].e_perm
= header
->a_entries
[i
].e_perm
;
162 new->a_entries
[i
].e_id
= header
->a_entries
[i
].e_id
;
163 new->a_entries
[i
].e_stat
= cpu_to_le32(ES_UNK
);
168 EXPORT_SYMBOL(lustre_posix_acl_xattr_2ext
);
171 * Filter out the "nobody" entries in the posix ACL.
173 int lustre_posix_acl_xattr_filter(posix_acl_xattr_header
*header
, size_t size
,
174 posix_acl_xattr_header
**out
)
176 int count
, i
, j
, rc
= 0;
178 posix_acl_xattr_header
*new;
182 if (size
< sizeof(*new))
185 new = kzalloc(size
, GFP_NOFS
);
186 if (unlikely(new == NULL
))
189 new->a_version
= cpu_to_le32(CFS_ACL_XATTR_VERSION
);
190 count
= CFS_ACL_XATTR_COUNT(size
, posix_acl_xattr
);
191 for (i
= 0, j
= 0; i
< count
; i
++) {
192 id
= le32_to_cpu(header
->a_entries
[i
].e_id
);
193 switch (le16_to_cpu(header
->a_entries
[i
].e_tag
)) {
198 if (id
!= ACL_UNDEFINED_ID
) {
203 memcpy(&new->a_entries
[j
++], &header
->a_entries
[i
],
204 sizeof(posix_acl_xattr_entry
));
207 if (id
!= NOBODY_UID
)
208 memcpy(&new->a_entries
[j
++],
209 &header
->a_entries
[i
],
210 sizeof(posix_acl_xattr_entry
));
213 if (id
!= NOBODY_GID
)
214 memcpy(&new->a_entries
[j
++],
215 &header
->a_entries
[i
],
216 sizeof(posix_acl_xattr_entry
));
224 /* free unused space. */
225 rc
= lustre_posix_acl_xattr_reduce_space(&new, count
, j
);
239 EXPORT_SYMBOL(lustre_posix_acl_xattr_filter
);
242 * Release the posix ACL space.
244 void lustre_posix_acl_xattr_free(posix_acl_xattr_header
*header
, int size
)
248 EXPORT_SYMBOL(lustre_posix_acl_xattr_free
);
251 * Release the extended ACL space.
253 void lustre_ext_acl_xattr_free(ext_acl_xattr_header
*header
)
257 EXPORT_SYMBOL(lustre_ext_acl_xattr_free
);
259 static ext_acl_xattr_entry
*
260 lustre_ext_acl_xattr_search(ext_acl_xattr_header
*header
,
261 posix_acl_xattr_entry
*entry
, int *pos
)
263 int once
, start
, end
, i
, j
, count
= le32_to_cpu(header
->a_count
);
270 for (i
= start
; i
< end
; i
++) {
271 if (header
->a_entries
[i
].e_tag
== entry
->e_tag
&&
272 header
->a_entries
[i
].e_id
== entry
->e_id
) {
277 return &header
->a_entries
[j
];
292 * Merge the posix ACL and the extended ACL into new posix ACL.
294 int lustre_acl_xattr_merge2posix(posix_acl_xattr_header
*posix_header
, int size
,
295 ext_acl_xattr_header
*ext_header
,
296 posix_acl_xattr_header
**out
)
298 int posix_count
, posix_size
, i
, j
;
299 int ext_count
= le32_to_cpu(ext_header
->a_count
), pos
= 0, rc
= 0;
300 posix_acl_xattr_entry pe
= {ACL_MASK
, 0, ACL_UNDEFINED_ID
};
301 posix_acl_xattr_header
*new;
302 ext_acl_xattr_entry
*ee
, ae
;
304 lustre_posix_acl_cpu_to_le(&pe
, &pe
);
305 ee
= lustre_ext_acl_xattr_search(ext_header
, &pe
, &pos
);
306 if (ee
== NULL
|| le32_to_cpu(ee
->e_stat
) == ES_DEL
) {
307 /* there are only base ACL entries at most. */
309 posix_size
= CFS_ACL_XATTR_SIZE(posix_count
, posix_acl_xattr
);
310 new = kzalloc(posix_size
, GFP_NOFS
);
311 if (unlikely(new == NULL
))
314 new->a_version
= cpu_to_le32(CFS_ACL_XATTR_VERSION
);
315 for (i
= 0, j
= 0; i
< ext_count
; i
++) {
316 lustre_ext_acl_le_to_cpu(&ae
,
317 &ext_header
->a_entries
[i
]);
322 if (ae
.e_id
!= ACL_UNDEFINED_ID
) {
327 if (ae
.e_stat
!= ES_DEL
) {
328 new->a_entries
[j
].e_tag
=
329 ext_header
->a_entries
[i
].e_tag
;
330 new->a_entries
[j
].e_perm
=
331 ext_header
->a_entries
[i
].e_perm
;
332 new->a_entries
[j
++].e_id
=
333 ext_header
->a_entries
[i
].e_id
;
339 if (ae
.e_stat
== ES_DEL
)
347 /* maybe there are valid ACL_USER or ACL_GROUP entries in the
348 * original server-side ACL, they are regarded as ES_UNC stat.*/
351 if (unlikely(size
< 0))
357 CFS_ACL_XATTR_COUNT(size
, posix_acl_xattr
);
358 posix_count
= ori_posix_count
+ ext_count
;
360 CFS_ACL_XATTR_SIZE(posix_count
, posix_acl_xattr
);
361 new = kzalloc(posix_size
, GFP_NOFS
);
362 if (unlikely(new == NULL
))
365 new->a_version
= cpu_to_le32(CFS_ACL_XATTR_VERSION
);
366 /* 1. process the unchanged ACL entries
367 * in the original server-side ACL. */
369 for (i
= 0, j
= 0; i
< ori_posix_count
; i
++) {
370 ee
= lustre_ext_acl_xattr_search(ext_header
,
371 &posix_header
->a_entries
[i
], &pos
);
373 memcpy(&new->a_entries
[j
++],
374 &posix_header
->a_entries
[i
],
375 sizeof(posix_acl_xattr_entry
));
378 /* 2. process the non-deleted entries
379 * from client-side extended ACL. */
380 for (i
= 0; i
< ext_count
; i
++) {
381 if (le16_to_cpu(ext_header
->a_entries
[i
].e_stat
) !=
383 new->a_entries
[j
].e_tag
=
384 ext_header
->a_entries
[i
].e_tag
;
385 new->a_entries
[j
].e_perm
=
386 ext_header
->a_entries
[i
].e_perm
;
387 new->a_entries
[j
++].e_id
=
388 ext_header
->a_entries
[i
].e_id
;
393 /* free unused space. */
394 rc
= lustre_posix_acl_xattr_reduce_space(&new, posix_count
, j
);
408 EXPORT_SYMBOL(lustre_acl_xattr_merge2posix
);
411 * Merge the posix ACL and the extended ACL into new extended ACL.
413 ext_acl_xattr_header
*
414 lustre_acl_xattr_merge2ext(posix_acl_xattr_header
*posix_header
, int size
,
415 ext_acl_xattr_header
*ext_header
)
417 int ori_ext_count
, posix_count
, ext_count
, ext_size
;
418 int i
, j
, pos
= 0, rc
= 0;
419 posix_acl_xattr_entry pae
;
420 ext_acl_xattr_header
*new;
421 ext_acl_xattr_entry
*ee
, eae
;
423 if (unlikely(size
< 0))
424 return ERR_PTR(-EINVAL
);
428 posix_count
= CFS_ACL_XATTR_COUNT(size
, posix_acl_xattr
);
429 ori_ext_count
= le32_to_cpu(ext_header
->a_count
);
430 ext_count
= posix_count
+ ori_ext_count
;
431 ext_size
= CFS_ACL_XATTR_SIZE(ext_count
, ext_acl_xattr
);
433 new = kzalloc(ext_size
, GFP_NOFS
);
434 if (unlikely(new == NULL
))
435 return ERR_PTR(-ENOMEM
);
437 for (i
= 0, j
= 0; i
< posix_count
; i
++) {
438 lustre_posix_acl_le_to_cpu(&pae
, &posix_header
->a_entries
[i
]);
444 if (pae
.e_id
!= ACL_UNDEFINED_ID
) {
449 /* ignore "nobody" entry. */
450 if (pae
.e_id
== NOBODY_UID
)
453 new->a_entries
[j
].e_tag
=
454 posix_header
->a_entries
[i
].e_tag
;
455 new->a_entries
[j
].e_perm
=
456 posix_header
->a_entries
[i
].e_perm
;
457 new->a_entries
[j
].e_id
=
458 posix_header
->a_entries
[i
].e_id
;
459 ee
= lustre_ext_acl_xattr_search(ext_header
,
460 &posix_header
->a_entries
[i
], &pos
);
462 if (posix_header
->a_entries
[i
].e_perm
!=
464 /* entry modified. */
466 new->a_entries
[j
++].e_stat
=
469 /* entry unchanged. */
471 new->a_entries
[j
++].e_stat
=
475 new->a_entries
[j
++].e_stat
=
480 /* ignore "nobody" entry. */
481 if (pae
.e_id
== NOBODY_GID
)
483 new->a_entries
[j
].e_tag
=
484 posix_header
->a_entries
[i
].e_tag
;
485 new->a_entries
[j
].e_perm
=
486 posix_header
->a_entries
[i
].e_perm
;
487 new->a_entries
[j
].e_id
=
488 posix_header
->a_entries
[i
].e_id
;
489 ee
= lustre_ext_acl_xattr_search(ext_header
,
490 &posix_header
->a_entries
[i
], &pos
);
492 if (posix_header
->a_entries
[i
].e_perm
!=
494 /* entry modified. */
496 new->a_entries
[j
++].e_stat
=
499 /* entry unchanged. */
501 new->a_entries
[j
++].e_stat
=
505 new->a_entries
[j
++].e_stat
=
515 /* process deleted entries. */
516 for (i
= 0; i
< ori_ext_count
; i
++) {
517 lustre_ext_acl_le_to_cpu(&eae
, &ext_header
->a_entries
[i
]);
518 if (eae
.e_stat
== ES_UNK
) {
519 /* ignore "nobody" entry. */
520 if ((eae
.e_tag
== ACL_USER
&& eae
.e_id
== NOBODY_UID
) ||
521 (eae
.e_tag
== ACL_GROUP
&& eae
.e_id
== NOBODY_GID
))
524 new->a_entries
[j
].e_tag
=
525 ext_header
->a_entries
[i
].e_tag
;
526 new->a_entries
[j
].e_perm
=
527 ext_header
->a_entries
[i
].e_perm
;
528 new->a_entries
[j
].e_id
= ext_header
->a_entries
[i
].e_id
;
529 new->a_entries
[j
++].e_stat
= cpu_to_le32(ES_DEL
);
533 new->a_count
= cpu_to_le32(j
);
534 /* free unused space. */
535 rc
= lustre_ext_acl_xattr_reduce_space(&new, ext_count
);
544 EXPORT_SYMBOL(lustre_acl_xattr_merge2ext
);