From: Greg Hudson Date: Mon, 16 Jun 2014 16:41:03 +0000 (-0400) Subject: Add SASL support to LDAP KDB module X-Git-Tag: krb5-1.13-alpha1~47 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e94082d8c923cff454c1bc53b377ba394a3cec3c;p=thirdparty%2Fkrb5.git 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 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 . ticket: 7944 (new) --- diff --git a/src/Makefile.in b/src/Makefile.in index 522f21d44f..60a17d913f 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 002c2f7a56..c7cff814c6 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 2e22470155..659c4f8c79 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 38846eb518..d9cb5a4b27 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 319c7017d4..3e98b53147 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 78ea428056..16ac60be3d 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 +#ifdef HAVE_SASL_SASL_H +#include +#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 6c1ac5d3b9..4a29aa5b5a 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);