Files
heimdal/lib/krb5/test_cc.c
T
2026-06-10 17:26:54 -05:00

3512 lines
116 KiB
C

/*
* Copyright (c) 2003 - 2007 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of KTH nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
/*
* If this test fails with
*
* krb5_cc_gen_new: KEYRING: Key has been revoked
*
* then run
*
* keyctl new_session
*/
#include "krb5_locl.h"
#include <getarg.h>
#include <err.h>
#ifdef HAVE_KEYUTILS_H
#include <keyutils.h>
#endif
static const char *unlink_this;
static const char *unlink_this2;
static char *tmpdir;
static int debug_flag = 0;
static int version_flag = 0;
static int help_flag = 0;
#define TEST_CC_TEMPLATE "%{TEMP}/krb5-cc-test-XXXXXX"
static void
cleanup(void)
{
char *s = NULL;
if (asprintf(&s, "%s/cc", tmpdir) > -1 && s != NULL)
unlink(s);
free(s);
if (asprintf(&s, "%s/scc", tmpdir) > -1 && s != NULL)
unlink(s);
free(s);
if (asprintf(&s, "%s/cccol/foobar+lha@H5L.SE", tmpdir) > -1 && s != NULL)
unlink(s);
free(s);
if (asprintf(&s, "%s/cccol/foobar+lha@SU.SE", tmpdir) > -1 && s != NULL)
unlink(s);
free(s);
if (asprintf(&s, "%s/cccol/foobar", tmpdir) > -1 && s != NULL)
unlink(s);
free(s);
if (asprintf(&s, "%s/cccol", tmpdir) > -1 && s != NULL)
rmdir(s);
free(s);
if (asprintf(&s, "%s/dcc/tkt.lha@H5L.SE", tmpdir) > -1 && s != NULL)
unlink(s);
free(s);
if (asprintf(&s, "%s/dcc/tkt.lha@SU.SE", tmpdir) > -1 && s != NULL)
unlink(s);
free(s);
if (asprintf(&s, "%s/dcc/tkt", tmpdir) > -1 && s != NULL)
unlink(s);
free(s);
if (asprintf(&s, "%s/dcc/primary", tmpdir) > -1 && s != NULL)
unlink(s);
free(s);
if (asprintf(&s, "%s/dcc", tmpdir) > -1 && s != NULL)
rmdir(s);
free(s);
if (unlink_this)
unlink(unlink_this);
unlink_this = NULL;
if (unlink_this2)
unlink(unlink_this2);
unlink_this2 = NULL;
rmdir(tmpdir);
}
static void
make_dir(krb5_context context)
{
krb5_error_code ret;
char *template = NULL;
char *dcc = NULL;
ret = _krb5_expand_path_tokens(context, TEST_CC_TEMPLATE, 1, &template);
if (ret)
krb5_err(context, 1, ret, "_krb5_expand_path_tokens(%s) failed",
TEST_CC_TEMPLATE);
if ((tmpdir = mkdtemp(template)) == NULL)
krb5_err(context, 1, errno, "mkdtemp(%s) failed", template);
if (asprintf(&dcc, "%s/dcc", tmpdir) == -1 || dcc == NULL)
krb5_err(context, 1, errno, "asprintf failed");
free(dcc);
atexit(cleanup);
}
static void
test_default_name(krb5_context context)
{
krb5_error_code ret;
const char *p;
char *test_cc_name = NULL;
const char *p3;
char *p1, *p2;
char *exp_test_cc_name;
if (asprintf(&test_cc_name, "%s/cc", tmpdir) == -1 || test_cc_name == NULL)
krb5_err(context, 1, errno, "out of memory");
/* Convert slashes to backslashes */
ret = _krb5_expand_path_tokens(context, test_cc_name, 1,
&exp_test_cc_name);
if (ret)
krb5_err(context, 1, ret, "_krb5_expand_path_tokens(%s) failed",
test_cc_name);
free(test_cc_name);
test_cc_name = NULL;
p = krb5_cc_default_name(context);
if (p == NULL)
krb5_errx (context, 1, "krb5_cc_default_name 1 failed");
p1 = estrdup(p);
ret = krb5_cc_set_default_name(context, NULL);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_set_default_name(NULL) failed");
p = krb5_cc_default_name(context);
if (p == NULL)
krb5_errx (context, 1, "krb5_cc_default_name 2 failed");
p2 = estrdup(p);
if (strcmp(p1, p2) != 0)
krb5_errx (context, 1, "krb5_cc_default_name no longer same");
ret = krb5_cc_set_default_name(context, exp_test_cc_name);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_set_default_name(%s) failed",
exp_test_cc_name);
p = krb5_cc_default_name(context);
if (p == NULL)
krb5_errx (context, 1, "krb5_cc_default_name 2 failed");
if (strncmp(p, "FILE:", sizeof("FILE:") - 1) == 0)
p3 = p + sizeof("FILE:") - 1;
else
p3 = p;
if (strcmp(exp_test_cc_name, p3) != 0) {
#ifdef WIN32
krb5_warnx(context, 1,
"krb5_cc_default_name() returned %s; expected %s",
p, exp_test_cc_name);
#else
krb5_errx(context, 1,
"krb5_cc_default_name() returned %s; expected %s",
p, exp_test_cc_name);
#endif
}
free(exp_test_cc_name);
free(p1);
free(p2);
}
/*
* Check that a closed cc still keeps it data and that it's no longer
* there when it's destroyed.
*/
static void
test_mcache(krb5_context context)
{
krb5_error_code ret;
krb5_ccache id, id2;
const char *nc, *tc;
char *c;
krb5_principal p, p2;
ret = krb5_parse_name(context, "lha@SU.SE", &p);
if (ret)
krb5_err(context, 1, ret, "krb5_parse_name");
ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_new_unique");
ret = krb5_cc_initialize(context, id, p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_initialize");
nc = krb5_cc_get_name(context, id);
if (nc == NULL)
krb5_errx(context, 1, "krb5_cc_get_name");
tc = krb5_cc_get_type(context, id);
if (tc == NULL)
krb5_errx(context, 1, "krb5_cc_get_name");
if (asprintf(&c, "%s:%s", tc, nc) < 0 || c == NULL)
errx(1, "malloc");
krb5_cc_close(context, id);
ret = krb5_cc_resolve(context, c, &id2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve");
ret = krb5_cc_get_principal(context, id2, &p2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_get_principal");
if (krb5_principal_compare(context, p, p2) == FALSE)
krb5_errx(context, 1, "p != p2");
krb5_cc_destroy(context, id2);
krb5_free_principal(context, p);
krb5_free_principal(context, p2);
ret = krb5_cc_resolve(context, c, &id2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve");
ret = krb5_cc_get_principal(context, id2, &p2);
if (ret == 0)
krb5_errx(context, 1, "krb5_cc_get_principal");
krb5_cc_destroy(context, id2);
free(c);
}
/*
* Test that init works on a destroyed cc.
*/
static void
test_init_vs_destroy(krb5_context context, const char *type)
{
krb5_error_code ret;
krb5_ccache id, id2;
krb5_principal p, p2;
char *n = NULL;
ret = krb5_parse_name(context, "lha@SU.SE", &p);
if (ret)
krb5_err(context, 1, ret, "krb5_parse_name");
ret = krb5_cc_new_unique(context, type, NULL, &id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_new_unique: %s", type);
if (asprintf(&n, "%s:%s",
krb5_cc_get_type(context, id),
krb5_cc_get_name(context, id)) < 0 || n == NULL)
errx(1, "malloc");
if (strcmp(krb5_cc_get_type(context, id), "FILE") == 0)
unlink_this = krb5_cc_get_name(context, id);
ret = krb5_cc_resolve(context, n, &id2);
free(n);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve");
krb5_cc_destroy(context, id);
ret = krb5_cc_initialize(context, id2, p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_initialize");
ret = krb5_cc_get_principal(context, id2, &p2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_get_principal");
krb5_cc_destroy(context, id2);
unlink_this = NULL;
krb5_free_principal(context, p);
krb5_free_principal(context, p2);
}
static void
test_cache_remove(krb5_context context, const char *type)
{
krb5_error_code ret;
krb5_ccache id;
krb5_principal p;
krb5_creds cred, found;
ret = krb5_parse_name(context, "lha@SU.SE", &p);
if (ret)
krb5_err(context, 1, ret, "krb5_parse_name");
ret = krb5_cc_new_unique(context, type, NULL, &id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_gen_new: %s", type);
if (strcmp(krb5_cc_get_type(context, id), "FILE") == 0)
unlink_this = krb5_cc_get_name(context, id);
ret = krb5_cc_initialize(context, id, p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_initialize");
/* */
memset(&cred, 0, sizeof(cred));
ret = krb5_parse_name(context, "krbtgt/SU.SE@SU.SE", &cred.server);
if (ret)
krb5_err(context, 1, ret, "krb5_parse_name");
ret = krb5_parse_name(context, "lha@SU.SE", &cred.client);
if (ret)
krb5_err(context, 1, ret, "krb5_parse_name");
cred.times.endtime = time(NULL) + 300;
ret = krb5_cc_store_cred(context, id, &cred);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_store_cred");
ret = krb5_cc_remove_cred(context, id, 0, &cred);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_remove_cred");
memset(&found, 0, sizeof(found));
ret = krb5_cc_retrieve_cred(context, id, KRB5_TC_MATCH_TIMES,
&cred, &found);
if (ret == 0)
krb5_err(context, 1, ret, "krb5_cc_remove_cred didn't");
ret = krb5_cc_destroy(context, id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_destroy");
unlink_this = NULL;
krb5_free_principal(context, p);
krb5_free_principal(context, cred.server);
krb5_free_principal(context, cred.client);
}
static void
make_cursor_cred(krb5_context context, krb5_creds *cred, const char *server)
{
krb5_error_code ret;
memset(cred, 0, sizeof(*cred));
ret = krb5_parse_name(context, "lha@SU.SE", &cred->client);
if (ret)
krb5_err(context, 1, ret, "krb5_parse_name");
ret = krb5_parse_name(context, server, &cred->server);
if (ret)
krb5_err(context, 1, ret, "krb5_parse_name");
cred->times.endtime = time(NULL) + 300;
}
static void
write_file_bytes(krb5_context context, const char *path,
const void *data, size_t len)
{
const unsigned char *p = data;
ssize_t bytes;
int fd;
fd = open(path, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY | O_CLOEXEC, 0600);
if (fd < 0)
krb5_err(context, 1, errno, "open(%s)", path);
rk_cloexec(fd);
while (len) {
bytes = write(fd, p, len);
if (bytes <= 0) {
int ret = bytes < 0 ? errno : EIO;
close(fd);
krb5_err(context, 1, ret, "write(%s)", path);
}
p += bytes;
len -= bytes;
}
if (close(fd) < 0)
krb5_err(context, 1, errno, "close(%s)", path);
}
static void
store_or_die(krb5_context context, krb5_error_code ret, const char *what)
{
if (ret)
krb5_err(context, 1, ret, "%s", what);
}
static void
write_storage_file(krb5_context context, const char *path, krb5_storage *sp)
{
krb5_error_code ret;
krb5_data data;
ret = krb5_storage_to_data(sp, &data);
if (ret)
krb5_err(context, 1, ret, "krb5_storage_to_data");
write_file_bytes(context, path, data.data, data.length);
krb5_data_free(&data);
}
static void
write_fcache_v4_file(krb5_context context, const char *path,
krb5_boolean write_length, int16_t length,
krb5_boolean write_dtag, int16_t dtag,
krb5_boolean write_data_len, int16_t data_len,
const void *payload, size_t payload_len)
{
krb5_storage *sp;
sp = krb5_storage_emem();
if (sp == NULL)
krb5_err(context, 1, ENOMEM, "krb5_storage_emem");
store_or_die(context, krb5_store_int8(sp, 5), "store pvno");
store_or_die(context, krb5_store_int8(sp, 4), "store fcache version");
if (write_length)
store_or_die(context, krb5_store_int16(sp, length), "store tag length");
if (write_dtag)
store_or_die(context, krb5_store_int16(sp, dtag), "store dtag");
if (write_data_len)
store_or_die(context, krb5_store_int16(sp, data_len), "store dlength");
if (payload_len)
store_or_die(context, krb5_storage_write(sp, rk_UNCONST(payload),
payload_len) == payload_len ?
0 : EIO, "store payload");
write_storage_file(context, path, sp);
krb5_storage_free(sp);
}
static void
expect_bad_file_cache(krb5_context context, const char *path, const char *what)
{
krb5_error_code ret;
krb5_ccache id;
krb5_principal p;
char *ccname = NULL;
if (asprintf(&ccname, "FILE:%s", path) == -1 || ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_cc_resolve(context, ccname, &id);
free(ccname);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve bad FILE cache");
ret = krb5_cc_get_principal(context, id, &p);
if (ret == 0) {
krb5_free_principal(context, p);
krb5_errx(context, 1, "%s unexpectedly parsed", what);
}
ret = krb5_cc_close(context, id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_close bad FILE cache");
}
static void
expect_bad_file_cache_seq(krb5_context context, const char *path,
const char *what)
{
krb5_error_code ret;
krb5_ccache id;
krb5_cc_cursor cursor;
char *ccname = NULL;
if (asprintf(&ccname, "FILE:%s", path) == -1 || ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_cc_resolve(context, ccname, &id);
free(ccname);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve bad FILE cache seq");
ret = krb5_cc_start_seq_get(context, id, &cursor);
if (ret == 0) {
krb5_cc_end_seq_get(context, id, &cursor);
krb5_errx(context, 1, "%s unexpectedly started iteration", what);
}
ret = krb5_cc_close(context, id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_close bad FILE cache seq");
}
static void
expect_bad_cc_resolve(krb5_context context, const char *ccname,
const char *what)
{
krb5_error_code ret;
krb5_ccache id;
ret = krb5_cc_resolve(context, ccname, &id);
if (ret == 0) {
krb5_cc_close(context, id);
krb5_errx(context, 1, "%s unexpectedly resolved", what);
}
}
static void
restore_env(const char *name, const char *value)
{
#ifndef HAVE_UNSETENV
char *assignment;
#endif
if (value) {
setenv(name, value, 1);
return;
}
#ifdef HAVE_UNSETENV
unsetenv(name);
#else
if (asprintf(&assignment, "%s=", name) == -1 || assignment == NULL)
err(1, "asprintf");
if (putenv(assignment))
err(1, "putenv");
#endif
}
static krb5_boolean
server_principal_match(krb5_context context, void *matchctx,
const krb5_creds *cred)
{
return krb5_principal_compare(context, cred->server, matchctx);
}
static void
check_cred_contents(krb5_context context, const krb5_creds *expected,
const krb5_creds *actual, const char *what)
{
if (!krb5_principal_compare(context, expected->client, actual->client) ||
!krb5_principal_compare(context, expected->server, actual->server) ||
expected->times.endtime != actual->times.endtime)
krb5_errx(context, 1, "%s credential mismatch", what);
}
static void
check_config_roundtrip(krb5_context context, krb5_ccache id,
krb5_principal principal, const char *name,
const char *ccname)
{
krb5_error_code ret;
krb5_data data, data2;
data.data = rk_UNCONST("value");
data.length = strlen("value");
ret = krb5_cc_set_config(context, id, principal, name, &data);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_set_config %s %s", name, ccname);
ret = krb5_cc_get_config(context, id, principal, name, &data2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_get_config %s %s", name, ccname);
if (data.length != data2.length ||
memcmp(data.data, data2.data, data.length) != 0)
krb5_errx(context, 1, "config value mismatch for %s %s", name,
ccname);
krb5_data_free(&data2);
data.data = rk_UNCONST("replacement");
data.length = strlen("replacement");
ret = krb5_cc_set_config(context, id, principal, name, &data);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_set_config replace %s %s",
name, ccname);
ret = krb5_cc_get_config(context, id, principal, name, &data2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_get_config replace %s %s",
name, ccname);
if (data.length != data2.length ||
memcmp(data.data, data2.data, data.length) != 0)
krb5_errx(context, 1, "config replacement mismatch for %s %s",
name, ccname);
krb5_data_free(&data2);
ret = krb5_cc_set_config(context, id, principal, name, NULL);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_set_config delete %s %s",
name, ccname);
ret = krb5_cc_get_config(context, id, principal, name, &data2);
if (ret == 0) {
krb5_data_free(&data2);
krb5_errx(context, 1, "deleted config still present for %s %s",
name, ccname);
}
}
static void
test_cache_common_backend_ops(krb5_context context, const char *ccname)
{
krb5_error_code ret;
krb5_ccache id = NULL;
krb5_cc_cursor cursor;
krb5_principal p = NULL;
krb5_creds cred, found, tgt;
krb5_deltat offset;
krb5_timestamp mtime;
time_t lifetime;
char *full_name = NULL;
char *friendly = NULL;
int version;
krb5_boolean saw_cred, saw_tgt;
memset(&cred, 0, sizeof(cred));
memset(&found, 0, sizeof(found));
memset(&tgt, 0, sizeof(tgt));
ret = krb5_parse_name(context, "lha@SU.SE", &p);
if (ret)
krb5_err(context, 1, ret, "krb5_parse_name");
ret = krb5_cc_resolve(context, ccname, &id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve %s", ccname);
ret = krb5_cc_initialize(context, id, p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_initialize %s", ccname);
ret = krb5_cc_get_full_name(context, id, &full_name);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_get_full_name %s", ccname);
if (full_name == NULL || strchr(full_name, ':') == NULL)
krb5_errx(context, 1, "invalid full name for %s", ccname);
free(full_name);
full_name = NULL;
ret = krb5_cc_set_flags(context, id, 0);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_set_flags %s", ccname);
version = krb5_cc_get_version(context, id);
if (version < 0)
krb5_errx(context, 1, "negative ccache version for %s", ccname);
ret = krb5_cc_set_kdc_offset(context, id, 37);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_set_kdc_offset %s", ccname);
ret = krb5_cc_get_kdc_offset(context, id, &offset);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_get_kdc_offset %s", ccname);
if (strcmp(krb5_cc_get_type(context, id), krb5_cc_type_memory) == 0 &&
offset != 37)
krb5_errx(context, 1, "MEMORY kdc offset was %ld",
(long)offset);
ret = krb5_cc_get_friendly_name(context, id, &friendly);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_get_friendly_name %s", ccname);
free(friendly);
friendly = NULL;
ret = krb5_cc_set_friendly_name(context, id, "common friendly");
if (ret)
krb5_err(context, 1, ret, "krb5_cc_set_friendly_name %s", ccname);
ret = krb5_cc_get_friendly_name(context, id, &friendly);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_get_friendly_name configured %s",
ccname);
if (strcmp(friendly, "common friendly") != 0)
krb5_errx(context, 1, "friendly name for %s was %s", ccname,
friendly);
free(friendly);
friendly = NULL;
make_cursor_cred(context, &cred, "host/common@SU.SE");
ret = krb5_cc_store_cred(context, id, &cred);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_store_cred %s", ccname);
make_cursor_cred(context, &tgt, "krbtgt/SU.SE@SU.SE");
ret = krb5_cc_store_cred(context, id, &tgt);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_store_cred TGT %s", ccname);
ret = krb5_cc_retrieve_cred(context, id, 0, &cred, &found);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_retrieve_cred %s", ccname);
check_cred_contents(context, &cred, &found, "retrieved service");
krb5_free_cred_contents(context, &found);
memset(&found, 0, sizeof(found));
ret = krb5_cc_retrieve_cred(context, id, 0, &tgt, &found);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_retrieve_cred TGT %s", ccname);
check_cred_contents(context, &tgt, &found, "retrieved TGT");
krb5_free_cred_contents(context, &found);
memset(&found, 0, sizeof(found));
ret = krb5_cc_start_seq_get(context, id, &cursor);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_start_seq_get %s", ccname);
saw_cred = saw_tgt = FALSE;
while ((ret = krb5_cc_next_cred(context, id, &cursor, &found)) == 0) {
if (krb5_is_config_principal(context, found.server)) {
krb5_free_cred_contents(context, &found);
memset(&found, 0, sizeof(found));
continue;
} else if (krb5_principal_compare(context, found.server, cred.server))
saw_cred = TRUE;
else if (krb5_principal_compare(context, found.server, tgt.server))
saw_tgt = TRUE;
else
krb5_errx(context, 1, "unexpected iterated cred for %s", ccname);
krb5_free_cred_contents(context, &found);
memset(&found, 0, sizeof(found));
}
if (ret != KRB5_CC_END)
krb5_err(context, 1, ret, "krb5_cc_next_cred %s", ccname);
if (!saw_cred || !saw_tgt)
krb5_errx(context, 1, "missing iterated cred for %s", ccname);
ret = krb5_cc_end_seq_get(context, id, &cursor);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_end_seq_get %s", ccname);
ret = krb5_cc_get_lifetime(context, id, &lifetime);
if (ret || lifetime <= 0)
krb5_err(context, 1, ret, "krb5_cc_get_lifetime %s", ccname);
ret = krb5_cc_last_change_time(context, id, &mtime);
if (ret != 0 && ret != KRB5_CC_NOSUPP)
krb5_err(context, 1, ret, "krb5_cc_last_change_time %s", ccname);
if (ret == 0 && mtime == 0)
krb5_errx(context, 1, "zero last-change time for %s", ccname);
check_config_roundtrip(context, id, NULL, "common-global-config",
ccname);
check_config_roundtrip(context, id, p, "common-principal-config",
ccname);
ret = krb5_cc_remove_cred(context, id, 0, &cred);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_remove_cred %s", ccname);
ret = krb5_cc_retrieve_cred(context, id, 0, &cred, &found);
if (ret == 0) {
krb5_free_cred_contents(context, &found);
krb5_errx(context, 1, "removed cred still present for %s", ccname);
}
ret = krb5_cc_retrieve_cred(context, id, 0, &tgt, &found);
if (ret)
krb5_err(context, 1, ret, "TGT missing after remove_cred %s", ccname);
check_cred_contents(context, &tgt, &found, "remaining TGT");
krb5_free_cred_contents(context, &found);
memset(&found, 0, sizeof(found));
krb5_free_cred_contents(context, &cred);
krb5_free_cred_contents(context, &tgt);
krb5_free_principal(context, p);
ret = krb5_cc_destroy(context, id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_destroy %s", ccname);
}
static void
test_cache_defaults_and_common_ops(krb5_context context)
{
krb5_error_code ret;
krb5_context env_context = NULL;
krb5_ccache id = NULL, id2 = NULL;
krb5_ccache fromid = NULL, toid = NULL;
krb5_principal p = NULL, p2 = NULL;
krb5_creds cred, cred2, mcred, found;
krb5_cc_cache_cursor cache_cursor;
krb5_timestamp mtime;
char *full_name = NULL;
char *common_dir = NULL;
char *old_default_name = NULL;
char *old_krb5ccname = NULL;
char *old_krb5cctype = NULL;
const char *name;
unsigned int matched;
memset(&cred, 0, sizeof(cred));
memset(&cred2, 0, sizeof(cred2));
memset(&mcred, 0, sizeof(mcred));
memset(&found, 0, sizeof(found));
ret = krb5_cc_register(context, &krb5_mcc_ops, FALSE);
if (ret != KRB5_CC_TYPE_EXISTS)
krb5_err(context, 1, ret, "krb5_cc_register duplicate MEMORY");
old_krb5ccname = getenv("KRB5CCNAME") ? estrdup(getenv("KRB5CCNAME")) : NULL;
old_krb5cctype = getenv("KRB5CCTYPE") ? estrdup(getenv("KRB5CCTYPE")) : NULL;
name = krb5_cc_default_name(context);
if (name)
old_default_name = estrdup(name);
setenv("KRB5CCTYPE", "UNKNOWN-CCACHE-TYPE", 1);
ret = krb5_init_context(&env_context);
if (ret)
krb5_err(context, 1, ret, "krb5_init_context unknown type");
ret = krb5_cc_resolve_sub(env_context, NULL, NULL, NULL, &id);
if (ret != KRB5_CC_UNKNOWN_TYPE)
krb5_err(env_context, 1, ret, "krb5_cc_resolve_sub unknown type");
krb5_free_context(env_context);
env_context = NULL;
restore_env("KRB5CCTYPE", old_krb5cctype);
setenv("KRB5CCNAME", "MEMORY:env-one", 1);
ret = krb5_cc_set_default_name(context, NULL);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_set_default_name env-one");
name = krb5_cc_default_name(context);
if (name == NULL || strcmp(name, "MEMORY:env-one") != 0)
krb5_errx(context, 1, "krb5_cc_default_name env-one");
setenv("KRB5CCNAME", "MEMORY:env-two", 1);
name = krb5_cc_default_name(context);
if (name == NULL || strcmp(name, "MEMORY:env-two") != 0)
krb5_errx(context, 1, "krb5_cc_default_name env-two");
restore_env("KRB5CCNAME", old_krb5ccname);
setenv("KRB5CCTYPE", "MEMORY", 1);
ret = krb5_init_context(&env_context);
if (ret)
krb5_err(context, 1, ret, "krb5_init_context");
name = krb5_cc_default_name(env_context);
if (name == NULL || strcmp(name, "MEMORY:") != 0)
krb5_errx(env_context, 1, "MEMORY default name was %s",
name ? name : "<null>");
ret = krb5_cc_new_unique(env_context, NULL, NULL, &id);
if (ret)
krb5_err(env_context, 1, ret, "krb5_cc_new_unique default MEMORY");
ret = krb5_cc_destroy(env_context, id);
if (ret)
krb5_err(env_context, 1, ret, "krb5_cc_destroy default MEMORY");
id = NULL;
krb5_free_context(env_context);
restore_env("KRB5CCTYPE", old_krb5cctype);
ret = krb5_init_context(&env_context);
if (ret)
krb5_err(context, 1, ret, "krb5_init_context configured default");
ret = krb5_set_config(env_context,
"[libdefaults]\n"
"\tdefault_cc_name = MEMORY:configured-default\n");
if (ret)
krb5_err(env_context, 1, ret, "krb5_set_config default_cc_name");
name = krb5_cc_default_name(env_context);
if (name == NULL || strcmp(name, "MEMORY:configured-default") != 0)
krb5_errx(env_context, 1, "configured default name was %s",
name ? name : "<null>");
krb5_free_context(env_context);
env_context = NULL;
setenv("KRB5CCTYPE", "MEMORY", 1);
ret = krb5_init_context(&env_context);
if (ret)
krb5_err(context, 1, ret, "krb5_init_context collection default");
full_name = krb5_cccol_get_default_ccname(env_context);
if (full_name == NULL || strcmp(full_name, "MEMORY:") != 0)
krb5_errx(env_context, 1, "collection default name was %s",
full_name ? full_name : "<null>");
free(full_name);
full_name = NULL;
krb5_free_context(env_context);
env_context = NULL;
restore_env("KRB5CCTYPE", old_krb5cctype);
test_cache_common_backend_ops(context, "MEMORY:cache-common-memory");
if (asprintf(&full_name, "FILE:%s/cache-common-file", tmpdir) == -1 ||
full_name == NULL)
krb5_err(context, 1, errno, "asprintf common FILE");
test_cache_common_backend_ops(context, full_name);
free(full_name);
full_name = NULL;
if (krb5_cc_get_prefix_ops(context, krb5_cc_type_scc)) {
if (asprintf(&full_name, "SCC:%s/cache-common-scc", tmpdir) == -1 ||
full_name == NULL)
krb5_err(context, 1, errno, "asprintf common SCC");
test_cache_common_backend_ops(context, full_name);
unlink(full_name + sizeof("SCC:") - 1);
free(full_name);
full_name = NULL;
}
if (asprintf(&common_dir, "%s/cache-common-dir", tmpdir) == -1 ||
common_dir == NULL ||
asprintf(&full_name, "DIR:%s:common", common_dir) == -1 ||
full_name == NULL)
krb5_err(context, 1, errno, "asprintf common DIR");
test_cache_common_backend_ops(context, full_name);
rmdir(common_dir);
free(common_dir);
common_dir = NULL;
free(full_name);
full_name = NULL;
#ifdef HAVE_KEYUTILS_H
test_cache_common_backend_ops(context,
"KEYRING:process:cache-common-keyring");
#endif
ret = krb5_parse_name(context, "lha@SU.SE", &p);
if (ret)
krb5_err(context, 1, ret, "krb5_parse_name");
ret = krb5_cc_resolve(context, "MEMORY:cache-naming", &id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve MEMORY");
ret = krb5_cc_initialize(context, id, p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_initialize MEMORY");
name = krb5_cc_get_name(context, id);
if (name == NULL || strcmp(name, "cache-naming") != 0)
krb5_errx(context, 1, "MEMORY name was %s",
name ? name : "<null>");
ret = krb5_cc_get_full_name(context, id, &full_name);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_get_full_name");
if (strcmp(full_name, "MEMORY:cache-naming") != 0)
krb5_errx(context, 1, "krb5_cc_get_full_name got %s", full_name);
free(full_name);
full_name = NULL;
if (krb5_cc_get_ops(context, id) != &krb5_mcc_ops)
krb5_errx(context, 1, "krb5_cc_get_ops");
ret = krb5_cc_resolve(context, "MEMORY:anonymous", &id2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve anonymous MEMORY");
ret = krb5_cc_initialize(context, id2, p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_initialize anonymous MEMORY");
ret = krb5_cc_destroy(context, id2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_destroy anonymous MEMORY");
id2 = NULL;
ret = krb5_cccol_last_change_time(context, NULL, &mtime);
if (ret || mtime == 0)
krb5_err(context, 1, ret, "krb5_cccol_last_change_time");
make_cursor_cred(context, &cred, "host/server@SU.SE");
if (krb5_is_config_principal(context, cred.server))
krb5_errx(context, 1, "service ticket is a config principal");
ret = krb5_make_principal(context, &p2, "X-CACHECONF:", "not-conf", NULL);
if (ret)
krb5_err(context, 1, ret, "krb5_make_principal not-conf");
if (krb5_is_config_principal(context, p2))
krb5_errx(context, 1, "not-conf is a config principal");
krb5_free_principal(context, p2);
p2 = NULL;
krb5_cc_clear_mcred(&mcred);
if (mcred.client != NULL || mcred.server != NULL)
krb5_errx(context, 1, "krb5_cc_clear_mcred");
ret = krb5_cc_set_default_name(context, "MEMORY:cache-default");
if (ret)
krb5_err(context, 1, ret, "krb5_cc_set_default_name cache-default");
ret = krb5_cc_default_sub(context, "cache-sub", &id2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_default_sub");
name = krb5_cc_get_name(context, id2);
if (name == NULL || strcmp(name, "cache-sub") != 0)
krb5_errx(context, 1, "default name was %s",
name ? name : "<null>");
ret = krb5_cc_destroy(context, id2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_destroy default sub");
id2 = NULL;
ret = krb5_cc_default_for(context, p, &id2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_default_for");
name = krb5_cc_get_name(context, id2);
if (name == NULL || strchr(name, '/') || strchr(name, '+') ||
strchr(name, ':') || strchr(name, '\\'))
krb5_errx(context, 1, "default_for name was %s",
name ? name : "<null>");
ret = krb5_cc_destroy(context, id2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_destroy default for");
id2 = NULL;
ret = krb5_parse_name(context, "svc/foo+bar\\:baz\\\\quux@SU.SE", &p2);
if (ret)
krb5_err(context, 1, ret, "krb5_parse_name resolve_for");
ret = krb5_cc_resolve_for(context, krb5_cc_type_memory, "MEMORY:ignored",
p2, &id2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve_for MEMORY");
name = krb5_cc_get_name(context, id2);
if (name == NULL || strchr(name, '/') || strchr(name, '+') ||
strchr(name, ':') || strchr(name, '\\'))
krb5_errx(context, 1, "unsanitized name was %s",
name ? name : "<null>");
ret = krb5_cc_destroy(context, id2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_destroy resolve_for");
id2 = NULL;
krb5_free_principal(context, p2);
p2 = NULL;
ret = krb5_cc_resolve(context, "MEMORY:copy-match-from", &fromid);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve copy source");
ret = krb5_cc_resolve(context, "MEMORY:copy-match-to", &toid);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve copy target");
ret = krb5_cc_initialize(context, fromid, p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_initialize copy source");
make_cursor_cred(context, &cred2, "host/matched@SU.SE");
ret = krb5_cc_store_cred(context, fromid, &cred2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_store_cred matched");
ret = krb5_cc_store_cred(context, fromid, &cred);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_store_cred unmatched");
ret = krb5_cc_copy_match_f(context, fromid, toid, server_principal_match,
cred2.server, &matched);
if (ret || matched != 1)
krb5_err(context, 1, ret, "krb5_cc_copy_match_f");
ret = krb5_cc_retrieve_cred(context, toid, 0, &cred2, &found);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_retrieve_cred matched");
krb5_free_cred_contents(context, &found);
memset(&found, 0, sizeof(found));
ret = krb5_cc_retrieve_cred(context, toid, 0, &cred, &found);
if (ret == 0)
krb5_errx(context, 1, "krb5_cc_copy_match_f copied unmatched cred");
ret = krb5_cc_destroy(context, fromid);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_destroy copy source");
fromid = NULL;
ret = krb5_cc_destroy(context, toid);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_destroy copy target");
toid = NULL;
ret = krb5_cc_resolve(context, "MEMORY:cache-end-seq", &id2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve cache-end-seq");
ret = krb5_cc_initialize(context, id2, p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_initialize cache-end-seq");
ret = krb5_cc_cache_get_first(context, krb5_cc_type_memory, &cache_cursor);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_cache_get_first MEMORY");
ret = krb5_cc_cache_end_seq_get(context, cache_cursor);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_cache_end_seq_get MEMORY");
ret = krb5_cc_destroy(context, id2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_destroy cache-end-seq");
id2 = NULL;
ret = krb5_cc_resolve(context, "MEMORY:move-fallback-from", &fromid);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve move source");
if (asprintf(&full_name, "FILE:%s/move-fallback", tmpdir) == -1 ||
full_name == NULL)
krb5_err(context, 1, errno, "asprintf move target");
ret = krb5_cc_resolve(context, full_name, &toid);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve move target");
free(full_name);
full_name = NULL;
ret = krb5_cc_initialize(context, fromid, p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_initialize move source");
ret = krb5_cc_store_cred(context, fromid, &cred);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_store_cred move source");
ret = krb5_cc_move(context, fromid, toid);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_move fallback");
fromid = NULL;
ret = krb5_cc_get_principal(context, toid, &p2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_get_principal moved fallback");
if (!krb5_principal_compare(context, p, p2))
krb5_errx(context, 1, "moved fallback principal mismatch");
krb5_free_principal(context, p2);
p2 = NULL;
ret = krb5_cc_retrieve_cred(context, toid, 0, &cred, &found);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_retrieve_cred moved fallback");
check_cred_contents(context, &cred, &found, "moved fallback");
krb5_free_cred_contents(context, &found);
memset(&found, 0, sizeof(found));
ret = krb5_cc_destroy(context, toid);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_destroy move target");
toid = NULL;
ret = krb5_cc_cache_get_first(context, "UNKNOWN-CCACHE-TYPE", &cache_cursor);
if (ret != KRB5_CC_UNKNOWN_TYPE)
krb5_err(context, 1, ret, "krb5_cc_cache_get_first unknown type");
ret = krb5_cc_new_unique(context, "UNKNOWN-CCACHE-TYPE", NULL, &id2);
if (ret != KRB5_CC_UNKNOWN_TYPE)
krb5_err(context, 1, ret, "krb5_cc_new_unique unknown type");
if (krb5_cc_support_switch(context, krb5_cc_type_memory))
krb5_errx(context, 1, "MEMORY should not support switch");
if (krb5_cc_support_switch(context, "UNKNOWN-CCACHE-TYPE"))
krb5_errx(context, 1, "unknown type should not support switch");
krb5_free_cred_contents(context, &cred);
krb5_free_cred_contents(context, &cred2);
krb5_free_principal(context, p);
ret = krb5_cc_destroy(context, id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_destroy memory naming");
ret = krb5_cc_set_default_name(context, old_default_name);
if (ret)
krb5_err(context, 1, ret, "restore default ccache name");
free(old_default_name);
free(old_krb5ccname);
free(old_krb5cctype);
free(common_dir);
}
static void
test_fcache_file_format_and_collections(krb5_context context)
{
krb5_error_code ret;
krb5_context iter_context = NULL;
krb5_ccache id = NULL, id2 = NULL, id3 = NULL, iter_id = NULL;
krb5_cc_cursor cursor;
krb5_cc_cache_cursor cache_cursor;
krb5_principal p = NULL, p2 = NULL, got_p = NULL;
krb5_creds cred, found;
krb5_deltat offset;
const char *name;
char *old_default_name = NULL;
char *full_name = NULL;
char *path = NULL, *path2 = NULL, *ccname = NULL;
char *dir = NULL, *config = NULL;
char *primary_name = NULL, *sub_name = NULL, *sub2_name = NULL;
int old_fcache_vno = 0;
int32_t old_kdc_sec = 0, old_kdc_usec = 0;
unsigned char raw[2];
unsigned char payload = 1;
int version;
size_t count;
krb5_boolean saw_p, saw_p2;
memset(&cred, 0, sizeof(cred));
memset(&found, 0, sizeof(found));
ret = krb5_parse_name(context, "lha@SU.SE", &p);
if (ret)
krb5_err(context, 1, ret, "krb5_parse_name");
ret = krb5_parse_name(context, "sub@SU.SE", &p2);
if (ret)
krb5_err(context, 1, ret, "krb5_parse_name");
ret = krb5_get_fcache_version(context, &old_fcache_vno);
if (ret)
krb5_err(context, 1, ret, "krb5_get_fcache_version");
ret = krb5_get_kdc_sec_offset(context, &old_kdc_sec, &old_kdc_usec);
if (ret)
krb5_err(context, 1, ret, "krb5_get_kdc_sec_offset");
name = krb5_cc_default_name(context);
if (name)
old_default_name = estrdup(name);
if (asprintf(&path, "%s/fcache-default", tmpdir) == -1 || path == NULL ||
asprintf(&ccname, "FILE:%s", path) == -1 || ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_cc_set_default_name(context, ccname);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_set_default_name FILE");
ret = krb5_cc_resolve_sub(context, NULL, NULL, NULL, &id);
if (ret == 0)
krb5_errx(context, 1, "krb5_cc_resolve_sub FILE without names");
ret = krb5_cc_default_sub(context, "sub-default", &id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_default_sub FILE");
name = krb5_cc_get_name(context, id);
if (name == NULL || strstr(name, "sub-default") == NULL)
krb5_errx(context, 1, "FILE default-sub name was %s",
name ? name : "<null>");
ret = krb5_cc_close(context, id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_close FILE default sub");
id = NULL;
free(path);
free(ccname);
path = ccname = NULL;
if (asprintf(&path, "%s/fcache-split", tmpdir) == -1 || path == NULL ||
asprintf(&ccname, "FILE:%s+child", path) == -1 || ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_cc_resolve(context, ccname, &id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve FILE split");
ret = krb5_cc_get_full_name(context, id, &full_name);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_get_full_name FILE split");
if (strcmp(full_name, ccname) != 0)
krb5_errx(context, 1, "FILE split full name was %s", full_name);
free(full_name);
full_name = NULL;
if (strcmp(krb5_cc_get_name(context, id),
ccname + sizeof("FILE:") - 1) != 0)
krb5_errx(context, 1, "FILE split name was %s",
krb5_cc_get_name(context, id));
ret = krb5_cc_close(context, id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_close FILE split");
id = NULL;
free(ccname);
ccname = NULL;
if (asprintf(&ccname, "FILE:%s+", path) == -1 || ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_cc_resolve(context, ccname, &id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve FILE trailing split");
ret = krb5_cc_get_full_name(context, id, &full_name);
if (ret)
krb5_err(context, 1, ret,
"krb5_cc_get_full_name FILE trailing split");
if (strcmp(full_name, ccname) != 0)
krb5_errx(context, 1, "FILE trailing split full name was %s",
full_name);
free(full_name);
full_name = NULL;
ret = krb5_cc_close(context, id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_close FILE trailing split");
id = NULL;
free(path);
free(ccname);
path = ccname = NULL;
for (version = 1; version <= 4; version++) {
ret = krb5_set_fcache_version(context, version);
if (ret)
krb5_err(context, 1, ret, "krb5_set_fcache_version");
ret = krb5_set_kdc_sec_offset(context, version == 4 ? 123 : 0,
version == 4 ? 456 : 0);
if (ret)
krb5_err(context, 1, ret, "krb5_set_kdc_sec_offset");
if (asprintf(&path, "%s/fcache-v%d", tmpdir, version) == -1 ||
path == NULL ||
asprintf(&ccname, "FILE:%s", path) == -1 || ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_cc_resolve(context, ccname, &id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve FILE version");
ret = krb5_cc_initialize(context, id, p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_initialize FILE version");
make_cursor_cred(context, &cred, "host/fcache@SU.SE");
ret = krb5_cc_store_cred(context, id, &cred);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_store_cred FILE version");
if (krb5_cc_get_version(context, id) != version)
krb5_errx(context, 1, "FILE cache version mismatch");
ret = krb5_cc_get_principal(context, id, &got_p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_get_principal FILE version");
if (!krb5_principal_compare(context, p, got_p))
krb5_errx(context, 1, "FILE principal mismatch");
krb5_free_principal(context, got_p);
got_p = NULL;
ret = krb5_cc_retrieve_cred(context, id, 0, &cred, &found);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_retrieve_cred FILE version");
check_cred_contents(context, &cred, &found, "FILE retrieved");
krb5_free_cred_contents(context, &found);
memset(&found, 0, sizeof(found));
ret = krb5_cc_start_seq_get(context, id, &cursor);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_start_seq_get FILE version");
ret = krb5_cc_next_cred(context, id, &cursor, &found);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_next_cred FILE version");
check_cred_contents(context, &cred, &found, "FILE iterated");
krb5_free_cred_contents(context, &found);
memset(&found, 0, sizeof(found));
ret = krb5_cc_next_cred(context, id, &cursor, &found);
if (ret != KRB5_CC_END)
krb5_err(context, 1, ret, "krb5_cc_next_cred FILE end");
ret = krb5_cc_end_seq_get(context, id, &cursor);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_end_seq_get FILE version");
if (version == 4) {
ret = krb5_cc_get_kdc_offset(context, id, &offset);
if (ret || offset != 123)
krb5_err(context, 1, ret, "krb5_cc_get_kdc_offset FILE");
cursor = NULL;
ret = krb5_cc_next_cred(context, id, &cursor, &found);
if (ret == 0)
krb5_errx(context, 1,
"FILE cache accepted null next cursor");
ret = krb5_cc_end_seq_get(context, id, &cursor);
if (ret == 0)
krb5_errx(context, 1,
"FILE cache accepted null end cursor");
}
krb5_free_cred_contents(context, &cred);
ret = krb5_cc_destroy(context, id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_destroy FILE version");
id = NULL;
free(path);
free(ccname);
path = ccname = NULL;
}
ret = krb5_set_fcache_version(context, old_fcache_vno);
if (ret)
krb5_err(context, 1, ret, "restore fcache version");
ret = krb5_set_kdc_sec_offset(context, old_kdc_sec, old_kdc_usec);
if (ret)
krb5_err(context, 1, ret, "restore kdc offset");
if (asprintf(&path, "%s/fcache-empty", tmpdir) == -1 || path == NULL)
krb5_err(context, 1, errno, "asprintf");
write_file_bytes(context, path, NULL, 0);
expect_bad_file_cache(context, path, "empty FILE cache");
expect_bad_file_cache_seq(context, path, "empty FILE cache");
unlink(path);
free(path);
path = NULL;
raw[0] = 4;
raw[1] = 4;
if (asprintf(&path, "%s/fcache-bad-pvno", tmpdir) == -1 || path == NULL)
krb5_err(context, 1, errno, "asprintf");
write_file_bytes(context, path, raw, sizeof(raw));
expect_bad_file_cache(context, path, "bad pvno FILE cache");
unlink(path);
free(path);
path = NULL;
raw[0] = 5;
if (asprintf(&path, "%s/fcache-missing-tag", tmpdir) == -1 || path == NULL)
krb5_err(context, 1, errno, "asprintf");
write_file_bytes(context, path, raw, 1);
expect_bad_file_cache(context, path, "missing tag FILE cache");
unlink(path);
free(path);
path = NULL;
if (asprintf(&path, "%s/fcache-v4-no-length", tmpdir) == -1 || path == NULL)
krb5_err(context, 1, errno, "asprintf");
write_fcache_v4_file(context, path, FALSE, 0, FALSE, 0, FALSE, 0, NULL, 0);
expect_bad_file_cache(context, path, "v4 missing tag length FILE cache");
unlink(path);
free(path);
path = NULL;
if (asprintf(&path, "%s/fcache-v4-no-dtag", tmpdir) == -1 || path == NULL)
krb5_err(context, 1, errno, "asprintf");
write_fcache_v4_file(context, path, TRUE, 4, FALSE, 0, FALSE, 0, NULL, 0);
expect_bad_file_cache(context, path, "v4 missing dtag FILE cache");
unlink(path);
free(path);
path = NULL;
if (asprintf(&path, "%s/fcache-v4-no-dlen", tmpdir) == -1 || path == NULL)
krb5_err(context, 1, errno, "asprintf");
write_fcache_v4_file(context, path, TRUE, 4, TRUE, 99, FALSE, 0, NULL, 0);
expect_bad_file_cache(context, path, "v4 missing dlength FILE cache");
unlink(path);
free(path);
path = NULL;
if (asprintf(&path, "%s/fcache-v4-short-kdc", tmpdir) == -1 || path == NULL)
krb5_err(context, 1, errno, "asprintf");
write_fcache_v4_file(context, path, TRUE, 12, TRUE, 1, TRUE, 8, NULL, 0);
expect_bad_file_cache(context, path, "v4 short kdc offset FILE cache");
unlink(path);
free(path);
path = NULL;
if (asprintf(&path, "%s/fcache-v4-short-unknown", tmpdir) == -1 ||
path == NULL)
krb5_err(context, 1, errno, "asprintf");
write_fcache_v4_file(context, path, TRUE, 5, TRUE, 99, TRUE, 1, NULL, 0);
expect_bad_file_cache(context, path, "v4 short unknown tag FILE cache");
unlink(path);
free(path);
path = NULL;
if (asprintf(&path, "%s/fcache-v4-unknown-tag", tmpdir) == -1 ||
path == NULL)
krb5_err(context, 1, errno, "asprintf");
write_fcache_v4_file(context, path, TRUE, 5, TRUE, 99, TRUE, 1,
&payload, 1);
expect_bad_file_cache(context, path, "v4 unknown tag FILE cache");
expect_bad_file_cache_seq(context, path, "v4 unknown tag FILE cache");
unlink(path);
free(path);
path = NULL;
if (asprintf(&path, "%s/fcache-missing", tmpdir) == -1 || path == NULL)
krb5_err(context, 1, errno, "asprintf");
unlink(path);
expect_bad_file_cache(context, path, "missing FILE cache");
free(path);
path = NULL;
if (asprintf(&path, "%s/fcache-directory", tmpdir) == -1 || path == NULL)
krb5_err(context, 1, errno, "asprintf");
if (mkdir(path, 0700) == -1)
krb5_err(context, 1, errno, "mkdir(%s)", path);
expect_bad_file_cache(context, path, "directory FILE cache");
rmdir(path);
free(path);
path = NULL;
#ifndef _WIN32
if (asprintf(&path, "%s/fcache-symlink-target", tmpdir) == -1 ||
path == NULL ||
asprintf(&path2, "%s/fcache-symlink", tmpdir) == -1 || path2 == NULL)
krb5_err(context, 1, errno, "asprintf");
raw[0] = 5;
raw[1] = 4;
write_file_bytes(context, path, raw, sizeof(raw));
if (symlink(path, path2) == -1)
krb5_err(context, 1, errno, "symlink(%s)", path2);
expect_bad_file_cache(context, path2, "symlink FILE cache");
unlink(path2);
unlink(path);
free(path);
free(path2);
path = path2 = NULL;
if (asprintf(&path, "%s/fcache-hardlink-target", tmpdir) == -1 ||
path == NULL ||
asprintf(&path2, "%s/fcache-hardlink", tmpdir) == -1 || path2 == NULL)
krb5_err(context, 1, errno, "asprintf");
write_file_bytes(context, path, raw, sizeof(raw));
if (link(path, path2) == -1)
krb5_err(context, 1, errno, "link(%s)", path2);
expect_bad_file_cache(context, path2, "hardlink FILE cache");
unlink(path2);
unlink(path);
free(path);
free(path2);
path = path2 = NULL;
#endif
#ifndef _WIN32
if (asprintf(&path, "%s/fcache-open-denied", tmpdir) == -1 ||
path == NULL ||
asprintf(&ccname, "FILE:%s", path) == -1 || ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_cc_resolve(context, ccname, &id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve open denied");
ret = krb5_cc_initialize(context, id, p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_initialize open denied");
make_cursor_cred(context, &cred, "host/open-denied@SU.SE");
ret = krb5_cc_store_cred(context, id, &cred);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_store_cred open denied");
krb5_free_cred_contents(context, &cred);
memset(&cred, 0, sizeof(cred));
if (geteuid() != 0) {
if (chmod(path, 0000) == -1)
krb5_err(context, 1, errno, "chmod(%s)", path);
ret = krb5_cc_get_principal(context, id, &got_p);
if (ret == 0)
krb5_errx(context, 1, "chmod 000 FILE cache opened");
if (chmod(path, 0600) == -1)
krb5_err(context, 1, errno, "chmod(%s)", path);
}
ret = krb5_cc_destroy(context, id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_destroy open denied");
id = NULL;
free(path);
free(ccname);
path = ccname = NULL;
if (asprintf(&path, "%s/fcache-strict-mode", tmpdir) == -1 ||
path == NULL ||
asprintf(&ccname, "FILE:%s", path) == -1 || ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_cc_resolve(context, ccname, &id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve strict mode");
ret = krb5_cc_initialize(context, id, p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_initialize strict mode");
make_cursor_cred(context, &cred, "host/strict-mode@SU.SE");
ret = krb5_cc_store_cred(context, id, &cred);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_store_cred strict mode");
krb5_free_cred_contents(context, &cred);
memset(&cred, 0, sizeof(cred));
if (chmod(path, 0644) == -1)
krb5_err(context, 1, errno, "chmod(%s)", path);
ret = krb5_cc_get_principal(context, id, &got_p);
if (ret == 0)
krb5_errx(context, 1, "group-readable FILE cache opened");
if (chmod(path, 0600) == -1)
krb5_err(context, 1, errno, "chmod(%s)", path);
ret = krb5_cc_destroy(context, id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_destroy strict mode");
id = NULL;
free(path);
free(ccname);
path = ccname = NULL;
if (geteuid() != 0) {
if (asprintf(&path, "%s/fcache-remove-readonly", tmpdir) == -1 ||
path == NULL ||
asprintf(&ccname, "FILE:%s", path) == -1 || ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_cc_resolve(context, ccname, &id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve remove readonly");
ret = krb5_cc_initialize(context, id, p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_initialize remove readonly");
make_cursor_cred(context, &cred, "host/remove-readonly@SU.SE");
ret = krb5_cc_store_cred(context, id, &cred);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_store_cred remove readonly");
if (chmod(path, 0400) == -1)
krb5_err(context, 1, errno, "chmod(%s)", path);
ret = krb5_cc_remove_cred(context, id, 0, &cred);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_remove_cred remove readonly");
if (chmod(path, 0600) == -1)
krb5_err(context, 1, errno, "chmod(%s)", path);
krb5_free_cred_contents(context, &cred);
memset(&cred, 0, sizeof(cred));
ret = krb5_cc_destroy(context, id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_destroy remove readonly");
id = NULL;
free(path);
free(ccname);
path = ccname = NULL;
}
#endif
if (asprintf(&path, "%s/no-such-dir/fcache-init", tmpdir) == -1 ||
path == NULL ||
asprintf(&ccname, "FILE:%s", path) == -1 || ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_cc_resolve(context, ccname, &id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve missing parent");
ret = krb5_cc_initialize(context, id, p);
if (ret == 0)
krb5_errx(context, 1, "FILE cache initialized in missing parent");
ret = krb5_cc_close(context, id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_close missing parent");
id = NULL;
free(path);
free(ccname);
path = ccname = NULL;
if (asprintf(&path, "%s/fcache-move-missing-from", tmpdir) == -1 ||
path == NULL ||
asprintf(&path2, "%s/fcache-move-missing-to", tmpdir) == -1 ||
path2 == NULL)
krb5_err(context, 1, errno, "asprintf");
if (asprintf(&ccname, "FILE:%s", path) == -1 || ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_cc_resolve(context, ccname, &id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve missing move from");
free(ccname);
ccname = NULL;
if (asprintf(&ccname, "FILE:%s", path2) == -1 || ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_cc_resolve(context, ccname, &id2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve missing move to");
ret = krb5_cc_move(context, id, id2);
if (ret == 0)
krb5_errx(context, 1, "FILE move of missing source succeeded");
ret = krb5_cc_destroy(context, id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_destroy missing move from");
id = NULL;
ret = krb5_cc_destroy(context, id2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_destroy missing move to");
id2 = NULL;
free(path);
free(path2);
free(ccname);
path = path2 = ccname = NULL;
if (asprintf(&path, "%s/fcache-move-to-dir-from", tmpdir) == -1 ||
path == NULL ||
asprintf(&path2, "%s/fcache-move-to-dir-to", tmpdir) == -1 ||
path2 == NULL)
krb5_err(context, 1, errno, "asprintf");
if (mkdir(path2, 0700) == -1)
krb5_err(context, 1, errno, "mkdir(%s)", path2);
if (asprintf(&ccname, "FILE:%s", path) == -1 || ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_cc_resolve(context, ccname, &id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve move tmp dir from");
free(ccname);
ccname = NULL;
if (asprintf(&ccname, "FILE:%s", path2) == -1 || ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_cc_resolve(context, ccname, &id2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve move tmp dir to");
ret = krb5_cc_initialize(context, id, p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_initialize move tmp dir");
ret = krb5_cc_move(context, id, id2);
if (ret == 0)
krb5_errx(context, 1, "FILE move to directory succeeded");
ret = krb5_cc_destroy(context, id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_destroy move tmp dir from");
id = NULL;
ret = krb5_cc_close(context, id2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_close move tmp dir to");
id2 = NULL;
rmdir(path2);
free(path);
free(path2);
free(ccname);
path = path2 = ccname = NULL;
if (asprintf(&path, "%s/fcache-move-tmp-from", tmpdir) == -1 ||
path == NULL ||
asprintf(&path2, "%s/fcache-move-tmp-to", tmpdir) == -1 ||
path2 == NULL)
krb5_err(context, 1, errno, "asprintf");
if (asprintf(&ccname, "FILE:%s", path) == -1 || ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_cc_resolve(context, ccname, &id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve move tmp from");
free(ccname);
ccname = NULL;
if (asprintf(&ccname, "FILE:%s", path2) == -1 || ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_cc_resolve(context, ccname, &id2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve move tmp to");
ret = krb5_cc_initialize(context, id, p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_initialize move tmp");
ret = krb5_cc_move(context, id, id2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_move FILE tmp");
id = NULL;
ret = krb5_cc_get_principal(context, id2, &got_p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_get_principal move tmp");
if (!krb5_principal_compare(context, p, got_p))
krb5_errx(context, 1, "FILE tmp move principal mismatch");
krb5_free_principal(context, got_p);
got_p = NULL;
ret = krb5_cc_destroy(context, id2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_destroy move tmp");
id2 = NULL;
free(path);
free(path2);
free(ccname);
path = path2 = ccname = NULL;
if (asprintf(&dir, "%s/fcache-switch-dir", tmpdir) == -1 || dir == NULL ||
asprintf(&ccname, "FILE:%s+sub", dir) == -1 || ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
if (mkdir(dir, 0700) == -1)
krb5_err(context, 1, errno, "mkdir(%s)", dir);
ret = krb5_cc_resolve(context, ccname, &id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve switch dir");
ret = krb5_cc_initialize(context, id, p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_initialize switch dir");
make_cursor_cred(context, &cred, "host/switch-dir@SU.SE");
ret = krb5_cc_store_cred(context, id, &cred);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_store_cred switch dir");
ret = krb5_cc_switch(context, id);
if (ret == 0)
krb5_errx(context, 1, "FILE switch to directory primary succeeded");
krb5_free_cred_contents(context, &cred);
memset(&cred, 0, sizeof(cred));
ret = krb5_cc_destroy(context, id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_destroy switch dir");
id = NULL;
rmdir(dir);
free(dir);
free(ccname);
dir = ccname = NULL;
if (asprintf(&dir, "%s/fccol2", tmpdir) == -1 || dir == NULL)
krb5_err(context, 1, errno, "asprintf");
if (mkdir(dir, 0700) == -1)
krb5_err(context, 1, errno, "mkdir(%s)", dir);
if (asprintf(&primary_name, "FILE:%s/primary", dir) == -1 ||
primary_name == NULL ||
asprintf(&sub_name, "FILE:%s/primary+sub1", dir) == -1 ||
sub_name == NULL ||
asprintf(&sub2_name, "FILE:%s/primary+sub2", dir) == -1 ||
sub2_name == NULL ||
asprintf(&config,
"[libdefaults]\n"
"\tdefault_cc_name = %s\n"
"\tdefault_file_cache_collections = %s\n"
"\tenable_file_cache_iteration = true\n",
primary_name, primary_name) == -1 || config == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_init_context(&iter_context);
if (ret)
krb5_err(context, 1, ret, "krb5_init_context fcache iteration");
ret = krb5_set_config(iter_context, config);
if (ret)
krb5_err(iter_context, 1, ret, "krb5_set_config fcache iteration");
ret = krb5_cc_resolve(iter_context, primary_name, &id);
if (ret)
krb5_err(iter_context, 1, ret, "krb5_cc_resolve fcache primary");
ret = krb5_cc_initialize(iter_context, id, p);
if (ret)
krb5_err(iter_context, 1, ret, "krb5_cc_initialize fcache primary");
make_cursor_cred(iter_context, &cred, "host/primary@SU.SE");
ret = krb5_cc_store_cred(iter_context, id, &cred);
if (ret)
krb5_err(iter_context, 1, ret, "krb5_cc_store_cred primary");
krb5_free_cred_contents(iter_context, &cred);
memset(&cred, 0, sizeof(cred));
ret = krb5_cc_resolve(iter_context, sub_name, &id2);
if (ret)
krb5_err(iter_context, 1, ret, "krb5_cc_resolve fcache sub");
ret = krb5_cc_initialize(iter_context, id2, p2);
if (ret)
krb5_err(iter_context, 1, ret, "krb5_cc_initialize fcache sub");
make_cursor_cred(iter_context, &cred, "host/sub@SU.SE");
ret = krb5_cc_store_cred(iter_context, id2, &cred);
if (ret)
krb5_err(iter_context, 1, ret, "krb5_cc_store_cred sub");
krb5_free_cred_contents(iter_context, &cred);
memset(&cred, 0, sizeof(cred));
ret = krb5_cc_resolve(iter_context, sub2_name, &id3);
if (ret)
krb5_err(iter_context, 1, ret, "krb5_cc_resolve fcache sub2");
ret = krb5_cc_initialize(iter_context, id3, p);
if (ret)
krb5_err(iter_context, 1, ret, "krb5_cc_initialize fcache sub2");
make_cursor_cred(iter_context, &cred, "host/sub2@SU.SE");
ret = krb5_cc_store_cred(iter_context, id3, &cred);
if (ret)
krb5_err(iter_context, 1, ret, "krb5_cc_store_cred sub2");
krb5_free_cred_contents(iter_context, &cred);
memset(&cred, 0, sizeof(cred));
if (asprintf(&path, "%s/primary+notfile", dir) == -1 || path == NULL)
krb5_err(context, 1, errno, "asprintf");
if (mkdir(path, 0700) == -1)
krb5_err(context, 1, errno, "mkdir(%s)", path);
ret = krb5_cc_switch(iter_context, id);
if (ret)
krb5_err(iter_context, 1, ret, "krb5_cc_switch fcache primary");
ret = krb5_cc_switch(iter_context, id2);
if (ret)
krb5_err(iter_context, 1, ret, "krb5_cc_switch fcache sub");
ret = krb5_cc_get_principal(iter_context, id, &got_p);
if (ret)
krb5_err(iter_context, 1, ret, "krb5_cc_get_principal switched");
if (!krb5_principal_compare(iter_context, p2, got_p))
krb5_errx(iter_context, 1, "fcc_set_default_cache did not copy");
krb5_free_principal(iter_context, got_p);
got_p = NULL;
ret = krb5_cc_cache_get_first(iter_context, krb5_cc_type_file,
&cache_cursor);
if (ret)
krb5_err(iter_context, 1, ret, "krb5_cc_cache_get_first FILE");
ret = krb5_cc_cache_next(iter_context, cache_cursor, &iter_id);
if (ret)
krb5_err(iter_context, 1, ret, "krb5_cc_cache_next FILE early");
krb5_cc_close(iter_context, iter_id);
iter_id = NULL;
ret = krb5_cc_cache_next(iter_context, cache_cursor, &iter_id);
if (ret)
krb5_err(iter_context, 1, ret, "krb5_cc_cache_next FILE early sub");
krb5_cc_close(iter_context, iter_id);
iter_id = NULL;
ret = krb5_cc_cache_end_seq_get(iter_context, cache_cursor);
if (ret)
krb5_err(iter_context, 1, ret, "krb5_cc_cache_end_seq_get FILE early");
ret = krb5_cc_cache_get_first(iter_context, krb5_cc_type_file,
&cache_cursor);
if (ret)
krb5_err(iter_context, 1, ret, "krb5_cc_cache_get_first FILE");
count = 0;
while ((ret = krb5_cc_cache_next(iter_context, cache_cursor, &iter_id)) == 0) {
count++;
if (strcmp(krb5_cc_get_type(iter_context, iter_id),
krb5_cc_type_file) != 0)
krb5_errx(iter_context, 1, "FILE iteration returned %s",
krb5_cc_get_type(iter_context, iter_id));
krb5_cc_close(iter_context, iter_id);
iter_id = NULL;
}
if (ret != KRB5_CC_END)
krb5_err(iter_context, 1, ret, "krb5_cc_cache_next FILE");
ret = krb5_cc_cache_end_seq_get(iter_context, cache_cursor);
if (ret)
krb5_err(iter_context, 1, ret, "krb5_cc_cache_end_seq_get FILE");
if (count != 3)
krb5_errx(iter_context, 1, "FILE cache iteration found %lu caches",
(unsigned long)count);
ret = krb5_cc_destroy(iter_context, id2);
if (ret)
krb5_err(iter_context, 1, ret, "krb5_cc_destroy fcache sub");
id2 = NULL;
ret = krb5_cc_destroy(iter_context, id3);
if (ret)
krb5_err(iter_context, 1, ret, "krb5_cc_destroy fcache sub2");
id3 = NULL;
ret = krb5_cc_destroy(iter_context, id);
if (ret)
krb5_err(iter_context, 1, ret, "krb5_cc_destroy fcache primary");
id = NULL;
krb5_free_context(iter_context);
iter_context = NULL;
rmdir(path);
free(path);
path = NULL;
rmdir(dir);
free(dir);
dir = NULL;
free(config);
config = NULL;
free(primary_name);
primary_name = NULL;
free(sub_name);
sub_name = NULL;
free(sub2_name);
sub2_name = NULL;
if (asprintf(&primary_name, "FILE:%s/fccol-missing/primary", tmpdir) == -1 ||
primary_name == NULL ||
asprintf(&config,
"[libdefaults]\n"
"\tdefault_cc_name = %s\n"
"\tdefault_file_cache_collections = %s\n"
"\tenable_file_cache_iteration = true\n",
primary_name, primary_name) == -1 || config == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_init_context(&iter_context);
if (ret)
krb5_err(context, 1, ret,
"krb5_init_context fcache missing iteration");
ret = krb5_set_config(iter_context, config);
if (ret)
krb5_err(iter_context, 1, ret,
"krb5_set_config fcache missing iteration");
ret = krb5_cc_cache_get_first(iter_context, krb5_cc_type_file,
&cache_cursor);
if (ret)
krb5_err(iter_context, 1, ret,
"krb5_cc_cache_get_first FILE missing dir");
ret = krb5_cc_cache_next(iter_context, cache_cursor, &iter_id);
if (ret)
krb5_err(iter_context, 1, ret,
"krb5_cc_cache_next FILE missing dir base");
ret = krb5_cc_close(iter_context, iter_id);
if (ret)
krb5_err(iter_context, 1, ret,
"krb5_cc_close FILE missing dir base");
iter_id = NULL;
ret = krb5_cc_cache_next(iter_context, cache_cursor, &iter_id);
if (ret != KRB5_CC_END)
krb5_err(iter_context, 1, ret,
"krb5_cc_cache_next FILE missing dir end");
ret = krb5_cc_cache_end_seq_get(iter_context, cache_cursor);
if (ret)
krb5_err(iter_context, 1, ret,
"krb5_cc_cache_end_seq_get FILE missing dir");
krb5_free_context(iter_context);
iter_context = NULL;
free(config);
config = NULL;
free(primary_name);
primary_name = NULL;
if (asprintf(&primary_name, "FILE:fcache-rel-%ld", (long)getpid()) == -1 ||
primary_name == NULL ||
asprintf(&sub_name, "%s+sub", primary_name) == -1 ||
sub_name == NULL ||
asprintf(&ccname, "%s+default", primary_name) == -1 ||
ccname == NULL ||
asprintf(&config,
"[libdefaults]\n"
"\tdefault_cc_name = %s\n"
"\tdefault_file_cache_collections = %s\n"
"\tenable_file_cache_iteration = true\n",
ccname, primary_name) == -1 || config == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_init_context(&iter_context);
if (ret)
krb5_err(context, 1, ret,
"krb5_init_context fcache relative iteration");
ret = krb5_set_config(iter_context, config);
if (ret)
krb5_err(iter_context, 1, ret,
"krb5_set_config fcache relative iteration");
ret = krb5_cc_resolve(iter_context, primary_name, &id);
if (ret)
krb5_err(iter_context, 1, ret,
"krb5_cc_resolve fcache relative primary");
ret = krb5_cc_initialize(iter_context, id, p);
if (ret)
krb5_err(iter_context, 1, ret,
"krb5_cc_initialize fcache relative primary");
make_cursor_cred(iter_context, &cred, "host/relative-primary@SU.SE");
ret = krb5_cc_store_cred(iter_context, id, &cred);
if (ret)
krb5_err(iter_context, 1, ret,
"krb5_cc_store_cred fcache relative primary");
krb5_free_cred_contents(iter_context, &cred);
memset(&cred, 0, sizeof(cred));
ret = krb5_cc_resolve(iter_context, sub_name, &id2);
if (ret)
krb5_err(iter_context, 1, ret, "krb5_cc_resolve fcache relative sub");
ret = krb5_cc_initialize(iter_context, id2, p2);
if (ret)
krb5_err(iter_context, 1, ret,
"krb5_cc_initialize fcache relative sub");
make_cursor_cred(iter_context, &cred, "host/relative-sub@SU.SE");
ret = krb5_cc_store_cred(iter_context, id2, &cred);
if (ret)
krb5_err(iter_context, 1, ret,
"krb5_cc_store_cred fcache relative sub");
krb5_free_cred_contents(iter_context, &cred);
memset(&cred, 0, sizeof(cred));
ret = krb5_cc_resolve(iter_context, ccname, &id3);
if (ret)
krb5_err(iter_context, 1, ret,
"krb5_cc_resolve fcache relative default");
ret = krb5_cc_initialize(iter_context, id3, p);
if (ret)
krb5_err(iter_context, 1, ret,
"krb5_cc_initialize fcache relative default");
make_cursor_cred(iter_context, &cred, "host/relative-default@SU.SE");
ret = krb5_cc_store_cred(iter_context, id3, &cred);
if (ret)
krb5_err(iter_context, 1, ret,
"krb5_cc_store_cred fcache relative default");
krb5_free_cred_contents(iter_context, &cred);
memset(&cred, 0, sizeof(cred));
ret = krb5_cc_cache_get_first(iter_context, krb5_cc_type_file,
&cache_cursor);
if (ret)
krb5_err(iter_context, 1, ret,
"krb5_cc_cache_get_first FILE relative");
count = 0;
saw_p = saw_p2 = FALSE;
while ((ret = krb5_cc_cache_next(iter_context, cache_cursor, &iter_id)) == 0) {
count++;
if (strcmp(krb5_cc_get_type(iter_context, iter_id),
krb5_cc_type_file) != 0)
krb5_errx(iter_context, 1, "relative FILE iteration returned %s",
krb5_cc_get_type(iter_context, iter_id));
ret = krb5_cc_get_principal(iter_context, iter_id, &got_p);
if (ret)
krb5_err(iter_context, 1, ret,
"krb5_cc_get_principal relative FILE iterated");
if (krb5_principal_compare(iter_context, p, got_p))
saw_p = TRUE;
else if (krb5_principal_compare(iter_context, p2, got_p))
saw_p2 = TRUE;
else
krb5_errx(iter_context, 1,
"relative FILE iteration returned unexpected principal");
krb5_free_principal(iter_context, got_p);
got_p = NULL;
krb5_cc_close(iter_context, iter_id);
iter_id = NULL;
}
if (ret != KRB5_CC_END)
krb5_err(iter_context, 1, ret,
"krb5_cc_cache_next FILE relative");
ret = krb5_cc_cache_end_seq_get(iter_context, cache_cursor);
if (ret)
krb5_err(iter_context, 1, ret,
"krb5_cc_cache_end_seq_get FILE relative");
if (count < 2)
krb5_errx(iter_context, 1,
"relative FILE cache iteration found %lu caches",
(unsigned long)count);
if (!saw_p || !saw_p2)
krb5_errx(iter_context, 1,
"relative FILE iteration missed an expected principal");
ret = krb5_cc_destroy(iter_context, id3);
if (ret)
krb5_err(iter_context, 1, ret,
"krb5_cc_destroy fcache relative default");
id3 = NULL;
ret = krb5_cc_destroy(iter_context, id2);
if (ret)
krb5_err(iter_context, 1, ret,
"krb5_cc_destroy fcache relative sub");
id2 = NULL;
ret = krb5_cc_destroy(iter_context, id);
if (ret)
krb5_err(iter_context, 1, ret,
"krb5_cc_destroy fcache relative primary");
id = NULL;
krb5_free_context(iter_context);
iter_context = NULL;
free(config);
config = NULL;
free(primary_name);
primary_name = NULL;
free(sub_name);
sub_name = NULL;
free(ccname);
ccname = NULL;
ret = krb5_cc_set_default_name(context, old_default_name);
if (ret)
krb5_err(context, 1, ret, "restore default ccache name after fcache");
free(old_default_name);
free(full_name);
free(path);
free(path2);
free(ccname);
free(dir);
free(config);
free(primary_name);
free(sub_name);
free(sub2_name);
krb5_free_principal(context, p);
krb5_free_principal(context, p2);
}
static void
test_dcache_names_and_collections(krb5_context context)
{
krb5_error_code ret;
krb5_context cfg_context = NULL;
krb5_ccache id = NULL, id2 = NULL, iter_id = NULL;
krb5_cc_cache_cursor cache_cursor;
krb5_principal p = NULL, got_p = NULL;
krb5_creds cred;
const char *name;
char *old_default_name = NULL;
char *dir = NULL, *dcc = NULL, *dcc_plain = NULL, *ccname = NULL;
char *path = NULL, *path2 = NULL, *config = NULL;
size_t count;
memset(&cred, 0, sizeof(cred));
ret = krb5_parse_name(context, "lha@SU.SE", &p);
if (ret)
krb5_err(context, 1, ret, "krb5_parse_name dcache");
name = krb5_cc_default_name(context);
if (name)
old_default_name = estrdup(name);
if (asprintf(&dir, "%s/dccover", tmpdir) == -1 || dir == NULL ||
asprintf(&dcc, "DIR:%s/", dir) == -1 || dcc == NULL ||
asprintf(&dcc_plain, "DIR:%s", dir) == -1 || dcc_plain == NULL)
krb5_err(context, 1, errno, "asprintf");
if (mkdir(dir, 0700) == -1)
krb5_err(context, 1, errno, "mkdir(%s)", dir);
ret = krb5_cc_set_default_name(context, dcc);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_set_default_name DIR");
expect_bad_cc_resolve(context, "DIR:", "empty DIR cache name");
if (asprintf(&ccname, "DIR:%s/dccover-missing/child", tmpdir) == -1 ||
ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
expect_bad_cc_resolve(context, ccname, "DIR cache missing parent");
free(ccname);
ccname = NULL;
if (asprintf(&path, "%s/dccover-file", tmpdir) == -1 || path == NULL ||
asprintf(&ccname, "DIR:%s", path) == -1 || ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
write_file_bytes(context, path, "x", 1);
expect_bad_cc_resolve(context, ccname, "DIR cache directory is file");
unlink(path);
free(path);
free(ccname);
path = ccname = NULL;
if (asprintf(&path, "%s/primary", dir) == -1 || path == NULL)
krb5_err(context, 1, errno, "asprintf");
write_file_bytes(context, path, "notcache\n", sizeof("notcache\n") - 1);
expect_bad_cc_resolve(context, dcc_plain, "DIR cache bad primary");
unlink(path);
#ifndef _WIN32
if (mkdir(path, 0700) == -1)
krb5_err(context, 1, errno, "mkdir(%s)", path);
expect_bad_cc_resolve(context, dcc_plain, "DIR cache directory primary");
rmdir(path);
#endif
free(path);
path = NULL;
if (asprintf(&ccname, "DIR::%s/notcache", dir) == -1 || ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
expect_bad_cc_resolve(context, ccname, "DIR explicit non-tkt cache");
free(ccname);
ccname = NULL;
if (asprintf(&ccname, "DIR:%s:tktbad/name", dir) == -1 ||
ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
expect_bad_cc_resolve(context, ccname, "DIR cache subsidiary with slash");
free(ccname);
ccname = NULL;
expect_bad_cc_resolve(context, "DIR::/tkt.empty",
"DIR cache with empty directory");
if (asprintf(&path, "%s/dccover-file2", tmpdir) == -1 ||
path == NULL ||
asprintf(&ccname, "DIR:%s:sub", path) == -1 || ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
write_file_bytes(context, path, "x", 1);
expect_bad_cc_resolve(context, ccname, "DIR cache file collection");
unlink(path);
free(path);
free(ccname);
path = ccname = NULL;
if (asprintf(&ccname, "DIR:%s:colon", dir) == -1 || ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_cc_resolve(context, ccname, &id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve DIR path:NAME");
free(ccname);
ccname = NULL;
name = krb5_cc_get_name(context, id);
if (name == NULL || strstr(name, dir) == NULL ||
strstr(name, "/tkt.colon") == NULL)
krb5_errx(context, 1, "DIR name was %s",
name ? name : "<null>");
ret = krb5_cc_close(context, id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_close DIR path:NAME");
id = NULL;
if (asprintf(&ccname, "DIR::%s/tkt.explicit", dir) == -1 ||
ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_cc_resolve(context, ccname, &id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve DIR explicit path");
free(ccname);
ccname = NULL;
name = krb5_cc_get_name(context, id);
if (name == NULL || strstr(name, dir) == NULL ||
strstr(name, "/tkt.explicit") == NULL)
krb5_errx(context, 1, "DIR explicit name was %s",
name ? name : "<null>");
ret = krb5_cc_close(context, id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_close DIR explicit path");
id = NULL;
if (asprintf(&config,
"[libdefaults]\n"
"\tdefault_cc_collection = DIR:%s\n", dir) == -1 ||
config == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_init_context(&cfg_context);
if (ret)
krb5_err(context, 1, ret, "krb5_init_context DIR config");
ret = krb5_set_config(cfg_context, config);
if (ret)
krb5_err(cfg_context, 1, ret, "krb5_set_config DIR config");
ret = krb5_cc_resolve(cfg_context, "DIR::named", &id);
if (ret)
krb5_err(cfg_context, 1, ret, "krb5_cc_resolve DIR::NAME");
name = krb5_cc_get_name(cfg_context, id);
if (name == NULL || strstr(name, dir) == NULL ||
strstr(name, "/tkt.named") == NULL)
krb5_errx(cfg_context, 1, "DIR::NAME name was %s",
name ? name : "<null>");
ret = krb5_cc_close(cfg_context, id);
if (ret)
krb5_err(cfg_context, 1, ret, "krb5_cc_close DIR::NAME");
id = NULL;
ret = krb5_cc_resolve_sub(cfg_context, NULL, NULL, "subname", &id);
if (ret)
krb5_err(cfg_context, 1, ret, "krb5_cc_resolve_sub DIR default");
name = krb5_cc_get_name(cfg_context, id);
if (name == NULL || strstr(name, dir) == NULL ||
strstr(name, "/tkt.subname") == NULL)
krb5_errx(cfg_context, 1, "DIR default sub name was %s",
name ? name : "<null>");
ret = krb5_cc_close(cfg_context, id);
if (ret)
krb5_err(cfg_context, 1, ret, "krb5_cc_close DIR default sub");
id = NULL;
krb5_free_context(cfg_context);
cfg_context = NULL;
free(config);
config = NULL;
if (asprintf(&config,
"[libdefaults]\n"
"\tdefault_cc_collection = DIR:%%{\n") == -1 ||
config == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_init_context(&cfg_context);
if (ret)
krb5_err(context, 1, ret, "krb5_init_context DIR bad config");
ret = krb5_set_config(cfg_context, config);
if (ret)
krb5_err(cfg_context, 1, ret, "krb5_set_config DIR bad config");
ret = krb5_cc_resolve_sub(cfg_context, NULL, NULL, "subname", &id);
if (ret == 0) {
krb5_cc_close(cfg_context, id);
krb5_errx(cfg_context, 1,
"DIR default subsidiary accepted bad default collection");
}
ret = krb5_cc_resolve(cfg_context, "DIR::named", &id);
if (ret == 0) {
krb5_cc_close(cfg_context, id);
krb5_errx(cfg_context, 1,
"DIR::NAME accepted bad default collection");
}
krb5_free_context(cfg_context);
cfg_context = NULL;
free(config);
config = NULL;
if (asprintf(&config,
"[libdefaults]\n"
"\tdefault_cc_collection = FILE:%s/not-dir\n", tmpdir) == -1 ||
config == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_init_context(&cfg_context);
if (ret)
krb5_err(context, 1, ret, "krb5_init_context DIR fallback config");
ret = krb5_set_config(cfg_context, config);
if (ret)
krb5_err(cfg_context, 1, ret, "krb5_set_config DIR fallback config");
ret = krb5_cc_new_unique(cfg_context, krb5_cc_type_dcc, NULL, &id);
if (ret)
krb5_err(cfg_context, 1, ret, "krb5_cc_new_unique DIR fallback");
ret = krb5_cc_destroy(cfg_context, id);
if (ret)
krb5_err(cfg_context, 1, ret, "krb5_cc_destroy DIR fallback");
id = NULL;
krb5_free_context(cfg_context);
cfg_context = NULL;
free(config);
config = NULL;
if (asprintf(&path, "%s/primary", dir) == -1 || path == NULL)
krb5_err(context, 1, errno, "asprintf");
if (mkdir(path, 0700) == -1)
krb5_err(context, 1, errno, "mkdir(%s)", path);
if (asprintf(&ccname, "DIR:%s:renamefail", dir) == -1 || ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_cc_resolve(context, ccname, &id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve DIR rename failure");
free(ccname);
ccname = NULL;
ret = krb5_cc_initialize(context, id, p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_initialize DIR rename failure");
ret = krb5_cc_switch(context, id);
if (ret == 0)
krb5_errx(context, 1, "DIR switch over primary directory succeeded");
ret = krb5_cc_destroy(context, id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_destroy DIR rename failure");
id = NULL;
rmdir(path);
free(path);
path = NULL;
#ifndef _WIN32
if (geteuid() != 0) {
if (asprintf(&ccname, "DIR:%s:nowrite", dir) == -1 ||
ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_cc_resolve(context, ccname, &id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve DIR no-write");
free(ccname);
ccname = NULL;
ret = krb5_cc_initialize(context, id, p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_initialize DIR no-write");
if (chmod(dir, 0500) == -1)
krb5_err(context, 1, errno, "chmod(%s)", dir);
ret = krb5_cc_switch(context, id);
if (ret == 0)
krb5_errx(context, 1, "DIR switch in no-write directory succeeded");
if (chmod(dir, 0700) == -1)
krb5_err(context, 1, errno, "chmod(%s)", dir);
ret = krb5_cc_destroy(context, id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_destroy DIR no-write");
id = NULL;
if (asprintf(&path, "%s/dccover-no-search", tmpdir) == -1 ||
path == NULL ||
asprintf(&ccname, "DIR:%s/child:sub", path) == -1 ||
ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
if (mkdir(path, 0700) == -1)
krb5_err(context, 1, errno, "mkdir(%s)", path);
if (chmod(path, 0000) == -1)
krb5_err(context, 1, errno, "chmod(%s)", path);
expect_bad_cc_resolve(context, ccname, "DIR cache no-search parent");
if (chmod(path, 0700) == -1)
krb5_err(context, 1, errno, "chmod(%s)", path);
rmdir(path);
free(path);
free(ccname);
path = ccname = NULL;
if (asprintf(&path, "%s/dccover-no-write-new", tmpdir) == -1 ||
path == NULL ||
asprintf(&config,
"[libdefaults]\n"
"\tdefault_cc_collection = DIR:%s\n", path) == -1 ||
config == NULL)
krb5_err(context, 1, errno, "asprintf");
if (mkdir(path, 0700) == -1)
krb5_err(context, 1, errno, "mkdir(%s)", path);
ret = krb5_init_context(&cfg_context);
if (ret)
krb5_err(context, 1, ret,
"krb5_init_context DIR no-write new");
ret = krb5_set_config(cfg_context, config);
if (ret)
krb5_err(cfg_context, 1, ret,
"krb5_set_config DIR no-write new");
if (chmod(path, 0500) == -1)
krb5_err(context, 1, errno, "chmod(%s)", path);
ret = krb5_cc_new_unique(cfg_context, krb5_cc_type_dcc, NULL, &id);
if (ret == 0) {
krb5_cc_destroy(cfg_context, id);
krb5_errx(cfg_context, 1,
"DIR new unique in no-write directory succeeded");
}
if (chmod(path, 0700) == -1)
krb5_err(context, 1, errno, "chmod(%s)", path);
krb5_free_context(cfg_context);
cfg_context = NULL;
rmdir(path);
free(path);
free(config);
path = config = NULL;
}
#endif
if (asprintf(&ccname, "DIR:%s:move-from", dir) == -1 || ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_cc_resolve(context, ccname, &id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve DIR move from");
free(ccname);
ccname = NULL;
ret = krb5_cc_initialize(context, id, p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_initialize DIR move from");
make_cursor_cred(context, &cred, "host/dcache-move@SU.SE");
ret = krb5_cc_store_cred(context, id, &cred);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_store_cred DIR move");
krb5_free_cred_contents(context, &cred);
memset(&cred, 0, sizeof(cred));
if (asprintf(&ccname, "DIR:%s:move-to", dir) == -1 || ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_cc_resolve(context, ccname, &id2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve DIR move to");
free(ccname);
ccname = NULL;
ret = krb5_cc_move(context, id, id2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_move DIR");
id = NULL;
ret = krb5_cc_get_principal(context, id2, &got_p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_get_principal DIR moved");
if (!krb5_principal_compare(context, p, got_p))
krb5_errx(context, 1, "DIR moved principal mismatch");
krb5_free_principal(context, got_p);
got_p = NULL;
ret = krb5_cc_destroy(context, id2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_destroy DIR moved");
id2 = NULL;
if (asprintf(&ccname, "DIR:%s:primary", dir) == -1 || ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_cc_resolve(context, ccname, &id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve DIR primary");
free(ccname);
ccname = NULL;
ret = krb5_cc_initialize(context, id, p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_initialize DIR primary");
make_cursor_cred(context, &cred, "host/dcache-primary@SU.SE");
ret = krb5_cc_store_cred(context, id, &cred);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_store_cred DIR primary");
krb5_free_cred_contents(context, &cred);
memset(&cred, 0, sizeof(cred));
ret = krb5_cc_switch(context, id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_switch DIR primary");
ret = krb5_cc_resolve(context, dcc_plain, &iter_id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve DIR switched primary");
ret = krb5_cc_get_principal(context, iter_id, &got_p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_get_principal DIR switched");
if (!krb5_principal_compare(context, p, got_p))
krb5_errx(context, 1, "DIR switched primary mismatch");
krb5_free_principal(context, got_p);
got_p = NULL;
ret = krb5_cc_close(context, iter_id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_close DIR switched primary");
iter_id = NULL;
if (asprintf(&ccname, "DIR:%s:other", dir) == -1 || ccname == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_cc_resolve(context, ccname, &id2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve DIR other");
free(ccname);
ccname = NULL;
ret = krb5_cc_initialize(context, id2, p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_initialize DIR other");
make_cursor_cred(context, &cred, "host/dcache-other@SU.SE");
ret = krb5_cc_store_cred(context, id2, &cred);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_store_cred DIR other");
krb5_free_cred_contents(context, &cred);
memset(&cred, 0, sizeof(cred));
if (asprintf(&path, "%s/tkt.notfile", dir) == -1 || path == NULL ||
asprintf(&path2, "%s/notcache", dir) == -1 || path2 == NULL)
krb5_err(context, 1, errno, "asprintf");
if (mkdir(path, 0700) == -1)
krb5_err(context, 1, errno, "mkdir(%s)", path);
write_file_bytes(context, path2, "x", 1);
free(dcc);
dcc = NULL;
if (asprintf(&dcc, "DIR:%s/:ignored", dir) == -1 || dcc == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_cc_set_default_name(context, dcc);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_set_default_name DIR iter");
ret = krb5_cc_cache_get_first(context, krb5_cc_type_dcc, &cache_cursor);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_cache_get_first DIR");
count = 0;
while ((ret = krb5_cc_cache_next(context, cache_cursor, &iter_id)) == 0) {
count++;
if (strcmp(krb5_cc_get_type(context, iter_id), krb5_cc_type_file) != 0)
krb5_errx(context, 1, "DIR iteration returned %s",
krb5_cc_get_type(context, iter_id));
krb5_cc_close(context, iter_id);
iter_id = NULL;
}
if (ret != KRB5_CC_END)
krb5_err(context, 1, ret, "krb5_cc_cache_next DIR");
ret = krb5_cc_cache_end_seq_get(context, cache_cursor);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_cache_end_seq_get DIR");
if (count != 2)
krb5_errx(context, 1, "DIR cache iteration found %lu caches",
(unsigned long)count);
rmdir(path);
unlink(path2);
free(path);
free(path2);
path = path2 = NULL;
ret = krb5_cc_destroy(context, id2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_destroy DIR other");
id2 = NULL;
ret = krb5_cc_destroy(context, id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_destroy DIR primary");
id = NULL;
if (asprintf(&path, "%s/tkt.notfile", dir) == -1 || path == NULL ||
asprintf(&path2, "%s/primary", dir) == -1 || path2 == NULL)
krb5_err(context, 1, errno, "asprintf");
if (mkdir(path, 0700) == -1)
krb5_err(context, 1, errno, "mkdir(%s)", path);
write_file_bytes(context, path2, "tkt.notfile\n",
sizeof("tkt.notfile\n") - 1);
ret = krb5_cc_set_default_name(context, dcc_plain);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_set_default_name DIR no primary");
ret = krb5_cc_cache_get_first(context, krb5_cc_type_dcc, &cache_cursor);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_cache_get_first DIR no primary");
ret = krb5_cc_cache_next(context, cache_cursor, &iter_id);
if (ret != KRB5_CC_END)
krb5_err(context, 1, ret, "krb5_cc_cache_next DIR no primary");
ret = krb5_cc_cache_end_seq_get(context, cache_cursor);
if (ret)
krb5_err(context, 1, ret,
"krb5_cc_cache_end_seq_get DIR no primary");
rmdir(path);
unlink(path2);
free(path);
free(path2);
path = path2 = NULL;
free(dcc);
dcc = NULL;
if (asprintf(&dcc, "DIR:%s/no-such-dcache-iter", tmpdir) == -1 ||
dcc == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_cc_set_default_name(context, dcc);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_set_default_name DIR missing iter");
ret = krb5_cc_cache_get_first(context, krb5_cc_type_dcc, &cache_cursor);
if (ret == 0) {
krb5_cc_cache_end_seq_get(context, cache_cursor);
krb5_errx(context, 1, "DIR iteration opened a missing directory");
}
ret = krb5_cc_set_default_name(context, old_default_name);
if (ret)
krb5_err(context, 1, ret, "restore default ccache name after dcache");
rmdir(dir);
free(old_default_name);
free(dir);
free(dcc);
free(dcc_plain);
free(ccname);
free(path);
free(path2);
free(config);
krb5_free_principal(context, p);
}
static void
expect_memory_cursor_invalidated(krb5_context context, krb5_ccache id,
krb5_cc_cursor *cursor, const char *what)
{
krb5_error_code ret;
krb5_creds found;
memset(&found, 0, sizeof(found));
ret = krb5_cc_next_cred(context, id, cursor, &found);
if (ret == 0) {
krb5_free_cred_contents(context, &found);
krb5_errx(context, 1,
"MEMORY cursor was not invalidated after %s", what);
}
if (ret != ENOENT && ret != KRB5_CC_END)
krb5_err(context, 1, ret,
"unexpected MEMORY cursor invalidation error after %s", what);
ret = krb5_cc_end_seq_get(context, id, cursor);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_end_seq_get");
}
static void
test_mcache_cursor_invalidation(krb5_context context)
{
krb5_error_code ret;
krb5_ccache id, id2;
krb5_cc_cursor cursor;
krb5_principal p;
krb5_creds cred1, cred2;
char *name = NULL;
ret = krb5_parse_name(context, "lha@SU.SE", &p);
if (ret)
krb5_err(context, 1, ret, "krb5_parse_name");
ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_new_unique");
if (asprintf(&name, "%s:%s", krb5_cc_get_type(context, id),
krb5_cc_get_name(context, id)) == -1 || name == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_cc_resolve(context, name, &id2);
free(name);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_resolve");
make_cursor_cred(context, &cred1, "krbtgt/SU.SE@SU.SE");
make_cursor_cred(context, &cred2, "krbtgt/H5L.SE@SU.SE");
ret = krb5_cc_initialize(context, id, p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_initialize");
ret = krb5_cc_store_cred(context, id, &cred1);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_store_cred");
ret = krb5_cc_start_seq_get(context, id, &cursor);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_start_seq_get");
ret = krb5_cc_initialize(context, id2, p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_initialize");
expect_memory_cursor_invalidated(context, id, &cursor, "initialize");
ret = krb5_cc_initialize(context, id, p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_initialize");
ret = krb5_cc_store_cred(context, id, &cred1);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_store_cred");
ret = krb5_cc_store_cred(context, id, &cred2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_store_cred");
ret = krb5_cc_start_seq_get(context, id, &cursor);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_start_seq_get");
ret = krb5_cc_remove_cred(context, id2, 0, &cred2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_remove_cred");
expect_memory_cursor_invalidated(context, id, &cursor, "remove");
krb5_free_cred_contents(context, &cred1);
krb5_free_cred_contents(context, &cred2);
krb5_cc_destroy(context, id);
krb5_cc_close(context, id2);
krb5_free_principal(context, p);
}
static void
test_mcc_default(void)
{
krb5_context context;
krb5_error_code ret;
krb5_ccache id, id2;
int i;
for (i = 0; i < 10; i++) {
ret = krb5_init_context(&context);
if (ret)
krb5_err(context, 1, ret, "krb5_init_context");
ret = krb5_cc_set_default_name(context, "MEMORY:foo");
if (ret)
krb5_err(context, 1, ret, "krb5_cc_set_default_name");
ret = krb5_cc_default(context, &id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_default");
ret = krb5_cc_default(context, &id2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_default");
ret = krb5_cc_close(context, id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_close");
ret = krb5_cc_close(context, id2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_close");
krb5_free_context(context);
}
}
const struct {
const char *str;
int fail;
const char *res;
} cc_names[] = {
{ "foo", 0, "foo" },
{ "foo%}", 0, "foo%}" },
{ "%{uid}", 0, NULL },
{ "%{euid}", 0, NULL },
{ "%{username}", 0, NULL },
{ "foo%{null}", 0, "foo" },
{ "foo%{null}bar", 0, "foobar" },
{ "%{", 1, NULL },
{ "%{foo %{", 1, NULL },
{ "%{{", 1, NULL },
{ "%{{}", 1, NULL },
{ "%{nulll}", 1, NULL },
{ "%{does not exist}", 1, NULL },
{ "%{}", 1, NULL },
#ifdef WIN32
{ "%{APPDATA}", 0, NULL },
{ "%{COMMON_APPDATA}", 0, NULL},
{ "%{LOCAL_APPDATA}", 0, NULL},
{ "%{SYSTEM}", 0, NULL},
{ "%{WINDOWS}", 0, NULL},
{ "%{TEMP}", 0, NULL},
{ "%{USERID}", 0, NULL},
{ "%{uid}", 0, NULL},
{ "%{USERCONFIG}", 0, NULL},
{ "%{COMMONCONFIG}", 0, NULL},
{ "%{LIBDIR}", 0, NULL},
{ "%{BINDIR}", 0, NULL},
{ "%{LIBEXEC}", 0, NULL},
{ "%{SBINDIR}", 0, NULL},
#endif
};
static void
test_def_cc_name(krb5_context context)
{
krb5_error_code ret;
char *str;
int i;
for (i = 0; i < sizeof(cc_names)/sizeof(cc_names[0]); i++) {
ret = _krb5_expand_default_cc_name(context, cc_names[i].str, &str);
if (ret) {
if (cc_names[i].fail == 0)
krb5_errx(context, 1, "test %d \"%s\" failed",
i, cc_names[i].str);
} else {
if (cc_names[i].fail)
krb5_errx(context, 1, "test %d \"%s\" was successful",
i, cc_names[i].str);
if (cc_names[i].res && strcmp(cc_names[i].res, str) != 0)
krb5_errx(context, 1, "test %d %s != %s",
i, cc_names[i].res, str);
if (debug_flag)
printf("%s => %s\n", cc_names[i].str, str);
free(str);
}
}
}
static void
test_cache_find(krb5_context context, const char *principal, int find)
{
krb5_principal client;
krb5_error_code ret;
krb5_ccache id = NULL;
ret = krb5_parse_name(context, principal, &client);
if (ret)
krb5_err(context, 1, ret, "parse_name for %s failed", principal);
ret = krb5_cc_cache_match(context, client, &id);
if (ret && find)
krb5_err(context, 1, ret, "cc_cache_match for %s failed", principal);
if (ret == 0 && !find)
krb5_err(context, 1, ret, "cc_cache_match for %s found", principal);
if (id)
krb5_cc_close(context, id);
krb5_free_principal(context, client);
}
static void
test_cache_iter(krb5_context context, const char *type, int destroy)
{
krb5_cc_cache_cursor cursor;
krb5_error_code ret;
krb5_ccache id;
ret = krb5_cc_cache_get_first (context, type, &cursor);
if (ret == KRB5_CC_NOSUPP)
return;
else if (ret)
krb5_err(context, 1, ret, "krb5_cc_cache_get_first(%s)", type);
while ((ret = krb5_cc_cache_next (context, cursor, &id)) == 0) {
krb5_principal principal;
char *name;
heim_assert(id != NULL, "credentials cache is non-NULL");
if (debug_flag)
printf("name: %s\n", krb5_cc_get_name(context, id));
ret = krb5_cc_get_principal(context, id, &principal);
if (ret == 0) {
ret = krb5_unparse_name(context, principal, &name);
if (ret == 0) {
if (debug_flag)
printf("\tprincipal: %s\n", name);
free(name);
}
krb5_free_principal(context, principal);
}
if (destroy)
krb5_cc_destroy(context, id);
else
krb5_cc_close(context, id);
}
krb5_cc_cache_end_seq_get(context, cursor);
}
static void
test_cache_iter_all(krb5_context context)
{
krb5_cccol_cursor cursor;
krb5_error_code ret;
krb5_ccache id;
ret = krb5_cccol_cursor_new (context, &cursor);
if (ret)
krb5_err(context, 1, ret, "krb5_cccol_cursor_new");
while ((ret = krb5_cccol_cursor_next (context, cursor, &id)) == 0 && id != NULL) {
krb5_principal principal;
char *name;
if (debug_flag)
printf("name: %s\n", krb5_cc_get_name(context, id));
ret = krb5_cc_get_principal(context, id, &principal);
if (ret == 0) {
ret = krb5_unparse_name(context, principal, &name);
if (ret == 0) {
if (debug_flag)
printf("\tprincipal: %s\n", name);
free(name);
}
krb5_free_principal(context, principal);
}
krb5_cc_close(context, id);
}
krb5_cccol_cursor_free(context, &cursor);
}
static void
test_copy(krb5_context context, const char *from, const char *to)
{
krb5_ccache fromid, toid;
krb5_error_code ret;
krb5_principal p, p2;
ret = krb5_parse_name(context, "lha@SU.SE", &p);
if (ret)
krb5_err(context, 1, ret, "krb5_parse_name");
ret = krb5_cc_new_unique(context, from, NULL, &fromid);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_new_unique: %s", from);
if (strcmp(krb5_cc_get_type(context, fromid), "FILE") == 0)
unlink_this = krb5_cc_get_name(context, fromid);
ret = krb5_cc_initialize(context, fromid, p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_initialize");
ret = krb5_cc_new_unique(context, to, NULL, &toid);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_gen_new: %s", to);
if (strcmp(krb5_cc_get_type(context, toid), "FILE") == 0)
unlink_this2 = krb5_cc_get_name(context, toid);
ret = krb5_cc_copy_cache(context, fromid, toid);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_copy_cache");
ret = krb5_cc_get_principal(context, toid, &p2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_get_principal");
if (krb5_principal_compare(context, p, p2) == FALSE)
krb5_errx(context, 1, "p != p2");
krb5_free_principal(context, p);
krb5_free_principal(context, p2);
krb5_cc_destroy(context, fromid);
krb5_cc_destroy(context, toid);
unlink_this = unlink_this2 = NULL;
}
static void
test_move(krb5_context context, const char *type)
{
const krb5_cc_ops *ops;
krb5_ccache fromid, toid;
krb5_error_code ret;
krb5_principal p, p2;
krb5_creds cred, tocred;
ops = krb5_cc_get_prefix_ops(context, type);
if (ops == NULL)
return;
ret = krb5_cc_new_unique(context, type, NULL, &fromid);
if (ret == KRB5_CC_NOSUPP)
return;
else if (ret)
krb5_err(context, 1, ret, "krb5_cc_new_unique: %s", type);
ret = krb5_parse_name(context, "lha@SU.SE", &p);
if (ret)
krb5_err(context, 1, ret, "krb5_parse_name");
ret = krb5_cc_initialize(context, fromid, p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_initialize");
memset(&cred, 0, sizeof(cred));
ret = krb5_parse_name(context, "krbtgt/SU.SE@SU.SE", &cred.server);
if (ret)
krb5_err(context, 1, ret, "krb5_parse_name");
ret = krb5_parse_name(context, "lha@SU.SE", &cred.client);
if (ret)
krb5_err(context, 1, ret, "krb5_parse_name");
ret = krb5_cc_store_cred(context, fromid, &cred);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_store_cred");
ret = krb5_cc_new_unique(context, type, NULL, &toid);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_new_unique");
ret = krb5_cc_move(context, fromid, toid);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_move");
ret = krb5_cc_get_principal(context, toid, &p2);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_get_principal");
if (krb5_principal_compare(context, p, p2) == FALSE)
krb5_errx(context, 1, "p != p2");
ret = krb5_cc_retrieve_cred(context, toid, 0, &cred, &tocred);
if (ret)
krb5_errx(context, 1, "move failed");
krb5_free_cred_contents(context, &cred);
krb5_free_cred_contents(context, &tocred);
krb5_free_principal(context, p);
krb5_free_principal(context, p2);
krb5_cc_destroy(context, toid);
}
static void
test_prefix_ops(krb5_context context, const char *name, const krb5_cc_ops *ops)
{
const krb5_cc_ops *o;
o = krb5_cc_get_prefix_ops(context, name);
if (o == NULL)
krb5_errx(context, 1, "found no match for prefix '%s'", name);
if (strcmp(o->prefix, ops->prefix) != 0)
krb5_errx(context, 1, "ops for prefix '%s' is not "
"the expected %s != %s", name, o->prefix, ops->prefix);
}
static void
test_cc_config(krb5_context context, const char *cc_type,
const char *cc_name, size_t count)
{
krb5_error_code ret;
krb5_principal p;
krb5_ccache id;
unsigned int i;
ret = krb5_cc_new_unique(context, cc_type, cc_name, &id);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_new_unique");
ret = krb5_parse_name(context, "lha@SU.SE", &p);
if (ret)
krb5_err(context, 1, ret, "krb5_parse_name");
ret = krb5_cc_initialize(context, id, p);
if (ret)
krb5_err(context, 1, ret, "krb5_cc_initialize");
for (i = 0; i < count; i++) {
krb5_data data, data2;
const char *name = "foo";
krb5_principal p1 = NULL;
if (i & 1)
p1 = p;
data.data = rk_UNCONST(name);
data.length = strlen(name);
/*
* Because of how krb5_cc_set_config() this will also test
* krb5_cc_remove_cred().
*/
ret = krb5_cc_set_config(context, id, p1, "FriendlyName", &data);
if (ret)
krb5_errx(context, 1, "krb5_cc_set_config: add");
ret = krb5_cc_get_config(context, id, p1, "FriendlyName", &data2);
if (ret)
krb5_errx(context, 1, "krb5_cc_get_config: first");
if (data.length != data2.length ||
memcmp(data.data, data2.data, data.length) != 0)
krb5_errx(context, 1, "krb5_cc_get_config: did not fetch what was set");
krb5_data_free(&data2);
data.data = rk_UNCONST("bar");
data.length = strlen("bar");
ret = krb5_cc_set_config(context, id, p1, "FriendlyName", &data);
if (ret)
krb5_errx(context, 1, "krb5_cc_set_config: add -second");
ret = krb5_cc_get_config(context, id, p1, "FriendlyName", &data2);
if (ret)
krb5_errx(context, 1, "krb5_cc_get_config: second");
if (data.length != data2.length ||
memcmp(data.data, data2.data, data.length) != 0)
krb5_errx(context, 1, "krb5_cc_get_config: replace failed");
krb5_data_free(&data2);
ret = krb5_cc_set_config(context, id, p1, "FriendlyName", NULL);
if (ret)
krb5_errx(context, 1, "krb5_cc_set_config: delete");
ret = krb5_cc_get_config(context, id, p1, "FriendlyName", &data2);
if (ret == 0)
krb5_errx(context, 1, "krb5_cc_get_config: non-existant");
if (data2.length)
krb5_errx(context, 1, "krb5_cc_get_config: delete failed");
}
krb5_cc_destroy(context, id);
krb5_free_principal(context, p);
}
static krb5_error_code
test_cccol(krb5_context context, const char *def_cccol, const char **what)
{
krb5_cc_cache_cursor cursor;
krb5_error_code ret;
krb5_principal p1, p2;
krb5_ccache id, id1, id2;
krb5_creds cred1, cred2;
size_t match1 = 0;
size_t match2 = 0;
memset(&cred1, 0, sizeof(cred1));
memset(&cred2, 0, sizeof(cred2));
*what = "krb5_parse_name";
ret = krb5_parse_name(context, "krbtgt/SU.SE@SU.SE", &cred1.server);
if (ret) return ret;
ret = krb5_parse_name(context, "lha@SU.SE", &cred1.client);
if (ret) return ret;
ret = krb5_parse_name(context, "krbtgt/H5L.SE@H5L.SE", &cred2.server);
if (ret) return ret;
ret = krb5_parse_name(context, "lha@H5L.SE", &cred2.client);
if (ret) return ret;
*what = "krb5_cc_set_default_name";
ret = krb5_cc_set_default_name(context, def_cccol);
if (ret) return ret;
*what = "krb5_cc_default";
ret = krb5_cc_default(context, &id1);
if (ret) return ret;
*what = "krb5_cc_initialize";
ret = krb5_cc_initialize(context, id1, cred1.client);
if (ret) return ret;
*what = "krb5_cc_store_cred";
ret = krb5_cc_store_cred(context, id1, &cred1);
if (ret) return ret;
*what = "krb5_cc_resolve";
ret = krb5_cc_resolve_for(context, NULL, def_cccol, cred2.client, &id2);
if (ret) return ret;
*what = "krb5_cc_initialize";
ret = krb5_cc_initialize(context, id2, cred2.client);
if (ret) return ret;
*what = "krb5_cc_store_cred";
ret = krb5_cc_store_cred(context, id2, &cred2);
if (ret) return ret;
krb5_cc_close(context, id1);
krb5_cc_close(context, id2);
id1 = id2 = NULL;
*what = "krb5_cc_default";
ret = krb5_cc_default(context, &id1);
if (ret) return ret;
*what = "krb5_cc_resolve";
ret = krb5_cc_resolve_for(context, NULL, def_cccol, cred2.client, &id2);
if (ret) return ret;
*what = "krb5_cc_get_principal";
ret = krb5_cc_get_principal(context, id1, &p1);
if (ret) return ret;
ret = krb5_cc_get_principal(context, id2, &p2);
if (ret) return ret;
if (!krb5_principal_compare(context, p1, cred1.client)) {
char *u1 = NULL;
char *u2 = NULL;
(void) krb5_unparse_name(context, p1, &u1);
(void) krb5_unparse_name(context, cred1.client, &u2);
warnx("Inconsistent principals for ccaches in %s: %s vs %s "
"(expected lha@SU.SE)", def_cccol, u1, u2);
return EINVAL;
}
if (!krb5_principal_compare(context, p2, cred2.client)) {
char *u1 = NULL;
char *u2 = NULL;
(void) krb5_unparse_name(context, p2, &u1);
(void) krb5_unparse_name(context, cred2.client, &u2);
warnx("Inconsistent principals for ccaches in %s: %s and %s "
"(expected lha@H5L.SE)", def_cccol, u1, u2);
return EINVAL;
}
krb5_free_principal(context, p1);
krb5_free_principal(context, p2);
*what = "krb5_cc_cache_get_first";
ret = krb5_cc_cache_get_first(context, NULL, &cursor);
if (ret) return ret;
*what = "krb5_cc_cache_next";
while (krb5_cc_cache_next(context, cursor, &id) == 0) {
krb5_principal p;
*what = "krb5_cc_get_principal";
ret = krb5_cc_get_principal(context, id, &p);
if (ret) return ret;
if (krb5_principal_compare(context, p, cred1.client))
match1++;
else if (krb5_principal_compare(context, p, cred2.client))
match2++;
krb5_free_principal(context, p);
krb5_cc_close(context, id);
}
(void) krb5_cc_cache_end_seq_get(context, cursor);
*what = "cccol iteration inconsistency";
if (match1 != 1 || match2 != 1)
return EINVAL;
krb5_cc_close(context, id1);
krb5_cc_close(context, id2);
krb5_free_cred_contents(context, &cred1);
krb5_free_cred_contents(context, &cred2);
return 0;
}
static void
test_cccol_dcache(krb5_context context)
{
krb5_error_code ret;
char *dcc = NULL;
const char *what;
if (asprintf(&dcc, "DIR:%s/dcc", tmpdir) == -1 || dcc == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = test_cccol(context, dcc, &what);
free(dcc);
if (ret)
krb5_err(context, 1, ret, "%s", what);
}
static void
test_cccol_scache(krb5_context context)
{
krb5_error_code ret;
char *scache = NULL;
const char *what;
int fd;
if (asprintf(&scache, "SCC:%s/scache", tmpdir) == -1 || scache == NULL)
krb5_err(context, 1, errno, "asprintf");
if ((fd = open(scache + sizeof("SCC:") - 1, O_CREAT | O_RDWR, 0600)) == -1)
krb5_err(context, 1, errno, "open(%s)", scache + sizeof("SCC:") - 1);
(void) close(fd);
ret = test_cccol(context, scache, &what);
(void) unlink(scache + sizeof("SCC:") - 1);
free(scache);
if (ret)
krb5_err(context, 1, ret, "%s", what);
}
static struct getargs args[] = {
{"debug", 'd', arg_flag, &debug_flag,
"turn on debuggin", NULL },
{"version", 0, arg_flag, &version_flag,
"print version", NULL },
{"help", 0, arg_flag, &help_flag,
NULL, NULL }
};
static void
usage (int ret)
{
arg_printusage (args, sizeof(args)/sizeof(*args), NULL, "hostname ...");
exit (ret);
}
int
main(int argc, char **argv)
{
krb5_context context;
krb5_error_code ret;
int optidx = 0;
krb5_ccache id1, id2;
setprogname(argv[0]);
if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
usage(1);
if (help_flag)
usage (0);
if(version_flag){
print_version(NULL);
exit(0);
}
argc -= optidx;
argv += optidx;
ret = krb5_init_context(&context);
if (ret)
errx (1, "krb5_init_context failed: %d", ret);
make_dir(context);
test_cache_remove(context, krb5_cc_type_file);
test_cache_remove(context, krb5_cc_type_memory);
#ifdef USE_SQLITE
test_cache_remove(context, krb5_cc_type_scc);
#endif
#ifdef HAVE_KEYUTILS_H
keyctl_join_session_keyring(NULL);
test_cache_remove(context, krb5_cc_type_keyring);
#endif
test_default_name(context);
test_mcache(context);
test_mcache_cursor_invalidation(context);
/*
* XXX Make sure to set default ccache names for each cc type!
* Otherwise we clobber the user's ccaches.
*/
test_init_vs_destroy(context, krb5_cc_type_memory);
test_init_vs_destroy(context, krb5_cc_type_file);
#if 0
test_init_vs_destroy(context, krb5_cc_type_api);
#endif
/*
* Cleanup so we can check that the permissions on the directory created by
* scc are correct.
*/
cleanup();
test_init_vs_destroy(context, krb5_cc_type_scc);
#if defined(S_IRWXG) && defined(S_IRWXO)
{
struct stat st;
if (stat(tmpdir, &st) == 0) {
if ((st.st_mode & S_IRWXG) ||
(st.st_mode & S_IRWXO))
krb5_errx(context, 1,
"SQLite3 ccache dir perms wrong: %d", st.st_mode);
}
}
#endif
test_init_vs_destroy(context, krb5_cc_type_dcc);
#ifdef HAVE_KEYUTILS_H
test_init_vs_destroy(context, krb5_cc_type_keyring);
#endif
test_mcc_default();
test_def_cc_name(context);
test_cache_defaults_and_common_ops(context);
test_fcache_file_format_and_collections(context);
test_dcache_names_and_collections(context);
test_cache_iter_all(context);
test_cache_iter(context, krb5_cc_type_memory, 0);
{
krb5_principal p;
krb5_cc_new_unique(context, krb5_cc_type_memory, "bar", &id1);
krb5_cc_new_unique(context, krb5_cc_type_memory, "baz", &id2);
krb5_parse_name(context, "lha@SU.SE", &p);
krb5_cc_initialize(context, id1, p);
krb5_free_principal(context, p);
}
test_cache_find(context, "lha@SU.SE", 1);
test_cache_find(context, "hulabundulahotentot@SU.SE", 0);
/*
* XXX We should compose and krb5_cc_set_default_name() a default ccache
* for each cc type that we test with test_cache_iter(), and we should do
* that inside test_cache_iter().
*
* Alternatively we should remove test_cache_iter() in favor of
* test_cccol(), which is a much more complete test.
*/
test_cache_iter(context, krb5_cc_type_memory, 0);
test_cache_iter(context, krb5_cc_type_memory, 1);
test_cache_iter(context, krb5_cc_type_memory, 0);
test_cache_iter(context, krb5_cc_type_file, 0);
test_cache_iter(context, krb5_cc_type_api, 0);
test_cache_iter(context, krb5_cc_type_scc, 0);
test_cache_iter(context, krb5_cc_type_scc, 1);
#if 0
test_cache_iter(context, krb5_cc_type_dcc, 0);
test_cache_iter(context, krb5_cc_type_dcc, 1);
#endif
#ifdef HAVE_KEYUTILS_H
test_cache_iter(context, krb5_cc_type_keyring, 0);
test_cache_iter(context, krb5_cc_type_keyring, 1);
#endif
test_copy(context, krb5_cc_type_file, krb5_cc_type_file);
test_copy(context, krb5_cc_type_memory, krb5_cc_type_memory);
test_copy(context, krb5_cc_type_file, krb5_cc_type_memory);
test_copy(context, krb5_cc_type_memory, krb5_cc_type_file);
test_copy(context, krb5_cc_type_scc, krb5_cc_type_file);
test_copy(context, krb5_cc_type_file, krb5_cc_type_scc);
test_copy(context, krb5_cc_type_scc, krb5_cc_type_memory);
test_copy(context, krb5_cc_type_memory, krb5_cc_type_scc);
#if 0
test_copy(context, krb5_cc_type_dcc, krb5_cc_type_memory);
test_copy(context, krb5_cc_type_dcc, krb5_cc_type_file);
test_copy(context, krb5_cc_type_dcc, krb5_cc_type_scc);
#endif
#ifdef HAVE_KEYUTILS_H
test_copy(context, krb5_cc_type_keyring, krb5_cc_type_file);
test_copy(context, "KEYRING:", "KEYRING:bar");
test_copy(context, "KEYRING:bar", "KEYRING:baz");
# ifdef HAVE_KEYCTL_GET_PERSISTENT
test_copy(context, krb5_cc_type_file, "KEYRING:persistent");
test_copy(context, "KEYRING:persistent:", krb5_cc_type_file);
test_copy(context, krb5_cc_type_file, "KEYRING:persistent:foo");
test_copy(context, "KEYRING:persistent:foo", krb5_cc_type_file);
# endif
test_copy(context, krb5_cc_type_memory, "KEYRING:process:");
test_copy(context, "KEYRING:process:", krb5_cc_type_memory);
test_copy(context, krb5_cc_type_memory, "KEYRING:process:foo");
test_copy(context, "KEYRING:process:foo", krb5_cc_type_memory);
test_copy(context, krb5_cc_type_memory, "KEYRING:thread:");
test_copy(context, "KEYRING:thread:", krb5_cc_type_memory);
test_copy(context, krb5_cc_type_memory, "KEYRING:thread:foo");
test_copy(context, "KEYRING:thread:foo", krb5_cc_type_memory);
test_copy(context, krb5_cc_type_memory, "KEYRING:session:");
test_copy(context, "KEYRING:session:", krb5_cc_type_memory);
test_copy(context, krb5_cc_type_memory, "KEYRING:session:foo");
test_copy(context, "KEYRING:session:foo", krb5_cc_type_memory);
test_copy(context, krb5_cc_type_file, "KEYRING:user:");
test_copy(context, "KEYRING:user:", krb5_cc_type_file);
test_copy(context, krb5_cc_type_file, "KEYRING:user:foo");
test_copy(context, "KEYRING:user:foo", krb5_cc_type_memory);
#endif /* HAVE_KEYUTILS_H */
test_move(context, krb5_cc_type_file);
test_move(context, krb5_cc_type_memory);
test_move(context, krb5_cc_type_scc);
#if 0
test_move(context, krb5_cc_type_dcc);
#endif
#ifdef HAVE_KEYUTILS_H
test_move(context, krb5_cc_type_keyring);
# ifdef HAVE_KEYCTL_GET_PERSISTENT
test_move(context, "KEYRING:persistent:");
test_move(context, "KEYRING:persistent:foo");
# endif
test_move(context, "KEYRING:process:");
test_move(context, "KEYRING:process:foo");
test_move(context, "KEYRING:thread:");
test_move(context, "KEYRING:thread:foo");
test_move(context, "KEYRING:session:");
test_move(context, "KEYRING:session:foo");
test_move(context, "KEYRING:user:");
test_move(context, "KEYRING:user:foo");
#endif /* HAVE_KEYUTILS_H */
test_prefix_ops(context, "FILE:/tmp/foo", &krb5_fcc_ops);
test_prefix_ops(context, "FILE", &krb5_fcc_ops);
test_prefix_ops(context, "MEMORY", &krb5_mcc_ops);
test_prefix_ops(context, "MEMORY:foo", &krb5_mcc_ops);
test_prefix_ops(context, "/tmp/kaka", &krb5_fcc_ops);
#ifdef HAVE_SCC
test_prefix_ops(context, "SCC:", &krb5_scc_ops);
test_prefix_ops(context, "SCC:foo", &krb5_scc_ops);
#endif
#if 0
test_prefix_ops(context, "DIR:", &krb5_dcc_ops);
test_prefix_ops(context, "DIR:tkt1", &krb5_dcc_ops);
#endif
#ifdef HAVE_KEYUTILS_H
test_prefix_ops(context, "KEYRING:", &krb5_krcc_ops);
test_prefix_ops(context, "KEYRING:foo", &krb5_krcc_ops);
#endif /* HAVE_KEYUTILS_H */
krb5_cc_destroy(context, id1);
krb5_cc_destroy(context, id2);
test_cc_config(context, "MEMORY", "bar", 1000); /* 1000 because fast */
test_cc_config(context, "FILE", "/tmp/foocc", 30); /* 30 because slower */
test_cccol_dcache(context);
test_cccol_scache(context);
#ifdef HAVE_KEYUTILS_H
{
const char *what;
ret = test_cccol(context, "KEYRING:legacy:fooccol", &what);
if (ret)
krb5_err(context, 1, ret, "%s", what);
ret = test_cccol(context, "MEMORY:fooccol", &what);
if (ret)
krb5_err(context, 1, ret, "%s", what);
}
#endif /* HAVE_KEYUTILS_H */
{
const char *what;
char *config = NULL;
char *fname = NULL;
char *d = NULL;
if (asprintf(&d, "%s/cccol", tmpdir) == -1 || d == NULL)
krb5_err(context, 1, errno, "asprintf");
if (mkdir(d, 0700) == -1)
krb5_err(context, 1, errno, "mkdir(%s)", d);
if (asprintf(&fname, "%s/foobar", d) == -1 || fname == NULL ||
asprintf(&config,
"[libdefaults]\n"
"\tdefault_file_cache_collections = FILE:%1$s/cccol/foobar\n"
"\tenable_file_cache_iteration = true\n",
tmpdir) == -1 || config == NULL)
krb5_err(context, 1, errno, "asprintf");
ret = krb5_set_config(context, config);
if (ret)
krb5_err(context, 1, ret,
"Could not configure context from string:\n%s\n", config);
ret = test_cccol(context, fname, &what);
if (ret)
krb5_err(context, 1, ret, "%s", what);
free(config);
free(fname);
free(d);
}
krb5_free_context(context);
#if 0
sleep(60);
#endif
return 0;
}