* sec_acl.cc (setacl): Fix bug which leads to ACE duplication in

case owner SID == group SID.
	(getacl): Reverse order of SID test against group or owner sid to
	prefer owner attributes over group attributes.  Disable setting group
	permissions equivalent to owner permissions if owner == group.  Add
	comment to explain why.  Fix indentation.
	* security.cc (get_attribute_from_acl): Change type of local variables
	containing permission to mode_t.  Apply deny mask to group if group SID
	== owner SID to avoid Everyone permissions to spill over into group
	permissions.  Disable setting group permissions equivalent to owner
	permissions if owner == group.  Add comment to explain why.
	* uinfo.cc (pwdgrp::fetch_account_from_windows): Allow user SID as
	group account if user is a "Microsoft Account".  Explain why.  Drop
	workaround enforcing primary group "Users" for "Microsoft Accounts".
This commit is contained in:
Corinna Vinschen 2015-02-27 12:59:09 +00:00
parent d2f9dbb3ee
commit 06371539bd
4 changed files with 93 additions and 52 deletions

View File

@ -1,3 +1,20 @@
2015-02-27 Corinna Vinschen <corinna@vinschen.de>
* sec_acl.cc (setacl): Fix bug which leads to ACE duplication in
case owner SID == group SID.
(getacl): Reverse order of SID test against group or owner sid to
prefer owner attributes over group attributes. Disable setting group
permissions equivalent to owner permissions if owner == group. Add
comment to explain why. Fix indentation.
* security.cc (get_attribute_from_acl): Change type of local variables
containing permission to mode_t. Apply deny mask to group if group SID
== owner SID to avoid Everyone permissions to spill over into group
permissions. Disable setting group permissions equivalent to owner
permissions if owner == group. Add comment to explain why.
* uinfo.cc (pwdgrp::fetch_account_from_windows): Allow user SID as
group account if user is a "Microsoft Account". Explain why. Drop
workaround enforcing primary group "Users" for "Microsoft Accounts".
2015-02-26 Corinna Vinschen <corinna@vinschen.de> 2015-02-26 Corinna Vinschen <corinna@vinschen.de>
* ldap.cc (cyg_ldap::wait): Call cygwait with cw_infinite timeout value * ldap.cc (cyg_ldap::wait): Call cygwait with cw_infinite timeout value

View File

@ -169,7 +169,7 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
*allow |= FILE_DELETE_CHILD; *allow |= FILE_DELETE_CHILD;
invalid[i] = true; invalid[i] = true;
} }
bool isownergroup = (owner_sid == group_sid); bool isownergroup = (owner == group);
DWORD owner_deny = ~owner_allow & (group_allow | other_allow); DWORD owner_deny = ~owner_allow & (group_allow | other_allow);
owner_deny &= ~(STANDARD_RIGHTS_READ owner_deny &= ~(STANDARD_RIGHTS_READ
| FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES); | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES);
@ -179,27 +179,27 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
/* Set deny ACE for owner. */ /* Set deny ACE for owner. */
if (owner_deny if (owner_deny
&& !add_access_denied_ace (acl, ace_off++, owner_deny, && !add_access_denied_ace (acl, ace_off++, owner_deny,
owner_sid, acl_len, NO_INHERITANCE)) owner, acl_len, NO_INHERITANCE))
return -1; return -1;
/* Set deny ACE for group here to respect the canonical order, /* Set deny ACE for group here to respect the canonical order,
if this does not impact owner */ if this does not impact owner */
if (group_deny && !(group_deny & owner_allow) && !isownergroup if (group_deny && !(group_deny & owner_allow) && !isownergroup
&& !add_access_denied_ace (acl, ace_off++, group_deny, && !add_access_denied_ace (acl, ace_off++, group_deny,
group_sid, acl_len, NO_INHERITANCE)) group, acl_len, NO_INHERITANCE))
return -1; return -1;
/* Set allow ACE for owner. */ /* Set allow ACE for owner. */
if (!add_access_allowed_ace (acl, ace_off++, owner_allow, if (!add_access_allowed_ace (acl, ace_off++, owner_allow,
owner_sid, acl_len, NO_INHERITANCE)) owner, acl_len, NO_INHERITANCE))
return -1; return -1;
/* Set deny ACE for group, if still needed. */ /* Set deny ACE for group, if still needed. */
if (group_deny & owner_allow && !isownergroup if (group_deny & owner_allow && !isownergroup
&& !add_access_denied_ace (acl, ace_off++, group_deny, && !add_access_denied_ace (acl, ace_off++, group_deny,
group_sid, acl_len, NO_INHERITANCE)) group, acl_len, NO_INHERITANCE))
return -1; return -1;
/* Set allow ACE for group. */ /* Set allow ACE for group. */
if (!isownergroup if (!isownergroup
&& !add_access_allowed_ace (acl, ace_off++, group_allow, && !add_access_allowed_ace (acl, ace_off++, group_allow,
group_sid, acl_len, NO_INHERITANCE)) group, acl_len, NO_INHERITANCE))
return -1; return -1;
/* Set allow ACE for everyone. */ /* Set allow ACE for everyone. */
if (!add_access_allowed_ace (acl, ace_off++, other_allow, if (!add_access_allowed_ace (acl, ace_off++, other_allow,
@ -451,16 +451,16 @@ getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp)
type = OTHER_OBJ; type = OTHER_OBJ;
id = ILLEGAL_GID; id = ILLEGAL_GID;
} }
else if (ace_sid == group_sid)
{
type = GROUP_OBJ;
id = gid;
}
else if (ace_sid == owner_sid) else if (ace_sid == owner_sid)
{ {
type = USER_OBJ; type = USER_OBJ;
id = uid; id = uid;
} }
else if (ace_sid == group_sid)
{
type = GROUP_OBJ;
id = gid;
}
else if (ace_sid == well_known_creator_group_sid) else if (ace_sid == well_known_creator_group_sid)
{ {
type = DEF_GROUP_OBJ; type = DEF_GROUP_OBJ;
@ -563,19 +563,26 @@ getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp)
} }
if ((pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) < 0) if ((pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) < 0)
pos = MAX_ACL_ENTRIES; pos = MAX_ACL_ENTRIES;
if (aclbufp) { if (aclbufp)
if (owner_sid == group_sid) {
lacl[0].a_perm = lacl[1].a_perm; #if 0
if (pos > nentries) /* Disable owner/group permissions equivalence if owner SID == group SID.
{ It's technically not quite correct, but it helps in case a security
set_errno (ENOSPC); conscious application checks if a file has too open permissions. In
return -1; fact, since owner == group, there's no security issue here. */
} if (owner_sid == group_sid)
memcpy (aclbufp, lacl, pos * sizeof (aclent_t)); lacl[1].a_perm = lacl[0].a_perm;
for (i = 0; i < pos; ++i) #endif
aclbufp[i].a_perm &= ~(DENY_R | DENY_W | DENY_X); if (pos > nentries)
aclsort32 (pos, 0, aclbufp); {
} set_errno (ENOSPC);
return -1;
}
memcpy (aclbufp, lacl, pos * sizeof (aclent_t));
for (i = 0; i < pos; ++i)
aclbufp[i].a_perm &= ~(DENY_R | DENY_W | DENY_X);
aclsort32 (pos, 0, aclbufp);
}
syscall_printf ("%R = getacl(%S)", pos, pc.get_nt_native_path ()); syscall_printf ("%R = getacl(%S)", pos, pc.get_nt_native_path ());
return pos; return pos;
} }

View File

@ -239,9 +239,9 @@ get_attribute_from_acl (mode_t *attribute, PACL acl, PSID owner_sid,
PSID group_sid, bool grp_member) PSID group_sid, bool grp_member)
{ {
ACCESS_ALLOWED_ACE *ace; ACCESS_ALLOWED_ACE *ace;
int allow = 0; mode_t allow = 0;
int deny = 0; mode_t deny = 0;
int *flags, *anti; mode_t *flags, *anti;
for (DWORD i = 0; i < acl->AceCount; ++i) for (DWORD i = 0; i < acl->AceCount; ++i)
{ {
@ -301,6 +301,17 @@ get_attribute_from_acl (mode_t *attribute, PACL acl, PSID owner_sid,
*flags |= ((!(*anti & S_IWUSR)) ? S_IWUSR : 0); *flags |= ((!(*anti & S_IWUSR)) ? S_IWUSR : 0);
if (ace->Mask & FILE_EXEC_BITS) if (ace->Mask & FILE_EXEC_BITS)
*flags |= ((!(*anti & S_IXUSR)) ? S_IXUSR : 0); *flags |= ((!(*anti & S_IXUSR)) ? S_IXUSR : 0);
/* Apply deny mask to group if group SID == owner SID. */
if (group_sid && RtlEqualSid (owner_sid, group_sid)
&& ace->Header.AceType == ACCESS_DENIED_ACE_TYPE)
{
if (ace->Mask & FILE_READ_BITS)
*flags |= ((!(*anti & S_IRUSR)) ? S_IRGRP : 0);
if (ace->Mask & FILE_WRITE_BITS)
*flags |= ((!(*anti & S_IWUSR)) ? S_IWGRP : 0);
if (ace->Mask & FILE_EXEC_BITS)
*flags |= ((!(*anti & S_IXUSR)) ? S_IXGRP : 0);
}
} }
else if (ace_sid == group_sid) else if (ace_sid == group_sid)
{ {
@ -331,6 +342,11 @@ get_attribute_from_acl (mode_t *attribute, PACL acl, PSID owner_sid,
} }
} }
*attribute &= ~(S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX | S_ISGID | S_ISUID); *attribute &= ~(S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX | S_ISGID | S_ISUID);
#if 0
/* Disable owner/group permissions equivalence if owner SID == group SID.
It's technically not quite correct, but it helps in case a security
conscious application checks if a file has too open permissions. In
fact, since owner == group, there's no security issue here. */
if (owner_sid && group_sid && RtlEqualSid (owner_sid, group_sid) if (owner_sid && group_sid && RtlEqualSid (owner_sid, group_sid)
/* FIXME: temporary exception for /var/empty */ /* FIXME: temporary exception for /var/empty */
&& well_known_system_sid != group_sid) && well_known_system_sid != group_sid)
@ -340,6 +356,7 @@ get_attribute_from_acl (mode_t *attribute, PACL acl, PSID owner_sid,
| ((allow & S_IWUSR) ? S_IWGRP : 0) | ((allow & S_IWUSR) ? S_IWGRP : 0)
| ((allow & S_IXUSR) ? S_IXGRP : 0)); | ((allow & S_IXUSR) ? S_IXGRP : 0));
} }
#endif
*attribute |= allow; *attribute |= allow;
} }

View File

@ -2053,12 +2053,31 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap)
switch (acc_type) switch (acc_type)
{ {
case SidTypeUser: case SidTypeUser:
/* Don't allow users as group. While this is technically possible, if (is_group () && acc_type == SidTypeUser)
it doesn't make sense in a POSIX scenario. It *is* used for {
Microsoft Accounts, but those are converted to well-known groups /* Don't allow users as group. While this is technically
above. */ possible, it doesn't make sense in a POSIX scenario.
if (is_group ())
return NULL; And then there are the so-called Microsoft Accounts. The
special SID with security authority 11 is converted to a
well known group above, but additionally, when logging in
with such an account, the user's primary group SID is the
user's SID. Those we let pass, but no others. */
bool its_ok = false;
if (wincap.has_microsoft_accounts ())
{
struct cyg_USER_INFO_24 *ui24;
if (NetUserGetInfo (NULL, name, 24, (PBYTE *) &ui24)
== NERR_Success)
{
if (ui24->usri24_internet_identity)
its_ok = true;
NetApiBufferFree (ui24);
}
}
if (!its_ok)
return NULL;
}
/*FALLTHRU*/ /*FALLTHRU*/
case SidTypeGroup: case SidTypeGroup:
case SidTypeAlias: case SidTypeAlias:
@ -2231,25 +2250,6 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap)
debug_printf ("NetUserGetInfo(%W) %u", name, nas); debug_printf ("NetUserGetInfo(%W) %u", name, nas);
break; break;
} }
/* Logging in with a Microsoft Account, the user's primary
group SID is the user's SID. Security sensitive tools
expecting tight file permissions choke on that. We need
an explicit primary group which is not identical to the
user account. Unfortunately, while the default primary
group of the account in SAM is still "None", "None" is not
in the user token group list. So, what we do here is to
use "Users" as a sane default primary group instead. */
if (wincap.has_microsoft_accounts ())
{
struct cyg_USER_INFO_24 *ui24;
nas = NetUserGetInfo (NULL, name, 24, (PBYTE *) &ui24);
if (nas == NERR_Success)
{
if (ui24->usri24_internet_identity)
gid = DOMAIN_ALIAS_RID_USERS;
NetApiBufferFree (ui24);
}
}
/* Fetch user attributes. */ /* Fetch user attributes. */
home = cygheap->pg.get_home (ui, sid, dom, name, home = cygheap->pg.get_home (ui, sid, dom, name,
fully_qualified_name); fully_qualified_name);