diff options
Diffstat (limited to 'sys')
50 files changed, 1802 insertions, 23 deletions
diff --git a/sys/coda/coda_vfsops.c b/sys/coda/coda_vfsops.c index 04cf95b..7450c97 100644 --- a/sys/coda/coda_vfsops.c +++ b/sys/coda/coda_vfsops.c @@ -534,7 +534,9 @@ struct vfsops coda_vfsops = { vfs_stdfhtovp, vfs_stdcheckexp, vfs_stdvptofh, - vfs_stdinit + vfs_stdinit, + vfs_stduninit, + vfs_stdextattrctl, }; VFS_SET(coda_vfsops, coda, VFCF_NETWORK); diff --git a/sys/conf/files b/sys/conf/files index f915d1d..8766d9a 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -329,6 +329,7 @@ kern/kern_linker.c standard kern/link_aout.c standard kern/link_elf.c standard kern/kern_acct.c standard +kern/kern_acl.c standard kern/kern_clock.c standard kern/kern_conf.c standard kern/kern_descrip.c standard diff --git a/sys/fs/cd9660/cd9660_vfsops.c b/sys/fs/cd9660/cd9660_vfsops.c index 3ecdb06..01690a4 100644 --- a/sys/fs/cd9660/cd9660_vfsops.c +++ b/sys/fs/cd9660/cd9660_vfsops.c @@ -88,6 +88,8 @@ static struct vfsops cd9660_vfsops = { cd9660_checkexp, cd9660_vptofh, cd9660_init, + vfs_stduninit, + vfs_stdextattrctl, }; VFS_SET(cd9660_vfsops, cd9660, VFCF_READONLY); diff --git a/sys/fs/coda/coda_vfsops.c b/sys/fs/coda/coda_vfsops.c index 04cf95b..7450c97 100644 --- a/sys/fs/coda/coda_vfsops.c +++ b/sys/fs/coda/coda_vfsops.c @@ -534,7 +534,9 @@ struct vfsops coda_vfsops = { vfs_stdfhtovp, vfs_stdcheckexp, vfs_stdvptofh, - vfs_stdinit + vfs_stdinit, + vfs_stduninit, + vfs_stdextattrctl, }; VFS_SET(coda_vfsops, coda, VFCF_NETWORK); diff --git a/sys/fs/fdescfs/fdesc_vfsops.c b/sys/fs/fdescfs/fdesc_vfsops.c index a451c18..0105ff7 100644 --- a/sys/fs/fdescfs/fdesc_vfsops.c +++ b/sys/fs/fdescfs/fdesc_vfsops.c @@ -227,6 +227,8 @@ static struct vfsops fdesc_vfsops = { vfs_stdcheckexp, vfs_stdvptofh, fdesc_init, + vfs_stduninit, + vfs_stdextattrctl, }; VFS_SET(fdesc_vfsops, fdesc, VFCF_SYNTHETIC); diff --git a/sys/fs/hpfs/hpfs_vfsops.c b/sys/fs/hpfs/hpfs_vfsops.c index 7e4750f..1a7f85c 100644 --- a/sys/fs/hpfs/hpfs_vfsops.c +++ b/sys/fs/hpfs/hpfs_vfsops.c @@ -738,7 +738,8 @@ static struct vfsops hpfs_vfsops = { hpfs_checkexp, hpfs_vptofh, hpfs_init, - NULL + vfs_stduninit, + vfs_stdextattrctl, }; VFS_SET(hpfs_vfsops, hpfs, 0); #else /* defined(__NetBSD__) */ diff --git a/sys/fs/msdosfs/msdosfs_vfsops.c b/sys/fs/msdosfs/msdosfs_vfsops.c index 3fd65ec..4af4cf3 100644 --- a/sys/fs/msdosfs/msdosfs_vfsops.c +++ b/sys/fs/msdosfs/msdosfs_vfsops.c @@ -986,7 +986,9 @@ static struct vfsops msdosfs_vfsops = { msdosfs_fhtovp, msdosfs_checkexp, msdosfs_vptofh, - msdosfs_init + msdosfs_init, + vfs_stduninit, + vfs_stdextattrctl, }; VFS_SET(msdosfs_vfsops, msdos, 0); diff --git a/sys/fs/ntfs/ntfs_vfsops.c b/sys/fs/ntfs/ntfs_vfsops.c index 6bc0555..d4883be 100644 --- a/sys/fs/ntfs/ntfs_vfsops.c +++ b/sys/fs/ntfs/ntfs_vfsops.c @@ -1008,7 +1008,8 @@ static struct vfsops ntfs_vfsops = { ntfs_checkexp, ntfs_vptofh, ntfs_init, - NULL + vfs_stduninit, + vfs_stdextattrctl, }; VFS_SET(ntfs_vfsops, ntfs, 0); #elif defined(__NetBSD__) diff --git a/sys/fs/nullfs/null_vfsops.c b/sys/fs/nullfs/null_vfsops.c index 1bdc083..cbeadc3 100644 --- a/sys/fs/nullfs/null_vfsops.c +++ b/sys/fs/nullfs/null_vfsops.c @@ -417,6 +417,19 @@ nullfs_vptofh(vp, fhp) return VFS_VPTOFH(NULLVPTOLOWERVP(vp), fhp); } +static int +nullfs_extattrctl(mp, cmd, attrname, arg, p) + struct mount *mp; + int cmd; + char *attrname; + caddr_t arg; + struct proc *p; +{ + return VFS_EXTATTRCTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, attrname, + arg, p); +} + + static struct vfsops null_vfsops = { nullfs_mount, nullfs_start, @@ -430,6 +443,8 @@ static struct vfsops null_vfsops = { nullfs_checkexp, nullfs_vptofh, nullfs_init, + vfs_stduninit, + nullfs_extattrctl, }; VFS_SET(null_vfsops, null, VFCF_LOOPBACK); diff --git a/sys/fs/nwfs/nwfs_vfsops.c b/sys/fs/nwfs/nwfs_vfsops.c index f99bba7..5e7c597 100644 --- a/sys/fs/nwfs/nwfs_vfsops.c +++ b/sys/fs/nwfs/nwfs_vfsops.c @@ -93,7 +93,8 @@ static struct vfsops nwfs_vfsops = { vfs_stdcheckexp, vfs_stdvptofh, /* shouldn't happen */ nwfs_init, - nwfs_uninit + nwfs_uninit, + vfs_stdextattrctl, }; diff --git a/sys/fs/portalfs/portal_vfsops.c b/sys/fs/portalfs/portal_vfsops.c index d750b53..950d383 100644 --- a/sys/fs/portalfs/portal_vfsops.c +++ b/sys/fs/portalfs/portal_vfsops.c @@ -256,6 +256,8 @@ static struct vfsops portal_vfsops = { vfs_stdcheckexp, vfs_stdvptofh, vfs_stdinit, + vfs_stduninit, + vfs_stdextattrctl, }; VFS_SET(portal_vfsops, portal, VFCF_SYNTHETIC); diff --git a/sys/fs/procfs/procfs_vfsops.c b/sys/fs/procfs/procfs_vfsops.c index 0533764..b1d4d43 100644 --- a/sys/fs/procfs/procfs_vfsops.c +++ b/sys/fs/procfs/procfs_vfsops.c @@ -172,6 +172,8 @@ static struct vfsops procfs_vfsops = { vfs_stdcheckexp, vfs_stdvptofh, vfs_stdinit, + vfs_stduninit, + vfs_stdextattrctl, }; VFS_SET(procfs_vfsops, procfs, VFCF_SYNTHETIC); diff --git a/sys/fs/umapfs/umap_vfsops.c b/sys/fs/umapfs/umap_vfsops.c index 48894fe..6e0c0b6 100644 --- a/sys/fs/umapfs/umap_vfsops.c +++ b/sys/fs/umapfs/umap_vfsops.c @@ -75,6 +75,9 @@ static int umapfs_unmount __P((struct mount *mp, int mntflags, static int umapfs_vget __P((struct mount *mp, ino_t ino, struct vnode **vpp)); static int umapfs_vptofh __P((struct vnode *vp, struct fid *fhp)); +static int umapfs_extattrctl __P((struct mount *mp, int cmd, + char *attrname, caddr_t arg, + struct proc *p)); /* * Mount umap layer @@ -430,6 +433,19 @@ umapfs_vptofh(vp, fhp) return (VFS_VPTOFH(UMAPVPTOLOWERVP(vp), fhp)); } +static int +umapfs_extattrctl(mp, cmd, attrname, arg, p) + struct mount *mp; + int cmd; + char *attrname; + caddr_t arg; + struct proc *p; +{ + return (VFS_EXTATTRCTL(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, cmd, attrname, + arg, p)); +} + + static struct vfsops umap_vfsops = { umapfs_mount, umapfs_start, @@ -443,6 +459,8 @@ static struct vfsops umap_vfsops = { umapfs_checkexp, umapfs_vptofh, umapfs_init, + vfs_stduninit, + umapfs_extattrctl, }; VFS_SET(umap_vfsops, umap, VFCF_LOOPBACK); diff --git a/sys/fs/unionfs/union_vfsops.c b/sys/fs/unionfs/union_vfsops.c index f5782fa..8b58e55 100644 --- a/sys/fs/unionfs/union_vfsops.c +++ b/sys/fs/unionfs/union_vfsops.c @@ -502,6 +502,8 @@ static struct vfsops union_vfsops = { vfs_stdcheckexp, vfs_stdvptofh, union_init, + vfs_stduninit, + vfs_stdextattrctl, }; VFS_SET(union_vfsops, union, VFCF_LOOPBACK); diff --git a/sys/gnu/ext2fs/ext2_vfsops.c b/sys/gnu/ext2fs/ext2_vfsops.c index b85dbcc..9053682 100644 --- a/sys/gnu/ext2fs/ext2_vfsops.c +++ b/sys/gnu/ext2fs/ext2_vfsops.c @@ -97,6 +97,8 @@ static struct vfsops ext2fs_vfsops = { ufs_check_export, ext2_vptofh, ext2_init, + vfs_stduninit, + vfs_stdextattrctl, }; VFS_SET(ext2fs_vfsops, ext2fs, 0); diff --git a/sys/gnu/fs/ext2fs/ext2_vfsops.c b/sys/gnu/fs/ext2fs/ext2_vfsops.c index b85dbcc..9053682 100644 --- a/sys/gnu/fs/ext2fs/ext2_vfsops.c +++ b/sys/gnu/fs/ext2fs/ext2_vfsops.c @@ -97,6 +97,8 @@ static struct vfsops ext2fs_vfsops = { ufs_check_export, ext2_vptofh, ext2_init, + vfs_stduninit, + vfs_stdextattrctl, }; VFS_SET(ext2fs_vfsops, ext2fs, 0); diff --git a/sys/isofs/cd9660/cd9660_vfsops.c b/sys/isofs/cd9660/cd9660_vfsops.c index 3ecdb06..01690a4 100644 --- a/sys/isofs/cd9660/cd9660_vfsops.c +++ b/sys/isofs/cd9660/cd9660_vfsops.c @@ -88,6 +88,8 @@ static struct vfsops cd9660_vfsops = { cd9660_checkexp, cd9660_vptofh, cd9660_init, + vfs_stduninit, + vfs_stdextattrctl, }; VFS_SET(cd9660_vfsops, cd9660, VFCF_READONLY); diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c index 5e54940..addde32 100644 --- a/sys/kern/init_sysent.c +++ b/sys/kern/init_sysent.c @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: src/sys/kern/syscalls.master,v 1.67 1999/11/17 21:32:33 brian Exp + * created from FreeBSD: src/sys/kern/syscalls.master,v 1.68 1999/12/19 05:54:46 rwatson Exp */ #include "opt_compat.h" @@ -367,4 +367,16 @@ struct sysent sysent[] = { { 1, (sy_call_t *)sigreturn }, /* 344 = sigreturn */ { 0, (sy_call_t *)nosys }, /* 345 = sigtimedwait */ { 0, (sy_call_t *)nosys }, /* 346 = sigwaitinfo */ + { 3, (sy_call_t *)acl_syscall_get_file }, /* 347 = acl_syscall_get_file */ + { 3, (sy_call_t *)acl_syscall_set_file }, /* 348 = acl_syscall_set_file */ + { 3, (sy_call_t *)acl_syscall_get_fd }, /* 349 = acl_syscall_get_fd */ + { 3, (sy_call_t *)acl_syscall_set_fd }, /* 350 = acl_syscall_set_fd */ + { 2, (sy_call_t *)acl_syscall_delete_file }, /* 351 = acl_syscall_delete_file */ + { 2, (sy_call_t *)acl_syscall_delete_fd }, /* 352 = acl_syscall_delete_fd */ + { 3, (sy_call_t *)acl_syscall_aclcheck_file }, /* 353 = acl_syscall_aclcheck_file */ + { 3, (sy_call_t *)acl_syscall_aclcheck_fd }, /* 354 = acl_syscall_aclcheck_fd */ + { 4, (sy_call_t *)extattrctl }, /* 355 = extattrctl */ + { 4, (sy_call_t *)extattr_set_file }, /* 356 = extattr_set_file */ + { 4, (sy_call_t *)extattr_get_file }, /* 357 = extattr_get_file */ + { 2, (sy_call_t *)extattr_delete_file }, /* 358 = extattr_delete_file */ }; diff --git a/sys/kern/kern_acl.c b/sys/kern/kern_acl.c new file mode 100644 index 0000000..5df8d6a --- /dev/null +++ b/sys/kern/kern_acl.c @@ -0,0 +1,281 @@ +/*- + * Copyright (c) 1999 Robert N. M. Watson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Generic routines to support file system ACLs, at a syntactic level + * Semantics are the responsibility of the underlying file system + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/sysproto.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/vnode.h> +#include <sys/lock.h> +#include <sys/namei.h> +#include <sys/file.h> +#include <sys/proc.h> +#include <sys/sysent.h> +#include <sys/errno.h> +#include <sys/stat.h> +#include <sys/acl.h> +#include <vm/vm_zone.h> + +static MALLOC_DEFINE(M_ACL, "acl", "access control list"); + +static int vacl_set_acl(struct proc *p, struct vnode *vp, acl_type_t type, + struct acl *aclp); +static int vacl_get_acl(struct proc *p, struct vnode *vp, acl_type_t type, + struct acl *aclp); +static int vacl_aclcheck(struct proc *p, struct vnode *vp, acl_type_t type, + struct acl *aclp); + +/* + * These calls wrap the real vnode operations, and are called by the + * syscall code once the syscall has converted the path or file + * descriptor to a vnode (unlocked). The aclp pointer is assumed + * still to point to userland, so this should not be consumed within + * the kernel except by syscall code. Other code should directly + * invoke VOP_{SET,GET}ACL. + */ + +/* + * Given a vnode, set its ACL. + */ +static int +vacl_set_acl(struct proc *p, struct vnode *vp, acl_type_t type, + struct acl *aclp) +{ + struct acl inkernacl; + int error; + + error = copyin(aclp, &inkernacl, sizeof(struct acl)); + if (error) + return(error); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); + error = VOP_SETACL(vp, type, &inkernacl, p->p_ucred, p); + VOP_UNLOCK(vp, 0, p); + return(error); +} + +/* + * Given a vnode, get its ACL. + */ +static int +vacl_get_acl(struct proc *p, struct vnode *vp, acl_type_t type, + struct acl *aclp) +{ + struct acl inkernelacl; + int error; + + error = VOP_GETACL(vp, type, &inkernelacl, p->p_ucred, p); + if (error == 0) + error = copyout(&inkernelacl, aclp, sizeof(struct acl)); + return (error); +} + +/* + * Given a vnode, delete its ACL. + */ +static int +vacl_delete(struct proc *p, struct vnode *vp, acl_type_t type) +{ + int error; + + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); + error = VOP_SETACL(vp, ACL_TYPE_DEFAULT, 0, p->p_ucred, p); + VOP_UNLOCK(vp, 0, p); + return (error); +} + +/* + * Given a vnode, check whether an ACL is appropriate for it + */ +static int +vacl_aclcheck(struct proc *p, struct vnode *vp, acl_type_t type, + struct acl *aclp) +{ + struct acl inkernelacl; + int error; + + error = copyin(aclp, &inkernelacl, sizeof(struct acl)); + if (error) + return(error); + error = VOP_ACLCHECK(vp, type, &inkernelacl, p->p_ucred, p); + return (error); +} + +/* + * syscalls -- convert the path/fd to a vnode, and call vacl_whatever. + * Don't need to lock, as the vacl_ code will get/release any locks + * required. + */ + +/* + * Given a file path, get an ACL for it + */ +int +acl_syscall_get_file(struct proc *p, struct acl_syscall_get_file_args *uap) +{ + struct nameidata nd; + int error; + + /* what flags are required here -- possible not LOCKLEAF? */ + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + error = namei(&nd); + if (error) + return(error); + error = vacl_get_acl(p, nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp)); + NDFREE(&nd, 0); + return (error); +} + +/* + * Given a file path, set an ACL for it + */ +int +acl_syscall_set_file(struct proc *p, struct acl_syscall_set_file_args *uap) +{ + struct nameidata nd; + int error; + + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + error = namei(&nd); + if (error) + return(error); + error = vacl_set_acl(p, nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp)); + NDFREE(&nd, 0); + return (error); +} + +/* + * Given a file descriptor, get an ACL for it + */ +int +acl_syscall_get_fd(struct proc *p, struct acl_syscall_get_fd_args *uap) +{ + struct file *fp; + int error; + + error = getvnode(p->p_fd, SCARG(uap, filedes), &fp); + if (error) + return(error); + return vacl_get_acl(p, (struct vnode *)fp->f_data, SCARG(uap, type), + SCARG(uap, aclp)); +} + +/* + * Given a file descriptor, set an ACL for it + */ +int +acl_syscall_set_fd(struct proc *p, struct acl_syscall_set_fd_args *uap) +{ + struct file *fp; + int error; + + error = getvnode(p->p_fd, SCARG(uap, filedes), &fp); + if (error) + return(error); + return vacl_set_acl(p, (struct vnode *)fp->f_data, SCARG(uap, type), + SCARG(uap, aclp)); +} + +/* + * Given a file path, delete an ACL from it. + */ +int +acl_syscall_delete_file(struct proc *p, + struct acl_syscall_delete_file_args *uap) +{ + struct nameidata nd; + int error; + + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + error = namei(&nd); + if (error) + return(error); + error = vacl_delete(p, nd.ni_vp, SCARG(uap, type)); + NDFREE(&nd, 0); + return (error); +} + +/* + * Given a file path, delete an ACL from it. + */ +int +acl_syscall_delete_fd(struct proc *p, + struct acl_syscall_delete_fd_args *uap) +{ + struct file *fp; + int error; + + error = getvnode(p->p_fd, SCARG(uap, filedes), &fp); + if (error) + return(error); + error = vacl_delete(p, (struct vnode *)fp->f_data, SCARG(uap, type)); + return (error); +} + +/* + * Given a file path, check an ACL for it + */ +int +acl_syscall_aclcheck_file(struct proc *p, + struct acl_syscall_aclcheck_file_args *uap) +{ + struct nameidata nd; + int error; + + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + error = namei(&nd); + if (error) + return(error); + error = vacl_aclcheck(p, nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp)); + NDFREE(&nd, 0); + return (error); +} + +/* + * Given a file descriptor, check an ACL for it + */ +int +acl_syscall_aclcheck_fd(struct proc *p, + struct acl_syscall_aclcheck_fd_args *uap) +{ + struct file *fp; + int error; + + error = getvnode(p->p_fd, SCARG(uap, filedes), &fp); + if (error) + return(error); + return vacl_aclcheck(p, (struct vnode *)fp->f_data, SCARG(uap, type), + SCARG(uap, aclp)); +} diff --git a/sys/kern/makesyscalls.sh b/sys/kern/makesyscalls.sh index f8e2726..bdbd5c6 100644 --- a/sys/kern/makesyscalls.sh +++ b/sys/kern/makesyscalls.sh @@ -112,6 +112,7 @@ s/\$//g printf "#ifndef %s\n", sysproto_h > sysarg printf "#define\t%s\n\n", sysproto_h > sysarg printf "#include <sys/signal.h>\n\n" > sysarg + printf "#include <sys/acl.h>\n\n" > sysarg printf "struct proc;\n\n" > sysarg printf "#define\tPAD_(t)\t(sizeof(register_t) <= sizeof(t) ? \\\n" > sysarg printf "\t\t0 : sizeof(register_t) - sizeof(t))\n\n" > sysarg diff --git a/sys/kern/subr_acl_posix1e.c b/sys/kern/subr_acl_posix1e.c new file mode 100644 index 0000000..5df8d6a --- /dev/null +++ b/sys/kern/subr_acl_posix1e.c @@ -0,0 +1,281 @@ +/*- + * Copyright (c) 1999 Robert N. M. Watson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Generic routines to support file system ACLs, at a syntactic level + * Semantics are the responsibility of the underlying file system + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/sysproto.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/vnode.h> +#include <sys/lock.h> +#include <sys/namei.h> +#include <sys/file.h> +#include <sys/proc.h> +#include <sys/sysent.h> +#include <sys/errno.h> +#include <sys/stat.h> +#include <sys/acl.h> +#include <vm/vm_zone.h> + +static MALLOC_DEFINE(M_ACL, "acl", "access control list"); + +static int vacl_set_acl(struct proc *p, struct vnode *vp, acl_type_t type, + struct acl *aclp); +static int vacl_get_acl(struct proc *p, struct vnode *vp, acl_type_t type, + struct acl *aclp); +static int vacl_aclcheck(struct proc *p, struct vnode *vp, acl_type_t type, + struct acl *aclp); + +/* + * These calls wrap the real vnode operations, and are called by the + * syscall code once the syscall has converted the path or file + * descriptor to a vnode (unlocked). The aclp pointer is assumed + * still to point to userland, so this should not be consumed within + * the kernel except by syscall code. Other code should directly + * invoke VOP_{SET,GET}ACL. + */ + +/* + * Given a vnode, set its ACL. + */ +static int +vacl_set_acl(struct proc *p, struct vnode *vp, acl_type_t type, + struct acl *aclp) +{ + struct acl inkernacl; + int error; + + error = copyin(aclp, &inkernacl, sizeof(struct acl)); + if (error) + return(error); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); + error = VOP_SETACL(vp, type, &inkernacl, p->p_ucred, p); + VOP_UNLOCK(vp, 0, p); + return(error); +} + +/* + * Given a vnode, get its ACL. + */ +static int +vacl_get_acl(struct proc *p, struct vnode *vp, acl_type_t type, + struct acl *aclp) +{ + struct acl inkernelacl; + int error; + + error = VOP_GETACL(vp, type, &inkernelacl, p->p_ucred, p); + if (error == 0) + error = copyout(&inkernelacl, aclp, sizeof(struct acl)); + return (error); +} + +/* + * Given a vnode, delete its ACL. + */ +static int +vacl_delete(struct proc *p, struct vnode *vp, acl_type_t type) +{ + int error; + + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); + error = VOP_SETACL(vp, ACL_TYPE_DEFAULT, 0, p->p_ucred, p); + VOP_UNLOCK(vp, 0, p); + return (error); +} + +/* + * Given a vnode, check whether an ACL is appropriate for it + */ +static int +vacl_aclcheck(struct proc *p, struct vnode *vp, acl_type_t type, + struct acl *aclp) +{ + struct acl inkernelacl; + int error; + + error = copyin(aclp, &inkernelacl, sizeof(struct acl)); + if (error) + return(error); + error = VOP_ACLCHECK(vp, type, &inkernelacl, p->p_ucred, p); + return (error); +} + +/* + * syscalls -- convert the path/fd to a vnode, and call vacl_whatever. + * Don't need to lock, as the vacl_ code will get/release any locks + * required. + */ + +/* + * Given a file path, get an ACL for it + */ +int +acl_syscall_get_file(struct proc *p, struct acl_syscall_get_file_args *uap) +{ + struct nameidata nd; + int error; + + /* what flags are required here -- possible not LOCKLEAF? */ + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + error = namei(&nd); + if (error) + return(error); + error = vacl_get_acl(p, nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp)); + NDFREE(&nd, 0); + return (error); +} + +/* + * Given a file path, set an ACL for it + */ +int +acl_syscall_set_file(struct proc *p, struct acl_syscall_set_file_args *uap) +{ + struct nameidata nd; + int error; + + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + error = namei(&nd); + if (error) + return(error); + error = vacl_set_acl(p, nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp)); + NDFREE(&nd, 0); + return (error); +} + +/* + * Given a file descriptor, get an ACL for it + */ +int +acl_syscall_get_fd(struct proc *p, struct acl_syscall_get_fd_args *uap) +{ + struct file *fp; + int error; + + error = getvnode(p->p_fd, SCARG(uap, filedes), &fp); + if (error) + return(error); + return vacl_get_acl(p, (struct vnode *)fp->f_data, SCARG(uap, type), + SCARG(uap, aclp)); +} + +/* + * Given a file descriptor, set an ACL for it + */ +int +acl_syscall_set_fd(struct proc *p, struct acl_syscall_set_fd_args *uap) +{ + struct file *fp; + int error; + + error = getvnode(p->p_fd, SCARG(uap, filedes), &fp); + if (error) + return(error); + return vacl_set_acl(p, (struct vnode *)fp->f_data, SCARG(uap, type), + SCARG(uap, aclp)); +} + +/* + * Given a file path, delete an ACL from it. + */ +int +acl_syscall_delete_file(struct proc *p, + struct acl_syscall_delete_file_args *uap) +{ + struct nameidata nd; + int error; + + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + error = namei(&nd); + if (error) + return(error); + error = vacl_delete(p, nd.ni_vp, SCARG(uap, type)); + NDFREE(&nd, 0); + return (error); +} + +/* + * Given a file path, delete an ACL from it. + */ +int +acl_syscall_delete_fd(struct proc *p, + struct acl_syscall_delete_fd_args *uap) +{ + struct file *fp; + int error; + + error = getvnode(p->p_fd, SCARG(uap, filedes), &fp); + if (error) + return(error); + error = vacl_delete(p, (struct vnode *)fp->f_data, SCARG(uap, type)); + return (error); +} + +/* + * Given a file path, check an ACL for it + */ +int +acl_syscall_aclcheck_file(struct proc *p, + struct acl_syscall_aclcheck_file_args *uap) +{ + struct nameidata nd; + int error; + + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + error = namei(&nd); + if (error) + return(error); + error = vacl_aclcheck(p, nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp)); + NDFREE(&nd, 0); + return (error); +} + +/* + * Given a file descriptor, check an ACL for it + */ +int +acl_syscall_aclcheck_fd(struct proc *p, + struct acl_syscall_aclcheck_fd_args *uap) +{ + struct file *fp; + int error; + + error = getvnode(p->p_fd, SCARG(uap, filedes), &fp); + if (error) + return(error); + return vacl_aclcheck(p, (struct vnode *)fp->f_data, SCARG(uap, type), + SCARG(uap, aclp)); +} diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c index 9fe3e56..a0c55e4 100644 --- a/sys/kern/syscalls.c +++ b/sys/kern/syscalls.c @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: src/sys/kern/syscalls.master,v 1.67 1999/11/17 21:32:33 brian Exp + * created from FreeBSD: src/sys/kern/syscalls.master,v 1.68 1999/12/19 05:54:46 rwatson Exp */ char *syscallnames[] = { @@ -354,4 +354,16 @@ char *syscallnames[] = { "sigreturn", /* 344 = sigreturn */ "#345", /* 345 = sigtimedwait */ "#346", /* 346 = sigwaitinfo */ + "acl_syscall_get_file", /* 347 = acl_syscall_get_file */ + "acl_syscall_set_file", /* 348 = acl_syscall_set_file */ + "acl_syscall_get_fd", /* 349 = acl_syscall_get_fd */ + "acl_syscall_set_fd", /* 350 = acl_syscall_set_fd */ + "acl_syscall_delete_file", /* 351 = acl_syscall_delete_file */ + "acl_syscall_delete_fd", /* 352 = acl_syscall_delete_fd */ + "acl_syscall_aclcheck_file", /* 353 = acl_syscall_aclcheck_file */ + "acl_syscall_aclcheck_fd", /* 354 = acl_syscall_aclcheck_fd */ + "extattrctl", /* 355 = extattrctl */ + "extattr_set_file", /* 356 = extattr_set_file */ + "extattr_get_file", /* 357 = extattr_get_file */ + "extattr_delete_file", /* 358 = extattr_delete_file */ }; diff --git a/sys/kern/vfs_acl.c b/sys/kern/vfs_acl.c new file mode 100644 index 0000000..5df8d6a --- /dev/null +++ b/sys/kern/vfs_acl.c @@ -0,0 +1,281 @@ +/*- + * Copyright (c) 1999 Robert N. M. Watson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Generic routines to support file system ACLs, at a syntactic level + * Semantics are the responsibility of the underlying file system + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/sysproto.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/vnode.h> +#include <sys/lock.h> +#include <sys/namei.h> +#include <sys/file.h> +#include <sys/proc.h> +#include <sys/sysent.h> +#include <sys/errno.h> +#include <sys/stat.h> +#include <sys/acl.h> +#include <vm/vm_zone.h> + +static MALLOC_DEFINE(M_ACL, "acl", "access control list"); + +static int vacl_set_acl(struct proc *p, struct vnode *vp, acl_type_t type, + struct acl *aclp); +static int vacl_get_acl(struct proc *p, struct vnode *vp, acl_type_t type, + struct acl *aclp); +static int vacl_aclcheck(struct proc *p, struct vnode *vp, acl_type_t type, + struct acl *aclp); + +/* + * These calls wrap the real vnode operations, and are called by the + * syscall code once the syscall has converted the path or file + * descriptor to a vnode (unlocked). The aclp pointer is assumed + * still to point to userland, so this should not be consumed within + * the kernel except by syscall code. Other code should directly + * invoke VOP_{SET,GET}ACL. + */ + +/* + * Given a vnode, set its ACL. + */ +static int +vacl_set_acl(struct proc *p, struct vnode *vp, acl_type_t type, + struct acl *aclp) +{ + struct acl inkernacl; + int error; + + error = copyin(aclp, &inkernacl, sizeof(struct acl)); + if (error) + return(error); + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); + error = VOP_SETACL(vp, type, &inkernacl, p->p_ucred, p); + VOP_UNLOCK(vp, 0, p); + return(error); +} + +/* + * Given a vnode, get its ACL. + */ +static int +vacl_get_acl(struct proc *p, struct vnode *vp, acl_type_t type, + struct acl *aclp) +{ + struct acl inkernelacl; + int error; + + error = VOP_GETACL(vp, type, &inkernelacl, p->p_ucred, p); + if (error == 0) + error = copyout(&inkernelacl, aclp, sizeof(struct acl)); + return (error); +} + +/* + * Given a vnode, delete its ACL. + */ +static int +vacl_delete(struct proc *p, struct vnode *vp, acl_type_t type) +{ + int error; + + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); + error = VOP_SETACL(vp, ACL_TYPE_DEFAULT, 0, p->p_ucred, p); + VOP_UNLOCK(vp, 0, p); + return (error); +} + +/* + * Given a vnode, check whether an ACL is appropriate for it + */ +static int +vacl_aclcheck(struct proc *p, struct vnode *vp, acl_type_t type, + struct acl *aclp) +{ + struct acl inkernelacl; + int error; + + error = copyin(aclp, &inkernelacl, sizeof(struct acl)); + if (error) + return(error); + error = VOP_ACLCHECK(vp, type, &inkernelacl, p->p_ucred, p); + return (error); +} + +/* + * syscalls -- convert the path/fd to a vnode, and call vacl_whatever. + * Don't need to lock, as the vacl_ code will get/release any locks + * required. + */ + +/* + * Given a file path, get an ACL for it + */ +int +acl_syscall_get_file(struct proc *p, struct acl_syscall_get_file_args *uap) +{ + struct nameidata nd; + int error; + + /* what flags are required here -- possible not LOCKLEAF? */ + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + error = namei(&nd); + if (error) + return(error); + error = vacl_get_acl(p, nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp)); + NDFREE(&nd, 0); + return (error); +} + +/* + * Given a file path, set an ACL for it + */ +int +acl_syscall_set_file(struct proc *p, struct acl_syscall_set_file_args *uap) +{ + struct nameidata nd; + int error; + + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + error = namei(&nd); + if (error) + return(error); + error = vacl_set_acl(p, nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp)); + NDFREE(&nd, 0); + return (error); +} + +/* + * Given a file descriptor, get an ACL for it + */ +int +acl_syscall_get_fd(struct proc *p, struct acl_syscall_get_fd_args *uap) +{ + struct file *fp; + int error; + + error = getvnode(p->p_fd, SCARG(uap, filedes), &fp); + if (error) + return(error); + return vacl_get_acl(p, (struct vnode *)fp->f_data, SCARG(uap, type), + SCARG(uap, aclp)); +} + +/* + * Given a file descriptor, set an ACL for it + */ +int +acl_syscall_set_fd(struct proc *p, struct acl_syscall_set_fd_args *uap) +{ + struct file *fp; + int error; + + error = getvnode(p->p_fd, SCARG(uap, filedes), &fp); + if (error) + return(error); + return vacl_set_acl(p, (struct vnode *)fp->f_data, SCARG(uap, type), + SCARG(uap, aclp)); +} + +/* + * Given a file path, delete an ACL from it. + */ +int +acl_syscall_delete_file(struct proc *p, + struct acl_syscall_delete_file_args *uap) +{ + struct nameidata nd; + int error; + + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + error = namei(&nd); + if (error) + return(error); + error = vacl_delete(p, nd.ni_vp, SCARG(uap, type)); + NDFREE(&nd, 0); + return (error); +} + +/* + * Given a file path, delete an ACL from it. + */ +int +acl_syscall_delete_fd(struct proc *p, + struct acl_syscall_delete_fd_args *uap) +{ + struct file *fp; + int error; + + error = getvnode(p->p_fd, SCARG(uap, filedes), &fp); + if (error) + return(error); + error = vacl_delete(p, (struct vnode *)fp->f_data, SCARG(uap, type)); + return (error); +} + +/* + * Given a file path, check an ACL for it + */ +int +acl_syscall_aclcheck_file(struct proc *p, + struct acl_syscall_aclcheck_file_args *uap) +{ + struct nameidata nd; + int error; + + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + error = namei(&nd); + if (error) + return(error); + error = vacl_aclcheck(p, nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp)); + NDFREE(&nd, 0); + return (error); +} + +/* + * Given a file descriptor, check an ACL for it + */ +int +acl_syscall_aclcheck_fd(struct proc *p, + struct acl_syscall_aclcheck_fd_args *uap) +{ + struct file *fp; + int error; + + error = getvnode(p->p_fd, SCARG(uap, filedes), &fp); + if (error) + return(error); + return vacl_aclcheck(p, (struct vnode *)fp->f_data, SCARG(uap, type), + SCARG(uap, aclp)); +} diff --git a/sys/kern/vfs_default.c b/sys/kern/vfs_default.c index 35df911..92642ff 100644 --- a/sys/kern/vfs_default.c +++ b/sys/kern/vfs_default.c @@ -80,6 +80,11 @@ static struct vnodeopv_entry_desc default_vnodeop_entries[] = { { &vop_revoke_desc, (vop_t *) vop_revoke }, { &vop_strategy_desc, (vop_t *) vop_nostrategy }, { &vop_unlock_desc, (vop_t *) vop_nounlock }, + { &vop_getacl_desc, (vop_t *) vop_eopnotsupp }, + { &vop_setacl_desc, (vop_t *) vop_eopnotsupp }, + { &vop_aclcheck_desc, (vop_t *) vop_eopnotsupp }, + { &vop_getextattr_desc, (vop_t *) vop_eopnotsupp }, + { &vop_setextattr_desc, (vop_t *) vop_eopnotsupp }, { NULL, NULL } }; @@ -615,4 +620,15 @@ vfs_stduninit (vfsp) return(0); } +int +vfs_stdextattrctl(mp, cmd, attrname, arg, p) + struct mount *mp; + int cmd; + char *attrname; + caddr_t arg; + struct proc *p; +{ + return(EOPNOTSUPP); +} + /* end of vfs default ops */ diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c index 1de7cf1..4f8878c 100644 --- a/sys/kern/vfs_extattr.c +++ b/sys/kern/vfs_extattr.c @@ -60,13 +60,14 @@ #include <sys/vnode.h> #include <sys/proc.h> #include <sys/dirent.h> +#include <sys/extattr.h> +#include <machine/limits.h> #include <miscfs/union/union.h> - +#include <sys/sysctl.h> #include <vm/vm.h> #include <vm/vm_object.h> #include <vm/vm_zone.h> -#include <sys/sysctl.h> static int change_dir __P((struct nameidata *ndp, struct proc *p)); static void checkdirs __P((struct vnode *olddp)); @@ -3362,3 +3363,193 @@ fhstatfs(p, uap) } return (copyout(sp, SCARG(uap, buf), sizeof(*sp))); } + +/* + * Syscall to push extended attribute configuration information into the + * VFS. Accepts a path, which it converts to a mountpoint, as well as + * a command (int cmd), and attribute name and misc data. For now, the + * attribute name is left in userspace for consumption by the VFS_op. + * It will probably be changed to be copied into sysspace by the + * syscall in the future, once issues with various consumers of the + * attribute code have raised their hands. + * + * Currently this is used only by UFS Extended Attributes. + */ +int +extattrctl(p, uap) + struct proc *p; + struct extattrctl_args *uap; +{ + struct nameidata nd; + struct mount *mp; + int error; + + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + if ((error = namei(&nd)) != 0) + return (error); + mp = nd.ni_vp->v_mount; + NDFREE(&nd, 0); + return (VFS_EXTATTRCTL(mp, SCARG(uap, cmd), SCARG(uap, attrname), + SCARG(uap, arg), p)); +} + +/* + * Syscall to set a named extended attribute on a file or directory. + * Accepts attribute name, and a uio structure pointing to the data to set. + * The uio is consumed in the style of writev(). The real work happens + * in VOP_SETEXTATTR(). + */ +int +extattr_set_file(p, uap) + struct proc *p; + struct extattr_set_file_args *uap; +{ + struct nameidata nd; + struct uio auio; + struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV]; + char attrname[EXTATTR_MAXNAMELEN]; + u_int iovlen, cnt; + int error, i; + + error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN); + if (error) + return (error); + NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, SCARG(uap, path), + p); + if ((error = namei(&nd)) != 0) + return(error); + iovlen = uap->iovcnt * sizeof(struct iovec); + if (uap->iovcnt > UIO_SMALLIOV) { + if (uap->iovcnt > UIO_MAXIOV) { + error = EINVAL; + goto done; + } + MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK); + needfree = iov; + } else + iov = aiov; + auio.uio_iov = iov; + auio.uio_iovcnt = uap->iovcnt; + auio.uio_rw = UIO_WRITE; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_procp = p; + auio.uio_offset = 0; + if ((error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))) + goto done; + auio.uio_resid = 0; + for (i = 0; i < uap->iovcnt; i++) { + if (iov->iov_len > INT_MAX - auio.uio_resid) { + error = EINVAL; + goto done; + } + auio.uio_resid += iov->iov_len; + iov++; + } + cnt = auio.uio_resid; + error = VOP_SETEXTATTR(nd.ni_vp, attrname, &auio, p->p_cred->pc_ucred, + p); + if (auio.uio_resid != cnt && (error == ERESTART || + error == EINTR || error == EWOULDBLOCK)) + error = 0; + cnt -= auio.uio_resid; + p->p_retval[0] = cnt; +done: + if (needfree) + FREE(needfree, M_IOV); + NDFREE(&nd, 0); + return (error); +} + +/* + * Syscall to get a named extended attribute on a file or directory. + * Accepts attribute name, and a uio structure pointing to a buffer for the + * data. The uio is consumed in the style of readv(). The real work + * happens in VOP_GETEXTATTR(); + */ +int +extattr_get_file(p, uap) + struct proc *p; + struct extattr_get_file_args *uap; +{ + struct nameidata nd; + struct uio auio; + struct iovec *iov, *needfree, aiov[UIO_SMALLIOV]; + char attrname[EXTATTR_MAXNAMELEN]; + u_int iovlen, cnt; + int error, i; + + error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN); + if (error) + return (error); + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + if ((error = namei(&nd)) != 0) + return (error); + iovlen = uap->iovcnt * sizeof (struct iovec); + if (uap->iovcnt > UIO_SMALLIOV) { + if (uap->iovcnt > UIO_MAXIOV) { + NDFREE(&nd, 0); + return (EINVAL); + } + MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK); + needfree = iov; + } else { + iov = aiov; + needfree = NULL; + } + auio.uio_iov = iov; + auio.uio_iovcnt = uap->iovcnt; + auio.uio_rw = UIO_READ; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_procp = p; + auio.uio_offset = 0; + if ((error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))) + goto done; + auio.uio_resid = 0; + for (i = 0; i < uap->iovcnt; i++) { + if (iov->iov_len > INT_MAX - auio.uio_resid) { + error = EINVAL; + goto done; + } + auio.uio_resid += iov->iov_len; + iov++; + } + cnt = auio.uio_resid; + error = VOP_GETEXTATTR(nd.ni_vp, attrname, &auio, p->p_cred->pc_ucred, + p); + if (auio.uio_resid != cnt && (error == ERESTART || + error == EINTR || error == EWOULDBLOCK)) + error = 0; + cnt -= auio.uio_resid; + p->p_retval[0] = cnt; +done: + if (needfree) + FREE(needfree, M_IOV); + NDFREE(&nd, 0); + return(error); +} + +/* + * Syscall to delete a named extended attribute from a file or directory. + * Accepts attribute name. The real work happens in VOP_SETEXTATTR(). + */ +int +extattr_delete_file(p, uap) + struct proc *p; + struct extattr_delete_file_args *uap; +{ + struct nameidata nd; + char attrname[EXTATTR_MAXNAMELEN]; + int error; + + error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN); + if (error) + return(error); + NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, SCARG(uap, path), + p); + if ((error = namei(&nd)) != 0) + return(error); + error = VOP_SETEXTATTR(nd.ni_vp, attrname, NULL, p->p_cred->pc_ucred, + p); + NDFREE(&nd, 0); + return(error); +} diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 1de7cf1..4f8878c 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -60,13 +60,14 @@ #include <sys/vnode.h> #include <sys/proc.h> #include <sys/dirent.h> +#include <sys/extattr.h> +#include <machine/limits.h> #include <miscfs/union/union.h> - +#include <sys/sysctl.h> #include <vm/vm.h> #include <vm/vm_object.h> #include <vm/vm_zone.h> -#include <sys/sysctl.h> static int change_dir __P((struct nameidata *ndp, struct proc *p)); static void checkdirs __P((struct vnode *olddp)); @@ -3362,3 +3363,193 @@ fhstatfs(p, uap) } return (copyout(sp, SCARG(uap, buf), sizeof(*sp))); } + +/* + * Syscall to push extended attribute configuration information into the + * VFS. Accepts a path, which it converts to a mountpoint, as well as + * a command (int cmd), and attribute name and misc data. For now, the + * attribute name is left in userspace for consumption by the VFS_op. + * It will probably be changed to be copied into sysspace by the + * syscall in the future, once issues with various consumers of the + * attribute code have raised their hands. + * + * Currently this is used only by UFS Extended Attributes. + */ +int +extattrctl(p, uap) + struct proc *p; + struct extattrctl_args *uap; +{ + struct nameidata nd; + struct mount *mp; + int error; + + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + if ((error = namei(&nd)) != 0) + return (error); + mp = nd.ni_vp->v_mount; + NDFREE(&nd, 0); + return (VFS_EXTATTRCTL(mp, SCARG(uap, cmd), SCARG(uap, attrname), + SCARG(uap, arg), p)); +} + +/* + * Syscall to set a named extended attribute on a file or directory. + * Accepts attribute name, and a uio structure pointing to the data to set. + * The uio is consumed in the style of writev(). The real work happens + * in VOP_SETEXTATTR(). + */ +int +extattr_set_file(p, uap) + struct proc *p; + struct extattr_set_file_args *uap; +{ + struct nameidata nd; + struct uio auio; + struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV]; + char attrname[EXTATTR_MAXNAMELEN]; + u_int iovlen, cnt; + int error, i; + + error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN); + if (error) + return (error); + NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, SCARG(uap, path), + p); + if ((error = namei(&nd)) != 0) + return(error); + iovlen = uap->iovcnt * sizeof(struct iovec); + if (uap->iovcnt > UIO_SMALLIOV) { + if (uap->iovcnt > UIO_MAXIOV) { + error = EINVAL; + goto done; + } + MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK); + needfree = iov; + } else + iov = aiov; + auio.uio_iov = iov; + auio.uio_iovcnt = uap->iovcnt; + auio.uio_rw = UIO_WRITE; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_procp = p; + auio.uio_offset = 0; + if ((error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))) + goto done; + auio.uio_resid = 0; + for (i = 0; i < uap->iovcnt; i++) { + if (iov->iov_len > INT_MAX - auio.uio_resid) { + error = EINVAL; + goto done; + } + auio.uio_resid += iov->iov_len; + iov++; + } + cnt = auio.uio_resid; + error = VOP_SETEXTATTR(nd.ni_vp, attrname, &auio, p->p_cred->pc_ucred, + p); + if (auio.uio_resid != cnt && (error == ERESTART || + error == EINTR || error == EWOULDBLOCK)) + error = 0; + cnt -= auio.uio_resid; + p->p_retval[0] = cnt; +done: + if (needfree) + FREE(needfree, M_IOV); + NDFREE(&nd, 0); + return (error); +} + +/* + * Syscall to get a named extended attribute on a file or directory. + * Accepts attribute name, and a uio structure pointing to a buffer for the + * data. The uio is consumed in the style of readv(). The real work + * happens in VOP_GETEXTATTR(); + */ +int +extattr_get_file(p, uap) + struct proc *p; + struct extattr_get_file_args *uap; +{ + struct nameidata nd; + struct uio auio; + struct iovec *iov, *needfree, aiov[UIO_SMALLIOV]; + char attrname[EXTATTR_MAXNAMELEN]; + u_int iovlen, cnt; + int error, i; + + error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN); + if (error) + return (error); + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); + if ((error = namei(&nd)) != 0) + return (error); + iovlen = uap->iovcnt * sizeof (struct iovec); + if (uap->iovcnt > UIO_SMALLIOV) { + if (uap->iovcnt > UIO_MAXIOV) { + NDFREE(&nd, 0); + return (EINVAL); + } + MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK); + needfree = iov; + } else { + iov = aiov; + needfree = NULL; + } + auio.uio_iov = iov; + auio.uio_iovcnt = uap->iovcnt; + auio.uio_rw = UIO_READ; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_procp = p; + auio.uio_offset = 0; + if ((error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))) + goto done; + auio.uio_resid = 0; + for (i = 0; i < uap->iovcnt; i++) { + if (iov->iov_len > INT_MAX - auio.uio_resid) { + error = EINVAL; + goto done; + } + auio.uio_resid += iov->iov_len; + iov++; + } + cnt = auio.uio_resid; + error = VOP_GETEXTATTR(nd.ni_vp, attrname, &auio, p->p_cred->pc_ucred, + p); + if (auio.uio_resid != cnt && (error == ERESTART || + error == EINTR || error == EWOULDBLOCK)) + error = 0; + cnt -= auio.uio_resid; + p->p_retval[0] = cnt; +done: + if (needfree) + FREE(needfree, M_IOV); + NDFREE(&nd, 0); + return(error); +} + +/* + * Syscall to delete a named extended attribute from a file or directory. + * Accepts attribute name. The real work happens in VOP_SETEXTATTR(). + */ +int +extattr_delete_file(p, uap) + struct proc *p; + struct extattr_delete_file_args *uap; +{ + struct nameidata nd; + char attrname[EXTATTR_MAXNAMELEN]; + int error; + + error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN); + if (error) + return(error); + NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, SCARG(uap, path), + p); + if ((error = namei(&nd)) != 0) + return(error); + error = VOP_SETEXTATTR(nd.ni_vp, attrname, NULL, p->p_cred->pc_ucred, + p); + NDFREE(&nd, 0); + return(error); +} diff --git a/sys/kern/vnode_if.src b/sys/kern/vnode_if.src index bbfe4d4..479cc92 100644 --- a/sys/kern/vnode_if.src +++ b/sys/kern/vnode_if.src @@ -154,7 +154,7 @@ vop_access { # vop_getattr { IN struct vnode *vp; - IN struct vattr *vap; + OUT struct vattr *vap; IN struct ucred *cred; IN struct proc *p; }; @@ -484,3 +484,58 @@ vop_bwrite { IN struct vnode *vp; IN struct buf *bp; }; + +# +#% getacl vp = = = +# +vop_getacl { + IN struct vnode *vp; + IN acl_type_t type; + OUT struct acl *aclp; + IN struct ucred *cred; + IN struct proc *p; +}; + +# +#% setacl vp L L L +# +vop_setacl { + IN struct vnode *vp; + IN acl_type_t type; + IN struct acl *aclp; + IN struct ucred *cred; + IN struct proc *p; +}; + +# +#% aclcheck vp = = = +# +vop_aclcheck { + IN struct vnode *vp; + IN acl_type_t type; + IN struct acl *aclp; + IN struct ucred *cred; + IN struct proc *p; +}; + +# +#% getextattr vp = = = +# +vop_getextattr { + IN struct vnode *vp; + IN char *name; + INOUT struct uio *uio; + IN struct ucred *cred; + IN struct proc *p; +}; + +# +#% setextattr vp L L L +# +vop_setextattr { + IN struct vnode *vp; + IN char *name; + INOUT struct uio *uio; + IN struct ucred *cred; + IN struct proc *p; +}; diff --git a/sys/miscfs/devfs/devfs_vfsops.c b/sys/miscfs/devfs/devfs_vfsops.c index 73f7d70..f440a83 100644 --- a/sys/miscfs/devfs/devfs_vfsops.c +++ b/sys/miscfs/devfs/devfs_vfsops.c @@ -305,7 +305,9 @@ static struct vfsops devfs_vfsops = { vfs_stdfhtovp, vfs_stdcheckexp, vfs_stdvptofh, - devfs_init + devfs_init, + vfs_stduninit, + vfs_stdextattrctl, }; VFS_SET(devfs_vfsops, devfs, 0); diff --git a/sys/miscfs/fdesc/fdesc_vfsops.c b/sys/miscfs/fdesc/fdesc_vfsops.c index a451c18..0105ff7 100644 --- a/sys/miscfs/fdesc/fdesc_vfsops.c +++ b/sys/miscfs/fdesc/fdesc_vfsops.c @@ -227,6 +227,8 @@ static struct vfsops fdesc_vfsops = { vfs_stdcheckexp, vfs_stdvptofh, fdesc_init, + vfs_stduninit, + vfs_stdextattrctl, }; VFS_SET(fdesc_vfsops, fdesc, VFCF_SYNTHETIC); diff --git a/sys/miscfs/kernfs/kernfs_vfsops.c b/sys/miscfs/kernfs/kernfs_vfsops.c index a08e9d4..e55c540 100644 --- a/sys/miscfs/kernfs/kernfs_vfsops.c +++ b/sys/miscfs/kernfs/kernfs_vfsops.c @@ -255,6 +255,8 @@ static struct vfsops kernfs_vfsops = { vfs_stdcheckexp, vfs_stdvptofh, vfs_stdinit, + vfs_stduninit, + vfs_stdextattrctl, }; VFS_SET(kernfs_vfsops, kernfs, VFCF_SYNTHETIC); diff --git a/sys/miscfs/nullfs/null_vfsops.c b/sys/miscfs/nullfs/null_vfsops.c index 1bdc083..cbeadc3 100644 --- a/sys/miscfs/nullfs/null_vfsops.c +++ b/sys/miscfs/nullfs/null_vfsops.c @@ -417,6 +417,19 @@ nullfs_vptofh(vp, fhp) return VFS_VPTOFH(NULLVPTOLOWERVP(vp), fhp); } +static int +nullfs_extattrctl(mp, cmd, attrname, arg, p) + struct mount *mp; + int cmd; + char *attrname; + caddr_t arg; + struct proc *p; +{ + return VFS_EXTATTRCTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, attrname, + arg, p); +} + + static struct vfsops null_vfsops = { nullfs_mount, nullfs_start, @@ -430,6 +443,8 @@ static struct vfsops null_vfsops = { nullfs_checkexp, nullfs_vptofh, nullfs_init, + vfs_stduninit, + nullfs_extattrctl, }; VFS_SET(null_vfsops, null, VFCF_LOOPBACK); diff --git a/sys/miscfs/portal/portal_vfsops.c b/sys/miscfs/portal/portal_vfsops.c index d750b53..950d383 100644 --- a/sys/miscfs/portal/portal_vfsops.c +++ b/sys/miscfs/portal/portal_vfsops.c @@ -256,6 +256,8 @@ static struct vfsops portal_vfsops = { vfs_stdcheckexp, vfs_stdvptofh, vfs_stdinit, + vfs_stduninit, + vfs_stdextattrctl, }; VFS_SET(portal_vfsops, portal, VFCF_SYNTHETIC); diff --git a/sys/miscfs/procfs/procfs_vfsops.c b/sys/miscfs/procfs/procfs_vfsops.c index 0533764..b1d4d43 100644 --- a/sys/miscfs/procfs/procfs_vfsops.c +++ b/sys/miscfs/procfs/procfs_vfsops.c @@ -172,6 +172,8 @@ static struct vfsops procfs_vfsops = { vfs_stdcheckexp, vfs_stdvptofh, vfs_stdinit, + vfs_stduninit, + vfs_stdextattrctl, }; VFS_SET(procfs_vfsops, procfs, VFCF_SYNTHETIC); diff --git a/sys/miscfs/umapfs/umap_vfsops.c b/sys/miscfs/umapfs/umap_vfsops.c index 48894fe..6e0c0b6 100644 --- a/sys/miscfs/umapfs/umap_vfsops.c +++ b/sys/miscfs/umapfs/umap_vfsops.c @@ -75,6 +75,9 @@ static int umapfs_unmount __P((struct mount *mp, int mntflags, static int umapfs_vget __P((struct mount *mp, ino_t ino, struct vnode **vpp)); static int umapfs_vptofh __P((struct vnode *vp, struct fid *fhp)); +static int umapfs_extattrctl __P((struct mount *mp, int cmd, + char *attrname, caddr_t arg, + struct proc *p)); /* * Mount umap layer @@ -430,6 +433,19 @@ umapfs_vptofh(vp, fhp) return (VFS_VPTOFH(UMAPVPTOLOWERVP(vp), fhp)); } +static int +umapfs_extattrctl(mp, cmd, attrname, arg, p) + struct mount *mp; + int cmd; + char *attrname; + caddr_t arg; + struct proc *p; +{ + return (VFS_EXTATTRCTL(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, cmd, attrname, + arg, p)); +} + + static struct vfsops umap_vfsops = { umapfs_mount, umapfs_start, @@ -443,6 +459,8 @@ static struct vfsops umap_vfsops = { umapfs_checkexp, umapfs_vptofh, umapfs_init, + vfs_stduninit, + umapfs_extattrctl, }; VFS_SET(umap_vfsops, umap, VFCF_LOOPBACK); diff --git a/sys/miscfs/union/union_vfsops.c b/sys/miscfs/union/union_vfsops.c index f5782fa..8b58e55 100644 --- a/sys/miscfs/union/union_vfsops.c +++ b/sys/miscfs/union/union_vfsops.c @@ -502,6 +502,8 @@ static struct vfsops union_vfsops = { vfs_stdcheckexp, vfs_stdvptofh, union_init, + vfs_stduninit, + vfs_stdextattrctl, }; VFS_SET(union_vfsops, union, VFCF_LOOPBACK); diff --git a/sys/msdosfs/msdosfs_vfsops.c b/sys/msdosfs/msdosfs_vfsops.c index 3fd65ec..4af4cf3 100644 --- a/sys/msdosfs/msdosfs_vfsops.c +++ b/sys/msdosfs/msdosfs_vfsops.c @@ -986,7 +986,9 @@ static struct vfsops msdosfs_vfsops = { msdosfs_fhtovp, msdosfs_checkexp, msdosfs_vptofh, - msdosfs_init + msdosfs_init, + vfs_stduninit, + vfs_stdextattrctl, }; VFS_SET(msdosfs_vfsops, msdos, 0); diff --git a/sys/nfs/nfs_vfsops.c b/sys/nfs/nfs_vfsops.c index 8a0c368..9ddb428 100644 --- a/sys/nfs/nfs_vfsops.c +++ b/sys/nfs/nfs_vfsops.c @@ -126,6 +126,7 @@ static struct vfsops nfs_vfsops = { vfs_stdvptofh, /* shouldn't happen */ nfs_init, nfs_uninit, + vfs_stdextattrctl, }; VFS_SET(nfs_vfsops, nfs, VFCF_NETWORK); diff --git a/sys/nfsclient/nfs_vfsops.c b/sys/nfsclient/nfs_vfsops.c index 8a0c368..9ddb428 100644 --- a/sys/nfsclient/nfs_vfsops.c +++ b/sys/nfsclient/nfs_vfsops.c @@ -126,6 +126,7 @@ static struct vfsops nfs_vfsops = { vfs_stdvptofh, /* shouldn't happen */ nfs_init, nfs_uninit, + vfs_stdextattrctl, }; VFS_SET(nfs_vfsops, nfs, VFCF_NETWORK); diff --git a/sys/ntfs/ntfs_vfsops.c b/sys/ntfs/ntfs_vfsops.c index 6bc0555..d4883be 100644 --- a/sys/ntfs/ntfs_vfsops.c +++ b/sys/ntfs/ntfs_vfsops.c @@ -1008,7 +1008,8 @@ static struct vfsops ntfs_vfsops = { ntfs_checkexp, ntfs_vptofh, ntfs_init, - NULL + vfs_stduninit, + vfs_stdextattrctl, }; VFS_SET(ntfs_vfsops, ntfs, 0); #elif defined(__NetBSD__) diff --git a/sys/nwfs/nwfs_vfsops.c b/sys/nwfs/nwfs_vfsops.c index f99bba7..5e7c597 100644 --- a/sys/nwfs/nwfs_vfsops.c +++ b/sys/nwfs/nwfs_vfsops.c @@ -93,7 +93,8 @@ static struct vfsops nwfs_vfsops = { vfs_stdcheckexp, vfs_stdvptofh, /* shouldn't happen */ nwfs_init, - nwfs_uninit + nwfs_uninit, + vfs_stdextattrctl, }; diff --git a/sys/sys/acl.h b/sys/sys/acl.h new file mode 100644 index 0000000..3a13fab --- /dev/null +++ b/sys/sys/acl.h @@ -0,0 +1,169 @@ +/*- + * Copyright (c) 1999 Robert N. M. Watson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ +/* + * Userland/kernel interface for Access Control Lists + * + * This code from the FreeBSD POSIX.1e implementation. Not all of the ACL + * code is committed yet; in order to use the library routines listed + * below, you'll need to download libposix1e_acl from the POSIX.1e + * implementation page, or possibly update to a more recent version of + * FreeBSD, as the code may have been committed. + * + * The POSIX.1e implementation page may be reached at: + * http://www.watson.org/fbsd-hardening/posix1e/ + * + * However, all syscalls will pass through to appropriate VFS vnops, so + * file systems implementing the vnops are accessible through the syscalls. + */ + +#ifndef _SYS_ACL_H +#define _SYS_ACL_H + +/* + * POSIX.1e ACL types + */ + +#define MAX_ACL_ENTRIES 32 /* maximum entries in an ACL */ +#define _POSIX_ACL_PATH_MAX MAX_ACL_ENTRIES + +typedef int acl_type_t; +typedef int acl_tag_t; +typedef mode_t acl_perm_t; + +struct acl_entry { + acl_tag_t ae_tag; + uid_t ae_id; + acl_perm_t ae_perm; +}; +typedef struct acl_entry *acl_entry_t; + +struct acl { + int acl_cnt; + struct acl_entry acl_entry[MAX_ACL_ENTRIES]; +}; +typedef struct acl *acl_t; + +/* + * Possible valid values for a_type of acl_entry_t + */ +#define ACL_USER_OBJ 0x00000001 +#define ACL_USER 0x00000002 +#define ACL_GROUP_OBJ 0x00000004 +#define ACL_GROUP 0x00000008 +#define ACL_MASK 0x00000010 +#define ACL_OTHER 0x00000020 +#define ACL_OTHER_OBJ ACL_OTHER +#define ACL_AFS_ID 0x00000040 + +#define ACL_TYPE_ACCESS 0x00000000 +#define ACL_TYPE_DEFAULT 0x00000001 + +/* + * Possible flags in a_perm field + */ +#define ACL_PERM_EXEC 0x0001 +#define ACL_PERM_WRITE 0x0002 +#define ACL_PERM_READ 0x0004 +#define ACL_PERM_NONE 0x0000 +#define ACL_PERM_BITS (ACL_PERM_EXEC | ACL_PERM_WRITE | ACL_PERM_READ) +#define ACL_POSIX1E_BITS (ACL_PERM_EXEC | ACL_PERM_WRITE | ACL_PERM_READ) + +#ifdef KERNEL +/* + * Storage for ACLs and support structures + */ +#ifdef MALLOC_DECLARE +MALLOC_DECLARE(M_ACL); +#endif + +/* + * Dummy declarations so that we can expose acl_access all over the place + * without worrying about including ucred and friends. vnode.h does the + * same thing. + */ +struct ucred; +struct proc; + +/* + * POSIX.1e and generic kernel/vfs semantics functions--not currently in the + * base distribution, but will be soon. + */ +struct vattr; +struct vop_getacl_args; +struct vop_aclcheck_args; + +int posix1e_acl_access(struct acl *a_acl, int a_mode, struct ucred *a_cred, + struct proc *a_p); +void generic_attr_to_posix1e_acl(struct acl *a_acl, struct vattr *vattr); +int generic_vop_getacl(struct vop_getacl_args *ap); +int generic_vop_aclcheck(struct vop_aclcheck_args *ap); +int posix1e_vop_aclcheck(struct vop_aclcheck_args *ap); + +#else /* KERNEL */ + +/* + * Syscall interface -- use the library calls instead as the syscalls + * have strict acl entry ordering requirements + */ +int acl_syscall_get_file(char *path, acl_type_t type, struct acl *aclp); +int acl_syscall_set_file(char *path, acl_type_t type, struct acl *aclp); +int acl_syscall_get_fd(int filedes, acl_type_t type, struct acl *aclp); +int acl_syscall_set_fd(int filedes, acl_type_t type, struct acl *aclp); +int acl_syscall_delete_file(const char *path_p, acl_type_t type); +int acl_syscall_delete_fd(int filedes, acl_type_t type); +int acl_syscall_aclcheck_file(char *path, acl_type_t type, + struct acl *aclp); +int acl_syscall_aclcheck_fd(int filedes, acl_type_t type, + struct acl *aclp); + +/* + * Supported POSIX.1e ACL manipulation and assignment/retrieval API + * These are currently provided by libposix1e_acl, which is not shipped + * with the base distribution, but will be soon. Some of these are + * from POSIX.1e-extensions. + * + * Not all POSIX.1e ACL functions are listed here yet, but more will + * be soon. + */ +int acl_calc_mask(acl_t *acl_p); +int acl_delete_def_file(const char *path_p); +int acl_delete_def_fd(int filedes); +acl_t acl_from_text(const char *buf_p); +acl_t acl_get_fd(int fd, acl_type_t type); +acl_t acl_get_file(const char *path_p, acl_type_t type); +acl_t acl_init(int count); +int acl_set_fd(int fd, acl_t acl, acl_type_t type); +int acl_set_file(const char *path_p, acl_type_t type, acl_t acl); +char *acl_to_text(acl_t acl, ssize_t *len_p); +int acl_valid(acl_t acl); +int acl_valid_file(const char *path_p, acl_type_t type, acl_t acl); +int acl_valid_fd(int fd, acl_type_t type, acl_t acl); +int acl_free(void *obj_p); + +#endif /* KERNEL */ +#endif /* _SYS_ACL_H */ diff --git a/sys/sys/extattr.h b/sys/sys/extattr.h new file mode 100644 index 0000000..d81be11 --- /dev/null +++ b/sys/sys/extattr.h @@ -0,0 +1,57 @@ +/*- + * Copyright (c) 1999 Robert N. M. Watson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ +/* + * Userland/kernel interface for Extended File System Attributes + * + * This code from the FreeBSD POSIX.1e implementation. While the syscalls + * are fully implemented, invoking the VFS vnops and VFS calls as necessary, + * no file systems shipped with this version of FreeBSD implement these + * calls. Extensions to UFS/FFS to support extended attributes are + * available from the POSIX.1e implementation page, or possibly in a more + * recent version of FreeBSD. + * + * The POSIX.1e implementation page may be reached at: + * http://www.watson.org/fbsd-hardening/posix1e/ + */ + +#ifndef _SYS_EXTATTR_H_ +#define _SYS_EXTATTR_H_ + +#define EXTATTR_MAXNAMELEN NAME_MAX + +#ifndef KERNEL + +int extattrctl(char *path, int cmd, char *attrname, caddr_t arg); +int extattr_set_file(char *path, char *attrname, struct iovec *iovp, + u_int iovcnt); +int extattr_get_file(char *path, char *attrname, struct iovec *iovp, + u_int iovcnt); +int extattr_delete_file(char *path, char *attrname); + +#endif /* KERNEL */ +#endif /* _SYS_EXTATTR_H_ */ diff --git a/sys/sys/mount.h b/sys/sys/mount.h index f0ad319..51743e9 100644 --- a/sys/sys/mount.h +++ b/sys/sys/mount.h @@ -331,6 +331,9 @@ struct vfsops { int (*vfs_vptofh) __P((struct vnode *vp, struct fid *fhp)); int (*vfs_init) __P((struct vfsconf *)); int (*vfs_uninit) __P((struct vfsconf *)); + int (*vfs_extattrctl) __P((struct mount *mp, int cmd, + char *attrname, caddr_t arg, + struct proc *p)); }; #define VFS_MOUNT(MP, PATH, DATA, NDP, P) \ @@ -347,6 +350,8 @@ struct vfsops { #define VFS_VPTOFH(VP, FIDP) (*(VP)->v_mount->mnt_op->vfs_vptofh)(VP, FIDP) #define VFS_CHECKEXP(MP, NAM, EXFLG, CRED) \ (*(MP)->mnt_op->vfs_checkexp)(MP, NAM, EXFLG, CRED) +#define VFS_EXTATTRCTL(MP, C, N, A, P) \ + (*(MP)->mnt_op->vfs_extattrctl)(MP, C, N, A, P) #include <sys/module.h> @@ -439,6 +444,8 @@ int vfs_stdcheckexp __P((struct mount *mp, struct sockaddr *nam, int vfs_stdvptofh __P((struct vnode *vp, struct fid *fhp)); int vfs_stdinit __P((struct vfsconf *)); int vfs_stduninit __P((struct vfsconf *)); +int vfs_stdextattrctl __P((struct mount *mp, int cmd, char *attrname, + caddr_t arg, struct proc *p)); #else /* !KERNEL */ diff --git a/sys/sys/syscall-hide.h b/sys/sys/syscall-hide.h index 1a8b3f6..5c563f4 100644 --- a/sys/sys/syscall-hide.h +++ b/sys/sys/syscall-hide.h @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: src/sys/kern/syscalls.master,v 1.67 1999/11/17 21:32:33 brian Exp + * created from FreeBSD: src/sys/kern/syscalls.master,v 1.68 1999/12/19 05:54:46 rwatson Exp */ HIDE_POSIX(fork) @@ -262,3 +262,15 @@ HIDE_POSIX(sigsuspend) HIDE_POSIX(sigaction) HIDE_POSIX(sigpending) HIDE_BSD(sigreturn) +HIDE_BSD(acl_syscall_get_file) +HIDE_BSD(acl_syscall_set_file) +HIDE_BSD(acl_syscall_get_fd) +HIDE_BSD(acl_syscall_set_fd) +HIDE_BSD(acl_syscall_delete_file) +HIDE_BSD(acl_syscall_delete_fd) +HIDE_BSD(acl_syscall_aclcheck_file) +HIDE_BSD(acl_syscall_aclcheck_fd) +HIDE_BSD(extattrctl) +HIDE_BSD(extattr_set_file) +HIDE_BSD(extattr_get_file) +HIDE_BSD(extattr_delete_file) diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h index 5452b90..d438e57 100644 --- a/sys/sys/syscall.h +++ b/sys/sys/syscall.h @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: src/sys/kern/syscalls.master,v 1.67 1999/11/17 21:32:33 brian Exp + * created from FreeBSD: src/sys/kern/syscalls.master,v 1.68 1999/12/19 05:54:46 rwatson Exp */ #define SYS_syscall 0 @@ -267,4 +267,16 @@ #define SYS_sigaction 342 #define SYS_sigpending 343 #define SYS_sigreturn 344 -#define SYS_MAXSYSCALL 347 +#define SYS_acl_syscall_get_file 347 +#define SYS_acl_syscall_set_file 348 +#define SYS_acl_syscall_get_fd 349 +#define SYS_acl_syscall_set_fd 350 +#define SYS_acl_syscall_delete_file 351 +#define SYS_acl_syscall_delete_fd 352 +#define SYS_acl_syscall_aclcheck_file 353 +#define SYS_acl_syscall_aclcheck_fd 354 +#define SYS_extattrctl 355 +#define SYS_extattr_set_file 356 +#define SYS_extattr_get_file 357 +#define SYS_extattr_delete_file 358 +#define SYS_MAXSYSCALL 359 diff --git a/sys/sys/syscall.mk b/sys/sys/syscall.mk index 2e0c760..08c9f4c 100644 --- a/sys/sys/syscall.mk +++ b/sys/sys/syscall.mk @@ -1,7 +1,7 @@ # FreeBSD system call names. # DO NOT EDIT-- this file is automatically generated. # $FreeBSD$ -# created from FreeBSD: src/sys/kern/syscalls.master,v 1.67 1999/11/17 21:32:33 brian Exp +# created from FreeBSD: src/sys/kern/syscalls.master,v 1.68 1999/12/19 05:54:46 rwatson Exp MIASM = \ syscall.o \ exit.o \ @@ -217,4 +217,16 @@ MIASM = \ sigsuspend.o \ sigaction.o \ sigpending.o \ - sigreturn.o + sigreturn.o \ + acl_syscall_get_file.o \ + acl_syscall_set_file.o \ + acl_syscall_get_fd.o \ + acl_syscall_set_fd.o \ + acl_syscall_delete_file.o \ + acl_syscall_delete_fd.o \ + acl_syscall_aclcheck_file.o \ + acl_syscall_aclcheck_fd.o \ + extattrctl.o \ + extattr_set_file.o \ + extattr_get_file.o \ + extattr_delete_file.o diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h index dba7ab0..0689a9a 100644 --- a/sys/sys/sysproto.h +++ b/sys/sys/sysproto.h @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: src/sys/kern/syscalls.master,v 1.67 1999/11/17 21:32:33 brian Exp + * created from FreeBSD: src/sys/kern/syscalls.master,v 1.68 1999/12/19 05:54:46 rwatson Exp */ #ifndef _SYS_SYSPROTO_H_ @@ -11,6 +11,8 @@ #include <sys/signal.h> +#include <sys/acl.h> + struct proc; #define PAD_(t) (sizeof(register_t) <= sizeof(t) ? \ @@ -927,6 +929,66 @@ struct sigpending_args { struct sigreturn_args { ucontext_t * sigcntxp; char sigcntxp_[PAD_(ucontext_t *)]; }; +struct acl_syscall_get_file_args { + char * path; char path_[PAD_(char *)]; + acl_type_t type; char type_[PAD_(acl_type_t)]; + struct acl * aclp; char aclp_[PAD_(struct acl *)]; +}; +struct acl_syscall_set_file_args { + char * path; char path_[PAD_(char *)]; + acl_type_t type; char type_[PAD_(acl_type_t)]; + struct acl * aclp; char aclp_[PAD_(struct acl *)]; +}; +struct acl_syscall_get_fd_args { + int filedes; char filedes_[PAD_(int)]; + acl_type_t type; char type_[PAD_(acl_type_t)]; + struct acl * aclp; char aclp_[PAD_(struct acl *)]; +}; +struct acl_syscall_set_fd_args { + int filedes; char filedes_[PAD_(int)]; + acl_type_t type; char type_[PAD_(acl_type_t)]; + struct acl * aclp; char aclp_[PAD_(struct acl *)]; +}; +struct acl_syscall_delete_file_args { + char * path; char path_[PAD_(char *)]; + acl_type_t type; char type_[PAD_(acl_type_t)]; +}; +struct acl_syscall_delete_fd_args { + int filedes; char filedes_[PAD_(int)]; + acl_type_t type; char type_[PAD_(acl_type_t)]; +}; +struct acl_syscall_aclcheck_file_args { + char * path; char path_[PAD_(char *)]; + acl_type_t type; char type_[PAD_(acl_type_t)]; + struct acl * aclp; char aclp_[PAD_(struct acl *)]; +}; +struct acl_syscall_aclcheck_fd_args { + int filedes; char filedes_[PAD_(int)]; + acl_type_t type; char type_[PAD_(acl_type_t)]; + struct acl * aclp; char aclp_[PAD_(struct acl *)]; +}; +struct extattrctl_args { + char * path; char path_[PAD_(char *)]; + int cmd; char cmd_[PAD_(int)]; + char * attrname; char attrname_[PAD_(char *)]; + caddr_t arg; char arg_[PAD_(caddr_t)]; +}; +struct extattr_set_file_args { + char * path; char path_[PAD_(char *)]; + char * attrname; char attrname_[PAD_(char *)]; + struct iovec * iovp; char iovp_[PAD_(struct iovec *)]; + u_int iovcnt; char iovcnt_[PAD_(u_int)]; +}; +struct extattr_get_file_args { + char * path; char path_[PAD_(char *)]; + char * attrname; char attrname_[PAD_(char *)]; + struct iovec * iovp; char iovp_[PAD_(struct iovec *)]; + u_int iovcnt; char iovcnt_[PAD_(u_int)]; +}; +struct extattr_delete_file_args { + char * path; char path_[PAD_(char *)]; + char * attrname; char attrname_[PAD_(char *)]; +}; int nosys __P((struct proc *, struct nosys_args *)); void exit __P((struct proc *, struct rexit_args *)) __dead2; int fork __P((struct proc *, struct fork_args *)); @@ -1140,6 +1202,18 @@ int sigsuspend __P((struct proc *, struct sigsuspend_args *)); int sigaction __P((struct proc *, struct sigaction_args *)); int sigpending __P((struct proc *, struct sigpending_args *)); int sigreturn __P((struct proc *, struct sigreturn_args *)); +int acl_syscall_get_file __P((struct proc *, struct acl_syscall_get_file_args *)); +int acl_syscall_set_file __P((struct proc *, struct acl_syscall_set_file_args *)); +int acl_syscall_get_fd __P((struct proc *, struct acl_syscall_get_fd_args *)); +int acl_syscall_set_fd __P((struct proc *, struct acl_syscall_set_fd_args *)); +int acl_syscall_delete_file __P((struct proc *, struct acl_syscall_delete_file_args *)); +int acl_syscall_delete_fd __P((struct proc *, struct acl_syscall_delete_fd_args *)); +int acl_syscall_aclcheck_file __P((struct proc *, struct acl_syscall_aclcheck_file_args *)); +int acl_syscall_aclcheck_fd __P((struct proc *, struct acl_syscall_aclcheck_fd_args *)); +int extattrctl __P((struct proc *, struct extattrctl_args *)); +int extattr_set_file __P((struct proc *, struct extattr_set_file_args *)); +int extattr_get_file __P((struct proc *, struct extattr_get_file_args *)); +int extattr_delete_file __P((struct proc *, struct extattr_delete_file_args *)); #ifdef COMPAT_43 diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index 8046fb8..afb6bfc 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -40,6 +40,7 @@ #include <sys/queue.h> #include <sys/select.h> #include <sys/uio.h> +#include <sys/acl.h> #include <machine/lock.h> diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index 216bb45..ee6fe3e 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -83,6 +83,8 @@ static struct vfsops ufs_vfsops = { ufs_check_export, ffs_vptofh, ffs_init, + vfs_stduninit, + vfs_stdextattrctl, }; VFS_SET(ufs_vfsops, ufs, 0); diff --git a/sys/ufs/mfs/mfs_vfsops.c b/sys/ufs/mfs/mfs_vfsops.c index 268590f..6e034d1 100644 --- a/sys/ufs/mfs/mfs_vfsops.c +++ b/sys/ufs/mfs/mfs_vfsops.c @@ -108,6 +108,8 @@ static struct vfsops mfs_vfsops = { ufs_check_export, ffs_vptofh, mfs_init, + vfs_stduninit, + vfs_stdextattrctl, }; VFS_SET(mfs_vfsops, mfs, 0); |