diff options
Diffstat (limited to 'source4/heimdal/lib/krb5')
24 files changed, 1637 insertions, 171 deletions
diff --git a/source4/heimdal/lib/krb5/acache.c b/source4/heimdal/lib/krb5/acache.c index 004926bc89..d20c24699b 100644 --- a/source4/heimdal/lib/krb5/acache.c +++ b/source4/heimdal/lib/krb5/acache.c @@ -37,7 +37,7 @@ #include <dlfcn.h> #endif -RCSID("$Id: acache.c,v 1.16 2006/10/19 11:41:38 lha Exp $"); +RCSID("$Id: acache.c,v 1.17 2007/01/08 15:31:01 lha Exp $"); /* XXX should we fetch these for each open ? */ static HEIMDAL_MUTEX acc_mutex = HEIMDAL_MUTEX_INITIALIZER; @@ -106,7 +106,12 @@ init_ccapi(krb5_context context) } #ifdef HAVE_DLOPEN - cc_handle = dlopen(lib, 0); + +#ifndef RTLD_LAZY +#define RTLD_LAZY 0 +#endif + + cc_handle = dlopen(lib, RTLD_LAZY); if (cc_handle == NULL) { HEIMDAL_MUTEX_unlock(&acc_mutex); krb5_set_error_string(context, "Failed to load %s", lib); diff --git a/source4/heimdal/lib/krb5/config_file.c b/source4/heimdal/lib/krb5/config_file.c index 66051303ed..bbd9cf4c78 100644 --- a/source4/heimdal/lib/krb5/config_file.c +++ b/source4/heimdal/lib/krb5/config_file.c @@ -32,7 +32,7 @@ */ #include "krb5_locl.h" -RCSID("$Id: config_file.c,v 1.54 2006/04/02 00:59:19 lha Exp $"); +RCSID("$Id: config_file.c,v 1.55 2006/12/04 23:35:54 lha Exp $"); #ifndef HAVE_NETINFO @@ -158,8 +158,7 @@ parse_list(struct fileptr *f, unsigned *lineno, krb5_config_binding **parent, char *p; ++*lineno; - if (buf[strlen(buf) - 1] == '\n') - buf[strlen(buf) - 1] = '\0'; + buf[strcspn(buf, "\r\n")] = '\0'; p = buf; while(isspace((unsigned char)*p)) ++p; @@ -255,8 +254,7 @@ krb5_config_parse_debug (struct fileptr *f, char *p; ++*lineno; - if(buf[strlen(buf) - 1] == '\n') - buf[strlen(buf) - 1] = '\0'; + buf[strcspn(buf, "\r\n")] = '\0'; p = buf; while(isspace((unsigned char)*p)) ++p; diff --git a/source4/heimdal/lib/krb5/context.c b/source4/heimdal/lib/krb5/context.c index f3b0fad347..d0317da375 100644 --- a/source4/heimdal/lib/krb5/context.c +++ b/source4/heimdal/lib/krb5/context.c @@ -34,7 +34,7 @@ #include "krb5_locl.h" #include <com_err.h> -RCSID("$Id: context.c,v 1.111 2006/11/08 02:55:46 lha Exp $"); +RCSID("$Id: context.c,v 1.112 2006/11/24 14:24:33 lha Exp $"); #define INIT_FIELD(C, T, E, D, F) \ (C)->E = krb5_config_get_ ## T ## _default ((C), NULL, (D), \ @@ -180,7 +180,7 @@ init_context_from_config_file(krb5_context context) /* prefer dns_lookup_kdc over srv_lookup. */ INIT_FIELD(context, bool, srv_lookup, TRUE, "srv_lookup"); INIT_FIELD(context, bool, srv_lookup, context->srv_lookup, "dns_lookup_kdc"); - INIT_FIELD(context, int, large_msg_size, 6000, "large_message_size"); + INIT_FIELD(context, int, large_msg_size, 1400, "large_message_size"); INIT_FIELD(context, bool, dns_canonicalize_hostname, TRUE, "dns_canonicalize_hostname"); context->default_cc_name = NULL; return 0; diff --git a/source4/heimdal/lib/krb5/crypto.c b/source4/heimdal/lib/krb5/crypto.c index 9f6ef6b82b..6d4a81baa8 100644 --- a/source4/heimdal/lib/krb5/crypto.c +++ b/source4/heimdal/lib/krb5/crypto.c @@ -32,7 +32,7 @@ */ #include "krb5_locl.h" -RCSID("$Id: crypto.c,v 1.145 2006/10/22 07:32:40 lha Exp $"); +RCSID("$Id: crypto.c,v 1.146 2006/11/17 21:58:47 lha Exp $"); #undef CRYPTO_DEBUG #ifdef CRYPTO_DEBUG @@ -1076,6 +1076,21 @@ krb5_enctype_keysize(krb5_context context, } krb5_error_code KRB5_LIB_FUNCTION +krb5_enctype_keybits(krb5_context context, + krb5_enctype type, + size_t *keybits) +{ + struct encryption_type *et = _find_enctype(type); + if(et == NULL) { + krb5_set_error_string(context, "encryption type %d not supported", + type); + return KRB5_PROG_ETYPE_NOSUPP; + } + *keybits = et->keytype->bits; + return 0; +} + +krb5_error_code KRB5_LIB_FUNCTION krb5_generate_random_keyblock(krb5_context context, krb5_enctype type, krb5_keyblock *key) diff --git a/source4/heimdal/lib/krb5/fcache.c b/source4/heimdal/lib/krb5/fcache.c index 79b809d2a2..7441509e38 100644 --- a/source4/heimdal/lib/krb5/fcache.c +++ b/source4/heimdal/lib/krb5/fcache.c @@ -33,7 +33,7 @@ #include "krb5_locl.h" -RCSID("$Id: fcache.c,v 1.52 2006/04/02 01:04:37 lha Exp $"); +RCSID("$Id: fcache.c,v 1.54 2006/12/15 21:35:52 lha Exp $"); typedef struct krb5_fcache{ char *filename; @@ -699,6 +699,62 @@ fcc_get_version(krb5_context context, return FCACHE(id)->version; } +struct fcache_iter { + int first; +}; + +static krb5_error_code +fcc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor) +{ + struct fcache_iter *iter; + + iter = calloc(1, sizeof(*iter)); + if (iter == NULL) { + krb5_set_error_string(context, "malloc - out of memory"); + return ENOMEM; + } + iter->first = 1; + *cursor = iter; + return 0; +} + +static krb5_error_code +fcc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id) +{ + struct fcache_iter *iter = cursor; + krb5_error_code ret; + const char *fn; + char *expandedfn = NULL; + + if (!iter->first) { + krb5_clear_error_string(context); + return KRB5_CC_END; + } + iter->first = 0; + + fn = krb5_cc_default_name(context); + if (strncasecmp(fn, "FILE:", 5) != 0) { + ret = _krb5_expand_default_cc_name(context, + KRB5_DEFAULT_CCNAME_FILE, + &expandedfn); + if (ret) + return ret; + } + ret = krb5_cc_resolve(context, fn, id); + if (expandedfn) + free(expandedfn); + + return ret; +} + +static krb5_error_code +fcc_end_cache_get(krb5_context context, krb5_cc_cursor cursor) +{ + struct fcache_iter *iter = cursor; + free(iter); + return 0; +} + const krb5_cc_ops krb5_fcc_ops = { "FILE", fcc_get_name, @@ -715,5 +771,8 @@ const krb5_cc_ops krb5_fcc_ops = { fcc_end_get, fcc_remove_cred, fcc_set_flags, - fcc_get_version + fcc_get_version, + fcc_get_cache_first, + fcc_get_cache_next, + fcc_end_cache_get }; diff --git a/source4/heimdal/lib/krb5/get_cred.c b/source4/heimdal/lib/krb5/get_cred.c index b404c30f6e..663b5e7f1b 100644 --- a/source4/heimdal/lib/krb5/get_cred.c +++ b/source4/heimdal/lib/krb5/get_cred.c @@ -33,7 +33,7 @@ #include <krb5_locl.h> -RCSID("$Id: get_cred.c,v 1.112 2006/06/06 21:22:54 lha Exp $"); +RCSID("$Id: get_cred.c,v 1.113 2006/11/21 05:14:01 lha Exp $"); /* * Take the `body' and encode it into `padata' using the credentials @@ -458,7 +458,7 @@ get_cred_kdc_usage(krb5_context context, ret = krb5_create_checksum(context, crypto, - KRB5_KU_TGS_IMPERSONATE, + KRB5_KU_OTHER_CKSUM, 0, data.data, data.length, diff --git a/source4/heimdal/lib/krb5/init_creds.c b/source4/heimdal/lib/krb5/init_creds.c index 6dacb316d8..a331524a7e 100644 --- a/source4/heimdal/lib/krb5/init_creds.c +++ b/source4/heimdal/lib/krb5/init_creds.c @@ -33,7 +33,7 @@ #include "krb5_locl.h" -RCSID("$Id: init_creds.c,v 1.28 2006/09/04 14:28:54 lha Exp $"); +RCSID("$Id: init_creds.c,v 1.30 2006/11/23 16:27:36 lha Exp $"); void KRB5_LIB_FUNCTION krb5_get_init_creds_opt_init(krb5_get_init_creds_opt *opt) @@ -130,9 +130,10 @@ _krb5_get_init_creds_opt_set_krb5_error(krb5_context context, void KRB5_LIB_FUNCTION -krb5_get_init_creds_opt_free(krb5_get_init_creds_opt *opt) +krb5_get_init_creds_opt_free(krb5_context context, + krb5_get_init_creds_opt *opt) { - if (opt->opt_private == NULL) + if (opt == NULL || opt->opt_private == NULL) return; if (opt->opt_private->refcount < 1) /* abort ? */ return; diff --git a/source4/heimdal/lib/krb5/init_creds_pw.c b/source4/heimdal/lib/krb5/init_creds_pw.c index d43ae0ae6f..f6f6eac7d5 100644 --- a/source4/heimdal/lib/krb5/init_creds_pw.c +++ b/source4/heimdal/lib/krb5/init_creds_pw.c @@ -33,7 +33,7 @@ #include "krb5_locl.h" -RCSID("$Id: init_creds_pw.c,v 1.101 2006/10/02 12:00:59 lha Exp $"); +RCSID("$Id: init_creds_pw.c,v 1.105 2007/01/09 10:44:59 lha Exp $"); typedef struct krb5_get_init_creds_ctx { KDCOptions flags; @@ -656,7 +656,7 @@ free_paid(krb5_context context, struct pa_info_data *ppaid) { krb5_free_salt(context, ppaid->salt); if (ppaid->s2kparams) - krb5_data_free(ppaid->s2kparams); + krb5_free_data(context, ppaid->s2kparams); } @@ -729,8 +729,8 @@ pa_etype_info2(krb5_context context, if (e.val[i].salt == NULL) krb5_free_salt(context, salt); if (ret == 0) { - free_ETYPE_INFO2(&e); - return paid; + free_ETYPE_INFO2(&e); + return paid; } } } @@ -1092,23 +1092,31 @@ process_pa_data_to_md(krb5_context context, (*out_md)->len = 0; (*out_md)->val = NULL; - if (in_md->len != 0) { - struct pa_info_data paid, *ppaid; + /* + * Make sure we don't sent both ENC-TS and PK-INIT pa data, no + * need to expose our password protecting our PKCS12 key. + */ - memset(&paid, 0, sizeof(paid)); + if (ctx->pk_init_ctx) { + + ret = pa_data_to_md_pkinit(context, a, creds->client, ctx, *out_md); + if (ret) + return ret; + } else if (in_md->len != 0) { + struct pa_info_data paid, *ppaid; + + memset(&paid, 0, sizeof(paid)); + paid.etype = ENCTYPE_NULL; ppaid = process_pa_info(context, creds->client, a, &paid, in_md); - + pa_data_to_md_ts_enc(context, a, creds->client, ctx, ppaid, *out_md); if (ppaid) free_paid(context, ppaid); } pa_data_add_pac_request(context, ctx, *out_md); - ret = pa_data_to_md_pkinit(context, a, creds->client, ctx, *out_md); - if (ret) - return ret; if ((*out_md)->len == 0) { free(*out_md); @@ -1503,7 +1511,7 @@ krb5_get_init_creds_password(krb5_context context, free (q); if (ret) { memset (buf, 0, sizeof(buf)); - krb5_get_init_creds_opt_free(options); + krb5_get_init_creds_opt_free(context, options); ret = KRB5_LIBOS_PWDINTR; krb5_clear_error_string (context); return ret; @@ -1515,7 +1523,7 @@ krb5_get_init_creds_password(krb5_context context, ret = krb5_get_init_creds_opt_set_pa_password(context, options, password, NULL); if (ret) { - krb5_get_init_creds_opt_free(options); + krb5_get_init_creds_opt_free(context, options); memset(buf, 0, sizeof(buf)); return ret; } @@ -1523,7 +1531,7 @@ krb5_get_init_creds_password(krb5_context context, ret = krb5_get_init_creds(context, creds, client, prompter, data, start_time, in_tkt_service, options); - krb5_get_init_creds_opt_free(options); + krb5_get_init_creds_opt_free(context, options); memset(buf, 0, sizeof(buf)); return ret; } diff --git a/source4/heimdal/lib/krb5/krb5-private.h b/source4/heimdal/lib/krb5/krb5-private.h index ba2f75ad22..c3e5732753 100644 --- a/source4/heimdal/lib/krb5/krb5-private.h +++ b/source4/heimdal/lib/krb5/krb5-private.h @@ -73,15 +73,6 @@ _krb5_extract_ticket ( krb5_decrypt_proc /*decrypt_proc*/, krb5_const_pointer /*decryptarg*/); -int -_krb5_find_type_in_ad ( - krb5_context /*context*/, - int /*type*/, - krb5_data */*data*/, - krb5_boolean */*found*/, - krb5_keyblock */*sessionkey*/, - const AuthorizationData */*ad*/); - void _krb5_free_krbhst_info (krb5_krbhst_info */*hi*/); @@ -299,38 +290,17 @@ _krb5_oid_to_enctype ( const heim_oid */*oid*/, krb5_enctype */*etype*/); -void -_krb5_pac_free ( - krb5_context /*context*/, - struct krb5_pac */*pac*/); - -krb5_error_code -_krb5_pac_parse ( - krb5_context /*context*/, - const void */*ptr*/, - size_t /*len*/, - struct krb5_pac **/*pac*/); - krb5_error_code _krb5_pac_sign ( krb5_context /*context*/, struct krb5_pac */*p*/, time_t /*authtime*/, krb5_principal /*principal*/, - krb5_keyblock */*server_key*/, - krb5_keyblock */*priv_key*/, + const krb5_keyblock */*server_key*/, + const krb5_keyblock */*priv_key*/, krb5_data */*data*/); krb5_error_code -_krb5_pac_verify ( - krb5_context /*context*/, - struct krb5_pac */*pac*/, - time_t /*authtime*/, - krb5_principal /*principal*/, - krb5_keyblock */*server*/, - krb5_keyblock */*privsvr*/); - -krb5_error_code _krb5_parse_moduli ( krb5_context /*context*/, const char */*file*/, diff --git a/source4/heimdal/lib/krb5/krb5-protos.h b/source4/heimdal/lib/krb5/krb5-protos.h index 8b61e8d7d2..9dfe487b0a 100644 --- a/source4/heimdal/lib/krb5/krb5-protos.h +++ b/source4/heimdal/lib/krb5/krb5-protos.h @@ -499,10 +499,11 @@ krb5_boolean KRB5_LIB_FUNCTION krb5_c_is_keyed_cksum (krb5_cksumtype /*ctype*/); krb5_error_code KRB5_LIB_FUNCTION -krb5_c_keylength ( +krb5_c_keylengths ( krb5_context /*context*/, krb5_enctype /*enctype*/, - size_t */*len*/); + size_t */*ilen*/, + size_t */*keylen*/); krb5_error_code KRB5_LIB_FUNCTION krb5_c_make_checksum ( @@ -1520,6 +1521,12 @@ krb5_enctype_disable ( krb5_enctype /*enctype*/); krb5_error_code KRB5_LIB_FUNCTION +krb5_enctype_keybits ( + krb5_context /*context*/, + krb5_enctype /*type*/, + size_t */*keybits*/); + +krb5_error_code KRB5_LIB_FUNCTION krb5_enctype_keysize ( krb5_context /*context*/, krb5_enctype /*type*/, @@ -2021,7 +2028,9 @@ krb5_get_init_creds_opt_alloc ( krb5_get_init_creds_opt **/*opt*/); void KRB5_LIB_FUNCTION -krb5_get_init_creds_opt_free (krb5_get_init_creds_opt */*opt*/); +krb5_get_init_creds_opt_free ( + krb5_context /*context*/, + krb5_get_init_creds_opt */*opt*/); krb5_error_code KRB5_LIB_FUNCTION krb5_get_init_creds_opt_get_error ( @@ -2189,6 +2198,9 @@ krb5_get_server_rcache ( krb5_boolean KRB5_LIB_FUNCTION krb5_get_use_admin_kdc (krb5_context /*context*/); +krb5_log_facility * KRB5_LIB_FUNCTION +krb5_get_warn_dest (krb5_context /*context*/); + size_t krb5_get_wrapped_length ( krb5_context /*context*/, @@ -2609,12 +2621,172 @@ krb5_net_write_block ( size_t /*len*/, time_t /*timeout*/); +krb5_error_code +krb5_ntlm_alloc ( + krb5_context /*context*/, + krb5_ntlm */*ntlm*/); + +krb5_error_code +krb5_ntlm_free ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/); + +krb5_error_code +krb5_ntlm_init_get_challange ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/, + krb5_data */*challange*/); + +krb5_error_code +krb5_ntlm_init_get_flags ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/, + uint32_t */*flags*/); + +krb5_error_code +krb5_ntlm_init_get_opaque ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/, + krb5_data */*opaque*/); + +krb5_error_code +krb5_ntlm_init_get_targetinfo ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/, + krb5_data */*data*/); + +krb5_error_code +krb5_ntlm_init_get_targetname ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/, + char **/*name*/); + +krb5_error_code +krb5_ntlm_init_request ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/, + krb5_realm /*realm*/, + krb5_ccache /*ccache*/, + uint32_t /*flags*/, + const char */*hostname*/, + const char */*domainname*/); + +krb5_error_code +krb5_ntlm_rep_get_sessionkey ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/, + krb5_data */*data*/); + +krb5_boolean +krb5_ntlm_rep_get_status ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/); + +krb5_error_code +krb5_ntlm_req_set_flags ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/, + uint32_t /*flags*/); + +krb5_error_code +krb5_ntlm_req_set_lm ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/, + void */*hash*/, + size_t /*len*/); + +krb5_error_code +krb5_ntlm_req_set_ntlm ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/, + void */*hash*/, + size_t /*len*/); + +krb5_error_code +krb5_ntlm_req_set_opaque ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/, + krb5_data */*opaque*/); + +krb5_error_code +krb5_ntlm_req_set_session ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/, + void */*sessionkey*/, + size_t /*length*/); + +krb5_error_code +krb5_ntlm_req_set_targetname ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/, + const char */*targetname*/); + +krb5_error_code +krb5_ntlm_req_set_username ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/, + const char */*username*/); + +krb5_error_code +krb5_ntlm_request ( + krb5_context /*context*/, + krb5_ntlm /*ntlm*/, + krb5_realm /*realm*/, + krb5_ccache /*ccache*/); + krb5_error_code KRB5_LIB_FUNCTION krb5_openlog ( krb5_context /*context*/, const char */*program*/, krb5_log_facility **/*fac*/); +krb5_error_code +krb5_pac_add_buffer ( + krb5_context /*context*/, + struct krb5_pac */*p*/, + uint32_t /*type*/, + const krb5_data */*data*/); + +void +krb5_pac_free ( + krb5_context /*context*/, + struct krb5_pac */*pac*/); + +krb5_error_code +krb5_pac_get_buffer ( + krb5_context /*context*/, + struct krb5_pac */*p*/, + uint32_t /*type*/, + krb5_data */*data*/); + +krb5_error_code +krb5_pac_get_types ( + krb5_context /*context*/, + struct krb5_pac */*p*/, + size_t */*len*/, + uint32_t **/*types*/); + +krb5_error_code +krb5_pac_init ( + krb5_context /*context*/, + struct krb5_pac **/*pac*/); + +krb5_error_code +krb5_pac_parse ( + krb5_context /*context*/, + const void */*ptr*/, + size_t /*len*/, + struct krb5_pac **/*pac*/); + +krb5_error_code +krb5_pac_verify ( + krb5_context /*context*/, + const struct krb5_pac */*pac*/, + time_t /*authtime*/, + krb5_const_principal /*principal*/, + const krb5_keyblock */*server*/, + const krb5_keyblock */*privsvr*/); + int KRB5_LIB_FUNCTION krb5_padata_add ( krb5_context /*context*/, @@ -2904,6 +3076,12 @@ krb5_rd_req_in_set_keytab ( krb5_rd_req_in_ctx /*in*/, krb5_keytab /*keytab*/); +krb5_error_code KRB5_LIB_FUNCTION +krb5_rd_req_in_set_pac_check ( + krb5_context /*context*/, + krb5_rd_req_in_ctx /*in*/, + krb5_boolean /*flag*/); + void KRB5_LIB_FUNCTION krb5_rd_req_out_ctx_free ( krb5_context /*context*/, @@ -3515,6 +3693,11 @@ krb5_ticket_get_client ( const krb5_ticket */*ticket*/, krb5_principal */*client*/); +time_t KRB5_LIB_FUNCTION +krb5_ticket_get_endtime ( + krb5_context /*context*/, + const krb5_ticket */*ticket*/); + krb5_error_code KRB5_LIB_FUNCTION krb5_ticket_get_server ( krb5_context /*context*/, diff --git a/source4/heimdal/lib/krb5/krb5.h b/source4/heimdal/lib/krb5/krb5.h index 1b26e8b3e7..55a83fb533 100644 --- a/source4/heimdal/lib/krb5/krb5.h +++ b/source4/heimdal/lib/krb5/krb5.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -/* $Id: krb5.h,v 1.255 2006/11/12 08:33:07 lha Exp $ */ +/* $Id: krb5.h,v 1.259 2007/01/03 18:51:52 lha Exp $ */ #ifndef __KRB5_H__ #define __KRB5_H__ @@ -77,8 +77,10 @@ typedef struct krb5_get_creds_opt_data *krb5_get_creds_opt; struct krb5_digest; typedef struct krb5_digest *krb5_digest; +struct krb5_ntlm; +typedef struct krb5_ntlm *krb5_ntlm; -struct krb5_pac; +typedef struct krb5_pac *krb5_pac; typedef struct krb5_rd_req_in_ctx *krb5_rd_req_in_ctx; typedef struct krb5_rd_req_out_ctx *krb5_rd_req_out_ctx; @@ -216,8 +218,6 @@ typedef enum krb5_key_usage { /* Keyusage for the server referral in a TGS req */ KRB5_KU_SAM_ENC_NONCE_SAD = 27, /* Encryption of the SAM-NONCE-OR-SAD field */ - KRB5_KU_TGS_IMPERSONATE = -17, - /* Checksum type used in the impersonate field */ KRB5_KU_DIGEST_ENCRYPT = -18, /* Encryption key usage used in the digest encryption field */ KRB5_KU_DIGEST_OPAQUE = -19, @@ -716,6 +716,7 @@ typedef struct krb5_krbhst_data *krb5_krbhst_handle; #define KRB5_KRBHST_ADMIN 2 #define KRB5_KRBHST_CHANGEPW 3 #define KRB5_KRBHST_KRB524 4 +#define KRB5_KRBHST_KCA 5 typedef struct krb5_krbhst_info { enum { KRB5_KRBHST_UDP, diff --git a/source4/heimdal/lib/krb5/krb5_locl.h b/source4/heimdal/lib/krb5/krb5_locl.h index 3fb5461b3c..35d046c8d9 100644 --- a/source4/heimdal/lib/krb5/krb5_locl.h +++ b/source4/heimdal/lib/krb5/krb5_locl.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-2002 Kungliga Tekniska Högskolan + * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -/* $Id: krb5_locl.h,v 1.93 2006/10/20 18:13:31 lha Exp $ */ +/* $Id: krb5_locl.h,v 1.97 2006/12/15 16:46:51 lha Exp $ */ #ifndef __KRB5_LOCL_H__ #define __KRB5_LOCL_H__ @@ -239,20 +239,20 @@ typedef struct krb5_context_data { int large_msg_size; int dns_canonicalize_hostname; struct send_to_kdc *send_to_kdc; - void *mem_ctx; /* Some parts of Samba4 need a valid - memory context (under the event - context) to use */ } krb5_context_data; +#define KRB5_DEFAULT_CCNAME_FILE "FILE:/tmp/krb5cc_%{uid}" +#define KRB5_DEFAULT_CCNAME_API "API:" + /* * Configurable options */ #ifndef KRB5_DEFAULT_CCNAME #ifdef __APPLE__ -#define KRB5_DEFAULT_CCNAME "API:" +#define KRB5_DEFAULT_CCNAME KRB5_DEFAULT_CCNAME_API #else -#define KRB5_DEFAULT_CCNAME "FILE:/tmp/krb5cc_%{uid}" +#define KRB5_DEFAULT_CCNAME KRB5_DEFAULT_CCNAME_FILE #endif #endif diff --git a/source4/heimdal/lib/krb5/krbhst.c b/source4/heimdal/lib/krb5/krbhst.c index f395f0d0c3..3e281e5c63 100644 --- a/source4/heimdal/lib/krb5/krbhst.c +++ b/source4/heimdal/lib/krb5/krbhst.c @@ -35,7 +35,7 @@ #include <resolve.h> #include "locate_plugin.h" -RCSID("$Id: krbhst.c,v 1.58 2006/11/12 20:05:20 lha Exp $"); +RCSID("$Id: krbhst.c,v 1.61 2006/11/30 17:23:08 lha Exp $"); static int string_to_proto(const char *string) @@ -493,7 +493,7 @@ add_locate(void *ctx, int type, struct sockaddr *addr) if (ret != 0) return 0; - memset(&hints, 0, sizeof(hints)); + make_hints(&hints, krbhst_get_default_proto(kd)); ret = getaddrinfo(host, port, &hints, &ai); if (ret) return 0; @@ -521,7 +521,7 @@ plugin_get_hosts(krb5_context context, struct krb5_krbhst_data *kd, enum locate_service_type type) { - struct krb5_plugin *list, *e; + struct krb5_plugin *list = NULL, *e; krb5_error_code ret; ret = _krb5_plugin_find(context, PLUGIN_TYPE_DATA, "resolve", &list); @@ -619,6 +619,13 @@ admin_get_next(krb5_context context, { krb5_error_code ret; + if ((kd->flags & KD_PLUGIN) == 0) { + plugin_get_hosts(context, kd, locate_service_kadmin); + kd->flags |= KD_PLUGIN; + if(get_next(kd, host)) + return 0; + } + if((kd->flags & KD_CONFIG) == 0) { config_get_hosts(context, kd, "admin_server"); kd->flags |= KD_CONFIG; @@ -660,6 +667,13 @@ kpasswd_get_next(krb5_context context, { krb5_error_code ret; + if ((kd->flags & KD_PLUGIN) == 0) { + plugin_get_hosts(context, kd, locate_service_kpasswd); + kd->flags |= KD_PLUGIN; + if(get_next(kd, host)) + return 0; + } + if((kd->flags & KD_CONFIG) == 0) { config_get_hosts(context, kd, "kpasswd_server"); kd->flags |= KD_CONFIG; @@ -705,6 +719,13 @@ krb524_get_next(krb5_context context, struct krb5_krbhst_data *kd, krb5_krbhst_info **host) { + if ((kd->flags & KD_PLUGIN) == 0) { + plugin_get_hosts(context, kd, locate_service_krb524); + kd->flags |= KD_PLUGIN; + if(get_next(kd, host)) + return 0; + } + if((kd->flags & KD_CONFIG) == 0) { config_get_hosts(context, kd, "krb524_server"); if(get_next(kd, host)) diff --git a/source4/heimdal/lib/krb5/log.c b/source4/heimdal/lib/krb5/log.c index e6fcb6bbb9..9523ca848c 100644 --- a/source4/heimdal/lib/krb5/log.c +++ b/source4/heimdal/lib/krb5/log.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-2002 Kungliga Tekniska Högskolan + * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -33,7 +33,7 @@ #include "krb5_locl.h" -RCSID("$Id: log.c,v 1.39 2006/04/24 15:09:27 lha Exp $"); +RCSID("$Id: log.c,v 1.40 2006/11/21 08:08:46 lha Exp $"); struct facility { int min; diff --git a/source4/heimdal/lib/krb5/mit_glue.c b/source4/heimdal/lib/krb5/mit_glue.c index 493c4cd845..c4d3ff5390 100755 --- a/source4/heimdal/lib/krb5/mit_glue.c +++ b/source4/heimdal/lib/krb5/mit_glue.c @@ -32,7 +32,7 @@ */ #include "krb5_locl.h" -RCSID("$Id: mit_glue.c,v 1.9 2006/11/09 21:24:16 lha Exp $"); +RCSID("$Id: mit_glue.c,v 1.12 2006/11/17 22:17:46 lha Exp $"); /* * Glue for MIT API @@ -327,9 +327,16 @@ krb5_c_make_random_key(krb5_context context, } krb5_error_code KRB5_LIB_FUNCTION -krb5_c_keylength(krb5_context context, - krb5_enctype enctype, - size_t *len) +krb5_c_keylengths(krb5_context context, + krb5_enctype enctype, + size_t *ilen, + size_t *keylen) { - return krb5_enctype_keysize(context, enctype, len); + krb5_error_code ret; + + ret = krb5_enctype_keybits(context, enctype, ilen); + if (ret) + return ret; + *ilen = (*ilen + 7) / 8; + return krb5_enctype_keysize(context, enctype, keylen); } diff --git a/source4/heimdal/lib/krb5/mk_req_ext.c b/source4/heimdal/lib/krb5/mk_req_ext.c index 18b0e3552f..8646c4ebea 100644 --- a/source4/heimdal/lib/krb5/mk_req_ext.c +++ b/source4/heimdal/lib/krb5/mk_req_ext.c @@ -33,7 +33,7 @@ #include <krb5_locl.h> -RCSID("$Id: mk_req_ext.c,v 1.32 2006/03/19 20:33:13 lha Exp $"); +RCSID("$Id: mk_req_ext.c,v 1.33 2006/12/27 12:07:22 lha Exp $"); krb5_error_code _krb5_mk_req_internal(krb5_context context, @@ -91,7 +91,9 @@ _krb5_mk_req_internal(krb5_context context, in_data->length, &c); } else if(ac->keyblock->keytype == ETYPE_ARCFOUR_HMAC_MD5 || - ac->keyblock->keytype == ETYPE_ARCFOUR_HMAC_MD5_56) { + ac->keyblock->keytype == ETYPE_ARCFOUR_HMAC_MD5_56 || + ac->keyblock->keytype == ETYPE_DES_CBC_MD4 || + ac->keyblock->keytype == ETYPE_DES_CBC_MD5) { /* this is to make MS kdc happy */ ret = krb5_create_checksum(context, NULL, diff --git a/source4/heimdal/lib/krb5/pac.c b/source4/heimdal/lib/krb5/pac.c new file mode 100644 index 0000000000..5bc7235459 --- /dev/null +++ b/source4/heimdal/lib/krb5/pac.c @@ -0,0 +1,1034 @@ +/* + * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +RCSID("$Id: pac.c,v 1.13 2007/01/09 11:22:56 lha Exp $"); + +struct PAC_INFO_BUFFER { + uint32_t type; + uint32_t buffersize; + uint32_t offset_hi; + uint32_t offset_lo; +}; + +struct PACTYPE { + uint32_t numbuffers; + uint32_t version; + struct PAC_INFO_BUFFER buffers[1]; +}; + +struct krb5_pac { + struct PACTYPE *pac; + krb5_data data; + struct PAC_INFO_BUFFER *server_checksum; + struct PAC_INFO_BUFFER *privsvr_checksum; + struct PAC_INFO_BUFFER *logon_name; +}; + +#define PAC_ALIGNMENT 8 + +#define PACTYPE_SIZE 8 +#define PAC_INFO_BUFFER_SIZE 16 + +#define PAC_SERVER_CHECKSUM 6 +#define PAC_PRIVSVR_CHECKSUM 7 +#define PAC_LOGON_NAME 10 + +#define CHECK(r,f,l) \ + do { \ + if (((r) = f ) != 0) { \ + krb5_clear_error_string(context); \ + goto l; \ + } \ + } while(0) + +static const char zeros[PAC_ALIGNMENT] = { 0 }; + +/* + * + */ + +krb5_error_code +krb5_pac_parse(krb5_context context, const void *ptr, size_t len, + struct krb5_pac **pac) +{ + krb5_error_code ret; + struct krb5_pac *p; + krb5_storage *sp = NULL; + uint32_t i, tmp, tmp2, header_end; + + p = calloc(1, sizeof(*p)); + if (p == NULL) { + ret = ENOMEM; + krb5_set_error_string(context, "out of memory"); + goto out; + } + + sp = krb5_storage_from_readonly_mem(ptr, len); + if (sp == NULL) { + ret = ENOMEM; + krb5_set_error_string(context, "out of memory"); + goto out; + } + krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); + + CHECK(ret, krb5_ret_uint32(sp, &tmp), out); + CHECK(ret, krb5_ret_uint32(sp, &tmp2), out); + if (tmp < 1) { + krb5_set_error_string(context, "PAC have too few buffer"); + ret = EINVAL; /* Too few buffers */ + goto out; + } + if (tmp2 != 0) { + krb5_set_error_string(context, "PAC have wrong version"); + ret = EINVAL; /* Wrong version */ + goto out; + } + + p->pac = calloc(1, + sizeof(*p->pac) + (sizeof(p->pac->buffers[0]) * (tmp - 1))); + if (p->pac == NULL) { + krb5_set_error_string(context, "out of memory"); + ret = ENOMEM; + goto out; + } + + p->pac->numbuffers = tmp; + p->pac->version = tmp2; + + header_end = PACTYPE_SIZE + (PAC_INFO_BUFFER_SIZE * p->pac->numbuffers); + if (header_end > len) { + ret = EINVAL; + goto out; + } + + for (i = 0; i < p->pac->numbuffers; i++) { + CHECK(ret, krb5_ret_uint32(sp, &p->pac->buffers[i].type), out); + CHECK(ret, krb5_ret_uint32(sp, &p->pac->buffers[i].buffersize), out); + CHECK(ret, krb5_ret_uint32(sp, &p->pac->buffers[i].offset_lo), out); + CHECK(ret, krb5_ret_uint32(sp, &p->pac->buffers[i].offset_hi), out); + + /* consistency checks */ + if (p->pac->buffers[i].offset_lo & (PAC_ALIGNMENT - 1)) { + krb5_set_error_string(context, "PAC out of allignment"); + ret = EINVAL; + goto out; + } + if (p->pac->buffers[i].offset_hi) { + krb5_set_error_string(context, "PAC high offset set"); + ret = EINVAL; + goto out; + } + if (p->pac->buffers[i].offset_lo > len) { + krb5_set_error_string(context, "PAC offset off end"); + ret = EINVAL; + goto out; + } + if (p->pac->buffers[i].offset_lo < header_end) { + krb5_set_error_string(context, "PAC offset inside header: %d %d", + p->pac->buffers[i].offset_lo, header_end); + ret = EINVAL; + goto out; + } + if (p->pac->buffers[i].buffersize > len - p->pac->buffers[i].offset_lo){ + krb5_set_error_string(context, "PAC length off end"); + ret = EINVAL; + goto out; + } + + /* let save pointer to data we need later */ + if (p->pac->buffers[i].type == PAC_SERVER_CHECKSUM) { + if (p->server_checksum) { + krb5_set_error_string(context, "PAC have two server checksums"); + ret = EINVAL; + goto out; + } + p->server_checksum = &p->pac->buffers[i]; + } else if (p->pac->buffers[i].type == PAC_PRIVSVR_CHECKSUM) { + if (p->privsvr_checksum) { + krb5_set_error_string(context, "PAC have two KDC checksums"); + ret = EINVAL; + goto out; + } + p->privsvr_checksum = &p->pac->buffers[i]; + } else if (p->pac->buffers[i].type == PAC_LOGON_NAME) { + if (p->logon_name) { + krb5_set_error_string(context, "PAC have two logon names"); + ret = EINVAL; + goto out; + } + p->logon_name = &p->pac->buffers[i]; + } + } + + ret = krb5_data_copy(&p->data, ptr, len); + if (ret) + goto out; + + krb5_storage_free(sp); + + *pac = p; + return 0; + +out: + if (sp) + krb5_storage_free(sp); + if (p) { + if (p->pac) + free(p->pac); + free(p); + } + *pac = NULL; + + return ret; +} + +krb5_error_code +krb5_pac_init(krb5_context context, struct krb5_pac **pac) +{ + krb5_error_code ret; + struct krb5_pac *p; + + p = calloc(1, sizeof(*p)); + if (p == NULL) { + krb5_set_error_string(context, "out of memory"); + return ENOMEM; + } + + p->pac = calloc(1, sizeof(*p->pac)); + if (p->pac == NULL) { + free(p); + krb5_set_error_string(context, "out of memory"); + return ENOMEM; + } + + ret = krb5_data_alloc(&p->data, PACTYPE_SIZE); + if (ret) { + free (p->pac); + free(p); + krb5_set_error_string(context, "out of memory"); + return ret; + } + + + *pac = p; + return 0; +} + +krb5_error_code +krb5_pac_add_buffer(krb5_context context, struct krb5_pac *p, + uint32_t type, const krb5_data *data) +{ + krb5_error_code ret; + void *ptr; + size_t len, offset, header_end; + uint32_t i; + + len = p->pac->numbuffers + 1; + if (len < p->pac->numbuffers) + return EINVAL; + + ptr = realloc(p->pac, + sizeof(*p->pac) + (sizeof(p->pac->buffers[0]) * len)); + if (ptr == NULL) { + krb5_set_error_string(context, "out of memory"); + return ENOMEM; + } + p->pac = ptr; + + for (i = 0; i < len; i++) + p->pac->buffers[i].offset_lo += PAC_INFO_BUFFER_SIZE; + + offset = p->data.length + PAC_INFO_BUFFER_SIZE; + + p->pac->buffers[len - 1].type = type; + p->pac->buffers[len - 1].buffersize = data->length; + p->pac->buffers[len - 1].offset_lo = offset; + p->pac->buffers[len - 1].offset_hi = 0; + + len = p->data.length + data->length + PAC_INFO_BUFFER_SIZE; + if (len < p->data.length) { + krb5_set_error_string(context, "integer overrun"); + return EINVAL; + } + + /* align to PAC_ALIGNMENT */ + len = ((len + PAC_ALIGNMENT - 1) / PAC_ALIGNMENT) * PAC_ALIGNMENT; + + ret = krb5_data_realloc(&p->data, len); + if (ret) { + krb5_set_error_string(context, "out of memory"); + return ret; + } + + /* make place for PAC INFO BUFFER header */ + header_end = PACTYPE_SIZE + (PAC_INFO_BUFFER_SIZE * p->pac->numbuffers); + memmove((unsigned char *)p->data.data + header_end, + (unsigned char *)p->data.data + header_end + PAC_INFO_BUFFER_SIZE, + PAC_INFO_BUFFER_SIZE); + + /* + * + */ + + memcpy((unsigned char *)p->data.data + offset, + data->data, data->length); + memset((unsigned char *)p->data.data + offset + data->length, + 0, p->data.length - offset - data->length); + + p->pac->numbuffers += 1; + + return 0; +} + +krb5_error_code +krb5_pac_get_buffer(krb5_context context, struct krb5_pac *p, + uint32_t type, krb5_data *data) +{ + krb5_error_code ret; + uint32_t i; + + /* + * Hide the checksums from external consumers + */ + + if (type == PAC_PRIVSVR_CHECKSUM || type == PAC_SERVER_CHECKSUM) { + ret = krb5_data_alloc(data, 16); + if (ret) { + krb5_set_error_string(context, "out of memory"); + return ret; + } + memset(data->data, 0, data->length); + return 0; + } + + for (i = 0; i < p->pac->numbuffers; i++) { + size_t len = p->pac->buffers[i].buffersize; + size_t offset = p->pac->buffers[i].offset_lo; + + if (p->pac->buffers[i].type != type) + continue; + + ret = krb5_data_copy(data, (unsigned char *)p->data.data + offset, len); + if (ret) { + krb5_set_error_string(context, "Out of memory"); + return ret; + } + return 0; + } + krb5_set_error_string(context, "No PAC buffer of type %lu was found", + (unsigned long)type); + return ENOENT; +} + +/* + * + */ + +krb5_error_code +krb5_pac_get_types(krb5_context context, + struct krb5_pac *p, + size_t *len, + uint32_t **types) +{ + size_t i; + + *types = calloc(p->pac->numbuffers, sizeof(*types)); + if (*types == NULL) { + *len = 0; + krb5_set_error_string(context, "out of memory"); + return ENOMEM; + } + for (i = 0; i < p->pac->numbuffers; i++) + (*types)[i] = p->pac->buffers[i].type; + *len = p->pac->numbuffers; + + return 0; +} + +/* + * + */ + +void +krb5_pac_free(krb5_context context, struct krb5_pac *pac) +{ + krb5_data_free(&pac->data); + free(pac->pac); + free(pac); +} + +/* + * + */ + +static krb5_error_code +verify_checksum(krb5_context context, + const struct PAC_INFO_BUFFER *sig, + const krb5_data *data, + void *ptr, size_t len, + const krb5_keyblock *key) +{ + krb5_crypto crypto = NULL; + krb5_storage *sp = NULL; + uint32_t type; + krb5_error_code ret; + Checksum cksum; + + sp = krb5_storage_from_mem((char *)data->data + sig->offset_lo, + sig->buffersize); + if (sp == NULL) { + krb5_set_error_string(context, "out of memory"); + return ENOMEM; + } + krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); + + CHECK(ret, krb5_ret_uint32(sp, &type), out); + cksum.cksumtype = type; + cksum.checksum.length = + sig->buffersize - krb5_storage_seek(sp, 0, SEEK_CUR); + cksum.checksum.data = malloc(cksum.checksum.length); + if (cksum.checksum.data == NULL) { + krb5_set_error_string(context, "out of memory"); + ret = ENOMEM; + goto out; + } + ret = krb5_storage_read(sp, cksum.checksum.data, cksum.checksum.length); + if (ret != cksum.checksum.length) { + krb5_set_error_string(context, "PAC checksum missing checksum"); + ret = EINVAL; + goto out; + } + + if (!krb5_checksum_is_keyed(context, cksum.cksumtype)) { + krb5_set_error_string (context, "Checksum type %d not keyed", + cksum.cksumtype); + ret = EINVAL; + goto out; + } + + ret = krb5_crypto_init(context, key, 0, &crypto); + if (ret) + goto out; + + ret = krb5_verify_checksum(context, crypto, KRB5_KU_OTHER_CKSUM, + ptr, len, &cksum); + krb5_crypto_destroy(context, crypto); + krb5_storage_free(sp); + + return ret; + +out: + if (sp) + krb5_storage_free(sp); + if (crypto) + krb5_crypto_destroy(context, crypto); + return ret; +} + +static krb5_error_code +create_checksum(krb5_context context, + const krb5_keyblock *key, + void *data, size_t datalen, + void *sig, size_t siglen) +{ + krb5_crypto crypto = NULL; + krb5_error_code ret; + Checksum cksum; + + ret = krb5_crypto_init(context, key, 0, &crypto); + if (ret) + return ret; + + ret = krb5_create_checksum(context, crypto, KRB5_KU_OTHER_CKSUM, 0, + data, datalen, &cksum); + krb5_crypto_destroy(context, crypto); + if (ret) + return ret; + + if (cksum.checksum.length != siglen) { + krb5_set_error_string(context, "pac checksum wrong length"); + free_Checksum(&cksum); + return EINVAL; + } + + memcpy(sig, cksum.checksum.data, siglen); + free_Checksum(&cksum); + + return 0; +} + + +/* + * + */ + +#define NTTIME_EPOCH 0x019DB1DED53E8000LL + +static uint64_t +unix2nttime(time_t unix_time) +{ + long long wt; + wt = unix_time * (uint64_t)10000000 + (uint64_t)NTTIME_EPOCH; + return wt; +} + +static krb5_error_code +verify_logonname(krb5_context context, + const struct PAC_INFO_BUFFER *logon_name, + const krb5_data *data, + time_t authtime, + krb5_const_principal principal) +{ + krb5_error_code ret; + krb5_principal p2; + uint32_t time1, time2; + krb5_storage *sp; + uint16_t len; + char *s; + + sp = krb5_storage_from_readonly_mem((const char *)data->data + logon_name->offset_lo, + logon_name->buffersize); + if (sp == NULL) { + krb5_set_error_string(context, "Out of memory"); + return ENOMEM; + } + + krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); + + CHECK(ret, krb5_ret_uint32(sp, &time1), out); + CHECK(ret, krb5_ret_uint32(sp, &time2), out); + + { + uint64_t t1, t2; + t1 = unix2nttime(authtime); + t2 = ((uint64_t)time2 << 32) | time1; + if (t1 != t2) { + krb5_storage_free(sp); + krb5_set_error_string(context, "PAC timestamp mismatch"); + return EINVAL; + } + } + CHECK(ret, krb5_ret_uint16(sp, &len), out); + if (len == 0) { + krb5_storage_free(sp); + krb5_set_error_string(context, "PAC logon name length missing"); + return EINVAL; + } + + s = malloc(len); + if (s == NULL) { + krb5_storage_free(sp); + krb5_set_error_string(context, "Out of memory"); + return ENOMEM; + } + ret = krb5_storage_read(sp, s, len); + if (ret != len) { + krb5_storage_free(sp); + krb5_set_error_string(context, "Failed to read pac logon name"); + return EINVAL; + } + krb5_storage_free(sp); +#if 1 /* cheat for now */ + { + size_t i; + + if (len & 1) { + krb5_set_error_string(context, "PAC logon name malformed"); + return EINVAL; + } + + for (i = 0; i < len / 2; i++) { + if (s[(i * 2) + 1]) { + krb5_set_error_string(context, "PAC logon name not ASCII"); + return EINVAL; + } + s[i] = s[i * 2]; + } + s[i] = '\0'; + } +#else + { + uint16_t *ucs2; + ssize_t ucs2len; + size_t u8len; + + ucs2 = malloc(sizeof(ucs2[0]) * len / 2); + if (ucs2) + abort(); + ucs2len = wind_ucs2read(s, len / 2, ucs2); + free(s); + if (len < 0) + return -1; + ret = wind_ucs2toutf8(ucs2, ucs2len, NULL, &u8len); + if (ret < 0) + abort(); + s = malloc(u8len + 1); + if (s == NULL) + abort(); + wind_ucs2toutf8(ucs2, ucs2len, s, &u8len); + free(ucs2); + } +#endif + ret = krb5_parse_name_flags(context, s, KRB5_PRINCIPAL_PARSE_NO_REALM, &p2); + free(s); + if (ret) + return ret; + + if (krb5_principal_compare_any_realm(context, principal, p2) != TRUE) { + krb5_set_error_string(context, "PAC logon name mismatch"); + ret = EINVAL; + } + krb5_free_principal(context, p2); + return ret; +out: + return ret; +} + +/* + * + */ + +static krb5_error_code +build_logon_name(krb5_context context, + time_t authtime, + krb5_const_principal principal, + krb5_data *logon) +{ + krb5_error_code ret; + krb5_storage *sp; + uint64_t t; + char *s, *s2; + size_t i, len; + + t = unix2nttime(authtime); + + krb5_data_zero(logon); + + sp = krb5_storage_emem(); + if (sp == NULL) { + krb5_set_error_string(context, "out of memory"); + return ENOMEM; + } + krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); + + CHECK(ret, krb5_store_uint32(sp, t & 0xffffffff), out); + CHECK(ret, krb5_store_uint32(sp, t >> 32), out); + + ret = krb5_unparse_name_flags(context, principal, + KRB5_PRINCIPAL_UNPARSE_NO_REALM, &s); + if (ret) + goto out; + + len = strlen(s); + + CHECK(ret, krb5_store_uint16(sp, len * 2), out); + +#if 1 /* cheat for now */ + s2 = malloc(len * 2); + if (s2 == NULL) { + ret = ENOMEM; + free(s); + goto out; + } + for (i = 0; i < len; i++) { + s2[i * 2] = s[i]; + s2[i * 2 + 1] = 0; + } + free(s); +#else + /* write libwind code here */ +#endif + + ret = krb5_storage_write(sp, s2, len * 2); + free(s2); + if (ret != len * 2) { + ret = ENOMEM; + goto out; + } + ret = krb5_storage_to_data(sp, logon); + if (ret) + goto out; + krb5_storage_free(sp); + + return 0; +out: + krb5_storage_free(sp); + return ret; +} + + +/* + * + */ + +krb5_error_code +krb5_pac_verify(krb5_context context, + const struct krb5_pac *pac, + time_t authtime, + krb5_const_principal principal, + const krb5_keyblock *server, + const krb5_keyblock *privsvr) +{ + krb5_error_code ret; + + if (pac->server_checksum == NULL) { + krb5_set_error_string(context, "PAC missing server checksum"); + return EINVAL; + } + if (pac->privsvr_checksum == NULL) { + krb5_set_error_string(context, "PAC missing kdc checksum"); + return EINVAL; + } + if (pac->logon_name == NULL) { + krb5_set_error_string(context, "PAC missing logon name"); + return EINVAL; + } + + ret = verify_logonname(context, + pac->logon_name, + &pac->data, + authtime, + principal); + if (ret) + return ret; + + /* + * in the service case, clean out data option of the privsvr and + * server checksum before checking the checksum. + */ + { + krb5_data *copy; + + ret = krb5_copy_data(context, &pac->data, ©); + if (ret) + return ret; + + if (pac->server_checksum->buffersize < 4) + return EINVAL; + if (pac->privsvr_checksum->buffersize < 4) + return EINVAL; + + memset((char *)copy->data + pac->server_checksum->offset_lo + 4, + 0, + pac->server_checksum->buffersize - 4); + + memset((char *)copy->data + pac->privsvr_checksum->offset_lo + 4, + 0, + pac->privsvr_checksum->buffersize - 4); + + ret = verify_checksum(context, + pac->server_checksum, + &pac->data, + copy->data, + copy->length, + server); + krb5_free_data(context, copy); + if (ret) + return ret; + } + if (privsvr) { + ret = verify_checksum(context, + pac->privsvr_checksum, + &pac->data, + (char *)pac->data.data + + pac->server_checksum->offset_lo + 4, + pac->server_checksum->buffersize - 4, + privsvr); + if (ret) + return ret; + } + + return 0; +} + +/* + * + */ + +static krb5_error_code +fill_zeros(krb5_context context, krb5_storage *sp, size_t len) +{ + ssize_t sret; + size_t l; + + while (len) { + l = len; + if (l > sizeof(zeros)) + l = sizeof(zeros); + sret = krb5_storage_write(sp, zeros, l); + if (sret <= 0) { + krb5_set_error_string(context, "out of memory"); + return ENOMEM; + } + len -= sret; + } + return 0; +} + +static krb5_error_code +pac_checksum(krb5_context context, + const krb5_keyblock *key, + uint32_t *cksumtype, + size_t *cksumsize) +{ + krb5_cksumtype cktype; + krb5_error_code ret; + krb5_crypto crypto = NULL; + + ret = krb5_crypto_init(context, key, 0, &crypto); + if (ret) + return ret; + + ret = krb5_crypto_get_checksum_type(context, crypto, &cktype); + ret = krb5_crypto_destroy(context, crypto); + if (ret) + return ret; + + if (krb5_checksum_is_keyed(context, cktype) == FALSE) { + krb5_set_error_string(context, "PAC checksum type is not keyed"); + return EINVAL; + } + + ret = krb5_checksumsize(context, cktype, cksumsize); + if (ret) + return ret; + + *cksumtype = (uint32_t)cktype; + + return 0; +} + +krb5_error_code +_krb5_pac_sign(krb5_context context, + struct krb5_pac *p, + time_t authtime, + krb5_principal principal, + const krb5_keyblock *server_key, + const krb5_keyblock *priv_key, + krb5_data *data) +{ + krb5_error_code ret; + krb5_storage *sp = NULL, *spdata = NULL; + uint32_t end; + size_t server_size, priv_size; + uint32_t server_offset = 0, priv_offset = 0; + uint32_t server_cksumtype = 0, priv_cksumtype = 0; + int i, num = 0; + krb5_data logon, d; + + krb5_data_zero(&logon); + + if (p->server_checksum == NULL) + num++; + if (p->privsvr_checksum == NULL) + num++; + if (p->logon_name == NULL) + num++; + + if (num) { + void *ptr; + + ptr = realloc(p->pac, sizeof(*p->pac) + (sizeof(p->pac->buffers[0]) * (p->pac->numbuffers + num - 1))); + if (ptr == NULL) { + krb5_set_error_string(context, "out of memory"); + return ENOMEM; + } + p->pac = ptr; + + if (p->server_checksum == NULL) { + p->server_checksum = &p->pac->buffers[p->pac->numbuffers++]; + memset(p->server_checksum, 0, sizeof(*p->server_checksum)); + p->server_checksum->type = PAC_SERVER_CHECKSUM; + } + if (p->privsvr_checksum == NULL) { + p->privsvr_checksum = &p->pac->buffers[p->pac->numbuffers++]; + memset(p->privsvr_checksum, 0, sizeof(*p->privsvr_checksum)); + p->privsvr_checksum->type = PAC_PRIVSVR_CHECKSUM; + } + if (p->logon_name == NULL) { + p->logon_name = &p->pac->buffers[p->pac->numbuffers++]; + memset(p->logon_name, 0, sizeof(*p->logon_name)); + p->logon_name->type = PAC_LOGON_NAME; + } + } + + /* Calculate LOGON NAME */ + ret = build_logon_name(context, authtime, principal, &logon); + if (ret) + goto out; + + /* Set lengths for checksum */ + + ret = pac_checksum(context, server_key, &server_cksumtype, &server_size); + if (ret) + goto out; + ret = pac_checksum(context, priv_key, &priv_cksumtype, &priv_size); + if (ret) + goto out; + + /* Encode PAC */ + sp = krb5_storage_emem(); + if (sp == NULL) { + krb5_set_error_string(context, "out of memory"); + return ENOMEM; + } + krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); + + spdata = krb5_storage_emem(); + if (spdata == NULL) { + krb5_storage_free(sp); + krb5_set_error_string(context, "out of memory"); + return ENOMEM; + } + krb5_storage_set_flags(spdata, KRB5_STORAGE_BYTEORDER_LE); + + CHECK(ret, krb5_store_uint32(sp, p->pac->numbuffers), out); + CHECK(ret, krb5_store_uint32(sp, p->pac->version), out); + + end = PACTYPE_SIZE + (PAC_INFO_BUFFER_SIZE * p->pac->numbuffers); + + for (i = 0; i < p->pac->numbuffers; i++) { + uint32_t len; + size_t sret; + void *ptr = NULL; + + /* store data */ + + if (p->pac->buffers[i].type == PAC_SERVER_CHECKSUM) { + len = server_size + 4; + server_offset = end + 4; + CHECK(ret, krb5_store_uint32(spdata, server_cksumtype), out); + CHECK(ret, fill_zeros(context, spdata, server_size), out); + } else if (p->pac->buffers[i].type == PAC_PRIVSVR_CHECKSUM) { + len = priv_size + 4; + priv_offset = end + 4; + CHECK(ret, krb5_store_uint32(spdata, priv_cksumtype), out); + CHECK(ret, fill_zeros(context, spdata, priv_size), out); + } else if (p->pac->buffers[i].type == PAC_LOGON_NAME) { + len = krb5_storage_write(spdata, logon.data, logon.length); + if (logon.length != len) { + ret = EINVAL; + goto out; + } + } else { + len = p->pac->buffers[i].buffersize; + ptr = (char *)p->data.data + p->pac->buffers[i].offset_lo; + + sret = krb5_storage_write(spdata, ptr, len); + if (sret != len) { + krb5_set_error_string(context, "out of memory"); + ret = ENOMEM; + goto out; + } + /* XXX if not aligned, fill_zeros */ + } + + /* write header */ + CHECK(ret, krb5_store_uint32(sp, p->pac->buffers[i].type), out); + CHECK(ret, krb5_store_uint32(sp, len), out); + CHECK(ret, krb5_store_uint32(sp, end), out); + CHECK(ret, krb5_store_uint32(sp, 0), out); + + /* advance data endpointer and align */ + { + int32_t e; + + end += len; + e = ((end + PAC_ALIGNMENT - 1) / PAC_ALIGNMENT) * PAC_ALIGNMENT; + if (end != e) { + CHECK(ret, fill_zeros(context, spdata, e - end), out); + } + end = e; + } + + } + + /* assert (server_offset != 0 && priv_offset != 0); */ + + /* export PAC */ + ret = krb5_storage_to_data(spdata, &d); + if (ret) { + krb5_set_error_string(context, "out of memory"); + goto out; + } + ret = krb5_storage_write(sp, d.data, d.length); + if (ret != d.length) { + krb5_data_free(&d); + krb5_set_error_string(context, "out of memory"); + ret = ENOMEM; + goto out; + } + krb5_data_free(&d); + + ret = krb5_storage_to_data(sp, &d); + if (ret) { + krb5_set_error_string(context, "out of memory"); + goto out; + } + + /* sign */ + + ret = create_checksum(context, server_key, + d.data, d.length, + (char *)d.data + server_offset, server_size); + if (ret) { + krb5_data_free(&d); + goto out; + } + + ret = create_checksum(context, priv_key, + (char *)d.data + server_offset, server_size, + (char *)d.data + priv_offset, priv_size); + if (ret) { + krb5_data_free(&d); + goto out; + } + + /* done */ + *data = d; + + krb5_data_free(&logon); + krb5_storage_free(sp); + krb5_storage_free(spdata); + + return 0; +out: + krb5_data_free(&logon); + if (sp) + krb5_storage_free(sp); + if (spdata) + krb5_storage_free(spdata); + return ret; +} diff --git a/source4/heimdal/lib/krb5/pkinit.c b/source4/heimdal/lib/krb5/pkinit.c index f519b5ad08..4f8ed8fe07 100755 --- a/source4/heimdal/lib/krb5/pkinit.c +++ b/source4/heimdal/lib/krb5/pkinit.c @@ -33,7 +33,7 @@ #include "krb5_locl.h" -RCSID("$Id: pkinit.c,v 1.110 2006/10/14 09:52:50 lha Exp $"); +RCSID("$Id: pkinit.c,v 1.120 2006/12/08 02:48:09 lha Exp $"); struct krb5_dh_moduli { char *name; @@ -81,12 +81,26 @@ struct krb5_pk_init_ctx_data { DH *dh; krb5_data *clientDHNonce; struct krb5_dh_moduli **m; + hx509_peer_info peer; + int type; int require_binding; int require_eku; int require_krbtgt_otherName; int require_hostname_match; }; +static void +_krb5_pk_copy_error(krb5_context context, + hx509_context hx509ctx, + int hxret, + const char *fmt, + ...) + __attribute__ ((format (printf, 4, 5))); + +/* + * + */ + void KRB5_LIB_FUNCTION _krb5_pk_cert_free(struct krb5_pk_cert *cert) { @@ -130,6 +144,7 @@ _krb5_pk_create_sign(krb5_context context, const heim_oid *eContentType, krb5_data *eContent, struct krb5_pk_identity *id, + hx509_peer_info peer, krb5_data *sd_data) { hx509_cert cert; @@ -137,16 +152,22 @@ _krb5_pk_create_sign(krb5_context context, int ret; ret = hx509_query_alloc(id->hx509ctx, &q); - if (ret) + if (ret) { + _krb5_pk_copy_error(context, id->hx509ctx, ret, + "Allocate query to find signing certificate"); return ret; + } hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE); ret = hx509_certs_find(id->hx509ctx, id->certs, q, &cert); hx509_query_free(id->hx509ctx, q); - if (ret) + if (ret) { + _krb5_pk_copy_error(context, id->hx509ctx, ret, + "Find certificate to signed CMS data"); return ret; + } ret = hx509_cms_create_signed_1(id->hx509ctx, eContentType, @@ -154,9 +175,12 @@ _krb5_pk_create_sign(krb5_context context, eContent->length, NULL, cert, + peer, NULL, - NULL, + id->certs, sd_data); + if (ret) + _krb5_pk_copy_error(context, id->hx509ctx, ret, "create CMS signedData"); hx509_cert_free(cert); return ret; @@ -402,6 +426,19 @@ build_auth_pack(krb5_context context, a->clientPublicValue->subjectPublicKey.data = dhbuf.data; } + { + a->supportedCMSTypes = calloc(1, sizeof(*a->supportedCMSTypes)); + if (a->supportedCMSTypes == NULL) + return ENOMEM; + + ret = hx509_crypto_available(ctx->id->hx509ctx, HX509_SELECT_ALL, NULL, + &a->supportedCMSTypes->val, + &a->supportedCMSTypes->len); + if (ret) + return ret; + } + + return ret; } @@ -429,7 +466,6 @@ _krb5_pk_mk_ContentInfo(krb5_context context, static krb5_error_code pk_mk_padata(krb5_context context, - int compat, krb5_pk_init_ctx ctx, const KDC_REQ_BODY *req_body, unsigned nonce, @@ -446,7 +482,7 @@ pk_mk_padata(krb5_context context, krb5_data_zero(&sd_buf); memset(&content_info, 0, sizeof(content_info)); - if (compat == COMPAT_WIN2K) { + if (ctx->type == COMPAT_WIN2K) { AuthPack_Win2k ap; krb5_timestamp sec; int32_t usec; @@ -483,7 +519,7 @@ pk_mk_padata(krb5_context context, krb5_abortx(context, "internal ASN1 encoder error"); oid = oid_id_pkcs7_data(); - } else if (compat == COMPAT_IETF) { + } else if (ctx->type == COMPAT_IETF) { AuthPack ap; memset(&ap, 0, sizeof(ap)); @@ -510,7 +546,8 @@ pk_mk_padata(krb5_context context, ret = _krb5_pk_create_sign(context, oid, &buf, - ctx->id, + ctx->id, + ctx->peer, &sd_buf); krb5_data_free(&buf); if (ret) @@ -529,7 +566,7 @@ pk_mk_padata(krb5_context context, if (buf.length != size) krb5_abortx(context, "Internal ASN1 encoder error"); - if (compat == COMPAT_WIN2K) { + if (ctx->type == COMPAT_WIN2K) { PA_PK_AS_REQ_Win2k winreq; pa_type = KRB5_PADATA_PK_AS_REQ_WIN; @@ -542,7 +579,7 @@ pk_mk_padata(krb5_context context, &winreq, &size, ret); free_PA_PK_AS_REQ_Win2k(&winreq); - } else if (compat == COMPAT_IETF) { + } else if (ctx->type == COMPAT_IETF) { PA_PK_AS_REQ req; pa_type = KRB5_PADATA_PK_AS_REQ; @@ -583,7 +620,7 @@ pk_mk_padata(krb5_context context, if (ret) free(buf.data); - if (ret == 0 && compat == COMPAT_WIN2K) + if (ret == 0 && ctx->type == COMPAT_WIN2K) krb5_padata_add(context, md, KRB5_PADATA_PK_AS_09_BINDING, NULL, 0); out: @@ -601,13 +638,13 @@ _krb5_pk_mk_padata(krb5_context context, METHOD_DATA *md) { krb5_pk_init_ctx ctx = c; - int win2k_compat, type; + int win2k_compat; win2k_compat = krb5_config_get_bool_default(context, NULL, FALSE, "realms", req_body->realm, - "win2k_pkinit", + "pkinit_win2k", NULL); if (context->pkinit_flags & KRB5_PKINIT_WIN2K) win2k_compat = 1; @@ -618,11 +655,11 @@ _krb5_pk_mk_padata(krb5_context context, FALSE, "realms", req_body->realm, - "win2k_pkinit_require_binding", + "pkinit_win2k_require_binding", NULL); - type = COMPAT_WIN2K; + ctx->type = COMPAT_WIN2K; } else - type = COMPAT_IETF; + ctx->type = COMPAT_IETF; ctx->require_eku = krb5_config_get_bool_default(context, NULL, @@ -647,7 +684,7 @@ _krb5_pk_mk_padata(krb5_context context, "pkinit_require_hostname_match", NULL); - return pk_mk_padata(context, type, ctx, req_body, nonce, md); + return pk_mk_padata(context, ctx, req_body, nonce, md); } krb5_error_code KRB5_LIB_FUNCTION @@ -673,13 +710,8 @@ _krb5_pk_verify_sign(krb5_context context, content, &signer_certs); if (ret) { - char *s = hx509_get_error_string(id->hx509ctx, ret); - if (s) { - krb5_set_error_string(context, - "CMS verify signed failed with %s", s); - free(s); - } else - krb5_clear_error_string(context); + _krb5_pk_copy_error(context, id->hx509ctx, ret, + "CMS verify signed failed"); return ret; } @@ -692,7 +724,8 @@ _krb5_pk_verify_sign(krb5_context context, ret = hx509_get_one_cert(id->hx509ctx, signer_certs, &(*signer)->cert); if (ret) { - krb5_clear_error_string(context); + _krb5_pk_copy_error(context, id->hx509ctx, ret, + "Failed to get on of the signer certs"); goto out; } @@ -932,8 +965,11 @@ pk_rd_pa_reply_enckey(krb5_context context, NULL, &contentType, &content); - if (ret) + if (ret) { + _krb5_pk_copy_error(context, ctx->id->hx509ctx, ret, + "Failed to unenvelope CMS data in PK-INIT reply"); return ret; + } p = content.data; length = content.length; @@ -1212,8 +1248,13 @@ _krb5_pk_rd_pa_reply(krb5_context context, size_t size; /* Check for IETF PK-INIT first */ - if (pa->padata_type == KRB5_PADATA_PK_AS_REP) { + if (ctx->type == COMPAT_IETF) { PA_PK_AS_REP rep; + + if (pa->padata_type != KRB5_PADATA_PK_AS_REP) { + krb5_set_error_string(context, "PKINIT: wrong padata recv"); + return EINVAL; + } memset(&rep, 0, sizeof(rep)); @@ -1269,14 +1310,19 @@ _krb5_pk_rd_pa_reply(krb5_context context, ret = EINVAL; break; } - if (ret == 0) - return ret; - } - /* Check for Windows encoding of the AS-REP pa data */ - { + } else if (ctx->type == COMPAT_WIN2K) { PA_PK_AS_REP_Win2k w2krep; + /* Check for Windows encoding of the AS-REP pa data */ + +#if 0 /* should this be ? */ + if (pa->padata_type != KRB5_PADATA_PK_AS_REP) { + krb5_set_error_string(context, "PKINIT: wrong padata recv"); + return EINVAL; + } +#endif + memset(&w2krep, 0, sizeof(w2krep)); ret = decode_PA_PK_AS_REP_Win2k(pa->padata_value.data, @@ -1317,6 +1363,9 @@ _krb5_pk_rd_pa_reply(krb5_context context, break; } + } else { + krb5_set_error_string(context, "PKINIT: unknown reply type"); + ret = EINVAL; } return ret; @@ -1428,25 +1477,34 @@ _krb5_pk_load_id(krb5_context context, } ret = hx509_certs_init(id->hx509ctx, user_id, 0, lock, &id->certs); - if (ret) + if (ret) { + _krb5_pk_copy_error(context, id->hx509ctx, ret, + "Failed to init cert certs"); goto out; + } ret = hx509_certs_init(id->hx509ctx, anchor_id, 0, NULL, &id->anchors); - if (ret) + if (ret) { + _krb5_pk_copy_error(context, id->hx509ctx, ret, + "Failed to init anchors"); goto out; + } ret = hx509_certs_init(id->hx509ctx, "MEMORY:pkinit-cert-chain", 0, NULL, &id->certpool); - if (ret) + if (ret) { + _krb5_pk_copy_error(context, id->hx509ctx, ret, + "Failed to init chain"); goto out; + } while (chain_list && *chain_list) { ret = hx509_certs_append(id->hx509ctx, id->certpool, NULL, *chain_list); if (ret) { - krb5_set_error_string(context, - "pkinit failed to load chain %s", - *chain_list); + _krb5_pk_copy_error(context, id->hx509ctx, ret, + "Failed to laod chain %s", + *chain_list); goto out; } chain_list++; @@ -1455,7 +1513,8 @@ _krb5_pk_load_id(krb5_context context, if (revoke_list) { ret = hx509_revoke_init(id->hx509ctx, &id->revokectx); if (ret) { - krb5_set_error_string(context, "revoke failed to init"); + _krb5_pk_copy_error(context, id->hx509ctx, ret, + "Failed init revoke list"); goto out; } @@ -1464,9 +1523,8 @@ _krb5_pk_load_id(krb5_context context, id->revokectx, *revoke_list); if (ret) { - krb5_set_error_string(context, - "pkinit failed to load revoke %s", - *revoke_list); + _krb5_pk_copy_error(context, id->hx509ctx, ret, + "Failed load revoke list"); goto out; } revoke_list++; @@ -1475,8 +1533,11 @@ _krb5_pk_load_id(krb5_context context, hx509_context_set_missing_revoke(id->hx509ctx, 1); ret = hx509_verify_init_ctx(id->hx509ctx, &id->verify_ctx); - if (ret) + if (ret) { + _krb5_pk_copy_error(context, id->hx509ctx, ret, + "Failed init verify context"); goto out; + } hx509_verify_attach_anchors(id->verify_ctx, id->anchors); hx509_verify_attach_revoke(id->verify_ctx, id->revokectx); @@ -1504,9 +1565,25 @@ select_dh_group(krb5_context context, DH *dh, unsigned long bits, { const struct krb5_dh_moduli *m; - m = moduli[1]; /* XXX */ - if (m == NULL) - m = moduli[0]; /* XXX */ + if (bits == 0) { + m = moduli[1]; /* XXX */ + if (m == NULL) + m = moduli[0]; /* XXX */ + } else { + int i; + for (i = 0; moduli[i] != NULL; i++) { + if (bits < moduli[i]->bits) + break; + } + if (moduli[i] == NULL) { + krb5_set_error_string(context, + "Did not find a DH group parameter " + "matching requirement of %lu bits", + bits); + return EINVAL; + } + m = moduli[i]; + } dh->p = integer_to_BN(context, "p", &m->p); if (dh->p == NULL) @@ -1822,25 +1899,25 @@ krb5_get_init_creds_opt_set_pkinit(krb5_context context, opt->opt_private->pk_init_ctx->require_binding = 0; opt->opt_private->pk_init_ctx->require_eku = 1; opt->opt_private->pk_init_ctx->require_krbtgt_otherName = 1; - + opt->opt_private->pk_init_ctx->peer = NULL; /* XXX implement krb5_appdefault_strings */ if (pool == NULL) pool = krb5_config_get_strings(context, NULL, "appdefaults", - "pkinit-pool", + "pkinit_pool", NULL); if (pki_revoke == NULL) pki_revoke = krb5_config_get_strings(context, NULL, "appdefaults", - "pkinit-revoke", + "pkinit_revoke", NULL); if (x509_anchors == NULL) { krb5_appdefault_string(context, "kinit", krb5_principal_get_realm(context, principal), - "pkinit-anchors", NULL, &anchors); + "pkinit_anchors", NULL, &anchors); x509_anchors = anchors; } @@ -1861,12 +1938,19 @@ krb5_get_init_creds_opt_set_pkinit(krb5_context context, if ((flags & 2) == 0) { const char *moduli_file; + unsigned long dh_min_bits; moduli_file = krb5_config_get_string(context, NULL, "libdefaults", "moduli", NULL); + dh_min_bits = + krb5_config_get_int_default(context, NULL, 0, + "libdefaults", + "pkinit_dh_min_bits", + NULL); + ret = _krb5_parse_moduli(context, moduli_file, &opt->opt_private->pk_init_ctx->m); if (ret) { @@ -1881,7 +1965,8 @@ krb5_get_init_creds_opt_set_pkinit(krb5_context context, return ENOMEM; } - ret = select_dh_group(context, opt->opt_private->pk_init_ctx->dh, 0, + ret = select_dh_group(context, opt->opt_private->pk_init_ctx->dh, + dh_min_bits, opt->opt_private->pk_init_ctx->m); if (ret) { _krb5_get_init_creds_opt_free_pkinit(opt); @@ -1901,3 +1986,36 @@ krb5_get_init_creds_opt_set_pkinit(krb5_context context, return EINVAL; #endif } + +/* + * + */ + +static void +_krb5_pk_copy_error(krb5_context context, + hx509_context hx509ctx, + int hxret, + const char *fmt, + ...) +{ + va_list va; + char *s, *f; + + va_start(va, fmt); + vasprintf(&f, fmt, va); + va_end(va); + if (f == NULL) { + krb5_clear_error_string(context); + return; + } + + s = hx509_get_error_string(hx509ctx, hxret); + if (s == NULL) { + krb5_clear_error_string(context); + free(f); + return; + } + krb5_set_error_string(context, "%s: %s", f, s); + free(s); + free(f); +} diff --git a/source4/heimdal/lib/krb5/plugin.c b/source4/heimdal/lib/krb5/plugin.c index 294807faab..ce7171dbf0 100644 --- a/source4/heimdal/lib/krb5/plugin.c +++ b/source4/heimdal/lib/krb5/plugin.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. * @@ -32,7 +32,7 @@ */ #include "krb5_locl.h" -RCSID("$Id: plugin.c,v 1.2 2006/11/12 21:39:43 lha Exp $"); +RCSID("$Id: plugin.c,v 1.4 2007/01/09 17:46:01 lha Exp $"); #ifdef HAVE_DLFCN_H #include <dlfcn.h> #endif @@ -89,7 +89,11 @@ loadlib(krb5_context context, return ENOMEM; } - (*e)->dsohandle = dlopen(lib, 0); +#ifndef RTLD_LAZY +#define RTLD_LAZY 0 +#endif + + (*e)->dsohandle = dlopen(lib, RTLD_LAZY); if ((*e)->dsohandle == NULL) { free(*e); krb5_set_error_string(context, "Failed to load %s: %s", diff --git a/source4/heimdal/lib/krb5/principal.c b/source4/heimdal/lib/krb5/principal.c index 4d13e7db11..57fcf63dcf 100644 --- a/source4/heimdal/lib/krb5/principal.c +++ b/source4/heimdal/lib/krb5/principal.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-2002 Kungliga Tekniska Högskolan + * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -41,7 +41,7 @@ #include <fnmatch.h> #include "resolve.h" -RCSID("$Id: principal.c,v 1.99 2006/10/18 06:53:22 lha Exp $"); +RCSID("$Id: principal.c,v 1.100 2006/12/17 22:53:39 lha Exp $"); #define princ_num_comp(P) ((P)->name.name_string.len) #define princ_type(P) ((P)->name.name_type) diff --git a/source4/heimdal/lib/krb5/rd_req.c b/source4/heimdal/lib/krb5/rd_req.c index 3352334f65..b7dea2a327 100644 --- a/source4/heimdal/lib/krb5/rd_req.c +++ b/source4/heimdal/lib/krb5/rd_req.c @@ -33,7 +33,7 @@ #include <krb5_locl.h> -RCSID("$Id: rd_req.c,v 1.68 2006/11/07 17:11:31 lha Exp $"); +RCSID("$Id: rd_req.c,v 1.70 2007/01/04 11:27:20 lha Exp $"); static krb5_error_code decrypt_tkt_enc_part (krb5_context context, @@ -513,6 +513,7 @@ krb5_verify_ap_req2(krb5_context context, struct krb5_rd_req_in_ctx { krb5_keytab keytab; krb5_keyblock *keyblock; + krb5_boolean no_pac_check; }; struct krb5_rd_req_out_ctx { @@ -546,6 +547,16 @@ krb5_rd_req_in_set_keytab(krb5_context context, } krb5_error_code KRB5_LIB_FUNCTION +krb5_rd_req_in_set_pac_check(krb5_context context, + krb5_rd_req_in_ctx in, + krb5_boolean flag) +{ + in->no_pac_check = !flag; + return 0; +} + + +krb5_error_code KRB5_LIB_FUNCTION krb5_rd_req_in_set_keyblock(krb5_context context, krb5_rd_req_in_ctx in, krb5_keyblock *keyblock) @@ -822,6 +833,36 @@ krb5_rd_req_ctx(krb5_context context, &o->ap_req_options, &o->ticket); + if (ret) + goto out; + + /* If there is a PAC, verify its server signature */ + if (inctx->no_pac_check == FALSE) { + krb5_pac pac; + krb5_data data; + + ret = krb5_ticket_get_authorization_data_type(context, + o->ticket, + KRB5_AUTHDATA_WIN2K_PAC, + &data); + if (ret == 0) { + ret = krb5_pac_parse(context, data.data, data.length, &pac); + krb5_data_free(&data); + if (ret) + goto out; + + ret = krb5_pac_verify(context, + pac, + o->ticket->ticket.authtime, + o->ticket->client, + o->keyblock, + NULL); + krb5_pac_free(context, pac); + if (ret) + goto out; + } + ret = 0; + } out: if (ret || outctx == NULL) { krb5_rd_req_out_ctx_free(context, o); diff --git a/source4/heimdal/lib/krb5/store.c b/source4/heimdal/lib/krb5/store.c index e75f28ca5f..5422c540b9 100644 --- a/source4/heimdal/lib/krb5/store.c +++ b/source4/heimdal/lib/krb5/store.c @@ -34,7 +34,7 @@ #include "krb5_locl.h" #include "store-int.h" -RCSID("$Id: store.c,v 1.59 2006/08/18 08:39:13 lha Exp $"); +RCSID("$Id: store.c,v 1.60 2006/12/17 22:49:37 lha Exp $"); #define BYTEORDER_IS(SP, V) (((SP)->flags & KRB5_STORAGE_BYTEORDER_MASK) == (V)) #define BYTEORDER_IS_LE(SP) BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_LE) @@ -577,6 +577,7 @@ krb5_ret_principal(krb5_storage *sp, p->name.name_string.val = calloc(ncomp, sizeof(*p->name.name_string.val)); if(p->name.name_string.val == NULL && ncomp != 0){ free(p->realm); + free(p); return ENOMEM; } for(i = 0; i < ncomp; i++){ diff --git a/source4/heimdal/lib/krb5/ticket.c b/source4/heimdal/lib/krb5/ticket.c index fdc2a1b3a5..81372c158e 100644 --- a/source4/heimdal/lib/krb5/ticket.c +++ b/source4/heimdal/lib/krb5/ticket.c @@ -33,7 +33,7 @@ #include "krb5_locl.h" -RCSID("$Id: ticket.c,v 1.15 2006/10/14 09:53:19 lha Exp $"); +RCSID("$Id: ticket.c,v 1.18 2006/12/28 20:49:18 lha Exp $"); krb5_error_code KRB5_LIB_FUNCTION krb5_free_ticket(krb5_context context, @@ -97,6 +97,13 @@ krb5_ticket_get_server(krb5_context context, return krb5_copy_principal(context, ticket->server, server); } +time_t KRB5_LIB_FUNCTION +krb5_ticket_get_endtime(krb5_context context, + const krb5_ticket *ticket) +{ + return ticket->ticket.endtime; +} + static int find_type_in_ad(krb5_context context, int type, @@ -107,10 +114,6 @@ find_type_in_ad(krb5_context context, const AuthorizationData *ad, int level) { - /* It is not an error if nothing in here, that is reported by *found */ - /* Setting a default error causes found to be set to FALSE, on - * recursion to an second embedded authz data even if the first - * element contains the required type */ krb5_error_code ret = 0; int i; @@ -148,8 +151,8 @@ find_type_in_ad(krb5_context context, "IF_RELEVANT with %d", ret); goto out; } - ret = find_type_in_ad(context, type, data, found, 0, sessionkey, - &child, level + 1); + ret = find_type_in_ad(context, type, data, found, FALSE, + sessionkey, &child, level + 1); free_AuthorizationData(&child); if (ret) goto out; @@ -232,19 +235,6 @@ out: return ret; } -int -_krb5_find_type_in_ad(krb5_context context, - int type, - krb5_data *data, - krb5_boolean *found, - krb5_keyblock *sessionkey, - const AuthorizationData *ad) -{ - krb5_data_zero(data); - return find_type_in_ad(context, type, data, found, TRUE, sessionkey, ad, 0); -} - - /* * Extract the authorization data type of `type' from the * 'ticket'. Store the field in `data'. This function is to use for @@ -259,7 +249,9 @@ krb5_ticket_get_authorization_data_type(krb5_context context, { AuthorizationData *ad; krb5_error_code ret; - krb5_boolean found = 0; + krb5_boolean found = FALSE; + + krb5_data_zero(data); ad = ticket->ticket.authorization_data; if (ticket->ticket.authorization_data == NULL) { @@ -267,8 +259,8 @@ krb5_ticket_get_authorization_data_type(krb5_context context, return ENOENT; /* XXX */ } - ret = _krb5_find_type_in_ad(context, type, data, &found, &ticket->ticket.key, - ticket->ticket.authorization_data); + ret = find_type_in_ad(context, type, data, &found, TRUE, + &ticket->ticket.key, ad, 0); if (ret) return ret; if (!found) { diff --git a/source4/heimdal/lib/krb5/warn.c b/source4/heimdal/lib/krb5/warn.c index f9825914ee..4252865301 100644 --- a/source4/heimdal/lib/krb5/warn.c +++ b/source4/heimdal/lib/krb5/warn.c @@ -34,7 +34,7 @@ #include "krb5_locl.h" #include <err.h> -RCSID("$Id: warn.c,v 1.15 2004/05/25 21:46:26 lha Exp $"); +RCSID("$Id: warn.c,v 1.16 2006/11/21 08:06:40 lha Exp $"); static krb5_error_code _warnerr(krb5_context context, int do_errtext, krb5_error_code code, int level, const char *fmt, va_list ap) @@ -203,3 +203,9 @@ krb5_set_warn_dest(krb5_context context, krb5_log_facility *fac) context->warn_dest = fac; return 0; } + +krb5_log_facility * KRB5_LIB_FUNCTION +krb5_get_warn_dest(krb5_context context) +{ + return context->warn_dest; +} |