In my first reading of POSIX.1e, I misinterpreted handling of the
ACL_USER_OBJ and ACL_GROUP_OBJ fields, believing that modification of the access ACL could be used by privileged processes to change file/directory ownership. In fact, this is incorrect; ACL_*_OBJ (+ ACL_MASK and ACL_OTHER) should have undefined ae_id fields; this commit attempts to correct that misunderstanding. o Modify arguments to vaccess_acl_posix1e() to accept the uid and gid associated with the vnode, as those can no longer be extracted from the ACL passed as an argument. Perform all comparisons against the passed arguments. This actually has the effect of simplifying a number of components of this call, as well as reducing the indent level, but now seperates handling of ACL_GROUP_OBJ from ACL_GROUP. o Modify acl_posix1e_check() to return EINVAL if the ae_id field of any of the ACL_{USER_OBJ,GROUP_OBJ,MASK,OTHER} entries is a value other than ACL_UNDEFINED_ID. As a temporary work-around to allow clean upgrades, set the ae_id field to ACL_UNDEFINED_ID before each check so that this cannot cause a failure in the short term (this work-around will be removed when the userland libraries and utilities are updated to take this change into account). o Modify ufs_sync_acl_from_inode() so that it forces ACL_{USER_OBJ,GROUP_OBJ,MASK,OTHER} ae_id fields to ACL_UNDEFINED_ID when synchronizing the ACL from the inode. o Modify ufs_sync_inode_from_acl to not propagate uid and gid information to the inode from the ACL during ACL update. Also modify the masking of permission bits that may be set from ALLPERMS to (S_IRWXU|S_IRWXG|S_IRWXO), as ACLs currently do not carry none-ACCESSPERMS (S_ISUID, S_ISGID, S_ISTXT). o Modify ufs_getacl() so that when it emulates an access ACL from the inode, it initializes the ae_id fields to ACL_UNDEFINED_ID. o Clean up ufs_setacl() substantially since it is no longer possible to perform chown/chgrp operations using vop_setacl(), so all the access control for that can be eliminated. o Modify ufs_access() so that it passes owner uid and gid information into vaccess_acl_posix1e(). Pointed out by: jedger Obtained from: TrustedBSD Project
This commit is contained in:
parent
10335cc26a
commit
4d8f0e847f
@ -51,8 +51,8 @@ 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);
|
||||
static int vacl_aclcheck(struct proc *p, struct vnode *vp,
|
||||
acl_type_t type, struct acl *aclp);
|
||||
|
||||
/*
|
||||
* Implement a version of vaccess() that understands POSIX.1e ACL semantics.
|
||||
@ -60,8 +60,8 @@ static int vacl_aclcheck(struct proc *p, struct vnode *vp, acl_type_t type,
|
||||
* vaccess() eventually.
|
||||
*/
|
||||
int
|
||||
vaccess_acl_posix1e(enum vtype type, struct acl *acl, mode_t acc_mode,
|
||||
struct ucred *cred, int *privused)
|
||||
vaccess_acl_posix1e(enum vtype type, uid_t file_uid, gid_t file_gid,
|
||||
struct acl *acl, mode_t acc_mode, struct ucred *cred, int *privused)
|
||||
{
|
||||
struct acl_entry *acl_other, *acl_mask;
|
||||
mode_t dac_granted;
|
||||
@ -123,7 +123,7 @@ vaccess_acl_posix1e(enum vtype type, struct acl *acl, mode_t acc_mode,
|
||||
for (i = 0; i < acl->acl_cnt; i++) {
|
||||
switch (acl->acl_entry[i].ae_tag) {
|
||||
case ACL_USER_OBJ:
|
||||
if (acl->acl_entry[i].ae_id != cred->cr_uid)
|
||||
if (file_uid != cred->cr_uid)
|
||||
break;
|
||||
dac_granted = 0;
|
||||
dac_granted |= VADMIN;
|
||||
@ -209,13 +209,13 @@ vaccess_acl_posix1e(enum vtype type, struct acl *acl, mode_t acc_mode,
|
||||
dac_granted &= acl_mask_granted;
|
||||
if ((acc_mode & dac_granted) == acc_mode)
|
||||
return (0);
|
||||
if ((acc_mode & (dac_granted | cap_granted)) ==
|
||||
acc_mode) {
|
||||
if (privused != NULL)
|
||||
*privused = 1;
|
||||
return (0);
|
||||
}
|
||||
goto error;
|
||||
if ((acc_mode & (dac_granted | cap_granted)) !=
|
||||
acc_mode)
|
||||
goto error;
|
||||
|
||||
if (privused != NULL)
|
||||
*privused = 1;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,22 +229,41 @@ vaccess_acl_posix1e(enum vtype type, struct acl *acl, mode_t acc_mode,
|
||||
for (i = 0; i < acl->acl_cnt; i++) {
|
||||
switch (acl->acl_entry[i].ae_tag) {
|
||||
case ACL_GROUP_OBJ:
|
||||
if (file_gid != cred->cr_groups[0])
|
||||
break;
|
||||
dac_granted = 0;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
|
||||
dac_granted |= VEXEC;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_READ)
|
||||
dac_granted |= VREAD;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_WRITE)
|
||||
dac_granted |= VWRITE;
|
||||
dac_granted &= acl_mask_granted;
|
||||
|
||||
if ((acc_mode & dac_granted) == acc_mode)
|
||||
return (0);
|
||||
|
||||
group_matched = 1;
|
||||
break;
|
||||
|
||||
case ACL_GROUP:
|
||||
if (groupmember(acl->acl_entry[i].ae_id, cred)) {
|
||||
dac_granted = 0;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
|
||||
dac_granted |= VEXEC;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_READ)
|
||||
dac_granted |= VREAD;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_WRITE)
|
||||
dac_granted |= VWRITE;
|
||||
dac_granted &= acl_mask_granted;
|
||||
if (!groupmember(acl->acl_entry[i].ae_id, cred))
|
||||
break;
|
||||
dac_granted = 0;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
|
||||
dac_granted |= VEXEC;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_READ)
|
||||
dac_granted |= VREAD;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_WRITE)
|
||||
dac_granted |= VWRITE;
|
||||
dac_granted &= acl_mask_granted;
|
||||
|
||||
if ((acc_mode & dac_granted) == acc_mode)
|
||||
return (0);
|
||||
if ((acc_mode & dac_granted) == acc_mode)
|
||||
return (0);
|
||||
|
||||
group_matched = 1;
|
||||
break;
|
||||
|
||||
group_matched = 1;
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
@ -257,27 +276,46 @@ vaccess_acl_posix1e(enum vtype type, struct acl *acl, mode_t acc_mode,
|
||||
for (i = 0; i < acl->acl_cnt; i++) {
|
||||
switch (acl->acl_entry[i].ae_tag) {
|
||||
case ACL_GROUP_OBJ:
|
||||
case ACL_GROUP:
|
||||
if (groupmember(acl->acl_entry[i].ae_id,
|
||||
cred)) {
|
||||
dac_granted = 0;
|
||||
if (acl->acl_entry[i].ae_perm &
|
||||
ACL_EXECUTE)
|
||||
if (file_gid != cred->cr_groups[0])
|
||||
break;
|
||||
dac_granted = 0;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
|
||||
dac_granted |= VEXEC;
|
||||
if (acl->acl_entry[i].ae_perm &
|
||||
ACL_READ)
|
||||
dac_granted |= VREAD;
|
||||
if (acl->acl_entry[i].ae_perm &
|
||||
ACL_WRITE)
|
||||
dac_granted |= VWRITE;
|
||||
dac_granted &= acl_mask_granted;
|
||||
if ((acc_mode & (dac_granted |
|
||||
cap_granted)) == acc_mode) {
|
||||
if (privused != NULL)
|
||||
*privused = 1;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
if (acl->acl_entry[i].ae_perm & ACL_READ)
|
||||
dac_granted |= VREAD;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_WRITE)
|
||||
dac_granted |= VWRITE;
|
||||
dac_granted &= acl_mask_granted;
|
||||
|
||||
if ((acc_mode & (dac_granted | cap_granted)) !=
|
||||
acc_mode)
|
||||
break;
|
||||
|
||||
if (privused != NULL)
|
||||
*privused = 1;
|
||||
return (0);
|
||||
|
||||
case ACL_GROUP:
|
||||
if (!groupmember(acl->acl_entry[i].ae_id,
|
||||
cred))
|
||||
break;
|
||||
dac_granted = 0;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
|
||||
dac_granted |= VEXEC;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_READ)
|
||||
dac_granted |= VREAD;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_WRITE)
|
||||
dac_granted |= VWRITE;
|
||||
dac_granted &= acl_mask_granted;
|
||||
|
||||
if ((acc_mode & (dac_granted | cap_granted)) !=
|
||||
acc_mode)
|
||||
break;
|
||||
|
||||
if (privused != NULL)
|
||||
*privused = 1;
|
||||
return (0);
|
||||
|
||||
default:
|
||||
}
|
||||
}
|
||||
@ -454,21 +492,37 @@ acl_posix1e_check(struct acl *acl)
|
||||
*/
|
||||
switch(acl->acl_entry[i].ae_tag) {
|
||||
case ACL_USER_OBJ:
|
||||
acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
|
||||
if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
|
||||
return (EINVAL);
|
||||
num_acl_user_obj++;
|
||||
break;
|
||||
case ACL_GROUP_OBJ:
|
||||
acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
|
||||
if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
|
||||
return (EINVAL);
|
||||
num_acl_group_obj++;
|
||||
break;
|
||||
case ACL_USER:
|
||||
if (acl->acl_entry[i].ae_id == ACL_UNDEFINED_ID)
|
||||
return (EINVAL);
|
||||
num_acl_user++;
|
||||
break;
|
||||
case ACL_GROUP:
|
||||
if (acl->acl_entry[i].ae_id == ACL_UNDEFINED_ID)
|
||||
return (EINVAL);
|
||||
num_acl_group++;
|
||||
break;
|
||||
case ACL_OTHER:
|
||||
acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
|
||||
if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
|
||||
return (EINVAL);
|
||||
num_acl_other++;
|
||||
break;
|
||||
case ACL_MASK:
|
||||
acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
|
||||
if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
|
||||
return (EINVAL);
|
||||
num_acl_mask++;
|
||||
break;
|
||||
default:
|
||||
|
@ -51,8 +51,8 @@ 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);
|
||||
static int vacl_aclcheck(struct proc *p, struct vnode *vp,
|
||||
acl_type_t type, struct acl *aclp);
|
||||
|
||||
/*
|
||||
* Implement a version of vaccess() that understands POSIX.1e ACL semantics.
|
||||
@ -60,8 +60,8 @@ static int vacl_aclcheck(struct proc *p, struct vnode *vp, acl_type_t type,
|
||||
* vaccess() eventually.
|
||||
*/
|
||||
int
|
||||
vaccess_acl_posix1e(enum vtype type, struct acl *acl, mode_t acc_mode,
|
||||
struct ucred *cred, int *privused)
|
||||
vaccess_acl_posix1e(enum vtype type, uid_t file_uid, gid_t file_gid,
|
||||
struct acl *acl, mode_t acc_mode, struct ucred *cred, int *privused)
|
||||
{
|
||||
struct acl_entry *acl_other, *acl_mask;
|
||||
mode_t dac_granted;
|
||||
@ -123,7 +123,7 @@ vaccess_acl_posix1e(enum vtype type, struct acl *acl, mode_t acc_mode,
|
||||
for (i = 0; i < acl->acl_cnt; i++) {
|
||||
switch (acl->acl_entry[i].ae_tag) {
|
||||
case ACL_USER_OBJ:
|
||||
if (acl->acl_entry[i].ae_id != cred->cr_uid)
|
||||
if (file_uid != cred->cr_uid)
|
||||
break;
|
||||
dac_granted = 0;
|
||||
dac_granted |= VADMIN;
|
||||
@ -209,13 +209,13 @@ vaccess_acl_posix1e(enum vtype type, struct acl *acl, mode_t acc_mode,
|
||||
dac_granted &= acl_mask_granted;
|
||||
if ((acc_mode & dac_granted) == acc_mode)
|
||||
return (0);
|
||||
if ((acc_mode & (dac_granted | cap_granted)) ==
|
||||
acc_mode) {
|
||||
if (privused != NULL)
|
||||
*privused = 1;
|
||||
return (0);
|
||||
}
|
||||
goto error;
|
||||
if ((acc_mode & (dac_granted | cap_granted)) !=
|
||||
acc_mode)
|
||||
goto error;
|
||||
|
||||
if (privused != NULL)
|
||||
*privused = 1;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,22 +229,41 @@ vaccess_acl_posix1e(enum vtype type, struct acl *acl, mode_t acc_mode,
|
||||
for (i = 0; i < acl->acl_cnt; i++) {
|
||||
switch (acl->acl_entry[i].ae_tag) {
|
||||
case ACL_GROUP_OBJ:
|
||||
if (file_gid != cred->cr_groups[0])
|
||||
break;
|
||||
dac_granted = 0;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
|
||||
dac_granted |= VEXEC;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_READ)
|
||||
dac_granted |= VREAD;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_WRITE)
|
||||
dac_granted |= VWRITE;
|
||||
dac_granted &= acl_mask_granted;
|
||||
|
||||
if ((acc_mode & dac_granted) == acc_mode)
|
||||
return (0);
|
||||
|
||||
group_matched = 1;
|
||||
break;
|
||||
|
||||
case ACL_GROUP:
|
||||
if (groupmember(acl->acl_entry[i].ae_id, cred)) {
|
||||
dac_granted = 0;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
|
||||
dac_granted |= VEXEC;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_READ)
|
||||
dac_granted |= VREAD;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_WRITE)
|
||||
dac_granted |= VWRITE;
|
||||
dac_granted &= acl_mask_granted;
|
||||
if (!groupmember(acl->acl_entry[i].ae_id, cred))
|
||||
break;
|
||||
dac_granted = 0;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
|
||||
dac_granted |= VEXEC;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_READ)
|
||||
dac_granted |= VREAD;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_WRITE)
|
||||
dac_granted |= VWRITE;
|
||||
dac_granted &= acl_mask_granted;
|
||||
|
||||
if ((acc_mode & dac_granted) == acc_mode)
|
||||
return (0);
|
||||
if ((acc_mode & dac_granted) == acc_mode)
|
||||
return (0);
|
||||
|
||||
group_matched = 1;
|
||||
break;
|
||||
|
||||
group_matched = 1;
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
@ -257,27 +276,46 @@ vaccess_acl_posix1e(enum vtype type, struct acl *acl, mode_t acc_mode,
|
||||
for (i = 0; i < acl->acl_cnt; i++) {
|
||||
switch (acl->acl_entry[i].ae_tag) {
|
||||
case ACL_GROUP_OBJ:
|
||||
case ACL_GROUP:
|
||||
if (groupmember(acl->acl_entry[i].ae_id,
|
||||
cred)) {
|
||||
dac_granted = 0;
|
||||
if (acl->acl_entry[i].ae_perm &
|
||||
ACL_EXECUTE)
|
||||
if (file_gid != cred->cr_groups[0])
|
||||
break;
|
||||
dac_granted = 0;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
|
||||
dac_granted |= VEXEC;
|
||||
if (acl->acl_entry[i].ae_perm &
|
||||
ACL_READ)
|
||||
dac_granted |= VREAD;
|
||||
if (acl->acl_entry[i].ae_perm &
|
||||
ACL_WRITE)
|
||||
dac_granted |= VWRITE;
|
||||
dac_granted &= acl_mask_granted;
|
||||
if ((acc_mode & (dac_granted |
|
||||
cap_granted)) == acc_mode) {
|
||||
if (privused != NULL)
|
||||
*privused = 1;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
if (acl->acl_entry[i].ae_perm & ACL_READ)
|
||||
dac_granted |= VREAD;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_WRITE)
|
||||
dac_granted |= VWRITE;
|
||||
dac_granted &= acl_mask_granted;
|
||||
|
||||
if ((acc_mode & (dac_granted | cap_granted)) !=
|
||||
acc_mode)
|
||||
break;
|
||||
|
||||
if (privused != NULL)
|
||||
*privused = 1;
|
||||
return (0);
|
||||
|
||||
case ACL_GROUP:
|
||||
if (!groupmember(acl->acl_entry[i].ae_id,
|
||||
cred))
|
||||
break;
|
||||
dac_granted = 0;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
|
||||
dac_granted |= VEXEC;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_READ)
|
||||
dac_granted |= VREAD;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_WRITE)
|
||||
dac_granted |= VWRITE;
|
||||
dac_granted &= acl_mask_granted;
|
||||
|
||||
if ((acc_mode & (dac_granted | cap_granted)) !=
|
||||
acc_mode)
|
||||
break;
|
||||
|
||||
if (privused != NULL)
|
||||
*privused = 1;
|
||||
return (0);
|
||||
|
||||
default:
|
||||
}
|
||||
}
|
||||
@ -454,21 +492,37 @@ acl_posix1e_check(struct acl *acl)
|
||||
*/
|
||||
switch(acl->acl_entry[i].ae_tag) {
|
||||
case ACL_USER_OBJ:
|
||||
acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
|
||||
if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
|
||||
return (EINVAL);
|
||||
num_acl_user_obj++;
|
||||
break;
|
||||
case ACL_GROUP_OBJ:
|
||||
acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
|
||||
if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
|
||||
return (EINVAL);
|
||||
num_acl_group_obj++;
|
||||
break;
|
||||
case ACL_USER:
|
||||
if (acl->acl_entry[i].ae_id == ACL_UNDEFINED_ID)
|
||||
return (EINVAL);
|
||||
num_acl_user++;
|
||||
break;
|
||||
case ACL_GROUP:
|
||||
if (acl->acl_entry[i].ae_id == ACL_UNDEFINED_ID)
|
||||
return (EINVAL);
|
||||
num_acl_group++;
|
||||
break;
|
||||
case ACL_OTHER:
|
||||
acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
|
||||
if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
|
||||
return (EINVAL);
|
||||
num_acl_other++;
|
||||
break;
|
||||
case ACL_MASK:
|
||||
acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
|
||||
if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
|
||||
return (EINVAL);
|
||||
num_acl_mask++;
|
||||
break;
|
||||
default:
|
||||
|
@ -51,8 +51,8 @@ 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);
|
||||
static int vacl_aclcheck(struct proc *p, struct vnode *vp,
|
||||
acl_type_t type, struct acl *aclp);
|
||||
|
||||
/*
|
||||
* Implement a version of vaccess() that understands POSIX.1e ACL semantics.
|
||||
@ -60,8 +60,8 @@ static int vacl_aclcheck(struct proc *p, struct vnode *vp, acl_type_t type,
|
||||
* vaccess() eventually.
|
||||
*/
|
||||
int
|
||||
vaccess_acl_posix1e(enum vtype type, struct acl *acl, mode_t acc_mode,
|
||||
struct ucred *cred, int *privused)
|
||||
vaccess_acl_posix1e(enum vtype type, uid_t file_uid, gid_t file_gid,
|
||||
struct acl *acl, mode_t acc_mode, struct ucred *cred, int *privused)
|
||||
{
|
||||
struct acl_entry *acl_other, *acl_mask;
|
||||
mode_t dac_granted;
|
||||
@ -123,7 +123,7 @@ vaccess_acl_posix1e(enum vtype type, struct acl *acl, mode_t acc_mode,
|
||||
for (i = 0; i < acl->acl_cnt; i++) {
|
||||
switch (acl->acl_entry[i].ae_tag) {
|
||||
case ACL_USER_OBJ:
|
||||
if (acl->acl_entry[i].ae_id != cred->cr_uid)
|
||||
if (file_uid != cred->cr_uid)
|
||||
break;
|
||||
dac_granted = 0;
|
||||
dac_granted |= VADMIN;
|
||||
@ -209,13 +209,13 @@ vaccess_acl_posix1e(enum vtype type, struct acl *acl, mode_t acc_mode,
|
||||
dac_granted &= acl_mask_granted;
|
||||
if ((acc_mode & dac_granted) == acc_mode)
|
||||
return (0);
|
||||
if ((acc_mode & (dac_granted | cap_granted)) ==
|
||||
acc_mode) {
|
||||
if (privused != NULL)
|
||||
*privused = 1;
|
||||
return (0);
|
||||
}
|
||||
goto error;
|
||||
if ((acc_mode & (dac_granted | cap_granted)) !=
|
||||
acc_mode)
|
||||
goto error;
|
||||
|
||||
if (privused != NULL)
|
||||
*privused = 1;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,22 +229,41 @@ vaccess_acl_posix1e(enum vtype type, struct acl *acl, mode_t acc_mode,
|
||||
for (i = 0; i < acl->acl_cnt; i++) {
|
||||
switch (acl->acl_entry[i].ae_tag) {
|
||||
case ACL_GROUP_OBJ:
|
||||
if (file_gid != cred->cr_groups[0])
|
||||
break;
|
||||
dac_granted = 0;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
|
||||
dac_granted |= VEXEC;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_READ)
|
||||
dac_granted |= VREAD;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_WRITE)
|
||||
dac_granted |= VWRITE;
|
||||
dac_granted &= acl_mask_granted;
|
||||
|
||||
if ((acc_mode & dac_granted) == acc_mode)
|
||||
return (0);
|
||||
|
||||
group_matched = 1;
|
||||
break;
|
||||
|
||||
case ACL_GROUP:
|
||||
if (groupmember(acl->acl_entry[i].ae_id, cred)) {
|
||||
dac_granted = 0;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
|
||||
dac_granted |= VEXEC;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_READ)
|
||||
dac_granted |= VREAD;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_WRITE)
|
||||
dac_granted |= VWRITE;
|
||||
dac_granted &= acl_mask_granted;
|
||||
if (!groupmember(acl->acl_entry[i].ae_id, cred))
|
||||
break;
|
||||
dac_granted = 0;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
|
||||
dac_granted |= VEXEC;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_READ)
|
||||
dac_granted |= VREAD;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_WRITE)
|
||||
dac_granted |= VWRITE;
|
||||
dac_granted &= acl_mask_granted;
|
||||
|
||||
if ((acc_mode & dac_granted) == acc_mode)
|
||||
return (0);
|
||||
if ((acc_mode & dac_granted) == acc_mode)
|
||||
return (0);
|
||||
|
||||
group_matched = 1;
|
||||
break;
|
||||
|
||||
group_matched = 1;
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
@ -257,27 +276,46 @@ vaccess_acl_posix1e(enum vtype type, struct acl *acl, mode_t acc_mode,
|
||||
for (i = 0; i < acl->acl_cnt; i++) {
|
||||
switch (acl->acl_entry[i].ae_tag) {
|
||||
case ACL_GROUP_OBJ:
|
||||
case ACL_GROUP:
|
||||
if (groupmember(acl->acl_entry[i].ae_id,
|
||||
cred)) {
|
||||
dac_granted = 0;
|
||||
if (acl->acl_entry[i].ae_perm &
|
||||
ACL_EXECUTE)
|
||||
if (file_gid != cred->cr_groups[0])
|
||||
break;
|
||||
dac_granted = 0;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
|
||||
dac_granted |= VEXEC;
|
||||
if (acl->acl_entry[i].ae_perm &
|
||||
ACL_READ)
|
||||
dac_granted |= VREAD;
|
||||
if (acl->acl_entry[i].ae_perm &
|
||||
ACL_WRITE)
|
||||
dac_granted |= VWRITE;
|
||||
dac_granted &= acl_mask_granted;
|
||||
if ((acc_mode & (dac_granted |
|
||||
cap_granted)) == acc_mode) {
|
||||
if (privused != NULL)
|
||||
*privused = 1;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
if (acl->acl_entry[i].ae_perm & ACL_READ)
|
||||
dac_granted |= VREAD;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_WRITE)
|
||||
dac_granted |= VWRITE;
|
||||
dac_granted &= acl_mask_granted;
|
||||
|
||||
if ((acc_mode & (dac_granted | cap_granted)) !=
|
||||
acc_mode)
|
||||
break;
|
||||
|
||||
if (privused != NULL)
|
||||
*privused = 1;
|
||||
return (0);
|
||||
|
||||
case ACL_GROUP:
|
||||
if (!groupmember(acl->acl_entry[i].ae_id,
|
||||
cred))
|
||||
break;
|
||||
dac_granted = 0;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_EXECUTE)
|
||||
dac_granted |= VEXEC;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_READ)
|
||||
dac_granted |= VREAD;
|
||||
if (acl->acl_entry[i].ae_perm & ACL_WRITE)
|
||||
dac_granted |= VWRITE;
|
||||
dac_granted &= acl_mask_granted;
|
||||
|
||||
if ((acc_mode & (dac_granted | cap_granted)) !=
|
||||
acc_mode)
|
||||
break;
|
||||
|
||||
if (privused != NULL)
|
||||
*privused = 1;
|
||||
return (0);
|
||||
|
||||
default:
|
||||
}
|
||||
}
|
||||
@ -454,21 +492,37 @@ acl_posix1e_check(struct acl *acl)
|
||||
*/
|
||||
switch(acl->acl_entry[i].ae_tag) {
|
||||
case ACL_USER_OBJ:
|
||||
acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
|
||||
if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
|
||||
return (EINVAL);
|
||||
num_acl_user_obj++;
|
||||
break;
|
||||
case ACL_GROUP_OBJ:
|
||||
acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
|
||||
if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
|
||||
return (EINVAL);
|
||||
num_acl_group_obj++;
|
||||
break;
|
||||
case ACL_USER:
|
||||
if (acl->acl_entry[i].ae_id == ACL_UNDEFINED_ID)
|
||||
return (EINVAL);
|
||||
num_acl_user++;
|
||||
break;
|
||||
case ACL_GROUP:
|
||||
if (acl->acl_entry[i].ae_id == ACL_UNDEFINED_ID)
|
||||
return (EINVAL);
|
||||
num_acl_group++;
|
||||
break;
|
||||
case ACL_OTHER:
|
||||
acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
|
||||
if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
|
||||
return (EINVAL);
|
||||
num_acl_other++;
|
||||
break;
|
||||
case ACL_MASK:
|
||||
acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */
|
||||
if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID)
|
||||
return (EINVAL);
|
||||
num_acl_mask++;
|
||||
break;
|
||||
default:
|
||||
|
@ -563,8 +563,9 @@ int speedup_syncer __P((void));
|
||||
int textvp_fullpath __P((struct proc *p, char **retbuf, char **retfreebuf));
|
||||
int vaccess __P((enum vtype type, mode_t file_mode, uid_t uid, gid_t gid,
|
||||
mode_t acc_mode, struct ucred *cred, int *privused));
|
||||
int vaccess_acl_posix1e __P((enum vtype type, struct acl *acl,
|
||||
mode_t acc_mode, struct ucred *cred, int *privused));
|
||||
int vaccess_acl_posix1e __P((enum vtype type, uid_t file_uid,
|
||||
gid_t file_gid, struct acl *acl, mode_t acc_mode,
|
||||
struct ucred *cred, int *privused));
|
||||
void vattr_null __P((struct vattr *vap));
|
||||
int vcount __P((struct vnode *vp));
|
||||
void vdrop __P((struct vnode *));
|
||||
|
@ -79,23 +79,23 @@ ufs_sync_acl_from_inode(struct inode *ip, struct acl *acl)
|
||||
case ACL_USER_OBJ:
|
||||
acl->acl_entry[i].ae_perm = acl_posix1e_mode_to_perm(
|
||||
ACL_USER_OBJ, ip->i_mode);
|
||||
acl->acl_entry[i].ae_id = ip->i_uid;
|
||||
acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID;
|
||||
break;
|
||||
|
||||
case ACL_GROUP_OBJ:
|
||||
acl_group_obj = &acl->acl_entry[i];
|
||||
acl->acl_entry[i].ae_id = ip->i_gid;
|
||||
acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID;
|
||||
break;
|
||||
|
||||
case ACL_OTHER:
|
||||
acl->acl_entry[i].ae_perm = acl_posix1e_mode_to_perm(
|
||||
ACL_OTHER, ip->i_mode);
|
||||
acl->acl_entry[i].ae_id = 0;
|
||||
acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID;
|
||||
break;
|
||||
|
||||
case ACL_MASK:
|
||||
acl_mask = &acl->acl_entry[i];
|
||||
acl->acl_entry[i].ae_id = 0;
|
||||
acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID;
|
||||
break;
|
||||
|
||||
case ACL_USER:
|
||||
@ -159,12 +159,10 @@ ufs_sync_inode_from_acl(struct acl *acl, struct inode *ip,
|
||||
switch (acl->acl_entry[i].ae_tag) {
|
||||
case ACL_USER_OBJ:
|
||||
acl_user_obj = &acl->acl_entry[i];
|
||||
ip->i_uid = acl->acl_entry[i].ae_id;
|
||||
break;
|
||||
|
||||
case ACL_GROUP_OBJ:
|
||||
acl_group_obj = &acl->acl_entry[i];
|
||||
ip->i_gid = acl->acl_entry[i].ae_id;
|
||||
break;
|
||||
|
||||
case ACL_OTHER:
|
||||
@ -191,14 +189,14 @@ ufs_sync_inode_from_acl(struct acl *acl, struct inode *ip,
|
||||
/*
|
||||
* There is no ACL_MASK, so use the ACL_GROUP_OBJ entry.
|
||||
*/
|
||||
ip->i_mode &= ~ALLPERMS;
|
||||
ip->i_mode &= ~(S_IRWXU|S_IRWXG|S_IRWXO);
|
||||
ip->i_mode |= acl_posix1e_perms_to_mode(acl_user_obj,
|
||||
acl_group_obj, acl_other);
|
||||
} else {
|
||||
/*
|
||||
* Use the ACL_MASK entry.
|
||||
*/
|
||||
ip->i_mode &= ~ALLPERMS;
|
||||
ip->i_mode &= ~(S_IRWXU|S_IRWXG|S_IRWXO);
|
||||
ip->i_mode |= acl_posix1e_perms_to_mode(acl_user_obj,
|
||||
acl_mask, acl_other);
|
||||
}
|
||||
@ -257,13 +255,13 @@ ufs_getacl(ap)
|
||||
*/
|
||||
ap->a_aclp->acl_cnt = 3;
|
||||
ap->a_aclp->acl_entry[0].ae_tag = ACL_USER_OBJ;
|
||||
ap->a_aclp->acl_entry[0].ae_id = 0;
|
||||
ap->a_aclp->acl_entry[0].ae_id = ACL_UNDEFINED_ID;
|
||||
ap->a_aclp->acl_entry[0].ae_perm = 0;
|
||||
ap->a_aclp->acl_entry[1].ae_tag = ACL_GROUP_OBJ;
|
||||
ap->a_aclp->acl_entry[1].ae_id = 0;
|
||||
ap->a_aclp->acl_entry[1].ae_id = ACL_UNDEFINED_ID;
|
||||
ap->a_aclp->acl_entry[1].ae_perm = 0;
|
||||
ap->a_aclp->acl_entry[2].ae_tag = ACL_OTHER;
|
||||
ap->a_aclp->acl_entry[2].ae_id = 0;
|
||||
ap->a_aclp->acl_entry[2].ae_id = ACL_UNDEFINED_ID;
|
||||
ap->a_aclp->acl_entry[2].ae_perm = 0;
|
||||
ufs_sync_acl_from_inode(ip, ap->a_aclp);
|
||||
error = 0;
|
||||
@ -359,11 +357,8 @@ ufs_setacl(ap)
|
||||
} */ *ap;
|
||||
{
|
||||
struct inode *ip = VTOI(ap->a_vp);
|
||||
struct acl_entry *acl_user_obj, *acl_group_obj, *acl_other;
|
||||
mode_t old_mode, preserve_mask;
|
||||
uid_t old_uid, new_uid = 0;
|
||||
gid_t old_gid, new_gid = 0;
|
||||
int error, i;
|
||||
int error;
|
||||
|
||||
/*
|
||||
* If this is a set operation rather than a delete operation,
|
||||
@ -405,64 +400,6 @@ ufs_setacl(ap)
|
||||
if ((error = VOP_ACCESS(ap->a_vp, VADMIN, ap->a_cred, ap->a_p)))
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* ACL_TYPE_ACCESS may involve the changing of ownership, sticky
|
||||
* bit, setugid bits on the file or directory. As such, it requires
|
||||
* special handling to identify these changes, and to authorize
|
||||
* them.
|
||||
* ACL_TYPE_DEFAULT does not require this, and ap->a_aclp should
|
||||
* not be dereferenced without a NULL check, as it may be a delete
|
||||
* operation.
|
||||
*/
|
||||
switch(ap->a_type) {
|
||||
case ACL_TYPE_ACCESS:
|
||||
/*
|
||||
* Identify ACL_USER_OBJ, ACL_GROUP_OBJ, and determine if
|
||||
* they have changed. If so, authorize in the style of
|
||||
* ufs_chown(). While we're at it, identify ACL_OTHER.
|
||||
*/
|
||||
acl_user_obj = acl_group_obj = acl_other = NULL;
|
||||
for (i = 0; i < ap->a_aclp->acl_cnt; i++)
|
||||
switch(ap->a_aclp->acl_entry[i].ae_tag) {
|
||||
case ACL_USER_OBJ:
|
||||
acl_user_obj = &ap->a_aclp->acl_entry[i];
|
||||
new_uid = acl_user_obj->ae_id;
|
||||
break;
|
||||
case ACL_GROUP_OBJ:
|
||||
acl_group_obj = &ap->a_aclp->acl_entry[i];
|
||||
new_gid = acl_group_obj->ae_id;
|
||||
break;
|
||||
case ACL_OTHER:
|
||||
acl_other = &ap->a_aclp->acl_entry[i];
|
||||
break;
|
||||
default:
|
||||
}
|
||||
old_uid = ip->i_uid;
|
||||
old_gid = ip->i_gid;
|
||||
|
||||
/*
|
||||
* Authorize changes to base object ownership in the style
|
||||
* of ufs_chown().
|
||||
*/
|
||||
if (new_uid != old_uid && (error = suser_xxx(ap->a_cred,
|
||||
ap->a_p, PRISON_ROOT)))
|
||||
return (error);
|
||||
if (new_gid != old_gid && !groupmember(new_gid, ap->a_cred) &&
|
||||
(error = suser_xxx(ap->a_cred, ap->a_p, PRISON_ROOT)))
|
||||
return (error);
|
||||
|
||||
case ACL_TYPE_DEFAULT:
|
||||
/*
|
||||
* ACL_TYPE_DEFAULT can literally be written straight into
|
||||
* the EA unhindered, as it has gone through sanity checking
|
||||
* already.
|
||||
*/
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("ufs_setacl(): unknown acl type\n");
|
||||
}
|
||||
|
||||
switch(ap->a_type) {
|
||||
case ACL_TYPE_ACCESS:
|
||||
error = vn_extattr_set(ap->a_vp, IO_NODELOCKED,
|
||||
@ -509,22 +446,9 @@ ufs_setacl(ap)
|
||||
* Now that the EA is successfully updated, update the
|
||||
* inode and mark it as changed.
|
||||
*/
|
||||
old_uid = ip->i_uid;
|
||||
old_gid = ip->i_gid;
|
||||
old_mode = ip->i_mode;
|
||||
preserve_mask = ISVTX | ISGID | ISUID;
|
||||
ufs_sync_inode_from_acl(ap->a_aclp, ip, preserve_mask);
|
||||
|
||||
/*
|
||||
* Clear the ISGID and ISUID bits if the ownership has
|
||||
* changed, or appropriate privilege is not available.
|
||||
* XXX: This should probably be a check for broadening
|
||||
* availability of the bits, but it's not clear from the
|
||||
* spec.
|
||||
*/
|
||||
if (suser_xxx(ap->a_cred, NULL, PRISON_ROOT) &&
|
||||
(ip->i_gid != old_gid || ip->i_uid != old_uid))
|
||||
ip->i_mode &= ~(ISUID | ISGID);
|
||||
ip->i_flag |= IN_CHANGE;
|
||||
}
|
||||
|
||||
|
@ -353,8 +353,8 @@ ufs_access(ap)
|
||||
ap->a_mode, ap->a_cred, NULL);
|
||||
break;
|
||||
case 0:
|
||||
error = vaccess_acl_posix1e(vp->v_type, acl, ap->a_mode,
|
||||
ap->a_cred, NULL);
|
||||
error = vaccess_acl_posix1e(vp->v_type, ip->i_uid, ip->i_gid,
|
||||
acl, ap->a_mode, ap->a_cred, NULL);
|
||||
break;
|
||||
default:
|
||||
printf("ufs_access(): Error retrieving ACL on object (%d).\n",
|
||||
|
Loading…
Reference in New Issue
Block a user