1 /*
2 * GPL HEADER START
3 *
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 *
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.
9 *
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).
15 *
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
19 *
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
22 * have any questions.
23 *
24 * GPL HEADER END
25 */
26 /*
27 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28 * Use is subject to license terms.
29 *
30 * Copyright (c) 2012, Intel Corporation.
31 */
32 /*
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
35 *
36 * lustre/obdclass/acl.c
37 *
38 * Lustre Access Control List.
39 *
40 * Author: Fan Yong <fanyong@clusterfs.com>
41 */
42
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"
48
49 #ifdef CONFIG_FS_POSIX_ACL
50
51 #define CFS_ACL_XATTR_VERSION POSIX_ACL_XATTR_VERSION
52
53 enum {
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 */
59 };
60
lustre_ext_acl_le_to_cpu(ext_acl_xattr_entry * d,ext_acl_xattr_entry * s)61 static inline void lustre_ext_acl_le_to_cpu(ext_acl_xattr_entry *d,
62 ext_acl_xattr_entry *s)
63 {
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);
68 }
69
lustre_ext_acl_cpu_to_le(ext_acl_xattr_entry * d,ext_acl_xattr_entry * s)70 static inline void lustre_ext_acl_cpu_to_le(ext_acl_xattr_entry *d,
71 ext_acl_xattr_entry *s)
72 {
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);
77 }
78
lustre_posix_acl_le_to_cpu(posix_acl_xattr_entry * d,posix_acl_xattr_entry * s)79 static inline void lustre_posix_acl_le_to_cpu(posix_acl_xattr_entry *d,
80 posix_acl_xattr_entry *s)
81 {
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);
85 }
86
lustre_posix_acl_cpu_to_le(posix_acl_xattr_entry * d,posix_acl_xattr_entry * s)87 static inline void lustre_posix_acl_cpu_to_le(posix_acl_xattr_entry *d,
88 posix_acl_xattr_entry *s)
89 {
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);
93 }
94
95
96 /* if "new_count == 0", then "new = {a_version, NULL}", NOT NULL. */
lustre_posix_acl_xattr_reduce_space(posix_acl_xattr_header ** header,int old_count,int new_count)97 static int lustre_posix_acl_xattr_reduce_space(posix_acl_xattr_header **header,
98 int old_count, int new_count)
99 {
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;
103
104 if (unlikely(old_count <= new_count))
105 return old_size;
106
107 OBD_ALLOC(new, new_size);
108 if (unlikely(new == NULL))
109 return -ENOMEM;
110
111 memcpy(new, *header, new_size);
112 OBD_FREE(*header, old_size);
113 *header = new;
114 return new_size;
115 }
116
117 /* if "new_count == 0", then "new = {0, NULL}", NOT NULL. */
lustre_ext_acl_xattr_reduce_space(ext_acl_xattr_header ** header,int old_count)118 static int lustre_ext_acl_xattr_reduce_space(ext_acl_xattr_header **header,
119 int old_count)
120 {
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;
125
126 if (unlikely(old_count <= ext_count))
127 return 0;
128
129 OBD_ALLOC(new, ext_size);
130 if (unlikely(new == NULL))
131 return -ENOMEM;
132
133 memcpy(new, *header, ext_size);
134 OBD_FREE(*header, old_size);
135 *header = new;
136 return 0;
137 }
138
139 /*
140 * Generate new extended ACL based on the posix ACL.
141 */
142 ext_acl_xattr_header *
lustre_posix_acl_xattr_2ext(posix_acl_xattr_header * header,int size)143 lustre_posix_acl_xattr_2ext(posix_acl_xattr_header *header, int size)
144 {
145 int count, i, esize;
146 ext_acl_xattr_header *new;
147
148 if (unlikely(size < 0))
149 return ERR_PTR(-EINVAL);
150 else if (!size)
151 count = 0;
152 else
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);
158
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);
165 }
166
167 return new;
168 }
169 EXPORT_SYMBOL(lustre_posix_acl_xattr_2ext);
170
171 /*
172 * Filter out the "nobody" entries in the posix ACL.
173 */
lustre_posix_acl_xattr_filter(posix_acl_xattr_header * header,size_t size,posix_acl_xattr_header ** out)174 int lustre_posix_acl_xattr_filter(posix_acl_xattr_header *header, size_t size,
175 posix_acl_xattr_header **out)
176 {
177 int count, i, j, rc = 0;
178 __u32 id;
179 posix_acl_xattr_header *new;
180
181 if (!size)
182 return 0;
183 if (size < sizeof(*new))
184 return -EINVAL;
185
186 OBD_ALLOC(new, size);
187 if (unlikely(new == NULL))
188 return -ENOMEM;
189
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)) {
195 case ACL_USER_OBJ:
196 case ACL_GROUP_OBJ:
197 case ACL_MASK:
198 case ACL_OTHER:
199 if (id != ACL_UNDEFINED_ID) {
200 rc = -EIO;
201 goto _out;
202 }
203
204 memcpy(&new->a_entries[j++], &header->a_entries[i],
205 sizeof(posix_acl_xattr_entry));
206 break;
207 case ACL_USER:
208 if (id != NOBODY_UID)
209 memcpy(&new->a_entries[j++],
210 &header->a_entries[i],
211 sizeof(posix_acl_xattr_entry));
212 break;
213 case ACL_GROUP:
214 if (id != NOBODY_GID)
215 memcpy(&new->a_entries[j++],
216 &header->a_entries[i],
217 sizeof(posix_acl_xattr_entry));
218 break;
219 default:
220 rc = -EIO;
221 goto _out;
222 }
223 }
224
225 /* free unused space. */
226 rc = lustre_posix_acl_xattr_reduce_space(&new, count, j);
227 if (rc >= 0) {
228 size = rc;
229 *out = new;
230 rc = 0;
231 }
232
233 _out:
234 if (rc) {
235 OBD_FREE(new, size);
236 size = rc;
237 }
238 return size;
239 }
240 EXPORT_SYMBOL(lustre_posix_acl_xattr_filter);
241
242 /*
243 * Release the posix ACL space.
244 */
lustre_posix_acl_xattr_free(posix_acl_xattr_header * header,int size)245 void lustre_posix_acl_xattr_free(posix_acl_xattr_header *header, int size)
246 {
247 OBD_FREE(header, size);
248 }
249 EXPORT_SYMBOL(lustre_posix_acl_xattr_free);
250
251 /*
252 * Release the extended ACL space.
253 */
lustre_ext_acl_xattr_free(ext_acl_xattr_header * header)254 void lustre_ext_acl_xattr_free(ext_acl_xattr_header *header)
255 {
256 OBD_FREE(header, CFS_ACL_XATTR_SIZE(le32_to_cpu(header->a_count), \
257 ext_acl_xattr));
258 }
259 EXPORT_SYMBOL(lustre_ext_acl_xattr_free);
260
261 static ext_acl_xattr_entry *
lustre_ext_acl_xattr_search(ext_acl_xattr_header * header,posix_acl_xattr_entry * entry,int * pos)262 lustre_ext_acl_xattr_search(ext_acl_xattr_header *header,
263 posix_acl_xattr_entry *entry, int *pos)
264 {
265 int once, start, end, i, j, count = le32_to_cpu(header->a_count);
266
267 once = 0;
268 start = *pos;
269 end = count;
270
271 again:
272 for (i = start; i < end; i++) {
273 if (header->a_entries[i].e_tag == entry->e_tag &&
274 header->a_entries[i].e_id == entry->e_id) {
275 j = i;
276 if (++i >= count)
277 i = 0;
278 *pos = i;
279 return &header->a_entries[j];
280 }
281 }
282
283 if (!once) {
284 once = 1;
285 start = 0;
286 end = *pos;
287 goto again;
288 }
289
290 return NULL;
291 }
292
293 /*
294 * Merge the posix ACL and the extended ACL into new posix ACL.
295 */
lustre_acl_xattr_merge2posix(posix_acl_xattr_header * posix_header,int size,ext_acl_xattr_header * ext_header,posix_acl_xattr_header ** out)296 int lustre_acl_xattr_merge2posix(posix_acl_xattr_header *posix_header, int size,
297 ext_acl_xattr_header *ext_header,
298 posix_acl_xattr_header **out)
299 {
300 int posix_count, posix_size, i, j;
301 int ext_count = le32_to_cpu(ext_header->a_count), pos = 0, rc = 0;
302 posix_acl_xattr_entry pe = {ACL_MASK, 0, ACL_UNDEFINED_ID};
303 posix_acl_xattr_header *new;
304 ext_acl_xattr_entry *ee, ae;
305
306 lustre_posix_acl_cpu_to_le(&pe, &pe);
307 ee = lustre_ext_acl_xattr_search(ext_header, &pe, &pos);
308 if (ee == NULL || le32_to_cpu(ee->e_stat) == ES_DEL) {
309 /* there are only base ACL entries at most. */
310 posix_count = 3;
311 posix_size = CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
312 OBD_ALLOC(new, posix_size);
313 if (unlikely(new == NULL))
314 return -ENOMEM;
315
316 new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
317 for (i = 0, j = 0; i < ext_count; i++) {
318 lustre_ext_acl_le_to_cpu(&ae,
319 &ext_header->a_entries[i]);
320 switch (ae.e_tag) {
321 case ACL_USER_OBJ:
322 case ACL_GROUP_OBJ:
323 case ACL_OTHER:
324 if (ae.e_id != ACL_UNDEFINED_ID) {
325 rc = -EIO;
326 goto _out;
327 }
328
329 if (ae.e_stat != ES_DEL) {
330 new->a_entries[j].e_tag =
331 ext_header->a_entries[i].e_tag;
332 new->a_entries[j].e_perm =
333 ext_header->a_entries[i].e_perm;
334 new->a_entries[j++].e_id =
335 ext_header->a_entries[i].e_id;
336 }
337 break;
338 case ACL_MASK:
339 case ACL_USER:
340 case ACL_GROUP:
341 if (ae.e_stat == ES_DEL)
342 break;
343 default:
344 rc = -EIO;
345 goto _out;
346 }
347 }
348 } else {
349 /* maybe there are valid ACL_USER or ACL_GROUP entries in the
350 * original server-side ACL, they are regarded as ES_UNC stat.*/
351 int ori_posix_count;
352
353 if (unlikely(size < 0))
354 return -EINVAL;
355 else if (!size)
356 ori_posix_count = 0;
357 else
358 ori_posix_count =
359 CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
360 posix_count = ori_posix_count + ext_count;
361 posix_size =
362 CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
363 OBD_ALLOC(new, posix_size);
364 if (unlikely(new == NULL))
365 return -ENOMEM;
366
367 new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
368 /* 1. process the unchanged ACL entries
369 * in the original server-side ACL. */
370 pos = 0;
371 for (i = 0, j = 0; i < ori_posix_count; i++) {
372 ee = lustre_ext_acl_xattr_search(ext_header,
373 &posix_header->a_entries[i], &pos);
374 if (ee == NULL)
375 memcpy(&new->a_entries[j++],
376 &posix_header->a_entries[i],
377 sizeof(posix_acl_xattr_entry));
378 }
379
380 /* 2. process the non-deleted entries
381 * from client-side extended ACL. */
382 for (i = 0; i < ext_count; i++) {
383 if (le16_to_cpu(ext_header->a_entries[i].e_stat) !=
384 ES_DEL) {
385 new->a_entries[j].e_tag =
386 ext_header->a_entries[i].e_tag;
387 new->a_entries[j].e_perm =
388 ext_header->a_entries[i].e_perm;
389 new->a_entries[j++].e_id =
390 ext_header->a_entries[i].e_id;
391 }
392 }
393 }
394
395 /* free unused space. */
396 rc = lustre_posix_acl_xattr_reduce_space(&new, posix_count, j);
397 if (rc >= 0) {
398 posix_size = rc;
399 *out = new;
400 rc = 0;
401 }
402
403 _out:
404 if (rc) {
405 OBD_FREE(new, posix_size);
406 posix_size = rc;
407 }
408 return posix_size;
409 }
410 EXPORT_SYMBOL(lustre_acl_xattr_merge2posix);
411
412 /*
413 * Merge the posix ACL and the extended ACL into new extended ACL.
414 */
415 ext_acl_xattr_header *
lustre_acl_xattr_merge2ext(posix_acl_xattr_header * posix_header,int size,ext_acl_xattr_header * ext_header)416 lustre_acl_xattr_merge2ext(posix_acl_xattr_header *posix_header, int size,
417 ext_acl_xattr_header *ext_header)
418 {
419 int ori_ext_count, posix_count, ext_count, ext_size;
420 int i, j, pos = 0, rc = 0;
421 posix_acl_xattr_entry pae;
422 ext_acl_xattr_header *new;
423 ext_acl_xattr_entry *ee, eae;
424
425 if (unlikely(size < 0))
426 return ERR_PTR(-EINVAL);
427 else if (!size)
428 posix_count = 0;
429 else
430 posix_count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
431 ori_ext_count = le32_to_cpu(ext_header->a_count);
432 ext_count = posix_count + ori_ext_count;
433 ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr);
434
435 OBD_ALLOC(new, ext_size);
436 if (unlikely(new == NULL))
437 return ERR_PTR(-ENOMEM);
438
439 for (i = 0, j = 0; i < posix_count; i++) {
440 lustre_posix_acl_le_to_cpu(&pae, &posix_header->a_entries[i]);
441 switch (pae.e_tag) {
442 case ACL_USER_OBJ:
443 case ACL_GROUP_OBJ:
444 case ACL_MASK:
445 case ACL_OTHER:
446 if (pae.e_id != ACL_UNDEFINED_ID) {
447 rc = -EIO;
448 goto out;
449 }
450 case ACL_USER:
451 /* ignore "nobody" entry. */
452 if (pae.e_id == NOBODY_UID)
453 break;
454
455 new->a_entries[j].e_tag =
456 posix_header->a_entries[i].e_tag;
457 new->a_entries[j].e_perm =
458 posix_header->a_entries[i].e_perm;
459 new->a_entries[j].e_id =
460 posix_header->a_entries[i].e_id;
461 ee = lustre_ext_acl_xattr_search(ext_header,
462 &posix_header->a_entries[i], &pos);
463 if (ee) {
464 if (posix_header->a_entries[i].e_perm !=
465 ee->e_perm)
466 /* entry modified. */
467 ee->e_stat =
468 new->a_entries[j++].e_stat =
469 cpu_to_le32(ES_MOD);
470 else
471 /* entry unchanged. */
472 ee->e_stat =
473 new->a_entries[j++].e_stat =
474 cpu_to_le32(ES_UNC);
475 } else {
476 /* new entry. */
477 new->a_entries[j++].e_stat =
478 cpu_to_le32(ES_ADD);
479 }
480 break;
481 case ACL_GROUP:
482 /* ignore "nobody" entry. */
483 if (pae.e_id == NOBODY_GID)
484 break;
485 new->a_entries[j].e_tag =
486 posix_header->a_entries[i].e_tag;
487 new->a_entries[j].e_perm =
488 posix_header->a_entries[i].e_perm;
489 new->a_entries[j].e_id =
490 posix_header->a_entries[i].e_id;
491 ee = lustre_ext_acl_xattr_search(ext_header,
492 &posix_header->a_entries[i], &pos);
493 if (ee) {
494 if (posix_header->a_entries[i].e_perm !=
495 ee->e_perm)
496 /* entry modified. */
497 ee->e_stat =
498 new->a_entries[j++].e_stat =
499 cpu_to_le32(ES_MOD);
500 else
501 /* entry unchanged. */
502 ee->e_stat =
503 new->a_entries[j++].e_stat =
504 cpu_to_le32(ES_UNC);
505 } else {
506 /* new entry. */
507 new->a_entries[j++].e_stat =
508 cpu_to_le32(ES_ADD);
509 }
510 break;
511 default:
512 rc = -EIO;
513 goto out;
514 }
515 }
516
517 /* process deleted entries. */
518 for (i = 0; i < ori_ext_count; i++) {
519 lustre_ext_acl_le_to_cpu(&eae, &ext_header->a_entries[i]);
520 if (eae.e_stat == ES_UNK) {
521 /* ignore "nobody" entry. */
522 if ((eae.e_tag == ACL_USER && eae.e_id == NOBODY_UID) ||
523 (eae.e_tag == ACL_GROUP && eae.e_id == NOBODY_GID))
524 continue;
525
526 new->a_entries[j].e_tag =
527 ext_header->a_entries[i].e_tag;
528 new->a_entries[j].e_perm =
529 ext_header->a_entries[i].e_perm;
530 new->a_entries[j].e_id = ext_header->a_entries[i].e_id;
531 new->a_entries[j++].e_stat = cpu_to_le32(ES_DEL);
532 }
533 }
534
535 new->a_count = cpu_to_le32(j);
536 /* free unused space. */
537 rc = lustre_ext_acl_xattr_reduce_space(&new, ext_count);
538
539 out:
540 if (rc) {
541 OBD_FREE(new, ext_size);
542 new = ERR_PTR(rc);
543 }
544 return new;
545 }
546 EXPORT_SYMBOL(lustre_acl_xattr_merge2ext);
547
548 #endif
549