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>
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 OBD_ALLOC(new, new_size);
108 if (unlikely(new == NULL))
111 memcpy(new, *header, new_size);
112 OBD_FREE(*header, old_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 int old_size = CFS_ACL_XATTR_SIZE(old_count, ext_acl_xattr);
124 ext_acl_xattr_header *new;
126 if (unlikely(old_count <= ext_count))
129 OBD_ALLOC(new, ext_size);
130 if (unlikely(new == NULL))
133 memcpy(new, *header, ext_size);
134 OBD_FREE(*header, old_size);
140 * Generate new extended ACL based on the posix ACL.
142 ext_acl_xattr_header *
143 lustre_posix_acl_xattr_2ext(posix_acl_xattr_header *header, int size)
146 ext_acl_xattr_header *new;
148 if (unlikely(size < 0))
149 return ERR_PTR(-EINVAL);
153 count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
154 esize = CFS_ACL_XATTR_SIZE(count, ext_acl_xattr);
155 OBD_ALLOC(new, esize);
156 if (unlikely(new == NULL))
157 return ERR_PTR(-ENOMEM);
159 new->a_count = cpu_to_le32(count);
160 for (i = 0; i < count; i++) {
161 new->a_entries[i].e_tag = header->a_entries[i].e_tag;
162 new->a_entries[i].e_perm = header->a_entries[i].e_perm;
163 new->a_entries[i].e_id = header->a_entries[i].e_id;
164 new->a_entries[i].e_stat = cpu_to_le32(ES_UNK);
169 EXPORT_SYMBOL(lustre_posix_acl_xattr_2ext);
172 * Filter out the "nobody" entries in the posix ACL.
174 int lustre_posix_acl_xattr_filter(posix_acl_xattr_header *header, int size,
175 posix_acl_xattr_header **out)
177 int count, i, j, rc = 0;
179 posix_acl_xattr_header *new;
181 if (unlikely(size < 0))
186 OBD_ALLOC(new, size);
187 if (unlikely(new == NULL))
190 new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
191 count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
192 for (i = 0, j = 0; i < count; i++) {
193 id = le32_to_cpu(header->a_entries[i].e_id);
194 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
199 if (id != ACL_UNDEFINED_ID)
200 GOTO(_out, rc = -EIO);
202 memcpy(&new->a_entries[j++], &header->a_entries[i],
203 sizeof(posix_acl_xattr_entry));
206 if (id != NOBODY_UID)
207 memcpy(&new->a_entries[j++],
208 &header->a_entries[i],
209 sizeof(posix_acl_xattr_entry));
212 if (id != NOBODY_GID)
213 memcpy(&new->a_entries[j++],
214 &header->a_entries[i],
215 sizeof(posix_acl_xattr_entry));
218 GOTO(_out, rc = -EIO);
222 /* free unused space. */
223 rc = lustre_posix_acl_xattr_reduce_space(&new, count, j);
237 EXPORT_SYMBOL(lustre_posix_acl_xattr_filter);
240 * Release the posix ACL space.
242 void lustre_posix_acl_xattr_free(posix_acl_xattr_header *header, int size)
244 OBD_FREE(header, size);
246 EXPORT_SYMBOL(lustre_posix_acl_xattr_free);
249 * Release the extended ACL space.
251 void lustre_ext_acl_xattr_free(ext_acl_xattr_header *header)
253 OBD_FREE(header, CFS_ACL_XATTR_SIZE(le32_to_cpu(header->a_count), \
256 EXPORT_SYMBOL(lustre_ext_acl_xattr_free);
258 static ext_acl_xattr_entry *
259 lustre_ext_acl_xattr_search(ext_acl_xattr_header *header,
260 posix_acl_xattr_entry *entry, int *pos)
262 int once, start, end, i, j, count = le32_to_cpu(header->a_count);
269 for (i = start; i < end; i++) {
270 if (header->a_entries[i].e_tag == entry->e_tag &&
271 header->a_entries[i].e_id == entry->e_id) {
276 return &header->a_entries[j];
291 * Merge the posix ACL and the extended ACL into new posix ACL.
293 int lustre_acl_xattr_merge2posix(posix_acl_xattr_header *posix_header, int size,
294 ext_acl_xattr_header *ext_header,
295 posix_acl_xattr_header **out)
297 int posix_count, posix_size, i, j;
298 int ext_count = le32_to_cpu(ext_header->a_count), pos = 0, rc = 0;
299 posix_acl_xattr_entry pe = {ACL_MASK, 0, ACL_UNDEFINED_ID};
300 posix_acl_xattr_header *new;
301 ext_acl_xattr_entry *ee, ae;
303 lustre_posix_acl_cpu_to_le(&pe, &pe);
304 ee = lustre_ext_acl_xattr_search(ext_header, &pe, &pos);
305 if (ee == NULL || le32_to_cpu(ee->e_stat) == ES_DEL) {
306 /* there are only base ACL entries at most. */
308 posix_size = CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
309 OBD_ALLOC(new, posix_size);
310 if (unlikely(new == NULL))
313 new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
314 for (i = 0, j = 0; i < ext_count; i++) {
315 lustre_ext_acl_le_to_cpu(&ae,
316 &ext_header->a_entries[i]);
321 if (ae.e_id != ACL_UNDEFINED_ID)
322 GOTO(_out, rc = -EIO);
324 if (ae.e_stat != ES_DEL) {
325 new->a_entries[j].e_tag =
326 ext_header->a_entries[i].e_tag;
327 new->a_entries[j].e_perm =
328 ext_header->a_entries[i].e_perm;
329 new->a_entries[j++].e_id =
330 ext_header->a_entries[i].e_id;
336 if (ae.e_stat == ES_DEL)
339 GOTO(_out, rc = -EIO);
343 /* maybe there are valid ACL_USER or ACL_GROUP entries in the
344 * original server-side ACL, they are regarded as ES_UNC stat.*/
347 if (unlikely(size < 0))
353 CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
354 posix_count = ori_posix_count + ext_count;
356 CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
357 OBD_ALLOC(new, posix_size);
358 if (unlikely(new == NULL))
361 new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
362 /* 1. process the unchanged ACL entries
363 * in the original server-side ACL. */
365 for (i = 0, j = 0; i < ori_posix_count; i++) {
366 ee = lustre_ext_acl_xattr_search(ext_header,
367 &posix_header->a_entries[i], &pos);
369 memcpy(&new->a_entries[j++],
370 &posix_header->a_entries[i],
371 sizeof(posix_acl_xattr_entry));
374 /* 2. process the non-deleted entries
375 * from client-side extended ACL. */
376 for (i = 0; i < ext_count; i++) {
377 if (le16_to_cpu(ext_header->a_entries[i].e_stat) !=
379 new->a_entries[j].e_tag =
380 ext_header->a_entries[i].e_tag;
381 new->a_entries[j].e_perm =
382 ext_header->a_entries[i].e_perm;
383 new->a_entries[j++].e_id =
384 ext_header->a_entries[i].e_id;
389 /* free unused space. */
390 rc = lustre_posix_acl_xattr_reduce_space(&new, posix_count, j);
399 OBD_FREE(new, posix_size);
404 EXPORT_SYMBOL(lustre_acl_xattr_merge2posix);
407 * Merge the posix ACL and the extended ACL into new extended ACL.
409 ext_acl_xattr_header *
410 lustre_acl_xattr_merge2ext(posix_acl_xattr_header *posix_header, int size,
411 ext_acl_xattr_header *ext_header)
413 int ori_ext_count, posix_count, ext_count, ext_size;
414 int i, j, pos = 0, rc = 0;
415 posix_acl_xattr_entry pae;
416 ext_acl_xattr_header *new;
417 ext_acl_xattr_entry *ee, eae;
419 if (unlikely(size < 0))
420 return ERR_PTR(-EINVAL);
424 posix_count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
425 ori_ext_count = le32_to_cpu(ext_header->a_count);
426 ext_count = posix_count + ori_ext_count;
427 ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr);
429 OBD_ALLOC(new, ext_size);
430 if (unlikely(new == NULL))
431 return ERR_PTR(-ENOMEM);
433 for (i = 0, j = 0; i < posix_count; i++) {
434 lustre_posix_acl_le_to_cpu(&pae, &posix_header->a_entries[i]);
440 if (pae.e_id != ACL_UNDEFINED_ID)
441 GOTO(out, rc = -EIO);
443 /* ignore "nobody" entry. */
444 if (pae.e_id == NOBODY_UID)
447 new->a_entries[j].e_tag =
448 posix_header->a_entries[i].e_tag;
449 new->a_entries[j].e_perm =
450 posix_header->a_entries[i].e_perm;
451 new->a_entries[j].e_id =
452 posix_header->a_entries[i].e_id;
453 ee = lustre_ext_acl_xattr_search(ext_header,
454 &posix_header->a_entries[i], &pos);
456 if (posix_header->a_entries[i].e_perm !=
458 /* entry modified. */
460 new->a_entries[j++].e_stat =
463 /* entry unchanged. */
465 new->a_entries[j++].e_stat =
469 new->a_entries[j++].e_stat =
474 /* ignore "nobody" entry. */
475 if (pae.e_id == NOBODY_GID)
477 new->a_entries[j].e_tag =
478 posix_header->a_entries[i].e_tag;
479 new->a_entries[j].e_perm =
480 posix_header->a_entries[i].e_perm;
481 new->a_entries[j].e_id =
482 posix_header->a_entries[i].e_id;
483 ee = lustre_ext_acl_xattr_search(ext_header,
484 &posix_header->a_entries[i], &pos);
486 if (posix_header->a_entries[i].e_perm !=
488 /* entry modified. */
490 new->a_entries[j++].e_stat =
493 /* entry unchanged. */
495 new->a_entries[j++].e_stat =
499 new->a_entries[j++].e_stat =
504 GOTO(out, rc = -EIO);
508 /* process deleted entries. */
509 for (i = 0; i < ori_ext_count; i++) {
510 lustre_ext_acl_le_to_cpu(&eae, &ext_header->a_entries[i]);
511 if (eae.e_stat == ES_UNK) {
512 /* ignore "nobody" entry. */
513 if ((eae.e_tag == ACL_USER && eae.e_id == NOBODY_UID) ||
514 (eae.e_tag == ACL_GROUP && eae.e_id == NOBODY_GID))
517 new->a_entries[j].e_tag =
518 ext_header->a_entries[i].e_tag;
519 new->a_entries[j].e_perm =
520 ext_header->a_entries[i].e_perm;
521 new->a_entries[j].e_id = ext_header->a_entries[i].e_id;
522 new->a_entries[j++].e_stat = cpu_to_le32(ES_DEL);
526 new->a_count = cpu_to_le32(j);
527 /* free unused space. */
528 rc = lustre_ext_acl_xattr_reduce_space(&new, ext_count);
532 OBD_FREE(new, ext_size);
537 EXPORT_SYMBOL(lustre_acl_xattr_merge2ext);