Changeset View
Changeset View
Standalone View
Standalone View
head/sys/kern/vfs_acl.c
Show First 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | |||||
#include <security/audit/audit.h> | #include <security/audit/audit.h> | ||||
#include <security/mac/mac_framework.h> | #include <security/mac/mac_framework.h> | ||||
CTASSERT(ACL_MAX_ENTRIES >= OLDACL_MAX_ENTRIES); | CTASSERT(ACL_MAX_ENTRIES >= OLDACL_MAX_ENTRIES); | ||||
MALLOC_DEFINE(M_ACL, "acl", "Access Control Lists"); | MALLOC_DEFINE(M_ACL, "acl", "Access Control Lists"); | ||||
static int kern___acl_aclcheck_path(struct thread *td, const char *path, | |||||
acl_type_t type, struct acl *aclp, int follow); | |||||
static int kern___acl_delete_path(struct thread *td, const char *path, | |||||
acl_type_t type, int follow); | |||||
static int kern___acl_get_path(struct thread *td, const char *path, | |||||
acl_type_t type, struct acl *aclp, int follow); | |||||
static int kern___acl_set_path(struct thread *td, const char *path, | |||||
acl_type_t type, const struct acl *aclp, int follow); | |||||
static int vacl_set_acl(struct thread *td, struct vnode *vp, | static int vacl_set_acl(struct thread *td, struct vnode *vp, | ||||
acl_type_t type, struct acl *aclp); | acl_type_t type, const struct acl *aclp); | ||||
static int vacl_get_acl(struct thread *td, struct vnode *vp, | static int vacl_get_acl(struct thread *td, struct vnode *vp, | ||||
acl_type_t type, struct acl *aclp); | acl_type_t type, struct acl *aclp); | ||||
static int vacl_aclcheck(struct thread *td, struct vnode *vp, | static int vacl_aclcheck(struct thread *td, struct vnode *vp, | ||||
acl_type_t type, struct acl *aclp); | acl_type_t type, const struct acl *aclp); | ||||
int | int | ||||
acl_copy_oldacl_into_acl(const struct oldacl *source, struct acl *dest) | acl_copy_oldacl_into_acl(const struct oldacl *source, struct acl *dest) | ||||
{ | { | ||||
int i; | int i; | ||||
if (source->acl_cnt < 0 || source->acl_cnt > OLDACL_MAX_ENTRIES) | if (source->acl_cnt < 0 || source->acl_cnt > OLDACL_MAX_ENTRIES) | ||||
return (EINVAL); | return (EINVAL); | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | |||||
* either ACL_TYPE_ACCESS_OLD or ACL_TYPE_DEFAULT_OLD (which previously were | * either ACL_TYPE_ACCESS_OLD or ACL_TYPE_DEFAULT_OLD (which previously were | ||||
* known as ACL_TYPE_ACCESS and ACL_TYPE_DEFAULT), then it's the "struct | * known as ACL_TYPE_ACCESS and ACL_TYPE_DEFAULT), then it's the "struct | ||||
* oldacl". If it's something else, then it's the new "struct acl". In the | * oldacl". If it's something else, then it's the new "struct acl". In the | ||||
* latter case, the routines below just copyin/copyout the contents. In the | * latter case, the routines below just copyin/copyout the contents. In the | ||||
* former case, they copyin the "struct oldacl" and convert it to the new | * former case, they copyin the "struct oldacl" and convert it to the new | ||||
* format. | * format. | ||||
*/ | */ | ||||
static int | static int | ||||
acl_copyin(void *user_acl, struct acl *kernel_acl, acl_type_t type) | acl_copyin(const void *user_acl, struct acl *kernel_acl, acl_type_t type) | ||||
{ | { | ||||
int error; | int error; | ||||
struct oldacl old; | struct oldacl old; | ||||
switch (type) { | switch (type) { | ||||
case ACL_TYPE_ACCESS_OLD: | case ACL_TYPE_ACCESS_OLD: | ||||
case ACL_TYPE_DEFAULT_OLD: | case ACL_TYPE_DEFAULT_OLD: | ||||
error = copyin(user_acl, &old, sizeof(old)); | error = copyin(user_acl, &old, sizeof(old)); | ||||
if (error != 0) | if (error != 0) | ||||
break; | break; | ||||
acl_copy_oldacl_into_acl(&old, kernel_acl); | acl_copy_oldacl_into_acl(&old, kernel_acl); | ||||
break; | break; | ||||
default: | default: | ||||
error = copyin(user_acl, kernel_acl, sizeof(*kernel_acl)); | error = copyin(user_acl, kernel_acl, sizeof(*kernel_acl)); | ||||
if (kernel_acl->acl_maxcnt != ACL_MAX_ENTRIES) | if (kernel_acl->acl_maxcnt != ACL_MAX_ENTRIES) | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
static int | static int | ||||
acl_copyout(struct acl *kernel_acl, void *user_acl, acl_type_t type) | acl_copyout(const struct acl *kernel_acl, void *user_acl, acl_type_t type) | ||||
{ | { | ||||
uint32_t am; | uint32_t am; | ||||
int error; | int error; | ||||
struct oldacl old; | struct oldacl old; | ||||
switch (type) { | switch (type) { | ||||
case ACL_TYPE_ACCESS_OLD: | case ACL_TYPE_ACCESS_OLD: | ||||
case ACL_TYPE_DEFAULT_OLD: | case ACL_TYPE_DEFAULT_OLD: | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | |||||
* Other code should directly invoke VOP_{SET,GET}ACL. | * Other code should directly invoke VOP_{SET,GET}ACL. | ||||
*/ | */ | ||||
/* | /* | ||||
* Given a vnode, set its ACL. | * Given a vnode, set its ACL. | ||||
*/ | */ | ||||
static int | static int | ||||
vacl_set_acl(struct thread *td, struct vnode *vp, acl_type_t type, | vacl_set_acl(struct thread *td, struct vnode *vp, acl_type_t type, | ||||
struct acl *aclp) | const struct acl *aclp) | ||||
{ | { | ||||
struct acl *inkernelacl; | struct acl *inkernelacl; | ||||
struct mount *mp; | struct mount *mp; | ||||
int error; | int error; | ||||
AUDIT_ARG_VALUE(type); | AUDIT_ARG_VALUE(type); | ||||
inkernelacl = acl_alloc(M_WAITOK); | inkernelacl = acl_alloc(M_WAITOK); | ||||
error = acl_copyin(aclp, inkernelacl, type); | error = acl_copyin(aclp, inkernelacl, type); | ||||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Given a vnode, check whether an ACL is appropriate for it | * Given a vnode, check whether an ACL is appropriate for it | ||||
* | * | ||||
* XXXRW: No vnode lock held so can't audit vnode state...? | * XXXRW: No vnode lock held so can't audit vnode state...? | ||||
*/ | */ | ||||
static int | static int | ||||
vacl_aclcheck(struct thread *td, struct vnode *vp, acl_type_t type, | vacl_aclcheck(struct thread *td, struct vnode *vp, acl_type_t type, | ||||
struct acl *aclp) | const struct acl *aclp) | ||||
{ | { | ||||
struct acl *inkernelacl; | struct acl *inkernelacl; | ||||
int error; | int error; | ||||
inkernelacl = acl_alloc(M_WAITOK); | inkernelacl = acl_alloc(M_WAITOK); | ||||
error = acl_copyin(aclp, inkernelacl, type); | error = acl_copyin(aclp, inkernelacl, type); | ||||
if (error != 0) | if (error != 0) | ||||
goto out; | goto out; | ||||
Show All 10 Lines | |||||
*/ | */ | ||||
/* | /* | ||||
* Given a file path, get an ACL for it | * Given a file path, get an ACL for it | ||||
*/ | */ | ||||
int | int | ||||
sys___acl_get_file(struct thread *td, struct __acl_get_file_args *uap) | sys___acl_get_file(struct thread *td, struct __acl_get_file_args *uap) | ||||
{ | { | ||||
struct nameidata nd; | |||||
int error; | |||||
NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path, | return (kern___acl_get_path(td, uap->path, uap->type, uap->aclp, | ||||
td); | FOLLOW)); | ||||
error = namei(&nd); | |||||
if (error == 0) { | |||||
error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp); | |||||
NDFREE(&nd, 0); | |||||
} | } | ||||
return (error); | |||||
} | |||||
/* | /* | ||||
* Given a file path, get an ACL for it; don't follow links. | * Given a file path, get an ACL for it; don't follow links. | ||||
*/ | */ | ||||
int | int | ||||
sys___acl_get_link(struct thread *td, struct __acl_get_link_args *uap) | sys___acl_get_link(struct thread *td, struct __acl_get_link_args *uap) | ||||
{ | { | ||||
return(kern___acl_get_path(td, uap->path, uap->type, uap->aclp, | |||||
NOFOLLOW)); | |||||
} | |||||
static int | |||||
kern___acl_get_path(struct thread *td, const char *path, acl_type_t type, | |||||
struct acl *aclp, int follow) | |||||
{ | |||||
struct nameidata nd; | struct nameidata nd; | ||||
int error; | int error; | ||||
NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path, | NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, UIO_USERSPACE, path, td); | ||||
td); | |||||
error = namei(&nd); | error = namei(&nd); | ||||
if (error == 0) { | if (error == 0) { | ||||
error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp); | error = vacl_get_acl(td, nd.ni_vp, type, aclp); | ||||
NDFREE(&nd, 0); | NDFREE(&nd, 0); | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Given a file path, set an ACL for it. | * Given a file path, set an ACL for it. | ||||
*/ | */ | ||||
int | int | ||||
sys___acl_set_file(struct thread *td, struct __acl_set_file_args *uap) | sys___acl_set_file(struct thread *td, struct __acl_set_file_args *uap) | ||||
{ | { | ||||
struct nameidata nd; | |||||
int error; | |||||
NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path, | return(kern___acl_set_path(td, uap->path, uap->type, uap->aclp, | ||||
td); | FOLLOW)); | ||||
error = namei(&nd); | |||||
if (error == 0) { | |||||
error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp); | |||||
NDFREE(&nd, 0); | |||||
} | } | ||||
return (error); | |||||
} | |||||
/* | /* | ||||
* Given a file path, set an ACL for it; don't follow links. | * Given a file path, set an ACL for it; don't follow links. | ||||
*/ | */ | ||||
int | int | ||||
sys___acl_set_link(struct thread *td, struct __acl_set_link_args *uap) | sys___acl_set_link(struct thread *td, struct __acl_set_link_args *uap) | ||||
{ | { | ||||
return(kern___acl_set_path(td, uap->path, uap->type, uap->aclp, | |||||
NOFOLLOW)); | |||||
} | |||||
static int | |||||
kern___acl_set_path(struct thread *td, const char *path, | |||||
acl_type_t type, const struct acl *aclp, int follow) | |||||
{ | |||||
struct nameidata nd; | struct nameidata nd; | ||||
int error; | int error; | ||||
NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path, | NDINIT(&nd, LOOKUP, follow | AUDITVNODE1, UIO_USERSPACE, path, td); | ||||
td); | |||||
error = namei(&nd); | error = namei(&nd); | ||||
if (error == 0) { | if (error == 0) { | ||||
error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp); | error = vacl_set_acl(td, nd.ni_vp, type, aclp); | ||||
NDFREE(&nd, 0); | NDFREE(&nd, 0); | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Given a file descriptor, get an ACL for it. | * Given a file descriptor, get an ACL for it. | ||||
*/ | */ | ||||
Show All 35 Lines | |||||
} | } | ||||
/* | /* | ||||
* Given a file path, delete an ACL from it. | * Given a file path, delete an ACL from it. | ||||
*/ | */ | ||||
int | int | ||||
sys___acl_delete_file(struct thread *td, struct __acl_delete_file_args *uap) | sys___acl_delete_file(struct thread *td, struct __acl_delete_file_args *uap) | ||||
{ | { | ||||
struct nameidata nd; | |||||
int error; | |||||
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td); | return (kern___acl_delete_path(td, uap->path, uap->type, FOLLOW)); | ||||
error = namei(&nd); | |||||
if (error == 0) { | |||||
error = vacl_delete(td, nd.ni_vp, uap->type); | |||||
NDFREE(&nd, 0); | |||||
} | } | ||||
return (error); | |||||
} | |||||
/* | /* | ||||
* Given a file path, delete an ACL from it; don't follow links. | * Given a file path, delete an ACL from it; don't follow links. | ||||
*/ | */ | ||||
int | int | ||||
sys___acl_delete_link(struct thread *td, struct __acl_delete_link_args *uap) | sys___acl_delete_link(struct thread *td, struct __acl_delete_link_args *uap) | ||||
{ | { | ||||
return (kern___acl_delete_path(td, uap->path, uap->type, NOFOLLOW)); | |||||
} | |||||
static int | |||||
kern___acl_delete_path(struct thread *td, const char *path, | |||||
acl_type_t type, int follow) | |||||
{ | |||||
struct nameidata nd; | struct nameidata nd; | ||||
int error; | int error; | ||||
NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td); | NDINIT(&nd, LOOKUP, follow, UIO_USERSPACE, path, td); | ||||
error = namei(&nd); | error = namei(&nd); | ||||
if (error == 0) { | if (error == 0) { | ||||
error = vacl_delete(td, nd.ni_vp, uap->type); | error = vacl_delete(td, nd.ni_vp, type); | ||||
NDFREE(&nd, 0); | NDFREE(&nd, 0); | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Given a file path, delete an ACL from it. | * Given a file path, delete an ACL from it. | ||||
*/ | */ | ||||
Show All 15 Lines | |||||
} | } | ||||
/* | /* | ||||
* Given a file path, check an ACL for it. | * Given a file path, check an ACL for it. | ||||
*/ | */ | ||||
int | int | ||||
sys___acl_aclcheck_file(struct thread *td, struct __acl_aclcheck_file_args *uap) | sys___acl_aclcheck_file(struct thread *td, struct __acl_aclcheck_file_args *uap) | ||||
{ | { | ||||
struct nameidata nd; | |||||
int error; | |||||
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td); | return (kern___acl_aclcheck_path(td, uap->path, uap->type, uap->aclp, | ||||
error = namei(&nd); | FOLLOW)); | ||||
if (error == 0) { | |||||
error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp); | |||||
NDFREE(&nd, 0); | |||||
} | } | ||||
return (error); | |||||
} | |||||
/* | /* | ||||
* Given a file path, check an ACL for it; don't follow links. | * Given a file path, check an ACL for it; don't follow links. | ||||
*/ | */ | ||||
int | int | ||||
sys___acl_aclcheck_link(struct thread *td, struct __acl_aclcheck_link_args *uap) | sys___acl_aclcheck_link(struct thread *td, struct __acl_aclcheck_link_args *uap) | ||||
{ | { | ||||
return (kern___acl_aclcheck_path(td, uap->path, uap->type, uap->aclp, | |||||
NOFOLLOW)); | |||||
} | |||||
static int | |||||
kern___acl_aclcheck_path(struct thread *td, const char *path, acl_type_t type, | |||||
struct acl *aclp, int follow) | |||||
{ | |||||
struct nameidata nd; | struct nameidata nd; | ||||
int error; | int error; | ||||
NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td); | NDINIT(&nd, LOOKUP, follow, UIO_USERSPACE, path, td); | ||||
error = namei(&nd); | error = namei(&nd); | ||||
if (error == 0) { | if (error == 0) { | ||||
error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp); | error = vacl_aclcheck(td, nd.ni_vp, type, aclp); | ||||
NDFREE(&nd, 0); | NDFREE(&nd, 0); | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Given a file descriptor, check an ACL for it. | * Given a file descriptor, check an ACL for it. | ||||
*/ | */ | ||||
Show All 37 Lines |