From: Stefan Metzmacher Date: Wed, 6 Mar 2024 09:13:11 +0000 (+0100) Subject: s3:libads: add ads_set_reconnect_fn() and only reconnect if we can get creds X-Git-Tag: tdb-1.4.11~763 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=81a6c54fddc7b1d783d8c1c9a1b4607e5e055bff;p=thirdparty%2Fsamba.git s3:libads: add ads_set_reconnect_fn() and only reconnect if we can get creds This reconnect is only useful for long running connections (e.g. in winbindd) and there we'll make use of it... Signed-off-by: Stefan Metzmacher Reviewed-by: Andreas Schneider --- diff --git a/source3/include/ads.h b/source3/include/ads.h index 6c9e57b9ed0..92430cd1edc 100644 --- a/source3/include/ads.h +++ b/source3/include/ads.h @@ -6,6 +6,9 @@ basically this is a wrapper around ldap */ +struct cli_credentials; +struct ads_reconnect_state; + #include "libads/ads_status.h" #include "smb_ldap.h" #include "librpc/gen_ndr/ads.h" @@ -19,6 +22,14 @@ struct ads_saslwrap_ops { void (*disconnect)(struct ads_saslwrap *); }; +struct ads_reconnect_state { + NTSTATUS (*fn)(struct ads_struct *ads, + void *private_data, + TALLOC_CTX *mem_ctx, + struct cli_credentials **creds); + void *private_data; +}; + typedef struct ads_struct ADS_STRUCT; #ifdef HAVE_ADS diff --git a/source3/libads/ads_ldap_protos.h b/source3/libads/ads_ldap_protos.h index b063815678a..aba80476c05 100644 --- a/source3/libads/ads_ldap_protos.h +++ b/source3/libads/ads_ldap_protos.h @@ -77,6 +77,12 @@ ADS_STATUS ads_search(ADS_STRUCT *ads, LDAPMessage **res, const char *expr, const char **attrs); ADS_STATUS ads_search_dn(ADS_STRUCT *ads, LDAPMessage **res, const char *dn, const char **attrs); +void ads_set_reconnect_fn(ADS_STRUCT *ads, + NTSTATUS (*fn)(struct ads_struct *ads, + void *private_data, + TALLOC_CTX *mem_ctx, + struct cli_credentials **creds), + void *private_data); ADS_STATUS ads_do_search_all_args(ADS_STRUCT *ads, const char *bind_path, int scope, const char *expr, const char **attrs, void *args, diff --git a/source3/libads/ads_struct.c b/source3/libads/ads_struct.c index 55f55e7e364..c597d58230f 100644 --- a/source3/libads/ads_struct.c +++ b/source3/libads/ads_struct.c @@ -216,6 +216,13 @@ ADS_STRUCT *ads_init(TALLOC_CTX *mem_ctx, ads->auth.flags = wrap_flags; + ads->auth.reconnect_state = talloc_zero(ads, + struct ads_reconnect_state); + if (ads->auth.reconnect_state == NULL) { + TALLOC_FREE(ads); + return NULL; + } + /* Start with the configured page size when the connection is new, * we will drop it by half we get a timeout. */ ads->config.ldap_page_size = lp_ldap_page_size(); diff --git a/source3/libads/ldap_utils.c b/source3/libads/ldap_utils.c index c08f046a405..9d6d962a2bc 100644 --- a/source3/libads/ldap_utils.c +++ b/source3/libads/ldap_utils.c @@ -23,9 +23,21 @@ #include "includes.h" #include "ads.h" #include "lib/param/loadparm.h" +#include "auth/credentials/credentials.h" #ifdef HAVE_LDAP +void ads_set_reconnect_fn(ADS_STRUCT *ads, + NTSTATUS (*fn)(struct ads_struct *ads, + void *private_data, + TALLOC_CTX *mem_ctx, + struct cli_credentials **creds), + void *private_data) +{ + ads->auth.reconnect_state->fn = fn; + ads->auth.reconnect_state->private_data = private_data; +} + static ADS_STATUS ads_ranged_search_internal(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, int scope, @@ -84,6 +96,9 @@ static ADS_STATUS ads_do_search_retry_internal(ADS_STRUCT *ads, const char *bind } while (--count) { + struct cli_credentials *creds = NULL; + char *cred_name = NULL; + NTSTATUS ntstatus; if (NT_STATUS_EQUAL(ads_ntstatus(status), NT_STATUS_IO_TIMEOUT) && ads->config.ldap_page_size >= (lp_ldap_page_size() / 4) && @@ -98,24 +113,49 @@ static ADS_STATUS ads_do_search_retry_internal(ADS_STRUCT *ads, const char *bind ads_msgfree(ads, *res); *res = NULL; - DEBUG(3,("Reopening ads connection to realm '%s' after error %s\n", - ads->config.realm, ads_errstr(status))); - ads_disconnect(ads); - status = ads_connect(ads); + if (ads->auth.reconnect_state->fn == NULL) { + DBG_NOTICE("Search for %s in <%s> failed: %s\n", + expr, bp, ads_errstr(status)); + SAFE_FREE(bp); + return status; + } + + ntstatus = ads->auth.reconnect_state->fn(ads, + ads->auth.reconnect_state->private_data, + ads, &creds); + if (!NT_STATUS_IS_OK(ntstatus)) { + DBG_WARNING("Failed to get creds for realm(%s): %s\n", + ads->server.realm, nt_errstr(ntstatus)); + DBG_WARNING("Search for %s in <%s> failed: %s\n", + expr, bp, ads_errstr(status)); + SAFE_FREE(bp); + return status; + } + + cred_name = cli_credentials_get_unparsed_name(creds, creds); + DBG_NOTICE("Reopening ads connection as %s to " + "realm '%s' after error %s\n", + cred_name, ads->server.realm, ads_errstr(status)); + + status = ads_connect_creds(ads, creds); if (!ADS_ERR_OK(status)) { - DEBUG(1,("ads_search_retry: failed to reconnect (%s)\n", - ads_errstr(status))); + DBG_WARNING("Reconnect ads connection as %s to " + "realm '%s' failed: %s\n", + cred_name, ads->server.realm, + ads_errstr(status)); /* * We need to keep the ads pointer * from being freed here as we don't own it and * callers depend on it being around. */ ads_disconnect(ads); + TALLOC_FREE(creds); SAFE_FREE(bp); return status; } + TALLOC_FREE(creds); *res = NULL; diff --git a/source3/librpc/idl/ads.idl b/source3/librpc/idl/ads.idl index 49fafb37abf..82b4c1fc172 100644 --- a/source3/librpc/idl/ads.idl +++ b/source3/librpc/idl/ads.idl @@ -54,6 +54,7 @@ interface ads ads_auth_flags flags; string ccache_name; NTTIME expire_time; + [ignore] struct ads_reconnect_state *reconnect_state; } ads_auth; typedef [nopull,nopush] struct {