From 490fbf55a4b0027fb3e2be14b1ecd8ad2671a5a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20B=C5=99ezina?= Date: Tue, 9 Dec 2025 13:19:14 +0100 Subject: [PATCH 1/2] errors: add ERR_SERVER_FAILURE To indicate server communication error. --- src/util/util_errors.c | 2 ++ src/util/util_errors.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/util/util_errors.c b/src/util/util_errors.c index 691e9509d67..48badb914d7 100644 --- a/src/util/util_errors.c +++ b/src/util/util_errors.c @@ -156,6 +156,8 @@ struct err_string error_to_str[] = { { "Certificate authority file not found"}, /* ERR_CA_DB_NOT_FOUND */ + { "Server failure"}, /* ERR_SERVER_FAILURE */ + { "ERR_LAST" } /* ERR_LAST */ }; diff --git a/src/util/util_errors.h b/src/util/util_errors.h index 358f51f3e1b..244ade63341 100644 --- a/src/util/util_errors.h +++ b/src/util/util_errors.h @@ -181,6 +181,8 @@ enum sssd_errors { ERR_CA_DB_NOT_FOUND, + ERR_SERVER_FAILURE, + ERR_LAST /* ALWAYS LAST */ }; From 88af6012bbaec3e8256f99d192c98aa86354ddc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20B=C5=99ezina?= Date: Tue, 9 Dec 2025 12:37:11 +0100 Subject: [PATCH 2/2] sdap: remove be context from sdap_cli_connect code This is a steps towards new implementation of new failover mechanism. The new code will reuse sdap_cli_connect to connect to the LDAP server but it will not use any be resolver stuff. This patch moves be resolver usage one level up so the connection code can be easily reused. It also moves kinit before connecting to LDAP into a separate, standalone step (previously it was connect -> kinit -> sasl bind, now it is kinit -> connect -> sasl bind). --- src/providers/ipa/ipa_auth.c | 12 +- src/providers/ldap/ldap_auth.c | 25 +- src/providers/ldap/sdap_async.h | 28 +- src/providers/ldap/sdap_async_connection.c | 486 +++++++++++++-------- src/providers/ldap/sdap_id_op.c | 16 +- src/providers/ldap/sdap_online_check.c | 9 +- 6 files changed, 360 insertions(+), 216 deletions(-) diff --git a/src/providers/ipa/ipa_auth.c b/src/providers/ipa/ipa_auth.c index a776026e62e..3bbee7d85a8 100644 --- a/src/providers/ipa/ipa_auth.c +++ b/src/providers/ipa/ipa_auth.c @@ -329,11 +329,11 @@ static void ipa_pam_auth_handler_flag_done(struct tevent_req *subreq) if (password_migration) { sdap_auth_ctx = state->auth_ctx->sdap_auth_ctx; - subreq = sdap_cli_connect_send(state, state->ev, - sdap_auth_ctx->opts, - sdap_auth_ctx->be, - sdap_auth_ctx->service, - true, CON_TLS_ON, true); + subreq = sdap_cli_resolve_and_connect_send(state, state->ev, + sdap_auth_ctx->opts, + sdap_auth_ctx->be, + sdap_auth_ctx->service, + true, CON_TLS_ON, true); if (subreq == NULL) { state->pd->pam_status = PAM_SYSTEM_ERR; goto done; @@ -373,7 +373,7 @@ static void ipa_pam_auth_handler_connect_done(struct tevent_req *subreq) state->pd->pam_status = PAM_SYSTEM_ERR; - ret = sdap_cli_connect_recv(subreq, state, NULL, &sh, NULL); + ret = sdap_cli_resolve_and_connect_recv(subreq, state, NULL, &sh, NULL); talloc_free(subreq); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "Cannot connect to LDAP server to perform " diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c index 431ba2e7901..5970d9a3d8d 100644 --- a/src/providers/ldap/ldap_auth.c +++ b/src/providers/ldap/ldap_auth.c @@ -797,11 +797,12 @@ static struct tevent_req *auth_connect_send(struct tevent_req *req) use_tls = false; } - subreq = sdap_cli_connect_send(state, state->ev, state->ctx->opts, - state->ctx->be, - state->sdap_service, false, - use_tls ? CON_TLS_ON : CON_TLS_OFF, - skip_conn_auth); + subreq = sdap_cli_resolve_and_connect_send(state, state->ev, + state->ctx->opts, + state->ctx->be, + state->sdap_service, false, + use_tls ? CON_TLS_ON : CON_TLS_OFF, + skip_conn_auth); if (subreq == NULL) { tevent_req_error(req, ENOMEM); @@ -850,16 +851,18 @@ static void auth_connect_done(struct tevent_req *subreq) struct auth_state); int ret; - ret = sdap_cli_connect_recv(subreq, state, NULL, &state->sh, NULL); + ret = sdap_cli_resolve_and_connect_recv(subreq, state, NULL, &state->sh, + NULL); talloc_zfree(subreq); if (ret != EOK) { - /* As sdap_cli_connect_recv() returns EIO in case all the servers are - * down and we have to go offline, let's treat it accordingly here and - * allow the PAM responder to switch to offline authentication. + /* As sdap_cli_resolve_and_connect_recv() returns EIO in case all the + * servers are down and we have to go offline, let's treat it + * accordingly here and allow the PAM responder to switch to offline + * authentication. * * Unfortunately, there's not much pattern within our code and the way - * to indicate we're going down in this part of the code is returning - * an ETIMEDOUT. + * to indicate we're going down in this part of the code is returning an + * ETIMEDOUT. */ if (ret == EIO) { tevent_req_error(req, ETIMEDOUT); diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h index 700cd6f9c44..1d02e5ce63e 100644 --- a/src/providers/ldap/sdap_async.h +++ b/src/providers/ldap/sdap_async.h @@ -213,17 +213,37 @@ enum connect_tls { struct tevent_req *sdap_cli_connect_send(TALLOC_CTX *memctx, struct tevent_context *ev, struct sdap_options *opts, - struct be_ctx *be, - struct sdap_service *service, + const char *uri, + struct sockaddr *sockaddr, + socklen_t sockaddr_len, bool skip_rootdse, enum connect_tls force_tls, - bool skip_auth); + bool skip_auth, + time_t kinit_expire_time); + int sdap_cli_connect_recv(struct tevent_req *req, TALLOC_CTX *memctx, - bool *can_retry, struct sdap_handle **gsh, struct sdap_server_opts **srv_opts); +struct tevent_req * +sdap_cli_resolve_and_connect_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sdap_options *opts, + struct be_ctx *be, + struct sdap_service *service, + bool skip_rootdse, + enum connect_tls force_tls, + bool skip_auth); + +errno_t +sdap_cli_resolve_and_connect_recv(struct tevent_req *req, + TALLOC_CTX *memctx, + bool *can_retry, + struct sdap_handle **gsh, + struct sdap_server_opts **srv_opts); + + /* Exposes all options of generic send while allowing to parse by map */ struct tevent_req *sdap_get_and_parse_generic_send(TALLOC_CTX *memctx, struct tevent_context *ev, diff --git a/src/providers/ldap/sdap_async_connection.c b/src/providers/ldap/sdap_async_connection.c index c8e325c77f5..2b81d0c6526 100644 --- a/src/providers/ldap/sdap_async_connection.c +++ b/src/providers/ldap/sdap_async_connection.c @@ -1460,8 +1460,9 @@ errno_t sdap_auth_recv(struct tevent_req *req, struct sdap_cli_connect_state { struct tevent_context *ev; struct sdap_options *opts; - struct sdap_service *service; - struct be_ctx *be; + const char *uri; + struct sockaddr *sockaddr; + socklen_t sockaddr_len; bool use_rootdse; enum sdap_rootdse_read_opts rootdse_access; @@ -1469,25 +1470,21 @@ struct sdap_cli_connect_state { struct sdap_handle *sh; - struct fo_server *srv; - struct sdap_server_opts *srv_opts; enum connect_tls force_tls; bool do_auth; bool use_tls; + time_t kinit_expire_time; int retry_attempts; }; -static int sdap_cli_resolve_next(struct tevent_req *req); -static void sdap_cli_resolve_done(struct tevent_req *subreq); +static int sdap_cli_connect_step(struct tevent_req *req); static void sdap_cli_connect_done(struct tevent_req *subreq); static void sdap_cli_rootdse_step(struct tevent_req *req); static void sdap_cli_rootdse_done(struct tevent_req *subreq); static errno_t sdap_cli_use_rootdse(struct sdap_cli_connect_state *state); -static void sdap_cli_kinit_step(struct tevent_req *req); -static void sdap_cli_kinit_done(struct tevent_req *subreq); static void sdap_cli_auth_step(struct tevent_req *req); static void sdap_cli_auth_done(struct tevent_req *subreq); static errno_t sdap_cli_auth_reconnect(struct tevent_req *subreq); @@ -1557,11 +1554,13 @@ decide_tls_usage(enum connect_tls force_tls, struct dp_option *basic, struct tevent_req *sdap_cli_connect_send(TALLOC_CTX *memctx, struct tevent_context *ev, struct sdap_options *opts, - struct be_ctx *be, - struct sdap_service *service, + const char *uri, + struct sockaddr *sockaddr, + socklen_t sockaddr_len, bool skip_rootdse, enum connect_tls force_tls, - bool skip_auth) + bool skip_auth, + time_t kinit_expire_time) { struct sdap_cli_connect_state *state; struct tevent_req *req; @@ -1572,16 +1571,17 @@ struct tevent_req *sdap_cli_connect_send(TALLOC_CTX *memctx, state->ev = ev; state->opts = opts; - state->service = service; - state->be = be; - state->srv = NULL; + state->uri = uri; + state->sockaddr = sockaddr; + state->sockaddr_len = sockaddr_len; state->srv_opts = NULL; state->use_rootdse = !skip_rootdse; - state->rootdse_access = decide_rootdse_access (opts->basic); + state->rootdse_access = decide_rootdse_access(opts->basic); state->force_tls = force_tls; state->do_auth = !skip_auth; + state->kinit_expire_time = kinit_expire_time; - ret = sdap_cli_resolve_next(req); + ret = sdap_cli_connect_step(req); if (ret) { tevent_req_error(req, ret); tevent_req_post(req, ev); @@ -1589,64 +1589,32 @@ struct tevent_req *sdap_cli_connect_send(TALLOC_CTX *memctx, return req; } -static int sdap_cli_resolve_next(struct tevent_req *req) +static int sdap_cli_connect_step(struct tevent_req *req) { - struct sdap_cli_connect_state *state = tevent_req_data(req, - struct sdap_cli_connect_state); + struct sdap_cli_connect_state *state; struct tevent_req *subreq; + errno_t ret; - /* Before stepping to next server destroy any connection from previous attempt */ - talloc_zfree(state->sh); - - /* NOTE: this call may cause service->uri to be refreshed - * with a new valid server. Do not use service->uri before */ - subreq = be_resolve_server_send(state, state->ev, - state->be, state->service->name, - state->srv == NULL ? true : false); - if (!subreq) { - return ENOMEM; - } - - tevent_req_set_callback(subreq, sdap_cli_resolve_done, req); - return EOK; -} - -static void sdap_cli_resolve_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct sdap_cli_connect_state *state = tevent_req_data(req, - struct sdap_cli_connect_state); - int ret; - - ret = be_resolve_server_recv(subreq, state, &state->srv); - talloc_zfree(subreq); - if (ret) { - state->srv = NULL; - /* all servers have been tried and none - * was found good, go offline */ - tevent_req_error(req, EIO); - return; - } + state = tevent_req_data(req, struct sdap_cli_connect_state); ret = decide_tls_usage(state->force_tls, state->opts->basic, - state->service->uri, &state->use_tls); + state->uri, &state->use_tls); if (ret != EOK) { - tevent_req_error(req, EINVAL); - return; + return EINVAL; } subreq = sdap_connect_send(state, state->ev, state->opts, - state->service->uri, - state->service->sockaddr, - state->service->sockaddr_len, + state->uri, + state->sockaddr, + state->sockaddr_len, state->use_tls); if (!subreq) { - tevent_req_error(req, ENOMEM); - return; + return ENOMEM; } + tevent_req_set_callback(subreq, sdap_cli_connect_done, req); + return EOK; } static void sdap_cli_connect_done(struct tevent_req *subreq) @@ -1667,9 +1635,9 @@ static void sdap_cli_connect_done(struct tevent_req *subreq) "TLS handshake was interruped, provider will retry\n"); state->retry_attempts++; subreq = sdap_connect_send(state, state->ev, state->opts, - state->service->uri, - state->service->sockaddr, - state->service->sockaddr_len, + state->uri, + state->sockaddr, + state->sockaddr_len, state->use_tls); if (!subreq) { @@ -1682,14 +1650,7 @@ static void sdap_cli_connect_done(struct tevent_req *subreq) } else if (ret != EOK) { state->retry_attempts = 0; /* retry another server */ - be_fo_set_port_status(state->be, state->service->name, - state->srv, PORT_NOT_WORKING); - - ret = sdap_cli_resolve_next(req); - if (ret != EOK) { - tevent_req_error(req, ret); - } - + tevent_req_error(req, ERR_SERVER_FAILURE); return; } state->retry_attempts = 0; @@ -1714,13 +1675,6 @@ static void sdap_cli_connect_done(struct tevent_req *subreq) } } - if (state->do_auth && sasl_mech && sdap_sasl_mech_needs_kinit(sasl_mech)) { - if (dp_opt_get_bool(state->opts->basic, SDAP_KRB5_KINIT)) { - sdap_cli_kinit_step(req); - return; - } - } - sdap_cli_auth_step(req); } @@ -1763,12 +1717,7 @@ static void sdap_cli_rootdse_done(struct tevent_req *subreq) talloc_zfree(subreq); if (ret) { if (ret == ETIMEDOUT) { /* retry another server */ - be_fo_set_port_status(state->be, state->service->name, - state->srv, PORT_NOT_WORKING); - ret = sdap_cli_resolve_next(req); - if (ret != EOK) { - tevent_req_error(req, ret); - } + tevent_req_error(req, ERR_SERVER_FAILURE); return; } @@ -1799,13 +1748,6 @@ static void sdap_cli_rootdse_done(struct tevent_req *subreq) } } - if (state->do_auth && sasl_mech && sdap_sasl_mech_needs_kinit(sasl_mech)) { - if (dp_opt_get_bool(state->opts->basic, SDAP_KRB5_KINIT)) { - sdap_cli_kinit_step(req); - return; - } - } - sdap_cli_auth_step(req); } @@ -1833,7 +1775,7 @@ static errno_t sdap_cli_use_rootdse(struct sdap_cli_connect_state *state) } ret = sdap_get_server_opts_from_rootdse(state, - state->service->uri, + state->uri, state->rootdse, state->opts, &state->srv_opts); if (ret) { @@ -1845,58 +1787,6 @@ static errno_t sdap_cli_use_rootdse(struct sdap_cli_connect_state *state) return EOK; } -static void sdap_cli_kinit_step(struct tevent_req *req) -{ - struct sdap_cli_connect_state *state = tevent_req_data(req, - struct sdap_cli_connect_state); - struct tevent_req *subreq; - - subreq = sdap_kinit_send(state, state->ev, - state->be, - state->sh, - state->service->kinit_service_name, - dp_opt_get_int(state->opts->basic, - SDAP_OPT_TIMEOUT), - dp_opt_get_string(state->opts->basic, - SDAP_KRB5_KEYTAB), - dp_opt_get_string(state->opts->basic, - SDAP_SASL_AUTHID), - sdap_gssapi_realm(state->opts->basic), - dp_opt_get_bool(state->opts->basic, - SDAP_KRB5_CANONICALIZE), - dp_opt_get_int(state->opts->basic, - SDAP_KRB5_TICKET_LIFETIME)); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, sdap_cli_kinit_done, req); -} - -static void sdap_cli_kinit_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct sdap_cli_connect_state *state = tevent_req_data(req, - struct sdap_cli_connect_state); - time_t expire_time = 0; - errno_t ret; - - ret = sdap_kinit_recv(subreq, &expire_time); - talloc_zfree(subreq); - if (ret != EOK) { - /* We're not able to authenticate to the LDAP server. - * There's not much we can do except for going offline */ - DEBUG(SSSDBG_TRACE_FUNC, - "Cannot get a TGT: ret [%d](%s)\n", ret, sss_strerror(ret)); - tevent_req_error(req, EACCES); - return; - } - state->sh->expire_time = expire_time; - - sdap_cli_auth_step(req); -} - static void sdap_cli_auth_step(struct tevent_req *req) { struct sdap_cli_connect_state *state = tevent_req_data(req, @@ -1933,6 +1823,7 @@ static void sdap_cli_auth_step(struct tevent_req *req) /* Set the LDAP expiration time * If SASL has already set it, use the sooner of the two */ + state->sh->expire_time = state->kinit_expire_time; now = time(NULL); expire_timeout = dp_opt_get_int(state->opts->basic, SDAP_EXPIRE_TIMEOUT); expire_offset = dp_opt_get_int(state->opts->basic, SDAP_EXPIRE_OFFSET); @@ -2017,15 +1908,15 @@ static errno_t sdap_cli_auth_reconnect(struct tevent_req *req) state = tevent_req_data(req, struct sdap_cli_connect_state); ret = decide_tls_usage(state->force_tls, state->opts->basic, - state->service->uri, &state->use_tls); + state->uri, &state->use_tls); if (ret != EOK) { goto done; } subreq = sdap_connect_send(state, state->ev, state->opts, - state->service->uri, - state->service->sockaddr, - state->service->sockaddr_len, + state->uri, + state->sockaddr, + state->sockaddr_len, state->use_tls); if (subreq == NULL) { @@ -2133,12 +2024,7 @@ static void sdap_cli_rootdse_auth_done(struct tevent_req *subreq) if (ret == ETIMEDOUT) { /* The server we authenticated against went down. Retry another * one */ - be_fo_set_port_status(state->be, state->service->name, - state->srv, PORT_NOT_WORKING); - ret = sdap_cli_resolve_next(req); - if (ret != EOK) { - tevent_req_error(req, ret); - } + tevent_req_error(req, ERR_SERVER_FAILURE); return; } @@ -2167,48 +2053,282 @@ static void sdap_cli_rootdse_auth_done(struct tevent_req *subreq) int sdap_cli_connect_recv(struct tevent_req *req, TALLOC_CTX *memctx, - bool *can_retry, struct sdap_handle **gsh, struct sdap_server_opts **srv_opts) { struct sdap_cli_connect_state *state = tevent_req_data(req, struct sdap_cli_connect_state); - enum tevent_req_state tstate; - uint64_t err_uint64; - int err; - if (can_retry) { - *can_retry = true; - } - if (tevent_req_is_error(req, &tstate, &err_uint64)) { - /* mark the server as bad if connection failed */ - if (state->srv) { - DEBUG(SSSDBG_OP_FAILURE, "Unable to establish connection " - "[%"PRIu64"]: %s\n", err_uint64, sss_strerror(err_uint64)); + TEVENT_REQ_RETURN_ON_ERROR(req); - be_fo_set_port_status(state->be, state->service->name, - state->srv, PORT_NOT_WORKING); - } else { - if (can_retry) { - *can_retry = false; - } + if (gsh) { + if (*gsh) { + talloc_zfree(*gsh); } - - if (tstate == TEVENT_REQ_USER_ERROR) { - err = (int)err_uint64; - if (err == EOK) { - return EINVAL; - } - return err; + *gsh = talloc_steal(memctx, state->sh); + if (!*gsh) { + return ENOMEM; } - return EIO; - } else if (state->srv) { - DEBUG(SSSDBG_TRACE_FUNC, "Connection established.\n"); + } else { + talloc_zfree(state->sh); + } + + if (srv_opts) { + *srv_opts = talloc_steal(memctx, state->srv_opts); + } + + return EOK; +} + +struct sdap_cli_resolve_and_connect_state { + struct tevent_context *ev; + struct sdap_options *opts; + struct sdap_service *service; + struct be_ctx *be; + + bool use_rootdse; + struct sysdb_attrs *rootdse; + + struct sdap_handle *sh; + + struct fo_server *srv; + struct sdap_server_opts *srv_opts; + + enum connect_tls force_tls; + bool do_auth; + + bool can_retry; + time_t kinit_expire_time; +}; + +static errno_t sdap_cli_resolve_and_connect_kinit_step(struct tevent_req *req); +static void sdap_cli_resolve_and_connect_kinit_done(struct tevent_req *subreq); +static errno_t sdap_cli_resolve_and_connect_next_server(struct tevent_req *req); +static void sdap_cli_resolve_and_connect_next_server_done(struct tevent_req *subreq); +static void sdap_cli_resolve_and_connect_done(struct tevent_req *subreq); + +struct tevent_req * +sdap_cli_resolve_and_connect_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sdap_options *opts, + struct be_ctx *be, + struct sdap_service *service, + bool skip_rootdse, + enum connect_tls force_tls, + bool skip_auth) +{ + struct sdap_cli_resolve_and_connect_state *state; + struct tevent_req *req; + errno_t ret; + + req = tevent_req_create(mem_ctx, &state, + struct sdap_cli_resolve_and_connect_state); + if (req == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); + return NULL; + } + + state->ev = ev; + state->opts = opts; + state->service = service; + state->be = be; + state->srv = NULL; + state->srv_opts = NULL; + state->use_rootdse = !skip_rootdse; + state->force_tls = force_tls; + state->do_auth = !skip_auth; + state->can_retry = true; + + ret = sdap_cli_resolve_and_connect_kinit_step(req); + if (ret != EOK) { + tevent_req_error(req, ret); + tevent_req_post(req, ev); + } + + return req; +} + +static errno_t sdap_cli_resolve_and_connect_kinit_step(struct tevent_req *req) +{ + struct sdap_cli_resolve_and_connect_state *state; + struct tevent_req *subreq; + const char *sasl_mech; + + state = tevent_req_data(req, struct sdap_cli_resolve_and_connect_state); + sasl_mech = dp_opt_get_string(state->opts->basic, SDAP_SASL_MECH); + + if (!state->do_auth || sasl_mech == NULL + || !sdap_sasl_mech_needs_kinit(sasl_mech) + || !dp_opt_get_bool(state->opts->basic, SDAP_KRB5_KINIT)) { + /* kinit is not needed, skip this step */ + return sdap_cli_resolve_and_connect_next_server(req); + } + + subreq = sdap_kinit_send(state, state->ev, + state->be, + state->sh, + state->service->kinit_service_name, + dp_opt_get_int(state->opts->basic, + SDAP_OPT_TIMEOUT), + dp_opt_get_string(state->opts->basic, + SDAP_KRB5_KEYTAB), + dp_opt_get_string(state->opts->basic, + SDAP_SASL_AUTHID), + sdap_gssapi_realm(state->opts->basic), + dp_opt_get_bool(state->opts->basic, + SDAP_KRB5_CANONICALIZE), + dp_opt_get_int(state->opts->basic, + SDAP_KRB5_TICKET_LIFETIME)); + if (subreq == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!\n"); + return ENOMEM; + } + + tevent_req_set_callback(subreq, sdap_cli_resolve_and_connect_kinit_done, req); + return EOK; +} + +static void sdap_cli_resolve_and_connect_kinit_done(struct tevent_req *subreq) +{ + struct sdap_cli_resolve_and_connect_state *state; + struct tevent_req *req; + errno_t ret; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_cli_resolve_and_connect_state); + + ret = sdap_kinit_recv(subreq, &state->kinit_expire_time); + talloc_zfree(subreq); + if (ret != EOK) { + /* We're not able to authenticate to the LDAP server. + * There's not much we can do except for going offline */ + DEBUG(SSSDBG_TRACE_FUNC, + "Cannot get a TGT: ret [%d](%s)\n", ret, sss_strerror(ret)); + tevent_req_error(req, EACCES); + return; + } + + ret = sdap_cli_resolve_and_connect_next_server(req); + if (ret != EOK) { + tevent_req_error(req, ret); + } +} + +static errno_t sdap_cli_resolve_and_connect_next_server(struct tevent_req *req) +{ + struct sdap_cli_resolve_and_connect_state *state; + struct tevent_req *subreq; + + state = tevent_req_data(req, struct sdap_cli_resolve_and_connect_state); + + /* Before stepping to next server destroy any connection from previous + * attempt */ + talloc_zfree(state->sh); + + /* NOTE: this call may cause service->uri to be refreshed + * with a new valid server. Do not use service->uri before */ + subreq = be_resolve_server_send(state, state->ev, + state->be, state->service->name, + state->srv == NULL ? true : false); + if (!subreq) { + return ENOMEM; + } + + tevent_req_set_callback(subreq, + sdap_cli_resolve_and_connect_next_server_done, req); + return EOK; +} + +static void sdap_cli_resolve_and_connect_next_server_done(struct tevent_req *subreq) +{ + struct sdap_cli_resolve_and_connect_state *state; + struct tevent_req *req; + int ret; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_cli_resolve_and_connect_state); + + ret = be_resolve_server_recv(subreq, state, &state->srv); + talloc_zfree(subreq); + if (ret) { + state->srv = NULL; + state->can_retry = false; + /* all servers have been tried and none + * was found good, go offline */ + tevent_req_error(req, EIO); + return; + } + + subreq = sdap_cli_connect_send(state, state->ev, state->opts, + state->service->uri, + state->service->sockaddr, + state->service->sockaddr_len, + !state->use_rootdse, + state->force_tls, + !state->do_auth, + state->kinit_expire_time); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sdap_cli_resolve_and_connect_done, req); +} + +static void +sdap_cli_resolve_and_connect_done(struct tevent_req *subreq) +{ + struct sdap_cli_resolve_and_connect_state *state; + struct tevent_req *req; + errno_t ret; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_cli_resolve_and_connect_state); + + ret = sdap_cli_connect_recv(subreq, state, &state->sh, &state->srv_opts); + talloc_zfree(subreq); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Unable to establish connection " + "[%d]: %s\n", ret, sss_strerror(ret)); be_fo_set_port_status(state->be, state->service->name, - state->srv, PORT_WORKING); + state->srv, PORT_NOT_WORKING); } + if (ret == ERR_SERVER_FAILURE) { + /* try next server */ + ret = sdap_cli_resolve_and_connect_next_server(req); + if (ret != EOK) { + tevent_req_error(req, ret); + } + return; + } else if (ret != EOK) { + tevent_req_error(req, ret); + return; + } + + DEBUG(SSSDBG_TRACE_FUNC, "Connection established.\n"); + be_fo_set_port_status(state->be, state->service->name, state->srv, + PORT_WORKING); + + tevent_req_done(req); +} + +errno_t +sdap_cli_resolve_and_connect_recv(struct tevent_req *req, + TALLOC_CTX *memctx, + bool *can_retry, + struct sdap_handle **gsh, + struct sdap_server_opts **srv_opts) +{ + struct sdap_cli_resolve_and_connect_state *state = NULL; + state = tevent_req_data(req, struct sdap_cli_resolve_and_connect_state); + + if (can_retry != NULL) { + *can_retry = state->can_retry; + } + + TEVENT_REQ_RETURN_ON_ERROR(req); + if (gsh) { if (*gsh) { talloc_zfree(*gsh); diff --git a/src/providers/ldap/sdap_id_op.c b/src/providers/ldap/sdap_id_op.c index 857a6359f07..f9fe516708c 100644 --- a/src/providers/ldap/sdap_id_op.c +++ b/src/providers/ldap/sdap_id_op.c @@ -643,11 +643,11 @@ static int sdap_id_op_connect_step(struct tevent_req *req) talloc_set_destructor(conn_data, sdap_id_conn_data_destroy); conn_data->conn_cache = conn_cache; - subreq = sdap_cli_connect_send(conn_data, state->ev, - state->id_conn->id_ctx->opts, - state->id_conn->id_ctx->be, - state->id_conn->service, false, - CON_TLS_DFL, false); + subreq = sdap_cli_resolve_and_connect_send(conn_data, state->ev, + state->id_conn->id_ctx->opts, + state->id_conn->id_ctx->be, + state->id_conn->service, false, + CON_TLS_DFL, false); if (!subreq) { ret = ENOMEM; @@ -691,8 +691,8 @@ static void sdap_id_op_connect_done(struct tevent_req *subreq) int ret; int ret_nonfatal; - ret = sdap_cli_connect_recv(subreq, conn_data, &can_retry, - &conn_data->sh, &srv_opts); + ret = sdap_cli_resolve_and_connect_recv(subreq, conn_data, &can_retry, + &conn_data->sh, &srv_opts); conn_data->connect_req = NULL; talloc_zfree(subreq); @@ -705,7 +705,7 @@ static void sdap_id_op_connect_done(struct tevent_req *subreq) if (ret == EOK && (!conn_data->sh || !conn_data->sh->connected)) { DEBUG(SSSDBG_FATAL_FAILURE, - "sdap_cli_connect_recv returned bogus connection\n"); + "sdap_cli_resolve_and_connect_recv returned bogus connection\n"); ret = EFAULT; } diff --git a/src/providers/ldap/sdap_online_check.c b/src/providers/ldap/sdap_online_check.c index f99664562ee..cd26841c2f3 100644 --- a/src/providers/ldap/sdap_online_check.c +++ b/src/providers/ldap/sdap_online_check.c @@ -52,9 +52,9 @@ static struct tevent_req *sdap_online_check_send(TALLOC_CTX *mem_ctx, state->id_ctx = id_ctx; state->be_ctx = be_ctx = id_ctx->be; - subreq = sdap_cli_connect_send(state, be_ctx->ev, id_ctx->opts, be_ctx, - id_ctx->conn->service, false, - CON_TLS_DFL, false); + subreq = sdap_cli_resolve_and_connect_send(state, be_ctx->ev, id_ctx->opts, + be_ctx, id_ctx->conn->service, + false, CON_TLS_DFL, false); if (subreq == NULL) { ret = ENOMEM; tevent_req_error(req, ret); @@ -81,7 +81,8 @@ static void sdap_online_check_connect_done(struct tevent_req *subreq) id_ctx = state->id_ctx; - ret = sdap_cli_connect_recv(subreq, state, &can_retry, NULL, &srv_opts); + ret = sdap_cli_resolve_and_connect_recv(subreq, state, &can_retry, NULL, + &srv_opts); talloc_zfree(subreq); if (ret != EOK) { if (can_retry == false) {