vfs_acl.c revision 167211
154803Srwatson/*-
2160146Srwatson * Copyright (c) 1999-2006 Robert N. M. Watson
354803Srwatson * All rights reserved.
454803Srwatson *
585845Srwatson * This software was developed by Robert Watson for the TrustedBSD Project.
685845Srwatson *
754803Srwatson * Redistribution and use in source and binary forms, with or without
854803Srwatson * modification, are permitted provided that the following conditions
954803Srwatson * are met:
1054803Srwatson * 1. Redistributions of source code must retain the above copyright
1154803Srwatson *    notice, this list of conditions and the following disclaimer.
1254803Srwatson * 2. Redistributions in binary form must reproduce the above copyright
1354803Srwatson *    notice, this list of conditions and the following disclaimer in the
1454803Srwatson *    documentation and/or other materials provided with the distribution.
1554803Srwatson *
1654803Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1754803Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1854803Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1954803Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2054803Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2154803Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2254803Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2354803Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2454803Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2554803Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2654803Srwatson * SUCH DAMAGE.
2754803Srwatson */
2854803Srwatson/*
2973890Srwatson * Developed by the TrustedBSD Project.
30160146Srwatson *
31160146Srwatson * ACL system calls and other functions common across different ACL types.
32160146Srwatson * Type-specific routines go into subr_acl_<type>.c.
3354803Srwatson */
3454803Srwatson
35116182Sobrien#include <sys/cdefs.h>
36116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/vfs_acl.c 167211 2007-03-04 22:36:48Z rwatson $");
37116182Sobrien
38101122Srwatson#include "opt_mac.h"
39101122Srwatson
4054803Srwatson#include <sys/param.h>
4154803Srwatson#include <sys/systm.h>
4254803Srwatson#include <sys/sysproto.h>
4354803Srwatson#include <sys/kernel.h>
4454803Srwatson#include <sys/malloc.h>
45150262Scsjp#include <sys/mount.h>
4654803Srwatson#include <sys/vnode.h>
4754803Srwatson#include <sys/lock.h>
4882713Sdillon#include <sys/mutex.h>
4954803Srwatson#include <sys/namei.h>
5054803Srwatson#include <sys/file.h>
51108524Salfred#include <sys/filedesc.h>
5254803Srwatson#include <sys/proc.h>
5354803Srwatson#include <sys/sysent.h>
5454803Srwatson#include <sys/acl.h>
5554803Srwatson
56163606Srwatson#include <security/mac/mac_framework.h>
57163606Srwatson
58149811Scsjp#include <vm/uma.h>
5954803Srwatson
60149811Scsjpuma_zone_t	acl_zone;
6198927Srwatsonstatic int	vacl_set_acl(struct thread *td, struct vnode *vp,
6298927Srwatson		    acl_type_t type, struct acl *aclp);
6398927Srwatsonstatic int	vacl_get_acl(struct thread *td, struct vnode *vp,
6498927Srwatson		    acl_type_t type, struct acl *aclp);
6585582Srwatsonstatic int	vacl_aclcheck(struct thread *td, struct vnode *vp,
6698927Srwatson		    acl_type_t type, struct acl *aclp);
6754803Srwatson
6854803Srwatson/*
69165983Srwatson * These calls wrap the real vnode operations, and are called by the syscall
70165983Srwatson * code once the syscall has converted the path or file descriptor to a vnode
71165983Srwatson * (unlocked).  The aclp pointer is assumed still to point to userland, so
72165983Srwatson * this should not be consumed within the kernel except by syscall code.
73165983Srwatson * Other code should directly invoke VOP_{SET,GET}ACL.
7454803Srwatson */
7554803Srwatson
7654803Srwatson/*
7754803Srwatson * Given a vnode, set its ACL.
7854803Srwatson */
7954803Srwatsonstatic int
8085582Srwatsonvacl_set_acl(struct thread *td, struct vnode *vp, acl_type_t type,
8156272Srwatson    struct acl *aclp)
8254803Srwatson{
8354803Srwatson	struct acl inkernacl;
8490202Srwatson	struct mount *mp;
8554803Srwatson	int error;
8654803Srwatson
8754803Srwatson	error = copyin(aclp, &inkernacl, sizeof(struct acl));
8854803Srwatson	if (error)
8954803Srwatson		return(error);
9090202Srwatson	error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
9190202Srwatson	if (error != 0)
9290202Srwatson		return (error);
9391406Sjhb	VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
9483366Sjulian	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
95101122Srwatson#ifdef MAC
96101122Srwatson	error = mac_check_vnode_setacl(td->td_ucred, vp, type, &inkernacl);
97101122Srwatson	if (error != 0)
98101122Srwatson		goto out;
99101122Srwatson#endif
10091406Sjhb	error = VOP_SETACL(vp, type, &inkernacl, td->td_ucred, td);
101101122Srwatson#ifdef MAC
102101122Srwatsonout:
103101122Srwatson#endif
10483366Sjulian	VOP_UNLOCK(vp, 0, td);
10590202Srwatson	vn_finished_write(mp);
10671699Sjhb	return(error);
10754803Srwatson}
10854803Srwatson
10954803Srwatson/*
11054803Srwatson * Given a vnode, get its ACL.
11154803Srwatson */
11254803Srwatsonstatic int
11385582Srwatsonvacl_get_acl(struct thread *td, struct vnode *vp, acl_type_t type,
11454803Srwatson    struct acl *aclp)
11554803Srwatson{
11654803Srwatson	struct acl inkernelacl;
11754803Srwatson	int error;
11854803Srwatson
11991406Sjhb	VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
12083366Sjulian	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
121101122Srwatson#ifdef MAC
122101122Srwatson	error = mac_check_vnode_getacl(td->td_ucred, vp, type);
123101122Srwatson	if (error != 0)
124101122Srwatson		goto out;
125101122Srwatson#endif
12691406Sjhb	error = VOP_GETACL(vp, type, &inkernelacl, td->td_ucred, td);
127101122Srwatson#ifdef MAC
128101122Srwatsonout:
129101122Srwatson#endif
13083366Sjulian	VOP_UNLOCK(vp, 0, td);
13154803Srwatson	if (error == 0)
13254803Srwatson		error = copyout(&inkernelacl, aclp, sizeof(struct acl));
13354803Srwatson	return (error);
13454803Srwatson}
13554803Srwatson
13654803Srwatson/*
13754803Srwatson * Given a vnode, delete its ACL.
13854803Srwatson */
13954803Srwatsonstatic int
14085582Srwatsonvacl_delete(struct thread *td, struct vnode *vp, acl_type_t type)
14154803Srwatson{
14290202Srwatson	struct mount *mp;
14354803Srwatson	int error;
14454803Srwatson
14590202Srwatson	error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
14690202Srwatson	if (error)
14790202Srwatson		return (error);
14891406Sjhb	VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
14983366Sjulian	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
150101122Srwatson#ifdef MAC
151101122Srwatson	error = mac_check_vnode_deleteacl(td->td_ucred, vp, type);
152101122Srwatson	if (error)
153101122Srwatson		goto out;
154101122Srwatson#endif
155101122Srwatson	error = VOP_SETACL(vp, type, 0, td->td_ucred, td);
156101122Srwatson#ifdef MAC
157101122Srwatsonout:
158101122Srwatson#endif
15983366Sjulian	VOP_UNLOCK(vp, 0, td);
16090202Srwatson	vn_finished_write(mp);
16154803Srwatson	return (error);
16254803Srwatson}
16354803Srwatson
16454803Srwatson/*
16554803Srwatson * Given a vnode, check whether an ACL is appropriate for it
16654803Srwatson */
16754803Srwatsonstatic int
16885582Srwatsonvacl_aclcheck(struct thread *td, struct vnode *vp, acl_type_t type,
16954803Srwatson    struct acl *aclp)
17054803Srwatson{
17154803Srwatson	struct acl inkernelacl;
17254803Srwatson	int error;
17354803Srwatson
17454803Srwatson	error = copyin(aclp, &inkernelacl, sizeof(struct acl));
17554803Srwatson	if (error)
17654803Srwatson		return(error);
17791406Sjhb	error = VOP_ACLCHECK(vp, type, &inkernelacl, td->td_ucred, td);
17854803Srwatson	return (error);
17954803Srwatson}
18054803Srwatson
18154803Srwatson/*
182165983Srwatson * syscalls -- convert the path/fd to a vnode, and call vacl_whatever.  Don't
183165983Srwatson * need to lock, as the vacl_ code will get/release any locks required.
18454803Srwatson */
18554803Srwatson
18654803Srwatson/*
18754803Srwatson * Given a file path, get an ACL for it
18854803Srwatson */
18954803Srwatsonint
19085582Srwatson__acl_get_file(struct thread *td, struct __acl_get_file_args *uap)
19154803Srwatson{
19254803Srwatson	struct nameidata nd;
193150262Scsjp	int vfslocked, error;
19454803Srwatson
195150262Scsjp	NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
19654803Srwatson	error = namei(&nd);
197150262Scsjp	vfslocked = NDHASGIANT(&nd);
19882713Sdillon	if (error == 0) {
199107855Salfred		error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp);
20082713Sdillon		NDFREE(&nd, 0);
20182713Sdillon	}
202150262Scsjp	VFS_UNLOCK_GIANT(vfslocked);
20354803Srwatson	return (error);
20454803Srwatson}
20554803Srwatson
20654803Srwatson/*
207108407Srwatson * Given a file path, get an ACL for it; don't follow links.
208108407Srwatson */
209108407Srwatsonint
210108407Srwatson__acl_get_link(struct thread *td, struct __acl_get_link_args *uap)
211108407Srwatson{
212108407Srwatson	struct nameidata nd;
213150262Scsjp	int vfslocked, error;
214108407Srwatson
215150262Scsjp	NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
216108407Srwatson	error = namei(&nd);
217150262Scsjp	vfslocked = NDHASGIANT(&nd);
218108407Srwatson	if (error == 0) {
219108407Srwatson		error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp);
220108407Srwatson		NDFREE(&nd, 0);
221108407Srwatson	}
222150262Scsjp	VFS_UNLOCK_GIANT(vfslocked);
223108407Srwatson	return (error);
224108407Srwatson}
225108407Srwatson
226108407Srwatson/*
227167211Srwatson * Given a file path, set an ACL for it.
22854803Srwatson */
22954803Srwatsonint
23085582Srwatson__acl_set_file(struct thread *td, struct __acl_set_file_args *uap)
23154803Srwatson{
23254803Srwatson	struct nameidata nd;
233150262Scsjp	int vfslocked, error;
23454803Srwatson
235150262Scsjp	NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
23654803Srwatson	error = namei(&nd);
237150262Scsjp	vfslocked = NDHASGIANT(&nd);
23882713Sdillon	if (error == 0) {
239107855Salfred		error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp);
24082713Sdillon		NDFREE(&nd, 0);
24182713Sdillon	}
242150262Scsjp	VFS_UNLOCK_GIANT(vfslocked);
24354803Srwatson	return (error);
24454803Srwatson}
24554803Srwatson
24654803Srwatson/*
247108407Srwatson * Given a file path, set an ACL for it; don't follow links.
248108407Srwatson */
249108407Srwatsonint
250108407Srwatson__acl_set_link(struct thread *td, struct __acl_set_link_args *uap)
251108407Srwatson{
252108407Srwatson	struct nameidata nd;
253150262Scsjp	int vfslocked, error;
254108407Srwatson
255150262Scsjp	NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
256108407Srwatson	error = namei(&nd);
257150262Scsjp	vfslocked = NDHASGIANT(&nd);
258108407Srwatson	if (error == 0) {
259108407Srwatson		error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp);
260108407Srwatson		NDFREE(&nd, 0);
261108407Srwatson	}
262150262Scsjp	VFS_UNLOCK_GIANT(vfslocked);
263108407Srwatson	return (error);
264108407Srwatson}
265108407Srwatson
266108407Srwatson/*
26754803Srwatson * Given a file descriptor, get an ACL for it
26854803Srwatson */
26954803Srwatsonint
27085582Srwatson__acl_get_fd(struct thread *td, struct __acl_get_fd_args *uap)
27154803Srwatson{
27254803Srwatson	struct file *fp;
273150262Scsjp	int vfslocked, error;
27454803Srwatson
275107849Salfred	error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
27682713Sdillon	if (error == 0) {
277150262Scsjp		vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
278116678Sphk		error = vacl_get_acl(td, fp->f_vnode, uap->type, uap->aclp);
27989306Salfred		fdrop(fp, td);
280150262Scsjp		VFS_UNLOCK_GIANT(vfslocked);
28182713Sdillon	}
28282713Sdillon	return (error);
28354803Srwatson}
28454803Srwatson
28554803Srwatson/*
28654803Srwatson * Given a file descriptor, set an ACL for it
28754803Srwatson */
28854803Srwatsonint
28985582Srwatson__acl_set_fd(struct thread *td, struct __acl_set_fd_args *uap)
29054803Srwatson{
29154803Srwatson	struct file *fp;
292150262Scsjp	int vfslocked, error;
29354803Srwatson
294107849Salfred	error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
29582713Sdillon	if (error == 0) {
296150262Scsjp		vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
297116678Sphk		error = vacl_set_acl(td, fp->f_vnode, uap->type, uap->aclp);
29889306Salfred		fdrop(fp, td);
299150262Scsjp		VFS_UNLOCK_GIANT(vfslocked);
30082713Sdillon	}
30182713Sdillon	return (error);
30254803Srwatson}
30354803Srwatson
30454803Srwatson/*
30554803Srwatson * Given a file path, delete an ACL from it.
30654803Srwatson */
30754803Srwatsonint
30885582Srwatson__acl_delete_file(struct thread *td, struct __acl_delete_file_args *uap)
30954803Srwatson{
31054803Srwatson	struct nameidata nd;
311150262Scsjp	int vfslocked, error;
31254803Srwatson
313150262Scsjp	NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
31454803Srwatson	error = namei(&nd);
315150262Scsjp	vfslocked = NDHASGIANT(&nd);
31682713Sdillon	if (error == 0) {
317107849Salfred		error = vacl_delete(td, nd.ni_vp, uap->type);
31882713Sdillon		NDFREE(&nd, 0);
31982713Sdillon	}
320150262Scsjp	VFS_UNLOCK_GIANT(vfslocked);
32154803Srwatson	return (error);
32254803Srwatson}
32354803Srwatson
32454803Srwatson/*
325108407Srwatson * Given a file path, delete an ACL from it; don't follow links.
326108407Srwatson */
327108407Srwatsonint
328108407Srwatson__acl_delete_link(struct thread *td, struct __acl_delete_link_args *uap)
329108407Srwatson{
330108407Srwatson	struct nameidata nd;
331150262Scsjp	int vfslocked, error;
332108407Srwatson
333150262Scsjp	NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
334108407Srwatson	error = namei(&nd);
335150262Scsjp	vfslocked = NDHASGIANT(&nd);
336108407Srwatson	if (error == 0) {
337108407Srwatson		error = vacl_delete(td, nd.ni_vp, uap->type);
338108407Srwatson		NDFREE(&nd, 0);
339108407Srwatson	}
340150262Scsjp	VFS_UNLOCK_GIANT(vfslocked);
341108407Srwatson	return (error);
342108407Srwatson}
343108407Srwatson
344108407Srwatson/*
34554803Srwatson * Given a file path, delete an ACL from it.
34654803Srwatson */
34754803Srwatsonint
34885582Srwatson__acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap)
34954803Srwatson{
35054803Srwatson	struct file *fp;
351150262Scsjp	int vfslocked, error;
35254803Srwatson
353107849Salfred	error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
35482713Sdillon	if (error == 0) {
355150262Scsjp		vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
356116678Sphk		error = vacl_delete(td, fp->f_vnode, uap->type);
35789306Salfred		fdrop(fp, td);
358150262Scsjp		VFS_UNLOCK_GIANT(vfslocked);
35982713Sdillon	}
36054803Srwatson	return (error);
36154803Srwatson}
36254803Srwatson
36354803Srwatson/*
364167211Srwatson * Given a file path, check an ACL for it.
36554803Srwatson */
36654803Srwatsonint
36785582Srwatson__acl_aclcheck_file(struct thread *td, struct __acl_aclcheck_file_args *uap)
36854803Srwatson{
36954803Srwatson	struct nameidata	nd;
370150262Scsjp	int vfslocked, error;
37154803Srwatson
372150262Scsjp	NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
37354803Srwatson	error = namei(&nd);
374150262Scsjp	vfslocked = NDHASGIANT(&nd);
37582713Sdillon	if (error == 0) {
376107855Salfred		error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp);
37782713Sdillon		NDFREE(&nd, 0);
37882713Sdillon	}
379150262Scsjp	VFS_UNLOCK_GIANT(vfslocked);
38054803Srwatson	return (error);
38154803Srwatson}
38254803Srwatson
38354803Srwatson/*
384108407Srwatson * Given a file path, check an ACL for it; don't follow links.
385108407Srwatson */
386108407Srwatsonint
387108407Srwatson__acl_aclcheck_link(struct thread *td, struct __acl_aclcheck_link_args *uap)
388108407Srwatson{
389108407Srwatson	struct nameidata	nd;
390150262Scsjp	int vfslocked, error;
391108407Srwatson
392150262Scsjp	NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
393108407Srwatson	error = namei(&nd);
394150262Scsjp	vfslocked = NDHASGIANT(&nd);
395108407Srwatson	if (error == 0) {
396108407Srwatson		error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp);
397108407Srwatson		NDFREE(&nd, 0);
398108407Srwatson	}
399150262Scsjp	VFS_UNLOCK_GIANT(vfslocked);
400108407Srwatson	return (error);
401108407Srwatson}
402108407Srwatson
403108407Srwatson/*
404167211Srwatson * Given a file descriptor, check an ACL for it.
40554803Srwatson */
40654803Srwatsonint
40785582Srwatson__acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap)
40854803Srwatson{
40954803Srwatson	struct file *fp;
410150262Scsjp	int vfslocked, error;
41154803Srwatson
412107849Salfred	error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
41382713Sdillon	if (error == 0) {
414150262Scsjp		vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
415116678Sphk		error = vacl_aclcheck(td, fp->f_vnode, uap->type, uap->aclp);
41689306Salfred		fdrop(fp, td);
417150262Scsjp		VFS_UNLOCK_GIANT(vfslocked);
41882713Sdillon	}
41982713Sdillon	return (error);
42054803Srwatson}
421149811Scsjp
422149811Scsjp/* ARGUSED */
423149811Scsjp
424149811Scsjpstatic void
425149811Scsjpaclinit(void *dummy __unused)
426149811Scsjp{
427149811Scsjp
428149811Scsjp	acl_zone = uma_zcreate("ACL UMA zone", sizeof(struct acl),
429149811Scsjp	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
430149811Scsjp}
431149811ScsjpSYSINIT(acls, SI_SUB_ACL, SI_ORDER_FIRST, aclinit, NULL)
432