Skip to content

Commit

Permalink
Add SASL support to LDAP KDB module
Browse files Browse the repository at this point in the history
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@netst.org>.

ticket: 7944 (new)
  • Loading branch information
greghudson committed Jul 19, 2014
1 parent 89b3b6b commit e94082d
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 10 deletions.
1 change: 1 addition & 0 deletions src/Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {}' > $@
Expand Down
3 changes: 3 additions & 0 deletions src/config/pre.in
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
6 changes: 6 additions & 0 deletions src/configure.in
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
8 changes: 8 additions & 0 deletions src/include/k5-int.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 4 additions & 0 deletions src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
87 changes: 77 additions & 10 deletions src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap_conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down
68 changes: 68 additions & 0 deletions src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit e94082d

Please sign in to comment.