1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/ccache/cccursor.c */
4 * Copyright 2006, 2007 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.
28 * cursor for sequential traversal of ccaches
32 #include "../krb/int-proto.h"
36 struct _krb5_cccol_cursor {
37 krb5_cc_typecursor typecursor;
38 const krb5_cc_ops *ops;
39 krb5_cc_ptcursor ptcursor;
41 /* typedef of krb5_cccol_cursor is in krb5.h */
43 krb5_error_code KRB5_CALLCONV
44 krb5_cccol_cursor_new(krb5_context context,
45 krb5_cccol_cursor *cursor)
47 krb5_error_code ret = 0;
48 krb5_cccol_cursor n = NULL;
51 n = malloc(sizeof(*n));
59 ret = krb5int_cc_typecursor_new(context, &n->typecursor);
64 /* Find first backend with ptcursor functionality. */
65 ret = krb5int_cc_typecursor_next(context, n->typecursor, &n->ops);
66 if (ret || n->ops == NULL)
68 } while (n->ops->ptcursor_new == NULL);
70 ret = n->ops->ptcursor_new(context, &n->ptcursor);
76 krb5_cccol_cursor_free(context, &n);
82 krb5_error_code KRB5_CALLCONV
83 krb5_cccol_cursor_next(krb5_context context,
84 krb5_cccol_cursor cursor,
85 krb5_ccache *ccache_out)
87 krb5_error_code ret = 0;
92 /* Are we out of backends? */
93 if (cursor->ops == NULL)
97 ret = cursor->ops->ptcursor_next(context, cursor->ptcursor, &ccache);
100 if (ccache != NULL) {
101 *ccache_out = ccache;
105 ret = cursor->ops->ptcursor_free(context, &cursor->ptcursor);
110 /* Find next type with ptcursor functionality. */
111 ret = krb5int_cc_typecursor_next(context, cursor->typecursor,
115 if (cursor->ops == NULL)
117 } while (cursor->ops->ptcursor_new == NULL);
119 ret = cursor->ops->ptcursor_new(context, &cursor->ptcursor);
125 krb5_error_code KRB5_CALLCONV
126 krb5_cccol_cursor_free(krb5_context context,
127 krb5_cccol_cursor *cursor)
129 krb5_cccol_cursor c = *cursor;
134 if (c->ptcursor != NULL)
135 c->ops->ptcursor_free(context, &c->ptcursor);
136 if (c->typecursor != NULL)
137 krb5int_cc_typecursor_free(context, &c->typecursor);
144 krb5_error_code KRB5_CALLCONV
145 krb5_cccol_last_change_time(krb5_context context,
146 krb5_timestamp *change_time)
148 krb5_error_code ret = 0;
149 krb5_cccol_cursor c = NULL;
150 krb5_ccache ccache = NULL;
151 krb5_timestamp last_time = 0;
152 krb5_timestamp max_change_time = 0;
156 ret = krb5_cccol_cursor_new(context, &c);
159 ret = krb5_cccol_cursor_next(context, c, &ccache);
161 ret = krb5_cc_last_change_time(context, ccache, &last_time);
162 if (!ret && last_time > max_change_time) {
163 max_change_time = last_time;
171 *change_time = max_change_time;
176 * krb5_cccol_lock and krb5_cccol_unlock are defined in ccbase.c
179 krb5_error_code KRB5_CALLCONV
180 krb5_cc_cache_match(krb5_context context, krb5_principal client,
181 krb5_ccache *cache_out)
184 krb5_cccol_cursor cursor;
185 krb5_ccache cache = NULL;
186 krb5_principal princ;
191 ret = krb5_cccol_cursor_new(context, &cursor);
195 while ((ret = krb5_cccol_cursor_next(context, cursor, &cache)) == 0 &&
197 ret = krb5_cc_get_principal(context, cache, &princ);
199 eq = krb5_principal_compare(context, princ, client);
200 krb5_free_principal(context, princ);
204 krb5_cc_close(context, cache);
206 krb5_cccol_cursor_free(context, &cursor);
210 ret = krb5_unparse_name(context, client, &name);
212 k5_setmsg(context, KRB5_CC_NOTFOUND,
213 _("Can't find client principal %s in cache collection"),
215 krb5_free_unparsed_name(context, name);
217 ret = KRB5_CC_NOTFOUND;
223 /* Store the error state for code from context into errsave, but only if code
224 * indicates an error and errsave is empty. */
226 save_first_error(krb5_context context, krb5_error_code code,
227 struct errinfo *errsave)
229 if (code && code != KRB5_CC_END && !errsave->code)
230 k5_save_ctx_error(context, code, errsave);
233 krb5_error_code KRB5_CALLCONV
234 krb5_cccol_have_content(krb5_context context)
237 krb5_cccol_cursor col_cursor;
238 krb5_cc_cursor cache_cursor;
241 krb5_boolean found = FALSE;
242 struct errinfo errsave = EMPTY_ERRINFO;
245 ret = krb5_cccol_cursor_new(context, &col_cursor);
246 save_first_error(context, ret, &errsave);
251 ret = krb5_cccol_cursor_next(context, col_cursor, &cache);
252 save_first_error(context, ret, &errsave);
253 if (ret || cache == NULL)
256 ret = krb5_cc_start_seq_get(context, cache, &cache_cursor);
257 save_first_error(context, ret, &errsave);
259 krb5_cc_close(context, cache);
263 ret = krb5_cc_next_cred(context, cache, &cache_cursor, &creds);
264 save_first_error(context, ret, &errsave);
268 if (!krb5_is_config_principal(context, creds.server))
270 krb5_free_cred_contents(context, &creds);
272 krb5_cc_end_seq_get(context, cache, &cache_cursor);
273 krb5_cc_close(context, cache);
275 krb5_cccol_cursor_free(context, &col_cursor);
281 /* Report the first error we encountered. */
282 ret = k5_restore_ctx_error(context, &errsave);
283 k5_wrapmsg(context, ret, KRB5_CC_NOTFOUND,
284 _("No Kerberos credentials available"));
286 /* Report the default cache name. */
287 defname = krb5_cc_default_name(context);
288 if (defname != NULL) {
289 k5_setmsg(context, KRB5_CC_NOTFOUND,
290 _("No Kerberos credentials available "
291 "(default cache: %s)"), defname);
294 return KRB5_CC_NOTFOUND;