diff --git a/kdc/fast.c b/kdc/fast.c index 5c80d29ba..1e981d27a 100644 --- a/kdc/fast.c +++ b/kdc/fast.c @@ -46,6 +46,7 @@ get_fastuser_crypto(astgs_request_t r, krb5_enctype enctype, *crypto = NULL; + /* TODO: salt cookie key with client name and realm */ ret = krb5_make_principal(r->context, &fast_princ, KRB5_WELLKNOWN_ORG_H5L_REALM, KRB5_WELLKNOWN_NAME, "org.h5l.fast-cookie", NULL); @@ -116,7 +117,7 @@ fast_parse_cookie(astgs_request_t r, const PA_DATA *pa) goto out; if (r->fast.expiration < kdc_time) { - kdc_log(r->context, r->config, 2, "fast cookie expired"); + kdc_log(r->context, r->config, 2, "FAST cookie expired"); ret = KRB5KDC_ERR_POLICY; goto out; } @@ -140,15 +141,18 @@ fast_add_cookie(astgs_request_t r, METHOD_DATA *method_data) r->fast.expiration = kdc_time + FAST_EXPIRATION_TIME; - ASN1_MALLOC_ENCODE(KDCFastState, data.data, data.length, + ASN1_MALLOC_ENCODE(KDCFastState, data.data, data.length, &r->fast, &size, ret); if (ret) return ret; - heim_assert(size == data.length, "internal asn1 encoder error"); + heim_assert(size == data.length, "internal asn.1 encoder error"); ret = get_fastuser_crypto(r, KRB5_ENCTYPE_NULL, &crypto); - if (ret) + if (ret) { + kdc_log(r->context, r->config, 0, + "Failed to find FAST principal for cookie encryption: %d", ret); goto out; + } ret = krb5_encrypt_EncryptedData(r->context, crypto, KRB5_KU_H5L_COOKIE, @@ -157,24 +161,26 @@ fast_add_cookie(astgs_request_t r, METHOD_DATA *method_data) krb5_crypto_destroy(r->context, crypto); if (ret) goto out; - - free(data.data); + + krb5_data_free(&data); shell.version = "H5L1"; - ASN1_MALLOC_ENCODE(KDCFastCookie, data.data, data.length, + ASN1_MALLOC_ENCODE(KDCFastCookie, data.data, data.length, &shell, &size, ret); free_EncryptedData(&shell.cookie); if (ret) goto out; - heim_assert(size == data.length, "internal asn1 encoder error"); - + heim_assert(size == data.length, "internal asn.1 encoder error"); + ret = krb5_padata_add(r->context, method_data, KRB5_PADATA_FX_COOKIE, data.data, data.length); + if (ret == 0) + krb5_data_zero(&data); + out: - if (ret) - free(data.data); + krb5_data_free(&data); return ret; } @@ -209,9 +215,8 @@ _kdc_fast_mk_response(krb5_context context, &fastrep, &size, ret); if (ret) return ret; - if (buf.length != size) - krb5_abortx(context, "internal asn.1 error"); - + heim_assert(size == buf.length, "internal asn.1 encoder error"); + fxfastrep.element = choice_PA_FX_FAST_REPLY_armored_data; ret = krb5_encrypt_EncryptedData(context, @@ -230,9 +235,8 @@ _kdc_fast_mk_response(krb5_context context, free_PA_FX_FAST_REPLY(&fxfastrep); if (ret) return ret; - if (data->length != size) - krb5_abortx(context, "internal asn.1 error"); - + heim_assert(size == data->length, "internal asn.1 encoder error"); + return 0; } @@ -244,9 +248,8 @@ _kdc_fast_mk_error(astgs_request_t r, const KDC_REQ_BODY *req_body, krb5_error_code outer_error, const char *e_text, + krb5_principal error_client, krb5_principal error_server, - const PrincipalName *error_client_name, - const Realm *error_client_realm, time_t *csec, int *cusec, krb5_data *error_msg) { @@ -257,15 +260,16 @@ _kdc_fast_mk_error(astgs_request_t r, krb5_data_zero(&e_data); - if (armor_crypto || (r && r->fast.fast_state.len)) { - if (r) - ret = fast_add_cookie(r, error_method); - else - ret = krb5_padata_add(context, error_method, - KRB5_PADATA_FX_COOKIE, - NULL, 0); + heim_assert(r != NULL, "invalid request in _kdc_fast_mk_error"); + + /* + * FX-COOKIE can be used outside of FAST, e.g. SRP or GSS. + */ + if (armor_crypto || r->fast.fast_state.len) { + ret = fast_add_cookie(r, error_method); if (ret) { - kdc_log(r->context, r->config, 1, "failed to add fast cookie with: %d", ret); + kdc_log(r->context, r->config, 1, + "Failed to add FAST cookie: %d", ret); free_METHOD_DATA(error_method); return ret; } @@ -277,19 +281,18 @@ _kdc_fast_mk_error(astgs_request_t r, memset(&fxfastrep, 0, sizeof(fxfastrep)); memset(&fastrep, 0, sizeof(fastrep)); - + /* first add the KRB-ERROR to the fast errors */ - ret = krb5_mk_error_ext(context, - outer_error, - e_text, - NULL, - error_server, - error_client_name, - error_client_realm, - NULL, - NULL, - &e_data); + ret = krb5_mk_error(context, + outer_error, + e_text, + NULL, + error_client, + error_server, + NULL, + NULL, + &e_data); if (ret) return ret; @@ -301,18 +304,22 @@ _kdc_fast_mk_error(astgs_request_t r, return ret; } - error_client_name = NULL; - error_client_realm = NULL; - error_server = NULL; - e_text = NULL; + outer_error = KRB5_KDC_ERR_MORE_PREAUTH_DATA_REQUIRED; + e_text = NULL; + if (r->fast.flags.requested_hidden_names) { + error_client = NULL; + error_server = NULL; + } + csec = 0; + cusec = 0; ret = _kdc_fast_mk_response(context, armor_crypto, - error_method, NULL, NULL, + error_method, NULL, NULL, req_body->nonce, &e_data); free_METHOD_DATA(error_method); if (ret) return ret; - + ret = krb5_padata_add(context, error_method, KRB5_PADATA_FX_FAST, e_data.data, e_data.length); @@ -321,31 +328,31 @@ _kdc_fast_mk_error(astgs_request_t r, } if (error_method && error_method->len) { - ASN1_MALLOC_ENCODE(METHOD_DATA, e_data.data, e_data.length, + ASN1_MALLOC_ENCODE(METHOD_DATA, e_data.data, e_data.length, error_method, &size, ret); if (ret) return ret; - if (e_data.length != size) - krb5_abortx(context, "internal asn.1 error"); + heim_assert(size == e_data.length, "internal asn.1 encoder error"); } - - ret = krb5_mk_error_ext(context, - outer_error, - e_text, - (e_data.length ? &e_data : NULL), - error_server, - error_client_name, - error_client_realm, - csec, - cusec, - error_msg); + + ret = krb5_mk_error(context, + outer_error, + e_text, + (e_data.length ? &e_data : NULL), + error_client, + error_server, + csec, + cusec, + error_msg); krb5_data_free(&e_data); return ret; } static krb5_error_code -fast_unwrap_request(astgs_request_t r) +fast_unwrap_request(astgs_request_t r, + krb5_ticket *tgs_ticket, + krb5_auth_context tgs_ac) { krb5_principal armor_server = NULL; hdb_entry_ex *armor_user = NULL; @@ -358,101 +365,120 @@ fast_unwrap_request(astgs_request_t r) krb5_error_code ret; krb5_ap_req ap_req; KrbFastReq fastreq; - size_t len, size; - krb5_data data; const PA_DATA *pa; + krb5_data data; + size_t len; int i = 0; pa = _kdc_find_padata(&r->req, &i, KRB5_PADATA_FX_FAST); - if (pa == NULL) + if (pa == NULL) { + if (tgs_ac && r->fast_asserted) { + kdc_log(r->context, r->config, 1, + "Client asserted FAST but did not include FX-FAST pa-data"); + ret = KRB5KRB_AP_ERR_MODIFIED; + goto out; + } + + kdc_log(r->context, r->config, 10, "Not a FAST request"); return 0; + } ret = decode_PA_FX_FAST_REQUEST(pa->padata_value.data, pa->padata_value.length, &fxreq, &len); - if (ret) - goto out; - if (len != pa->padata_value.length) { - ret = KRB5KDC_ERR_PREAUTH_FAILED; + if (ret) { + kdc_log(r->context, r->config, 4, + "Failed to decode PA-FX-FAST-REQUEST: %d", ret); goto out; } if (fxreq.element != choice_PA_FX_FAST_REQUEST_armored_data) { - kdc_log(r->context, r->config, 2, - "AS-REQ FAST contain unknown type: %d", (int)fxreq.element); + kdc_log(r->context, r->config, 4, + "PA-FX-FAST-REQUEST contains unknown type: %d", + (int)fxreq.element); ret = KRB5KDC_ERR_PREAUTH_FAILED; goto out; } - /* pull out armor key */ - if (fxreq.u.armored_data.armor == NULL) { - kdc_log(r->context, r->config, 2, + /* + * If check for armor data or it's not a TGS-REQ with implicit + * armor. + */ + if (fxreq.u.armored_data.armor == NULL && tgs_ac == NULL) { + kdc_log(r->context, r->config, 4, "AS-REQ armor missing"); ret = KRB5KDC_ERR_PREAUTH_FAILED; goto out; } - if (fxreq.u.armored_data.armor->armor_type != 1) { - kdc_log(r->context, r->config, 2, - "AS-REQ armor type not ap-req"); - ret = KRB5KDC_ERR_PREAUTH_FAILED; - goto out; - } - - ret = krb5_decode_ap_req(r->context, - &fxreq.u.armored_data.armor->armor_value, - &ap_req); - if(ret) { - kdc_log(r->context, r->config, 2, "AP-REQ decode failed"); - goto out; - } + /* + * + */ + if (tgs_ac == NULL) { + if (fxreq.u.armored_data.armor->armor_type != 1) { + kdc_log(r->context, r->config, 4, + "Incorrect AS-REQ armor type"); + ret = KRB5KDC_ERR_PREAUTH_FAILED; + goto out; + } - /* Save that principal that was in the request */ - ret = _krb5_principalname2krb5_principal(r->context, - &armor_server, - ap_req.ticket.sname, - ap_req.ticket.realm); - if (ret) { - free_AP_REQ(&ap_req); - goto out; - } + ret = krb5_decode_ap_req(r->context, + &fxreq.u.armored_data.armor->armor_value, + &ap_req); + if(ret) { + kdc_log(r->context, r->config, 4, "Failed to decode AP-REQ"); + goto out; + } - ret = _kdc_db_fetch(r->context, r->config, armor_server, - HDB_F_GET_KRBTGT - | HDB_F_DELAY_NEW_KEYS, - NULL, NULL, &armor_user); - if(ret == HDB_ERR_NOT_FOUND_HERE) { - kdc_log(r->context, r->config, 5, - "armor key does not have secrets at this KDC, " - "need to proxy"); - free_AP_REQ(&ap_req); - goto out; - } else if (ret) { - free_AP_REQ(&ap_req); - ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; - goto out; - } + /* Save that principal that was in the request */ + ret = _krb5_principalname2krb5_principal(r->context, + &armor_server, + ap_req.ticket.sname, + ap_req.ticket.realm); + if (ret) { + free_AP_REQ(&ap_req); + goto out; + } - ret = hdb_enctype2key(r->context, &armor_user->entry, NULL, - ap_req.ticket.enc_part.etype, - &armor_key); - if (ret) { - free_AP_REQ(&ap_req); - goto out; - } + ret = _kdc_db_fetch(r->context, r->config, armor_server, + HDB_F_GET_KRBTGT | HDB_F_DELAY_NEW_KEYS, + NULL, NULL, &armor_user); + if(ret == HDB_ERR_NOT_FOUND_HERE) { + kdc_log(r->context, r->config, 5, + "Armor key does not have secrets at this KDC, " + "need to proxy"); + goto out; + } else if (ret) { + free_AP_REQ(&ap_req); + ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; + goto out; + } - ret = krb5_verify_ap_req2(r->context, &ac, - &ap_req, - armor_server, - &armor_key->key, - 0, - &ap_req_options, - &ticket, - KRB5_KU_AP_REQ_AUTH); - free_AP_REQ(&ap_req); - if (ret) - goto out; + ret = hdb_enctype2key(r->context, &armor_user->entry, NULL, + ap_req.ticket.enc_part.etype, + &armor_key); + if (ret) { + free_AP_REQ(&ap_req); + goto out; + } + + ret = krb5_verify_ap_req2(r->context, &ac, + &ap_req, + armor_server, + &armor_key->key, + 0, + &ap_req_options, + &ticket, + KRB5_KU_AP_REQ_AUTH); + free_AP_REQ(&ap_req); + if (ret) + goto out; + } else { + heim_assert(tgs_ticket != NULL, "TGS authentication context without ticket"); + ac = tgs_ac; + ticket = tgs_ticket; + } if (ac->remote_subkey == NULL) { krb5_auth_con_free(r->context, ac); @@ -460,31 +486,21 @@ fast_unwrap_request(astgs_request_t r) "FAST AP-REQ remote subkey missing"); ret = KRB5KDC_ERR_PREAUTH_FAILED; goto out; - } + } + + r->fast.flags.kdc_verified = + !_kdc_is_anonymous_pkinit(r->context, ticket->client); ret = _krb5_fast_armor_key(r->context, ac->remote_subkey, &ticket->ticket.key, &armorkey, &r->armor_crypto); - krb5_auth_con_free(r->context, ac); - krb5_free_ticket(r->context, ticket); if (ret) goto out; krb5_free_keyblock_contents(r->context, &armorkey); - /* verify req-checksum of the outer body */ - ret = _kdc_verify_checksum(r->context, r->armor_crypto, - KRB5_KU_FAST_REQ_CHKSUM, - &r->req.req_body._save, - &fxreq.u.armored_data.req_checksum); - if (ret) { - kdc_log(r->context, r->config, 2, - "FAST request have a bad checksum"); - goto out; - } - ret = krb5_decrypt_EncryptedData(r->context, r->armor_crypto, KRB5_KU_FAST_ENC, &fxreq.u.armored_data.enc_fast_req, @@ -495,24 +511,57 @@ fast_unwrap_request(astgs_request_t r) goto out; } - ret = decode_KrbFastReq(data.data, data.length, &fastreq, &size); - if (ret) { - krb5_data_free(&data); - goto out; - } - if (data.length != size) { - krb5_data_free(&data); - ret = KRB5KDC_ERR_PREAUTH_FAILED; - goto out; - } + ret = decode_KrbFastReq(data.data, data.length, &fastreq, NULL); krb5_data_free(&data); - - free_KDC_REQ_BODY(&r->req.req_body); - ret = copy_KDC_REQ_BODY(&fastreq.req_body, &r->req.req_body); if (ret) goto out; - - /* check for unsupported mandatory options */ + + /* + * verify req-checksum of the outer body + */ + if (tgs_ac) { + /* + * -- For TGS, contains the checksum performed over the type + * -- AP-REQ in the PA-TGS-REQ padata. + */ + i = 0; + pa = _kdc_find_padata(&r->req, &i, KRB5_PADATA_TGS_REQ); + if (pa == NULL) { + kdc_log(r->context, r->config, 4, + "FAST TGS request missing TGS-REQ padata"); + ret = KRB5KRB_ERR_GENERIC; + goto out; + } + + ret = _kdc_verify_checksum(r->context, r->armor_crypto, + KRB5_KU_FAST_REQ_CHKSUM, + &pa->padata_value, + &fxreq.u.armored_data.req_checksum); + if (ret) { + kdc_log(r->context, r->config, 2, + "Bad checksum in FAST TGS request"); + goto out; + } + } else { + /* + * -- For AS, contains the checksum performed over the type + * -- KDC-REQ-BODY for the req-body field of the KDC-REQ + * -- structure; + */ + ret = _kdc_verify_checksum(r->context, r->armor_crypto, + KRB5_KU_FAST_REQ_CHKSUM, + &r->req.req_body._save, + &fxreq.u.armored_data.req_checksum); + if (ret) { + kdc_log(r->context, r->config, 2, + "Bad checksum in FAST AS request"); + goto out; + } + } + + /* + * check for unsupported mandatory options + */ if (FastOptions2int(fastreq.fast_options) & 0xfffc) { kdc_log(r->context, r->config, 2, "FAST unsupported mandatory option set"); @@ -520,6 +569,8 @@ fast_unwrap_request(astgs_request_t r) goto out; } + r->fast.flags.requested_hidden_names = fastreq.fast_options.hide_client_names; + /* KDC MUST ignore outer pa data preauth-14 - 6.5.5 */ if (r->req.padata) free_METHOD_DATA(r->req.padata); @@ -530,10 +581,22 @@ fast_unwrap_request(astgs_request_t r) if (ret) goto out; + free_KDC_REQ_BODY(&r->req.req_body); + ret = copy_KDC_REQ_BODY(&fastreq.req_body, &r->req.req_body); + if (ret) + goto out; + free_KrbFastReq(&fastreq); free_PA_FX_FAST_REQUEST(&fxreq); + kdc_log(r->context, r->config, 5, "Client selected FAST"); + out: + if (ac && ac != tgs_ac) + krb5_auth_con_free(r->context, ac); + if (ticket && ticket != tgs_ticket) + krb5_free_ticket(r->context, ticket); + if (armor_server) krb5_free_principal(r->context, armor_server); if(armor_user) @@ -542,30 +605,70 @@ fast_unwrap_request(astgs_request_t r) return ret; } +/* + * + */ krb5_error_code -_kdc_fast_unwrap_request(astgs_request_t r) +_kdc_fast_unwrap_request(astgs_request_t r, + krb5_ticket *tgs_ticket, + krb5_auth_context tgs_ac) { krb5_error_code ret; const PA_DATA *pa; int i = 0; - ret = fast_unwrap_request(r); + ret = fast_unwrap_request(r, tgs_ticket, tgs_ac); if (ret) return ret; /* - * Non-FAST mechanisms may use FX-COOKIE to manage state. + * FX-COOKIE can be used outside of FAST, e.g. SRP or GSS. */ pa = _kdc_find_padata(&r->req, &i, KRB5_PADATA_FX_COOKIE); - if (pa) { + if (pa) ret = fast_parse_cookie(r, pa); + + return ret; +} + +/* + * Strengthen reply key by mixing with a random key that is + * protected by FAST. + */ +krb5_error_code +_kdc_fast_strengthen_reply_key(astgs_request_t r) +{ + if (r->armor_crypto) { + krb5_keyblock new_reply_key; + krb5_error_code ret; + + kdc_log(r->context, r->config, 5, + "FAST strengthen reply key with strengthen-key"); + + heim_assert(r->reply_key.keytype != KRB5_ENCTYPE_NULL, "NULL reply key enctype"); + + ret = krb5_generate_random_keyblock(r->context, r->reply_key.keytype, + &r->strengthen_key); + if (ret) + krb5_abortx(r->context, "random generator fail"); + + ret = _krb5_fast_cf2(r->context, + &r->strengthen_key, "strengthenkey", + &r->reply_key, "replykey", + &new_reply_key, NULL); if (ret) return ret; + + krb5_free_keyblock_contents(r->context, &r->reply_key); + r->reply_key = new_reply_key; } return 0; } +/* + * Zero and free KDCFastState + */ void _kdc_free_fast_state(KDCFastState *state) { diff --git a/kdc/kdc-tester.c b/kdc/kdc-tester.c index cbe4b1c00..65d52ec66 100644 --- a/kdc/kdc-tester.c +++ b/kdc/kdc-tester.c @@ -269,6 +269,8 @@ eval_kinit(heim_dict_t o) ret = krb5_init_creds_set_fast_ccache(kdc_context, ctx, fast_cc); if (ret) krb5_err(kdc_context, 1, ret, "krb5_init_creds_set_fast_ccache"); + + fast_cc = NULL; } if (password) { diff --git a/kdc/kdc_locl.h b/kdc/kdc_locl.h index a2fdb06a6..5e776eb5b 100644 --- a/kdc/kdc_locl.h +++ b/kdc/kdc_locl.h @@ -93,6 +93,13 @@ struct astgs_request_desc { krb5_timestamp pa_endtime; krb5_timestamp pa_max_life; + krb5_keyblock strengthen_key; + const Key *ticket_key; + + /* only valid for tgs-req */ + unsigned int rk_is_subkey : 1; + unsigned int fast_asserted : 1; + krb5_crypto armor_crypto; KDCFastState fast; diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 755fc91c5..e7c0070d6 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -555,62 +555,10 @@ pa_gss_validate(astgs_request_t r, const PA_DATA *pa) return ret; } -/* - * - */ - -static krb5_error_code -make_pa_enc_challange(astgs_request_t r, krb5_crypto crypto) -{ - krb5_context context = r->context; - METHOD_DATA *md = &r->outpadata; - PA_ENC_TS_ENC p; - unsigned char *buf; - size_t buf_size; - size_t len; - EncryptedData encdata; - krb5_error_code ret; - int32_t usec; - int usec2; - - krb5_us_timeofday (context, &p.patimestamp, &usec); - usec2 = usec; - p.pausec = &usec2; - - ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC, buf, buf_size, &p, &len, ret); - if (ret) - return ret; - if(buf_size != len) - krb5_abortx(context, "internal error in ASN.1 encoder"); - - ret = krb5_encrypt_EncryptedData(context, - crypto, - KRB5_KU_ENC_CHALLENGE_KDC, - buf, - len, - 0, - &encdata); - free(buf); - if (ret) - return ret; - - ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_size, &encdata, &len, ret); - free_EncryptedData(&encdata); - if (ret) - return ret; - if(buf_size != len) - krb5_abortx(context, "internal error in ASN.1 encoder"); - - ret = krb5_padata_add(context, md, KRB5_PADATA_ENCRYPTED_CHALLENGE, buf, len); - if (ret) - free(buf); - return ret; -} - static krb5_error_code pa_enc_chal_validate(astgs_request_t r, const PA_DATA *pa) { - krb5_data pepper1, pepper2, ts_data; + krb5_data pepper1, pepper2; int invalidPassword = 0; EncryptedData enc_data; krb5_enctype aenctype; @@ -652,39 +600,46 @@ pa_enc_chal_validate(astgs_request_t r, const PA_DATA *pa) krb5_crypto_getenctype(r->context, r->armor_crypto, &aenctype); + kdc_log(r->context, r->config, 5, "FAST armor enctype is: %d", (int)aenctype); + for (i = 0; i < r->client->entry.keys.len; i++) { - krb5_crypto challangecrypto, longtermcrypto; - krb5_keyblock challangekey; - PA_ENC_TS_ENC p; + krb5_crypto challengecrypto, longtermcrypto; + krb5_keyblock challengekey; k = &r->client->entry.keys.val[i]; ret = krb5_crypto_init(r->context, &k->key, 0, &longtermcrypto); if (ret) - continue; + continue; ret = krb5_crypto_fx_cf2(r->context, r->armor_crypto, longtermcrypto, &pepper1, &pepper2, aenctype, - &challangekey); - krb5_crypto_destroy(r->context, longtermcrypto); - if (ret) + &challengekey); + if (ret) { + krb5_crypto_destroy(r->context, longtermcrypto); continue; + } - ret = krb5_crypto_init(r->context, &challangekey, 0, - &challangecrypto); - if (ret) + ret = krb5_crypto_init(r->context, &challengekey, 0, + &challengecrypto); + krb5_free_keyblock_contents(r->context, &challengekey); + if (ret) { + krb5_crypto_destroy(r->context, longtermcrypto); continue; - - ret = krb5_decrypt_EncryptedData(r->context, challangecrypto, - KRB5_KU_ENC_CHALLENGE_CLIENT, - &enc_data, - &ts_data); + } + + ret = _krb5_validate_pa_enc_challenge(r->context, + challengecrypto, + KRB5_KU_ENC_CHALLENGE_CLIENT, + &enc_data, + r->cname); + krb5_crypto_destroy(r->context, challengecrypto); if (ret) { const char *msg = krb5_get_error_message(r->context, ret); krb5_error_code ret2; char *str = NULL; - invalidPassword = 1; + invalidPassword = (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY); ret2 = krb5_enctype_to_string(r->context, k->key.keytype, &str); if (ret2) @@ -695,68 +650,66 @@ pa_enc_chal_validate(astgs_request_t r, const PA_DATA *pa) krb5_free_error_message(r->context, msg); free(str); + krb5_crypto_destroy(r->context, longtermcrypto); continue; } - - ret = decode_PA_ENC_TS_ENC(ts_data.data, - ts_data.length, - &p, - &size); - krb5_data_free(&ts_data); - if(ret){ - krb5_crypto_destroy(r->context, challangecrypto); - ret = KRB5KDC_ERR_PREAUTH_FAILED; - _kdc_r_log(r, 4, "Failed to decode PA-ENC-TS_ENC -- %s", - r->cname); - continue; - } + + /* + * Found a key that the client used, lets pick that as the reply key + */ - if (labs(kdc_time - p.patimestamp) > r->context->max_skew) { - char client_time[100]; - - krb5_crypto_destroy(r->context, challangecrypto); - - krb5_format_time(r->context, p.patimestamp, - client_time, sizeof(client_time), TRUE); - - ret = KRB5KRB_AP_ERR_SKEW; - _kdc_r_log(r, 4, "Too large time skew, " - "client time %s is out by %u > %u seconds -- %s", - client_time, - (unsigned)labs(kdc_time - p.patimestamp), - r->context->max_skew, - r->cname); - - free_PA_ENC_TS_ENC(&p); + krb5_free_keyblock_contents(r->context, &r->reply_key); + ret = krb5_copy_keyblock_contents(r->context, &k->key, &r->reply_key); + if (ret) { + krb5_crypto_destroy(r->context, longtermcrypto); goto out; } - free_PA_ENC_TS_ENC(&p); + krb5_free_keyblock_contents(r->context, &challengekey); - ret = make_pa_enc_challange(r, challangecrypto); - krb5_crypto_destroy(r->context, challangecrypto); + /* + * Provide KDC authentication to the client, uses a different + * challenge key (different pepper). + */ + + pepper1.data = "kdcchallengearmor"; + pepper1.length = strlen(pepper1.data); + + ret = krb5_crypto_fx_cf2(r->context, r->armor_crypto, longtermcrypto, + &pepper1, &pepper2, aenctype, + &challengekey); + krb5_crypto_destroy(r->context, longtermcrypto); + if (ret) + goto out; + + ret = krb5_crypto_init(r->context, &challengekey, 0, &challengecrypto); + krb5_free_keyblock_contents(r->context, &challengekey); + if (ret) + goto out; + + ret = _krb5_make_pa_enc_challenge(r->context, challengecrypto, + KRB5_KU_ENC_CHALLENGE_KDC, + &r->outpadata); + krb5_crypto_destroy(r->context, challengecrypto); if (ret) goto out; set_salt_padata(&r->outpadata, k->salt); - krb5_free_keyblock_contents(r->context, &r->reply_key); - ret = krb5_copy_keyblock_contents(r->context, &k->key, &r->reply_key); - if (ret) - goto out; - /* - * Success - */ + /* + * Success + */ if (r->clientdb->hdb_auth_status) r->clientdb->hdb_auth_status(r->context, r->clientdb, r->client, HDB_AUTH_SUCCESS); goto out; } + ret = KRB5KDC_ERR_PREAUTH_FAILED; + if (invalidPassword && r->clientdb->hdb_auth_status) { r->clientdb->hdb_auth_status(r->context, r->clientdb, r->client, HDB_AUTH_WRONG_PASSWORD); - ret = KRB5KDC_ERR_PREAUTH_FAILED; } out: free_EncryptedData(&enc_data); @@ -1016,11 +969,11 @@ log_patypes(astgs_request_t r, METHOD_DATA *padata) krb5_error_code _kdc_encode_reply(krb5_context context, krb5_kdc_configuration *config, - krb5_crypto armor_crypto, uint32_t nonce, + astgs_request_t r, uint32_t nonce, KDC_REP *rep, EncTicketPart *et, EncKDCRepPart *ek, krb5_enctype etype, int skvno, const EncryptionKey *skey, - int ckvno, const EncryptionKey *reply_key, + int ckvno, int rk_is_subkey, const char **e_text, krb5_data *reply) @@ -1066,10 +1019,9 @@ _kdc_encode_reply(krb5_context context, return ret; } - if (armor_crypto) { - krb5_data data; - krb5_keyblock *strengthen_key = NULL; + if (r && r->armor_crypto) { KrbFastFinished finished; + krb5_data data; kdc_log(context, config, 4, "FAST armor protection"); @@ -1088,7 +1040,7 @@ _kdc_encode_reply(krb5_context context, if (data.length != len) krb5_abortx(context, "internal asn.1 error"); - ret = krb5_create_checksum(context, armor_crypto, + ret = krb5_create_checksum(context, r->armor_crypto, KRB5_KU_FAST_FINISHED, 0, data.data, data.length, &finished.ticket_checksum); @@ -1096,8 +1048,8 @@ _kdc_encode_reply(krb5_context context, if (ret) return ret; - ret = _kdc_fast_mk_response(context, armor_crypto, - rep->padata, strengthen_key, &finished, + ret = _kdc_fast_mk_response(context, r->armor_crypto, + rep->padata, &r->strengthen_key, &finished, nonce, &data); free_Checksum(&finished.ticket_checksum); if (ret) @@ -1120,9 +1072,9 @@ _kdc_encode_reply(krb5_context context, return ret; /* - * Hide client name of privacy reasons + * Hide client name for privacy reasons */ - if (1 /* r->fast_options.hide_client_names */) { + if (r->fast.flags.requested_hidden_names) { Realm anon_realm = KRB5_ANON_REALM; free_Realm(&rep->crealm); @@ -1152,7 +1104,7 @@ _kdc_encode_reply(krb5_context context, *e_text = "KDC internal error"; return KRB5KRB_ERR_GENERIC; } - ret = krb5_crypto_init(context, reply_key, 0, &crypto); + ret = krb5_crypto_init(context, &r->reply_key, 0, &crypto); if (ret) { const char *msg = krb5_get_error_message(context, ret); free(buf); @@ -1988,7 +1940,6 @@ _kdc_as_rep(astgs_request_t r) Key *skey; int found_pa = 0; int i, flags = HDB_F_FOR_AS_REQ; - METHOD_DATA error_method; const PA_DATA *pa; krb5_boolean is_tgs; const char *msg; @@ -1996,13 +1947,11 @@ _kdc_as_rep(astgs_request_t r) Key *krbtgt_key; memset(&rep, 0, sizeof(rep)); - error_method.len = 0; - error_method.val = NULL; /* * Look for FAST armor and unwrap */ - ret = _kdc_fast_unwrap_request(r); + ret = _kdc_fast_unwrap_request(r, NULL, NULL); if (ret) { _kdc_r_log(r, 1, "FAST unwrap request from %s failed: %d", from, ret); goto out; @@ -2081,10 +2030,10 @@ _kdc_as_rep(astgs_request_t r) r->cname, fixed_client_name); free(fixed_client_name); - ret = _kdc_fast_mk_error(r, &error_method, r->armor_crypto, + ret = _kdc_fast_mk_error(r, &r->outpadata, r->armor_crypto, &req->req_body, KRB5_KDC_ERR_WRONG_REALM, - NULL, r->server_princ, NULL, - &r->client->entry.principal->realm, + NULL, + r->client->entry.principal, r->server_princ, NULL, NULL, r->reply); goto out; } @@ -2174,7 +2123,7 @@ _kdc_as_rep(astgs_request_t r) NULL, &ckey, &default_salt); if (ret2 == 0) { ret2 = get_pa_etype_info_both(context, config, &b->etype, - &error_method, ckey, !default_salt); + &r->outpadata, ckey, !default_salt); if (ret2 != 0) ret = ret2; } @@ -2203,7 +2152,7 @@ _kdc_as_rep(astgs_request_t r) for (n = 0; n < sizeof(pat) / sizeof(pat[0]); n++) { if ((pat[n].flags & PA_ANNOUNCE) == 0) continue; - ret = krb5_padata_add(context, &error_method, + ret = krb5_padata_add(context, &r->outpadata, pat[n].type, NULL, 0); if (ret) goto out; @@ -2217,7 +2166,7 @@ _kdc_as_rep(astgs_request_t r) NULL, &ckey, &default_salt); if (ret == 0) { ret = get_pa_etype_info_both(context, config, &b->etype, - &error_method, ckey, !default_salt); + &r->outpadata, ckey, !default_salt); if (ret) goto out; } @@ -2253,7 +2202,7 @@ _kdc_as_rep(astgs_request_t r) * with in a preauth mech. */ - ret = _kdc_check_access(r, req, &error_method); + ret = _kdc_check_access(r, req, &r->outpadata); if(ret) goto out; @@ -2577,6 +2526,14 @@ _kdc_as_rep(astgs_request_t r) r->et.flags.enc_pa_rep = r->ek.flags.enc_pa_rep = 1; + /* + * update reply-key with strengthen-key + */ + + ret = _kdc_fast_strengthen_reply_key(r); + if (ret) + goto out; + /* * Add REQ_ENC_PA_REP if client supports it */ @@ -2599,11 +2556,11 @@ _kdc_as_rep(astgs_request_t r) */ ret = _kdc_encode_reply(context, config, - r->armor_crypto, req->req_body.nonce, + r, req->req_body.nonce, &rep, &r->et, &r->ek, setype, r->server->entry.kvno, &skey->key, r->client->entry.kvno, - &r->reply_key, 0, &r->e_text, r->reply); + 0, &r->e_text, r->reply); if (ret) goto out; @@ -2624,16 +2581,12 @@ out: */ if (ret != 0 && ret != HDB_ERR_NOT_FOUND_HERE && r->reply->length == 0) ret = _kdc_fast_mk_error(r, - (ret == KRB5_KDC_ERR_MORE_PREAUTH_DATA_REQUIRED) - ? &r->outpadata : &error_method, + &r->outpadata, r->armor_crypto, &req->req_body, ret, r->e_text, + r->client_princ, r->server_princ, - r->client_princ ? - &r->client_princ->name : NULL, - r->client_princ ? - &r->client_princ->realm : NULL, NULL, NULL, r->reply); @@ -2641,8 +2594,6 @@ out: free_EncKDCRepPart(&r->ek); _kdc_free_fast_state(&r->fast); - if (error_method.len) - free_METHOD_DATA(&error_method); if (r->outpadata.len) free_METHOD_DATA(&r->outpadata); if (r->client_princ) { @@ -2665,5 +2616,7 @@ out: } krb5_free_keyblock_contents(r->context, &r->reply_key); krb5_free_keyblock_contents(r->context, &r->session_key); + krb5_free_keyblock_contents(r->context, &r->strengthen_key); + return ret; } diff --git a/kdc/krb5tgs.c b/kdc/krb5tgs.c index 2d1677b5a..24d1c830c 100644 --- a/kdc/krb5tgs.c +++ b/kdc/krb5tgs.c @@ -515,8 +515,6 @@ static krb5_error_code tgs_make_reply(astgs_request_t r, krb5_principal tgt_name, const EncTicketPart *tgt, - const krb5_keyblock *replykey, - int rk_is_subkey, const EncryptionKey *serverkey, const EncryptionKey *krbtgtkey, const krb5_keyblock *sessionkey, @@ -526,14 +524,12 @@ tgs_make_reply(astgs_request_t r, krb5_principal server_principal, hdb_entry_ex *client, krb5_principal client_principal, - const char *tgt_realm, + const char *tgt_realm, krb5_pac mspac, uint16_t rodc_id, krb5_boolean add_ticket_sig, const METHOD_DATA *enc_pa_data) { - krb5_context context = r->context; - krb5_kdc_configuration *config = r->config; KDC_REQ_BODY *b = &r->req.req_body; const char **e_text = &r->e_text; krb5_data *reply = r->reply; @@ -570,17 +566,17 @@ tgs_make_reply(astgs_request_t r, */ #define GLOBAL_FORCE_TRANSITED_CHECK \ - (config->trpolicy == TRPOLICY_ALWAYS_CHECK) + (r->config->trpolicy == TRPOLICY_ALWAYS_CHECK) #define GLOBAL_ALLOW_PER_PRINCIPAL \ - (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL) + (r->config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL) #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \ - (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST) + (r->config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST) /* these will consult the database in future release */ #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0 - ret = fix_transited_encoding(context, config, + ret = fix_transited_encoding(r->context, r->config, !f.disable_transited_check || GLOBAL_FORCE_TRANSITED_CHECK || PRINCIPAL_FORCE_TRANSITED_CHECK(server) || @@ -588,8 +584,8 @@ tgs_make_reply(astgs_request_t r, PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) || GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK), &tgt->transited, &et, - krb5_principal_get_realm(context, client_principal), - krb5_principal_get_realm(context, server->entry.principal), + krb5_principal_get_realm(r->context, client_principal), + krb5_principal_get_realm(r->context, server->entry.principal), tgt_realm); if(ret) goto out; @@ -682,20 +678,20 @@ tgs_make_reply(astgs_request_t r, et.authorization_data = calloc(1, sizeof(*et.authorization_data)); if (et.authorization_data == NULL) { ret = ENOMEM; - krb5_set_error_message(context, ret, "malloc: out of memory"); + krb5_set_error_message(r->context, ret, "malloc: out of memory"); goto out; } } for(i = 0; i < auth_data->len ; i++) { ret = add_AuthorizationData(et.authorization_data, &auth_data->val[i]); if (ret) { - krb5_set_error_message(context, ret, "malloc: out of memory"); + krb5_set_error_message(r->context, ret, "malloc: out of memory"); goto out; } } } - ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key); + ret = krb5_copy_keyblock_contents(r->context, sessionkey, &et.key); if (ret) goto out; et.crealm = rep.crealm; @@ -732,10 +728,10 @@ tgs_make_reply(astgs_request_t r, goto out; } - if (krb5_enctype_valid(context, serverkey->keytype) != 0 + if (krb5_enctype_valid(r->context, serverkey->keytype) != 0 && _kdc_is_weak_exception(server->entry.principal, serverkey->keytype)) { - krb5_enctype_enable(context, serverkey->keytype); + krb5_enctype_enable(r->context, serverkey->keytype); is_weak = 1; } @@ -748,7 +744,7 @@ tgs_make_reply(astgs_request_t r, if (mspac && !et.flags.anonymous) { /* The PAC should be the last change to the ticket. */ - ret = _krb5_kdc_pac_sign_ticket(context, mspac, tgt_name, serverkey, + ret = _krb5_kdc_pac_sign_ticket(r->context, mspac, tgt_name, serverkey, krbtgtkey, rodc_id, add_ticket_sig, &et); if (ret) goto out; @@ -764,15 +760,14 @@ tgs_make_reply(astgs_request_t r, CAST session key. Should the DES3 etype be added to the etype list, even if we don't want a session key with DES3? */ - ret = _kdc_encode_reply(context, config, NULL, 0, + ret = _kdc_encode_reply(r->context, r->config, r, b->nonce, &rep, &et, &ek, serverkey->keytype, kvno, - serverkey, 0, replykey, rk_is_subkey, + serverkey, 0, r->rk_is_subkey, e_text, reply); if (is_weak) - krb5_enctype_disable(context, serverkey->keytype); + krb5_enctype_disable(r->context, serverkey->keytype); - r->reply_key.keytype = replykey->keytype; _log_astgs_req(r, serverkey->keytype); out: @@ -887,6 +882,33 @@ need_referral(krb5_context context, krb5_kdc_configuration *config, return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0; } +static krb5_error_code +validate_fast_ad(astgs_request_t r, krb5_authdata *auth_data) +{ + krb5_error_code ret; + krb5_data data; + + krb5_data_zero(&data); + + ret = _krb5_get_ad(r->context, auth_data, NULL, + KRB5_AUTHDATA_FX_FAST_USED, &data); + if (ret == 0) { + r->fast_asserted = 1; + krb5_data_free(&data); + } + + ret = _krb5_get_ad(r->context, auth_data, NULL, + KRB5_AUTHDATA_FX_FAST_ARMOR, &data); + if (ret == 0) { + kdc_log(r->context, r->config, 2, + "Invalid ticket usage: TGS-REQ contains AD-fx-fast-armor"); + krb5_data_free(&data); + return KRB5KRB_AP_ERR_BAD_INTEGRITY; + } + + return 0; +} + static krb5_error_code tgs_parse_request(astgs_request_t r, const PA_DATA *tgs_req, @@ -898,10 +920,7 @@ tgs_parse_request(astgs_request_t r, const struct sockaddr *from_addr, time_t **csec, int **cusec, - AuthorizationData **auth_data, - krb5_keyblock **replykey, - Key **header_key, - int *rk_is_subkey) + AuthorizationData **auth_data) { krb5_context context = r->context; krb5_kdc_configuration *config = r->config; @@ -925,7 +944,6 @@ tgs_parse_request(astgs_request_t r, *auth_data = NULL; *csec = NULL; *cusec = NULL; - *replykey = NULL; memset(&ap_req, 0, sizeof(ap_req)); ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req); @@ -1070,7 +1088,7 @@ next_kvno: goto out; } - *header_key = tkey; + r->ticket_key = tkey; { krb5_authenticator auth; @@ -1091,7 +1109,11 @@ next_kvno: goto out; } **cusec = auth->cusec; + + ret = validate_fast_ad(r, auth->authorization_data); krb5_free_authenticator(context, &auth); + if (ret) + goto out; } } @@ -1103,7 +1125,7 @@ next_kvno: } usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY; - *rk_is_subkey = 1; + r->rk_is_subkey = 1; ret = krb5_auth_con_getremotesubkey(context, ac, &subkey); if(ret){ @@ -1115,7 +1137,7 @@ next_kvno: } if(subkey == NULL){ usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION; - *rk_is_subkey = 0; + r->rk_is_subkey = 0; ret = krb5_auth_con_getkey(context, ac, &subkey); if(ret) { @@ -1134,12 +1156,16 @@ next_kvno: goto out; } - *replykey = subkey; + krb5_free_keyblock_contents(r->context, &r->reply_key); + ret = krb5_copy_keyblock_contents(r->context, subkey, &r->reply_key); + krb5_free_keyblock(r->context, subkey); + if (ret) + goto out; if (b->enc_authorization_data) { krb5_data ad; - ret = krb5_crypto_init(context, subkey, 0, &crypto); + ret = krb5_crypto_init(context, &r->reply_key, 0, &crypto); if (ret) { const char *msg = krb5_get_error_message(context, ret); krb5_auth_con_free(context, ac); @@ -1175,8 +1201,21 @@ next_kvno: ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */ goto out; } + + ret = validate_fast_ad(r, *auth_data); + if (ret) + goto out; } + + /* + * Check for FAST request + */ + + ret = _kdc_fast_unwrap_request(r, *ticket, ac); + if (ret) + goto out; + krb5_auth_con_free(context, ac); out: @@ -1316,9 +1355,6 @@ static krb5_error_code tgs_build_reply(astgs_request_t priv, hdb_entry_ex *krbtgt, krb5_enctype krbtgt_etype, - Key *tkey_check, - const krb5_keyblock *replykey, - int rk_is_subkey, krb5_ticket *ticket, const char **e_text, AuthorizationData **auth_data, @@ -1781,7 +1817,7 @@ server_lookup: priv->client = client; ret = check_PAC(context, config, cp, NULL, client, server, krbtgt, krbtgt, - &tkey_check->key, &tkey_check->key, tgt, &kdc_issued, &mspac); + &priv->ticket_key->key, &priv->ticket_key->key, tgt, &kdc_issued, &mspac); if (ret) { const char *msg = krb5_get_error_message(context, ret); _kdc_audit_addreason((kdc_request_t)priv, "PAC check failed"); @@ -2101,7 +2137,7 @@ server_lookup: * a S4U_DELEGATION_INFO blob to the PAC. */ ret = check_PAC(context, config, tp, dp, adclient, server, krbtgt, client, - &clientkey->key, &tkey_check->key, &adtkt, &ad_kdc_issued, &mspac); + &clientkey->key, &priv->ticket_key->key, &adtkt, &ad_kdc_issued, &mspac); if (adclient) _kdc_free_ent(context, adclient); if (ret) { @@ -2230,8 +2266,6 @@ server_lookup: ret = tgs_make_reply(priv, tp, tgt, - replykey, - rk_is_subkey, ekey, &tkey_sign->key, &sessionkey, @@ -2297,16 +2331,13 @@ _kdc_tgs_rep(astgs_request_t r) AuthorizationData *auth_data = NULL; krb5_error_code ret; int i = 0; - const PA_DATA *tgs_req; - Key *header_key = NULL; + const PA_DATA *tgs_req, *pa; hdb_entry_ex *krbtgt = NULL; krb5_ticket *ticket = NULL; const char *e_text = NULL; krb5_enctype krbtgt_etype = ETYPE_NULL; - krb5_keyblock *replykey = NULL; - int rk_is_subkey = 0; time_t *csec = NULL; int *cusec = NULL; @@ -2317,8 +2348,16 @@ _kdc_tgs_rep(astgs_request_t r) goto out; } - tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ); + i = 0; + pa = _kdc_find_padata(&r->req, &i, KRB5_PADATA_FX_FAST_ARMOR); + if (pa) { + kdc_log(r->context, r->config, 10, "Found TGS-REQ FAST armor inside TGS-REQ pa-data"); + ret = KRB5KRB_ERR_GENERIC; + goto out; + } + i = 0; + tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ); if(tgs_req == NULL){ ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP; @@ -2333,10 +2372,7 @@ _kdc_tgs_rep(astgs_request_t r) &e_text, from, from_addr, &csec, &cusec, - &auth_data, - &replykey, - &header_key, - &rk_is_subkey); + &auth_data); if (ret == HDB_ERR_NOT_FOUND_HERE) { /* kdc_log() is called in tgs_parse_request() */ goto out; @@ -2347,19 +2383,13 @@ _kdc_tgs_rep(astgs_request_t r) goto out; } - { - const PA_DATA *pa = _kdc_find_padata(req, &i, KRB5_PADATA_FX_FAST); - if (pa) - kdc_log(context, config, 5, "Got TGS FAST request"); - } - + ret = _kdc_fast_strengthen_reply_key(r); + if (ret) + goto out; ret = tgs_build_reply(r, krbtgt, krbtgt_etype, - header_key, - replykey, - rk_is_subkey, ticket, &e_text, &auth_data, @@ -2378,21 +2408,15 @@ _kdc_tgs_rep(astgs_request_t r) } out: - if (replykey) - krb5_free_keyblock(context, replykey); - if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){ - /* XXX add fast wrapping on the error */ METHOD_DATA error_method = { 0, NULL }; - kdc_log(context, config, 5, "tgs-req: sending error: %d to client", ret); ret = _kdc_fast_mk_error(r, &error_method, - NULL, - NULL, - ret, NULL, - NULL, + r->armor_crypto, + &req->req_body, + ret, r->e_text, NULL, NULL, csec, cusec, data); @@ -2400,11 +2424,17 @@ out: } free(csec); free(cusec); + + krb5_free_keyblock_contents(r->context, &r->reply_key); + krb5_free_keyblock_contents(r->context, &r->strengthen_key); + if (ticket) krb5_free_ticket(context, ticket); if(krbtgt) _kdc_free_ent(context, krbtgt); + _kdc_free_fast_state(&r->fast); + if (auth_data) { free_AuthorizationData(auth_data); free(auth_data); diff --git a/kuser/kinit.c b/kuser/kinit.c index b95fd91c5..fd3d3caf5 100644 --- a/kuser/kinit.c +++ b/kuser/kinit.c @@ -1077,6 +1077,18 @@ get_new_tickets(krb5_context context, goto out; } + ret = krb5_init_creds_store_config(context, ctx, tempccache); + if (ret) { + krb5_warn(context, ret, "krb5_init_creds_store_config"); + goto out; + } + + ret = krb5_init_creds_warn_user(context, ctx); + if (ret) { + krb5_warn(context, ret, "krb5_init_creds_warn_user"); + goto out; + } + krb5_init_creds_free(context, ctx); ctx = NULL; diff --git a/lib/krb5/libkrb5-exports.def.in b/lib/krb5/libkrb5-exports.def.in index 239df0c89..a3c896d6b 100644 --- a/lib/krb5/libkrb5-exports.def.in +++ b/lib/krb5/libkrb5-exports.def.in @@ -862,6 +862,8 @@ EXPORTS krb5_init_creds_set_sitename krb5_init_creds_step krb5_init_creds_store + krb5_init_creds_store_config + krb5_init_creds_warn_user krb5_process_last_request ; testing diff --git a/lib/krb5/version-script.map b/lib/krb5/version-script.map index 84ea0addb..445382fa5 100644 --- a/lib/krb5/version-script.map +++ b/lib/krb5/version-script.map @@ -850,7 +850,9 @@ HEIMDAL_KRB5_2.0 { krb5_init_creds_set_sitename; krb5_init_creds_step; krb5_init_creds_store; + krb5_init_creds_store_config; krb5_init_creds_free; + krb5_init_creds_warn_user; # testing krb5_time_abs;