Whamcloud - gitweb
2ff73968b4d92fe8b5a63fb9c9da605932693a2b
[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 #include <lustre_idmap.h>
45 #include <md_object.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 EXPORT_SYMBOL(lustre_posix_acl_permission);
153
154 /*
155  * Modify the ACL for the chmod.
156  */
157 int lustre_posix_acl_chmod_masq(posix_acl_xattr_entry *entry, u32 mode,
158                                 int count)
159 {
160         posix_acl_xattr_entry *group_obj = NULL, *mask_obj = NULL, *pa, *pe;
161
162         /* There is implicit conversion between S_IRWX modes and ACL_* modes.
163          * Don't bother explicitly converting them unless they actually change.
164          */
165         BUILD_BUG_ON(S_IROTH != ACL_READ);
166         BUILD_BUG_ON(S_IWOTH != ACL_WRITE);
167         BUILD_BUG_ON(S_IXOTH != ACL_EXECUTE);
168
169         for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
170                 switch (le16_to_cpu(pa->e_tag)) {
171                 case ACL_USER_OBJ:
172                         pa->e_perm = cpu_to_le16((mode & S_IRWXU) >> 6);
173                         break;
174                 case ACL_USER:
175                 case ACL_GROUP:
176                         break;
177                 case ACL_GROUP_OBJ:
178                         group_obj = pa;
179                         break;
180                 case ACL_MASK:
181                         mask_obj = pa;
182                         break;
183                 case ACL_OTHER:
184                         pa->e_perm = cpu_to_le16(mode & S_IRWXO);
185                         break;
186                 default:
187                         return -EIO;
188                 }
189         }
190
191         if (mask_obj) {
192                 mask_obj->e_perm = cpu_to_le16((mode & S_IRWXG) >> 3);
193         } else {
194                 if (!group_obj)
195                         return -EIO;
196                 group_obj->e_perm = cpu_to_le16((mode & S_IRWXG) >> 3);
197         }
198
199         return 0;
200 }
201 EXPORT_SYMBOL(lustre_posix_acl_chmod_masq);
202
203 /*
204  * Returns 0 if the acl can be exactly represented in the traditional
205  * file mode permission bits, or else 1. Returns -E... on error.
206  */
207 int
208 lustre_posix_acl_equiv_mode(posix_acl_xattr_entry *entry, mode_t *mode_p,
209                             int count)
210 {
211         posix_acl_xattr_entry *pa, *pe;
212         mode_t mode = 0;
213         int not_equiv = 0;
214
215         for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
216                 __u16 perm = le16_to_cpu(pa->e_perm);
217                 switch (le16_to_cpu(pa->e_tag)) {
218                         case ACL_USER_OBJ:
219                                 mode |= (perm & S_IRWXO) << 6;
220                                 break;
221                         case ACL_GROUP_OBJ:
222                                 mode |= (perm & S_IRWXO) << 3;
223                                 break;
224                         case ACL_OTHER:
225                                 mode |= perm & S_IRWXO;
226                                 break;
227                         case ACL_MASK:
228                                 mode = (mode & ~S_IRWXG) |
229                                         ((perm & S_IRWXO) << 3);
230                                 not_equiv = 1;
231                                 break;
232                         case ACL_USER:
233                         case ACL_GROUP:
234                                 not_equiv = 1;
235                                 break;
236                         default:
237                                 return -EINVAL;
238                 }
239         }
240         if (mode_p)
241                 *mode_p = (*mode_p & ~S_IRWXUGO) | mode;
242         return not_equiv;
243 }
244 EXPORT_SYMBOL(lustre_posix_acl_equiv_mode);
245
246 /*
247  * Modify acl when creating a new object.
248  */
249 int lustre_posix_acl_create_masq(posix_acl_xattr_entry *entry, u32 *pmode,
250                                  int count)
251 {
252         posix_acl_xattr_entry *group_obj = NULL, *mask_obj = NULL, *pa, *pe;
253         posix_acl_xattr_entry ae;
254         u32 mode = *pmode;
255         int not_equiv = 0;
256
257         for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
258                 lustre_posix_acl_le_to_cpu(&ae, pa);
259                 switch (ae.e_tag) {
260                 case ACL_USER_OBJ:
261                         ae.e_perm &= (mode >> 6) | ~(0007);
262                         pa->e_perm = cpu_to_le16(ae.e_perm);
263                         mode &= (ae.e_perm << 6) | ~S_IRWXU;
264                         break;
265                 case ACL_USER:
266                 case ACL_GROUP:
267                         not_equiv = 1;
268                         break;
269                 case ACL_GROUP_OBJ:
270                         group_obj = pa;
271                         break;
272                 case ACL_OTHER:
273                         ae.e_perm &= mode | ~(0007);
274                         pa->e_perm = cpu_to_le16(ae.e_perm);
275                         mode &= ae.e_perm | ~(0007);
276                         break;
277                 case ACL_MASK:
278                         mask_obj = pa;
279                         not_equiv = 1;
280                         break;
281                 default:
282                         return -EIO;
283                 }
284         }
285
286         if (mask_obj) {
287                 ae.e_perm = le16_to_cpu(mask_obj->e_perm) &
288                                         ((mode >> 3) | ~(0007));
289                 mode &= (ae.e_perm << 3) | ~S_IRWXG;
290                 mask_obj->e_perm = cpu_to_le16(ae.e_perm);
291         } else {
292                 if (!group_obj)
293                         return -EIO;
294                 ae.e_perm = le16_to_cpu(group_obj->e_perm) &
295                                         ((mode >> 3) | ~(0007));
296                 mode &= (ae.e_perm << 3) | ~S_IRWXG;
297                 group_obj->e_perm = cpu_to_le16(ae.e_perm);
298         }
299
300         *pmode = (*pmode & ~S_IRWXUGO) | mode;
301         return not_equiv;
302 }
303 EXPORT_SYMBOL(lustre_posix_acl_create_masq);
304 #endif