From: Corinna Vinschen Date: Wed, 25 Jun 2014 09:10:50 +0000 (+0000) Subject: * autoload.cc (ldap_search_sW): Replace ldap_search_stW. X-Git-Tag: sid-snapshot-20140801~8 X-Git-Url: https://sourceware.org/git/?a=commitdiff_plain;h=e35b92c202d85eed0bf2ac526370beb8d2f053de;p=newlib-cygwin.git * autoload.cc (ldap_search_sW): Replace ldap_search_stW. (LdapMapErrorToWin32): Import. * fhandler_disk_file.cc (fhandler_base::fstat_by_nfs_ea): Accommodate change to cyg_ldap::open. * ldap.cc (CYG_LDAP_TIMEOUT): Remove. (CYG_LDAP_ENUM_TIMEOUT): Remove. (def_tv): Remove. (enum_tv): Remove. (cyg_ldap::map_ldaperr_to_errno): New method to map LDAP error codes to POSIX errno codes. Explicitly map LDAP_NO_RESULTS_RETURNED to ENMFILE. (cyg_ldap::wait): Ditto. (struct cyg_ldap_init): New struct. (cyg_ldap::connect_ssl): Return ULONG. Drop setting LDAP_OPT_TIMELIMIT. Add call to ldap_search_sW to fetch root DSE. (cyg_ldap::connect_non_ssl): Ditto. (ldap_init_thr): New static thread function. (cyg_ldap::connect): New method to call connect_ssl/connect_non_ssl in an interruptible cygthread. (struct cyg_ldap_search): New struct. (cyg_ldap::search_s): New method to perform generic synchronous search. (ldap_search_thr): New static thread function. (cyg_ldap::search): New method to call search_s in an interruptible cygthread. (struct cyg_ldap_next_page): New struct. (cyg_ldap::next_page_s): New method to perform generic synchronous paged search. (ldap_next_page_thr): New static thread function. (cyg_ldap::next_page): New method to call next_page_s in an interruptible cygthread. (cyg_ldap::open): Return POSIX errno. Call connect method. (cyg_ldap::fetch_ad_account): Call search method rather than ldap_search_stW. (cyg_ldap::enumerate_ad_accounts): Return POSIX errno. Use infinite timeout in call to ldap_search_init_pageW. (cyg_ldap::next_account): Return POSIX errno. Call next_page method rather than ldap_get_next_page_s. (cyg_ldap::fetch_posix_offset_for_domain): Call search method rather than ldap_search_stW. (cyg_ldap::fetch_unix_sid_from_ad): Ditto. (cyg_ldap::fetch_unix_name_from_rfc2307): Ditto. * ldap.h (class cyg_ldap): Accommodate aforementioned changes. * passwd.cc (pg_ent::enumerate_ad): Ditto. Break search if one of cyg_ldap::enumerate_ad_accounts or cldap.next_account returns with an error code other than ENMFILE. * sec_helper.cc (cygpsid::get_id): Accommodate change to cyg_ldap::open. * uinfo.cc (fetch_posix_offset): Ditto. --- diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index c55b34bcc..26978251b 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,52 @@ +2014-06-25 Corinna Vinschen + + * autoload.cc (ldap_search_sW): Replace ldap_search_stW. + (LdapMapErrorToWin32): Import. + * fhandler_disk_file.cc (fhandler_base::fstat_by_nfs_ea): Accommodate + change to cyg_ldap::open. + * ldap.cc (CYG_LDAP_TIMEOUT): Remove. + (CYG_LDAP_ENUM_TIMEOUT): Remove. + (def_tv): Remove. + (enum_tv): Remove. + (cyg_ldap::map_ldaperr_to_errno): New method to map LDAP error codes to + POSIX errno codes. Explicitly map LDAP_NO_RESULTS_RETURNED to ENMFILE. + (cyg_ldap::wait): Ditto. + (struct cyg_ldap_init): New struct. + (cyg_ldap::connect_ssl): Return ULONG. Drop setting LDAP_OPT_TIMELIMIT. + Add call to ldap_search_sW to fetch root DSE. + (cyg_ldap::connect_non_ssl): Ditto. + (ldap_init_thr): New static thread function. + (cyg_ldap::connect): New method to call connect_ssl/connect_non_ssl in + an interruptible cygthread. + (struct cyg_ldap_search): New struct. + (cyg_ldap::search_s): New method to perform generic synchronous search. + (ldap_search_thr): New static thread function. + (cyg_ldap::search): New method to call search_s in an interruptible + cygthread. + (struct cyg_ldap_next_page): New struct. + (cyg_ldap::next_page_s): New method to perform generic synchronous + paged search. + (ldap_next_page_thr): New static thread function. + (cyg_ldap::next_page): New method to call next_page_s in an + interruptible cygthread. + (cyg_ldap::open): Return POSIX errno. Call connect method. + (cyg_ldap::fetch_ad_account): Call search method rather than + ldap_search_stW. + (cyg_ldap::enumerate_ad_accounts): Return POSIX errno. Use infinite + timeout in call to ldap_search_init_pageW. + (cyg_ldap::next_account): Return POSIX errno. Call next_page method + rather than ldap_get_next_page_s. + (cyg_ldap::fetch_posix_offset_for_domain): Call search method rather + than ldap_search_stW. + (cyg_ldap::fetch_unix_sid_from_ad): Ditto. + (cyg_ldap::fetch_unix_name_from_rfc2307): Ditto. + * ldap.h (class cyg_ldap): Accommodate aforementioned changes. + * passwd.cc (pg_ent::enumerate_ad): Ditto. Break search if one of + cyg_ldap::enumerate_ad_accounts or cldap.next_account returns with + an error code other than ENMFILE. + * sec_helper.cc (cygpsid::get_id): Accommodate change to cyg_ldap::open. + * uinfo.cc (fetch_posix_offset): Ditto. + 2014-06-23 Corinna Vinschen * spawn.cc (find_exec): Initialize err (CID 60111). diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc index 5cc296e25..8e3733e5c 100644 --- a/winsup/cygwin/autoload.cc +++ b/winsup/cygwin/autoload.cc @@ -597,13 +597,14 @@ LoadDLLfunc (ldap_msgfree, 0, wldap32) LoadDLLfunc (ldap_next_entry, 0, wldap32) LoadDLLfunc (ldap_search_abandon_page, 0, wldap32) LoadDLLfunc (ldap_search_init_pageW, 0, wldap32) -LoadDLLfunc (ldap_search_stW, 0, wldap32) +LoadDLLfunc (ldap_search_sW, 0, wldap32) LoadDLLfunc (ldap_set_option, 0, wldap32) LoadDLLfunc (ldap_sslinitW, 0, wldap32) LoadDLLfunc (ldap_unbind, 0, wldap32) LoadDLLfunc (ldap_value_freeW, 0, wldap32) LoadDLLfunc (ldap_value_free_len, 0, wldap32) LoadDLLfunc (LdapGetLastError, 0, wldap32) +LoadDLLfunc (LdapMapErrorToWin32, 0, wldap32) #pragma pop_macro ("mangle") LoadDLLfunc (WNetCloseEnum, 4, mpr) diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc index b03e9c7fd..ac8116486 100644 --- a/winsup/cygwin/fhandler_disk_file.cc +++ b/winsup/cygwin/fhandler_disk_file.cc @@ -354,7 +354,7 @@ fhandler_base::fstat_by_nfs_ea (struct stat *buf) uid_t map_uid = ILLEGAL_UID; domain = cygheap->dom.get_rfc2307_domain (); - if ((ldap_open = cldap.open (domain))) + if ((ldap_open = (cldap.open (domain) == NO_ERROR))) map_uid = cldap.remap_uid (nfs_attr->uid); if (map_uid == ILLEGAL_UID) map_uid = MAP_UNIX_TO_CYGWIN_ID (nfs_attr->uid); @@ -366,7 +366,7 @@ fhandler_base::fstat_by_nfs_ea (struct stat *buf) gid_t map_gid = ILLEGAL_GID; domain = cygheap->dom.get_rfc2307_domain (); - if ((ldap_open || cldap.open (domain))) + if ((ldap_open || cldap.open (domain) == NO_ERROR)) map_gid = cldap.remap_gid (nfs_attr->gid); if (map_gid == ILLEGAL_GID) map_gid = MAP_UNIX_TO_CYGWIN_ID (nfs_attr->gid); diff --git a/winsup/cygwin/ldap.cc b/winsup/cygwin/ldap.cc index 0010c1df9..fa19c307e 100644 --- a/winsup/cygwin/ldap.cc +++ b/winsup/cygwin/ldap.cc @@ -22,14 +22,8 @@ details. */ #include "dsgetdc.h" #include "tls_pbuf.h" -#define CYG_LDAP_TIMEOUT 5 /* seconds */ -#define CYG_LDAP_ENUM_TIMEOUT 60 /* seconds */ - #define CYG_LDAP_ENUM_PAGESIZE 100 /* entries per page */ -static LDAP_TIMEVAL def_tv = { CYG_LDAP_TIMEOUT, 0 }; -static LDAP_TIMEVAL enum_tv = { CYG_LDAP_ENUM_TIMEOUT, 0 }; - static PWCHAR rootdse_attr[] = { (PWCHAR) L"defaultNamingContext", @@ -78,38 +72,84 @@ PWCHAR rfc2307_gid_attr[] = NULL }; -bool +/* ================================================================= */ +/* Helper methods. */ +/* ================================================================= */ + +inline int +cyg_ldap::map_ldaperr_to_errno (ULONG lerr) +{ + switch (lerr) + { + case LDAP_SUCCESS: + return NO_ERROR; + case LDAP_NO_RESULTS_RETURNED: + /* LdapMapErrorToWin32 maps LDAP_NO_RESULTS_RETURNED to ERROR_MORE_DATA, + which in turn is mapped to EMSGSIZE by geterrno_from_win_error. This + is SO wrong, especially considering that LDAP_MORE_RESULTS_TO_RETURN + is mapped to ERROR_MORE_DATA as well :-P */ + return ENMFILE; + default: + break; + } + return geterrno_from_win_error (LdapMapErrorToWin32 (lerr)); +} + +inline int +cyg_ldap::wait (cygthread *thr) +{ + if (!thr) + return EIO; + if (cygwait (*thr, INFINITE, cw_sig | cw_sig_eintr) != WAIT_OBJECT_0) + { + thr->terminate_thread (); + _my_tls.call_signal_handler (); + return EINTR; + } + thr->detach (); + return 0; +} + +/* ================================================================= */ +/* Helper struct and functions for interruptible LDAP initalization. */ +/* ================================================================= */ + +struct cyg_ldap_init { + cyg_ldap *that; + PCWSTR domain; + bool ssl; + ULONG ret; +}; + +ULONG cyg_ldap::connect_ssl (PCWSTR domain) { - ULONG ret, timelimit = CYG_LDAP_TIMEOUT; + ULONG ret; if (!(lh = ldap_sslinitW ((PWCHAR) domain, LDAP_SSL_PORT, 1))) { debug_printf ("ldap_init(%W) error 0x%02x", domain, LdapGetLastError ()); - return false; + return LdapGetLastError (); } - if ((ret = ldap_set_option (lh, LDAP_OPT_TIMELIMIT, &timelimit)) - != LDAP_SUCCESS) - debug_printf ("ldap_set_option(LDAP_OPT_TIMELIMIT) error 0x%02x", ret); if ((ret = ldap_bind_s (lh, NULL, NULL, LDAP_AUTH_NEGOTIATE)) != LDAP_SUCCESS) - { - debug_printf ("ldap_bind(%W) 0x%02x", domain, ret); - ldap_unbind (lh); - lh = NULL; - return false; - } - return true; + debug_printf ("ldap_bind(%W) 0x%02x", domain, ret); + else if ((ret = ldap_search_sW (lh, NULL, LDAP_SCOPE_BASE, + (PWCHAR) L"(objectclass=*)", rootdse_attr, + 0, &msg)) + != LDAP_SUCCESS) + debug_printf ("ldap_search(%W, ROOTDSE) error 0x%02x", domain, ret); + return ret; } -bool +ULONG cyg_ldap::connect_non_ssl (PCWSTR domain) { - ULONG ret, timelimit = CYG_LDAP_TIMEOUT; + ULONG ret; if (!(lh = ldap_initW ((PWCHAR) domain, LDAP_PORT))) { debug_printf ("ldap_init(%W) error 0x%02x", domain, LdapGetLastError ()); - return false; + return LdapGetLastError (); } if ((ret = ldap_set_option (lh, LDAP_OPT_SIGN, LDAP_OPT_ON)) != LDAP_SUCCESS) @@ -117,40 +157,133 @@ cyg_ldap::connect_non_ssl (PCWSTR domain) if ((ret = ldap_set_option (lh, LDAP_OPT_ENCRYPT, LDAP_OPT_ON)) != LDAP_SUCCESS) debug_printf ("ldap_set_option(LDAP_OPT_ENCRYPT) error 0x%02x", ret); - if ((ret = ldap_set_option (lh, LDAP_OPT_TIMELIMIT, &timelimit)) - != LDAP_SUCCESS) - debug_printf ("ldap_set_option(LDAP_OPT_TIMELIMIT) error 0x%02x", ret); if ((ret = ldap_bind_s (lh, NULL, NULL, LDAP_AUTH_NEGOTIATE)) != LDAP_SUCCESS) + debug_printf ("ldap_bind(%W) 0x%02x", domain, ret); + else if ((ret = ldap_search_sW (lh, NULL, LDAP_SCOPE_BASE, + (PWCHAR) L"(objectclass=*)", rootdse_attr, + 0, &msg)) + != LDAP_SUCCESS) + debug_printf ("ldap_search(%W, ROOTDSE) error 0x%02x", domain, ret); + return ret; +} + +static DWORD WINAPI +ldap_init_thr (LPVOID param) +{ + cyg_ldap_init *cl = (cyg_ldap_init *) param; + cl->ret = cl->ssl ? cl->that->connect_ssl (cl->domain) + : cl->that->connect_non_ssl (cl->domain); + return 0; +} + +inline int +cyg_ldap::connect (PCWSTR domain) +{ + /* FIXME? connect_ssl can take ages even when failing, so we're trying to + do everything the non-SSL (but still encrypted) way. */ + cyg_ldap_init cl = { this, domain, false, NO_ERROR }; + cygthread *thr = new cygthread (ldap_init_thr, &cl, "ldap_init"); + return wait (thr) ?: map_ldaperr_to_errno (cl.ret); +} + +/* ================================================================= */ +/* Helper struct and functions for interruptible LDAP search. */ +/* ================================================================= */ + +struct cyg_ldap_search { + cyg_ldap *that; + PWCHAR base; + PWCHAR filter; + PWCHAR *attrs; + ULONG ret; +}; + +ULONG +cyg_ldap::search_s (PWCHAR base, PWCHAR filter, PWCHAR *attrs) +{ + ULONG ret; + + if ((ret = ldap_search_sW (lh, base, LDAP_SCOPE_SUBTREE, filter, + attrs, 0, &msg)) != LDAP_SUCCESS) + debug_printf ("ldap_search_sW(%W,%W) error 0x%02x", base, filter, ret); + return ret; +} + +static DWORD WINAPI +ldap_search_thr (LPVOID param) +{ + cyg_ldap_search *cl = (cyg_ldap_search *) param; + cl->ret = cl->that->search_s (cl->base, cl->filter, cl->attrs); + return 0; +} + +inline int +cyg_ldap::search (PWCHAR base, PWCHAR filter, PWCHAR *attrs) +{ + cyg_ldap_search cl = { this, base, filter, attrs, NO_ERROR }; + cygthread *thr = new cygthread (ldap_search_thr, &cl, "ldap_search"); + return wait (thr) ?: map_ldaperr_to_errno (cl.ret); +} + +/* ================================================================= */ +/* Helper struct and functions for interruptible LDAP page search. */ +/* ================================================================= */ + +struct cyg_ldap_next_page { + cyg_ldap *that; + ULONG ret; +}; + +ULONG +cyg_ldap::next_page_s () +{ + ULONG total; + ULONG ret; + + do { - debug_printf ("ldap_bind(%W) 0x%02x", domain, ret); - ldap_unbind (lh); - lh = NULL; - return false; + ret = ldap_get_next_page_s (lh, srch_id, NULL, CYG_LDAP_ENUM_PAGESIZE, + &total, &srch_msg); } - return true; + while (ret == LDAP_SUCCESS && ldap_count_entries (lh, srch_msg) == 0); + if (ret && ret != LDAP_NO_RESULTS_RETURNED) + debug_printf ("ldap_result() error 0x%02x", ret); + return ret; } -bool +static DWORD WINAPI +ldap_next_page_thr (LPVOID param) +{ + cyg_ldap_next_page *cl = (cyg_ldap_next_page *) param; + cl->ret = cl->that->next_page_s (); + return 0; +} + +inline int +cyg_ldap::next_page () +{ + cyg_ldap_next_page cl = { this, NO_ERROR }; + cygthread *thr = new cygthread (ldap_next_page_thr, &cl, "ldap_next_page"); + return wait (thr) ?: map_ldaperr_to_errno (cl.ret); +} + +/* ================================================================= */ +/* Public methods. */ +/* ================================================================= */ + +int cyg_ldap::open (PCWSTR domain) { - ULONG ret; + int ret = 0; /* Already open? */ if (lh) - return true; + return 0; - /* FIXME? connect_ssl can take ages even when failing, so we're trying to - do everything the non-SSL (but still encrypted) way. */ - if (/*!connect_ssl (NULL) && */ !connect_non_ssl (domain)) - return false; - if ((ret = ldap_search_stW (lh, NULL, LDAP_SCOPE_BASE, - (PWCHAR) L"(objectclass=*)", rootdse_attr, - 0, &def_tv, &msg)) - != LDAP_SUCCESS) - { - debug_printf ("ldap_search(%W, ROOTDSE) error 0x%02x", domain, ret); - goto err; - } + if ((ret = connect (domain)) != NO_ERROR) + goto err; + /* Prime `ret' and fetch ROOTDSE search result. */ + ret = EIO; if (!(entry = ldap_first_entry (lh, msg))) { debug_printf ("No ROOTDSE entry for %W", domain); @@ -179,10 +312,11 @@ cyg_ldap::open (PCWSTR domain) ldap_value_freeW (val); val = NULL; ldap_msgfree (msg); - msg = entry = NULL; return true; + msg = entry = NULL; + return 0; err: close (); - return false; + return ret; } void @@ -215,7 +349,6 @@ cyg_ldap::fetch_ad_account (PSID sid, bool group, PCWSTR domain) LONG len = (LONG) RtlLengthSid (sid); PBYTE s = (PBYTE) sid; static WCHAR hex_wchars[] = L"0123456789abcdef"; - ULONG ret; tmp_pathbuf tp; if (msg) @@ -256,13 +389,8 @@ cyg_ldap::fetch_ad_account (PSID sid, bool group, PCWSTR domain) } } attr = group ? group_attr : user_attr; - if ((ret = ldap_search_stW (lh, rdse, LDAP_SCOPE_SUBTREE, filter, - attr, 0, &def_tv, &msg)) != LDAP_SUCCESS) - { - debug_printf ("ldap_search_stW(%W,%W) error 0x%02x", - rdse, filter, ret); + if (search (rdse, filter, attr) != 0) return false; - } if (!(entry = ldap_first_entry (lh, msg))) { debug_printf ("No entry for %W in rootdse %W", filter, rdse); @@ -271,15 +399,16 @@ cyg_ldap::fetch_ad_account (PSID sid, bool group, PCWSTR domain) return true; } -bool +int cyg_ldap::enumerate_ad_accounts (PCWSTR domain, bool group) { + int ret; tmp_pathbuf tp; PCWSTR filter; close (); - if (!open (domain)) - return false; + if ((ret = open (domain)) != NO_ERROR) + return ret; if (!group) filter = L"(&(objectClass=User)" @@ -296,26 +425,23 @@ cyg_ldap::enumerate_ad_accounts (PCWSTR domain, bool group) "(!(groupType:" LDAP_MATCHING_RULE_BIT_AND ":=1))" "(objectSid=*))"; srch_id = ldap_search_init_pageW (lh, rootdse, LDAP_SCOPE_SUBTREE, - (PWCHAR) filter, sid_attr, 0, - NULL, NULL, CYG_LDAP_ENUM_TIMEOUT, - CYG_LDAP_ENUM_PAGESIZE, NULL); + (PWCHAR) filter, sid_attr, 0, NULL, NULL, + INFINITE, CYG_LDAP_ENUM_PAGESIZE, NULL); if (srch_id == NULL) { debug_printf ("ldap_search_init_pageW(%W,%W) error 0x%02x", rootdse, filter, LdapGetLastError ()); - return false; + return map_ldaperr_to_errno (LdapGetLastError ()); } - return true; + return NO_ERROR; } -bool +int cyg_ldap::next_account (cygsid &sid) { ULONG ret; PLDAP_BERVAL *bval; - ULONG total; - if (srch_entry) { if ((srch_entry = ldap_next_entry (lh, srch_entry)) @@ -323,38 +449,32 @@ cyg_ldap::next_account (cygsid &sid) { sid = (PSID) bval[0]->bv_val; ldap_value_free_len (bval); - return true; + return NO_ERROR; } ldap_msgfree (srch_msg); srch_msg = srch_entry = NULL; } - do - { - ret = ldap_get_next_page_s (lh, srch_id, &enum_tv, CYG_LDAP_ENUM_PAGESIZE, - &total, &srch_msg); - } - while (ret == LDAP_SUCCESS && ldap_count_entries (lh, srch_msg) == 0); - if (ret == LDAP_NO_RESULTS_RETURNED) - ; - else if (ret != LDAP_SUCCESS) - debug_printf ("ldap_result() error 0x%02x", ret); - else if ((srch_entry = ldap_first_entry (lh, srch_msg)) - && (bval = ldap_get_values_lenW (lh, srch_entry, sid_attr[0]))) + ret = next_page (); + if (ret == NO_ERROR) { - sid = (PSID) bval[0]->bv_val; - ldap_value_free_len (bval); - return true; + if ((srch_entry = ldap_first_entry (lh, srch_msg)) + && (bval = ldap_get_values_lenW (lh, srch_entry, sid_attr[0]))) + { + sid = (PSID) bval[0]->bv_val; + ldap_value_free_len (bval); + return NO_ERROR; + } + ret = EIO; } ldap_search_abandon_page (lh, srch_id); srch_id = NULL; - return false; + return ret; } uint32_t cyg_ldap::fetch_posix_offset_for_domain (PCWSTR domain) { WCHAR filter[300]; - ULONG ret; if (msg) { @@ -370,14 +490,8 @@ cyg_ldap::fetch_posix_offset_for_domain (PCWSTR domain) 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, &def_tv, &msg)) - != LDAP_SUCCESS) - { - debug_printf ("ldap_search_stW(%W,%W) error 0x%02x", - rootdse, filter, ret); - return 0; - } + if (search (rootdse, filter, attr = tdom_attr) != 0) + return 0; if (!(entry = ldap_first_entry (lh, msg))) { debug_printf ("No entry for %W in rootdse %W", filter, rootdse); @@ -410,7 +524,6 @@ bool cyg_ldap::fetch_unix_sid_from_ad (uint32_t id, cygsid &sid, bool group) { WCHAR filter[48]; - ULONG ret; PLDAP_BERVAL *bval; if (msg) @@ -422,13 +535,8 @@ cyg_ldap::fetch_unix_sid_from_ad (uint32_t id, cygsid &sid, bool group) __small_swprintf (filter, L"(&(objectClass=Group)(gidNumber=%u))", id); else __small_swprintf (filter, L"(&(objectClass=User)(uidNumber=%u))", id); - if ((ret = ldap_search_stW (lh, rootdse, LDAP_SCOPE_SUBTREE, filter, - sid_attr, 0, &def_tv, &msg)) != LDAP_SUCCESS) - { - debug_printf ("ldap_search_stW(%W,%W) error 0x%02x", - rootdse, filter, ret); - return false; - } + if (search (rootdse, filter, sid_attr) != 0) + return false; if ((entry = ldap_first_entry (lh, msg)) && (bval = ldap_get_values_lenW (lh, entry, sid_attr[0]))) { @@ -443,7 +551,6 @@ PWCHAR cyg_ldap::fetch_unix_name_from_rfc2307 (uint32_t id, bool group) { WCHAR filter[52]; - ULONG ret; if (msg) { @@ -461,13 +568,8 @@ cyg_ldap::fetch_unix_name_from_rfc2307 (uint32_t id, bool group) else __small_swprintf (filter, L"(&(objectClass=posixAccount)(uidNumber=%u))", id); - if ((ret = ldap_search_stW (lh, rootdse, LDAP_SCOPE_SUBTREE, filter, attr, - 0, &def_tv, &msg)) != LDAP_SUCCESS) - { - debug_printf ("ldap_search_stW(%W,%W) error 0x%02x", - rootdse, filter, ret); - return NULL; - } + if (search (rootdse, filter, attr) != 0) + return NULL; if (!(entry = ldap_first_entry (lh, msg))) { debug_printf ("No entry for %W in rootdse %W", filter, rootdse); diff --git a/winsup/cygwin/ldap.h b/winsup/cygwin/ldap.h index 696fbebe0..7f90a3821 100644 --- a/winsup/cygwin/ldap.h +++ b/winsup/cygwin/ldap.h @@ -36,8 +36,11 @@ class cyg_ldap { PLDAPSearch srch_id; PLDAPMessage srch_msg, srch_entry; - bool connect_ssl (PCWSTR domain); - bool connect_non_ssl (PCWSTR domain); + inline int map_ldaperr_to_errno (ULONG lerr); + inline int wait (cygthread *thr); + inline int connect (PCWSTR domain); + inline int search (PWCHAR base, PWCHAR filter, PWCHAR *attrs); + inline int next_page (); bool fetch_unix_sid_from_ad (uint32_t id, cygsid &sid, bool group); PWCHAR fetch_unix_name_from_rfc2307 (uint32_t id, bool group); PWCHAR get_string_attribute (int idx); @@ -49,12 +52,17 @@ public: {} ~cyg_ldap () { close (); } + ULONG connect_ssl (PCWSTR domain); + ULONG connect_non_ssl (PCWSTR domain); + ULONG search_s (PWCHAR base, PWCHAR filter, PWCHAR *attrs); + ULONG next_page_s (); + operator PLDAP () const { return lh; } - bool open (PCWSTR in_domain); + int open (PCWSTR in_domain); void close (); bool fetch_ad_account (PSID sid, bool group, PCWSTR domain = NULL); - bool enumerate_ad_accounts (PCWSTR domain, bool group); - bool next_account (cygsid &sid); + int enumerate_ad_accounts (PCWSTR domain, bool group); + int next_account (cygsid &sid); uint32_t fetch_posix_offset_for_domain (PCWSTR domain); uid_t remap_uid (uid_t uid); gid_t remap_gid (gid_t gid); diff --git a/winsup/cygwin/passwd.cc b/winsup/cygwin/passwd.cc index 4482ce124..928633559 100644 --- a/winsup/cygwin/passwd.cc +++ b/winsup/cygwin/passwd.cc @@ -593,13 +593,19 @@ pg_ent::enumerate_ad () if (!cnt) { PDS_DOMAIN_TRUSTSW td; + int ret; if (!resume) { ++resume; - if (!nss_db_enum_primary () - || !cldap.enumerate_ad_accounts (NULL, group)) + if (!nss_db_enum_primary ()) continue; + if ((ret = cldap.enumerate_ad_accounts (NULL, group)) != NO_ERROR) + { + cldap.close (); + set_errno (ret); + return NULL; + } } else if ((td = cygheap->dom.trusted_domain (resume - 1))) { @@ -612,9 +618,15 @@ pg_ent::enumerate_ad () if (((enums & ENUM_TDOMS_ALL) && td->Flags & DS_DOMAIN_PRIMARY) || !td->DomainSid || (!nss_db_enum_tdom (td->NetbiosDomainName) - && !nss_db_enum_tdom (td->DnsDomainName)) - || !cldap.enumerate_ad_accounts (td->DnsDomainName, group)) + && !nss_db_enum_tdom (td->DnsDomainName))) continue; + if ((ret = cldap.enumerate_ad_accounts (td->DnsDomainName, group)) + != NO_ERROR) + { + cldap.close (); + set_errno (ret); + return NULL; + } } else { @@ -624,7 +636,8 @@ pg_ent::enumerate_ad () } ++cnt; cygsid sid; - if (cldap.next_account (sid)) + int ret = cldap.next_account (sid); + if (ret == NO_ERROR) { fetch_user_arg_t arg; arg.type = SID_arg; @@ -632,6 +645,13 @@ pg_ent::enumerate_ad () char *line = pg.fetch_account_from_windows (arg, &cldap); if (line) return pg.add_account_post_fetch (line, false); + ret = EIO; + } + if (ret != ENMFILE) + { + cldap.close (); + set_errno (ret); + return NULL; } cnt = 0; } diff --git a/winsup/cygwin/sec_helper.cc b/winsup/cygwin/sec_helper.cc index 00123935b..946e78a8e 100644 --- a/winsup/cygwin/sec_helper.cc +++ b/winsup/cygwin/sec_helper.cc @@ -122,7 +122,7 @@ cygpsid::get_id (BOOL search_grp, int *type, cyg_ldap *pldap) gid_t map_gid = cygheap->ugid_cache.get_gid (gid); if (map_gid == ILLEGAL_GID) { - if (pldap->open (cygheap->dom.get_rfc2307_domain ())) + if (pldap->open (cygheap->dom.get_rfc2307_domain ()) == NO_ERROR) map_gid = pldap->remap_gid (gid); if (map_gid == ILLEGAL_GID) map_gid = MAP_UNIX_TO_CYGWIN_ID (gid); @@ -151,7 +151,7 @@ cygpsid::get_id (BOOL search_grp, int *type, cyg_ldap *pldap) uid_t map_uid = cygheap->ugid_cache.get_uid (uid); if (map_uid == ILLEGAL_UID) { - if (pldap->open (cygheap->dom.get_rfc2307_domain ())) + if (pldap->open (cygheap->dom.get_rfc2307_domain ()) == NO_ERROR) map_uid = pldap->remap_uid (uid); if (map_uid == ILLEGAL_UID) map_uid = MAP_UNIX_TO_CYGWIN_ID (uid); diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc index 2b91835f1..cc757f9fe 100644 --- a/winsup/cygwin/uinfo.cc +++ b/winsup/cygwin/uinfo.cc @@ -1141,7 +1141,7 @@ fetch_posix_offset (PDS_DOMAIN_TRUSTSW td, cyg_ldap *cldap) if (!td->PosixOffset && !(td->Flags & DS_DOMAIN_PRIMARY) && td->DomainSid) { - if (!cldap->open (NULL)) + if (cldap->open (NULL) != NO_ERROR) { /* We're probably running under a local account, so we're not allowed to fetch any information from AD beyond the most obvious. Never @@ -1241,7 +1241,7 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap) DC for some weird reason. Use LDAP instead. */ PWCHAR val; - if (cldap->open (NULL) + if (cldap->open (NULL) == NO_ERROR && cldap->fetch_ad_account (sid, is_group ()) && (val = cldap->get_group_name ())) { @@ -1598,7 +1598,7 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap) if (is_domain_account) { /* Use LDAP to fetch domain account infos. */ - if (!cldap->open (NULL)) + if (cldap->open (NULL) != NO_ERROR) break; if (cldap->fetch_ad_account (sid, is_group (), domain)) {