Preliminary read side implementation of new permission handling.
* acl.h (MAX_ACL_ENTRIES): Raise to 2730. Add comment to explain. * sec_acl.cc: Add leading comment to explain new ACL style. Add definitions and macros to use for bits in new Cygwin ACL. (DENY_RWX): New mask value for all temporary deny bits. (getace): Add bool parameter to decide when leaving all bits intact, rather than filtering them per the already set bits. (get_posix_access): New function, taking over functionality to read POSIX ACL from SECURITY_DESCRIPTOR. (getacl): Just call get_posix_access. * sec_helper.cc (well_known_cygwin_sid): Define. * security.cc (get_attribute_from_acl): Remove. (get_info_from_sd): Remove. (get_reg_sd): Call get_posix_access instead of get_info_from_sd. (get_file_attribute): Ditto. (get_object_attribute): Ditto. * security.h (well_known_cygwin_sid): Declare. (get_posix_access): Add prototype. * Throughout, use simpler ACE macros from Windows' accctrl.h. Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
parent
4a9636b1d6
commit
52f01a0ff8
|
@ -1,3 +1,26 @@
|
||||||
|
2015-03-18 Corinna Vinschen <corinna@vinschen.de>
|
||||||
|
|
||||||
|
Preliminary read side implementation of new permission handling.
|
||||||
|
* acl.h (MAX_ACL_ENTRIES): Raise to 2730. Add comment to explain.
|
||||||
|
* sec_acl.cc: Add leading comment to explain new ACL style.
|
||||||
|
Add definitions and macros to use for bits in new Cygwin ACL.
|
||||||
|
(DENY_RWX): New mask value for all temporary deny bits.
|
||||||
|
(getace): Add bool parameter to decide when leaving all bits intact,
|
||||||
|
rather than filtering them per the already set bits.
|
||||||
|
(get_posix_access): New function, taking over functionality to read
|
||||||
|
POSIX ACL from SECURITY_DESCRIPTOR.
|
||||||
|
(getacl): Just call get_posix_access.
|
||||||
|
* sec_helper.cc (well_known_cygwin_sid): Define.
|
||||||
|
* security.cc (get_attribute_from_acl): Remove.
|
||||||
|
(get_info_from_sd): Remove.
|
||||||
|
(get_reg_sd): Call get_posix_access instead of get_info_from_sd.
|
||||||
|
(get_file_attribute): Ditto.
|
||||||
|
(get_object_attribute): Ditto.
|
||||||
|
* security.h (well_known_cygwin_sid): Declare.
|
||||||
|
(get_posix_access): Add prototype.
|
||||||
|
|
||||||
|
* Throughout, use simpler ACE macros from Windows' accctrl.h.
|
||||||
|
|
||||||
2015-03-18 Corinna Vinschen <corinna@vinschen.de>
|
2015-03-18 Corinna Vinschen <corinna@vinschen.de>
|
||||||
|
|
||||||
* grp.cc (pwdgrp::parse_group): Call cygsid::getfromgr_passwd.
|
* grp.cc (pwdgrp::parse_group): Call cygsid::getfromgr_passwd.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* cygwin/acl.h header file for Cygwin.
|
/* cygwin/acl.h header file for Cygwin.
|
||||||
|
|
||||||
Copyright 1999, 2000, 2001, 2002, 2010, 2014 Red Hat, Inc.
|
Copyright 1999, 2000, 2001, 2002, 2010, 2014, 2015 Red Hat, Inc.
|
||||||
Written by C. Vinschen.
|
Written by C. Vinschen.
|
||||||
|
|
||||||
This file is part of Cygwin.
|
This file is part of Cygwin.
|
||||||
|
@ -25,8 +25,16 @@ extern "C" {
|
||||||
#define GETACL (0x1)
|
#define GETACL (0x1)
|
||||||
#define GETACLCNT (0x2)
|
#define GETACLCNT (0x2)
|
||||||
|
|
||||||
|
/* Windows ACLs have a maximum size of 64K. Counting the most pessimistic way,
|
||||||
|
the maximum number of ACEs is 3276. Technet claims "approximately 1820",
|
||||||
|
which uses the length of normal user and group SIDs for the computation.
|
||||||
|
We're now going with 2730, the number of aclent_t entries matching a 32K
|
||||||
|
buffer.
|
||||||
|
On one hand, there are only a limited number of SIDs shorter than the normal
|
||||||
|
user/group SIDs, on the other hand there are no deny aclent_t entries, so we
|
||||||
|
should be fine with 32K aclbuf_t buffers provided by the caller. */
|
||||||
#define MIN_ACL_ENTRIES (3) // minimal acl entries from GETACLCNT
|
#define MIN_ACL_ENTRIES (3) // minimal acl entries from GETACLCNT
|
||||||
#define MAX_ACL_ENTRIES (256) // max entries of each type
|
#define MAX_ACL_ENTRIES (2730) // max entries of each type
|
||||||
|
|
||||||
// Return values of aclcheck(3) in case of error */
|
// Return values of aclcheck(3) in case of error */
|
||||||
#define GRP_ERROR (0x1)
|
#define GRP_ERROR (0x1)
|
||||||
|
|
|
@ -24,6 +24,64 @@ details. */
|
||||||
#include "ntdll.h"
|
#include "ntdll.h"
|
||||||
#include "tls_pbuf.h"
|
#include "tls_pbuf.h"
|
||||||
|
|
||||||
|
/* How does a correctly constructed new-style Windows ACL claiming to be a
|
||||||
|
POSIX ACL look like?
|
||||||
|
|
||||||
|
- Cygwin ACE (special bits, CLASS_OBJ).
|
||||||
|
|
||||||
|
- If a USER entry has more permissions than any group, Everyone, or if it
|
||||||
|
has more permissions than allowed by the CLASS_OBJ entry:
|
||||||
|
|
||||||
|
USER deny ACEs == POSIX allow
|
||||||
|
& ^(mask | all group allows | Everyone allow)
|
||||||
|
|
||||||
|
- USER_OBJ allow ACE
|
||||||
|
- USER allow ACEs
|
||||||
|
|
||||||
|
The POSIX permissions returned for a USER entry are the allow bits alone!
|
||||||
|
|
||||||
|
- If a GROUP entry has more permissions than Everyone, or if it has more
|
||||||
|
permissions than allowed by the CLASS_OBJ entry:
|
||||||
|
|
||||||
|
GROUP deny ACEs == POSIX allow & ^(mask | Everyone allow)
|
||||||
|
|
||||||
|
- GROUP_OBJ allow ACE
|
||||||
|
- GROUP allow ACEs
|
||||||
|
|
||||||
|
The POSIX permissions returned for a GROUP entry are the allow bits alone!
|
||||||
|
|
||||||
|
- OTHER_OBJ allow ACE
|
||||||
|
|
||||||
|
Rinse and repeat for default ACEs with INHERIT flags set.
|
||||||
|
|
||||||
|
- Default Cygwin ACE (S_ISGID, CLASS_OBJ). */
|
||||||
|
|
||||||
|
/* POSIX <-> Win32 */
|
||||||
|
|
||||||
|
/* Historically, these bits are stored in a NULL SID ACE. To distinguish
|
||||||
|
the new ACL style from the old one, we're now using an invented SID, the
|
||||||
|
Cygwin SID (S-1-0-1132029815). The new ACEs can exist twice in an ACL,
|
||||||
|
the "normal one" containg CLASS_OBJ and special bits, and the one with
|
||||||
|
INHERIT bit set to pass the DEF_CLASS_OBJ bits and the S_ISGID bit on. */
|
||||||
|
#define CYG_ACE_ISVTX 0x001 /* 0x200 <-> 0x001 */
|
||||||
|
#define CYG_ACE_ISGID 0x002 /* 0x400 <-> 0x002 */
|
||||||
|
#define CYG_ACE_ISUID 0x004 /* 0x800 <-> 0x004 */
|
||||||
|
#define CYG_ACE_ISBITS_TO_POSIX(val) \
|
||||||
|
(((val) & 0x007) << 9)
|
||||||
|
#define CYG_ACE_ISBITS_TO_WIN(val) \
|
||||||
|
(((val) & (S_ISVTX | S_ISUID | S_IS_GID)) >> 9)
|
||||||
|
|
||||||
|
#define CYG_ACE_MASK_X 0x008 /* 0x001 <-> 0x008 */
|
||||||
|
#define CYG_ACE_MASK_W 0x010 /* 0x002 <-> 0x010 */
|
||||||
|
#define CYG_ACE_MASK_R 0x020 /* 0x004 <-> 0x020 */
|
||||||
|
#define CYG_ACE_MASK_RWX 0x038
|
||||||
|
#define CYG_ACE_MASK_VALID 0x040 /* has mask if set */
|
||||||
|
#define CYG_ACE_MASK_TO_POSIX(val) \
|
||||||
|
(((val) & CYG_ACE_MASK_RWX) >> 3)
|
||||||
|
#define CYG_ACE_MASK_TO_WIN(val) \
|
||||||
|
((((val) & S_IRWXO) << 3) \
|
||||||
|
| CYG_ACE_MASK_VALID)
|
||||||
|
|
||||||
static int
|
static int
|
||||||
searchace (aclent_t *aclp, int nentries, int type, uid_t id = ILLEGAL_UID)
|
searchace (aclent_t *aclp, int nentries, int type, uid_t id = ILLEGAL_UID)
|
||||||
{
|
{
|
||||||
|
@ -235,8 +293,7 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
|
||||||
allow |= FILE_DELETE_CHILD;
|
allow |= FILE_DELETE_CHILD;
|
||||||
/* Set inherit property. */
|
/* Set inherit property. */
|
||||||
DWORD inheritance = (aclbufp[i].a_type & ACL_DEFAULT)
|
DWORD inheritance = (aclbufp[i].a_type & ACL_DEFAULT)
|
||||||
? (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE
|
? (SUB_CONTAINERS_AND_OBJECTS_INHERIT | INHERIT_ONLY)
|
||||||
| INHERIT_ONLY_ACE)
|
|
||||||
: NO_INHERITANCE;
|
: NO_INHERITANCE;
|
||||||
/*
|
/*
|
||||||
* If a specific acl contains a corresponding default entry with
|
* If a specific acl contains a corresponding default entry with
|
||||||
|
@ -251,7 +308,7 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
|
||||||
? aclbufp[i].a_id : ILLEGAL_UID)) >= 0
|
? aclbufp[i].a_id : ILLEGAL_UID)) >= 0
|
||||||
&& aclbufp[i].a_perm == aclbufp[i + 1 + pos].a_perm)
|
&& aclbufp[i].a_perm == aclbufp[i + 1 + pos].a_perm)
|
||||||
{
|
{
|
||||||
inheritance = CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE;
|
inheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
|
||||||
/* invalidate the corresponding default entry. */
|
/* invalidate the corresponding default entry. */
|
||||||
invalid[i + 1 + pos] = true;
|
invalid[i + 1 + pos] = true;
|
||||||
}
|
}
|
||||||
|
@ -337,15 +394,19 @@ setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
|
||||||
#define DENY_R 040000
|
#define DENY_R 040000
|
||||||
#define DENY_W 020000
|
#define DENY_W 020000
|
||||||
#define DENY_X 010000
|
#define DENY_X 010000
|
||||||
|
#define DENY_RWX (DENY_R | DENY_W | DENY_X)
|
||||||
|
|
||||||
|
/* New style ACL means, just read the bits and store them away. Don't
|
||||||
|
create masked values on your own. */
|
||||||
static void
|
static void
|
||||||
getace (aclent_t &acl, int type, int id, DWORD win_ace_mask,
|
getace (aclent_t &acl, int type, int id, DWORD win_ace_mask,
|
||||||
DWORD win_ace_type)
|
DWORD win_ace_type, bool new_style)
|
||||||
{
|
{
|
||||||
acl.a_type = type;
|
acl.a_type = type;
|
||||||
acl.a_id = id;
|
acl.a_id = id;
|
||||||
|
|
||||||
if ((win_ace_mask & FILE_READ_BITS) && !(acl.a_perm & (S_IROTH | DENY_R)))
|
if ((win_ace_mask & FILE_READ_BITS)
|
||||||
|
&& (new_style || !(acl.a_perm & (S_IROTH | DENY_R))))
|
||||||
{
|
{
|
||||||
if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE)
|
if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE)
|
||||||
acl.a_perm |= S_IROTH;
|
acl.a_perm |= S_IROTH;
|
||||||
|
@ -353,7 +414,8 @@ getace (aclent_t &acl, int type, int id, DWORD win_ace_mask,
|
||||||
acl.a_perm |= DENY_R;
|
acl.a_perm |= DENY_R;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((win_ace_mask & FILE_WRITE_BITS) && !(acl.a_perm & (S_IWOTH | DENY_W)))
|
if ((win_ace_mask & FILE_WRITE_BITS)
|
||||||
|
&& (new_style || !(acl.a_perm & (S_IWOTH | DENY_W))))
|
||||||
{
|
{
|
||||||
if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE)
|
if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE)
|
||||||
acl.a_perm |= S_IWOTH;
|
acl.a_perm |= S_IWOTH;
|
||||||
|
@ -361,7 +423,8 @@ getace (aclent_t &acl, int type, int id, DWORD win_ace_mask,
|
||||||
acl.a_perm |= DENY_W;
|
acl.a_perm |= DENY_W;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((win_ace_mask & FILE_EXEC_BITS) && !(acl.a_perm & (S_IXOTH | DENY_X)))
|
if ((win_ace_mask & FILE_EXEC_BITS)
|
||||||
|
&& (new_style || !(acl.a_perm & (S_IXOTH | DENY_X))))
|
||||||
{
|
{
|
||||||
if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE)
|
if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE)
|
||||||
acl.a_perm |= S_IXOTH;
|
acl.a_perm |= S_IXOTH;
|
||||||
|
@ -370,40 +433,92 @@ getace (aclent_t &acl, int type, int id, DWORD win_ace_mask,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* From the SECURITY_DESCRIPTOR given in psd, compute user, owner, posix
|
||||||
|
attributes, as well as the POSIX acl. The function returns the number
|
||||||
|
of entries returned in aclbufp, or -1 in case of error. */
|
||||||
int
|
int
|
||||||
getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp)
|
get_posix_access (PSECURITY_DESCRIPTOR psd,
|
||||||
|
mode_t *attr_ret, uid_t *uid_ret, gid_t *gid_ret,
|
||||||
|
aclent_t *aclbufp, int nentries)
|
||||||
{
|
{
|
||||||
security_descriptor sd;
|
tmp_pathbuf tp;
|
||||||
|
|
||||||
if (get_file_sd (handle, pc, sd, false))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
cygpsid owner_sid;
|
|
||||||
cygpsid group_sid;
|
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
BOOLEAN dummy;
|
BOOLEAN dummy, acl_exists;
|
||||||
|
PACL acl;
|
||||||
|
PACCESS_ALLOWED_ACE ace;
|
||||||
|
cygpsid owner_sid, group_sid;
|
||||||
|
cyg_ldap cldap;
|
||||||
uid_t uid;
|
uid_t uid;
|
||||||
gid_t gid;
|
gid_t gid;
|
||||||
cyg_ldap cldap;
|
mode_t attr = 0;
|
||||||
|
aclent_t *lacl = NULL;
|
||||||
|
cygpsid ace_sid;
|
||||||
|
int pos, type, id;
|
||||||
|
|
||||||
status = RtlGetOwnerSecurityDescriptor (sd, (PSID *) &owner_sid, &dummy);
|
bool new_style = false;
|
||||||
|
int types_def = 0;
|
||||||
|
int def_pgrp_pos = -1;
|
||||||
|
bool has_class_perm = false, has_def_class_perm = false;
|
||||||
|
mode_t class_perm = 0, def_class_perm = 0;
|
||||||
|
|
||||||
|
if (aclbufp && nentries < MIN_ACL_ENTRIES)
|
||||||
|
{
|
||||||
|
set_errno (EINVAL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* If reading the security descriptor failed, treat the object as
|
||||||
|
unreadable. */
|
||||||
|
if (!psd)
|
||||||
|
{
|
||||||
|
if (attr_ret)
|
||||||
|
*attr_ret &= S_IFMT;
|
||||||
|
if (uid_ret)
|
||||||
|
*uid_ret = ILLEGAL_UID;
|
||||||
|
if (gid_ret)
|
||||||
|
*gid_ret = ILLEGAL_GID;
|
||||||
|
if (aclbufp)
|
||||||
|
{
|
||||||
|
aclbufp[0].a_type = USER_OBJ;
|
||||||
|
aclbufp[0].a_id = ILLEGAL_UID;
|
||||||
|
aclbufp[0].a_perm = 0;
|
||||||
|
aclbufp[1].a_type = GROUP_OBJ;
|
||||||
|
aclbufp[1].a_id = ILLEGAL_GID;
|
||||||
|
aclbufp[1].a_perm = 0;
|
||||||
|
aclbufp[2].a_type = OTHER_OBJ;
|
||||||
|
aclbufp[2].a_id = ILLEGAL_GID;
|
||||||
|
aclbufp[2].a_perm = 0;
|
||||||
|
return MIN_ACL_ENTRIES;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Fetch owner, group, and ACL from security descriptor. */
|
||||||
|
status = RtlGetOwnerSecurityDescriptor (psd, (PSID *) &owner_sid, &dummy);
|
||||||
if (!NT_SUCCESS (status))
|
if (!NT_SUCCESS (status))
|
||||||
{
|
{
|
||||||
__seterrno_from_nt_status (status);
|
__seterrno_from_nt_status (status);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
status = RtlGetGroupSecurityDescriptor (psd, (PSID *) &group_sid, &dummy);
|
||||||
|
if (!NT_SUCCESS (status))
|
||||||
|
{
|
||||||
|
__seterrno_from_nt_status (status);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
status = RtlGetDaclSecurityDescriptor (psd, &acl_exists, &acl, &dummy);
|
||||||
|
if (!NT_SUCCESS (status))
|
||||||
|
{
|
||||||
|
__seterrno_from_nt_status (status);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* Set uidret, gidret, and initalize attributes. */
|
||||||
uid = owner_sid.get_uid (&cldap);
|
uid = owner_sid.get_uid (&cldap);
|
||||||
|
|
||||||
status = RtlGetGroupSecurityDescriptor (sd, (PSID *) &group_sid, &dummy);
|
|
||||||
if (!NT_SUCCESS (status))
|
|
||||||
{
|
|
||||||
__seterrno_from_nt_status (status);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
gid = group_sid.get_gid (&cldap);
|
gid = group_sid.get_gid (&cldap);
|
||||||
|
if (attr_ret)
|
||||||
|
attr |= (*attr_ret & S_IFMT);
|
||||||
|
|
||||||
aclent_t lacl[MAX_ACL_ENTRIES];
|
/* Create and initialize local aclent_t array. */
|
||||||
memset (&lacl, 0, MAX_ACL_ENTRIES * sizeof (aclent_t));
|
lacl = (aclent_t *) tp.c_get ();
|
||||||
|
memset (lacl, 0, MAX_ACL_ENTRIES * sizeof (aclent_t *));
|
||||||
lacl[0].a_type = USER_OBJ;
|
lacl[0].a_type = USER_OBJ;
|
||||||
lacl[0].a_id = uid;
|
lacl[0].a_id = uid;
|
||||||
lacl[1].a_type = GROUP_OBJ;
|
lacl[1].a_type = GROUP_OBJ;
|
||||||
|
@ -411,102 +526,127 @@ getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp)
|
||||||
lacl[2].a_type = OTHER_OBJ;
|
lacl[2].a_type = OTHER_OBJ;
|
||||||
lacl[2].a_id = ILLEGAL_GID;
|
lacl[2].a_id = ILLEGAL_GID;
|
||||||
|
|
||||||
PACL acl;
|
/* No ACEs? Everybody has full access. */
|
||||||
BOOLEAN acl_exists;
|
if (!acl_exists || !acl || acl->AceCount == 0)
|
||||||
|
|
||||||
status = RtlGetDaclSecurityDescriptor (sd, &acl_exists, &acl, &dummy);
|
|
||||||
if (!NT_SUCCESS (status))
|
|
||||||
{
|
{
|
||||||
__seterrno_from_nt_status (status);
|
for (pos = 0; pos < MIN_ACL_ENTRIES; ++pos)
|
||||||
return -1;
|
lacl[pos].a_perm = S_IROTH | S_IWOTH | S_IXOTH;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pos, i, types_def = 0;
|
for (int i = 0; i < acl->AceCount; ++i)
|
||||||
int pgrp_pos = 1, def_pgrp_pos = -1;
|
|
||||||
bool has_class_perm = false, has_def_class_perm = false;
|
|
||||||
mode_t class_perm = 0, def_class_perm = 0;
|
|
||||||
|
|
||||||
if (!acl_exists || !acl)
|
|
||||||
for (pos = 0; pos < 3; ++pos)
|
|
||||||
lacl[pos].a_perm = S_IROTH | S_IWOTH | S_IXOTH;
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
for (i = 0; i < acl->AceCount; ++i)
|
if (!NT_SUCCESS (RtlGetAce (acl, i, (PVOID *) &ace)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ace_sid = (PSID) &ace->SidStart;
|
||||||
|
|
||||||
|
if (ace_sid == well_known_null_sid)
|
||||||
{
|
{
|
||||||
ACCESS_ALLOWED_ACE *ace;
|
/* Old-style or non-Cygwin ACL. Fetch only the special bits. */
|
||||||
|
attr |= CYG_ACE_ISBITS_TO_POSIX (ace->Mask);
|
||||||
if (!NT_SUCCESS (RtlGetAce (acl, i, (PVOID *) &ace)))
|
continue;
|
||||||
continue;
|
}
|
||||||
|
if (ace_sid == well_known_cygwin_sid)
|
||||||
cygpsid ace_sid ((PSID) &ace->SidStart);
|
{
|
||||||
int id;
|
/* New-style ACL. Note the fact that a mask value is present since
|
||||||
int type = 0;
|
that changes how getace fetches the information. That's fine,
|
||||||
|
because the Cygwin SID ACE is supposed to precede all USER, GROUP
|
||||||
if (ace_sid == well_known_null_sid)
|
and GROUP_OBJ entries. Any ACL not created that way has been
|
||||||
|
rearranged by the Windows functionality to create the brain-dead
|
||||||
|
"canonical" ACL order and is broken anyway. */
|
||||||
|
attr |= CYG_ACE_ISBITS_TO_POSIX (ace->Mask);
|
||||||
|
if (ace->Mask & CYG_ACE_MASK_VALID)
|
||||||
{
|
{
|
||||||
/* Simply ignore. */
|
new_style = true;
|
||||||
continue;
|
type = (ace->Header.AceFlags & SUB_CONTAINERS_AND_OBJECTS_INHERIT)
|
||||||
|
? DEF_CLASS_OBJ : CLASS_OBJ;
|
||||||
|
if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, ILLEGAL_GID))
|
||||||
|
>= 0)
|
||||||
|
{
|
||||||
|
lacl[pos].a_type = type;
|
||||||
|
lacl[pos].a_id = ILLEGAL_GID;
|
||||||
|
lacl[pos].a_perm = CYG_ACE_MASK_TO_POSIX (ace->Mask);
|
||||||
|
}
|
||||||
|
if (type == CLASS_OBJ) /* Needed for POSIX permissions. */
|
||||||
|
{
|
||||||
|
has_class_perm = true;
|
||||||
|
class_perm = lacl[pos].a_perm;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
has_def_class_perm = true;
|
||||||
|
def_class_perm = lacl[pos].a_perm;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (ace_sid == well_known_world_sid)
|
continue;
|
||||||
{
|
}
|
||||||
type = OTHER_OBJ;
|
else if (ace_sid == owner_sid)
|
||||||
id = ILLEGAL_GID;
|
{
|
||||||
}
|
type = USER_OBJ;
|
||||||
else if (ace_sid == owner_sid)
|
id = uid;
|
||||||
{
|
}
|
||||||
type = USER_OBJ;
|
else if (ace_sid == group_sid)
|
||||||
id = uid;
|
{
|
||||||
}
|
type = GROUP_OBJ;
|
||||||
else if (ace_sid == group_sid)
|
id = gid;
|
||||||
{
|
}
|
||||||
type = GROUP_OBJ;
|
else if (ace_sid == well_known_world_sid)
|
||||||
id = gid;
|
{
|
||||||
}
|
type = OTHER_OBJ;
|
||||||
else if (ace_sid == well_known_creator_group_sid)
|
id = ILLEGAL_GID;
|
||||||
{
|
}
|
||||||
type = DEF_GROUP_OBJ;
|
else if (ace_sid == well_known_creator_owner_sid)
|
||||||
types_def |= type;
|
{
|
||||||
id = ILLEGAL_GID;
|
type = DEF_USER_OBJ;
|
||||||
}
|
types_def |= type;
|
||||||
else if (ace_sid == well_known_creator_owner_sid)
|
id = ILLEGAL_GID;
|
||||||
{
|
}
|
||||||
type = DEF_USER_OBJ;
|
else if (ace_sid == well_known_creator_group_sid)
|
||||||
types_def |= type;
|
{
|
||||||
id = ILLEGAL_GID;
|
type = DEF_GROUP_OBJ;
|
||||||
}
|
types_def |= type;
|
||||||
else
|
id = ILLEGAL_GID;
|
||||||
id = ace_sid.get_id (TRUE, &type, &cldap);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
id = ace_sid.get_id (TRUE, &type, &cldap);
|
||||||
if (!type)
|
if (!type)
|
||||||
continue;
|
continue;
|
||||||
if (!(ace->Header.AceFlags & INHERIT_ONLY_ACE || type & ACL_DEFAULT))
|
}
|
||||||
|
if (!(ace->Header.AceFlags & INHERIT_ONLY || type & ACL_DEFAULT))
|
||||||
|
{
|
||||||
|
if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, id)) >= 0)
|
||||||
{
|
{
|
||||||
if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, id)) >= 0)
|
getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType,
|
||||||
|
new_style && type & (USER | GROUP));
|
||||||
|
if (!new_style)
|
||||||
{
|
{
|
||||||
getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType);
|
|
||||||
/* Fix up CLASS_OBJ value. */
|
/* Fix up CLASS_OBJ value. */
|
||||||
if (type == USER || type == GROUP)
|
if (type & (USER | GROUP))
|
||||||
{
|
{
|
||||||
has_class_perm = true;
|
has_class_perm = true;
|
||||||
class_perm |= lacl[pos].a_perm;
|
class_perm |= lacl[pos].a_perm;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((ace->Header.AceFlags
|
}
|
||||||
& (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE))
|
if ((ace->Header.AceFlags & SUB_CONTAINERS_AND_OBJECTS_INHERIT))
|
||||||
&& pc.isdir ())
|
{
|
||||||
|
if (type == USER_OBJ)
|
||||||
|
type = USER;
|
||||||
|
else if (type == GROUP_OBJ)
|
||||||
|
type = GROUP;
|
||||||
|
type |= ACL_DEFAULT;
|
||||||
|
types_def |= type;
|
||||||
|
if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, id)) >= 0)
|
||||||
{
|
{
|
||||||
if (type == USER_OBJ)
|
getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType,
|
||||||
type = USER;
|
new_style && type & (USER | GROUP));
|
||||||
else if (type == GROUP_OBJ)
|
if (!new_style)
|
||||||
type = GROUP;
|
|
||||||
type |= ACL_DEFAULT;
|
|
||||||
types_def |= type;
|
|
||||||
if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, id)) >= 0)
|
|
||||||
{
|
{
|
||||||
getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType);
|
|
||||||
/* Fix up DEF_CLASS_OBJ value. */
|
/* Fix up DEF_CLASS_OBJ value. */
|
||||||
if (type == DEF_USER || type == DEF_GROUP)
|
if (type & (USER | GROUP))
|
||||||
{
|
{
|
||||||
has_def_class_perm = true;
|
has_def_class_perm = true;
|
||||||
def_class_perm |= lacl[pos].a_perm;
|
def_class_perm |= lacl[pos].a_perm;
|
||||||
|
@ -517,80 +657,134 @@ getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* If secondary user and group entries exist in the ACL, fake a matching
|
}
|
||||||
CLASS_OBJ entry. The CLASS_OBJ permissions are the or'ed permissions
|
/* If this is an old-style or non-Cygwin ACL, and secondary user and group
|
||||||
of the primary group permissions and all secondary user and group
|
entries exist in the ACL, fake a matching CLASS_OBJ entry. The CLASS_OBJ
|
||||||
permissions. */
|
permissions are the or'ed permissions of the primary group permissions
|
||||||
if (has_class_perm && (pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) >= 0)
|
and all secondary user and group permissions. */
|
||||||
|
if (!new_style && has_class_perm
|
||||||
|
&& (pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) >= 0)
|
||||||
|
{
|
||||||
|
lacl[pos].a_type = CLASS_OBJ;
|
||||||
|
lacl[pos].a_id = ILLEGAL_GID;
|
||||||
|
lacl[pos].a_perm = class_perm | lacl[1].a_perm;
|
||||||
|
}
|
||||||
|
/* Ensure that the default acl contains at least
|
||||||
|
DEF_(USER|GROUP|OTHER)_OBJ entries. */
|
||||||
|
if (types_def && (pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) >= 0)
|
||||||
|
{
|
||||||
|
if (!(types_def & USER_OBJ))
|
||||||
{
|
{
|
||||||
lacl[pos].a_type = CLASS_OBJ;
|
lacl[pos].a_type = DEF_USER_OBJ;
|
||||||
lacl[pos].a_id = ILLEGAL_GID;
|
lacl[pos].a_id = uid;
|
||||||
lacl[pos].a_perm = class_perm | lacl[pgrp_pos].a_perm;
|
lacl[pos].a_perm = lacl[0].a_perm;
|
||||||
|
pos++;
|
||||||
}
|
}
|
||||||
/* Ensure that the default acl contains at least
|
if (!(types_def & GROUP_OBJ) && pos < MAX_ACL_ENTRIES)
|
||||||
DEF_(USER|GROUP|OTHER)_OBJ entries. */
|
|
||||||
if (types_def && (pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) >= 0)
|
|
||||||
{
|
{
|
||||||
if (!(types_def & USER_OBJ))
|
lacl[pos].a_type = DEF_GROUP_OBJ;
|
||||||
{
|
lacl[pos].a_id = gid;
|
||||||
lacl[pos].a_type = DEF_USER_OBJ;
|
lacl[pos].a_perm = lacl[1].a_perm;
|
||||||
lacl[pos].a_id = uid;
|
/* Note the position of the DEF_GROUP_OBJ entry. */
|
||||||
lacl[pos].a_perm = lacl[0].a_perm;
|
def_pgrp_pos = pos;
|
||||||
pos++;
|
pos++;
|
||||||
}
|
|
||||||
if (!(types_def & GROUP_OBJ) && pos < MAX_ACL_ENTRIES)
|
|
||||||
{
|
|
||||||
lacl[pos].a_type = DEF_GROUP_OBJ;
|
|
||||||
lacl[pos].a_id = gid;
|
|
||||||
lacl[pos].a_perm = lacl[1].a_perm;
|
|
||||||
/* Note the position of the DEF_GROUP_OBJ entry. */
|
|
||||||
def_pgrp_pos = pos;
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
if (!(types_def & OTHER_OBJ) && pos < MAX_ACL_ENTRIES)
|
|
||||||
{
|
|
||||||
lacl[pos].a_type = DEF_OTHER_OBJ;
|
|
||||||
lacl[pos].a_id = ILLEGAL_GID;
|
|
||||||
lacl[pos].a_perm = lacl[2].a_perm;
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/* If secondary user default and group default entries exist in the ACL,
|
if (!(types_def & OTHER_OBJ) && pos < MAX_ACL_ENTRIES)
|
||||||
fake a matching DEF_CLASS_OBJ entry. The DEF_CLASS_OBJ permissions are
|
|
||||||
the or'ed permissions of the primary group default permissions and all
|
|
||||||
secondary user and group default permissions. */
|
|
||||||
if (has_def_class_perm
|
|
||||||
&& (pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) >= 0)
|
|
||||||
{
|
{
|
||||||
lacl[pos].a_type = DEF_CLASS_OBJ;
|
lacl[pos].a_type = DEF_OTHER_OBJ;
|
||||||
lacl[pos].a_id = ILLEGAL_GID;
|
lacl[pos].a_id = ILLEGAL_GID;
|
||||||
lacl[pos].a_perm = def_class_perm;
|
lacl[pos].a_perm = lacl[2].a_perm;
|
||||||
if (def_pgrp_pos >= 0)
|
pos++;
|
||||||
lacl[pos].a_perm |= lacl[def_pgrp_pos].a_perm;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* If this is an old-style or non-Cygwin ACL, and secondary user default
|
||||||
|
and group default entries exist in the ACL, fake a matching DEF_CLASS_OBJ
|
||||||
|
entry. The DEF_CLASS_OBJ permissions are the or'ed permissions of the
|
||||||
|
primary group default permissions and all secondary user and group def.
|
||||||
|
permissions. */
|
||||||
|
if (!new_style && has_def_class_perm
|
||||||
|
&& (pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) >= 0)
|
||||||
|
{
|
||||||
|
lacl[pos].a_type = DEF_CLASS_OBJ;
|
||||||
|
lacl[pos].a_id = ILLEGAL_GID;
|
||||||
|
lacl[pos].a_perm = def_class_perm;
|
||||||
|
if (def_pgrp_pos >= 0)
|
||||||
|
lacl[pos].a_perm |= lacl[def_pgrp_pos].a_perm;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure `pos' contains the number of used entries in lacl. */
|
||||||
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;
|
||||||
|
|
||||||
|
/* For old-style or non-Cygwin ACLs, check for merging permissions. */
|
||||||
|
if (!new_style)
|
||||||
|
for (int i = 0; i < pos; ++i)
|
||||||
|
{
|
||||||
|
/* Current user? If the user entry has a deny ACE, don't check. */
|
||||||
|
if (lacl[i].a_id == myself->uid
|
||||||
|
&& lacl[i].a_type & (USER_OBJ | USER)
|
||||||
|
&& !(lacl[i].a_type & ACL_DEFAULT)
|
||||||
|
&& !(lacl[i].a_perm & DENY_RWX))
|
||||||
|
{
|
||||||
|
int gpos;
|
||||||
|
gid_t grps[NGROUPS_MAX];
|
||||||
|
cyg_ldap cldap;
|
||||||
|
|
||||||
|
/* Sum up all permissions of groups the user is member of, plus
|
||||||
|
everyone perms, and merge them to user perms. */
|
||||||
|
mode_t grp_perm = lacl[2].a_perm & S_IRWXO;
|
||||||
|
int gnum = internal_getgroups (NGROUPS_MAX, grps, &cldap);
|
||||||
|
for (int g = 0; g < gnum && grp_perm != S_IRWXO; ++g)
|
||||||
|
if ((gpos = 1, grps[g] == lacl[gpos].a_id)
|
||||||
|
|| (gpos = searchace (lacl, MAX_ACL_ENTRIES, GROUP, grps[g]))
|
||||||
|
>= 0)
|
||||||
|
grp_perm |= lacl[gpos].a_perm & S_IRWXO;
|
||||||
|
lacl[i].a_perm |= grp_perm;
|
||||||
|
}
|
||||||
|
/* For all groups, if everyone has more permissions, add everyone
|
||||||
|
perms to group perms. Skip groups with deny ACE. */
|
||||||
|
else if (lacl[i].a_id & (GROUP_OBJ | GROUP)
|
||||||
|
&& !(lacl[i].a_type & ACL_DEFAULT)
|
||||||
|
&& !(lacl[i].a_perm & DENY_RWX))
|
||||||
|
lacl[i].a_perm |= lacl[2].a_perm & S_IRWXO;
|
||||||
|
}
|
||||||
|
/* Construct POSIX permission bits. Fortunately we know exactly where
|
||||||
|
to fetch the affecting bits from, at least as long as the array
|
||||||
|
hasn't been sorted. */
|
||||||
|
attr |= (lacl[0].a_perm & S_IRWXO) << 6;
|
||||||
|
attr |= (has_class_perm ? class_perm : (lacl[1].a_perm & S_IRWXO)) << 3;
|
||||||
|
attr |= (lacl[2].a_perm & S_IRWXO);
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (uid_ret)
|
||||||
|
*uid_ret = uid;
|
||||||
|
if (gid_ret)
|
||||||
|
*gid_ret = gid;
|
||||||
|
if (attr_ret)
|
||||||
|
*attr_ret = attr;
|
||||||
if (aclbufp)
|
if (aclbufp)
|
||||||
{
|
{
|
||||||
#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)
|
|
||||||
lacl[1].a_perm = lacl[0].a_perm;
|
|
||||||
#endif
|
|
||||||
if (pos > nentries)
|
if (pos > nentries)
|
||||||
{
|
{
|
||||||
set_errno (ENOSPC);
|
set_errno (ENOSPC);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
memcpy (aclbufp, lacl, pos * sizeof (aclent_t));
|
memcpy (aclbufp, lacl, pos * sizeof (aclent_t));
|
||||||
for (i = 0; i < pos; ++i)
|
for (int i = 0; i < pos; ++i)
|
||||||
aclbufp[i].a_perm &= ~(DENY_R | DENY_W | DENY_X);
|
aclbufp[i].a_perm &= S_IRWXO;
|
||||||
aclsort32 (pos, 0, aclbufp);
|
aclsort32 (pos, 0, aclbufp);
|
||||||
}
|
}
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
getacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp)
|
||||||
|
{
|
||||||
|
security_descriptor sd;
|
||||||
|
|
||||||
|
if (get_file_sd (handle, pc, sd, false))
|
||||||
|
return -1;
|
||||||
|
int pos = get_posix_access (sd, NULL, NULL, NULL, aclbufp, nentries);
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,8 @@ SECURITY_ATTRIBUTES NO_COPY_RO sec_all_nih =
|
||||||
|
|
||||||
MKSID (well_known_null_sid, "S-1-0-0",
|
MKSID (well_known_null_sid, "S-1-0-0",
|
||||||
SECURITY_NULL_SID_AUTHORITY, 1, SECURITY_NULL_RID);
|
SECURITY_NULL_SID_AUTHORITY, 1, SECURITY_NULL_RID);
|
||||||
|
MKSID (well_known_cygwin_sid, "S-1-0-1132029815",
|
||||||
|
SECURITY_NULL_SID_AUTHORITY, 1, 0x43796777); /* "Cygw" */
|
||||||
MKSID (well_known_world_sid, "S-1-1-0",
|
MKSID (well_known_world_sid, "S-1-1-0",
|
||||||
SECURITY_WORLD_SID_AUTHORITY, 1, SECURITY_WORLD_RID);
|
SECURITY_WORLD_SID_AUTHORITY, 1, SECURITY_WORLD_RID);
|
||||||
MKSID (well_known_local_sid, "S-1-2-0",
|
MKSID (well_known_local_sid, "S-1-2-0",
|
||||||
|
@ -616,22 +618,21 @@ _recycler_sd (void *buf, bool users, bool dir)
|
||||||
pre-Vista permissions the same way as on Vista and later. */
|
pre-Vista permissions the same way as on Vista and later. */
|
||||||
RtlCreateAcl (dacl, MAX_DACL_LEN (3), ACL_REVISION);
|
RtlCreateAcl (dacl, MAX_DACL_LEN (3), ACL_REVISION);
|
||||||
RtlAddAccessAllowedAceEx (dacl, ACL_REVISION,
|
RtlAddAccessAllowedAceEx (dacl, ACL_REVISION,
|
||||||
dir ? CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE
|
dir ? SUB_CONTAINERS_AND_OBJECTS_INHERIT
|
||||||
: NO_INHERITANCE,
|
: NO_INHERITANCE,
|
||||||
FILE_ALL_ACCESS, well_known_admins_sid);
|
FILE_ALL_ACCESS, well_known_admins_sid);
|
||||||
RtlAddAccessAllowedAceEx (dacl, ACL_REVISION,
|
RtlAddAccessAllowedAceEx (dacl, ACL_REVISION,
|
||||||
dir ? CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE
|
dir ? SUB_CONTAINERS_AND_OBJECTS_INHERIT
|
||||||
: NO_INHERITANCE,
|
: NO_INHERITANCE,
|
||||||
FILE_ALL_ACCESS, well_known_system_sid);
|
FILE_ALL_ACCESS, well_known_system_sid);
|
||||||
if (users)
|
if (users)
|
||||||
RtlAddAccessAllowedAceEx (dacl, ACL_REVISION, NO_PROPAGATE_INHERIT_ACE,
|
RtlAddAccessAllowedAceEx (dacl, ACL_REVISION, INHERIT_NO_PROPAGATE,
|
||||||
FILE_GENERIC_READ | FILE_GENERIC_EXECUTE
|
FILE_GENERIC_READ | FILE_GENERIC_EXECUTE
|
||||||
| FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES,
|
| FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES,
|
||||||
well_known_users_sid);
|
well_known_users_sid);
|
||||||
else
|
else
|
||||||
RtlAddAccessAllowedAceEx (dacl, ACL_REVISION,
|
RtlAddAccessAllowedAceEx (dacl, ACL_REVISION,
|
||||||
dir ? CONTAINER_INHERIT_ACE
|
dir ? SUB_CONTAINERS_AND_OBJECTS_INHERIT
|
||||||
| OBJECT_INHERIT_ACE
|
|
||||||
: NO_INHERITANCE,
|
: NO_INHERITANCE,
|
||||||
FILE_ALL_ACCESS, cygheap->user.sid ());
|
FILE_ALL_ACCESS, cygheap->user.sid ());
|
||||||
LPVOID ace;
|
LPVOID ace;
|
||||||
|
|
|
@ -234,194 +234,6 @@ set_file_sd (HANDLE fh, path_conv &pc, security_descriptor &sd, bool is_chown)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
get_attribute_from_acl (mode_t *attribute, PACL acl, PSID owner_sid,
|
|
||||||
PSID group_sid, bool grp_member)
|
|
||||||
{
|
|
||||||
ACCESS_ALLOWED_ACE *ace;
|
|
||||||
mode_t allow = 0;
|
|
||||||
mode_t deny = 0;
|
|
||||||
mode_t *flags, *anti;
|
|
||||||
bool isownergroup = RtlEqualSid (owner_sid, group_sid);
|
|
||||||
|
|
||||||
for (DWORD i = 0; i < acl->AceCount; ++i)
|
|
||||||
{
|
|
||||||
if (!NT_SUCCESS (RtlGetAce (acl, i, (PVOID *) &ace)))
|
|
||||||
continue;
|
|
||||||
if (ace->Header.AceFlags & INHERIT_ONLY_ACE)
|
|
||||||
continue;
|
|
||||||
switch (ace->Header.AceType)
|
|
||||||
{
|
|
||||||
case ACCESS_ALLOWED_ACE_TYPE:
|
|
||||||
flags = &allow;
|
|
||||||
anti = &deny;
|
|
||||||
break;
|
|
||||||
case ACCESS_DENIED_ACE_TYPE:
|
|
||||||
flags = &deny;
|
|
||||||
anti = &allow;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
cygpsid ace_sid ((PSID) &ace->SidStart);
|
|
||||||
if (ace_sid == well_known_world_sid)
|
|
||||||
{
|
|
||||||
if (ace->Mask & FILE_READ_BITS)
|
|
||||||
*flags |= ((!(*anti & S_IROTH)) ? S_IROTH : 0)
|
|
||||||
| ((!isownergroup && !(*anti & S_IRGRP)) ? S_IRGRP : 0)
|
|
||||||
| ((!(*anti & S_IRUSR)) ? S_IRUSR : 0);
|
|
||||||
if (ace->Mask & FILE_WRITE_BITS)
|
|
||||||
*flags |= ((!(*anti & S_IWOTH)) ? S_IWOTH : 0)
|
|
||||||
| ((!isownergroup && !(*anti & S_IWGRP)) ? S_IWGRP : 0)
|
|
||||||
| ((!(*anti & S_IWUSR)) ? S_IWUSR : 0);
|
|
||||||
if (ace->Mask & FILE_EXEC_BITS)
|
|
||||||
*flags |= ((!(*anti & S_IXOTH)) ? S_IXOTH : 0)
|
|
||||||
| ((!isownergroup && !(*anti & S_IXGRP)) ? S_IXGRP : 0)
|
|
||||||
| ((!(*anti & S_IXUSR)) ? S_IXUSR : 0);
|
|
||||||
if ((S_ISDIR (*attribute)) &&
|
|
||||||
(ace->Mask & (FILE_WRITE_DATA | FILE_EXECUTE | FILE_DELETE_CHILD))
|
|
||||||
== (FILE_WRITE_DATA | FILE_EXECUTE))
|
|
||||||
*flags |= S_ISVTX;
|
|
||||||
}
|
|
||||||
else if (ace_sid == well_known_null_sid)
|
|
||||||
{
|
|
||||||
/* Read SUID, SGID and VTX bits from NULL ACE. */
|
|
||||||
if (ace->Mask & FILE_READ_DATA)
|
|
||||||
*flags |= S_ISVTX;
|
|
||||||
if (ace->Mask & FILE_WRITE_DATA)
|
|
||||||
*flags |= S_ISGID;
|
|
||||||
if (ace->Mask & FILE_APPEND_DATA)
|
|
||||||
*flags |= S_ISUID;
|
|
||||||
}
|
|
||||||
else if (ace_sid == owner_sid)
|
|
||||||
{
|
|
||||||
if (ace->Mask & FILE_READ_BITS)
|
|
||||||
*flags |= ((!(*anti & S_IRUSR)) ? S_IRUSR : 0);
|
|
||||||
if (ace->Mask & FILE_WRITE_BITS)
|
|
||||||
*flags |= ((!(*anti & S_IWUSR)) ? S_IWUSR : 0);
|
|
||||||
if (ace->Mask & FILE_EXEC_BITS)
|
|
||||||
*flags |= ((!(*anti & S_IXUSR)) ? S_IXUSR : 0);
|
|
||||||
/* Apply deny mask to group if group SID == owner SID. */
|
|
||||||
if (group_sid && isownergroup
|
|
||||||
&& 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)
|
|
||||||
{
|
|
||||||
if (ace->Mask & FILE_READ_BITS)
|
|
||||||
*flags |= ((!(*anti & S_IRGRP)) ? S_IRGRP : 0)
|
|
||||||
| ((grp_member && !(*anti & S_IRUSR)) ? S_IRUSR : 0);
|
|
||||||
if (ace->Mask & FILE_WRITE_BITS)
|
|
||||||
*flags |= ((!(*anti & S_IWGRP)) ? S_IWGRP : 0)
|
|
||||||
| ((grp_member && !(*anti & S_IWUSR)) ? S_IWUSR : 0);
|
|
||||||
if (ace->Mask & FILE_EXEC_BITS)
|
|
||||||
*flags |= ((!(*anti & S_IXGRP)) ? S_IXGRP : 0)
|
|
||||||
| ((grp_member && !(*anti & S_IXUSR)) ? S_IXUSR : 0);
|
|
||||||
}
|
|
||||||
else if (flags == &allow)
|
|
||||||
{
|
|
||||||
/* Simplified computation of additional group permissions based on
|
|
||||||
the CLASS_OBJ value. CLASS_OBJ represents the or'ed value of
|
|
||||||
the primary group permissions and all secondary user and group
|
|
||||||
permissions. FIXME: This only takes ACCESS_ALLOWED_ACEs into
|
|
||||||
account. The computation with additional ACCESS_DENIED_ACE
|
|
||||||
handling is much more complicated. */
|
|
||||||
if (ace->Mask & FILE_READ_BITS)
|
|
||||||
*flags |= S_IRGRP;
|
|
||||||
if (ace->Mask & FILE_WRITE_BITS)
|
|
||||||
*flags |= S_IWGRP;
|
|
||||||
if (ace->Mask & FILE_EXEC_BITS)
|
|
||||||
*flags |= S_IXGRP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*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)
|
|
||||||
/* FIXME: temporary exception for /var/empty */
|
|
||||||
&& well_known_system_sid != group_sid)
|
|
||||||
{
|
|
||||||
allow &= ~(S_IRGRP | S_IWGRP | S_IXGRP);
|
|
||||||
allow |= (((allow & S_IRUSR) ? S_IRGRP : 0)
|
|
||||||
| ((allow & S_IWUSR) ? S_IWGRP : 0)
|
|
||||||
| ((allow & S_IXUSR) ? S_IXGRP : 0));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
*attribute |= allow;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
get_info_from_sd (PSECURITY_DESCRIPTOR psd, mode_t *attribute,
|
|
||||||
uid_t *uidret, gid_t *gidret)
|
|
||||||
{
|
|
||||||
if (!psd)
|
|
||||||
{
|
|
||||||
/* If reading the security descriptor failed, treat the object
|
|
||||||
as unreadable. */
|
|
||||||
if (attribute)
|
|
||||||
*attribute &= ~(S_IRWXU | S_IRWXG | S_IRWXO);
|
|
||||||
if (uidret)
|
|
||||||
*uidret = ILLEGAL_UID;
|
|
||||||
if (gidret)
|
|
||||||
*gidret = ILLEGAL_GID;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cygpsid owner_sid;
|
|
||||||
cygpsid group_sid;
|
|
||||||
NTSTATUS status;
|
|
||||||
BOOLEAN dummy;
|
|
||||||
|
|
||||||
status = RtlGetOwnerSecurityDescriptor (psd, (PSID *) &owner_sid, &dummy);
|
|
||||||
if (!NT_SUCCESS (status))
|
|
||||||
debug_printf ("RtlGetOwnerSecurityDescriptor: %y", status);
|
|
||||||
status = RtlGetGroupSecurityDescriptor (psd, (PSID *) &group_sid, &dummy);
|
|
||||||
if (!NT_SUCCESS (status))
|
|
||||||
debug_printf ("RtlGetGroupSecurityDescriptor: %y", status);
|
|
||||||
|
|
||||||
uid_t uid;
|
|
||||||
gid_t gid;
|
|
||||||
bool grp_member = get_sids_info (owner_sid, group_sid, &uid, &gid);
|
|
||||||
if (uidret)
|
|
||||||
*uidret = uid;
|
|
||||||
if (gidret)
|
|
||||||
*gidret = gid;
|
|
||||||
|
|
||||||
if (!attribute)
|
|
||||||
{
|
|
||||||
syscall_printf ("uid %u, gid %u", uid, gid);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PACL acl;
|
|
||||||
BOOLEAN acl_exists;
|
|
||||||
|
|
||||||
status = RtlGetDaclSecurityDescriptor (psd, &acl_exists, &acl, &dummy);
|
|
||||||
if (!NT_SUCCESS (status))
|
|
||||||
{
|
|
||||||
__seterrno_from_nt_status (status);
|
|
||||||
*attribute &= ~(S_IRWXU | S_IRWXG | S_IRWXO);
|
|
||||||
}
|
|
||||||
else if (!acl_exists || !acl)
|
|
||||||
*attribute |= S_IRWXU | S_IRWXG | S_IRWXO;
|
|
||||||
else
|
|
||||||
get_attribute_from_acl (attribute, acl, owner_sid, group_sid, grp_member);
|
|
||||||
|
|
||||||
syscall_printf ("%sACL %y, uid %u, gid %u",
|
|
||||||
(!acl_exists || !acl)?"NO ":"", *attribute, uid, gid);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
get_reg_sd (HANDLE handle, security_descriptor &sd_ret)
|
get_reg_sd (HANDLE handle, security_descriptor &sd_ret)
|
||||||
{
|
{
|
||||||
|
@ -454,7 +266,7 @@ get_reg_attribute (HKEY hkey, mode_t *attribute, uid_t *uidret,
|
||||||
|
|
||||||
if (!get_reg_sd (hkey, sd))
|
if (!get_reg_sd (hkey, sd))
|
||||||
{
|
{
|
||||||
get_info_from_sd (sd, attribute, uidret, gidret);
|
get_posix_access (sd, attribute, uidret, gidret, NULL, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* The entries are already set to default values */
|
/* The entries are already set to default values */
|
||||||
|
@ -471,7 +283,7 @@ get_file_attribute (HANDLE handle, path_conv &pc,
|
||||||
|
|
||||||
if (!get_file_sd (handle, pc, sd, false))
|
if (!get_file_sd (handle, pc, sd, false))
|
||||||
{
|
{
|
||||||
get_info_from_sd (sd, attribute, uidret, gidret);
|
get_posix_access (sd, attribute, uidret, gidret, NULL, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* ENOSYS is returned by get_file_sd if fetching the DACL from a remote
|
/* ENOSYS is returned by get_file_sd if fetching the DACL from a remote
|
||||||
|
@ -773,10 +585,10 @@ alloc_sd (path_conv &pc, uid_t uid, gid_t gid, int attribute,
|
||||||
{
|
{
|
||||||
if ((S_ISDIR (attribute) && (attribute & S_JUSTCREATED))
|
if ((S_ISDIR (attribute) && (attribute & S_JUSTCREATED))
|
||||||
|| (ace->Header.AceFlags
|
|| (ace->Header.AceFlags
|
||||||
& (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE)) == 0)
|
& (SUB_CONTAINERS_AND_OBJECTS_INHERIT)) == 0)
|
||||||
continue;
|
continue;
|
||||||
else
|
else
|
||||||
ace->Header.AceFlags |= INHERIT_ONLY_ACE;
|
ace->Header.AceFlags |= INHERIT_ONLY;
|
||||||
}
|
}
|
||||||
if (attribute & S_JUSTCREATED)
|
if (attribute & S_JUSTCREATED)
|
||||||
{
|
{
|
||||||
|
@ -797,8 +609,7 @@ alloc_sd (path_conv &pc, uid_t uid, gid_t gid, int attribute,
|
||||||
it inherits the default ACL from its parent, so mark
|
it inherits the default ACL from its parent, so mark
|
||||||
all unrelated, inherited ACEs inheritable. */
|
all unrelated, inherited ACEs inheritable. */
|
||||||
if (S_ISDIR (attribute))
|
if (S_ISDIR (attribute))
|
||||||
ace->Header.AceFlags |= CONTAINER_INHERIT_ACE
|
ace->Header.AceFlags |= SUB_CONTAINERS_AND_OBJECTS_INHERIT;
|
||||||
| OBJECT_INHERIT_ACE;
|
|
||||||
}
|
}
|
||||||
else if (uid == ILLEGAL_UID && gid == ILLEGAL_UID
|
else if (uid == ILLEGAL_UID && gid == ILLEGAL_UID
|
||||||
&& ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE
|
&& ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE
|
||||||
|
@ -835,8 +646,7 @@ alloc_sd (path_conv &pc, uid_t uid, gid_t gid, int attribute,
|
||||||
Cygwin applications don't need this. */
|
Cygwin applications don't need this. */
|
||||||
if (S_ISDIR (attribute) && (attribute & S_JUSTCREATED))
|
if (S_ISDIR (attribute) && (attribute & S_JUSTCREATED))
|
||||||
{
|
{
|
||||||
const DWORD inherit = CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE
|
const DWORD inherit = SUB_CONTAINERS_AND_OBJECTS_INHERIT | INHERIT_ONLY;
|
||||||
| INHERIT_ONLY_ACE;
|
|
||||||
/* 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,
|
||||||
well_known_creator_owner_sid, acl_len,
|
well_known_creator_owner_sid, acl_len,
|
||||||
|
@ -936,7 +746,7 @@ get_object_attribute (HANDLE handle, uid_t *uidret, gid_t *gidret,
|
||||||
|
|
||||||
if (get_object_sd (handle, sd))
|
if (get_object_sd (handle, sd))
|
||||||
return -1;
|
return -1;
|
||||||
get_info_from_sd (sd, attribute, uidret, gidret);
|
get_posix_access (sd, attribute, uidret, gidret, NULL, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -393,6 +393,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
extern cygpsid well_known_null_sid;
|
extern cygpsid well_known_null_sid;
|
||||||
|
extern cygpsid well_known_cygwin_sid;
|
||||||
extern cygpsid well_known_world_sid;
|
extern cygpsid well_known_world_sid;
|
||||||
extern cygpsid well_known_local_sid;
|
extern cygpsid well_known_local_sid;
|
||||||
extern cygpsid well_known_console_logon_sid;
|
extern cygpsid well_known_console_logon_sid;
|
||||||
|
@ -463,6 +464,8 @@ bool get_sids_info (cygpsid, cygpsid, uid_t * , gid_t *);
|
||||||
struct acl;
|
struct acl;
|
||||||
extern "C" int aclsort32 (int, int, struct acl *);
|
extern "C" int aclsort32 (int, int, struct acl *);
|
||||||
extern "C" int acl32 (const char *, int, int, struct acl *);
|
extern "C" int acl32 (const char *, int, int, struct acl *);
|
||||||
|
int get_posix_access (PSECURITY_DESCRIPTOR, mode_t *, uid_t *, gid_t *,
|
||||||
|
struct acl *, int);
|
||||||
int getacl (HANDLE, path_conv &, int, struct acl *);
|
int getacl (HANDLE, path_conv &, int, struct acl *);
|
||||||
int setacl (HANDLE, path_conv &, int, struct acl *, bool &);
|
int setacl (HANDLE, path_conv &, int, struct acl *, bool &);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue