diff options
Diffstat (limited to 'server/providers/ldap/sdap_async_connection.c')
-rw-r--r-- | server/providers/ldap/sdap_async_connection.c | 1141 |
1 files changed, 0 insertions, 1141 deletions
diff --git a/server/providers/ldap/sdap_async_connection.c b/server/providers/ldap/sdap_async_connection.c deleted file mode 100644 index 18e47d3b7..000000000 --- a/server/providers/ldap/sdap_async_connection.c +++ /dev/null @@ -1,1141 +0,0 @@ -/* - SSSD - - Async LDAP Helper routines - - Copyright (C) Simo Sorce <ssorce@redhat.com> - 2009 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include <sasl/sasl.h> -#include "util/util.h" -#include "util/sss_krb5.h" -#include "providers/ldap/sdap_async_private.h" - -#define LDAP_X_SSSD_PASSWORD_EXPIRED 0x555D - -/* ==Connect-to-LDAP-Server=============================================== */ - -struct sdap_connect_state { - struct tevent_context *ev; - struct sdap_options *opts; - struct sdap_handle *sh; - - struct sdap_op *op; - - struct sdap_msg *reply; - int result; -}; - -static void sdap_connect_done(struct sdap_op *op, - struct sdap_msg *reply, - int error, void *pvt); - -struct tevent_req *sdap_connect_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_options *opts, - const char *uri, - bool use_start_tls) -{ - struct tevent_req *req; - struct sdap_connect_state *state; - struct timeval tv; - int ver; - int lret; - int ret = EOK; - int msgid; - bool ldap_referrals; - - req = tevent_req_create(memctx, &state, struct sdap_connect_state); - if (!req) return NULL; - - state->reply = talloc(state, struct sdap_msg); - if (!state->reply) { - talloc_zfree(req); - return NULL; - } - - state->ev = ev; - state->opts = opts; - state->sh = sdap_handle_create(state); - if (!state->sh) { - talloc_zfree(req); - return NULL; - } - /* Initialize LDAP handler */ - lret = ldap_initialize(&state->sh->ldap, uri); - if (lret != LDAP_SUCCESS) { - DEBUG(1, ("ldap_initialize failed: %s\n", ldap_err2string(lret))); - goto fail; - } - - /* Force ldap version to 3 */ - ver = LDAP_VERSION3; - lret = ldap_set_option(state->sh->ldap, LDAP_OPT_PROTOCOL_VERSION, &ver); - if (lret != LDAP_OPT_SUCCESS) { - DEBUG(1, ("Failed to set ldap version to 3\n")); - goto fail; - } - - /* Set Network Timeout */ - tv.tv_sec = dp_opt_get_int(opts->basic, SDAP_NETWORK_TIMEOUT); - tv.tv_usec = 0; - lret = ldap_set_option(state->sh->ldap, LDAP_OPT_NETWORK_TIMEOUT, &tv); - if (lret != LDAP_OPT_SUCCESS) { - DEBUG(1, ("Failed to set network timeout to %d\n", - dp_opt_get_int(opts->basic, SDAP_NETWORK_TIMEOUT))); - goto fail; - } - - /* Set Default Timeout */ - tv.tv_sec = dp_opt_get_int(opts->basic, SDAP_OPT_TIMEOUT); - tv.tv_usec = 0; - lret = ldap_set_option(state->sh->ldap, LDAP_OPT_TIMEOUT, &tv); - if (lret != LDAP_OPT_SUCCESS) { - DEBUG(1, ("Failed to set default timeout to %d\n", - dp_opt_get_int(opts->basic, SDAP_OPT_TIMEOUT))); - goto fail; - } - - /* Set Referral chasing */ - ldap_referrals = dp_opt_get_bool(opts->basic, SDAP_REFERRALS); - lret = ldap_set_option(state->sh->ldap, LDAP_OPT_REFERRALS, - (ldap_referrals ? LDAP_OPT_ON : LDAP_OPT_OFF)); - if (lret != LDAP_OPT_SUCCESS) { - DEBUG(1, ("Failed to set referral chasing to %s\n", - (ldap_referrals ? "LDAP_OPT_ON" : "LDAP_OPT_OFF"))); - goto fail; - } - -#ifdef HAVE_LDAP_CONNCB - struct ldap_cb_data *cb_data; - - /* add connection callback */ - state->sh->conncb = talloc_zero(state->sh, struct ldap_conncb); - if (state->sh->conncb == NULL) { - DEBUG(1, ("talloc_zero failed.\n")); - ret = ENOMEM; - goto fail; - } - - cb_data = talloc_zero(state->sh->conncb, struct ldap_cb_data); - if (cb_data == NULL) { - DEBUG(1, ("talloc_zero failed.\n")); - ret = ENOMEM; - goto fail; - } - cb_data->sh = state->sh; - cb_data->ev = state->ev; - - state->sh->conncb->lc_add = sdap_ldap_connect_callback_add; - state->sh->conncb->lc_del = sdap_ldap_connect_callback_del; - state->sh->conncb->lc_arg = cb_data; - - lret = ldap_set_option(state->sh->ldap, LDAP_OPT_CONNECT_CB, - state->sh->conncb); - if (lret != LDAP_OPT_SUCCESS) { - DEBUG(1, ("Failed to set connection callback\n")); - goto fail; - } -#endif - - /* if we do not use start_tls the connection is not really connected yet - * just fake an async procedure and leave connection to the bind call */ - if (!use_start_tls) { - tevent_req_post(req, ev); - return req; - } - - DEBUG(4, ("Executing START TLS\n")); - - lret = ldap_start_tls(state->sh->ldap, NULL, NULL, &msgid); - if (lret != LDAP_SUCCESS) { - DEBUG(3, ("ldap_start_tls failed: [%s]", ldap_err2string(ret))); - goto fail; - } - - state->sh->connected = true; -#ifndef HAVE_LDAP_CONNCB - ret = sdap_install_ldap_callbacks(state->sh, state->ev); - if (ret) goto fail; -#endif - - /* FIXME: get timeouts from configuration, for now 5 secs. */ - ret = sdap_op_add(state, ev, state->sh, msgid, - sdap_connect_done, req, 5, &state->op); - if (ret) { - DEBUG(1, ("Failed to set up operation!\n")); - goto fail; - } - - return req; - -fail: - if (ret) { - tevent_req_error(req, ret); - } else { - if (lret == LDAP_SERVER_DOWN) { - tevent_req_error(req, ETIMEDOUT); - } else { - tevent_req_error(req, EIO); - } - } - tevent_req_post(req, ev); - return req; -} - -static void sdap_connect_done(struct sdap_op *op, - struct sdap_msg *reply, - int error, void *pvt) -{ - struct tevent_req *req = talloc_get_type(pvt, struct tevent_req); - struct sdap_connect_state *state = tevent_req_data(req, - struct sdap_connect_state); - char *errmsg; - int ret; - - if (error) { - tevent_req_error(req, error); - return; - } - - state->reply = talloc_steal(state, reply); - - ret = ldap_parse_result(state->sh->ldap, state->reply->msg, - &state->result, NULL, &errmsg, NULL, NULL, 0); - if (ret != LDAP_SUCCESS) { - DEBUG(2, ("ldap_parse_result failed (%d)\n", state->op->msgid)); - tevent_req_error(req, EIO); - return; - } - - DEBUG(3, ("START TLS result: %s(%d), %s\n", - ldap_err2string(state->result), state->result, errmsg)); - - if (ldap_tls_inplace(state->sh->ldap)) { - DEBUG(9, ("SSL/TLS handler already in place.\n")); - tevent_req_done(req); - return; - } - -/* FIXME: take care that ldap_install_tls might block */ - ret = ldap_install_tls(state->sh->ldap); - if (ret != LDAP_SUCCESS) { - DEBUG(1, ("ldap_install_tls failed: [%d][%s]\n", ret, - ldap_err2string(ret))); - state->result = ret; - tevent_req_error(req, EIO); - return; - } - - tevent_req_done(req); -} - -int sdap_connect_recv(struct tevent_req *req, - TALLOC_CTX *memctx, - struct sdap_handle **sh) -{ - struct sdap_connect_state *state = tevent_req_data(req, - struct sdap_connect_state); - enum tevent_req_state tstate; - uint64_t err = EIO; - - if (tevent_req_is_error(req, &tstate, &err)) { - /* if tstate shows in progress, it is because - * we did not ask to perform tls, just pretend all is fine */ - if (tstate != TEVENT_REQ_IN_PROGRESS) { - return err; - } - } - - *sh = talloc_steal(memctx, state->sh); - if (!*sh) { - return ENOMEM; - } - return EOK; -} - -/* ==Simple-Bind========================================================== */ - -struct simple_bind_state { - struct tevent_context *ev; - struct sdap_handle *sh; - const char *user_dn; - struct berval *pw; - - struct sdap_op *op; - - struct sdap_msg *reply; - int result; -}; - -static void simple_bind_done(struct sdap_op *op, - struct sdap_msg *reply, - int error, void *pvt); - -static struct tevent_req *simple_bind_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_handle *sh, - const char *user_dn, - struct berval *pw) -{ - struct tevent_req *req; - struct simple_bind_state *state; - int ret = EOK; - int msgid; - int ldap_err; - LDAPControl *request_controls[2]; - - req = tevent_req_create(memctx, &state, struct simple_bind_state); - if (!req) return NULL; - - state->reply = talloc(state, struct sdap_msg); - if (!state->reply) { - talloc_zfree(req); - return NULL; - } - - state->ev = ev; - state->sh = sh; - state->user_dn = user_dn; - state->pw = pw; - - ret = sss_ldap_control_create(LDAP_CONTROL_PASSWORDPOLICYREQUEST, - 0, NULL, 0, &request_controls[0]); - if (ret != LDAP_SUCCESS) { - DEBUG(1, ("sss_ldap_control_create failed.\n")); - goto fail; - } - request_controls[1] = NULL; - - DEBUG(4, ("Executing simple bind as: %s\n", state->user_dn)); - - ret = ldap_sasl_bind(state->sh->ldap, state->user_dn, LDAP_SASL_SIMPLE, - state->pw, request_controls, NULL, &msgid); - ldap_control_free(request_controls[0]); - if (ret == -1 || msgid == -1) { - ret = ldap_get_option(state->sh->ldap, - LDAP_OPT_RESULT_CODE, &ldap_err); - if (ret != LDAP_OPT_SUCCESS) { - DEBUG(1, ("ldap_bind failed (couldn't get ldap error)\n")); - ret = LDAP_LOCAL_ERROR; - } else { - DEBUG(1, ("ldap_bind failed (%d)[%s]\n", - ldap_err, ldap_err2string(ldap_err))); - ret = ldap_err; - } - goto fail; - } - DEBUG(8, ("ldap simple bind sent, msgid = %d\n", msgid)); - - if (!sh->connected) { - sh->connected = true; -#ifndef HAVE_LDAP_CONNCB - ret = sdap_install_ldap_callbacks(sh, ev); - if (ret) goto fail; -#endif - } - - /* FIXME: get timeouts from configuration, for now 5 secs. */ - ret = sdap_op_add(state, ev, sh, msgid, - simple_bind_done, req, 5, &state->op); - if (ret) { - DEBUG(1, ("Failed to set up operation!\n")); - goto fail; - } - - return req; - -fail: - if (ret == LDAP_SERVER_DOWN) { - tevent_req_error(req, ETIMEDOUT); - } else { - tevent_req_error(req, EIO); - } - tevent_req_post(req, ev); - return req; -} - -static void simple_bind_done(struct sdap_op *op, - struct sdap_msg *reply, - int error, void *pvt) -{ - struct tevent_req *req = talloc_get_type(pvt, struct tevent_req); - struct simple_bind_state *state = tevent_req_data(req, - struct simple_bind_state); - char *errmsg; - int ret; - LDAPControl **response_controls; - int c; - ber_int_t pp_grace; - ber_int_t pp_expire; - LDAPPasswordPolicyError pp_error; - - if (error) { - tevent_req_error(req, error); - return; - } - - state->reply = talloc_steal(state, reply); - - ret = ldap_parse_result(state->sh->ldap, state->reply->msg, - &state->result, NULL, &errmsg, NULL, - &response_controls, 0); - if (ret != LDAP_SUCCESS) { - DEBUG(2, ("ldap_parse_result failed (%d)\n", state->op->msgid)); - ret = EIO; - goto done; - } - - if (response_controls == NULL) { - DEBUG(5, ("Server returned no controls.\n")); - } else { - for (c = 0; response_controls[c] != NULL; c++) { - DEBUG(9, ("Server returned control [%s].\n", - response_controls[c]->ldctl_oid)); - if (strcmp(response_controls[c]->ldctl_oid, - LDAP_CONTROL_PASSWORDPOLICYRESPONSE) == 0) { - ret = ldap_parse_passwordpolicy_control(state->sh->ldap, - response_controls[c], - &pp_expire, &pp_grace, - &pp_error); - if (ret != LDAP_SUCCESS) { - DEBUG(1, ("ldap_parse_passwordpolicy_control failed.\n")); - ret = EIO; - goto done; - } - - DEBUG(7, ("Password Policy Response: expire [%d] grace [%d] " - "error [%s].\n", pp_expire, pp_grace, - ldap_passwordpolicy_err2txt(pp_error))); - - if (state->result == LDAP_SUCCESS && - (pp_error == PP_changeAfterReset || pp_grace > 0)) { - DEBUG(4, ("User must set a new password.\n")); - state->result = LDAP_X_SSSD_PASSWORD_EXPIRED; - } - } - } - } - - DEBUG(3, ("Bind result: %s(%d), %s\n", - ldap_err2string(state->result), state->result, errmsg)); - - ret = LDAP_SUCCESS; -done: - ldap_controls_free(response_controls); - - if (ret == LDAP_SUCCESS) { - tevent_req_done(req); - } else { - tevent_req_error(req, ret); - } -} - -static int simple_bind_recv(struct tevent_req *req, int *ldaperr) -{ - struct simple_bind_state *state = tevent_req_data(req, - struct simple_bind_state); - - *ldaperr = LDAP_OTHER; - TEVENT_REQ_RETURN_ON_ERROR(req); - - *ldaperr = state->result; - return EOK; -} - -/* ==SASL-Bind============================================================ */ - -struct sasl_bind_state { - struct tevent_context *ev; - struct sdap_handle *sh; - - const char *sasl_mech; - const char *sasl_user; - struct berval *sasl_cred; - - int result; -}; - -static int sdap_sasl_interact(LDAP *ld, unsigned flags, - void *defaults, void *interact); - -static struct tevent_req *sasl_bind_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_handle *sh, - const char *sasl_mech, - const char *sasl_user, - struct berval *sasl_cred) -{ - struct tevent_req *req; - struct sasl_bind_state *state; - int ret = EOK; - - req = tevent_req_create(memctx, &state, struct sasl_bind_state); - if (!req) return NULL; - - state->ev = ev; - state->sh = sh; - state->sasl_mech = sasl_mech; - state->sasl_user = sasl_user; - state->sasl_cred = sasl_cred; - - DEBUG(4, ("Executing sasl bind mech: %s, user: %s\n", - sasl_mech, sasl_user)); - - /* FIXME: Warning, this is a sync call! - * No async variant exist in openldap libraries yet */ - - ret = ldap_sasl_interactive_bind_s(state->sh->ldap, NULL, - sasl_mech, NULL, NULL, - LDAP_SASL_QUIET, - (*sdap_sasl_interact), state); - state->result = ret; - if (ret != LDAP_SUCCESS) { - DEBUG(1, ("ldap_sasl_bind failed (%d)[%s]\n", - ret, ldap_err2string(ret))); - goto fail; - } - - if (!sh->connected) { - sh->connected = true; -#ifndef HAVE_LDAP_CONNCB - ret = sdap_install_ldap_callbacks(sh, ev); - if (ret) goto fail; -#endif - } - - tevent_req_post(req, ev); - return req; - -fail: - if (ret == LDAP_SERVER_DOWN) { - tevent_req_error(req, ETIMEDOUT); - } else { - tevent_req_error(req, EIO); - } - tevent_req_post(req, ev); - return req; -} - -static int sdap_sasl_interact(LDAP *ld, unsigned flags, - void *defaults, void *interact) -{ - struct sasl_bind_state *state = talloc_get_type(defaults, - struct sasl_bind_state); - sasl_interact_t *in = (sasl_interact_t *)interact; - - if (!ld) return LDAP_PARAM_ERROR; - - while (in->id != SASL_CB_LIST_END) { - - switch (in->id) { - case SASL_CB_GETREALM: - case SASL_CB_AUTHNAME: - case SASL_CB_PASS: - if (in->defresult) { - in->result = in->defresult; - } else { - in->result = ""; - } - in->len = strlen(in->result); - break; - case SASL_CB_USER: - if (state->sasl_user) { - in->result = state->sasl_user; - } else if (in->defresult) { - in->result = in->defresult; - } else { - in->result = ""; - } - in->len = strlen(in->result); - break; - case SASL_CB_NOECHOPROMPT: - case SASL_CB_ECHOPROMPT: - goto fail; - } - - in++; - } - - return LDAP_SUCCESS; - -fail: - return LDAP_UNAVAILABLE; -} - -static int sasl_bind_recv(struct tevent_req *req, int *ldaperr) -{ - struct sasl_bind_state *state = tevent_req_data(req, - struct sasl_bind_state); - enum tevent_req_state tstate; - uint64_t err = EIO; - - if (tevent_req_is_error(req, &tstate, &err)) { - if (tstate != TEVENT_REQ_IN_PROGRESS) { - *ldaperr = LDAP_OTHER; - return err; - } - } - - *ldaperr = state->result; - return EOK; -} - -/* ==Perform-Kinit-given-keytab-and-principal============================= */ - -struct sdap_kinit_state { - int result; -}; - -static void sdap_kinit_done(struct tevent_req *subreq); - -struct tevent_req *sdap_kinit_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_handle *sh, - int timeout, - const char *keytab, - const char *principal, - const char *realm) -{ - struct tevent_req *req; - struct tevent_req *subreq; - struct sdap_kinit_state *state; - int ret; - - DEBUG(6, ("Attempting kinit (%s, %s, %s)\n", keytab, principal, realm)); - - req = tevent_req_create(memctx, &state, struct sdap_kinit_state); - if (!req) return NULL; - - state->result = SDAP_AUTH_FAILED; - - if (keytab) { - ret = setenv("KRB5_KTNAME", keytab, 1); - if (ret == -1) { - DEBUG(2, ("Failed to set KRB5_KTNAME to %s\n", keytab)); - return NULL; - } - } - - subreq = sdap_get_tgt_send(state, ev, realm, principal, keytab, timeout); - if (!subreq) { - talloc_zfree(req); - return NULL; - } - tevent_req_set_callback(subreq, sdap_kinit_done, req); - - return req; -} - -static void sdap_kinit_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct sdap_kinit_state *state = tevent_req_data(req, - struct sdap_kinit_state); - - int ret; - int result; - char *ccname = NULL; - - ret = sdap_get_tgt_recv(subreq, state, &result, &ccname); - talloc_zfree(subreq); - if (ret != EOK) { - state->result = SDAP_AUTH_FAILED; - DEBUG(1, ("child failed (%d [%s])\n", ret, strerror(ret))); - tevent_req_error(req, ret); - return; - } - - if (result == EOK) { - ret = setenv("KRB5CCNAME", ccname, 1); - if (ret == -1) { - DEBUG(2, ("Unable to set env. variable KRB5CCNAME!\n")); - state->result = SDAP_AUTH_FAILED; - tevent_req_error(req, EFAULT); - } - - state->result = SDAP_AUTH_SUCCESS; - tevent_req_done(req); - return; - } - - DEBUG(4, ("Could not get TGT: %d [%s]\n", result, strerror(result))); - state->result = SDAP_AUTH_FAILED; - tevent_req_error(req, EIO); -} - -int sdap_kinit_recv(struct tevent_req *req, enum sdap_result *result) -{ - struct sdap_kinit_state *state = tevent_req_data(req, - struct sdap_kinit_state); - enum tevent_req_state tstate; - uint64_t err = EIO; - - if (tevent_req_is_error(req, &tstate, &err)) { - if (tstate != TEVENT_REQ_IN_PROGRESS) { - *result = SDAP_ERROR; - return err; - } - } - - *result = state->result; - return EOK; -} - - -/* ==Authenticaticate-User-by-DN========================================== */ - -struct sdap_auth_state { - const char *user_dn; - struct berval pw; - - int result; - bool is_sasl; -}; - -static void sdap_auth_done(struct tevent_req *subreq); - -/* TODO: handle sasl_cred */ -struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, - struct tevent_context *ev, - struct sdap_handle *sh, - const char *sasl_mech, - const char *sasl_user, - const char *user_dn, - const char *authtok_type, - struct dp_opt_blob authtok) -{ - struct tevent_req *req, *subreq; - struct sdap_auth_state *state; - - if (authtok_type != NULL && strcasecmp(authtok_type,"password") != 0) { - DEBUG(1,("Authentication token type [%s] is not supported")); - return NULL; - } - - req = tevent_req_create(memctx, &state, struct sdap_auth_state); - if (!req) return NULL; - - state->user_dn = user_dn; - state->pw.bv_val = (char *)authtok.data; - state->pw.bv_len = authtok.length; - - if (sasl_mech) { - state->is_sasl = true; - subreq = sasl_bind_send(state, ev, sh, sasl_mech, sasl_user, NULL); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return tevent_req_post(req, ev); - } - } else { - state->is_sasl = false; - subreq = simple_bind_send(state, ev, sh, user_dn, &state->pw); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return tevent_req_post(req, ev); - } - } - - tevent_req_set_callback(subreq, sdap_auth_done, req); - return req; -} - -static void sdap_auth_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct sdap_auth_state *state = tevent_req_data(req, - struct sdap_auth_state); - int ret; - - if (state->is_sasl) { - ret = sasl_bind_recv(subreq, &state->result); - } else { - ret = simple_bind_recv(subreq, &state->result); - } - if (ret != EOK) { - tevent_req_error(req, ret); - return; - } - - tevent_req_done(req); -} - -int sdap_auth_recv(struct tevent_req *req, enum sdap_result *result) -{ - struct sdap_auth_state *state = tevent_req_data(req, - struct sdap_auth_state); - - *result = SDAP_ERROR; - TEVENT_REQ_RETURN_ON_ERROR(req); - - switch (state->result) { - case LDAP_SUCCESS: - *result = SDAP_AUTH_SUCCESS; - break; - case LDAP_INVALID_CREDENTIALS: - *result = SDAP_AUTH_FAILED; - break; - case LDAP_X_SSSD_PASSWORD_EXPIRED: - *result = SDAP_AUTH_PW_EXPIRED; - break; - default: - break; - } - - return EOK; -} - -/* ==Client connect============================================ */ - -struct sdap_cli_connect_state { - struct tevent_context *ev; - struct sdap_options *opts; - struct sdap_service *service; - - bool use_rootdse; - struct sysdb_attrs *rootdse; - - struct sdap_handle *sh; - - struct fo_server *srv; -}; - -static void sdap_cli_resolve_done(struct tevent_req *subreq); -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 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); - -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, - struct sysdb_attrs **rootdse) -{ - struct tevent_req *req, *subreq; - struct sdap_cli_connect_state *state; - - req = tevent_req_create(memctx, &state, struct sdap_cli_connect_state); - if (!req) return NULL; - - state->ev = ev; - state->opts = opts; - state->service = service; - state->srv = NULL; - - if (rootdse) { - state->use_rootdse = true; - state->rootdse = *rootdse; - } else { - state->use_rootdse = false; - state->rootdse = NULL; - } - - /* 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, ev, be, service->name); - if (!subreq) { - talloc_zfree(req); - return NULL; - } - tevent_req_set_callback(subreq, sdap_cli_resolve_done, req); - - return req; -} - -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->srv); - talloc_zfree(subreq); - if (ret) { - /* all servers have been tried and none - * was found good, go offline */ - tevent_req_error(req, EIO); - return; - } - - subreq = sdap_connect_send(state, state->ev, state->opts, - state->service->uri, - dp_opt_get_bool(state->opts->basic, - SDAP_ID_TLS)); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, sdap_cli_connect_done, req); -} - -static void sdap_cli_connect_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); - const char *sasl_mech; - int ret; - - ret = sdap_connect_recv(subreq, state, &state->sh); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - if (state->use_rootdse && !state->rootdse) { - /* fetch the rootDSE this time */ - sdap_cli_rootdse_step(req); - return; - } - - sasl_mech = dp_opt_get_string(state->opts->basic, SDAP_SASL_MECH); - - if (sasl_mech && state->use_rootdse) { - /* check if server claims to support GSSAPI */ - if (!sdap_rootdse_sasl_mech_is_supported(state->rootdse, - sasl_mech)) { - tevent_req_error(req, ENOTSUP); - return; - } - } - - if (sasl_mech && (strcasecmp(sasl_mech, "GSSAPI") == 0)) { - if (dp_opt_get_bool(state->opts->basic, SDAP_KRB5_KINIT)) { - sdap_cli_kinit_step(req); - return; - } - } - - sdap_cli_auth_step(req); -} - -static void sdap_cli_rootdse_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_get_rootdse_send(state, state->ev, state->opts, state->sh); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, sdap_cli_rootdse_done, req); - - if (!state->sh->connected) { - /* this rootdse search is performed before we actually do a bind, - * so we need to set up the callbacks or we will never get notified - * of a reply */ - state->sh->connected = true; -#ifndef HAVE_LDAP_CONNCB - int ret; - - ret = sdap_install_ldap_callbacks(state->sh, state->ev); - if (ret) { - tevent_req_error(req, ret); - } -#endif - } -} - -static void sdap_cli_rootdse_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); - const char *sasl_mech; - int ret; - - ret = sdap_get_rootdse_recv(subreq, state, &state->rootdse); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - sasl_mech = dp_opt_get_string(state->opts->basic, SDAP_SASL_MECH); - - if (sasl_mech && state->use_rootdse) { - /* check if server claims to support GSSAPI */ - if (!sdap_rootdse_sasl_mech_is_supported(state->rootdse, - sasl_mech)) { - tevent_req_error(req, ENOTSUP); - return; - } - } - - if (sasl_mech && (strcasecmp(sasl_mech, "GSSAPI") == 0)) { - if (dp_opt_get_bool(state->opts->basic, SDAP_KRB5_KINIT)) { - sdap_cli_kinit_step(req); - return; - } - } - - sdap_cli_auth_step(req); -} - -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->sh, - 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), - dp_opt_get_string(state->opts->basic, - SDAP_KRB5_REALM)); - 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); - enum sdap_result result; - int ret; - - ret = sdap_kinit_recv(subreq, &result); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - if (result != SDAP_AUTH_SUCCESS) { - tevent_req_error(req, EACCES); - return; - } - - 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, - struct sdap_cli_connect_state); - struct tevent_req *subreq; - - subreq = sdap_auth_send(state, - state->ev, - state->sh, - dp_opt_get_string(state->opts->basic, - SDAP_SASL_MECH), - dp_opt_get_string(state->opts->basic, - SDAP_SASL_AUTHID), - dp_opt_get_string(state->opts->basic, - SDAP_DEFAULT_BIND_DN), - dp_opt_get_string(state->opts->basic, - SDAP_DEFAULT_AUTHTOK_TYPE), - dp_opt_get_blob(state->opts->basic, - SDAP_DEFAULT_AUTHTOK)); - if (!subreq) { - tevent_req_error(req, ENOMEM); - return; - } - tevent_req_set_callback(subreq, sdap_cli_auth_done, req); -} - -static void sdap_cli_auth_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - enum sdap_result result; - int ret; - - ret = sdap_auth_recv(subreq, &result); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - if (result != SDAP_AUTH_SUCCESS) { - tevent_req_error(req, EACCES); - return; - } - - tevent_req_done(req); -} - -int sdap_cli_connect_recv(struct tevent_req *req, - TALLOC_CTX *memctx, - struct sdap_handle **gsh, - struct sysdb_attrs **rootdse) -{ - struct sdap_cli_connect_state *state = tevent_req_data(req, - struct sdap_cli_connect_state); - enum tevent_req_state tstate; - uint64_t err; - - if (tevent_req_is_error(req, &tstate, &err)) { - /* mark the server as bad if connection failed */ - if (state->srv) { - fo_set_port_status(state->srv, PORT_NOT_WORKING); - } - - if (tstate == TEVENT_REQ_USER_ERROR) { - return err; - } - return EIO; - } else if (state->srv) { - fo_set_port_status(state->srv, PORT_WORKING); - } - - if (gsh) { - *gsh = talloc_steal(memctx, state->sh); - if (!*gsh) { - return ENOMEM; - } - } else { - talloc_zfree(state->sh); - } - - if (rootdse) { - if (state->use_rootdse) { - *rootdse = talloc_steal(memctx, state->rootdse); - if (!*rootdse) { - return ENOMEM; - } - } else { - *rootdse = NULL; - } - } else { - talloc_zfree(rootdse); - } - - return EOK; -} - |