#include "k5-int.h"
#include "cc-int.h"
#include "../krb/int-proto.h"
#define KRB5_OK 0
static int
times_match_exact(const krb5_ticket_times *t1, const krb5_ticket_times *t2)
{
return (t1->authtime == t2->authtime &&
t1->starttime == t2->starttime &&
t1->endtime == t2->endtime &&
t1->renew_till == t2->renew_till);
}
static krb5_boolean
times_match(const krb5_ticket_times *t1, const krb5_ticket_times *t2)
{
if (t1->renew_till) {
if (ts_after(t1->renew_till, t2->renew_till))
return FALSE;
}
if (t1->endtime) {
if (ts_after(t1->endtime, t2->endtime))
return FALSE;
}
return TRUE;
}
static krb5_boolean
princs_match(krb5_context context, krb5_flags whichfields,
const krb5_creds *mcreds, const krb5_creds *creds)
{
if (mcreds->client != NULL &&
!krb5_principal_compare(context, mcreds->client, creds->client))
return FALSE;
if (mcreds->server == NULL)
return TRUE;
if (whichfields & KRB5_TC_MATCH_SRV_NAMEONLY) {
return krb5_principal_compare_any_realm(context, mcreds->server,
creds->server);
} else {
return krb5_principal_compare(context, mcreds->server, creds->server);
}
}
static krb5_boolean
authdata_match(krb5_authdata *const *mdata, krb5_authdata *const *data)
{
const krb5_authdata *mdatap, *datap;
if (mdata == data)
return TRUE;
if (mdata == NULL)
return *data == NULL;
if (data == NULL)
return *mdata == NULL;
while ((mdatap = *mdata) && (datap = *data)) {
if ((mdatap->ad_type != datap->ad_type) ||
(mdatap->length != datap->length) ||
(memcmp ((char *)mdatap->contents,
(char *)datap->contents, (unsigned) mdatap->length) != 0))
return FALSE;
mdata++;
data++;
}
return (*mdata == NULL) && (*data == NULL);
}
static krb5_boolean
data_match(const krb5_data *data1, const krb5_data *data2)
{
if (!data1) {
if (!data2)
return TRUE;
else
return FALSE;
}
if (!data2) return FALSE;
return data_eq(*data1, *data2) ? TRUE : FALSE;
}
static int
pref (krb5_enctype my_ktype, int nktypes, krb5_enctype *ktypes)
{
int i;
for (i = 0; i < nktypes; i++)
if (my_ktype == ktypes[i])
return i;
return -1;
}
krb5_boolean
krb5int_cc_creds_match_request(krb5_context context, krb5_flags whichfields,
krb5_creds *mcreds, krb5_creds *creds)
{
krb5_boolean is_skey;
if (!princs_match(context, whichfields, mcreds, creds))
return FALSE;
is_skey = (whichfields & KRB5_TC_MATCH_IS_SKEY) ? mcreds->is_skey : FALSE;
if (creds->is_skey != is_skey)
return FALSE;
if ((whichfields & KRB5_TC_MATCH_FLAGS_EXACT) &&
mcreds->ticket_flags != creds->ticket_flags)
return FALSE;
if ((whichfields & KRB5_TC_MATCH_FLAGS) &&
(creds->ticket_flags & mcreds->ticket_flags) != mcreds->ticket_flags)
return FALSE;
if ((whichfields & KRB5_TC_MATCH_TIMES_EXACT) &&
!times_match_exact(&mcreds->times, &creds->times))
return FALSE;
if ((whichfields & KRB5_TC_MATCH_TIMES) &&
!times_match(&mcreds->times, &creds->times))
return FALSE;
if ((whichfields & KRB5_TC_MATCH_AUTHDATA) &&
!authdata_match(mcreds->authdata, creds->authdata))
return FALSE;
if ((whichfields & KRB5_TC_MATCH_2ND_TKT) &&
!data_match(&mcreds->second_ticket, &creds->second_ticket))
return FALSE;
if ((whichfields & KRB5_TC_MATCH_KTYPE) &&
mcreds->keyblock.enctype != creds->keyblock.enctype)
return FALSE;
return TRUE;
}
static krb5_error_code
krb5_cc_retrieve_cred_seq (krb5_context context, krb5_ccache id,
krb5_flags whichfields, krb5_creds *mcreds,
krb5_creds *creds, int nktypes, krb5_enctype *ktypes)
{
krb5_cc_cursor cursor;
krb5_error_code kret;
krb5_error_code nomatch_err = KRB5_CC_NOTFOUND;
struct {
krb5_creds creds;
int pref;
} fetched, best;
int have_creds = 0;
#define fetchcreds (fetched.creds)
kret = krb5_cc_start_seq_get(context, id, &cursor);
if (kret != KRB5_OK)
return kret;
while (krb5_cc_next_cred(context, id, &cursor, &fetchcreds) == KRB5_OK) {
if (krb5int_cc_creds_match_request(context, whichfields, mcreds, &fetchcreds))
{
if (ktypes) {
fetched.pref = pref (fetchcreds.keyblock.enctype,
nktypes, ktypes);
if (fetched.pref < 0)
nomatch_err = KRB5_CC_NOT_KTYPE;
else if (!have_creds || fetched.pref < best.pref) {
if (have_creds)
krb5_free_cred_contents (context, &best.creds);
else
have_creds = 1;
best = fetched;
continue;
}
} else {
krb5_cc_end_seq_get(context, id, &cursor);
*creds = fetchcreds;
return KRB5_OK;
}
}
krb5_free_cred_contents(context, &fetchcreds);
}
krb5_cc_end_seq_get(context, id, &cursor);
if (have_creds) {
*creds = best.creds;
return KRB5_OK;
} else
return nomatch_err;
}
krb5_error_code
k5_cc_retrieve_cred_default(krb5_context context, krb5_ccache id,
krb5_flags flags, krb5_creds *mcreds,
krb5_creds *creds)
{
krb5_enctype *ktypes;
int nktypes;
krb5_error_code ret;
if (flags & KRB5_TC_SUPPORTED_KTYPES) {
ret = krb5_get_tgs_ktypes (context, mcreds->server, &ktypes);
if (ret)
return ret;
nktypes = k5_count_etypes (ktypes);
ret = krb5_cc_retrieve_cred_seq (context, id, flags, mcreds, creds,
nktypes, ktypes);
free (ktypes);
return ret;
} else {
return krb5_cc_retrieve_cred_seq (context, id, flags, mcreds, creds,
0, 0);
}
}