diff options
Diffstat (limited to 'server/providers/ldap')
-rw-r--r-- | server/providers/ldap/ldap_auth.c | 3 | ||||
-rw-r--r-- | server/providers/ldap/ldap_id.c | 132 | ||||
-rw-r--r-- | server/providers/ldap/sdap.c | 9 | ||||
-rw-r--r-- | server/providers/ldap/sdap.h | 6 | ||||
-rw-r--r-- | server/providers/ldap/sdap_async.c | 387 | ||||
-rw-r--r-- | server/providers/ldap/sdap_async.h | 10 |
6 files changed, 488 insertions, 59 deletions
diff --git a/server/providers/ldap/ldap_auth.c b/server/providers/ldap/ldap_auth.c index 430ac216..b1667c4b 100644 --- a/server/providers/ldap/ldap_auth.c +++ b/server/providers/ldap/ldap_auth.c @@ -257,7 +257,8 @@ static void auth_get_user_dn_done(struct tevent_req *subreq) } subreq = sdap_auth_send(state, state->ev, state->sh, - state->dn, "password", state->password); + NULL, NULL, state->dn, + "password", state->password); if (!subreq) { tevent_req_error(req, ENOMEM); return; diff --git a/server/providers/ldap/ldap_id.c b/server/providers/ldap/ldap_id.c index 12fb476b..271eaea1 100644 --- a/server/providers/ldap/ldap_id.c +++ b/server/providers/ldap/ldap_id.c @@ -95,24 +95,17 @@ static bool connected(struct sdap_id_ctx *ctx) struct sdap_id_connect_state { struct tevent_context *ev; struct sdap_id_ctx *ctx; - bool use_start_tls; - char *defaultBindDn; - char *defaultAuthtokType; - struct sdap_blob defaultAuthtok; struct sdap_handle *sh; }; static void sdap_id_connect_done(struct tevent_req *subreq); +static void sdap_id_kinit_done(struct tevent_req *subreq); static void sdap_id_bind_done(struct tevent_req *subreq); static struct tevent_req *sdap_id_connect_send(TALLOC_CTX *memctx, struct tevent_context *ev, - struct sdap_id_ctx *ctx, - bool use_start_tls, - char *defaultBindDn, - char *defaultAuthtokType, - struct sdap_blob defaultAuthtok) + struct sdap_id_ctx *ctx) { struct tevent_req *req, *subreq; struct sdap_id_connect_state *state; @@ -122,12 +115,9 @@ static struct tevent_req *sdap_id_connect_send(TALLOC_CTX *memctx, state->ev = ev; state->ctx = ctx; - state->use_start_tls = use_start_tls; - state->defaultBindDn = defaultBindDn; - state->defaultAuthtokType = defaultAuthtokType; - state->defaultAuthtok = defaultAuthtok; - subreq = sdap_connect_send(state, ev, ctx->opts, use_start_tls); + subreq = sdap_connect_send(state, ev, ctx->opts, + sdap_go_get_bool(ctx->opts->basic, SDAP_ID_TLS)); if (!subreq) { talloc_zfree(req); return NULL; @@ -143,6 +133,7 @@ static void sdap_id_connect_done(struct tevent_req *subreq) struct tevent_req); struct sdap_id_connect_state *state = tevent_req_data(req, struct sdap_id_connect_state); + const char *sasl_mech; int ret; ret = sdap_connect_recv(subreq, state, &state->sh); @@ -152,14 +143,81 @@ static void sdap_id_connect_done(struct tevent_req *subreq) return; } - /* TODO: use authentication (SASL/GSSAPI) when necessary */ - subreq = sdap_auth_send(state, state->ev, state->sh, state->defaultBindDn, - state->defaultAuthtokType, state->defaultAuthtok); + sasl_mech = sdap_go_get_string(state->ctx->opts->basic, SDAP_SASL_MECH); + if (sasl_mech && (strcasecmp(sasl_mech, "GSSAPI") == 0)) { + if (sdap_go_get_bool(state->ctx->opts->basic, SDAP_KRB5_KINIT)) { + subreq = sdap_kinit_send(state, state->ev, state->sh, + sdap_go_get_string(state->ctx->opts->basic, + SDAP_KRB5_KEYTAB), + sdap_go_get_string(state->ctx->opts->basic, + SDAP_SASL_AUTHID), + sdap_go_get_string(state->ctx->opts->basic, + SDAP_KRB5_REALM)); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sdap_id_kinit_done, req); + return; + } + } + + subreq = sdap_auth_send(state, + state->ev, + state->sh, + sasl_mech, + sdap_go_get_string(state->ctx->opts->basic, + SDAP_SASL_AUTHID), + sdap_go_get_string(state->ctx->opts->basic, + SDAP_DEFAULT_BIND_DN), + sdap_go_get_string(state->ctx->opts->basic, + SDAP_DEFAULT_AUTHTOK_TYPE), + sdap_go_get_blob(state->ctx->opts->basic, + SDAP_DEFAULT_AUTHTOK)); if (!subreq) { tevent_req_error(req, ENOMEM); return; } + tevent_req_set_callback(subreq, sdap_id_bind_done, req); +} + +static void sdap_id_kinit_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sdap_id_connect_state *state = tevent_req_data(req, + struct sdap_id_connect_state); + 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; + } + + subreq = sdap_auth_send(state, + state->ev, + state->sh, + sdap_go_get_string(state->ctx->opts->basic, + SDAP_SASL_MECH), + sdap_go_get_string(state->ctx->opts->basic, + SDAP_SASL_AUTHID), + sdap_go_get_string(state->ctx->opts->basic, + SDAP_DEFAULT_BIND_DN), + sdap_go_get_string(state->ctx->opts->basic, + SDAP_DEFAULT_AUTHTOK_TYPE), + sdap_go_get_blob(state->ctx->opts->basic, + SDAP_DEFAULT_AUTHTOK)); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } tevent_req_set_callback(subreq, sdap_id_bind_done, req); } @@ -267,13 +325,7 @@ static struct tevent_req *users_get_send(TALLOC_CTX *memctx, /* FIXME: add option to decide if tls should be used * or SASL/GSSAPI, etc ... */ - subreq = sdap_id_connect_send(state, ev, ctx, false, - sdap_go_get_string(ctx->opts->basic, - SDAP_DEFAULT_BIND_DN), - sdap_go_get_string(ctx->opts->basic, - SDAP_DEFAULT_AUTHTOK_TYPE), - sdap_go_get_blob(ctx->opts->basic, - SDAP_DEFAULT_AUTHTOK)); + subreq = sdap_id_connect_send(state, ev, ctx); if (!subreq) { ret = ENOMEM; goto fail; @@ -436,13 +488,7 @@ static struct tevent_req *groups_get_send(TALLOC_CTX *memctx, /* FIXME: add option to decide if tls should be used * or SASL/GSSAPI, etc ... */ - subreq = sdap_id_connect_send(state, ev, ctx, false, - sdap_go_get_string(ctx->opts->basic, - SDAP_DEFAULT_BIND_DN), - sdap_go_get_string(ctx->opts->basic, - SDAP_DEFAULT_AUTHTOK_TYPE), - sdap_go_get_blob(ctx->opts->basic, - SDAP_DEFAULT_AUTHTOK)); + subreq = sdap_id_connect_send(state, ev, ctx); if (!subreq) { ret = ENOMEM; goto fail; @@ -579,13 +625,7 @@ static struct tevent_req *groups_by_user_send(TALLOC_CTX *memctx, /* FIXME: add option to decide if tls should be used * or SASL/GSSAPI, etc ... */ - subreq = sdap_id_connect_send(state, ev, ctx, false, - sdap_go_get_string(ctx->opts->basic, - SDAP_DEFAULT_BIND_DN), - sdap_go_get_string(ctx->opts->basic, - SDAP_DEFAULT_AUTHTOK_TYPE), - sdap_go_get_blob(ctx->opts->basic, - SDAP_DEFAULT_AUTHTOK)); + subreq = sdap_id_connect_send(state, ev, ctx); if (!subreq) { ret = ENOMEM; goto fail; @@ -1039,13 +1079,7 @@ static struct tevent_req *enum_users_send(TALLOC_CTX *memctx, /* FIXME: add option to decide if tls should be used * or SASL/GSSAPI, etc ... */ - subreq = sdap_id_connect_send(state, ev, ctx, false, - sdap_go_get_string(ctx->opts->basic, - SDAP_DEFAULT_BIND_DN), - sdap_go_get_string(ctx->opts->basic, - SDAP_DEFAULT_AUTHTOK_TYPE), - sdap_go_get_blob(ctx->opts->basic, - SDAP_DEFAULT_AUTHTOK)); + subreq = sdap_id_connect_send(state, ev, ctx); if (!subreq) { ret = ENOMEM; goto fail; @@ -1192,13 +1226,7 @@ static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx, /* FIXME: add option to decide if tls should be used * or SASL/GSSAPI, etc ... */ - subreq = sdap_id_connect_send(state, ev, ctx, false, - sdap_go_get_string(ctx->opts->basic, - SDAP_DEFAULT_BIND_DN), - sdap_go_get_string(ctx->opts->basic, - SDAP_DEFAULT_AUTHTOK_TYPE), - sdap_go_get_blob(ctx->opts->basic, - SDAP_DEFAULT_AUTHTOK)); + subreq = sdap_id_connect_send(state, ev, ctx); if (!subreq) { ret = ENOMEM; goto fail; diff --git a/server/providers/ldap/sdap.c b/server/providers/ldap/sdap.c index 07e48c18..cc435ce0 100644 --- a/server/providers/ldap/sdap.c +++ b/server/providers/ldap/sdap.c @@ -51,7 +51,14 @@ struct sdap_gen_opts default_basic_opts[] = { { "ldap_enumeration_refresh_timeout", SDAP_NUMBER, { .number = 300 }, NULL_NUMBER }, { "ldap_stale_time", SDAP_NUMBER, { .number = 1800 }, NULL_NUMBER }, { "ldap_tls_cacert", SDAP_STRING, NULL_STRING, NULL_STRING }, - { "ldap_tls_cacertdir", SDAP_STRING, NULL_STRING, NULL_STRING } + { "ldap_tls_cacertdir", SDAP_STRING, NULL_STRING, NULL_STRING }, + { "ldap_id_use_start_tls", SDAP_BOOL, BOOL_FALSE, BOOL_FALSE }, + { "ldap_sasl_mech", SDAP_STRING, NULL_STRING, NULL_STRING }, + { "ldap_sasl_authid", SDAP_STRING, NULL_STRING, NULL_STRING }, + { "ldap_krb5_keytab", SDAP_STRING, NULL_STRING, NULL_STRING }, + { "ldap_krb5_init_creds", SDAP_BOOL, BOOL_TRUE, BOOL_TRUE }, + /* use the same parm name as the krb5 module so we set it only once */ + { "krb5_realm", SDAP_STRING, NULL_STRING, NULL_STRING } }; struct sdap_id_map rfc2307_user_map[] = { diff --git a/server/providers/ldap/sdap.h b/server/providers/ldap/sdap.h index 8a932d3d..cb98668c 100644 --- a/server/providers/ldap/sdap.h +++ b/server/providers/ldap/sdap.h @@ -90,6 +90,12 @@ enum sdap_basic_opt { SDAP_STALE_TIME, SDAP_TLS_CACERT, SDAP_TLS_CACERTDIR, + SDAP_ID_TLS, + SDAP_SASL_MECH, + SDAP_SASL_AUTHID, + SDAP_KRB5_KEYTAB, + SDAP_KRB5_KINIT, + SDAP_KRB5_REALM, SDAP_OPTS_BASIC /* opts counter */ }; diff --git a/server/providers/ldap/sdap_async.c b/server/providers/ldap/sdap_async.c index 16511748..471cff6d 100644 --- a/server/providers/ldap/sdap_async.c +++ b/server/providers/ldap/sdap_async.c @@ -19,6 +19,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <ctype.h> +#include <sasl/sasl.h> +#include <krb5/krb5.h> #include "db/sysdb.h" #include "providers/ldap/sdap_async.h" @@ -767,6 +769,362 @@ static int simple_bind_recv(struct tevent_req *req, int *ldaperr) 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; + ret = sdap_install_ldap_callbacks(sh, ev); + if (ret) goto fail; + } + + 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; + + if (tevent_req_is_error(req, &tstate, &err)) { + if (tstate != TEVENT_REQ_IN_PROGRESS) { + *ldaperr = LDAP_OTHER; + if (err) return err; + return EIO; + } + } + + *ldaperr = state->result; + return EOK; +} + +/* ==Perform-Kinit-given-keytab-and-principal============================= */ + +static int sdap_krb5_get_tgt_sync(TALLOC_CTX *memctx, + const char *realm_str, + const char *princ_str, + const char *keytab_name) +{ + char *ccname; + char *realm_name = NULL; + char *full_princ = NULL; + krb5_context context = NULL; + krb5_keytab keytab = NULL; + krb5_ccache ccache = NULL; + krb5_principal kprinc; + krb5_creds my_creds; + krb5_get_init_creds_opt options; + krb5_error_code krberr; + int ret; + + krberr = krb5_init_context(&context); + if (krberr) { + DEBUG(2, ("Failed to init kerberos context\n")); + return EFAULT; + } + + if (!realm_str) { + krberr = krb5_get_default_realm(context, &realm_name); + if (krberr) { + DEBUG(2, ("Failed to get default realm name: %s\n", + krb5_get_error_message(context, krberr))); + ret = EFAULT; + goto done; + } + } else { + realm_name = talloc_strdup(memctx, realm_str); + if (!realm_name) { + ret = ENOMEM; + goto done; + } + } + + if (princ_str) { + if (!strchr(princ_str, '@')) { + full_princ = talloc_asprintf(memctx, "%s@%s", + princ_str, realm_name); + } else { + full_princ = talloc_strdup(memctx, princ_str); + } + } else { + char hostname[512]; + + ret = gethostname(hostname, 511); + if (ret == -1) { + ret = errno; + goto done; + } + hostname[511] = '\0'; + + full_princ = talloc_asprintf(memctx, "host/%s@%s", + hostname, realm_name); + } + if (!full_princ) { + ret = ENOMEM; + goto done; + } + DEBUG(1, ("Principal name is: [%s]\n", full_princ)); + + krberr = krb5_parse_name(context, full_princ, &kprinc); + if (krberr) { + DEBUG(2, ("Unable to build principal: %s\n", + krb5_get_error_message(context, krberr))); + ret = EFAULT; + goto done; + } + + if (keytab_name) { + krberr = krb5_kt_resolve(context, keytab_name, &keytab); + } else { + krberr = krb5_kt_default(context, &keytab); + } + if (krberr) { + DEBUG(2, ("Failed to read keytab file: %s\n", + krb5_get_error_message(context, krberr))); + ret = EFAULT; + goto done; + } + + ccname = talloc_asprintf(memctx, "FILE:%s/ccache_%s", DB_PATH, realm_name); + if (!ccname) { + ret = ENOMEM; + goto done; + } + + ret = setenv("KRB5CCNAME", ccname, 1); + if (ret == -1) { + DEBUG(2, ("Unable to set env. variable KRB5CCNAME!\n")); + ret = EFAULT; + goto done; + } + + krberr = krb5_cc_resolve(context, ccname, &ccache); + if (krberr) { + DEBUG(2, ("Failed to set cache name: %s\n", + krb5_get_error_message(context, krberr))); + ret = EFAULT; + goto done; + } + + memset(&my_creds, 0, sizeof(my_creds)); + memset(&options, 0, sizeof(options)); + + krb5_get_init_creds_opt_set_address_list(&options, NULL); + krb5_get_init_creds_opt_set_forwardable(&options, 0); + krb5_get_init_creds_opt_set_proxiable(&options, 0); + /* set a very short lifetime, we don't keep the ticket around */ + krb5_get_init_creds_opt_set_tkt_life(&options, 300); + + krberr = krb5_get_init_creds_keytab(context, &my_creds, kprinc, + keytab, 0, NULL, &options); + + if (krberr) { + DEBUG(2, ("Failed to init credentials: %s\n", + krb5_get_error_message(context, krberr))); + ret = EFAULT; + goto done; + } + + krberr = krb5_cc_initialize(context, ccache, kprinc); + if (krberr) { + DEBUG(2, ("Failed to init ccache: %s\n", + krb5_get_error_message(context, krberr))); + ret = EFAULT; + goto done; + } + + krberr = krb5_cc_store_cred(context, ccache, &my_creds); + if (krberr) { + DEBUG(2, ("Failed to store creds: %s\n", + krb5_get_error_message(context, krberr))); + ret = EFAULT; + goto done; + } + + ret = EOK; + +done: + if (keytab) krb5_kt_close(context, keytab); + if (context) krb5_free_context(context); + return ret; +} + +struct sdap_kinit_state { + int result; +}; + +/* TODO: make it really async */ +struct tevent_req *sdap_kinit_send(TALLOC_CTX *memctx, + struct tevent_context *ev, + struct sdap_handle *sh, + const char *keytab, + const char *principal, + const char *realm) +{ + struct tevent_req *req; + 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)); + ret = EFAULT; + goto fail; + } + } + + ret = sdap_krb5_get_tgt_sync(state, realm, principal, keytab); + if (ret == EOK) { + state->result = SDAP_AUTH_SUCCESS; + } else { + goto fail; + } + + tevent_req_post(req, ev); + return req; + +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} + +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; + + if (tevent_req_is_error(req, &tstate, &err)) { + if (tstate != TEVENT_REQ_IN_PROGRESS) { + *result = SDAP_ERROR; + if (err) return err; + return EIO; + } + } + + *result = state->result; + return EOK; +} + + /* ==Authenticaticate-User-by-DN========================================== */ struct sdap_auth_state { @@ -774,13 +1132,17 @@ struct sdap_auth_state { 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 sdap_blob authtok) @@ -800,10 +1162,20 @@ struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx, state->pw.bv_val = (char *)authtok.data; state->pw.bv_len = authtok.length; - subreq = simple_bind_send(state, ev, sh, user_dn, &state->pw); - if (!subreq) { - tevent_req_error(req, EFAULT); - return tevent_req_post(req, ev); + 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); @@ -818,11 +1190,16 @@ static void sdap_auth_done(struct tevent_req *subreq) struct sdap_auth_state); int ret; - ret = simple_bind_recv(subreq, &state->result); + 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); } diff --git a/server/providers/ldap/sdap_async.h b/server/providers/ldap/sdap_async.h index 08b84d8b..b79960a5 100644 --- a/server/providers/ldap/sdap_async.h +++ b/server/providers/ldap/sdap_async.h @@ -54,9 +54,19 @@ struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx, int sdap_get_groups_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, char **timestamp); +struct tevent_req *sdap_kinit_send(TALLOC_CTX *memctx, + struct tevent_context *ev, + struct sdap_handle *sh, + const char *keytab, + const char *principal, + const char *realm); +int sdap_kinit_recv(struct tevent_req *req, enum sdap_result *result); + 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 sdap_blob authtok); |