+/* Return true if auto_fast_armor is enabled for realm. */
+static krb5_boolean
+auto_fast_armor_enabled(profile_t profile, const krb5_data *realm)
+{
+ krb5_error_code ret;
+ char *realmstr;
+ int bval;
+
+ realmstr = k5memdup0(realm->data, realm->length, &ret);
+ if (realmstr == NULL)
+ return FALSE;
+ ret = profile_get_boolean(profile, KRB5_CONF_REALMS, realmstr,
+ KRB5_CONF_AUTO_FAST_ARMOR, FALSE, &bval);
+ free(realmstr);
+ return (ret == 0) ? bval : FALSE;
+}
+
+/*
+ * Return true if ctx should first acquire FAST armor using anonymous PKINIT.
+ * This decision is primarily dependent on the auto_fast_armor config option,
+ * but we don't acquire armor if the caller passed in an armor ccache or if the
+ * state machine is already performing an anonymous PKINIT request.
+ */
+static krb5_boolean
+want_auto_armor(krb5_context context, krb5_init_creds_context ctx)
+{
+ if (k5_gic_opt_get_fast_ccache_name(ctx->opt) != NULL)
+ return FALSE;
+ if (krb5_principal_compare_any_realm(context, ctx->request->client,
+ krb5_anonymous_principal()))
+ return FALSE;
+ return auto_fast_armor_enabled(context->profile,
+ &ctx->request->client->realm);
+}
+
+/* Create a memory ccache and nested init_creds context for acquiring FAST amor
+ * via anonymous PKINIT. */
+static krb5_error_code
+begin_auto_armor(krb5_context context, krb5_init_creds_context ctx)
+{
+ krb5_error_code ret;
+ krb5_principal anon_princ = NULL;
+ const krb5_data *realm = &ctx->request->client->realm;
+
+ TRACE_INIT_CREDS_AUTO_FAST_ARMOR(context);
+
+ ret = krb5_cc_new_unique(context, "MEMORY", NULL, &ctx->auto_armor_ccache);
+ if (ret)
+ goto cleanup;
+
+ ret = krb5_build_principal_ext(context, &anon_princ,
+ realm->length, realm->data,
+ strlen(KRB5_WELLKNOWN_NAMESTR),
+ KRB5_WELLKNOWN_NAMESTR,
+ strlen(KRB5_ANONYMOUS_PRINCSTR),
+ KRB5_ANONYMOUS_PRINCSTR, 0);
+ if (ret)
+ goto cleanup;
+ anon_princ->type = KRB5_NT_WELLKNOWN;
+
+ ret = krb5_get_init_creds_opt_alloc(context, &ctx->auto_armor_opt);
+ if (ret)
+ goto cleanup;
+ krb5_get_init_creds_opt_set_anonymous(ctx->auto_armor_opt, 1);
+ krb5_get_init_creds_opt_set_tkt_life(ctx->auto_armor_opt, 60 * 60);
+ ret = krb5_get_init_creds_opt_set_out_ccache(context, ctx->auto_armor_opt,
+ ctx->auto_armor_ccache);
+ if (ret)
+ goto cleanup;
+
+ ret = krb5_init_creds_init(context, anon_princ, NULL, NULL,
+ ctx->start_time, ctx->auto_armor_opt,
+ &ctx->auto_armor_ctx);
+ if (ret)
+ goto cleanup;
+
+cleanup:
+ krb5_free_principal(context, anon_princ);
+ return ret;
+}
+