vfs_acl.c revision 177785
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 177785 2008-03-31 12:01:21Z kib $");
37116182Sobrien
38101122Srwatson#include "opt_mac.h"
39101122Srwatson
4054803Srwatson#include <sys/param.h>
4154803Srwatson#include <sys/systm.h>
4254803Srwatson#include <sys/sysproto.h>
43177785Skib#include <sys/fcntl.h>
4454803Srwatson#include <sys/kernel.h>
4554803Srwatson#include <sys/malloc.h>
46150262Scsjp#include <sys/mount.h>
4754803Srwatson#include <sys/vnode.h>
4854803Srwatson#include <sys/lock.h>
4982713Sdillon#include <sys/mutex.h>
5054803Srwatson#include <sys/namei.h>
5154803Srwatson#include <sys/file.h>
52108524Salfred#include <sys/filedesc.h>
5354803Srwatson#include <sys/proc.h>
5454803Srwatson#include <sys/sysent.h>
5554803Srwatson#include <sys/acl.h>
5654803Srwatson
57163606Srwatson#include <security/mac/mac_framework.h>
58163606Srwatson
59149811Scsjp#include <vm/uma.h>
6054803Srwatson
61149811Scsjpuma_zone_t	acl_zone;
6298927Srwatsonstatic int	vacl_set_acl(struct thread *td, struct vnode *vp,
6398927Srwatson		    acl_type_t type, struct acl *aclp);
6498927Srwatsonstatic int	vacl_get_acl(struct thread *td, struct vnode *vp,
6598927Srwatson		    acl_type_t type, struct acl *aclp);
6685582Srwatsonstatic int	vacl_aclcheck(struct thread *td, struct vnode *vp,
6798927Srwatson		    acl_type_t type, struct acl *aclp);
6854803Srwatson
6954803Srwatson/*
70165983Srwatson * These calls wrap the real vnode operations, and are called by the syscall
71165983Srwatson * code once the syscall has converted the path or file descriptor to a vnode
72165983Srwatson * (unlocked).  The aclp pointer is assumed still to point to userland, so
73165983Srwatson * this should not be consumed within the kernel except by syscall code.
74165983Srwatson * Other code should directly invoke VOP_{SET,GET}ACL.
7554803Srwatson */
7654803Srwatson
7754803Srwatson/*
7854803Srwatson * Given a vnode, set its ACL.
7954803Srwatson */
8054803Srwatsonstatic int
8185582Srwatsonvacl_set_acl(struct thread *td, struct vnode *vp, acl_type_t type,
8256272Srwatson    struct acl *aclp)
8354803Srwatson{
8454803Srwatson	struct acl inkernacl;
8590202Srwatson	struct mount *mp;
8654803Srwatson	int error;
8754803Srwatson
8854803Srwatson	error = copyin(aclp, &inkernacl, sizeof(struct acl));
8954803Srwatson	if (error)
9054803Srwatson		return(error);
9190202Srwatson	error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
9290202Srwatson	if (error != 0)
9390202Srwatson		return (error);
9491406Sjhb	VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
95175202Sattilio	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
96101122Srwatson#ifdef MAC
97172930Srwatson	error = mac_vnode_check_setacl(td->td_ucred, vp, type, &inkernacl);
98101122Srwatson	if (error != 0)
99101122Srwatson		goto out;
100101122Srwatson#endif
10191406Sjhb	error = VOP_SETACL(vp, type, &inkernacl, td->td_ucred, td);
102101122Srwatson#ifdef MAC
103101122Srwatsonout:
104101122Srwatson#endif
105175294Sattilio	VOP_UNLOCK(vp, 0);
10690202Srwatson	vn_finished_write(mp);
10771699Sjhb	return(error);
10854803Srwatson}
10954803Srwatson
11054803Srwatson/*
11154803Srwatson * Given a vnode, get its ACL.
11254803Srwatson */
11354803Srwatsonstatic int
11485582Srwatsonvacl_get_acl(struct thread *td, struct vnode *vp, acl_type_t type,
11554803Srwatson    struct acl *aclp)
11654803Srwatson{
11754803Srwatson	struct acl inkernelacl;
11854803Srwatson	int error;
11954803Srwatson
12091406Sjhb	VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
121175202Sattilio	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
122101122Srwatson#ifdef MAC
123172930Srwatson	error = mac_vnode_check_getacl(td->td_ucred, vp, type);
124101122Srwatson	if (error != 0)
125101122Srwatson		goto out;
126101122Srwatson#endif
12791406Sjhb	error = VOP_GETACL(vp, type, &inkernelacl, td->td_ucred, td);
128101122Srwatson#ifdef MAC
129101122Srwatsonout:
130101122Srwatson#endif
131175294Sattilio	VOP_UNLOCK(vp, 0);
13254803Srwatson	if (error == 0)
13354803Srwatson		error = copyout(&inkernelacl, aclp, sizeof(struct acl));
13454803Srwatson	return (error);
13554803Srwatson}
13654803Srwatson
13754803Srwatson/*
13854803Srwatson * Given a vnode, delete its ACL.
13954803Srwatson */
14054803Srwatsonstatic int
14185582Srwatsonvacl_delete(struct thread *td, struct vnode *vp, acl_type_t type)
14254803Srwatson{
14390202Srwatson	struct mount *mp;
14454803Srwatson	int error;
14554803Srwatson
14690202Srwatson	error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
14790202Srwatson	if (error)
14890202Srwatson		return (error);
14991406Sjhb	VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
150175202Sattilio	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
151101122Srwatson#ifdef MAC
152172930Srwatson	error = mac_vnode_check_deleteacl(td->td_ucred, vp, type);
153101122Srwatson	if (error)
154101122Srwatson		goto out;
155101122Srwatson#endif
156101122Srwatson	error = VOP_SETACL(vp, type, 0, td->td_ucred, td);
157101122Srwatson#ifdef MAC
158101122Srwatsonout:
159101122Srwatson#endif
160175294Sattilio	VOP_UNLOCK(vp, 0);
16190202Srwatson	vn_finished_write(mp);
16254803Srwatson	return (error);
16354803Srwatson}
16454803Srwatson
16554803Srwatson/*
16654803Srwatson * Given a vnode, check whether an ACL is appropriate for it
16754803Srwatson */
16854803Srwatsonstatic int
16985582Srwatsonvacl_aclcheck(struct thread *td, struct vnode *vp, acl_type_t type,
17054803Srwatson    struct acl *aclp)
17154803Srwatson{
17254803Srwatson	struct acl inkernelacl;
17354803Srwatson	int error;
17454803Srwatson
17554803Srwatson	error = copyin(aclp, &inkernelacl, sizeof(struct acl));
17654803Srwatson	if (error)
17754803Srwatson		return(error);
17891406Sjhb	error = VOP_ACLCHECK(vp, type, &inkernelacl, td->td_ucred, td);
17954803Srwatson	return (error);
18054803Srwatson}
18154803Srwatson
18254803Srwatson/*
183165983Srwatson * syscalls -- convert the path/fd to a vnode, and call vacl_whatever.  Don't
184165983Srwatson * need to lock, as the vacl_ code will get/release any locks required.
18554803Srwatson */
18654803Srwatson
18754803Srwatson/*
18854803Srwatson * Given a file path, get an ACL for it
18954803Srwatson */
19054803Srwatsonint
19185582Srwatson__acl_get_file(struct thread *td, struct __acl_get_file_args *uap)
19254803Srwatson{
19354803Srwatson	struct nameidata nd;
194150262Scsjp	int vfslocked, error;
19554803Srwatson
196150262Scsjp	NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
19754803Srwatson	error = namei(&nd);
198150262Scsjp	vfslocked = NDHASGIANT(&nd);
19982713Sdillon	if (error == 0) {
200107855Salfred		error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp);
20182713Sdillon		NDFREE(&nd, 0);
20282713Sdillon	}
203150262Scsjp	VFS_UNLOCK_GIANT(vfslocked);
20454803Srwatson	return (error);
20554803Srwatson}
20654803Srwatson
20754803Srwatson/*
208108407Srwatson * Given a file path, get an ACL for it; don't follow links.
209108407Srwatson */
210108407Srwatsonint
211108407Srwatson__acl_get_link(struct thread *td, struct __acl_get_link_args *uap)
212108407Srwatson{
213108407Srwatson	struct nameidata nd;
214150262Scsjp	int vfslocked, error;
215108407Srwatson
216150262Scsjp	NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
217108407Srwatson	error = namei(&nd);
218150262Scsjp	vfslocked = NDHASGIANT(&nd);
219108407Srwatson	if (error == 0) {
220108407Srwatson		error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp);
221108407Srwatson		NDFREE(&nd, 0);
222108407Srwatson	}
223150262Scsjp	VFS_UNLOCK_GIANT(vfslocked);
224108407Srwatson	return (error);
225108407Srwatson}
226108407Srwatson
227108407Srwatson/*
228167211Srwatson * Given a file path, set an ACL for it.
22954803Srwatson */
23054803Srwatsonint
23185582Srwatson__acl_set_file(struct thread *td, struct __acl_set_file_args *uap)
23254803Srwatson{
23354803Srwatson	struct nameidata nd;
234150262Scsjp	int vfslocked, error;
23554803Srwatson
236150262Scsjp	NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
23754803Srwatson	error = namei(&nd);
238150262Scsjp	vfslocked = NDHASGIANT(&nd);
23982713Sdillon	if (error == 0) {
240107855Salfred		error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp);
24182713Sdillon		NDFREE(&nd, 0);
24282713Sdillon	}
243150262Scsjp	VFS_UNLOCK_GIANT(vfslocked);
24454803Srwatson	return (error);
24554803Srwatson}
24654803Srwatson
24754803Srwatson/*
248108407Srwatson * Given a file path, set an ACL for it; don't follow links.
249108407Srwatson */
250108407Srwatsonint
251108407Srwatson__acl_set_link(struct thread *td, struct __acl_set_link_args *uap)
252108407Srwatson{
253108407Srwatson	struct nameidata nd;
254150262Scsjp	int vfslocked, error;
255108407Srwatson
256150262Scsjp	NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
257108407Srwatson	error = namei(&nd);
258150262Scsjp	vfslocked = NDHASGIANT(&nd);
259108407Srwatson	if (error == 0) {
260108407Srwatson		error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp);
261108407Srwatson		NDFREE(&nd, 0);
262108407Srwatson	}
263150262Scsjp	VFS_UNLOCK_GIANT(vfslocked);
264108407Srwatson	return (error);
265108407Srwatson}
266108407Srwatson
267108407Srwatson/*
268167234Srwatson * Given a file descriptor, get an ACL for it.
26954803Srwatson */
27054803Srwatsonint
27185582Srwatson__acl_get_fd(struct thread *td, struct __acl_get_fd_args *uap)
27254803Srwatson{
27354803Srwatson	struct file *fp;
274150262Scsjp	int vfslocked, error;
27554803Srwatson
276107849Salfred	error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
27782713Sdillon	if (error == 0) {
278150262Scsjp		vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
279116678Sphk		error = vacl_get_acl(td, fp->f_vnode, uap->type, uap->aclp);
28089306Salfred		fdrop(fp, td);
281150262Scsjp		VFS_UNLOCK_GIANT(vfslocked);
28282713Sdillon	}
28382713Sdillon	return (error);
28454803Srwatson}
28554803Srwatson
28654803Srwatson/*
287167234Srwatson * Given a file descriptor, set an ACL for it.
28854803Srwatson */
28954803Srwatsonint
29085582Srwatson__acl_set_fd(struct thread *td, struct __acl_set_fd_args *uap)
29154803Srwatson{
29254803Srwatson	struct file *fp;
293150262Scsjp	int vfslocked, error;
29454803Srwatson
295107849Salfred	error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
29682713Sdillon	if (error == 0) {
297150262Scsjp		vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
298116678Sphk		error = vacl_set_acl(td, fp->f_vnode, uap->type, uap->aclp);
29989306Salfred		fdrop(fp, td);
300150262Scsjp		VFS_UNLOCK_GIANT(vfslocked);
30182713Sdillon	}
30282713Sdillon	return (error);
30354803Srwatson}
30454803Srwatson
30554803Srwatson/*
30654803Srwatson * Given a file path, delete an ACL from it.
30754803Srwatson */
30854803Srwatsonint
30985582Srwatson__acl_delete_file(struct thread *td, struct __acl_delete_file_args *uap)
31054803Srwatson{
31154803Srwatson	struct nameidata nd;
312150262Scsjp	int vfslocked, error;
31354803Srwatson
314150262Scsjp	NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
31554803Srwatson	error = namei(&nd);
316150262Scsjp	vfslocked = NDHASGIANT(&nd);
31782713Sdillon	if (error == 0) {
318107849Salfred		error = vacl_delete(td, nd.ni_vp, uap->type);
31982713Sdillon		NDFREE(&nd, 0);
32082713Sdillon	}
321150262Scsjp	VFS_UNLOCK_GIANT(vfslocked);
32254803Srwatson	return (error);
32354803Srwatson}
32454803Srwatson
32554803Srwatson/*
326108407Srwatson * Given a file path, delete an ACL from it; don't follow links.
327108407Srwatson */
328108407Srwatsonint
329108407Srwatson__acl_delete_link(struct thread *td, struct __acl_delete_link_args *uap)
330108407Srwatson{
331108407Srwatson	struct nameidata nd;
332150262Scsjp	int vfslocked, error;
333108407Srwatson
334150262Scsjp	NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
335108407Srwatson	error = namei(&nd);
336150262Scsjp	vfslocked = NDHASGIANT(&nd);
337108407Srwatson	if (error == 0) {
338108407Srwatson		error = vacl_delete(td, nd.ni_vp, uap->type);
339108407Srwatson		NDFREE(&nd, 0);
340108407Srwatson	}
341150262Scsjp	VFS_UNLOCK_GIANT(vfslocked);
342108407Srwatson	return (error);
343108407Srwatson}
344108407Srwatson
345108407Srwatson/*
34654803Srwatson * Given a file path, delete an ACL from it.
34754803Srwatson */
34854803Srwatsonint
34985582Srwatson__acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap)
35054803Srwatson{
35154803Srwatson	struct file *fp;
352150262Scsjp	int vfslocked, error;
35354803Srwatson
354107849Salfred	error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
35582713Sdillon	if (error == 0) {
356150262Scsjp		vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
357116678Sphk		error = vacl_delete(td, fp->f_vnode, uap->type);
35889306Salfred		fdrop(fp, td);
359150262Scsjp		VFS_UNLOCK_GIANT(vfslocked);
36082713Sdillon	}
36154803Srwatson	return (error);
36254803Srwatson}
36354803Srwatson
36454803Srwatson/*
365167211Srwatson * Given a file path, check an ACL for it.
36654803Srwatson */
36754803Srwatsonint
36885582Srwatson__acl_aclcheck_file(struct thread *td, struct __acl_aclcheck_file_args *uap)
36954803Srwatson{
37054803Srwatson	struct nameidata	nd;
371150262Scsjp	int vfslocked, error;
37254803Srwatson
373150262Scsjp	NDINIT(&nd, LOOKUP, MPSAFE|FOLLOW, UIO_USERSPACE, uap->path, td);
37454803Srwatson	error = namei(&nd);
375150262Scsjp	vfslocked = NDHASGIANT(&nd);
37682713Sdillon	if (error == 0) {
377107855Salfred		error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp);
37882713Sdillon		NDFREE(&nd, 0);
37982713Sdillon	}
380150262Scsjp	VFS_UNLOCK_GIANT(vfslocked);
38154803Srwatson	return (error);
38254803Srwatson}
38354803Srwatson
38454803Srwatson/*
385108407Srwatson * Given a file path, check an ACL for it; don't follow links.
386108407Srwatson */
387108407Srwatsonint
388108407Srwatson__acl_aclcheck_link(struct thread *td, struct __acl_aclcheck_link_args *uap)
389108407Srwatson{
390108407Srwatson	struct nameidata	nd;
391150262Scsjp	int vfslocked, error;
392108407Srwatson
393150262Scsjp	NDINIT(&nd, LOOKUP, MPSAFE|NOFOLLOW, UIO_USERSPACE, uap->path, td);
394108407Srwatson	error = namei(&nd);
395150262Scsjp	vfslocked = NDHASGIANT(&nd);
396108407Srwatson	if (error == 0) {
397108407Srwatson		error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp);
398108407Srwatson		NDFREE(&nd, 0);
399108407Srwatson	}
400150262Scsjp	VFS_UNLOCK_GIANT(vfslocked);
401108407Srwatson	return (error);
402108407Srwatson}
403108407Srwatson
404108407Srwatson/*
405167211Srwatson * Given a file descriptor, check an ACL for it.
40654803Srwatson */
40754803Srwatsonint
40885582Srwatson__acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap)
40954803Srwatson{
41054803Srwatson	struct file *fp;
411150262Scsjp	int vfslocked, error;
41254803Srwatson
413107849Salfred	error = getvnode(td->td_proc->p_fd, uap->filedes, &fp);
41482713Sdillon	if (error == 0) {
415150262Scsjp		vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
416116678Sphk		error = vacl_aclcheck(td, fp->f_vnode, uap->type, uap->aclp);
41789306Salfred		fdrop(fp, td);
418150262Scsjp		VFS_UNLOCK_GIANT(vfslocked);
41982713Sdillon	}
42082713Sdillon	return (error);
42154803Srwatson}
422149811Scsjp
423149811Scsjp/* ARGUSED */
424149811Scsjp
425149811Scsjpstatic void
426149811Scsjpaclinit(void *dummy __unused)
427149811Scsjp{
428149811Scsjp
429149811Scsjp	acl_zone = uma_zcreate("ACL UMA zone", sizeof(struct acl),
430149811Scsjp	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
431149811Scsjp}
432177253SrwatsonSYSINIT(acls, SI_SUB_ACL, SI_ORDER_FIRST, aclinit, NULL);
433