FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_acl.c
1 /*-
2 * Copyright (c) 1999-2003 Robert N. M. Watson
3 * All rights reserved.
4 *
5 * This software was developed by Robert Watson for the TrustedBSD Project.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28 /*
29 * Developed by the TrustedBSD Project.
30 * Support for POSIX.1e access control lists.
31 */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD: releng/5.3/sys/kern/kern_acl.c 136588 2004-10-16 08:43:07Z cvs2svn $");
35
36 #include "opt_mac.h"
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/sysproto.h>
41 #include <sys/kernel.h>
42 #include <sys/mac.h>
43 #include <sys/malloc.h>
44 #include <sys/vnode.h>
45 #include <sys/lock.h>
46 #include <sys/mutex.h>
47 #include <sys/namei.h>
48 #include <sys/file.h>
49 #include <sys/filedesc.h>
50 #include <sys/proc.h>
51 #include <sys/sysent.h>
52 #include <sys/errno.h>
53 #include <sys/stat.h>
54 #include <sys/acl.h>
55
56 MALLOC_DEFINE(M_ACL, "acl", "access control list");
57
58 static int vacl_set_acl(struct thread *td, struct vnode *vp,
59 acl_type_t type, struct acl *aclp);
60 static int vacl_get_acl(struct thread *td, struct vnode *vp,
61 acl_type_t type, struct acl *aclp);
62 static int vacl_aclcheck(struct thread *td, struct vnode *vp,
63 acl_type_t type, struct acl *aclp);
64
65 /*
66 * Implement a version of vaccess() that understands POSIX.1e ACL semantics.
67 * Return 0 on success, else an errno value. Should be merged into
68 * vaccess() eventually.
69 */
70 int
71 vaccess_acl_posix1e(enum vtype type, uid_t file_uid, gid_t file_gid,
72 struct acl *acl, mode_t acc_mode, struct ucred *cred, int *privused)
73 {
74 struct acl_entry *acl_other, *acl_mask;
75 mode_t dac_granted;
76 mode_t cap_granted;
77 mode_t acl_mask_granted;
78 int group_matched, i;
79
80 /*
81 * Look for a normal, non-privileged way to access the file/directory
82 * as requested. If it exists, go with that. Otherwise, attempt
83 * to use privileges granted via cap_granted. In some cases,
84 * which privileges to use may be ambiguous due to "best match",
85 * in which case fall back on first match for the time being.
86 */
87 if (privused != NULL)
88 *privused = 0;
89
90 /*
91 * Determine privileges now, but don't apply until we've found
92 * a DAC entry that matches but has failed to allow access.
93 */
94 #ifndef CAPABILITIES
95 if (suser_cred(cred, SUSER_ALLOWJAIL) == 0)
96 cap_granted = VALLPERM;
97 else
98 cap_granted = 0;
99 #else
100 cap_granted = 0;
101
102 if (type == VDIR) {
103 if ((acc_mode & VEXEC) && !cap_check(cred, NULL,
104 CAP_DAC_READ_SEARCH, SUSER_ALLOWJAIL))
105 cap_granted |= VEXEC;
106 } else {
107 if ((acc_mode & VEXEC) && !cap_check(cred, NULL,
108 CAP_DAC_EXECUTE, SUSER_ALLOWJAIL))
109 cap_granted |= VEXEC;
110 }
111
112 if ((acc_mode & VREAD) && !cap_check(cred, NULL, CAP_DAC_READ_SEARCH,
113 SUSER_ALLOWJAIL))
114 cap_granted |= VREAD;
115
116 if (((acc_mode & VWRITE) || (acc_mode & VAPPEND)) &&
117 !cap_check(cred, NULL, CAP_DAC_WRITE, SUSER_ALLOWJAIL))
118 cap_granted |= (VWRITE | VAPPEND);
119
120 if ((acc_mode & VADMIN) && !cap_check(cred, NULL, CAP_FOWNER,
121 SUSER_ALLOWJAIL))
122 cap_granted |= VADMIN;
123 #endif /* CAPABILITIES */
124
125 /*
126 * The owner matches if the effective uid associated with the
127 * credential matches that of the ACL_USER_OBJ entry. While we're
128 * doing the first scan, also cache the location of the ACL_MASK
129 * and ACL_OTHER entries, preventing some future iterations.
130 */
131 acl_mask = acl_other = NULL;
132 for (i = 0; i < acl->acl_cnt; i++) {
133 switch (acl->acl_entry[i].ae_tag) {
134 case ACL_USER_OBJ:
135 if (file_uid != cred->cr_uid)
136 break;
137 dac_granted = 0;
138 dac_granted |= VADMIN;
139 if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
140 dac_granted |= VEXEC;
141 if (acl->acl_entry[i].ae_perm & ACL_READ)
142 dac_granted |= VREAD;
143 if (acl->acl_entry[i].ae_perm & ACL_WRITE)
144 dac_granted |= (VWRITE | VAPPEND);
145 if ((acc_mode & dac_granted) == acc_mode)
146 return (0);
147 if ((acc_mode & (dac_granted | cap_granted)) ==
148 acc_mode) {
149 if (privused != NULL)
150 *privused = 1;
151 return (0);
152 }
153 goto error;
154
155 case ACL_MASK:
156 acl_mask = &acl->acl_entry[i];
157 break;
158
159 case ACL_OTHER:
160 acl_other = &acl->acl_entry[i];
161 break;
162
163 default:
164 break;
165 }
166 }
167
168 /*
169 * An ACL_OTHER entry should always exist in a valid access
170 * ACL. If it doesn't, then generate a serious failure. For now,
171 * this means a debugging message and EPERM, but in the future
172 * should probably be a panic.
173 */
174 if (acl_other == NULL) {
175 /*
176 * XXX This should never happen
177 */
178 printf("vaccess_acl_posix1e: ACL_OTHER missing\n");
179 return (EPERM);
180 }
181
182 /*
183 * Checks against ACL_USER, ACL_GROUP_OBJ, and ACL_GROUP fields
184 * are masked by an ACL_MASK entry, if any. As such, first identify
185 * the ACL_MASK field, then iterate through identifying potential
186 * user matches, then group matches. If there is no ACL_MASK,
187 * assume that the mask allows all requests to succeed.
188 */
189 if (acl_mask != NULL) {
190 acl_mask_granted = 0;
191 if (acl_mask->ae_perm & ACL_EXECUTE)
192 acl_mask_granted |= VEXEC;
193 if (acl_mask->ae_perm & ACL_READ)
194 acl_mask_granted |= VREAD;
195 if (acl_mask->ae_perm & ACL_WRITE)
196 acl_mask_granted |= (VWRITE | VAPPEND);
197 } else
198 acl_mask_granted = VEXEC | VREAD | VWRITE | VAPPEND;
199
200 /*
201 * Iterate through user ACL entries. Do checks twice, first
202 * without privilege, and then if a match is found but failed,
203 * a second time with privilege.
204 */
205
206 /*
207 * Check ACL_USER ACL entries.
208 */
209 for (i = 0; i < acl->acl_cnt; i++) {
210 switch (acl->acl_entry[i].ae_tag) {
211 case ACL_USER:
212 if (acl->acl_entry[i].ae_id != cred->cr_uid)
213 break;
214 dac_granted = 0;
215 if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
216 dac_granted |= VEXEC;
217 if (acl->acl_entry[i].ae_perm & ACL_READ)
218 dac_granted |= VREAD;
219 if (acl->acl_entry[i].ae_perm & ACL_WRITE)
220 dac_granted |= (VWRITE | VAPPEND);
221 dac_granted &= acl_mask_granted;
222 if ((acc_mode & dac_granted) == acc_mode)
223 return (0);
224 if ((acc_mode & (dac_granted | cap_granted)) !=
225 acc_mode)
226 goto error;
227
228 if (privused != NULL)
229 *privused = 1;
230 return (0);
231 }
232 }
233
234 /*
235 * Group match is best-match, not first-match, so find a
236 * "best" match. Iterate across, testing each potential group
237 * match. Make sure we keep track of whether we found a match
238 * or not, so that we know if we should try again with any
239 * available privilege, or if we should move on to ACL_OTHER.
240 */
241 group_matched = 0;
242 for (i = 0; i < acl->acl_cnt; i++) {
243 switch (acl->acl_entry[i].ae_tag) {
244 case ACL_GROUP_OBJ:
245 if (!groupmember(file_gid, cred))
246 break;
247 dac_granted = 0;
248 if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
249 dac_granted |= VEXEC;
250 if (acl->acl_entry[i].ae_perm & ACL_READ)
251 dac_granted |= VREAD;
252 if (acl->acl_entry[i].ae_perm & ACL_WRITE)
253 dac_granted |= (VWRITE | VAPPEND);
254 dac_granted &= acl_mask_granted;
255
256 if ((acc_mode & dac_granted) == acc_mode)
257 return (0);
258
259 group_matched = 1;
260 break;
261
262 case ACL_GROUP:
263 if (!groupmember(acl->acl_entry[i].ae_id, cred))
264 break;
265 dac_granted = 0;
266 if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
267 dac_granted |= VEXEC;
268 if (acl->acl_entry[i].ae_perm & ACL_READ)
269 dac_granted |= VREAD;
270 if (acl->acl_entry[i].ae_perm & ACL_WRITE)
271 dac_granted |= (VWRITE | VAPPEND);
272 dac_granted &= acl_mask_granted;
273
274 if ((acc_mode & dac_granted) == acc_mode)
275 return (0);
276
277 group_matched = 1;
278 break;
279
280 default:
281 break;
282 }
283 }
284
285 if (group_matched == 1) {
286 /*
287 * There was a match, but it did not grant rights via
288 * pure DAC. Try again, this time with privilege.
289 */
290 for (i = 0; i < acl->acl_cnt; i++) {
291 switch (acl->acl_entry[i].ae_tag) {
292 case ACL_GROUP_OBJ:
293 if (!groupmember(file_gid, cred))
294 break;
295 dac_granted = 0;
296 if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
297 dac_granted |= VEXEC;
298 if (acl->acl_entry[i].ae_perm & ACL_READ)
299 dac_granted |= VREAD;
300 if (acl->acl_entry[i].ae_perm & ACL_WRITE)
301 dac_granted |= (VWRITE | VAPPEND);
302 dac_granted &= acl_mask_granted;
303
304 if ((acc_mode & (dac_granted | cap_granted)) !=
305 acc_mode)
306 break;
307
308 if (privused != NULL)
309 *privused = 1;
310 return (0);
311
312 case ACL_GROUP:
313 if (!groupmember(acl->acl_entry[i].ae_id,
314 cred))
315 break;
316 dac_granted = 0;
317 if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
318 dac_granted |= VEXEC;
319 if (acl->acl_entry[i].ae_perm & ACL_READ)
320 dac_granted |= VREAD;
321 if (acl->acl_entry[i].ae_perm & ACL_WRITE)
322 dac_granted |= (VWRITE | VAPPEND);
323 dac_granted &= acl_mask_granted;
324
325 if ((acc_mode & (dac_granted | cap_granted)) !=
326 acc_mode)
327 break;
328
329 if (privused != NULL)
330 *privused = 1;
331 return (0);
332
333 default:
334 break;
335 }
336 }
337 /*
338 * Even with privilege, group membership was not sufficient.
339 * Return failure.
340 */
341 goto error;
342 }
343
344 /*
345 * Fall back on ACL_OTHER. ACL_MASK is not applied to ACL_OTHER.
346 */
347 dac_granted = 0;
348 if (acl_other->ae_perm & ACL_EXECUTE)
349 dac_granted |= VEXEC;
350 if (acl_other->ae_perm & ACL_READ)
351 dac_granted |= VREAD;
352 if (acl_other->ae_perm & ACL_WRITE)
353 dac_granted |= (VWRITE | VAPPEND);
354
355 if ((acc_mode & dac_granted) == acc_mode)
356 return (0);
357 if ((acc_mode & (dac_granted | cap_granted)) == acc_mode) {
358 if (privused != NULL)
359 *privused = 1;
360 return (0);
361 }
362
363 error:
364 return ((acc_mode & VADMIN) ? EPERM : EACCES);
365 }
366
367 /*
368 * For the purposes of filesystems maintaining the _OBJ entries in an
369 * inode with a mode_t field, this routine converts a mode_t entry
370 * to an acl_perm_t.
371 */
372 acl_perm_t
373 acl_posix1e_mode_to_perm(acl_tag_t tag, mode_t mode)
374 {
375 acl_perm_t perm = 0;
376
377 switch(tag) {
378 case ACL_USER_OBJ:
379 if (mode & S_IXUSR)
380 perm |= ACL_EXECUTE;
381 if (mode & S_IRUSR)
382 perm |= ACL_READ;
383 if (mode & S_IWUSR)
384 perm |= ACL_WRITE;
385 return (perm);
386
387 case ACL_GROUP_OBJ:
388 if (mode & S_IXGRP)
389 perm |= ACL_EXECUTE;
390 if (mode & S_IRGRP)
391 perm |= ACL_READ;
392 if (mode & S_IWGRP)
393 perm |= ACL_WRITE;
394 return (perm);
395
396 case ACL_OTHER:
397 if (mode & S_IXOTH)
398 perm |= ACL_EXECUTE;
399 if (mode & S_IROTH)
400 perm |= ACL_READ;
401 if (mode & S_IWOTH)
402 perm |= ACL_WRITE;
403 return (perm);
404
405 default:
406 printf("acl_posix1e_mode_to_perm: invalid tag (%d)\n", tag);
407 return (0);
408 }
409 }
410
411 /*
412 * Given inode information (uid, gid, mode), return an acl entry of the
413 * appropriate type.
414 */
415 struct acl_entry
416 acl_posix1e_mode_to_entry(acl_tag_t tag, uid_t uid, gid_t gid, mode_t mode)
417 {
418 struct acl_entry acl_entry;
419
420 acl_entry.ae_tag = tag;
421 acl_entry.ae_perm = acl_posix1e_mode_to_perm(tag, mode);
422 switch(tag) {
423 case ACL_USER_OBJ:
424 acl_entry.ae_id = uid;
425 break;
426
427 case ACL_GROUP_OBJ:
428 acl_entry.ae_id = gid;
429 break;
430
431 case ACL_OTHER:
432 acl_entry.ae_id = ACL_UNDEFINED_ID;
433 break;
434
435 default:
436 acl_entry.ae_id = ACL_UNDEFINED_ID;
437 printf("acl_posix1e_mode_to_entry: invalid tag (%d)\n", tag);
438 }
439
440 return (acl_entry);
441 }
442
443 /*
444 * Utility function to generate a file mode given appropriate ACL entries.
445 */
446 mode_t
447 acl_posix1e_perms_to_mode(struct acl_entry *acl_user_obj_entry,
448 struct acl_entry *acl_group_obj_entry, struct acl_entry *acl_other_entry)
449 {
450 mode_t mode;
451
452 mode = 0;
453 if (acl_user_obj_entry->ae_perm & ACL_EXECUTE)
454 mode |= S_IXUSR;
455 if (acl_user_obj_entry->ae_perm & ACL_READ)
456 mode |= S_IRUSR;
457 if (acl_user_obj_entry->ae_perm & ACL_WRITE)
458 mode |= S_IWUSR;
459 if (acl_group_obj_entry->ae_perm & ACL_EXECUTE)
460 mode |= S_IXGRP;
461 if (acl_group_obj_entry->ae_perm & ACL_READ)
462 mode |= S_IRGRP;
463 if (acl_group_obj_entry->ae_perm & ACL_WRITE)
464 mode |= S_IWGRP;
465 if (acl_other_entry->ae_perm & ACL_EXECUTE)
466 mode |= S_IXOTH;
467 if (acl_other_entry->ae_perm & ACL_READ)
468 mode |= S_IROTH;
469 if (acl_other_entry->ae_perm & ACL_WRITE)
470 mode |= S_IWOTH;
471
472 return (mode);
473 }
474
475 /*
476 * Utility function to generate a file mode given a complete POSIX.1e
477 * access ACL. Note that if the ACL is improperly formed, this may
478 * result in a panic.
479 */
480 mode_t
481 acl_posix1e_acl_to_mode(struct acl *acl)
482 {
483 struct acl_entry *acl_mask, *acl_user_obj, *acl_group_obj, *acl_other;
484 int i;
485
486 /*
487 * Find the ACL entries relevant to a POSIX permission mode.
488 */
489 acl_user_obj = acl_group_obj = acl_other = acl_mask = NULL;
490 for (i = 0; i < acl->acl_cnt; i++) {
491 switch (acl->acl_entry[i].ae_tag) {
492 case ACL_USER_OBJ:
493 acl_user_obj = &acl->acl_entry[i];
494 break;
495
496 case ACL_GROUP_OBJ:
497 acl_group_obj = &acl->acl_entry[i];
498 break;
499
500 case ACL_OTHER:
501 acl_other = &acl->acl_entry[i];
502 break;
503
504 case ACL_MASK:
505 acl_mask = &acl->acl_entry[i];
506 break;
507
508 case ACL_USER:
509 case ACL_GROUP:
510 break;
511
512 default:
513 panic("acl_posix1e_acl_to_mode: bad ae_tag");
514 }
515 }
516
517 if (acl_user_obj == NULL || acl_group_obj == NULL || acl_other == NULL)
518 panic("acl_posix1e_acl_to_mode: missing base ae_tags");
519
520 /*
521 * POSIX.1e specifies that if there is an ACL_MASK entry, we replace
522 * the mode "group" bits with its permissions. If there isn't, we
523 * use the ACL_GROUP_OBJ permissions.
524 */
525 if (acl_mask != NULL)
526 return (acl_posix1e_perms_to_mode(acl_user_obj, acl_mask,
527 acl_other));
528 else
529 return (acl_posix1e_perms_to_mode(acl_user_obj, acl_group_obj,
530 acl_other));
531 }
532
533 /*
534 * Perform a syntactic check of the ACL, sufficient to allow an
535 * implementing filesystem to determine if it should accept this and
536 * rely on the POSIX.1e ACL properties.
537 */
538 int
539 acl_posix1e_check(struct acl *acl)
540 {
541 int num_acl_user_obj, num_acl_user, num_acl_group_obj, num_acl_group;
542 int num_acl_mask, num_acl_other, i;
543
544 /*
545 * Verify that the number of entries does not exceed the maximum
546 * defined for acl_t.
547 * Verify that the correct number of various sorts of ae_tags are
548 * present:
549 * Exactly one ACL_USER_OBJ
550 * Exactly one ACL_GROUP_OBJ
551 * Exactly one ACL_OTHER
552 * If any ACL_USER or ACL_GROUP entries appear, then exactly one
553 * ACL_MASK entry must also appear.
554 * Verify that all ae_perm entries are in ACL_PERM_BITS.
555 * Verify all ae_tag entries are understood by this implementation.
556 * Note: Does not check for uniqueness of qualifier (ae_id) field.
557 */
558 num_acl_user_obj = num_acl_user = num_acl_group_obj = num_acl_group =
559 num_acl_mask = num_acl_other = 0;
560 if (acl->acl_cnt > ACL_MAX_ENTRIES || acl->acl_cnt < 0)
561 return (EINVAL);
562 for (i = 0; i < acl->acl_cnt; i++) {
563 /*
564 * Check for a valid tag.
565 */
566 switch(acl->acl_entry[i].ae_tag) {
567 case ACL_USER_OBJ:
568 acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
569 if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
570 return (EINVAL);
571 num_acl_user_obj++;
572 break;
573 case ACL_GROUP_OBJ:
574 acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
575 if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
576 return (EINVAL);
577 num_acl_group_obj++;
578 break;
579 case ACL_USER:
580 if (acl->acl_entry[i].ae_id == ACL_UNDEFINED_ID)
581 return (EINVAL);
582 num_acl_user++;
583 break;
584 case ACL_GROUP:
585 if (acl->acl_entry[i].ae_id == ACL_UNDEFINED_ID)
586 return (EINVAL);
587 num_acl_group++;
588 break;
589 case ACL_OTHER:
590 acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
591 if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
592 return (EINVAL);
593 num_acl_other++;
594 break;
595 case ACL_MASK:
596 acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
597 if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
598 return (EINVAL);
599 num_acl_mask++;
600 break;
601 default:
602 return (EINVAL);
603 }
604 /*
605 * Check for valid perm entries.
606 */
607 if ((acl->acl_entry[i].ae_perm | ACL_PERM_BITS) !=
608 ACL_PERM_BITS)
609 return (EINVAL);
610 }
611 if ((num_acl_user_obj != 1) || (num_acl_group_obj != 1) ||
612 (num_acl_other != 1) || (num_acl_mask != 0 && num_acl_mask != 1))
613 return (EINVAL);
614 if (((num_acl_group != 0) || (num_acl_user != 0)) &&
615 (num_acl_mask != 1))
616 return (EINVAL);
617 return (0);
618 }
619
620 /*
621 * Given a requested mode for a new object, and a default ACL, combine
622 * the two to produce a new mode. Be careful not to clear any bits that
623 * aren't intended to be affected by the POSIX.1e ACL. Eventually,
624 * this might also take the cmask as an argument, if we push that down
625 * into per-filesystem-code.
626 */
627 mode_t
628 acl_posix1e_newfilemode(mode_t cmode, struct acl *dacl)
629 {
630 mode_t mode;
631
632 mode = cmode;
633 /*
634 * The current composition policy is that a permission bit must
635 * be set in *both* the ACL and the requested creation mode for
636 * it to appear in the resulting mode/ACL. First clear any
637 * possibly effected bits, then reconstruct.
638 */
639 mode &= ACL_PRESERVE_MASK;
640 mode |= (ACL_OVERRIDE_MASK & cmode & acl_posix1e_acl_to_mode(dacl));
641
642 return (mode);
643 }
644
645 /*
646 * These calls wrap the real vnode operations, and are called by the
647 * syscall code once the syscall has converted the path or file
648 * descriptor to a vnode (unlocked). The aclp pointer is assumed
649 * still to point to userland, so this should not be consumed within
650 * the kernel except by syscall code. Other code should directly
651 * invoke VOP_{SET,GET}ACL.
652 */
653
654 /*
655 * Given a vnode, set its ACL.
656 */
657 static int
658 vacl_set_acl(struct thread *td, struct vnode *vp, acl_type_t type,
659 struct acl *aclp)
660 {
661 struct acl inkernacl;
662 struct mount *mp;
663 int error;
664
665 error = copyin(aclp, &inkernacl, sizeof(struct acl));
666 if (error)
667 return(error);
668 error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
669 if (error != 0)
670 return (error);
671 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
672 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
673 #ifdef MAC
674 error = mac_check_vnode_setacl(td->td_ucred, vp, type, &inkernacl);
675 if (error != 0)
676 goto out;
677 #endif
678 error = VOP_SETACL(vp, type, &inkernacl, td->td_ucred, td);
679 #ifdef MAC
680 out:
681 #endif
682 VOP_UNLOCK(vp, 0, td);
683 vn_finished_write(mp);
684 return(error);
685 }
686
687 /*
688 * Given a vnode, get its ACL.
689 */
690 static int
691 vacl_get_acl(struct thread *td, struct vnode *vp, acl_type_t type,
692 struct acl *aclp)
693 {
694 struct acl inkernelacl;
695 int error;
696
697 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
698 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
699 #ifdef MAC
700 error = mac_check_vnode_getacl(td->td_ucred, vp, type);
701 if (error != 0)
702 goto out;
703 #endif
704 error = VOP_GETACL(vp, type, &inkernelacl, td->td_ucred, td);
705 #ifdef MAC
706 out:
707 #endif
708 VOP_UNLOCK(vp, 0, td);
709 if (error == 0)
710 error = copyout(&inkernelacl, aclp, sizeof(struct acl));
711 return (error);
712 }
713
714 /*
715 * Given a vnode, delete its ACL.
716 */
717 static int
718 vacl_delete(struct thread *td, struct vnode *vp, acl_type_t type)
719 {
720 struct mount *mp;
721 int error;
722
723 error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
724 if (error)
725 return (error);
726 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
727 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
728 #ifdef MAC
729 error = mac_check_vnode_deleteacl(td->td_ucred, vp, type);
730 if (error)
731 goto out;
732 #endif
733 error = VOP_SETACL(vp, type, 0, td->td_ucred, td);
734 #ifdef MAC
735 out:
736 #endif
737 VOP_UNLOCK(vp, 0, td);
738 vn_finished_write(mp);
739 return (error);
740 }
741
742 /*
743 * Given a vnode, check whether an ACL is appropriate for it
744 */
745 static int
746 vacl_aclcheck(struct thread *td, struct vnode *vp, acl_type_t type,
747 struct acl *aclp)
748 {
749 struct acl inkernelacl;
750 int error;
751
752 error = copyin(aclp, &inkernelacl, sizeof(struct acl));
753 if (error)
754 return(error);
755 error = VOP_ACLCHECK(vp, type, &inkernelacl, td->td_ucred, td);
756 return (error);
757 }
758
759 /*
760 * syscalls -- convert the path/fd to a vnode, and call vacl_whatever.
761 * Don't need to lock, as the vacl_ code will get/release any locks
762 * required.
763 */
764
765 /*
766 * Given a file path, get an ACL for it
767 *
768 * MPSAFE
769 */
770 int
771 __acl_get_file(struct thread *td, struct __acl_get_file_args *uap)
772 {
773 struct nameidata nd;
774 int error;
775
776 mtx_lock(&Giant);
777 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
778 error = namei(&nd);
779 if (error == 0) {
780 error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp);
781 NDFREE(&nd, 0);
782 }
783 mtx_unlock(&Giant);
784 return (error);
785 }
786
787 /*
788 * Given a file path, get an ACL for it; don't follow links.
789 *
790 * MPSAFE
791 */
792 int
793 __acl_get_link(struct thread *td, struct __acl_get_link_args *uap)
794 {
795 struct nameidata nd;
796 int error;
797
798 mtx_lock(&Giant);
799 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td);
800 error = namei(&nd);
801 if (error == 0) {
802 error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp);
803 NDFREE(&nd, 0);
804 }
805 mtx_unlock(&Giant);
806 return (error);
807 }
808
809 /*
810 * Given a file path, set an ACL for it
811 *
812 * MPSAFE
813 */
814 int
815 __acl_set_file(struct thread *td, struct __acl_set_file_args *uap)
816 {
817 struct nameidata nd;
818 int error;
819
820 mtx_lock(&Giant);
821 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
822 error = namei(&nd);
823 if (error == 0) {
824 error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp);
825 NDFREE(&nd, 0);
826 }
827 mtx_unlock(&Giant);
828 return (error);
829 }
830
831 /*
832 * Given a file path, set an ACL for it; don't follow links.
833 *
834 * MPSAFE
835 */
836 int
837 __acl_set_link(struct thread *td, struct __acl_set_link_args *uap)
838 {
839 struct nameidata nd;
840 int error;
841
842 mtx_lock(&Giant);
843 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td);
844 error = namei(&nd);
845 if (error == 0) {
846 error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp);
847 NDFREE(&nd, 0);
848 }
849 mtx_unlock(&Giant);
850 return (error);
851 }
852
853 /*
854 * Given a file descriptor, get an ACL for it
855 *
856 * MPSAFE
857 */
858 int
859 __acl_get_fd(struct thread *td, struct __acl_get_fd_args *uap)
860 {
861 struct file *fp;
862 int error;
863
864 mtx_lock(&Giant);
865 error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
866 if (error == 0) {
867 error = vacl_get_acl(td, fp->f_vnode, uap->type, uap->aclp);
868 fdrop(fp, td);
869 }
870 mtx_unlock(&Giant);
871 return (error);
872 }
873
874 /*
875 * Given a file descriptor, set an ACL for it
876 *
877 * MPSAFE
878 */
879 int
880 __acl_set_fd(struct thread *td, struct __acl_set_fd_args *uap)
881 {
882 struct file *fp;
883 int error;
884
885 mtx_lock(&Giant);
886 error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
887 if (error == 0) {
888 error = vacl_set_acl(td, fp->f_vnode, uap->type, uap->aclp);
889 fdrop(fp, td);
890 }
891 mtx_unlock(&Giant);
892 return (error);
893 }
894
895 /*
896 * Given a file path, delete an ACL from it.
897 *
898 * MPSAFE
899 */
900 int
901 __acl_delete_file(struct thread *td, struct __acl_delete_file_args *uap)
902 {
903 struct nameidata nd;
904 int error;
905
906 mtx_lock(&Giant);
907 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
908 error = namei(&nd);
909 if (error == 0) {
910 error = vacl_delete(td, nd.ni_vp, uap->type);
911 NDFREE(&nd, 0);
912 }
913 mtx_unlock(&Giant);
914 return (error);
915 }
916
917 /*
918 * Given a file path, delete an ACL from it; don't follow links.
919 *
920 * MPSAFE
921 */
922 int
923 __acl_delete_link(struct thread *td, struct __acl_delete_link_args *uap)
924 {
925 struct nameidata nd;
926 int error;
927
928 mtx_lock(&Giant);
929 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td);
930 error = namei(&nd);
931 if (error == 0) {
932 error = vacl_delete(td, nd.ni_vp, uap->type);
933 NDFREE(&nd, 0);
934 }
935 mtx_unlock(&Giant);
936 return (error);
937 }
938
939 /*
940 * Given a file path, delete an ACL from it.
941 *
942 * MPSAFE
943 */
944 int
945 __acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap)
946 {
947 struct file *fp;
948 int error;
949
950 mtx_lock(&Giant);
951 error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
952 if (error == 0) {
953 error = vacl_delete(td, fp->f_vnode, uap->type);
954 fdrop(fp, td);
955 }
956 mtx_unlock(&Giant);
957 return (error);
958 }
959
960 /*
961 * Given a file path, check an ACL for it
962 *
963 * MPSAFE
964 */
965 int
966 __acl_aclcheck_file(struct thread *td, struct __acl_aclcheck_file_args *uap)
967 {
968 struct nameidata nd;
969 int error;
970
971 mtx_lock(&Giant);
972 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
973 error = namei(&nd);
974 if (error == 0) {
975 error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp);
976 NDFREE(&nd, 0);
977 }
978 mtx_unlock(&Giant);
979 return (error);
980 }
981
982 /*
983 * Given a file path, check an ACL for it; don't follow links.
984 *
985 * MPSAFE
986 */
987 int
988 __acl_aclcheck_link(struct thread *td, struct __acl_aclcheck_link_args *uap)
989 {
990 struct nameidata nd;
991 int error;
992
993 mtx_lock(&Giant);
994 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td);
995 error = namei(&nd);
996 if (error == 0) {
997 error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp);
998 NDFREE(&nd, 0);
999 }
1000 mtx_unlock(&Giant);
1001 return (error);
1002 }
1003
1004 /*
1005 * Given a file descriptor, check an ACL for it
1006 *
1007 * MPSAFE
1008 */
1009 int
1010 __acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap)
1011 {
1012 struct file *fp;
1013 int error;
1014
1015 mtx_lock(&Giant);
1016 error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
1017 if (error == 0) {
1018 error = vacl_aclcheck(td, fp->f_vnode, uap->type, uap->aclp);
1019 fdrop(fp, td);
1020 }
1021 mtx_unlock(&Giant);
1022 return (error);
1023 }
Cache object: 53eccd501b2ff1a9aac9b3cb67d0c789
|