1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/ccache/cc_retr.c */
4 * Copyright 1990,1991,1999,2007,2008 by the Massachusetts Institute of Technology.
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
29 #include "../krb/int-proto.h"
33 #define set(bits) (whichfields & bits)
34 #define flags_match(a,b) (((a) & (b)) == (a))
37 times_match_exact(const krb5_ticket_times *t1, const krb5_ticket_times *t2)
39 return (t1->authtime == t2->authtime &&
40 t1->starttime == t2->starttime &&
41 t1->endtime == t2->endtime &&
42 t1->renew_till == t2->renew_till);
46 times_match(const krb5_ticket_times *t1, const krb5_ticket_times *t2)
49 if (t1->renew_till > t2->renew_till)
50 return FALSE; /* this one expires too late */
53 if (t1->endtime > t2->endtime)
54 return FALSE; /* this one expires too late */
56 /* only care about expiration on a times_match */
61 standard_fields_match(krb5_context context, const krb5_creds *mcreds, const krb5_creds *creds)
63 return (krb5_principal_compare(context, mcreds->client,creds->client)
64 && krb5_principal_compare(context, mcreds->server,creds->server));
67 /* only match the server name portion, not the server realm portion */
70 srvname_match(krb5_context context, const krb5_creds *mcreds, const krb5_creds *creds)
73 krb5_principal_data p1, p2;
75 retval = krb5_principal_compare(context, mcreds->client,creds->client);
79 * Hack to ignore the server realm for the purposes of the compare.
84 return krb5_principal_compare(context, &p1, &p2);
88 authdata_match(krb5_authdata *const *mdata, krb5_authdata *const *data)
90 const krb5_authdata *mdatap, *datap;
99 return *mdata == NULL;
101 while ((mdatap = *mdata) && (datap = *data)) {
102 if ((mdatap->ad_type != datap->ad_type) ||
103 (mdatap->length != datap->length) ||
104 (memcmp ((char *)mdatap->contents,
105 (char *)datap->contents, (unsigned) mdatap->length) != 0))
110 return (*mdata == NULL) && (*data == NULL);
114 data_match(const krb5_data *data1, const krb5_data *data2)
122 if (!data2) return FALSE;
124 return data_eq(*data1, *data2) ? TRUE : FALSE;
128 pref (krb5_enctype my_ktype, int nktypes, krb5_enctype *ktypes)
131 for (i = 0; i < nktypes; i++)
132 if (my_ktype == ktypes[i])
139 * Searches the credentials cache for a credential matching mcreds,
140 * with the fields specified by whichfields. If one if found, it is
141 * returned in creds, which should be freed by the caller with
142 * krb5_free_credentials().
144 * The fields are interpreted in the following way (all constants are
145 * preceded by KRB5_TC_). MATCH_IS_SKEY requires the is_skey field to
146 * match exactly. MATCH_TIMES requires the requested lifetime to be
147 * at least as great as that specified; MATCH_TIMES_EXACT requires the
148 * requested lifetime to be exactly that specified. MATCH_FLAGS
149 * requires only the set bits in mcreds be set in creds;
150 * MATCH_FLAGS_EXACT requires all bits to match.
152 * Flag SUPPORTED_KTYPES means check all matching entries that have
153 * any supported enctype (according to tgs_enctypes) and return the one
154 * with the enctype listed earliest. Return CC_NOT_KTYPE if a match
155 * is found *except* for having a supported enctype.
165 krb5int_cc_creds_match_request(krb5_context context, krb5_flags whichfields, krb5_creds *mcreds, krb5_creds *creds)
167 if (((set(KRB5_TC_MATCH_SRV_NAMEONLY) &&
168 srvname_match(context, mcreds, creds)) ||
169 standard_fields_match(context, mcreds, creds))
171 (! set(KRB5_TC_MATCH_IS_SKEY) ||
172 mcreds->is_skey == creds->is_skey)
174 (! set(KRB5_TC_MATCH_FLAGS_EXACT) ||
175 mcreds->ticket_flags == creds->ticket_flags)
177 (! set(KRB5_TC_MATCH_FLAGS) ||
178 flags_match(mcreds->ticket_flags, creds->ticket_flags))
180 (! set(KRB5_TC_MATCH_TIMES_EXACT) ||
181 times_match_exact(&mcreds->times, &creds->times))
183 (! set(KRB5_TC_MATCH_TIMES) ||
184 times_match(&mcreds->times, &creds->times))
186 ( ! set(KRB5_TC_MATCH_AUTHDATA) ||
187 authdata_match(mcreds->authdata, creds->authdata))
189 (! set(KRB5_TC_MATCH_2ND_TKT) ||
190 data_match (&mcreds->second_ticket, &creds->second_ticket))
192 ((! set(KRB5_TC_MATCH_KTYPE))||
193 (mcreds->keyblock.enctype == creds->keyblock.enctype)))
198 static krb5_error_code
199 krb5_cc_retrieve_cred_seq (krb5_context context, krb5_ccache id,
200 krb5_flags whichfields, krb5_creds *mcreds,
201 krb5_creds *creds, int nktypes, krb5_enctype *ktypes)
203 /* This function could be considerably faster if it kept indexing */
204 /* information.. sounds like a "next version" idea to me. :-) */
206 krb5_cc_cursor cursor;
207 krb5_error_code kret;
208 krb5_error_code nomatch_err = KRB5_CC_NOTFOUND;
214 krb5_flags oflags = 0;
215 #define fetchcreds (fetched.creds)
217 kret = krb5_cc_start_seq_get(context, id, &cursor);
221 while (krb5_cc_next_cred(context, id, &cursor, &fetchcreds) == KRB5_OK) {
222 if (krb5int_cc_creds_match_request(context, whichfields, mcreds, &fetchcreds))
225 fetched.pref = pref (fetchcreds.keyblock.enctype,
227 if (fetched.pref < 0)
228 nomatch_err = KRB5_CC_NOT_KTYPE;
229 else if (!have_creds || fetched.pref < best.pref) {
231 krb5_free_cred_contents (context, &best.creds);
238 krb5_cc_end_seq_get(context, id, &cursor);
244 /* This one doesn't match */
245 krb5_free_cred_contents(context, &fetchcreds);
248 /* If we get here, a match wasn't found */
249 krb5_cc_end_seq_get(context, id, &cursor);
258 k5_cc_retrieve_cred_default(krb5_context context, krb5_ccache id,
259 krb5_flags flags, krb5_creds *mcreds,
262 krb5_enctype *ktypes;
266 if (flags & KRB5_TC_SUPPORTED_KTYPES) {
267 ret = krb5_get_tgs_ktypes (context, mcreds->server, &ktypes);
270 nktypes = k5_count_etypes (ktypes);
272 ret = krb5_cc_retrieve_cred_seq (context, id, flags, mcreds, creds,
277 return krb5_cc_retrieve_cred_seq (context, id, flags, mcreds, creds,