From 898e26c82f9f8b105f867516f7866c3479986628 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Tue, 29 Jul 2014 08:53:13 +0000 Subject: [PATCH] * cygheap.h (class cygheap_domain_info): Remove lowest_tdo_posix_offset. * ldap.cc (cyg_ldap::fetch_posix_offset_for_domain): Return UINT32_MAX in case of error. * security.h (PRIMARY_POSIX_OFFSET): Define. (NOACCESS_POSIX_OFFSET): Define. (UNUSABLE_POSIX_OFFSET): Define. * uinfo.cc (cygheap_domain_info::init): Drop initializing lowest_tdo_posix_offset. (pwdgrp::fetch_account_from_file): Set PosixOffset to either UNUSABLE_POSIX_OFFSET or NOACCESS_POSIX_OFFSET in case we don't get a sensible offset from AD. Explain why. Drop setting ch lowest_tdo_posix_offset. (pwdgrp::fetch_account_from_windows): Replace constant 0x100000 with PRIMARY_POSIX_OFFSET throughout. --- winsup/cygwin/ChangeLog | 17 +++++++++++++++++ winsup/cygwin/cygheap.h | 2 -- winsup/cygwin/ldap.cc | 6 ++++-- winsup/cygwin/security.h | 10 ++++++++++ winsup/cygwin/uinfo.cc | 34 ++++++++++++++++++---------------- 5 files changed, 49 insertions(+), 20 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 6c8395df3..c793266e9 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,20 @@ +2014-07-29 Corinna Vinschen + + * cygheap.h (class cygheap_domain_info): Remove lowest_tdo_posix_offset. + * ldap.cc (cyg_ldap::fetch_posix_offset_for_domain): Return UINT32_MAX + in case of error. + * security.h (PRIMARY_POSIX_OFFSET): Define. + (NOACCESS_POSIX_OFFSET): Define. + (UNUSABLE_POSIX_OFFSET): Define. + * uinfo.cc (cygheap_domain_info::init): Drop initializing + lowest_tdo_posix_offset. + (pwdgrp::fetch_account_from_file): Set PosixOffset to either + UNUSABLE_POSIX_OFFSET or NOACCESS_POSIX_OFFSET in case we don't get a + sensible offset from AD. Explain why. Drop setting ch + lowest_tdo_posix_offset. + (pwdgrp::fetch_account_from_windows): Replace constant 0x100000 with + PRIMARY_POSIX_OFFSET throughout. + 2014-07-24 Corinna Vinschen * fhandler_socket.cc (fhandler_socket::send_internal): Fix value of diff --git a/winsup/cygwin/cygheap.h b/winsup/cygwin/cygheap.h index c4b2ed9ad..b08569d13 100644 --- a/winsup/cygwin/cygheap.h +++ b/winsup/cygwin/cygheap.h @@ -371,8 +371,6 @@ class cygheap_domain_info PWCHAR rfc2307_domain_buf; public: - ULONG lowest_tdo_posix_offset; - bool init (); inline PCWSTR primary_flat_name () const { return pdom_name; } diff --git a/winsup/cygwin/ldap.cc b/winsup/cygwin/ldap.cc index fa19c307e..df7756809 100644 --- a/winsup/cygwin/ldap.cc +++ b/winsup/cygwin/ldap.cc @@ -471,6 +471,8 @@ cyg_ldap::next_account (cygsid &sid) return ret; } +/* Return UINT32_MAX on error to allow differing between not being able + to fetch a value and a real 0 offset. */ uint32_t cyg_ldap::fetch_posix_offset_for_domain (PCWSTR domain) { @@ -491,11 +493,11 @@ cyg_ldap::fetch_posix_offset_for_domain (PCWSTR domain) __small_swprintf (filter, L"(&(objectClass=trustedDomain)(%W=%W))", wcschr (domain, L'.') ? L"name" : L"flatName", domain); if (search (rootdse, filter, attr = tdom_attr) != 0) - return 0; + return UINT32_MAX; if (!(entry = ldap_first_entry (lh, msg))) { debug_printf ("No entry for %W in rootdse %W", filter, rootdse); - return 0; + return UINT32_MAX; } return get_num_attribute (0); } diff --git a/winsup/cygwin/security.h b/winsup/cygwin/security.h index 6b6c33955..eb3e0f1e5 100644 --- a/winsup/cygwin/security.h +++ b/winsup/cygwin/security.h @@ -24,6 +24,16 @@ void uinfo_init (); #define ILLEGAL_UID ((uid_t)-1) #define ILLEGAL_GID ((gid_t)-1) +/* Offset for accounts in the primary domain of the machine. */ +#define PRIMARY_POSIX_OFFSET (0x00100000) + +/* Fake POSIX offsets used in scenarios in which the account has no permission + to fetch the POSIX offset, or when the admins have set the offset to an + unreasonable low value. The values are chosen in the hope that they won't + collide with "real" offsets. */ +#define NOACCESS_POSIX_OFFSET (0xfe500000) +#define UNUSABLE_POSIX_OFFSET (0xfea00000) + /* For UNIX accounts not mapped to Windows accounts via winbind, Samba returns SIDs of the form S-1-22-x-y, with x == 1 for users and x == 2 for groups, and y == UNIX uid/gid. NFS returns no SIDs at all, but the plain UNIX diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc index 0151563fe..ed533bd8a 100644 --- a/winsup/cygwin/uinfo.cc +++ b/winsup/cygwin/uinfo.cc @@ -815,9 +815,6 @@ cygheap_domain_info::init () lsa_close_policy (lsa); if (cygheap->dom.member_machine ()) { - /* For a domain member machine fetch all trusted domain info. - Start out with UNIX_POSIX_OFFSET. */ - lowest_tdo_posix_offset = UNIX_POSIX_OFFSET; ret = DsEnumerateDomainTrustsW (NULL, DS_DOMAIN_DIRECT_INBOUND | DS_DOMAIN_DIRECT_OUTBOUND | DS_DOMAIN_IN_FOREST, @@ -1138,24 +1135,29 @@ pwdgrp::fetch_account_from_file (fetch_user_arg_t &arg) static ULONG fetch_posix_offset (PDS_DOMAIN_TRUSTSW td, cyg_ldap *cldap) { - uint32_t id_val = 0; + uint32_t id_val = UINT32_MAX; if (!td->PosixOffset && !(td->Flags & DS_DOMAIN_PRIMARY) && td->DomainSid) { if (cldap->open (NULL) == NO_ERROR) id_val = cldap->fetch_posix_offset_for_domain (td->DnsDomainName); - if (!id_val) + if (id_val < PRIMARY_POSIX_OFFSET) + { + /* If the offset is less than the primay domain offset, we're bound + to suffer collisions with system and local accounts. Move offset + to a fixed replacement fake offset. This may result in collisions + between other domains all of which were moved to this replacement + offset, but we can't fix all problems caused by careless admins. */ + id_val = UNUSABLE_POSIX_OFFSET; + } + else if (id_val == UINT32_MAX) { /* We're probably running under a local account, so we're not allowed - to fetch any information from AD beyond the most obvious. - Alternatively we're suffering IT madness and some admin has - actually set the POSIX offset to 0. Either way, fake a reasonable - posix offset and hope for the best. */ - id_val = cygheap->dom.lowest_tdo_posix_offset - 0x00800000; + to fetch any information from AD beyond the most obvious. Fake a + reasonable posix offset as above and hope for the best. */ + id_val = NOACCESS_POSIX_OFFSET; } td->PosixOffset = id_val; - if (id_val < cygheap->dom.lowest_tdo_posix_offset) - cygheap->dom.lowest_tdo_posix_offset = id_val; } return td->PosixOffset; } @@ -1425,7 +1427,7 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap) /* Identity assertion SIDs. */ __small_swprintf (sidstr, L"S-1-18-%u", arg.id & 0xffff); } - else if (arg.id < 0x100000) + else if (arg.id < PRIMARY_POSIX_OFFSET) { /* Nothing. */ debug_printf ("Invalid POSIX id %u", arg.id); @@ -1467,7 +1469,7 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap) { /* Primary domain */ PWCHAR s = cygheap->dom.primary_sid ().pstring (sidstr); - __small_swprintf (s, L"-%u", arg.id - 0x100000); + __small_swprintf (s, L"-%u", arg.id - PRIMARY_POSIX_OFFSET); } posix_offset = 0; } @@ -1526,7 +1528,7 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap) /* Primary domain account? */ if (!wcscasecmp (dom, cygheap->dom.primary_flat_name ())) { - posix_offset = 0x100000; + posix_offset = PRIMARY_POSIX_OFFSET; /* In theory domain should have been set to cygheap->dom.primary_dns_name (), but it turns out that not setting the domain here has advantages. @@ -1859,7 +1861,7 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap) if (RtlEqualSid (sid, cygheap->dom.primary_sid ())) { domain = cygheap->dom.primary_flat_name (); - posix_offset = 0x100000; + posix_offset = PRIMARY_POSIX_OFFSET; } else for (ULONG idx = 0; (td = cygheap->dom.trusted_domain (idx)); ++idx)