From daa3dd779fbaec36142d112f8a47c7b9f23177c1 Mon Sep 17 00:00:00 2001 From: Pavel Reichl Date: Mon, 15 Sep 2014 14:13:21 +0100 Subject: SDAP: check that connection is open before bind Tivoli server does not return an empty response when being asked for the rootDSE data but an error. In this case the rootDSE lookup in SSSD will terminate the connection to the server and return a error. But since errors except timeouts are ignored SSSD will try to continue with the bind, but since the connection is already terminated this will fail as well. And this will terminate the whole operation. Make sure the connection is open before performing bind operation. Resolves: https://fedorahosted.org/sssd/ticket/2435 Reviewed-by: Jakub Hrozek --- src/providers/ldap/sdap_async_connection.c | 113 ++++++++++++++++++++++++++--- 1 file changed, 103 insertions(+), 10 deletions(-) (limited to 'src/providers/ldap') diff --git a/src/providers/ldap/sdap_async_connection.c b/src/providers/ldap/sdap_async_connection.c index cc6c58aae..304505458 100644 --- a/src/providers/ldap/sdap_async_connection.c +++ b/src/providers/ldap/sdap_async_connection.c @@ -1399,6 +1399,7 @@ struct sdap_cli_connect_state { enum connect_tls force_tls; bool do_auth; + bool use_tls; }; static int sdap_cli_resolve_next(struct tevent_req *req); @@ -1411,6 +1412,8 @@ 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); +static void sdap_cli_auth_reconnect_done(struct tevent_req *subreq); static void sdap_cli_rootdse_auth_done(struct tevent_req *subreq); static errno_t @@ -1507,15 +1510,6 @@ static void sdap_cli_resolve_done(struct tevent_req *subreq) struct sdap_cli_connect_state *state = tevent_req_data(req, struct sdap_cli_connect_state); int ret; - bool use_tls; - - ret = decide_tls_usage(state->force_tls, state->opts->basic, - state->service->uri, &use_tls); - - if (ret != EOK) { - tevent_req_error(req, EINVAL); - return; - } ret = be_resolve_server_recv(subreq, &state->srv); talloc_zfree(subreq); @@ -1527,10 +1521,18 @@ static void sdap_cli_resolve_done(struct tevent_req *subreq) return; } + ret = decide_tls_usage(state->force_tls, state->opts->basic, + state->service->uri, &state->use_tls); + + if (ret != EOK) { + tevent_req_error(req, EINVAL); + return; + } + subreq = sdap_connect_send(state, state->ev, state->opts, state->service->uri, state->service->sockaddr, - use_tls); + state->use_tls); if (!subreq) { tevent_req_error(req, ENOMEM); return; @@ -1782,6 +1784,21 @@ static void sdap_cli_auth_step(struct tevent_req *req) struct sss_auth_token *authtok; errno_t ret; + /* It's possible that connection was terminated by server (e.g. #2435), + to overcome this try to connect again. */ + if (state->sh == NULL || !state->sh->connected) { + DEBUG(SSSDBG_TRACE_FUNC, "No connection available. " + "Trying to reconnect.\n"); + ret = sdap_cli_auth_reconnect(req); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, + "sdap_cli_auth_reconnect failed: %d:[%s]", + ret, sss_strerror(ret)); + tevent_req_error(req, ret); + } + return; + } + /* Set the LDAP expiration time * If SASL has already set it, use the sooner of the two */ @@ -1843,6 +1860,82 @@ static void sdap_cli_auth_step(struct tevent_req *req) tevent_req_set_callback(subreq, sdap_cli_auth_done, req); } +static errno_t sdap_cli_auth_reconnect(struct tevent_req *req) +{ + struct sdap_cli_connect_state *state; + struct tevent_req *subreq; + errno_t ret; + + 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); + if (ret != EOK) { + goto done; + } + + subreq = sdap_connect_send(state, state->ev, state->opts, + state->service->uri, + state->service->sockaddr, + state->use_tls); + + if (subreq == NULL) { + ret = ENOMEM; + goto done; + } + + tevent_req_set_callback(subreq, sdap_cli_auth_reconnect_done, req); + + ret = EOK; + +done: + return ret; +} + +static void sdap_cli_auth_reconnect_done(struct tevent_req *subreq) +{ + struct sdap_cli_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_connect_state); + + talloc_zfree(state->sh); + + ret = sdap_connect_recv(subreq, state, &state->sh); + talloc_zfree(subreq); + if (ret != EOK) { + goto done; + } + + /* if TLS was used, the sdap handle is already marked as connected */ + if (!state->use_tls) { + /* we need to mark handle as connected to allow anonymous bind */ + ret = sdap_set_connected(state->sh, state->ev); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "sdap_set_connected() failed.\n"); + goto done; + } + } + + /* End request if reconnecting failed to avoid endless loop */ + if (state->sh == NULL || !state->sh->connected) { + DEBUG(SSSDBG_CRIT_FAILURE, "Failed to reconnect.\n"); + ret = EIO; + goto done; + } + + sdap_cli_auth_step(req); + + ret = EOK; + +done: + if (ret != EOK) { + tevent_req_error(req, ret); + } +} + static void sdap_cli_auth_done(struct tevent_req *subreq) { struct tevent_req *req = tevent_req_callback_data(subreq, -- cgit