krb5: Improve cccol sub naming; add gss_store_cred_into2()
- Formalize the TYPE:collection_name:subsidiary_name naming scheme for ccaches in ccache collections - KEYRING: ccaches are weird because they have one more optional field: the "anchor", so rather than just assume a naming convention everywhere, we add new functions as well - Add krb5_cc_{resolve,default}_sub() that allows one to specify a "subsidiary" ccache name in a collection separately from the collection name - Add krb5_cc_{resolve,default}_for() which take a principal name, unparse it, and use it as the subsidiary ccache name (with colons replaced) - Make kinit use the new interfaces - Add missing DIR ccache iteration functionality - Revamps test_cc - Add krb5_cc_get_collection() and krb5_cc_get_subsidiary() - Bump the ccops SPI version number - Add gss_store_cred_into2() - Make MEMORY:anonymous not linked into the global MEMORY ccache collection, and uses this for delegated cred handles TBD: - Split this up into a krb5 change and gss mech_krb5 change? - Add krb5_cc_init_and_store() utility, per Greg's suggestion?
This commit is contained in:
@@ -40,6 +40,7 @@
|
||||
typedef struct krb5_scache {
|
||||
char *name;
|
||||
char *file;
|
||||
char *sub;
|
||||
sqlite3 *db;
|
||||
|
||||
sqlite_uint64 cid;
|
||||
@@ -66,7 +67,7 @@ typedef struct krb5_scache {
|
||||
#else
|
||||
#define KRB5_SCACHE_DB "/tmp/krb5scc_%{uid}"
|
||||
#endif
|
||||
#define KRB5_SCACHE_NAME "SCC:" SCACHE_DEF_NAME ":" KRB5_SCACHE_DB
|
||||
#define KRB5_SCACHE_NAME "SCC:" KRB5_SCACHE_DB ":" SCACHE_DEF_NAME
|
||||
|
||||
#define SCACHE_INVALID_CID ((sqlite_uint64)-1)
|
||||
|
||||
@@ -103,7 +104,8 @@ typedef struct krb5_scache {
|
||||
#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=?"
|
||||
#define SQL_SCACHE_NAME "SELECT oid FROM caches WHERE NAME=? OR " \
|
||||
"(PRINCIPAL IS NOT NULL AND PRINCIPAL=?)"
|
||||
|
||||
#define SQL_CCREDS "" \
|
||||
"CREATE TABLE credentials (" \
|
||||
@@ -153,8 +155,12 @@ free_krb5(void *str)
|
||||
static void
|
||||
scc_free(krb5_scache *s)
|
||||
{
|
||||
if (!s)
|
||||
return;
|
||||
if (s->file)
|
||||
free(s->file);
|
||||
if (s->sub)
|
||||
free(s->sub);
|
||||
if (s->name)
|
||||
free(s->name);
|
||||
|
||||
@@ -225,22 +231,53 @@ exec_stmt(krb5_context context, sqlite3 *db, const char *str,
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
default_db(krb5_context context, sqlite3 **db)
|
||||
default_db(krb5_context context, const char *name, sqlite3 **db, char **file)
|
||||
{
|
||||
char *name;
|
||||
char *s = NULL;
|
||||
char *f = NULL;
|
||||
int ret;
|
||||
|
||||
ret = _krb5_expand_default_cc_name(context, KRB5_SCACHE_DB, &name);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (file)
|
||||
*file = NULL;
|
||||
|
||||
ret = sqlite3_open_v2(name, db, SQLITE_OPEN_READWRITE, NULL);
|
||||
free(name);
|
||||
if (name == NULL) {
|
||||
if ((name = krb5_cc_default_name(context))) {
|
||||
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 (ret)
|
||||
return ret;
|
||||
name = s;
|
||||
}
|
||||
}
|
||||
|
||||
if (strncmp(name, "SCC:", sizeof("SCC:") - 1) == 0)
|
||||
name += sizeof("SCC:") - 1;
|
||||
|
||||
if ((f = strdup(name)) == NULL) {
|
||||
free(s);
|
||||
return krb5_enomem(context);
|
||||
}
|
||||
free(s);
|
||||
|
||||
if ((s = strrchr(f, ':')))
|
||||
*s = '\0';
|
||||
|
||||
ret = sqlite3_open_v2(f, db, SQLITE_OPEN_READWRITE, NULL);
|
||||
if (ret != SQLITE_OK) {
|
||||
sqlite3_close_v2(*db);
|
||||
krb5_clear_error_message(context);
|
||||
free(f);
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
if (file)
|
||||
*file = f;
|
||||
else
|
||||
free(f);
|
||||
|
||||
#ifdef TRACEME
|
||||
sqlite3_trace(*db, trace, NULL);
|
||||
#endif
|
||||
@@ -249,14 +286,14 @@ default_db(krb5_context context, sqlite3 **db)
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
get_def_name(krb5_context context, char **str)
|
||||
get_def_name(krb5_context context, char *filein, char **str, char **file)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
sqlite3_stmt *stmt;
|
||||
const char *name;
|
||||
sqlite3 *db;
|
||||
|
||||
ret = default_db(context, &db);
|
||||
ret = default_db(context, filein, &db, file);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -294,10 +331,15 @@ out:
|
||||
|
||||
|
||||
static krb5_scache * KRB5_CALLCONV
|
||||
scc_alloc(krb5_context context, const char *name)
|
||||
scc_alloc(krb5_context context,
|
||||
const char *name,
|
||||
const char *sub,
|
||||
int new_unique)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
krb5_error_code ret = 0;
|
||||
krb5_scache *s;
|
||||
char *freeme = NULL;
|
||||
char *subsidiary;
|
||||
|
||||
ALLOC(s, 1);
|
||||
if(s == NULL)
|
||||
@@ -305,41 +347,87 @@ scc_alloc(krb5_context context, const char *name)
|
||||
|
||||
s->cid = SCACHE_INVALID_CID;
|
||||
|
||||
if (name) {
|
||||
char *file;
|
||||
|
||||
if (*name == '\0') {
|
||||
ret = get_def_name(context, &s->name);
|
||||
if (ret)
|
||||
s->name = strdup(SCACHE_DEF_NAME);
|
||||
} else
|
||||
s->name = strdup(name);
|
||||
|
||||
file = strrchr(s->name, ':');
|
||||
if (file) {
|
||||
*file++ = '\0';
|
||||
s->file = strdup(file);
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = _krb5_expand_default_cc_name(context, KRB5_SCACHE_DB, &s->file);
|
||||
}
|
||||
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 {
|
||||
_krb5_expand_default_cc_name(context, KRB5_SCACHE_DB, &s->file);
|
||||
ret = asprintf(&s->name, "unique-%p", s);
|
||||
s->sub = NULL;
|
||||
s->file = NULL;
|
||||
s->name = NULL;
|
||||
|
||||
if (name == NULL)
|
||||
name = krb5_cc_default_name(context);
|
||||
if (name == NULL) {
|
||||
ret = _krb5_expand_default_cc_name(context, KRB5_SCACHE_DB,
|
||||
&freeme);
|
||||
if (ret) {
|
||||
free(s);
|
||||
return NULL;
|
||||
}
|
||||
name = freeme;
|
||||
}
|
||||
|
||||
if (strncmp(name, "SCC:", sizeof("SCC:") - 1) == 0)
|
||||
name += sizeof("SCC:") - 1;
|
||||
|
||||
if ((s->file = strdup(name)) == NULL) {
|
||||
(void) krb5_enomem(context);
|
||||
scc_free(s);
|
||||
free(freeme);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((subsidiary = strrchr(s->file, ':'))) {
|
||||
#ifdef WIN32
|
||||
if (subsidiary == &s->file + 1)
|
||||
subsidiary = NULL;
|
||||
else
|
||||
#endif
|
||||
*(subsidiary++) = '\0';
|
||||
}
|
||||
|
||||
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 (ret < 0 || s->file == NULL || s->name == NULL) {
|
||||
|
||||
if (ret == 0 && s->file && s->sub &&
|
||||
(asprintf(&s->name, "%s:%s", s->file, s->sub) < 0 || s->name == NULL))
|
||||
ret = krb5_enomem(context);
|
||||
if (ret || s->file == NULL || s->sub == NULL || s->name == NULL) {
|
||||
scc_free(s);
|
||||
free(freeme);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
open_database(krb5_context context, krb5_scache *s, int flags)
|
||||
{
|
||||
struct stat st;
|
||||
int ret;
|
||||
|
||||
|
||||
if (!(flags & SQLITE_OPEN_CREATE) && stat(s->file, &st) == 0 &&
|
||||
st.st_size == 0)
|
||||
return ENOENT;
|
||||
ret = sqlite3_open_v2(s->file, &s->db, SQLITE_OPEN_READWRITE|flags, NULL);
|
||||
if (ret) {
|
||||
if (s->db) {
|
||||
@@ -361,7 +449,7 @@ create_cache(krb5_context context, krb5_scache *s)
|
||||
{
|
||||
int ret;
|
||||
|
||||
sqlite3_bind_text(s->icache, 1, s->name, -1, NULL);
|
||||
sqlite3_bind_text(s->icache, 1, s->sub, -1, NULL);
|
||||
do {
|
||||
ret = sqlite3_step(s->icache);
|
||||
} while (ret == SQLITE_ROW);
|
||||
@@ -477,20 +565,32 @@ bind_principal(krb5_context context,
|
||||
*
|
||||
*/
|
||||
|
||||
static const char* KRB5_CALLCONV
|
||||
static krb5_error_code KRB5_CALLCONV
|
||||
scc_get_name(krb5_context context,
|
||||
krb5_ccache id)
|
||||
krb5_ccache id,
|
||||
const char **name,
|
||||
const char **file,
|
||||
const char **sub)
|
||||
{
|
||||
return SCACHE(id)->name;
|
||||
if (name)
|
||||
*name = SCACHE(id)->name;
|
||||
if (file)
|
||||
*file = SCACHE(id)->file;
|
||||
if (sub)
|
||||
*sub = SCACHE(id)->sub;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static krb5_error_code KRB5_CALLCONV
|
||||
scc_resolve(krb5_context context, krb5_ccache *id, const char *res)
|
||||
scc_resolve(krb5_context context,
|
||||
krb5_ccache *id,
|
||||
const char *res,
|
||||
const char *sub)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
krb5_scache *s;
|
||||
int ret;
|
||||
|
||||
s = scc_alloc(context, res);
|
||||
s = scc_alloc(context, res, sub, 0);
|
||||
if (s == NULL) {
|
||||
krb5_set_error_message(context, KRB5_CC_NOMEM,
|
||||
N_("malloc: out of memory", ""));
|
||||
@@ -503,12 +603,12 @@ scc_resolve(krb5_context context, krb5_ccache *id, const char *res)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = sqlite3_bind_text(s->scache_name, 1, s->name, -1, NULL);
|
||||
ret = sqlite3_bind_text(s->scache_name, 1, s->sub, -1, NULL);
|
||||
if (ret != SQLITE_OK) {
|
||||
krb5_set_error_message(context, ENOMEM,
|
||||
"bind name: %s", sqlite3_errmsg(s->db));
|
||||
scc_free(s);
|
||||
return ENOMEM;
|
||||
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) {
|
||||
@@ -540,7 +640,7 @@ scc_gen_new(krb5_context context, krb5_ccache *id)
|
||||
{
|
||||
krb5_scache *s;
|
||||
|
||||
s = scc_alloc(context, NULL);
|
||||
s = scc_alloc(context, NULL, NULL, 1);
|
||||
|
||||
if (s == NULL) {
|
||||
krb5_set_error_message(context, KRB5_CC_NOMEM,
|
||||
@@ -557,7 +657,7 @@ scc_gen_new(krb5_context context, krb5_ccache *id)
|
||||
static krb5_error_code KRB5_CALLCONV
|
||||
scc_initialize(krb5_context context,
|
||||
krb5_ccache id,
|
||||
krb5_principal primary_principal)
|
||||
krb5_principal principal)
|
||||
{
|
||||
krb5_scache *s = SCACHE(id);
|
||||
krb5_error_code ret;
|
||||
@@ -589,7 +689,7 @@ scc_initialize(krb5_context context,
|
||||
}
|
||||
}
|
||||
|
||||
ret = bind_principal(context, s->db, s->ucachep, 1, primary_principal);
|
||||
ret = bind_principal(context, s->db, s->ucachep, 1, principal);
|
||||
if (ret)
|
||||
goto rollback;
|
||||
sqlite3_bind_int(s->ucachep, 2, s->cid);
|
||||
@@ -827,8 +927,8 @@ scc_get_principal(krb5_context context,
|
||||
if (sqlite3_step(s->scache) != SQLITE_ROW) {
|
||||
sqlite3_reset(s->scache);
|
||||
krb5_set_error_message(context, KRB5_CC_END,
|
||||
N_("No principal for cache SCC:%s:%s", ""),
|
||||
s->name, s->file);
|
||||
N_("No principal for cache SCC:%s", ""),
|
||||
s->name);
|
||||
return KRB5_CC_END;
|
||||
}
|
||||
|
||||
@@ -836,8 +936,8 @@ scc_get_principal(krb5_context context,
|
||||
sqlite3_reset(s->scache);
|
||||
krb5_set_error_message(context, KRB5_CC_END,
|
||||
N_("Principal data of wrong type "
|
||||
"for SCC:%s:%s", ""),
|
||||
s->name, s->file);
|
||||
"for SCC:%s", ""),
|
||||
s->name);
|
||||
return KRB5_CC_END;
|
||||
}
|
||||
|
||||
@@ -845,8 +945,8 @@ scc_get_principal(krb5_context context,
|
||||
if (str == NULL) {
|
||||
sqlite3_reset(s->scache);
|
||||
krb5_set_error_message(context, KRB5_CC_END,
|
||||
N_("Principal not set for SCC:%s:%s", ""),
|
||||
s->name, s->file);
|
||||
N_("Principal not set for SCC:%s", ""),
|
||||
s->name);
|
||||
return KRB5_CC_END;
|
||||
}
|
||||
|
||||
@@ -1001,8 +1101,8 @@ next:
|
||||
|
||||
if (sqlite3_column_type(ctx->credstmt, 0) != SQLITE_BLOB) {
|
||||
krb5_set_error_message(context, KRB5_CC_END,
|
||||
N_("credential of wrong type for SCC:%s:%s", ""),
|
||||
s->name, s->file);
|
||||
N_("credential of wrong type for SCC:%s", ""),
|
||||
s->name);
|
||||
sqlite3_reset(ctx->credstmt);
|
||||
return KRB5_CC_END;
|
||||
}
|
||||
@@ -1079,8 +1179,8 @@ scc_remove_cred(krb5_context context,
|
||||
ret = KRB5_CC_END;
|
||||
krb5_set_error_message(context, ret,
|
||||
N_("Credential of wrong type "
|
||||
"for SCC:%s:%s", ""),
|
||||
s->name, s->file);
|
||||
"for SCC:%s", ""),
|
||||
s->name);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1134,6 +1234,7 @@ scc_set_flags(krb5_context context,
|
||||
|
||||
struct cache_iter {
|
||||
char *drop;
|
||||
char *file;
|
||||
sqlite3 *db;
|
||||
sqlite3_stmt *stmt;
|
||||
};
|
||||
@@ -1151,8 +1252,8 @@ scc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor)
|
||||
if (ctx == NULL)
|
||||
return krb5_enomem(context);
|
||||
|
||||
ret = default_db(context, &ctx->db);
|
||||
if (ctx->db == NULL) {
|
||||
ret = default_db(context, NULL, &ctx->db, &ctx->file);
|
||||
if (ret) {
|
||||
free(ctx);
|
||||
return ret;
|
||||
}
|
||||
@@ -1160,48 +1261,48 @@ scc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor)
|
||||
ret = asprintf(&name, "cacheIteration%pPid%d",
|
||||
ctx, (int)getpid());
|
||||
if (ret < 0 || name == NULL) {
|
||||
sqlite3_close(ctx->db);
|
||||
free(ctx);
|
||||
return krb5_enomem(context);
|
||||
sqlite3_close(ctx->db);
|
||||
free(ctx);
|
||||
return krb5_enomem(context);
|
||||
}
|
||||
|
||||
ret = asprintf(&ctx->drop, "DROP TABLE %s", name);
|
||||
if (ret < 0 || ctx->drop == NULL) {
|
||||
sqlite3_close(ctx->db);
|
||||
free(name);
|
||||
free(ctx);
|
||||
return krb5_enomem(context);
|
||||
sqlite3_close(ctx->db);
|
||||
free(name);
|
||||
free(ctx);
|
||||
return krb5_enomem(context);
|
||||
}
|
||||
|
||||
ret = asprintf(&str, "CREATE TEMPORARY TABLE %s AS SELECT name FROM caches",
|
||||
name);
|
||||
name);
|
||||
if (ret < 0 || str == NULL) {
|
||||
sqlite3_close(ctx->db);
|
||||
free(name);
|
||||
free(ctx->drop);
|
||||
free(ctx);
|
||||
return krb5_enomem(context);
|
||||
sqlite3_close(ctx->db);
|
||||
free(name);
|
||||
free(ctx->drop);
|
||||
free(ctx);
|
||||
return krb5_enomem(context);
|
||||
}
|
||||
|
||||
ret = exec_stmt(context, ctx->db, str, KRB5_CC_IO);
|
||||
free(str);
|
||||
str = NULL;
|
||||
if (ret) {
|
||||
sqlite3_close(ctx->db);
|
||||
free(name);
|
||||
free(ctx->drop);
|
||||
free(ctx);
|
||||
return ret;
|
||||
sqlite3_close(ctx->db);
|
||||
free(name);
|
||||
free(ctx->drop);
|
||||
free(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = asprintf(&str, "SELECT name FROM %s", name);
|
||||
if (ret < 0 || str == NULL) {
|
||||
exec_stmt(context, ctx->db, ctx->drop, 0);
|
||||
sqlite3_close(ctx->db);
|
||||
free(name);
|
||||
free(ctx->drop);
|
||||
free(ctx);
|
||||
return krb5_enomem(context);
|
||||
exec_stmt(context, ctx->db, ctx->drop, 0);
|
||||
sqlite3_close(ctx->db);
|
||||
free(name);
|
||||
free(ctx->drop);
|
||||
free(ctx);
|
||||
return krb5_enomem(context);
|
||||
}
|
||||
free(name);
|
||||
|
||||
@@ -1249,10 +1350,13 @@ again:
|
||||
goto again;
|
||||
|
||||
ret = _krb5_cc_allocate(context, &krb5_scc_ops, id);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return scc_resolve(context, id, name);
|
||||
if (ret == 0)
|
||||
ret = scc_resolve(context, id, ctx->file, name);
|
||||
if (ret) {
|
||||
free(*id);
|
||||
*id = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static krb5_error_code KRB5_CALLCONV
|
||||
@@ -1263,6 +1367,7 @@ scc_end_cache_get(krb5_context context, krb5_cc_cursor cursor)
|
||||
exec_stmt(context, ctx->db, ctx->drop, 0);
|
||||
sqlite3_finalize(ctx->stmt);
|
||||
sqlite3_close(ctx->db);
|
||||
free(ctx->file);
|
||||
free(ctx->drop);
|
||||
free(ctx);
|
||||
return 0;
|
||||
@@ -1304,7 +1409,7 @@ scc_move(krb5_context context, krb5_ccache from, krb5_ccache to)
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_bind_text(sfrom->ucachen, 1, sto->name, -1, NULL);
|
||||
sqlite3_bind_text(sfrom->ucachen, 1, sto->sub, -1, NULL);
|
||||
sqlite3_bind_int(sfrom->ucachen, 2, sfrom->cid);
|
||||
|
||||
do {
|
||||
@@ -1334,20 +1439,8 @@ rollback:
|
||||
static krb5_error_code KRB5_CALLCONV
|
||||
scc_get_default_name(krb5_context context, char **str)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
char *name;
|
||||
|
||||
*str = NULL;
|
||||
|
||||
ret = get_def_name(context, &name);
|
||||
if (ret)
|
||||
return _krb5_expand_default_cc_name(context, KRB5_SCACHE_NAME, str);
|
||||
|
||||
ret = asprintf(str, "SCC:%s", name);
|
||||
free(name);
|
||||
if (ret < 0 || *str == NULL)
|
||||
return krb5_enomem(context);
|
||||
return 0;
|
||||
return _krb5_expand_default_cc_name(context, KRB5_SCACHE_NAME, str);
|
||||
}
|
||||
|
||||
static krb5_error_code KRB5_CALLCONV
|
||||
@@ -1364,7 +1457,7 @@ scc_set_default(krb5_context context, krb5_ccache id)
|
||||
return KRB5_CC_IO;
|
||||
}
|
||||
|
||||
ret = sqlite3_bind_text(s->umaster, 1, s->name, -1, NULL);
|
||||
ret = sqlite3_bind_text(s->umaster, 1, s->sub, -1, NULL);
|
||||
if (ret) {
|
||||
sqlite3_reset(s->umaster);
|
||||
krb5_set_error_message(context, KRB5_CC_IO,
|
||||
|
Reference in New Issue
Block a user