Skip to content

Commit

Permalink
Use cached S4U2Proxy tickets in GSSAPI
Browse files Browse the repository at this point in the history
Ticket #7047 allowed credentials obtain using S4U2Proxy through GSSAPI
to be cached, but doesn't actually use the cached credentials.  Modify
get_credentials() to check the cache for the desired client name
first, then to make an S4U2Proxy request if we don't find it.

Test this change by adding code to t_s4u.c to repeat the constrained
delegation request and verify that only three tickets are present in
the cache.

[ghudson@mit.edu: squash commits; commit message rewrite; minor style
edits; changed test code to use gss_store_cred_into() to avoid the
need to pick a principal to initialize the ccache with]

ticket: 8372 (new)
  • Loading branch information
iboukris authored and greghudson committed Feb 29, 2016
1 parent 01d2bd6 commit f149b9c
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 34 deletions.
71 changes: 37 additions & 34 deletions src/lib/gssapi/krb5/init_sec_context.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ static krb5_error_code get_credentials(context, cred, server, now,
krb5_creds **out_creds;
{
krb5_error_code code;
krb5_creds in_creds, evidence_creds, *result_creds = NULL;
krb5_creds in_creds, evidence_creds, mcreds, *result_creds = NULL;
krb5_flags flags = 0;

*out_creds = NULL;
Expand All @@ -139,37 +139,7 @@ static krb5_error_code get_credentials(context, cred, server, now,

assert(cred->name != NULL);

/*
* 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->impersonator &&
!krb5_principal_compare(context, cred->impersonator, server->princ)) {
krb5_creds mcreds;

flags |= KRB5_GC_CANONICALIZE | KRB5_GC_CONSTRAINED_DELEGATION;

memset(&mcreds, 0, sizeof(mcreds));

mcreds.magic = KV5M_CREDS;
mcreds.server = cred->impersonator;
mcreds.client = cred->name->princ;

code = krb5_cc_retrieve_cred(context, cred->ccache,
KRB5_TC_MATCH_AUTHDATA, &mcreds,
&evidence_creds);
if (code)
goto cleanup;

assert(evidence_creds.ticket_flags & TKT_FLG_FORWARDABLE);

in_creds.client = cred->impersonator;
in_creds.second_ticket = evidence_creds.ticket;
} else {
in_creds.client = cred->name->princ;
}

in_creds.client = cred->name->princ;
in_creds.server = server->princ;
in_creds.times.endtime = endtime;
in_creds.authdata = NULL;
Expand All @@ -188,12 +158,45 @@ static krb5_error_code get_credentials(context, cred, server, now,
goto cleanup;
}

/* Don't go out over the network if we used IAKERB */
if (cred->iakerb_mech)
/*
* For IAKERB or constrained delegation, only check the cache in this step.
* For IAKERB we will ask the server to make any necessary TGS requests;
* for constrained delegation we will adjust in_creds and make an S4U2Proxy
* request below if the cache lookup fails.
*/
if (cred->impersonator != NULL || cred->iakerb_mech)
flags |= KRB5_GC_CACHED;

code = krb5_get_credentials(context, flags, cred->ccache,
&in_creds, &result_creds);

/*
* Try constrained delegation if we have proxy credentials, unless
* we are trying to get a ticket to ourselves (in which case we could
* just use the evidence ticket directly from cache).
*/
if (code == KRB5_CC_NOTFOUND && cred->impersonator != NULL &&
!cred->iakerb_mech &&
!krb5_principal_compare(context, cred->impersonator, server->princ)) {

memset(&mcreds, 0, sizeof(mcreds));
mcreds.magic = KV5M_CREDS;
mcreds.server = cred->impersonator;
mcreds.client = cred->name->princ;
code = krb5_cc_retrieve_cred(context, cred->ccache,
KRB5_TC_MATCH_AUTHDATA, &mcreds,
&evidence_creds);
if (code)
goto cleanup;

assert(evidence_creds.ticket_flags & TKT_FLG_FORWARDABLE);
in_creds.client = cred->impersonator;
in_creds.second_ticket = evidence_creds.ticket;
flags = KRB5_GC_CANONICALIZE | KRB5_GC_CONSTRAINED_DELEGATION;
code = krb5_get_credentials(context, flags, cred->ccache,
&in_creds, &result_creds);
}

if (code)
goto cleanup;

Expand Down
66 changes: 66 additions & 0 deletions src/tests/gssapi/t_s4u.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,55 @@ init_accept_sec_context(gss_cred_id_t claimant_cred_handle,
(void)gss_delete_sec_context(&minor, &acceptor_context, NULL);
}

static void
check_ticket_count(gss_cred_id_t cred, int expected)
{
krb5_error_code ret;
krb5_context context = NULL;
krb5_creds kcred;
krb5_cc_cursor cur;
krb5_ccache ccache;
int count = 0;
gss_key_value_set_desc store;
gss_key_value_element_desc elem;
OM_uint32 major, minor;
const char *ccname = "MEMORY:count";

store.count = 1;
store.elements = &elem;
elem.key = "ccache";
elem.value = ccname;
major = gss_store_cred_into(&minor, cred, GSS_C_INITIATE, &mech_krb5, 1, 0,
&store, NULL, NULL);
check_gsserr("gss_store_cred_into", major, minor);

ret = krb5_init_context(&context);
check_k5err(context, "krb5_init_context", ret);

ret = krb5_cc_resolve(context, ccname, &ccache);
check_k5err(context, "krb5_cc_resolve", ret);

ret = krb5_cc_start_seq_get(context, ccache, &cur);
check_k5err(context, "krb5_cc_start_seq_get", ret);

while (!krb5_cc_next_cred(context, ccache, &cur, &kcred)) {
if (!krb5_is_config_principal(context, kcred.server))
count++;
krb5_free_cred_contents(context, &kcred);
}

ret = krb5_cc_end_seq_get(context, ccache, &cur);
check_k5err(context, "krb5_cc_end_seq_get", ret);

if (expected != count) {
printf("Expected %d tickets but got %d\n", expected, count);
exit(1);
}

krb5_cc_destroy(context, ccache);
krb5_free_context(context);
}

static void
constrained_delegate(gss_OID_set desired_mechs, gss_name_t target,
gss_cred_id_t delegated_cred_handle,
Expand Down Expand Up @@ -162,9 +211,26 @@ constrained_delegate(gss_OID_set desired_mechs, gss_name_t target,
&time_rec);
check_gsserr("gss_init_sec_context", major, minor);

(void)gss_release_buffer(&minor, &token);
(void)gss_delete_sec_context(&minor, &initiator_context, NULL);

/* Ensure a second call does not acquire new ticket. */
major = gss_init_sec_context(&minor, delegated_cred_handle,
&initiator_context, target,
mechs ? &mechs->elements[0] : &mech_krb5,
GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG,
GSS_C_INDEFINITE, GSS_C_NO_CHANNEL_BINDINGS,
GSS_C_NO_BUFFER, NULL, &token, NULL,
&time_rec);
check_gsserr("gss_init_sec_context", major, minor);

(void)gss_release_buffer(&minor, &token);
(void)gss_delete_sec_context(&minor, &initiator_context, NULL);
(void)gss_release_oid_set(&minor, &mechs);

/* We expect three tickets: our TGT, the evidence ticket, and the ticket to
* the target service. */
check_ticket_count(delegated_cred_handle, 3);
}

int
Expand Down

0 comments on commit f149b9c

Please sign in to comment.