* sec_acl.cc (setacl): Add comment. Handle NULL ACE for SUID, SGID,
and VTX bits. Create owner, group, other and NULL entries in the same way and in the same order as alloc_sd. (getacl): Skip NULL ACE.
This commit is contained in:
parent
e7ee42f33d
commit
ebf78cec85
|
@ -1,3 +1,10 @@
|
|||
2014-08-31 Corinna Vinschen <corinna@vinschen.de>
|
||||
|
||||
* sec_acl.cc (setacl): Add comment. Handle NULL ACE for SUID, SGID,
|
||||
and VTX bits. Create owner, group, other and NULL entries in the same
|
||||
way and in the same order as alloc_sd.
|
||||
(getacl): Skip NULL ACE.
|
||||
|
||||
2014-08-28 Corinna Vinschen <corinna@vinschen.de>
|
||||
|
||||
* fhandler.cc (fhandler_base::facl): Drop CLASS_OBJ entry.
|
||||
|
|
|
@ -36,6 +36,7 @@ searchace (aclent_t *aclp, int nentries, int type, uid_t id = ILLEGAL_UID)
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* This function *requires* an acl list sorted with aclsort{32}. */
|
||||
int
|
||||
setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
|
||||
bool &writable)
|
||||
|
@ -47,7 +48,8 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
|
|||
return -1;
|
||||
|
||||
NTSTATUS status;
|
||||
BOOLEAN dummy;
|
||||
PACL acl;
|
||||
BOOLEAN acl_exists, dummy;
|
||||
|
||||
/* Get owner SID. */
|
||||
PSID owner_sid;
|
||||
|
@ -69,9 +71,32 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
|
|||
}
|
||||
cygsid group (group_sid);
|
||||
|
||||
/* Search for NULL ACE and store state of SUID, SGID and VTX bits. */
|
||||
DWORD null_mask = 0;
|
||||
if (NT_SUCCESS (RtlGetDaclSecurityDescriptor (sd_ret, &acl_exists, &acl,
|
||||
&dummy)))
|
||||
for (USHORT i = 0; i < acl->AceCount; ++i)
|
||||
{
|
||||
ACCESS_ALLOWED_ACE *ace;
|
||||
if (NT_SUCCESS (RtlGetAce (acl, i, (PVOID *) &ace)))
|
||||
{
|
||||
cygpsid ace_sid ((PSID) &ace->SidStart);
|
||||
if (ace_sid == well_known_null_sid)
|
||||
{
|
||||
null_mask = ace->Mask;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize local security descriptor. */
|
||||
SECURITY_DESCRIPTOR sd;
|
||||
RtlCreateSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION);
|
||||
|
||||
/* As in alloc_sd, set SE_DACL_PROTECTED to prevent the DACL from being
|
||||
modified by inheritable ACEs. */
|
||||
RtlSetControlSecurityDescriptor (&sd, SE_DACL_PROTECTED, SE_DACL_PROTECTED);
|
||||
|
||||
status = RtlSetOwnerSecurityDescriptor (&sd, owner, FALSE);
|
||||
if (!NT_SUCCESS (status))
|
||||
{
|
||||
|
@ -86,7 +111,7 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
|
|||
}
|
||||
|
||||
/* Fill access control list. */
|
||||
PACL acl = (PACL) tp.w_get ();
|
||||
acl = (PACL) tp.w_get ();
|
||||
size_t acl_len = sizeof (ACL);
|
||||
int ace_off = 0;
|
||||
|
||||
|
@ -100,15 +125,94 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
|
|||
|
||||
writable = false;
|
||||
|
||||
/* Pre-compute owner, group, and other permissions to allow creating
|
||||
matching deny ACEs as in alloc_sd. */
|
||||
DWORD owner_allow = 0, group_allow = 0, other_allow = 0;
|
||||
PDWORD allow;
|
||||
for (int i = 0; i < nentries; ++i)
|
||||
{
|
||||
switch (aclbufp[i].a_type)
|
||||
{
|
||||
case USER_OBJ:
|
||||
allow = &owner_allow;
|
||||
*allow = STANDARD_RIGHTS_ALL;
|
||||
break;
|
||||
case GROUP_OBJ:
|
||||
allow = &group_allow;
|
||||
break;
|
||||
case OTHER_OBJ:
|
||||
allow = &other_allow;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
*allow |= STANDARD_RIGHTS_READ | SYNCHRONIZE
|
||||
| (pc.fs_is_samba () ? 0 : FILE_READ_ATTRIBUTES);
|
||||
if (aclbufp[i].a_perm & S_IROTH)
|
||||
*allow |= FILE_GENERIC_READ;
|
||||
if (aclbufp[i].a_perm & S_IWOTH)
|
||||
{
|
||||
*allow |= FILE_GENERIC_WRITE;
|
||||
writable = true;
|
||||
}
|
||||
if (aclbufp[i].a_perm & S_IXOTH)
|
||||
*allow |= FILE_GENERIC_EXECUTE & ~FILE_READ_ATTRIBUTES;
|
||||
/* Keep S_ISVTX rule in sync with alloc_sd. */
|
||||
if (pc.isdir ()
|
||||
&& (aclbufp[i].a_perm & (S_IWOTH | S_IXOTH)) == (S_IWOTH | S_IXOTH)
|
||||
&& (aclbufp[i].a_type == USER_OBJ
|
||||
|| !(null_mask & FILE_READ_DATA)))
|
||||
*allow |= FILE_DELETE_CHILD;
|
||||
aclbufp[i].a_type = 0;
|
||||
}
|
||||
bool isownergroup = (owner_sid == group_sid);
|
||||
DWORD owner_deny = ~owner_allow & (group_allow | other_allow);
|
||||
owner_deny &= ~(STANDARD_RIGHTS_READ
|
||||
| FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES);
|
||||
DWORD group_deny = ~group_allow & other_allow;
|
||||
group_deny &= ~(STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES);
|
||||
|
||||
/* Set deny ACE for owner. */
|
||||
if (owner_deny
|
||||
&& !add_access_denied_ace (acl, ace_off++, owner_deny,
|
||||
owner_sid, acl_len, NO_INHERITANCE))
|
||||
return -1;
|
||||
/* Set deny ACE for group here to respect the canonical order,
|
||||
if this does not impact owner */
|
||||
if (group_deny && !(group_deny & owner_allow) && !isownergroup
|
||||
&& !add_access_denied_ace (acl, ace_off++, group_deny,
|
||||
group_sid, acl_len, NO_INHERITANCE))
|
||||
return -1;
|
||||
/* Set allow ACE for owner. */
|
||||
if (!add_access_allowed_ace (acl, ace_off++, owner_allow,
|
||||
owner_sid, acl_len, NO_INHERITANCE))
|
||||
return -1;
|
||||
/* Set deny ACE for group, if still needed. */
|
||||
if (group_deny & owner_allow && !isownergroup
|
||||
&& !add_access_denied_ace (acl, ace_off++, group_deny,
|
||||
group_sid, acl_len, NO_INHERITANCE))
|
||||
return -1;
|
||||
/* Set allow ACE for group. */
|
||||
if (!isownergroup
|
||||
&& !add_access_allowed_ace (acl, ace_off++, group_allow,
|
||||
group_sid, acl_len, NO_INHERITANCE))
|
||||
return -1;
|
||||
/* Set allow ACE for everyone. */
|
||||
if (!add_access_allowed_ace (acl, ace_off++, other_allow,
|
||||
well_known_world_sid, acl_len, NO_INHERITANCE))
|
||||
return -1;
|
||||
/* If a NULL ACE exists, copy it verbatim. */
|
||||
if (null_mask)
|
||||
if (!add_access_allowed_ace (acl, ace_off++, null_mask, well_known_null_sid,
|
||||
acl_len, NO_INHERITANCE))
|
||||
return -1;
|
||||
for (int i = 0; i < nentries; ++i)
|
||||
{
|
||||
DWORD allow;
|
||||
/* Owner has more standard rights set. */
|
||||
if ((aclbufp[i].a_type & ~ACL_DEFAULT) == USER_OBJ)
|
||||
allow = STANDARD_RIGHTS_ALL
|
||||
| (pc.fs_is_samba ()
|
||||
? 0 : (FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES));
|
||||
else
|
||||
/* Skip invalidated entries. */
|
||||
if (!aclbufp[i].a_type)
|
||||
continue;
|
||||
|
||||
allow = STANDARD_RIGHTS_READ
|
||||
| (pc.fs_is_samba () ? 0 : FILE_READ_ATTRIBUTES);
|
||||
if (aclbufp[i].a_perm & S_IROTH)
|
||||
|
@ -120,7 +224,10 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
|
|||
}
|
||||
if (aclbufp[i].a_perm & S_IXOTH)
|
||||
allow |= FILE_GENERIC_EXECUTE & ~FILE_READ_ATTRIBUTES;
|
||||
if ((aclbufp[i].a_perm & (S_IWOTH | S_IXOTH)) == (S_IWOTH | S_IXOTH))
|
||||
/* Keep S_ISVTX rule in sync with alloc_sd. */
|
||||
if (pc.isdir ()
|
||||
&& (aclbufp[i].a_perm & (S_IWOTH | S_IXOTH)) == (S_IWOTH | S_IXOTH)
|
||||
&& !(null_mask & FILE_READ_DATA))
|
||||
allow |= FILE_DELETE_CHILD;
|
||||
/* Set inherit property. */
|
||||
DWORD inheritance = (aclbufp[i].a_type & ACL_DEFAULT)
|
||||
|
@ -133,7 +240,7 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
|
|||
* inheritance bits is created.
|
||||
*/
|
||||
if (!(aclbufp[i].a_type & ACL_DEFAULT)
|
||||
&& aclbufp[i].a_type & (USER|GROUP|OTHER_OBJ)
|
||||
&& aclbufp[i].a_type & (USER|GROUP)
|
||||
&& (pos = searchace (aclbufp + i + 1, nentries - i - 1,
|
||||
aclbufp[i].a_type | ACL_DEFAULT,
|
||||
(aclbufp[i].a_type & (USER|GROUP))
|
||||
|
@ -141,16 +248,11 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
|
|||
&& aclbufp[i].a_perm == aclbufp[i + 1 + pos].a_perm)
|
||||
{
|
||||
inheritance = CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE;
|
||||
/* This invalidates the corresponding default entry. */
|
||||
aclbufp[i + 1 + pos].a_type = USER|GROUP|ACL_DEFAULT;
|
||||
/* invalidate the corresponding default entry. */
|
||||
aclbufp[i + 1 + pos].a_type = 0;
|
||||
}
|
||||
switch (aclbufp[i].a_type)
|
||||
{
|
||||
case USER_OBJ:
|
||||
if (!add_access_allowed_ace (acl, ace_off++, allow,
|
||||
owner, acl_len, inheritance))
|
||||
return -1;
|
||||
break;
|
||||
case DEF_USER_OBJ:
|
||||
if (!add_access_allowed_ace (acl, ace_off++, allow,
|
||||
well_known_creator_owner_sid, acl_len, inheritance))
|
||||
|
@ -168,11 +270,6 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
|
|||
sid, acl_len, inheritance))
|
||||
return -1;
|
||||
break;
|
||||
case GROUP_OBJ:
|
||||
if (!add_access_allowed_ace (acl, ace_off++, allow,
|
||||
group, acl_len, inheritance))
|
||||
return -1;
|
||||
break;
|
||||
case DEF_GROUP_OBJ:
|
||||
if (!add_access_allowed_ace (acl, ace_off++, allow,
|
||||
well_known_creator_group_sid, acl_len, inheritance))
|
||||
|
@ -190,13 +287,11 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
|
|||
sid, acl_len, inheritance))
|
||||
return -1;
|
||||
break;
|
||||
case OTHER_OBJ:
|
||||
case DEF_OTHER_OBJ:
|
||||
if (!add_access_allowed_ace (acl, ace_off++, allow,
|
||||
well_known_world_sid,
|
||||
acl_len, inheritance))
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Set AclSize to computed value. */
|
||||
|
@ -340,6 +435,11 @@ getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp)
|
|||
int id;
|
||||
int type = 0;
|
||||
|
||||
if (ace_sid == well_known_null_sid)
|
||||
{
|
||||
/* Simply ignore. */
|
||||
continue;
|
||||
}
|
||||
if (ace_sid == well_known_world_sid)
|
||||
{
|
||||
type = OTHER_OBJ;
|
||||
|
|
Loading…
Reference in New Issue