From cbe8cbd9ebecdd4aec8830748dadb3721f6cdd70 Mon Sep 17 00:00:00 2001 From: Stephen Gallagher Date: Tue, 20 Dec 2011 16:13:59 -0500 Subject: Add compatibility layer for Heimdal Kerberos implementation --- src/external/krb5.m4 | 10 +++++- src/providers/krb5/krb5_child.c | 10 +++--- src/providers/krb5/krb5_utils.c | 10 +++--- src/providers/ldap/ldap_child.c | 5 +++ src/util/sss_krb5.c | 70 ++++++++++++++++++++++++++++++++++------- src/util/sss_krb5.h | 15 +++++++++ 6 files changed, 99 insertions(+), 21 deletions(-) diff --git a/src/external/krb5.m4 b/src/external/krb5.m4 index 40d632ce5..a8707c6e1 100644 --- a/src/external/krb5.m4 +++ b/src/external/krb5.m4 @@ -37,13 +37,21 @@ SAVE_LIBS=$LIBS CFLAGS="$CFLAGS $KRB5_CFLAGS" LIBS="$LIBS $KRB5_LIBS" AC_CHECK_HEADERS([krb5.h krb5/krb5.h]) +AC_CHECK_TYPES([krb5_ticket_times, krb5_times], [], [], + [[#include ]]) AC_CHECK_FUNCS([krb5_get_init_creds_opt_alloc krb5_get_error_message \ krb5_free_unparsed_name \ krb5_get_init_creds_opt_set_expire_callback \ krb5_get_init_creds_opt_set_fast_ccache_name \ krb5_get_init_creds_opt_set_fast_flags \ krb5_get_init_creds_opt_set_canonicalize \ - krb5_unparse_name_flags]) + krb5_unparse_name_flags \ + krb5_get_init_creds_opt_set_change_password_prompt \ + krb5_free_keytab_entry_contents \ + krb5_kt_free_entry \ + krb5_princ_realm \ + krb5_get_time_offsets \ + krb5_principal_get_realm]) CFLAGS=$SAVE_CFLAGS LIBS=$SAVE_LIBS diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c index 297e3a763..c83179b4b 100644 --- a/src/providers/krb5/krb5_child.c +++ b/src/providers/krb5/krb5_child.c @@ -530,7 +530,7 @@ static krb5_error_code validate_tgt(struct krb5_req *kr) break; } - kerr = krb5_free_keytab_entry_contents(kr->ctx, &entry); + kerr = sss_krb5_free_keytab_entry_contents(kr->ctx, &entry); if (kerr != 0) { DEBUG(1, ("Failed to free keytab entry.\n")); } @@ -578,7 +578,7 @@ done: if (krb5_kt_close(kr->ctx, keytab) != 0) { DEBUG(1, ("krb5_kt_close failed")); } - if (krb5_free_keytab_entry_contents(kr->ctx, &entry) != 0) { + if (sss_krb5_free_keytab_entry_contents(kr->ctx, &entry) != 0) { DEBUG(1, ("Failed to free keytab entry.\n")); } if (principal != NULL) { @@ -1194,7 +1194,7 @@ static int krb5_cleanup(void *ptr) static krb5_error_code get_tgt_times(krb5_context ctx, const char *ccname, krb5_principal server_principal, krb5_principal client_principal, - krb5_ticket_times *tgtt) + sss_krb5_ticket_times *tgtt) { krb5_error_code krberr; krb5_ccache ccache = NULL; @@ -1247,7 +1247,7 @@ static krb5_error_code check_fast_ccache(krb5_context ctx, const char *primary, krb5_error_code kerr; char *ccname; char *server_name; - krb5_ticket_times tgtt; + sss_krb5_ticket_times tgtt; krb5_keytab keytab = NULL; krb5_principal client_princ = NULL; krb5_principal server_princ = NULL; @@ -1420,6 +1420,7 @@ static int krb5_child_setup(struct krb5_req *kr, uint32_t offline) goto failed; } +#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_CHANGE_PASSWORD_PROMPT /* A prompter is used to catch messages about when a password will * expired. The library shall not use the prompter to ask for a new password * but shall return KRB5KDC_ERR_KEY_EXP. */ @@ -1428,6 +1429,7 @@ static int krb5_child_setup(struct krb5_req *kr, uint32_t offline) KRB5_DEBUG(1, kerr); goto failed; } +#endif lifetime_str = getenv(SSSD_KRB5_RENEWABLE_LIFETIME); if (lifetime_str == NULL) { diff --git a/src/providers/krb5/krb5_utils.c b/src/providers/krb5/krb5_utils.c index 2957598cc..c97d58e7c 100644 --- a/src/providers/krb5/krb5_utils.c +++ b/src/providers/krb5/krb5_utils.c @@ -431,6 +431,8 @@ errno_t get_ccache_file_data(const char *ccache_file, const char *client_name, char *server_name; krb5_creds mcred; krb5_creds cred; + const char *realm_name; + int realm_length; kerr = krb5_init_context(&ctx); if (kerr != 0) { @@ -444,11 +446,11 @@ errno_t get_ccache_file_data(const char *ccache_file, const char *client_name, goto done; } + sss_krb5_princ_realm(ctx, client_princ, &realm_name, &realm_length); + server_name = talloc_asprintf(NULL, "krbtgt/%.*s@%.*s", - krb5_princ_realm(ctx, client_princ)->length, - krb5_princ_realm(ctx, client_princ)->data, - krb5_princ_realm(ctx, client_princ)->length, - krb5_princ_realm(ctx, client_princ)->data); + realm_length, realm_name, + realm_length, realm_name); if (server_name == NULL) { kerr = KRB5_CC_NOMEM; DEBUG(1, ("talloc_asprintf failed.\n")); diff --git a/src/providers/ldap/ldap_child.c b/src/providers/ldap/ldap_child.c index 160cc1ce4..05aadde90 100644 --- a/src/providers/ldap/ldap_child.c +++ b/src/providers/ldap/ldap_child.c @@ -287,6 +287,7 @@ static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx, goto done; } +#ifdef HAVE_KRB5_GET_TIME_OFFSETS krberr = krb5_get_time_offsets(context, &kdc_time_offset, &kdc_time_offset_usec); if (krberr) { DEBUG(2, ("Failed to get KDC time offset: %s\n", @@ -297,6 +298,10 @@ static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx, kdc_time_offset++; } } +#else + /* If we don't have this function, just assume no offset */ + kdc_time_offset = 0; +#endif krberr = 0; *ccname_out = ccname; diff --git a/src/util/sss_krb5.c b/src/util/sss_krb5.c index 3311ef542..fe76afc52 100644 --- a/src/util/sss_krb5.c +++ b/src/util/sss_krb5.c @@ -44,6 +44,8 @@ errno_t select_principal_from_keytab(TALLOC_CTX *mem_ctx, int i = 0; errno_t ret; char *principal_string; + const char *realm_name; + int realm_len; /** * Priority of lookup: @@ -164,9 +166,11 @@ errno_t select_principal_from_keytab(TALLOC_CTX *mem_ctx, } if (_realm) { + sss_krb5_princ_realm(krb_ctx, client_princ, + &realm_name, + &realm_len); *_realm = talloc_asprintf(mem_ctx, "%.*s", - krb5_princ_realm(ctx, client_princ)->length, - krb5_princ_realm(ctx, client_princ)->data); + realm_len, realm_name); if (!*_realm) { DEBUG(1, ("talloc_asprintf failed")); if (_principal) talloc_zfree(*_principal); @@ -322,7 +326,7 @@ int sss_krb5_verify_keytab_ex(const char *principal, const char *keytab_name, found = true; } free(kt_principal); - krberr = krb5_free_keytab_entry_contents(context, &entry); + krberr = sss_krb5_free_keytab_entry_contents(context, &entry); if (krberr) { /* This should never happen. The API docs for this function * specify only success for this function @@ -378,18 +382,19 @@ static bool match_principal(krb5_context ctx, const char *pattern_primary, const char *pattern_realm) { - krb5_data *realm_data; char *primary = NULL; char *primary_str = NULL; int primary_str_len = 0; int tmp_len; int len_diff; + const char *realm_name; + int realm_len; int mode = MODE_NORMAL; TALLOC_CTX *tmp_ctx; bool ret = false; - realm_data = krb5_princ_realm(ctx, principal); + sss_krb5_princ_realm(ctx, principal, &realm_name, &realm_len); tmp_ctx = talloc_new(NULL); if (!tmp_ctx) { @@ -425,8 +430,8 @@ static bool match_principal(krb5_context ctx, } } - if (!pattern_realm || (realm_data->length == strlen(pattern_realm) && - strncmp(realm_data->data, pattern_realm, realm_data->length) == 0)) { + if (!pattern_realm || (realm_len == strlen(pattern_realm) && + strncmp(realm_name, pattern_realm, realm_len) == 0)) { DEBUG(7, ("Principal matched to the sample (%s@%s).\n", pattern_primary, pattern_realm)); ret = true; @@ -466,7 +471,7 @@ krb5_error_code find_principal_in_keytab(krb5_context ctx, break; } - kerr = krb5_free_keytab_entry_contents(ctx, &entry); + kerr = sss_krb5_free_keytab_entry_contents(ctx, &entry); if (kerr != 0) { DEBUG(1, ("Failed to free keytab entry.\n")); } @@ -504,7 +509,7 @@ krb5_error_code find_principal_in_keytab(krb5_context ctx, kerr = 0; done: - kerr_d = krb5_free_keytab_entry_contents(ctx, &entry); + kerr_d = sss_krb5_free_keytab_entry_contents(ctx, &entry); if (kerr_d != 0) { DEBUG(1, ("Failed to free keytab entry.\n")); } @@ -917,9 +922,50 @@ cleanup: void sss_krb5_get_init_creds_opt_set_canonicalize(krb5_get_init_creds_opt *opts, int canonicalize) { -#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_CANONICALIZE - return krb5_get_init_creds_opt_set_canonicalize(opts, canonicalize); + /* FIXME: The extra check for HAVE_KRB5_TICKET_TIMES is a workaround due to Heimdal + * defining krb5_get_init_creds_opt_set_canonicalize() with a different set of + * arguments. We should use a better configure check in the future. + */ +#if defined(HAVE_KRB5_GET_INIT_CREDS_OPT_SET_CANONICALIZE) && defined(HAVE_KRB5_TICKET_TIMES) + krb5_get_init_creds_opt_set_canonicalize(opts, canonicalize); #else - DEBUG(SSSDBG_OP_FAILURE, ("Kerberos principal canonicalization is not avaliable!\n")); + DEBUG(SSSDBG_OP_FAILURE, ("Kerberos principal canonicalization is not available!\n")); #endif } + +#ifdef HAVE_KRB5_PRINCIPAL_GET_REALM +void sss_krb5_princ_realm(krb5_context context, krb5_const_principal princ, + const char **realm, int *len) +{ + *realm = krb5_principal_get_realm(context, princ); + *len = strlen(*realm); +} +#else +void sss_krb5_princ_realm(krb5_context context, krb5_const_principal princ, + const char **realm, int *len) +{ + const krb5_data *data; + + data = krb5_princ_realm(context, princ); + if (data) { + *realm = data->data; + *len = data->length; + } +} +#endif + +#ifdef HAVE_KRB5_FREE_KEYTAB_ENTRY_CONTENTS +krb5_error_code +sss_krb5_free_keytab_entry_contents(krb5_context context, + krb5_keytab_entry *entry) +{ + return krb5_free_keytab_entry_contents(context, entry); +} +#else +krb5_error_code +sss_krb5_free_keytab_entry_contents(krb5_context context, + krb5_keytab_entry *entry) +{ + return krb5_kt_free_entry(context, entry); +} +#endif diff --git a/src/util/sss_krb5.h b/src/util/sss_krb5.h index 039b79af0..52e6c5d48 100644 --- a/src/util/sss_krb5.h +++ b/src/util/sss_krb5.h @@ -115,4 +115,19 @@ sss_krb5_unparse_name_flags(krb5_context context, krb5_const_principal principal void sss_krb5_get_init_creds_opt_set_canonicalize(krb5_get_init_creds_opt *opts, int canonicalize); +/* === Compatibility routines for the Heimdal Kerberos implementation === */ + +void sss_krb5_princ_realm(krb5_context context, krb5_const_principal princ, + const char **realm, int *len); + +krb5_error_code +sss_krb5_free_keytab_entry_contents(krb5_context context, + krb5_keytab_entry *entry); + +#ifdef HAVE_KRB5_TICKET_TIMES +typedef krb5_ticket_times sss_krb5_ticket_times; +#elif HAVE_KRB5_TIMES +typedef krb5_times sss_krb5_ticket_times; +#endif + #endif /* __SSS_KRB5_H__ */ -- cgit