summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--server/man/sssd-ldap.5.xml79
-rw-r--r--server/providers/ldap/ldap_auth.c3
-rw-r--r--server/providers/ldap/ldap_id.c132
-rw-r--r--server/providers/ldap/sdap.c9
-rw-r--r--server/providers/ldap/sdap.h6
-rw-r--r--server/providers/ldap/sdap_async.c387
-rw-r--r--server/providers/ldap/sdap_async.h10
7 files changed, 567 insertions, 59 deletions
diff --git a/server/man/sssd-ldap.5.xml b/server/man/sssd-ldap.5.xml
index b5efb11d0..7a86c7a3c 100644
--- a/server/man/sssd-ldap.5.xml
+++ b/server/man/sssd-ldap.5.xml
@@ -485,6 +485,85 @@
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>ldap_id_use_start_tls (boolean)</term>
+ <listitem>
+ <para>
+ Specifies that the id_provider connection must also
+ use tls to protect the channel.
+ </para>
+ <para>
+ Default: false
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>ldap_sasl_mech (string)</term>
+ <listitem>
+ <para>
+ Specify the sasl mechanism to use.
+ Currently only GSSAPI is tested and supported.
+ </para>
+ <para>
+ Default: none
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>ldap_sasl_authid (string)</term>
+ <listitem>
+ <para>
+ Specify the sasl authorization id to use.
+ When GSSAPI is used, this represents the kerberos
+ principal used for authentication to the directory.
+ </para>
+ <para>
+ Default: host/machine.fqdn@REALM
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>ldap_krb5_keytab (string)</term>
+ <listitem>
+ <para>
+ Specify keytab to use when using SASL/GSSAPI.
+ </para>
+ <para>
+ Default: System keytab, normally /etc/krb5.keytab
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>ldap_krb5_init_creds (boolean)</term>
+ <listitem>
+ <para>
+ Specifies that the id_provider should init
+ kerberos credentials (TGT).
+ This action is perfromed only if SASL is used and
+ the mechanism selected is GSSAPI.
+ </para>
+ <para>
+ Default: true
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>krb5_realm (string)</term>
+ <listitem>
+ <para>
+ Specify the kerberos REALM (for SASL/GSSAPI auth).
+ </para>
+ <para>
+ Default: System defaults, see /etc/krb5.conf
+ </para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
</para>
</refsect1>
diff --git a/server/providers/ldap/ldap_auth.c b/server/providers/ldap/ldap_auth.c
index 430ac216b..b1667c4bf 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 12fb476b0..271eaea11 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 07e48c18c..cc435ce00 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 8a932d3d4..cb98668ca 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 165117483..471cff6d4 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 08b84d8b6..b79960a50 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);