diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 47659cf25..35fd1a894 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,14 @@ +2014-03-03 Corinna Vinschen + + * sec_helper.cc (cygpsid::get_id): Move Samba SID->uid/gid mapping + from get_sids_info here. + (get_sids_info): Vice versa. + * security.cc (convert_samba_sd): New static function to map a Samba + security descriptor to a security descriptor with UNIX users and groups + converted to Windows SIDs per RFC 2307 mapping. + (check_file_access): Call convert_samba_sd on Samba security + descriptors. + 2014-02-28 Corinna Vinschen * uinfo.cc (pwdgrp::fetch_account_from_windows): Only fetch extended diff --git a/winsup/cygwin/sec_helper.cc b/winsup/cygwin/sec_helper.cc index 23dfc94e8..69df2baf8 100644 --- a/winsup/cygwin/sec_helper.cc +++ b/winsup/cygwin/sec_helper.cc @@ -103,9 +103,27 @@ cygpsid::get_id (BOOL search_grp, int *type, cyg_ldap *pldap) struct group *gr; if (cygheap->user.groups.pgsid == psid) id = myself->gid; + else if (sid_id_auth (psid) == 22) + { + /* Samba UNIX group. Try to map to Cygwin gid. If there's no + mapping in the cache, try to fetch it from the configured + RFC 2307 domain (see last comment in cygheap_domain_info::init() + for more information) and add it to the mapping cache. */ + gid_t gid = sid_sub_auth_rid (psid); + gid_t map_gid = cygheap->ugid_cache.get_gid (gid); + if (map_gid == ILLEGAL_GID) + { + if (pldap->open (cygheap->dom.get_rfc2307_domain ())) + map_gid = pldap->remap_gid (gid); + if (map_gid == ILLEGAL_GID) + map_gid = MAP_UNIX_TO_CYGWIN_ID (gid); + cygheap->ugid_cache.add_gid (gid, map_gid); + } + id = (uid_t) map_gid; + } else if ((gr = internal_getgrsid (*this, pldap))) id = gr->gr_gid; - if (id != ILLEGAL_UID) + if ((gid_t) id != ILLEGAL_GID) { if (type) *type = GROUP; @@ -117,6 +135,21 @@ cygpsid::get_id (BOOL search_grp, int *type, cyg_ldap *pldap) struct passwd *pw; if (*this == cygheap->user.sid ()) id = myself->uid; + else if (sid_id_auth (psid) == 22) + { + /* Samba UNIX user. See comment above. */ + uid_t uid = sid_sub_auth_rid (psid); + uid_t map_uid = cygheap->ugid_cache.get_uid (uid); + if (map_uid == ILLEGAL_UID) + { + if (pldap->open (cygheap->dom.get_rfc2307_domain ())) + map_uid = pldap->remap_uid (uid); + if (map_uid == ILLEGAL_UID) + map_uid = MAP_UNIX_TO_CYGWIN_ID (uid); + cygheap->ugid_cache.add_uid (uid, map_uid); + } + id = map_uid; + } else if ((pw = internal_getpwsid (*this, pldap))) id = pw->pw_uid; if (id != ILLEGAL_UID && type) @@ -295,44 +328,16 @@ cygsidlist::add (const PSID nsi, bool well_known) bool get_sids_info (cygpsid owner_sid, cygpsid group_sid, uid_t * uidret, gid_t * gidret) { - struct passwd *pw; - struct group *gr = NULL; BOOL ret = false; - PWCHAR domain; cyg_ldap cldap; owner_sid.debug_print ("get_sids_info: owner SID ="); group_sid.debug_print ("get_sids_info: group SID ="); - if (group_sid == cygheap->user.groups.pgsid) - *gidret = myself->gid; - else if (sid_id_auth (group_sid) == 22) + *uidret = owner_sid.get_uid (&cldap); + *gidret = group_sid.get_gid (&cldap); + if (*uidret == myself->uid) { - /* Samba UNIX group. Try to map to Cygwin gid. If there's no mapping in - the cache, try to fetch it from the configured RFC 2307 domain (see - last comment in cygheap_domain_info::init() for more information) and - add it to the mapping cache. */ - gid_t gid = sid_sub_auth_rid (group_sid); - gid_t map_gid = cygheap->ugid_cache.get_gid (gid); - if (map_gid == ILLEGAL_GID) - { - domain = cygheap->dom.get_rfc2307_domain (); - if (cldap.open (domain)) - map_gid = cldap.remap_gid (gid); - if (map_gid == ILLEGAL_GID) - map_gid = MAP_UNIX_TO_CYGWIN_ID (gid); - cygheap->ugid_cache.add_gid (gid, map_gid); - } - *gidret = map_gid; - } - else if ((gr = internal_getgrsid (group_sid, &cldap))) - *gidret = gr->gr_gid; - else - *gidret = ILLEGAL_GID; - - if (owner_sid == cygheap->user.sid ()) - { - *uidret = myself->uid; if (*gidret == myself->gid) ret = TRUE; else @@ -340,34 +345,6 @@ get_sids_info (cygpsid owner_sid, cygpsid group_sid, uid_t * uidret, gid_t * gid ? cygheap->user.imp_token () : NULL, group_sid, &ret); } - else if (sid_id_auth (owner_sid) == 22) - { - /* Samba UNIX user. See comment above. */ - uid_t uid = sid_sub_auth_rid (owner_sid); - uid_t map_uid = cygheap->ugid_cache.get_uid (uid); - if (map_uid == ILLEGAL_UID) - { - domain = cygheap->dom.get_rfc2307_domain (); - if (cldap.open (domain)) - map_uid = cldap.remap_uid (uid); - if (map_uid == ILLEGAL_UID) - map_uid = MAP_UNIX_TO_CYGWIN_ID (uid); - cygheap->ugid_cache.add_uid (uid, map_uid); - } - *uidret = map_uid; - } - else if ((pw = internal_getpwsid (owner_sid, &cldap))) - { - *uidret = pw->pw_uid; - if (gr || (*gidret != ILLEGAL_GID - && (gr = internal_getgrgid (*gidret, &cldap)))) - for (int idx = 0; gr->gr_mem[idx]; ++idx) - if ((ret = strcasematch (pw->pw_name, gr->gr_mem[idx]))) - break; - } - else - *uidret = ILLEGAL_UID; - return (bool) ret; } diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc index 200bfb782..07b3fa00d 100644 --- a/winsup/cygwin/security.cc +++ b/winsup/cygwin/security.cc @@ -1046,6 +1046,95 @@ check_access (security_descriptor &sd, GENERIC_MAPPING &mapping, return ret; } +/* Samba override. Check security descriptor for Samba UNIX user and group + accounts and check if we have an RFC 2307 mapping to a Windows account. + Create a new security descriptor with all of the UNIX acocunts with + valid mapping replaced with their WIndows counterpart. */ +static void +convert_samba_sd (security_descriptor &sd_ret) +{ + NTSTATUS status; + BOOLEAN dummy; + PSID sid; + cygsid owner; + cygsid group; + SECURITY_DESCRIPTOR sd; + cyg_ldap cldap; + tmp_pathbuf tp; + PACL acl, oacl; + size_t acl_len; + PACCESS_ALLOWED_ACE ace; + + if (!NT_SUCCESS (RtlGetOwnerSecurityDescriptor (sd_ret, &sid, &dummy))) + return; + owner = sid; + if (!NT_SUCCESS (RtlGetGroupSecurityDescriptor (sd_ret, &sid, &dummy))) + return; + group = sid; + + if (sid_id_auth (owner) == 22) + { + struct passwd *pwd; + uid_t uid = owner.get_uid (&cldap); + if (uid < UNIX_POSIX_OFFSET && (pwd = internal_getpwuid (uid))) + owner.getfrompw (pwd); + } + if (sid_id_auth (group) == 22) + { + struct group *grp; + gid_t gid = group.get_gid (&cldap); + if (gid < UNIX_POSIX_OFFSET && (grp = internal_getgrgid (gid))) + group.getfromgr (grp); + } + + if (!NT_SUCCESS (RtlGetDaclSecurityDescriptor (sd_ret, &dummy, + &oacl, &dummy))) + return; + acl = (PACL) tp.w_get (); + RtlCreateAcl (acl, ACL_MAXIMUM_SIZE, ACL_REVISION); + acl_len = sizeof (ACL); + + for (DWORD i = 0; i < oacl->AceCount; ++i) + if (NT_SUCCESS (RtlGetAce (oacl, i, (PVOID *) &ace))) + { + cygsid ace_sid ((PSID) &ace->SidStart); + if (sid_id_auth (ace_sid) == 22) + { + if (sid_sub_auth (ace_sid, 0) == 1) /* user */ + { + struct passwd *pwd; + uid_t uid = ace_sid.get_uid (&cldap); + if (uid < UNIX_POSIX_OFFSET && (pwd = internal_getpwuid (uid))) + ace_sid.getfrompw (pwd); + } + else /* group */ + { + struct group *grp; + gid_t gid = ace_sid.get_gid (&cldap); + if (gid < UNIX_POSIX_OFFSET && (grp = internal_getgrgid (gid))) + ace_sid.getfromgr (grp); + } + if (!add_access_allowed_ace (acl, i, ace->Mask, ace_sid, acl_len, + ace->Header.AceFlags)) + return; + } + } + acl->AclSize = acl_len; + + RtlCreateSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION); + RtlSetControlSecurityDescriptor (&sd, SE_DACL_PROTECTED, SE_DACL_PROTECTED); + RtlSetOwnerSecurityDescriptor (&sd, owner, FALSE); + RtlSetGroupSecurityDescriptor (&sd, group, FALSE); + + status = RtlSetDaclSecurityDescriptor (&sd, TRUE, acl, FALSE); + if (!NT_SUCCESS (status)) + return; + DWORD sd_size = 0; + status = RtlAbsoluteToSelfRelativeSD (&sd, sd_ret, &sd_size); + if (sd_size > 0 && sd_ret.malloc (sd_size)) + RtlAbsoluteToSelfRelativeSD (&sd, sd_ret, &sd_size); +} + int check_file_access (path_conv &pc, int flags, bool effective) { @@ -1059,7 +1148,12 @@ check_file_access (path_conv &pc, int flags, bool effective) if (flags & X_OK) desired |= FILE_EXECUTE; if (!get_file_sd (pc.handle (), pc, sd, false)) - ret = check_access (sd, file_mapping, desired, flags, effective); + { + /* Tweak Samba security descriptor as necessary. */ + if (pc.fs_is_samba ()) + convert_samba_sd (sd); + ret = check_access (sd, file_mapping, desired, flags, effective); + } debug_printf ("flags %y, ret %d", flags, ret); return ret; }