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) { 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 */ };