krb5 commit: Add SASL support to LDAP KDB module
Greg Hudson
ghudson at MIT.EDU
Sat Jul 19 16:39:25 EDT 2014
https://github.com/krb5/krb5/commit/e94082d8c923cff454c1bc53b377ba394a3cec3c
commit e94082d8c923cff454c1bc53b377ba394a3cec3c
Author: Greg Hudson <ghudson at mit.edu>
Date: Mon Jun 16 12:41:03 2014 -0400
Add SASL support to LDAP KDB module
Add variables for the SASL mechanism, authcid, authzid, and realm. If
a SASL mechanism is set, perform an interactive bind with that
mechanism. If <sasl/sasl.h> is found at build time, provide the
authcid, authzid, and realm in the interaction function, and provide a
SASL secret read from the service password file (under the authcid) if
we found one.
Based on a patch from Zoran Pericic <zpericic at netst.org>.
ticket: 7944 (new)
src/Makefile.in | 1 +
src/config/pre.in | 3 +
src/configure.in | 6 ++
src/include/k5-int.h | 8 ++
src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h | 4 +
src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap_conn.c | 87 +++++++++++++++++++---
src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c | 68 +++++++++++++++++
7 files changed, 167 insertions(+), 10 deletions(-)
diff --git a/src/Makefile.in b/src/Makefile.in
index 522f21d..60a17d9 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -555,6 +555,7 @@ pyrunenv.vals: Makefile
eval echo 'env['\\\'$$i\\\''] = '\\\'\$$$$i\\\'; \
done > $@
echo "tls_impl = '$(TLS_IMPL)'" >> $@
+ echo "have_sasl = '$(HAVE_SASL)'" >> $@
runenv.py: pyrunenv.vals
echo 'env = {}' > $@
diff --git a/src/config/pre.in b/src/config/pre.in
index 002c2f7..c7cff81 100644
--- a/src/config/pre.in
+++ b/src/config/pre.in
@@ -434,6 +434,9 @@ TLS_IMPL = @TLS_IMPL@
TLS_IMPL_CFLAGS = @TLS_IMPL_CFLAGS@
TLS_IMPL_LIBS = @TLS_IMPL_LIBS@
+# Whether we have the SASL header file for the LDAP KDB module
+HAVE_SASL = @HAVE_SASL@
+
# error table rules
#
### /* these are invoked as $(...) foo.et, which works, but could be better */
diff --git a/src/configure.in b/src/configure.in
index 2e22470..659c4f8 100644
--- a/src/configure.in
+++ b/src/configure.in
@@ -1171,6 +1171,12 @@ if test -n "$OPENLDAP_PLUGIN"; then
AC_DEFINE([ENABLE_LDAP], 1, [Define if LDAP KDB support within the Kerberos library (mainly ASN.1 code) should be enabled.])
AC_SUBST(LDAP_LIBS)
+ AC_CHECK_HEADERS([sasl/sasl.h], [HAVE_SASL=yes], [HAVE_SASL=no])
+ AC_SUBST(HAVE_SASL)
+ if test "$HAVE_SASL" = no; then
+ AC_MSG_WARN([not building LDAP SASL support])
+ fi
+
K5_GEN_MAKEFILE(plugins/kdb/ldap)
K5_GEN_MAKEFILE(plugins/kdb/ldap/ldap_util)
K5_GEN_MAKEFILE(plugins/kdb/ldap/libkdb_ldap)
diff --git a/src/include/k5-int.h b/src/include/k5-int.h
index 38846eb..d9cb5a4 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -239,7 +239,15 @@ typedef unsigned char u_char;
#define KRB5_CONF_KRB524_SERVER "krb524_server"
#define KRB5_CONF_LDAP_CONNS_PER_SERVER "ldap_conns_per_server"
#define KRB5_CONF_LDAP_KADMIND_DN "ldap_kadmind_dn"
+#define KRB5_CONF_LDAP_KADMIND_SASL_AUTHCID "ldap_kadmind_sasl_authcid"
+#define KRB5_CONF_LDAP_KADMIND_SASL_AUTHZID "ldap_kadmind_sasl_authzid"
+#define KRB5_CONF_LDAP_KADMIND_SASL_MECH "ldap_kadmind_sasl_mech"
+#define KRB5_CONF_LDAP_KADMIND_SASL_REALM "ldap_kadmind_sasl_realm"
#define KRB5_CONF_LDAP_KDC_DN "ldap_kdc_dn"
+#define KRB5_CONF_LDAP_KDC_SASL_AUTHCID "ldap_kdc_sasl_authcid"
+#define KRB5_CONF_LDAP_KDC_SASL_AUTHZID "ldap_kdc_sasl_authzid"
+#define KRB5_CONF_LDAP_KDC_SASL_MECH "ldap_kdc_sasl_mech"
+#define KRB5_CONF_LDAP_KDC_SASL_REALM "ldap_kdc_sasl_realm"
#define KRB5_CONF_LDAP_KERBEROS_CONTAINER_DN "ldap_kerberos_container_dn"
#define KRB5_CONF_LDAP_SERVERS "ldap_servers"
#define KRB5_CONF_LDAP_SERVICE_PASSWORD_FILE "ldap_service_password_file"
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h b/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h
index 319c701..3e98b53 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h
+++ b/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h
@@ -199,6 +199,10 @@ typedef struct _krb5_ldap_context {
char *bind_dn;
char *bind_pwd;
char *service_password_file;
+ char *sasl_mech;
+ char *sasl_authcid;
+ char *sasl_authzid;
+ char *sasl_realm;
char *root_certificate_file;
krb5_ui_4 cert_count; /* certificate count */
k5_mutex_t hndl_lock;
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap_conn.c b/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap_conn.c
index 78ea428..16ac60b 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap_conn.c
+++ b/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap_conn.c
@@ -36,6 +36,9 @@
#include "ldap_main.h"
#include "ldap_service_stash.h"
#include <kdb5.h>
+#ifdef HAVE_SASL_SASL_H
+#include <sasl/sasl.h>
+#endif
/* Ensure that we have the parameters we need to authenticate to the LDAP
* server. Read the password if necessary. */
@@ -44,6 +47,19 @@ validate_context(krb5_context context, krb5_ldap_context *ctx)
{
krb5_error_code ret;
+ if (ctx->sasl_mech != NULL) {
+ /* Read the password for use as the SASL secret if we can, but do not
+ * require one as not all mechanisms need it. */
+ if (ctx->bind_pwd == NULL && ctx->sasl_authcid != NULL &&
+ ctx->service_password_file != NULL) {
+ (void)krb5_ldap_readpassword(context, ctx->service_password_file,
+ ctx->sasl_authcid, &ctx->bind_pwd);
+ }
+ return 0;
+ }
+
+ /* For a simple bind, a DN and password are required. */
+
if (ctx->bind_dn == NULL) {
k5_setmsg(context, EINVAL, _("LDAP bind dn value missing"));
return EINVAL;
@@ -77,22 +93,73 @@ validate_context(krb5_context context, krb5_ldap_context *ctx)
* Internal Functions called by init functions.
*/
+#ifdef HAVE_SASL_SASL_H
+
+static int
+interact(LDAP *ld, unsigned flags, void *defaults, void *sin)
+{
+ sasl_interact_t *in = NULL;
+ krb5_ldap_context *ctx = defaults;
+
+ for (in = sin; in != NULL && in->id != SASL_CB_LIST_END; in++) {
+ if (in->id == SASL_CB_AUTHNAME)
+ in->result = ctx->sasl_authcid;
+ else if (in->id == SASL_CB_USER)
+ in->result = ctx->sasl_authzid;
+ else if (in->id == SASL_CB_GETREALM)
+ in->result = ctx->sasl_realm;
+ else if (in->id == SASL_CB_PASS)
+ in->result = ctx->bind_pwd;
+ else
+ return LDAP_OTHER;
+ in->len = (in->result != NULL) ? strlen(in->result) : 0;
+ }
+
+ return LDAP_SUCCESS;
+}
+
+#else /* HAVE_SASL_SASL_H */
+
+/* We can't define an interaction function, so only non-interactive mechs like
+ * EXTERNAL can work. */
+static int
+interact(LDAP *ld, unsigned flags, void *defaults, void *sin)
+{
+ return LDAP_OTHER;
+}
+
+#endif
+
static krb5_error_code
authenticate(krb5_ldap_context *ctx, krb5_ldap_server_handle *server)
{
int st;
struct berval bv;
- bv.bv_val = ctx->bind_pwd;
- bv.bv_len = strlen(ctx->bind_pwd);
- st = ldap_sasl_bind_s(server->ldap_handle, ctx->bind_dn, NULL, &bv, NULL,
- NULL, NULL);
- if (st != LDAP_SUCCESS) {
- k5_setmsg(ctx->kcontext, KRB5_KDB_ACCESS_ERROR,
- _("Cannot bind to LDAP server '%s' as '%s': %s"),
- server->server_info->server_name, ctx->bind_dn,
- ldap_err2string(st));
- return KRB5_KDB_ACCESS_ERROR;
+ if (ctx->sasl_mech != NULL) {
+ st = ldap_sasl_interactive_bind_s(server->ldap_handle, NULL,
+ ctx->sasl_mech, NULL, NULL,
+ LDAP_SASL_QUIET, interact, ctx);
+ if (st != LDAP_SUCCESS) {
+ k5_setmsg(ctx->kcontext, KRB5_KDB_ACCESS_ERROR,
+ _("Cannot bind to LDAP server '%s' with SASL mechanism "
+ "'%s': %s"), server->server_info->server_name,
+ ctx->sasl_mech, ldap_err2string(st));
+ return KRB5_KDB_ACCESS_ERROR;
+ }
+ } else {
+ /* Do a simple bind with DN and password. */
+ bv.bv_val = ctx->bind_pwd;
+ bv.bv_len = strlen(ctx->bind_pwd);
+ st = ldap_sasl_bind_s(server->ldap_handle, ctx->bind_dn, NULL, &bv,
+ NULL, NULL, NULL);
+ if (st != LDAP_SUCCESS) {
+ k5_setmsg(ctx->kcontext, KRB5_KDB_ACCESS_ERROR,
+ _("Cannot bind to LDAP server '%s' as '%s': %s"),
+ server->server_info->server_name, ctx->bind_dn,
+ ldap_err2string(st));
+ return KRB5_KDB_ACCESS_ERROR;
+ }
}
return 0;
}
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c
index 6c1ac5d..4a29aa5 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c
+++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c
@@ -243,6 +243,34 @@ krb5_ldap_parse_db_params(krb5_context context, char **db_args)
ret = ENOMEM;
goto cleanup;
}
+ } else if (!strcmp(opt, "sasl_mech")) {
+ free(ctx->sasl_mech);
+ ctx->sasl_mech = strdup(val);
+ if (ctx->sasl_mech == NULL) {
+ ret = ENOMEM;
+ goto cleanup;
+ }
+ } else if (!strcmp(opt, "sasl_authcid")) {
+ free(ctx->sasl_authcid);
+ ctx->sasl_authcid = strdup(val);
+ if (ctx->sasl_authcid == NULL) {
+ ret = ENOMEM;
+ goto cleanup;
+ }
+ } else if (!strcmp(opt, "sasl_authzid")) {
+ free(ctx->sasl_authzid);
+ ctx->sasl_authzid = strdup(val);
+ if (ctx->sasl_authzid == NULL) {
+ ret = ENOMEM;
+ goto cleanup;
+ }
+ } else if (!strcmp(opt, "sasl_realm")) {
+ free(ctx->sasl_realm);
+ ctx->sasl_realm = strdup(val);
+ if (ctx->sasl_realm == NULL) {
+ ret = ENOMEM;
+ goto cleanup;
+ }
} else if (!strcmp(opt, "host")) {
ret = add_server_entry(context, val);
if (ret)
@@ -334,6 +362,42 @@ krb5_ldap_read_server_params(krb5_context context, char *conf_section,
return ret;
}
+ if (ldap_context->sasl_mech == NULL) {
+ name = choose_var(srv_type, KRB5_CONF_LDAP_KDC_SASL_MECH,
+ KRB5_CONF_LDAP_KADMIND_SASL_MECH);
+ ret = prof_get_string_def(context, conf_section, name,
+ &ldap_context->sasl_mech);
+ if (ret)
+ return ret;
+ }
+
+ if (ldap_context->sasl_authcid == NULL) {
+ name = choose_var(srv_type, KRB5_CONF_LDAP_KDC_SASL_AUTHCID,
+ KRB5_CONF_LDAP_KADMIND_SASL_AUTHCID);
+ ret = prof_get_string_def(context, conf_section, name,
+ &ldap_context->sasl_authcid);
+ if (ret)
+ return ret;
+ }
+
+ if (ldap_context->sasl_authzid == NULL) {
+ name = choose_var(srv_type, KRB5_CONF_LDAP_KDC_SASL_AUTHZID,
+ KRB5_CONF_LDAP_KADMIND_SASL_AUTHZID);
+ ret = prof_get_string_def(context, conf_section, name,
+ &ldap_context->sasl_authzid);
+ if (ret)
+ return ret;
+ }
+
+ if (ldap_context->sasl_realm == NULL) {
+ name = choose_var(srv_type, KRB5_CONF_LDAP_KDC_SASL_REALM,
+ KRB5_CONF_LDAP_KADMIND_SASL_REALM);
+ ret = prof_get_string_def(context, conf_section, name,
+ &ldap_context->sasl_realm);
+ if (ret)
+ return ret;
+ }
+
/* Read the LDAP server URL list. */
if (ldap_context->server_info_list == NULL) {
ret = profile_get_string(context->profile, KDB_MODULE_SECTION,
@@ -394,6 +458,10 @@ krb5_ldap_free_server_context_params(krb5_ldap_context *ctx)
free(list);
ctx->server_info_list = NULL;
+ free(ctx->sasl_mech);
+ free(ctx->sasl_authcid);
+ free(ctx->sasl_authzid);
+ free(ctx->sasl_realm);
free(ctx->conf_section);
free(ctx->bind_dn);
zapfreestr(ctx->bind_pwd);
More information about the cvs-krb5
mailing list