Whamcloud - gitweb
07364bcb60505dce105573b4f3cd2d94077ac785
[fs/lustre-release.git] / lustre / obdclass / acl.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
30  * Use is subject to license terms.
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 #ifndef EXPORT_SYMTAB
44 # define EXPORT_SYMTAB
45 #endif
46
47 #define DEBUG_SUBSYSTEM S_SEC
48
49 #include <linux/lustre_acl.h>
50 #include <lustre_eacl.h>
51 #include <obd_support.h>
52
53 #ifdef CONFIG_FS_POSIX_ACL
54
55 #define CFS_ACL_XATTR_VERSION POSIX_ACL_XATTR_VERSION
56
57 enum {
58         ES_UNK  = 0,    /* unknown stat */
59         ES_UNC  = 1,    /* ACL entry is not changed */
60         ES_MOD  = 2,    /* ACL entry is modified */
61         ES_ADD  = 3,    /* ACL entry is added */
62         ES_DEL  = 4     /* ACL entry is deleted */
63 };
64
65 static inline void lustre_ext_acl_le_to_cpu(ext_acl_xattr_entry *d,
66                                             ext_acl_xattr_entry *s)
67 {
68         d->e_tag        = le16_to_cpu(s->e_tag);
69         d->e_perm       = le16_to_cpu(s->e_perm);
70         d->e_id         = le32_to_cpu(s->e_id);
71         d->e_stat       = le32_to_cpu(s->e_stat);
72 }
73
74 static inline void lustre_ext_acl_cpu_to_le(ext_acl_xattr_entry *d,
75                                             ext_acl_xattr_entry *s)
76 {
77         d->e_tag        = cpu_to_le16(s->e_tag);
78         d->e_perm       = cpu_to_le16(s->e_perm);
79         d->e_id         = cpu_to_le32(s->e_id);
80         d->e_stat       = cpu_to_le32(s->e_stat);
81 }
82
83 static inline void lustre_posix_acl_le_to_cpu(posix_acl_xattr_entry *d,
84                                               posix_acl_xattr_entry *s)
85 {
86         d->e_tag        = le16_to_cpu(s->e_tag);
87         d->e_perm       = le16_to_cpu(s->e_perm);
88         d->e_id         = le32_to_cpu(s->e_id);
89 }
90
91 static inline void lustre_posix_acl_cpu_to_le(posix_acl_xattr_entry *d,
92                                               posix_acl_xattr_entry *s)
93 {
94         d->e_tag        = cpu_to_le16(s->e_tag);
95         d->e_perm       = cpu_to_le16(s->e_perm);
96         d->e_id         = cpu_to_le32(s->e_id);
97 }
98
99 /*
100  * Check permission based on POSIX ACL.
101  */
102 int lustre_posix_acl_permission(struct md_ucred *mu, struct lu_attr *la,
103                                 int want, posix_acl_xattr_entry *entry,
104                                 int count)
105 {
106         posix_acl_xattr_entry *pa, *pe, *mask_obj;
107         posix_acl_xattr_entry ae, me;
108         int found = 0;
109
110         if (count <= 0)
111                 return -EACCES;
112
113         for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
114                 lustre_posix_acl_le_to_cpu(&ae, pa);
115                 switch (ae.e_tag) {
116                 case ACL_USER_OBJ:
117                         /* (May have been checked already) */
118                         if (la->la_uid == mu->mu_fsuid)
119                                 goto check_perm;
120                         break;
121                 case ACL_USER:
122                         if (ae.e_id == mu->mu_fsuid)
123                                 goto mask;
124                         break;
125                 case ACL_GROUP_OBJ:
126                         if (lustre_in_group_p(mu, la->la_gid)) {
127                                 found = 1;
128                                 if ((ae.e_perm & want) == want)
129                                         goto mask;
130                         }
131                         break;
132                 case ACL_GROUP:
133                         if (lustre_in_group_p(mu, ae.e_id)) {
134                                 found = 1;
135                                 if ((ae.e_perm & want) == want)
136                                         goto mask;
137                         }
138                         break;
139                 case ACL_MASK:
140                         break;
141                 case ACL_OTHER:
142                         if (found)
143                                 return -EACCES;
144                         else
145                                 goto check_perm;
146                 default:
147                         return -EIO;
148                 }
149         }
150         return -EIO;
151
152 mask:
153         for (mask_obj = pa + 1; mask_obj <= pe; mask_obj++) {
154                 lustre_posix_acl_le_to_cpu(&me, mask_obj);
155                 if (me.e_tag == ACL_MASK) {
156                         if ((ae.e_perm & me.e_perm & want) == want)
157                                 return 0;
158
159                         return -EACCES;
160                 }
161         }
162
163 check_perm:
164         if ((ae.e_perm & want) == want)
165                 return 0;
166
167         return -EACCES;
168 }
169 EXPORT_SYMBOL(lustre_posix_acl_permission);
170
171 /*
172  * Modify the ACL for the chmod.
173  */
174 int lustre_posix_acl_chmod_masq(posix_acl_xattr_entry *entry, __u32 mode,
175                                 int count)
176 {
177         posix_acl_xattr_entry *group_obj = NULL, *mask_obj = NULL, *pa, *pe;
178
179         for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
180                 switch (le16_to_cpu(pa->e_tag)) {
181                 case ACL_USER_OBJ:
182                         pa->e_perm = cpu_to_le16((mode & S_IRWXU) >> 6);
183                         break;
184                 case ACL_USER:
185                 case ACL_GROUP:
186                         break;
187                 case ACL_GROUP_OBJ:
188                         group_obj = pa;
189                         break;
190                 case ACL_MASK:
191                         mask_obj = pa;
192                         break;
193                 case ACL_OTHER:
194                         pa->e_perm = cpu_to_le16(mode & S_IRWXO);
195                         break;
196                 default:
197                         return -EIO;
198                 }
199         }
200
201         if (mask_obj) {
202                 mask_obj->e_perm = cpu_to_le16((mode & S_IRWXG) >> 3);
203         } else {
204                 if (!group_obj)
205                         return -EIO;
206                 group_obj->e_perm = cpu_to_le16((mode & S_IRWXG) >> 3);
207         }
208
209         return 0;
210 }
211 EXPORT_SYMBOL(lustre_posix_acl_chmod_masq);
212
213 /*
214  * Modify acl when creating a new object.
215  */
216 int lustre_posix_acl_create_masq(posix_acl_xattr_entry *entry, __u32 *pmode,
217                                  int count)
218 {
219         posix_acl_xattr_entry *group_obj = NULL, *mask_obj = NULL, *pa, *pe;
220         posix_acl_xattr_entry ae;
221         __u32 mode = *pmode;
222         int not_equiv = 0;
223
224         for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
225                 lustre_posix_acl_le_to_cpu(&ae, pa);
226                 switch (ae.e_tag) {
227                 case ACL_USER_OBJ:
228                         ae.e_perm &= (mode >> 6) | ~S_IRWXO;
229                         pa->e_perm = cpu_to_le16(ae.e_perm);
230                         mode &= (ae.e_perm << 6) | ~S_IRWXU;
231                         break;
232                 case ACL_USER:
233                 case ACL_GROUP:
234                         not_equiv = 1;
235                         break;
236                 case ACL_GROUP_OBJ:
237                         group_obj = pa;
238                         break;
239                 case ACL_OTHER:
240                         ae.e_perm &= mode | ~S_IRWXO;
241                         pa->e_perm = cpu_to_le16(ae.e_perm);
242                         mode &= ae.e_perm | ~S_IRWXO;
243                         break;
244                 case ACL_MASK:
245                         mask_obj = pa;
246                         not_equiv = 1;
247                         break;
248                 default:
249                         return -EIO;
250                 }
251         }
252
253         if (mask_obj) {
254                 ae.e_perm = le16_to_cpu(mask_obj->e_perm) &
255                             ((mode >> 3) | ~S_IRWXO);
256                 mode &= (ae.e_perm << 3) | ~S_IRWXG;
257                 mask_obj->e_perm = cpu_to_le16(ae.e_perm);
258         } else {
259                 if (!group_obj)
260                         return -EIO;
261                 ae.e_perm = le16_to_cpu(group_obj->e_perm) &
262                             ((mode >> 3) | ~S_IRWXO);
263                 mode &= (ae.e_perm << 3) | ~S_IRWXG;
264                 group_obj->e_perm = cpu_to_le16(ae.e_perm);
265         }
266
267         *pmode = (*pmode & ~S_IRWXUGO) | mode;
268         return not_equiv;
269 }
270 EXPORT_SYMBOL(lustre_posix_acl_create_masq);
271
272 /* if "new_count == 0", then "new = {a_version, NULL}", NOT NULL. */
273 static int lustre_posix_acl_xattr_reduce_space(posix_acl_xattr_header **header,
274                                                int old_count, int new_count)
275 {
276         int old_size = CFS_ACL_XATTR_SIZE(old_count, posix_acl_xattr);
277         int new_size = CFS_ACL_XATTR_SIZE(new_count, posix_acl_xattr);
278         posix_acl_xattr_header *new;
279
280         if (unlikely(old_count <= new_count))
281                 return old_size;
282
283         OBD_ALLOC(new, new_size);
284         if (unlikely(new == NULL))
285                 return -ENOMEM;
286
287         memcpy(new, *header, new_size);
288         OBD_FREE(*header, old_size);
289         *header = new;
290         return new_size;
291 }
292
293 /* if "new_count == 0", then "new = {0, NULL}", NOT NULL. */
294 static int lustre_ext_acl_xattr_reduce_space(ext_acl_xattr_header **header,
295                                              int old_count)
296 {
297         int ext_count = le32_to_cpu((*header)->a_count);
298         int ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr);
299         int old_size = CFS_ACL_XATTR_SIZE(old_count, ext_acl_xattr);
300         ext_acl_xattr_header *new;
301
302         if (unlikely(old_count <= ext_count))
303                 return 0;
304
305         OBD_ALLOC(new, ext_size);
306         if (unlikely(new == NULL))
307                 return -ENOMEM;
308
309         memcpy(new, *header, ext_size);
310         OBD_FREE(*header, old_size);
311         *header = new;
312         return 0;
313 }
314
315 /*
316  * Generate new extended ACL based on the posix ACL.
317  */
318 ext_acl_xattr_header *
319 lustre_posix_acl_xattr_2ext(posix_acl_xattr_header *header, int size)
320 {
321         int count, i, esize;
322         ext_acl_xattr_header *new;
323         ENTRY;
324
325         if (unlikely(size < 0))
326                 RETURN(ERR_PTR(-EINVAL));
327         else if (!size)
328                 count = 0;
329         else
330                 count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
331         esize = CFS_ACL_XATTR_SIZE(count, ext_acl_xattr);
332         OBD_ALLOC(new, esize);
333         if (unlikely(new == NULL))
334                 RETURN(ERR_PTR(-ENOMEM));
335
336         new->a_count = cpu_to_le32(count);
337         for (i = 0; i < count; i++) {
338                 new->a_entries[i].e_tag  = header->a_entries[i].e_tag;
339                 new->a_entries[i].e_perm = header->a_entries[i].e_perm;
340                 new->a_entries[i].e_id   = header->a_entries[i].e_id;
341                 new->a_entries[i].e_stat = cpu_to_le32(ES_UNK);
342         }
343
344         RETURN(new);
345 }
346 EXPORT_SYMBOL(lustre_posix_acl_xattr_2ext);
347
348 /*
349  * Filter out the "nobody" entries in the posix ACL.
350  */
351 int lustre_posix_acl_xattr_filter(posix_acl_xattr_header *header, int size,
352                                   posix_acl_xattr_header **out)
353 {
354         int count, i, j, rc = 0;
355         __u32 id;
356         posix_acl_xattr_header *new;
357         ENTRY;
358
359         if (unlikely(size < 0))
360                 RETURN(-EINVAL);
361         else if (!size)
362                 RETURN(0);
363
364         OBD_ALLOC(new, size);
365         if (unlikely(new == NULL))
366                 RETURN(-ENOMEM);
367
368         new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
369         count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
370         for (i = 0, j = 0; i < count; i++) {
371                 id = le32_to_cpu(header->a_entries[i].e_id);
372                 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
373                 case ACL_USER_OBJ:
374                 case ACL_GROUP_OBJ:
375                 case ACL_MASK:
376                 case ACL_OTHER:
377                         if (id != ACL_UNDEFINED_ID)
378                                 GOTO(_out, rc = -EIO);
379
380                         memcpy(&new->a_entries[j++], &header->a_entries[i],
381                                sizeof(posix_acl_xattr_entry));
382                         break;
383                 case ACL_USER:
384                         if (id != NOBODY_UID)
385                                 memcpy(&new->a_entries[j++],
386                                        &header->a_entries[i],
387                                        sizeof(posix_acl_xattr_entry));
388                         break;
389                 case ACL_GROUP:
390                         if (id != NOBODY_GID)
391                                 memcpy(&new->a_entries[j++],
392                                        &header->a_entries[i],
393                                        sizeof(posix_acl_xattr_entry));
394                         break;
395                 default:
396                         GOTO(_out, rc = -EIO);
397                 }
398         }
399
400         /* free unused space. */
401         rc = lustre_posix_acl_xattr_reduce_space(&new, count, j);
402         if (rc >= 0) {
403                 size = rc;
404                 *out = new;
405                 rc = 0;
406         }
407         EXIT;
408
409 _out:
410         if (rc) {
411                 OBD_FREE(new, size);
412                 size = rc;
413         }
414         return size;
415 }
416 EXPORT_SYMBOL(lustre_posix_acl_xattr_filter);
417
418 /*
419  * Convert server-side uid/gid in the posix ACL items to the client-side ones.
420  * convert rule:
421  * @CFS_IC_NOTHING
422  *  nothing to be converted.
423  * @CFS_IC_ALL
424  *  mapped ids are converted to client-side ones,
425  *  unmapped ones are converted to "nobody".
426  * @CFS_IC_MAPPED
427  *  only mapped ids are converted to "nobody".
428  * @CFS_IC_UNMAPPED
429  *  only unmapped ids are converted to "nobody".
430  */
431 int lustre_posix_acl_xattr_id2client(struct md_ucred *mu,
432                                      struct lustre_idmap_table *t,
433                                      posix_acl_xattr_header *header,
434                                      int size, int flags)
435 {
436         int count, i;
437         __u32 id;
438         ENTRY;
439
440         if (unlikely(size < 0))
441                 RETURN(-EINVAL);
442         else if (!size)
443                 RETURN(0);
444
445         if (unlikely(flags == CFS_IC_NOTHING))
446                 RETURN(0);
447
448         count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
449         for (i = 0; i < count; i++) {
450                 id = le32_to_cpu(header->a_entries[i].e_id);
451                 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
452                 case ACL_USER_OBJ:
453                 case ACL_GROUP_OBJ:
454                 case ACL_MASK:
455                 case ACL_OTHER:
456                         if (id != ACL_UNDEFINED_ID)
457                                 RETURN(-EIO);
458                         break;
459                 case ACL_USER:
460                         id = lustre_idmap_lookup_uid(mu, t, 1, id);
461                         if (flags == CFS_IC_ALL) {
462                                 if (id == CFS_IDMAP_NOTFOUND)
463                                         id = NOBODY_UID;
464                                 header->a_entries[i].e_id = cpu_to_le32(id);
465                         } else if (flags == CFS_IC_MAPPED) {
466                                 if (id != CFS_IDMAP_NOTFOUND)
467                                         header->a_entries[i].e_id =
468                                                         cpu_to_le32(NOBODY_UID);
469                         } else if (flags == CFS_IC_UNMAPPED) {
470                                 if (id == CFS_IDMAP_NOTFOUND)
471                                         header->a_entries[i].e_id =
472                                                         cpu_to_le32(NOBODY_UID);
473                         }
474                         break;
475                 case ACL_GROUP:
476                         id = lustre_idmap_lookup_gid(mu, t, 1, id);
477                         if (flags == CFS_IC_ALL) {
478                                 if (id == CFS_IDMAP_NOTFOUND)
479                                         id = NOBODY_GID;
480                                 header->a_entries[i].e_id = cpu_to_le32(id);
481                         } else if (flags == CFS_IC_MAPPED) {
482                                 if (id != CFS_IDMAP_NOTFOUND)
483                                         header->a_entries[i].e_id =
484                                                         cpu_to_le32(NOBODY_GID);
485                         } else if (flags == CFS_IC_UNMAPPED) {
486                                 if (id == CFS_IDMAP_NOTFOUND)
487                                         header->a_entries[i].e_id =
488                                                         cpu_to_le32(NOBODY_GID);
489                         }
490                         break;
491                  default:
492                         RETURN(-EIO);
493                 }
494         }
495     RETURN(0);
496 }
497 EXPORT_SYMBOL(lustre_posix_acl_xattr_id2client);
498
499 /*
500  * Release the posix ACL space.
501  */
502 void lustre_posix_acl_xattr_free(posix_acl_xattr_header *header, int size)
503 {
504         OBD_FREE(header, size);
505 }
506 EXPORT_SYMBOL(lustre_posix_acl_xattr_free);
507
508 /*
509  * Converts client-side uid/gid in the extended ACL items to server-side ones.
510  * convert rule:
511  *  mapped ids are converted to server-side ones,
512  *  unmapped ones cause "EPERM" error.
513  */
514 int lustre_ext_acl_xattr_id2server(struct md_ucred *mu,
515                                    struct lustre_idmap_table *t,
516                                    ext_acl_xattr_header *header)
517
518 {
519         int i, count = le32_to_cpu(header->a_count);
520         __u32 id;
521         ENTRY;
522
523         for (i = 0; i < count; i++) {
524                 id = le32_to_cpu(header->a_entries[i].e_id);
525                 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
526                 case ACL_USER_OBJ:
527                 case ACL_GROUP_OBJ:
528                 case ACL_MASK:
529                 case ACL_OTHER:
530                         if (id != ACL_UNDEFINED_ID)
531                                 RETURN(-EIO);
532                         break;
533                 case ACL_USER:
534                         id = lustre_idmap_lookup_uid(mu, t, 0, id);
535                         if (id == CFS_IDMAP_NOTFOUND)
536                                 RETURN(-EPERM);
537                         else
538                                 header->a_entries[i].e_id = cpu_to_le32(id);
539                         break;
540                 case ACL_GROUP:
541                         id = lustre_idmap_lookup_gid(mu, t, 0, id);
542                         if (id == CFS_IDMAP_NOTFOUND)
543                                 RETURN(-EPERM);
544                         else
545                                 header->a_entries[i].e_id = cpu_to_le32(id);
546                         break;
547                 default:
548                         RETURN(-EIO);
549                 }
550         }
551         RETURN(0);
552 }
553 EXPORT_SYMBOL(lustre_ext_acl_xattr_id2server);
554
555 /*
556  * Release the extended ACL space.
557  */
558 void lustre_ext_acl_xattr_free(ext_acl_xattr_header *header)
559 {
560         OBD_FREE(header, CFS_ACL_XATTR_SIZE(le32_to_cpu(header->a_count), \
561                                             ext_acl_xattr));
562 }
563 EXPORT_SYMBOL(lustre_ext_acl_xattr_free);
564
565 static ext_acl_xattr_entry *
566 lustre_ext_acl_xattr_search(ext_acl_xattr_header *header,
567                             posix_acl_xattr_entry *entry, int *pos)
568 {
569         int once, start, end, i, j, count = le32_to_cpu(header->a_count);
570
571         once = 0;
572         start = *pos;
573         end = count;
574
575 again:
576         for (i = start; i < end; i++) {
577                 if (header->a_entries[i].e_tag == entry->e_tag &&
578                     header->a_entries[i].e_id == entry->e_id) {
579                         j = i;
580                         if (++i >= count)
581                                 i = 0;
582                         *pos = i;
583                         return &header->a_entries[j];
584                 }
585         }
586
587         if (!once) {
588                 once = 1;
589                 start = 0;
590                 end = *pos;
591                 goto again;
592         }
593
594         return NULL;
595 }
596
597 /*
598  * Merge the posix ACL and the extended ACL into new posix ACL.
599  */
600 int lustre_acl_xattr_merge2posix(posix_acl_xattr_header *posix_header, int size,
601                                  ext_acl_xattr_header *ext_header,
602                                  posix_acl_xattr_header **out)
603 {
604         int posix_count, posix_size, i, j;
605         int ext_count = le32_to_cpu(ext_header->a_count), pos = 0, rc = 0;
606         posix_acl_xattr_entry pe = {ACL_MASK, 0, ACL_UNDEFINED_ID};
607         posix_acl_xattr_header *new;
608         ext_acl_xattr_entry *ee, ae;
609         ENTRY;
610
611         lustre_posix_acl_cpu_to_le(&pe, &pe);
612         ee = lustre_ext_acl_xattr_search(ext_header, &pe, &pos);
613         if (ee == NULL || le32_to_cpu(ee->e_stat) == ES_DEL) {
614                 /* there are only base ACL entries at most. */
615                 posix_count = 3;
616                 posix_size = CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
617                 OBD_ALLOC(new, posix_size);
618                 if (unlikely(new == NULL))
619                         RETURN(-ENOMEM);
620
621                 new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
622                 for (i = 0, j = 0; i < ext_count; i++) {
623                         lustre_ext_acl_le_to_cpu(&ae,
624                                                  &ext_header->a_entries[i]);
625                         switch (ae.e_tag) {
626                         case ACL_USER_OBJ:
627                         case ACL_GROUP_OBJ:
628                         case ACL_OTHER:
629                                 if (ae.e_id != ACL_UNDEFINED_ID)
630                                         GOTO(_out, rc = -EIO);
631
632                                 if (ae.e_stat != ES_DEL) {
633                                         new->a_entries[j].e_tag =
634                                                 ext_header->a_entries[i].e_tag;
635                                         new->a_entries[j].e_perm =
636                                                 ext_header->a_entries[i].e_perm;
637                                         new->a_entries[j++].e_id =
638                                                 ext_header->a_entries[i].e_id;
639                                 }
640                                 break;
641                         case ACL_MASK:
642                         case ACL_USER:
643                         case ACL_GROUP:
644                                 if (ae.e_stat == ES_DEL)
645                                         break;
646                         default:
647                                 GOTO(_out, rc = -EIO);
648                         }
649                 }
650         } else {
651                 /* maybe there are valid ACL_USER or ACL_GROUP entries in the
652                  * original server-side ACL, they are regarded as ES_UNC stat.*/
653                 int ori_posix_count;
654
655                 if (unlikely(size < 0))
656                         RETURN(-EINVAL);
657                 else if (!size)
658                         ori_posix_count = 0;
659                 else
660                         ori_posix_count =
661                                 CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
662                 posix_count = ori_posix_count + ext_count;
663                 posix_size =
664                         CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
665                 OBD_ALLOC(new, posix_size);
666                 if (unlikely(new == NULL))
667                         RETURN(-ENOMEM);
668
669                 new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
670                 /* 1. process the unchanged ACL entries
671                  *    in the original server-side ACL. */
672                 pos = 0;
673                 for (i = 0, j = 0; i < ori_posix_count; i++) {
674                         ee = lustre_ext_acl_xattr_search(ext_header,
675                                         &posix_header->a_entries[i], &pos);
676                         if (ee == NULL)
677                                 memcpy(&new->a_entries[j++],
678                                        &posix_header->a_entries[i],
679                                        sizeof(posix_acl_xattr_entry));
680                 }
681
682                 /* 2. process the non-deleted entries
683                  *    from client-side extended ACL. */
684                 for (i = 0; i < ext_count; i++) {
685                         if (le16_to_cpu(ext_header->a_entries[i].e_stat) !=
686                             ES_DEL) {
687                                 new->a_entries[j].e_tag =
688                                                 ext_header->a_entries[i].e_tag;
689                                 new->a_entries[j].e_perm =
690                                                 ext_header->a_entries[i].e_perm;
691                                 new->a_entries[j++].e_id =
692                                                 ext_header->a_entries[i].e_id;
693                         }
694                 }
695         }
696
697         /* free unused space. */
698         rc = lustre_posix_acl_xattr_reduce_space(&new, posix_count, j);
699         if (rc >= 0) {
700                 posix_size = rc;
701                 *out = new;
702                 rc = 0;
703         }
704         EXIT;
705
706 _out:
707         if (rc) {
708                 OBD_FREE(new, posix_size);
709                 posix_size = rc;
710         }
711         return posix_size;
712 }
713 EXPORT_SYMBOL(lustre_acl_xattr_merge2posix);
714
715 /*
716  * Merge the posix ACL and the extended ACL into new extended ACL.
717  */
718 ext_acl_xattr_header *
719 lustre_acl_xattr_merge2ext(posix_acl_xattr_header *posix_header, int size,
720                            ext_acl_xattr_header *ext_header)
721 {
722         int ori_ext_count, posix_count, ext_count, ext_size;
723         int i, j, pos = 0, rc = 0;
724         posix_acl_xattr_entry pae;
725         ext_acl_xattr_header *new;
726         ext_acl_xattr_entry *ee, eae;
727         ENTRY;
728
729         if (unlikely(size < 0))
730                 RETURN(ERR_PTR(-EINVAL));
731         else if (!size)
732                 posix_count = 0;
733         else
734                 posix_count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
735         ori_ext_count = le32_to_cpu(ext_header->a_count);
736         ext_count = posix_count + ori_ext_count;
737         ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr);
738
739         OBD_ALLOC(new, ext_size);
740         if (unlikely(new == NULL))
741                 RETURN(ERR_PTR(-ENOMEM));
742
743         for (i = 0, j = 0; i < posix_count; i++) {
744                 lustre_posix_acl_le_to_cpu(&pae, &posix_header->a_entries[i]);
745                 switch (pae.e_tag) {
746                 case ACL_USER_OBJ:
747                 case ACL_GROUP_OBJ:
748                 case ACL_MASK:
749                 case ACL_OTHER:
750                         if (pae.e_id != ACL_UNDEFINED_ID)
751                                 GOTO(out, rc = -EIO);
752                 case ACL_USER:
753                         /* ignore "nobody" entry. */
754                         if (pae.e_id == NOBODY_UID)
755                                 break;
756
757                         new->a_entries[j].e_tag =
758                                         posix_header->a_entries[i].e_tag;
759                         new->a_entries[j].e_perm =
760                                         posix_header->a_entries[i].e_perm;
761                         new->a_entries[j].e_id =
762                                         posix_header->a_entries[i].e_id;
763                         ee = lustre_ext_acl_xattr_search(ext_header,
764                                         &posix_header->a_entries[i], &pos);
765                         if (ee) {
766                                 if (posix_header->a_entries[i].e_perm !=
767                                                                 ee->e_perm)
768                                         /* entry modified. */
769                                         ee->e_perm =
770                                         new->a_entries[j++].e_stat =
771                                                         cpu_to_le32(ES_MOD);
772                                 else
773                                         /* entry unchanged. */
774                                         ee->e_perm =
775                                         new->a_entries[j++].e_stat =
776                                                         cpu_to_le32(ES_UNC);
777                         } else {
778                                 /* new entry. */
779                                 new->a_entries[j++].e_stat =
780                                                         cpu_to_le32(ES_ADD);
781                         }
782                         break;
783                 case ACL_GROUP:
784                         /* ignore "nobody" entry. */
785                         if (pae.e_id == NOBODY_GID)
786                                 break;
787                         new->a_entries[j].e_tag =
788                                         posix_header->a_entries[i].e_tag;
789                         new->a_entries[j].e_perm =
790                                         posix_header->a_entries[i].e_perm;
791                         new->a_entries[j].e_id =
792                                         posix_header->a_entries[i].e_id;
793                         ee = lustre_ext_acl_xattr_search(ext_header,
794                                         &posix_header->a_entries[i], &pos);
795                         if (ee) {
796                                 if (posix_header->a_entries[i].e_perm !=
797                                                                 ee->e_perm)
798                                         /* entry modified. */
799                                         ee->e_perm =
800                                         new->a_entries[j++].e_stat =
801                                                         cpu_to_le32(ES_MOD);
802                                 else
803                                         /* entry unchanged. */
804                                         ee->e_perm =
805                                         new->a_entries[j++].e_stat =
806                                                         cpu_to_le32(ES_UNC);
807                         } else {
808                                 /* new entry. */
809                                 new->a_entries[j++].e_stat =
810                                                         cpu_to_le32(ES_ADD);
811                         }
812                         break;
813                 default:
814                         GOTO(out, rc = -EIO);
815                 }
816         }
817
818         /* process deleted entries. */
819         for (i = 0; i < ori_ext_count; i++) {
820                 lustre_ext_acl_le_to_cpu(&eae, &ext_header->a_entries[i]);
821                 if (eae.e_stat == ES_UNK) {
822                         /* ignore "nobody" entry. */
823                         if ((eae.e_tag == ACL_USER && eae.e_id == NOBODY_UID) ||
824                             (eae.e_tag == ACL_GROUP && eae.e_id == NOBODY_GID))
825                                 continue;
826
827                         new->a_entries[j].e_tag =
828                                                 ext_header->a_entries[i].e_tag;
829                         new->a_entries[j].e_perm =
830                                                 ext_header->a_entries[i].e_perm;
831                         new->a_entries[j].e_id = ext_header->a_entries[i].e_id;
832                         new->a_entries[j++].e_stat = cpu_to_le32(ES_DEL);
833                 }
834         }
835
836         new->a_count = cpu_to_le32(j);
837         /* free unused space. */
838         rc = lustre_ext_acl_xattr_reduce_space(&new, ext_count);
839         EXIT;
840
841 out:
842         if (rc) {
843                 OBD_FREE(new, ext_size);
844                 new = ERR_PTR(rc);
845         }
846         return new;
847 }
848 EXPORT_SYMBOL(lustre_acl_xattr_merge2ext);
849
850 #endif