1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-08 21:18:16 +03:00

third_party/heimdal: Provide krb5_init_creds_opt_set_fast_ccache() and krb5_init_creds_opt_set_fast_flags() (import lorikeet-heimdal-202311290114 (commit 4c8517e161396330c76240bf09609a0dd5f9ea20))

It is easier for external callers to manipulate the krb5_get_init_creds_opt
(via the helpers) as this is passed down from higher up than the krb5_init_creds_context.

And just as importantly, alignment with MIT makes end-user callers happier.

Finally, this resolves the ambiguity as to which layer owns the
krb5_ccache, because now we match the MIT behaviour the init_creds code
re-opens a private copy inside libkrb5, meaning the caller closes the
cache it opened, rather than handing it over to the library.

(The unrelated changes are fixes to the test_pac test, also included in this import,
but in distinct lorikeet-heimdal commits, to allow it to compile)

Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Joseph Sutton <josephsutton@catalyst.net.nz>
This commit is contained in:
Andrew Bartlett 2023-11-29 14:16:16 +13:00
parent a757a51a26
commit 6222d572ee
9 changed files with 161 additions and 49 deletions

View File

@ -258,10 +258,6 @@ eval_kinit(heim_dict_t o)
krb5_err(kdc_context, 1, ret, "krb5_get_init_creds_opt_set_pkinit");
}
ret = krb5_init_creds_init(kdc_context, client, NULL, NULL, 0, opt, &ctx);
if (ret)
krb5_err(kdc_context, 1, ret, "krb5_init_creds_init");
fast_armor_cc = heim_dict_get_value(o, HSTR("fast-armor-cc"));
if (fast_armor_cc) {
@ -269,13 +265,21 @@ eval_kinit(heim_dict_t o)
if (ret)
krb5_err(kdc_context, 1, ret, "krb5_cc_resolve");
ret = krb5_init_creds_set_fast_ccache(kdc_context, ctx, fast_cc);
ret = krb5_get_init_creds_opt_set_fast_ccache(kdc_context, opt, fast_cc);
if (ret)
krb5_err(kdc_context, 1, ret, "krb5_init_creds_set_fast_ccache");
krb5_err(kdc_context, 1, ret, "krb5_get_init_creds_set_fast_ccache");
ret = krb5_get_init_creds_opt_set_fast_flags(kdc_context, opt, KRB5_FAST_REQUIRED|KRB5_FAST_KDC_VERIFIED);
if (ret)
krb5_err(kdc_context, 1, ret, "krb5_get_init_creds_set_fast_ccache");
fast_cc = NULL;
}
ret = krb5_init_creds_init(kdc_context, client, NULL, NULL, 0, opt, &ctx);
if (ret)
krb5_err(kdc_context, 1, ret, "krb5_init_creds_init");
if (password) {
ret = krb5_init_creds_set_password(kdc_context, ctx,
heim_string_get_utf8(password));

View File

@ -742,6 +742,7 @@ get_new_tickets(krb5_context context,
gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL;
gss_OID gss_mech = GSS_C_NO_OID;
krb5_principal federated_name = NULL;
krb5_ccache fastid = NULL;
#ifndef NO_NTLM
struct ntlm_buf ntlmkey;
@ -970,6 +971,33 @@ get_new_tickets(krb5_context context,
}
}
if (fast_armor_cache_string) {
if (pk_anon_fast_armor > 0)
krb5_errx(context, 1,
N_("cannot specify FAST armor cache with FAST "
"anonymous PKINIT option", ""));
pk_anon_fast_armor = 0;
ret = krb5_cc_resolve(context, fast_armor_cache_string, &fastid);
if (ret) {
krb5_warn(context, ret, "krb5_cc_resolve(FAST cache)");
goto out;
}
ret = krb5_get_init_creds_opt_set_fast_ccache(context, opt, fastid);
if (ret) {
krb5_warn(context, ret, "krb5_init_creds_set_fast_ccache");
goto out;
}
ret = krb5_get_init_creds_opt_set_fast_flags(context, opt,
KRB5_FAST_REQUIRED);
if (ret) {
krb5_warn(context, ret, "krb5_init_creds_set_fast_flags");
goto out;
}
}
ret = krb5_init_creds_init(context, principal, prompter, NULL, start_time, opt, &ctx);
if (ret) {
krb5_warn(context, ret, "krb5_init_creds_init");
@ -1001,25 +1029,7 @@ get_new_tickets(krb5_context context,
}
if (fast_armor_cache_string) {
krb5_ccache fastid = NULL;
if (pk_anon_fast_armor > 0)
krb5_errx(context, 1,
N_("cannot specify FAST armor cache with FAST "
"anonymous PKINIT option", ""));
pk_anon_fast_armor = 0;
ret = krb5_cc_resolve(context, fast_armor_cache_string, &fastid);
if (ret) {
krb5_warn(context, ret, "krb5_cc_resolve(FAST cache)");
goto out;
}
ret = krb5_init_creds_set_fast_ccache(context, ctx, fastid);
if (ret) {
krb5_warn(context, ret, "krb5_init_creds_set_fast_ccache");
goto out;
}
/* handled above */
} else if (pk_anon_fast_armor == -1) {
ret = _krb5_init_creds_set_fast_anon_pkinit_optimistic(context, ctx);
if (ret) {
@ -1227,6 +1237,8 @@ out:
krb5_cc_destroy(context, tempccache);
if (enctype)
free(enctype);
if (fastid)
krb5_cc_close(context, fastid);
return ret;
}

View File

@ -89,6 +89,7 @@ krb5_get_init_creds_opt_free(krb5_context context,
return;
if (--opt->opt_private->refcount == 0) {
_krb5_get_init_creds_opt_free_pkinit(opt);
free(opt->opt_private->fast_armor_ccache_name);
free(opt->opt_private);
}
memset(opt, 0, sizeof(*opt));
@ -393,6 +394,51 @@ krb5_get_init_creds_opt_set_process_last_req(krb5_context context,
return 0;
}
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_get_init_creds_opt_set_fast_ccache(krb5_context context,
krb5_get_init_creds_opt *opt,
krb5_ccache fast_ccache)
{
char *fast_ccache_name;
int ret = krb5_cc_get_full_name(context,
fast_ccache,
&fast_ccache_name);
if (ret)
return ret;
ret = krb5_get_init_creds_opt_set_fast_ccache_name(context,
opt,
fast_ccache_name);
krb5_xfree(fast_ccache_name);
return ret;
}
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_get_init_creds_opt_set_fast_ccache_name(krb5_context context,
krb5_get_init_creds_opt *opt,
const char *fast_ccache_name)
{
if (opt->opt_private->fast_armor_ccache_name)
free(opt->opt_private->fast_armor_ccache_name);
opt->opt_private->fast_armor_ccache_name = strdup(fast_ccache_name);
if (opt->opt_private->fast_armor_ccache_name == NULL)
return krb5_enomem(context);
return 0;
}
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_get_init_creds_opt_set_fast_flags(krb5_context context,
krb5_get_init_creds_opt *opt,
krb5_flags flags)
{
heim_assert((flags & ~KRB5_FAST_PUBLIC_FLAGS) == 0, "invalid flags passed to krb5_get_init_creds_opt_set_fast_flags()");
opt->opt_private->fast_flags = flags;
return 0;
}
#ifndef HEIMDAL_SMALLER

View File

@ -579,6 +579,25 @@ get_init_creds_common(krb5_context context,
else
ctx->runflags.change_password_prompt = ctx->prompter != NULL;
if (options->opt_private->fast_armor_ccache_name) {
/* Open the caller-supplied FAST ccache and set the caller flags */
ret = krb5_cc_resolve(context, options->opt_private->fast_armor_ccache_name,
&ctx->fast_state.armor_ccache);
if (ret)
goto out;
}
ctx->fast_state.flags = options->opt_private->fast_flags;
/*
* If FAST is required with a real credential cache, then the KDC
* will be verified. This allows the
* krb5_get_init_creds_opt_set_fast API to work like MIT without
* exposing KRB5_FAST_KDC_VERIFIED to callers
*/
if (ctx->fast_state.flags & KRB5_FAST_REQUIRED)
ctx->fast_state.flags |= KRB5_FAST_KDC_VERIFIED;
out:
if (default_opt)
krb5_get_init_creds_opt_free(context, default_opt);

View File

@ -804,6 +804,8 @@ typedef struct _krb5_get_init_creds_opt krb5_get_init_creds_opt;
#define KRB5_GET_INIT_CREDS_OPT_DISABLE_TRANSITED_CHECK 0x0200
#define KRB5_GET_INIT_CREDS_OPT_CHANGE_PASSWORD_PROMPT 0x0400
#define KRB5_FAST_REQUIRED 0x0001 /* fast required by action of caller */
/* krb5_init_creds_step flags argument */
#define KRB5_INIT_CREDS_STEP_FLAG_CONTINUE 0x0001

View File

@ -263,6 +263,9 @@ struct _krb5_get_init_creds_opt_private {
krb5_gic_process_last_req func;
void *ctx;
} lr;
krb5_flags fast_flags;
char *fast_armor_ccache_name;
};
typedef uint32_t krb5_enctype_set;
@ -433,22 +436,24 @@ struct krb5_pk_init_ctx_data {
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_PUBLIC_FLAGS 0x0000ff
/* #define KRB5_FAST_REQUIRED 0x000001 - fast required by action of caller defined in krb5.h*/
#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_REPLY_KEY_USE_TO_ENCRYPT_THE_REPLY 0x000100
#define KRB5_FAST_REPLY_KEY_USE_IN_TRANSACTION 0x000200
#define KRB5_FAST_KDC_REPLY_KEY_REPLACED 0x000400
#define KRB5_FAST_REPLY_REPLY_VERIFIED 0x000800
#define KRB5_FAST_STRONG 0x001000
#define KRB5_FAST_EXPECTED 0x002000 /* in exchange with KDC, fast was discovered */
#define KRB5_FAST_DISABLED 0x008000
#define KRB5_FAST_AS_REQ 0x1000
#define KRB5_FAST_ANON_PKINIT_ARMOR 0x2000
#define KRB5_FAST_KDC_VERIFIED 0x4000
#define KRB5_FAST_AP_ARMOR_SERVICE 0x010000
#define KRB5_FAST_OPTIMISTIC 0x020000 /* Optimistic try, like Anon + PKINIT or service fast bit */
#define KRB5_FAST_REQUIRE_ENC_PA 0x040000
#define KRB5_FAST_AS_REQ 0x100000
#define KRB5_FAST_ANON_PKINIT_ARMOR 0x200000
#define KRB5_FAST_KDC_VERIFIED 0x400000
krb5_keyblock *reply_key;
krb5_ccache armor_ccache;

View File

@ -374,6 +374,9 @@ EXPORTS
krb5_get_init_creds_opt_set_salt
krb5_get_init_creds_opt_set_tkt_life
krb5_get_init_creds_opt_set_win2k
krb5_get_init_creds_opt_set_fast_ccache
krb5_get_init_creds_opt_set_fast_ccache_name
krb5_get_init_creds_opt_set_fast_flags
krb5_get_init_creds_password
krb5_get_instance
krb5_get_kdc_cred

View File

@ -872,8 +872,12 @@ check_ticket_signature(krb5_context context,
&ticket.sname) == !!signedticket,
"ticket-signature");
/*
* We have to not verify the KDC checksum as the saved PAC has no
* full checksum, and krb5_pac_verify requires this now
*/
ret = krb5_pac_verify(context, pac, et.authtime, client,
tkt->key, tkt->kdc_key);
tkt->key, NULL);
if (ret)
t_err(context, tkt->name, "krb5_pac_verify ticket-sig", ret);
@ -894,9 +898,13 @@ check_ticket_signature(krb5_context context,
if (ret)
t_err(context, tkt->name, "remove_AuthorizationData", ret);
/*
* While we should do a full PAC signature in the same case as
* signedticket, the saved examples do not have one
*/
ret = _krb5_kdc_pac_sign_ticket(context, pac, client, tkt->key,
tkt->kdc_key, tkt->rodc_id,
NULL, NULL, signedticket, &et, NULL);
NULL, NULL, signedticket, FALSE, &et, NULL);
if (ret)
t_err(context, tkt->name, "_krb5_kdc_pac_sign_ticket", ret);
@ -915,9 +923,14 @@ check_ticket_signature(krb5_context context,
if (ret)
t_err(context, tkt->name, "remove_AuthorizationData 2", ret);
/*
* This time we will not be doing a krb5_data_cmp() so we add the
* full signature so that we can run that check in
* krb5_pac_verify()
*/
ret = _krb5_kdc_pac_sign_ticket(context, pac, client, tkt->key,
tkt->kdc_key, tkt->rodc_id,
NULL, NULL, signedticket, &et, NULL);
NULL, NULL, signedticket, TRUE, &et, NULL);
if (ret)
t_err(context, tkt->name, "_krb5_kdcsignedticketsign_ticket 2", ret);
@ -1015,13 +1028,18 @@ main(int argc, char **argv)
if (ret)
krb5_err(context, 1, ret, "krb5_pac_parse");
/*
* We have to not verify the KDC checksum as the saved PAC has no
* full checksum, and krb5_pac_verify requires this now
*/
ret = krb5_pac_verify(context, pac, authtime, p,
&member_keyblock, &kdc_keyblock);
&member_keyblock, NULL);
if (ret)
krb5_err(context, 1, ret, "krb5_pac_verify");
ret = _krb5_pac_sign(context, pac, authtime, p,
&member_keyblock, &kdc_keyblock, 0, NULL, NULL,
TRUE,
NULL, &data);
if (ret)
krb5_err(context, 1, ret, "_krb5_pac_sign");
@ -1048,14 +1066,14 @@ main(int argc, char **argv)
if (ret)
krb5_err(context, 1, ret, "krb5_pac_init");
/* our two user buffer plus the three "system" buffers */
/* our two user buffer plus the four "system" buffers */
ret = krb5_pac_get_types(context, pac, &len, &list);
if (ret)
krb5_err(context, 1, ret, "krb5_pac_get_types");
for (i = 0; i < len; i++) {
/* skip server_cksum, privsvr_cksum, and logon_name */
if (list[i] == 6 || list[i] == 7 || list[i] == 10)
if (list[i] == 6 || list[i] == 7 || list[i] == 10 || list[i] == 19)
continue;
ret = krb5_pac_get_buffer(context, pac, list[i], &data);
@ -1079,7 +1097,7 @@ main(int argc, char **argv)
ret = _krb5_pac_sign(context, pac2, authtime, p,
&member_keyblock, &kdc_keyblock, 0,
NULL, NULL, NULL, &data);
NULL, NULL, TRUE, NULL, &data);
if (ret)
krb5_err(context, 1, ret, "_krb5_pac_sign 4");
@ -1179,7 +1197,7 @@ main(int argc, char **argv)
ret = _krb5_pac_sign(context, pac, authtime, p,
&member_keyblock, &kdc_keyblock, 0,
NULL, NULL, NULL, &data);
NULL, NULL, TRUE, NULL, &data);
if (ret)
krb5_err(context, 1, ret, "_krb5_pac_sign");
@ -1199,11 +1217,11 @@ main(int argc, char **argv)
uint32_t *list;
size_t len;
/* our two user buffer plus the three "system" buffers */
/* our two user buffer plus the four "system" buffers */
ret = krb5_pac_get_types(context, pac, &len, &list);
if (ret)
krb5_err(context, 1, ret, "krb5_pac_get_types");
if (len != 5)
if (len != 6)
krb5_errx(context, 1, "list wrong length");
free(list);
}

View File

@ -370,6 +370,9 @@ HEIMDAL_KRB5_2.0 {
krb5_get_init_creds_opt_set_salt;
krb5_get_init_creds_opt_set_tkt_life;
krb5_get_init_creds_opt_set_win2k;
krb5_get_init_creds_opt_set_fast_ccache;
krb5_get_init_creds_opt_set_fast_ccache_name;
krb5_get_init_creds_opt_set_fast_flags;
krb5_get_init_creds_password;
krb5_get_instance;
krb5_get_kdc_cred;