From 2f4e8fbdf1d4ba1e00fcab93af91fe4f4f40250d Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Tue, 20 Jul 2010 18:35:50 +0200 Subject: Validate keytab at startup In addition to validating the keytab everytime a TGT is requested, we also validate the keytab on back end startup to give early warning that the keytab is not usable. Fixes: #556 --- src/providers/ldap/ldap_child.c | 51 +---------- src/providers/ldap/sdap_child_helpers.c | 16 ++++ src/util/sss_krb5.c | 153 ++++++++++++++++++++++++++++++++ src/util/sss_krb5.h | 9 ++ 4 files changed, 181 insertions(+), 48 deletions(-) diff --git a/src/providers/ldap/ldap_child.c b/src/providers/ldap/ldap_child.c index 17c26855e..f51040a7f 100644 --- a/src/providers/ldap/ldap_child.c +++ b/src/providers/ldap/ldap_child.c @@ -143,10 +143,6 @@ static int ldap_child_get_tgt_sync(TALLOC_CTX *memctx, krb5_error_code krberr; krb5_timestamp kdc_time_offset; int kdc_time_offset_usec; - krb5_kt_cursor cursor; - krb5_keytab_entry entry; - char *principal; - bool found; int ret; krberr = krb5_init_context(&context); @@ -227,50 +223,9 @@ static int ldap_child_get_tgt_sync(TALLOC_CTX *memctx, } /* Verify the keytab */ - krberr = krb5_kt_start_seq_get(context, keytab, &cursor); - if (krberr) { - DEBUG(0, ("Cannot read keytab [%s].\n", keytab_name)); - - sss_log(SSS_LOG_ERR, "Error reading keytab file [%s]: [%d][%s]. " - "Unable to create GSSAPI-encrypted LDAP connection.", - keytab_name, krberr, - sss_krb5_get_error_message(context, krberr)); - - ret = EFAULT; - goto done; - } - - found = false; - while((ret = krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0){ - krb5_unparse_name(context, entry.principal, &principal); - if (strcmp(full_princ, principal) == 0) { - found = true; - } - free(principal); - krb5_free_keytab_entry_contents(context, &entry); - - if (found) { - break; - } - } - krberr = krb5_kt_end_seq_get(context, keytab, &cursor); - if (krberr) { - DEBUG(0, ("Could not close keytab.\n")); - sss_log(SSS_LOG_ERR, "Could not close keytab file [%s].", - keytab_name); - ret = EFAULT; - goto done; - } - - if (!found) { - DEBUG(0, ("Principal [%s] not found in keytab [%s]\n", - full_princ, keytab_name)); - sss_log(SSS_LOG_ERR, "Error processing keytab file [%s]: " - "Principal [%s] was not found. " - "Unable to create GSSAPI-encrypted LDAP connection.", - keytab_name, full_princ); - - ret = EFAULT; + ret = sss_krb5_verify_keytab_ex(full_princ, keytab_name, context, keytab); + if (ret) { + DEBUG(2, ("Unable to verify principal is present in the keytab\n")); goto done; } diff --git a/src/providers/ldap/sdap_child_helpers.c b/src/providers/ldap/sdap_child_helpers.c index 58b757efd..1b1224859 100644 --- a/src/providers/ldap/sdap_child_helpers.c +++ b/src/providers/ldap/sdap_child_helpers.c @@ -29,6 +29,7 @@ #include #include "util/util.h" +#include "util/sss_krb5.h" #include "providers/ldap/ldap_common.h" #include "providers/ldap/sdap_async_private.h" #include "providers/child_common.h" @@ -455,6 +456,21 @@ int setup_child(struct sdap_id_ctx *ctx) return EOK; } + if (mech && (strcasecmp(mech, "GSSAPI") == 0)) { + ret = sss_krb5_verify_keytab(dp_opt_get_string(ctx->opts->basic, + SDAP_SASL_AUTHID), + dp_opt_get_string(ctx->opts->basic, + SDAP_KRB5_REALM), + dp_opt_get_string(ctx->opts->basic, + SDAP_KRB5_KEYTAB)); + + if (ret != EOK) { + DEBUG(0, ("Could not verify keytab\n")) + return ret; + } + + } + if (debug_to_file != 0 && ldap_child_debug_fd == -1) { ret = open_debug_file_ex("ldap_child", &debug_filep); if (ret != EOK) { diff --git a/src/util/sss_krb5.c b/src/util/sss_krb5.c index 0bc25df17..bbb62f11a 100644 --- a/src/util/sss_krb5.c +++ b/src/util/sss_krb5.c @@ -26,7 +26,160 @@ #include "util/util.h" #include "util/sss_krb5.h" +int sss_krb5_verify_keytab(const char *principal, + const char *realm_str, + const char *keytab_name) +{ + krb5_context context = NULL; + krb5_keytab keytab = NULL; + krb5_error_code krberr; + int ret; + char *full_princ = NULL; + char *realm_name = NULL; + char *default_realm = NULL; + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) { + return ENOMEM; + } + + krberr = krb5_init_context(&context); + if (krberr) { + DEBUG(2, ("Failed to init kerberos context\n")); + 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(0, ("Failed to read keytab file: %s\n", + sss_krb5_get_error_message(context, krberr))); + ret = EFAULT; + goto done; + } + + if (!realm_str) { + krberr = krb5_get_default_realm(context, &default_realm); + if (krberr) { + DEBUG(2, ("Failed to get default realm name: %s\n", + sss_krb5_get_error_message(context, krberr))); + ret = EFAULT; + goto done; + } + + realm_name = talloc_strdup(tmp_ctx, default_realm); + krb5_free_default_realm(context, default_realm); + if (!realm_name) { + ret = ENOMEM; + goto done; + } + } else { + realm_name = talloc_strdup(tmp_ctx, realm_str); + if (!realm_name) { + ret = ENOMEM; + goto done; + } + } + if (principal) { + if (!strchr(principal, '@')) { + full_princ = talloc_asprintf(tmp_ctx, "%s@%s", + principal, realm_name); + } else { + full_princ = talloc_strdup(tmp_ctx, principal); + } + } else { + char hostname[512]; + + ret = gethostname(hostname, 511); + if (ret == -1) { + ret = errno; + goto done; + } + hostname[511] = '\0'; + + full_princ = talloc_asprintf(tmp_ctx, "host/%s@%s", + hostname, realm_name); + } + if (!full_princ) { + ret = ENOMEM; + goto done; + } + DEBUG(4, ("Principal name is: [%s]\n", full_princ)); + + ret = sss_krb5_verify_keytab_ex(full_princ, keytab_name, context, keytab); + if (ret) goto done; + + ret = EOK; +done: + if (keytab) krb5_kt_close(context, keytab); + if (context) krb5_free_context(context); + talloc_free(tmp_ctx); + return ret; +} + +int sss_krb5_verify_keytab_ex(const char *principal, const char *keytab_name, + krb5_context context, krb5_keytab keytab) +{ + bool found; + char *kt_principal; + krb5_error_code krberr; + krb5_kt_cursor cursor; + krb5_keytab_entry entry; + + krberr = krb5_kt_start_seq_get(context, keytab, &cursor); + if (krberr) { + DEBUG(0, ("Cannot read keytab [%s].\n", keytab_name)); + + sss_log(SSS_LOG_ERR, "Error reading keytab file [%s]: [%d][%s]. " + "Unable to create GSSAPI-encrypted LDAP connection.", + keytab_name, krberr, + sss_krb5_get_error_message(context, krberr)); + + return EIO; + } + + found = false; + while((krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0){ + krb5_unparse_name(context, entry.principal, &kt_principal); + if (strcmp(principal, kt_principal) == 0) { + found = true; + } + free(kt_principal); + krb5_free_keytab_entry_contents(context, &entry); + + if (found) { + break; + } + } + + krberr = krb5_kt_end_seq_get(context, keytab, &cursor); + if (krberr) { + DEBUG(0, ("Could not close keytab.\n")); + sss_log(SSS_LOG_ERR, "Could not close keytab file [%s].", + keytab_name); + return EIO; + } + + if (!found) { + DEBUG(0, ("Principal [%s] not found in keytab [%s]\n", + principal, keytab_name ? keytab_name : "default")); + sss_log(SSS_LOG_ERR, "Error processing keytab file [%s]: " + "Principal [%s] was not found. " + "Unable to create GSSAPI-encrypted LDAP connection.", + keytab_name, principal); + + return EFAULT; + } + + return EOK; +} const char *KRB5_CALLCONV sss_krb5_get_error_message(krb5_context ctx, krb5_error_code ec) diff --git a/src/util/sss_krb5.h b/src/util/sss_krb5.h index 60994e123..bc7a4f8a2 100644 --- a/src/util/sss_krb5.h +++ b/src/util/sss_krb5.h @@ -24,6 +24,7 @@ #include "config.h" #include +#include #ifdef HAVE_KRB5_KRB5_H #include @@ -47,4 +48,12 @@ void KRB5_CALLCONV sss_krb5_free_unparsed_name(krb5_context context, char *name) krb5_error_code check_for_valid_tgt(const char *ccname, const char *realm, const char *client_princ_str, bool *result); + +int sss_krb5_verify_keytab(const char *principal, + const char *realm_str, + const char *keytab_name); + +int sss_krb5_verify_keytab_ex(const char *principal, const char *keytab_name, + krb5_context context, krb5_keytab keytab); + #endif /* __SSS_KRB5_H__ */ -- cgit