xref: /freebsd/sys/kern/vfs_acl.c (revision d086ded32300bc0f33fb1574d0bcfccfbc60881d)
1 /*-
2  * Copyright (c) 1999, 2000, 2001, 2002 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$");
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, PRISON_ROOT) == 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, PRISON_ROOT))
105 			cap_granted |= VEXEC;
106 	} else {
107 		if ((acc_mode & VEXEC) && !cap_check(cred, NULL,
108 		    CAP_DAC_EXECUTE, PRISON_ROOT))
109 			cap_granted |= VEXEC;
110 	}
111 
112 	if ((acc_mode & VREAD) && !cap_check(cred, NULL, CAP_DAC_READ_SEARCH,
113 	    PRISON_ROOT))
114 		cap_granted |= VREAD;
115 
116 	if (((acc_mode & VWRITE) || (acc_mode & VAPPEND)) &&
117 	    !cap_check(cred, NULL, CAP_DAC_WRITE, PRISON_ROOT))
118 		cap_granted |= (VWRITE | VAPPEND);
119 
120 	if ((acc_mode & VADMIN) && !cap_check(cred, NULL, CAP_FOWNER,
121 	    PRISON_ROOT))
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  * Perform a syntactic check of the ACL, sufficient to allow an
477  * implementing filesystem to determine if it should accept this and
478  * rely on the POSIX.1e ACL properties.
479  */
480 int
481 acl_posix1e_check(struct acl *acl)
482 {
483 	int num_acl_user_obj, num_acl_user, num_acl_group_obj, num_acl_group;
484 	int num_acl_mask, num_acl_other, i;
485 
486 	/*
487 	 * Verify that the number of entries does not exceed the maximum
488 	 * defined for acl_t.
489 	 * Verify that the correct number of various sorts of ae_tags are
490 	 * present:
491 	 *   Exactly one ACL_USER_OBJ
492 	 *   Exactly one ACL_GROUP_OBJ
493 	 *   Exactly one ACL_OTHER
494 	 *   If any ACL_USER or ACL_GROUP entries appear, then exactly one
495 	 *   ACL_MASK entry must also appear.
496 	 * Verify that all ae_perm entries are in ACL_PERM_BITS.
497 	 * Verify all ae_tag entries are understood by this implementation.
498 	 * Note: Does not check for uniqueness of qualifier (ae_id) field.
499 	 */
500 	num_acl_user_obj = num_acl_user = num_acl_group_obj = num_acl_group =
501 	    num_acl_mask = num_acl_other = 0;
502 	if (acl->acl_cnt > ACL_MAX_ENTRIES || acl->acl_cnt < 0)
503 		return (EINVAL);
504 	for (i = 0; i < acl->acl_cnt; i++) {
505 		/*
506 		 * Check for a valid tag.
507 		 */
508 		switch(acl->acl_entry[i].ae_tag) {
509 		case ACL_USER_OBJ:
510 			acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
511 			if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
512 				return (EINVAL);
513 			num_acl_user_obj++;
514 			break;
515 		case ACL_GROUP_OBJ:
516 			acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
517 			if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
518 				return (EINVAL);
519 			num_acl_group_obj++;
520 			break;
521 		case ACL_USER:
522 			if (acl->acl_entry[i].ae_id == ACL_UNDEFINED_ID)
523 				return (EINVAL);
524 			num_acl_user++;
525 			break;
526 		case ACL_GROUP:
527 			if (acl->acl_entry[i].ae_id == ACL_UNDEFINED_ID)
528 				return (EINVAL);
529 			num_acl_group++;
530 			break;
531 		case ACL_OTHER:
532 			acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
533 			if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
534 				return (EINVAL);
535 			num_acl_other++;
536 			break;
537 		case ACL_MASK:
538 			acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
539 			if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
540 				return (EINVAL);
541 			num_acl_mask++;
542 			break;
543 		default:
544 			return (EINVAL);
545 		}
546 		/*
547 		 * Check for valid perm entries.
548 		 */
549 		if ((acl->acl_entry[i].ae_perm | ACL_PERM_BITS) !=
550 		    ACL_PERM_BITS)
551 			return (EINVAL);
552 	}
553 	if ((num_acl_user_obj != 1) || (num_acl_group_obj != 1) ||
554 	    (num_acl_other != 1) || (num_acl_mask != 0 && num_acl_mask != 1))
555 		return (EINVAL);
556 	if (((num_acl_group != 0) || (num_acl_user != 0)) &&
557 	    (num_acl_mask != 1))
558 		return (EINVAL);
559 	return (0);
560 }
561 
562 /*
563  * These calls wrap the real vnode operations, and are called by the
564  * syscall code once the syscall has converted the path or file
565  * descriptor to a vnode (unlocked).  The aclp pointer is assumed
566  * still to point to userland, so this should not be consumed within
567  * the kernel except by syscall code.  Other code should directly
568  * invoke VOP_{SET,GET}ACL.
569  */
570 
571 /*
572  * Given a vnode, set its ACL.
573  */
574 static int
575 vacl_set_acl(struct thread *td, struct vnode *vp, acl_type_t type,
576     struct acl *aclp)
577 {
578 	struct acl inkernacl;
579 	struct mount *mp;
580 	int error;
581 
582 	error = copyin(aclp, &inkernacl, sizeof(struct acl));
583 	if (error)
584 		return(error);
585 	error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
586 	if (error != 0)
587 		return (error);
588 	VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
589 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
590 #ifdef MAC
591 	error = mac_check_vnode_setacl(td->td_ucred, vp, type, &inkernacl);
592 	if (error != 0)
593 		goto out;
594 #endif
595 	error = VOP_SETACL(vp, type, &inkernacl, td->td_ucred, td);
596 #ifdef MAC
597 out:
598 #endif
599 	VOP_UNLOCK(vp, 0, td);
600 	vn_finished_write(mp);
601 	return(error);
602 }
603 
604 /*
605  * Given a vnode, get its ACL.
606  */
607 static int
608 vacl_get_acl(struct thread *td, struct vnode *vp, acl_type_t type,
609     struct acl *aclp)
610 {
611 	struct acl inkernelacl;
612 	int error;
613 
614 	VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
615 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
616 #ifdef MAC
617 	error = mac_check_vnode_getacl(td->td_ucred, vp, type);
618 	if (error != 0)
619 		goto out;
620 #endif
621 	error = VOP_GETACL(vp, type, &inkernelacl, td->td_ucred, td);
622 #ifdef MAC
623 out:
624 #endif
625 	VOP_UNLOCK(vp, 0, td);
626 	if (error == 0)
627 		error = copyout(&inkernelacl, aclp, sizeof(struct acl));
628 	return (error);
629 }
630 
631 /*
632  * Given a vnode, delete its ACL.
633  */
634 static int
635 vacl_delete(struct thread *td, struct vnode *vp, acl_type_t type)
636 {
637 	struct mount *mp;
638 	int error;
639 
640 	error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
641 	if (error)
642 		return (error);
643 	VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
644 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
645 #ifdef MAC
646 	error = mac_check_vnode_deleteacl(td->td_ucred, vp, type);
647 	if (error)
648 		goto out;
649 #endif
650 	error = VOP_SETACL(vp, type, 0, td->td_ucred, td);
651 #ifdef MAC
652 out:
653 #endif
654 	VOP_UNLOCK(vp, 0, td);
655 	vn_finished_write(mp);
656 	return (error);
657 }
658 
659 /*
660  * Given a vnode, check whether an ACL is appropriate for it
661  */
662 static int
663 vacl_aclcheck(struct thread *td, struct vnode *vp, acl_type_t type,
664     struct acl *aclp)
665 {
666 	struct acl inkernelacl;
667 	int error;
668 
669 	error = copyin(aclp, &inkernelacl, sizeof(struct acl));
670 	if (error)
671 		return(error);
672 	error = VOP_ACLCHECK(vp, type, &inkernelacl, td->td_ucred, td);
673 	return (error);
674 }
675 
676 /*
677  * syscalls -- convert the path/fd to a vnode, and call vacl_whatever.
678  * Don't need to lock, as the vacl_ code will get/release any locks
679  * required.
680  */
681 
682 /*
683  * Given a file path, get an ACL for it
684  *
685  * MPSAFE
686  */
687 int
688 __acl_get_file(struct thread *td, struct __acl_get_file_args *uap)
689 {
690 	struct nameidata nd;
691 	int error;
692 
693 	mtx_lock(&Giant);
694 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
695 	error = namei(&nd);
696 	if (error == 0) {
697 		error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp);
698 		NDFREE(&nd, 0);
699 	}
700 	mtx_unlock(&Giant);
701 	return (error);
702 }
703 
704 /*
705  * Given a file path, get an ACL for it; don't follow links.
706  *
707  * MPSAFE
708  */
709 int
710 __acl_get_link(struct thread *td, struct __acl_get_link_args *uap)
711 {
712 	struct nameidata nd;
713 	int error;
714 
715 	mtx_lock(&Giant);
716 	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td);
717 	error = namei(&nd);
718 	if (error == 0) {
719 		error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp);
720 		NDFREE(&nd, 0);
721 	}
722 	mtx_unlock(&Giant);
723 	return (error);
724 }
725 
726 /*
727  * Given a file path, set an ACL for it
728  *
729  * MPSAFE
730  */
731 int
732 __acl_set_file(struct thread *td, struct __acl_set_file_args *uap)
733 {
734 	struct nameidata nd;
735 	int error;
736 
737 	mtx_lock(&Giant);
738 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
739 	error = namei(&nd);
740 	if (error == 0) {
741 		error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp);
742 		NDFREE(&nd, 0);
743 	}
744 	mtx_unlock(&Giant);
745 	return (error);
746 }
747 
748 /*
749  * Given a file path, set an ACL for it; don't follow links.
750  *
751  * MPSAFE
752  */
753 int
754 __acl_set_link(struct thread *td, struct __acl_set_link_args *uap)
755 {
756 	struct nameidata nd;
757 	int error;
758 
759 	mtx_lock(&Giant);
760 	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td);
761 	error = namei(&nd);
762 	if (error == 0) {
763 		error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp);
764 		NDFREE(&nd, 0);
765 	}
766 	mtx_unlock(&Giant);
767 	return (error);
768 }
769 
770 /*
771  * Given a file descriptor, get an ACL for it
772  *
773  * MPSAFE
774  */
775 int
776 __acl_get_fd(struct thread *td, struct __acl_get_fd_args *uap)
777 {
778 	struct file *fp;
779 	int error;
780 
781 	mtx_lock(&Giant);
782 	error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
783 	if (error == 0) {
784 		error = vacl_get_acl(td, fp->f_data, uap->type, uap->aclp);
785 		fdrop(fp, td);
786 	}
787 	mtx_unlock(&Giant);
788 	return (error);
789 }
790 
791 /*
792  * Given a file descriptor, set an ACL for it
793  *
794  * MPSAFE
795  */
796 int
797 __acl_set_fd(struct thread *td, struct __acl_set_fd_args *uap)
798 {
799 	struct file *fp;
800 	int error;
801 
802 	mtx_lock(&Giant);
803 	error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
804 	if (error == 0) {
805 		error = vacl_set_acl(td, fp->f_data, uap->type, uap->aclp);
806 		fdrop(fp, td);
807 	}
808 	mtx_unlock(&Giant);
809 	return (error);
810 }
811 
812 /*
813  * Given a file path, delete an ACL from it.
814  *
815  * MPSAFE
816  */
817 int
818 __acl_delete_file(struct thread *td, struct __acl_delete_file_args *uap)
819 {
820 	struct nameidata nd;
821 	int error;
822 
823 	mtx_lock(&Giant);
824 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
825 	error = namei(&nd);
826 	if (error == 0) {
827 		error = vacl_delete(td, nd.ni_vp, uap->type);
828 		NDFREE(&nd, 0);
829 	}
830 	mtx_unlock(&Giant);
831 	return (error);
832 }
833 
834 /*
835  * Given a file path, delete an ACL from it; don't follow links.
836  *
837  * MPSAFE
838  */
839 int
840 __acl_delete_link(struct thread *td, struct __acl_delete_link_args *uap)
841 {
842 	struct nameidata nd;
843 	int error;
844 
845 	mtx_lock(&Giant);
846 	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td);
847 	error = namei(&nd);
848 	if (error == 0) {
849 		error = vacl_delete(td, nd.ni_vp, uap->type);
850 		NDFREE(&nd, 0);
851 	}
852 	mtx_unlock(&Giant);
853 	return (error);
854 }
855 
856 /*
857  * Given a file path, delete an ACL from it.
858  *
859  * MPSAFE
860  */
861 int
862 __acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap)
863 {
864 	struct file *fp;
865 	int error;
866 
867 	mtx_lock(&Giant);
868 	error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
869 	if (error == 0) {
870 		error = vacl_delete(td, fp->f_data, uap->type);
871 		fdrop(fp, td);
872 	}
873 	mtx_unlock(&Giant);
874 	return (error);
875 }
876 
877 /*
878  * Given a file path, check an ACL for it
879  *
880  * MPSAFE
881  */
882 int
883 __acl_aclcheck_file(struct thread *td, struct __acl_aclcheck_file_args *uap)
884 {
885 	struct nameidata	nd;
886 	int	error;
887 
888 	mtx_lock(&Giant);
889 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
890 	error = namei(&nd);
891 	if (error == 0) {
892 		error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp);
893 		NDFREE(&nd, 0);
894 	}
895 	mtx_unlock(&Giant);
896 	return (error);
897 }
898 
899 /*
900  * Given a file path, check an ACL for it; don't follow links.
901  *
902  * MPSAFE
903  */
904 int
905 __acl_aclcheck_link(struct thread *td, struct __acl_aclcheck_link_args *uap)
906 {
907 	struct nameidata	nd;
908 	int	error;
909 
910 	mtx_lock(&Giant);
911 	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td);
912 	error = namei(&nd);
913 	if (error == 0) {
914 		error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp);
915 		NDFREE(&nd, 0);
916 	}
917 	mtx_unlock(&Giant);
918 	return (error);
919 }
920 
921 /*
922  * Given a file descriptor, check an ACL for it
923  *
924  * MPSAFE
925  */
926 int
927 __acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap)
928 {
929 	struct file *fp;
930 	int error;
931 
932 	mtx_lock(&Giant);
933 	error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
934 	if (error == 0) {
935 		error = vacl_aclcheck(td, fp->f_data, uap->type, uap->aclp);
936 		fdrop(fp, td);
937 	}
938 	mtx_unlock(&Giant);
939 	return (error);
940 }
941