summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimo Sorce <ssorce@redhat.com>2009-09-25 09:46:30 -0400
committerStephen Gallagher <sgallagh@redhat.com>2009-10-01 08:42:36 -0400
commitbc58f5892d3a8f6b28e2148c5a0cca34b63ef354 (patch)
treee7db3c657227adb86f49abd84ca4fa426e929621
parentd4341d654beb1f6c87d7f70ef0142f23aadac957 (diff)
downloadsssd-bc58f5892d3a8f6b28e2148c5a0cca34b63ef354.tar.gz
sssd-bc58f5892d3a8f6b28e2148c5a0cca34b63ef354.tar.xz
sssd-bc58f5892d3a8f6b28e2148c5a0cca34b63ef354.zip
Initial implementation of sasl bind support
Inits krb5 credentials, if sasl mech is GSSAPI. Tested with GSSAPI and host keytab as well as user credentials. Updates also manpages with the new options.
-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);