summaryrefslogtreecommitdiffstats
path: root/server/providers/ldap/sdap_async_connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'server/providers/ldap/sdap_async_connection.c')
-rw-r--r--server/providers/ldap/sdap_async_connection.c1141
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;
-}
-