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) {
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_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_init_creds_set_fast_ccache");
+ 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));
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;
}
}
+ 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");
}
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) {
krb5_cc_destroy(context, tempccache);
if (enctype)
free(enctype);
+ if (fastid)
+ krb5_cc_close(context, fastid);
return ret;
}
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));
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
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);
#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
krb5_gic_process_last_req func;
void *ctx;
} lr;
+
+ krb5_flags fast_flags;
+ char *fast_armor_ccache_name;
};
typedef uint32_t krb5_enctype_set;
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
+#define KRB5_FAST_PUBLIC_FLAGS 0x0000ff
+/* #define KRB5_FAST_REQUIRED 0x000001 - fast required by action of caller defined in krb5.h*/
+
+#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_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;
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
&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);
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);
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);
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");
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);
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");
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");
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);
}
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;