Whamcloud - gitweb
LU-8837 lmv: don't use lqr_alloc spinlock in lmv
[fs/lustre-release.git] / lustre / mdd / mdd_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.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2012, 2013, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  * Lustre is a trademark of Sun Microsystems, Inc.
31  *
32  * lustre/obdclass/acl.c
33  *
34  * Lustre Access Control List.
35  *
36  * Author: Fan Yong <fanyong@clusterfs.com>
37  */
38
39 #define DEBUG_SUBSYSTEM S_SEC
40 #include <lu_object.h>
41 #include <lustre_acl.h>
42 #include <obd_support.h>
43 #include <lustre_idmap.h>
44 #include <md_object.h>
45 #include "mdd_internal.h"
46
47 #ifdef CONFIG_LUSTRE_FS_POSIX_ACL
48
49 static inline void lustre_posix_acl_le_to_cpu(posix_acl_xattr_entry *d,
50                                               posix_acl_xattr_entry *s)
51 {
52         d->e_tag = le16_to_cpu(s->e_tag);
53         d->e_perm = le16_to_cpu(s->e_perm);
54         d->e_id = le32_to_cpu(s->e_id);
55 }
56
57 #if 0
58 static inline void lustre_posix_acl_cpu_to_le(posix_acl_xattr_entry *d,
59                                               posix_acl_xattr_entry *s)
60 {
61         d->e_tag = cpu_to_le16(s->e_tag);
62         d->e_perm = cpu_to_le16(s->e_perm);
63         d->e_id = cpu_to_le32(s->e_id);
64 }
65 #endif
66
67 /*
68  * Check permission based on POSIX ACL.
69  */
70 int lustre_posix_acl_permission(struct lu_ucred *mu, const struct lu_attr *la,
71                                 unsigned int may_mask,
72                                 posix_acl_xattr_entry *entry, int count)
73 {
74         posix_acl_xattr_entry *pa, *pe, *mask_obj;
75         posix_acl_xattr_entry ae, me;
76         __u16 acl_want;
77         int found = 0;
78
79         if (count <= 0)
80                 return -EACCES;
81
82         /* There is implicit conversion between MAY_* modes and ACL_* modes.
83          * Don't bother explicitly converting them unless they actually change.
84          */
85         if (0) {
86                 acl_want = (may_mask & MAY_READ  ? ACL_READ : 0) |
87                            (may_mask & MAY_WRITE ? ACL_WRITE : 0) |
88                            (may_mask & MAY_EXEC  ? ACL_EXECUTE : 0);
89         } else {
90                 BUILD_BUG_ON(MAY_READ != ACL_READ);
91                 BUILD_BUG_ON(MAY_WRITE != ACL_WRITE);
92                 BUILD_BUG_ON(MAY_EXEC != ACL_EXECUTE);
93
94                 acl_want = may_mask;
95         }
96
97         for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
98                 lustre_posix_acl_le_to_cpu(&ae, pa);
99                 switch (ae.e_tag) {
100                 case ACL_USER_OBJ:
101                         /* (May have been checked already) */
102                         if (la->la_uid == mu->uc_fsuid)
103                                 goto check_perm;
104                         break;
105                 case ACL_USER:
106                         if (ae.e_id == mu->uc_fsuid)
107                                 goto mask;
108                         break;
109                 case ACL_GROUP_OBJ:
110                         if (lustre_in_group_p(mu, la->la_gid)) {
111                                 found = 1;
112                                 if ((ae.e_perm & acl_want) == acl_want)
113                                         goto mask;
114                         }
115                         break;
116                 case ACL_GROUP:
117                         if (lustre_in_group_p(mu, ae.e_id)) {
118                                 found = 1;
119                                 if ((ae.e_perm & acl_want) == acl_want)
120                                         goto mask;
121                         }
122                         break;
123                 case ACL_MASK:
124                         break;
125                 case ACL_OTHER:
126                         if (found)
127                                 return -EACCES;
128                         goto check_perm;
129                 default:
130                         return -EIO;
131 }
132         }
133         return -EIO;
134
135 mask:
136         for (mask_obj = pa + 1; mask_obj <= pe; mask_obj++) {
137                 lustre_posix_acl_le_to_cpu(&me, mask_obj);
138                 if (me.e_tag == ACL_MASK) {
139                         if ((ae.e_perm & me.e_perm & acl_want) == acl_want)
140                                 return 0;
141
142                         return -EACCES;
143                 }
144         }
145
146 check_perm:
147         if ((ae.e_perm & acl_want) == acl_want)
148                 return 0;
149
150         return -EACCES;
151 }
152
153 /*
154  * Modify the ACL for the chmod.
155  */
156 int lustre_posix_acl_chmod_masq(posix_acl_xattr_entry *entry, u32 mode,
157                                 int count)
158 {
159         posix_acl_xattr_entry *group_obj = NULL, *mask_obj = NULL, *pa, *pe;
160
161         /* There is implicit conversion between S_IRWX modes and ACL_* modes.
162          * Don't bother explicitly converting them unless they actually change.
163          */
164         BUILD_BUG_ON(S_IROTH != ACL_READ);
165         BUILD_BUG_ON(S_IWOTH != ACL_WRITE);
166         BUILD_BUG_ON(S_IXOTH != ACL_EXECUTE);
167
168         for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
169                 switch (le16_to_cpu(pa->e_tag)) {
170                 case ACL_USER_OBJ:
171                         pa->e_perm = cpu_to_le16((mode & S_IRWXU) >> 6);
172                         break;
173                 case ACL_USER:
174                 case ACL_GROUP:
175                         break;
176                 case ACL_GROUP_OBJ:
177                         group_obj = pa;
178                         break;
179                 case ACL_MASK:
180                         mask_obj = pa;
181                         break;
182                 case ACL_OTHER:
183                         pa->e_perm = cpu_to_le16(mode & S_IRWXO);
184                         break;
185                 default:
186                         return -EIO;
187                 }
188         }
189
190         if (mask_obj) {
191                 mask_obj->e_perm = cpu_to_le16((mode & S_IRWXG) >> 3);
192         } else {
193                 if (!group_obj)
194                         return -EIO;
195                 group_obj->e_perm = cpu_to_le16((mode & S_IRWXG) >> 3);
196         }
197
198         return 0;
199 }
200
201 /*
202  * Returns 0 if the acl can be exactly represented in the traditional
203  * file mode permission bits, or else 1. Returns -E... on error.
204  */
205 int
206 lustre_posix_acl_equiv_mode(posix_acl_xattr_entry *entry, mode_t *mode_p,
207                             int count)
208 {
209         posix_acl_xattr_entry *pa, *pe;
210         mode_t mode = 0;
211         int not_equiv = 0;
212
213         for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
214                 __u16 perm = le16_to_cpu(pa->e_perm);
215                 switch (le16_to_cpu(pa->e_tag)) {
216                         case ACL_USER_OBJ:
217                                 mode |= (perm & S_IRWXO) << 6;
218                                 break;
219                         case ACL_GROUP_OBJ:
220                                 mode |= (perm & S_IRWXO) << 3;
221                                 break;
222                         case ACL_OTHER:
223                                 mode |= perm & S_IRWXO;
224                                 break;
225                         case ACL_MASK:
226                                 mode = (mode & ~S_IRWXG) |
227                                         ((perm & S_IRWXO) << 3);
228                                 not_equiv = 1;
229                                 break;
230                         case ACL_USER:
231                         case ACL_GROUP:
232                                 not_equiv = 1;
233                                 break;
234                         default:
235                                 return -EINVAL;
236                 }
237         }
238         if (mode_p)
239                 *mode_p = (*mode_p & ~S_IRWXUGO) | mode;
240         return not_equiv;
241 }
242
243 /*
244  * Modify acl when creating a new object.
245  */
246 int lustre_posix_acl_create_masq(posix_acl_xattr_entry *entry, u32 *pmode,
247                                  int count)
248 {
249         posix_acl_xattr_entry *group_obj = NULL, *mask_obj = NULL, *pa, *pe;
250         posix_acl_xattr_entry ae;
251         u32 mode = *pmode;
252         int not_equiv = 0;
253
254         for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
255                 lustre_posix_acl_le_to_cpu(&ae, pa);
256                 switch (ae.e_tag) {
257                 case ACL_USER_OBJ:
258                         ae.e_perm &= (mode >> 6) | ~(0007);
259                         pa->e_perm = cpu_to_le16(ae.e_perm);
260                         mode &= (ae.e_perm << 6) | ~S_IRWXU;
261                         break;
262                 case ACL_USER:
263                 case ACL_GROUP:
264                         not_equiv = 1;
265                         break;
266                 case ACL_GROUP_OBJ:
267                         group_obj = pa;
268                         break;
269                 case ACL_OTHER:
270                         ae.e_perm &= mode | ~(0007);
271                         pa->e_perm = cpu_to_le16(ae.e_perm);
272                         mode &= ae.e_perm | ~(0007);
273                         break;
274                 case ACL_MASK:
275                         mask_obj = pa;
276                         not_equiv = 1;
277                         break;
278                 default:
279                         return -EIO;
280                 }
281         }
282
283         if (mask_obj) {
284                 ae.e_perm = le16_to_cpu(mask_obj->e_perm) &
285                                         ((mode >> 3) | ~(0007));
286                 mode &= (ae.e_perm << 3) | ~S_IRWXG;
287                 mask_obj->e_perm = cpu_to_le16(ae.e_perm);
288         } else {
289                 if (!group_obj)
290                         return -EIO;
291                 ae.e_perm = le16_to_cpu(group_obj->e_perm) &
292                                         ((mode >> 3) | ~(0007));
293                 mode &= (ae.e_perm << 3) | ~S_IRWXG;
294                 group_obj->e_perm = cpu_to_le16(ae.e_perm);
295         }
296
297         *pmode = (*pmode & ~S_IRWXUGO) | mode;
298         return not_equiv;
299 }
300 #endif