Merge branch 'kconfig' of git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild
[linux-2.6-block.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 <lu_object.h>
45 #include <lustre_acl.h>
46 #include <lustre_eacl.h>
47 #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         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. */
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 *
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  */
174 int lustre_posix_acl_xattr_filter(posix_acl_xattr_header *header, int 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 (unlikely(size < 0))
182                 return -EINVAL;
183         else if (!size)
184                 return 0;
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                                 GOTO(_out, rc = -EIO);
201
202                         memcpy(&new->a_entries[j++], &header->a_entries[i],
203                                sizeof(posix_acl_xattr_entry));
204                         break;
205                 case ACL_USER:
206                         if (id != NOBODY_UID)
207                                 memcpy(&new->a_entries[j++],
208                                        &header->a_entries[i],
209                                        sizeof(posix_acl_xattr_entry));
210                         break;
211                 case ACL_GROUP:
212                         if (id != NOBODY_GID)
213                                 memcpy(&new->a_entries[j++],
214                                        &header->a_entries[i],
215                                        sizeof(posix_acl_xattr_entry));
216                         break;
217                 default:
218                         GOTO(_out, rc = -EIO);
219                 }
220         }
221
222         /* free unused space. */
223         rc = lustre_posix_acl_xattr_reduce_space(&new, count, j);
224         if (rc >= 0) {
225                 size = rc;
226                 *out = new;
227                 rc = 0;
228         }
229
230 _out:
231         if (rc) {
232                 OBD_FREE(new, size);
233                 size = rc;
234         }
235         return size;
236 }
237 EXPORT_SYMBOL(lustre_posix_acl_xattr_filter);
238
239 /*
240  * Release the posix ACL space.
241  */
242 void lustre_posix_acl_xattr_free(posix_acl_xattr_header *header, int size)
243 {
244         OBD_FREE(header, size);
245 }
246 EXPORT_SYMBOL(lustre_posix_acl_xattr_free);
247
248 /*
249  * Release the extended ACL space.
250  */
251 void lustre_ext_acl_xattr_free(ext_acl_xattr_header *header)
252 {
253         OBD_FREE(header, CFS_ACL_XATTR_SIZE(le32_to_cpu(header->a_count), \
254                                             ext_acl_xattr));
255 }
256 EXPORT_SYMBOL(lustre_ext_acl_xattr_free);
257
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)
261 {
262         int once, start, end, i, j, count = le32_to_cpu(header->a_count);
263
264         once = 0;
265         start = *pos;
266         end = count;
267
268 again:
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) {
272                         j = i;
273                         if (++i >= count)
274                                 i = 0;
275                         *pos = i;
276                         return &header->a_entries[j];
277                 }
278         }
279
280         if (!once) {
281                 once = 1;
282                 start = 0;
283                 end = *pos;
284                 goto again;
285         }
286
287         return NULL;
288 }
289
290 /*
291  * Merge the posix ACL and the extended ACL into new posix ACL.
292  */
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)
296 {
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;
302
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. */
307                 posix_count = 3;
308                 posix_size = CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
309                 OBD_ALLOC(new, posix_size);
310                 if (unlikely(new == NULL))
311                         return -ENOMEM;
312
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]);
317                         switch (ae.e_tag) {
318                         case ACL_USER_OBJ:
319                         case ACL_GROUP_OBJ:
320                         case ACL_OTHER:
321                                 if (ae.e_id != ACL_UNDEFINED_ID)
322                                         GOTO(_out, rc = -EIO);
323
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;
331                                 }
332                                 break;
333                         case ACL_MASK:
334                         case ACL_USER:
335                         case ACL_GROUP:
336                                 if (ae.e_stat == ES_DEL)
337                                         break;
338                         default:
339                                 GOTO(_out, rc = -EIO);
340                         }
341                 }
342         } else {
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.*/
345                 int ori_posix_count;
346
347                 if (unlikely(size < 0))
348                         return -EINVAL;
349                 else if (!size)
350                         ori_posix_count = 0;
351                 else
352                         ori_posix_count =
353                                 CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
354                 posix_count = ori_posix_count + ext_count;
355                 posix_size =
356                         CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
357                 OBD_ALLOC(new, posix_size);
358                 if (unlikely(new == NULL))
359                         return -ENOMEM;
360
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. */
364                 pos = 0;
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);
368                         if (ee == NULL)
369                                 memcpy(&new->a_entries[j++],
370                                        &posix_header->a_entries[i],
371                                        sizeof(posix_acl_xattr_entry));
372                 }
373
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) !=
378                             ES_DEL) {
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;
385                         }
386                 }
387         }
388
389         /* free unused space. */
390         rc = lustre_posix_acl_xattr_reduce_space(&new, posix_count, j);
391         if (rc >= 0) {
392                 posix_size = rc;
393                 *out = new;
394                 rc = 0;
395         }
396
397 _out:
398         if (rc) {
399                 OBD_FREE(new, posix_size);
400                 posix_size = rc;
401         }
402         return posix_size;
403 }
404 EXPORT_SYMBOL(lustre_acl_xattr_merge2posix);
405
406 /*
407  * Merge the posix ACL and the extended ACL into new extended ACL.
408  */
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)
412 {
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;
418
419         if (unlikely(size < 0))
420                 return ERR_PTR(-EINVAL);
421         else if (!size)
422                 posix_count = 0;
423         else
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);
428
429         OBD_ALLOC(new, ext_size);
430         if (unlikely(new == NULL))
431                 return ERR_PTR(-ENOMEM);
432
433         for (i = 0, j = 0; i < posix_count; i++) {
434                 lustre_posix_acl_le_to_cpu(&pae, &posix_header->a_entries[i]);
435                 switch (pae.e_tag) {
436                 case ACL_USER_OBJ:
437                 case ACL_GROUP_OBJ:
438                 case ACL_MASK:
439                 case ACL_OTHER:
440                         if (pae.e_id != ACL_UNDEFINED_ID)
441                                 GOTO(out, rc = -EIO);
442                 case ACL_USER:
443                         /* ignore "nobody" entry. */
444                         if (pae.e_id == NOBODY_UID)
445                                 break;
446
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);
455                         if (ee) {
456                                 if (posix_header->a_entries[i].e_perm !=
457                                                                 ee->e_perm)
458                                         /* entry modified. */
459                                         ee->e_stat =
460                                         new->a_entries[j++].e_stat =
461                                                         cpu_to_le32(ES_MOD);
462                                 else
463                                         /* entry unchanged. */
464                                         ee->e_stat =
465                                         new->a_entries[j++].e_stat =
466                                                         cpu_to_le32(ES_UNC);
467                         } else {
468                                 /* new entry. */
469                                 new->a_entries[j++].e_stat =
470                                                         cpu_to_le32(ES_ADD);
471                         }
472                         break;
473                 case ACL_GROUP:
474                         /* ignore "nobody" entry. */
475                         if (pae.e_id == NOBODY_GID)
476                                 break;
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);
485                         if (ee) {
486                                 if (posix_header->a_entries[i].e_perm !=
487                                                                 ee->e_perm)
488                                         /* entry modified. */
489                                         ee->e_stat =
490                                         new->a_entries[j++].e_stat =
491                                                         cpu_to_le32(ES_MOD);
492                                 else
493                                         /* entry unchanged. */
494                                         ee->e_stat =
495                                         new->a_entries[j++].e_stat =
496                                                         cpu_to_le32(ES_UNC);
497                         } else {
498                                 /* new entry. */
499                                 new->a_entries[j++].e_stat =
500                                                         cpu_to_le32(ES_ADD);
501                         }
502                         break;
503                 default:
504                         GOTO(out, rc = -EIO);
505                 }
506         }
507
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))
515                                 continue;
516
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);
523                 }
524         }
525
526         new->a_count = cpu_to_le32(j);
527         /* free unused space. */
528         rc = lustre_ext_acl_xattr_reduce_space(&new, ext_count);
529
530 out:
531         if (rc) {
532                 OBD_FREE(new, ext_size);
533                 new = ERR_PTR(rc);
534         }
535         return new;
536 }
537 EXPORT_SYMBOL(lustre_acl_xattr_merge2ext);
538
539 #endif