summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>1999-12-19 06:08:07 +0000
committerrwatson <rwatson@FreeBSD.org>1999-12-19 06:08:07 +0000
commit4b6baecfc724bac12be9de99924e828b1e68046e (patch)
treeccf64e27cf5f979dcaaf7e55bb2a486df8b3f567 /sys/kern
parent114c517da1a1c0bab8d9fa884b67102ec0768fa1 (diff)
downloadFreeBSD-src-4b6baecfc724bac12be9de99924e828b1e68046e.zip
FreeBSD-src-4b6baecfc724bac12be9de99924e828b1e68046e.tar.gz
Second pass commit to introduce new ACL and Extended Attribute system
calls, vnops, vfsops, both in /kern, and to individual file systems that require a vfsop_ array entry. Reviewed by: eivind
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/init_sysent.c14
-rw-r--r--sys/kern/kern_acl.c281
-rw-r--r--sys/kern/makesyscalls.sh1
-rw-r--r--sys/kern/subr_acl_posix1e.c281
-rw-r--r--sys/kern/syscalls.c14
-rw-r--r--sys/kern/vfs_acl.c281
-rw-r--r--sys/kern/vfs_default.c16
-rw-r--r--sys/kern/vfs_extattr.c195
-rw-r--r--sys/kern/vfs_syscalls.c195
-rw-r--r--sys/kern/vnode_if.src57
10 files changed, 1328 insertions, 7 deletions
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;
+};
OpenPOWER on IntegriCloud