eval echo 'env['\\\'$$i\\\''] = '\\\'\$$$$i\\\'; \
done > $@
echo "tls_impl = '$(TLS_IMPL)'" >> $@
+ echo "have_sasl = '$(HAVE_SASL)'" >> $@
runenv.py: pyrunenv.vals
echo 'env = {}' > $@
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 */
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)
#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"
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;
#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. */
{
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;
* 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;
}
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)
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,
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);