ufs_acl.c revision 105179
174822Srwatson/*-
285845Srwatson * Copyright (c) 1999-2001 Robert N. M. Watson
374822Srwatson * All rights reserved.
474822Srwatson *
585845Srwatson * This software was developed by Robert Watson for the TrustedBSD Project.
685845Srwatson *
774822Srwatson * Redistribution and use in source and binary forms, with or without
874822Srwatson * modification, are permitted provided that the following conditions
974822Srwatson * are met:
1074822Srwatson * 1. Redistributions of source code must retain the above copyright
1174822Srwatson *    notice, this list of conditions and the following disclaimer.
1274822Srwatson * 2. Redistributions in binary form must reproduce the above copyright
1374822Srwatson *    notice, this list of conditions and the following disclaimer in the
1474822Srwatson *    documentation and/or other materials provided with the distribution.
1574822Srwatson *
1674822Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1774822Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1874822Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1974822Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2074822Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2174822Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2274822Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2374822Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2474822Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2574822Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2674822Srwatson * SUCH DAMAGE.
2774822Srwatson *
2874822Srwatson * $FreeBSD: head/sys/ufs/ufs/ufs_acl.c 105179 2002-10-15 21:28:24Z rwatson $
2974822Srwatson */
3074822Srwatson/*
3174822Srwatson * Developed by the TrustedBSD Project.
3274822Srwatson * Support for POSIX.1e access control lists: UFS-specific support functions.
3374822Srwatson */
3474822Srwatson
3574822Srwatson#include "opt_ufs.h"
3674822Srwatson#include "opt_quota.h"
3774822Srwatson
3874822Srwatson#include <sys/param.h>
3974822Srwatson#include <sys/systm.h>
4074822Srwatson#include <sys/stat.h>
4174822Srwatson#include <sys/mount.h>
4274822Srwatson#include <sys/vnode.h>
4374822Srwatson#include <sys/types.h>
4474822Srwatson#include <sys/acl.h>
4574822Srwatson#include <sys/event.h>
4674822Srwatson#include <sys/extattr.h>
4774822Srwatson
4874822Srwatson#include <ufs/ufs/quota.h>
4974822Srwatson#include <ufs/ufs/inode.h>
5074822Srwatson#include <ufs/ufs/acl.h>
5174822Srwatson#include <ufs/ufs/extattr.h>
5274822Srwatson#include <ufs/ufs/dir.h>
5374822Srwatson#include <ufs/ufs/ufsmount.h>
5474822Srwatson#include <ufs/ufs/ufs_extern.h>
5574822Srwatson
5674822Srwatson#ifdef UFS_ACL
5774822Srwatson
5874822Srwatson/*
5974822Srwatson * Synchronize an ACL and an inode by copying over appropriate inode fields
6074822Srwatson * to the passed ACL.  Assumes an ACL that would satisfy acl_posix1e_check(),
6174822Srwatson * and may panic if not.
6274822Srwatson */
6374822Srwatsonvoid
6474822Srwatsonufs_sync_acl_from_inode(struct inode *ip, struct acl *acl)
6574822Srwatson{
6674822Srwatson	struct acl_entry	*acl_mask, *acl_group_obj;
6774822Srwatson	int	i;
6874822Srwatson
6974822Srwatson	/*
7074822Srwatson	 * Update ACL_USER_OBJ, ACL_OTHER, but simply identify ACL_MASK
7174822Srwatson	 * and ACL_GROUP_OBJ for use after we know whether ACL_MASK is
7274822Srwatson	 * present.
7374822Srwatson	 */
7474822Srwatson	acl_mask = NULL;
7574822Srwatson	acl_group_obj = NULL;
7674822Srwatson	for (i = 0; i < acl->acl_cnt; i++) {
7774822Srwatson		switch (acl->acl_entry[i].ae_tag) {
7874822Srwatson		case ACL_USER_OBJ:
7974822Srwatson			acl->acl_entry[i].ae_perm = acl_posix1e_mode_to_perm(
8074822Srwatson			    ACL_USER_OBJ, ip->i_mode);
8175571Srwatson			acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID;
8274822Srwatson			break;
8374822Srwatson
8474822Srwatson		case ACL_GROUP_OBJ:
8574822Srwatson			acl_group_obj = &acl->acl_entry[i];
8675571Srwatson			acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID;
8774822Srwatson			break;
8874822Srwatson
8974822Srwatson		case ACL_OTHER:
9074822Srwatson			acl->acl_entry[i].ae_perm = acl_posix1e_mode_to_perm(
9174822Srwatson			    ACL_OTHER, ip->i_mode);
9275571Srwatson			acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID;
9374822Srwatson			break;
9474822Srwatson
9574822Srwatson		case ACL_MASK:
9674822Srwatson			acl_mask = &acl->acl_entry[i];
9775571Srwatson			acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID;
9874822Srwatson			break;
9974822Srwatson
10074822Srwatson		case ACL_USER:
10174822Srwatson		case ACL_GROUP:
10274822Srwatson			break;
10374822Srwatson
10474822Srwatson		default:
10574822Srwatson			panic("ufs_sync_acl_from_inode(): bad ae_tag");
10674822Srwatson		}
10774822Srwatson	}
10874822Srwatson
10974822Srwatson	if (acl_group_obj == NULL)
11074822Srwatson		panic("ufs_sync_acl_from_inode(): no ACL_GROUP_OBJ");
11174822Srwatson
11274822Srwatson	if (acl_mask == NULL) {
11374822Srwatson		/*
11474822Srwatson		 * There is no ACL_MASK, so update ACL_GROUP_OBJ.
11574822Srwatson		 */
11674822Srwatson		acl_group_obj->ae_perm = acl_posix1e_mode_to_perm(
11774822Srwatson		    ACL_GROUP_OBJ, ip->i_mode);
11874822Srwatson	} else {
11974822Srwatson		/*
12074822Srwatson		 * Update the ACL_MASK entry instead of ACL_GROUP_OBJ.
12174822Srwatson		 */
12274822Srwatson		acl_mask->ae_perm = acl_posix1e_mode_to_perm(ACL_GROUP_OBJ,
12374822Srwatson		    ip->i_mode);
12474822Srwatson	}
12574822Srwatson}
12674822Srwatson
12774822Srwatson/*
12874822Srwatson * Synchronize an inode and an ACL by copying over appropriate ACL fields to
12974822Srwatson * the passed inode.  Assumes an ACL that would satisfy acl_posix1e_check(),
13074822Srwatson * and may panic if not.  This code will preserve existing use of the
13174822Srwatson * sticky, setugid, and non-permission bits in the mode field.  It may
13274822Srwatson * be that the caller wishes to have previously authorized these changes,
13374822Srwatson * and may also want to clear the setugid bits in some situations.
13474822Srwatson */
13574822Srwatsonvoid
13674822Srwatsonufs_sync_inode_from_acl(struct acl *acl, struct inode *ip,
13774822Srwatson    mode_t preserve_mask)
13874822Srwatson{
13974822Srwatson	struct acl_entry	*acl_mask, *acl_user_obj, *acl_group_obj;
14074822Srwatson	struct acl_entry	*acl_other;
14174822Srwatson	mode_t	preserve_mode;
14274822Srwatson	int	i;
14374822Srwatson
14474822Srwatson	/*
14574822Srwatson	 * Preserve old mode so we can restore appropriate bits of it.
14674822Srwatson	 */
14774822Srwatson	preserve_mode = (ip->i_mode & preserve_mask);
14874822Srwatson
14974822Srwatson	/*
15074822Srwatson	 * Identify the ACL_MASK and all other entries appearing in the
15174822Srwatson	 * inode mode.
15274822Srwatson	 */
15374822Srwatson	acl_user_obj = NULL;
15474822Srwatson	acl_group_obj = NULL;
15574822Srwatson	acl_other = NULL;
15674822Srwatson	acl_mask = NULL;
15774822Srwatson	for (i = 0; i < acl->acl_cnt; i++) {
15874822Srwatson		switch (acl->acl_entry[i].ae_tag) {
15974822Srwatson		case ACL_USER_OBJ:
16074822Srwatson			acl_user_obj = &acl->acl_entry[i];
16174822Srwatson			break;
16274822Srwatson
16374822Srwatson		case ACL_GROUP_OBJ:
16474822Srwatson			acl_group_obj = &acl->acl_entry[i];
16574822Srwatson			break;
16674822Srwatson
16774822Srwatson		case ACL_OTHER:
16874822Srwatson			acl_other = &acl->acl_entry[i];
16974822Srwatson			break;
17074822Srwatson
17174822Srwatson		case ACL_MASK:
17274822Srwatson			acl_mask = &acl->acl_entry[i];
17374822Srwatson			break;
17474822Srwatson
17574822Srwatson		case ACL_USER:
17674822Srwatson		case ACL_GROUP:
17774822Srwatson			break;
17874822Srwatson
17974822Srwatson		default:
18074822Srwatson			panic("ufs_sync_inode_from_acl(): bad ae_tag");
18174822Srwatson		}
18274822Srwatson	}
18374822Srwatson
18474822Srwatson	if (acl_user_obj == NULL || acl_group_obj == NULL || acl_other == NULL)
18574822Srwatson		panic("ufs_sync_inode_from_acl(): missing ae_tags");
18674822Srwatson
18774822Srwatson	if (acl_mask == NULL) {
18874822Srwatson		/*
18974822Srwatson		 * There is no ACL_MASK, so use the ACL_GROUP_OBJ entry.
19074822Srwatson		 */
19175571Srwatson		ip->i_mode &= ~(S_IRWXU|S_IRWXG|S_IRWXO);
19274822Srwatson		ip->i_mode |= acl_posix1e_perms_to_mode(acl_user_obj,
19374822Srwatson		    acl_group_obj, acl_other);
19498542Smckusick		DIP(ip, i_mode) = ip->i_mode;
19574822Srwatson	} else {
19674822Srwatson		/*
19774822Srwatson		 * Use the ACL_MASK entry.
19874822Srwatson		 */
19975571Srwatson		ip->i_mode &= ~(S_IRWXU|S_IRWXG|S_IRWXO);
20074822Srwatson		ip->i_mode |= acl_posix1e_perms_to_mode(acl_user_obj,
20174822Srwatson		    acl_mask, acl_other);
20298542Smckusick		DIP(ip, i_mode) = ip->i_mode;
20374822Srwatson	}
20474822Srwatson	ip->i_mode |= preserve_mode;
20598542Smckusick	DIP(ip, i_mode) = ip->i_mode;
20674822Srwatson}
20774822Srwatson
20874822Srwatson/*
20974822Srwatson * Retrieve the ACL on a file.
21074822Srwatson *
21174822Srwatson * As part of the ACL is stored in the inode, and the rest in an EA,
21274822Srwatson * assemble both into a final ACL product.  Right now this is not done
21374822Srwatson * very efficiently.
21474822Srwatson */
21574822Srwatsonint
21674822Srwatsonufs_getacl(ap)
21774822Srwatson	struct vop_getacl_args /* {
21874822Srwatson		struct vnode *vp;
21974822Srwatson		struct acl_type_t type;
22074822Srwatson		struct acl *aclp;
22174822Srwatson		struct ucred *cred;
22283366Sjulian		struct thread *td;
22374822Srwatson	} */ *ap;
22474822Srwatson{
22574822Srwatson	struct inode *ip = VTOI(ap->a_vp);
22674822Srwatson	int error, len;
22774822Srwatson
228105179Srwatson	/*
229105179Srwatson	 * XXX: If ufs_getacl() should work on file systems not supporting
230105179Srwatson	 * ACLs, remove this check.
231105179Srwatson	 */
232105179Srwatson	if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0)
233105179Srwatson		return (EOPNOTSUPP);
23474822Srwatson
23574822Srwatson	/*
23674822Srwatson	 * Attempt to retrieve the ACL based on the ACL type.
23774822Srwatson	 */
23874822Srwatson	bzero(ap->a_aclp, sizeof(*ap->a_aclp));
23975077Srwatson	len = sizeof(*ap->a_aclp);
24074822Srwatson	switch(ap->a_type) {
24174822Srwatson	case ACL_TYPE_ACCESS:
24274822Srwatson		/*
24374822Srwatson		 * ACL_TYPE_ACCESS ACLs may or may not be stored in the
24474822Srwatson		 * EA, as they are in fact a combination of the inode
24574822Srwatson		 * ownership/permissions and the EA contents.  If the
24674822Srwatson		 * EA is present, merge the two in a temporary ACL
24774822Srwatson		 * storage, otherwise just return the inode contents.
24874822Srwatson		 */
24974822Srwatson		error = vn_extattr_get(ap->a_vp, IO_NODELOCKED,
25074822Srwatson		    POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE,
25174822Srwatson		    POSIX1E_ACL_ACCESS_EXTATTR_NAME, &len, (char *) ap->a_aclp,
25283366Sjulian		    ap->a_td);
25374822Srwatson		switch (error) {
25496755Strhodes		/* XXX: If ufs_getacl() should work on filesystems without
25574822Srwatson		 * the EA configured, add case EOPNOTSUPP here. */
25691814Sgreen		case ENOATTR:
25774822Srwatson			/*
25874822Srwatson			 * Legitimately no ACL set on object, purely
25974822Srwatson			 * emulate it through the inode.  These fields will
26074822Srwatson			 * be updated when the ACL is synchronized with
26174822Srwatson			 * the inode later.
26274822Srwatson			 */
26374822Srwatson			ap->a_aclp->acl_cnt = 3;
26474822Srwatson			ap->a_aclp->acl_entry[0].ae_tag = ACL_USER_OBJ;
26575571Srwatson			ap->a_aclp->acl_entry[0].ae_id = ACL_UNDEFINED_ID;
26682770Sjedgar			ap->a_aclp->acl_entry[0].ae_perm = ACL_PERM_NONE;
26774822Srwatson			ap->a_aclp->acl_entry[1].ae_tag = ACL_GROUP_OBJ;
26875571Srwatson			ap->a_aclp->acl_entry[1].ae_id = ACL_UNDEFINED_ID;
26982770Sjedgar			ap->a_aclp->acl_entry[1].ae_perm = ACL_PERM_NONE;
27074822Srwatson			ap->a_aclp->acl_entry[2].ae_tag = ACL_OTHER;
27175571Srwatson			ap->a_aclp->acl_entry[2].ae_id = ACL_UNDEFINED_ID;
27282770Sjedgar			ap->a_aclp->acl_entry[2].ae_perm = ACL_PERM_NONE;
27374822Srwatson			ufs_sync_acl_from_inode(ip, ap->a_aclp);
27474822Srwatson			error = 0;
27574822Srwatson			break;
27674822Srwatson
27774822Srwatson		case 0:
27874822Srwatson			if (len != sizeof(*ap->a_aclp)) {
27974822Srwatson				/*
28074822Srwatson				 * A short (or long) read, meaning that for
28174822Srwatson				 * some reason the ACL is corrupted.  Return
28274822Srwatson				 * EPERM since the object DAC protections
28374822Srwatson				 * are unsafe.
28474822Srwatson				 */
28574822Srwatson				printf("ufs_getacl(): Loaded invalid ACL ("
28674822Srwatson				    "%d bytes)\n", len);
28774822Srwatson				return (EPERM);
28874822Srwatson			}
28974822Srwatson			ufs_sync_acl_from_inode(ip, ap->a_aclp);
29074822Srwatson			break;
29174822Srwatson
29297724Salfred		default:
29397724Salfred			break;
29474822Srwatson		}
29574822Srwatson		break;
29674822Srwatson
29774822Srwatson	case ACL_TYPE_DEFAULT:
29874822Srwatson		if (ap->a_vp->v_type != VDIR) {
29974822Srwatson			error = EINVAL;
30074822Srwatson			break;
30174822Srwatson		}
30274822Srwatson		error = vn_extattr_get(ap->a_vp, IO_NODELOCKED,
30374822Srwatson		    POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE,
30474822Srwatson		    POSIX1E_ACL_DEFAULT_EXTATTR_NAME, &len,
30583366Sjulian		    (char *) ap->a_aclp, ap->a_td);
30674822Srwatson		/*
30774822Srwatson		 * Unlike ACL_TYPE_ACCESS, there is no relationship between
30874822Srwatson		 * the inode contents and the ACL, and it is therefore
30974822Srwatson		 * possible for the request for the ACL to fail since the
31074822Srwatson		 * ACL is undefined.  In this situation, return success
31174822Srwatson		 * and an empty ACL, as required by POSIX.1e.
31274822Srwatson		 */
31374822Srwatson		switch (error) {
31496755Strhodes		/* XXX: If ufs_getacl() should work on filesystems without
31574822Srwatson		 * the EA configured, add case EOPNOTSUPP here. */
31691814Sgreen		case ENOATTR:
31774822Srwatson			bzero(ap->a_aclp, sizeof(*ap->a_aclp));
31874822Srwatson			ap->a_aclp->acl_cnt = 0;
31974822Srwatson			error = 0;
32074822Srwatson			break;
32174822Srwatson
32274822Srwatson		case 0:
32375077Srwatson			if (len != sizeof(*ap->a_aclp)) {
32475077Srwatson				/*
32575077Srwatson				 * A short (or long) read, meaning that for
32675077Srwatson				 * some reason the ACL is corrupted.  Return
32775077Srwatson				 * EPERM since the object default DAC
32875077Srwatson				 * protections are unsafe.
32975077Srwatson				 */
33075077Srwatson				printf("ufs_getacl(): Loaded invalid ACL ("
33175077Srwatson				    "%d bytes)\n", len);
33275077Srwatson				return (EPERM);
33375077Srwatson			}
33474822Srwatson			break;
33574822Srwatson
33697724Salfred		default:
33797724Salfred			break;
33874822Srwatson		}
33974822Srwatson		break;
34074822Srwatson
34174822Srwatson	default:
34274822Srwatson		error = EINVAL;
34374822Srwatson	}
34474822Srwatson
34574822Srwatson	return (error);
34674822Srwatson}
34774822Srwatson
34874822Srwatson/*
34974822Srwatson * Set the ACL on a file.
35074822Srwatson *
35174822Srwatson * As part of the ACL is stored in the inode, and the rest in an EA,
35274822Srwatson * this is necessarily non-atomic, and has complex authorization.
35374822Srwatson * As ufs_setacl() includes elements of ufs_chown() and ufs_chmod(),
35474822Srwatson * a fair number of different access checks may be required to go ahead
35574822Srwatson * with the operation at all.
35674822Srwatson */
35774822Srwatsonint
35874822Srwatsonufs_setacl(ap)
35974822Srwatson	struct vop_setacl_args /* {
36074822Srwatson		struct vnode *vp;
36174822Srwatson		acl_type_t type;
36274822Srwatson		struct acl *aclp;
36374822Srwatson		struct ucred *cred;
36474822Srwatson		struct proc *p;
36574822Srwatson	} */ *ap;
36674822Srwatson{
36774822Srwatson	struct inode *ip = VTOI(ap->a_vp);
36874822Srwatson	mode_t old_mode, preserve_mask;
36975571Srwatson	int error;
37074822Srwatson
371105179Srwatson	if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0)
372105179Srwatson		return (EOPNOTSUPP);
373105179Srwatson
37474822Srwatson	/*
37574822Srwatson	 * If this is a set operation rather than a delete operation,
37674822Srwatson	 * invoke VOP_ACLCHECK() on the passed ACL to determine if it is
37774822Srwatson	 * valid for the target.  This will include a check on ap->a_type.
37874822Srwatson	 */
37974822Srwatson	if (ap->a_aclp != NULL) {
38074822Srwatson		/*
38174822Srwatson		 * Set operation.
38274822Srwatson		 */
38374822Srwatson		error = VOP_ACLCHECK(ap->a_vp, ap->a_type, ap->a_aclp,
38483366Sjulian		    ap->a_cred, ap->a_td);
38574822Srwatson		if (error != 0)
38674822Srwatson			return (error);
38774822Srwatson	} else {
38874822Srwatson		/*
38974822Srwatson		 * Delete operation.
39074822Srwatson		 * POSIX.1e allows only deletion of the default ACL on a
39174822Srwatson		 * directory (ACL_TYPE_DEFAULT).
39274822Srwatson		 */
39374822Srwatson		if (ap->a_type != ACL_TYPE_DEFAULT)
39474822Srwatson			return (EINVAL);
39574822Srwatson		if (ap->a_vp->v_type != VDIR)
39674822Srwatson			return (ENOTDIR);
39774822Srwatson	}
39874822Srwatson
39974822Srwatson	if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
40074822Srwatson		return (EROFS);
40174822Srwatson
40274822Srwatson	/*
40374822Srwatson	 * Authorize the ACL operation.
40474822Srwatson	 */
40574822Srwatson	if (ip->i_flags & (IMMUTABLE | APPEND))
40674822Srwatson		return (EPERM);
40774822Srwatson
40874822Srwatson	/*
40974822Srwatson	 * Must hold VADMIN (be file owner) or have appropriate privilege.
41074822Srwatson	 */
41183366Sjulian	if ((error = VOP_ACCESS(ap->a_vp, VADMIN, ap->a_cred, ap->a_td)))
41274822Srwatson		return (error);
41374822Srwatson
41474822Srwatson	switch(ap->a_type) {
41574822Srwatson	case ACL_TYPE_ACCESS:
41674822Srwatson		error = vn_extattr_set(ap->a_vp, IO_NODELOCKED,
41774822Srwatson		    POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE,
41874822Srwatson		    POSIX1E_ACL_ACCESS_EXTATTR_NAME, sizeof(*ap->a_aclp),
41983366Sjulian		    (char *) ap->a_aclp, ap->a_td);
42074822Srwatson		break;
42174822Srwatson
42274822Srwatson	case ACL_TYPE_DEFAULT:
42374822Srwatson		if (ap->a_aclp == NULL) {
42474822Srwatson			error = vn_extattr_rm(ap->a_vp, IO_NODELOCKED,
42574822Srwatson			    POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE,
42683366Sjulian			    POSIX1E_ACL_DEFAULT_EXTATTR_NAME, ap->a_td);
42774822Srwatson			/*
42874822Srwatson			 * Attempting to delete a non-present default ACL
42974822Srwatson			 * will return success for portability purposes.
43074822Srwatson			 * (TRIX)
43185581Srwatson			 *
43285581Srwatson			 * XXX: Note that since we can't distinguish
43385581Srwatson			 * "that EA is not supported" from "that EA is not
43485581Srwatson			 * defined", the success case here overlaps the
43591814Sgreen			 * the ENOATTR->EOPNOTSUPP case below.
43674822Srwatson		 	 */
43791814Sgreen			if (error == ENOATTR)
43874822Srwatson				error = 0;
43974822Srwatson		} else
44074822Srwatson			error = vn_extattr_set(ap->a_vp, IO_NODELOCKED,
44174822Srwatson			    POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE,
44274822Srwatson			    POSIX1E_ACL_DEFAULT_EXTATTR_NAME,
44383366Sjulian			    sizeof(*ap->a_aclp), (char *) ap->a_aclp, ap->a_td);
44474822Srwatson		break;
44574822Srwatson
44674822Srwatson	default:
44774822Srwatson		error = EINVAL;
44874822Srwatson	}
44974822Srwatson	/*
45074822Srwatson	 * Map lack of attribute definition in UFS_EXTATTR into lack of
45196755Strhodes	 * support for ACLs on the filesystem.
45274822Srwatson	 */
45391814Sgreen	if (error == ENOATTR)
45474822Srwatson		return (EOPNOTSUPP);
45574822Srwatson	if (error != 0)
45674822Srwatson		return (error);
45774822Srwatson
45874822Srwatson	if (ap->a_type == ACL_TYPE_ACCESS) {
45974822Srwatson		/*
46074822Srwatson		 * Now that the EA is successfully updated, update the
46174822Srwatson		 * inode and mark it as changed.
46274822Srwatson		 */
46374822Srwatson		old_mode = ip->i_mode;
46474822Srwatson		preserve_mask = ISVTX | ISGID | ISUID;
46574822Srwatson		ufs_sync_inode_from_acl(ap->a_aclp, ip, preserve_mask);
46674822Srwatson		ip->i_flag |= IN_CHANGE;
46774822Srwatson	}
46874822Srwatson
46974822Srwatson	VN_KNOTE(ap->a_vp, NOTE_ATTRIB);
47074822Srwatson	return (0);
47174822Srwatson}
47274822Srwatson
47374822Srwatson/*
47474822Srwatson * Check the validity of an ACL for a file.
47574822Srwatson */
47674822Srwatsonint
47774822Srwatsonufs_aclcheck(ap)
47874822Srwatson	struct vop_aclcheck_args /* {
47974822Srwatson		struct vnode *vp;
48074822Srwatson		acl_type_t type;
48174822Srwatson		struct acl *aclp;
48274822Srwatson		struct ucred *cred;
48383366Sjulian		struct thread *td;
48474822Srwatson	} */ *ap;
48574822Srwatson{
48674822Srwatson
487105179Srwatson	if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0)
488105179Srwatson		return (EOPNOTSUPP);
489105179Srwatson
49074822Srwatson	/*
49174822Srwatson	 * Verify we understand this type of ACL, and that it applies
49274822Srwatson	 * to this kind of object.
49374822Srwatson	 * Rely on the acl_posix1e_check() routine to verify the contents.
49474822Srwatson	 */
49574822Srwatson	switch(ap->a_type) {
49674822Srwatson	case ACL_TYPE_ACCESS:
49774822Srwatson		break;
49874822Srwatson
49974822Srwatson	case ACL_TYPE_DEFAULT:
50074822Srwatson		if (ap->a_vp->v_type != VDIR)
50174822Srwatson			return (EINVAL);
50274822Srwatson		break;
50374822Srwatson
50474822Srwatson	default:
50574822Srwatson		return (EINVAL);
50674822Srwatson	}
50774822Srwatson	return (acl_posix1e_check(ap->a_aclp));
50874822Srwatson}
50974822Srwatson
51074822Srwatson#endif /* !UFS_ACL */
511