Make somewhat more working...
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@22815 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
@@ -41,17 +41,20 @@ typedef struct krb5_scache {
|
|||||||
char *file;
|
char *file;
|
||||||
sqlite3 *db;
|
sqlite3 *db;
|
||||||
|
|
||||||
int cid;
|
sqlite_uint64 cid;
|
||||||
|
|
||||||
/* */
|
/* */
|
||||||
HEIMDAL_MUTEX imutex;
|
HEIMDAL_MUTEX imutex;
|
||||||
sqlite3_stmt *icred;
|
sqlite3_stmt *icred;
|
||||||
|
sqlite3_stmt *dcred;
|
||||||
sqlite3_stmt *iprincipal;
|
sqlite3_stmt *iprincipal;
|
||||||
|
|
||||||
sqlite3_stmt *icache;
|
sqlite3_stmt *icache;
|
||||||
|
sqlite3_stmt *ucachen;
|
||||||
sqlite3_stmt *ucachep;
|
sqlite3_stmt *ucachep;
|
||||||
|
sqlite3_stmt *dcache;
|
||||||
sqlite3_stmt *scache;
|
sqlite3_stmt *scache;
|
||||||
|
sqlite3_stmt *scache_name;
|
||||||
|
|
||||||
} krb5_scache;
|
} krb5_scache;
|
||||||
|
|
||||||
@@ -62,15 +65,17 @@ typedef struct krb5_scache {
|
|||||||
#define SCACHE_STRING(x) #x
|
#define SCACHE_STRING(x) #x
|
||||||
#define SCACHE_XSTRING(x) SCACHE_STRING(x)
|
#define SCACHE_XSTRING(x) SCACHE_STRING(x)
|
||||||
|
|
||||||
#define SCACHE_DEF_CID 0
|
#define SCACHE_INVALID_CID ((sqlite_uint64)-1)
|
||||||
|
#define SCACHE_DEF_CID 1
|
||||||
#define SCACHE_DEF_CID_NAME SCACHE_XSTRING(SCACHE_DEF_CID)
|
#define SCACHE_DEF_CID_NAME SCACHE_XSTRING(SCACHE_DEF_CID)
|
||||||
|
#define SCACHE_DEF_NAME "Default-cache"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define SQL_CMASTER "" \
|
#define SQL_CMASTER "" \
|
||||||
"CREATE TABLE master (" \
|
"CREATE TABLE master (" \
|
||||||
"version INTEGER NOT NULL," \
|
"version INTEGER NOT NULL," \
|
||||||
"defaultcache INTEGER NOT NULL" \
|
"defaultcache INTEGER NOT NULL" \
|
||||||
")"
|
")"
|
||||||
@@ -83,9 +88,18 @@ typedef struct krb5_scache {
|
|||||||
"name TEXT NOT NULL" \
|
"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_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_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 "SELECT principal,name FROM caches WHERE OID=?"
|
||||||
|
#define SQL_SCACHE_NAME "SELECT oid FROM caches WHERE NAME=?"
|
||||||
|
|
||||||
#define SQL_CCREDS "" \
|
#define SQL_CCREDS "" \
|
||||||
"CREATE TABLE credentials (" \
|
"CREATE TABLE credentials (" \
|
||||||
@@ -95,7 +109,14 @@ typedef struct krb5_scache {
|
|||||||
"cred BLOB 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) VALUES (?,?,?,?)"
|
#define SQL_ICRED "INSERT INTO credentials (cid, kvno, etype, cred) VALUES (?,?,?,?)"
|
||||||
|
#define SQL_DCRED "DELETE FROM credentials WHERE cid=?"
|
||||||
|
|
||||||
#define SQL_CPRINCIPALS "" \
|
#define SQL_CPRINCIPALS "" \
|
||||||
"CREATE TABLE principals (" \
|
"CREATE TABLE principals (" \
|
||||||
@@ -122,15 +143,17 @@ free_krb5(void *str)
|
|||||||
krb5_xfree(str);
|
krb5_xfree(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static void
|
||||||
*
|
scc_free(krb5_scache *s)
|
||||||
*/
|
|
||||||
|
|
||||||
static const char*
|
|
||||||
scc_get_name(krb5_context context,
|
|
||||||
krb5_ccache id)
|
|
||||||
{
|
{
|
||||||
return SCACHE(id)->name;
|
if (s->file)
|
||||||
|
free(s->file);
|
||||||
|
if (s->name)
|
||||||
|
free(s->name);
|
||||||
|
/* XXX handle stmts */
|
||||||
|
if (s->db)
|
||||||
|
sqlite3_close(s->db);
|
||||||
|
free(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_scache *
|
static krb5_scache *
|
||||||
@@ -142,10 +165,31 @@ scc_alloc(const char *name)
|
|||||||
if(s == NULL)
|
if(s == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* XXX resolve name */
|
s->cid = SCACHE_INVALID_CID;
|
||||||
s->cid = SCACHE_DEF_CID;
|
|
||||||
s->file = DEFAULT_SCACHE;
|
if (name) {
|
||||||
s->name = SCACHE_DEF_CID_NAME;
|
char *file;
|
||||||
|
|
||||||
|
if (*name == '\0') {
|
||||||
|
/* XXX get default cid */
|
||||||
|
name = SCACHE_DEF_NAME;
|
||||||
|
}
|
||||||
|
s->name = strdup(name);
|
||||||
|
file = strchr(s->name, ':');
|
||||||
|
if (file) {
|
||||||
|
*file++ = '\0';
|
||||||
|
s->file = strdup(file);
|
||||||
|
} else {
|
||||||
|
s->file = strdup(DEFAULT_SCACHE);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s->file = strdup(DEFAULT_SCACHE);
|
||||||
|
asprintf(&s->name, "unique:%08x", (unsigned long)s);
|
||||||
|
}
|
||||||
|
if (s->file == NULL || s->name == NULL) {
|
||||||
|
scc_free(s);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
HEIMDAL_MUTEX_init(&s->imutex);
|
HEIMDAL_MUTEX_init(&s->imutex);
|
||||||
|
|
||||||
@@ -171,10 +215,68 @@ open_database(krb5_context context, krb5_scache *s, int flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code
|
static krb5_error_code
|
||||||
make_database(krb5_context context, krb5_scache *s, int create)
|
prepare_stmt(krb5_context context, sqlite3 *db, sqlite3_stmt **stmt, const char *str)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
ret = sqlite3_prepare_v2(db, str, -1, stmt, NULL);
|
||||||
|
if (ret != SQLITE_OK) {
|
||||||
|
krb5_set_error_string(context, "Failed to prepare stmt %s: %s",
|
||||||
|
str, sqlite3_errmsg(db));
|
||||||
|
return ENOENT;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static krb5_error_code
|
||||||
|
exec_stmt(krb5_context context, sqlite3 *db, const char *str,
|
||||||
|
krb5_error_code code)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = sqlite3_exec(db, str, NULL, NULL, NULL);
|
||||||
|
if (ret != SQLITE_OK) {
|
||||||
|
krb5_set_error_string(context, "Execute %s: %s", str,
|
||||||
|
sqlite3_errmsg(db));
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static krb5_error_code
|
||||||
|
create_cache(krb5_context context, krb5_scache *s)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
sqlite3_bind_text(s->icache, 1, s->name, -1, NULL);
|
||||||
|
do {
|
||||||
|
ret = sqlite3_step(s->icache);
|
||||||
|
} while (ret == SQLITE_ROW);
|
||||||
|
if (ret != SQLITE_DONE) {
|
||||||
|
krb5_set_error_string(context, "Failed to add scache: %d", ret);
|
||||||
|
return KRB5_CC_IO;
|
||||||
|
}
|
||||||
|
sqlite3_reset(s->icache);
|
||||||
|
|
||||||
|
s->cid = sqlite3_last_insert_rowid(s->db);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static void
|
||||||
|
trace(void* ptr, const char * str)
|
||||||
|
{
|
||||||
|
printf("SQL: %s\n", str);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static krb5_error_code
|
||||||
|
make_database(krb5_context context, krb5_scache *s)
|
||||||
|
{
|
||||||
|
int created_file = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (s->db)
|
if (s->db)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -184,75 +286,134 @@ make_database(krb5_context context, krb5_scache *s, int create)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
sqlite3_exec(s->db, SQL_CMASTER, NULL, NULL, NULL);
|
created_file = 1;
|
||||||
sqlite3_exec(s->db, SQL_CCACHE, NULL, NULL, NULL);
|
|
||||||
ret = sqlite3_exec(s->db, SQL_CCREDS, NULL, NULL, NULL);
|
|
||||||
if (ret != SQLITE_OK) {
|
|
||||||
krb5_set_error_string(context, "Failed to create table creds: %s",
|
|
||||||
sqlite3_errmsg(s->db));
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
sqlite3_exec(s->db, SQL_CPRINCIPALS, NULL, NULL, NULL);
|
|
||||||
|
|
||||||
sqlite3_exec(s->db, SQL_SETUP_MASTER, NULL, NULL, NULL);
|
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);
|
||||||
|
if (ret) goto out;
|
||||||
|
|
||||||
|
ret = exec_stmt(context, s->db, SQL_TCACHE, KRB5_CC_IO);
|
||||||
|
if (ret) goto out;
|
||||||
|
ret = exec_stmt(context, s->db, SQL_TCRED, KRB5_CC_IO);
|
||||||
|
if (ret) goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = sqlite3_prepare_v2(s->db, SQL_ICRED, -1, &s->icred, NULL);
|
#if 0
|
||||||
if (ret != SQLITE_OK) {
|
sqlite3_trace(s->db, trace, NULL);
|
||||||
krb5_set_error_string(context, "Failed to create icred: %s",
|
#endif
|
||||||
sqlite3_errmsg(s->db));
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
ret = sqlite3_prepare_v2(s->db, SQL_IPRINCIPAL, -1, &s->iprincipal, NULL);
|
|
||||||
if (ret != SQLITE_OK) {
|
|
||||||
krb5_set_error_string(context, "Failed to create iprincipal: %s",
|
|
||||||
sqlite3_errmsg(s->db));
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = sqlite3_prepare_v2(s->db, SQL_ICACHE, -1, &s->icache, NULL);
|
ret = prepare_stmt(context, s->db, &s->icred, SQL_ICRED);
|
||||||
if (ret != SQLITE_OK) {
|
if (ret) goto out;
|
||||||
krb5_set_error_string(context, "Failed to create icache: %s",
|
ret = prepare_stmt(context, s->db, &s->dcred, SQL_DCRED);
|
||||||
sqlite3_errmsg(s->db));
|
if (ret) goto out;
|
||||||
goto end;
|
ret = prepare_stmt(context, s->db, &s->iprincipal, SQL_IPRINCIPAL);
|
||||||
}
|
if (ret) goto out;
|
||||||
sqlite3_prepare_v2(s->db, SQL_UCACHE_PRINCIPAL, -1, &s->ucachep, NULL);
|
ret = prepare_stmt(context, s->db, &s->icache, SQL_ICACHE);
|
||||||
sqlite3_prepare_v2(s->db, SQL_SCACHE, -1, &s->scache, NULL);
|
if (ret) goto out;
|
||||||
|
ret = prepare_stmt(context, s->db, &s->ucachen, SQL_UCACHE_NAME);
|
||||||
if (create) {
|
if (ret) goto out;
|
||||||
/* create inital entry */
|
ret = prepare_stmt(context, s->db, &s->ucachep, SQL_UCACHE_PRINCIPAL);
|
||||||
sqlite3_bind_text(s->icache, 1, s->name, -1, NULL);
|
if (ret) goto out;
|
||||||
do {
|
ret = prepare_stmt(context, s->db, &s->dcache, SQL_DCACHE);
|
||||||
ret = sqlite3_step(s->icache);
|
if (ret) goto out;
|
||||||
} while (ret == SQLITE_ROW);
|
ret = prepare_stmt(context, s->db, &s->scache, SQL_SCACHE);
|
||||||
if (ret != SQLITE_DONE) {
|
if (ret) goto out;
|
||||||
krb5_set_error_string(context, "Failed to add scache: %d", ret);
|
ret = prepare_stmt(context, s->db, &s->scache_name, SQL_SCACHE_NAME);
|
||||||
goto end;
|
if (ret) goto out;
|
||||||
}
|
|
||||||
sqlite3_reset(s->icred);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
end:
|
out:
|
||||||
if (s->db)
|
if (s->db)
|
||||||
sqlite3_close(s->db);
|
sqlite3_close(s->db);
|
||||||
if (create)
|
if (created_file)
|
||||||
unlink(s->file);
|
unlink(s->file);
|
||||||
|
|
||||||
return ENOENT;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static krb5_error_code
|
||||||
|
bind_principal(krb5_context context,
|
||||||
|
sqlite3 *db,
|
||||||
|
sqlite3_stmt *stmt,
|
||||||
|
int col,
|
||||||
|
krb5_const_principal principal)
|
||||||
|
{
|
||||||
|
krb5_error_code ret;
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
ret = krb5_unparse_name(context, principal, &str);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = sqlite3_bind_text(stmt, col, str, -1, free_krb5);
|
||||||
|
if (ret != SQLITE_OK) {
|
||||||
|
krb5_xfree(str);
|
||||||
|
krb5_set_error_string(context, "bind principal: %s",
|
||||||
|
sqlite3_errmsg(db));
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const char*
|
||||||
|
scc_get_name(krb5_context context,
|
||||||
|
krb5_ccache id)
|
||||||
|
{
|
||||||
|
return SCACHE(id)->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code
|
static krb5_error_code
|
||||||
scc_resolve(krb5_context context, krb5_ccache *id, const char *res)
|
scc_resolve(krb5_context context, krb5_ccache *id, const char *res)
|
||||||
{
|
{
|
||||||
krb5_scache *s;
|
krb5_scache *s;
|
||||||
|
int ret;
|
||||||
|
|
||||||
s = scc_alloc(res);
|
s = scc_alloc(res);
|
||||||
if (s == NULL) {
|
if (s == NULL) {
|
||||||
krb5_set_error_string (context, "malloc: out of memory");
|
krb5_set_error_string (context, "malloc: out of memory");
|
||||||
return KRB5_CC_NOMEM;
|
return KRB5_CC_NOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = make_database(context, s);
|
||||||
|
if (ret) {
|
||||||
|
scc_free(s);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = sqlite3_bind_text(s->scache_name, 1, s->name, -1, NULL);
|
||||||
|
if (ret != SQLITE_OK) {
|
||||||
|
krb5_set_error_string(context, "bind name: %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);
|
||||||
|
krb5_set_error_string(context, "Cache name of wrong type "
|
||||||
|
"for scache %ld",
|
||||||
|
(unsigned long)s->name);
|
||||||
|
return KRB5_CC_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->cid = sqlite3_column_int(s->scache_name, 0);
|
||||||
|
} else {
|
||||||
|
s->cid = SCACHE_INVALID_CID;
|
||||||
|
}
|
||||||
|
sqlite3_reset(s->scache);
|
||||||
|
|
||||||
(*id)->data.data = s;
|
(*id)->data.data = s;
|
||||||
(*id)->data.length = sizeof(*s);
|
(*id)->data.length = sizeof(*s);
|
||||||
@@ -271,7 +432,6 @@ scc_gen_new(krb5_context context, krb5_ccache *id)
|
|||||||
krb5_set_error_string (context, "malloc: out of memory");
|
krb5_set_error_string (context, "malloc: out of memory");
|
||||||
return KRB5_CC_NOMEM;
|
return KRB5_CC_NOMEM;
|
||||||
}
|
}
|
||||||
s->cid = 0;
|
|
||||||
|
|
||||||
(*id)->data.data = s;
|
(*id)->data.data = s;
|
||||||
(*id)->data.length = sizeof(*s);
|
(*id)->data.length = sizeof(*s);
|
||||||
@@ -286,27 +446,54 @@ scc_initialize(krb5_context context,
|
|||||||
{
|
{
|
||||||
krb5_scache *s = SCACHE(id);
|
krb5_scache *s = SCACHE(id);
|
||||||
krb5_error_code ret;
|
krb5_error_code ret;
|
||||||
char *str;
|
|
||||||
|
|
||||||
ret = make_database(context, s, 1);
|
ret = make_database(context, s);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = krb5_unparse_name(context, primary_principal, &str);
|
sqlite3_exec(s->db, "BEGIN TRANSACTION", NULL, NULL, NULL);
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
sqlite3_bind_text(s->ucachep, 1, str, -1, free_krb5);
|
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) {
|
||||||
|
krb5_clear_error_string(context);
|
||||||
|
ret = KRB5_CC_IO;
|
||||||
|
goto rollback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = bind_principal(context, s->db, s->ucachep, 1, primary_principal);
|
||||||
|
if (ret)
|
||||||
|
goto rollback;
|
||||||
sqlite3_bind_int(s->ucachep, 2, s->cid);
|
sqlite3_bind_int(s->ucachep, 2, s->cid);
|
||||||
|
|
||||||
if (sqlite3_step(s->ucachep) != SQLITE_DONE)
|
do {
|
||||||
ret = EPERM; /* XXX */
|
ret = sqlite3_step(s->ucachep);
|
||||||
|
} while (ret == SQLITE_ROW);
|
||||||
sqlite3_reset(s->ucachep);
|
sqlite3_reset(s->ucachep);
|
||||||
|
if (ret != SQLITE_DONE) {
|
||||||
|
krb5_clear_error_string(context);
|
||||||
|
ret = KRB5_CC_IO;
|
||||||
|
goto rollback;
|
||||||
|
}
|
||||||
|
|
||||||
/* XXX delete all entries for this cid, trigger ? */
|
sqlite3_exec(s->db, "END TRANSACTION", NULL, NULL, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
rollback:
|
||||||
|
sqlite3_exec(s->db, "ROLLBACK", NULL, NULL, NULL);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code
|
static krb5_error_code
|
||||||
@@ -351,18 +538,40 @@ encode_creds(krb5_context context, krb5_creds *creds, krb5_data *data)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static krb5_error_code
|
||||||
|
decode_creds(krb5_context context, const void *data, size_t length,
|
||||||
|
krb5_creds *creds)
|
||||||
|
{
|
||||||
|
krb5_error_code ret;
|
||||||
|
krb5_storage *sp;
|
||||||
|
|
||||||
|
sp = krb5_storage_from_readonly_mem(data, length);
|
||||||
|
if (sp == NULL) {
|
||||||
|
krb5_set_error_string(context, "malloc: out of memory");
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = krb5_ret_creds(sp, creds);
|
||||||
|
krb5_storage_free(sp);
|
||||||
|
if (ret) {
|
||||||
|
krb5_set_error_string(context, "Failed to read credential");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static krb5_error_code
|
static krb5_error_code
|
||||||
scc_store_cred(krb5_context context,
|
scc_store_cred(krb5_context context,
|
||||||
krb5_ccache id,
|
krb5_ccache id,
|
||||||
krb5_creds *creds)
|
krb5_creds *creds)
|
||||||
{
|
{
|
||||||
unsigned long long credid;
|
sqlite_uint64 credid;
|
||||||
krb5_scache *s = SCACHE(id);
|
krb5_scache *s = SCACHE(id);
|
||||||
krb5_error_code ret;
|
krb5_error_code ret;
|
||||||
krb5_data data;
|
krb5_data data;
|
||||||
char *str;
|
|
||||||
|
|
||||||
ret = make_database(context, s, 0);
|
ret = make_database(context, s);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -370,6 +579,7 @@ scc_store_cred(krb5_context context,
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
sqlite3_bind_int(s->icred, 1, s->cid);
|
||||||
{
|
{
|
||||||
int kvno = 0;
|
int kvno = 0;
|
||||||
Ticket t;
|
Ticket t;
|
||||||
@@ -385,47 +595,58 @@ scc_store_cred(krb5_context context,
|
|||||||
if(t.enc_part.kvno)
|
if(t.enc_part.kvno)
|
||||||
kvno = *t.enc_part.kvno;
|
kvno = *t.enc_part.kvno;
|
||||||
|
|
||||||
sqlite3_bind_int(s->icred, 1, kvno);
|
sqlite3_bind_int(s->icred, 2, kvno);
|
||||||
sqlite3_bind_int(s->icred, 2, t.enc_part.etype);
|
sqlite3_bind_int(s->icred, 3, t.enc_part.etype);
|
||||||
|
|
||||||
free_Ticket(&t);
|
free_Ticket(&t);
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlite3_bind_blob(s->icred, 3, data.data, data.length, free_data);
|
sqlite3_bind_blob(s->icred, 4, data.data, data.length, free_data);
|
||||||
|
|
||||||
sqlite3_exec(s->db, "BEGIN TRANSACTION", NULL, NULL, NULL);
|
sqlite3_exec(s->db, "BEGIN TRANSACTION", NULL, NULL, NULL);
|
||||||
|
|
||||||
if (sqlite3_step(s->icred) != SQLITE_DONE)
|
do {
|
||||||
goto rollback;
|
ret = sqlite3_step(s->icred);
|
||||||
|
} while (ret == SQLITE_ROW);
|
||||||
sqlite3_reset(s->icred);
|
sqlite3_reset(s->icred);
|
||||||
|
if (ret != SQLITE_DONE) {
|
||||||
|
krb5_set_error_string(context, "Failed to add credential: %s",
|
||||||
|
sqlite3_errmsg(s->db));
|
||||||
|
goto rollback;
|
||||||
|
}
|
||||||
|
|
||||||
credid = sqlite3_last_insert_rowid(s->db);
|
credid = sqlite3_last_insert_rowid(s->db);
|
||||||
|
|
||||||
{
|
{
|
||||||
krb5_unparse_name(context, creds->server, &str);
|
bind_principal(context, s->db, s->iprincipal, 1, creds->server);
|
||||||
|
|
||||||
sqlite3_bind_text(s->iprincipal, 1, str, -1, free_krb5);
|
|
||||||
sqlite3_bind_int(s->iprincipal, 2, 1);
|
sqlite3_bind_int(s->iprincipal, 2, 1);
|
||||||
sqlite3_bind_int(s->iprincipal, 3, credid);
|
sqlite3_bind_int(s->iprincipal, 3, credid);
|
||||||
|
|
||||||
if (sqlite3_step(s->icred) != SQLITE_DONE)
|
do {
|
||||||
|
ret = sqlite3_step(s->iprincipal);
|
||||||
|
} while (ret == SQLITE_ROW);
|
||||||
|
sqlite3_reset(s->iprincipal);
|
||||||
|
if (ret != SQLITE_DONE) {
|
||||||
|
krb5_set_error_string(context, "Failed to add principal: %s",
|
||||||
|
sqlite3_errmsg(s->db));
|
||||||
goto rollback;
|
goto rollback;
|
||||||
|
}
|
||||||
sqlite3_reset(s->icred);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
krb5_unparse_name(context, creds->client, &str);
|
bind_principal(context, s->db, s->iprincipal, 1, creds->client);
|
||||||
|
|
||||||
sqlite3_bind_text(s->iprincipal, 1, str, -1, free_krb5);
|
|
||||||
sqlite3_bind_int(s->iprincipal, 2, 0);
|
sqlite3_bind_int(s->iprincipal, 2, 0);
|
||||||
sqlite3_bind_int(s->iprincipal, 3, credid);
|
sqlite3_bind_int(s->iprincipal, 3, credid);
|
||||||
|
|
||||||
if (sqlite3_step(s->icred) != SQLITE_DONE)
|
do {
|
||||||
|
ret = sqlite3_step(s->iprincipal);
|
||||||
|
} while (ret == SQLITE_ROW);
|
||||||
|
sqlite3_reset(s->iprincipal);
|
||||||
|
if (ret != SQLITE_DONE) {
|
||||||
|
krb5_set_error_string(context, "Failed to add principal: %s",
|
||||||
|
sqlite3_errmsg(s->db));
|
||||||
goto rollback;
|
goto rollback;
|
||||||
|
}
|
||||||
sqlite3_reset(s->icred);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlite3_exec(s->db, "END TRANSACTION", NULL, NULL, NULL);
|
sqlite3_exec(s->db, "END TRANSACTION", NULL, NULL, NULL);
|
||||||
@@ -433,7 +654,7 @@ scc_store_cred(krb5_context context,
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
rollback:
|
rollback:
|
||||||
|
krb5_set_error_string(context, "store credentials: %s", sqlite3_errmsg(s->db));
|
||||||
sqlite3_exec(s->db, "ROLLBACK", NULL, NULL, NULL);
|
sqlite3_exec(s->db, "ROLLBACK", NULL, NULL, NULL);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -450,7 +671,7 @@ scc_get_principal(krb5_context context,
|
|||||||
|
|
||||||
*principal = NULL;
|
*principal = NULL;
|
||||||
|
|
||||||
ret = make_database(context, s, 0);
|
ret = make_database(context, s);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -458,23 +679,26 @@ scc_get_principal(krb5_context context,
|
|||||||
|
|
||||||
if (sqlite3_step(s->scache) != SQLITE_ROW) {
|
if (sqlite3_step(s->scache) != SQLITE_ROW) {
|
||||||
sqlite3_reset(s->scache);
|
sqlite3_reset(s->scache);
|
||||||
krb5_set_error_string(context, "No principal for scache %d", s->cid);
|
krb5_set_error_string(context, "No principal for scache %ld",
|
||||||
return ENOENT;
|
(unsigned long)s->cid);
|
||||||
|
return KRB5_CC_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sqlite3_column_type(s->scache, 2) == SQLITE_TEXT) {
|
if (sqlite3_column_type(s->scache, 0) != SQLITE_TEXT) {
|
||||||
sqlite3_reset(s->scache);
|
sqlite3_reset(s->scache);
|
||||||
krb5_set_error_string(context, "Principal data of wrong type "
|
krb5_set_error_string(context, "Principal data of wrong type "
|
||||||
"for scache %d", s->cid);
|
"for scache %ld",
|
||||||
return ENOENT;
|
(unsigned long)s->cid);
|
||||||
|
return KRB5_CC_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
str = (const char *)sqlite3_column_text(s->scache, 2);
|
str = (const char *)sqlite3_column_text(s->scache, 0);
|
||||||
if (str == NULL) {
|
if (str == NULL) {
|
||||||
sqlite3_reset(s->scache);
|
sqlite3_reset(s->scache);
|
||||||
krb5_set_error_string(context, "Principal not set "
|
krb5_set_error_string(context, "Principal not set "
|
||||||
"for scache %d", s->cid);
|
"for scache %ld",
|
||||||
return ENOENT;
|
(unsigned long)s->cid);
|
||||||
|
return KRB5_CC_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = krb5_parse_name(context, str, principal);
|
ret = krb5_parse_name(context, str, principal);
|
||||||
@@ -491,13 +715,31 @@ scc_get_first (krb5_context context,
|
|||||||
{
|
{
|
||||||
krb5_scache *s = SCACHE(id);
|
krb5_scache *s = SCACHE(id);
|
||||||
krb5_error_code ret;
|
krb5_error_code ret;
|
||||||
|
sqlite3_stmt *stmt;
|
||||||
|
|
||||||
ret = make_database(context, s, 0);
|
*cursor = NULL;
|
||||||
|
|
||||||
|
ret = make_database(context, s);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
krb5_clear_error_string(context);
|
if (s->cid == SCACHE_INVALID_CID)
|
||||||
return KRB5_CC_END;
|
return KRB5_CC_END;
|
||||||
|
|
||||||
|
ret = prepare_stmt(context, s->db, &stmt,
|
||||||
|
"SELECT cred FROM credentials WHERE cid = ?");
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = sqlite3_bind_int(stmt, 1, s->cid);
|
||||||
|
if (ret) {
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
krb5_clear_error_string(context);
|
||||||
|
return KRB5_CC_END;
|
||||||
|
}
|
||||||
|
*cursor = stmt;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code
|
static krb5_error_code
|
||||||
@@ -506,8 +748,37 @@ scc_get_next (krb5_context context,
|
|||||||
krb5_cc_cursor *cursor,
|
krb5_cc_cursor *cursor,
|
||||||
krb5_creds *creds)
|
krb5_creds *creds)
|
||||||
{
|
{
|
||||||
|
sqlite3_stmt *stmt = *cursor;
|
||||||
|
krb5_scache *s = SCACHE(id);
|
||||||
|
krb5_error_code ret;
|
||||||
|
|
||||||
|
const void *data = NULL;
|
||||||
|
size_t len = 0;
|
||||||
|
|
||||||
|
ret = sqlite3_step(stmt);
|
||||||
|
if (ret == SQLITE_DONE) {
|
||||||
|
krb5_clear_error_string(context);
|
||||||
|
return KRB5_CC_END;
|
||||||
|
} else if (ret != SQLITE_ROW) {
|
||||||
|
krb5_set_error_string(context, "Database failed: %s",
|
||||||
|
sqlite3_errmsg(s->db));
|
||||||
|
return KRB5_CC_IO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sqlite3_column_type(stmt, 0) != SQLITE_BLOB) {
|
||||||
|
krb5_set_error_string(context, "credential of wrong type "
|
||||||
|
"for scache %ld",
|
||||||
|
(unsigned long)s->cid);
|
||||||
|
return KRB5_CC_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = sqlite3_column_blob(stmt, 0);
|
||||||
|
len = sqlite3_column_bytes(stmt, 0);
|
||||||
|
|
||||||
|
ret = decode_creds(context, data, len, creds);
|
||||||
|
|
||||||
krb5_clear_error_string(context);
|
krb5_clear_error_string(context);
|
||||||
return KRB5_CC_END;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code
|
static krb5_error_code
|
||||||
@@ -515,6 +786,7 @@ scc_end_get (krb5_context context,
|
|||||||
krb5_ccache id,
|
krb5_ccache id,
|
||||||
krb5_cc_cursor *cursor)
|
krb5_cc_cursor *cursor)
|
||||||
{
|
{
|
||||||
|
sqlite3_finalize((sqlite3_stmt *)*cursor);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,7 +799,7 @@ scc_remove_cred(krb5_context context,
|
|||||||
krb5_scache *s = SCACHE(id);
|
krb5_scache *s = SCACHE(id);
|
||||||
krb5_error_code ret;
|
krb5_error_code ret;
|
||||||
|
|
||||||
ret = make_database(context, s, 0);
|
ret = make_database(context, s);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -569,22 +841,64 @@ scc_move(krb5_context context, krb5_ccache from, krb5_ccache to)
|
|||||||
krb5_scache *sto = SCACHE(to);
|
krb5_scache *sto = SCACHE(to);
|
||||||
krb5_error_code ret;
|
krb5_error_code ret;
|
||||||
|
|
||||||
ret = make_database(context, sfrom, 0);
|
if (strcmp(sfrom->file, sto->file) != 0) {
|
||||||
|
krb5_set_error_string(context, "Can't handle cross database "
|
||||||
|
"credential move: %s -> %s",
|
||||||
|
sfrom->file, sto->file);
|
||||||
|
return KRB5_CC_BADNAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = make_database(context, sfrom);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = make_database(context, sto, 1);
|
sqlite3_exec(sfrom->db, "BEGIN TRANSACTION", NULL, NULL, NULL);
|
||||||
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_string(context, "Failed to delete old cache: %d", ret);
|
||||||
|
goto rollback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_bind_text(sfrom->ucachen, 1, sto->name, -1, NULL);
|
||||||
|
sqlite3_bind_int(sfrom->ucachen, 2, sfrom->cid);
|
||||||
|
|
||||||
|
do {
|
||||||
|
ret = sqlite3_step(sfrom->ucachen);
|
||||||
|
} while (ret == SQLITE_ROW);
|
||||||
|
sqlite3_reset(sfrom->ucachen);
|
||||||
|
if (ret != SQLITE_DONE) {
|
||||||
|
krb5_set_error_string(context, "Failed to update new cache: %d", ret);
|
||||||
|
goto rollback;
|
||||||
|
}
|
||||||
|
|
||||||
|
sto->cid = sfrom->cid;
|
||||||
|
|
||||||
|
sqlite3_exec(sfrom->db, "END TRANSACTION", NULL, NULL, NULL);
|
||||||
|
|
||||||
|
/* free sfrom */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
rollback:
|
||||||
|
|
||||||
|
sqlite3_exec(sfrom->db, "ROLLBACK", NULL, NULL, NULL);
|
||||||
|
|
||||||
|
return KRB5_CC_IO;
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code
|
static krb5_error_code
|
||||||
scc_default_name(krb5_context context, char **str)
|
scc_default_name(krb5_context context, char **str)
|
||||||
{
|
{
|
||||||
asprintf(str, "SCACHE:%s:%s", DEFAULT_SCACHE, SCACHE_DEF_CID_NAME);
|
asprintf(str, "SCACHE:%s:%s", DEFAULT_SCACHE, SCACHE_DEF_NAME);
|
||||||
if (*str == NULL) {
|
if (*str == NULL) {
|
||||||
krb5_set_error_string(context, "out of memory");
|
krb5_set_error_string(context, "out of memory");
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
|
Reference in New Issue
Block a user