subr_acl_posix1e.c revision 73890
1/*-
2 * Copyright (c) 1999, 2000, 2001 Robert N. M. Watson
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/kern/subr_acl_posix1e.c 73890 2001-03-06 17:28:24Z rwatson $
27 */
28/*
29 * Developed by the TrustedBSD Project.
30 * Support for POSIX.1e access control lists.
31 */
32
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/sysproto.h>
36#include <sys/kernel.h>
37#include <sys/malloc.h>
38#include <sys/vnode.h>
39#include <sys/lock.h>
40#include <sys/namei.h>
41#include <sys/file.h>
42#include <sys/proc.h>
43#include <sys/sysent.h>
44#include <sys/errno.h>
45#include <sys/stat.h>
46#include <sys/acl.h>
47
48MALLOC_DEFINE(M_ACL, "acl", "access control list");
49
50static int	vacl_set_acl(struct proc *p, struct vnode *vp, acl_type_t type,
51	    struct acl *aclp);
52static int	vacl_get_acl(struct proc *p, struct vnode *vp, acl_type_t type,
53	    struct acl *aclp);
54static int	vacl_aclcheck(struct proc *p, struct vnode *vp, acl_type_t type,
55	    struct acl *aclp);
56
57/*
58 * Implement a version of vaccess() that understands POSIX.1e ACL semantics.
59 * Return 0 on success, else an errno value.  Should be merged into
60 * vaccess() eventually.
61 */
62int
63vaccess_acl_posix1e(enum vtype type, struct acl *acl, mode_t acc_mode,
64    struct ucred *cred, int *privused)
65{
66	struct acl_entry *acl_other, *acl_mask;
67	mode_t dac_granted;
68	mode_t cap_granted;
69	mode_t acl_mask_granted;
70	int group_matched, i;
71
72	/*
73	 * Look for a normal, non-privileged way to access the file/directory
74	 * as requested.  If it exists, go with that.  Otherwise, attempt
75	 * to use privileges granted via cap_granted.  In some cases,
76	 * which privileges to use may be ambiguous due to "best match",
77	 * in which case fall back on first match for the time being.
78	 */
79	if (privused != NULL)
80		*privused = 0;
81
82	/*
83	 * Determine privileges now, but don't apply until we've found
84	 * a DAC match that has failed to allow access.
85	 */
86#ifndef CAPABILITIES
87	if (suser_xxx(cred, NULL, PRISON_ROOT) == 0)
88		cap_granted = (VEXEC | VREAD | VWRITE | VADMIN);
89	else
90		cap_granted = 0;
91#else
92	cap_granted = 0;
93
94	if (type == VDIR) {
95		if ((acc_mode & VEXEC) && !cap_check(cred, NULL,
96		     CAP_DAC_READ_SEARCH, PRISON_ROOT))
97			cap_granted |= VEXEC;
98	} else {
99		if ((acc_mode & VEXEC) && !cap_check(cred, NULL,
100		    CAP_DAC_EXECUTE, PRISON_ROOT))
101			cap_granted |= VEXEC;
102	}
103
104	if ((acc_mode & VREAD) && !cap_check(cred, NULL, CAP_DAC_READ_SEARCH,
105	    PRISON_ROOT))
106		cap_granted |= VREAD;
107
108	if ((acc_mode & VWRITE) && !cap_check(cred, NULL, CAP_DAC_WRITE,
109	    PRISON_ROOT))
110		cap_granted |= VWRITE;
111
112	if ((acc_mode & VADMIN) && !cap_check(cred, NULL, CAP_FOWNER,
113	    PRISON_ROOT))
114		cap_granted |= VADMIN;
115#endif /* CAPABILITIES */
116
117	/*
118	 * Check the owner.
119	 * Also, record locations of ACL_MASK and ACL_OTHER for reference
120	 * later if the owner doesn't match.
121	 */
122	acl_mask = acl_other = NULL;
123	for (i = 0; i < acl->acl_cnt; i++) {
124		switch (acl->acl_entry[i].ae_tag) {
125		case ACL_USER_OBJ:
126			if (acl->acl_entry[i].ae_id != cred->cr_uid)
127				break;
128			dac_granted = 0;
129			dac_granted |= VADMIN;
130			if (acl->acl_entry[i].ae_perm & ACL_PERM_EXEC)
131				dac_granted |= VEXEC;
132			if (acl->acl_entry[i].ae_perm & ACL_PERM_READ)
133				dac_granted |= VREAD;
134			if (acl->acl_entry[i].ae_perm & ACL_PERM_WRITE)
135				dac_granted |= VWRITE;
136			if ((acc_mode & dac_granted) == acc_mode)
137				return (0);
138			if ((acc_mode & (dac_granted | cap_granted)) ==
139			    acc_mode) {
140				if (privused != NULL)
141					*privused = 1;
142				return (0);
143			}
144			goto error;
145
146		case ACL_MASK:
147			acl_mask = &acl->acl_entry[i];
148			break;
149
150		case ACL_OTHER:
151			acl_other = &acl->acl_entry[i];
152			break;
153
154		default:
155		}
156	}
157
158	/*
159	 * Checks against ACL_USER, ACL_GROUP_OBJ, and ACL_GROUP fields
160	 * are masked by an ACL_MASK entry, if any.  As such, first identify
161	 * the ACL_MASK field, then iterate through identifying potential
162	 * user matches, then group matches.  If there is no ACL_MASK,
163	 * assume that the mask allows all requests to succeed.
164	 * Also keep track of the location of ACL_OTHER for later consumption.
165	 */
166	if (acl_other == NULL) {
167		/*
168		 * XXX: This should never happen.  Only properly formatted
169		 * ACLs should be passed to vaccess_acl_posix1e.
170		 * Should make this a panic post-debugging.
171		 */
172		printf("vaccess_acl_posix1e: ACL_OTHER missing\n");
173		return (EPERM);
174	}
175	if (acl_mask != NULL) {
176		acl_mask_granted = 0;
177		if (acl_mask->ae_perm & ACL_PERM_EXEC)
178			acl_mask_granted |= VEXEC;
179		if (acl_mask->ae_perm & ACL_PERM_READ)
180			acl_mask_granted |= VREAD;
181		if (acl_mask->ae_perm & ACL_PERM_WRITE)
182			acl_mask_granted |= VWRITE;
183	} else
184		acl_mask_granted = VEXEC | VREAD | VWRITE;
185
186	/*
187	 * We have to check each type even if we know ACL_MASK will reject,
188	 * as we need to know what match there might have been, and
189	 * therefore what further types we might be allowed to check.
190	 * Do the checks twice -- once without privilege, and a second time
191	 * with, if there was a match.
192	 */
193
194	/*
195	 * Check ACL_USER ACL entries.
196	 */
197	for (i = 0; i < acl->acl_cnt; i++) {
198		switch (acl->acl_entry[i].ae_tag) {
199		case ACL_USER:
200			if (acl->acl_entry[i].ae_id != cred->cr_uid)
201				break;
202			dac_granted = 0;
203			if (acl->acl_entry[i].ae_perm & ACL_PERM_EXEC)
204				dac_granted |= VEXEC;
205			if (acl->acl_entry[i].ae_perm & ACL_PERM_READ)
206				dac_granted |= VREAD;
207			if (acl->acl_entry[i].ae_perm & ACL_PERM_WRITE)
208				dac_granted |= VWRITE;
209			dac_granted &= acl_mask_granted;
210			if ((acc_mode & dac_granted) == acc_mode)
211				return (0);
212			if ((acc_mode & (dac_granted | cap_granted)) ==
213			    acc_mode) {
214				if (privused != NULL)
215					*privused = 1;
216				return (0);
217			}
218			goto error;
219		}
220	}
221
222	/*
223	 * Group match is best-match, not first-match, so find a
224	 * "best" match.  Iterate across, testing each potential group
225	 * match.  Make sure we keep track of whether we found a match
226	 * or not, so that we know if we can move on to ACL_OTHER.
227	 */
228	group_matched = 0;
229	for (i = 0; i < acl->acl_cnt; i++) {
230		switch (acl->acl_entry[i].ae_tag) {
231		case ACL_GROUP_OBJ:
232		case ACL_GROUP:
233			if (groupmember(acl->acl_entry[i].ae_id, cred)) {
234				dac_granted = 0;
235				if (acl->acl_entry[i].ae_perm & ACL_PERM_EXEC)
236					dac_granted |= VEXEC;
237				if (acl->acl_entry[i].ae_perm & ACL_PERM_READ)
238					dac_granted |= VREAD;
239				if (acl->acl_entry[i].ae_perm & ACL_PERM_WRITE)
240					dac_granted |= VWRITE;
241				dac_granted  &= acl_mask_granted;
242
243				if ((acc_mode & dac_granted) == acc_mode)
244					return (0);
245
246				group_matched = 1;
247			}
248		default:
249		}
250	}
251
252	if (group_matched == 1) {
253		/*
254		 * There was a match, but it did not grant rights via
255		 * pure DAC.  Try again, this time with privilege.
256		 */
257		for (i = 0; i < acl->acl_cnt; i++) {
258			switch (acl->acl_entry[i].ae_tag) {
259			case ACL_GROUP_OBJ:
260			case ACL_GROUP:
261				if (groupmember(acl->acl_entry[i].ae_id,
262				    cred)) {
263					dac_granted = 0;
264					if (acl->acl_entry[i].ae_perm &
265					    ACL_PERM_EXEC)
266					dac_granted |= VEXEC;
267					if (acl->acl_entry[i].ae_perm &
268					    ACL_PERM_READ)
269						dac_granted |= VREAD;
270					if (acl->acl_entry[i].ae_perm &
271					    ACL_PERM_WRITE)
272						dac_granted |= VWRITE;
273					dac_granted &= acl_mask_granted;
274					if ((acc_mode & (dac_granted |
275					    cap_granted)) == acc_mode) {
276						if (privused != NULL)
277							*privused = 1;
278						return (0);
279					}
280				}
281			default:
282			}
283		}
284		/*
285		 * Even with privilege, group membership was not sufficient.
286		 * Return failure.
287		 */
288		goto error;
289	}
290
291	/*
292	 * Fall back on ACL_OTHER.  ACL_MASK is not applied to ACL_OTHER.
293	 */
294	dac_granted = 0;
295	if (acl_other->ae_perm & ACL_PERM_EXEC)
296		dac_granted |= VEXEC;
297	if (acl_other->ae_perm & ACL_PERM_READ)
298		dac_granted |= VREAD;
299	if (acl_other->ae_perm & ACL_PERM_WRITE)
300		dac_granted |= VWRITE;
301
302	if ((acc_mode & dac_granted) == acc_mode)
303		return (0);
304	if ((acc_mode & (dac_granted | cap_granted)) == acc_mode) {
305		if (privused != NULL)
306			*privused = 1;
307		return (0);
308	}
309
310error:
311	return ((acc_mode & VADMIN) ? EPERM : EACCES);
312}
313
314/*
315 * For the purposes of file systems maintaining the _OBJ entries in an
316 * inode with a mode_t field, this routine converts a mode_t entry
317 * to an acl_perm_t.
318 */
319acl_perm_t
320acl_posix1e_mode_to_perm(acl_tag_t tag, mode_t mode)
321{
322	acl_perm_t	perm = 0;
323
324	switch(tag) {
325	case ACL_USER_OBJ:
326		if (mode & S_IXUSR)
327			perm |= ACL_PERM_EXEC;
328		if (mode & S_IRUSR)
329			perm |= ACL_PERM_READ;
330		if (mode & S_IWUSR)
331			perm |= ACL_PERM_WRITE;
332		return (perm);
333
334	case ACL_GROUP_OBJ:
335		if (mode & S_IXGRP)
336			perm |= ACL_PERM_EXEC;
337		if (mode & S_IRGRP)
338			perm |= ACL_PERM_READ;
339		if (mode & S_IWGRP)
340			perm |= ACL_PERM_WRITE;
341		return (perm);
342
343	case ACL_OTHER:
344		if (mode & S_IXOTH)
345			perm |= ACL_PERM_EXEC;
346		if (mode & S_IROTH)
347			perm |= ACL_PERM_READ;
348		if (mode & S_IWOTH)
349			perm |= ACL_PERM_WRITE;
350		return (perm);
351
352	default:
353		printf("acl_posix1e_mode_to_perm: invalid tag (%d)\n", tag);
354		return (0);
355	}
356}
357
358/*
359 * Given inode information (uid, gid, mode), return an acl entry of the
360 * appropriate type.
361 */
362struct acl_entry
363acl_posix1e_mode_to_entry(acl_tag_t tag, uid_t uid, gid_t gid, mode_t mode)
364{
365	struct acl_entry	acl_entry;
366
367	acl_entry.ae_tag = tag;
368	acl_entry.ae_perm = acl_posix1e_mode_to_perm(tag, mode);
369	switch(tag) {
370	case ACL_USER_OBJ:
371		acl_entry.ae_id = uid;
372		break;
373
374	case ACL_GROUP_OBJ:
375		acl_entry.ae_id = gid;
376		break;
377
378	case ACL_OTHER:
379		acl_entry.ae_id = 0;
380		break;
381
382	default:
383		acl_entry.ae_id = 0;
384		printf("acl_posix1e_mode_to_entry: invalid tag (%d)\n", tag);
385	}
386
387	return (acl_entry);
388}
389
390/*
391 * Utility function to generate a file mode given appropriate ACL entries.
392 */
393mode_t
394acl_posix1e_perms_to_mode(struct acl_entry *acl_user_obj_entry,
395    struct acl_entry *acl_group_obj_entry, struct acl_entry *acl_other_entry)
396{
397	mode_t	mode;
398
399	mode = 0;
400	if (acl_user_obj_entry->ae_perm & ACL_PERM_EXEC)
401		mode |= S_IXUSR;
402	if (acl_user_obj_entry->ae_perm & ACL_PERM_READ)
403		mode |= S_IRUSR;
404	if (acl_user_obj_entry->ae_perm & ACL_PERM_WRITE)
405		mode |= S_IWUSR;
406	if (acl_group_obj_entry->ae_perm & ACL_PERM_EXEC)
407		mode |= S_IXGRP;
408	if (acl_group_obj_entry->ae_perm & ACL_PERM_READ)
409		mode |= S_IRGRP;
410	if (acl_group_obj_entry->ae_perm & ACL_PERM_WRITE)
411		mode |= S_IWGRP;
412	if (acl_other_entry->ae_perm & ACL_PERM_EXEC)
413		mode |= S_IXOTH;
414	if (acl_other_entry->ae_perm & ACL_PERM_READ)
415		mode |= S_IROTH;
416	if (acl_other_entry->ae_perm & ACL_PERM_WRITE)
417		mode |= S_IWOTH;
418
419	return (mode);
420}
421
422/*
423 * Perform a syntactic check of the ACL, sufficient to allow an
424 * implementing file system to determine if it should accept this and
425 * rely on the POSIX.1e ACL properties.
426 */
427int
428acl_posix1e_check(struct acl *acl)
429{
430	int num_acl_user_obj, num_acl_user, num_acl_group_obj, num_acl_group;
431	int num_acl_mask, num_acl_other, i;
432
433	/*
434	 * Verify that the number of entries does not exceed the maximum
435	 * defined for acl_t.
436	 * Verify that the correct number of various sorts of ae_tags are
437	 * present:
438	 *   Exactly one ACL_USER_OBJ
439	 *   Exactly one ACL_GROUP_OBJ
440	 *   Exactly one ACL_OTHER
441	 *   If any ACL_USER or ACL_GROUP entries appear, then exactly one
442	 *   ACL_MASK entry must also appear.
443	 * Verify that all ae_perm entries are in ACL_PERM_BITS.
444	 * Verify all ae_tag entries are understood by this implementation.
445	 * Note: Does not check for uniqueness of qualifier (ae_id) field.
446	 */
447	num_acl_user_obj = num_acl_user = num_acl_group_obj = num_acl_group =
448	    num_acl_mask = num_acl_other = 0;
449	if (acl->acl_cnt > ACL_MAX_ENTRIES || acl->acl_cnt < 0)
450		return (EINVAL);
451	for (i = 0; i < acl->acl_cnt; i++) {
452		/*
453		 * Check for a valid tag.
454		 */
455		switch(acl->acl_entry[i].ae_tag) {
456		case ACL_USER_OBJ:
457			num_acl_user_obj++;
458			break;
459		case ACL_GROUP_OBJ:
460			num_acl_group_obj++;
461			break;
462		case ACL_USER:
463			num_acl_user++;
464			break;
465		case ACL_GROUP:
466			num_acl_group++;
467			break;
468		case ACL_OTHER:
469			num_acl_other++;
470			break;
471		case ACL_MASK:
472			num_acl_mask++;
473			break;
474		default:
475			return (EINVAL);
476		}
477		/*
478		 * Check for valid perm entries.
479		 */
480		if ((acl->acl_entry[i].ae_perm | ACL_PERM_BITS) !=
481		    ACL_PERM_BITS)
482			return (EINVAL);
483	}
484	if ((num_acl_user_obj != 1) || (num_acl_group_obj != 1) ||
485	    (num_acl_other != 1) || (num_acl_mask != 0 && num_acl_mask != 1))
486		return (EINVAL);
487	if (((num_acl_group != 0) || (num_acl_user != 0)) &&
488	    (num_acl_mask != 1))
489		return (EINVAL);
490	return (0);
491}
492
493/*
494 * These calls wrap the real vnode operations, and are called by the
495 * syscall code once the syscall has converted the path or file
496 * descriptor to a vnode (unlocked).  The aclp pointer is assumed
497 * still to point to userland, so this should not be consumed within
498 * the kernel except by syscall code.  Other code should directly
499 * invoke VOP_{SET,GET}ACL.
500 */
501
502/*
503 * Given a vnode, set its ACL.
504 */
505static int
506vacl_set_acl(struct proc *p, struct vnode *vp, acl_type_t type,
507    struct acl *aclp)
508{
509	struct acl inkernacl;
510	int error;
511
512	error = copyin(aclp, &inkernacl, sizeof(struct acl));
513	if (error)
514		return(error);
515	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
516	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
517	error = VOP_SETACL(vp, type, &inkernacl, p->p_ucred, p);
518	VOP_UNLOCK(vp, 0, p);
519	return(error);
520}
521
522/*
523 * Given a vnode, get its ACL.
524 */
525static int
526vacl_get_acl(struct proc *p, struct vnode *vp, acl_type_t type,
527    struct acl *aclp)
528{
529	struct acl inkernelacl;
530	int error;
531
532	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
533	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
534	error = VOP_GETACL(vp, type, &inkernelacl, p->p_ucred, p);
535	VOP_UNLOCK(vp, 0, p);
536	if (error == 0)
537		error = copyout(&inkernelacl, aclp, sizeof(struct acl));
538	return (error);
539}
540
541/*
542 * Given a vnode, delete its ACL.
543 */
544static int
545vacl_delete(struct proc *p, struct vnode *vp, acl_type_t type)
546{
547	int error;
548
549	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
550	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
551	error = VOP_SETACL(vp, ACL_TYPE_DEFAULT, 0, p->p_ucred, p);
552	VOP_UNLOCK(vp, 0, p);
553	return (error);
554}
555
556/*
557 * Given a vnode, check whether an ACL is appropriate for it
558 */
559static int
560vacl_aclcheck(struct proc *p, struct vnode *vp, acl_type_t type,
561    struct acl *aclp)
562{
563	struct acl inkernelacl;
564	int error;
565
566	error = copyin(aclp, &inkernelacl, sizeof(struct acl));
567	if (error)
568		return(error);
569	error = VOP_ACLCHECK(vp, type, &inkernelacl, p->p_ucred, p);
570	return (error);
571}
572
573/*
574 * syscalls -- convert the path/fd to a vnode, and call vacl_whatever.
575 * Don't need to lock, as the vacl_ code will get/release any locks
576 * required.
577 */
578
579/*
580 * Given a file path, get an ACL for it
581 */
582int
583__acl_get_file(struct proc *p, struct __acl_get_file_args *uap)
584{
585	struct nameidata nd;
586	int error;
587
588	/* what flags are required here -- possible not LOCKLEAF? */
589	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
590	error = namei(&nd);
591	if (error)
592		return(error);
593	error = vacl_get_acl(p, nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp));
594	NDFREE(&nd, 0);
595	return (error);
596}
597
598/*
599 * Given a file path, set an ACL for it
600 */
601int
602__acl_set_file(struct proc *p, struct __acl_set_file_args *uap)
603{
604	struct nameidata nd;
605	int error;
606
607	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
608	error = namei(&nd);
609	if (error)
610		return(error);
611	error = vacl_set_acl(p, nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp));
612	NDFREE(&nd, 0);
613	return (error);
614}
615
616/*
617 * Given a file descriptor, get an ACL for it
618 */
619int
620__acl_get_fd(struct proc *p, struct __acl_get_fd_args *uap)
621{
622	struct file *fp;
623	int error;
624
625	error = getvnode(p->p_fd, SCARG(uap, filedes), &fp);
626	if (error)
627		return(error);
628	return vacl_get_acl(p, (struct vnode *)fp->f_data, SCARG(uap, type),
629	    SCARG(uap, aclp));
630}
631
632/*
633 * Given a file descriptor, set an ACL for it
634 */
635int
636__acl_set_fd(struct proc *p, struct __acl_set_fd_args *uap)
637{
638	struct file *fp;
639	int error;
640
641	error = getvnode(p->p_fd, SCARG(uap, filedes), &fp);
642	if (error)
643		return(error);
644	return vacl_set_acl(p, (struct vnode *)fp->f_data, SCARG(uap, type),
645	    SCARG(uap, aclp));
646}
647
648/*
649 * Given a file path, delete an ACL from it.
650 */
651int
652__acl_delete_file(struct proc *p, struct __acl_delete_file_args *uap)
653{
654	struct nameidata nd;
655	int error;
656
657	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
658	error = namei(&nd);
659	if (error)
660		return(error);
661	error = vacl_delete(p, nd.ni_vp, SCARG(uap, type));
662	NDFREE(&nd, 0);
663	return (error);
664}
665
666/*
667 * Given a file path, delete an ACL from it.
668 */
669int
670__acl_delete_fd(struct proc *p, struct __acl_delete_fd_args *uap)
671{
672	struct file *fp;
673	int error;
674
675	error = getvnode(p->p_fd, SCARG(uap, filedes), &fp);
676	if (error)
677		return(error);
678	error = vacl_delete(p, (struct vnode *)fp->f_data, SCARG(uap, type));
679	return (error);
680}
681
682/*
683 * Given a file path, check an ACL for it
684 */
685int
686__acl_aclcheck_file(struct proc *p, struct __acl_aclcheck_file_args *uap)
687{
688	struct nameidata	nd;
689	int	error;
690
691	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
692	error = namei(&nd);
693	if (error)
694		return(error);
695	error = vacl_aclcheck(p, nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp));
696	NDFREE(&nd, 0);
697	return (error);
698}
699
700/*
701 * Given a file descriptor, check an ACL for it
702 */
703int
704__acl_aclcheck_fd(struct proc *p, struct __acl_aclcheck_fd_args *uap)
705{
706	struct file *fp;
707	int error;
708
709	error = getvnode(p->p_fd, SCARG(uap, filedes), &fp);
710	if (error)
711		return(error);
712	return vacl_aclcheck(p, (struct vnode *)fp->f_data, SCARG(uap, type),
713	    SCARG(uap, aclp));
714}
715