Reapply POSIX ACL changes.
- New, unified implementation of POSIX permission and ACL handling. The new ACLs now store the POSIX ACL MASK/CLASS_OBJ permission mask, and they allow to inherit the S_ISGID bit. ACL inheritance now really works as desired, in a limited, but theoretically equivalent fashion even for non-Cygwin processes. To accommodate Windows default ACLs, the new code ignores SYSTEM and Administrators group permissions when computing the MASK/CLASS_OBJ permission mask on old ACLs, and it doesn't deny access to SYSTEM and Administrators group based on the value of MASK/CLASS_OBJ when creating the new ACLs. The new code now handles the S_ISGID bit on directories as on Linux: Setting S_ISGID on a directory causes new files and subdirs created within to inherit its group, rather than the primary group of the user who created the file. This only works for files and directories created by Cygwin processes. 2015-05-29 Corinna Vinschen <corinna@vinschen.de> Reapply POSIX ACL changes. * utils.xml (setfacl): Show new option output. (getfacl): Show new option output. * sec_acl.cc (get_posix_access): Check for Cygwin "standard" ACL. Apply umask, if so. Align comments. * security.cc (set_created_file_access): Fix permission masking by incoming requested file mode. * sec_acl.cc (set_posix_access): Apply mask only in terms of execute bit for SYSTEM and Admins group. * sec_acl.cc (set_posix_access): Don't create DENY ACEs for USER and GROUP entries if they are the same as USER_OBJ or GROUP_OBJ. * 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. * sec_acl.cc (set_posix_access): Move merging group perms into owner perms in case of owner == group after mask has been computed. Take mask into account when doing so to avoid unnecessary ACCESS_DENIED_ACE. * sec_acl.cc (get_posix_access): Only set saw_group_obj flag if we saw the ACCESS_ALLOWED_ACE. * fhandler_disk_file.cc (fhandler_disk_file::fchmod): Deliberatly set GROUP_OBJ and CLASS_OBJ perms to new group perms. Add comment to explain why. * security.cc (set_created_file_access): Ditto. * sec_acl.cc (set_posix_access): Replace previous patch. Return EINVAL if uid and/or guid is invalid and not backed by an actual Windows account. * sec_acl.cc (set_posix_access): Workaround owner/group SIDs being NULL. * sec_acl.cc (set_posix_access): Handle files with owner == group. Rephrase switch statement checking against unfiltered a_type value. (get_posix_access): Handle files with owner == group. * sec_acl.cc (get_posix_access): Don't use GROUP_OBJ access to fix up CLASS_OBJ mask on old-style ACLs. Fix a comment. * sec_acl.cc (set_posix_access): Always make sure Admins have WRITE_DAC and WRITE_OWNER permissions. * security.h (create_object_sd_from_attribute): Drop handle parameter from prototype. * security.cc (create_object_sd_from_attribute): Drop handle parameter. Just create the standard POSIXy security descriptor. (set_object_attribute): Accommodate dropped paramter in call to create_object_sd_from_attribute. * fhandler_tty.cc: Ditto, throughout. * fhandler_disk_file.cc (fhandler_disk_file::fchmod): Fix typo in mask computation. * fhandler.cc (fhandler_base::open_with_arch): Call open with mode not umasked. (fhandler_base::open): Explicitely umask mode on NFS here. Call new set_created_file_access rather than set_file_attribute. * fhandler_disk_file.cc (fhandler_disk_file::fchmod): Reimplement setting permissions on filesystems supporting ACLs using the new set_posix_access call. (fhandler_disk_file::fchown): Ditto. (fhandler_disk_file::mkdir): Call new set_created_file_access rather than set_file_attribute. * fhandler_socket.cc (fhandler_socket::bind): Don't umask here. Add WRITE_OWNER access to allow writing group in case of SGID bit set. Call new set_created_file_access rather than set_file_attribute. * path.cc (symlink_worker): Call new set_created_file_access rather than set_file_attribute. * sec_acl.cc (searchace): Un-staticize. (set_posix_access): New, complementary functionality to get_posix_access. (setacl): Implement in terms of get_posix_access/set_posix_access. (get_posix_access): Add handling for just created files requiring their first Cygwin ACL. Fix new_style recognition. Handle SGID bit. For old-style ACLs, ignore SYSTEM and Administrators when computing the {DEF_}CLASS_OBJ perms. * security.cc (get_file_sd): Revamp comment. Change and (hopefully) speed up inheritance processing for just created files. (alloc_sd): Remove. (set_security_attribute): Call set_posix_access instead of alloc_sd. (get_object_attribute): Fix return value. (create_object_sd_from_attribute): Call set_posix_access instead of alloc_sd. (set_file_attribute): Remove. (set_created_file_access): New function implemented in terms of get_posix_access/set_posix_access. * security.h (set_file_attribute): Remove prototype. (set_created_file_access): Add prototype. (searchace): Ditto. (set_posix_access): Ditto. * syscalls.cc (open): Call open_with_arch with mode not umasked. * sec_acl.cc: Change preceeding comment explaining new-style ACLs. Describe how to generate deny ACEs in more detail. Accommodate the fact that a NULL deny ACE is used for {DEF_}CLASS_OBJ, rather than a special Cygwin ACE. Improve further comments. (CYG_ACE_NEW_STYLE): Define. (get_posix_access): Change from Cygwin ACE to NULL deny ACE. Fix CLASS_OBJ handling to generate CLASS_OBJ and DEF_CLASS_OBJ from a single NULL deny ACE if the inheritance flags say so. * sec_helper.cc (well_known_cygwin_sid): Remove. * security.h (well_known_cygwin_sid): Drop declaration. * sec_acl.cc (CYG_ACE_ISBITS_TO_WIN): Fix typo. (get_posix_access): Rename index variable from i to idx. Define only once at top level. * security.cc (add_access_allowed_ace): Drop unused parameter "offset". Accommodate throughout. (add_access_denied_ace): Ditto. * sec_acl.cc: Accommodate above change throughout. * security.h (add_access_allowed_ace): Adjust prototype to above change. (add_access_denied_ace): Ditto. * sec_acl.cc (get_posix_access): Handle multiple ACEs for the owner and primary group of the file. Handle the default primary group ACE as DEF_GROUP_OBJ entry if the directory has the S_ISGID bit set. Add comments. Minor code rearrangements. 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. * getfacl.c (main): Special-case SYSTEM and Admins group. Add comments. * setfacl.c: Align more to Linux tool. (delacl): New function to delete acl entries only. (modacl): Drop delete functionality. Add handling of recomputing the mask and default mask values. (delallacl): Rename from delacl. (setfacl): Call delacl in Delete case. Call delallacl in DeleteAll and DeleteDef case. (usage): Accommodate new options. Rearrange and rephrase slightly. (longopts): Emit 'x' in --delete case. Add --no-mask and --mask options. (opts): Add -x and -n options. (main): Handle -d and -x the same. Handle -n and --mask options. Drop handling for -r option. * getfacl.c (usage): Align more closely to Linux version. Add new options -c, -e, -E. Change formatting to accommodate longer options. (longopts): Rename --noname to --numeric. Keep --noname for backward compatibility. Add --omit-header, --all-effective and --no-effective options. (opts): Add -c, -e and -E option. (main): Handle new -c, -e, and -E options. Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
@ -846,7 +846,7 @@ int __reg1
|
||||
fhandler_disk_file::fchmod (mode_t mode)
|
||||
{
|
||||
extern int chmod_device (path_conv& pc, mode_t mode);
|
||||
int res = -1;
|
||||
int ret = -1;
|
||||
int oret = 0;
|
||||
NTSTATUS status;
|
||||
IO_STATUS_BLOCK io;
|
||||
@ -893,17 +893,45 @@ fhandler_disk_file::fchmod (mode_t mode)
|
||||
if (!NT_SUCCESS (status))
|
||||
__seterrno_from_nt_status (status);
|
||||
else
|
||||
res = 0;
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (pc.has_acls ())
|
||||
{
|
||||
if (pc.isdir ())
|
||||
mode |= S_IFDIR;
|
||||
if (!set_file_attribute (get_handle (), pc,
|
||||
ILLEGAL_UID, ILLEGAL_GID, mode))
|
||||
res = 0;
|
||||
security_descriptor sd, sd_ret;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
tmp_pathbuf tp;
|
||||
aclent_t *aclp;
|
||||
int nentries, idx;
|
||||
|
||||
if (!get_file_sd (get_handle (), pc, sd, false))
|
||||
{
|
||||
aclp = (aclent_t *) tp.c_get ();
|
||||
if ((nentries = get_posix_access (sd, NULL, &uid, &gid,
|
||||
aclp, MAX_ACL_ENTRIES)) >= 0)
|
||||
{
|
||||
/* Overwrite ACL permissions as required by POSIX 1003.1e
|
||||
draft 17. */
|
||||
aclp[0].a_perm = (mode >> 6) & S_IRWXO;
|
||||
/* Deliberate deviation from POSIX 1003.1e here. We're not
|
||||
writing CLASS_OBJ *or* GROUP_OBJ, but both. Otherwise we're
|
||||
going to be in constant trouble with user expectations. */
|
||||
if ((idx = searchace (aclp, nentries, GROUP_OBJ)) >= 0)
|
||||
aclp[idx].a_perm = (mode >> 3) & S_IRWXO;
|
||||
if (nentries > MIN_ACL_ENTRIES
|
||||
&& (idx = searchace (aclp, nentries, CLASS_OBJ)) >= 0)
|
||||
aclp[idx].a_perm = (mode >> 3) & S_IRWXO;
|
||||
if ((idx = searchace (aclp, nentries, OTHER_OBJ)) >= 0)
|
||||
aclp[idx].a_perm = mode & S_IRWXO;
|
||||
if (pc.isdir ())
|
||||
mode |= S_IFDIR;
|
||||
if (set_posix_access (mode, uid, gid, aclp, nentries, sd_ret,
|
||||
pc.fs_is_samba ()))
|
||||
ret = set_file_sd (get_handle (), pc, sd_ret, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If the mode has any write bits set, the DOS R/O flag is in the way. */
|
||||
@ -940,20 +968,28 @@ fhandler_disk_file::fchmod (mode_t mode)
|
||||
if (!NT_SUCCESS (status))
|
||||
__seterrno_from_nt_status (status);
|
||||
else
|
||||
res = 0;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
out:
|
||||
if (oret)
|
||||
close_fs ();
|
||||
|
||||
return res;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int __reg2
|
||||
fhandler_disk_file::fchown (uid_t uid, gid_t gid)
|
||||
{
|
||||
int oret = 0;
|
||||
int ret = -1;
|
||||
security_descriptor sd, sd_ret;
|
||||
mode_t attr = pc.isdir () ? S_IFDIR : 0;
|
||||
uid_t old_uid;
|
||||
gid_t old_gid;
|
||||
tmp_pathbuf tp;
|
||||
aclent_t *aclp;
|
||||
int nentries;
|
||||
|
||||
if (!pc.has_acls ())
|
||||
{
|
||||
@ -970,52 +1006,71 @@ fhandler_disk_file::fchown (uid_t uid, gid_t gid)
|
||||
return -1;
|
||||
}
|
||||
|
||||
mode_t attrib = 0;
|
||||
if (pc.isdir ())
|
||||
attrib |= S_IFDIR;
|
||||
uid_t old_uid;
|
||||
int res = get_file_attribute (get_handle (), pc, &attrib, &old_uid, NULL);
|
||||
if (!res)
|
||||
{
|
||||
/* Typical Windows default ACLs can contain permissions for one
|
||||
group, while being owned by another user/group. The permission
|
||||
bits returned above are pretty much useless then. Creating a
|
||||
new ACL with these useless permissions results in a potentially
|
||||
broken symlink. So what we do here is to set the underlying
|
||||
permissions of symlinks to a sensible value which allows the
|
||||
world to read the symlink and only the new owner to change it. */
|
||||
if (pc.issymlink ())
|
||||
attrib = S_IFLNK | STD_RBITS | STD_WBITS;
|
||||
res = set_file_attribute (get_handle (), pc, uid, gid, attrib);
|
||||
/* If you're running a Samba server which has no winbind running, the
|
||||
uid<->SID mapping is disfunctional. Even trying to chown to your
|
||||
own account fails since the account used on the server is the UNIX
|
||||
account which gets used for the standard user mapping. This is a
|
||||
default mechanism which doesn't know your real Windows SID.
|
||||
There are two possible error codes in different Samba releases for
|
||||
this situation, one of them is unfortunately the not very significant
|
||||
STATUS_ACCESS_DENIED. Instead of relying on the error codes, we're
|
||||
using the below very simple heuristic. If set_file_attribute failed,
|
||||
and the original user account was either already unknown, or one of
|
||||
the standard UNIX accounts, we're faking success. */
|
||||
if (res == -1 && pc.fs_is_samba ())
|
||||
{
|
||||
PSID sid;
|
||||
if (get_file_sd (get_handle (), pc, sd, false))
|
||||
goto out;
|
||||
|
||||
if (old_uid == ILLEGAL_UID
|
||||
|| ((sid = sidfromuid (old_uid, NULL)) != NO_SID
|
||||
&& RtlEqualPrefixSid (sid,
|
||||
well_known_samba_unix_user_fake_sid)))
|
||||
{
|
||||
debug_printf ("Faking chown worked on standalone Samba");
|
||||
res = 0;
|
||||
}
|
||||
aclp = (aclent_t *) tp.c_get ();
|
||||
if ((nentries = get_posix_access (sd, &attr, &old_uid, &old_gid,
|
||||
aclp, MAX_ACL_ENTRIES)) < 0)
|
||||
goto out;
|
||||
|
||||
if (uid == ILLEGAL_UID)
|
||||
uid = old_uid;
|
||||
if (gid == ILLEGAL_GID)
|
||||
gid = old_gid;
|
||||
if (uid == old_uid && gid == old_gid)
|
||||
{
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Windows ACLs can contain permissions for one group, while being owned by
|
||||
another user/group. The permission bits returned above are pretty much
|
||||
useless then. Creating a new ACL with these useless permissions results
|
||||
in a potentially broken symlink. So what we do here is to set the
|
||||
underlying permissions of symlinks to a sensible value which allows the
|
||||
world to read the symlink and only the new owner to change it. */
|
||||
if (pc.issymlink ())
|
||||
for (int idx = 0; idx < nentries; ++idx)
|
||||
{
|
||||
aclp[idx].a_perm |= S_IROTH;
|
||||
if (aclp[idx].a_type & USER_OBJ)
|
||||
aclp[idx].a_perm |= S_IWOTH;
|
||||
}
|
||||
|
||||
if (set_posix_access (attr, uid, gid, aclp, nentries, sd_ret,
|
||||
pc.fs_is_samba ()))
|
||||
ret = set_file_sd (get_handle (), pc, sd_ret, true);
|
||||
|
||||
/* If you're running a Samba server with no winbind, the uid<->SID mapping
|
||||
is disfunctional. Even trying to chown to your own account fails since
|
||||
the account used on the server is the UNIX account which gets used for
|
||||
the standard user mapping. This is a default mechanism which doesn't
|
||||
know your real Windows SID. There are two possible error codes in
|
||||
different Samba releases for this situation, one of them unfortunately
|
||||
the not very significant STATUS_ACCESS_DENIED. Instead of relying on
|
||||
the error codes, we're using the below very simple heuristic.
|
||||
If set_file_sd failed, and the original user account was either already
|
||||
unknown, or one of the standard UNIX accounts, we're faking success. */
|
||||
if (ret == -1 && pc.fs_is_samba ())
|
||||
{
|
||||
PSID sid;
|
||||
|
||||
if (uid == old_uid
|
||||
|| ((sid = sidfromuid (old_uid, NULL)) != NO_SID
|
||||
&& RtlEqualPrefixSid (sid,
|
||||
well_known_samba_unix_user_fake_sid)))
|
||||
{
|
||||
debug_printf ("Faking chown worked on standalone Samba");
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (oret)
|
||||
close_fs ();
|
||||
|
||||
return res;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int __reg3
|
||||
@ -1774,10 +1829,11 @@ fhandler_disk_file::mkdir (mode_t mode)
|
||||
p, plen);
|
||||
if (NT_SUCCESS (status))
|
||||
{
|
||||
/* Set the "directory attribute" so that pc.isdir() returns correct
|
||||
value in subsequent function calls. */
|
||||
pc.file_attributes (FILE_ATTRIBUTE_DIRECTORY);
|
||||
if (has_acls ())
|
||||
set_file_attribute (dir, pc, ILLEGAL_UID, ILLEGAL_GID,
|
||||
S_JUSTCREATED | S_IFDIR
|
||||
| ((mode & 07777) & ~cygheap->umask));
|
||||
set_created_file_access (dir, pc, mode & 07777);
|
||||
NtClose (dir);
|
||||
res = 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user