From 0e5482c791b9d99a44ca62323aa4dedbbf8d188e Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 20 Apr 2011 12:03:48 +1000 Subject: libcli/auth: Move more kerberos wrapping in common These functions are required to get the krb5 PAC parsing and verfication in common. Andrew Bartlett --- libcli/auth/krb5_wrap.c | 207 +++++++++++++++++++++++++++++++++++++++++- libcli/auth/krb5_wrap.h | 24 +++++ source3/libsmb/clikrb5.c | 228 ----------------------------------------------- 3 files changed, 230 insertions(+), 229 deletions(-) diff --git a/libcli/auth/krb5_wrap.c b/libcli/auth/krb5_wrap.c index 0a466fdd4e..c69e3946c6 100644 --- a/libcli/auth/krb5_wrap.c +++ b/libcli/auth/krb5_wrap.c @@ -3,7 +3,7 @@ simple kerberos5 routines for active directory Copyright (C) Andrew Tridgell 2001 Copyright (C) Luke Howard 2002-2003 - Copyright (C) Andrew Bartlett 2005 + Copyright (C) Andrew Bartlett 2005-2011 Copyright (C) Guenther Deschner 2005-2009 This program is free software; you can redistribute it and/or modify @@ -24,6 +24,7 @@ #ifdef HAVE_KRB5 #include "libcli/auth/krb5_wrap.h" +#include "librpc/gen_ndr/krb5pac.h" #if defined(HAVE_KRB5_PRINCIPAL2SALT) && defined(HAVE_KRB5_USE_ENCTYPE) && defined(HAVE_KRB5_STRING_TO_KEY) && defined(HAVE_KRB5_ENCRYPT_BLOCK) int create_kerberos_key_from_string_direct(krb5_context context, @@ -102,6 +103,210 @@ int create_kerberos_key_from_string_direct(krb5_context context, #endif } +/************************************************************** + Wrappers around kerberos string functions that convert from + utf8 -> unix charset and vica versa. +**************************************************************/ + +/************************************************************** + krb5_parse_name that takes a UNIX charset. +**************************************************************/ + + krb5_error_code smb_krb5_parse_name(krb5_context context, + const char *name, /* in unix charset */ + krb5_principal *principal) +{ + krb5_error_code ret; + char *utf8_name; + size_t converted_size; + + if (!push_utf8_talloc(talloc_tos(), &utf8_name, name, &converted_size)) { + return ENOMEM; + } + + ret = krb5_parse_name(context, utf8_name, principal); + TALLOC_FREE(utf8_name); + return ret; +} + +#if !defined(HAVE_KRB5_FREE_UNPARSED_NAME) +static void krb5_free_unparsed_name(krb5_context context, char *val) +{ + SAFE_FREE(val); +} +#endif + +/************************************************************** + krb5_parse_name that returns a UNIX charset name. Must + be freed with talloc_free() call. +**************************************************************/ + +krb5_error_code smb_krb5_unparse_name(TALLOC_CTX *mem_ctx, + krb5_context context, + krb5_const_principal principal, + char **unix_name) +{ + krb5_error_code ret; + char *utf8_name; + size_t converted_size; + + *unix_name = NULL; + ret = krb5_unparse_name(context, principal, &utf8_name); + if (ret) { + return ret; + } + + if (!pull_utf8_talloc(mem_ctx, unix_name, utf8_name, &converted_size)) { + krb5_free_unparsed_name(context, utf8_name); + return ENOMEM; + } + krb5_free_unparsed_name(context, utf8_name); + return 0; +} + + krb5_error_code smb_krb5_parse_name_norealm(krb5_context context, + const char *name, + krb5_principal *principal) +{ +#ifdef HAVE_KRB5_PARSE_NAME_NOREALM + return smb_krb5_parse_name_norealm_conv(context, name, principal); +#endif + + /* we are cheating here because parse_name will in fact set the realm. + * We don't care as the only caller of smb_krb5_parse_name_norealm + * ignores the realm anyway when calling + * smb_krb5_principal_compare_any_realm later - Guenther */ + + return smb_krb5_parse_name(context, name, principal); +} + + bool smb_krb5_principal_compare_any_realm(krb5_context context, + krb5_const_principal princ1, + krb5_const_principal princ2) +{ +#ifdef HAVE_KRB5_PRINCIPAL_COMPARE_ANY_REALM + + return krb5_principal_compare_any_realm(context, princ1, princ2); + +/* krb5_princ_size is a macro in MIT */ +#elif defined(HAVE_KRB5_PRINC_SIZE) || defined(krb5_princ_size) + + int i, len1, len2; + const krb5_data *p1, *p2; + + len1 = krb5_princ_size(context, princ1); + len2 = krb5_princ_size(context, princ2); + + if (len1 != len2) + return False; + + for (i = 0; i < len1; i++) { + + p1 = krb5_princ_component(context, CONST_DISCARD(krb5_principal, princ1), i); + p2 = krb5_princ_component(context, CONST_DISCARD(krb5_principal, princ2), i); + + if (p1->length != p2->length || memcmp(p1->data, p2->data, p1->length)) + return False; + } + + return True; +#else +#error NO_SUITABLE_PRINCIPAL_COMPARE_FUNCTION +#endif +} + + void smb_krb5_checksum_from_pac_sig(krb5_checksum *cksum, + struct PAC_SIGNATURE_DATA *sig) +{ +#ifdef HAVE_CHECKSUM_IN_KRB5_CHECKSUM + cksum->cksumtype = (krb5_cksumtype)sig->type; + cksum->checksum.length = sig->signature.length; + cksum->checksum.data = sig->signature.data; +#else + cksum->checksum_type = (krb5_cksumtype)sig->type; + cksum->length = sig->signature.length; + cksum->contents = sig->signature.data; +#endif +} + + krb5_error_code smb_krb5_verify_checksum(krb5_context context, + const krb5_keyblock *keyblock, + krb5_keyusage usage, + krb5_checksum *cksum, + uint8_t *data, + size_t length) +{ + krb5_error_code ret; + + /* verify the checksum */ + + /* welcome to the wonderful world of samba's kerberos abstraction layer: + * + * function heimdal 0.6.1rc3 heimdal 0.7 MIT krb 1.4.2 + * ----------------------------------------------------------------------------- + * krb5_c_verify_checksum - works works + * krb5_verify_checksum works (6 args) works (6 args) broken (7 args) + */ + +#if defined(HAVE_KRB5_C_VERIFY_CHECKSUM) + { + krb5_boolean checksum_valid = false; + krb5_data input; + + input.data = (char *)data; + input.length = length; + + ret = krb5_c_verify_checksum(context, + keyblock, + usage, + &input, + cksum, + &checksum_valid); + if (ret) { + DEBUG(3,("smb_krb5_verify_checksum: krb5_c_verify_checksum() failed: %s\n", + error_message(ret))); + return ret; + } + + if (!checksum_valid) + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + } + +#elif KRB5_VERIFY_CHECKSUM_ARGS == 6 && defined(HAVE_KRB5_CRYPTO_INIT) && defined(HAVE_KRB5_CRYPTO) && defined(HAVE_KRB5_CRYPTO_DESTROY) + + /* Warning: MIT's krb5_verify_checksum cannot be used as it will use a key + * without enctype and it ignores any key_usage types - Guenther */ + + { + + krb5_crypto crypto; + ret = krb5_crypto_init(context, + keyblock, + 0, + &crypto); + if (ret) { + DEBUG(0,("smb_krb5_verify_checksum: krb5_crypto_init() failed: %s\n", + error_message(ret))); + return ret; + } + + ret = krb5_verify_checksum(context, + crypto, + usage, + data, + length, + cksum); + + krb5_crypto_destroy(context, crypto); + } + +#else +#error UNKNOWN_KRB5_VERIFY_CHECKSUM_FUNCTION +#endif + + return ret; +} + char *smb_get_krb5_error_message(krb5_context context, krb5_error_code code, TALLOC_CTX *mem_ctx) { char *ret; diff --git a/libcli/auth/krb5_wrap.h b/libcli/auth/krb5_wrap.h index e608efe58c..3cdcedc971 100644 --- a/libcli/auth/krb5_wrap.h +++ b/libcli/auth/krb5_wrap.h @@ -21,6 +21,8 @@ */ #include "system/kerberos.h" +struct PAC_SIGNATURE_DATA; +struct PAC_DATA; int create_kerberos_key_from_string_direct(krb5_context context, krb5_principal host_princ, @@ -30,3 +32,25 @@ int create_kerberos_key_from_string_direct(krb5_context context, void kerberos_free_data_contents(krb5_context context, krb5_data *pdata); krb5_error_code smb_krb5_kt_free_entry(krb5_context context, krb5_keytab_entry *kt_entry); char *smb_get_krb5_error_message(krb5_context context, krb5_error_code code, TALLOC_CTX *mem_ctx); + + krb5_error_code smb_krb5_parse_name(krb5_context context, + const char *name, /* in unix charset */ + krb5_principal *principal); +krb5_error_code smb_krb5_unparse_name(TALLOC_CTX *mem_ctx, + krb5_context context, + krb5_const_principal principal, + char **unix_name); + krb5_error_code smb_krb5_parse_name_norealm(krb5_context context, + const char *name, + krb5_principal *principal); + bool smb_krb5_principal_compare_any_realm(krb5_context context, + krb5_const_principal princ1, + krb5_const_principal princ2); + void smb_krb5_checksum_from_pac_sig(krb5_checksum *cksum, + struct PAC_SIGNATURE_DATA *sig); + krb5_error_code smb_krb5_verify_checksum(krb5_context context, + const krb5_keyblock *keyblock, + krb5_keyusage usage, + krb5_checksum *cksum, + uint8_t *data, + size_t length); diff --git a/source3/libsmb/clikrb5.c b/source3/libsmb/clikrb5.c index b341ff4be6..a872d2df61 100644 --- a/source3/libsmb/clikrb5.c +++ b/source3/libsmb/clikrb5.c @@ -50,84 +50,6 @@ krb5_error_code krb5_auth_con_set_req_cksumtype( krb5_cksumtype cksumtype); #endif -/************************************************************** - Wrappers around kerberos string functions that convert from - utf8 -> unix charset and vica versa. -**************************************************************/ - -/************************************************************** - krb5_parse_name that takes a UNIX charset. -**************************************************************/ - - krb5_error_code smb_krb5_parse_name(krb5_context context, - const char *name, /* in unix charset */ - krb5_principal *principal) -{ - krb5_error_code ret; - char *utf8_name; - size_t converted_size; - - if (!push_utf8_talloc(talloc_tos(), &utf8_name, name, &converted_size)) { - return ENOMEM; - } - - ret = krb5_parse_name(context, utf8_name, principal); - TALLOC_FREE(utf8_name); - return ret; -} - -#ifdef HAVE_KRB5_PARSE_NAME_NOREALM -/************************************************************** - krb5_parse_name_norealm that takes a UNIX charset. -**************************************************************/ - -static krb5_error_code smb_krb5_parse_name_norealm_conv(krb5_context context, - const char *name, /* in unix charset */ - krb5_principal *principal) -{ - krb5_error_code ret; - char *utf8_name; - size_t converted_size; - - *principal = NULL; - if (!push_utf8_talloc(talloc_tos(), &utf8_name, name, &converted_size)) { - return ENOMEM; - } - - ret = krb5_parse_name_norealm(context, utf8_name, principal); - TALLOC_FREE(utf8_name); - return ret; -} -#endif - -/************************************************************** - krb5_parse_name that returns a UNIX charset name. Must - be freed with talloc_free() call. -**************************************************************/ - -krb5_error_code smb_krb5_unparse_name(TALLOC_CTX *mem_ctx, - krb5_context context, - krb5_const_principal principal, - char **unix_name) -{ - krb5_error_code ret; - char *utf8_name; - size_t converted_size; - - *unix_name = NULL; - ret = krb5_unparse_name(context, principal, &utf8_name); - if (ret) { - return ret; - } - - if (!pull_utf8_talloc(mem_ctx, unix_name, utf8_name, &converted_size)) { - krb5_free_unparsed_name(context, utf8_name); - return ENOMEM; - } - krb5_free_unparsed_name(context, utf8_name); - return 0; -} - #ifndef HAVE_KRB5_SET_REAL_TIME /* * This function is not in the Heimdal mainline. @@ -530,13 +452,6 @@ bool unwrap_pac(TALLOC_CTX *mem_ctx, DATA_BLOB *auth_data, DATA_BLOB *unwrapped_ #endif /* HAVE_KRB5_LOCATE_KDC */ -#if !defined(HAVE_KRB5_FREE_UNPARSED_NAME) - void krb5_free_unparsed_name(krb5_context context, char *val) -{ - SAFE_FREE(val); -} -#endif - void kerberos_set_creds_enctype(krb5_creds *pcreds, int enctype) { #if defined(HAVE_KRB5_KEYBLOCK_IN_CREDS) @@ -1010,98 +925,6 @@ done: } #endif - void smb_krb5_checksum_from_pac_sig(krb5_checksum *cksum, - struct PAC_SIGNATURE_DATA *sig) -{ -#ifdef HAVE_CHECKSUM_IN_KRB5_CHECKSUM - cksum->cksumtype = (krb5_cksumtype)sig->type; - cksum->checksum.length = sig->signature.length; - cksum->checksum.data = sig->signature.data; -#else - cksum->checksum_type = (krb5_cksumtype)sig->type; - cksum->length = sig->signature.length; - cksum->contents = sig->signature.data; -#endif -} - - krb5_error_code smb_krb5_verify_checksum(krb5_context context, - const krb5_keyblock *keyblock, - krb5_keyusage usage, - krb5_checksum *cksum, - uint8 *data, - size_t length) -{ - krb5_error_code ret; - - /* verify the checksum */ - - /* welcome to the wonderful world of samba's kerberos abstraction layer: - * - * function heimdal 0.6.1rc3 heimdal 0.7 MIT krb 1.4.2 - * ----------------------------------------------------------------------------- - * krb5_c_verify_checksum - works works - * krb5_verify_checksum works (6 args) works (6 args) broken (7 args) - */ - -#if defined(HAVE_KRB5_C_VERIFY_CHECKSUM) - { - krb5_boolean checksum_valid = False; - krb5_data input; - - input.data = (char *)data; - input.length = length; - - ret = krb5_c_verify_checksum(context, - keyblock, - usage, - &input, - cksum, - &checksum_valid); - if (ret) { - DEBUG(3,("smb_krb5_verify_checksum: krb5_c_verify_checksum() failed: %s\n", - error_message(ret))); - return ret; - } - - if (!checksum_valid) - ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; - } - -#elif KRB5_VERIFY_CHECKSUM_ARGS == 6 && defined(HAVE_KRB5_CRYPTO_INIT) && defined(HAVE_KRB5_CRYPTO) && defined(HAVE_KRB5_CRYPTO_DESTROY) - - /* Warning: MIT's krb5_verify_checksum cannot be used as it will use a key - * without enctype and it ignores any key_usage types - Guenther */ - - { - - krb5_crypto crypto; - ret = krb5_crypto_init(context, - keyblock, - 0, - &crypto); - if (ret) { - DEBUG(0,("smb_krb5_verify_checksum: krb5_crypto_init() failed: %s\n", - error_message(ret))); - return ret; - } - - ret = krb5_verify_checksum(context, - crypto, - usage, - data, - length, - cksum); - - krb5_crypto_destroy(context, crypto); - } - -#else -#error UNKNOWN_KRB5_VERIFY_CHECKSUM_FUNCTION -#endif - - return ret; -} - time_t get_authtime_from_tkt(krb5_ticket *tkt) { #if defined(HAVE_KRB5_TKT_ENC_PART2) @@ -1276,57 +1099,6 @@ out: return ret; } - krb5_error_code smb_krb5_parse_name_norealm(krb5_context context, - const char *name, - krb5_principal *principal) -{ -#ifdef HAVE_KRB5_PARSE_NAME_NOREALM - return smb_krb5_parse_name_norealm_conv(context, name, principal); -#endif - - /* we are cheating here because parse_name will in fact set the realm. - * We don't care as the only caller of smb_krb5_parse_name_norealm - * ignores the realm anyway when calling - * smb_krb5_principal_compare_any_realm later - Guenther */ - - return smb_krb5_parse_name(context, name, principal); -} - - bool smb_krb5_principal_compare_any_realm(krb5_context context, - krb5_const_principal princ1, - krb5_const_principal princ2) -{ -#ifdef HAVE_KRB5_PRINCIPAL_COMPARE_ANY_REALM - - return krb5_principal_compare_any_realm(context, princ1, princ2); - -/* krb5_princ_size is a macro in MIT */ -#elif defined(HAVE_KRB5_PRINC_SIZE) || defined(krb5_princ_size) - - int i, len1, len2; - const krb5_data *p1, *p2; - - len1 = krb5_princ_size(context, princ1); - len2 = krb5_princ_size(context, princ2); - - if (len1 != len2) - return False; - - for (i = 0; i < len1; i++) { - - p1 = krb5_princ_component(context, CONST_DISCARD(krb5_principal, princ1), i); - p2 = krb5_princ_component(context, CONST_DISCARD(krb5_principal, princ2), i); - - if (p1->length != p2->length || memcmp(p1->data, p2->data, p1->length)) - return False; - } - - return True; -#else -#error NO_SUITABLE_PRINCIPAL_COMPARE_FUNCTION -#endif -} - krb5_error_code smb_krb5_renew_ticket(const char *ccache_string, /* FILE:/tmp/krb5cc_0 */ const char *client_string, /* gd@BER.SUSE.DE */ const char *service_string, /* krbtgt/BER.SUSE.DE@BER.SUSE.DE */ -- cgit