From d5e2118a357b91f7280605ce3c52bb5e6306cedd 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 6680766..392e82f 100644 --- a/source3/libads/ads_status.c +++ b/source3/libads/ads_status.c @@ -79,6 +79,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 45a291bba0252f370ea74403cdae8bb8122329df 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 | 28 ++++++++++++++++++++++------ 1 files changed, 22 insertions(+), 6 deletions(-) diff --git a/source3/winbindd/winbindd_ads.c b/source3/winbindd/winbindd_ads.c index b0ca9b8..3102a2a 100644 --- a/source3/winbindd/winbindd_ads.c +++ b/source3/winbindd/winbindd_ads.c @@ -180,8 +180,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; } @@ -325,9 +329,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); @@ -532,12 +540,16 @@ static NTSTATUS query_user(struct winbindd_domain *domain, goto done; } rc = ads_search_retry(ads, &msg, ldap_exp, attrs); - free(ldap_exp); + SAFE_FREE(ldap_exp); TALLOC_FREE(sidstr); - 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))); - goto done; + 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); @@ -632,11 +644,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 26ded1cd43135494f1bbcbe36ec394e6033e850a 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 62d51ce..ff3dc12 100644 --- a/source3/include/ads.h +++ b/source3/include/ads.h @@ -108,6 +108,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 aef35ad..2d9ea17 100644 --- a/source3/libads/ads_struct.c +++ b/source3/libads/ads_struct.c @@ -148,6 +148,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 f18ded1..99ec2e4 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -924,11 +924,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 = CONST_DISCARD(char *, ADS_PAGE_CTL_OID); diff --git a/source3/libads/ldap_utils.c b/source3/libads/ldap_utils.c index 871449a..f3a535a 100644 --- a/source3/libads/ldap_utils.c +++ b/source3/libads/ldap_utils.c @@ -68,6 +68,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 19d1078cf0ce8637133048dd8421818ebdd05507 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 83aef18..e5e76be 100644 --- a/source3/utils/net_ads.c +++ b/source3/utils/net_ads.c @@ -2156,7 +2156,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