#include "cc-int.h"
#include "../krb/int-proto.h"
#include "../os/os-proto.h"
#include <assert.h>
struct _krb5_cccol_cursor {
krb5_cc_typecursor typecursor;
const krb5_cc_ops *ops;
krb5_cc_ptcursor ptcursor;
};
krb5_error_code KRB5_CALLCONV
krb5_cccol_cursor_new(krb5_context context,
krb5_cccol_cursor *cursor)
{
krb5_error_code ret = 0;
krb5_cccol_cursor n = NULL;
*cursor = NULL;
n = malloc(sizeof(*n));
if (n == NULL)
return ENOMEM;
n->typecursor = NULL;
n->ptcursor = NULL;
n->ops = NULL;
ret = krb5int_cc_typecursor_new(context, &n->typecursor);
if (ret)
goto errout;
do {
ret = krb5int_cc_typecursor_next(context, n->typecursor, &n->ops);
if (ret || n->ops == NULL)
goto errout;
} while (n->ops->ptcursor_new == NULL);
ret = n->ops->ptcursor_new(context, &n->ptcursor);
if (ret)
goto errout;
errout:
if (ret) {
krb5_cccol_cursor_free(context, &n);
}
*cursor = n;
return ret;
}
krb5_error_code KRB5_CALLCONV
krb5_cccol_cursor_next(krb5_context context,
krb5_cccol_cursor cursor,
krb5_ccache *ccache_out)
{
krb5_error_code ret = 0;
krb5_ccache ccache;
*ccache_out = NULL;
if (cursor->ops == NULL)
return 0;
while (1) {
ret = cursor->ops->ptcursor_next(context, cursor->ptcursor, &ccache);
if (ret)
return ret;
if (ccache != NULL) {
*ccache_out = ccache;
return 0;
}
ret = cursor->ops->ptcursor_free(context, &cursor->ptcursor);
if (ret)
return ret;
do {
ret = krb5int_cc_typecursor_next(context, cursor->typecursor,
&cursor->ops);
if (ret)
return ret;
if (cursor->ops == NULL)
return 0;
} while (cursor->ops->ptcursor_new == NULL);
ret = cursor->ops->ptcursor_new(context, &cursor->ptcursor);
if (ret)
return ret;
}
}
krb5_error_code KRB5_CALLCONV
krb5_cccol_cursor_free(krb5_context context,
krb5_cccol_cursor *cursor)
{
krb5_cccol_cursor c = *cursor;
if (c == NULL)
return 0;
if (c->ptcursor != NULL)
c->ops->ptcursor_free(context, &c->ptcursor);
if (c->typecursor != NULL)
krb5int_cc_typecursor_free(context, &c->typecursor);
free(c);
*cursor = NULL;
return 0;
}
static krb5_error_code
match_caches(krb5_context context, krb5_const_principal client,
krb5_ccache *cache_out)
{
krb5_error_code ret;
krb5_cccol_cursor cursor;
krb5_ccache cache = NULL;
krb5_principal princ;
krb5_boolean eq;
*cache_out = NULL;
ret = krb5_cccol_cursor_new(context, &cursor);
if (ret)
return ret;
while ((ret = krb5_cccol_cursor_next(context, cursor, &cache)) == 0 &&
cache != NULL) {
ret = krb5_cc_get_principal(context, cache, &princ);
if (ret == 0) {
eq = krb5_principal_compare(context, princ, client);
krb5_free_principal(context, princ);
if (eq)
break;
}
krb5_cc_close(context, cache);
}
krb5_cccol_cursor_free(context, &cursor);
if (ret)
return ret;
if (cache == NULL)
return KRB5_CC_NOTFOUND;
*cache_out = cache;
return 0;
}
krb5_error_code KRB5_CALLCONV
krb5_cc_cache_match(krb5_context context, krb5_principal client,
krb5_ccache *cache_out)
{
krb5_error_code ret;
struct canonprinc iter = { client, .subst_defrealm = TRUE };
krb5_const_principal canonprinc = NULL;
krb5_ccache cache = NULL;
char *name;
*cache_out = NULL;
while ((ret = k5_canonprinc(context, &iter, &canonprinc)) == 0 &&
canonprinc != NULL) {
ret = match_caches(context, canonprinc, &cache);
if (ret != KRB5_CC_NOTFOUND)
break;
}
free_canonprinc(&iter);
if (ret == 0 && canonprinc == NULL) {
ret = KRB5_CC_NOTFOUND;
if (krb5_unparse_name(context, client, &name) == 0) {
k5_setmsg(context, ret,
_("Can't find client principal %s in cache collection"),
name);
krb5_free_unparsed_name(context, name);
}
}
TRACE_CC_CACHE_MATCH(context, client, ret);
if (ret)
return ret;
*cache_out = cache;
return 0;
}
static void
save_first_error(krb5_context context, krb5_error_code code,
struct errinfo *errsave)
{
if (code && code != KRB5_FCC_NOFILE && !errsave->code)
k5_save_ctx_error(context, code, errsave);
}
krb5_error_code KRB5_CALLCONV
krb5_cccol_have_content(krb5_context context)
{
krb5_error_code ret;
krb5_cccol_cursor col_cursor;
krb5_ccache cache;
krb5_principal princ;
krb5_boolean found = FALSE;
struct errinfo errsave = EMPTY_ERRINFO;
const char *defname;
ret = krb5_cccol_cursor_new(context, &col_cursor);
save_first_error(context, ret, &errsave);
if (ret)
goto no_entries;
while (!found) {
ret = krb5_cccol_cursor_next(context, col_cursor, &cache);
save_first_error(context, ret, &errsave);
if (ret || cache == NULL)
break;
princ = NULL;
ret = krb5_cc_get_principal(context, cache, &princ);
save_first_error(context, ret, &errsave);
if (!ret)
found = TRUE;
krb5_free_principal(context, princ);
krb5_cc_close(context, cache);
}
krb5_cccol_cursor_free(context, &col_cursor);
if (found) {
k5_clear_error(&errsave);
return 0;
}
no_entries:
if (errsave.code) {
ret = k5_restore_ctx_error(context, &errsave);
k5_wrapmsg(context, ret, KRB5_CC_NOTFOUND,
_("No Kerberos credentials available"));
} else {
defname = krb5_cc_default_name(context);
if (defname != NULL) {
k5_setmsg(context, KRB5_CC_NOTFOUND,
_("No Kerberos credentials available "
"(default cache: %s)"), defname);
}
}
return KRB5_CC_NOTFOUND;
}