From 91adebe749beb0dc23cacaea316cb2b724776aad Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 13 Jun 2007 05:44:24 +0000 Subject: r23456: Update Samba4 to current lorikeet-heimdal. Andrew Bartlett (This used to be commit ae0f81ab235c72cceb120bcdeb051a483cf3cc4f) --- source4/heimdal/kdc/524.c | 2 +- source4/heimdal/kdc/default_config.c | 376 +++++++++++++---------------------- source4/heimdal/kdc/digest.c | 277 +++++++++++++++++++++++--- source4/heimdal/kdc/headers.h | 2 +- source4/heimdal/kdc/kaserver.c | 2 +- source4/heimdal/kdc/kdc-private.h | 11 +- source4/heimdal/kdc/kdc-protos.h | 21 +- source4/heimdal/kdc/kdc.h | 4 +- source4/heimdal/kdc/kdc_locl.h | 17 +- source4/heimdal/kdc/kerberos4.c | 2 +- source4/heimdal/kdc/kerberos5.c | 198 +++++++++++++----- source4/heimdal/kdc/krb5tgs.c | 35 ++-- source4/heimdal/kdc/kx509.c | 196 +++++++++++++----- source4/heimdal/kdc/log.c | 2 +- source4/heimdal/kdc/misc.c | 2 +- source4/heimdal/kdc/pkinit.c | 264 +++++++++++++++++------- source4/heimdal/kdc/process.c | 84 +++++++- source4/heimdal/kdc/rx.h | 2 +- source4/heimdal/kdc/windc.c | 9 +- source4/heimdal/kdc/windc_plugin.h | 6 +- 20 files changed, 1024 insertions(+), 488 deletions(-) (limited to 'source4/heimdal/kdc') diff --git a/source4/heimdal/kdc/524.c b/source4/heimdal/kdc/524.c index 56c12efd60..3e4ad29253 100644 --- a/source4/heimdal/kdc/524.c +++ b/source4/heimdal/kdc/524.c @@ -33,7 +33,7 @@ #include "kdc_locl.h" -RCSID("$Id: 524.c,v 1.40 2006/10/06 17:06:30 lha Exp $"); +RCSID("$Id: 524.c 18270 2006-10-06 17:06:30Z lha $"); #include diff --git a/source4/heimdal/kdc/default_config.c b/source4/heimdal/kdc/default_config.c index 2352020d86..c28bd424ea 100644 --- a/source4/heimdal/kdc/default_config.c +++ b/source4/heimdal/kdc/default_config.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan + * Copyright (c) 1997-2007 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * * All rights reserved. @@ -33,110 +33,61 @@ */ #include "kdc_locl.h" +#include +#include -int require_preauth = -1; /* 1 == require preauth for all principals */ +RCSID("$Id: default_config.c 20532 2007-04-23 07:46:57Z lha $"); -const char *trpolicy_str; -int disable_des = -1; -int enable_v4 = -1; -int enable_kaserver = -1; -int enable_524 = -1; -int enable_v4_cross_realm = -1; -int detach_from_console = -1; - -char *v4_realm; - -/* - * Setup some of the defaults for the KDC configuration. - * - * Note: Caller must also fill in: - * - db - * - num_db - * - logf - * -*/ - -void -krb5_kdc_default_config(krb5_kdc_configuration *config) -{ - memset(config, 0, sizeof(*config)); - config->require_preauth = TRUE; - config->kdc_warn_pwexpire = 0; - config->encode_as_rep_as_tgs_rep = FALSE; /* bug compatibility */ - config->check_ticket_addresses = TRUE; - config->allow_null_ticket_addresses = TRUE; - config->allow_anonymous = FALSE; - config->trpolicy = TRPOLICY_ALWAYS_CHECK; - config->enable_v4 = FALSE; - config->enable_kaserver = FALSE; - config->enable_524 = FALSE; /* overriden by enable_v4 in configure()) */ - config->enable_v4_cross_realm = FALSE; - config->enable_pkinit = FALSE; - config->enable_pkinit_princ_in_cert = TRUE; - config->db = NULL; - config->num_db = 0; - config->logf = NULL; -} - - -/* - * Setup some valudes for the KDC configuration, from the config file - * - * Note: Caller must also fill in: - * - db - * - num_db - * - logf - * -*/ - -void krb5_kdc_configure(krb5_context context, krb5_kdc_configuration *config) +int +krb5_kdc_get_config(krb5_context context, krb5_kdc_configuration **config) { - const char *p; - if(require_preauth == -1) { - config->require_preauth = krb5_config_get_bool_default(context, NULL, - config->require_preauth, - "kdc", - "require-preauth", NULL); - } else { - config->require_preauth = require_preauth; - } + krb5_kdc_configuration *c; - if(enable_v4 == -1) { - config->enable_v4 = krb5_config_get_bool_default(context, NULL, - config->enable_v4, - "kdc", - "enable-kerberos4", - NULL); - } else { - config->enable_v4 = enable_v4; + c = calloc(1, sizeof(*c)); + if (c == NULL) { + krb5_set_error_string(context, "malloc: out of memory"); + return ENOMEM; } - if(enable_v4_cross_realm == -1) { - config->enable_v4_cross_realm = - krb5_config_get_bool_default(context, NULL, - config->enable_v4_cross_realm, - "kdc", - "enable-kerberos4-cross-realm", - NULL); - } else { - config->enable_v4_cross_realm = enable_v4_cross_realm; - } - - if(enable_524 == -1) { - config->enable_524 = krb5_config_get_bool_default(context, NULL, - config->enable_v4, - "kdc", "enable-524", - NULL); - } else { - config->enable_524 = enable_524; - } - - config->enable_digest = + c->require_preauth = TRUE; + c->kdc_warn_pwexpire = 0; + c->encode_as_rep_as_tgs_rep = FALSE; + c->check_ticket_addresses = TRUE; + c->allow_null_ticket_addresses = TRUE; + c->allow_anonymous = FALSE; + c->trpolicy = TRPOLICY_ALWAYS_CHECK; + c->enable_v4 = FALSE; + c->enable_kaserver = FALSE; + c->enable_524 = FALSE; + c->enable_v4_cross_realm = FALSE; + c->enable_pkinit = FALSE; + c->enable_pkinit_princ_in_cert = TRUE; + c->db = NULL; + c->num_db = 0; + c->logf = NULL; + + c->require_preauth = krb5_config_get_bool_default(context, NULL, - FALSE, - "kdc", - "enable-digest", NULL); + c->require_preauth, + "kdc", "require-preauth", NULL); + c->enable_v4 = + krb5_config_get_bool_default(context, NULL, + c->enable_v4, + "kdc", "enable-kerberos4", NULL); + c->enable_v4_cross_realm = + krb5_config_get_bool_default(context, NULL, + c->enable_v4_cross_realm, + "kdc", + "enable-kerberos4-cross-realm", NULL); + c->enable_524 = + krb5_config_get_bool_default(context, NULL, + c->enable_v4, + "kdc", "enable-524", NULL); + c->enable_digest = + krb5_config_get_bool_default(context, NULL, + FALSE, + "kdc", "enable-digest", NULL); { const char *digests; @@ -146,46 +97,57 @@ void krb5_kdc_configure(krb5_context context, krb5_kdc_configuration *config) "digests_allowed", NULL); if (digests == NULL) digests = "ntlm-v2"; - config->digests_allowed = parse_flags(digests, - _kdc_digestunits, - 0); - if (config->digests_allowed == -1) { - kdc_log(context, config, 0, + c->digests_allowed = parse_flags(digests,_kdc_digestunits, 0); + if (c->digests_allowed == -1) { + kdc_log(context, c, 0, "unparsable digest units (%s), turning off digest", digests); - config->enable_digest = 0; - } else if (config->digests_allowed == 0) { - kdc_log(context, config, 0, + c->enable_digest = 0; + } else if (c->digests_allowed == 0) { + kdc_log(context, c, 0, "no digest enable, turning digest off", digests); - config->enable_digest = 0; + c->enable_digest = 0; } } - config->enable_kx509 = + c->enable_kx509 = krb5_config_get_bool_default(context, NULL, FALSE, - "kdc", - "enable-kx509", NULL); + "kdc", "enable-kx509", NULL); + + if (c->enable_kx509) { + c->kx509_template = + krb5_config_get_string(context, NULL, + "kdc", "kx509_template", NULL); + c->kx509_ca = + krb5_config_get_string(context, NULL, + "kdc", "kx509_ca", NULL); + if (c->kx509_ca == NULL || c->kx509_template == NULL) { + kdc_log(context, c, 0, + "missing kx509 configuration, turning off"); + c->enable_kx509 = FALSE; + } + } - config->check_ticket_addresses = + c->check_ticket_addresses = krb5_config_get_bool_default(context, NULL, - config->check_ticket_addresses, + c->check_ticket_addresses, "kdc", "check-ticket-addresses", NULL); - config->allow_null_ticket_addresses = + c->allow_null_ticket_addresses = krb5_config_get_bool_default(context, NULL, - config->allow_null_ticket_addresses, + c->allow_null_ticket_addresses, "kdc", "allow-null-ticket-addresses", NULL); - config->allow_anonymous = + c->allow_anonymous = krb5_config_get_bool_default(context, NULL, - config->allow_anonymous, + c->allow_anonymous, "kdc", "allow-anonymous", NULL); - config->max_datagram_reply_length = + c->max_datagram_reply_length = krb5_config_get_int_default(context, NULL, 1400, @@ -193,178 +155,124 @@ void krb5_kdc_configure(krb5_context context, krb5_kdc_configuration *config) "max-kdc-datagram-reply-length", NULL); - trpolicy_str = - krb5_config_get_string_default(context, NULL, "DEFAULT", "kdc", - "transited-policy", NULL); - if(strcasecmp(trpolicy_str, "always-check") == 0) { - config->trpolicy = TRPOLICY_ALWAYS_CHECK; - } else if(strcasecmp(trpolicy_str, "allow-per-principal") == 0) { - config->trpolicy = TRPOLICY_ALLOW_PER_PRINCIPAL; - } else if(strcasecmp(trpolicy_str, "always-honour-request") == 0) { - config->trpolicy = TRPOLICY_ALWAYS_HONOUR_REQUEST; - } else if(strcasecmp(trpolicy_str, "DEFAULT") == 0) { - /* default */ - } else { - kdc_log(context, config, - 0, "unknown transited-policy: %s, reverting to default (always-check)", - trpolicy_str); + { + const char *trpolicy_str; + + trpolicy_str = + krb5_config_get_string_default(context, NULL, "DEFAULT", "kdc", + "transited-policy", NULL); + if(strcasecmp(trpolicy_str, "always-check") == 0) { + c->trpolicy = TRPOLICY_ALWAYS_CHECK; + } else if(strcasecmp(trpolicy_str, "allow-per-principal") == 0) { + c->trpolicy = TRPOLICY_ALLOW_PER_PRINCIPAL; + } else if(strcasecmp(trpolicy_str, "always-honour-request") == 0) { + c->trpolicy = TRPOLICY_ALWAYS_HONOUR_REQUEST; + } else if(strcasecmp(trpolicy_str, "DEFAULT") == 0) { + /* default */ + } else { + kdc_log(context, c, 0, + "unknown transited-policy: %s, " + "reverting to default (always-check)", + trpolicy_str); + } } - - if (krb5_config_get_string(context, NULL, "kdc", - "enforce-transited-policy", NULL)) - krb5_errx(context, 1, "enforce-transited-policy deprecated, " - "use [kdc]transited-policy instead"); - if(v4_realm == NULL){ + { + const char *p; p = krb5_config_get_string (context, NULL, "kdc", "v4-realm", NULL); if(p != NULL) { - config->v4_realm = strdup(p); - if (config->v4_realm == NULL) + c->v4_realm = strdup(p); + if (c->v4_realm == NULL) krb5_errx(context, 1, "out of memory"); } else { - config->v4_realm = NULL; + c->v4_realm = NULL; } - } else { - config->v4_realm = v4_realm; } - if (enable_kaserver == -1) { - config->enable_kaserver = - krb5_config_get_bool_default(context, - NULL, - config->enable_kaserver, - "kdc", - "enable-kaserver", - NULL); - } else { - config->enable_kaserver = enable_kaserver; - } + c->enable_kaserver = + krb5_config_get_bool_default(context, + NULL, + c->enable_kaserver, + "kdc", "enable-kaserver", NULL); - config->encode_as_rep_as_tgs_rep = + + c->encode_as_rep_as_tgs_rep = krb5_config_get_bool_default(context, NULL, - config->encode_as_rep_as_tgs_rep, + c->encode_as_rep_as_tgs_rep, "kdc", - "encode_as_rep_as_tgs_rep", - NULL); - - config->kdc_warn_pwexpire = + "encode_as_rep_as_tgs_rep", NULL); + + c->kdc_warn_pwexpire = krb5_config_get_time_default (context, NULL, - config->kdc_warn_pwexpire, - "kdc", - "kdc_warn_pwexpire", - NULL); + c->kdc_warn_pwexpire, + "kdc", "kdc_warn_pwexpire", NULL); - if(detach_from_console == -1) - detach_from_console = krb5_config_get_bool_default(context, NULL, - DETACH_IS_DEFAULT, - "kdc", - "detach", NULL); #ifdef PKINIT - config->enable_pkinit = + c->enable_pkinit = krb5_config_get_bool_default(context, NULL, - config->enable_pkinit, + c->enable_pkinit, "kdc", "enable-pkinit", NULL); - if (config->enable_pkinit) { + if (c->enable_pkinit) { const char *user_id, *anchors, *ocsp_file; char **pool_list, **revoke_list; - user_id = krb5_config_get_string(context, NULL, - "kdc", - "pkinit_identity", - NULL); + user_id = + krb5_config_get_string(context, NULL, + "kdc", "pkinit_identity", NULL); if (user_id == NULL) krb5_errx(context, 1, "pkinit enabled but no identity"); anchors = krb5_config_get_string(context, NULL, - "kdc", - "pkinit_anchors", - NULL); + "kdc", "pkinit_anchors", NULL); if (anchors == NULL) krb5_errx(context, 1, "pkinit enabled but no X509 anchors"); - pool_list = krb5_config_get_strings(context, NULL, - "kdc", - "pkinit_pool", - NULL); + pool_list = + krb5_config_get_strings(context, NULL, + "kdc", "pkinit_pool", NULL); - revoke_list = krb5_config_get_strings(context, NULL, - "kdc", - "pkinit_revoke", - NULL); + revoke_list = + krb5_config_get_strings(context, NULL, + "kdc", "pkinit_revoke", NULL); ocsp_file = krb5_config_get_string(context, NULL, - "kdc", - "pkinit_kdc_ocsp", - NULL); + "kdc", "pkinit_kdc_ocsp", NULL); if (ocsp_file) { - config->pkinit_kdc_ocsp_file = strdup(ocsp_file); - if (config->pkinit_kdc_ocsp_file == NULL) + c->pkinit_kdc_ocsp_file = strdup(ocsp_file); + if (c->pkinit_kdc_ocsp_file == NULL) krb5_errx(context, 1, "out of memory"); } - _kdc_pk_initialize(context, config, user_id, anchors, + + _kdc_pk_initialize(context, c, user_id, anchors, pool_list, revoke_list); krb5_config_free_strings(pool_list); krb5_config_free_strings(revoke_list); - config->enable_pkinit_princ_in_cert = - krb5_config_get_bool_default(context, - NULL, - config->enable_pkinit_princ_in_cert, + c->enable_pkinit_princ_in_cert = + krb5_config_get_bool_default(context, NULL, + c->enable_pkinit_princ_in_cert, "kdc", "pkinit_principal_in_certificate", NULL); } - config->pkinit_dh_min_bits = - krb5_config_get_int_default(context, - NULL, + c->pkinit_dh_min_bits = + krb5_config_get_int_default(context, NULL, 0, - "kdc", - "pkinit_dh_min_bits", - NULL); + "kdc", "pkinit_dh_min_bits", NULL); #endif - if(config->v4_realm == NULL && (config->enable_kaserver || config->enable_v4)){ -#ifdef KRB4 - config->v4_realm = malloc(40); /* REALM_SZ */ - if (config->v4_realm == NULL) - krb5_errx(context, 1, "out of memory"); - krb_get_lrealm(config->v4_realm, 1); -#else - krb5_errx(context, 1, "No Kerberos 4 realm configured"); -#endif - } - if(disable_des == -1) - disable_des = krb5_config_get_bool_default(context, NULL, - FALSE, - "kdc", - "disable-des", NULL); - if(disable_des) { - krb5_enctype_disable(context, ETYPE_DES_CBC_CRC); - krb5_enctype_disable(context, ETYPE_DES_CBC_MD4); - krb5_enctype_disable(context, ETYPE_DES_CBC_MD5); - krb5_enctype_disable(context, ETYPE_DES_CBC_NONE); - krb5_enctype_disable(context, ETYPE_DES_CFB64_NONE); - krb5_enctype_disable(context, ETYPE_DES_PCBC_NONE); - - kdc_log(context, config, - 0, "DES was disabled, turned off Kerberos V4, 524 " - "and kaserver"); - config->enable_v4 = 0; - config->enable_524 = 0; - config->enable_kaserver = 0; - } + *config = c; - _kdc_windc_init(context); + return 0; } - diff --git a/source4/heimdal/kdc/digest.c b/source4/heimdal/kdc/digest.c index 2c012a2ead..811ab639f1 100644 --- a/source4/heimdal/kdc/digest.c +++ b/source4/heimdal/kdc/digest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 Kungliga Tekniska Högskolan + * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -34,8 +34,9 @@ #include "kdc_locl.h" #include -RCSID("$Id: digest.c,v 1.19 2006/12/28 17:03:51 lha Exp $"); +RCSID("$Id: digest.c 20877 2007-06-04 04:07:26Z lha $"); +#define MS_CHAP_V2 0x20 #define CHAP_MD5 0x10 #define DIGEST_MD5 0x08 #define NTLM_V2 0x04 @@ -43,6 +44,7 @@ RCSID("$Id: digest.c,v 1.19 2006/12/28 17:03:51 lha Exp $"); #define NTLM_V1 0x01 const struct units _kdc_digestunits[] = { + {"ms-chap-v2", 1U << 5}, {"chap-md5", 1U << 4}, {"digest-md5", 1U << 3}, {"ntlm-v2", 1U << 2}, @@ -135,6 +137,25 @@ fill_targetinfo(krb5_context context, } +static const unsigned char ms_chap_v2_magic1[39] = { + 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, + 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, + 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 +}; +static const unsigned char ms_chap_v2_magic2[41] = { + 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, + 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, + 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, + 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, + 0x6E +}; +static const unsigned char ms_rfc3079_magic1[27] = { + 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d, + 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 +}; + /* * */ @@ -382,11 +403,6 @@ _kdc_do_digest(krb5_context context, goto out; } - ret = krb5_store_stringz(sp, *r.u.initReply.identifier); - if (ret) { - krb5_clear_error_string(context); - goto out; - } } else r.u.initReply.identifier = NULL; @@ -461,13 +477,7 @@ _kdc_do_digest(krb5_context context, } krb5_store_stringz(sp, ireq.u.digestRequest.serverNonce); - if (ireq.u.digestRequest.identifier) { - ret = krb5_store_stringz(sp, *ireq.u.digestRequest.identifier); - if (ret) { - krb5_clear_error_string(context); - goto out; - } - } + if (ireq.u.digestRequest.hostname) { ret = krb5_store_stringz(sp, *ireq.u.digestRequest.hostname); if (ret) { @@ -587,6 +597,7 @@ _kdc_do_digest(krb5_context context, if (strcasecmp(ireq.u.digestRequest.type, "CHAP") == 0) { MD5_CTX ctx; unsigned char md[MD5_DIGEST_LENGTH]; + char *mdx; char id; if ((config->digests_allowed & CHAP_MD5) == 0) { @@ -613,16 +624,30 @@ _kdc_do_digest(krb5_context context, MD5_Update(&ctx, serverNonce.data, serverNonce.length); MD5_Final(md, &ctx); - r.element = choice_DigestRepInner_response; - hex_encode(md, sizeof(md), &r.u.response.responseData); - if (r.u.response.responseData == NULL) { + hex_encode(md, sizeof(md), &mdx); + if (mdx == NULL) { krb5_clear_error_string(context); ret = ENOMEM; goto out; } + + r.element = choice_DigestRepInner_response; + + ret = strcasecmp(mdx, ireq.u.digestRequest.responseData); + free(mdx); + if (ret == 0) { + r.u.response.success = TRUE; + } else { + kdc_log(context, config, 0, + "CHAP reply mismatch for %s", + ireq.u.digestRequest.username); + r.u.response.success = FALSE; + } + } else if (strcasecmp(ireq.u.digestRequest.type, "SASL-DIGEST-MD5") == 0) { MD5_CTX ctx; unsigned char md[MD5_DIGEST_LENGTH]; + char *mdx; char *A1, *A2; if ((config->digests_allowed & DIGEST_MD5) == 0) { @@ -709,21 +734,212 @@ _kdc_do_digest(krb5_context context, MD5_Final(md, &ctx); - r.element = choice_DigestRepInner_response; - hex_encode(md, sizeof(md), &r.u.response.responseData); - free(A1); free(A2); - if (r.u.response.responseData == NULL) { - krb5_set_error_string(context, "out of memory"); + hex_encode(md, sizeof(md), &mdx); + if (mdx == NULL) { + krb5_clear_error_string(context); + ret = ENOMEM; + goto out; + } + + r.element = choice_DigestRepInner_response; + ret = strcasecmp(mdx, ireq.u.digestRequest.responseData); + free(mdx); + if (ret == 0) { + r.u.response.success = TRUE; + } else { + kdc_log(context, config, 0, + "DIGEST-MD5 reply mismatch for %s", + ireq.u.digestRequest.username); + r.u.response.success = FALSE; + } + + } else if (strcasecmp(ireq.u.digestRequest.type, "MS-CHAP-V2") == 0) { + unsigned char md[SHA_DIGEST_LENGTH], challange[SHA_DIGEST_LENGTH]; + char *mdx; + const char *username; + struct ntlm_buf answer; + Key *key = NULL; + SHA_CTX ctx; + + if ((config->digests_allowed & MS_CHAP_V2) == 0) { + kdc_log(context, config, 0, "MS-CHAP-V2 not allowed"); + goto out; + } + + if (ireq.u.digestRequest.clientNonce == NULL) { + krb5_set_error_string(context, + "MS-CHAP-V2 clientNonce missing"); + ret = EINVAL; + goto out; + } + if (serverNonce.length != 16) { + krb5_set_error_string(context, + "MS-CHAP-V2 serverNonce wrong length"); + ret = EINVAL; + goto out; + } + + /* strip of the domain component */ + username = strchr(ireq.u.digestRequest.username, '\\'); + if (username == NULL) + username = ireq.u.digestRequest.username; + else + username++; + + /* ChallangeHash */ + SHA1_Init(&ctx); + { + ssize_t ssize; + krb5_data clientNonce; + + clientNonce.length = strlen(*ireq.u.digestRequest.clientNonce); + clientNonce.data = malloc(clientNonce.length); + if (clientNonce.data == NULL) { + ret = ENOMEM; + krb5_set_error_string(context, "out of memory"); + goto out; + } + + ssize = hex_decode(*ireq.u.digestRequest.clientNonce, + clientNonce.data, clientNonce.length); + if (ssize != 16) { + krb5_set_error_string(context, + "Failed to decode clientNonce"); + ret = ENOMEM; + goto out; + } + SHA1_Update(&ctx, clientNonce.data, ssize); + free(clientNonce.data); + } + SHA1_Update(&ctx, serverNonce.data, serverNonce.length); + SHA1_Update(&ctx, username, strlen(username)); + SHA1_Final(challange, &ctx); + + /* NtPasswordHash */ + ret = krb5_parse_name(context, username, &clientprincipal); + if (ret) + goto out; + + ret = _kdc_db_fetch(context, config, clientprincipal, + HDB_F_GET_CLIENT, NULL, &user); + krb5_free_principal(context, clientprincipal); + if (ret) { + krb5_set_error_string(context, + "MS-CHAP-V2 user %s not in database", + username); + goto out; + } + + ret = hdb_enctype2key(context, &user->entry, + ETYPE_ARCFOUR_HMAC_MD5, &key); + if (ret) { + krb5_set_error_string(context, + "MS-CHAP-V2 missing arcfour key %s", + username); + goto out; + } + + /* ChallengeResponse */ + ret = heim_ntlm_calculate_ntlm1(key->key.keyvalue.data, + key->key.keyvalue.length, + challange, &answer); + if (ret) { + krb5_set_error_string(context, "NTLM missing arcfour key"); + goto out; + } + + hex_encode(answer.data, answer.length, &mdx); + if (mdx == NULL) { + free(answer.data); + krb5_clear_error_string(context); ret = ENOMEM; goto out; } + r.element = choice_DigestRepInner_response; + ret = strcasecmp(mdx, ireq.u.digestRequest.responseData); + free(mdx); + if (ret == 0) { + r.u.response.success = TRUE; + } else { + kdc_log(context, config, 0, + "MS-CHAP-V2 reply mismatch for %s", + ireq.u.digestRequest.username); + r.u.response.success = FALSE; + } + + if (r.u.response.success) { + unsigned char hashhash[MD4_DIGEST_LENGTH]; + + /* hashhash */ + { + MD4_CTX hctx; + + MD4_Init(&hctx); + MD4_Update(&hctx, key->key.keyvalue.data, + key->key.keyvalue.length); + MD4_Final(hashhash, &hctx); + } + + /* GenerateAuthenticatorResponse */ + SHA1_Init(&ctx); + SHA1_Update(&ctx, hashhash, sizeof(hashhash)); + SHA1_Update(&ctx, answer.data, answer.length); + SHA1_Update(&ctx, ms_chap_v2_magic1,sizeof(ms_chap_v2_magic1)); + SHA1_Final(md, &ctx); + + SHA1_Init(&ctx); + SHA1_Update(&ctx, md, sizeof(md)); + SHA1_Update(&ctx, challange, 8); + SHA1_Update(&ctx, ms_chap_v2_magic2, sizeof(ms_chap_v2_magic2)); + SHA1_Final(md, &ctx); + + r.u.response.rsp = calloc(1, sizeof(*r.u.response.rsp)); + if (r.u.response.rsp == NULL) { + free(answer.data); + krb5_clear_error_string(context); + ret = ENOMEM; + goto out; + } + + hex_encode(md, sizeof(md), r.u.response.rsp); + if (r.u.response.rsp == NULL) { + free(answer.data); + krb5_clear_error_string(context); + ret = ENOMEM; + goto out; + } + + /* get_master, rfc 3079 3.4 */ + SHA1_Init(&ctx); + SHA1_Update(&ctx, hashhash, 16); /* md4(hash) */ + SHA1_Update(&ctx, answer.data, answer.length); + SHA1_Update(&ctx, ms_rfc3079_magic1, sizeof(ms_rfc3079_magic1)); + SHA1_Final(md, &ctx); + + free(answer.data); + + r.u.response.session_key = + calloc(1, sizeof(*r.u.response.session_key)); + if (r.u.response.session_key == NULL) { + krb5_clear_error_string(context); + ret = ENOMEM; + goto out; + } + + ret = krb5_data_copy(r.u.response.session_key, md, 16); + if (ret) { + krb5_clear_error_string(context); + goto out; + } + } + } else { r.element = choice_DigestRepInner_error; - asprintf(&r.u.error.reason, "unsupported digest type %s", + asprintf(&r.u.error.reason, "Unsupported digest type %s", ireq.u.digestRequest.type); if (r.u.error.reason == NULL) { krb5_set_error_string(context, "out of memory"); @@ -745,7 +961,6 @@ _kdc_do_digest(krb5_context context, goto out; } - r.element = choice_DigestRepInner_ntlmInitReply; r.u.ntlmInitReply.flags = NTLM_NEG_UNICODE; @@ -766,12 +981,12 @@ _kdc_do_digest(krb5_context context, NTLM_NEG_TARGET_DOMAIN | NTLM_ENC_128; -#define ALL \ - NTLM_NEG_SIGN| \ - NTLM_NEG_SEAL| \ - NTLM_NEG_ALWAYS_SIGN| \ - NTLM_NEG_NTLM2_SESSION| \ - NTLM_NEG_KEYEX +#define ALL \ + NTLM_NEG_SIGN| \ + NTLM_NEG_SEAL| \ + NTLM_NEG_ALWAYS_SIGN| \ + NTLM_NEG_NTLM2_SESSION| \ + NTLM_NEG_KEYEX r.u.ntlmInitReply.flags |= (ireq.u.ntlmInit.flags & (ALL)); @@ -989,6 +1204,7 @@ _kdc_do_digest(krb5_context context, if ((config->digests_allowed & NTLM_V1_SESSION) == 0) { kdc_log(context, config, 0, "NTLM v1-session not allowed"); + ret = EINVAL; goto out; } @@ -1048,6 +1264,7 @@ _kdc_do_digest(krb5_context context, krb5_set_error_string(context, "NTLM client failed to neg key " "exchange but still sent key"); + ret = EINVAL; goto out; } diff --git a/source4/heimdal/kdc/headers.h b/source4/heimdal/kdc/headers.h index 56ddc8090b..64f6b6e438 100644 --- a/source4/heimdal/kdc/headers.h +++ b/source4/heimdal/kdc/headers.h @@ -32,7 +32,7 @@ */ /* - * $Id: headers.h,v 1.22 2007/01/04 00:15:34 lha Exp $ + * $Id: headers.h 19658 2007-01-04 00:15:34Z lha $ */ #ifndef __HEADERS_H__ diff --git a/source4/heimdal/kdc/kaserver.c b/source4/heimdal/kdc/kaserver.c index ac282717ed..deb32e1019 100644 --- a/source4/heimdal/kdc/kaserver.c +++ b/source4/heimdal/kdc/kaserver.c @@ -33,7 +33,7 @@ #include "kdc_locl.h" -RCSID("$Id: kaserver.c,v 1.36 2006/08/23 11:43:44 lha Exp $"); +RCSID("$Id: kaserver.c 17904 2006-08-23 11:45:16Z lha $"); #include #include diff --git a/source4/heimdal/kdc/kdc-private.h b/source4/heimdal/kdc/kdc-private.h index d896bd10e9..030be9ae58 100644 --- a/source4/heimdal/kdc/kdc-private.h +++ b/source4/heimdal/kdc/kdc-private.h @@ -149,9 +149,9 @@ _kdc_find_etype ( Key **/*ret_key*/, krb5_enctype */*ret_etype*/); -PA_DATA* +const PA_DATA* _kdc_find_padata ( - KDC_REQ */*req*/, + const KDC_REQ */*req*/, int */*start*/, int /*type*/); @@ -249,8 +249,8 @@ krb5_error_code _kdc_pk_rd_padata ( krb5_context /*context*/, krb5_kdc_configuration */*config*/, - KDC_REQ */*req*/, - PA_DATA */*pa*/, + const KDC_REQ */*req*/, + const PA_DATA */*pa*/, pk_client_params **/*ret_params*/); krb5_error_code @@ -283,7 +283,4 @@ _kdc_windc_client_access ( struct hdb_entry_ex */*client*/, KDC_REQ */*req*/); -krb5_error_code -_kdc_windc_init (krb5_context /*context*/); - #endif /* __kdc_private_h__ */ diff --git a/source4/heimdal/kdc/kdc-protos.h b/source4/heimdal/kdc/kdc-protos.h index 69bc871b01..f7df365eb2 100644 --- a/source4/heimdal/kdc/kdc-protos.h +++ b/source4/heimdal/kdc/kdc-protos.h @@ -37,8 +37,10 @@ kdc_openlog ( krb5_context /*context*/, krb5_kdc_configuration */*config*/); -void -krb5_kdc_default_config (krb5_kdc_configuration */*config*/); +int +krb5_kdc_get_config ( + krb5_context /*context*/, + krb5_kdc_configuration **/*config*/); int krb5_kdc_process_krb5_request ( @@ -63,6 +65,21 @@ krb5_kdc_process_request ( struct sockaddr */*addr*/, int /*datagram_reply*/); +int +krb5_kdc_save_request ( + krb5_context /*context*/, + const char */*fn*/, + const unsigned char */*buf*/, + size_t /*len*/, + const krb5_data */*reply*/, + const struct sockaddr */*sa*/); + +void +krb5_kdc_update_time (struct timeval */*tv*/); + +krb5_error_code +krb5_kdc_windc_init (krb5_context /*context*/); + #ifdef __cplusplus } #endif diff --git a/source4/heimdal/kdc/kdc.h b/source4/heimdal/kdc/kdc.h index ea9eb7125e..eb24b4ee97 100644 --- a/source4/heimdal/kdc/kdc.h +++ b/source4/heimdal/kdc/kdc.h @@ -35,7 +35,7 @@ */ /* - * $Id: kdc.h,v 1.11 2006/12/28 21:06:56 lha Exp $ + * $Id: kdc.h 19907 2007-01-14 23:10:24Z lha $ */ #ifndef __KDC_H__ @@ -86,6 +86,8 @@ typedef struct krb5_kdc_configuration { size_t max_datagram_reply_length; int enable_kx509; + const char *kx509_template; + const char *kx509_ca; } krb5_kdc_configuration; diff --git a/source4/heimdal/kdc/kdc_locl.h b/source4/heimdal/kdc/kdc_locl.h index ae3b6584a5..fdbdf271de 100644 --- a/source4/heimdal/kdc/kdc_locl.h +++ b/source4/heimdal/kdc/kdc_locl.h @@ -32,7 +32,7 @@ */ /* - * $Id: kdc_locl.h,v 1.76 2006/12/26 17:18:14 lha Exp $ + * $Id: kdc_locl.h 20954 2007-06-07 03:30:15Z lha $ */ #ifndef __KDC_LOCL_H__ @@ -46,6 +46,7 @@ typedef struct pk_client_params pk_client_params; extern sig_atomic_t exit_flag; extern size_t max_request; +extern const char *request_log; extern const char *port_str; extern krb5_addresses explicit_addresses; @@ -55,18 +56,6 @@ extern int enable_http; extern int detach_from_console; -extern int require_preauth; /* 1 == require preauth for all principals */ - -extern const char *trpolicy_str; - -extern int disable_des; -extern int enable_v4; -extern int enable_kaserver; -extern int enable_524; -extern int enable_v4_cross_realm; - -extern char *v4_realm; - extern const struct units _kdc_digestunits[]; #define _PATH_KDC_CONF HDB_DB_DIR "/kdc.conf" @@ -81,6 +70,4 @@ loop(krb5_context context, krb5_kdc_configuration *config); krb5_kdc_configuration * configure(krb5_context context, int argc, char **argv); -void krb5_kdc_configure(krb5_context context, krb5_kdc_configuration *config); - #endif /* __KDC_LOCL_H__ */ diff --git a/source4/heimdal/kdc/kerberos4.c b/source4/heimdal/kdc/kerberos4.c index 97e98d86ad..3c76bb99b2 100644 --- a/source4/heimdal/kdc/kerberos4.c +++ b/source4/heimdal/kdc/kerberos4.c @@ -35,7 +35,7 @@ #include -RCSID("$Id: kerberos4.c,v 1.63 2006/10/08 13:43:27 lha Exp $"); +RCSID("$Id: kerberos4.c 18349 2006-10-08 13:43:52Z lha $"); #ifndef swap32 static uint32_t diff --git a/source4/heimdal/kdc/kerberos5.c b/source4/heimdal/kdc/kerberos5.c index bb0fda89e7..e34938447a 100644 --- a/source4/heimdal/kdc/kerberos5.c +++ b/source4/heimdal/kdc/kerberos5.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan + * Copyright (c) 1997-2007 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -33,7 +33,7 @@ #include "kdc_locl.h" -RCSID("$Id: kerberos5.c,v 1.231 2007/01/04 13:27:27 lha Exp $"); +RCSID("$Id: kerberos5.c 21040 2007-06-10 06:20:59Z lha $"); #define MAX_TIME ((time_t)((1U << 31) - 1)) @@ -70,9 +70,12 @@ set_salt_padata (METHOD_DATA *md, Salt *salt) } } -PA_DATA* -_kdc_find_padata(KDC_REQ *req, int *start, int type) +const PA_DATA* +_kdc_find_padata(const KDC_REQ *req, int *start, int type) { + if (req->padata == NULL) + return NULL; + while(*start < req->padata->len){ (*start)++; if(req->padata->val[*start - 1].padata_type == type) @@ -431,7 +434,8 @@ get_pa_etype_info(krb5_context context, ret = krb5_unparse_name(context, client->principal, &name); if (ret) name = rk_UNCONST(""); - kdc_log(context, config, 0, "internal error in get_pa_etype_info(%s): %d != %d", + kdc_log(context, config, 0, + "internal error in get_pa_etype_info(%s): %d != %d", name, n, pa.len); if (ret == 0) free(name); @@ -689,11 +693,11 @@ log_as_req(krb5_context context, } { - char _str[128]; + char fixedstr[128]; unparse_flags(KDCOptions2int(b->kdc_options), asn1_KDCOptions_units(), - _str, sizeof(_str)); - if(*_str) - kdc_log(context, config, 2, "Requested flags: %s", _str); + fixedstr, sizeof(fixedstr)); + if(*fixedstr) + kdc_log(context, config, 2, "Requested flags: %s", fixedstr); } } @@ -870,7 +874,7 @@ send_pac_p(krb5_context context, KDC_REQ *req) { krb5_error_code ret; PA_PAC_REQUEST pacreq; - PA_DATA *pa; + const PA_DATA *pa; int i = 0; pa = _kdc_find_padata(req, &i, KRB5_PADATA_PA_PAC_REQUEST); @@ -909,32 +913,37 @@ _kdc_as_rep(krb5_context context, KDCOptions f = b->kdc_options; hdb_entry_ex *client = NULL, *server = NULL; krb5_enctype cetype, setype, sessionetype; + krb5_data e_data; EncTicketPart et; EncKDCRepPart ek; krb5_principal client_princ = NULL, server_princ = NULL; char *client_name = NULL, *server_name = NULL; krb5_error_code ret = 0; const char *e_text = NULL; - krb5_data e_data; krb5_crypto crypto; Key *ckey, *skey; EncryptionKey *reply_key; + int flags = 0; #ifdef PKINIT pk_client_params *pkp = NULL; #endif memset(&rep, 0, sizeof(rep)); - memset(&e_data, 0, sizeof(e_data)); + krb5_data_zero(&e_data); + + if (f.canonicalize) + flags |= HDB_F_CANON; if(b->sname == NULL){ ret = KRB5KRB_ERR_GENERIC; e_text = "No server in request"; } else{ - _krb5_principalname2krb5_principal (context, - &server_princ, - *(b->sname), - b->realm); - ret = krb5_unparse_name(context, server_princ, &server_name); + ret = _krb5_principalname2krb5_principal (context, + &server_princ, + *(b->sname), + b->realm); + if (ret == 0) + ret = krb5_unparse_name(context, server_princ, &server_name); } if (ret) { kdc_log(context, config, 0, @@ -946,10 +955,26 @@ _kdc_as_rep(krb5_context context, ret = KRB5KRB_ERR_GENERIC; e_text = "No client in request"; } else { - _krb5_principalname2krb5_principal (context, - &client_princ, - *(b->cname), - b->realm); + + if (b->cname->name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) { + if (b->cname->name_string.len != 1) { + kdc_log(context, config, 0, + "AS-REQ malformed canon request from %s", from); + ret = KRB5_PARSE_MALFORMED; + goto out; + } + ret = krb5_parse_name(context, b->cname->name_string.val[0], + &client_princ); + if (ret) + goto out; + } else { + ret = _krb5_principalname2krb5_principal (context, + &client_princ, + *(b->cname), + b->realm); + if (ret) + goto out; + } ret = krb5_unparse_name(context, client_princ, &client_name); } if (ret) { @@ -962,7 +987,7 @@ _kdc_as_rep(krb5_context context, client_name, from, server_name); ret = _kdc_db_fetch(context, config, client_princ, - HDB_F_GET_CLIENT, NULL, &client); + HDB_F_GET_CLIENT | flags, NULL, &client); if(ret){ kdc_log(context, config, 0, "UNKNOWN -- %s: %s", client_name, krb5_get_err_text(context, ret)); @@ -996,7 +1021,7 @@ _kdc_as_rep(krb5_context context, if(req->padata){ int i; - PA_DATA *pa; + const PA_DATA *pa; int found_pa = 0; log_patypes(context, config, req->padata); @@ -1041,7 +1066,7 @@ _kdc_as_rep(krb5_context context, kdc_log(context, config, 0, "%s", e_text); pkp = NULL; - goto ts_enc; + goto out; } found_pa = 1; et.flags.pre_authent = 1; @@ -1169,6 +1194,8 @@ _kdc_as_rep(krb5_context context, (unsigned)abs(kdc_time - p.patimestamp), context->max_skew, client_name); +#if 1 + /* This code is from samba, needs testing */ /* * the following is needed to make windows clients * to retry using the timestamp in the error message @@ -1177,6 +1204,9 @@ _kdc_as_rep(krb5_context context, * is present... */ e_text = NULL; +#else + e_text = "Too large time skew"; +#endif goto out; } et.flags.pre_authent = 1; @@ -1227,6 +1257,12 @@ _kdc_as_rep(krb5_context context, pa->padata_type = KRB5_PADATA_PK_AS_REQ; pa->padata_value.length = 0; pa->padata_value.data = NULL; + + ret = realloc_method_data(&method_data); + pa = &method_data.val[method_data.len-1]; + pa->padata_type = KRB5_PADATA_PK_AS_REQ_WIN; + pa->padata_value.length = 0; + pa->padata_value.data = NULL; #endif /* @@ -1253,12 +1289,12 @@ _kdc_as_rep(krb5_context context, e_data.data = buf; e_data.length = len; e_text ="Need to use PA-ENC-TIMESTAMP/PA-PK-AS-REQ", + ret = KRB5KDC_ERR_PREAUTH_REQUIRED; kdc_log(context, config, 0, "No preauth found, returning PREAUTH-REQUIRED -- %s", client_name); - goto out; } @@ -1283,45 +1319,57 @@ _kdc_as_rep(krb5_context context, if(ret) goto out; + /* + * Select a session enctype from the list of the crypto systems + * supported enctype, is supported by the client and is one of the + * enctype of the enctype of the krbtgt. + * + * The later is used as a hint what enctype all KDC are supporting + * to make sure a newer version of KDC wont generate a session + * enctype that and older version of a KDC in the same realm can't + * decrypt. + * + * But if the KDC admin is paranoid and doesn't want to have "no + * the best" enctypes on the krbtgt, lets save the best pick from + * the client list and hope that that will work for any other + * KDCs. + */ { const krb5_enctype *p; - int i, j, y; + krb5_enctype clientbest = ETYPE_NULL; + int i, j; p = krb5_kerberos_enctypes(context); sessionetype = ETYPE_NULL; for (i = 0; p[i] != ETYPE_NULL && sessionetype == ETYPE_NULL; i++) { - /* check it's valid */ if (krb5_enctype_valid(context, p[i]) != 0) continue; - /* check if the client supports it */ for (j = 0; j < b->etype.len && sessionetype == ETYPE_NULL; j++) { - if (p[i] == b->etype.val[j]) { - /* - * if the server (krbtgt) has explicit etypes, - * check if it also supports it - */ - if (server->entry.etypes) { - for (y = 0; y < server->entry.etypes->len; y++) { - if (p[i] == server->entry.etypes->val[y]) { - sessionetype = p[i]; - break; - } - } - } else { - sessionetype = p[i]; - break; - } - } + Key *dummy; + /* check with client */ + if (p[i] != b->etype.val[j]) + continue; + /* save best of union of { client, crypto system } */ + if (clientbest == ETYPE_NULL) + clientbest = p[i]; + /* check with krbtgt */ + ret = hdb_enctype2key(context, &server->entry, p[i], &dummy); + if (ret) + continue; + sessionetype = p[i]; } } - if (sessionetype == ETYPE_NULL) { - kdc_log(context, config, 0, + /* if krbtgt had no shared keys with client, pick clients best */ + if (clientbest != ETYPE_NULL && sessionetype == ETYPE_NULL) { + sessionetype = clientbest; + } else if (sessionetype == ETYPE_NULL) { + kdc_log(context, config, 0, "Client (%s) from %s has no common enctypes with KDC" - "to use for the session key", - client_name, from); + "to use for the session key", + client_name, from); goto out; } } @@ -1534,6 +1582,58 @@ _kdc_as_rep(krb5_context context, set_salt_padata (rep.padata, ckey->salt); + /* Add signing of alias referral */ + if (f.canonicalize) { + PA_ClientCanonicalized canon; + krb5_data data; + PA_DATA pa; + krb5_crypto crypto; + size_t len; + + memset(&canon, 0, sizeof(canon)); + + canon.names.requested_name = *b->cname; + canon.names.real_name = client->entry.principal->name; + + ASN1_MALLOC_ENCODE(PA_ClientCanonicalizedNames, data.data, data.length, + &canon.names, &len, ret); + if (ret) + goto out; + if (data.length != len) + krb5_abortx(context, "internal asn.1 error"); + + /* sign using "returned session key" */ + ret = krb5_crypto_init(context, &et.key, 0, &crypto); + if (ret) { + free(data.data); + goto out; + } + + ret = krb5_create_checksum(context, crypto, + KRB5_KU_CANONICALIZED_NAMES, 0, + data.data, data.length, + &canon.canon_checksum); + free(data.data); + krb5_crypto_destroy(context, crypto); + if (ret) + goto out; + + ASN1_MALLOC_ENCODE(PA_ClientCanonicalized, data.data, data.length, + &canon, &len, ret); + free_Checksum(&canon.canon_checksum); + if (ret) + goto out; + if (data.length != len) + krb5_abortx(context, "internal asn.1 error"); + + pa.padata_type = KRB5_PADATA_CLIENT_CANONICALIZED; + pa.padata_value = data; + ret = add_METHOD_DATA(rep.padata, &pa); + free(data.data); + if (ret) + goto out; + } + if (rep.padata->len == 0) { free(rep.padata); rep.padata = NULL; diff --git a/source4/heimdal/kdc/krb5tgs.c b/source4/heimdal/kdc/krb5tgs.c index a056839e5f..02cd92de2e 100644 --- a/source4/heimdal/kdc/krb5tgs.c +++ b/source4/heimdal/kdc/krb5tgs.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan + * Copyright (c) 1997-2007 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -33,7 +33,7 @@ #include "kdc_locl.h" -RCSID("$Id: krb5tgs.c,v 1.25 2007/01/04 12:49:45 lha Exp $"); +RCSID("$Id: krb5tgs.c 21041 2007-06-10 06:21:12Z lha $"); /* * return the realm of a krbtgt-ticket or NULL @@ -656,7 +656,7 @@ tgs_make_reply(krb5_context context, KDC_REQ_BODY *b, krb5_const_principal tgt_name, const EncTicketPart *tgt, - const EncryptionKey *ekey, + const EncryptionKey *serverkey, const krb5_keyblock *sessionkey, krb5_kvno kvno, AuthorizationData *auth_data, @@ -883,7 +883,7 @@ tgs_make_reply(krb5_context context, ret = _kdc_encode_reply(context, config, &rep, &et, &ek, et.key.keytype, kvno, - ekey, 0, &tgt->key, e_text, reply); + serverkey, 0, &tgt->key, e_text, reply); out: free_TGS_REP(&rep); free_TransitedEncoding(&et.transited); @@ -1010,7 +1010,7 @@ static krb5_error_code tgs_parse_request(krb5_context context, krb5_kdc_configuration *config, KDC_REQ_BODY *b, - PA_DATA *tgs_req, + const PA_DATA *tgs_req, hdb_entry_ex **krbtgt, krb5_enctype *krbtgt_etype, krb5_ticket **ticket, @@ -1258,6 +1258,7 @@ tgs_build_reply(krb5_context context, krb5_keyblock sessionkey; krb5_kvno kvno; krb5_data rspac; + int cross_realm = 0; PrincipalName *s; Realm r; @@ -1421,6 +1422,8 @@ server_lookup: kdc_log(context, config, 1, "Client not found in database: %s: %s", cpn, krb5_get_err_text(context, ret)); + + cross_realm = 1; } /* @@ -1707,21 +1710,25 @@ server_lookup: /* check PAC if there is one */ { Key *tkey; + krb5_keyblock *tgtkey = NULL; - ret = hdb_enctype2key(context, &krbtgt->entry, - krbtgt_etype, &tkey); - if(ret) { - kdc_log(context, config, 0, - "Failed to find key for krbtgt PAC check"); - goto out; + if (!cross_realm) { + ret = hdb_enctype2key(context, &krbtgt->entry, + krbtgt_etype, &tkey); + if(ret) { + kdc_log(context, config, 0, + "Failed to find key for krbtgt PAC check"); + goto out; + } + tgtkey = &tkey->key; } ret = check_PAC(context, config, client_principal, - client, server, ekey, &tkey->key, + client, server, ekey, tgtkey, tgt, &rspac, &require_signedpath); if (ret) { kdc_log(context, config, 0, - "check_PAC check failed for %s (%s) from %s with %s", + "Verify PAC failed for %s (%s) from %s with %s", spn, cpn, from, krb5_get_err_text(context, ret)); goto out; } @@ -1804,7 +1811,7 @@ _kdc_tgs_rep(krb5_context context, AuthorizationData *auth_data = NULL; krb5_error_code ret; int i = 0; - PA_DATA *tgs_req = NULL; + const PA_DATA *tgs_req; hdb_entry_ex *krbtgt = NULL; krb5_ticket *ticket = NULL; diff --git a/source4/heimdal/kdc/kx509.c b/source4/heimdal/kdc/kx509.c index d817338f73..8414ecb4b2 100644 --- a/source4/heimdal/kdc/kx509.c +++ b/source4/heimdal/kdc/kx509.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 Kungliga Tekniska Högskolan + * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -33,8 +33,10 @@ #include "kdc_locl.h" #include +#include +#include -RCSID("$Id: kx509.c,v 1.1 2006/12/28 21:03:53 lha Exp $"); +RCSID("$Id: kx509.c 19992 2007-01-20 09:06:18Z lha $"); /* * @@ -140,72 +142,146 @@ build_certificate(krb5_context context, krb5_principal principal, krb5_data *certificate) { - /* XXX write code here to generate certificates */ - FILE *in, *out; - krb5_error_code ret; - const char *program; - char *str, *strkey; - char tstr[64]; - pid_t pid; + hx509_context hxctx = NULL; + hx509_ca_tbs tbs = NULL; + hx509_env env = NULL; + hx509_cert cert = NULL; + hx509_cert signer = NULL; + int ret; + + if (krb5_principal_get_comp_string(context, principal, 1) != NULL) { + kdc_log(context, config, 0, "Principal is not a user"); + return EINVAL; + } - snprintf(tstr, sizeof(tstr), "%lu", (unsigned long)endtime); + ret = hx509_context_init(&hxctx); + if (ret) + goto out; - ret = base64_encode(key->data, key->length, &strkey); - if (ret < 0) { - krb5_set_error_string(context, "failed to base64 encode key"); - return ENOMEM; - } + ret = hx509_env_init(hxctx, &env); + if (ret) + goto out; - program = krb5_config_get_string(context, - NULL, - "kdc", - "kx509_cert_program", - NULL); - if (program == NULL) { - free(strkey); - krb5_set_error_string(context, "no certificate program configured"); - return ENOENT; - } + ret = hx509_env_add(hxctx, env, "principal-name", + krb5_principal_get_comp_string(context, principal, 0)); + if (ret) + goto out; - ret = krb5_unparse_name(context, principal, &str); - if (ret) { - free(strkey); - return ret; + { + hx509_certs certs; + hx509_query *q; + + ret = hx509_certs_init(hxctx, config->kx509_ca, 0, + NULL, &certs); + if (ret) { + kdc_log(context, config, 0, "Failed to load CA %s", + config->kx509_ca); + goto out; + } + ret = hx509_query_alloc(hxctx, &q); + if (ret) { + hx509_certs_free(&certs); + goto out; + } + + hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); + hx509_query_match_option(q, HX509_QUERY_OPTION_KU_KEYCERTSIGN); + + ret = hx509_certs_find(hxctx, certs, q, &signer); + hx509_query_free(hxctx, q); + hx509_certs_free(&certs); + if (ret) { + kdc_log(context, config, 0, "Failed to find a CA in %s", + config->kx509_ca); + goto out; + } } - pid = pipe_execv(&in, &out, NULL, program, str, tstr, NULL); - free(str); - if (pid <= 0) { - free(strkey); - krb5_set_error_string(context, - "Failed to run the cert program %s", - program); - return ret; + ret = hx509_ca_tbs_init(hxctx, &tbs); + if (ret) + goto out; + + { + SubjectPublicKeyInfo spki; + heim_any any; + + memset(&spki, 0, sizeof(spki)); + + spki.subjectPublicKey.data = key->data; + spki.subjectPublicKey.length = key->length * 8; + + ret = der_copy_oid(oid_id_pkcs1_rsaEncryption(), + &spki.algorithm.algorithm); + + any.data = "\x05\x00"; + any.length = 2; + spki.algorithm.parameters = &any; + + ret = hx509_ca_tbs_set_spki(hxctx, tbs, &spki); + der_free_oid(&spki.algorithm.algorithm); + if (ret) + goto out; } - fprintf(in, "%s\n", strkey); - fclose(in); - free(strkey); { - unsigned buf[1024 * 10]; - size_t len; + hx509_certs certs; + hx509_cert template; - len = fread(buf, 1, sizeof(buf), out); - fclose(out); - if(len == 0) { - krb5_set_error_string(context, - "Certificate program returned no data"); - return KRB5KDC_ERR_PREAUTH_FAILED; + ret = hx509_certs_init(hxctx, config->kx509_template, 0, + NULL, &certs); + if (ret) { + kdc_log(context, config, 0, "Failed to load template %s", + config->kx509_template); + goto out; } - ret = krb5_data_copy(certificate, buf, len); + ret = hx509_get_one_cert(hxctx, certs, &template); + hx509_certs_free(&certs); if (ret) { - krb5_set_error_string(context, "Failed To copy certificate"); - return ret; + kdc_log(context, config, 0, "Failed to find template in %s", + config->kx509_template); + goto out; } + ret = hx509_ca_tbs_set_template(hxctx, tbs, + HX509_CA_TEMPLATE_SUBJECT| + HX509_CA_TEMPLATE_KU| + HX509_CA_TEMPLATE_EKU, + template); + hx509_cert_free(template); + if (ret) + goto out; } - kill(pid, SIGKILL); - waitpid(pid, NULL, 0); + + hx509_ca_tbs_set_notAfter(hxctx, tbs, endtime); + + hx509_ca_tbs_subject_expand(hxctx, tbs, env); + hx509_env_free(&env); + + ret = hx509_ca_sign(hxctx, tbs, signer, &cert); + hx509_cert_free(signer); + if (ret) + goto out; + + hx509_ca_tbs_free(&tbs); + + ret = hx509_cert_binary(hxctx, cert, certificate); + hx509_cert_free(cert); + if (ret) + goto out; + + hx509_context_free(&hxctx); + return 0; +out: + if (env) + hx509_env_free(&env); + if (tbs) + hx509_ca_tbs_free(&tbs); + if (signer) + hx509_cert_free(signer); + if (hxctx) + hx509_context_free(&hxctx); + krb5_set_error_string(context, "cert creation failed"); + return ret; } /* @@ -299,6 +375,20 @@ _kdc_do_kx509(krb5_context context, if (ret) goto out; + /* Verify that the key is encoded RSA key */ + { + RSAPublicKey key; + size_t size; + + ret = decode_RSAPublicKey(req->pk_key.data, req->pk_key.length, + &key, &size); + if (ret) + goto out; + free_RSAPublicKey(&key); + if (size != req->pk_key.length) + ; + } + ALLOC(rep.certificate); if (rep.certificate == NULL) goto out; diff --git a/source4/heimdal/kdc/log.c b/source4/heimdal/kdc/log.c index c316b0c5f8..977b1c9476 100644 --- a/source4/heimdal/kdc/log.c +++ b/source4/heimdal/kdc/log.c @@ -32,7 +32,7 @@ */ #include "kdc_locl.h" -RCSID("$Id: log.c,v 1.16 2005/06/30 01:52:48 lha Exp $"); +RCSID("$Id: log.c 15532 2005-06-30 01:54:49Z lha $"); void kdc_openlog(krb5_context context, diff --git a/source4/heimdal/kdc/misc.c b/source4/heimdal/kdc/misc.c index b511e1a7a8..ebf2873599 100644 --- a/source4/heimdal/kdc/misc.c +++ b/source4/heimdal/kdc/misc.c @@ -33,7 +33,7 @@ #include "kdc_locl.h" -RCSID("$Id: misc.c,v 1.32 2006/08/28 14:41:49 lha Exp $"); +RCSID("$Id: misc.c 17951 2006-08-28 14:41:49Z lha $"); struct timeval _kdc_now; diff --git a/source4/heimdal/kdc/pkinit.c b/source4/heimdal/kdc/pkinit.c index 418a38d030..bf62f879db 100755 --- a/source4/heimdal/kdc/pkinit.c +++ b/source4/heimdal/kdc/pkinit.c @@ -33,7 +33,7 @@ #include "kdc_locl.h" -RCSID("$Id: pkinit.c,v 1.86 2007/01/04 12:54:09 lha Exp $"); +RCSID("$Id: pkinit.c 21039 2007-06-10 06:20:31Z lha $"); #ifdef PKINIT @@ -97,7 +97,7 @@ static struct { static krb5_error_code pk_check_pkauthenticator_win2k(krb5_context context, PKAuthenticator_Win2k *a, - KDC_REQ *req) + const KDC_REQ *req) { krb5_timestamp now; @@ -114,7 +114,7 @@ pk_check_pkauthenticator_win2k(krb5_context context, static krb5_error_code pk_check_pkauthenticator(krb5_context context, PKAuthenticator *a, - KDC_REQ *req) + const KDC_REQ *req) { u_char *buf = NULL; size_t buf_size; @@ -365,8 +365,8 @@ get_dh_param(krb5_context context, krb5_error_code _kdc_pk_rd_padata(krb5_context context, krb5_kdc_configuration *config, - KDC_REQ *req, - PA_DATA *pa, + const KDC_REQ *req, + const PA_DATA *pa, pk_client_params **ret_params) { pk_client_params *client_params; @@ -375,7 +375,6 @@ _kdc_pk_rd_padata(krb5_context context, krb5_data eContent = { 0, NULL }; krb5_data signed_content = { 0, NULL }; const char *type = "unknown type"; - const heim_oid *pa_contentType; int have_data = 0; *ret_params = NULL; @@ -385,6 +384,8 @@ _kdc_pk_rd_padata(krb5_context context, return 0; } + hx509_verify_set_time(kdc_identity->verify_ctx, _kdc_now.tv_sec); + client_params = calloc(1, sizeof(*client_params)); if (client_params == NULL) { krb5_clear_error_string(context); @@ -396,7 +397,6 @@ _kdc_pk_rd_padata(krb5_context context, PA_PK_AS_REQ_Win2k r; type = "PK-INIT-Win2k"; - pa_contentType = oid_id_pkcs7_data(); ret = decode_PA_PK_AS_REQ_Win2k(pa->padata_value.data, pa->padata_value.length, @@ -422,7 +422,6 @@ _kdc_pk_rd_padata(krb5_context context, PA_PK_AS_REQ r; type = "PK-INIT-IETF"; - pa_contentType = oid_id_pkauthdata(); ret = decode_PA_PK_AS_REQ(pa->padata_value.data, pa->padata_value.length, @@ -467,7 +466,7 @@ _kdc_pk_rd_padata(krb5_context context, edi->val[i].issuerAndSerialNumber->length, &iasn, &size); - if (ret || size != 0) { + if (ret) { hx509_query_free(kdc_identity->hx509ctx, q); continue; } @@ -527,6 +526,7 @@ _kdc_pk_rd_padata(krb5_context context, kdc_identity->verify_ctx, signed_content.data, signed_content.length, + NULL, kdc_identity->certpool, &eContentType, &eContent, @@ -547,7 +547,9 @@ _kdc_pk_rd_padata(krb5_context context, } /* Signature is correct, now verify the signed message */ - if (der_heim_oid_cmp(&eContentType, pa_contentType)) { + if (der_heim_oid_cmp(&eContentType, oid_id_pkcs7_data()) != 0 && + der_heim_oid_cmp(&eContentType, oid_id_pkauthdata()) != 0) + { krb5_set_error_string(context, "got wrong oid for pkauthdata"); ret = KRB5_BADMSGTYPE; goto out; @@ -639,6 +641,8 @@ _kdc_pk_rd_padata(krb5_context context, kdc_log(context, config, 0, "PK-INIT request of type %s", type); out: + if (ret) + krb5_warn(context, ret, "PKINIT"); if (signed_content.data) free(signed_content.data); @@ -678,18 +682,41 @@ pk_mk_pa_reply_enckey(krb5_context context, krb5_keyblock *reply_key, ContentInfo *content_info) { + const heim_oid *envelopedAlg = NULL, *sdAlg = NULL; krb5_error_code ret; krb5_data buf, signed_data; size_t size; + int do_win2k = 0; krb5_data_zero(&buf); krb5_data_zero(&signed_data); + /* + * If the message client is a win2k-type but it send pa data + * 09-binding it expects a IETF (checksum) reply so there can be + * no replay attacks. + */ + switch (client_params->type) { case PKINIT_COMPAT_WIN2K: { + int i = 0; + if (_kdc_find_padata(req, &i, KRB5_PADATA_PK_AS_09_BINDING) == NULL) + do_win2k = 1; + break; + } + case PKINIT_COMPAT_27: + break; + default: + krb5_abortx(context, "internal pkinit error"); + } + + if (do_win2k) { ReplyKeyPack_Win2k kp; memset(&kp, 0, sizeof(kp)); + envelopedAlg = oid_id_rsadsi_des_ede3_cbc(); + sdAlg = oid_id_pkcs7_data(); + ret = copy_EncryptionKey(reply_key, &kp.replyKey); if (ret) { krb5_clear_error_string(context); @@ -701,13 +728,13 @@ pk_mk_pa_reply_enckey(krb5_context context, buf.data, buf.length, &kp, &size,ret); free_ReplyKeyPack_Win2k(&kp); - break; - } - case PKINIT_COMPAT_27: { + } else { krb5_crypto ascrypto; ReplyKeyPack kp; memset(&kp, 0, sizeof(kp)); + sdAlg = oid_id_pkrkeydata(); + ret = copy_EncryptionKey(reply_key, &kp.replyKey); if (ret) { krb5_clear_error_string(context); @@ -735,10 +762,6 @@ pk_mk_pa_reply_enckey(krb5_context context, } ASN1_MALLOC_ENCODE(ReplyKeyPack, buf.data, buf.length, &kp, &size,ret); free_ReplyKeyPack(&kp); - break; - } - default: - krb5_abortx(context, "internal pkinit error"); } if (ret) { krb5_set_error_string(context, "ASN.1 encoding of ReplyKeyPack " @@ -768,7 +791,8 @@ pk_mk_pa_reply_enckey(krb5_context context, goto out; ret = hx509_cms_create_signed_1(kdc_identity->hx509ctx, - oid_id_pkrkeydata(), + 0, + sdAlg, buf.data, buf.length, NULL, @@ -784,9 +808,21 @@ pk_mk_pa_reply_enckey(krb5_context context, if (ret) goto out; + if (client_params->type == PKINIT_COMPAT_WIN2K) { + ret = hx509_cms_wrap_ContentInfo(oid_id_pkcs7_signedData(), + &signed_data, + &buf); + if (ret) + goto out; + krb5_data_free(&signed_data); + signed_data = buf; + } + ret = hx509_cms_envelope_1(kdc_identity->hx509ctx, + 0, client_params->cert, - signed_data.data, signed_data.length, NULL, + signed_data.data, signed_data.length, + envelopedAlg, oid_id_pkcs7_signedData(), &buf); if (ret) goto out; @@ -881,6 +917,7 @@ pk_mk_pa_reply_dh(krb5_context context, goto out; ret = hx509_cms_create_signed_1(kdc_identity->hx509ctx, + 0, oid_id_pkdhkeydata(), buf.data, buf.length, @@ -1125,6 +1162,7 @@ _kdc_pk_mk_pa_reply(krb5_context context, krb5_data_free(&ocsp.data); ocsp.expire = 0; + ocsp.next_update = kdc_time + 60 * 5; fd = open(config->pkinit_kdc_ocsp_file, O_RDONLY); if (fd < 0) { @@ -1168,11 +1206,13 @@ _kdc_pk_mk_pa_reply(krb5_context context, "PK-INIT failed to verify ocsp data %d", ret); krb5_data_free(&ocsp.data); ocsp.expire = 0; - } else if (ocsp.expire > 180) + } else if (ocsp.expire > 180) { ocsp.expire -= 180; /* refetch the ocsp before it expire */ - + ocsp.next_update = ocsp.expire; + } else { + ocsp.next_update = kdc_time; + } out_ocsp: - ocsp.next_update = kdc_time + 3600; ret = 0; } @@ -1199,10 +1239,10 @@ out: } static int -pk_principal_from_X509(krb5_context context, - krb5_kdc_configuration *config, - hx509_cert client_cert, - krb5_const_principal match) +match_rfc_san(krb5_context context, + krb5_kdc_configuration *config, + hx509_cert client_cert, + krb5_const_principal match) { hx509_octet_string_list list; int ret, i, found = 0; @@ -1254,6 +1294,68 @@ out: return 0; } +static int +match_ms_upn_san(krb5_context context, + krb5_kdc_configuration *config, + hx509_cert client_cert, + krb5_const_principal match) +{ + hx509_octet_string_list list; + krb5_principal principal = NULL; + int ret, found = 0; + MS_UPN_SAN upn; + size_t size; + + memset(&list, 0 , sizeof(list)); + + ret = hx509_cert_find_subjectAltName_otherName(client_cert, + oid_id_pkinit_ms_san(), + &list); + if (ret) + goto out; + + if (list.len != 1) { + kdc_log(context, config, 0, + "More then one PK-INIT MS UPN SAN"); + goto out; + } + + ret = decode_MS_UPN_SAN(list.val[0].data, list.val[0].length, &upn, &size); + if (ret) { + kdc_log(context, config, 0, "Decode of MS-UPN-SAN failed"); + goto out; + } + + kdc_log(context, config, 0, "found MS UPN SAN: %s", upn); + + ret = krb5_parse_name(context, upn, &principal); + free_MS_UPN_SAN(&upn); + if (ret) { + kdc_log(context, config, 0, "Failed to parse principal in MS UPN SAN"); + goto out; + } + + /* + * This is very wrong, but will do for now, should really and a + * plugin to the windc layer to very this ACL. + */ + strupr(principal->realm); + + if (krb5_principal_compare(context, principal, match) == TRUE) + found = 1; + +out: + if (principal) + krb5_free_principal(context, principal); + hx509_free_octet_string_list(&list); + if (ret) + return ret; + + if (!found) + return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH; + + return 0; +} krb5_error_code _kdc_pk_check_client(krb5_context context, @@ -1283,14 +1385,22 @@ _kdc_pk_check_client(krb5_context context, *subject_name); if (config->enable_pkinit_princ_in_cert) { - ret = pk_principal_from_X509(context, config, - client_params->cert, - client->entry.principal); + ret = match_rfc_san(context, config, + client_params->cert, + client->entry.principal); if (ret == 0) { kdc_log(context, config, 5, "Found matching PK-INIT SAN in certificate"); return 0; } + ret = match_ms_upn_san(context, config, + client_params->cert, + client->entry.principal); + if (ret == 0) { + kdc_log(context, config, 5, + "Found matching MS UPN SAN in certificate"); + return 0; + } } ret = hdb_entry_get_pkinit_acl(&client->entry, &acl); @@ -1330,10 +1440,17 @@ _kdc_pk_check_client(krb5_context context, return 0; } + krb5_set_error_string(context, + "PKINIT no matching principals for %s", + *subject_name); + + kdc_log(context, config, 5, + "PKINIT no matching principals for %s", + *subject_name); + free(*subject_name); *subject_name = NULL; - krb5_set_error_string(context, "PKINIT no matching principals"); return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH; } @@ -1396,7 +1513,56 @@ _kdc_add_inital_verified_cas(krb5_context context, return ret; } +/* + * + */ +static void +load_mappings(krb5_context context, const char *fn) +{ + krb5_error_code ret; + char buf[1024]; + unsigned long lineno = 0; + FILE *f; + + f = fopen(fn, "r"); + if (f == NULL) + return; + + while (fgets(buf, sizeof(buf), f) != NULL) { + char *subject_name, *p; + + buf[strcspn(buf, "\n")] = '\0'; + lineno++; + + p = buf + strspn(buf, " \t"); + + if (*p == '#' || *p == '\0') + continue; + + subject_name = strchr(p, ':'); + if (subject_name == NULL) { + krb5_warnx(context, "pkinit mapping file line %lu " + "missing \":\" :%s", + lineno, buf); + continue; + } + *subject_name++ = '\0'; + + ret = add_principal_mapping(context, p, subject_name); + if (ret) { + krb5_warn(context, ret, "failed to add line %lu \":\" :%s\n", + lineno, buf); + continue; + } + } + + fclose(f); +} + +/* + * + */ krb5_error_code _kdc_pk_initialize(krb5_context context, @@ -1408,9 +1574,6 @@ _kdc_pk_initialize(krb5_context context, { const char *file; krb5_error_code ret; - char buf[1024]; - unsigned long lineno = 0; - FILE *f; file = krb5_config_get_string(context, NULL, "libdefaults", "moduli", NULL); @@ -1481,41 +1644,8 @@ _kdc_pk_initialize(krb5_context context, "kdc", "pkinit_mappings_file", NULL); - f = fopen(file, "r"); - if (f == NULL) { - krb5_warnx(context, "PKINIT: failed to load mappings file %s", file); - return 0; - } - - while (fgets(buf, sizeof(buf), f) != NULL) { - char *subject_name, *p; - - buf[strcspn(buf, "\n")] = '\0'; - lineno++; - - p = buf + strspn(buf, " \t"); - - if (*p == '#' || *p == '\0') - continue; - subject_name = strchr(p, ':'); - if (subject_name == NULL) { - krb5_warnx(context, "pkinit mapping file line %lu " - "missing \":\" :%s", - lineno, buf); - continue; - } - *subject_name++ = '\0'; - - ret = add_principal_mapping(context, p, subject_name); - if (ret) { - krb5_warn(context, ret, "failed to add line %lu \":\" :%s\n", - lineno, buf); - continue; - } - } - - fclose(f); + load_mappings(context, file); return 0; } diff --git a/source4/heimdal/kdc/process.c b/source4/heimdal/kdc/process.c index a64efaa05d..1d0a01a215 100644 --- a/source4/heimdal/kdc/process.c +++ b/source4/heimdal/kdc/process.c @@ -34,7 +34,20 @@ #include "kdc_locl.h" -RCSID("$Id: process.c,v 1.7 2006/12/28 21:09:35 lha Exp $"); +RCSID("$Id: process.c 20959 2007-06-07 04:46:06Z lha $"); + +/* + * + */ + +void +krb5_kdc_update_time(struct timeval *tv) +{ + if (tv == NULL) + gettimeofday(&_kdc_now, NULL); + else + _kdc_now = *tv; +} /* * handle the request in `buf, len', from `addr' (or `from' as a string), @@ -59,7 +72,6 @@ krb5_kdc_process_request(krb5_context context, krb5_error_code ret; size_t i; - gettimeofday(&_kdc_now, NULL); if(decode_AS_REQ(buf, len, &req, &i) == 0){ krb5_data req_buffer; @@ -121,7 +133,6 @@ krb5_kdc_process_krb5_request(krb5_context context, krb5_error_code ret; size_t i; - gettimeofday(&_kdc_now, NULL); if(decode_AS_REQ(buf, len, &req, &i) == 0){ krb5_data req_buffer; @@ -139,3 +150,70 @@ krb5_kdc_process_krb5_request(krb5_context context, } return -1; } + +/* + * + */ + +int +krb5_kdc_save_request(krb5_context context, + const char *fn, + const unsigned char *buf, + size_t len, + const krb5_data *reply, + const struct sockaddr *sa) +{ + krb5_storage *sp; + krb5_address a; + int fd, ret; + uint32_t t; + krb5_data d; + + memset(&a, 0, sizeof(a)); + + d.data = rk_UNCONST(buf); + d.length = len; + t = _kdc_now.tv_sec; + + fd = open(fn, O_WRONLY|O_CREAT|O_APPEND, 0600); + if (fd < 0) { + krb5_set_error_string(context, "Failed to open: %s", fn); + return errno; + } + + sp = krb5_storage_from_fd(fd); + close(fd); + if (sp == NULL) { + krb5_set_error_string(context, "Storage failed to open fd"); + return ENOMEM; + } + + ret = krb5_sockaddr2address(context, sa, &a); + if (ret) + goto out; + + krb5_store_uint32(sp, 1); + krb5_store_uint32(sp, t); + krb5_store_address(sp, a); + krb5_store_data(sp, d); + { + Der_class cl; + Der_type ty; + unsigned int tag; + ret = der_get_tag (reply->data, reply->length, + &cl, &ty, &tag, NULL); + if (ret) { + krb5_store_uint32(sp, 0xffffffff); + krb5_store_uint32(sp, 0xffffffff); + } else { + krb5_store_uint32(sp, MAKE_TAG(cl, ty, 0)); + krb5_store_uint32(sp, tag); + } + } + + krb5_free_address(context, &a); +out: + krb5_storage_free(sp); + + return 0; +} diff --git a/source4/heimdal/kdc/rx.h b/source4/heimdal/kdc/rx.h index 370e33732f..18806d79da 100644 --- a/source4/heimdal/kdc/rx.h +++ b/source4/heimdal/kdc/rx.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -/* $Id: rx.h,v 1.5 2006/05/05 10:51:10 lha Exp $ */ +/* $Id: rx.h 17447 2006-05-05 10:52:01Z lha $ */ #ifndef __RX_H__ #define __RX_H__ diff --git a/source4/heimdal/kdc/windc.c b/source4/heimdal/kdc/windc.c index 41e4ad1bbc..395ab73432 100644 --- a/source4/heimdal/kdc/windc.c +++ b/source4/heimdal/kdc/windc.c @@ -33,7 +33,7 @@ #include "kdc_locl.h" -RCSID("$Id: windc.c,v 1.3 2007/01/04 11:10:06 lha Exp $"); +RCSID("$Id: windc.c 20559 2007-04-24 16:00:07Z lha $"); static krb5plugin_windc_ftable *windcft; static void *windcctx; @@ -43,7 +43,7 @@ static void *windcctx; */ krb5_error_code -_kdc_windc_init(krb5_context context) +krb5_kdc_windc_init(krb5_context context) { struct krb5_plugin *list = NULL, *e; krb5_error_code ret; @@ -91,10 +91,11 @@ _kdc_pac_verify(krb5_context context, krb5_pac *pac) { if (windcft == NULL) { - krb5_set_error_string(context, "Can't verify WINDC, no function"); + krb5_set_error_string(context, "Can't verify PAC, no function"); return EINVAL; } - return (windcft->pac_verify)(windcctx, context, client_principal, client, server, pac); + return (windcft->pac_verify)(windcctx, context, + client_principal, client, server, pac); } krb5_error_code diff --git a/source4/heimdal/kdc/windc_plugin.h b/source4/heimdal/kdc/windc_plugin.h index a3b7534480..ec480cf950 100644 --- a/source4/heimdal/kdc/windc_plugin.h +++ b/source4/heimdal/kdc/windc_plugin.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -/* $Id: windc_plugin.h,v 1.2 2007/01/04 11:13:51 lha Exp $ */ +/* $Id: windc_plugin.h 19798 2007-01-10 15:24:51Z lha $ */ #ifndef HEIMDAL_KRB5_PAC_PLUGIN_H #define HEIMDAL_KRB5_PAC_PLUGIN_H 1 @@ -58,7 +58,9 @@ typedef krb5_error_code typedef krb5_error_code (*krb5plugin_windc_pac_verify)(void *, krb5_context, const krb5_principal, - struct hdb_entry_ex *, struct hdb_entry_ex *, krb5_pac *); + struct hdb_entry_ex *, + struct hdb_entry_ex *, + krb5_pac *); typedef krb5_error_code (*krb5plugin_windc_client_access)( -- cgit