Support acl(2) method for reading pty ACLs, fix pty chown
* fhandler.h (fhandler_pty_slave::facl): Add prototype. * fhandler_tty.cc (fhandler_pty_slave::facl): New method. (fhandler_pty_slave::fchown): Fix uid/gid handling. * sec_acl.cc (set_posix_access): Drop superfluous class_idx variable. Simplify and move around code in a few places. To improve ACL readability, add r/w permissions to Admins ACE appended to pty ACL. Add comment to explain Windows ACE Mask filtering being in the way of creating a real CLASS_OBJ. (get_posix_access): Fake CLASS_OBJ for ptys. Explain why. * security.cc (get_object_attribute): Add S_IFCHR flag to attributes when calling get_posix_access. Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
parent
02bbbb7506
commit
f63dffb818
|
@ -1,3 +1,17 @@
|
||||||
|
2015-04-17 Corinna Vinschen <corinna@vinschen.de>
|
||||||
|
|
||||||
|
* fhandler.h (fhandler_pty_slave::facl): Add prototype.
|
||||||
|
* fhandler_tty.cc (fhandler_pty_slave::facl): New method.
|
||||||
|
(fhandler_pty_slave::fchown): Fix uid/gid handling.
|
||||||
|
* sec_acl.cc (set_posix_access): Drop superfluous class_idx variable.
|
||||||
|
Simplify and move around code in a few places. To improve ACL
|
||||||
|
readability, add r/w permissions to Admins ACE appended to pty ACL.
|
||||||
|
Add comment to explain Windows ACE Mask filtering being in the way of
|
||||||
|
creating a real CLASS_OBJ.
|
||||||
|
(get_posix_access): Fake CLASS_OBJ for ptys. Explain why.
|
||||||
|
* security.cc (get_object_attribute): Add S_IFCHR flag to attributes
|
||||||
|
when calling get_posix_access.
|
||||||
|
|
||||||
2015-04-17 Corinna Vinschen <corinna@vinschen.de>
|
2015-04-17 Corinna Vinschen <corinna@vinschen.de>
|
||||||
|
|
||||||
* uinfo.cc (pwdgrp::fetch_account_from_windows): Always revert SID
|
* uinfo.cc (pwdgrp::fetch_account_from_windows): Always revert SID
|
||||||
|
|
|
@ -1545,6 +1545,7 @@ class fhandler_pty_slave: public fhandler_pty_common
|
||||||
select_record *select_read (select_stuff *);
|
select_record *select_read (select_stuff *);
|
||||||
virtual char const *ttyname () { return pc.dev.name; }
|
virtual char const *ttyname () { return pc.dev.name; }
|
||||||
int __reg2 fstat (struct stat *buf);
|
int __reg2 fstat (struct stat *buf);
|
||||||
|
int __reg3 facl (int, int, struct acl *);
|
||||||
int __reg1 fchmod (mode_t mode);
|
int __reg1 fchmod (mode_t mode);
|
||||||
int __reg2 fchown (uid_t uid, gid_t gid);
|
int __reg2 fchown (uid_t uid, gid_t gid);
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ details. */
|
||||||
#include "winsup.h"
|
#include "winsup.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
|
#include <sys/acl.h>
|
||||||
#include <cygwin/kd.h>
|
#include <cygwin/kd.h>
|
||||||
#include "cygerrno.h"
|
#include "cygerrno.h"
|
||||||
#include "security.h"
|
#include "security.h"
|
||||||
|
@ -1018,6 +1019,62 @@ fhandler_pty_slave::fstat (struct stat *st)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int __reg3
|
||||||
|
fhandler_pty_slave::facl (int cmd, int nentries, aclent_t *aclbufp)
|
||||||
|
{
|
||||||
|
int res = -1;
|
||||||
|
bool to_close = false;
|
||||||
|
security_descriptor sd;
|
||||||
|
mode_t attr = S_IFCHR;
|
||||||
|
|
||||||
|
switch (cmd)
|
||||||
|
{
|
||||||
|
case SETACL:
|
||||||
|
if (!aclsort32 (nentries, 0, aclbufp))
|
||||||
|
set_errno (ENOTSUP);
|
||||||
|
break;
|
||||||
|
case GETACL:
|
||||||
|
if (!aclbufp)
|
||||||
|
{
|
||||||
|
set_errno (EFAULT);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*FALLTHRU*/
|
||||||
|
case GETACLCNT:
|
||||||
|
if (!input_available_event)
|
||||||
|
{
|
||||||
|
char buf[MAX_PATH];
|
||||||
|
shared_name (buf, INPUT_AVAILABLE_EVENT, get_minor ());
|
||||||
|
input_available_event = OpenEvent (READ_CONTROL, TRUE, buf);
|
||||||
|
if (input_available_event)
|
||||||
|
to_close = true;
|
||||||
|
}
|
||||||
|
if (!input_available_event
|
||||||
|
|| get_object_sd (input_available_event, sd))
|
||||||
|
{
|
||||||
|
res = get_posix_access (NULL, &attr, NULL, NULL, aclbufp, nentries);
|
||||||
|
if (aclbufp && res == MIN_ACL_ENTRIES)
|
||||||
|
{
|
||||||
|
aclbufp[0].a_perm = S_IROTH | S_IWOTH;
|
||||||
|
aclbufp[0].a_id = 18;
|
||||||
|
aclbufp[1].a_id = 544;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (cmd == GETACL)
|
||||||
|
res = get_posix_access (sd, &attr, NULL, NULL, aclbufp, nentries);
|
||||||
|
else
|
||||||
|
res = get_posix_access (sd, &attr, NULL, NULL, NULL, 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
set_errno (EINVAL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (to_close)
|
||||||
|
CloseHandle (input_available_event);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/* Helper function for fchmod and fchown, which just opens all handles
|
/* Helper function for fchmod and fchown, which just opens all handles
|
||||||
and signals success via bool return. */
|
and signals success via bool return. */
|
||||||
bool
|
bool
|
||||||
|
@ -1122,8 +1179,11 @@ fhandler_pty_slave::fchown (uid_t uid, gid_t gid)
|
||||||
RtlCreateSecurityDescriptor (sd, SECURITY_DESCRIPTOR_REVISION);
|
RtlCreateSecurityDescriptor (sd, SECURITY_DESCRIPTOR_REVISION);
|
||||||
if (!get_object_attribute (input_available_event, &o_uid, &o_gid, &mode))
|
if (!get_object_attribute (input_available_event, &o_uid, &o_gid, &mode))
|
||||||
{
|
{
|
||||||
if ((uid == ILLEGAL_UID || uid == o_uid)
|
if (uid == ILLEGAL_UID)
|
||||||
&& (gid == ILLEGAL_GID || gid == o_gid))
|
uid = o_uid;
|
||||||
|
if (gid == ILLEGAL_GID)
|
||||||
|
gid = o_gid;
|
||||||
|
if (uid == o_uid && gid == o_gid)
|
||||||
ret = 0;
|
ret = 0;
|
||||||
else if (!create_object_sd_from_attribute (uid, gid, mode, sd))
|
else if (!create_object_sd_from_attribute (uid, gid, mode, sd))
|
||||||
ret = fch_set_sd (sd, true);
|
ret = fch_set_sd (sd, true);
|
||||||
|
|
|
@ -140,9 +140,9 @@ set_posix_access (mode_t attr, uid_t uid, gid_t gid,
|
||||||
size_t acl_len = sizeof (ACL);
|
size_t acl_len = sizeof (ACL);
|
||||||
mode_t class_obj = 0, other_obj, group_obj, deny;
|
mode_t class_obj = 0, other_obj, group_obj, deny;
|
||||||
DWORD access;
|
DWORD access;
|
||||||
int idx, start_idx, class_idx, tmp_idx;
|
int idx, start_idx, tmp_idx;
|
||||||
bool owner_eq_group = false;
|
bool owner_eq_group = false;
|
||||||
bool dev_saw_admins = false;
|
bool dev_has_admins = false;
|
||||||
|
|
||||||
/* Initialize local security descriptor. */
|
/* Initialize local security descriptor. */
|
||||||
RtlCreateSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION);
|
RtlCreateSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION);
|
||||||
|
@ -172,8 +172,9 @@ set_posix_access (mode_t attr, uid_t uid, gid_t gid,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
owner_eq_group = RtlEqualSid (owner, group);
|
owner_eq_group = RtlEqualSid (owner, group);
|
||||||
|
if (S_ISCHR (attr))
|
||||||
|
dev_has_admins = well_known_admins_sid == owner
|
||||||
|
|| well_known_admins_sid == group;
|
||||||
|
|
||||||
/* No POSIX ACL? Use attr to generate one from scratch. */
|
/* No POSIX ACL? Use attr to generate one from scratch. */
|
||||||
if (!aclbufp)
|
if (!aclbufp)
|
||||||
|
@ -276,11 +277,12 @@ set_posix_access (mode_t attr, uid_t uid, gid_t gid,
|
||||||
|
|
||||||
/* ... class_obj. Create Cygwin ACE. Only the S_ISGID attribute gets
|
/* ... class_obj. Create Cygwin ACE. Only the S_ISGID attribute gets
|
||||||
inherited. */
|
inherited. */
|
||||||
access = CYG_ACE_ISBITS_TO_WIN (def ? attr & S_ISGID : attr);
|
access = CYG_ACE_ISBITS_TO_WIN (def ? attr & S_ISGID : attr)
|
||||||
class_idx = searchace (aclbufp, nentries, def | CLASS_OBJ);
|
| CYG_ACE_NEW_STYLE;
|
||||||
if (class_idx >= 0)
|
tmp_idx = searchace (aclbufp, nentries, def | CLASS_OBJ);
|
||||||
|
if (tmp_idx >= 0)
|
||||||
{
|
{
|
||||||
class_obj = aclbufp[class_idx].a_perm;
|
class_obj = aclbufp[tmp_idx].a_perm;
|
||||||
access |= CYG_ACE_MASK_TO_WIN (class_obj);
|
access |= CYG_ACE_MASK_TO_WIN (class_obj);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -288,9 +290,11 @@ set_posix_access (mode_t attr, uid_t uid, gid_t gid,
|
||||||
/* Setting class_obj to group_obj allows to write below code without
|
/* Setting class_obj to group_obj allows to write below code without
|
||||||
additional checks for existence of a CLASS_OBJ. */
|
additional checks for existence of a CLASS_OBJ. */
|
||||||
class_obj = group_obj;
|
class_obj = group_obj;
|
||||||
class_idx = -1;
|
|
||||||
}
|
}
|
||||||
access |= CYG_ACE_NEW_STYLE;
|
/* Note that Windows filters the ACE Mask value so it only reflects
|
||||||
|
the bit values supported by the object type. The result is that
|
||||||
|
we can't set a CLASS_OBJ value for ptys. The get_posix_access
|
||||||
|
function has to workaround that. */
|
||||||
if (!add_access_denied_ace (acl, access, well_known_null_sid, acl_len,
|
if (!add_access_denied_ace (acl, access, well_known_null_sid, acl_len,
|
||||||
inherit))
|
inherit))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -359,14 +363,6 @@ set_posix_access (mode_t attr, uid_t uid, gid_t gid,
|
||||||
if (aclbufp[idx].a_perm == S_IRWXO)
|
if (aclbufp[idx].a_perm == S_IRWXO)
|
||||||
access |= FILE_DELETE_CHILD;
|
access |= FILE_DELETE_CHILD;
|
||||||
}
|
}
|
||||||
/* For ptys check if the admins group is in the ACL. If so,
|
|
||||||
make sure the group has WRITE_DAC and WRITE_OWNER perms. */
|
|
||||||
if (S_ISCHR (attr) && !dev_saw_admins
|
|
||||||
&& aclsid[idx] == well_known_admins_sid)
|
|
||||||
{
|
|
||||||
access |= STD_RIGHTS_OWNER;
|
|
||||||
dev_saw_admins = true;
|
|
||||||
}
|
|
||||||
if (aclbufp[idx].a_perm & S_IROTH)
|
if (aclbufp[idx].a_perm & S_IROTH)
|
||||||
access |= FILE_ALLOW_READ;
|
access |= FILE_ALLOW_READ;
|
||||||
if (aclbufp[idx].a_perm & S_IWOTH)
|
if (aclbufp[idx].a_perm & S_IWOTH)
|
||||||
|
@ -379,6 +375,10 @@ set_posix_access (mode_t attr, uid_t uid, gid_t gid,
|
||||||
== (S_IWOTH | S_IXOTH)
|
== (S_IWOTH | S_IXOTH)
|
||||||
&& (!(attr & S_ISVTX) || aclbufp[idx].a_type & USER_OBJ))
|
&& (!(attr & S_ISVTX) || aclbufp[idx].a_type & USER_OBJ))
|
||||||
access |= FILE_DELETE_CHILD;
|
access |= FILE_DELETE_CHILD;
|
||||||
|
/* For ptys, make sure the Administrators group has WRITE_DAC
|
||||||
|
and WRITE_OWNER perms. */
|
||||||
|
if (dev_has_admins && aclsid[idx] == well_known_admins_sid)
|
||||||
|
access |= STD_RIGHTS_OWNER;
|
||||||
if (!add_access_allowed_ace (acl, access, aclsid[idx], acl_len,
|
if (!add_access_allowed_ace (acl, access, aclsid[idx], acl_len,
|
||||||
inherit))
|
inherit))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -386,8 +386,10 @@ set_posix_access (mode_t attr, uid_t uid, gid_t gid,
|
||||||
}
|
}
|
||||||
/* For ptys if the admins group isn't in the ACL, add an ACE to make
|
/* For ptys if the admins group isn't in the ACL, add an ACE to make
|
||||||
sure the group has WRITE_DAC and WRITE_OWNER perms. */
|
sure the group has WRITE_DAC and WRITE_OWNER perms. */
|
||||||
if (S_ISCHR (attr) && !dev_saw_admins
|
if (S_ISCHR (attr) && !dev_has_admins
|
||||||
&& !add_access_allowed_ace (acl, STD_RIGHTS_OWNER,
|
&& !add_access_allowed_ace (acl,
|
||||||
|
STD_RIGHTS_OWNER | FILE_ALLOW_READ
|
||||||
|
| FILE_ALLOW_WRITE,
|
||||||
well_known_admins_sid, acl_len,
|
well_known_admins_sid, acl_len,
|
||||||
NO_INHERITANCE))
|
NO_INHERITANCE))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -860,6 +862,20 @@ get_posix_access (PSECURITY_DESCRIPTOR psd,
|
||||||
lacl[pos].a_id = ILLEGAL_GID;
|
lacl[pos].a_id = ILLEGAL_GID;
|
||||||
lacl[pos].a_perm = class_perm | lacl[1].a_perm;
|
lacl[pos].a_perm = class_perm | lacl[1].a_perm;
|
||||||
}
|
}
|
||||||
|
/* For ptys, fake a mask if the admins group is neither owner nor group.
|
||||||
|
In that case we have an extra ACE for the admins group, and we need a
|
||||||
|
CLASS_OBJ to get a valid POSIX ACL. However, Windows filters the ACE
|
||||||
|
Mask value so it only reflects the bit values supported by the object
|
||||||
|
type. The result is that we can't set an explicit CLASS_OBJ value for
|
||||||
|
ptys in the NULL SID ACE. */
|
||||||
|
else if (S_ISCHR (attr) && owner_sid != well_known_admins_sid
|
||||||
|
&& group_sid != well_known_admins_sid
|
||||||
|
&& (pos = searchace (lacl, MAX_ACL_ENTRIES, CLASS_OBJ)) >= 0)
|
||||||
|
{
|
||||||
|
lacl[pos].a_type = CLASS_OBJ;
|
||||||
|
lacl[pos].a_id = ILLEGAL_GID;
|
||||||
|
lacl[pos].a_perm = lacl[1].a_perm; /* == group perms */
|
||||||
|
}
|
||||||
/* If this is a just created file, and there are no default permissions
|
/* If this is a just created file, and there are no default permissions
|
||||||
(probably no inherited ACEs so created from a default DACL), assign
|
(probably no inherited ACEs so created from a default DACL), assign
|
||||||
the permissions specified by the file creation mask. The values get
|
the permissions specified by the file creation mask. The values get
|
||||||
|
|
|
@ -401,11 +401,16 @@ get_object_attribute (HANDLE handle, uid_t *uidret, gid_t *gidret,
|
||||||
mode_t *attribute)
|
mode_t *attribute)
|
||||||
{
|
{
|
||||||
security_descriptor sd;
|
security_descriptor sd;
|
||||||
|
mode_t attr = S_IFCHR;
|
||||||
|
|
||||||
if (get_object_sd (handle, sd))
|
if (get_object_sd (handle, sd))
|
||||||
return -1;
|
return -1;
|
||||||
return get_posix_access (sd, attribute, uidret, gidret, NULL, 0) >= 0
|
if (attribute)
|
||||||
? 0 : -1;
|
*attribute |= S_IFCHR;
|
||||||
|
else
|
||||||
|
attribute = &attr;
|
||||||
|
return get_posix_access (sd, attribute, uidret, gidret, NULL, 0)
|
||||||
|
>= 0 ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
Loading…
Reference in New Issue