diff options
author | Andrew Tridgell <tridge@samba.org> | 2012-11-01 14:10:14 +1100 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 2012-11-01 15:40:41 +1100 |
commit | 0e6c5c036f8faddcc6ca65c26453ffaf248ed2b5 (patch) | |
tree | ef6ad67ad11ab8789a6bd602e27d09283d8932d2 | |
parent | b0cc0d5698d34aa7956b22faa8b79bd9b338286d (diff) | |
download | samba-0e6c5c036f8faddcc6ca65c26453ffaf248ed2b5.tar.gz samba-0e6c5c036f8faddcc6ca65c26453ffaf248ed2b5.tar.bz2 samba-0e6c5c036f8faddcc6ca65c26453ffaf248ed2b5.zip |
s4-ldapclient: cope with logon failure retry in LDAP
similar to what was done for rpc and cifs, we now retry once on logon
failure for ldap, allowing for a new ticket to be fetched when a
server password changes while we have a valid ticket for the old
password
Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
-rw-r--r-- | source4/libcli/ldap/ldap_bind.c | 116 |
1 files changed, 79 insertions, 37 deletions
diff --git a/source4/libcli/ldap/ldap_bind.c b/source4/libcli/ldap/ldap_bind.c index f167f17de9..b355e18e0d 100644 --- a/source4/libcli/ldap/ldap_bind.c +++ b/source4/libcli/ldap/ldap_bind.c @@ -221,9 +221,54 @@ _PUBLIC_ NTSTATUS ldap_bind_sasl(struct ldap_connection *conn, "supportedSASLMechanisms", NULL }; + unsigned int logon_retries = 0; + + status = ildap_search(conn, "", LDAP_SEARCH_SCOPE_BASE, "", supported_sasl_mech_attrs, + false, NULL, NULL, &sasl_mechs_msgs); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: %s\n", + nt_errstr(status))); + goto failed; + } + + count = ildap_count_entries(conn, sasl_mechs_msgs); + if (count != 1) { + DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: wrong number of replies: %d\n", + count)); + goto failed; + } + + tmp_ctx = talloc_new(conn); + if (tmp_ctx == NULL) goto failed; + + search = &sasl_mechs_msgs[0]->r.SearchResultEntry; + if (search->num_attributes != 1) { + DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: wrong number of attributes: %d != 1\n", + search->num_attributes)); + goto failed; + } + + sasl_names = talloc_array(tmp_ctx, const char *, search->attributes[0].num_values + 1); + if (!sasl_names) { + DEBUG(1, ("talloc_arry(char *, %d) failed\n", + count)); + goto failed; + } + + for (i=0; i<search->attributes[0].num_values; i++) { + sasl_names[i] = (const char *)search->attributes[0].values[i].data; + } + sasl_names[i] = NULL; gensec_init(); +try_logon_again: + /* + we loop back here on a logon failure, and re-create the + gensec session. The logon_retries counter ensures we don't + loop forever. + */ + status = gensec_client_start(conn, &conn->gensec, lpcfg_gensec_settings(conn, lp_ctx)); if (!NT_STATUS_IS_OK(status)) { @@ -266,43 +311,6 @@ _PUBLIC_ NTSTATUS ldap_bind_sasl(struct ldap_connection *conn, goto failed; } - status = ildap_search(conn, "", LDAP_SEARCH_SCOPE_BASE, "", supported_sasl_mech_attrs, - false, NULL, NULL, &sasl_mechs_msgs); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: %s\n", - nt_errstr(status))); - goto failed; - } - - count = ildap_count_entries(conn, sasl_mechs_msgs); - if (count != 1) { - DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: wrong number of replies: %d\n", - count)); - goto failed; - } - - tmp_ctx = talloc_new(conn); - if (tmp_ctx == NULL) goto failed; - - search = &sasl_mechs_msgs[0]->r.SearchResultEntry; - if (search->num_attributes != 1) { - DEBUG(1, ("Failed to inquire of target's available sasl mechs in rootdse search: wrong number of attributes: %d != 1\n", - search->num_attributes)); - goto failed; - } - - sasl_names = talloc_array(tmp_ctx, const char *, search->attributes[0].num_values + 1); - if (!sasl_names) { - DEBUG(1, ("talloc_arry(char *, %d) failed\n", - count)); - goto failed; - } - - for (i=0; i<search->attributes[0].num_values; i++) { - sasl_names[i] = (const char *)search->attributes[0].values[i].data; - } - sasl_names[i] = NULL; - status = gensec_start_mech_by_sasl_list(conn->gensec, sasl_names); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("None of the %d proposed SASL mechs were acceptable: %s\n", @@ -367,6 +375,40 @@ _PUBLIC_ NTSTATUS ldap_bind_sasl(struct ldap_connection *conn, result = response->r.BindResponse.response.resultcode; + if (result == LDAP_INVALID_CREDENTIALS) { + /* + try a second time on invalid credentials, to + give the user a chance to re-enter the + password and to handle the case where our + kerberos ticket is invalid as the server + password has changed + */ + const char *principal; + + principal = gensec_get_target_principal(conn->gensec); + if (principal == NULL) { + const char *hostname = gensec_get_target_hostname(conn->gensec); + const char *service = gensec_get_target_service(conn->gensec); + if (hostname != NULL && service != NULL) { + principal = talloc_asprintf(tmp_ctx, "%s/%s", service, hostname); + } + } + + if (cli_credentials_failed_kerberos_login(creds, principal, &logon_retries) || + cli_credentials_wrong_password(creds)) { + /* + destroy our gensec session and loop + back up to the top to retry, + offering the user a chance to enter + new credentials, or get a new ticket + if using kerberos + */ + talloc_free(conn->gensec); + conn->gensec = NULL; + goto try_logon_again; + } + } + if (result != LDAP_SUCCESS && result != LDAP_SASL_BIND_IN_PROGRESS) { status = ldap_check_response(conn, &response->r.BindResponse.response); |