From 4019064c5d866015a0d78b32dd051ec1dacf8ebf Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 25 Oct 2005 13:43:37 +0000 Subject: r11294: Update Heimdal in Samba4 to lorikeet-heimdal (which is in turn updated to CVS of 2005-10-24). Andrew Bartlett (This used to be commit 939d4f340feaad15d0a6a5da79feba2b2558f174) --- source4/heimdal/kdc/kdc.h | 5 +- source4/heimdal/kdc/kerberos5.c | 15 +- source4/heimdal/kdc/pkinit.c | 285 +++------- source4/heimdal/lib/asn1/der.h | 5 +- source4/heimdal/lib/gssapi/acquire_cred.c | 20 +- source4/heimdal/lib/gssapi/display_status.c | 42 +- source4/heimdal/lib/gssapi/gssapi_locl.h | 8 +- source4/heimdal/lib/gssapi/init_sec_context.c | 19 +- source4/heimdal/lib/hdb/hdb.c | 14 +- source4/heimdal/lib/krb5/acache.c | 110 +++- source4/heimdal/lib/krb5/cache.c | 215 ++++++- source4/heimdal/lib/krb5/init_creds.c | 36 +- source4/heimdal/lib/krb5/init_creds_pw.c | 32 +- source4/heimdal/lib/krb5/keytab_keyfile.c | 75 ++- source4/heimdal/lib/krb5/krb5-private.h | 42 +- source4/heimdal/lib/krb5/krb5-protos.h | 36 +- source4/heimdal/lib/krb5/krb5.h | 9 +- source4/heimdal/lib/krb5/krb5_locl.h | 5 +- source4/heimdal/lib/krb5/krbhst.c | 33 +- source4/heimdal/lib/krb5/mcache.c | 89 ++- source4/heimdal/lib/krb5/pkinit.c | 789 +++++++++++++++----------- source4/heimdal/lib/krb5/rd_cred.c | 53 +- source4/heimdal/lib/roken/roken-common.h | 6 +- source4/heimdal/lib/roken/roken.h | 11 +- 24 files changed, 1264 insertions(+), 690 deletions(-) (limited to 'source4/heimdal') diff --git a/source4/heimdal/kdc/kdc.h b/source4/heimdal/kdc/kdc.h index f186983cef..3d25729d4e 100644 --- a/source4/heimdal/kdc/kdc.h +++ b/source4/heimdal/kdc/kdc.h @@ -35,7 +35,7 @@ */ /* - * $Id: kdc.h,v 1.4 2005/06/30 01:50:42 lha Exp $ + * $Id: kdc.h,v 1.5 2005/10/21 17:11:21 lha Exp $ */ #ifndef __KDC_H__ @@ -74,6 +74,9 @@ typedef struct krb5_kdc_configuration { krb5_boolean enable_pkinit_princ_in_cert; krb5_log_facility *logf; + + int pkinit_dh_min_bits; + } krb5_kdc_configuration; #include diff --git a/source4/heimdal/kdc/kerberos5.c b/source4/heimdal/kdc/kerberos5.c index 3191ab19b7..fdc60761f3 100644 --- a/source4/heimdal/kdc/kerberos5.c +++ b/source4/heimdal/kdc/kerberos5.c @@ -853,11 +853,6 @@ _kdc_as_rep(krb5_context context, i = 0; if ((pa = find_padata(req, &i, KRB5_PADATA_PK_AS_REQ))) ; - if (pa == NULL) { - i = 0; - if((pa = find_padata(req, &i, KRB5_PADATA_PK_AS_REQ_19))) - ; - } if (pa == NULL) { i = 0; if((pa = find_padata(req, &i, KRB5_PADATA_PK_AS_REQ_WIN))) @@ -887,12 +882,14 @@ _kdc_as_rep(krb5_context context, e_text = "PKINIT certificate not allowed to " "impersonate principal"; _kdc_pk_free_client_param(context, pkp); + + kdc_log(context, config, 0, "%s", e_text); pkp = NULL; goto ts_enc; } found_pa = 1; et.flags.pre_authent = 1; - kdc_log(context, config, 2, + kdc_log(context, config, 0, "PKINIT pre-authentication succeeded -- %s using %s", client_name, client_cert); free(client_cert); @@ -1057,12 +1054,6 @@ _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_19; - pa->padata_value.length = 0; - pa->padata_value.data = NULL; #endif /* XXX check ret */ diff --git a/source4/heimdal/kdc/pkinit.c b/source4/heimdal/kdc/pkinit.c index 985c7c15e4..83c379825c 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.43 2005/09/21 00:40:32 lha Exp $"); +RCSID("$Id: pkinit.c,v 1.49 2005/10/21 17:14:19 lha Exp $"); #ifdef PKINIT @@ -65,7 +65,6 @@ struct krb5_pk_cert { enum pkinit_type { PKINIT_COMPAT_WIN2K = 1, - PKINIT_COMPAT_19 = 2, PKINIT_COMPAT_27 = 3 }; @@ -76,6 +75,7 @@ struct pk_client_params { unsigned nonce; DH *dh; EncryptionKey reply_key; + char *dh_group_name; }; struct pk_principal_mapping { @@ -111,6 +111,7 @@ struct pk_principal_mapping { static struct krb5_pk_identity *kdc_identity; static struct pk_principal_mapping principal_mappings; +static struct krb5_dh_moduli **moduli; /* * @@ -133,49 +134,6 @@ pk_check_pkauthenticator_win2k(krb5_context context, return 0; } -static krb5_error_code -pk_check_pkauthenticator_19(krb5_context context, - PKAuthenticator_19 *a, - KDC_REQ *req) -{ - u_char *buf = NULL; - size_t buf_size; - krb5_error_code ret; - size_t len; - krb5_timestamp now; - - krb5_timeofday (context, &now); - - /* XXX cusec */ - if (a->ctime == 0 || abs(a->ctime - now) > context->max_skew) { - krb5_clear_error_string(context); - return KRB5KRB_AP_ERR_SKEW; - } - - if (a->paChecksum.cksumtype != CKSUMTYPE_RSA_MD5 && - a->paChecksum.cksumtype != CKSUMTYPE_SHA1) - { - krb5_clear_error_string(context); - ret = KRB5KRB_ERR_GENERIC; - } - - ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, &req->req_body, &len, ret); - if (ret) { - krb5_clear_error_string(context); - return ret; - } - if (buf_size != len) - krb5_abortx(context, "Internal error in ASN.1 encoder"); - - ret = krb5_verify_checksum(context, NULL, 0, buf, len, - &a->paChecksum); - if (ret) - krb5_clear_error_string(context); - - free(buf); - return ret; -} - static krb5_error_code pk_check_pkauthenticator(krb5_context context, PKAuthenticator *a, @@ -281,35 +239,23 @@ _kdc_pk_free_client_param(krb5_context context, if (client_params->dh_public_key) BN_free(client_params->dh_public_key); krb5_free_keyblock_contents(context, &client_params->reply_key); + if (client_params->dh_group_name) + free(client_params->dh_group_name); memset(client_params, 0, sizeof(*client_params)); free(client_params); } -static krb5_error_code -check_dh_params(DH *dh) -{ - /* XXX check the DH parameters come from 1st or 2nd Oeakley Group */ - return 0; -} - static krb5_error_code generate_dh_keyblock(krb5_context context, pk_client_params *client_params, krb5_enctype enctype, krb5_keyblock *reply_key) { unsigned char *dh_gen_key = NULL; krb5_keyblock key; - int dh_gen_keylen; krb5_error_code ret; + size_t dh_gen_keylen, size; memset(&key, 0, sizeof(key)); - dh_gen_key = malloc(DH_size(client_params->dh)); - if (dh_gen_key == NULL) { - krb5_set_error_string(context, "malloc: out of memory"); - ret = ENOMEM; - goto out; - } - if (!DH_generate_key(client_params->dh)) { krb5_set_error_string(context, "Can't generate Diffie-Hellman " "keys (%s)", @@ -323,7 +269,20 @@ generate_dh_keyblock(krb5_context context, pk_client_params *client_params, goto out; } - dh_gen_keylen = DH_compute_key(dh_gen_key, + dh_gen_keylen = DH_size(client_params->dh); + size = BN_num_bytes(client_params->dh->p); + if (size < dh_gen_keylen) + size = dh_gen_keylen; + + dh_gen_key = malloc(size); + if (dh_gen_key == NULL) { + krb5_set_error_string(context, "malloc: out of memory"); + ret = ENOMEM; + goto out; + } + memset(dh_gen_key, 0, size - dh_gen_keylen); + + dh_gen_keylen = DH_compute_key(dh_gen_key + (size - dh_gen_keylen), client_params->dh_public_key, client_params->dh); if (dh_gen_keylen == -1) { @@ -363,7 +322,9 @@ integer_to_BN(krb5_context context, const char *field, heim_integer *f) } static krb5_error_code -get_dh_param(krb5_context context, SubjectPublicKeyInfo *dh_key_info, +get_dh_param(krb5_context context, + krb5_kdc_configuration *config, + SubjectPublicKeyInfo *dh_key_info, pk_client_params *client_params) { DomainParameters dhparam; @@ -395,6 +356,20 @@ get_dh_param(krb5_context context, SubjectPublicKeyInfo *dh_key_info, goto out; } + if ((dh_key_info->subjectPublicKey.length % 8) != 0) { + ret = KRB5_BADMSGTYPE; + krb5_set_error_string(context, "PKINIT: subjectPublicKey not aligned " + "to 8 bit boundary"); + goto out; + } + + + ret = _krb5_dh_group_ok(context, config->pkinit_dh_min_bits, + &dhparam.p, &dhparam.g, &dhparam.q, moduli, + &client_params->dh_group_name); + if (ret) + goto out; + dh = DH_new(); if (dh == NULL) { krb5_set_error_string(context, "Cannot create DH structure (%s)", @@ -415,22 +390,29 @@ get_dh_param(krb5_context context, SubjectPublicKeyInfo *dh_key_info, { heim_integer glue; - glue.data = dh_key_info->subjectPublicKey.data; - glue.length = dh_key_info->subjectPublicKey.length; + size_t size; + + ret = decode_DHPublicKey(dh_key_info->subjectPublicKey.data, + dh_key_info->subjectPublicKey.length / 8, + &glue, + &size); + if (ret) { + krb5_clear_error_string(context); + return ret; + } client_params->dh_public_key = integer_to_BN(context, "subjectPublicKey", &glue); - if (client_params->dh_public_key == NULL) { - krb5_clear_error_string(context); + free_heim_integer(&glue); + if (client_params->dh_public_key == NULL) goto out; - } } if (DH_check(dh, &dhret) != 1) { krb5_set_error_string(context, "PKINIT DH data not ok: %s", ERR_error_string(ERR_get_error(), NULL)); - ret = KRB5_KDC_ERR_KEY_SIZE; + ret = KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED; goto out; } @@ -525,13 +507,12 @@ _kdc_pk_rd_padata(krb5_context context, return 0; } - client_params = malloc(sizeof(*client_params)); + client_params = calloc(1, sizeof(*client_params)); if (client_params == NULL) { krb5_clear_error_string(context); ret = ENOMEM; goto out; } - memset(client_params, 0, sizeof(*client_params)); if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_WIN) { PA_PK_AS_REQ_Win2k r; @@ -586,51 +567,6 @@ _kdc_pk_rd_padata(krb5_context context, free_ContentInfo(&info); - } else if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_19) { - PA_PK_AS_REQ_19 r; - - type = "PK-INIT-19"; - pa_contentType = oid_id_pkauthdata(); - - ret = decode_PA_PK_AS_REQ_19(pa->padata_value.data, - pa->padata_value.length, - &r, - NULL); - if (ret) { - krb5_set_error_string(context, "Can't decode " - "PK-AS-REQ-19: %d", ret); - goto out; - } - - if (heim_oid_cmp(&r.signedAuthPack.contentType, - oid_id_pkcs7_signedData())) - { - krb5_set_error_string(context, "PK-AS-REQ-19 invalid content " - "type oid"); - free_PA_PK_AS_REQ_19(&r); - ret = KRB5KRB_ERR_GENERIC; - goto out; - } - - if (r.signedAuthPack.content == NULL) { - krb5_set_error_string(context, "PK-AS-REQ-19 no signed auth pack"); - free_PA_PK_AS_REQ_19(&r); - ret = KRB5KRB_ERR_GENERIC; - goto out; - } - - signed_content.data = malloc(r.signedAuthPack.content->length); - if (signed_content.data == NULL) { - ret = ENOMEM; - free_PA_PK_AS_REQ_19(&r); - krb5_set_error_string(context, "PK-AS-REQ-19 out of memory"); - goto out; - } - signed_content.length = r.signedAuthPack.content->length; - memcpy(signed_content.data, r.signedAuthPack.content->data, - signed_content.length); - - free_PA_PK_AS_REQ_19(&r); } else if (pa->padata_type == KRB5_PADATA_PK_AS_REQ) { PA_PK_AS_REQ r; ContentInfo info; @@ -701,12 +637,14 @@ _kdc_pk_rd_padata(krb5_context context, if (ret) goto out; +#if 0 /* Signature is correct, now verify the signed message */ if (heim_oid_cmp(&eContentType, pa_contentType)) { krb5_set_error_string(context, "got wrong oid for pkauthdata"); ret = KRB5_BADMSGTYPE; goto out; } +#endif if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_WIN) { AuthPack_Win2k ap; @@ -738,37 +676,6 @@ _kdc_pk_rd_padata(krb5_context context, } free_AuthPack_Win2k(&ap); - } else if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_19) { - AuthPack_19 ap; - - ret = decode_AuthPack_19(eContent.data, - eContent.length, - &ap, - NULL); - if (ret) { - krb5_set_error_string(context, "can't decode AuthPack: %d", ret); - free_AuthPack_19(&ap); - goto out; - } - - ret = pk_check_pkauthenticator_19(context, - &ap.pkAuthenticator, - req); - if (ret) { - free_AuthPack_19(&ap); - goto out; - } - - client_params->type = PKINIT_COMPAT_19; - client_params->nonce = ap.pkAuthenticator.nonce; - - if (ap.clientPublicValue) { - krb5_set_error_string(context, "PK-INIT, no support for DH"); - ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP; - free_AuthPack_19(&ap); - goto out; - } - free_AuthPack_19(&ap); } else if (pa->padata_type == KRB5_PADATA_PK_AS_REQ) { AuthPack ap; @@ -794,7 +701,8 @@ _kdc_pk_rd_padata(krb5_context context, client_params->nonce = ap.pkAuthenticator.nonce; if (ap.clientPublicValue) { - ret = get_dh_param(context, ap.clientPublicValue, client_params); + ret = get_dh_param(context, config, + ap.clientPublicValue, client_params); if (ret) { free_AuthPack(&ap); goto out; @@ -924,9 +832,8 @@ pk_mk_pa_reply_enckey(krb5_context context, enc_alg->parameters->length = params.length; switch (client_params->type) { - case PKINIT_COMPAT_WIN2K: - case PKINIT_COMPAT_19: { - ReplyKeyPack_19 kp; + case PKINIT_COMPAT_WIN2K: { + ReplyKeyPack_Win2k kp; memset(&kp, 0, sizeof(kp)); ret = copy_EncryptionKey(reply_key, &kp.replyKey); @@ -936,10 +843,10 @@ pk_mk_pa_reply_enckey(krb5_context context, } kp.nonce = client_params->nonce; - ASN1_MALLOC_ENCODE(ReplyKeyPack_19, + ASN1_MALLOC_ENCODE(ReplyKeyPack_Win2k, buf.data, buf.length, &kp, &size,ret); - free_ReplyKeyPack_19(&kp); + free_ReplyKeyPack_Win2k(&kp); } case PKINIT_COMPAT_27: { krb5_crypto ascrypto; @@ -1249,6 +1156,7 @@ _kdc_pk_mk_pa_reply(krb5_context context, if (client_params->type == PKINIT_COMPAT_27) { PA_PK_AS_REP rep; + const char *type, *other = ""; memset(&rep, 0, sizeof(rep)); @@ -1257,6 +1165,8 @@ _kdc_pk_mk_pa_reply(krb5_context context, if (client_params->dh == NULL) { ContentInfo info; + type = "enckey"; + rep.element = choice_PA_PK_AS_REP_encKeyPack; krb5_generate_random_keyblock(context, enctype, @@ -1287,11 +1197,11 @@ _kdc_pk_mk_pa_reply(krb5_context context, } else { ContentInfo info; - rep.element = choice_PA_PK_AS_REP_dhInfo; + type = "dh"; + if (client_params->dh_group_name) + other = client_params->dh_group_name; - ret = check_dh_params(client_params->dh); - if (ret) - return ret; + rep.element = choice_PA_PK_AS_REP_dhInfo; ret = generate_dh_keyblock(context, client_params, enctype, &client_params->reply_key); @@ -1332,41 +1242,8 @@ _kdc_pk_mk_pa_reply(krb5_context context, if (len != size) krb5_abortx(context, "Internal ASN.1 encoder error"); - } else if (client_params->type == PKINIT_COMPAT_19) { - PA_PK_AS_REP_19 rep; - - pa_type = KRB5_PADATA_PK_AS_REP_19; - - memset(&rep, 0, sizeof(rep)); + kdc_log(context, config, 0, "PK-INIT using %s %s", type, other); - if (client_params->dh == NULL) { - rep.element = choice_PA_PK_AS_REP_19_encKeyPack; - krb5_generate_random_keyblock(context, enctype, - &client_params->reply_key); - ret = pk_mk_pa_reply_enckey(context, - client_params, - req, - req_buffer, - &client_params->reply_key, - &rep.u.encKeyPack); - } else { - krb5_set_error_string(context, "DH -19 not implemented"); - ret = KRB5KRB_ERR_GENERIC; - } - if (ret) { - free_PA_PK_AS_REP_19(&rep); - goto out; - } - - ASN1_MALLOC_ENCODE(PA_PK_AS_REP_19, buf, len, &rep, &size, ret); - free_PA_PK_AS_REP_19(&rep); - if (ret) { - krb5_set_error_string(context, - "encode PA-PK-AS-REP-19 failed %d", ret); - goto out; - } - if (len != size) - krb5_abortx(context, "Internal ASN.1 encoder error"); } else if (client_params->type == PKINIT_COMPAT_WIN2K) { PA_PK_AS_REP_Win2k rep; @@ -1557,7 +1434,7 @@ _kdc_pk_check_client(krb5_context context, free(*subject_name); *subject_name = NULL; krb5_set_error_string(context, "PKINIT no matching principals"); - return KRB5_KDC_ERROR_CLIENT_NAME_MISMATCH; + return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH; } static krb5_error_code @@ -1598,12 +1475,19 @@ _kdc_pk_initialize(krb5_context context, const char *user_id, const char *x509_anchors) { - const char *mapping_file; + 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); + + ret = _krb5_parse_moduli(context, file, &moduli); + if (ret) + krb5_err(context, 1, ret, "PKINIT: failed to load modidi file"); + principal_mappings.len = 0; principal_mappings.val = NULL; @@ -1620,16 +1504,15 @@ _kdc_pk_initialize(krb5_context context, return ret; } - mapping_file = krb5_config_get_string_default(context, - NULL, - HDB_DB_DIR "/pki-mapping", - "kdc", - "pki-mappings-file", - NULL); - f = fopen(mapping_file, "r"); + file = krb5_config_get_string_default(context, + NULL, + HDB_DB_DIR "/pki-mapping", + "kdc", + "pki-mappings-file", + NULL); + f = fopen(file, "r"); if (f == NULL) { - krb5_warnx(context, "PKINIT: failed to load mappings file %s", - mapping_file); + krb5_warnx(context, "PKINIT: failed to load mappings file %s", file); return 0; } diff --git a/source4/heimdal/lib/asn1/der.h b/source4/heimdal/lib/asn1/der.h index a66a3908c6..1f89f875f5 100644 --- a/source4/heimdal/lib/asn1/der.h +++ b/source4/heimdal/lib/asn1/der.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -/* $Id: der.h,v 1.29 2005/07/12 06:27:19 lha Exp $ */ +/* $Id: der.h,v 1.30 2005/10/07 03:48:00 lha Exp $ */ #ifndef __DER_H__ #define __DER_H__ @@ -240,4 +240,7 @@ int der_get_type_num(const char *); const char * der_get_tag_name(unsigned); int der_get_tag_num(const char *); +int der_parse_hex_heim_integer(const char *, heim_integer *); +int der_print_hex_heim_integer(const heim_integer *, char **); + #endif /* __DER_H__ */ diff --git a/source4/heimdal/lib/gssapi/acquire_cred.c b/source4/heimdal/lib/gssapi/acquire_cred.c index 6ded413626..23c2603352 100644 --- a/source4/heimdal/lib/gssapi/acquire_cred.c +++ b/source4/heimdal/lib/gssapi/acquire_cred.c @@ -33,7 +33,7 @@ #include "gssapi_locl.h" -RCSID("$Id: acquire_cred.c,v 1.22 2005/01/05 02:32:26 lukeh Exp $"); +RCSID("$Id: acquire_cred.c,v 1.23 2005/10/21 12:44:08 lha Exp $"); static krb5_error_code get_keytab(krb5_context context, krb5_keytab *keytab) @@ -83,9 +83,23 @@ static OM_uint32 acquire_initiator_cred ret = GSS_S_FAILURE; memset(&cred, 0, sizeof(cred)); + /* If we have a preferred principal, lets try to find it in all + * caches, otherwise, fall back to default cache. Ignore + * errors. */ + if (ccache == NULL && handle->principal) { + kret = krb5_cc_cache_match (gssapi_krb5_context, + handle->principal, + NULL, + &ccache); + if (kret) { + ccache = NULL; + } else { + made_ccache = TRUE; + } + } if (ccache == NULL) { - kret = krb5_cc_default(context, &ccache); - if (kret) + kret = krb5_cc_default(gssapi_krb5_context, &ccache); + if (kret) goto end; made_ccache = TRUE; } diff --git a/source4/heimdal/lib/gssapi/display_status.c b/source4/heimdal/lib/gssapi/display_status.c index 6e9456aa2e..0aa88bb57c 100644 --- a/source4/heimdal/lib/gssapi/display_status.c +++ b/source4/heimdal/lib/gssapi/display_status.c @@ -33,7 +33,7 @@ #include "gssapi_locl.h" -RCSID("$Id: display_status.c,v 1.13 2005/08/23 08:30:55 lha Exp $"); +RCSID("$Id: display_status.c,v 1.14 2005/10/12 07:23:03 lha Exp $"); static const char * calling_error(OM_uint32 v) @@ -112,25 +112,47 @@ supplementary_error(OM_uint32 v) } void -gssapi_krb5_set_error_string (void) +gssapi_krb5_clear_status (void) { struct gssapi_thr_context *ctx = gssapi_get_thread_context(1); - char *e; + if (ctx == NULL) + return; + HEIMDAL_MUTEX_lock(&ctx->mutex); + if (ctx->error_string) + free(ctx->error_string); + ctx->error_string = NULL; + HEIMDAL_MUTEX_unlock(&ctx->mutex); +} + +void +gssapi_krb5_set_status (const char *fmt, ...) +{ + struct gssapi_thr_context *ctx = gssapi_get_thread_context(1); + va_list args; if (ctx == NULL) return; HEIMDAL_MUTEX_lock(&ctx->mutex); + va_start(args, fmt); if (ctx->error_string) free(ctx->error_string); + /* ignore failures, will use status code instead */ + vasprintf(&ctx->error_string, fmt, args); + va_end(args); + HEIMDAL_MUTEX_unlock(&ctx->mutex); +} + +void +gssapi_krb5_set_error_string (void) +{ + char *e; + e = krb5_get_error_string(gssapi_krb5_context); - if (e == NULL) - ctx->error_string = NULL; - else { - /* ignore failures, will use status code instead */ - ctx->error_string = strdup(e); + if (e) { + gssapi_krb5_set_status("%s", e); krb5_free_error_string(gssapi_krb5_context, e); - } - HEIMDAL_MUTEX_unlock(&ctx->mutex); + } else + gssapi_krb5_clear_status(); } char * diff --git a/source4/heimdal/lib/gssapi/gssapi_locl.h b/source4/heimdal/lib/gssapi/gssapi_locl.h index 47a37e4657..a25e2fdcc9 100644 --- a/source4/heimdal/lib/gssapi/gssapi_locl.h +++ b/source4/heimdal/lib/gssapi/gssapi_locl.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -/* $Id: gssapi_locl.h,v 1.40 2005/06/16 20:34:03 lha Exp $ */ +/* $Id: gssapi_locl.h,v 1.41 2005/10/12 15:20:37 lha Exp $ */ #ifndef GSSAPI_LOCL_H #define GSSAPI_LOCL_H @@ -245,6 +245,12 @@ gss_address_to_krb5addr(OM_uint32 gss_addr_type, int gss_oid_equal(const gss_OID a, const gss_OID b); +void +gssapi_krb5_clear_status (void); + +void +gssapi_krb5_set_status (const char *fmt, ...); + void gssapi_krb5_set_error_string (void); diff --git a/source4/heimdal/lib/gssapi/init_sec_context.c b/source4/heimdal/lib/gssapi/init_sec_context.c index 5c6c6a0f8e..93e8d44c86 100644 --- a/source4/heimdal/lib/gssapi/init_sec_context.c +++ b/source4/heimdal/lib/gssapi/init_sec_context.c @@ -33,7 +33,7 @@ #include "gssapi_locl.h" -RCSID("$Id: init_sec_context.c,v 1.59 2005/08/11 10:47:25 lha Exp $"); +RCSID("$Id: init_sec_context.c,v 1.60 2005/10/12 07:25:18 lha Exp $"); /* * copy the addresses from `input_chan_bindings' (if any) to @@ -848,16 +848,23 @@ spnego_reply ret = der_match_tag_and_length((const char *)indata.data, indata.length, ASN1_C_CONTEXT, CONS, 1, &len, &taglen); - if (ret) - return ret; + if (ret) { + gssapi_krb5_set_status("Failed to decode NegToken choice"); + *minor_status = ret; + return GSS_S_FAILURE; + } - if(len > indata.length - taglen) - return ASN1_OVERRUN; + if(len > indata.length - taglen) { + gssapi_krb5_set_status("Buffer overrun in NegToken choice"); + *minor_status = ASN1_OVERRUN; + return GSS_S_FAILURE; + } ret = decode_NegTokenTarg((const char *)indata.data + taglen, len, &targ, NULL); if (ret) { - *minor_status = ENOMEM; + gssapi_krb5_set_status("Failed to decode NegTokenTarg"); + *minor_status = ret; return GSS_S_FAILURE; } diff --git a/source4/heimdal/lib/hdb/hdb.c b/source4/heimdal/lib/hdb/hdb.c index 8233eb6ac7..c66579fab0 100644 --- a/source4/heimdal/lib/hdb/hdb.c +++ b/source4/heimdal/lib/hdb/hdb.c @@ -33,7 +33,7 @@ #include "hdb_locl.h" -RCSID("$Id: hdb.c,v 1.55 2005/08/19 13:07:03 lha Exp $"); +RCSID("$Id: hdb.c,v 1.56 2005/10/19 13:51:40 lha Exp $"); #ifdef HAVE_DLFCN_H #include @@ -170,7 +170,7 @@ hdb_check_db_format(krb5_context context, HDB *db) { krb5_data tag; krb5_data version; - krb5_error_code ret; + krb5_error_code ret, ret2; unsigned ver; int foo; @@ -181,9 +181,11 @@ hdb_check_db_format(krb5_context context, HDB *db) tag.data = HDB_DB_FORMAT_ENTRY; tag.length = strlen(tag.data); ret = (*db->hdb__get)(context, db, tag, &version); - db->hdb_unlock(context, db); + ret2 = db->hdb_unlock(context, db); if(ret) return ret; + if (ret2) + return ret2; foo = sscanf(version.data, "%u", &ver); krb5_data_free (&version); if (foo != 1) @@ -196,7 +198,7 @@ hdb_check_db_format(krb5_context context, HDB *db) krb5_error_code hdb_init_db(krb5_context context, HDB *db) { - krb5_error_code ret; + krb5_error_code ret, ret2; krb5_data tag; krb5_data version; char ver[32]; @@ -215,10 +217,10 @@ hdb_init_db(krb5_context context, HDB *db) version.data = ver; version.length = strlen(version.data) + 1; /* zero terminated */ ret = (*db->hdb__put)(context, db, 0, tag, version); - ret = db->hdb_unlock(context, db); + ret2 = db->hdb_unlock(context, db); if (ret) return ret; - return ret; + return ret2; } #ifdef HAVE_DLOPEN diff --git a/source4/heimdal/lib/krb5/acache.c b/source4/heimdal/lib/krb5/acache.c index 75f5315c71..7cf2c65d89 100644 --- a/source4/heimdal/lib/krb5/acache.c +++ b/source4/heimdal/lib/krb5/acache.c @@ -37,7 +37,7 @@ #include #endif -RCSID("$Id: acache.c,v 1.11 2005/06/16 19:32:44 lha Exp $"); +RCSID("$Id: acache.c,v 1.14 2005/10/03 08:44:18 lha Exp $"); /* XXX should we fetch these for each open ? */ static HEIMDAL_MUTEX acc_mutex = HEIMDAL_MUTEX_INITIALIZER; @@ -67,7 +67,7 @@ static const struct { { ccErrContextNotFound, KRB5_CC_NOTFOUND }, { ccIteratorEnd, KRB5_CC_END }, { ccErrNoMem, KRB5_CC_NOMEM }, - { ccErrServerUnavailable, KRB5_CC_BADNAME }, + { ccErrServerUnavailable, KRB5_CC_NOSUPP }, { ccNoError, 0 } }; @@ -110,7 +110,7 @@ init_ccapi(krb5_context context) if (cc_handle == NULL) { HEIMDAL_MUTEX_unlock(&acc_mutex); krb5_set_error_string(context, "Failed to load %s", lib); - return ccErrServerUnavailable; + return KRB5_CC_NOSUPP; } init_func = dlsym(cc_handle, "cc_initialize"); @@ -119,14 +119,14 @@ init_ccapi(krb5_context context) krb5_set_error_string(context, "Failed to find cc_initialize" "in %s: %s", lib, dlerror()); dlclose(cc_handle); - return ccErrServerUnavailable; + return KRB5_CC_NOSUPP; } return 0; #else HEIMDAL_MUTEX_unlock(&acc_mutex); krb5_set_error_string(context, "no support for shared object"); - return ccErrServerUnavailable; + return KRB5_CC_NOSUPP; #endif } @@ -633,8 +633,10 @@ acc_get_first (krb5_context context, int32_t error; error = (*a->ccache->func->new_credentials_iterator)(a->ccache, &iter); - if (error) + if (error) { + krb5_clear_error_string(context); return ENOENT; + } *cursor = iter; return 0; } @@ -761,6 +763,97 @@ acc_get_version(krb5_context context, return 0; } +struct cache_iter { + cc_context_t context; + cc_ccache_iterator_t iter; +}; + +static krb5_error_code +acc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor) +{ + struct cache_iter *iter; + krb5_error_code ret; + cc_int32 error; + + ret = init_ccapi(context); + if (ret) + return ret; + + iter = calloc(1, sizeof(*iter)); + if (iter == NULL) { + krb5_set_error_string(context, "malloc - out of memory"); + return ENOMEM; + } + + error = (*init_func)(&iter->context, ccapi_version_3, NULL, NULL); + if (error) { + free(iter); + return translate_cc_error(context, error); + } + + error = (*iter->context->func->new_ccache_iterator)(iter->context, + &iter->iter); + if (error) { + free(iter); + krb5_clear_error_string(context); + return ENOENT; + } + *cursor = iter; + return 0; +} + +static krb5_error_code +acc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id) +{ + struct cache_iter *iter = cursor; + cc_ccache_t cache; + krb5_acc *a; + krb5_error_code ret; + int32_t error; + + error = (*iter->iter->func->next)(iter->iter, &cache); + if (error) + return translate_cc_error(context, error); + + ret = _krb5_cc_allocate(context, &krb5_acc_ops, id); + if (ret) { + (*cache->func->release)(cache); + return ret; + } + + ret = acc_alloc(context, id); + if (ret) { + (*cache->func->release)(cache); + free(*id); + return ret; + } + + a = ACACHE(*id); + a->ccache = cache; + + a->cache_name = get_cc_name(a->ccache); + if (a->cache_name == NULL) { + acc_close(context, *id); + *id = NULL; + krb5_set_error_string(context, "malloc: out of memory"); + return ENOMEM; + } + return 0; +} + +static krb5_error_code +acc_end_cache_get(krb5_context context, krb5_cc_cursor cursor) +{ + struct cache_iter *iter = cursor; + + (*iter->iter->func->release)(iter->iter); + iter->iter = NULL; + (*iter->context->func->release)(iter->context); + iter->context = NULL; + free(iter); + return 0; +} + const krb5_cc_ops krb5_acc_ops = { "API", acc_get_name, @@ -777,5 +870,8 @@ const krb5_cc_ops krb5_acc_ops = { acc_end_get, acc_remove_cred, acc_set_flags, - acc_get_version + acc_get_version, + acc_get_cache_first, + acc_get_cache_next, + acc_end_cache_get }; diff --git a/source4/heimdal/lib/krb5/cache.c b/source4/heimdal/lib/krb5/cache.c index f293a96ed9..ec956409a7 100644 --- a/source4/heimdal/lib/krb5/cache.c +++ b/source4/heimdal/lib/krb5/cache.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -33,7 +33,7 @@ #include "krb5_locl.h" -RCSID("$Id: cache.c,v 1.71 2005/06/16 20:19:57 lha Exp $"); +RCSID("$Id: cache.c,v 1.73 2005/10/19 17:30:40 lha Exp $"); /* * Add a new ccache type with operations `ops', overwriting any @@ -76,6 +76,29 @@ krb5_cc_register(krb5_context context, return 0; } +/* + * Allocate the memory for a `id' and the that function table to + * `ops'. Returns 0 or and error code. + */ + +krb5_error_code +_krb5_cc_allocate(krb5_context context, + const krb5_cc_ops *ops, + krb5_ccache *id) +{ + krb5_ccache p; + + p = malloc (sizeof(*p)); + if(p == NULL) { + krb5_set_error_string(context, "malloc: out of memory"); + return KRB5_CC_NOMEM; + } + p->ops = ops; + *id = p; + + return 0; +} + /* * Allocate memory for a new ccache in `id' with operations `ops' * and name `residual'. @@ -89,18 +112,13 @@ allocate_ccache (krb5_context context, krb5_ccache *id) { krb5_error_code ret; - krb5_ccache p; - p = malloc(sizeof(*p)); - if(p == NULL) { - krb5_set_error_string(context, "malloc: out of memory"); - return KRB5_CC_NOMEM; - } - p->ops = ops; - *id = p; - ret = p->ops->resolve(context, id, residual); + ret = _krb5_cc_allocate(context, ops, id); + if (ret) + return ret; + ret = (*id)->ops->resolve(context, id, residual); if(ret) - free(p); + free(*id); return ret; } @@ -145,16 +163,12 @@ krb5_cc_gen_new(krb5_context context, const krb5_cc_ops *ops, krb5_ccache *id) { - krb5_ccache p; + krb5_error_code ret; - p = malloc (sizeof(*p)); - if (p == NULL) { - krb5_set_error_string(context, "malloc: out of memory"); - return KRB5_CC_NOMEM; - } - p->ops = ops; - *id = p; - return p->ops->gen_new(context, id); + ret = _krb5_cc_allocate(context, ops, id); + if (ret) + return ret; + return (*id)->ops->gen_new(context, id); } /* @@ -641,17 +655,172 @@ krb5_cc_clear_mcred(krb5_creds *mcred) /* * Get the cc ops that is registered in `context' to handle the - * `prefix'. Returns NULL if ops not found. + * `prefix'. `prefix' can be a complete credential cache name or a + * prefix, the function will only use part up to the first colon (:) + * if there is one. Returns NULL if ops not found. */ const krb5_cc_ops * krb5_cc_get_prefix_ops(krb5_context context, const char *prefix) { + char *p, *p1; int i; + + p = strdup(prefix); + if (p == NULL) { + krb5_set_error_string(context, "malloc - out of memory"); + return NULL; + } + p1 = strchr(p, ':'); + if (p1) + *p1 = '\0'; for(i = 0; i < context->num_cc_ops && context->cc_ops[i].prefix; i++) { - if(strcmp(context->cc_ops[i].prefix, prefix) == 0) + if(strcmp(context->cc_ops[i].prefix, p) == 0) { + free(p); return &context->cc_ops[i]; + } } + free(p); return NULL; } + +struct krb5_cc_cache_cursor_data { + const krb5_cc_ops *ops; + krb5_cc_cursor cursor; +}; + +/* + * Start iterating over all caches of `type'. If `type' is NULL, the + * default type is * used. `cursor' is initialized to the beginning. + * Return 0 or an error code. + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_cc_cache_get_first (krb5_context context, + const char *type, + krb5_cc_cache_cursor *cursor) +{ + const krb5_cc_ops *ops; + krb5_error_code ret; + + if (type == NULL) + type = krb5_cc_default_name(context); + + ops = krb5_cc_get_prefix_ops(context, type); + if (ops == NULL) { + krb5_set_error_string(context, "Unknown type \"%s\" when iterating " + "trying to iterate the credential caches", type); + return KRB5_CC_UNKNOWN_TYPE; + } + + if (ops->get_cache_first == NULL) { + krb5_set_error_string(context, "Credential cache type %s doesn't support " + "iterations over caches", ops->prefix); + return KRB5_CC_NOSUPP; + } + + *cursor = calloc(1, sizeof(**cursor)); + if (*cursor == NULL) { + krb5_set_error_string(context, "malloc - out of memory"); + return ENOMEM; + } + + (*cursor)->ops = ops; + + ret = ops->get_cache_first(context, &(*cursor)->cursor); + if (ret) { + free(*cursor); + *cursor = NULL; + } + return ret; +} + +/* + * Retrieve the next cache pointed to by (`cursor') in `id' + * and advance `cursor'. + * Return 0 or an error code. + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_cc_cache_next (krb5_context context, + krb5_cc_cache_cursor cursor, + krb5_ccache *id) +{ + return cursor->ops->get_cache_next(context, cursor->cursor, id); +} + +/* + * Destroy the cursor `cursor'. + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_cc_cache_end_seq_get (krb5_context context, + krb5_cc_cache_cursor cursor) +{ + krb5_error_code ret; + ret = cursor->ops->end_cache_get(context, cursor->cursor); + cursor->ops = NULL; + free(cursor); + return ret; +} + +/* + * Search for a matching credential cache of type `type' that have the + * `principal' as the default principal. If NULL is used for `type', + * the default type is used. On success, `id' needs to be freed with + * krb5_cc_close or krb5_cc_destroy. On failure, error code is + * returned and `id' is set to NULL. + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_cc_cache_match (krb5_context context, + krb5_principal client, + const char *type, + krb5_ccache *id) +{ + krb5_cc_cache_cursor cursor; + krb5_error_code ret; + krb5_ccache cache = NULL; + + *id = NULL; + + ret = krb5_cc_cache_get_first (context, type, &cursor); + if (ret) + return ret; + + while ((ret = krb5_cc_cache_next (context, cursor, &cache)) == 0) { + krb5_principal principal; + + ret = krb5_cc_get_principal(context, cache, &principal); + if (ret == 0) { + krb5_boolean match; + + match = krb5_principal_compare(context, principal, client); + krb5_free_principal(context, principal); + if (match) + break; + } + + krb5_cc_close(context, cache); + cache = NULL; + } + + krb5_cc_cache_end_seq_get(context, cursor); + + if (cache == NULL) { + char *str; + + krb5_unparse_name(context, client, &str); + + krb5_set_error_string(context, "Principal %s not found in a " + "credential cache", str ? str : ""); + if (str) + free(str); + return KRB5_CC_NOTFOUND; + } + *id = cache; + + return 0; +} + diff --git a/source4/heimdal/lib/krb5/init_creds.c b/source4/heimdal/lib/krb5/init_creds.c index 95c980d92c..51b8ebc392 100644 --- a/source4/heimdal/lib/krb5/init_creds.c +++ b/source4/heimdal/lib/krb5/init_creds.c @@ -33,14 +33,14 @@ #include "krb5_locl.h" -RCSID("$Id: init_creds.c,v 1.20 2004/11/09 18:50:43 lha Exp $"); +RCSID("$Id: init_creds.c,v 1.21 2005/10/12 12:45:27 lha Exp $"); void KRB5_LIB_FUNCTION krb5_get_init_creds_opt_init(krb5_get_init_creds_opt *opt) { memset (opt, 0, sizeof(*opt)); opt->flags = 0; - opt->private = NULL; + opt->opt_private = NULL; } krb5_error_code KRB5_LIB_FUNCTION @@ -56,13 +56,13 @@ krb5_get_init_creds_opt_alloc(krb5_context context, return ENOMEM; } krb5_get_init_creds_opt_init(o); - o->private = calloc(1, sizeof(*o->private)); - if (o->private == NULL) { + o->opt_private = calloc(1, sizeof(*o->opt_private)); + if (o->opt_private == NULL) { krb5_set_error_string(context, "out of memory"); free(o); return ENOMEM; } - o->private->refcount = 1; + o->opt_private->refcount = 1; *opt = o; return 0; } @@ -82,16 +82,16 @@ _krb5_get_init_creds_opt_copy(krb5_context context, } if (in) *opt = *in; - if(opt->private == NULL) { - opt->private = calloc(1, sizeof(*opt->private)); - if (opt->private == NULL) { + if(opt->opt_private == NULL) { + opt->opt_private = calloc(1, sizeof(*opt->opt_private)); + if (opt->opt_private == NULL) { krb5_set_error_string(context, "out of memory"); free(opt); return ENOMEM; } - opt->private->refcount = 1; + opt->opt_private->refcount = 1; } else - opt->private->refcount++; + opt->opt_private->refcount++; *out = opt; return 0; } @@ -99,13 +99,13 @@ _krb5_get_init_creds_opt_copy(krb5_context context, void KRB5_LIB_FUNCTION krb5_get_init_creds_opt_free(krb5_get_init_creds_opt *opt) { - if (opt->private == NULL) + if (opt->opt_private == NULL) return; - if (opt->private->refcount < 1) /* abort ? */ + if (opt->opt_private->refcount < 1) /* abort ? */ return; - if (--opt->private->refcount == 0) { + if (--opt->opt_private->refcount == 0) { _krb5_get_init_creds_opt_free_pkinit(opt); - free(opt->private); + free(opt->opt_private); } memset(opt, 0, sizeof(*opt)); free(opt); @@ -293,7 +293,7 @@ require_ext_opt(krb5_context context, krb5_get_init_creds_opt *opt, const char *type) { - if (opt->private == NULL) { + if (opt->opt_private == NULL) { krb5_set_error_string(context, "%s on non extendable opt", type); return EINVAL; } @@ -310,8 +310,8 @@ krb5_get_init_creds_opt_set_pa_password(krb5_context context, ret = require_ext_opt(context, opt, "init_creds_opt_set_pa_password"); if (ret) return ret; - opt->private->password = password; - opt->private->key_proc = key_proc; + opt->opt_private->password = password; + opt->opt_private->key_proc = key_proc; return 0; } @@ -324,7 +324,7 @@ krb5_get_init_creds_opt_set_pac_request(krb5_context context, ret = require_ext_opt(context, opt, "init_creds_opt_set_pac_req"); if (ret) return ret; - opt->private->req_pac = req_pac ? + opt->opt_private->req_pac = req_pac ? KRB5_PA_PAC_REQ_TRUE : KRB5_PA_PAC_REQ_FALSE; return 0; diff --git a/source4/heimdal/lib/krb5/init_creds_pw.c b/source4/heimdal/lib/krb5/init_creds_pw.c index 8fd5c4611f..3c694624bf 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.88 2005/08/13 08:25:32 lha Exp $"); +RCSID("$Id: init_creds_pw.c,v 1.90 2005/10/12 12:45:11 lha Exp $"); typedef struct krb5_get_init_creds_ctx { krb5_kdc_flags flags; @@ -275,11 +275,11 @@ get_init_creds_common(krb5_context context, options = &default_opt; } - if (options->private) { - ctx->password = options->private->password; - ctx->key_proc = options->private->key_proc; - ctx->req_pac = options->private->req_pac; - ctx->pk_init_ctx = options->private->pk_init_ctx; + if (options->opt_private) { + ctx->password = options->opt_private->password; + ctx->key_proc = options->opt_private->key_proc; + ctx->req_pac = options->opt_private->req_pac; + ctx->pk_init_ctx = options->opt_private->pk_init_ctx; } else ctx->req_pac = KRB5_PA_PAC_DONT_CARE; @@ -1014,10 +1014,10 @@ pa_data_to_md_pkinit(krb5_context context, return 0; #ifdef PKINIT return _krb5_pk_mk_padata(context, - ctx->pk_init_ctx, - &a->req_body, - ctx->pk_nonce, - md); + ctx->pk_init_ctx, + &a->req_body, + ctx->pk_nonce, + md); #else krb5_set_error_string(context, "no support for PKINIT compiled in"); return EINVAL; @@ -1114,6 +1114,7 @@ process_pa_data_to_key(krb5_context context, krb5_creds *creds, AS_REQ *a, krb5_kdc_rep *rep, + const krb5_krbhst_info *hi, krb5_keyblock **key) { struct pa_info_data paid, *ppaid = NULL; @@ -1158,6 +1159,7 @@ process_pa_data_to_key(krb5_context context, ret = _krb5_pk_rd_pa_reply(context, ctx->pk_init_ctx, etype, + hi, ctx->pk_nonce, &ctx->req_buffer, pa, @@ -1194,6 +1196,8 @@ init_cred_loop(krb5_context context, size_t len; size_t size; int send_to_kdc_flags = 0; + krb5_krbhst_info *hi = NULL; + memset(&md, 0, sizeof(md)); memset(&rep, 0, sizeof(rep)); @@ -1321,7 +1325,7 @@ init_cred_loop(krb5_context context, krb5_keyblock *key = NULL; ret = process_pa_data_to_key(context, ctx, creds, - &ctx->as_req, &rep, &key); + &ctx->as_req, &rep, hi, &key); if (ret) goto out; @@ -1462,8 +1466,8 @@ krb5_get_init_creds_password(krb5_context context, return ret; if (password == NULL && - options->private->password == NULL && - options->private->pk_init_ctx == NULL) + options->opt_private->password == NULL && + options->opt_private->pk_init_ctx == NULL) { krb5_prompt prompt; krb5_data password_data; @@ -1491,7 +1495,7 @@ krb5_get_init_creds_password(krb5_context context, password = password_data.data; } - if (options->private->password == NULL) { + if (options->opt_private->password == NULL) { ret = krb5_get_init_creds_opt_set_pa_password(context, options, password, NULL); if (ret) { diff --git a/source4/heimdal/lib/krb5/keytab_keyfile.c b/source4/heimdal/lib/krb5/keytab_keyfile.c index b53fa36a03..5c94291e72 100644 --- a/source4/heimdal/lib/krb5/keytab_keyfile.c +++ b/source4/heimdal/lib/krb5/keytab_keyfile.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan + * Copyright (c) 1997 - 2002, 2005 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -33,7 +33,7 @@ #include "krb5_locl.h" -RCSID("$Id: keytab_keyfile.c,v 1.16 2005/01/08 22:57:18 lha Exp $"); +RCSID("$Id: keytab_keyfile.c,v 1.17 2005/09/30 11:20:53 lha Exp $"); /* afs keyfile operations --------------------------------------- */ @@ -288,9 +288,16 @@ akf_add_entry(krb5_context context, krb5_storage *sp; - if (entry->keyblock.keyvalue.length != 8 - || entry->keyblock.keytype != ETYPE_DES_CBC_MD5) + if (entry->keyblock.keyvalue.length != 8) return 0; + switch(entry->keyblock.keytype) { + case ETYPE_DES_CBC_CRC: + case ETYPE_DES_CBC_MD4: + case ETYPE_DES_CBC_MD5: + break; + default: + return 0; + } fd = open (d->filename, O_RDWR | O_BINARY); if (fd < 0) { @@ -329,50 +336,72 @@ akf_add_entry(krb5_context context, return ret; } } + + /* + * Make sure we don't add the entry twice, assumes the DES + * encryption types are all the same key. + */ + if (len > 0) { + int32_t kvno; + int i; + + for (i = 0; i < len; i++) { + ret = krb5_ret_int32(sp, &kvno); + if (ret) { + krb5_set_error_string (context, "Failed got get kvno "); + goto out; + } + if(krb5_storage_seek(sp, 8, SEEK_CUR) < 0) { + krb5_set_error_string (context, "seek: %s", strerror(ret)); + goto out; + } + if (kvno == entry->vno) { + ret = 0; + goto out; + } + } + } + len++; if(krb5_storage_seek(sp, 0, SEEK_SET) < 0) { ret = errno; - krb5_storage_free(sp); - close(fd); krb5_set_error_string (context, "seek: %s", strerror(ret)); - return ret; + goto out; } ret = krb5_store_int32(sp, len); if(ret) { - krb5_storage_free(sp); - close(fd); + krb5_set_error_string(context, "keytab keyfile failed new length"); return ret; } - if(krb5_storage_seek(sp, (len - 1) * (8 + 4), SEEK_CUR) < 0) { ret = errno; - krb5_storage_free(sp); - close(fd); - krb5_set_error_string (context, "seek: %s", strerror(ret)); - return ret; + krb5_set_error_string (context, "seek to end: %s", strerror(ret)); + goto out; } ret = krb5_store_int32(sp, entry->vno); if(ret) { - krb5_storage_free(sp); - close(fd); - return ret; + krb5_set_error_string(context, "keytab keyfile failed store kvno"); + goto out; } ret = krb5_storage_write(sp, entry->keyblock.keyvalue.data, entry->keyblock.keyvalue.length); if(ret != entry->keyblock.keyvalue.length) { - krb5_storage_free(sp); - close(fd); - if(ret < 0) - return errno; - return ENOTTY; + if (ret < 0) + ret = errno; + else + ret = ENOTTY; + krb5_set_error_string(context, "keytab keyfile failed to add key"); + goto out; } + ret = 0; +out: krb5_storage_free(sp); close (fd); - return 0; + return ret; } const krb5_kt_ops krb5_akf_ops = { diff --git a/source4/heimdal/lib/krb5/krb5-private.h b/source4/heimdal/lib/krb5/krb5-private.h index ef47bd1e26..07d9329337 100644 --- a/source4/heimdal/lib/krb5/krb5-private.h +++ b/source4/heimdal/lib/krb5/krb5-private.h @@ -31,6 +31,12 @@ _krb5_aes_cts_encrypt ( unsigned char */*ivec*/, const int /*encryptp*/); +krb5_error_code +_krb5_cc_allocate ( + krb5_context /*context*/, + const krb5_cc_ops */*ops*/, + krb5_ccache */*id*/); + void _krb5_crc_init_table (void); @@ -40,6 +46,16 @@ _krb5_crc_update ( size_t /*len*/, u_int32_t /*res*/); +krb5_error_code +_krb5_dh_group_ok ( + krb5_context /*context*/, + unsigned long /*bits*/, + heim_integer */*p*/, + heim_integer */*g*/, + heim_integer */*q*/, + struct krb5_dh_moduli **/*moduli*/, + char **/*name*/); + krb5_error_code _krb5_expand_default_cc_name ( krb5_context /*context*/, @@ -61,6 +77,9 @@ _krb5_extract_ticket ( krb5_decrypt_proc /*decrypt_proc*/, krb5_const_pointer /*decryptarg*/); +void +_krb5_free_krbhst_info (krb5_krbhst_info */*hi*/); + krb5_error_code _krb5_get_default_principal_local ( krb5_context /*context*/, @@ -233,6 +252,12 @@ _krb5_krb_time_to_life ( time_t /*start*/, time_t /*end*/); +krb5_error_code +_krb5_krbhost_info_move ( + krb5_context /*context*/, + krb5_krbhst_info */*from*/, + krb5_krbhst_info **/*to*/); + krb5_error_code _krb5_mk_req_internal ( krb5_context /*context*/, @@ -257,6 +282,20 @@ _krb5_oid_to_enctype ( const heim_oid */*oid*/, krb5_enctype */*etype*/); +krb5_error_code +_krb5_parse_moduli ( + krb5_context /*context*/, + const char */*file*/, + struct krb5_dh_moduli ***/*moduli*/); + +krb5_error_code +_krb5_parse_moduli_line ( + krb5_context /*context*/, + const char */*file*/, + int /*lineno*/, + char */*p*/, + struct krb5_dh_moduli **/*m*/); + void KRB5_LIB_FUNCTION _krb5_pk_cert_free (struct krb5_pk_cert */*cert*/); @@ -308,6 +347,7 @@ _krb5_pk_rd_pa_reply ( krb5_context /*context*/, void */*c*/, krb5_enctype /*etype*/, + const krb5_krbhst_info */*hi*/, unsigned /*nonce*/, const krb5_data */*req_buffer*/, PA_DATA */*pa*/, @@ -316,7 +356,7 @@ _krb5_pk_rd_pa_reply ( krb5_error_code KRB5_LIB_FUNCTION _krb5_pk_verify_sign ( krb5_context /*context*/, - const char */*data*/, + const void */*data*/, size_t /*length*/, struct krb5_pk_identity */*id*/, heim_oid */*contentType*/, diff --git a/source4/heimdal/lib/krb5/krb5-protos.h b/source4/heimdal/lib/krb5/krb5-protos.h index 681ac4189b..a46f8b8f8f 100644 --- a/source4/heimdal/lib/krb5/krb5-protos.h +++ b/source4/heimdal/lib/krb5/krb5-protos.h @@ -535,6 +535,30 @@ krb5_c_verify_checksum ( const krb5_checksum */*cksum*/, krb5_boolean */*valid*/); +krb5_error_code KRB5_LIB_FUNCTION +krb5_cc_cache_end_seq_get ( + krb5_context /*context*/, + krb5_cc_cache_cursor /*cursor*/); + +krb5_error_code KRB5_LIB_FUNCTION +krb5_cc_cache_get_first ( + krb5_context /*context*/, + const char */*type*/, + krb5_cc_cache_cursor */*cursor*/); + +krb5_error_code KRB5_LIB_FUNCTION +krb5_cc_cache_match ( + krb5_context /*context*/, + krb5_principal /*client*/, + const char */*type*/, + krb5_ccache */*id*/); + +krb5_error_code KRB5_LIB_FUNCTION +krb5_cc_cache_next ( + krb5_context /*context*/, + krb5_cc_cache_cursor /*cursor*/, + krb5_ccache */*id*/); + void KRB5_LIB_FUNCTION krb5_cc_clear_mcred (krb5_creds */*mcred*/); @@ -2867,6 +2891,13 @@ krb5_set_real_time ( krb5_timestamp /*sec*/, int32_t /*usec*/); +krb5_error_code KRB5_LIB_FUNCTION +krb5_set_send_recv_func ( + krb5_context /*context*/, + krb5_send_and_recv_func_t /*func*/, + krb5_send_and_recv_close_func_t /*close_fn*/, + void */*data*/); + void KRB5_LIB_FUNCTION krb5_set_use_admin_kdc ( krb5_context /*context*/, @@ -3432,11 +3463,6 @@ krb5_write_safe_message ( krb5_error_code KRB5_LIB_FUNCTION krb5_xfree (void */*ptr*/); -krb5_error_code KRB5_LIB_FUNCTION -krb5_set_send_recv_func(krb5_context context, - krb5_send_and_recv_func_t func, - krb5_send_and_recv_close_func_t close_fn, - void *data); #ifdef __cplusplus } diff --git a/source4/heimdal/lib/krb5/krb5.h b/source4/heimdal/lib/krb5/krb5.h index 800683ef0c..ef595d4d20 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.237 2005/07/09 14:47:21 lha Exp $ */ +/* $Id: krb5.h,v 1.239 2005/10/12 12:39:28 lha Exp $ */ #ifndef __KRB5_H__ #define __KRB5_H__ @@ -368,6 +368,8 @@ typedef struct krb5_creds { krb5_ticket_flags flags; } krb5_creds; +typedef struct krb5_cc_cache_cursor_data *krb5_cc_cache_cursor; + typedef struct krb5_cc_ops { const char *prefix; const char* (*get_name)(krb5_context, krb5_ccache); @@ -388,6 +390,9 @@ typedef struct krb5_cc_ops { krb5_flags, krb5_creds*); krb5_error_code (*set_flags)(krb5_context, krb5_ccache, krb5_flags); int (*get_version)(krb5_context, krb5_ccache); + krb5_error_code (*get_cache_first)(krb5_context, krb5_cc_cursor *); + krb5_error_code (*get_cache_next)(krb5_context, krb5_cc_cursor, krb5_ccache *); + krb5_error_code (*end_cache_get)(krb5_context, krb5_cc_cursor); } krb5_cc_ops; struct krb5_log_facility; @@ -659,7 +664,7 @@ typedef struct _krb5_get_init_creds_opt { krb5_preauthtype *preauth_list; int preauth_list_length; krb5_data *salt; - struct _krb5_get_init_creds_opt_private *private; + struct _krb5_get_init_creds_opt_private *opt_private; } krb5_get_init_creds_opt; #define KRB5_GET_INIT_CREDS_OPT_TKT_LIFE 0x0001 diff --git a/source4/heimdal/lib/krb5/krb5_locl.h b/source4/heimdal/lib/krb5/krb5_locl.h index a64ccc586e..4a02677239 100644 --- a/source4/heimdal/lib/krb5/krb5_locl.h +++ b/source4/heimdal/lib/krb5/krb5_locl.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -/* $Id: krb5_locl.h,v 1.81 2005/05/29 14:28:39 lha Exp $ */ +/* $Id: krb5_locl.h,v 1.83 2005/10/07 12:08:02 lha Exp $ */ #ifndef __KRB5_LOCL_H__ #define __KRB5_LOCL_H__ @@ -141,6 +141,7 @@ struct krb5_pk_identity; struct krb5_pk_cert; struct ContentInfo; typedef struct krb5_pk_init_ctx_data *krb5_pk_init_ctx; +struct krb5_dh_moduli; /* v4 glue */ struct _krb5_krb_auth_data; @@ -161,6 +162,8 @@ struct _krb5_krb_auth_data; #define KEYTAB_DEFAULT "ANY:FILE:" SYSCONFDIR "/krb5.keytab,krb4:" SYSCONFDIR "/srvtab" #define KEYTAB_DEFAULT_MODIFY "FILE:" SYSCONFDIR "/krb5.keytab" +#define MODULI_FILE SYSCONFDIR "/krb5.moduli" + #ifndef O_BINARY #define O_BINARY 0 #endif diff --git a/source4/heimdal/lib/krb5/krbhst.c b/source4/heimdal/lib/krb5/krbhst.c index 98e9cb3f09..ef9f5dbd60 100644 --- a/source4/heimdal/lib/krb5/krbhst.c +++ b/source4/heimdal/lib/krb5/krbhst.c @@ -34,7 +34,7 @@ #include "krb5_locl.h" #include -RCSID("$Id: krbhst.c,v 1.52 2005/06/17 04:23:26 lha Exp $"); +RCSID("$Id: krbhst.c,v 1.53 2005/10/08 15:40:50 lha Exp $"); static int string_to_proto(const char *string) @@ -228,14 +228,37 @@ parse_hostspec(krb5_context context, struct krb5_krbhst_data *kd, return hi; } -static void -free_krbhst_info(krb5_krbhst_info *hi) +void +_krb5_free_krbhst_info(krb5_krbhst_info *hi) { if (hi->ai != NULL) freeaddrinfo(hi->ai); free(hi); } +krb5_error_code +_krb5_krbhost_info_move(krb5_context context, + krb5_krbhst_info *from, + krb5_krbhst_info **to) +{ + /* trailing NUL is included in structure */ + *to = calloc(1, sizeof(**to) + strlen(from->hostname)); + if(*to == NULL) { + krb5_set_error_string(context, "malloc - out of memory"); + return ENOMEM; + } + + (*to)->proto = from->proto; + (*to)->port = from->port; + (*to)->def_port = from->def_port; + (*to)->ai = from->ai; + from->ai = NULL; + (*to)->next = NULL; + strcpy((*to)->hostname, from->hostname); + return 0; +} + + static void append_host_hostinfo(struct krb5_krbhst_data *kd, struct krb5_krbhst_info *host) { @@ -245,7 +268,7 @@ append_host_hostinfo(struct krb5_krbhst_data *kd, struct krb5_krbhst_info *host) if(h->proto == host->proto && h->port == host->port && strcmp(h->hostname, host->hostname) == 0) { - free_krbhst_info(host); + _krb5_free_krbhst_info(host); return; } *kd->end = host; @@ -752,7 +775,7 @@ krb5_krbhst_free(krb5_context context, krb5_krbhst_handle handle) for (h = handle->hosts; h != NULL; h = next) { next = h->next; - free_krbhst_info(h); + _krb5_free_krbhst_info(h); } free(handle->realm); diff --git a/source4/heimdal/lib/krb5/mcache.c b/source4/heimdal/lib/krb5/mcache.c index 0a65d53849..9588d936d5 100644 --- a/source4/heimdal/lib/krb5/mcache.c +++ b/source4/heimdal/lib/krb5/mcache.c @@ -33,7 +33,7 @@ #include "krb5_locl.h" -RCSID("$Id: mcache.c,v 1.19 2004/04/25 19:25:35 joda Exp $"); +RCSID("$Id: mcache.c,v 1.20 2005/09/30 11:16:04 lha Exp $"); typedef struct krb5_mcache { char *name; @@ -162,20 +162,25 @@ mcc_initialize(krb5_context context, &m->primary_principal); } -static krb5_error_code -mcc_close(krb5_context context, - krb5_ccache id) +static int +mcc_close_internal(krb5_mcache *m) { - krb5_mcache *m = MCACHE(id); - if (--m->refcnt != 0) return 0; if (MISDEAD(m)) { free (m->name); - krb5_data_free(&id->data); + return 1; } + return 0; +} +static krb5_error_code +mcc_close(krb5_context context, + krb5_ccache id) +{ + if (mcc_close_internal(MCACHE(id))) + krb5_data_free(&id->data); return 0; } @@ -334,6 +339,70 @@ mcc_set_flags(krb5_context context, return 0; /* XXX */ } +struct mcache_iter { + krb5_mcache *cache; +}; + +static krb5_error_code +mcc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor) +{ + struct mcache_iter *iter; + + iter = calloc(1, sizeof(*iter)); + if (iter == NULL) { + krb5_set_error_string(context, "malloc - out of memory"); + return ENOMEM; + } + + HEIMDAL_MUTEX_lock(&mcc_mutex); + iter->cache = mcc_head; + if (iter->cache) + iter->cache->refcnt++; + HEIMDAL_MUTEX_unlock(&mcc_mutex); + + *cursor = iter; + return 0; +} + +static krb5_error_code +mcc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id) +{ + struct mcache_iter *iter = cursor; + krb5_error_code ret; + krb5_mcache *m; + + if (iter->cache == NULL) + return KRB5_CC_END; + + HEIMDAL_MUTEX_lock(&mcc_mutex); + m = iter->cache; + if (m->next) + m->next->refcnt++; + iter->cache = m->next; + HEIMDAL_MUTEX_unlock(&mcc_mutex); + + ret = _krb5_cc_allocate(context, &krb5_mcc_ops, id); + if (ret) + return ret; + + (*id)->data.data = m; + (*id)->data.length = sizeof(*m); + + return 0; +} + +static krb5_error_code +mcc_end_cache_get(krb5_context context, krb5_cc_cursor cursor) +{ + struct mcache_iter *iter = cursor; + + if (iter->cache) + mcc_close_internal(iter->cache); + iter->cache = NULL; + free(iter); + return 0; +} + const krb5_cc_ops krb5_mcc_ops = { "MEMORY", mcc_get_name, @@ -349,5 +418,9 @@ const krb5_cc_ops krb5_mcc_ops = { mcc_get_next, mcc_end_get, mcc_remove_cred, - mcc_set_flags + mcc_set_flags, + NULL, + mcc_get_cache_first, + mcc_get_cache_next, + mcc_end_cache_get }; diff --git a/source4/heimdal/lib/krb5/pkinit.c b/source4/heimdal/lib/krb5/pkinit.c index 7ac1436f6e..0c5dfc44e9 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.62 2005/09/20 23:21:36 lha Exp $"); +RCSID("$Id: pkinit.c,v 1.75 2005/10/21 17:18:38 lha Exp $"); #ifdef PKINIT @@ -57,12 +57,9 @@ RCSID("$Id: pkinit.c,v 1.62 2005/09/20 23:21:36 lha Exp $"); enum { COMPAT_WIN2K = 1, - COMPAT_19 = 2, - COMPAT_27 = 3 + COMPAT_IETF = 2 }; - - #define OPENSSL_ASN1_MALLOC_ENCODE(T, B, BL, S, R) \ { \ unsigned char *p; \ @@ -107,12 +104,22 @@ struct krb5_pk_cert { X509 *cert; }; +struct krb5_dh_moduli { + char *name; + unsigned long bits; + heim_integer p; + heim_integer g; + heim_integer q; +}; + struct krb5_pk_init_ctx_data { struct krb5_pk_identity *id; DH *dh; + krb5_data *clientDHNonce; + struct krb5_dh_moduli **m; + int require_binding; }; - void KRB5_LIB_FUNCTION _krb5_pk_cert_free(struct krb5_pk_cert *cert) { @@ -135,6 +142,20 @@ BN_to_integer(krb5_context context, BIGNUM *bn, heim_integer *integer) return 0; } +static BIGNUM * +integer_to_BN(krb5_context context, const char *field, const heim_integer *f) +{ + BIGNUM *bn; + + bn = BN_bin2bn((const unsigned char *)f->data, f->length, NULL); + if (bn == NULL) { + krb5_set_error_string(context, "PKINIT: parsing BN failed %s", field); + return NULL; + } + bn->neg = f->negative; + return bn; +} + /* * UI ex_data has the callback_data as passed to Engine. This is far * from being complete, we will only process one prompt @@ -251,7 +272,8 @@ _krb5_pk_create_sign(krb5_context context, krb5_data buf; SignedData sd; EVP_MD_CTX md; - int len, i; + int i; + unsigned len; size_t size; X509_NAME *issuer_name; @@ -443,75 +465,10 @@ _krb5_pk_create_sign(krb5_context context, return ret; } -static krb5_error_code -build_auth_pack_win2k(krb5_context context, - unsigned nonce, - const KDC_REQ_BODY *body, - AuthPack_Win2k *a) -{ - krb5_error_code ret; - krb5_timestamp sec; - int32_t usec; - - /* fill in PKAuthenticator */ - ret = copy_PrincipalName(body->sname, &a->pkAuthenticator.kdcName); - if (ret) - return ret; - ret = copy_Realm(&body->realm, &a->pkAuthenticator.kdcRealm); - if (ret) - return ret; - - krb5_us_timeofday(context, &sec, &usec); - a->pkAuthenticator.ctime = sec; - a->pkAuthenticator.cusec = usec; - a->pkAuthenticator.nonce = nonce; - - return 0; -} - -static krb5_error_code -build_auth_pack_19(krb5_context context, - unsigned nonce, - const KDC_REQ_BODY *body, - AuthPack_19 *a) -{ - size_t buf_size, len; - krb5_cksumtype cksum; - krb5_error_code ret; - void *buf; - krb5_timestamp sec; - int32_t usec; - - krb5_clear_error_string(context); - - /* XXX some PACKETCABLE needs implemetations need md5 */ - cksum = CKSUMTYPE_RSA_MD5; - - krb5_us_timeofday(context, &sec, &usec); - a->pkAuthenticator.ctime = sec; - a->pkAuthenticator.nonce = nonce; - - ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, body, &len, ret); - if (ret) - return ret; - if (buf_size != len) - krb5_abortx(context, "internal error in ASN.1 encoder"); - - ret = krb5_create_checksum(context, - NULL, - 0, - cksum, - buf, - len, - &a->pkAuthenticator.paChecksum); - free(buf); - - return ret; -} - static krb5_error_code build_auth_pack(krb5_context context, unsigned nonce, + krb5_pk_init_ctx ctx, DH *dh, const KDC_REQ_BODY *body, AuthPack *a) @@ -545,18 +502,39 @@ build_auth_pack(krb5_context context, len, &checksum); free(buf); - if (ret == 0) { - ret = krb5_data_copy(&a->pkAuthenticator.paChecksum, - checksum.checksum.data, checksum.checksum.length); - free_Checksum(&checksum); - } + if (ret) + return ret; - if (ret == 0 && dh) { + ret = krb5_data_copy(&a->pkAuthenticator.paChecksum, + checksum.checksum.data, checksum.checksum.length); + free_Checksum(&checksum); + if (ret) + return ret; + + if (dh) { DomainParameters dp; heim_integer dh_pub_key; krb5_data dhbuf; size_t size; + if (1 /* support_cached_dh */) { + ALLOC(a->clientDHNonce, 1); + if (a->clientDHNonce == NULL) { + krb5_clear_error_string(context); + return ENOMEM; + } + ret = krb5_data_alloc(a->clientDHNonce, 40); + if (a->clientDHNonce == NULL) { + krb5_clear_error_string(context); + return ENOMEM; + } + memset(a->clientDHNonce->data, 0, a->clientDHNonce->length); + ret = krb5_copy_data(context, a->clientDHNonce, + &ctx->clientDHNonce); + if (ret) + return ret; + } + ALLOC(a->clientPublicValue, 1); if (a->clientPublicValue == NULL) return ENOMEM; @@ -606,20 +584,11 @@ build_auth_pack(krb5_context context, if (ret) return ret; - dhbuf.length = length_heim_integer(&dh_pub_key); - dhbuf.data = malloc(dhbuf.length); - if (dhbuf.data == NULL) { - free_heim_integer(&dh_pub_key); - krb5_set_error_string(context, "malloc: out of memory"); - return ret; - } - ret = der_put_heim_integer((char *)dhbuf.data + dhbuf.length - 1, - dhbuf.length, &dh_pub_key, &size); + ASN1_MALLOC_ENCODE(DHPublicKey, dhbuf.data, dhbuf.length, + &dh_pub_key, &size, ret); free_heim_integer(&dh_pub_key); - if (ret) { - free(dhbuf.data); + if (ret) return ret; - } if (size != dhbuf.length) krb5_abortx(context, "asn1 internal error"); @@ -663,27 +632,40 @@ pk_mk_padata(krb5_context context, struct ContentInfo content_info; krb5_error_code ret; const heim_oid *oid; - PA_PK_AS_REQ req; size_t size; krb5_data buf, sd_buf; int pa_type; krb5_data_zero(&buf); krb5_data_zero(&sd_buf); - memset(&req, 0, sizeof(req)); memset(&content_info, 0, sizeof(content_info)); if (compat == COMPAT_WIN2K) { AuthPack_Win2k ap; + krb5_timestamp sec; + int32_t usec; memset(&ap, 0, sizeof(ap)); - ret = build_auth_pack_win2k(context, nonce, req_body, &ap); + /* fill in PKAuthenticator */ + ret = copy_PrincipalName(req_body->sname, &ap.pkAuthenticator.kdcName); + if (ret) { + free_AuthPack_Win2k(&ap); + krb5_clear_error_string(context); + goto out; + } + ret = copy_Realm(&req_body->realm, &ap.pkAuthenticator.kdcRealm); if (ret) { free_AuthPack_Win2k(&ap); + krb5_clear_error_string(context); goto out; } + krb5_us_timeofday(context, &sec, &usec); + ap.pkAuthenticator.ctime = sec; + ap.pkAuthenticator.cusec = usec; + ap.pkAuthenticator.nonce = nonce; + ASN1_MALLOC_ENCODE(AuthPack_Win2k, buf.data, buf.length, &ap, &size, ret); free_AuthPack_Win2k(&ap); @@ -695,33 +677,12 @@ pk_mk_padata(krb5_context context, krb5_abortx(context, "internal ASN1 encoder error"); oid = oid_id_pkcs7_data(); - } else if (compat == COMPAT_19) { - AuthPack_19 ap; - - memset(&ap, 0, sizeof(ap)); - - ret = build_auth_pack_19(context, nonce, req_body, &ap); - if (ret) { - free_AuthPack_19(&ap); - goto out; - } - - ASN1_MALLOC_ENCODE(AuthPack_19, buf.data, buf.length, &ap, &size, ret); - free_AuthPack_19(&ap); - if (ret) { - krb5_set_error_string(context, "AuthPack_19: %d", ret); - goto out; - } - if (buf.length != size) - krb5_abortx(context, "internal ASN1 encoder error"); - - oid = oid_id_pkauthdata(); - } else if (compat == COMPAT_27) { + } else if (compat == COMPAT_IETF) { AuthPack ap; memset(&ap, 0, sizeof(ap)); - ret = build_auth_pack(context, nonce, ctx->dh, req_body, &ap); + ret = build_auth_pack(context, nonce, ctx, ctx->dh, req_body, &ap); if (ret) { free_AuthPack(&ap); goto out; @@ -755,9 +716,12 @@ pk_mk_padata(krb5_context context, if (ret) goto out; - /* XXX tell the kdc what CAs the client is willing to accept */ - req.trustedCertifiers = NULL; - req.kdcPkId = NULL; + ASN1_MALLOC_ENCODE(ContentInfo, buf.data, buf.length, + &content_info, &size, ret); + if (ret) + goto out; + if (buf.length != size) + krb5_abortx(context, "Internal ASN1 encoder error"); if (compat == COMPAT_WIN2K) { PA_PK_AS_REQ_Win2k winreq; @@ -766,60 +730,29 @@ pk_mk_padata(krb5_context context, memset(&winreq, 0, sizeof(winreq)); - ASN1_MALLOC_ENCODE(ContentInfo, - winreq.signed_auth_pack.data, - winreq.signed_auth_pack.length, - &content_info, - &size, - ret); - if (ret) - goto out; - if (winreq.signed_auth_pack.length != size) - krb5_abortx(context, "Internal ASN1 encoder error"); + winreq.signed_auth_pack = buf; ASN1_MALLOC_ENCODE(PA_PK_AS_REQ_Win2k, buf.data, buf.length, &winreq, &size, ret); free_PA_PK_AS_REQ_Win2k(&winreq); - } else if (compat == COMPAT_19) { - PA_PK_AS_REQ_19 req_19; - - pa_type = KRB5_PADATA_PK_AS_REQ_19; - - memset(&req_19, 0, sizeof(req_19)); - - ret = copy_ContentInfo(&content_info, &req_19.signedAuthPack); - if (ret) { - krb5_clear_error_string(context); - goto out; - } - req_19.kdcCert = NULL; - req_19.trustedCertifiers = NULL; - req_19.encryptionCert = NULL; - - ASN1_MALLOC_ENCODE(PA_PK_AS_REQ_19, buf.data, buf.length, - &req_19, &size, ret); - - free_PA_PK_AS_REQ_19(&req_19); - - } else if (compat == COMPAT_27) { + } else if (compat == COMPAT_IETF) { + PA_PK_AS_REQ req; pa_type = KRB5_PADATA_PK_AS_REQ; - ASN1_MALLOC_ENCODE(ContentInfo, - req.signedAuthPack.data, - req.signedAuthPack.length, - &content_info, - &size, - ret); - if (ret) - goto out; - if (req.signedAuthPack.length != size) - krb5_abortx(context, "Internal ASN1 encoder error"); + memset(&req, 0, sizeof(req)); + req.signedAuthPack = buf; + + /* XXX tell the kdc what CAs the client is willing to accept */ + req.trustedCertifiers = NULL; + req.kdcPkId = NULL; ASN1_MALLOC_ENCODE(PA_PK_AS_REQ, buf.data, buf.length, &req, &size, ret); + free_PA_PK_AS_REQ(&req); + } else krb5_abortx(context, "internal pkinit error"); if (ret) { @@ -832,7 +765,11 @@ pk_mk_padata(krb5_context context, ret = krb5_padata_add(context, md, pa_type, buf.data, buf.length); if (ret) free(buf.data); - out: + + if (ret == 0 && compat == COMPAT_WIN2K) + krb5_padata_add(context, md, KRB5_PADATA_PK_AS_09_BINDING, NULL, 0); + +out: free_ContentInfo(&content_info); return ret; @@ -847,11 +784,7 @@ _krb5_pk_mk_padata(krb5_context context, METHOD_DATA *md) { krb5_pk_init_ctx ctx = c; - krb5_error_code ret; - size_t size; - krb5_data buf; - const char *provisioning_server; - int win2k_compat; + int win2k_compat, type; win2k_compat = krb5_config_get_bool_default(context, NULL, FALSE, @@ -863,45 +796,18 @@ _krb5_pk_mk_padata(krb5_context context, win2k_compat = 1; if (win2k_compat) { - ret = pk_mk_padata(context, COMPAT_WIN2K, ctx, req_body, nonce, md); - if (ret) - goto out; - } else { -#if 0 - ret = pk_mk_padata(context, COMPAT_19, ctx, req_body, nonce, md); - if (ret) - goto out; -#endif - ret = pk_mk_padata(context, COMPAT_27, ctx, req_body, nonce, md); - if (ret) - goto out; - } - - provisioning_server = - krb5_config_get_string(context, NULL, - "realms", - req_body->realm, - "packet-cable-provisioning-server", - NULL); - - if (provisioning_server) { - /* PacketCable requires the PROV-SRV-LOCATION authenticator */ - const PROV_SRV_LOCATION prov_server = rk_UNCONST(provisioning_server); - - ASN1_MALLOC_ENCODE(PROV_SRV_LOCATION, buf.data, buf.length, - &prov_server, &size, ret); - if (ret) - goto out; - if (buf.length != size) - krb5_abortx(context, "Internal ASN1 encoder error"); + ctx->require_binding = + krb5_config_get_bool_default(context, NULL, + FALSE, + "realms", + req_body->realm, + "win2k_pkinit_require_binding", + NULL); + type = COMPAT_WIN2K; + } else + type = COMPAT_IETF; - /* PacketCable uses -1 (application specific) as the auth data type */ - ret = krb5_padata_add(context, md, -1, buf.data, buf.length); - if (ret) - free(buf.data); - } - out: - return ret; + return pk_mk_padata(context, type, ctx, req_body, nonce, md); } static krb5_boolean @@ -997,7 +903,7 @@ pk_verify_chain_standard(krb5_context context, int i; int ret; - ret = KRB5_KDC_ERROR_CLIENT_NAME_MISMATCH; + ret = KRB5_KDC_ERR_CLIENT_NAME_MISMATCH; for (i = 0; i < sk_X509_num(chain); i++) { cert = sk_X509_value(chain, i); if (pk_peer_compare(context, client, cert) == TRUE) { @@ -1037,7 +943,7 @@ pk_verify_chain_standard(krb5_context context, ret = 0; break; case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: - ret = KRB5_KDC_ERROR_CANT_VERIFY_CERTIFICATE; + ret = KRB5_KDC_ERR_CANT_VERIFY_CERTIFICATE; krb5_set_error_string(context, "PKINIT: failed to verify " "certificate: %s ", X509_verify_cert_error_string(store_ctx->error)); @@ -1048,7 +954,7 @@ pk_verify_chain_standard(krb5_context context, case X509_V_ERR_CERT_NOT_YET_VALID: case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: case X509_V_ERR_CERT_HAS_EXPIRED: - ret = KRB5_KDC_ERROR_INVALID_CERTIFICATE; + ret = KRB5_KDC_ERR_INVALID_CERTIFICATE; krb5_set_error_string(context, "PKINIT: invalid certificate: %s ", X509_verify_cert_error_string(store_ctx->error)); break; @@ -1058,13 +964,13 @@ pk_verify_chain_standard(krb5_context context, case X509_V_ERR_CERT_CHAIN_TOO_LONG: case X509_V_ERR_PATH_LENGTH_EXCEEDED: case X509_V_ERR_INVALID_CA: - ret = KRB5_KDC_ERROR_INVALID_CERTIFICATE; + ret = KRB5_KDC_ERR_INVALID_CERTIFICATE; krb5_set_error_string(context, "PKINIT: unknown CA or can't " "verify certificate: %s", X509_verify_cert_error_string(store_ctx->error)); break; default: - ret = KRB5_KDC_ERROR_INVALID_CERTIFICATE; /* XXX */ + ret = KRB5_KDC_ERR_INVALID_CERTIFICATE; /* XXX */ krb5_set_error_string(context, "PKINIT: failed to verify " "certificate: %s (%ld) ", X509_verify_cert_error_string(store_ctx->error), @@ -1131,7 +1037,7 @@ cert_to_X509(krb5_context context, CertificateSet *set, krb5_error_code KRB5_LIB_FUNCTION _krb5_pk_verify_sign(krb5_context context, - const char *data, + const void *data, size_t length, struct krb5_pk_identity *id, heim_oid *contentType, @@ -1280,41 +1186,41 @@ _krb5_pk_verify_sign(krb5_context context, } static krb5_error_code -get_reply_key_19(krb5_context context, - const krb5_data *content, - unsigned nonce, - krb5_keyblock **key) +get_reply_key_win(krb5_context context, + const krb5_data *content, + unsigned nonce, + krb5_keyblock **key) { - ReplyKeyPack_19 key_pack; + ReplyKeyPack_Win2k key_pack; krb5_error_code ret; size_t size; - ret = decode_ReplyKeyPack_19(content->data, - content->length, - &key_pack, - &size); + ret = decode_ReplyKeyPack_Win2k(content->data, + content->length, + &key_pack, + &size); if (ret) { krb5_set_error_string(context, "PKINIT decoding reply key failed"); - free_ReplyKeyPack_19(&key_pack); + free_ReplyKeyPack_Win2k(&key_pack); return ret; } if (key_pack.nonce != nonce) { krb5_set_error_string(context, "PKINIT enckey nonce is wrong"); - free_ReplyKeyPack_19(&key_pack); + free_ReplyKeyPack_Win2k(&key_pack); return KRB5KRB_AP_ERR_MODIFIED; } *key = malloc (sizeof (**key)); if (*key == NULL) { krb5_set_error_string(context, "PKINIT failed allocating reply key"); - free_ReplyKeyPack_19(&key_pack); + free_ReplyKeyPack_Win2k(&key_pack); krb5_set_error_string(context, "malloc: out of memory"); return ENOMEM; } ret = copy_EncryptionKey(&key_pack.replyKey, *key); - free_ReplyKeyPack_19(&key_pack); + free_ReplyKeyPack_Win2k(&key_pack); if (ret) { krb5_set_error_string(context, "PKINIT failed copying reply key"); free(*key); @@ -1399,6 +1305,7 @@ pk_rd_pa_reply_enckey(krb5_context context, ContentInfo *rep, krb5_pk_init_ctx ctx, krb5_enctype etype, + const krb5_krbhst_info *hi, unsigned nonce, const krb5_data *req_buffer, PA_DATA *pa, @@ -1413,7 +1320,7 @@ pk_rd_pa_reply_enckey(krb5_context context, int length; size_t size; X509 *user_cert; - char *p; + void *p; krb5_boolean bret; krb5_data content; heim_oid contentType = { 0, NULL }; @@ -1481,13 +1388,13 @@ pk_rd_pa_reply_enckey(krb5_context context, goto out; - /* verify content type */ - if (type == COMPAT_WIN2K) { - if (heim_oid_cmp(&ed.encryptedContentInfo.contentType, oid_id_pkcs7_data())) { - ret = KRB5KRB_AP_ERR_MSG_TYPE; - goto out; - } - } else { + /* + * Try to verify content type. We can't do this for W2K case + * because W2K/W2K3 sends id-pkcs7-data, but Windows Vista sends + * id-pkcs7-signedData to all versions, even W2K clients. + */ + + if (type != COMPAT_WIN2K) { if (heim_oid_cmp(&ed.encryptedContentInfo.contentType, oid_id_pkcs7_signedData())) { ret = KRB5KRB_AP_ERR_MSG_TYPE; goto out; @@ -1563,7 +1470,7 @@ pk_rd_pa_reply_enckey(krb5_context context, } p = ci.content->data; length = ci.content->length; - } + } ret = _krb5_pk_verify_sign(context, p, @@ -1582,6 +1489,7 @@ pk_rd_pa_reply_enckey(krb5_context context, goto out; } +#if 0 if (type == COMPAT_WIN2K) { if (heim_oid_cmp(&contentType, oid_id_pkcs7_data()) != 0) { krb5_set_error_string(context, "PKINIT: reply key, wrong oid"); @@ -1595,13 +1503,15 @@ pk_rd_pa_reply_enckey(krb5_context context, goto out; } } +#endif switch(type) { case COMPAT_WIN2K: - case COMPAT_19: - ret = get_reply_key_19(context, &content, nonce, key); + ret = get_reply_key(context, &content, req_buffer, key); + if (ret != 0 && ctx->require_binding == 0) + ret = get_reply_key_win(context, &content, nonce, key); break; - case COMPAT_27: + case COMPAT_IETF: ret = get_reply_key(context, &content, req_buffer, key); break; } @@ -1628,6 +1538,7 @@ pk_rd_pa_reply_dh(krb5_context context, ContentInfo *rep, krb5_pk_init_ctx ctx, krb5_enctype etype, + const krb5_krbhst_info *hi, const DHNonce *c_n, const DHNonce *k_n, unsigned nonce, @@ -1674,7 +1585,8 @@ pk_rd_pa_reply_dh(krb5_context context, goto out; if (heim_oid_cmp(&contentType, oid_id_pkdhkeydata())) { - ret = KRB5KRB_AP_ERR_MSG_TYPE; /* XXX */ + krb5_set_error_string(context, "pkinit - dh reply contains wrong oid"); + ret = KRB5KRB_AP_ERR_MSG_TYPE; goto out; } @@ -1799,6 +1711,7 @@ krb5_error_code KRB5_LIB_FUNCTION _krb5_pk_rd_pa_reply(krb5_context context, void *c, krb5_enctype etype, + const krb5_krbhst_info *hi, unsigned nonce, const krb5_data *req_buffer, PA_DATA *pa, @@ -1836,8 +1749,10 @@ _krb5_pk_rd_pa_reply(krb5_context context, free_PA_PK_AS_REP(&rep); break; } - ret = pk_rd_pa_reply_dh(context, &ci, ctx, - etype, NULL, NULL, nonce, pa, key); + ret = pk_rd_pa_reply_dh(context, &ci, ctx, etype, hi, + ctx->clientDHNonce, + rep.u.dhInfo.serverDHNonce, + nonce, pa, key); free_ContentInfo(&ci); free_PA_PK_AS_REP(&rep); @@ -1854,8 +1769,8 @@ _krb5_pk_rd_pa_reply(krb5_context context, "ContentInfo: %d", ret); break; } - ret = pk_rd_pa_reply_enckey(context, COMPAT_27, &ci, ctx, - etype, nonce, req_buffer, pa, key); + ret = pk_rd_pa_reply_enckey(context, COMPAT_IETF, &ci, ctx, + etype, hi, nonce, req_buffer, pa, key); free_ContentInfo(&ci); return ret; default: @@ -1869,40 +1784,6 @@ _krb5_pk_rd_pa_reply(krb5_context context, return ret; } - /* Check for PK-INIT -19 */ - { - PA_PK_AS_REP_19 rep19; - - memset(&rep19, 0, sizeof(rep19)); - - ret = decode_PA_PK_AS_REP_19(pa->padata_value.data, - pa->padata_value.length, - &rep19, - &size); - if (ret == 0) { - switch(rep19.element) { - case choice_PA_PK_AS_REP_19_dhSignedData: - ret = pk_rd_pa_reply_dh(context, &rep19.u.dhSignedData, ctx, - etype, NULL, NULL, - nonce, pa, key); - break; - case choice_PA_PK_AS_REP_19_encKeyPack: - ret = pk_rd_pa_reply_enckey(context, COMPAT_19, - &rep19.u.encKeyPack, ctx, - etype, nonce, NULL, pa, key); - break; - default: - krb5_set_error_string(context, "PKINIT: -19 reply invalid " - "content type"); - ret = EINVAL; - break; - } - free_PA_PK_AS_REP_19(&rep19); - if (ret == 0) - return 0; - } - } - /* Check for Windows encoding of the AS-REP pa data */ { PA_PK_AS_REP_Win2k w2krep; @@ -1918,6 +1799,8 @@ _krb5_pk_rd_pa_reply(krb5_context context, "pkinit reply %d", ret); return ret; } + + krb5_clear_error_string(context); switch (w2krep.element) { case choice_PA_PK_AS_REP_Win2k_encKeyPack: @@ -1934,7 +1817,7 @@ _krb5_pk_rd_pa_reply(krb5_context context, return ret; } ret = pk_rd_pa_reply_enckey(context, COMPAT_WIN2K, &ci, ctx, - etype, nonce, NULL, pa, key); + etype, hi, nonce, NULL, pa, key); free_ContentInfo(&ci); break; default: @@ -2546,6 +2429,264 @@ _krb5_pk_load_openssl_id(krb5_context context, return ret; } +static int +parse_integer(krb5_context context, char **p, const char *file, int lineno, + const char *name, heim_integer *integer) +{ + int ret; + char *p1; + p1 = strsep(p, " \t"); + if (p1 == NULL) { + krb5_set_error_string(context, "moduli file %s missing %s on line %d", + file, name, lineno); + return EINVAL; + } + ret = der_parse_hex_heim_integer(p1, integer); + if (ret) { + krb5_set_error_string(context, "moduli file %s failed parsing %s " + "on line %d", + file, name, lineno); + return ret; + } + + return 0; +} + +krb5_error_code +_krb5_parse_moduli_line(krb5_context context, + const char *file, + int lineno, + char *p, + struct krb5_dh_moduli **m) +{ + struct krb5_dh_moduli *m1; + char *p1; + int ret; + + *m = NULL; + + m1 = calloc(1, sizeof(*m1)); + if (m1 == NULL) { + krb5_set_error_string(context, "malloc - out of memory"); + return ENOMEM; + } + + while (isspace((unsigned char)*p)) + p++; + if (*p == '#') + return 0; + ret = EINVAL; + + p1 = strsep(&p, " \t"); + if (p1 == NULL) { + krb5_set_error_string(context, "moduli file %s missing name " + "on line %d", file, lineno); + goto out; + } + m1->name = strdup(p1); + if (p1 == NULL) { + krb5_set_error_string(context, "malloc - out of memeory"); + ret = ENOMEM; + goto out; + } + + p1 = strsep(&p, " \t"); + if (p1 == NULL) { + krb5_set_error_string(context, "moduli file %s missing bits on line %d", + file, lineno); + goto out; + } + + m1->bits = atoi(p1); + if (m1->bits == 0) { + krb5_set_error_string(context, "moduli file %s have un-parsable " + "bits on line %d", file, lineno); + goto out; + } + + ret = parse_integer(context, &p, file, lineno, "p", &m1->p); + if (ret) + goto out; + ret = parse_integer(context, &p, file, lineno, "g", &m1->g); + if (ret) + goto out; + ret = parse_integer(context, &p, file, lineno, "q", &m1->q); + if (ret) + goto out; + + *m = m1; + + return 0; +out: + free(m1->name); + free_heim_integer(&m1->p); + free_heim_integer(&m1->g); + free_heim_integer(&m1->q); + free(m1); + return ret; +} + +static void +_krb5_free_moduli(struct krb5_dh_moduli **moduli) +{ + int i; + for (i = 0; moduli[i] != NULL; i++) { + free(moduli[i]->name); + free_heim_integer(&moduli[i]->p); + free_heim_integer(&moduli[i]->g); + free_heim_integer(&moduli[i]->q); + free(moduli[i]); + } + free(moduli); +} + +static const char *default_moduli = + /* bits */ + "RFC2412-MODP-group2 " + "1024 " + /* p */ + "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1" + "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD" + "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245" + "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" + "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381" + "FFFFFFFF" "FFFFFFFF " + /* g */ + "02 " + /* q */ + "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68" + "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E" + "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122" + "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6" + "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F67329C0" + "FFFFFFFF" "FFFFFFFF"; + + +krb5_error_code +_krb5_parse_moduli(krb5_context context, const char *file, + struct krb5_dh_moduli ***moduli) +{ + /* comment bits P G Q */ + krb5_error_code ret; + struct krb5_dh_moduli **m = NULL, **m2; + char buf[4096]; + FILE *f; + int lineno = 0, n = 0; + + *moduli = NULL; + + m = calloc(1, sizeof(m[0]) * 2); + if (m == NULL) { + krb5_set_error_string(context, "malloc: out of memory"); + return ENOMEM; + } + + strlcpy(buf, default_moduli, sizeof(buf)); + ret = _krb5_parse_moduli_line(context, "builtin", 1, buf, &m[0]); + if (ret) { + _krb5_free_moduli(m); + return ret; + } + n = 1; + + if (file == NULL) { + *moduli = m; + return 0; + } + + f = fopen(file, "r"); + if (f == NULL) { + *moduli = m; + return 0; + } + + while(fgets(buf, sizeof(buf), f) != NULL) { + struct krb5_dh_moduli *element; + + buf[strcspn(buf, "\n")] = '\0'; + lineno++; + + m2 = realloc(m, (n + 2) * sizeof(m[0])); + if (m2 == NULL) { + krb5_set_error_string(context, "malloc: out of memory"); + _krb5_free_moduli(m); + return ENOMEM; + } + m = m2; + + m[n] = NULL; + + ret = _krb5_parse_moduli_line(context, file, lineno, buf, &element); + if (ret) { + _krb5_free_moduli(m); + return ret; + } + if (element == NULL) + continue; + + m[n] = element; + m[n + 1] = NULL; + n++; + } + *moduli = m; + return 0; +} + +krb5_error_code +_krb5_dh_group_ok(krb5_context context, unsigned long bits, + heim_integer *p, heim_integer *g, heim_integer *q, + struct krb5_dh_moduli **moduli, + char **name) +{ + int i; + + if (name) + *name = NULL; + + for (i = 0; moduli[i] != NULL; i++) { + if (heim_integer_cmp(&moduli[i]->g, g) == 0 && + heim_integer_cmp(&moduli[i]->p, p) == 0 && + heim_integer_cmp(&moduli[i]->q, q) == 0) + { + if (bits && bits > moduli[i]->bits) { + krb5_set_error_string(context, "PKINIT: DH group parameter %s " + "no accepted, not enough bits generated", + moduli[i]->name); + return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED; + } + if (name) + *name = strdup(moduli[i]->name); + return 0; + } + } + krb5_set_error_string(context, "PKINIT: DH group parameter no ok"); + return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED; +} + +static krb5_error_code +select_dh_group(krb5_context context, DH *dh, unsigned long bits, + struct krb5_dh_moduli **moduli) +{ + const struct krb5_dh_moduli *m; + + m = moduli[1]; /* XXX */ + if (m == NULL) + m = moduli[0]; /* XXX */ + + dh->p = integer_to_BN(context, "p", &m->p); + if (dh->p == NULL) + return ENOMEM; + dh->g = integer_to_BN(context, "g", &m->g); + if (dh->g == NULL) + return ENOMEM; + dh->q = integer_to_BN(context, "q", &m->q); + if (dh->q == NULL) + return ENOMEM; + + return 0; +} + + #endif /* PKINIT */ void KRB5_LIB_FUNCTION @@ -2554,9 +2695,9 @@ _krb5_get_init_creds_opt_free_pkinit(krb5_get_init_creds_opt *opt) #ifdef PKINIT krb5_pk_init_ctx ctx; - if (opt->private == NULL || opt->private->pk_init_ctx == NULL) + if (opt->opt_private == NULL || opt->opt_private->pk_init_ctx == NULL) return; - ctx = opt->private->pk_init_ctx; + ctx = opt->opt_private->pk_init_ctx; if (ctx->dh) DH_free(ctx->dh); ctx->dh = NULL; @@ -2572,10 +2713,16 @@ _krb5_get_init_creds_opt_free_pkinit(krb5_get_init_creds_opt *opt) ENGINE_free(ctx->id->engine); ctx->id->engine = NULL; } + if (ctx->clientDHNonce) { + krb5_free_data(NULL, ctx->clientDHNonce); + ctx->clientDHNonce = NULL; + } + if (ctx->m) + _krb5_free_moduli(ctx->m); free(ctx->id); ctx->id = NULL; } - opt->private->pk_init_ctx = NULL; + opt->opt_private->pk_init_ctx = NULL; #endif } @@ -2593,79 +2740,73 @@ krb5_get_init_creds_opt_set_pkinit(krb5_context context, #ifdef PKINIT krb5_error_code ret; - if (opt->private == NULL) { + if (opt->opt_private == NULL) { krb5_set_error_string(context, "PKINIT: on non extendable opt"); return EINVAL; } - opt->private->pk_init_ctx = malloc(sizeof(*opt->private->pk_init_ctx)); - if (opt->private->pk_init_ctx == NULL) { + opt->opt_private->pk_init_ctx = + calloc(1, sizeof(*opt->opt_private->pk_init_ctx)); + if (opt->opt_private->pk_init_ctx == NULL) { krb5_set_error_string(context, "malloc: out of memory"); return ENOMEM; } - opt->private->pk_init_ctx->dh = NULL; - opt->private->pk_init_ctx->id = NULL; + opt->opt_private->pk_init_ctx->dh = NULL; + opt->opt_private->pk_init_ctx->id = NULL; + opt->opt_private->pk_init_ctx->clientDHNonce = NULL; + opt->opt_private->pk_init_ctx->require_binding = 0; + ret = _krb5_pk_load_openssl_id(context, - &opt->private->pk_init_ctx->id, + &opt->opt_private->pk_init_ctx->id, user_id, x509_anchors, prompter, prompter_data, password); if (ret) { - free(opt->private->pk_init_ctx); - opt->private->pk_init_ctx = NULL; + free(opt->opt_private->pk_init_ctx); + opt->opt_private->pk_init_ctx = NULL; + return ret; } - /* XXX */ - if (ret == 0 && (flags & 1) && !(flags & 2)) { - DH *dh; - const char *P = - "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1" - "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD" - "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245" - "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" - "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381" - "FFFFFFFF" "FFFFFFFF"; - const char *G = "2"; - const char *Q = - "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68" - "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E" - "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122" - "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6" - "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F67329C0" - "FFFFFFFF" "FFFFFFFF"; - - dh = DH_new(); - if (dh == NULL) { - krb5_set_error_string(context, "malloc: out of memory"); - _krb5_get_init_creds_opt_free_pkinit(opt); - return ENOMEM; - } - opt->private->pk_init_ctx->dh = dh; - if (!BN_hex2bn(&dh->p, P)) { - krb5_set_error_string(context, "malloc: out of memory"); + if ((flags & 2) == 0) { + const char *moduli_file; + + moduli_file = krb5_config_get_string_default(context, NULL, + MODULI_FILE, + "libdefaults", + "moduli", + NULL); + + ret = _krb5_parse_moduli(context, moduli_file, + &opt->opt_private->pk_init_ctx->m); + if (ret) { _krb5_get_init_creds_opt_free_pkinit(opt); - return ENOMEM; + return ret; } - if (!BN_hex2bn(&dh->g, G)) { + + opt->opt_private->pk_init_ctx->dh = DH_new(); + if (opt->opt_private->pk_init_ctx->dh == NULL) { krb5_set_error_string(context, "malloc: out of memory"); _krb5_get_init_creds_opt_free_pkinit(opt); return ENOMEM; } - if (!BN_hex2bn(&dh->q, Q)) { - krb5_set_error_string(context, "malloc: out of memory"); + + ret = select_dh_group(context, opt->opt_private->pk_init_ctx->dh, 0, + opt->opt_private->pk_init_ctx->m); + if (ret) { _krb5_get_init_creds_opt_free_pkinit(opt); - return ENOMEM; + return ret; } - /* XXX generate a new key for each request ? */ - if (DH_generate_key(dh) != 1) { + + if (DH_generate_key(opt->opt_private->pk_init_ctx->dh) != 1) { krb5_set_error_string(context, "malloc: out of memory"); _krb5_get_init_creds_opt_free_pkinit(opt); return ENOMEM; } } - return ret; + + return 0; #else krb5_set_error_string(context, "no support for PKINIT compiled in"); return EINVAL; diff --git a/source4/heimdal/lib/krb5/rd_cred.c b/source4/heimdal/lib/krb5/rd_cred.c index 2571591e9d..ddd5866aeb 100644 --- a/source4/heimdal/lib/krb5/rd_cred.c +++ b/source4/heimdal/lib/krb5/rd_cred.c @@ -33,7 +33,7 @@ #include -RCSID("$Id: rd_cred.c,v 1.24 2005/07/13 08:22:50 lha Exp $"); +RCSID("$Id: rd_cred.c,v 1.25 2005/09/23 03:37:57 lha Exp $"); static krb5_error_code compare_addrs(krb5_context context, @@ -99,24 +99,49 @@ krb5_rd_cred(krb5_context context, enc_krb_cred_part_data.length = cred.enc_part.cipher.length; enc_krb_cred_part_data.data = cred.enc_part.cipher.data; } else { - if (auth_context->remote_subkey) + /* Try both subkey and session key. + * + * RFC2140 claims we should use the session key, but Heimdal + * before 0.8 used the remote subkey if it was send in the + * auth_context. + */ + + if (auth_context->remote_subkey) { ret = krb5_crypto_init(context, auth_context->remote_subkey, 0, &crypto); - else + if (ret) + goto out; + + ret = krb5_decrypt_EncryptedData(context, + crypto, + KRB5_KU_KRB_CRED, + &cred.enc_part, + &enc_krb_cred_part_data); + + krb5_crypto_destroy(context, crypto); + } + + /* + * If there was not subkey, or we failed using subkey, + * retry using the session key + */ + if (auth_context->remote_subkey == NULL || ret == KRB5KRB_AP_ERR_BAD_INTEGRITY) + { + ret = krb5_crypto_init(context, auth_context->keyblock, 0, &crypto); - /* DK: MIT rsh */ - if (ret) - goto out; - - ret = krb5_decrypt_EncryptedData(context, - crypto, - KRB5_KU_KRB_CRED, - &cred.enc_part, - &enc_krb_cred_part_data); - - krb5_crypto_destroy(context, crypto); + if (ret) + goto out; + + ret = krb5_decrypt_EncryptedData(context, + crypto, + KRB5_KU_KRB_CRED, + &cred.enc_part, + &enc_krb_cred_part_data); + + krb5_crypto_destroy(context, crypto); + } if (ret) goto out; } diff --git a/source4/heimdal/lib/roken/roken-common.h b/source4/heimdal/lib/roken/roken-common.h index c4ba2edb7c..8368530ff7 100644 --- a/source4/heimdal/lib/roken/roken-common.h +++ b/source4/heimdal/lib/roken/roken-common.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -/* $Id: roken-common.h,v 1.62 2005/09/01 18:47:35 lha Exp $ */ +/* $Id: roken-common.h,v 1.64 2005/09/28 03:05:58 lha Exp $ */ #ifndef __ROKEN_COMMON_H__ #define __ROKEN_COMMON_H__ @@ -258,8 +258,6 @@ #define __attribute__(x) #endif -#define rk_UNCONST(x) ((void *)(unsigned long)(const void *)(x)) - ROKEN_CPP_START #ifndef IRIX4 /* fix for compiler bug */ @@ -396,6 +394,8 @@ rk_strpoolprintf(struct rk_strpool *, const char *, ...) void ROKEN_LIB_FUNCTION rk_strpoolfree(struct rk_strpool *); +void ROKEN_LIB_FUNCTION +rk_dumpdata (const char *, const void *, size_t); ROKEN_CPP_END diff --git a/source4/heimdal/lib/roken/roken.h b/source4/heimdal/lib/roken/roken.h index 04553caf48..853de9b112 100644 --- a/source4/heimdal/lib/roken/roken.h +++ b/source4/heimdal/lib/roken/roken.h @@ -32,11 +32,14 @@ * SUCH DAMAGE. */ -/* $Id: roken.h.in,v 1.177 2005/08/05 09:06:29 lha Exp $ */ +/* $Id: roken.h.in,v 1.178 2005/09/28 03:04:54 lha Exp $ */ #include #include #include +#ifdef HAVE_STDINT_H +#include +#endif #include #include @@ -138,6 +141,12 @@ typedef int ssize_t; ROKEN_CPP_START +#ifdef HAVE_UINTPTR_T +#define rk_UNCONST(x) ((void *)(uintptr_t)(const void *)(x)) +#else +#define rk_UNCONST(x) ((void *)(unsigned long)(const void *)(x)) +#endif + #if !defined(HAVE_SETSID) && defined(HAVE__SETSID) #define setsid _setsid #endif -- cgit