bc3fc4780cb9e53f7faf61ac5f75d395943de8b8
[deliverable/linux.git] / drivers / staging / lustre / lustre / obdclass / acl.c
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
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
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
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
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. */
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 new = kzalloc(new_size, GFP_NOFS);
108 if (unlikely(new == NULL))
109 return -ENOMEM;
110
111 memcpy(new, *header, new_size);
112 kfree(*header);
113 *header = new;
114 return new_size;
115 }
116
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,
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 ext_acl_xattr_header *new;
124
125 if (unlikely(old_count <= ext_count))
126 return 0;
127
128 new = kzalloc(ext_size, GFP_NOFS);
129 if (unlikely(new == NULL))
130 return -ENOMEM;
131
132 memcpy(new, *header, ext_size);
133 kfree(*header);
134 *header = new;
135 return 0;
136 }
137
138 /*
139 * Generate new extended ACL based on the posix ACL.
140 */
141 ext_acl_xattr_header *
142 lustre_posix_acl_xattr_2ext(posix_acl_xattr_header *header, int size)
143 {
144 int count, i, esize;
145 ext_acl_xattr_header *new;
146
147 if (unlikely(size < 0))
148 return ERR_PTR(-EINVAL);
149 else if (!size)
150 count = 0;
151 else
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);
157
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);
164 }
165
166 return new;
167 }
168 EXPORT_SYMBOL(lustre_posix_acl_xattr_2ext);
169
170 /*
171 * Filter out the "nobody" entries in the posix ACL.
172 */
173 int lustre_posix_acl_xattr_filter(posix_acl_xattr_header *header, size_t size,
174 posix_acl_xattr_header **out)
175 {
176 int count, i, j, rc = 0;
177 __u32 id;
178 posix_acl_xattr_header *new;
179
180 if (!size)
181 return 0;
182 if (size < sizeof(*new))
183 return -EINVAL;
184
185 new = kzalloc(size, GFP_NOFS);
186 if (unlikely(new == NULL))
187 return -ENOMEM;
188
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)) {
194 case ACL_USER_OBJ:
195 case ACL_GROUP_OBJ:
196 case ACL_MASK:
197 case ACL_OTHER:
198 if (id != ACL_UNDEFINED_ID) {
199 rc = -EIO;
200 goto _out;
201 }
202
203 memcpy(&new->a_entries[j++], &header->a_entries[i],
204 sizeof(posix_acl_xattr_entry));
205 break;
206 case ACL_USER:
207 if (id != NOBODY_UID)
208 memcpy(&new->a_entries[j++],
209 &header->a_entries[i],
210 sizeof(posix_acl_xattr_entry));
211 break;
212 case ACL_GROUP:
213 if (id != NOBODY_GID)
214 memcpy(&new->a_entries[j++],
215 &header->a_entries[i],
216 sizeof(posix_acl_xattr_entry));
217 break;
218 default:
219 rc = -EIO;
220 goto _out;
221 }
222 }
223
224 /* free unused space. */
225 rc = lustre_posix_acl_xattr_reduce_space(&new, count, j);
226 if (rc >= 0) {
227 size = rc;
228 *out = new;
229 rc = 0;
230 }
231
232 _out:
233 if (rc) {
234 kfree(new);
235 size = rc;
236 }
237 return size;
238 }
239 EXPORT_SYMBOL(lustre_posix_acl_xattr_filter);
240
241 /*
242 * Release the posix ACL space.
243 */
244 void lustre_posix_acl_xattr_free(posix_acl_xattr_header *header, int size)
245 {
246 kfree(header);
247 }
248 EXPORT_SYMBOL(lustre_posix_acl_xattr_free);
249
250 /*
251 * Release the extended ACL space.
252 */
253 void lustre_ext_acl_xattr_free(ext_acl_xattr_header *header)
254 {
255 kfree(header);
256 }
257 EXPORT_SYMBOL(lustre_ext_acl_xattr_free);
258
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)
262 {
263 int once, start, end, i, j, count = le32_to_cpu(header->a_count);
264
265 once = 0;
266 start = *pos;
267 end = count;
268
269 again:
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) {
273 j = i;
274 if (++i >= count)
275 i = 0;
276 *pos = i;
277 return &header->a_entries[j];
278 }
279 }
280
281 if (!once) {
282 once = 1;
283 start = 0;
284 end = *pos;
285 goto again;
286 }
287
288 return NULL;
289 }
290
291 /*
292 * Merge the posix ACL and the extended ACL into new posix ACL.
293 */
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)
297 {
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;
303
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. */
308 posix_count = 3;
309 posix_size = CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
310 new = kzalloc(posix_size, GFP_NOFS);
311 if (unlikely(new == NULL))
312 return -ENOMEM;
313
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]);
318 switch (ae.e_tag) {
319 case ACL_USER_OBJ:
320 case ACL_GROUP_OBJ:
321 case ACL_OTHER:
322 if (ae.e_id != ACL_UNDEFINED_ID) {
323 rc = -EIO;
324 goto _out;
325 }
326
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;
334 }
335 break;
336 case ACL_MASK:
337 case ACL_USER:
338 case ACL_GROUP:
339 if (ae.e_stat == ES_DEL)
340 break;
341 default:
342 rc = -EIO;
343 goto _out;
344 }
345 }
346 } else {
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.*/
349 int ori_posix_count;
350
351 if (unlikely(size < 0))
352 return -EINVAL;
353 else if (!size)
354 ori_posix_count = 0;
355 else
356 ori_posix_count =
357 CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
358 posix_count = ori_posix_count + ext_count;
359 posix_size =
360 CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
361 new = kzalloc(posix_size, GFP_NOFS);
362 if (unlikely(new == NULL))
363 return -ENOMEM;
364
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. */
368 pos = 0;
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);
372 if (ee == NULL)
373 memcpy(&new->a_entries[j++],
374 &posix_header->a_entries[i],
375 sizeof(posix_acl_xattr_entry));
376 }
377
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) !=
382 ES_DEL) {
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;
389 }
390 }
391 }
392
393 /* free unused space. */
394 rc = lustre_posix_acl_xattr_reduce_space(&new, posix_count, j);
395 if (rc >= 0) {
396 posix_size = rc;
397 *out = new;
398 rc = 0;
399 }
400
401 _out:
402 if (rc) {
403 kfree(new);
404 posix_size = rc;
405 }
406 return posix_size;
407 }
408 EXPORT_SYMBOL(lustre_acl_xattr_merge2posix);
409
410 /*
411 * Merge the posix ACL and the extended ACL into new extended ACL.
412 */
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)
416 {
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;
422
423 if (unlikely(size < 0))
424 return ERR_PTR(-EINVAL);
425 else if (!size)
426 posix_count = 0;
427 else
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);
432
433 new = kzalloc(ext_size, GFP_NOFS);
434 if (unlikely(new == NULL))
435 return ERR_PTR(-ENOMEM);
436
437 for (i = 0, j = 0; i < posix_count; i++) {
438 lustre_posix_acl_le_to_cpu(&pae, &posix_header->a_entries[i]);
439 switch (pae.e_tag) {
440 case ACL_USER_OBJ:
441 case ACL_GROUP_OBJ:
442 case ACL_MASK:
443 case ACL_OTHER:
444 if (pae.e_id != ACL_UNDEFINED_ID) {
445 rc = -EIO;
446 goto out;
447 }
448 case ACL_USER:
449 /* ignore "nobody" entry. */
450 if (pae.e_id == NOBODY_UID)
451 break;
452
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);
461 if (ee) {
462 if (posix_header->a_entries[i].e_perm !=
463 ee->e_perm)
464 /* entry modified. */
465 ee->e_stat =
466 new->a_entries[j++].e_stat =
467 cpu_to_le32(ES_MOD);
468 else
469 /* entry unchanged. */
470 ee->e_stat =
471 new->a_entries[j++].e_stat =
472 cpu_to_le32(ES_UNC);
473 } else {
474 /* new entry. */
475 new->a_entries[j++].e_stat =
476 cpu_to_le32(ES_ADD);
477 }
478 break;
479 case ACL_GROUP:
480 /* ignore "nobody" entry. */
481 if (pae.e_id == NOBODY_GID)
482 break;
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);
491 if (ee) {
492 if (posix_header->a_entries[i].e_perm !=
493 ee->e_perm)
494 /* entry modified. */
495 ee->e_stat =
496 new->a_entries[j++].e_stat =
497 cpu_to_le32(ES_MOD);
498 else
499 /* entry unchanged. */
500 ee->e_stat =
501 new->a_entries[j++].e_stat =
502 cpu_to_le32(ES_UNC);
503 } else {
504 /* new entry. */
505 new->a_entries[j++].e_stat =
506 cpu_to_le32(ES_ADD);
507 }
508 break;
509 default:
510 rc = -EIO;
511 goto out;
512 }
513 }
514
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))
522 continue;
523
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);
530 }
531 }
532
533 new->a_count = cpu_to_le32(j);
534 /* free unused space. */
535 rc = lustre_ext_acl_xattr_reduce_space(&new, ext_count);
536
537 out:
538 if (rc) {
539 kfree(new);
540 new = ERR_PTR(rc);
541 }
542 return new;
543 }
544 EXPORT_SYMBOL(lustre_acl_xattr_merge2ext);
545
546 #endif
This page took 0.044902 seconds and 4 git commands to generate.