* 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.
This commit is contained in:
Corinna Vinschen 2014-03-03 12:03:47 +00:00
parent f024a32928
commit c7b9a091a5
3 changed files with 143 additions and 61 deletions

View File

@ -1,3 +1,14 @@
2014-03-03 Corinna Vinschen <corinna@vinschen.de>
* 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 <corinna@vinschen.de> 2014-02-28 Corinna Vinschen <corinna@vinschen.de>
* uinfo.cc (pwdgrp::fetch_account_from_windows): Only fetch extended * uinfo.cc (pwdgrp::fetch_account_from_windows): Only fetch extended

View File

@ -103,9 +103,27 @@ cygpsid::get_id (BOOL search_grp, int *type, cyg_ldap *pldap)
struct group *gr; struct group *gr;
if (cygheap->user.groups.pgsid == psid) if (cygheap->user.groups.pgsid == psid)
id = myself->gid; 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))) else if ((gr = internal_getgrsid (*this, pldap)))
id = gr->gr_gid; id = gr->gr_gid;
if (id != ILLEGAL_UID) if ((gid_t) id != ILLEGAL_GID)
{ {
if (type) if (type)
*type = GROUP; *type = GROUP;
@ -117,6 +135,21 @@ cygpsid::get_id (BOOL search_grp, int *type, cyg_ldap *pldap)
struct passwd *pw; struct passwd *pw;
if (*this == cygheap->user.sid ()) if (*this == cygheap->user.sid ())
id = myself->uid; 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))) else if ((pw = internal_getpwsid (*this, pldap)))
id = pw->pw_uid; id = pw->pw_uid;
if (id != ILLEGAL_UID && type) if (id != ILLEGAL_UID && type)
@ -295,44 +328,16 @@ cygsidlist::add (const PSID nsi, bool well_known)
bool bool
get_sids_info (cygpsid owner_sid, cygpsid group_sid, uid_t * uidret, gid_t * gidret) 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; BOOL ret = false;
PWCHAR domain;
cyg_ldap cldap; cyg_ldap cldap;
owner_sid.debug_print ("get_sids_info: owner SID ="); owner_sid.debug_print ("get_sids_info: owner SID =");
group_sid.debug_print ("get_sids_info: group SID ="); group_sid.debug_print ("get_sids_info: group SID =");
if (group_sid == cygheap->user.groups.pgsid) *uidret = owner_sid.get_uid (&cldap);
*gidret = myself->gid; *gidret = group_sid.get_gid (&cldap);
else if (sid_id_auth (group_sid) == 22) 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) if (*gidret == myself->gid)
ret = TRUE; ret = TRUE;
else 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, ? cygheap->user.imp_token () : NULL,
group_sid, &ret); 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; return (bool) ret;
} }

View File

@ -1046,6 +1046,95 @@ check_access (security_descriptor &sd, GENERIC_MAPPING &mapping,
return ret; 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 int
check_file_access (path_conv &pc, int flags, bool effective) 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) if (flags & X_OK)
desired |= FILE_EXECUTE; desired |= FILE_EXECUTE;
if (!get_file_sd (pc.handle (), pc, sd, false)) 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); debug_printf ("flags %y, ret %d", flags, ret);
return ret; return ret;
} }