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