krb5: import Heimdal-597.121.1 AS/TGS client
Sync with most changes in AS/TGS client from Apple's Heimdal-597.121.1 (opensource.apple.com). Changes include: - FAST support in TGS client - Refactored pre-auth client to be more easily extensible - Pin KDC host and AD site name in API calls Note the completely refactored TGS client loop is not imported as that was considered too intrusive.
This commit is contained in:
@@ -1,9 +1,6 @@
|
||||
|
||||
-- in order of preference
|
||||
|
||||
- client: support KRB5_PADATA_ENCRYPTED_CHALLENGE in lib/krb5/init_creds_pw.c
|
||||
- client: don't support ENC-TS in FAST
|
||||
|
||||
- client: plugin support for fast plugins
|
||||
|
||||
- kdc: plugin support for fast plugins
|
||||
@@ -13,5 +10,3 @@
|
||||
-- using PK-INIT anonymous
|
||||
-- using host key
|
||||
|
||||
- client: tgs-req fast support
|
||||
- kdc: tgs-req fast support
|
||||
|
@@ -207,6 +207,9 @@ AUTHDATA-TYPE ::= INTEGER {
|
||||
KRB5-AUTHDATA-OSF-DCE(64),
|
||||
KRB5-AUTHDATA-SESAME(65),
|
||||
KRB5-AUTHDATA-OSF-DCE-PKI-CERTID(66),
|
||||
KRB5-AUTHDATA-AUTHENTICATION-STRENGTH(70),
|
||||
KRB5-AUTHDATA-FX-FAST-ARMOR(71),
|
||||
KRB5-AUTHDATA-FX-FAST-USED(72),
|
||||
KRB5-AUTHDATA-WIN2K-PAC(128),
|
||||
KRB5-AUTHDATA-GSS-API-ETYPE-NEGOTIATION(129), -- Authenticator only
|
||||
KRB5-AUTHDATA-SIGNTICKET-OLDER(-17),
|
||||
@@ -843,10 +846,11 @@ PA-FX-FAST-REPLY ::= CHOICE {
|
||||
}
|
||||
|
||||
KDCFastFlags ::= BIT STRING {
|
||||
use_reply_key(0),
|
||||
reply_key_used(1),
|
||||
reply_key_replaced(2),
|
||||
kdc_verfied(3)
|
||||
use-reply-key(0),
|
||||
reply-key-used(1),
|
||||
reply-key-replaced(2),
|
||||
kdc-verified(3),
|
||||
requested-hidden-names(4)
|
||||
}
|
||||
|
||||
-- KDCFastState is stored in FX_COOKIE
|
||||
|
@@ -22,6 +22,9 @@ error_code TOO_BIG, "Offset too large"
|
||||
error_code BAD_HDBENT_ENCODING, "Invalid HDB entry encoding"
|
||||
error_code RANDOM_OFFLINE, "No random source available"
|
||||
error_code CONFIG_BADFORMAT, "Improper format of configuration file"
|
||||
error_code PA_CONTINUE_NEEDED, "Need to continue preauth stepping"
|
||||
error_code PA_CANT_CONTINUE, "Can't continue with this preauth"
|
||||
error_code NO_MORE_PA_MECHS, "No more PA mechanisms available"
|
||||
|
||||
index 64
|
||||
prefix HEIM_PKINIT
|
||||
|
@@ -64,6 +64,7 @@ enum {
|
||||
HEIM_TID_ERROR = 133,
|
||||
HEIM_TID_DATA = 134,
|
||||
HEIM_TID_DB = 135,
|
||||
HEIM_TID_PA_AUTH_MECH = 136,
|
||||
HEIM_TID_USER = 255
|
||||
|
||||
};
|
||||
|
@@ -81,6 +81,7 @@ static krb5_error_code KRB5_LIB_CALL
|
||||
pa_gss_step(krb5_context context,
|
||||
krb5_gss_init_ctx gssic,
|
||||
const krb5_creds *kcred,
|
||||
gss_ctx_id_t *ctx,
|
||||
KDCOptions flags,
|
||||
krb5_data *enc_as_req,
|
||||
krb5_data *in,
|
||||
@@ -91,7 +92,6 @@ pa_gss_step(krb5_context context,
|
||||
|
||||
OM_uint32 major, minor;
|
||||
gss_cred_id_t cred;
|
||||
gss_ctx_id_t ctx;
|
||||
gss_name_t target_name = GSS_C_NO_NAME;
|
||||
OM_uint32 req_flags = GSS_C_MUTUAL_FLAG;
|
||||
OM_uint32 ret_flags;
|
||||
@@ -113,8 +113,6 @@ pa_gss_step(krb5_context context,
|
||||
_krb5_init_creds_set_gss_cred(context, gssic, cred);
|
||||
}
|
||||
|
||||
ctx = (gss_ctx_id_t)_krb5_init_creds_get_gss_context(context, gssic);
|
||||
|
||||
ret = krb5_make_principal(context, &tgs_name, kcred->server->realm,
|
||||
KRB5_TGS_NAME, kcred->server->realm, NULL);
|
||||
if (ret)
|
||||
@@ -129,7 +127,7 @@ pa_gss_step(krb5_context context,
|
||||
|
||||
major = gss_init_sec_context(&minor,
|
||||
cred,
|
||||
&ctx,
|
||||
ctx,
|
||||
target_name,
|
||||
(gss_OID)_krb5_init_creds_get_gss_mechanism(context, gssic),
|
||||
req_flags,
|
||||
@@ -141,8 +139,6 @@ pa_gss_step(krb5_context context,
|
||||
&ret_flags,
|
||||
NULL);
|
||||
|
||||
_krb5_init_creds_set_gss_context(context, gssic, ctx);
|
||||
|
||||
_krb5_gss_buffer_to_data(&output_token, out);
|
||||
|
||||
if (major == GSS_S_COMPLETE) {
|
||||
@@ -166,6 +162,7 @@ static krb5_error_code KRB5_LIB_CALL
|
||||
pa_gss_finish(krb5_context context,
|
||||
krb5_gss_init_ctx gssic,
|
||||
const krb5_creds *kcred,
|
||||
gss_ctx_id_t ctx,
|
||||
krb5int32 nonce,
|
||||
krb5_enctype enctype,
|
||||
krb5_principal *client_p,
|
||||
@@ -177,7 +174,6 @@ pa_gss_finish(krb5_context context,
|
||||
|
||||
OM_uint32 major, minor;
|
||||
gss_name_t initiator_name = GSS_C_NO_NAME;
|
||||
gss_ctx_id_t ctx = (gss_ctx_id_t)_krb5_init_creds_get_gss_context(context, gssic);
|
||||
|
||||
*client_p = NULL;
|
||||
*reply_key_p = NULL;
|
||||
|
@@ -50,7 +50,7 @@ _krb5_gss_map_error(OM_uint32 major, OM_uint32 minor)
|
||||
ret = 0;
|
||||
break;
|
||||
case GSS_S_CONTINUE_NEEDED:
|
||||
ret = KRB5_KDC_ERR_MORE_PREAUTH_DATA_REQUIRED;
|
||||
ret = HEIM_ERR_PA_CONTINUE_NEEDED;
|
||||
break;
|
||||
case GSS_S_BAD_NAME:
|
||||
case GSS_S_BAD_NAMETYPE:
|
||||
|
@@ -539,7 +539,7 @@ krb5_get_cred_from_kdc_opt(krb5_context context,
|
||||
{
|
||||
krb5_kdc_flags f;
|
||||
f.i = flags;
|
||||
return _krb5_get_cred_kdc_any(context, f, ccache,
|
||||
return _krb5_get_cred_kdc_any(context, f, ccache, NULL,
|
||||
in_creds, NULL, NULL,
|
||||
out_creds, ret_tgts);
|
||||
}
|
||||
|
773
lib/krb5/fast.c
773
lib/krb5/fast.c
@@ -32,7 +32,9 @@
|
||||
*/
|
||||
|
||||
#include "krb5_locl.h"
|
||||
|
||||
#ifndef WIN32
|
||||
#include <heim-ipc.h>
|
||||
#endif
|
||||
|
||||
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
|
||||
_krb5_fast_cf2(krb5_context context,
|
||||
@@ -93,3 +95,772 @@ _krb5_fast_armor_key(krb5_context context,
|
||||
armorkey,
|
||||
armor_crypto);
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
check_fast(krb5_context context, struct krb5_fast_state *state)
|
||||
{
|
||||
if (state && (state->flags & KRB5_FAST_EXPECTED)) {
|
||||
krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
|
||||
"Expected FAST, but no FAST "
|
||||
"was in the response from the KDC");
|
||||
return KRB5KRB_AP_ERR_MODIFIED;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
make_local_fast_ap_fxarmor(krb5_context context,
|
||||
krb5_ccache armor_ccache,
|
||||
krb5_const_realm realm,
|
||||
krb5_data *armor_value,
|
||||
krb5_keyblock *armor_key,
|
||||
krb5_crypto *armor_crypto)
|
||||
{
|
||||
krb5_auth_context auth_context = NULL;
|
||||
krb5_creds cred, *credp = NULL;
|
||||
krb5_error_code ret;
|
||||
krb5_data empty;
|
||||
krb5_const_realm tgs_realm;
|
||||
|
||||
krb5_data_zero(&empty);
|
||||
memset(&cred, 0, sizeof(cred));
|
||||
|
||||
ret = krb5_auth_con_init (context, &auth_context);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = krb5_cc_get_principal(context, armor_ccache, &cred.client);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Make sure we don't ask for a krbtgt/WELLKNOWN:ANONYMOUS
|
||||
*/
|
||||
if (krb5_principal_is_anonymous(context, cred.client,
|
||||
KRB5_ANON_MATCH_UNAUTHENTICATED))
|
||||
tgs_realm = realm;
|
||||
else
|
||||
tgs_realm = cred.client->realm;
|
||||
|
||||
ret = krb5_make_principal(context, &cred.server,
|
||||
tgs_realm,
|
||||
KRB5_TGS_NAME,
|
||||
tgs_realm,
|
||||
NULL);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = krb5_get_credentials(context, 0, armor_ccache, &cred, &credp);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = krb5_auth_con_add_AuthorizationData(context, auth_context,
|
||||
KRB5_AUTHDATA_FX_FAST_ARMOR,
|
||||
&empty);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = krb5_mk_req_extended(context,
|
||||
&auth_context,
|
||||
AP_OPTS_USE_SUBKEY,
|
||||
NULL,
|
||||
credp,
|
||||
armor_value);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = _krb5_fast_armor_key(context,
|
||||
auth_context->local_subkey,
|
||||
auth_context->keyblock,
|
||||
armor_key,
|
||||
armor_crypto);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
if (auth_context)
|
||||
krb5_auth_con_free(context, auth_context);
|
||||
if (credp)
|
||||
krb5_free_creds(context, credp);
|
||||
krb5_free_principal(context, cred.server);
|
||||
krb5_free_principal(context, cred.client);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
static heim_base_once_t armor_service_once = HEIM_BASE_ONCE_INIT;
|
||||
static heim_ipc armor_service = NULL;
|
||||
|
||||
static void
|
||||
fast_armor_init_ipc(void *ctx)
|
||||
{
|
||||
heim_ipc *ipc = ctx;
|
||||
heim_ipc_init_context("ANY:org.h5l.armor-service", ipc);
|
||||
}
|
||||
#endif
|
||||
|
||||
static krb5_error_code
|
||||
make_fast_ap_fxarmor(krb5_context context,
|
||||
struct krb5_fast_state *state,
|
||||
krb5_const_realm realm,
|
||||
KrbFastArmor **armor)
|
||||
{
|
||||
KrbFastArmor *fxarmor = NULL;
|
||||
krb5_error_code ret;
|
||||
|
||||
ALLOC(fxarmor, 1);
|
||||
if (fxarmor == NULL) {
|
||||
ret = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (state->flags & KRB5_FAST_AP_ARMOR_SERVICE) {
|
||||
#ifdef WIN32
|
||||
krb5_set_error_message(context, ENOTSUP, "Fast armor IPC service not supportted yet on Windows");
|
||||
ret = ENOTSUP;
|
||||
goto out;
|
||||
#else
|
||||
KERB_ARMOR_SERVICE_REPLY msg;
|
||||
krb5_data request, reply;
|
||||
|
||||
heim_base_once_f(&armor_service_once, &armor_service, fast_armor_init_ipc);
|
||||
if (armor_service == NULL) {
|
||||
krb5_set_error_message(context, ENOENT, "Failed to open fast armor service");
|
||||
ret = ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
krb5_data_zero(&reply);
|
||||
|
||||
request.data = rk_UNCONST(realm);
|
||||
request.length = strlen(realm);
|
||||
|
||||
ret = heim_ipc_call(armor_service, &request, &reply, NULL);
|
||||
if (ret) {
|
||||
krb5_set_error_message(context, ret, "Failed to get armor service credential");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = decode_KERB_ARMOR_SERVICE_REPLY(reply.data, reply.length, &msg, NULL);
|
||||
krb5_data_free(&reply);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = copy_KrbFastArmor(fxarmor, &msg.armor);
|
||||
if (ret) {
|
||||
free_KERB_ARMOR_SERVICE_REPLY(&msg);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = krb5_copy_keyblock_contents(context, &msg.armor_key, &state->armor_key);
|
||||
free_KERB_ARMOR_SERVICE_REPLY(&msg);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = krb5_crypto_init(context, &state->armor_key, 0, &state->armor_crypto);
|
||||
if (ret)
|
||||
goto out;
|
||||
#endif /* WIN32 */
|
||||
} else {
|
||||
fxarmor->armor_type = 1;
|
||||
|
||||
ret = make_local_fast_ap_fxarmor(context,
|
||||
state->armor_ccache,
|
||||
realm,
|
||||
&fxarmor->armor_value,
|
||||
&state->armor_key,
|
||||
&state->armor_crypto);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
*armor = fxarmor;
|
||||
fxarmor = NULL;
|
||||
|
||||
out:
|
||||
if (fxarmor) {
|
||||
free_KrbFastArmor(fxarmor);
|
||||
free(fxarmor);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
unwrap_fast_rep(krb5_context context,
|
||||
struct krb5_fast_state *state,
|
||||
PA_DATA *pa,
|
||||
KrbFastResponse *fastrep)
|
||||
{
|
||||
PA_FX_FAST_REPLY fxfastrep;
|
||||
krb5_error_code ret;
|
||||
|
||||
memset(&fxfastrep, 0, sizeof(fxfastrep));
|
||||
|
||||
ret = decode_PA_FX_FAST_REPLY(pa->padata_value.data,
|
||||
pa->padata_value.length,
|
||||
&fxfastrep, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (fxfastrep.element == choice_PA_FX_FAST_REPLY_armored_data) {
|
||||
krb5_data data;
|
||||
|
||||
ret = krb5_decrypt_EncryptedData(context,
|
||||
state->armor_crypto,
|
||||
KRB5_KU_FAST_REP,
|
||||
&fxfastrep.u.armored_data.enc_fast_rep,
|
||||
&data);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = decode_KrbFastResponse(data.data, data.length, fastrep, NULL);
|
||||
krb5_data_free(&data);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
} else {
|
||||
ret = KRB5KDC_ERR_PREAUTH_FAILED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
free_PA_FX_FAST_REPLY(&fxfastrep);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
set_anon_principal(krb5_context context, PrincipalName **p)
|
||||
{
|
||||
|
||||
ALLOC((*p), 1);
|
||||
if (*p == NULL)
|
||||
goto fail;
|
||||
|
||||
(*p)->name_type = KRB5_NT_PRINCIPAL;
|
||||
|
||||
ALLOC_SEQ(&(*p)->name_string, 2);
|
||||
if ((*p)->name_string.val == NULL)
|
||||
goto fail;
|
||||
|
||||
(*p)->name_string.val[0] = strdup(KRB5_WELLKNOWN_NAME);
|
||||
if ((*p)->name_string.val[0] == NULL)
|
||||
goto fail;
|
||||
|
||||
(*p)->name_string.val[1] = strdup(KRB5_ANON_NAME);
|
||||
if ((*p)->name_string.val[1] == NULL)
|
||||
goto fail;
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
if (*p) {
|
||||
if ((*p)->name_string.val) {
|
||||
free((*p)->name_string.val[0]);
|
||||
free((*p)->name_string.val[1]);
|
||||
free((*p)->name_string.val);
|
||||
}
|
||||
free(*p);
|
||||
}
|
||||
|
||||
return krb5_enomem(context);
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
_krb5_fast_create_armor(krb5_context context,
|
||||
struct krb5_fast_state *state,
|
||||
const char *realm)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
|
||||
if (state->armor_crypto == NULL) {
|
||||
if (state->armor_ccache || state->armor_ac || (state->flags & KRB5_FAST_AP_ARMOR_SERVICE)) {
|
||||
/*
|
||||
* Instead of keeping state in FX_COOKIE in the KDC, we
|
||||
* rebuild a new armor key for every request, because this
|
||||
* is what the MIT KDC expect and RFC6113 is vage about
|
||||
* what the behavior should be.
|
||||
*/
|
||||
state->type = choice_PA_FX_FAST_REQUEST_armored_data;
|
||||
} else {
|
||||
return check_fast(context, state);
|
||||
}
|
||||
}
|
||||
|
||||
if (state->type == choice_PA_FX_FAST_REQUEST_armored_data) {
|
||||
if (state->armor_crypto)
|
||||
krb5_crypto_destroy(context, state->armor_crypto);
|
||||
krb5_free_keyblock_contents(context, &state->armor_key);
|
||||
|
||||
/*
|
||||
* If we have a armor auth context, its because the caller
|
||||
* wants us to do an implicit FAST armor (TGS-REQ).
|
||||
*/
|
||||
if (state->armor_ac) {
|
||||
heim_assert((state->flags & KRB5_FAST_AS_REQ) == 0, "FAST AS with AC");
|
||||
|
||||
ret = _krb5_fast_armor_key(context,
|
||||
state->armor_ac->local_subkey,
|
||||
state->armor_ac->keyblock,
|
||||
&state->armor_key,
|
||||
&state->armor_crypto);
|
||||
if (ret)
|
||||
goto out;
|
||||
} else {
|
||||
heim_assert((state->flags & KRB5_FAST_AS_REQ) != 0, "FAST TGS without AC");
|
||||
|
||||
if (state->armor_data) {
|
||||
free_KrbFastArmor(state->armor_data);
|
||||
free(state->armor_data);
|
||||
}
|
||||
ret = make_fast_ap_fxarmor(context, state, realm,
|
||||
&state->armor_data);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
heim_abort("unknown state type: %d", (int)state->type);
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
krb5_error_code
|
||||
_krb5_fast_wrap_req(krb5_context context,
|
||||
struct krb5_fast_state *state,
|
||||
krb5_data *checksum_data,
|
||||
KDC_REQ *req)
|
||||
{
|
||||
PA_FX_FAST_REQUEST fxreq;
|
||||
krb5_error_code ret;
|
||||
KrbFastReq fastreq;
|
||||
krb5_data data, aschecksum_data;
|
||||
size_t size = 0;
|
||||
|
||||
if (state->flags & KRB5_FAST_DISABLED) {
|
||||
_krb5_debug(context, 10, "fast disabled, not doing any fast wrapping");
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(&fxreq, 0, sizeof(fxreq));
|
||||
memset(&fastreq, 0, sizeof(fastreq));
|
||||
krb5_data_zero(&data);
|
||||
krb5_data_zero(&aschecksum_data);
|
||||
|
||||
if (state->armor_crypto == NULL)
|
||||
return check_fast(context, state);
|
||||
|
||||
state->flags |= KRB5_FAST_EXPECTED;
|
||||
|
||||
fastreq.fast_options.hide_client_names = 1;
|
||||
|
||||
ret = copy_KDC_REQ_BODY(&req->req_body, &fastreq.req_body);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* In the case of a AS-REQ, remove all account names. Want to this
|
||||
* for TGS-REQ too, but due to layering this is tricky.
|
||||
*
|
||||
* 1. TGS-REQ need checksum of REQ-BODY
|
||||
* 2. FAST needs checksum of TGS-REQ, so, FAST needs to happen after TGS-REQ
|
||||
* 3. FAST privacy mangaling needs to happen before TGS-REQ does the checksum in 1.
|
||||
*
|
||||
* So lets not modify the bits for now for TGS-REQ
|
||||
*/
|
||||
if (state->flags & KRB5_FAST_AS_REQ) {
|
||||
free_KDC_REQ_BODY(&req->req_body);
|
||||
|
||||
req->req_body.realm = strdup(KRB5_ANON_REALM);
|
||||
if (req->req_body.realm == NULL) {
|
||||
ret = krb5_enomem(context);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = set_anon_principal(context, &req->req_body.cname);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ALLOC(req->req_body.till, 1);
|
||||
*req->req_body.till = 0;
|
||||
|
||||
heim_assert(checksum_data == NULL, "checksum data not NULL");
|
||||
|
||||
ASN1_MALLOC_ENCODE(KDC_REQ_BODY,
|
||||
aschecksum_data.data,
|
||||
aschecksum_data.length,
|
||||
&req->req_body,
|
||||
&size, ret);
|
||||
if (ret)
|
||||
goto out;
|
||||
heim_assert(aschecksum_data.length == size, "ASN.1 internal error");
|
||||
|
||||
checksum_data = &aschecksum_data;
|
||||
}
|
||||
|
||||
if (req->padata) {
|
||||
ret = copy_METHOD_DATA(req->padata, &fastreq.padata);
|
||||
free_METHOD_DATA(req->padata);
|
||||
if (ret)
|
||||
goto out;
|
||||
} else {
|
||||
ALLOC(req->padata, 1);
|
||||
if (req->padata == NULL) {
|
||||
ret = krb5_enomem(context);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ASN1_MALLOC_ENCODE(KrbFastReq, data.data, data.length, &fastreq, &size, ret);
|
||||
if (ret)
|
||||
goto out;
|
||||
heim_assert(data.length == size, "ASN.1 internal error");
|
||||
|
||||
fxreq.element = state->type;
|
||||
|
||||
if (state->type == choice_PA_FX_FAST_REQUEST_armored_data) {
|
||||
fxreq.u.armored_data.armor = state->armor_data;
|
||||
state->armor_data = NULL;
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
heim_assert(state->armor_crypto != NULL,
|
||||
"FAST armor key missing when FAST started");
|
||||
|
||||
ret = krb5_create_checksum(context, state->armor_crypto,
|
||||
KRB5_KU_FAST_REQ_CHKSUM, 0,
|
||||
checksum_data->data,
|
||||
checksum_data->length,
|
||||
&fxreq.u.armored_data.req_checksum);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = krb5_encrypt_EncryptedData(context, state->armor_crypto,
|
||||
KRB5_KU_FAST_ENC,
|
||||
data.data,
|
||||
data.length,
|
||||
0,
|
||||
&fxreq.u.armored_data.enc_fast_req);
|
||||
krb5_data_free(&data);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
} else {
|
||||
krb5_data_free(&data);
|
||||
heim_assert(false, "unknown FAST type, internal error");
|
||||
}
|
||||
|
||||
ASN1_MALLOC_ENCODE(PA_FX_FAST_REQUEST, data.data, data.length, &fxreq, &size, ret);
|
||||
if (ret)
|
||||
goto out;
|
||||
heim_assert(data.length == size, "ASN.1 internal error");
|
||||
|
||||
|
||||
ret = krb5_padata_add(context, req->padata, KRB5_PADATA_FX_FAST, data.data, data.length);
|
||||
if (ret)
|
||||
goto out;
|
||||
krb5_data_zero(&data);
|
||||
|
||||
out:
|
||||
free_KrbFastReq(&fastreq);
|
||||
free_PA_FX_FAST_REQUEST(&fxreq);
|
||||
krb5_data_free(&data);
|
||||
krb5_data_free(&aschecksum_data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
_krb5_fast_unwrap_error(krb5_context context,
|
||||
int32_t nonce,
|
||||
struct krb5_fast_state *state,
|
||||
METHOD_DATA *md,
|
||||
KRB_ERROR *error)
|
||||
{
|
||||
KrbFastResponse fastrep;
|
||||
krb5_error_code ret;
|
||||
PA_DATA *pa;
|
||||
int idx;
|
||||
|
||||
if (state->armor_crypto == NULL)
|
||||
return check_fast(context, state);
|
||||
|
||||
memset(&fastrep, 0, sizeof(fastrep));
|
||||
|
||||
if (error->error_code != KRB5_KDC_ERR_MORE_PREAUTH_DATA_REQUIRED)
|
||||
_krb5_debug(context, 10, "using FAST without FAST outer error code");
|
||||
|
||||
idx = 0;
|
||||
pa = krb5_find_padata(md->val, md->len, KRB5_PADATA_FX_FAST, &idx);
|
||||
if (pa == NULL) {
|
||||
ret = KRB5_KDCREP_MODIFIED;
|
||||
krb5_set_error_message(context, ret,
|
||||
N_("FAST fast response is missing FX-FAST", ""));
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = unwrap_fast_rep(context, state, pa, &fastrep);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (fastrep.strengthen_key || nonce != (int32_t)fastrep.nonce) {
|
||||
ret = KRB5KDC_ERR_PREAUTH_FAILED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
idx = 0;
|
||||
pa = krb5_find_padata(fastrep.padata.val, fastrep.padata.len, KRB5_PADATA_FX_ERROR, &idx);
|
||||
if (pa == NULL) {
|
||||
ret = KRB5_KDCREP_MODIFIED;
|
||||
krb5_set_error_message(context, ret, N_("No wrapped error", ""));
|
||||
goto out;
|
||||
}
|
||||
|
||||
free_KRB_ERROR(error);
|
||||
|
||||
ret = krb5_rd_error(context, &pa->padata_value, error);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (error->e_data)
|
||||
_krb5_debug(context, 10, "FAST wrapped KBB_ERROR contained e_data: %d",
|
||||
(int)error->e_data->length);
|
||||
|
||||
free_METHOD_DATA(md);
|
||||
md->val = fastrep.padata.val;
|
||||
md->len = fastrep.padata.len;
|
||||
|
||||
fastrep.padata.val = NULL;
|
||||
fastrep.padata.len = 0;
|
||||
|
||||
out:
|
||||
free_KrbFastResponse(&fastrep);
|
||||
return ret;
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
_krb5_fast_unwrap_kdc_rep(krb5_context context, int32_t nonce,
|
||||
krb5_data *chksumdata,
|
||||
struct krb5_fast_state *state, AS_REP *rep)
|
||||
{
|
||||
KrbFastResponse fastrep;
|
||||
krb5_error_code ret;
|
||||
PA_DATA *pa = NULL;
|
||||
int idx = 0;
|
||||
|
||||
if (state == NULL || state->armor_crypto == NULL || rep->padata == NULL)
|
||||
return check_fast(context, state);
|
||||
|
||||
/* find PA_FX_FAST_REPLY */
|
||||
|
||||
pa = krb5_find_padata(rep->padata->val, rep->padata->len,
|
||||
KRB5_PADATA_FX_FAST, &idx);
|
||||
if (pa == NULL)
|
||||
return check_fast(context, state);
|
||||
|
||||
memset(&fastrep, 0, sizeof(fastrep));
|
||||
|
||||
ret = unwrap_fast_rep(context, state, pa, &fastrep);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
free_METHOD_DATA(rep->padata);
|
||||
ret = copy_METHOD_DATA(&fastrep.padata, rep->padata);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (fastrep.strengthen_key) {
|
||||
if (state->strengthen_key)
|
||||
krb5_free_keyblock(context, state->strengthen_key);
|
||||
|
||||
ret = krb5_copy_keyblock(context, fastrep.strengthen_key, &state->strengthen_key);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (nonce != (int32_t)fastrep.nonce) {
|
||||
ret = KRB5KDC_ERR_PREAUTH_FAILED;
|
||||
goto out;
|
||||
}
|
||||
if (fastrep.finished) {
|
||||
PrincipalName cname;
|
||||
krb5_realm crealm = NULL;
|
||||
|
||||
if (chksumdata == NULL) {
|
||||
ret = KRB5KDC_ERR_PREAUTH_FAILED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = krb5_verify_checksum(context, state->armor_crypto,
|
||||
KRB5_KU_FAST_FINISHED,
|
||||
chksumdata->data, chksumdata->length,
|
||||
&fastrep.finished->ticket_checksum);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* update */
|
||||
ret = copy_Realm(&fastrep.finished->crealm, &crealm);
|
||||
if (ret)
|
||||
goto out;
|
||||
free_Realm(&rep->crealm);
|
||||
rep->crealm = crealm;
|
||||
|
||||
ret = copy_PrincipalName(&fastrep.finished->cname, &cname);
|
||||
if (ret)
|
||||
goto out;
|
||||
free_PrincipalName(&rep->cname);
|
||||
rep->cname = cname;
|
||||
} else if (chksumdata) {
|
||||
/* expected fastrep.finish but didn't get it */
|
||||
ret = KRB5KDC_ERR_PREAUTH_FAILED;
|
||||
}
|
||||
|
||||
out:
|
||||
free_KrbFastResponse(&fastrep);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
_krb5_fast_free(krb5_context context, struct krb5_fast_state *state)
|
||||
{
|
||||
if (state->armor_ccache) {
|
||||
if (state->flags & KRB5_FAST_ANON_PKINIT_ARMOR)
|
||||
krb5_cc_destroy(context, state->armor_ccache);
|
||||
else
|
||||
krb5_cc_close(context, state->armor_ccache);
|
||||
}
|
||||
if (state->armor_service)
|
||||
krb5_free_principal(context, state->armor_service);
|
||||
if (state->armor_crypto)
|
||||
krb5_crypto_destroy(context, state->armor_crypto);
|
||||
if (state->strengthen_key)
|
||||
krb5_free_keyblock(context, state->strengthen_key);
|
||||
krb5_free_keyblock_contents(context, &state->armor_key);
|
||||
if (state->armor_data) {
|
||||
free_KrbFastArmor(state->armor_data);
|
||||
free(state->armor_data);
|
||||
}
|
||||
|
||||
if (state->anon_pkinit_ctx)
|
||||
krb5_init_creds_free(context, state->anon_pkinit_ctx);
|
||||
if (state->anon_pkinit_opt)
|
||||
krb5_get_init_creds_opt_free(context, state->anon_pkinit_opt);
|
||||
|
||||
memset(state, 0, sizeof(*state));
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
_krb5_fast_anon_pkinit_step(krb5_context context,
|
||||
krb5_init_creds_context ctx,
|
||||
struct krb5_fast_state *state,
|
||||
krb5_data *in,
|
||||
krb5_data *out,
|
||||
krb5_krbhst_info *hostinfo,
|
||||
unsigned int *flags)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
krb5_const_realm realm = _krb5_init_creds_get_cred_client(context, ctx)->realm;
|
||||
krb5_init_creds_context anon_pk_ctx;
|
||||
krb5_principal principal = NULL, anon_pk_client;
|
||||
krb5_ccache ccache = NULL;
|
||||
krb5_creds cred;
|
||||
krb5_data data = { 3, rk_UNCONST("yes") };
|
||||
|
||||
memset(&cred, 0, sizeof(cred));
|
||||
|
||||
if (state->anon_pkinit_opt == NULL) {
|
||||
ret = krb5_get_init_creds_opt_alloc(context, &state->anon_pkinit_opt);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
krb5_get_init_creds_opt_set_tkt_life(state->anon_pkinit_opt, 60);
|
||||
krb5_get_init_creds_opt_set_anonymous(state->anon_pkinit_opt, TRUE);
|
||||
|
||||
ret = krb5_make_principal(context, &principal, realm,
|
||||
KRB5_WELLKNOWN_NAME, KRB5_ANON_NAME, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = krb5_get_init_creds_opt_set_pkinit(context,
|
||||
state->anon_pkinit_opt,
|
||||
principal,
|
||||
NULL, NULL, NULL, NULL,
|
||||
KRB5_GIC_OPT_PKINIT_ANONYMOUS |
|
||||
KRB5_GIC_OPT_PKINIT_NO_KDC_ANCHOR,
|
||||
NULL, NULL, NULL);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = krb5_init_creds_init(context, principal, NULL, NULL,
|
||||
_krb5_init_creds_get_cred_starttime(context, ctx),
|
||||
state->anon_pkinit_opt,
|
||||
&state->anon_pkinit_ctx);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
anon_pk_ctx = state->anon_pkinit_ctx;
|
||||
|
||||
ret = krb5_init_creds_step(context, anon_pk_ctx, in, out, hostinfo, flags);
|
||||
if (ret ||
|
||||
(*flags & KRB5_INIT_CREDS_STEP_FLAG_CONTINUE))
|
||||
goto out;
|
||||
|
||||
ret = krb5_process_last_request(context, state->anon_pkinit_opt, anon_pk_ctx);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = krb5_cc_new_unique(context, "MEMORY", NULL, &ccache);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = krb5_init_creds_get_creds(context, anon_pk_ctx, &cred);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (!cred.flags.b.enc_pa_rep) {
|
||||
ret = KRB5KDC_ERR_BADOPTION; /* KDC does not support FAST */
|
||||
goto out;
|
||||
}
|
||||
|
||||
anon_pk_client = _krb5_init_creds_get_cred_client(context, anon_pk_ctx);
|
||||
|
||||
ret = krb5_cc_initialize(context, ccache, anon_pk_client);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = krb5_cc_store_cred(context, ccache, &cred);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = krb5_cc_set_config(context, ccache, cred.server,
|
||||
"fast_avail", &data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (_krb5_pk_is_kdc_verified(context, state->anon_pkinit_opt))
|
||||
state->flags |= KRB5_FAST_KDC_VERIFIED;
|
||||
else
|
||||
state->flags &= ~(KRB5_FAST_KDC_VERIFIED);
|
||||
|
||||
state->armor_ccache = ccache;
|
||||
ccache = NULL;
|
||||
|
||||
krb5_init_creds_free(context, state->anon_pkinit_ctx);
|
||||
state->anon_pkinit_ctx = NULL;
|
||||
|
||||
krb5_get_init_creds_opt_free(context, state->anon_pkinit_opt);
|
||||
state->anon_pkinit_opt = NULL;
|
||||
|
||||
*flags |= KRB5_INIT_CREDS_STEP_FLAG_CONTINUE;
|
||||
|
||||
out:
|
||||
krb5_free_principal(context, principal);
|
||||
krb5_free_cred_contents(context, &cred);
|
||||
if (ccache)
|
||||
krb5_cc_destroy(context, ccache);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@
|
||||
* (Royal Institute of Technology, Stockholm, Sweden).
|
||||
* All rights reserved.
|
||||
*
|
||||
* Portions Copyright (c) 2009 Apple Inc. All rights reserved.
|
||||
* Portions Copyright (c) 2009 - 2010 Apple Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -38,8 +38,10 @@
|
||||
|
||||
static krb5_error_code
|
||||
get_cred_kdc_capath(krb5_context, krb5_kdc_flags,
|
||||
krb5_ccache, krb5_creds *, krb5_principal,
|
||||
Ticket *, krb5_creds **, krb5_creds ***);
|
||||
krb5_ccache, struct krb5_fast_state *,
|
||||
krb5_creds *, krb5_principal,
|
||||
Ticket *, const char *, const char *,
|
||||
krb5_creds **, krb5_creds ***);
|
||||
|
||||
/*
|
||||
* Take the `body' and encode it into `padata' using the credentials
|
||||
@@ -50,33 +52,31 @@ static krb5_error_code
|
||||
make_pa_tgs_req(krb5_context context,
|
||||
krb5_auth_context ac,
|
||||
KDC_REQ_BODY *body,
|
||||
PA_DATA *padata,
|
||||
krb5_creds *creds)
|
||||
krb5_ccache ccache,
|
||||
krb5_creds *creds,
|
||||
krb5_data *tgs_req)
|
||||
{
|
||||
u_char *buf;
|
||||
krb5_error_code ret;
|
||||
krb5_data in_data;
|
||||
size_t buf_size;
|
||||
size_t len = 0;
|
||||
krb5_data in_data;
|
||||
krb5_error_code ret;
|
||||
uint8_t *buf;
|
||||
|
||||
ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, body, &len, ret);
|
||||
if (ret)
|
||||
goto out;
|
||||
return ret;
|
||||
|
||||
if(buf_size != len)
|
||||
krb5_abortx(context, "internal error in ASN.1 encoder");
|
||||
|
||||
in_data.length = len;
|
||||
in_data.data = buf;
|
||||
ret = _krb5_mk_req_internal(context, &ac, 0, &in_data, creds,
|
||||
&padata->padata_value,
|
||||
ret = _krb5_mk_req_internal(context, &ac, 0, &in_data,
|
||||
creds, tgs_req,
|
||||
KRB5_KU_TGS_REQ_AUTH_CKSUM,
|
||||
KRB5_KU_TGS_REQ_AUTH);
|
||||
out:
|
||||
free (buf);
|
||||
if(ret)
|
||||
return ret;
|
||||
padata->padata_type = KRB5_PADATA_TGS_REQ;
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -138,6 +138,7 @@ set_auth_data (krb5_context context,
|
||||
static krb5_error_code
|
||||
init_tgs_req (krb5_context context,
|
||||
krb5_ccache ccache,
|
||||
struct krb5_fast_state *state,
|
||||
krb5_addresses *addresses,
|
||||
krb5_kdc_flags flags,
|
||||
Ticket *second_ticket,
|
||||
@@ -150,8 +151,11 @@ init_tgs_req (krb5_context context,
|
||||
{
|
||||
krb5_auth_context ac = NULL;
|
||||
krb5_error_code ret = 0;
|
||||
krb5_data tgs_req;
|
||||
|
||||
memset(t, 0, sizeof(*t));
|
||||
memset(t, 0, sizeof(*t));
|
||||
|
||||
t->pvno = 5;
|
||||
t->msg_type = krb_tgs_req;
|
||||
if (in_creds->session.keytype) {
|
||||
@@ -234,26 +238,19 @@ init_tgs_req (krb5_context context,
|
||||
if (ret)
|
||||
goto fail;
|
||||
}
|
||||
ALLOC(t->padata, 1);
|
||||
if (t->padata == NULL) {
|
||||
ret = krb5_enomem(context);
|
||||
goto fail;
|
||||
}
|
||||
ALLOC_SEQ(t->padata, 1 + padata->len);
|
||||
if (t->padata->val == NULL) {
|
||||
ret = krb5_enomem(context);
|
||||
goto fail;
|
||||
}
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < padata->len; i++) {
|
||||
ret = copy_PA_DATA(&padata->val[i], &t->padata->val[i + 1]);
|
||||
if (ret) {
|
||||
krb5_set_error_message(context, ret,
|
||||
N_("malloc: out of memory", ""));
|
||||
|
||||
if (padata) {
|
||||
if (t->padata == NULL) {
|
||||
ALLOC(t->padata, 1);
|
||||
if (t->padata == NULL) {
|
||||
ret = krb5_enomem(context);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
ret = copy_METHOD_DATA(padata, t->padata);
|
||||
if (ret)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = krb5_auth_con_init(context, &ac);
|
||||
@@ -264,19 +261,61 @@ init_tgs_req (krb5_context context,
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
ret = set_auth_data (context, &t->req_body, &in_creds->authdata,
|
||||
ac->local_subkey);
|
||||
if (state) {
|
||||
krb5_data empty;
|
||||
|
||||
krb5_data_zero(&empty);
|
||||
ret = krb5_auth_con_add_AuthorizationData(context, ac,
|
||||
KRB5_AUTHDATA_FX_FAST_USED,
|
||||
&empty);
|
||||
if (ret)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = set_auth_data(context, &t->req_body,
|
||||
&in_creds->authdata, ac->local_subkey);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
if (t->padata == NULL) {
|
||||
ALLOC(t->padata, 1);
|
||||
if (t->padata == NULL) {
|
||||
ret = krb5_enomem(context);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
ret = make_pa_tgs_req(context,
|
||||
ac,
|
||||
&t->req_body,
|
||||
&t->padata->val[0],
|
||||
krbtgt);
|
||||
ccache,
|
||||
krbtgt,
|
||||
&tgs_req);
|
||||
if(ret)
|
||||
goto fail;
|
||||
|
||||
if (state) {
|
||||
state->armor_ac = ac;
|
||||
ret = _krb5_fast_create_armor(context, state, NULL);
|
||||
state->armor_ac = NULL;
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
ret = _krb5_fast_wrap_req(context, state, &tgs_req, t);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
/* Its ok if there is no fast in the TGS-REP, older heimdal only support it in the AS code path */
|
||||
state->flags &= ~KRB5_FAST_EXPECTED;
|
||||
}
|
||||
|
||||
ret = krb5_padata_add(context, t->padata, KRB5_PADATA_TGS_REQ,
|
||||
tgs_req.data, tgs_req.length);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
krb5_data_zero(&tgs_req);
|
||||
|
||||
ret = krb5_auth_con_getlocalsubkey(context, ac, subkey);
|
||||
if (ret)
|
||||
goto fail;
|
||||
@@ -288,6 +327,8 @@ fail:
|
||||
t->req_body.addresses = NULL;
|
||||
free_TGS_REQ (t);
|
||||
}
|
||||
krb5_data_free(&tgs_req);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -336,6 +377,42 @@ _krb5_get_krbtgt(krb5_context context,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
fast_tgs_strengthen_key(krb5_context context,
|
||||
struct krb5_fast_state *state,
|
||||
krb5_keyblock *reply_key,
|
||||
krb5_keyblock *extract_key)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
|
||||
if (state && state->strengthen_key) {
|
||||
_krb5_debug(context, 5, "_krb5_fast_tgs_strengthen_key");
|
||||
|
||||
if (state->strengthen_key->keytype != reply_key->keytype) {
|
||||
krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
|
||||
N_("strengthen_key %d not same enctype as reply key %d", ""),
|
||||
state->strengthen_key->keytype, reply_key->keytype);
|
||||
return KRB5KRB_AP_ERR_MODIFIED;
|
||||
}
|
||||
|
||||
ret = _krb5_fast_cf2(context,
|
||||
state->strengthen_key,
|
||||
"strengthenkey",
|
||||
reply_key,
|
||||
"replykey",
|
||||
extract_key,
|
||||
NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
ret = krb5_copy_keyblock_contents(context, reply_key, extract_key);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* DCE compatible decrypt proc */
|
||||
static krb5_error_code KRB5_CALLCONV
|
||||
decrypt_tkt_with_subkey (krb5_context context,
|
||||
@@ -344,11 +421,14 @@ decrypt_tkt_with_subkey (krb5_context context,
|
||||
krb5_const_pointer skey,
|
||||
krb5_kdc_rep *dec_rep)
|
||||
{
|
||||
const krb5_keyblock *subkey = skey;
|
||||
struct krb5_decrypt_tkt_with_subkey_state *state;
|
||||
krb5_error_code ret = 0;
|
||||
krb5_data data;
|
||||
size_t size;
|
||||
krb5_crypto crypto;
|
||||
krb5_keyblock extract_key;
|
||||
|
||||
state = (struct krb5_decrypt_tkt_with_subkey_state *)skey;
|
||||
|
||||
assert(usage == 0);
|
||||
|
||||
@@ -357,8 +437,14 @@ decrypt_tkt_with_subkey (krb5_context context,
|
||||
/*
|
||||
* start out with trying with subkey if we have one
|
||||
*/
|
||||
if (subkey) {
|
||||
ret = krb5_crypto_init(context, subkey, 0, &crypto);
|
||||
if (state->subkey) {
|
||||
ret = fast_tgs_strengthen_key(context, state->fast_state,
|
||||
state->subkey, &extract_key);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = krb5_crypto_init(context, &extract_key, 0, &crypto);
|
||||
krb5_free_keyblock_contents(context, &extract_key);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = krb5_decrypt_EncryptedData (context,
|
||||
@@ -370,7 +456,7 @@ decrypt_tkt_with_subkey (krb5_context context,
|
||||
* If the is Windows 2000 DC, we need to retry with key usage
|
||||
* 8 when doing ARCFOUR.
|
||||
*/
|
||||
if (ret && subkey->keytype == ETYPE_ARCFOUR_HMAC_MD5) {
|
||||
if (ret && state->subkey->keytype == ETYPE_ARCFOUR_HMAC_MD5) {
|
||||
ret = krb5_decrypt_EncryptedData(context,
|
||||
crypto,
|
||||
8,
|
||||
@@ -379,7 +465,11 @@ decrypt_tkt_with_subkey (krb5_context context,
|
||||
}
|
||||
krb5_crypto_destroy(context, crypto);
|
||||
}
|
||||
if (subkey == NULL || ret) {
|
||||
if (state->subkey == NULL || ret) {
|
||||
ret = fast_tgs_strengthen_key(context, state->fast_state, key, &extract_key);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = krb5_crypto_init(context, key, 0, &crypto);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -412,19 +502,21 @@ decrypt_tkt_with_subkey (krb5_context context,
|
||||
static krb5_error_code
|
||||
get_cred_kdc(krb5_context context,
|
||||
krb5_ccache id,
|
||||
struct krb5_fast_state *fast_state,
|
||||
krb5_kdc_flags flags,
|
||||
krb5_addresses *addresses,
|
||||
krb5_creds *in_creds,
|
||||
krb5_creds *krbtgt,
|
||||
krb5_principal impersonate_principal,
|
||||
Ticket *second_ticket,
|
||||
const char *kdc_hostname,
|
||||
const char *sitename,
|
||||
krb5_creds *out_creds)
|
||||
{
|
||||
TGS_REQ req;
|
||||
krb5_data enc;
|
||||
krb5_data resp;
|
||||
krb5_kdc_rep rep = {0};
|
||||
KRB_ERROR error;
|
||||
krb5_error_code ret;
|
||||
unsigned nonce;
|
||||
krb5_keyblock *subkey = NULL;
|
||||
@@ -503,6 +595,7 @@ get_cred_kdc(krb5_context context,
|
||||
|
||||
ret = init_tgs_req (context,
|
||||
id,
|
||||
fast_state,
|
||||
addresses,
|
||||
flags,
|
||||
second_ticket,
|
||||
@@ -535,6 +628,11 @@ get_cred_kdc(krb5_context context,
|
||||
return ret;
|
||||
krb5_sendto_ctx_set_func(stctx, _krb5_kdc_retry, NULL);
|
||||
|
||||
if (kdc_hostname)
|
||||
krb5_sendto_set_hostname(context, stctx, kdc_hostname);
|
||||
if (sitename)
|
||||
krb5_sendto_set_sitename(context, stctx, sitename);
|
||||
|
||||
ret = krb5_sendto_context (context, stctx, &enc,
|
||||
krbtgt->server->name.name_string.val[1],
|
||||
&resp);
|
||||
@@ -544,18 +642,33 @@ get_cred_kdc(krb5_context context,
|
||||
goto out;
|
||||
|
||||
if(decode_TGS_REP(resp.data, resp.length, &rep.kdc_rep, &len) == 0) {
|
||||
struct krb5_decrypt_tkt_with_subkey_state state;
|
||||
unsigned eflags = 0;
|
||||
krb5_data data;
|
||||
size_t size;
|
||||
|
||||
ASN1_MALLOC_ENCODE(Ticket, data.data, data.length,
|
||||
&rep.kdc_rep.ticket, &size, ret);
|
||||
if (ret)
|
||||
goto out;
|
||||
heim_assert(data.length == size, "ASN.1 internal error");
|
||||
|
||||
ret = _krb5_fast_unwrap_kdc_rep(context, nonce, &data,
|
||||
fast_state, &rep.kdc_rep);
|
||||
krb5_data_free(&data);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = krb5_copy_principal(context,
|
||||
in_creds->client,
|
||||
&out_creds->client);
|
||||
if(ret)
|
||||
goto out2;
|
||||
goto out;
|
||||
ret = krb5_copy_principal(context,
|
||||
in_creds->server,
|
||||
&out_creds->server);
|
||||
if(ret)
|
||||
goto out2;
|
||||
goto out;
|
||||
/* this should go someplace else */
|
||||
out_creds->times.endtime = in_creds->times.endtime;
|
||||
|
||||
@@ -565,6 +678,9 @@ get_cred_kdc(krb5_context context,
|
||||
if (flags.b.request_anonymous)
|
||||
eflags |= EXTRACT_TICKET_MATCH_ANON;
|
||||
|
||||
state.subkey = subkey;
|
||||
state.fast_state = fast_state;
|
||||
|
||||
ret = _krb5_extract_ticket(context,
|
||||
&rep,
|
||||
out_creds,
|
||||
@@ -576,12 +692,36 @@ get_cred_kdc(krb5_context context,
|
||||
eflags,
|
||||
NULL,
|
||||
decrypt_tkt_with_subkey,
|
||||
subkey);
|
||||
out2:
|
||||
krb5_free_kdc_rep(context, &rep);
|
||||
} else if(krb5_rd_error(context, &resp, &error) == 0) {
|
||||
ret = krb5_error_from_rd_error(context, &error, in_creds);
|
||||
krb5_free_error_contents(context, &error);
|
||||
&state);
|
||||
} else if(krb5_rd_error(context, &resp, &rep.error) == 0) {
|
||||
METHOD_DATA md;
|
||||
|
||||
memset(&md, 0, sizeof(md));
|
||||
|
||||
if (rep.error.e_data) {
|
||||
ret = decode_METHOD_DATA(rep.error.e_data->data,
|
||||
rep.error.e_data->length,
|
||||
&md, NULL);
|
||||
if (ret) {
|
||||
krb5_set_error_message(context, ret,
|
||||
N_("Failed to decode METHOD-DATA", ""));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ret = _krb5_fast_unwrap_error(context, nonce, fast_state, &md, &rep.error);
|
||||
free_METHOD_DATA(&md);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = krb5_error_from_rd_error(context, &rep.error, in_creds);
|
||||
|
||||
/* log the failure */
|
||||
if (_krb5_have_debug(context, 5)) {
|
||||
const char *str = krb5_get_error_message(context, ret);
|
||||
_krb5_debug(context, 5, "parse_tgs_rep: KRB-ERROR %d/%s", ret, str);
|
||||
krb5_free_error_message(context, str);
|
||||
}
|
||||
} else if(resp.length > 0 && ((char*)resp.data)[0] == 4) {
|
||||
ret = KRB5KRB_AP_ERR_V4_REPLY;
|
||||
krb5_clear_error_message(context);
|
||||
@@ -591,6 +731,7 @@ get_cred_kdc(krb5_context context,
|
||||
}
|
||||
|
||||
out:
|
||||
krb5_free_kdc_rep(context, &rep);
|
||||
if (second_ticket == &second_ticket_data)
|
||||
free_Ticket(&second_ticket_data);
|
||||
free_METHOD_DATA(&padata);
|
||||
@@ -610,12 +751,15 @@ out:
|
||||
static krb5_error_code
|
||||
get_cred_kdc_address(krb5_context context,
|
||||
krb5_ccache id,
|
||||
struct krb5_fast_state *fast_state,
|
||||
krb5_kdc_flags flags,
|
||||
krb5_addresses *addrs,
|
||||
krb5_creds *in_creds,
|
||||
krb5_creds *krbtgt,
|
||||
krb5_principal impersonate_principal,
|
||||
Ticket *second_ticket,
|
||||
const char *kdc_hostname,
|
||||
const char *sitename,
|
||||
krb5_creds *out_creds)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
@@ -640,9 +784,9 @@ get_cred_kdc_address(krb5_context context,
|
||||
addrs = NULL;
|
||||
}
|
||||
}
|
||||
ret = get_cred_kdc(context, id, flags, addrs, in_creds,
|
||||
krbtgt, impersonate_principal,
|
||||
second_ticket, out_creds);
|
||||
ret = get_cred_kdc(context, id, fast_state, flags, addrs,
|
||||
in_creds, krbtgt, impersonate_principal,
|
||||
second_ticket, kdc_hostname, sitename, out_creds);
|
||||
krb5_free_addresses(context, &addresses);
|
||||
return ret;
|
||||
}
|
||||
@@ -659,6 +803,9 @@ krb5_get_kdc_cred(krb5_context context,
|
||||
{
|
||||
krb5_error_code ret;
|
||||
krb5_creds *krbtgt;
|
||||
struct krb5_fast_state fast_state;
|
||||
|
||||
memset(&fast_state, 0, sizeof(fast_state));
|
||||
|
||||
*out_creds = calloc(1, sizeof(**out_creds));
|
||||
if(*out_creds == NULL)
|
||||
@@ -672,9 +819,11 @@ krb5_get_kdc_cred(krb5_context context,
|
||||
*out_creds = NULL;
|
||||
return ret;
|
||||
}
|
||||
ret = get_cred_kdc(context, id, flags, addresses,
|
||||
in_creds, krbtgt, NULL, NULL, *out_creds);
|
||||
ret = get_cred_kdc(context, id, &fast_state, flags,
|
||||
addresses, in_creds, krbtgt,
|
||||
NULL, NULL, NULL, NULL, *out_creds);
|
||||
krb5_free_creds (context, krbtgt);
|
||||
_krb5_fast_free(context, &fast_state);
|
||||
if(ret) {
|
||||
free(*out_creds);
|
||||
*out_creds = NULL;
|
||||
@@ -752,10 +901,13 @@ static krb5_error_code
|
||||
get_cred_kdc_capath_worker(krb5_context context,
|
||||
krb5_kdc_flags flags,
|
||||
krb5_ccache ccache,
|
||||
struct krb5_fast_state *fast_state,
|
||||
krb5_creds *in_creds,
|
||||
krb5_const_realm try_realm,
|
||||
krb5_principal impersonate_principal,
|
||||
Ticket *second_ticket,
|
||||
const char *kdc_hostname,
|
||||
const char *sitename,
|
||||
krb5_creds **out_creds,
|
||||
krb5_creds ***ret_tgts)
|
||||
{
|
||||
@@ -802,11 +954,14 @@ get_cred_kdc_capath_worker(krb5_context context,
|
||||
ok_as_delegate = tgts.flags.b.ok_as_delegate;
|
||||
}
|
||||
|
||||
ret = get_cred_kdc_address(context, ccache, flags, NULL,
|
||||
in_creds, &tgts,
|
||||
impersonate_principal,
|
||||
second_ticket,
|
||||
*out_creds);
|
||||
ret = get_cred_kdc_address(context, ccache, fast_state,
|
||||
flags, NULL,
|
||||
in_creds, &tgts,
|
||||
impersonate_principal,
|
||||
second_ticket,
|
||||
kdc_hostname,
|
||||
sitename,
|
||||
*out_creds);
|
||||
krb5_free_cred_contents(context, &tgts);
|
||||
if (ret == 0 &&
|
||||
!krb5_principal_compare(context, in_creds->server,
|
||||
@@ -838,8 +993,10 @@ get_cred_kdc_capath_worker(krb5_context context,
|
||||
while (1) {
|
||||
heim_general_string tgt_inst;
|
||||
|
||||
ret = get_cred_kdc_capath(context, flags, ccache, &tmp_creds,
|
||||
NULL, NULL, &tgt, ret_tgts);
|
||||
ret = get_cred_kdc_capath(context, flags, ccache, fast_state,
|
||||
&tmp_creds, NULL, NULL,
|
||||
kdc_hostname, sitename,
|
||||
&tgt, ret_tgts);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
@@ -870,9 +1027,9 @@ get_cred_kdc_capath_worker(krb5_context context,
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = get_cred_kdc_address(context, ccache, flags, NULL,
|
||||
ret = get_cred_kdc_address(context, ccache, fast_state, flags, NULL,
|
||||
in_creds, tgt, impersonate_principal,
|
||||
second_ticket, *out_creds);
|
||||
second_ticket, kdc_hostname, sitename, *out_creds);
|
||||
if (ret == 0 &&
|
||||
!krb5_principal_compare(context, in_creds->server,
|
||||
(*out_creds)->server)) {
|
||||
@@ -915,9 +1072,12 @@ static krb5_error_code
|
||||
get_cred_kdc_capath(krb5_context context,
|
||||
krb5_kdc_flags flags,
|
||||
krb5_ccache ccache,
|
||||
struct krb5_fast_state *fast_state,
|
||||
krb5_creds *in_creds,
|
||||
krb5_principal impersonate_principal,
|
||||
Ticket *second_ticket,
|
||||
const char *kdc_hostname,
|
||||
const char *sitename,
|
||||
krb5_creds **out_creds,
|
||||
krb5_creds ***ret_tgts)
|
||||
{
|
||||
@@ -928,18 +1088,20 @@ get_cred_kdc_capath(krb5_context context,
|
||||
server_realm = krb5_principal_get_realm(context, in_creds->server);
|
||||
|
||||
try_realm = client_realm;
|
||||
ret = get_cred_kdc_capath_worker(context, flags, ccache, in_creds, try_realm,
|
||||
impersonate_principal, second_ticket, out_creds,
|
||||
ret_tgts);
|
||||
ret = get_cred_kdc_capath_worker(context, flags, ccache, fast_state,
|
||||
in_creds, try_realm, impersonate_principal,
|
||||
second_ticket, kdc_hostname, sitename,
|
||||
out_creds, ret_tgts);
|
||||
|
||||
if (ret == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN) {
|
||||
try_realm = krb5_config_get_string(context, NULL, "capaths",
|
||||
client_realm, server_realm, NULL);
|
||||
|
||||
if (try_realm != NULL && strcmp(try_realm, client_realm) != 0) {
|
||||
ret = get_cred_kdc_capath_worker(context, flags, ccache, in_creds,
|
||||
try_realm, impersonate_principal,
|
||||
second_ticket, out_creds, ret_tgts);
|
||||
ret = get_cred_kdc_capath_worker(context, flags, ccache, fast_state,
|
||||
in_creds, try_realm, impersonate_principal,
|
||||
second_ticket, kdc_hostname, sitename,
|
||||
out_creds, ret_tgts);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -963,9 +1125,12 @@ static krb5_error_code
|
||||
get_cred_kdc_referral(krb5_context context,
|
||||
krb5_kdc_flags flags,
|
||||
krb5_ccache ccache,
|
||||
struct krb5_fast_state *fast_state,
|
||||
krb5_creds *in_creds,
|
||||
krb5_principal impersonate_principal,
|
||||
Ticket *second_ticket,
|
||||
const char *kdc_hostname,
|
||||
const char *sitename,
|
||||
krb5_creds **out_creds)
|
||||
{
|
||||
krb5_realm start_realm = NULL;
|
||||
@@ -1076,9 +1241,9 @@ get_cred_kdc_referral(krb5_context context,
|
||||
ret = EINVAL;
|
||||
|
||||
if (ret) {
|
||||
ret = get_cred_kdc_address(context, ccache, flags, NULL,
|
||||
ret = get_cred_kdc_address(context, ccache, fast_state, flags, NULL,
|
||||
&referral, &tgt, impersonate_principal,
|
||||
second_ticket, &ticket);
|
||||
second_ticket, kdc_hostname, sitename, &ticket);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
@@ -1197,14 +1362,45 @@ KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
|
||||
_krb5_get_cred_kdc_any(krb5_context context,
|
||||
krb5_kdc_flags flags,
|
||||
krb5_ccache ccache,
|
||||
struct krb5_fast_state *fast_state,
|
||||
krb5_creds *in_creds,
|
||||
krb5_principal impersonate_principal,
|
||||
Ticket *second_ticket,
|
||||
krb5_creds **out_creds,
|
||||
krb5_creds ***ret_tgts)
|
||||
{
|
||||
char *kdc_hostname = NULL;
|
||||
char *sitename = NULL;
|
||||
krb5_error_code ret;
|
||||
krb5_deltat offset;
|
||||
krb5_data data;
|
||||
|
||||
/*
|
||||
* If we are using LKDC, lets pull out the addreses from the
|
||||
* ticket and use that.
|
||||
*/
|
||||
|
||||
ret = krb5_cc_get_config(context, ccache, NULL, "lkdc-hostname", &data);
|
||||
if (ret == 0) {
|
||||
kdc_hostname = malloc(data.length + 1);
|
||||
if (kdc_hostname == NULL)
|
||||
return krb5_enomem(context);
|
||||
|
||||
memcpy(kdc_hostname, data.data, data.length);
|
||||
kdc_hostname[data.length] = '\0';
|
||||
krb5_data_free(&data);
|
||||
}
|
||||
|
||||
ret = krb5_cc_get_config(context, ccache, NULL, "sitename", &data);
|
||||
if (ret == 0) {
|
||||
sitename = malloc(data.length + 1);
|
||||
if (sitename == NULL)
|
||||
return krb5_enomem(context);
|
||||
|
||||
memcpy(sitename, data.data, data.length);
|
||||
sitename[data.length] = '\0';
|
||||
krb5_data_free(&data);
|
||||
}
|
||||
|
||||
ret = krb5_cc_get_kdc_offset(context, ccache, &offset);
|
||||
if (ret == 0) {
|
||||
@@ -1219,24 +1415,36 @@ _krb5_get_cred_kdc_any(krb5_context context,
|
||||
*/
|
||||
ret = get_cred_kdc_capath(context,
|
||||
flags,
|
||||
ccache,
|
||||
in_creds,
|
||||
impersonate_principal,
|
||||
second_ticket,
|
||||
out_creds,
|
||||
ret_tgts);
|
||||
ccache,
|
||||
fast_state,
|
||||
in_creds,
|
||||
impersonate_principal,
|
||||
second_ticket,
|
||||
kdc_hostname,
|
||||
sitename,
|
||||
out_creds,
|
||||
ret_tgts);
|
||||
if (ret == 0 || skip_referrals(in_creds->server, &flags))
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Otherwise try referrals */
|
||||
return get_cred_kdc_referral(context,
|
||||
flags,
|
||||
ccache,
|
||||
in_creds,
|
||||
impersonate_principal,
|
||||
second_ticket,
|
||||
out_creds);
|
||||
ret = get_cred_kdc_referral(context,
|
||||
flags,
|
||||
ccache,
|
||||
fast_state,
|
||||
in_creds,
|
||||
impersonate_principal,
|
||||
second_ticket,
|
||||
kdc_hostname,
|
||||
sitename,
|
||||
out_creds);
|
||||
|
||||
out:
|
||||
free(kdc_hostname);
|
||||
free(sitename);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
@@ -1342,6 +1550,7 @@ krb5_get_credentials_with_flags(krb5_context context,
|
||||
krb5_creds *in_creds,
|
||||
krb5_creds **out_creds)
|
||||
{
|
||||
struct krb5_fast_state fast_state;
|
||||
krb5_error_code ret;
|
||||
krb5_name_canon_iterator name_canon_iter = NULL;
|
||||
krb5_name_canon_rule_options rule_opts;
|
||||
@@ -1351,6 +1560,8 @@ krb5_get_credentials_with_flags(krb5_context context,
|
||||
krb5_creds *res_creds;
|
||||
int i;
|
||||
|
||||
memset(&fast_state, 0, sizeof(fast_state));
|
||||
|
||||
if (_krb5_have_debug(context, 5)) {
|
||||
char *unparsed;
|
||||
|
||||
@@ -1380,7 +1591,7 @@ krb5_get_credentials_with_flags(krb5_context context,
|
||||
ret = krb5_name_canon_iterator_start(context, in_creds->server,
|
||||
&name_canon_iter);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
next_rule:
|
||||
krb5_free_cred_contents(context, res_creds);
|
||||
@@ -1416,7 +1627,7 @@ next_rule:
|
||||
options |= KRB5_GC_NO_STORE;
|
||||
|
||||
tgts = NULL;
|
||||
ret = _krb5_get_cred_kdc_any(context, flags, ccache,
|
||||
ret = _krb5_get_cred_kdc_any(context, flags, ccache, &fast_state,
|
||||
in_creds, NULL, NULL, out_creds, &tgts);
|
||||
for (i = 0; tgts && tgts[i]; i++) {
|
||||
if ((options & KRB5_GC_NO_STORE) == 0)
|
||||
@@ -1451,6 +1662,7 @@ out:
|
||||
in_creds->server = save_princ;
|
||||
krb5_free_creds(context, res_creds);
|
||||
krb5_free_name_canon_iterator(context, name_canon_iter);
|
||||
_krb5_fast_free(context, &fast_state);
|
||||
if (ret)
|
||||
return not_found(context, in_creds->server, ret);
|
||||
return 0;
|
||||
@@ -1569,6 +1781,7 @@ krb5_get_creds(krb5_context context,
|
||||
krb5_const_principal inprinc,
|
||||
krb5_creds **out_creds)
|
||||
{
|
||||
struct krb5_fast_state fast_state;
|
||||
krb5_kdc_flags flags;
|
||||
krb5_flags options;
|
||||
krb5_creds in_creds;
|
||||
@@ -1582,6 +1795,7 @@ krb5_get_creds(krb5_context context,
|
||||
int type;
|
||||
const char *comp;
|
||||
|
||||
memset(&fast_state, 0, sizeof(fast_state));
|
||||
memset(&in_creds, 0, sizeof(in_creds));
|
||||
in_creds.server = rk_UNCONST(inprinc);
|
||||
|
||||
@@ -1683,7 +1897,7 @@ next_rule:
|
||||
flags.b.request_anonymous = 1;
|
||||
|
||||
tgts = NULL;
|
||||
ret = _krb5_get_cred_kdc_any(context, flags, ccache,
|
||||
ret = _krb5_get_cred_kdc_any(context, flags, ccache, &fast_state,
|
||||
&in_creds, opt ? opt->self : 0,
|
||||
opt ? opt->ticket : 0, out_creds,
|
||||
&tgts);
|
||||
@@ -1717,6 +1931,7 @@ next_rule:
|
||||
}
|
||||
|
||||
out:
|
||||
_krb5_fast_free(context, &fast_state);
|
||||
krb5_free_creds(context, res_creds);
|
||||
krb5_free_principal(context, in_creds.client);
|
||||
krb5_free_name_canon_iterator(context, name_canon_iter);
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -136,6 +136,8 @@ struct ContentInfo;
|
||||
struct AlgorithmIdentifier;
|
||||
typedef struct krb5_pk_init_ctx_data *krb5_pk_init_ctx;
|
||||
struct krb5_dh_moduli;
|
||||
struct krb5_fast_state;
|
||||
struct krb5_gss_init_ctx_data;
|
||||
|
||||
/* v4 glue */
|
||||
struct _krb5_krb_auth_data;
|
||||
@@ -163,6 +165,7 @@ typedef krb5_error_code (KRB5_LIB_CALL *krb5_gssic_step)(
|
||||
krb5_context,
|
||||
krb5_gss_init_ctx,
|
||||
const krb5_creds *,
|
||||
struct gss_ctx_id_t_desc_struct **,
|
||||
KDCOptions options,
|
||||
krb5_data *,
|
||||
krb5_data *,
|
||||
@@ -172,6 +175,7 @@ typedef krb5_error_code (KRB5_LIB_CALL *krb5_gssic_finish)(
|
||||
krb5_context,
|
||||
krb5_gss_init_ctx,
|
||||
const krb5_creds *,
|
||||
struct gss_ctx_id_t_desc_struct *,
|
||||
krb5int32,
|
||||
krb5_enctype,
|
||||
krb5_principal *,
|
||||
@@ -187,10 +191,14 @@ typedef void (KRB5_LIB_CALL *krb5_gssic_delete_sec_context)(
|
||||
krb5_gss_init_ctx,
|
||||
struct gss_ctx_id_t_desc_struct *);
|
||||
|
||||
#define KRB5_GSS_IC_FLAG_RELEASE_CRED 1
|
||||
|
||||
#include <krb5-private.h>
|
||||
|
||||
#include "heim_threads.h"
|
||||
|
||||
extern const char _krb5_wellknown_lkdc[];
|
||||
|
||||
#define ALLOC(X, N) (X) = calloc((N), sizeof(*(X)))
|
||||
#define ALLOC_SEQ(X, N) do { (X)->len = (N); ALLOC((X)->val, (N)); } while(0)
|
||||
|
||||
@@ -246,10 +254,11 @@ struct _krb5_get_init_creds_opt_private {
|
||||
krb5_pk_init_ctx pk_init_ctx;
|
||||
krb5_get_init_creds_tristate addressless;
|
||||
int flags;
|
||||
#define KRB5_INIT_CREDS_CANONICALIZE 1
|
||||
#define KRB5_INIT_CREDS_NO_C_CANON_CHECK 2
|
||||
#define KRB5_INIT_CREDS_NO_C_NO_EKU_CHECK 4
|
||||
#define KRB5_INIT_CREDS_PKINIT_KX_VALID 32
|
||||
#define KRB5_INIT_CREDS_DONE 1
|
||||
#define KRB5_INIT_CREDS_CANONICALIZE 2
|
||||
#define KRB5_INIT_CREDS_NO_C_CANON_CHECK 4
|
||||
#define KRB5_INIT_CREDS_NO_C_NO_EKU_CHECK 8
|
||||
#define KRB5_INIT_CREDS_PKINIT_KX_VALID 32
|
||||
#define KRB5_INIT_CREDS_PKINIT_NO_KRBTGT_OTHERNAME_CHECK 64
|
||||
struct {
|
||||
krb5_gic_process_last_req func;
|
||||
@@ -421,6 +430,45 @@ struct krb5_pk_init_ctx_data {
|
||||
|
||||
#endif /* PKINIT */
|
||||
|
||||
struct krb5_fast_state {
|
||||
enum PA_FX_FAST_REQUEST_enum type;
|
||||
unsigned int flags;
|
||||
#define KRB5_FAST_REPLY_KEY_USE_TO_ENCRYPT_THE_REPLY 0x0001
|
||||
#define KRB5_FAST_REPLY_KEY_USE_IN_TRANSACTION 0x0002
|
||||
#define KRB5_FAST_KDC_REPLY_KEY_REPLACED 0x0004
|
||||
#define KRB5_FAST_REPLY_REPLY_VERIFIED 0x0008
|
||||
#define KRB5_FAST_STRONG 0x0010
|
||||
#define KRB5_FAST_EXPECTED 0x0020 /* in exchange with KDC, fast was discovered */
|
||||
#define KRB5_FAST_REQUIRED 0x0040 /* fast required by action of caller */
|
||||
#define KRB5_FAST_DISABLED 0x0080
|
||||
|
||||
#define KRB5_FAST_AP_ARMOR_SERVICE 0x0100
|
||||
#define KRB5_FAST_OPTIMISTIC 0x0200 /* Optimistic try, like Anon + PKINIT or service fast bit */
|
||||
#define KRB5_FAST_REQUIRE_ENC_PA 0x0400
|
||||
|
||||
#define KRB5_FAST_AS_REQ 0x1000
|
||||
#define KRB5_FAST_ANON_PKINIT_ARMOR 0x2000
|
||||
#define KRB5_FAST_KDC_VERIFIED 0x4000
|
||||
|
||||
krb5_keyblock *reply_key;
|
||||
krb5_ccache armor_ccache;
|
||||
krb5_auth_context armor_ac;
|
||||
KrbFastArmor *armor_data;
|
||||
krb5_principal armor_service;
|
||||
krb5_crypto armor_crypto;
|
||||
krb5_keyblock armor_key;
|
||||
krb5_keyblock *strengthen_key;
|
||||
|
||||
/* KRB5_FAST_ANON_PKINIT_ARMOR */
|
||||
krb5_get_init_creds_opt *anon_pkinit_opt;
|
||||
krb5_init_creds_context anon_pkinit_ctx;
|
||||
};
|
||||
|
||||
struct krb5_decrypt_tkt_with_subkey_state {
|
||||
krb5_keyblock *subkey;
|
||||
struct krb5_fast_state *fast_state;
|
||||
};
|
||||
|
||||
#define ISTILDE(x) (x == '~')
|
||||
#ifdef _WIN32
|
||||
# define ISPATHSEP(x) (x == '/' || x =='\\')
|
||||
|
@@ -65,7 +65,7 @@ is_invalid_tld_srv_target(const char *target)
|
||||
|
||||
static krb5_error_code
|
||||
srv_find_realm(krb5_context context, krb5_krbhst_info ***res, int *count,
|
||||
const char *realm, const char *dns_type,
|
||||
const char *realm, const char *dns_type, const char *sitename,
|
||||
const char *proto, const char *service, int port)
|
||||
{
|
||||
char domain[1024];
|
||||
@@ -93,7 +93,11 @@ srv_find_realm(krb5_context context, krb5_krbhst_info ***res, int *count,
|
||||
else
|
||||
def_port = port;
|
||||
|
||||
snprintf(domain, sizeof(domain), "_%s._%s.%s.", service, proto, realm);
|
||||
if (sitename)
|
||||
snprintf(domain, sizeof(domain), "_%s._%s.%s._sites.%s.",
|
||||
service, proto, sitename, realm);
|
||||
else
|
||||
snprintf(domain, sizeof(domain), "_%s._%s.%s.", service, proto, realm);
|
||||
|
||||
r = rk_dns_lookup(domain, dns_type);
|
||||
if(r == NULL) {
|
||||
@@ -169,19 +173,23 @@ struct krb5_krbhst_data {
|
||||
unsigned int flags;
|
||||
int def_port;
|
||||
int port; /* hardwired port number if != 0 */
|
||||
#define KD_CONFIG 1
|
||||
#define KD_SRV_UDP 2
|
||||
#define KD_SRV_TCP 4
|
||||
#define KD_SRV_HTTP 8
|
||||
#define KD_FALLBACK 16
|
||||
#define KD_CONFIG_EXISTS 32
|
||||
#define KD_LARGE_MSG 64
|
||||
#define KD_PLUGIN 128
|
||||
#define KD_HOSTNAMES 256
|
||||
#define KD_CONFIG 0x0001
|
||||
#define KD_SRV_UDP 0x0002
|
||||
#define KD_SRV_TCP 0x0004
|
||||
#define KD_SITE_SRV_UDP 0x0008
|
||||
#define KD_SITE_SRV_TCP 0x0010
|
||||
#define KD_SRV_HTTP 0x0020
|
||||
#define KD_SRV_KKDCP 0x0040
|
||||
#define KD_FALLBACK 0x0080
|
||||
#define KD_CONFIG_EXISTS 0x0100
|
||||
#define KD_LARGE_MSG 0x0200
|
||||
#define KD_PLUGIN 0x0400
|
||||
#define KD_HOSTNAMES 0x0800
|
||||
krb5_error_code (*get_next)(krb5_context, struct krb5_krbhst_data *,
|
||||
krb5_krbhst_info**);
|
||||
|
||||
char *hostname;
|
||||
char *sitename;
|
||||
unsigned int fallback_count;
|
||||
|
||||
struct krb5_krbhst_info *hosts, **index, **end;
|
||||
@@ -434,7 +442,7 @@ get_next(struct krb5_krbhst_data *kd, krb5_krbhst_info **host)
|
||||
|
||||
static void
|
||||
srv_get_hosts(krb5_context context, struct krb5_krbhst_data *kd,
|
||||
const char *proto, const char *service)
|
||||
const char *sitename, const char *proto, const char *service)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
krb5_krbhst_info **res;
|
||||
@@ -443,8 +451,8 @@ srv_get_hosts(krb5_context context, struct krb5_krbhst_data *kd,
|
||||
if (krb5_realm_is_lkdc(kd->realm))
|
||||
return;
|
||||
|
||||
ret = srv_find_realm(context, &res, &count, kd->realm, "SRV", proto, service,
|
||||
kd->port);
|
||||
ret = srv_find_realm(context, &res, &count, kd->realm, "SRV",
|
||||
sitename, proto, service, kd->port);
|
||||
_krb5_debug(context, 2, "searching DNS for realm %s %s.%s -> %d",
|
||||
kd->realm, proto, service, ret);
|
||||
if (ret)
|
||||
@@ -755,21 +763,28 @@ kdc_get_next(krb5_context context,
|
||||
}
|
||||
|
||||
if(context->srv_lookup) {
|
||||
if(kd->sitename && (kd->flags & KD_SITE_SRV_TCP) == 0) {
|
||||
srv_get_hosts(context, kd, kd->sitename, "tcp", "kerberos");
|
||||
kd->flags |= KD_SITE_SRV_TCP;
|
||||
if(get_next(kd, host))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if((kd->flags & KD_SRV_UDP) == 0 && (kd->flags & KD_LARGE_MSG) == 0) {
|
||||
srv_get_hosts(context, kd, "udp", kd->srv_label);
|
||||
srv_get_hosts(context, kd, NULL, "udp", kd->srv_label);
|
||||
kd->flags |= KD_SRV_UDP;
|
||||
if(get_next(kd, host))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if((kd->flags & KD_SRV_TCP) == 0) {
|
||||
srv_get_hosts(context, kd, "tcp", kd->srv_label);
|
||||
srv_get_hosts(context, kd, NULL, "tcp", kd->srv_label);
|
||||
kd->flags |= KD_SRV_TCP;
|
||||
if(get_next(kd, host))
|
||||
return 0;
|
||||
}
|
||||
if((kd->flags & KD_SRV_HTTP) == 0) {
|
||||
srv_get_hosts(context, kd, "http", kd->srv_label);
|
||||
srv_get_hosts(context, kd, NULL, "http", kd->srv_label);
|
||||
kd->flags |= KD_SRV_HTTP;
|
||||
if(get_next(kd, host))
|
||||
return 0;
|
||||
@@ -821,7 +836,7 @@ admin_get_next(krb5_context context,
|
||||
|
||||
if(context->srv_lookup) {
|
||||
if((kd->flags & KD_SRV_TCP) == 0) {
|
||||
srv_get_hosts(context, kd, "tcp", kd->srv_label);
|
||||
srv_get_hosts(context, kd, NULL, "tcp", kd->srv_label);
|
||||
kd->flags |= KD_SRV_TCP;
|
||||
if(get_next(kd, host))
|
||||
return 0;
|
||||
@@ -875,13 +890,13 @@ kpasswd_get_next(krb5_context context,
|
||||
|
||||
if(context->srv_lookup) {
|
||||
if((kd->flags & KD_SRV_UDP) == 0) {
|
||||
srv_get_hosts(context, kd, "udp", kd->srv_label);
|
||||
srv_get_hosts(context, kd, NULL, "udp", kd->srv_label);
|
||||
kd->flags |= KD_SRV_UDP;
|
||||
if(get_next(kd, host))
|
||||
return 0;
|
||||
}
|
||||
if((kd->flags & KD_SRV_TCP) == 0) {
|
||||
srv_get_hosts(context, kd, "tcp", kd->srv_label);
|
||||
srv_get_hosts(context, kd, NULL, "tcp", kd->srv_label);
|
||||
kd->flags |= KD_SRV_TCP;
|
||||
if(get_next(kd, host))
|
||||
return 0;
|
||||
@@ -917,6 +932,8 @@ krbhost_dealloc(void *ptr)
|
||||
}
|
||||
if (handle->hostname)
|
||||
free(handle->hostname);
|
||||
if (handle->sitename)
|
||||
free(handle->sitename);
|
||||
|
||||
free(handle->realm);
|
||||
}
|
||||
@@ -1089,6 +1106,19 @@ krb5_krbhst_set_hostname(krb5_context context,
|
||||
return 0;
|
||||
}
|
||||
|
||||
krb5_error_code KRB5_LIB_FUNCTION
|
||||
krb5_krbhst_set_sitename(krb5_context context,
|
||||
krb5_krbhst_handle handle,
|
||||
const char *sitename)
|
||||
{
|
||||
if (handle->sitename)
|
||||
free(handle->sitename);
|
||||
handle->sitename = strdup(sitename);
|
||||
if (handle->sitename == NULL)
|
||||
return krb5_enomem(context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
KRB5_LIB_FUNCTION void KRB5_LIB_CALL
|
||||
krb5_krbhst_reset(krb5_context context, krb5_krbhst_handle handle)
|
||||
{
|
||||
|
@@ -607,6 +607,8 @@ EXPORTS
|
||||
krb5_sendto_ctx_set_type
|
||||
krb5_sendto_kdc
|
||||
krb5_sendto_kdc_flags
|
||||
krb5_sendto_set_hostname
|
||||
krb5_sendto_set_sitename
|
||||
krb5_set_config
|
||||
krb5_set_config_files
|
||||
krb5_set_debug_dest
|
||||
@@ -799,10 +801,13 @@ EXPORTS
|
||||
_krb5_init_creds_get_gss_mechanism
|
||||
_krb5_init_creds_set_gss_cred
|
||||
_krb5_init_creds_get_gss_cred
|
||||
_krb5_init_creds_set_gss_context
|
||||
_krb5_init_creds_get_gss_context
|
||||
_krb5_init_creds_init_gss
|
||||
|
||||
; Private init_creds API
|
||||
_krb5_init_creds_get_cred_starttime
|
||||
_krb5_init_creds_get_cred_endtime
|
||||
_krb5_init_creds_get_cred_client
|
||||
|
||||
; Shared with libkadm5
|
||||
_krb5_load_plugins
|
||||
_krb5_unload_plugins
|
||||
@@ -834,6 +839,8 @@ EXPORTS
|
||||
_krb5_HMAC_MD5_checksum
|
||||
_krb5_crypto_set_flags
|
||||
_krb5_expand_path_tokens ;!
|
||||
_krb5_make_pa_enc_challenge
|
||||
_krb5_validate_pa_enc_challenge
|
||||
|
||||
; kinit helper
|
||||
krb5_get_init_creds_opt_set_pkinit_user_certs
|
||||
@@ -842,14 +849,17 @@ EXPORTS
|
||||
krb5_auth_con_getsendsubkey
|
||||
krb5_init_creds_free
|
||||
krb5_init_creds_get
|
||||
krb5_init_creds_get_as_reply_key
|
||||
krb5_init_creds_get_creds
|
||||
krb5_init_creds_get_error
|
||||
krb5_init_creds_init
|
||||
krb5_init_creds_set_fast_anon_pkinit
|
||||
krb5_init_creds_set_fast_ccache
|
||||
krb5_init_creds_set_keytab
|
||||
krb5_init_creds_set_kdc_hostname
|
||||
krb5_init_creds_set_password
|
||||
krb5_init_creds_set_service
|
||||
krb5_init_creds_set_sitename
|
||||
krb5_init_creds_step
|
||||
krb5_init_creds_store
|
||||
krb5_process_last_request
|
||||
|
@@ -151,6 +151,7 @@ struct krb5_sendto_ctx_data {
|
||||
krb5_sendto_ctx_func func;
|
||||
void *data;
|
||||
char *hostname;
|
||||
char *sitename;
|
||||
krb5_krbhst_handle krbhst;
|
||||
|
||||
/* context2 */
|
||||
@@ -181,6 +182,8 @@ dealloc_sendto_ctx(void *ptr)
|
||||
krb5_sendto_ctx ctx = (krb5_sendto_ctx)ptr;
|
||||
if (ctx->hostname)
|
||||
free(ctx->hostname);
|
||||
if (ctx->sitename)
|
||||
free(ctx->sitename);
|
||||
heim_release(ctx->hosts);
|
||||
heim_release(ctx->krbhst);
|
||||
}
|
||||
@@ -244,15 +247,28 @@ krb5_sendto_set_hostname(krb5_context context,
|
||||
* disposing of any previous value after.
|
||||
*/
|
||||
newname = strdup(hostname);
|
||||
if (newname == NULL) {
|
||||
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
|
||||
return ENOMEM;
|
||||
}
|
||||
if (newname == NULL)
|
||||
return krb5_enomem(context);
|
||||
free(ctx->hostname);
|
||||
ctx->hostname = newname;
|
||||
return 0;
|
||||
}
|
||||
|
||||
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
|
||||
krb5_sendto_set_sitename(krb5_context context,
|
||||
krb5_sendto_ctx ctx,
|
||||
const char *sitename)
|
||||
{
|
||||
char *newname;
|
||||
|
||||
newname = strdup(sitename);
|
||||
if (newname == NULL)
|
||||
return krb5_enomem(context);
|
||||
free(ctx->sitename);
|
||||
ctx->sitename = newname;
|
||||
return 0;
|
||||
}
|
||||
|
||||
KRB5_LIB_FUNCTION void KRB5_LIB_CALL
|
||||
_krb5_sendto_ctx_set_krb5hst(krb5_context context,
|
||||
krb5_sendto_ctx ctx,
|
||||
@@ -1189,7 +1205,11 @@ krb5_sendto_context(krb5_context context,
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ctx->sitename) {
|
||||
ret = krb5_krbhst_set_sitename(context, handle, ctx->sitename);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
handle = heim_retain(ctx->krbhst);
|
||||
}
|
||||
@@ -1266,6 +1286,24 @@ krb5_sendto_context(krb5_context context,
|
||||
&ctx->response, &action);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* If we are not done, ask to continue/reset
|
||||
*/
|
||||
switch (action) {
|
||||
case KRB5_SENDTO_DONE:
|
||||
break;
|
||||
case KRB5_SENDTO_RESET:
|
||||
case KRB5_SENDTO_CONTINUE:
|
||||
/* free response to clear it out so we don't loop */
|
||||
krb5_data_free(&ctx->response);
|
||||
break;
|
||||
default:
|
||||
ret = KRB5_KDC_UNREACH;
|
||||
krb5_set_error_message(context, ret,
|
||||
"sendto filter funcation return unsupported state: %d", (int)action);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case KRB5_SENDTO_FAILED:
|
||||
|
@@ -600,6 +600,8 @@ HEIMDAL_KRB5_2.0 {
|
||||
krb5_sendto_ctx_set_type;
|
||||
krb5_sendto_kdc;
|
||||
krb5_sendto_kdc_flags;
|
||||
krb5_sendto_set_hostname;
|
||||
krb5_sendto_set_sitename;
|
||||
krb5_set_config;
|
||||
krb5_set_config_files;
|
||||
krb5_set_debug_dest;
|
||||
@@ -791,10 +793,13 @@ HEIMDAL_KRB5_2.0 {
|
||||
_krb5_init_creds_get_gss_mechanism;
|
||||
_krb5_init_creds_set_gss_cred;
|
||||
_krb5_init_creds_get_gss_cred;
|
||||
_krb5_init_creds_set_gss_context;
|
||||
_krb5_init_creds_get_gss_context;
|
||||
_krb5_init_creds_init_gss;
|
||||
|
||||
# Private init_creds API
|
||||
_krb5_init_creds_get_cred_starttime;
|
||||
_krb5_init_creds_get_cred_endtime;
|
||||
_krb5_init_creds_get_cred_client;
|
||||
|
||||
# Shared with libkadm5
|
||||
_krb5_load_plugins;
|
||||
_krb5_unload_plugins;
|
||||
@@ -824,6 +829,8 @@ HEIMDAL_KRB5_2.0 {
|
||||
_krb5_s4u2self_to_checksumdata;
|
||||
_krb5_HMAC_MD5_checksum;
|
||||
_krb5_crypto_set_flags;
|
||||
_krb5_make_pa_enc_challenge;
|
||||
_krb5_validate_pa_enc_challenge;
|
||||
|
||||
# kinit helper
|
||||
krb5_get_init_creds_opt_set_pkinit_user_certs;
|
||||
@@ -834,10 +841,13 @@ HEIMDAL_KRB5_2.0 {
|
||||
krb5_init_creds_set_fast_anon_pkinit;
|
||||
krb5_init_creds_set_fast_ccache;
|
||||
krb5_init_creds_set_keytab;
|
||||
krb5_init_creds_set_kdc_hostname;
|
||||
krb5_init_creds_get;
|
||||
krb5_init_creds_get_as_reply_key;
|
||||
krb5_init_creds_get_creds;
|
||||
krb5_init_creds_get_error;
|
||||
krb5_init_creds_set_password;
|
||||
krb5_init_creds_set_sitename;
|
||||
krb5_init_creds_step;
|
||||
krb5_init_creds_store;
|
||||
krb5_init_creds_free;
|
||||
|
Reference in New Issue
Block a user