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