From 895be750bd3b1fe6ac01196fe6c830c5a6d6b30f Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 18 May 2012 17:38:48 +1000 Subject: [PATCH 1/4] s3-libads: Map LDAP_TIMELIMIT_EXCEEDED as NT_STATUS_IO_TIMEOUT This allows Samba to then handle this error in the same way it would for RPC connections Andrew Bartlett --- source3/libads/ads_status.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/source3/libads/ads_status.c b/source3/libads/ads_status.c index fc489a9..7465531 100644 --- a/source3/libads/ads_status.c +++ b/source3/libads/ads_status.c @@ -82,6 +82,9 @@ NTSTATUS ads_ntstatus(ADS_STATUS status) if (status.err.rc == LDAP_SUCCESS) { return NT_STATUS_OK; } + if (status.err.rc == LDAP_TIMELIMIT_EXCEEDED) { + return NT_STATUS_IO_TIMEOUT; + } return NT_STATUS_LDAP(status.err.rc); #endif #ifdef HAVE_KRB5 -- 1.7.7.6 From f9c6f18a0f9331b1e6545c7692affad495497291 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 18 May 2012 17:40:59 +1000 Subject: [PATCH 2/4] s3-winbindd: Always map the LDAP error code to an NTSTATUS We do this so that we catch LDAP_TIMELIMIT_EXCEEDED as NT_STATUS_IO_TIMEOUT, which has special handling in winbindd_cache.c Andrew Bartlett --- source3/winbindd/winbindd_ads.c | 24 ++++++++++++++++++++---- 1 files changed, 20 insertions(+), 4 deletions(-) diff --git a/source3/winbindd/winbindd_ads.c b/source3/winbindd/winbindd_ads.c index 610db7a..941c7c5 100644 --- a/source3/winbindd/winbindd_ads.c +++ b/source3/winbindd/winbindd_ads.c @@ -188,8 +188,12 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain, } rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs); - if (!ADS_ERR_OK(rc) || !res) { + if (!ADS_ERR_OK(rc)) { DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc))); + status = ads_ntstatus(rc); + } else if (!res) { + DEBUG(1,("query_user_list ads_search returned NULL res\n")); + goto done; } @@ -340,9 +344,13 @@ static NTSTATUS enum_dom_groups(struct winbindd_domain *domain, } rc = ads_search_retry(ads, &res, filter, attrs); - if (!ADS_ERR_OK(rc) || !res) { + if (!ADS_ERR_OK(rc)) { + status = ads_ntstatus(rc); DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc))); goto done; + } else if (!res) { + DEBUG(1,("enum_dom_groups ads_search returned NULL res\n")); + goto done; } count = ads_count_replies(ads, res); @@ -550,10 +558,14 @@ static NTSTATUS query_user(struct winbindd_domain *domain, } rc = ads_search_retry(ads, &msg, ldap_exp, attrs); SAFE_FREE(ldap_exp); - if (!ADS_ERR_OK(rc) || !msg) { + if (!ADS_ERR_OK(rc)) { DEBUG(1,("query_user(sid=%s) ads_search: %s\n", sid_string_dbg(sid), ads_errstr(rc))); return ads_ntstatus(rc); + } else if (!msg) { + DEBUG(1,("query_user(sid=%s) ads_search returned NULL res\n", + sid_string_dbg(sid))); + return NT_STATUS_INTERNAL_ERROR; } count = ads_count_replies(ads, msg); @@ -662,11 +674,15 @@ static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain, rc = ads_search_retry(ads, &res, ldap_exp, group_attrs); - if (!ADS_ERR_OK(rc) || !res) { + if (!ADS_ERR_OK(rc)) { DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc))); return ads_ntstatus(rc); + } else if (!res) { + DEBUG(1,("lookup_usergroups ads_search returned NULL res\n")); + return NT_STATUS_INTERNAL_ERROR; } + count = ads_count_replies(ads, res); *user_sids = NULL; -- 1.7.7.6 From 29451e8cf3c41e7fc625fb360336e380c8cf9c21 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 18 May 2012 22:01:14 +1000 Subject: [PATCH 3/4] s3-libads: Use a reducing page size to try and cope with a slow LDAP server If we cannot get 1000 users downloaded in 15seconds, try with 500, 250 and then 125 users at a time. Andrew Bartlett --- source3/include/ads.h | 1 + source3/libads/ads_struct.c | 4 ++++ source3/libads/ldap.c | 4 ++-- source3/libads/ldap_utils.c | 7 +++++++ 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/source3/include/ads.h b/source3/include/ads.h index bbe8671..3d5fc3a 100644 --- a/source3/include/ads.h +++ b/source3/include/ads.h @@ -61,6 +61,7 @@ typedef struct ads_struct { time_t current_time; char *schema_path; char *config_path; + int ldap_page_size; } config; /* info about the current LDAP connection */ diff --git a/source3/libads/ads_struct.c b/source3/libads/ads_struct.c index e6220fd..285057b 100644 --- a/source3/libads/ads_struct.c +++ b/source3/libads/ads_struct.c @@ -156,6 +156,10 @@ ADS_STRUCT *ads_init(const char *realm, ads->auth.flags = wrap_flags; + /* Start with a page size of 1000 when the connection is new, + * we will drop it by half we get a timeout. */ + ads->config.ldap_page_size = 1000; + return ads; } diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c index 9849542..e504c6d 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -931,11 +931,11 @@ static ADS_STATUS ads_do_paged_search_args(ADS_STRUCT *ads, cookie_be = ber_alloc_t(LBER_USE_DER); if (*cookie) { - ber_printf(cookie_be, "{iO}", (ber_int_t) 1000, *cookie); + ber_printf(cookie_be, "{iO}", (ber_int_t) ads->config.ldap_page_size, *cookie); ber_bvfree(*cookie); /* don't need it from last time */ *cookie = NULL; } else { - ber_printf(cookie_be, "{io}", (ber_int_t) 1000, "", 0); + ber_printf(cookie_be, "{io}", (ber_int_t) ads->config.ldap_page_size, "", 0); } ber_flatten(cookie_be, &cookie_bv); PagedResults.ldctl_oid = discard_const_p(char, ADS_PAGE_CTL_OID); diff --git a/source3/libads/ldap_utils.c b/source3/libads/ldap_utils.c index 2f1c1b8..3dd1060 100644 --- a/source3/libads/ldap_utils.c +++ b/source3/libads/ldap_utils.c @@ -84,6 +84,13 @@ static ADS_STATUS ads_do_search_retry_internal(ADS_STRUCT *ads, const char *bind while (--count) { + if (NT_STATUS_EQUAL(ads_ntstatus(status), NT_STATUS_IO_TIMEOUT) && ads->config.ldap_page_size >= 250) { + int new_page_size = (ads->config.ldap_page_size / 2); + DEBUG(1, ("Reducing LDAP page size from %d to %d due to IO_TIMEOUT\n", + ads->config.ldap_page_size, new_page_size)); + ads->config.ldap_page_size = new_page_size; + } + if (*res) ads_msgfree(ads, *res); *res = NULL; -- 1.7.7.6 From ece008ecb041c676e46d613898396a77e79325dc Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 18 May 2012 22:02:57 +1000 Subject: [PATCH 4/4] s3-utils: Use ads_do_search_retry in net ads search This makes it possible to search against a slow server, as will fallback from 1000 to (eventually) 125 users at a time. Andrew Bartlett --- source3/utils/net_ads.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c index 0ccb328..0df7f07 100644 --- a/source3/utils/net_ads.c +++ b/source3/utils/net_ads.c @@ -2251,7 +2251,7 @@ static int net_ads_search(struct net_context *c, int argc, const char **argv) ldap_exp = argv[0]; attrs = (argv + 1); - rc = ads_do_search_all(ads, ads->config.bind_path, + rc = ads_do_search_retry(ads, ads->config.bind_path, LDAP_SCOPE_SUBTREE, ldap_exp, attrs, &res); if (!ADS_ERR_OK(rc)) { -- 1.7.7.6