From f05facf7fed9be61b9b44e21eb543cdba8bcb48e Mon Sep 17 00:00:00 2001 From: Nicolas Williams Date: Mon, 29 May 2023 14:24:14 -0500 Subject: [PATCH] krb5: Improve SCC new unique (WIP) --- kcm/glue.c | 4 + kuser/kinit.1 | 8 + lib/gssapi/krb5/store_cred.c | 2 +- lib/krb5/acache.c | 7 +- lib/krb5/cache.c | 41 ++- lib/krb5/dcache.c | 36 +-- lib/krb5/fcache.c | 22 +- lib/krb5/kcm.c | 53 +++- lib/krb5/krb5.h | 2 +- lib/krb5/krcache.c | 16 +- lib/krb5/libkrb5-exports.def.in | 2 + lib/krb5/mcache.c | 7 +- lib/krb5/scache.c | 535 ++++++++++++++++---------------- lib/krb5/test_cc.c | 6 +- lib/krb5/version-script.map | 2 + 15 files changed, 408 insertions(+), 335 deletions(-) diff --git a/kcm/glue.c b/kcm/glue.c index 0895f48f05..610225b189 100644 --- a/kcm/glue.c +++ b/kcm/glue.c @@ -287,6 +287,10 @@ static const krb5_cc_ops krb5_kcmss_ops = { NULL, kcmss_get_name_2, kcmss_resolve_2, + NULL, + 0, + '\0', + ':' }; krb5_error_code diff --git a/kuser/kinit.1 b/kuser/kinit.1 index f374a7c062..82c21a0621 100644 --- a/kuser/kinit.1 +++ b/kuser/kinit.1 @@ -441,6 +441,14 @@ in the KEYRING collection named .Bl -tag -width Ds .It Ev KRB5CCNAME Specifies the default credentials cache. +.It Ev KRB5CCTYPE +Specifies the default credentials cache type. +This is only used when a specific credentials cache is not named with +.Ev KRB5CCNAME +or with an appropriate command-line option such as +.Fl c +for +.Nm . .It Ev KRB5_CONFIG The file name of .Pa krb5.conf , diff --git a/lib/gssapi/krb5/store_cred.c b/lib/gssapi/krb5/store_cred.c index 6d727b4e28..ec8af3fd4e 100644 --- a/lib/gssapi/krb5/store_cred.c +++ b/lib/gssapi/krb5/store_cred.c @@ -240,7 +240,7 @@ _gsskrb5_store_cred_into2(OM_uint32 *minor_status, HEIMDAL_MUTEX_lock(&input_cred->cred_id_mutex); if (cs_ccache_name && strchr(cs_ccache_name, '%')) { - ret = _krb5_expand_default_cc_name(context, cs_ccache_name, + ret = _krb5_expand_default_cc_name(context, NULL, cs_ccache_name, &ccache_name); if (ret) { HEIMDAL_MUTEX_unlock(&input_cred->cred_id_mutex); diff --git a/lib/krb5/acache.c b/lib/krb5/acache.c index 6cc1b8583a..70cb0a56fb 100644 --- a/lib/krb5/acache.c +++ b/lib/krb5/acache.c @@ -579,8 +579,9 @@ acc_resolve_2(krb5_context context, krb5_ccache *id, const char *res, const char } static krb5_error_code KRB5_CALLCONV -acc_gen_new(krb5_context context, krb5_ccache *id) +acc_gen_new_2(krb5_context context, const char *name, krb5_ccache *id) { + (void) name; return acc_alloc(context, id); } @@ -1098,7 +1099,7 @@ KRB5_LIB_VARIABLE const krb5_cc_ops krb5_acc_ops = { "API", NULL, NULL, - acc_gen_new, + NULL, acc_initialize, acc_destroy, acc_close, @@ -1122,7 +1123,7 @@ KRB5_LIB_VARIABLE const krb5_cc_ops krb5_acc_ops = { NULL, acc_get_name_2, acc_resolve_2, - NULL, + acc_gen_new_2, 0, ':', '\0', diff --git a/lib/krb5/cache.c b/lib/krb5/cache.c index 0a92a0cd7d..b5f1efe6e7 100644 --- a/lib/krb5/cache.c +++ b/lib/krb5/cache.c @@ -454,7 +454,9 @@ krb5_cc_new_unique(krb5_context context, const char *type, } else { ops = cc_get_prefix_ops(context, type, &res); if (res == NULL && hint == NULL && - strcmp(ops->prefix, def_type) != 0) { + !context->default_cc_name_defaulted && + strcmp(ops->prefix, def_type) != 0 && + strncmp(type, "MEMORY", sizeof("MEMORY")) != 0) { krb5_set_error_message(context, KRB5_CC_NOSUPP, "Refusing to create a new unique cache in " "the default collection for cache type %s " @@ -482,7 +484,7 @@ krb5_cc_new_unique(krb5_context context, const char *type, if (ret) return ret; if ((*id)->ops->gen_new_2) - ret = (*id)->ops->gen_new_2(context, type, hint ? hint : res, id); + ret = (*id)->ops->gen_new_2(context, hint ? hint : res, id); else ret = (*id)->ops->gen_new(context, id); if (ret) { @@ -626,17 +628,38 @@ krb5_cc_get_ops(krb5_context context, krb5_ccache id) */ KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL -_krb5_expand_default_cc_name(krb5_context context, const char *str, char **res) +_krb5_expand_default_cc_name(krb5_context context, const krb5_cc_ops *ops, const char *str, char **res) { - int filepath; - - filepath = (strncmp("FILE:", str, 5) == 0 - || strncmp("DIR:", str, 4) == 0 - || strncmp("SCC:", str, 4) == 0); + int filepath = 0; + if (ops == NULL) + ops = cc_get_prefix_ops(context, str, NULL); + if (ops == NULL) + filepath = ops->filepath; return _krb5_expand_path_tokens(context, str, filepath, res); } +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_default_cc_name(krb5_context context, + const krb5_cc_ops *ops, + const char *type, + const char *hardcoded_default, + char **res) +{ + const char *s; + + if (ops == NULL) + ops = cc_get_prefix_ops(context, type, NULL); + if (ops == NULL) + return _krb5_expand_path_tokens(context, hardcoded_default, 0, res); + + s = krb5_config_get_string(context, NULL, "libdefaults", + "default_ccache_name_by_type", type, NULL); + if (s) + return _krb5_expand_path_tokens(context, s, 0, res); + return _krb5_expand_path_tokens(context, hardcoded_default, 0, res); +} + /* * Return non-zero if envirnoment that will determine default krb5cc * name has changed. @@ -830,7 +853,7 @@ krb5_cc_configured_default_name(krb5_context context) cfg = krb5_config_get_string(context, NULL, "libdefaults", "default_ccache_name", NULL); if (cfg) { - ret = _krb5_expand_default_cc_name(context, cfg, &expanded); + ret = _krb5_expand_default_cc_name(context, NULL, cfg, &expanded); if (ret) { krb5_set_error_message(context, ret, "token expansion failed for %s", cfg); diff --git a/lib/krb5/dcache.c b/lib/krb5/dcache.c index f026e99b31..629c5012f6 100644 --- a/lib/krb5/dcache.c +++ b/lib/krb5/dcache.c @@ -488,26 +488,29 @@ dcc_resolve_2(krb5_context context, } static krb5_error_code KRB5_CALLCONV -dcc_gen_new(krb5_context context, krb5_ccache *id) +dcc_gen_new_2(krb5_context context, const char *name, krb5_ccache *id) { - krb5_error_code ret; + krb5_error_code ret = 0; char *def_dir = NULL; - char *name = NULL; + char *ccname = NULL; int fd = -1; - ret = get_default_dir(context, &def_dir); + if (name == NULL) { + ret = get_default_dir(context, &def_dir); + name = def_dir; + } if (ret == 0) - ret = verify_directory(context, def_dir); + ret = verify_directory(context, name); if (ret == 0 && - (asprintf(&name, "DIR::%s/tktXXXXXX", def_dir) == -1 || name == NULL)) + (asprintf(&ccname, "DIR::%s/tktXXXXXX", name) == -1 || name == NULL)) ret = krb5_enomem(context); - if (ret == 0 && (fd = mkstemp(name + sizeof("DIR::") - 1)) == -1) + if (ret == 0 && (fd = mkstemp(ccname + sizeof("DIR::") - 1)) == -1) ret = errno; if (ret == 0) - ret = dcc_resolve_2(context, id, name + sizeof("DIR:") - 1, NULL); + ret = dcc_resolve_2(context, id, ccname + sizeof("DIR:") - 1, NULL); free(def_dir); - free(name); + free(ccname); if (fd != -1) close(fd); return ret; @@ -773,15 +776,8 @@ dcc_move(krb5_context context, krb5_ccache from, krb5_ccache to) static krb5_error_code KRB5_CALLCONV dcc_get_default_name(krb5_context context, char **str) { - const char *def_cc_colname = - krb5_config_get_string_default(context, NULL, KRB5_DEFAULT_CCNAME_DIR, - "libdefaults", "default_cc_collection", - NULL); - - /* [libdefaults] default_cc_collection is for testing */ - if (strncmp(def_cc_colname, "DIR:", sizeof("DIR:") - 1) != 0) - def_cc_colname = KRB5_DEFAULT_CCNAME_DIR; - return _krb5_expand_default_cc_name(context, def_cc_colname, str); + return _krb5_default_cc_name(context, &krb5_dcc_ops, NULL, + KRB5_DEFAULT_CCNAME_DIR, str); } static krb5_error_code KRB5_CALLCONV @@ -827,7 +823,7 @@ KRB5_LIB_VARIABLE const krb5_cc_ops krb5_dcc_ops = { "DIR", NULL, NULL, - dcc_gen_new, + NULL, dcc_initialize, dcc_destroy, dcc_close, @@ -851,7 +847,7 @@ KRB5_LIB_VARIABLE const krb5_cc_ops krb5_dcc_ops = { dcc_get_kdc_offset, dcc_get_name_2, dcc_resolve_2, - NULL, + dcc_gen_new_2, 1, '\0', ':', diff --git a/lib/krb5/fcache.c b/lib/krb5/fcache.c index 17b8d8f97f..9d7d119815 100644 --- a/lib/krb5/fcache.c +++ b/lib/krb5/fcache.c @@ -371,13 +371,17 @@ _krb5_erase_file(krb5_context context, const char *filename) } static krb5_error_code KRB5_CALLCONV -fcc_gen_new(krb5_context context, krb5_ccache *id) +fcc_gen_new_2(krb5_context context, const char *name, krb5_ccache *id) { char *file = NULL, *exp_file = NULL; krb5_error_code ret; krb5_fcache *f; int fd; + if (name == NULL) + /* TODO use the first in [libdefaults] default_file_cache_collections */ + name = KRB5_DEFAULT_CCFILE_ROOT; + f = calloc(1, sizeof(*f)); if(f == NULL) { krb5_set_error_message(context, KRB5_CC_NOMEM, @@ -390,7 +394,7 @@ fcc_gen_new(krb5_context context, krb5_ccache *id) * instead so that new unique FILE ccaches can be found in the user's * default collection. * */ - ret = asprintf(&file, "%sXXXXXX", KRB5_DEFAULT_CCFILE_ROOT); + ret = asprintf(&file, "%sXXXXXX", name); if(ret < 0 || file == NULL) { free(f); krb5_set_error_message(context, KRB5_CC_NOMEM, @@ -1281,7 +1285,7 @@ is_default_collection(krb5_context context, const char *name, const char * const *def_locs, int *res) { krb5_error_code ret; - const char *def_loc[2] = { KRB5_DEFAULT_CCNAME_FILE, NULL }; + const char *def_loc[2] = { KRB5_DEFAULT_CCNAME_FILE, NULL }; /* XXX */ const char *sep; size_t namelen; size_t i; @@ -1300,7 +1304,8 @@ is_default_collection(krb5_context context, const char *name, for (i = 0; !(*res) && def_locs[i]; i++) { char *e = NULL; - if ((ret = _krb5_expand_default_cc_name(context, def_locs[i], &e))) + if ((ret = _krb5_expand_default_cc_name(context, &krb5_fcc_ops, + def_locs[i], &e))) return ret; *res = strncmp(e, name, namelen) == 0 && (sep == NULL || e[namelen] == FILESUBSEPCHR || e[namelen] == '\0'); @@ -1579,9 +1584,8 @@ fcc_move(krb5_context context, krb5_ccache from, krb5_ccache to) static krb5_error_code KRB5_CALLCONV fcc_get_default_name(krb5_context context, char **str) { - return _krb5_expand_default_cc_name(context, - KRB5_DEFAULT_CCNAME_FILE, - str); + return _krb5_default_cc_name(context, &krb5_fcc_ops, NULL, + KRB5_DEFAULT_CCNAME_FILE, str); } static krb5_error_code KRB5_CALLCONV @@ -1666,7 +1670,7 @@ KRB5_LIB_VARIABLE const krb5_cc_ops krb5_fcc_ops = { "FILE", NULL, NULL, - fcc_gen_new, + NULL, fcc_initialize, fcc_destroy, fcc_close, @@ -1690,7 +1694,7 @@ KRB5_LIB_VARIABLE const krb5_cc_ops krb5_fcc_ops = { fcc_get_kdc_offset, fcc_get_name_2, fcc_resolve_2, - NULL, + fcc_gen_new_2, 1, '+', '\0', diff --git a/lib/krb5/kcm.c b/lib/krb5/kcm.c index 85b486d1c7..f25ce854f6 100644 --- a/lib/krb5/kcm.c +++ b/lib/krb5/kcm.c @@ -172,10 +172,11 @@ kcm_alloc(krb5_context context, int aret; /* Get the KCM:%{UID} default */ - if (ops == &krb5_kcm_ops) - ret = _krb5_expand_default_cc_name(context, KRB5_DEFAULT_CCNAME_KCM_KCM, &local_def_name); - else - ret = _krb5_expand_default_cc_name(context, KRB5_DEFAULT_CCNAME_KCM_API, &local_def_name); + ret = _krb5_default_cc_name(context, ops, NULL, + ops == &krb5_kcm_ops ? + KRB5_DEFAULT_CCNAME_KCM_KCM : + KRB5_DEFAULT_CCNAME_KCM_API, + &local_def_name); if (ret) return ret; local_def_name_len = strlen(local_def_name); @@ -418,14 +419,36 @@ kcm_resolve_2_api(krb5_context context, * NameZ */ static krb5_error_code -kcm_gen_new(krb5_context context, const krb5_cc_ops *ops, krb5_ccache *id) +kcm_gen_new_2(krb5_context context, + const krb5_cc_ops *ops, + const char *name, + krb5_ccache *id) { krb5_kcmcache *k; krb5_error_code ret; krb5_storage *request, *response; krb5_data response_data; - ret = kcm_alloc(context, ops, NULL, NULL, id); + if (name) { + char *local_def_name = NULL; /* Our idea of default KCM cache name */ + + ret = _krb5_default_cc_name(context, ops, NULL, + ops == &krb5_kcm_ops ? + KRB5_DEFAULT_CCNAME_KCM_KCM : + KRB5_DEFAULT_CCNAME_KCM_API, + &local_def_name); + + if (strcmp(name, local_def_name + strlen(ops->prefix) + 1) != 0) { + krb5_set_error_message(context, KRB5_CC_NOSUPP, + "KEYRING cannot create new unique caches " + "in non-default collection"); + free(local_def_name); + return KRB5_CC_NOSUPP; + } + free(local_def_name); + } + + ret = kcm_alloc(context, ops, name, NULL, id); if (ret) return ret; @@ -461,15 +484,15 @@ kcm_gen_new(krb5_context context, const krb5_cc_ops *ops, krb5_ccache *id) } static krb5_error_code -kcm_gen_new_kcm(krb5_context context, krb5_ccache *id) +kcm_gen_new_2_kcm(krb5_context context, const char *name, krb5_ccache *id) { - return kcm_gen_new(context, &krb5_kcm_ops, id); + return kcm_gen_new_2(context, &krb5_kcm_ops, name, id); } static krb5_error_code -kcm_gen_new_api(krb5_context context, krb5_ccache *id) +kcm_gen_new_2_api(krb5_context context, const char *name, krb5_ccache *id) { - return kcm_gen_new(context, &krb5_akcm_ops, id); + return kcm_gen_new_2(context, &krb5_akcm_ops, name, id); } /* @@ -1154,7 +1177,7 @@ kcm_get_default_name(krb5_context context, const krb5_cc_ops *ops, krb5_storage_free(request); if (ret) { if (defstr) - return _krb5_expand_default_cc_name(context, defstr, str); + return _krb5_expand_default_cc_name(context, ops, defstr, str); return ret; } @@ -1290,7 +1313,7 @@ KRB5_LIB_VARIABLE const krb5_cc_ops krb5_kcm_ops = { "KCM", NULL, NULL, - kcm_gen_new_kcm, + NULL, kcm_initialize, kcm_destroy, kcm_close, @@ -1314,7 +1337,7 @@ KRB5_LIB_VARIABLE const krb5_cc_ops krb5_kcm_ops = { kcm_get_kdc_offset, kcm_get_name_2, kcm_resolve_2_kcm, - NULL, + kcm_gen_new_2_kcm, 0, ':', '\0', @@ -1325,7 +1348,7 @@ KRB5_LIB_VARIABLE const krb5_cc_ops krb5_akcm_ops = { "API", NULL, NULL, - kcm_gen_new_api, + NULL, kcm_initialize, kcm_destroy, kcm_close, @@ -1349,7 +1372,7 @@ KRB5_LIB_VARIABLE const krb5_cc_ops krb5_akcm_ops = { NULL, kcm_get_name_2, kcm_resolve_2_api, - NULL, + kcm_gen_new_2_api, 0, '\0', ':', diff --git a/lib/krb5/krb5.h b/lib/krb5/krb5.h index af9880593b..cde0c312d5 100644 --- a/lib/krb5/krb5.h +++ b/lib/krb5/krb5.h @@ -539,7 +539,7 @@ typedef struct krb5_cc_ops { krb5_error_code (KRB5_CALLCONV * resolve_2)(krb5_context, krb5_ccache *, const char *, const char *); /* Version 6 */ - krb5_error_code (KRB5_CALLCONV * gen_new_2)(krb5_context, const char *, const char *, krb5_ccache *); + krb5_error_code (KRB5_CALLCONV * gen_new_2)(krb5_context, const char *, krb5_ccache *); uint32_t filepath:1; /* Versions later than 6 can add bitfields here */ unsigned char subsep; unsigned char subrsep; diff --git a/lib/krb5/krcache.c b/lib/krb5/krcache.c index a4651e5947..5a869a47bf 100644 --- a/lib/krb5/krcache.c +++ b/lib/krb5/krcache.c @@ -463,7 +463,7 @@ get_default(krb5_context context, if (defname == NULL || strncmp(defname, "KEYRING:", 8) != 0) return 0; - return parse_residual(context, defname + 8, + return parse_residual(context, defname + sizeof("KEYRING:") - 1, panchor_name, pcollection_name, psubsidiary_name); } @@ -1294,7 +1294,7 @@ alloc_cache(krb5_context context, /* Create a new keyring cache with a unique name. */ static krb5_error_code KRB5_CALLCONV -krcc_gen_new(krb5_context context, krb5_ccache *id) +krcc_gen_new_2(krb5_context context, const char *name, krb5_ccache *id) { krb5_error_code ret; char *anchor_name, *collection_name, *subsidiary_name; @@ -1304,8 +1304,12 @@ krcc_gen_new(krb5_context context, krb5_ccache *id) key_serial_t cache_id = 0; /* Determine the collection in which we will create the cache.*/ - ret = get_default(context, &anchor_name, &collection_name, - &subsidiary_name); + if (name) + ret = parse_residual(context, name, &anchor_name, &collection_name, + &subsidiary_name); + else + ret = get_default(context, &anchor_name, &collection_name, + &subsidiary_name); if (ret) return ret; @@ -2046,7 +2050,7 @@ KRB5_LIB_VARIABLE const krb5_cc_ops krb5_krcc_ops = { "KEYRING", NULL, NULL, - krcc_gen_new, + NULL, krcc_initialize, krcc_destroy, krcc_close, @@ -2070,7 +2074,7 @@ KRB5_LIB_VARIABLE const krb5_cc_ops krb5_krcc_ops = { krcc_get_kdc_offset, krcc_get_name_2, krcc_resolve_2, - NULL, + krcc_gen_new_2, 0, '\0', ':', diff --git a/lib/krb5/libkrb5-exports.def.in b/lib/krb5/libkrb5-exports.def.in index 191a0c48c8..7c97b83511 100644 --- a/lib/krb5/libkrb5-exports.def.in +++ b/lib/krb5/libkrb5-exports.def.in @@ -881,6 +881,7 @@ EXPORTS krb5_time_abs; _krb5_n_fold _krb5_expand_default_cc_name + _krb5_default_cc_name ; FAST _krb5_fast_cf2 @@ -893,3 +894,4 @@ EXPORTS _krb5_expand_path_tokensv; _krb5_find_capath; _krb5_free_capath; + krb5_cc_parse_name; diff --git a/lib/krb5/mcache.c b/lib/krb5/mcache.c index c13d5504b8..94fe3b903c 100644 --- a/lib/krb5/mcache.c +++ b/lib/krb5/mcache.c @@ -176,11 +176,12 @@ mcc_resolve_2(krb5_context context, static krb5_error_code KRB5_CALLCONV -mcc_gen_new(krb5_context context, krb5_ccache *id) +mcc_gen_new_2(krb5_context context, const char *name, krb5_ccache *id) { krb5_error_code ret; krb5_mcache *m; + (void) name; if ((ret = mcc_alloc(context, NULL, &m))) return ret; @@ -614,7 +615,7 @@ KRB5_LIB_VARIABLE const krb5_cc_ops krb5_mcc_ops = { "MEMORY", NULL, NULL, - mcc_gen_new, + NULL, mcc_initialize, mcc_destroy, mcc_close, @@ -638,7 +639,7 @@ KRB5_LIB_VARIABLE const krb5_cc_ops krb5_mcc_ops = { mcc_get_kdc_offset, mcc_get_name_2, mcc_resolve_2, - NULL, + mcc_gen_new_2, 0, '\0', '\0', diff --git a/lib/krb5/scache.c b/lib/krb5/scache.c index f141c8ffb6..1afee8ba00 100644 --- a/lib/krb5/scache.c +++ b/lib/krb5/scache.c @@ -43,13 +43,11 @@ typedef struct krb5_scache { char *sub; sqlite3 *db; - sqlite_uint64 cid; - sqlite3_stmt *icred; - sqlite3_stmt *dcred; - sqlite3_stmt *iprincipal; sqlite3_stmt *icache; + sqlite3_stmt *icachep; + sqlite3_stmt *icache_unique; sqlite3_stmt *ucachen; sqlite3_stmt *ucachep; sqlite3_stmt *dcache; @@ -72,8 +70,8 @@ typedef struct krb5_scache { #define SCACHE_DEF_NAME "Default-cache" #define KRB5_SCACHE_DIR "%{TEMP}/krb5scc_%{uid}" -#define KRB5_SCACHE_DB KRB5_SCACHE_DIR "scc" -#define KRB5_SCACHE_NAME "SCC:" KRB5_SCACHE_DB ":" SCACHE_DEF_NAME +#define KRB5_SCACHE_DB KRB5_SCACHE_DIR "/scc" +#define KRB5_SCACHE_NAME ("SCC:" KRB5_SCACHE_DB ":" SCACHE_DEF_NAME) #define SCACHE_INVALID_CID ((sqlite_uint64)-1) @@ -81,66 +79,81 @@ typedef struct krb5_scache { * */ -#define SQL_CMASTER "" \ - "CREATE TABLE master (" \ - "oid INTEGER PRIMARY KEY," \ - "version INTEGER NOT NULL," \ - "defaultcache TEXT NOT NULL" \ + /* + * The "master" table is for designating the primary sub-cache, and as + * such it's got at most one row with rowid 1, thus the CHECK. + */ +#define SQL_CMASTER "" \ + "CREATE TABLE master (" \ + "oid INTEGER PRIMARY KEY," \ + "version INTEGER NOT NULL," \ + "defaultcache TEXT NOT NULL " \ + " REFERENCES caches (name) " \ + " ON DELETE SET NULL " \ + " ON UPDATE CASCADE " \ + "CHECK (oid = 1)" \ ")" #define SQL_SETUP_MASTER \ - "INSERT INTO master (version,defaultcache) VALUES(2, \"" SCACHE_DEF_NAME "\")" -#define SQL_UMASTER "UPDATE master SET defaultcache=? WHERE version=2" + "INSERT OR IGNORE INTO master " \ + "(oid,version,defaultcache) " \ + "VALUES(1, 2, \"" SCACHE_DEF_NAME "\")" +#define SQL_UMASTER \ + "UPDATE master SET defaultcache=? WHERE version=2" +#define SQL_PRAGMA_FK "PRAGMA foreign_keys = 1" #define SQL_CCACHE "" \ "CREATE TABLE caches (" \ - "oid INTEGER PRIMARY KEY," \ "principal TEXT," \ - "name TEXT NOT NULL" \ - ")" - -#define SQL_TCACHE "" \ - "CREATE TRIGGER CacheDropCreds AFTER DELETE ON caches " \ - "FOR EACH ROW BEGIN " \ - "DELETE FROM credentials WHERE cid=old.oid;" \ - "END" - -#define SQL_ICACHE "INSERT INTO caches (name) VALUES(?)" -#define SQL_UCACHE_NAME "UPDATE caches SET name=? WHERE OID=?" -#define SQL_UCACHE_PRINCIPAL "UPDATE caches SET principal=? WHERE OID=?" -#define SQL_DCACHE "DELETE FROM caches WHERE OID=?" -#define SQL_SCACHE "SELECT principal,name FROM caches WHERE OID=?" -#define SQL_SCACHE_NAME "SELECT oid FROM caches WHERE NAME=? OR " \ - "(PRINCIPAL IS NOT NULL AND PRINCIPAL=?)" + "name TEXT NOT NULL PRIMARY KEY" \ + ") WITHOUT ROWIDS" #define SQL_CCREDS "" \ "CREATE TABLE credentials (" \ - "oid INTEGER PRIMARY KEY," \ - "cid INTEGER NOT NULL," \ + "cache_name TEXT NOT NULL " \ + " REFERENCES caches(name) " \ + " ON DELETE CASCADE " \ + " ON UPDATE CASCADE," \ + "service TEXT NOT NULL, " \ "kvno INTEGER NOT NULL," \ "etype INTEGER NOT NULL," \ "created_at INTEGER NOT NULL," \ "cred BLOB NOT NULL" \ ")" -#define SQL_TCRED "" \ - "CREATE TRIGGER credDropPrincipal AFTER DELETE ON credentials " \ - "FOR EACH ROW BEGIN " \ - "DELETE FROM principals WHERE credential_id=old.oid;" \ - "END" - -#define SQL_ICRED "INSERT INTO credentials (cid, kvno, etype, cred, created_at) VALUES (?,?,?,?,?)" -#define SQL_DCRED "DELETE FROM credentials WHERE cid=?" +#define SQL_ICACHE "INSERT INTO caches (name) VALUES(?)" +#define SQL_ICACHE_PRINCIPAL \ + "INSERT OR REPLACE INTO caches (principal, name) VALUES(?, ?)" +#define SQL_ICACHE_UNIQUE \ + "WITH r AS (" \ + " SELECT abs(random()) % 2147483647 AS r)," \ + " r2 AS (" \ + " SELECT r " \ + " FROM r " \ + " WHERE NOT EXISTS (" \ + " SELECT name " \ + " FROM caches " \ + " WHERE name = 'unique-' || r) " \ + " LIMIT 1) " \ + "INSERT INTO caches (name) " \ + "SELECT 'unique-' || (SELECT r from r2) " \ + "RETURNING name AS name" +#define SQL_UCACHE_NAME "UPDATE caches SET name=? WHERE name=?" +#define SQL_UCACHE_PRINCIPAL "UPDATE caches SET principal=? WHERE name=?" +#define SQL_DCACHE "DELETE FROM caches WHERE name=?" +#define SQL_SCACHE "SELECT principal FROM caches WHERE name=?" +#define SQL_SCACHE_NAME "SELECT name FROM caches WHERE name=? OR " \ + "(principal IS NOT NULL AND principal=?)" + +#define SQL_ICRED \ + "INSERT INTO credentials " \ + " (cache_name, kvno, etype, cred, " \ + " created_at, service) " \ + "VALUES (?,?,?,?,?,?)" #define SQL_CPRINCIPALS "" \ - "CREATE TABLE principals (" \ - "oid INTEGER PRIMARY KEY," \ - "principal TEXT NOT NULL," \ - "type INTEGER NOT NULL," \ - "credential_id INTEGER NOT NULL" \ - ")" - -#define SQL_IPRINCIPAL "INSERT INTO principals (principal, type, credential_id) VALUES (?,?,?)" + "CREATE INDEX principals " \ + "ON caches (principal)" /* * sqlite destructors @@ -172,12 +185,10 @@ scc_free(krb5_scache *s) if (s->icred) sqlite3_finalize(s->icred); - if (s->dcred) - sqlite3_finalize(s->dcred); - if (s->iprincipal) - sqlite3_finalize(s->iprincipal); if (s->icache) sqlite3_finalize(s->icache); + if (s->icache_unique) + sqlite3_finalize(s->icache_unique); if (s->ucachen) sqlite3_finalize(s->ucachen); if (s->ucachep) @@ -196,6 +207,8 @@ scc_free(krb5_scache *s) free(s); } +static krb5_error_code KRB5_CALLCONV scc_get_default_name(krb5_context, char **); + #ifdef TRACEME static void trace(void* ptr, const char * str) @@ -287,9 +300,12 @@ default_db(krb5_context context, const char *name, sqlite3 **db, char **file) if ((name = krb5_cc_default_name(context))) { if (strncmp(name, "SCC:", sizeof("SCC:") - 1) == 0) name += sizeof("SCC:") - 1; + else if (strncmp(name, "SCC", sizeof("SCC") - 1) == 0) + name += sizeof("SCC") - 1; } - if (name == NULL) { - ret = _krb5_expand_default_cc_name(context, KRB5_SCACHE_DB, &s); + if (name == NULL || *name == '\0') { + ret = _krb5_default_cc_name(context, &krb5_scc_ops, NULL, + KRB5_SCACHE_DB, &s); if (ret) return ret; name = s; @@ -398,7 +414,9 @@ get_def_name(krb5_context context, char *filein, char **str, char **file) return ENOENT; } - +static krb5_error_code create_unique_cache(krb5_context, + krb5_scache *, + char **); static krb5_scache * KRB5_CALLCONV scc_alloc(krb5_context context, @@ -409,32 +427,20 @@ scc_alloc(krb5_context context, krb5_error_code ret = 0; krb5_scache *s; char *freeme = NULL; - char *subsidiary; + char *p; ALLOC(s, 1); if(s == NULL) return NULL; - s->cid = SCACHE_INVALID_CID; + s->sub = NULL; + s->file = NULL; + s->name = NULL; - if (name && *name && sub && *sub) { - if ((s->sub = strdup(sub)) == NULL || - (s->file = strdup(name)) == NULL) { - free(s->file); - free(s); - (void) krb5_enomem(context); - return NULL; - } - } else { - s->sub = NULL; - s->file = NULL; - s->name = NULL; - - if (name == NULL) - name = krb5_cc_default_name(context); + if (name == NULL) { if (name == NULL) { - ret = _krb5_expand_default_cc_name(context, KRB5_SCACHE_DB, - &freeme); + ret = _krb5_default_cc_name(context, &krb5_scc_ops, NULL, + KRB5_SCACHE_DB, &freeme); if (ret) { free(s); return NULL; @@ -444,42 +450,47 @@ scc_alloc(krb5_context context, if (strncmp(name, "SCC:", sizeof("SCC:") - 1) == 0) name += sizeof("SCC:") - 1; + } + if (name && *name) { if ((s->file = strdup(name)) == NULL) { - ret = krb5_enomem(context); - goto out; + free(s); + (void) krb5_enomem(context); + return NULL; } - - if ((subsidiary = strrchr(s->file, ':'))) { -#ifdef WIN32 - if (subsidiary == s->file + 1) - subsidiary = NULL; - else -#endif - *(subsidiary++) = '\0'; + if ((p = strchr(s->file, ':'))) { + *(p++) = '\0'; + if (!sub) + sub = p; } + if (sub && (s->sub = strdup(sub)) == NULL) { + free(s); + (void) krb5_enomem(context); + return NULL; + } + } - if (new_unique) { - ret = asprintf(&s->sub, "unique-%p", s) < 0 || s->sub == NULL ? - krb5_enomem(context) : 0; - } else if (subsidiary == NULL || *subsidiary == '\0') { - ret = get_def_name(context, s->file, &s->sub, NULL); - if (ret) { - if ((s->sub = strdup(SCACHE_DEF_NAME)) == NULL) - ret = krb5_enomem(context); - else - ret = 0; - } - } else if ((s->sub = strdup(subsidiary)) == NULL) { - ret = krb5_enomem(context); + + if (new_unique) { + free(s->sub); + s->sub = NULL; + ret = create_unique_cache(context, s, &s->sub); + } else if (sub == NULL || *sub == '\0') { + ret = get_def_name(context, s->file, &s->sub, NULL); + if (ret) { + if ((s->sub = strdup(SCACHE_DEF_NAME)) == NULL) + ret = krb5_enomem(context); + else + ret = 0; } + } else if ((s->sub = strdup(sub)) == NULL) { + ret = krb5_enomem(context); } if (ret == 0 && s->file && s->sub && (asprintf(&s->name, "%s:%s", s->file, s->sub) < 0 || s->name == NULL)) ret = krb5_enomem(context); - out: if (ret || s->file == NULL || s->sub == NULL || s->name == NULL) { scc_free(s); s = NULL; @@ -521,27 +532,6 @@ open_database(krb5_context context, krb5_scache *s, int flags) return 0; } -static krb5_error_code -create_cache(krb5_context context, krb5_scache *s) -{ - int ret; - - sqlite3_bind_text(s->icache, 1, s->sub, -1, NULL); - do { - ret = sqlite3_step(s->icache); - } while (ret == SQLITE_ROW); - if (ret != SQLITE_DONE) { - krb5_set_error_message(context, KRB5_CC_IO, - N_("Failed to add scache: %d", ""), ret); - return KRB5_CC_IO; - } - sqlite3_reset(s->icache); - - s->cid = sqlite3_last_insert_rowid(s->db); - - return 0; -} - static krb5_error_code make_database(krb5_context context, krb5_scache *s) { @@ -558,34 +548,33 @@ make_database(krb5_context context, krb5_scache *s) created_file = 1; - ret = exec_stmt(context, s->db, SQL_CMASTER, KRB5_CC_IO); - if (ret) goto out; ret = exec_stmt(context, s->db, SQL_CCACHE, KRB5_CC_IO); if (ret) goto out; - ret = exec_stmt(context, s->db, SQL_CCREDS, KRB5_CC_IO); - if (ret) goto out; ret = exec_stmt(context, s->db, SQL_CPRINCIPALS, KRB5_CC_IO); if (ret) goto out; - ret = exec_stmt(context, s->db, SQL_SETUP_MASTER, KRB5_CC_IO); + ret = exec_stmt(context, s->db, SQL_CMASTER, KRB5_CC_IO); if (ret) goto out; - - ret = exec_stmt(context, s->db, SQL_TCACHE, KRB5_CC_IO); + ret = exec_stmt(context, s->db, SQL_CCREDS, KRB5_CC_IO); if (ret) goto out; - ret = exec_stmt(context, s->db, SQL_TCRED, KRB5_CC_IO); + ret = exec_stmt(context, s->db, SQL_SETUP_MASTER, KRB5_CC_IO); if (ret) goto out; } + /* Enable foreign keys */ + ret = exec_stmt(context, s->db, SQL_PRAGMA_FK, KRB5_CC_IO); + if (ret) goto out; + #ifdef TRACEME sqlite3_trace(s->db, trace, NULL); #endif ret = prepare_stmt(context, s->db, &s->icred, SQL_ICRED); if (ret) goto out; - ret = prepare_stmt(context, s->db, &s->dcred, SQL_DCRED); + ret = prepare_stmt(context, s->db, &s->icache, SQL_ICACHE); if (ret) goto out; - ret = prepare_stmt(context, s->db, &s->iprincipal, SQL_IPRINCIPAL); + ret = prepare_stmt(context, s->db, &s->icachep, SQL_ICACHE_PRINCIPAL); if (ret) goto out; - ret = prepare_stmt(context, s->db, &s->icache, SQL_ICACHE); + ret = prepare_stmt(context, s->db, &s->icache_unique, SQL_ICACHE_UNIQUE); if (ret) goto out; ret = prepare_stmt(context, s->db, &s->ucachen, SQL_UCACHE_NAME); if (ret) goto out; @@ -619,6 +608,48 @@ make_database(krb5_context context, krb5_scache *s) return ret; } +static krb5_error_code +create_unique_cache(krb5_context context, krb5_scache *s, char **name) +{ + const char *str; + int done = 0; + int ret; + + *name = NULL; + ret = make_database(context, s); + if (ret) + return ret; + do { + do { + ret = sqlite3_step(s->icache_unique); + if (ret == SQLITE_ROW) { + if (sqlite3_column_type(s->scache, 1) != SQLITE_TEXT || + (str = (const char *)sqlite3_column_text(s->scache, 1)) == NULL) { + + sqlite3_reset(s->scache); + krb5_set_error_message(context, KRB5_CC_IO, + "Failed to add unique scache: %d", ret); + return KRB5_CC_IO; + } + free(*name); + if ((*name = strdup(str)) == NULL) { + sqlite3_reset(s->scache); + return krb5_enomem(context); + } + done = 1; + } + } while (ret == SQLITE_ROW); + if (ret != SQLITE_DONE) { + krb5_set_error_message(context, KRB5_CC_IO, + "Failed to add unique scache: %d", ret); + return KRB5_CC_IO; + } + sqlite3_reset(s->icache_unique); + } while (!done); + + return 0; +} + static krb5_error_code bind_principal(krb5_context context, sqlite3 *db, @@ -686,44 +717,33 @@ scc_resolve_2(krb5_context context, return ret; } - ret = sqlite3_bind_text(s->scache_name, 1, s->sub, -1, NULL); - if (ret != SQLITE_OK) { - krb5_set_error_message(context, ENOMEM, - "bind principal: %s", sqlite3_errmsg(s->db)); - scc_free(s); - return ENOMEM; - } - - if (sqlite3_step(s->scache_name) == SQLITE_ROW) { - - if (sqlite3_column_type(s->scache_name, 0) != SQLITE_INTEGER) { - sqlite3_reset(s->scache_name); - krb5_set_error_message(context, KRB5_CC_END, - N_("Cache name of wrong type " - "for scache %s", ""), - s->name); - scc_free(s); - return KRB5_CC_END; - } - - s->cid = sqlite3_column_int(s->scache_name, 0); - } else { - s->cid = SCACHE_INVALID_CID; - } - sqlite3_reset(s->scache_name); - (*id)->data.data = s; (*id)->data.length = sizeof(*s); - return 0; } static krb5_error_code KRB5_CALLCONV -scc_gen_new(krb5_context context, krb5_ccache *id) +scc_gen_new_2(krb5_context context, const char *name, krb5_ccache *id) { krb5_scache *s; + char *def_ccname = NULL; + + /* + * krb5_cc_new_unique() only takes a ccache _type_, but we + * really want to know the name of the ccache _collection_ to + * create the ccache in! This requires checking KRB5CCNAME, + * which may or may not be an SCC cache... + */ + if (name == NULL) { + krb5_error_code ret; + + ret = scc_get_default_name(context, &def_ccname); + if (ret) + return ret; + name = def_ccname + sizeof("SCC:") - 1; + } - s = scc_alloc(context, NULL, NULL, 1); + s = scc_alloc(context, name, NULL, 1); if (s == NULL) { krb5_set_error_message(context, KRB5_CC_NOMEM, @@ -752,40 +772,45 @@ scc_initialize(krb5_context context, ret = exec_stmt(context, s->db, "BEGIN IMMEDIATE TRANSACTION", KRB5_CC_IO); if (ret) return ret; - if (s->cid == SCACHE_INVALID_CID) { - ret = create_cache(context, s); - if (ret) - goto rollback; - } else { - sqlite3_bind_int(s->dcred, 1, s->cid); - do { - ret = sqlite3_step(s->dcred); - } while (ret == SQLITE_ROW); - sqlite3_reset(s->dcred); - if (ret != SQLITE_DONE) { - ret = KRB5_CC_IO; - krb5_set_error_message(context, ret, - N_("Failed to delete old " - "credentials: %s", ""), - sqlite3_errmsg(s->db)); - goto rollback; - } + if (sqlite3_bind_text(s->dcache, 1, s->sub, -1, SQLITE_STATIC) != SQLITE_OK) { + ret = KRB5_CC_IO; + krb5_set_error_message(context, ret, + "Failed to delete old credentials: %s", + sqlite3_errmsg(s->db)); + goto rollback; + } + do { + ret = sqlite3_step(s->dcache); + } while (ret == SQLITE_ROW); + sqlite3_reset(s->dcache); + if (ret != SQLITE_DONE) { + ret = KRB5_CC_IO; + krb5_set_error_message(context, ret, + "Failed to delete old credentials: %s", + sqlite3_errmsg(s->db)); + goto rollback; } - ret = bind_principal(context, s->db, s->ucachep, 1, principal); + ret = bind_principal(context, s->db, s->icachep, 1, principal); if (ret) goto rollback; - sqlite3_bind_int(s->ucachep, 2, s->cid); + if (sqlite3_bind_text(s->icachep, 1, s->sub, -1, SQLITE_STATIC) != SQLITE_OK) { + ret = KRB5_CC_IO; + krb5_set_error_message(context, ret, + "Failed to create to cache %s: %s", + s->name, sqlite3_errmsg(s->db)); + goto rollback; + } do { - ret = sqlite3_step(s->ucachep); + ret = sqlite3_step(s->icachep); } while (ret == SQLITE_ROW); - sqlite3_reset(s->ucachep); + sqlite3_reset(s->icachep); if (ret != SQLITE_DONE) { ret = KRB5_CC_IO; krb5_set_error_message(context, ret, - N_("Failed to bind principal to cache %s", ""), - sqlite3_errmsg(s->db)); + "Failed to create to cache %s: %s", + s->name, sqlite3_errmsg(s->db)); goto rollback; } @@ -816,17 +841,14 @@ scc_destroy(krb5_context context, krb5_scache *s = SCACHE(id); int ret; - if (s->cid == SCACHE_INVALID_CID) - return 0; - - sqlite3_bind_int(s->dcache, 1, s->cid); + sqlite3_bind_text(s->dcache, 1, s->sub, -1, SQLITE_STATIC); do { ret = sqlite3_step(s->dcache); } while (ret == SQLITE_ROW); sqlite3_reset(s->dcache); if (ret != SQLITE_DONE) { krb5_set_error_message(context, KRB5_CC_IO, - N_("Failed to destroy cache %s: %s", ""), + "Failed to destroy cache %s: %s", s->name, sqlite3_errmsg(s->db)); return KRB5_CC_IO; } @@ -887,7 +909,6 @@ scc_store_cred(krb5_context context, krb5_ccache id, krb5_creds *creds) { - sqlite_uint64 credid; krb5_scache *s = SCACHE(id); krb5_error_code ret; krb5_data data; @@ -900,7 +921,8 @@ scc_store_cred(krb5_context context, if (ret) return ret; - sqlite3_bind_int(s->icred, 1, s->cid); + /* XXX Error checking */ + sqlite3_bind_text(s->icred, 1, s->sub, -1, SQLITE_STATIC); { krb5_enctype etype = 0; int kvno = 0; @@ -923,8 +945,11 @@ scc_store_cred(krb5_context context, } + /* XXX Error checking */ sqlite3_bind_blob(s->icred, 4, data.data, data.length, free_data); sqlite3_bind_int(s->icred, 5, time(NULL)); + ret = bind_principal(context, s->db, s->icred, 6, creds->server); + if (ret) return ret; ret = exec_stmt(context, s->db, "BEGIN IMMEDIATE TRANSACTION", KRB5_CC_IO); if (ret) return ret; @@ -941,44 +966,6 @@ scc_store_cred(krb5_context context, goto rollback; } - credid = sqlite3_last_insert_rowid(s->db); - - { - bind_principal(context, s->db, s->iprincipal, 1, creds->server); - sqlite3_bind_int(s->iprincipal, 2, 1); - sqlite3_bind_int(s->iprincipal, 3, credid); - - do { - ret = sqlite3_step(s->iprincipal); - } while (ret == SQLITE_ROW); - sqlite3_reset(s->iprincipal); - if (ret != SQLITE_DONE) { - ret = KRB5_CC_IO; - krb5_set_error_message(context, ret, - N_("Failed to add principal: %s", ""), - sqlite3_errmsg(s->db)); - goto rollback; - } - } - - { - bind_principal(context, s->db, s->iprincipal, 1, creds->client); - sqlite3_bind_int(s->iprincipal, 2, 0); - sqlite3_bind_int(s->iprincipal, 3, credid); - - do { - ret = sqlite3_step(s->iprincipal); - } while (ret == SQLITE_ROW); - sqlite3_reset(s->iprincipal); - if (ret != SQLITE_DONE) { - ret = KRB5_CC_IO; - krb5_set_error_message(context, ret, - N_("Failed to add principal: %s", ""), - sqlite3_errmsg(s->db)); - goto rollback; - } - } - ret = exec_stmt(context, s->db, "COMMIT", KRB5_CC_IO); if (ret) return ret; @@ -1005,7 +992,7 @@ scc_get_principal(krb5_context context, if (ret) return ret; - sqlite3_bind_int(s->scache, 1, s->cid); + sqlite3_bind_text(s->scache, 1, s->sub, -1, SQLITE_STATIC); if (sqlite3_step(s->scache) != SQLITE_ROW) { sqlite3_reset(s->scache); @@ -1054,6 +1041,7 @@ scc_get_first (krb5_context context, krb5_scache *s = SCACHE(id); krb5_error_code ret; struct cred_ctx *ctx; + sqlite3_stmt *stmt; char *str = NULL, *name = NULL; *cursor = NULL; @@ -1068,14 +1056,6 @@ scc_get_first (krb5_context context, return ret; } - if (s->cid == SCACHE_INVALID_CID) { - krb5_set_error_message(context, KRB5_CC_END, - N_("Iterating a invalid scache %s", ""), - s->name); - free(ctx); - return KRB5_CC_END; - } - ret = asprintf(&name, "credIteration%pPid%d", ctx, (int)getpid()); if (ret < 0 || name == NULL) { @@ -1091,8 +1071,8 @@ scc_get_first (krb5_context context, } ret = asprintf(&str, "CREATE TEMPORARY TABLE %s " - "AS SELECT oid,created_at FROM credentials WHERE cid = %lu", - name, (unsigned long)s->cid); + "AS SELECT oid,created_at FROM credentials WHERE cache_name = ?", + name); if (ret < 0 || str == NULL) { free(ctx->drop); free(name); @@ -1100,6 +1080,22 @@ scc_get_first (krb5_context context, return krb5_enomem(context); } + ret = prepare_stmt(context, s->db, &stmt, str); + if (ret < 0 || str == NULL) { + free(ctx->drop); + free(name); + free(ctx); + return ret; + } + if (sqlite3_bind_text(stmt, 1, s->sub, -1, SQLITE_STATIC) != SQLITE_OK) { + free(ctx->drop); + free(name); + free(ctx); + krb5_set_error_message(context, KRB5_CC_IO, + "Could not initialize iteration of SCC:%s", + s->name); + return KRB5_CC_IO; + } ret = exec_stmt(context, s->db, str, KRB5_CC_IO); free(str); str = NULL; @@ -1234,13 +1230,19 @@ scc_remove_cred(krb5_context context, if (ret) return ret; + /* XXX Add service name if we have it */ ret = prepare_stmt(context, s->db, &stmt, "SELECT cred,oid FROM credentials " - "WHERE cid = ?"); + "WHERE cache_name = ?"); if (ret) return ret; - sqlite3_bind_int(stmt, 1, s->cid); + if (sqlite3_bind_text(stmt, 1, s->sub, -1, SQLITE_STATIC) != SQLITE_OK) { + krb5_set_error_message(context, KRB5_CC_IO, + N_("scache Database failed: %s", ""), + sqlite3_errmsg(s->db)); + return KRB5_CC_IO; + } /* find credential... */ while (1) { @@ -1477,25 +1479,22 @@ scc_move(krb5_context context, krb5_ccache from, krb5_ccache to) "BEGIN IMMEDIATE TRANSACTION", KRB5_CC_IO); if (ret) return ret; - if (sto->cid != SCACHE_INVALID_CID) { - /* drop old cache entry */ - - sqlite3_bind_int(sfrom->dcache, 1, sto->cid); - do { - ret = sqlite3_step(sfrom->dcache); - } while (ret == SQLITE_ROW); - sqlite3_reset(sfrom->dcache); - if (ret != SQLITE_DONE) { - krb5_set_error_message(context, KRB5_CC_IO, - N_("Failed to delete old cache: %d", ""), - (int)ret); - goto rollback; - } + /* drop the target name */ + sqlite3_bind_text(sfrom->dcache, 1, sto->sub, -1, SQLITE_STATIC); + do { + ret = sqlite3_step(sfrom->dcache); + } while (ret == SQLITE_ROW); + sqlite3_reset(sfrom->dcache); + if (ret != SQLITE_DONE) { + krb5_set_error_message(context, KRB5_CC_IO, + N_("Failed to delete old cache: %d", ""), + (int)ret); + goto rollback; } - sqlite3_bind_text(sfrom->ucachen, 1, sto->sub, -1, NULL); - sqlite3_bind_int(sfrom->ucachen, 2, sfrom->cid); - + /* Rename */ + sqlite3_bind_text(sfrom->ucachen, 1, sto->sub, -1, SQLITE_STATIC); + sqlite3_bind_text(sfrom->ucachen, 2, sfrom->sub, -1, SQLITE_STATIC); do { ret = sqlite3_step(sfrom->ucachen); } while (ret == SQLITE_ROW); @@ -1507,8 +1506,6 @@ scc_move(krb5_context context, krb5_ccache from, krb5_ccache to) goto rollback; } - sto->cid = sfrom->cid; - ret = exec_stmt(context, sfrom->db, "COMMIT", KRB5_CC_IO); if (ret) return ret; @@ -1523,8 +1520,8 @@ scc_move(krb5_context context, krb5_ccache from, krb5_ccache to) static krb5_error_code KRB5_CALLCONV scc_get_default_name(krb5_context context, char **str) { - *str = NULL; - return _krb5_expand_default_cc_name(context, KRB5_SCACHE_NAME, str); + return _krb5_default_cc_name(context, &krb5_scc_ops, NULL, + KRB5_SCACHE_NAME, str); } static krb5_error_code KRB5_CALLCONV @@ -1533,10 +1530,14 @@ scc_set_default(krb5_context context, krb5_ccache id) krb5_scache *s = SCACHE(id); krb5_error_code ret; - if (s->cid == SCACHE_INVALID_CID) { + ret = make_database(context, s); + if (ret) + return ret; + + if (!s->sub) { krb5_set_error_message(context, KRB5_CC_IO, - N_("Trying to set a invalid cache " - "as default %s", ""), + "Trying to set a invalid cache " + "as default %s", s->name); return KRB5_CC_IO; } @@ -1573,7 +1574,7 @@ KRB5_LIB_VARIABLE const krb5_cc_ops krb5_scc_ops = { "SCC", NULL, NULL, - scc_gen_new, + NULL, scc_initialize, scc_destroy, scc_close, @@ -1597,7 +1598,7 @@ KRB5_LIB_VARIABLE const krb5_cc_ops krb5_scc_ops = { NULL, scc_get_name_2, scc_resolve_2, - NULL, + scc_gen_new_2, 1, '\0', ':', diff --git a/lib/krb5/test_cc.c b/lib/krb5/test_cc.c index 0ca582eaac..81014e917d 100644 --- a/lib/krb5/test_cc.c +++ b/lib/krb5/test_cc.c @@ -200,6 +200,10 @@ test_default_name(krb5_context context) #endif } + ret = krb5_cc_set_default_name(context, NULL); + if (ret) + krb5_err(context, 1, ret, "krb5_cc_set_default_name(NULL) failed"); + free(exp_test_cc_name); free(p1); free(p2); @@ -460,7 +464,7 @@ test_def_cc_name(krb5_context context) 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); + ret = _krb5_expand_default_cc_name(context, NULL, cc_names[i].str, &str); if (ret) { if (cc_names[i].fail == 0) krb5_errx(context, 1, "test %d \"%s\" failed", diff --git a/lib/krb5/version-script.map b/lib/krb5/version-script.map index f6278e9ecb..38fea16c37 100644 --- a/lib/krb5/version-script.map +++ b/lib/krb5/version-script.map @@ -112,6 +112,7 @@ HEIMDAL_KRB5_2.0 { krb5_cc_new_unique; krb5_cc_next_cred; krb5_cc_next_cred_match; + krb5_cc_parse_name; krb5_cc_register; krb5_cc_remove_cred; krb5_cc_resolve; @@ -869,6 +870,7 @@ HEIMDAL_KRB5_2.0 { _krb5_aes_cts_encrypt; _krb5_n_fold; _krb5_expand_default_cc_name; + _krb5_default_cc_name; _krb5_expand_path_tokensv; _krb5_expand_path_tokens;