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.sun.com/software/products/lustre/docs/GPLv2.pdf
19 *
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21 * CA 95054 USA or visit www.sun.com if you need additional information or
22 * have any questions.
23 *
24 * GPL HEADER END
25 */
26 /*
27 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28 * Use is subject to license terms.
29 *
30 * Copyright (c) 2012, Intel Corporation.
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 #define DEBUG_SUBSYSTEM S_SEC
44 #include "../include/lu_object.h"
45 #include "../include/lustre_acl.h"
46 #include "../include/lustre_eacl.h"
47 #include "../include/obd_support.h"
48
49 #ifdef CONFIG_FS_POSIX_ACL
50
51 #define CFS_ACL_XATTR_VERSION POSIX_ACL_XATTR_VERSION
52
53 enum {
54 ES_UNK = 0, /* unknown stat */
55 ES_UNC = 1, /* ACL entry is not changed */
56 ES_MOD = 2, /* ACL entry is modified */
57 ES_ADD = 3, /* ACL entry is added */
58 ES_DEL = 4 /* ACL entry is deleted */
59 };
60
lustre_ext_acl_le_to_cpu(ext_acl_xattr_entry * d,ext_acl_xattr_entry * s)61 static inline void lustre_ext_acl_le_to_cpu(ext_acl_xattr_entry *d,
62 ext_acl_xattr_entry *s)
63 {
64 d->e_tag = le16_to_cpu(s->e_tag);
65 d->e_perm = le16_to_cpu(s->e_perm);
66 d->e_id = le32_to_cpu(s->e_id);
67 d->e_stat = le32_to_cpu(s->e_stat);
68 }
69
lustre_ext_acl_cpu_to_le(ext_acl_xattr_entry * d,ext_acl_xattr_entry * s)70 static inline void lustre_ext_acl_cpu_to_le(ext_acl_xattr_entry *d,
71 ext_acl_xattr_entry *s)
72 {
73 d->e_tag = cpu_to_le16(s->e_tag);
74 d->e_perm = cpu_to_le16(s->e_perm);
75 d->e_id = cpu_to_le32(s->e_id);
76 d->e_stat = cpu_to_le32(s->e_stat);
77 }
78
lustre_posix_acl_le_to_cpu(posix_acl_xattr_entry * d,posix_acl_xattr_entry * s)79 static inline void lustre_posix_acl_le_to_cpu(posix_acl_xattr_entry *d,
80 posix_acl_xattr_entry *s)
81 {
82 d->e_tag = le16_to_cpu(s->e_tag);
83 d->e_perm = le16_to_cpu(s->e_perm);
84 d->e_id = le32_to_cpu(s->e_id);
85 }
86
lustre_posix_acl_cpu_to_le(posix_acl_xattr_entry * d,posix_acl_xattr_entry * s)87 static inline void lustre_posix_acl_cpu_to_le(posix_acl_xattr_entry *d,
88 posix_acl_xattr_entry *s)
89 {
90 d->e_tag = cpu_to_le16(s->e_tag);
91 d->e_perm = cpu_to_le16(s->e_perm);
92 d->e_id = cpu_to_le32(s->e_id);
93 }
94
95 /* if "new_count == 0", then "new = {a_version, NULL}", NOT NULL. */
lustre_posix_acl_xattr_reduce_space(posix_acl_xattr_header ** header,int old_count,int new_count)96 static int lustre_posix_acl_xattr_reduce_space(posix_acl_xattr_header **header,
97 int old_count, int new_count)
98 {
99 int old_size = CFS_ACL_XATTR_SIZE(old_count, posix_acl_xattr);
100 int new_size = CFS_ACL_XATTR_SIZE(new_count, posix_acl_xattr);
101 posix_acl_xattr_header *new;
102
103 if (unlikely(old_count <= new_count))
104 return old_size;
105
106 new = kmemdup(*header, new_size, GFP_NOFS);
107 if (unlikely(new == NULL))
108 return -ENOMEM;
109
110 kfree(*header);
111 *header = new;
112 return new_size;
113 }
114
115 /* if "new_count == 0", then "new = {0, NULL}", NOT NULL. */
lustre_ext_acl_xattr_reduce_space(ext_acl_xattr_header ** header,int old_count)116 static int lustre_ext_acl_xattr_reduce_space(ext_acl_xattr_header **header,
117 int old_count)
118 {
119 int ext_count = le32_to_cpu((*header)->a_count);
120 int ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr);
121 ext_acl_xattr_header *new;
122
123 if (unlikely(old_count <= ext_count))
124 return 0;
125
126 new = kmemdup(*header, ext_size, GFP_NOFS);
127 if (unlikely(new == NULL))
128 return -ENOMEM;
129
130 kfree(*header);
131 *header = new;
132 return 0;
133 }
134
135 /*
136 * Generate new extended ACL based on the posix ACL.
137 */
138 ext_acl_xattr_header *
lustre_posix_acl_xattr_2ext(posix_acl_xattr_header * header,int size)139 lustre_posix_acl_xattr_2ext(posix_acl_xattr_header *header, int size)
140 {
141 int count, i, esize;
142 ext_acl_xattr_header *new;
143
144 if (unlikely(size < 0))
145 return ERR_PTR(-EINVAL);
146 else if (!size)
147 count = 0;
148 else
149 count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
150 esize = CFS_ACL_XATTR_SIZE(count, ext_acl_xattr);
151 new = kzalloc(esize, GFP_NOFS);
152 if (unlikely(new == NULL))
153 return ERR_PTR(-ENOMEM);
154
155 new->a_count = cpu_to_le32(count);
156 for (i = 0; i < count; i++) {
157 new->a_entries[i].e_tag = header->a_entries[i].e_tag;
158 new->a_entries[i].e_perm = header->a_entries[i].e_perm;
159 new->a_entries[i].e_id = header->a_entries[i].e_id;
160 new->a_entries[i].e_stat = cpu_to_le32(ES_UNK);
161 }
162
163 return new;
164 }
165 EXPORT_SYMBOL(lustre_posix_acl_xattr_2ext);
166
167 /*
168 * Filter out the "nobody" entries in the posix ACL.
169 */
lustre_posix_acl_xattr_filter(posix_acl_xattr_header * header,size_t size,posix_acl_xattr_header ** out)170 int lustre_posix_acl_xattr_filter(posix_acl_xattr_header *header, size_t size,
171 posix_acl_xattr_header **out)
172 {
173 int count, i, j, rc = 0;
174 __u32 id;
175 posix_acl_xattr_header *new;
176
177 if (!size)
178 return 0;
179 if (size < sizeof(*new))
180 return -EINVAL;
181
182 new = kzalloc(size, GFP_NOFS);
183 if (unlikely(new == NULL))
184 return -ENOMEM;
185
186 new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
187 count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
188 for (i = 0, j = 0; i < count; i++) {
189 id = le32_to_cpu(header->a_entries[i].e_id);
190 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
191 case ACL_USER_OBJ:
192 case ACL_GROUP_OBJ:
193 case ACL_MASK:
194 case ACL_OTHER:
195 if (id != ACL_UNDEFINED_ID) {
196 rc = -EIO;
197 goto _out;
198 }
199
200 memcpy(&new->a_entries[j++], &header->a_entries[i],
201 sizeof(posix_acl_xattr_entry));
202 break;
203 case ACL_USER:
204 if (id != NOBODY_UID)
205 memcpy(&new->a_entries[j++],
206 &header->a_entries[i],
207 sizeof(posix_acl_xattr_entry));
208 break;
209 case ACL_GROUP:
210 if (id != NOBODY_GID)
211 memcpy(&new->a_entries[j++],
212 &header->a_entries[i],
213 sizeof(posix_acl_xattr_entry));
214 break;
215 default:
216 rc = -EIO;
217 goto _out;
218 }
219 }
220
221 /* free unused space. */
222 rc = lustre_posix_acl_xattr_reduce_space(&new, count, j);
223 if (rc >= 0) {
224 size = rc;
225 *out = new;
226 rc = 0;
227 }
228
229 _out:
230 if (rc) {
231 kfree(new);
232 size = rc;
233 }
234 return size;
235 }
236 EXPORT_SYMBOL(lustre_posix_acl_xattr_filter);
237
238 /*
239 * Release the posix ACL space.
240 */
lustre_posix_acl_xattr_free(posix_acl_xattr_header * header,int size)241 void lustre_posix_acl_xattr_free(posix_acl_xattr_header *header, int size)
242 {
243 kfree(header);
244 }
245 EXPORT_SYMBOL(lustre_posix_acl_xattr_free);
246
247 /*
248 * Release the extended ACL space.
249 */
lustre_ext_acl_xattr_free(ext_acl_xattr_header * header)250 void lustre_ext_acl_xattr_free(ext_acl_xattr_header *header)
251 {
252 kfree(header);
253 }
254 EXPORT_SYMBOL(lustre_ext_acl_xattr_free);
255
256 static ext_acl_xattr_entry *
lustre_ext_acl_xattr_search(ext_acl_xattr_header * header,posix_acl_xattr_entry * entry,int * pos)257 lustre_ext_acl_xattr_search(ext_acl_xattr_header *header,
258 posix_acl_xattr_entry *entry, int *pos)
259 {
260 int once, start, end, i, j, count = le32_to_cpu(header->a_count);
261
262 once = 0;
263 start = *pos;
264 end = count;
265
266 again:
267 for (i = start; i < end; i++) {
268 if (header->a_entries[i].e_tag == entry->e_tag &&
269 header->a_entries[i].e_id == entry->e_id) {
270 j = i;
271 if (++i >= count)
272 i = 0;
273 *pos = i;
274 return &header->a_entries[j];
275 }
276 }
277
278 if (!once) {
279 once = 1;
280 start = 0;
281 end = *pos;
282 goto again;
283 }
284
285 return NULL;
286 }
287
288 /*
289 * Merge the posix ACL and the extended ACL into new extended ACL.
290 */
291 ext_acl_xattr_header *
lustre_acl_xattr_merge2ext(posix_acl_xattr_header * posix_header,int size,ext_acl_xattr_header * ext_header)292 lustre_acl_xattr_merge2ext(posix_acl_xattr_header *posix_header, int size,
293 ext_acl_xattr_header *ext_header)
294 {
295 int ori_ext_count, posix_count, ext_count, ext_size;
296 int i, j, pos = 0, rc = 0;
297 posix_acl_xattr_entry pae;
298 ext_acl_xattr_header *new;
299 ext_acl_xattr_entry *ee, eae;
300
301 if (unlikely(size < 0))
302 return ERR_PTR(-EINVAL);
303 else if (!size)
304 posix_count = 0;
305 else
306 posix_count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
307 ori_ext_count = le32_to_cpu(ext_header->a_count);
308 ext_count = posix_count + ori_ext_count;
309 ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr);
310
311 new = kzalloc(ext_size, GFP_NOFS);
312 if (unlikely(new == NULL))
313 return ERR_PTR(-ENOMEM);
314
315 for (i = 0, j = 0; i < posix_count; i++) {
316 lustre_posix_acl_le_to_cpu(&pae, &posix_header->a_entries[i]);
317 switch (pae.e_tag) {
318 case ACL_USER_OBJ:
319 case ACL_GROUP_OBJ:
320 case ACL_MASK:
321 case ACL_OTHER:
322 if (pae.e_id != ACL_UNDEFINED_ID) {
323 rc = -EIO;
324 goto out;
325 }
326 case ACL_USER:
327 /* ignore "nobody" entry. */
328 if (pae.e_id == NOBODY_UID)
329 break;
330
331 new->a_entries[j].e_tag =
332 posix_header->a_entries[i].e_tag;
333 new->a_entries[j].e_perm =
334 posix_header->a_entries[i].e_perm;
335 new->a_entries[j].e_id =
336 posix_header->a_entries[i].e_id;
337 ee = lustre_ext_acl_xattr_search(ext_header,
338 &posix_header->a_entries[i], &pos);
339 if (ee) {
340 if (posix_header->a_entries[i].e_perm !=
341 ee->e_perm)
342 /* entry modified. */
343 ee->e_stat =
344 new->a_entries[j++].e_stat =
345 cpu_to_le32(ES_MOD);
346 else
347 /* entry unchanged. */
348 ee->e_stat =
349 new->a_entries[j++].e_stat =
350 cpu_to_le32(ES_UNC);
351 } else {
352 /* new entry. */
353 new->a_entries[j++].e_stat =
354 cpu_to_le32(ES_ADD);
355 }
356 break;
357 case ACL_GROUP:
358 /* ignore "nobody" entry. */
359 if (pae.e_id == NOBODY_GID)
360 break;
361 new->a_entries[j].e_tag =
362 posix_header->a_entries[i].e_tag;
363 new->a_entries[j].e_perm =
364 posix_header->a_entries[i].e_perm;
365 new->a_entries[j].e_id =
366 posix_header->a_entries[i].e_id;
367 ee = lustre_ext_acl_xattr_search(ext_header,
368 &posix_header->a_entries[i], &pos);
369 if (ee) {
370 if (posix_header->a_entries[i].e_perm !=
371 ee->e_perm)
372 /* entry modified. */
373 ee->e_stat =
374 new->a_entries[j++].e_stat =
375 cpu_to_le32(ES_MOD);
376 else
377 /* entry unchanged. */
378 ee->e_stat =
379 new->a_entries[j++].e_stat =
380 cpu_to_le32(ES_UNC);
381 } else {
382 /* new entry. */
383 new->a_entries[j++].e_stat =
384 cpu_to_le32(ES_ADD);
385 }
386 break;
387 default:
388 rc = -EIO;
389 goto out;
390 }
391 }
392
393 /* process deleted entries. */
394 for (i = 0; i < ori_ext_count; i++) {
395 lustre_ext_acl_le_to_cpu(&eae, &ext_header->a_entries[i]);
396 if (eae.e_stat == ES_UNK) {
397 /* ignore "nobody" entry. */
398 if ((eae.e_tag == ACL_USER && eae.e_id == NOBODY_UID) ||
399 (eae.e_tag == ACL_GROUP && eae.e_id == NOBODY_GID))
400 continue;
401
402 new->a_entries[j].e_tag =
403 ext_header->a_entries[i].e_tag;
404 new->a_entries[j].e_perm =
405 ext_header->a_entries[i].e_perm;
406 new->a_entries[j].e_id = ext_header->a_entries[i].e_id;
407 new->a_entries[j++].e_stat = cpu_to_le32(ES_DEL);
408 }
409 }
410
411 new->a_count = cpu_to_le32(j);
412 /* free unused space. */
413 rc = lustre_ext_acl_xattr_reduce_space(&new, ext_count);
414
415 out:
416 if (rc) {
417 kfree(new);
418 new = ERR_PTR(rc);
419 }
420 return new;
421 }
422 EXPORT_SYMBOL(lustre_acl_xattr_merge2ext);
423
424 #endif
425