#define KRB5_CONF_V4_INSTANCE_CONVERT "v4_instance_convert"
#define KRB5_CONF_V4_REALM "v4_realm"
#define KRB5_CONF_ASTERISK "*"
+
+/* Cache configuration variables */
#define KRB5_CONF_FAST_AVAIL "fast_avail"
+#define KRB5_CONF_PROXY_IMPERSONATOR "proxy_impersonator"
/* Error codes used in KRB_ERROR protocol messages.
Return values of library routines are based on a different error table
return 0;
}
+/* If an impersonator config entry exists in ccache, set *impersonator_out to
+ * the parsed principal. Otherwise set *impersonator_out to NULL. */
+static krb5_error_code
+get_impersonator(krb5_context context, krb5_ccache ccache,
+ krb5_principal *impersonator_out)
+{
+ krb5_error_code code;
+ krb5_data data = empty_data(), data0 = empty_data();
+
+ *impersonator_out = NULL;
+
+ code = krb5_cc_get_config(context, ccache, NULL,
+ KRB5_CONF_PROXY_IMPERSONATOR, &data);
+ if (code)
+ return (code == KRB5_CC_NOTFOUND) ? 0 : code;
+
+ code = krb5int_copy_data_contents_add0(context, &data, &data0);
+ if (code)
+ goto cleanup;
+
+ code = krb5_parse_name(context, data0.data, impersonator_out);
+
+cleanup:
+ krb5_free_data_contents(context, &data);
+ krb5_free_data_contents(context, &data0);
+ return code;
+}
+
/* Check ccache and scan it for its expiry time. On success, cred takes
* ownership of ccache. */
static krb5_error_code
goto cleanup;
}
+ code = get_impersonator(context, ccache, &cred->impersonator);
+ if (code)
+ goto cleanup;
+
(void)krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
cred->ccache = ccache;
cred->usage = args->cred_usage;
cred->name = NULL;
+ cred->impersonator = NULL;
cred->iakerb_mech = args->iakerb;
cred->default_identity = (name == NULL);
#ifndef LEAN_CLIENT
/* name/type of credential */
gss_cred_usage_t usage;
krb5_gss_name_t name;
- unsigned int proxy_cred : 1;
+ krb5_principal impersonator;
unsigned int default_identity : 1;
unsigned int iakerb_mech : 1;
unsigned int destroy_ccache : 1;
krb5_error_code code;
krb5_creds in_creds, evidence_creds, *result_creds = NULL;
krb5_flags flags = 0;
- krb5_principal cc_princ = NULL;
*out_creds = NULL;
assert(cred->name != NULL);
- if ((code = krb5_cc_get_principal(context, cred->ccache, &cc_princ)))
- goto cleanup;
-
/*
* Do constrained delegation if we have proxy credentials and
* we're not trying to get a ticket to ourselves (in which case
* we can just use the S4U2Self or evidence ticket directly).
*/
- if (cred->proxy_cred &&
- !krb5_principal_compare(context, cc_princ, server->princ)) {
+ if (cred->impersonator &&
+ !krb5_principal_compare(context, cred->impersonator, server->princ)) {
krb5_creds mcreds;
flags |= KRB5_GC_CANONICALIZE |
memset(&mcreds, 0, sizeof(mcreds));
mcreds.magic = KV5M_CREDS;
- mcreds.times.endtime = cred->tgt_expire;
- mcreds.server = cc_princ;
+ mcreds.server = cred->impersonator;
mcreds.client = cred->name->princ;
code = krb5_cc_retrieve_cred(context, cred->ccache,
- KRB5_TC_MATCH_TIMES | KRB5_TC_MATCH_AUTHDATA,
- &mcreds,
+ KRB5_TC_MATCH_AUTHDATA, &mcreds,
&evidence_creds);
if (code)
goto cleanup;
assert(evidence_creds.ticket_flags & TKT_FLG_FORWARDABLE);
- in_creds.client = cc_princ;
+ in_creds.client = cred->impersonator;
in_creds.second_ticket = evidence_creds.ticket;
} else {
in_creds.client = cred->name->princ;
cleanup:
krb5_free_authdata(context, in_creds.authdata);
- krb5_free_principal(context, cc_princ);
krb5_free_cred_contents(context, &evidence_creds);
krb5_free_creds(context, result_creds);
if (cred->name)
kg_release_name(context, &cred->name);
+ krb5_free_principal(context, cred->impersonator);
+
if (cred->req_enctypes)
free(cred->req_enctypes);
}
+/*
+ * Set up cred to be an S4U2Proxy credential by copying in the impersonator's
+ * creds, setting a cache config variable with the impersonator principal name,
+ * and saving the impersonator principal name in the cred structure.
+ */
+static krb5_error_code
+make_proxy_cred(krb5_context context, krb5_gss_cred_id_t cred,
+ krb5_gss_cred_id_t impersonator_cred)
+{
+ krb5_error_code code;
+ krb5_data data;
+ char *str;
+
+ code = krb5_cc_copy_creds(context, impersonator_cred->ccache,
+ cred->ccache);
+ if (code)
+ return code;
+
+ code = krb5_unparse_name(context, impersonator_cred->name->princ, &str);
+ if (code)
+ return code;
+
+ data = string2data(str);
+ code = krb5_cc_set_config(context, cred->ccache, NULL,
+ KRB5_CONF_PROXY_IMPERSONATOR, &data);
+ krb5_free_unparsed_name(context, str);
+ if (code)
+ return code;
+
+ return krb5_copy_principal(context, impersonator_cred->name->princ,
+ &cred->impersonator);
+}
+
OM_uint32
kg_compose_deleg_cred(OM_uint32 *minor_status,
krb5_gss_cred_id_t impersonator_cred,
if (!kg_is_initiator_cred(impersonator_cred) ||
impersonator_cred->name == NULL ||
- impersonator_cred->proxy_cred) {
+ impersonator_cred->impersonator != NULL) {
code = G_BAD_USAGE;
goto cleanup;
}
if (code != 0)
goto cleanup;
- /*
- * Only return a "proxy" credential for use with constrained
- * delegation if the subject credentials are forwardable.
- * Submitting non-forwardable credentials to the KDC for use
- * with constrained delegation will only return an error.
- */
cred->usage = GSS_C_INITIATE;
- cred->proxy_cred = !!(subject_creds->ticket_flags & TKT_FLG_FORWARDABLE);
cred->tgt_expire = subject_creds->times.endtime;
goto cleanup;
cred->destroy_ccache = 1;
- code = krb5_cc_initialize(context, cred->ccache,
- cred->proxy_cred ? impersonator_cred->name->princ :
- subject_creds->client);
+ code = krb5_cc_initialize(context, cred->ccache, subject_creds->client);
if (code != 0)
goto cleanup;
- if (cred->proxy_cred) {
- /* Impersonator's TGT will be necessary for S4U2Proxy */
- code = krb5_cc_copy_creds(context, impersonator_cred->ccache,
- cred->ccache);
+ /*
+ * Only return a "proxy" credential for use with constrained
+ * delegation if the subject credentials are forwardable.
+ * Submitting non-forwardable credentials to the KDC for use
+ * with constrained delegation will only return an error.
+ */
+ if (subject_creds->ticket_flags & TKT_FLG_FORWARDABLE) {
+ code = make_proxy_cred(context, cred, impersonator_cred);
if (code != 0)
goto cleanup;
}
kcred = (krb5_gss_cred_id_t)input_cred_handle;
- if (kcred->ccache == NULL || kcred->proxy_cred) {
+ if (kcred->ccache == NULL) {
*minor_status = KG_CCACHE_NOMATCH;
major_status = GSS_S_DEFECTIVE_CREDENTIAL;
goto cleanup;
*minor_status = code;
return(GSS_S_DEFECTIVE_CREDENTIAL);
}
- if (!cred->proxy_cred &&
- !krb5_principal_compare(context, princ, cred->name->princ)) {
+ if (!krb5_principal_compare(context, princ, cred->name->princ)) {
k5_mutex_unlock(&cred->lock);
*minor_status = KG_CCACHE_NOMATCH;
return(GSS_S_DEFECTIVE_CREDENTIAL);