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