/*
* Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
*
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License"). You may not use this file except in compliance with the
- * License. Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
- *
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the
+ * License may not be used to create, or enable the creation or
+ * redistribution of, unlawful or unlicensed copies of an Apple operating
+ * system, or to circumvent, violate, or enable the circumvention or
+ * violation of, any terms of an Apple operating system software license
+ * agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
*/
/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
/*
#include <kern/assert.h>
#include <kern/kalloc.h>
+#include <libkern/OSByteOrder.h>
+
#include <miscfs/specfs/specdev.h>
#include <mach/mach_types.h>
return vp;
}
+/*
+ * Get a filesec and optional acl contents from an extended attribute.
+ * Function will attempt to retrive ACL, UUID, and GUID information using a
+ * read of a named extended attribute (KAUTH_FILESEC_XATTR).
+ *
+ * Parameters: vp The vnode on which to operate.
+ * fsecp The filesec (and ACL, if any) being
+ * retrieved.
+ * ctx The vnode context in which the
+ * operation is to be attempted.
+ *
+ * Returns: 0 Success
+ * !0 errno value
+ *
+ * Notes: The kauth_filesec_t in '*fsecp', if retrieved, will be in
+ * host byte order, as will be the ACL contents, if any.
+ * Internally, we will cannonize these values from network (PPC)
+ * byte order after we retrieve them so that the on-disk contents
+ * of the extended attribute are identical for both PPC and Intel
+ * (if we were not being required to provide this service via
+ * fallback, this would be the job of the filesystem
+ * 'VNOP_GETATTR' call).
+ *
+ * We use ntohl() because it has a transitive property on Intel
+ * machines and no effect on PPC mancines. This guarantees us
+ *
+ * XXX: Deleting rather than ignoreing a corrupt security structure is
+ * probably the only way to reset it without assistance from an
+ * file system integrity checking tool. Right now we ignore it.
+ *
+ * XXX: We should enummerate the possible errno values here, and where
+ * in the code they originated.
+ */
static int
vnode_get_filesec(vnode_t vp, kauth_filesec_t *fsecp, vfs_context_t ctx)
{
size_t fsec_size;
size_t xsize, rsize;
int error;
+ int i;
+ uint32_t host_fsec_magic;
+ uint32_t host_acl_entrycount;
fsec = NULL;
fsec_uio = NULL;
}
/*
- * Validate security structure. If it's corrupt, we will
- * just ignore it.
+ * Validate security structure; the validation must take place in host
+ * byte order. If it's corrupt, we will just ignore it.
*/
+
+ /* Validate the size before trying to convert it */
if (rsize < KAUTH_FILESEC_SIZE(0)) {
KAUTH_DEBUG("ACL - DATA TOO SMALL (%d)", rsize);
goto out;
}
- if (fsec->fsec_magic != KAUTH_FILESEC_MAGIC) {
- KAUTH_DEBUG("ACL - BAD MAGIC %x", fsec->fsec_magic);
- goto out;
- }
- if ((fsec->fsec_acl.acl_entrycount != KAUTH_FILESEC_NOACL) &&
- (fsec->fsec_acl.acl_entrycount > KAUTH_ACL_MAX_ENTRIES)) {
- KAUTH_DEBUG("ACL - BAD ENTRYCOUNT %x", fsec->fsec_entrycount);
+
+ /* Validate the magic number before trying to convert it */
+ host_fsec_magic = ntohl(KAUTH_FILESEC_MAGIC);
+ if (fsec->fsec_magic != host_fsec_magic) {
+ KAUTH_DEBUG("ACL - BAD MAGIC %x", host_fsec_magic);
goto out;
}
- if ((fsec->fsec_acl.acl_entrycount != KAUTH_FILESEC_NOACL) &&
- (KAUTH_FILESEC_SIZE(fsec->fsec_acl.acl_entrycount) > rsize)) {
- KAUTH_DEBUG("ACL - BUFFER OVERFLOW (%d entries too big for %d)", fsec->fsec_acl.acl_entrycount, rsize);
- goto out;
+
+ /* Validate the entry count before trying to convert it. */
+ host_acl_entrycount = ntohl(fsec->fsec_acl.acl_entrycount);
+ if (host_acl_entrycount != KAUTH_FILESEC_NOACL) {
+ if (host_acl_entrycount > KAUTH_ACL_MAX_ENTRIES) {
+ KAUTH_DEBUG("ACL - BAD ENTRYCOUNT %x", host_acl_entrycount);
+ goto out;
+ }
+ if (KAUTH_FILESEC_SIZE(host_acl_entrycount) > rsize) {
+ KAUTH_DEBUG("ACL - BUFFER OVERFLOW (%d entries too big for %d)", host_acl_entrycount, rsize);
+ goto out;
+ }
}
+ kauth_filesec_acl_setendian(KAUTH_ENDIAN_HOST, fsec, NULL);
+
*fsecp = fsec;
fsec = NULL;
error = 0;
return(error);
}
+/*
+ * Set a filesec and optional acl contents into an extended attribute.
+ * function will attempt to store ACL, UUID, and GUID information using a
+ * write to a named extended attribute (KAUTH_FILESEC_XATTR). The 'acl'
+ * may or may not point to the `fsec->fsec_acl`, depending on whether the
+ * original caller supplied an acl.
+ *
+ * Parameters: vp The vnode on which to operate.
+ * fsec The filesec being set.
+ * acl The acl to be associated with 'fsec'.
+ * ctx The vnode context in which the
+ * operation is to be attempted.
+ *
+ * Returns: 0 Success
+ * !0 errno value
+ *
+ * Notes: Both the fsec and the acl are always valid.
+ *
+ * The kauth_filesec_t in 'fsec', if any, is in host byte order,
+ * as are the acl contents, if they are used. Internally, we will
+ * cannonize these values into network (PPC) byte order before we
+ * attempt to write them so that the on-disk contents of the
+ * extended attribute are identical for both PPC and Intel (if we
+ * were not being required to provide this service via fallback,
+ * this would be the job of the filesystem 'VNOP_SETATTR' call).
+ * We reverse this process on the way out, so we leave with the
+ * same byte order we started with.
+ *
+ * XXX: We should enummerate the possible errno values here, and where
+ * in the code they originated.
+ */
static int
vnode_set_filesec(vnode_t vp, kauth_filesec_t fsec, kauth_acl_t acl, vfs_context_t ctx)
{
- uio_t fsec_uio;
- int error;
+ uio_t fsec_uio;
+ int error;
+ int i;
+ uint32_t saved_acl_copysize;
fsec_uio = NULL;
error = ENOMEM;
goto out;
}
+ /*
+ * Save the pre-converted ACL copysize, because it gets swapped too
+ * if we are running with the wrong endianness.
+ */
+ saved_acl_copysize = KAUTH_ACL_COPYSIZE(acl);
+
+ kauth_filesec_acl_setendian(KAUTH_ENDIAN_DISK, fsec, acl);
+
uio_addiov(fsec_uio, CAST_USER_ADDR_T(fsec), sizeof(struct kauth_filesec) - sizeof(struct kauth_acl));
- uio_addiov(fsec_uio, CAST_USER_ADDR_T(acl), KAUTH_ACL_COPYSIZE(acl));
+ uio_addiov(fsec_uio, CAST_USER_ADDR_T(acl), saved_acl_copysize);
error = vn_setxattr(vp,
KAUTH_FILESEC_XATTR,
fsec_uio,
ctx);
VFS_DEBUG(ctx, vp, "SETATTR - set ACL returning %d", error);
+ kauth_filesec_acl_setendian(KAUTH_ENDIAN_HOST, fsec, acl);
+
out:
if (fsec_uio != NULL)
uio_free(fsec_uio);
return(error);
}
+/*
+ * Set the attributes on a vnode in a vnode context.
+ *
+ * Parameters: vp The vnode whose attributes to set.
+ * vap A pointer to the attributes to set.
+ * ctx The vnode context in which the
+ * operation is to be attempted.
+ *
+ * Returns: 0 Success
+ * !0 errno value
+ *
+ * Notes: The kauth_filesec_t in 'vap', if any, is in host byte order.
+ *
+ * The contents of the data area pointed to by 'vap' may be
+ * modified if the vnode is on a filesystem which has been
+ * mounted with ingore ownership flags, or by the underlyng
+ * VFS itself, or by the fallback code, if the underlying VFS
+ * does not support ACL, UUID, or GUUID attributes directly.
+ *
+ * XXX: We should enummerate the possible errno values here, and where
+ * in the code they originated.
+ */
int
vnode_setattr(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
{
* Make sure the filesystem is mounted R/W.
* If not, return an error.
*/
- if (vfs_isrdonly(vp->v_mount))
- return(EROFS);
+ if (vfs_isrdonly(vp->v_mount)) {
+ error = EROFS;
+ goto out;
+ }
/*
* If ownership is being ignored on this volume, we silently discard
if (!vfs_extendedsecurity(vnode_mount(vp)) &&
(VATTR_IS_ACTIVE(vap, va_acl) || VATTR_IS_ACTIVE(vap, va_uuuid) || VATTR_IS_ACTIVE(vap, va_guuid))) {
KAUTH_DEBUG("SETATTR - returning ENOTSUP to request to set extended security");
- return(ENOTSUP);
+ error = ENOTSUP;
+ goto out;
}
error = VNOP_SETATTR(vp, vap, ctx);
add_fsevent(FSE_CHOWN, ctx, FSE_ARG_VNODE, vp, FSE_ARG_DONE);
}
}
+
+out:
return(error);
}
/*
- * Following an operation which sets attributes (setattr, create, etc.) we may
- * need to perform fallback operations to get attributes saved.
- */
+ * Fallback for setting the attributes on a vnode in a vnode context. This
+ * Function will attempt to store ACL, UUID, and GUID information utilizing
+ * a read/modify/write operation against an EA used as a backing store for
+ * the object.
+ *
+ * Parameters: vp The vnode whose attributes to set.
+ * vap A pointer to the attributes to set.
+ * ctx The vnode context in which the
+ * operation is to be attempted.
+ *
+ * Returns: 0 Success
+ * !0 errno value
+ *
+ * Notes: The kauth_filesec_t in 'vap', if any, is in host byte order,
+ * as are the fsec and lfsec, if they are used.
+ *
+ * The contents of the data area pointed to by 'vap' may be
+ * modified to indicate that the attribute is supported for
+ * any given requested attribute.
+ *
+ * XXX: We should enummerate the possible errno values here, and where
+ * in the code they originated.
+ */
int
vnode_setattr_fallback(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
{
/*
* Extended security fallback via extended attributes.
*
- * Note that we do not free the filesec; the caller is expected to do this.
+ * Note that we do not free the filesec; the caller is expected to
+ * do this.
*/
if (VATTR_NOT_RETURNED(vap, va_acl) ||
VATTR_NOT_RETURNED(vap, va_uuuid) ||
VFS_DEBUG(ctx, vp, "SETATTR - doing filesec fallback");
/*
- * Fail for file types that we don't permit extended security to be set on.
+ * Fail for file types that we don't permit extended security
+ * to be set on.
*/
if ((vp->v_type != VDIR) && (vp->v_type != VLNK) && (vp->v_type != VREG)) {
VFS_DEBUG(ctx, vp, "SETATTR - Can't write ACL to file type %d", vnode_vtype(vp));
}
/*
- * If we don't have all the extended security items, we need to fetch the existing
- * data to perform a read-modify-write operation.
+ * If we don't have all the extended security items, we need
+ * to fetch the existing data to perform a read-modify-write
+ * operation.
*/
fsec = NULL;
if (!VATTR_IS_ACTIVE(vap, va_acl) ||
}
/*
- * If the filesec data is all invalid, we can just remove the EA completely.
+ * If the filesec data is all invalid, we can just remove
+ * the EA completely.
*/
if ((facl->acl_entrycount == KAUTH_FILESEC_NOACL) &&
kauth_guid_equal(&fsec->fsec_owner, &kauth_null_guid) &&