From 85b8256d2ede42f03b5a2791790584853e404fef Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Thu, 13 Feb 2014 14:04:03 +0000 Subject: [PATCH] * ldap.cc (cyg_ldap::fetch_posix_offset_for_domain): If domain name has no dot, it's a Netbios name. Change the search filter expression accordingly and filter by flatName. Add comment. * uinfo.cc (cygheap_domain_info::init): Gracefully handle NULL DnsDomainName and DomainSid members in DS_DOMAIN_TRUSTSW strutures. Add comment. Fix comment preceeding fetching the mapping server from registry. (pwdgrp::fetch_account_from_file): Convert str to a local array. (fetch_posix_offset): New static function. (pwdgrp::fetch_account_from_windows): Add debug output in case LookupAccountSidW fails. Simplify code by calling fetch_posix_offset where appropriate. If LookupAccountSidW fails, check if the SID is one of the known trusted domains. If so, create a more informative account entry. --- winsup/cygwin/ChangeLog | 17 +++++ winsup/cygwin/ldap.cc | 5 +- winsup/cygwin/uinfo.cc | 149 ++++++++++++++++++++++++---------------- 3 files changed, 110 insertions(+), 61 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index aa2494298..495812c7d 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,20 @@ +2014-02-13 Corinna Vinschen + + * ldap.cc (cyg_ldap::fetch_posix_offset_for_domain): If domain name + has no dot, it's a Netbios name. Change the search filter expression + accordingly and filter by flatName. Add comment. + * uinfo.cc (cygheap_domain_info::init): Gracefully handle NULL + DnsDomainName and DomainSid members in DS_DOMAIN_TRUSTSW strutures. + Add comment. Fix comment preceeding fetching the mapping server + from registry. + (pwdgrp::fetch_account_from_file): Convert str to a local array. + (fetch_posix_offset): New static function. + (pwdgrp::fetch_account_from_windows): Add debug output in case + LookupAccountSidW fails. Simplify code by calling fetch_posix_offset + where appropriate. If LookupAccountSidW fails, check if the SID is + one of the known trusted domains. If so, create a more informative + account entry. + 2014-02-12 Corinna Vinschen * uinfo.cc (cygheap_pwdgrp::nss_init_line): Explicitely ignore a colon diff --git a/winsup/cygwin/ldap.cc b/winsup/cygwin/ldap.cc index 66a7dbb76..64e8949da 100644 --- a/winsup/cygwin/ldap.cc +++ b/winsup/cygwin/ldap.cc @@ -289,7 +289,10 @@ cyg_ldap::fetch_posix_offset_for_domain (PCWSTR domain) ldap_value_freeW (val); val = NULL; } - __small_swprintf (filter, L"(&(objectClass=trustedDomain)(name=%W))", domain); + /* If domain name has no dot, it's a Netbios name. In that case, filter + by flatName rather than by name. */ + __small_swprintf (filter, L"(&(objectClass=trustedDomain)(%W=%W))", + wcschr (domain, L'.') ? L"name" : L"flatName", domain); if ((ret = ldap_search_stW (lh, rootdse, LDAP_SCOPE_SUBTREE, filter, attr = tdom_attr, 0, &tv, &msg)) != LDAP_SUCCESS) { diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc index f207de577..e6533c23a 100644 --- a/winsup/cygwin/uinfo.cc +++ b/winsup/cygwin/uinfo.cc @@ -777,22 +777,32 @@ cygheap_domain_info::init () { /* Copy... */ tdom[idx].NetbiosDomainName = cwcsdup (td[idx].NetbiosDomainName); - tdom[idx].DnsDomainName = cwcsdup (td[idx].DnsDomainName); - ULONG len = RtlLengthSid (td[idx].DomainSid); - tdom[idx].DomainSid = cmalloc_abort(HEAP_BUF, len); - RtlCopySid (len, tdom[idx].DomainSid, td[idx].DomainSid); + /* DnsDomainName as well as DomainSid can be NULL. The reason is + usually a domain of type TRUST_TYPE_DOWNLEVEL. This can be an + old pre-AD domain, or a Netware domain, etc. If DnsDomainName + is NULL, just set it to NetbiosDomainName. This simplifies + subsequent code which doesn't have to check for a NULL pointer. */ + tdom[idx].DnsDomainName = td[idx].DnsDomainName + ? cwcsdup (td[idx].DnsDomainName) + : tdom[idx].NetbiosDomainName; + if (td[idx].DomainSid) + { + ULONG len = RtlLengthSid (td[idx].DomainSid); + tdom[idx].DomainSid = cmalloc_abort(HEAP_BUF, len); + RtlCopySid (len, tdom[idx].DomainSid, td[idx].DomainSid); + } /* ...and set PosixOffset to 0. This */ tdom[idx].PosixOffset = 0; } NetApiBufferFree (td); tdom_count = tdom_cnt; } - /* If we have NFS installed, we make use of a name mapping server. This - can be either Active Directory to map uids/gids directly to Windows SIDs, - or an AD LDS or other RFC 2307 compatible identity store. The name of - the mapping domain can be fetched from the registry key created by the - NFS client installation and entered by the user via nfsadmin or the - "Services For NFS" MMC snap-in. + /* If we have Microsoft Client for NFS installed, we make use of a name + mapping server. This can be either Active Directory to map uids/gids + directly to Windows SIDs, or an AD LDS or other RFC 2307 compatible + identity store. The name of the mapping domain can be fetched from the + registry key created by the NFS client installation and entered by the + user via nfsadmin or the "Services For NFS" MMC snap-in. Reference: http://blogs.technet.com/b/filecab/archive/2012/10/09/nfs-identity-mapping-in-windows-server-2012.aspx @@ -1042,7 +1052,7 @@ pwdgrp::fetch_account_from_file (fetch_user_arg_t &arg) NT_readline rl; tmp_pathbuf tp; char *buf = tp.c_get (); - char *str = tp.c_get (); + char str[128]; char *ret = NULL; /* Create search string. */ @@ -1066,6 +1076,34 @@ pwdgrp::fetch_account_from_file (fetch_user_arg_t &arg) return NULL; } +static ULONG +fetch_posix_offset (PDS_DOMAIN_TRUSTSW td, bool &ldap_open, cyg_ldap &cldap) +{ + uint32_t id_val; + + if (!td->PosixOffset && !(td->Flags & DS_DOMAIN_PRIMARY) && td->DomainSid) + { + if (!ldap_open && !(ldap_open = cldap.open (NULL))) + { + /* We're probably running under a local account, so we're not allowed + to fetch any information from AD beyond the most obvious. Never + mind, just fake a reasonable posix offset. */ + id_val = cygheap->dom.lowest_tdo_posix_offset + - 0x01000000; + } + else + id_val = cldap.fetch_posix_offset_for_domain (td->DnsDomainName); + if (id_val) + { + td->PosixOffset = id_val; + if (id_val < cygheap->dom.lowest_tdo_posix_offset) + cygheap->dom.lowest_tdo_posix_offset = id_val; + + } + } + return td->PosixOffset; +} + char * pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, bool group) { @@ -1111,6 +1149,8 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, bool group) case SID_arg: sid = *arg.sid; ret = LookupAccountSidW (NULL, sid, name, &nlen, dom, &dlen, &acc_type); + if (!ret) + debug_printf ("LookupAccountSid(%W), %E", sid.string (sidstr)); break; case NAME_arg: /* Skip leading domain separator. This denotes an alias or well-known @@ -1235,23 +1275,7 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, bool group) for (ULONG idx = 0; (td = cygheap->dom.trusted_domain (idx)); ++idx) { - /* If we don't have the PosixOffset of the domain, fetch it. - Skip primary domain. */ - if (!td->PosixOffset && !(td->Flags & DS_DOMAIN_PRIMARY)) - { - if (!ldap_open && !(ldap_open = cldap.open (NULL))) - id_val = cygheap->dom.lowest_tdo_posix_offset - - 0x01000000; - else - id_val = - cldap.fetch_posix_offset_for_domain (td->DnsDomainName); - if (id_val) - { - td->PosixOffset = id_val; - if (id_val < cygheap->dom.lowest_tdo_posix_offset) - cygheap->dom.lowest_tdo_posix_offset = id_val; - } - } + fetch_posix_offset (td, ldap_open, cldap); if (td->PosixOffset > posix_offset && td->PosixOffset <= arg.id) posix_offset = td->PosixOffset; } @@ -1344,36 +1368,13 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, bool group) for (ULONG idx = 0; (td = cygheap->dom.trusted_domain (idx)); ++idx) - { - if (wcscmp (dom, td->NetbiosDomainName)) - continue; - domain = td->DnsDomainName; - posix_offset = td->PosixOffset; - /* If we don't have the PosixOffset of the domain, - fetch it. */ - if (!posix_offset) - { - if (!ldap_open && !(ldap_open = cldap.open (NULL))) - { - /* We're probably running under a local account, - so we're not allowed to fetch any information - from AD beyond the most obvious. Never mind, - just fake a reasonable posix offset. */ - id_val = cygheap->dom.lowest_tdo_posix_offset - - 0x01000000; - } - else - id_val = - cldap.fetch_posix_offset_for_domain (domain); - if (id_val) - { - td->PosixOffset = posix_offset = id_val; - if (id_val < cygheap->dom.lowest_tdo_posix_offset) - cygheap->dom.lowest_tdo_posix_offset = id_val; - } - } - break; - } + if (!wcscmp (dom, td->NetbiosDomainName)) + { + domain = td->DnsDomainName; + posix_offset = + fetch_posix_offset (td, ldap_open, cldap); + break; + } if (!domain) { @@ -1640,8 +1641,36 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, bool group) } else { - wcpcpy (dom, L"Unknown"); - wcpcpy (name = namebuf, group ? L"Group" : L"User"); + if (sid_id_auth (sid) == 5 /* SECURITY_NT_AUTHORITY */ + && sid_sub_auth (sid, 0) == SECURITY_NT_NON_UNIQUE) + { + /* Check if we know the domain. If so, create a passwd/group + entry with domain prefix and RID as username. */ + PDS_DOMAIN_TRUSTSW td = NULL; + + sid_sub_auth_count (sid) = sid_sub_auth_count (sid) - 1; + for (ULONG idx = 0; (td = cygheap->dom.trusted_domain (idx)); ++idx) + if (td->DomainSid && RtlEqualSid (sid, td->DomainSid)) + { + domain = td->NetbiosDomainName; + posix_offset = fetch_posix_offset (td, ldap_open, cldap); + break; + } + } + if (domain) + { + sid_sub_auth_count (sid) = sid_sub_auth_count (sid) + 1; + wcscpy (dom, domain); + __small_swprintf (name = namebuf, L"%W(%u)", + group ? L"Group" : L"User", + sid_sub_auth_rid (sid)); + uid = posix_offset + sid_sub_auth_rid (sid); + } + else + { + wcpcpy (dom, L"Unknown"); + wcpcpy (name = namebuf, group ? L"Group" : L"User"); + } name_style = fully_qualified; }