f82568a780e35e8786958c49a1259434e2088b9cniq Async LDAP Helper routines
11e076839c8d5a82d55e710194d0daac51390dbdsf Copyright (C) Simo Sorce <ssorce@redhat.com> - 2009
f82568a780e35e8786958c49a1259434e2088b9cniq Copyright (C) 2010, rhafer@suse.de, Novell Inc.
f82568a780e35e8786958c49a1259434e2088b9cniq This program is free software; you can redistribute it and/or modify
f82568a780e35e8786958c49a1259434e2088b9cniq it under the terms of the GNU General Public License as published by
f82568a780e35e8786958c49a1259434e2088b9cniq the Free Software Foundation; either version 3 of the License, or
f82568a780e35e8786958c49a1259434e2088b9cniq (at your option) any later version.
f82568a780e35e8786958c49a1259434e2088b9cniq This program is distributed in the hope that it will be useful,
f82568a780e35e8786958c49a1259434e2088b9cniq but WITHOUT ANY WARRANTY; without even the implied warranty of
f82568a780e35e8786958c49a1259434e2088b9cniq MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
f82568a780e35e8786958c49a1259434e2088b9cniq GNU General Public License for more details.
5bfaaf573bacb45c1cf290ce85ecc676587e8a64jim You should have received a copy of the GNU General Public License
5bfaaf573bacb45c1cf290ce85ecc676587e8a64jim along with this program. If not, see <http://www.gnu.org/licenses/>.
f82568a780e35e8786958c49a1259434e2088b9cniq/* ==Connect-to-LDAP-Server=============================================== */
f82568a780e35e8786958c49a1259434e2088b9cniqstatic int sdap_rebind_proc(LDAP *ldap, LDAP_CONST char *url, ber_tag_t request,
f82568a780e35e8786958c49a1259434e2088b9cniqstatic void sdap_sys_connect_done(struct tevent_req *subreq);
f82568a780e35e8786958c49a1259434e2088b9cniq const char *uri,
f82568a780e35e8786958c49a1259434e2088b9cniq req = tevent_req_create(memctx, &state, struct sdap_connect_state);
f82568a780e35e8786958c49a1259434e2088b9cniq DEBUG(SSSDBG_CRIT_FAILURE, "Invalid uri or sockaddr\n");
f82568a780e35e8786958c49a1259434e2088b9cniq state->sh->page_size = dp_opt_get_int(state->opts->basic,
f82568a780e35e8786958c49a1259434e2088b9cniq timeout = dp_opt_get_int(state->opts->basic, SDAP_NETWORK_TIMEOUT);
f82568a780e35e8786958c49a1259434e2088b9cniq subreq = sss_ldap_init_send(state, ev, state->uri, sockaddr,
f82568a780e35e8786958c49a1259434e2088b9cniq sizeof(struct sockaddr_storage),
f82568a780e35e8786958c49a1259434e2088b9cniq DEBUG(SSSDBG_CRIT_FAILURE, "sss_ldap_init_send failed.\n");
f82568a780e35e8786958c49a1259434e2088b9cniq tevent_req_set_callback(subreq, sdap_sys_connect_done, req);
f82568a780e35e8786958c49a1259434e2088b9cniqstatic void sdap_sys_connect_done(struct tevent_req *subreq)
f82568a780e35e8786958c49a1259434e2088b9cniq struct tevent_req *req = tevent_req_callback_data(subreq,
f82568a780e35e8786958c49a1259434e2088b9cniq ret = sss_ldap_init_recv(subreq, &state->sh->ldap, &sd);
f82568a780e35e8786958c49a1259434e2088b9cniq "sdap_async_connect_call request failed: [%d]: %s.\n",
f82568a780e35e8786958c49a1259434e2088b9cniq ret = setup_ldap_connection_callbacks(state->sh, state->ev);
f82568a780e35e8786958c49a1259434e2088b9cniq "setup_ldap_connection_callbacks failed: [%d]: %s.\n",
f82568a780e35e8786958c49a1259434e2088b9cniq /* If sss_ldap_init_recv() does not return a valid file descriptor we have
f82568a780e35e8786958c49a1259434e2088b9cniq * to assume that the connection callback will be called by internally by
f82568a780e35e8786958c49a1259434e2088b9cniq * the OpenLDAP client library. */
f82568a780e35e8786958c49a1259434e2088b9cniq DEBUG(SSSDBG_CRIT_FAILURE, "sdap_call_conn_cb failed.\n");
f82568a780e35e8786958c49a1259434e2088b9cniq /* Force ldap version to 3 */
f82568a780e35e8786958c49a1259434e2088b9cniq lret = ldap_set_option(state->sh->ldap, LDAP_OPT_PROTOCOL_VERSION, &ver);
f82568a780e35e8786958c49a1259434e2088b9cniq DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set ldap version to 3\n");
f82568a780e35e8786958c49a1259434e2088b9cniq /* TODO: maybe this can be remove when we go async, currently we need it
f82568a780e35e8786958c49a1259434e2088b9cniq * to handle EINTR during poll(). */
f82568a780e35e8786958c49a1259434e2088b9cniq ret = ldap_set_option(state->sh->ldap, LDAP_OPT_RESTART, LDAP_OPT_ON);
f82568a780e35e8786958c49a1259434e2088b9cniq DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set restart option.\n");
f82568a780e35e8786958c49a1259434e2088b9cniq /* Set Network Timeout */
f82568a780e35e8786958c49a1259434e2088b9cniq tv.tv_sec = dp_opt_get_int(state->opts->basic, SDAP_NETWORK_TIMEOUT);
f82568a780e35e8786958c49a1259434e2088b9cniq lret = ldap_set_option(state->sh->ldap, LDAP_OPT_NETWORK_TIMEOUT, &tv);
f82568a780e35e8786958c49a1259434e2088b9cniq DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set network timeout to %d\n",
f82568a780e35e8786958c49a1259434e2088b9cniq dp_opt_get_int(state->opts->basic, SDAP_NETWORK_TIMEOUT));
f82568a780e35e8786958c49a1259434e2088b9cniq /* Set Default Timeout */
f82568a780e35e8786958c49a1259434e2088b9cniq tv.tv_sec = dp_opt_get_int(state->opts->basic, SDAP_OPT_TIMEOUT);
f82568a780e35e8786958c49a1259434e2088b9cniq lret = ldap_set_option(state->sh->ldap, LDAP_OPT_TIMEOUT, &tv);
f82568a780e35e8786958c49a1259434e2088b9cniq DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set default timeout to %d\n",
f82568a780e35e8786958c49a1259434e2088b9cniq /* Set Referral chasing */
f82568a780e35e8786958c49a1259434e2088b9cniq ldap_referrals = dp_opt_get_bool(state->opts->basic, SDAP_REFERRALS);
f82568a780e35e8786958c49a1259434e2088b9cniq lret = ldap_set_option(state->sh->ldap, LDAP_OPT_REFERRALS,
f82568a780e35e8786958c49a1259434e2088b9cniq DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set referral chasing to %s\n",
f82568a780e35e8786958c49a1259434e2088b9cniq rebind_proc_params->use_start_tls = state->use_start_tls;
f82568a780e35e8786958c49a1259434e2088b9cniq lret = ldap_set_rebind_proc(state->sh->ldap, sdap_rebind_proc,
f82568a780e35e8786958c49a1259434e2088b9cniq DEBUG(SSSDBG_CRIT_FAILURE, "ldap_set_rebind_proc failed.\n");
f82568a780e35e8786958c49a1259434e2088b9cniq /* Set alias dereferencing */
f82568a780e35e8786958c49a1259434e2088b9cniq ldap_deref = dp_opt_get_string(state->opts->basic, SDAP_DEREF);
f82568a780e35e8786958c49a1259434e2088b9cniq DEBUG(SSSDBG_CRIT_FAILURE, "deref_string_to_val failed.\n");
f82568a780e35e8786958c49a1259434e2088b9cniq lret = ldap_set_option(state->sh->ldap, LDAP_OPT_DEREF, &ldap_deref_val);
f82568a780e35e8786958c49a1259434e2088b9cniq /* Set host name canonicalization for LDAP SASL bind */
f82568a780e35e8786958c49a1259434e2088b9cniq sasl_nocanon = !dp_opt_get_bool(state->opts->basic, SDAP_SASL_CANONICALIZE);
f82568a780e35e8786958c49a1259434e2088b9cniq lret = ldap_set_option(state->sh->ldap, LDAP_OPT_X_SASL_NOCANON,
f82568a780e35e8786958c49a1259434e2088b9cniq /* Do not fail, just warn into both debug logs and syslog */
f82568a780e35e8786958c49a1259434e2088b9cniq "Failed to set LDAP SASL nocanon option to %s. If your system "
f82568a780e35e8786958c49a1259434e2088b9cniq "is configured to use SASL, LDAP operations might fail.\n",
f82568a780e35e8786958c49a1259434e2088b9cniq "Failed to set LDAP SASL nocanon option to %s. If your system "
f82568a780e35e8786958c49a1259434e2088b9cniq "is configured to use SASL, LDAP operations might fail.\n",
f82568a780e35e8786958c49a1259434e2088b9cniq sasl_mech = dp_opt_get_string(state->opts->basic, SDAP_SASL_MECH);
f82568a780e35e8786958c49a1259434e2088b9cniq sasl_minssf = dp_opt_get_int(state->opts->basic, SDAP_SASL_MINSSF);
f82568a780e35e8786958c49a1259434e2088b9cniq lret = ldap_set_option(state->sh->ldap, LDAP_OPT_X_SASL_SSF_MIN,
f82568a780e35e8786958c49a1259434e2088b9cniq DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set LDAP MIN SSF option "
f82568a780e35e8786958c49a1259434e2088b9cniq /* if we do not use start_tls the connection is not really connected yet
f82568a780e35e8786958c49a1259434e2088b9cniq * just fake an async procedure and leave connection to the bind call */
f82568a780e35e8786958c49a1259434e2088b9cniq lret = ldap_start_tls(state->sh->ldap, NULL, NULL, &msgid);
f82568a780e35e8786958c49a1259434e2088b9cniq optret = sss_ldap_get_diagnostic_msg(state, state->sh->ldap,
f82568a780e35e8786958c49a1259434e2088b9cniq DEBUG(SSSDBG_MINOR_FAILURE, "ldap_start_tls failed: [%s] [%s]\n",
f82568a780e35e8786958c49a1259434e2088b9cniq sss_log(SSS_LOG_ERR, "Could not start TLS. %s", errmsg);
f82568a780e35e8786958c49a1259434e2088b9cniq DEBUG(SSSDBG_MINOR_FAILURE, "ldap_start_tls failed: [%s]\n",
f82568a780e35e8786958c49a1259434e2088b9cniq "Check for certificate issues.");
f82568a780e35e8786958c49a1259434e2088b9cniq DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set up operation!\n");
f82568a780e35e8786958c49a1259434e2088b9cniq struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
f82568a780e35e8786958c49a1259434e2088b9cniq ret = ldap_parse_result(state->sh->ldap, state->reply->msg,
f82568a780e35e8786958c49a1259434e2088b9cniq DEBUG(SSSDBG_MINOR_FAILURE, "START TLS result: %s(%d), %s\n",
f82568a780e35e8786958c49a1259434e2088b9cniq sss_ldap_err2string(state->result), state->result, errmsg);
f82568a780e35e8786958c49a1259434e2088b9cniq DEBUG(SSSDBG_TRACE_ALL, "SSL/TLS handler already in place.\n");
f82568a780e35e8786958c49a1259434e2088b9cniq/* FIXME: take care that ldap_install_tls might block */
f82568a780e35e8786958c49a1259434e2088b9cniq optret = sss_ldap_get_diagnostic_msg(state, state->sh->ldap,
f82568a780e35e8786958c49a1259434e2088b9cniq DEBUG(SSSDBG_MINOR_FAILURE, "ldap_install_tls failed: [%s] [%s]\n",
f82568a780e35e8786958c49a1259434e2088b9cniq sss_log(SSS_LOG_ERR, "Could not start TLS encryption. %s", tlserr);
f82568a780e35e8786958c49a1259434e2088b9cniq DEBUG(SSSDBG_MINOR_FAILURE, "ldap_install_tls failed: [%s]\n",
f82568a780e35e8786958c49a1259434e2088b9cniq "Check for certificate issues.");
f82568a780e35e8786958c49a1259434e2088b9cniqstatic void sdap_connect_host_resolv_done(struct tevent_req *subreq);
f82568a780e35e8786958c49a1259434e2088b9cniqstatic void sdap_connect_host_done(struct tevent_req *subreq);
f82568a780e35e8786958c49a1259434e2088b9cniqstruct tevent_req *sdap_connect_host_send(TALLOC_CTX *mem_ctx,
f82568a780e35e8786958c49a1259434e2088b9cniq const char *protocol,
f82568a780e35e8786958c49a1259434e2088b9cniq const char *host,
f82568a780e35e8786958c49a1259434e2088b9cniq DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
f82568a780e35e8786958c49a1259434e2088b9cniq state->uri = talloc_asprintf(state, "%s://%s:%d", protocol, host, port);
f82568a780e35e8786958c49a1259434e2088b9cniq subreq = resolv_gethostbyname_send(state, state->ev, resolv_ctx,
f82568a780e35e8786958c49a1259434e2088b9cniq tevent_req_set_callback(subreq, sdap_connect_host_resolv_done, req);
f82568a780e35e8786958c49a1259434e2088b9cniqstatic void sdap_connect_host_resolv_done(struct tevent_req *subreq)
f82568a780e35e8786958c49a1259434e2088b9cniq req = tevent_req_callback_data(subreq, struct tevent_req);
f82568a780e35e8786958c49a1259434e2088b9cniq state = tevent_req_data(req, struct sdap_connect_host_state);
f82568a780e35e8786958c49a1259434e2088b9cniq ret = resolv_gethostbyname_recv(subreq, state, &status, NULL, &hostent);
f82568a780e35e8786958c49a1259434e2088b9cniq DEBUG(SSSDBG_OP_FAILURE, "Failed to resolve host %s: %s\n",
f82568a780e35e8786958c49a1259434e2088b9cniq sockaddr = resolv_get_sockaddr_address(state, hostent, state->port);
f82568a780e35e8786958c49a1259434e2088b9cniq DEBUG(SSSDBG_OP_FAILURE, "resolv_get_sockaddr_address() failed\n");
f82568a780e35e8786958c49a1259434e2088b9cniq DEBUG(SSSDBG_TRACE_FUNC, "Connecting to %s\n", state->uri);
f82568a780e35e8786958c49a1259434e2088b9cniq subreq = sdap_connect_send(state, state->ev, state->opts,
f82568a780e35e8786958c49a1259434e2088b9cniq tevent_req_set_callback(subreq, sdap_connect_host_done, req);
f82568a780e35e8786958c49a1259434e2088b9cniqstatic void sdap_connect_host_done(struct tevent_req *subreq)
f82568a780e35e8786958c49a1259434e2088b9cniq req = tevent_req_callback_data(subreq, struct tevent_req);
f82568a780e35e8786958c49a1259434e2088b9cniq state = tevent_req_data(req, struct sdap_connect_host_state);
f82568a780e35e8786958c49a1259434e2088b9cniq /* if TLS was used, the sdap handle is already marked as connected */
f82568a780e35e8786958c49a1259434e2088b9cniq /* we need to mark handle as connected to allow anonymous bind */
f82568a780e35e8786958c49a1259434e2088b9cniq DEBUG(SSSDBG_CRIT_FAILURE, "sdap_set_connected() failed\n");
f82568a780e35e8786958c49a1259434e2088b9cniq DEBUG(SSSDBG_TRACE_FUNC, "Successful connection to %s\n", state->uri);
return EOK;
int timeout,
const char *user_dn,
return NULL;
goto fail;
goto fail;
if (ret) {
goto fail;
return req;
fail:
return req;
struct simple_bind_state);
if (error) {
&response_controls, 0);
goto done;
LDAP_CONTROL_PASSWORDPOLICYRESPONSE) == 0) {
&pp_error);
goto done;
struct sdap_ppolicy_data);
goto done;
} else if (pp_grace >= 0) {
pp_grace);
} else if (pp_expire > 0) {
LDAP_CONTROL_PWEXPIRED) == 0) {
LDAP_CONTROL_PWEXPIRING) == 0) {
goto done;
goto done;
goto done;
done:
struct simple_bind_state);
return EOK;
const char *sasl_mech,
const char *sasl_user,
goto fail;
&diag_msg);
goto fail;
return req;
fail:
return req;
struct sasl_bind_state);
case SASL_CB_GETREALM:
case SASL_CB_USER:
case SASL_CB_PASS:
case SASL_CB_AUTHNAME:
case SASL_CB_NOECHOPROMPT:
case SASL_CB_ECHOPROMPT:
goto fail;
in++;
return LDAP_SUCCESS;
fail:
return LDAP_UNAVAILABLE;
return EOK;
const char *krb_service_name,
int timeout,
const char *keytab,
const char *principal,
const char *realm,
bool canonicalize,
int lifetime)
return NULL;
if (canonicalize) {
return NULL;
if (!subreq) {
return NULL;
return req;
struct sdap_kinit_state);
return NULL;
return next_req;
struct tevent_req);
struct sdap_kinit_state);
if (!tgtreq) {
struct tevent_req);
struct sdap_kinit_state);
if (!nextreq) {
if (!nextreq) {
struct sdap_kinit_state);
return ERR_INTERNAL;
return err;
return EOK;
const char *sasl_mech,
const char *sasl_user,
const char *user_dn,
int simple_bind_timeout)
if (sasl_mech) {
if (!subreq) {
if (!subreq) {
return req;
return EINVAL;
return EOK;
struct tevent_req);
struct sdap_auth_state);
struct sdap_auth_state);
return EOK;
static errno_t
switch (force_tls) {
case CON_TLS_DFL:
case CON_TLS_ON:
use_tls = true;
case CON_TLS_OFF:
use_tls = false;
return EINVAL;
use_tls = false;
return EOK;
bool skip_rootdse,
bool skip_auth)
if (ret) {
return req;
struct sdap_cli_connect_state);
if (!subreq) {
return ENOMEM;
return EOK;
struct tevent_req);
struct sdap_cli_connect_state);
if (ret) {
if (!subreq) {
struct tevent_req);
struct sdap_cli_connect_state);
if (ret) {
struct sdap_cli_connect_state);
if (!subreq) {
if (ret) {
struct tevent_req);
struct sdap_cli_connect_state);
if (ret) {
if (ret) {
return ret;
if (ret) {
return ret;
if (ret) {
return ret;
return EOK;
struct sdap_cli_connect_state);
if (!subreq) {
struct tevent_req);
struct sdap_cli_connect_state);
struct sdap_cli_connect_state);
if (ret) {
if (!subreq) {
goto done;
goto done;
done:
return ret;
goto done;
goto done;
goto done;
done:
struct tevent_req);
struct sdap_cli_connect_state);
if (ret) {
if (!subreq) {
struct tevent_req);
struct sdap_cli_connect_state);
if (ret) {
bool *can_retry,
struct sdap_cli_connect_state);
if (can_retry) {
*can_retry = true;
if (can_retry) {
*can_retry = false;
return EINVAL;
return err;
return EIO;
if (gsh) {
if (*gsh) {
if (!*gsh) {
return ENOMEM;
if (srv_opts) {
return EOK;
goto done;
goto done;
goto done;
goto done;
goto done;
done:
return lret;
struct sdap_rebind_proc_params);
return ERR_NETWORK_IO;
if (p->use_start_tls) {
return ret;
return LDAP_NO_MEMORY;
goto done;
&password);
goto done;
goto done;
done:
return ret;