1226031Sstas/* 2226031Sstas * Copyright (c) 2008 Kungliga Tekniska H��gskolan 3226031Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4226031Sstas * All rights reserved. 5226031Sstas * 6226031Sstas * Redistribution and use in source and binary forms, with or without 7226031Sstas * modification, are permitted provided that the following conditions 8226031Sstas * are met: 9226031Sstas * 10226031Sstas * 1. Redistributions of source code must retain the above copyright 11226031Sstas * notice, this list of conditions and the following disclaimer. 12226031Sstas * 13226031Sstas * 2. Redistributions in binary form must reproduce the above copyright 14226031Sstas * notice, this list of conditions and the following disclaimer in the 15226031Sstas * documentation and/or other materials provided with the distribution. 16226031Sstas * 17226031Sstas * 3. Neither the name of the Institute nor the names of its contributors 18226031Sstas * may be used to endorse or promote products derived from this software 19226031Sstas * without specific prior written permission. 20226031Sstas * 21226031Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22226031Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23226031Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24226031Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25226031Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26226031Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27226031Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28226031Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29226031Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30226031Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31226031Sstas * SUCH DAMAGE. 32226031Sstas */ 33226031Sstas 34226031Sstas#include "krb5_locl.h" 35226031Sstas 36226031Sstas#ifdef HAVE_SCC 37226031Sstas 38226031Sstas#include <sqlite3.h> 39226031Sstas 40226031Sstastypedef struct krb5_scache { 41226031Sstas char *name; 42226031Sstas char *file; 43226031Sstas sqlite3 *db; 44226031Sstas 45226031Sstas sqlite_uint64 cid; 46226031Sstas 47226031Sstas sqlite3_stmt *icred; 48226031Sstas sqlite3_stmt *dcred; 49226031Sstas sqlite3_stmt *iprincipal; 50226031Sstas 51226031Sstas sqlite3_stmt *icache; 52226031Sstas sqlite3_stmt *ucachen; 53226031Sstas sqlite3_stmt *ucachep; 54226031Sstas sqlite3_stmt *dcache; 55226031Sstas sqlite3_stmt *scache; 56226031Sstas sqlite3_stmt *scache_name; 57226031Sstas sqlite3_stmt *umaster; 58226031Sstas 59226031Sstas} krb5_scache; 60226031Sstas 61226031Sstas#define SCACHE(X) ((krb5_scache *)(X)->data.data) 62226031Sstas 63226031Sstas#define SCACHE_DEF_NAME "Default-cache" 64226031Sstas#ifdef KRB5_USE_PATH_TOKENS 65226031Sstas#define KRB5_SCACHE_DB "%{TEMP}/krb5scc_%{uid}" 66226031Sstas#else 67226031Sstas#define KRB5_SCACHE_DB "/tmp/krb5scc_%{uid}" 68226031Sstas#endif 69226031Sstas#define KRB5_SCACHE_NAME "SCC:" SCACHE_DEF_NAME ":" KRB5_SCACHE_DB 70226031Sstas 71226031Sstas#define SCACHE_INVALID_CID ((sqlite_uint64)-1) 72226031Sstas 73226031Sstas/* 74226031Sstas * 75226031Sstas */ 76226031Sstas 77226031Sstas#define SQL_CMASTER "" \ 78226031Sstas "CREATE TABLE master (" \ 79226031Sstas "oid INTEGER PRIMARY KEY," \ 80226031Sstas "version INTEGER NOT NULL," \ 81226031Sstas "defaultcache TEXT NOT NULL" \ 82226031Sstas ")" 83226031Sstas 84226031Sstas#define SQL_SETUP_MASTER \ 85226031Sstas "INSERT INTO master (version,defaultcache) VALUES(2, \"" SCACHE_DEF_NAME "\")" 86226031Sstas#define SQL_UMASTER "UPDATE master SET defaultcache=? WHERE version=2" 87226031Sstas 88226031Sstas#define SQL_CCACHE "" \ 89226031Sstas "CREATE TABLE caches (" \ 90226031Sstas "oid INTEGER PRIMARY KEY," \ 91226031Sstas "principal TEXT," \ 92226031Sstas "name TEXT NOT NULL" \ 93226031Sstas ")" 94226031Sstas 95226031Sstas#define SQL_TCACHE "" \ 96226031Sstas "CREATE TRIGGER CacheDropCreds AFTER DELETE ON caches " \ 97226031Sstas "FOR EACH ROW BEGIN " \ 98226031Sstas "DELETE FROM credentials WHERE cid=old.oid;" \ 99226031Sstas "END" 100226031Sstas 101226031Sstas#define SQL_ICACHE "INSERT INTO caches (name) VALUES(?)" 102226031Sstas#define SQL_UCACHE_NAME "UPDATE caches SET name=? WHERE OID=?" 103226031Sstas#define SQL_UCACHE_PRINCIPAL "UPDATE caches SET principal=? WHERE OID=?" 104226031Sstas#define SQL_DCACHE "DELETE FROM caches WHERE OID=?" 105226031Sstas#define SQL_SCACHE "SELECT principal,name FROM caches WHERE OID=?" 106226031Sstas#define SQL_SCACHE_NAME "SELECT oid FROM caches WHERE NAME=?" 107226031Sstas 108226031Sstas#define SQL_CCREDS "" \ 109226031Sstas "CREATE TABLE credentials (" \ 110226031Sstas "oid INTEGER PRIMARY KEY," \ 111226031Sstas "cid INTEGER NOT NULL," \ 112226031Sstas "kvno INTEGER NOT NULL," \ 113226031Sstas "etype INTEGER NOT NULL," \ 114226031Sstas "created_at INTEGER NOT NULL," \ 115226031Sstas "cred BLOB NOT NULL" \ 116226031Sstas ")" 117226031Sstas 118226031Sstas#define SQL_TCRED "" \ 119226031Sstas "CREATE TRIGGER credDropPrincipal AFTER DELETE ON credentials " \ 120226031Sstas "FOR EACH ROW BEGIN " \ 121226031Sstas "DELETE FROM principals WHERE credential_id=old.oid;" \ 122226031Sstas "END" 123226031Sstas 124226031Sstas#define SQL_ICRED "INSERT INTO credentials (cid, kvno, etype, cred, created_at) VALUES (?,?,?,?,?)" 125226031Sstas#define SQL_DCRED "DELETE FROM credentials WHERE cid=?" 126226031Sstas 127226031Sstas#define SQL_CPRINCIPALS "" \ 128226031Sstas "CREATE TABLE principals (" \ 129226031Sstas "oid INTEGER PRIMARY KEY," \ 130226031Sstas "principal TEXT NOT NULL," \ 131226031Sstas "type INTEGER NOT NULL," \ 132226031Sstas "credential_id INTEGER NOT NULL" \ 133226031Sstas ")" 134226031Sstas 135226031Sstas#define SQL_IPRINCIPAL "INSERT INTO principals (principal, type, credential_id) VALUES (?,?,?)" 136226031Sstas 137226031Sstas/* 138226031Sstas * sqlite destructors 139226031Sstas */ 140226031Sstas 141226031Sstasstatic void 142226031Sstasfree_data(void *data) 143226031Sstas{ 144226031Sstas free(data); 145226031Sstas} 146226031Sstas 147226031Sstasstatic void 148226031Sstasfree_krb5(void *str) 149226031Sstas{ 150226031Sstas krb5_xfree(str); 151226031Sstas} 152226031Sstas 153226031Sstasstatic void 154226031Sstasscc_free(krb5_scache *s) 155226031Sstas{ 156226031Sstas if (s->file) 157226031Sstas free(s->file); 158226031Sstas if (s->name) 159226031Sstas free(s->name); 160226031Sstas 161226031Sstas if (s->icred) 162226031Sstas sqlite3_finalize(s->icred); 163226031Sstas if (s->dcred) 164226031Sstas sqlite3_finalize(s->dcred); 165226031Sstas if (s->iprincipal) 166226031Sstas sqlite3_finalize(s->iprincipal); 167226031Sstas if (s->icache) 168226031Sstas sqlite3_finalize(s->icache); 169226031Sstas if (s->ucachen) 170226031Sstas sqlite3_finalize(s->ucachen); 171226031Sstas if (s->ucachep) 172226031Sstas sqlite3_finalize(s->ucachep); 173226031Sstas if (s->dcache) 174226031Sstas sqlite3_finalize(s->dcache); 175226031Sstas if (s->scache) 176226031Sstas sqlite3_finalize(s->scache); 177226031Sstas if (s->scache_name) 178226031Sstas sqlite3_finalize(s->scache_name); 179226031Sstas if (s->umaster) 180226031Sstas sqlite3_finalize(s->umaster); 181226031Sstas 182226031Sstas if (s->db) 183226031Sstas sqlite3_close(s->db); 184226031Sstas free(s); 185226031Sstas} 186226031Sstas 187226031Sstas#ifdef TRACEME 188226031Sstasstatic void 189226031Sstastrace(void* ptr, const char * str) 190226031Sstas{ 191226031Sstas printf("SQL: %s\n", str); 192226031Sstas} 193226031Sstas#endif 194226031Sstas 195226031Sstasstatic krb5_error_code 196226031Sstasprepare_stmt(krb5_context context, sqlite3 *db, 197226031Sstas sqlite3_stmt **stmt, const char *str) 198226031Sstas{ 199226031Sstas int ret; 200226031Sstas 201226031Sstas ret = sqlite3_prepare_v2(db, str, -1, stmt, NULL); 202226031Sstas if (ret != SQLITE_OK) { 203226031Sstas krb5_set_error_message(context, ENOENT, 204226031Sstas N_("Failed to prepare stmt %s: %s", ""), 205226031Sstas str, sqlite3_errmsg(db)); 206226031Sstas return ENOENT; 207226031Sstas } 208226031Sstas return 0; 209226031Sstas} 210226031Sstas 211226031Sstasstatic krb5_error_code 212226031Sstasexec_stmt(krb5_context context, sqlite3 *db, const char *str, 213226031Sstas krb5_error_code code) 214226031Sstas{ 215226031Sstas int ret; 216226031Sstas 217226031Sstas ret = sqlite3_exec(db, str, NULL, NULL, NULL); 218226031Sstas if (ret != SQLITE_OK && code) { 219226031Sstas krb5_set_error_message(context, code, 220226031Sstas N_("scache execute %s: %s", ""), str, 221226031Sstas sqlite3_errmsg(db)); 222226031Sstas return code; 223226031Sstas } 224226031Sstas return 0; 225226031Sstas} 226226031Sstas 227226031Sstasstatic krb5_error_code 228226031Sstasdefault_db(krb5_context context, sqlite3 **db) 229226031Sstas{ 230226031Sstas char *name; 231226031Sstas int ret; 232226031Sstas 233226031Sstas ret = _krb5_expand_default_cc_name(context, KRB5_SCACHE_DB, &name); 234226031Sstas if (ret) 235226031Sstas return ret; 236226031Sstas 237226031Sstas ret = sqlite3_open_v2(name, db, SQLITE_OPEN_READWRITE, NULL); 238226031Sstas free(name); 239226031Sstas if (ret != SQLITE_OK) { 240226031Sstas krb5_clear_error_message(context); 241226031Sstas return ENOENT; 242226031Sstas } 243226031Sstas 244226031Sstas#ifdef TRACEME 245226031Sstas sqlite3_trace(*db, trace, NULL); 246226031Sstas#endif 247226031Sstas 248226031Sstas return 0; 249226031Sstas} 250226031Sstas 251226031Sstasstatic krb5_error_code 252226031Sstasget_def_name(krb5_context context, char **str) 253226031Sstas{ 254226031Sstas krb5_error_code ret; 255226031Sstas sqlite3_stmt *stmt; 256226031Sstas const char *name; 257226031Sstas sqlite3 *db; 258226031Sstas 259226031Sstas ret = default_db(context, &db); 260226031Sstas if (ret) 261226031Sstas return ret; 262226031Sstas 263226031Sstas ret = prepare_stmt(context, db, &stmt, "SELECT defaultcache FROM master"); 264226031Sstas if (ret) { 265226031Sstas sqlite3_close(db); 266226031Sstas return ret; 267226031Sstas } 268226031Sstas 269226031Sstas ret = sqlite3_step(stmt); 270226031Sstas if (ret != SQLITE_ROW) 271226031Sstas goto out; 272226031Sstas 273226031Sstas if (sqlite3_column_type(stmt, 0) != SQLITE_TEXT) 274226031Sstas goto out; 275226031Sstas 276226031Sstas name = (const char *)sqlite3_column_text(stmt, 0); 277226031Sstas if (name == NULL) 278226031Sstas goto out; 279226031Sstas 280226031Sstas *str = strdup(name); 281226031Sstas if (*str == NULL) 282226031Sstas goto out; 283226031Sstas 284226031Sstas sqlite3_finalize(stmt); 285226031Sstas sqlite3_close(db); 286226031Sstas return 0; 287226031Sstasout: 288226031Sstas sqlite3_finalize(stmt); 289226031Sstas sqlite3_close(db); 290226031Sstas krb5_clear_error_message(context); 291226031Sstas return ENOENT; 292226031Sstas} 293226031Sstas 294226031Sstas 295226031Sstas 296226031Sstasstatic krb5_scache * KRB5_CALLCONV 297226031Sstasscc_alloc(krb5_context context, const char *name) 298226031Sstas{ 299226031Sstas krb5_error_code ret; 300226031Sstas krb5_scache *s; 301226031Sstas 302226031Sstas ALLOC(s, 1); 303226031Sstas if(s == NULL) 304226031Sstas return NULL; 305226031Sstas 306226031Sstas s->cid = SCACHE_INVALID_CID; 307226031Sstas 308226031Sstas if (name) { 309226031Sstas char *file; 310226031Sstas 311226031Sstas if (*name == '\0') { 312226031Sstas krb5_error_code ret; 313226031Sstas ret = get_def_name(context, &s->name); 314226031Sstas if (ret) 315226031Sstas s->name = strdup(SCACHE_DEF_NAME); 316226031Sstas } else 317226031Sstas s->name = strdup(name); 318226031Sstas 319226031Sstas file = strrchr(s->name, ':'); 320226031Sstas if (file) { 321226031Sstas *file++ = '\0'; 322226031Sstas s->file = strdup(file); 323226031Sstas ret = 0; 324226031Sstas } else { 325226031Sstas ret = _krb5_expand_default_cc_name(context, KRB5_SCACHE_DB, &s->file); 326226031Sstas } 327226031Sstas } else { 328226031Sstas _krb5_expand_default_cc_name(context, KRB5_SCACHE_DB, &s->file); 329226031Sstas ret = asprintf(&s->name, "unique-%p", s); 330226031Sstas } 331226031Sstas if (ret < 0 || s->file == NULL || s->name == NULL) { 332226031Sstas scc_free(s); 333226031Sstas return NULL; 334226031Sstas } 335226031Sstas 336226031Sstas return s; 337226031Sstas} 338226031Sstas 339226031Sstasstatic krb5_error_code 340226031Sstasopen_database(krb5_context context, krb5_scache *s, int flags) 341226031Sstas{ 342226031Sstas int ret; 343226031Sstas 344226031Sstas ret = sqlite3_open_v2(s->file, &s->db, SQLITE_OPEN_READWRITE|flags, NULL); 345226031Sstas if (ret) { 346226031Sstas if (s->db) { 347226031Sstas krb5_set_error_message(context, ENOENT, 348226031Sstas N_("Error opening scache file %s: %s", ""), 349226031Sstas s->file, sqlite3_errmsg(s->db)); 350226031Sstas sqlite3_close(s->db); 351226031Sstas s->db = NULL; 352226031Sstas } else 353226031Sstas krb5_set_error_message(context, ENOENT, 354226031Sstas N_("malloc: out of memory", "")); 355226031Sstas return ENOENT; 356226031Sstas } 357226031Sstas return 0; 358226031Sstas} 359226031Sstas 360226031Sstasstatic krb5_error_code 361226031Sstascreate_cache(krb5_context context, krb5_scache *s) 362226031Sstas{ 363226031Sstas int ret; 364226031Sstas 365226031Sstas sqlite3_bind_text(s->icache, 1, s->name, -1, NULL); 366226031Sstas do { 367226031Sstas ret = sqlite3_step(s->icache); 368226031Sstas } while (ret == SQLITE_ROW); 369226031Sstas if (ret != SQLITE_DONE) { 370226031Sstas krb5_set_error_message(context, KRB5_CC_IO, 371226031Sstas N_("Failed to add scache: %d", ""), ret); 372226031Sstas return KRB5_CC_IO; 373226031Sstas } 374226031Sstas sqlite3_reset(s->icache); 375226031Sstas 376226031Sstas s->cid = sqlite3_last_insert_rowid(s->db); 377226031Sstas 378226031Sstas return 0; 379226031Sstas} 380226031Sstas 381226031Sstasstatic krb5_error_code 382226031Sstasmake_database(krb5_context context, krb5_scache *s) 383226031Sstas{ 384226031Sstas int created_file = 0; 385226031Sstas int ret; 386226031Sstas 387226031Sstas if (s->db) 388226031Sstas return 0; 389226031Sstas 390226031Sstas ret = open_database(context, s, 0); 391226031Sstas if (ret) { 392226031Sstas mode_t oldumask = umask(077); 393226031Sstas ret = open_database(context, s, SQLITE_OPEN_CREATE); 394226031Sstas umask(oldumask); 395226031Sstas if (ret) goto out; 396226031Sstas 397226031Sstas created_file = 1; 398226031Sstas 399226031Sstas ret = exec_stmt(context, s->db, SQL_CMASTER, KRB5_CC_IO); 400226031Sstas if (ret) goto out; 401226031Sstas ret = exec_stmt(context, s->db, SQL_CCACHE, KRB5_CC_IO); 402226031Sstas if (ret) goto out; 403226031Sstas ret = exec_stmt(context, s->db, SQL_CCREDS, KRB5_CC_IO); 404226031Sstas if (ret) goto out; 405226031Sstas ret = exec_stmt(context, s->db, SQL_CPRINCIPALS, KRB5_CC_IO); 406226031Sstas if (ret) goto out; 407226031Sstas ret = exec_stmt(context, s->db, SQL_SETUP_MASTER, KRB5_CC_IO); 408226031Sstas if (ret) goto out; 409226031Sstas 410226031Sstas ret = exec_stmt(context, s->db, SQL_TCACHE, KRB5_CC_IO); 411226031Sstas if (ret) goto out; 412226031Sstas ret = exec_stmt(context, s->db, SQL_TCRED, KRB5_CC_IO); 413226031Sstas if (ret) goto out; 414226031Sstas } 415226031Sstas 416226031Sstas#ifdef TRACEME 417226031Sstas sqlite3_trace(s->db, trace, NULL); 418226031Sstas#endif 419226031Sstas 420226031Sstas ret = prepare_stmt(context, s->db, &s->icred, SQL_ICRED); 421226031Sstas if (ret) goto out; 422226031Sstas ret = prepare_stmt(context, s->db, &s->dcred, SQL_DCRED); 423226031Sstas if (ret) goto out; 424226031Sstas ret = prepare_stmt(context, s->db, &s->iprincipal, SQL_IPRINCIPAL); 425226031Sstas if (ret) goto out; 426226031Sstas ret = prepare_stmt(context, s->db, &s->icache, SQL_ICACHE); 427226031Sstas if (ret) goto out; 428226031Sstas ret = prepare_stmt(context, s->db, &s->ucachen, SQL_UCACHE_NAME); 429226031Sstas if (ret) goto out; 430226031Sstas ret = prepare_stmt(context, s->db, &s->ucachep, SQL_UCACHE_PRINCIPAL); 431226031Sstas if (ret) goto out; 432226031Sstas ret = prepare_stmt(context, s->db, &s->dcache, SQL_DCACHE); 433226031Sstas if (ret) goto out; 434226031Sstas ret = prepare_stmt(context, s->db, &s->scache, SQL_SCACHE); 435226031Sstas if (ret) goto out; 436226031Sstas ret = prepare_stmt(context, s->db, &s->scache_name, SQL_SCACHE_NAME); 437226031Sstas if (ret) goto out; 438226031Sstas ret = prepare_stmt(context, s->db, &s->umaster, SQL_UMASTER); 439226031Sstas if (ret) goto out; 440226031Sstas 441226031Sstas return 0; 442226031Sstas 443226031Sstasout: 444226031Sstas if (s->db) 445226031Sstas sqlite3_close(s->db); 446226031Sstas if (created_file) 447226031Sstas unlink(s->file); 448226031Sstas 449226031Sstas return ret; 450226031Sstas} 451226031Sstas 452226031Sstasstatic krb5_error_code 453226031Sstasbind_principal(krb5_context context, 454226031Sstas sqlite3 *db, 455226031Sstas sqlite3_stmt *stmt, 456226031Sstas int col, 457226031Sstas krb5_const_principal principal) 458226031Sstas{ 459226031Sstas krb5_error_code ret; 460226031Sstas char *str; 461226031Sstas 462226031Sstas ret = krb5_unparse_name(context, principal, &str); 463226031Sstas if (ret) 464226031Sstas return ret; 465226031Sstas 466226031Sstas ret = sqlite3_bind_text(stmt, col, str, -1, free_krb5); 467226031Sstas if (ret != SQLITE_OK) { 468226031Sstas krb5_xfree(str); 469226031Sstas krb5_set_error_message(context, ENOMEM, 470226031Sstas N_("scache bind principal: %s", ""), 471226031Sstas sqlite3_errmsg(db)); 472226031Sstas return ENOMEM; 473226031Sstas } 474226031Sstas return 0; 475226031Sstas} 476226031Sstas 477226031Sstas/* 478226031Sstas * 479226031Sstas */ 480226031Sstas 481226031Sstasstatic const char* KRB5_CALLCONV 482226031Sstasscc_get_name(krb5_context context, 483226031Sstas krb5_ccache id) 484226031Sstas{ 485226031Sstas return SCACHE(id)->name; 486226031Sstas} 487226031Sstas 488226031Sstasstatic krb5_error_code KRB5_CALLCONV 489226031Sstasscc_resolve(krb5_context context, krb5_ccache *id, const char *res) 490226031Sstas{ 491226031Sstas krb5_scache *s; 492226031Sstas int ret; 493226031Sstas 494226031Sstas s = scc_alloc(context, res); 495226031Sstas if (s == NULL) { 496226031Sstas krb5_set_error_message(context, KRB5_CC_NOMEM, 497226031Sstas N_("malloc: out of memory", "")); 498226031Sstas return KRB5_CC_NOMEM; 499226031Sstas } 500226031Sstas 501226031Sstas ret = make_database(context, s); 502226031Sstas if (ret) { 503226031Sstas scc_free(s); 504226031Sstas return ret; 505226031Sstas } 506226031Sstas 507226031Sstas ret = sqlite3_bind_text(s->scache_name, 1, s->name, -1, NULL); 508226031Sstas if (ret != SQLITE_OK) { 509226031Sstas krb5_set_error_message(context, ENOMEM, 510226031Sstas "bind name: %s", sqlite3_errmsg(s->db)); 511226031Sstas scc_free(s); 512226031Sstas return ENOMEM; 513226031Sstas } 514226031Sstas 515226031Sstas if (sqlite3_step(s->scache_name) == SQLITE_ROW) { 516226031Sstas 517226031Sstas if (sqlite3_column_type(s->scache_name, 0) != SQLITE_INTEGER) { 518226031Sstas sqlite3_reset(s->scache_name); 519226031Sstas krb5_set_error_message(context, KRB5_CC_END, 520226031Sstas N_("Cache name of wrong type " 521226031Sstas "for scache %s", ""), 522226031Sstas s->name); 523226031Sstas scc_free(s); 524226031Sstas return KRB5_CC_END; 525226031Sstas } 526226031Sstas 527226031Sstas s->cid = sqlite3_column_int(s->scache_name, 0); 528226031Sstas } else { 529226031Sstas s->cid = SCACHE_INVALID_CID; 530226031Sstas } 531226031Sstas sqlite3_reset(s->scache_name); 532226031Sstas 533226031Sstas (*id)->data.data = s; 534226031Sstas (*id)->data.length = sizeof(*s); 535226031Sstas 536226031Sstas return 0; 537226031Sstas} 538226031Sstas 539226031Sstasstatic krb5_error_code KRB5_CALLCONV 540226031Sstasscc_gen_new(krb5_context context, krb5_ccache *id) 541226031Sstas{ 542226031Sstas krb5_scache *s; 543226031Sstas 544226031Sstas s = scc_alloc(context, NULL); 545226031Sstas 546226031Sstas if (s == NULL) { 547226031Sstas krb5_set_error_message(context, KRB5_CC_NOMEM, 548226031Sstas N_("malloc: out of memory", "")); 549226031Sstas return KRB5_CC_NOMEM; 550226031Sstas } 551226031Sstas 552226031Sstas (*id)->data.data = s; 553226031Sstas (*id)->data.length = sizeof(*s); 554226031Sstas 555226031Sstas return 0; 556226031Sstas} 557226031Sstas 558226031Sstasstatic krb5_error_code KRB5_CALLCONV 559226031Sstasscc_initialize(krb5_context context, 560226031Sstas krb5_ccache id, 561226031Sstas krb5_principal primary_principal) 562226031Sstas{ 563226031Sstas krb5_scache *s = SCACHE(id); 564226031Sstas krb5_error_code ret; 565226031Sstas 566226031Sstas ret = make_database(context, s); 567226031Sstas if (ret) 568226031Sstas return ret; 569226031Sstas 570226031Sstas ret = exec_stmt(context, s->db, "BEGIN IMMEDIATE TRANSACTION", KRB5_CC_IO); 571226031Sstas if (ret) return ret; 572226031Sstas 573226031Sstas if (s->cid == SCACHE_INVALID_CID) { 574226031Sstas ret = create_cache(context, s); 575226031Sstas if (ret) 576226031Sstas goto rollback; 577226031Sstas } else { 578226031Sstas sqlite3_bind_int(s->dcred, 1, s->cid); 579226031Sstas do { 580226031Sstas ret = sqlite3_step(s->dcred); 581226031Sstas } while (ret == SQLITE_ROW); 582226031Sstas sqlite3_reset(s->dcred); 583226031Sstas if (ret != SQLITE_DONE) { 584226031Sstas ret = KRB5_CC_IO; 585226031Sstas krb5_set_error_message(context, ret, 586226031Sstas N_("Failed to delete old " 587226031Sstas "credentials: %s", ""), 588226031Sstas sqlite3_errmsg(s->db)); 589226031Sstas goto rollback; 590226031Sstas } 591226031Sstas } 592226031Sstas 593226031Sstas ret = bind_principal(context, s->db, s->ucachep, 1, primary_principal); 594226031Sstas if (ret) 595226031Sstas goto rollback; 596226031Sstas sqlite3_bind_int(s->ucachep, 2, s->cid); 597226031Sstas 598226031Sstas do { 599226031Sstas ret = sqlite3_step(s->ucachep); 600226031Sstas } while (ret == SQLITE_ROW); 601226031Sstas sqlite3_reset(s->ucachep); 602226031Sstas if (ret != SQLITE_DONE) { 603226031Sstas ret = KRB5_CC_IO; 604226031Sstas krb5_set_error_message(context, ret, 605226031Sstas N_("Failed to bind principal to cache %s", ""), 606226031Sstas sqlite3_errmsg(s->db)); 607226031Sstas goto rollback; 608226031Sstas } 609226031Sstas 610226031Sstas ret = exec_stmt(context, s->db, "COMMIT", KRB5_CC_IO); 611226031Sstas if (ret) return ret; 612226031Sstas 613226031Sstas return 0; 614226031Sstas 615226031Sstasrollback: 616226031Sstas exec_stmt(context, s->db, "ROLLBACK", 0); 617226031Sstas 618226031Sstas return ret; 619226031Sstas 620226031Sstas} 621226031Sstas 622226031Sstasstatic krb5_error_code KRB5_CALLCONV 623226031Sstasscc_close(krb5_context context, 624226031Sstas krb5_ccache id) 625226031Sstas{ 626226031Sstas scc_free(SCACHE(id)); 627226031Sstas return 0; 628226031Sstas} 629226031Sstas 630226031Sstasstatic krb5_error_code KRB5_CALLCONV 631226031Sstasscc_destroy(krb5_context context, 632226031Sstas krb5_ccache id) 633226031Sstas{ 634226031Sstas krb5_scache *s = SCACHE(id); 635226031Sstas int ret; 636226031Sstas 637226031Sstas if (s->cid == SCACHE_INVALID_CID) 638226031Sstas return 0; 639226031Sstas 640226031Sstas sqlite3_bind_int(s->dcache, 1, s->cid); 641226031Sstas do { 642226031Sstas ret = sqlite3_step(s->dcache); 643226031Sstas } while (ret == SQLITE_ROW); 644226031Sstas sqlite3_reset(s->dcache); 645226031Sstas if (ret != SQLITE_DONE) { 646226031Sstas krb5_set_error_message(context, KRB5_CC_IO, 647226031Sstas N_("Failed to destroy cache %s: %s", ""), 648226031Sstas s->name, sqlite3_errmsg(s->db)); 649226031Sstas return KRB5_CC_IO; 650226031Sstas } 651226031Sstas return 0; 652226031Sstas} 653226031Sstas 654226031Sstasstatic krb5_error_code 655226031Sstasencode_creds(krb5_context context, krb5_creds *creds, krb5_data *data) 656226031Sstas{ 657226031Sstas krb5_error_code ret; 658226031Sstas krb5_storage *sp; 659226031Sstas 660226031Sstas sp = krb5_storage_emem(); 661226031Sstas if (sp == NULL) { 662226031Sstas krb5_set_error_message(context, ENOMEM, 663226031Sstas N_("malloc: out of memory", "")); 664226031Sstas return ENOMEM; 665226031Sstas } 666226031Sstas 667226031Sstas ret = krb5_store_creds(sp, creds); 668226031Sstas if (ret) { 669226031Sstas krb5_set_error_message(context, ret, 670226031Sstas N_("Failed to store credential in scache", "")); 671226031Sstas krb5_storage_free(sp); 672226031Sstas return ret; 673226031Sstas } 674226031Sstas 675226031Sstas ret = krb5_storage_to_data(sp, data); 676226031Sstas krb5_storage_free(sp); 677226031Sstas if (ret) 678226031Sstas krb5_set_error_message(context, ret, 679226031Sstas N_("Failed to encode credential in scache", "")); 680226031Sstas return ret; 681226031Sstas} 682226031Sstas 683226031Sstasstatic krb5_error_code 684226031Sstasdecode_creds(krb5_context context, const void *data, size_t length, 685226031Sstas krb5_creds *creds) 686226031Sstas{ 687226031Sstas krb5_error_code ret; 688226031Sstas krb5_storage *sp; 689226031Sstas 690226031Sstas sp = krb5_storage_from_readonly_mem(data, length); 691226031Sstas if (sp == NULL) { 692226031Sstas krb5_set_error_message(context, ENOMEM, 693226031Sstas N_("malloc: out of memory", "")); 694226031Sstas return ENOMEM; 695226031Sstas } 696226031Sstas 697226031Sstas ret = krb5_ret_creds(sp, creds); 698226031Sstas krb5_storage_free(sp); 699226031Sstas if (ret) { 700226031Sstas krb5_set_error_message(context, ret, 701226031Sstas N_("Failed to read credential in scache", "")); 702226031Sstas return ret; 703226031Sstas } 704226031Sstas return 0; 705226031Sstas} 706226031Sstas 707226031Sstas 708226031Sstasstatic krb5_error_code KRB5_CALLCONV 709226031Sstasscc_store_cred(krb5_context context, 710226031Sstas krb5_ccache id, 711226031Sstas krb5_creds *creds) 712226031Sstas{ 713226031Sstas sqlite_uint64 credid; 714226031Sstas krb5_scache *s = SCACHE(id); 715226031Sstas krb5_error_code ret; 716226031Sstas krb5_data data; 717226031Sstas 718226031Sstas ret = make_database(context, s); 719226031Sstas if (ret) 720226031Sstas return ret; 721226031Sstas 722226031Sstas ret = encode_creds(context, creds, &data); 723226031Sstas if (ret) 724226031Sstas return ret; 725226031Sstas 726226031Sstas sqlite3_bind_int(s->icred, 1, s->cid); 727226031Sstas { 728226031Sstas krb5_enctype etype = 0; 729226031Sstas int kvno = 0; 730226031Sstas Ticket t; 731226031Sstas size_t len; 732226031Sstas 733226031Sstas ret = decode_Ticket(creds->ticket.data, 734226031Sstas creds->ticket.length, &t, &len); 735226031Sstas if (ret == 0) { 736226031Sstas if(t.enc_part.kvno) 737226031Sstas kvno = *t.enc_part.kvno; 738226031Sstas 739226031Sstas etype = t.enc_part.etype; 740226031Sstas 741226031Sstas free_Ticket(&t); 742226031Sstas } 743226031Sstas 744226031Sstas sqlite3_bind_int(s->icred, 2, kvno); 745226031Sstas sqlite3_bind_int(s->icred, 3, etype); 746226031Sstas 747226031Sstas } 748226031Sstas 749226031Sstas sqlite3_bind_blob(s->icred, 4, data.data, data.length, free_data); 750226031Sstas sqlite3_bind_int(s->icred, 5, time(NULL)); 751226031Sstas 752226031Sstas ret = exec_stmt(context, s->db, "BEGIN IMMEDIATE TRANSACTION", KRB5_CC_IO); 753226031Sstas if (ret) return ret; 754226031Sstas 755226031Sstas do { 756226031Sstas ret = sqlite3_step(s->icred); 757226031Sstas } while (ret == SQLITE_ROW); 758226031Sstas sqlite3_reset(s->icred); 759226031Sstas if (ret != SQLITE_DONE) { 760226031Sstas ret = KRB5_CC_IO; 761226031Sstas krb5_set_error_message(context, ret, 762226031Sstas N_("Failed to add credential: %s", ""), 763226031Sstas sqlite3_errmsg(s->db)); 764226031Sstas goto rollback; 765226031Sstas } 766226031Sstas 767226031Sstas credid = sqlite3_last_insert_rowid(s->db); 768226031Sstas 769226031Sstas { 770226031Sstas bind_principal(context, s->db, s->iprincipal, 1, creds->server); 771226031Sstas sqlite3_bind_int(s->iprincipal, 2, 1); 772226031Sstas sqlite3_bind_int(s->iprincipal, 3, credid); 773226031Sstas 774226031Sstas do { 775226031Sstas ret = sqlite3_step(s->iprincipal); 776226031Sstas } while (ret == SQLITE_ROW); 777226031Sstas sqlite3_reset(s->iprincipal); 778226031Sstas if (ret != SQLITE_DONE) { 779226031Sstas ret = KRB5_CC_IO; 780226031Sstas krb5_set_error_message(context, ret, 781226031Sstas N_("Failed to add principal: %s", ""), 782226031Sstas sqlite3_errmsg(s->db)); 783226031Sstas goto rollback; 784226031Sstas } 785226031Sstas } 786226031Sstas 787226031Sstas { 788226031Sstas bind_principal(context, s->db, s->iprincipal, 1, creds->client); 789226031Sstas sqlite3_bind_int(s->iprincipal, 2, 0); 790226031Sstas sqlite3_bind_int(s->iprincipal, 3, credid); 791226031Sstas 792226031Sstas do { 793226031Sstas ret = sqlite3_step(s->iprincipal); 794226031Sstas } while (ret == SQLITE_ROW); 795226031Sstas sqlite3_reset(s->iprincipal); 796226031Sstas if (ret != SQLITE_DONE) { 797226031Sstas ret = KRB5_CC_IO; 798226031Sstas krb5_set_error_message(context, ret, 799226031Sstas N_("Failed to add principal: %s", ""), 800226031Sstas sqlite3_errmsg(s->db)); 801226031Sstas goto rollback; 802226031Sstas } 803226031Sstas } 804226031Sstas 805226031Sstas ret = exec_stmt(context, s->db, "COMMIT", KRB5_CC_IO); 806226031Sstas if (ret) return ret; 807226031Sstas 808226031Sstas return 0; 809226031Sstas 810226031Sstasrollback: 811226031Sstas exec_stmt(context, s->db, "ROLLBACK", 0); 812226031Sstas 813226031Sstas return ret; 814226031Sstas} 815226031Sstas 816226031Sstasstatic krb5_error_code KRB5_CALLCONV 817226031Sstasscc_get_principal(krb5_context context, 818226031Sstas krb5_ccache id, 819226031Sstas krb5_principal *principal) 820226031Sstas{ 821226031Sstas krb5_scache *s = SCACHE(id); 822226031Sstas krb5_error_code ret; 823226031Sstas const char *str; 824226031Sstas 825226031Sstas *principal = NULL; 826226031Sstas 827226031Sstas ret = make_database(context, s); 828226031Sstas if (ret) 829226031Sstas return ret; 830226031Sstas 831226031Sstas sqlite3_bind_int(s->scache, 1, s->cid); 832226031Sstas 833226031Sstas if (sqlite3_step(s->scache) != SQLITE_ROW) { 834226031Sstas sqlite3_reset(s->scache); 835226031Sstas krb5_set_error_message(context, KRB5_CC_END, 836226031Sstas N_("No principal for cache SCC:%s:%s", ""), 837226031Sstas s->name, s->file); 838226031Sstas return KRB5_CC_END; 839226031Sstas } 840226031Sstas 841226031Sstas if (sqlite3_column_type(s->scache, 0) != SQLITE_TEXT) { 842226031Sstas sqlite3_reset(s->scache); 843226031Sstas krb5_set_error_message(context, KRB5_CC_END, 844226031Sstas N_("Principal data of wrong type " 845226031Sstas "for SCC:%s:%s", ""), 846226031Sstas s->name, s->file); 847226031Sstas return KRB5_CC_END; 848226031Sstas } 849226031Sstas 850226031Sstas str = (const char *)sqlite3_column_text(s->scache, 0); 851226031Sstas if (str == NULL) { 852226031Sstas sqlite3_reset(s->scache); 853226031Sstas krb5_set_error_message(context, KRB5_CC_END, 854226031Sstas N_("Principal not set for SCC:%s:%s", ""), 855226031Sstas s->name, s->file); 856226031Sstas return KRB5_CC_END; 857226031Sstas } 858226031Sstas 859226031Sstas ret = krb5_parse_name(context, str, principal); 860226031Sstas 861226031Sstas sqlite3_reset(s->scache); 862226031Sstas 863226031Sstas return ret; 864226031Sstas} 865226031Sstas 866226031Sstasstruct cred_ctx { 867226031Sstas char *drop; 868226031Sstas sqlite3_stmt *stmt; 869226031Sstas sqlite3_stmt *credstmt; 870226031Sstas}; 871226031Sstas 872226031Sstasstatic krb5_error_code KRB5_CALLCONV 873226031Sstasscc_get_first (krb5_context context, 874226031Sstas krb5_ccache id, 875226031Sstas krb5_cc_cursor *cursor) 876226031Sstas{ 877226031Sstas krb5_scache *s = SCACHE(id); 878226031Sstas krb5_error_code ret; 879226031Sstas struct cred_ctx *ctx; 880226031Sstas char *str = NULL, *name = NULL; 881226031Sstas 882226031Sstas *cursor = NULL; 883226031Sstas 884226031Sstas ctx = calloc(1, sizeof(*ctx)); 885226031Sstas if (ctx == NULL) { 886226031Sstas krb5_set_error_message(context, ENOMEM, 887226031Sstas N_("malloc: out of memory", "")); 888226031Sstas return ENOMEM; 889226031Sstas } 890226031Sstas 891226031Sstas ret = make_database(context, s); 892226031Sstas if (ret) { 893226031Sstas free(ctx); 894226031Sstas return ret; 895226031Sstas } 896226031Sstas 897226031Sstas if (s->cid == SCACHE_INVALID_CID) { 898226031Sstas krb5_set_error_message(context, KRB5_CC_END, 899226031Sstas N_("Iterating a invalid scache %s", ""), 900226031Sstas s->name); 901226031Sstas free(ctx); 902226031Sstas return KRB5_CC_END; 903226031Sstas } 904226031Sstas 905226031Sstas ret = asprintf(&name, "credIteration%pPid%d", 906226031Sstas ctx, (int)getpid()); 907226031Sstas if (ret < 0 || name == NULL) { 908226031Sstas krb5_set_error_message(context, ENOMEM, 909226031Sstas N_("malloc: out of memory", "")); 910226031Sstas free(ctx); 911226031Sstas return ENOMEM; 912226031Sstas } 913226031Sstas 914226031Sstas ret = asprintf(&ctx->drop, "DROP TABLE %s", name); 915226031Sstas if (ret < 0 || ctx->drop == NULL) { 916226031Sstas krb5_set_error_message(context, ENOMEM, 917226031Sstas N_("malloc: out of memory", "")); 918226031Sstas free(name); 919226031Sstas free(ctx); 920226031Sstas return ENOMEM; 921226031Sstas } 922226031Sstas 923226031Sstas ret = asprintf(&str, "CREATE TEMPORARY TABLE %s " 924226031Sstas "AS SELECT oid,created_at FROM credentials WHERE cid = %lu", 925226031Sstas name, (unsigned long)s->cid); 926226031Sstas if (ret < 0 || str == NULL) { 927226031Sstas free(ctx->drop); 928226031Sstas free(name); 929226031Sstas free(ctx); 930226031Sstas return ENOMEM; 931226031Sstas } 932226031Sstas 933226031Sstas ret = exec_stmt(context, s->db, str, KRB5_CC_IO); 934226031Sstas free(str); 935226031Sstas str = NULL; 936226031Sstas if (ret) { 937226031Sstas free(ctx->drop); 938226031Sstas free(name); 939226031Sstas free(ctx); 940226031Sstas return ret; 941226031Sstas } 942226031Sstas 943226031Sstas ret = asprintf(&str, "SELECT oid FROM %s ORDER BY created_at", name); 944226031Sstas if (ret < 0 || str == NULL) { 945226031Sstas exec_stmt(context, s->db, ctx->drop, 0); 946226031Sstas free(ctx->drop); 947226031Sstas free(name); 948226031Sstas free(ctx); 949226031Sstas return ret; 950226031Sstas } 951226031Sstas 952226031Sstas ret = prepare_stmt(context, s->db, &ctx->stmt, str); 953226031Sstas free(str); 954226031Sstas str = NULL; 955226031Sstas free(name); 956226031Sstas if (ret) { 957226031Sstas exec_stmt(context, s->db, ctx->drop, 0); 958226031Sstas free(ctx->drop); 959226031Sstas free(ctx); 960226031Sstas return ret; 961226031Sstas } 962226031Sstas 963226031Sstas ret = prepare_stmt(context, s->db, &ctx->credstmt, 964226031Sstas "SELECT cred FROM credentials WHERE oid = ?"); 965226031Sstas if (ret) { 966226031Sstas sqlite3_finalize(ctx->stmt); 967226031Sstas exec_stmt(context, s->db, ctx->drop, 0); 968226031Sstas free(ctx->drop); 969226031Sstas free(ctx); 970226031Sstas return ret; 971226031Sstas } 972226031Sstas 973226031Sstas *cursor = ctx; 974226031Sstas 975226031Sstas return 0; 976226031Sstas} 977226031Sstas 978226031Sstasstatic krb5_error_code KRB5_CALLCONV 979226031Sstasscc_get_next (krb5_context context, 980226031Sstas krb5_ccache id, 981226031Sstas krb5_cc_cursor *cursor, 982226031Sstas krb5_creds *creds) 983226031Sstas{ 984226031Sstas struct cred_ctx *ctx = *cursor; 985226031Sstas krb5_scache *s = SCACHE(id); 986226031Sstas krb5_error_code ret; 987226031Sstas sqlite_uint64 oid; 988226031Sstas const void *data = NULL; 989226031Sstas size_t len = 0; 990226031Sstas 991226031Sstasnext: 992226031Sstas ret = sqlite3_step(ctx->stmt); 993226031Sstas if (ret == SQLITE_DONE) { 994226031Sstas krb5_clear_error_message(context); 995226031Sstas return KRB5_CC_END; 996226031Sstas } else if (ret != SQLITE_ROW) { 997226031Sstas krb5_set_error_message(context, KRB5_CC_IO, 998226031Sstas N_("scache Database failed: %s", ""), 999226031Sstas sqlite3_errmsg(s->db)); 1000226031Sstas return KRB5_CC_IO; 1001226031Sstas } 1002226031Sstas 1003226031Sstas oid = sqlite3_column_int64(ctx->stmt, 0); 1004226031Sstas 1005226031Sstas /* read cred from credentials table */ 1006226031Sstas 1007226031Sstas sqlite3_bind_int(ctx->credstmt, 1, oid); 1008226031Sstas 1009226031Sstas ret = sqlite3_step(ctx->credstmt); 1010226031Sstas if (ret != SQLITE_ROW) { 1011226031Sstas sqlite3_reset(ctx->credstmt); 1012226031Sstas goto next; 1013226031Sstas } 1014226031Sstas 1015226031Sstas if (sqlite3_column_type(ctx->credstmt, 0) != SQLITE_BLOB) { 1016226031Sstas krb5_set_error_message(context, KRB5_CC_END, 1017226031Sstas N_("credential of wrong type for SCC:%s:%s", ""), 1018226031Sstas s->name, s->file); 1019226031Sstas sqlite3_reset(ctx->credstmt); 1020226031Sstas return KRB5_CC_END; 1021226031Sstas } 1022226031Sstas 1023226031Sstas data = sqlite3_column_blob(ctx->credstmt, 0); 1024226031Sstas len = sqlite3_column_bytes(ctx->credstmt, 0); 1025226031Sstas 1026226031Sstas ret = decode_creds(context, data, len, creds); 1027226031Sstas sqlite3_reset(ctx->credstmt); 1028226031Sstas return ret; 1029226031Sstas} 1030226031Sstas 1031226031Sstasstatic krb5_error_code KRB5_CALLCONV 1032226031Sstasscc_end_get (krb5_context context, 1033226031Sstas krb5_ccache id, 1034226031Sstas krb5_cc_cursor *cursor) 1035226031Sstas{ 1036226031Sstas struct cred_ctx *ctx = *cursor; 1037226031Sstas krb5_scache *s = SCACHE(id); 1038226031Sstas 1039226031Sstas sqlite3_finalize(ctx->stmt); 1040226031Sstas sqlite3_finalize(ctx->credstmt); 1041226031Sstas 1042226031Sstas exec_stmt(context, s->db, ctx->drop, 0); 1043226031Sstas 1044226031Sstas free(ctx->drop); 1045226031Sstas free(ctx); 1046226031Sstas 1047226031Sstas return 0; 1048226031Sstas} 1049226031Sstas 1050226031Sstasstatic krb5_error_code KRB5_CALLCONV 1051226031Sstasscc_remove_cred(krb5_context context, 1052226031Sstas krb5_ccache id, 1053226031Sstas krb5_flags which, 1054226031Sstas krb5_creds *mcreds) 1055226031Sstas{ 1056226031Sstas krb5_scache *s = SCACHE(id); 1057226031Sstas krb5_error_code ret; 1058226031Sstas sqlite3_stmt *stmt; 1059226031Sstas sqlite_uint64 credid = 0; 1060226031Sstas const void *data = NULL; 1061226031Sstas size_t len = 0; 1062226031Sstas 1063226031Sstas ret = make_database(context, s); 1064226031Sstas if (ret) 1065226031Sstas return ret; 1066226031Sstas 1067226031Sstas ret = prepare_stmt(context, s->db, &stmt, 1068226031Sstas "SELECT cred,oid FROM credentials " 1069226031Sstas "WHERE cid = ?"); 1070226031Sstas if (ret) 1071226031Sstas return ret; 1072226031Sstas 1073226031Sstas sqlite3_bind_int(stmt, 1, s->cid); 1074226031Sstas 1075226031Sstas /* find credential... */ 1076226031Sstas while (1) { 1077226031Sstas krb5_creds creds; 1078226031Sstas 1079226031Sstas ret = sqlite3_step(stmt); 1080226031Sstas if (ret == SQLITE_DONE) { 1081226031Sstas ret = 0; 1082226031Sstas break; 1083226031Sstas } else if (ret != SQLITE_ROW) { 1084226031Sstas ret = KRB5_CC_IO; 1085226031Sstas krb5_set_error_message(context, ret, 1086226031Sstas N_("scache Database failed: %s", ""), 1087226031Sstas sqlite3_errmsg(s->db)); 1088226031Sstas break; 1089226031Sstas } 1090226031Sstas 1091226031Sstas if (sqlite3_column_type(stmt, 0) != SQLITE_BLOB) { 1092226031Sstas ret = KRB5_CC_END; 1093226031Sstas krb5_set_error_message(context, ret, 1094226031Sstas N_("Credential of wrong type " 1095226031Sstas "for SCC:%s:%s", ""), 1096226031Sstas s->name, s->file); 1097226031Sstas break; 1098226031Sstas } 1099226031Sstas 1100226031Sstas data = sqlite3_column_blob(stmt, 0); 1101226031Sstas len = sqlite3_column_bytes(stmt, 0); 1102226031Sstas 1103226031Sstas ret = decode_creds(context, data, len, &creds); 1104226031Sstas if (ret) 1105226031Sstas break; 1106226031Sstas 1107226031Sstas ret = krb5_compare_creds(context, which, mcreds, &creds); 1108226031Sstas krb5_free_cred_contents(context, &creds); 1109226031Sstas if (ret) { 1110226031Sstas credid = sqlite3_column_int64(stmt, 1); 1111226031Sstas ret = 0; 1112226031Sstas break; 1113226031Sstas } 1114226031Sstas } 1115226031Sstas 1116226031Sstas sqlite3_finalize(stmt); 1117226031Sstas 1118226031Sstas if (id) { 1119226031Sstas ret = prepare_stmt(context, s->db, &stmt, 1120226031Sstas "DELETE FROM credentials WHERE oid=?"); 1121226031Sstas if (ret) 1122226031Sstas return ret; 1123226031Sstas sqlite3_bind_int(stmt, 1, credid); 1124226031Sstas 1125226031Sstas do { 1126226031Sstas ret = sqlite3_step(stmt); 1127226031Sstas } while (ret == SQLITE_ROW); 1128226031Sstas sqlite3_finalize(stmt); 1129226031Sstas if (ret != SQLITE_DONE) { 1130226031Sstas ret = KRB5_CC_IO; 1131226031Sstas krb5_set_error_message(context, ret, 1132226031Sstas N_("failed to delete scache credental", "")); 1133226031Sstas } else 1134226031Sstas ret = 0; 1135226031Sstas } 1136226031Sstas 1137226031Sstas return ret; 1138226031Sstas} 1139226031Sstas 1140226031Sstasstatic krb5_error_code KRB5_CALLCONV 1141226031Sstasscc_set_flags(krb5_context context, 1142226031Sstas krb5_ccache id, 1143226031Sstas krb5_flags flags) 1144226031Sstas{ 1145226031Sstas return 0; /* XXX */ 1146226031Sstas} 1147226031Sstas 1148226031Sstasstruct cache_iter { 1149226031Sstas char *drop; 1150226031Sstas sqlite3 *db; 1151226031Sstas sqlite3_stmt *stmt; 1152226031Sstas}; 1153226031Sstas 1154226031Sstasstatic krb5_error_code KRB5_CALLCONV 1155226031Sstasscc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor) 1156226031Sstas{ 1157226031Sstas struct cache_iter *ctx; 1158226031Sstas krb5_error_code ret; 1159226031Sstas char *name = NULL, *str = NULL; 1160226031Sstas 1161226031Sstas *cursor = NULL; 1162226031Sstas 1163226031Sstas ctx = calloc(1, sizeof(*ctx)); 1164226031Sstas if (ctx == NULL) { 1165226031Sstas krb5_set_error_message(context, ENOMEM, 1166226031Sstas N_("malloc: out of memory", "")); 1167226031Sstas return ENOMEM; 1168226031Sstas } 1169226031Sstas 1170226031Sstas ret = default_db(context, &ctx->db); 1171226031Sstas if (ctx->db == NULL) { 1172226031Sstas free(ctx); 1173226031Sstas return ret; 1174226031Sstas } 1175226031Sstas 1176226031Sstas ret = asprintf(&name, "cacheIteration%pPid%d", 1177226031Sstas ctx, (int)getpid()); 1178226031Sstas if (ret < 0 || name == NULL) { 1179226031Sstas krb5_set_error_message(context, ENOMEM, 1180226031Sstas N_("malloc: out of memory", "")); 1181226031Sstas sqlite3_close(ctx->db); 1182226031Sstas free(ctx); 1183226031Sstas return ENOMEM; 1184226031Sstas } 1185226031Sstas 1186226031Sstas ret = asprintf(&ctx->drop, "DROP TABLE %s", name); 1187226031Sstas if (ret < 0 || ctx->drop == NULL) { 1188226031Sstas krb5_set_error_message(context, ENOMEM, 1189226031Sstas N_("malloc: out of memory", "")); 1190226031Sstas sqlite3_close(ctx->db); 1191226031Sstas free(name); 1192226031Sstas free(ctx); 1193226031Sstas return ENOMEM; 1194226031Sstas } 1195226031Sstas 1196226031Sstas ret = asprintf(&str, "CREATE TEMPORARY TABLE %s AS SELECT name FROM caches", 1197226031Sstas name); 1198226031Sstas if (ret < 0 || str == NULL) { 1199226031Sstas krb5_set_error_message(context, ENOMEM, 1200226031Sstas N_("malloc: out of memory", "")); 1201226031Sstas sqlite3_close(ctx->db); 1202226031Sstas free(name); 1203226031Sstas free(ctx->drop); 1204226031Sstas free(ctx); 1205226031Sstas return ENOMEM; 1206226031Sstas } 1207226031Sstas 1208226031Sstas ret = exec_stmt(context, ctx->db, str, KRB5_CC_IO); 1209226031Sstas free(str); 1210226031Sstas str = NULL; 1211226031Sstas if (ret) { 1212226031Sstas sqlite3_close(ctx->db); 1213226031Sstas free(name); 1214226031Sstas free(ctx->drop); 1215226031Sstas free(ctx); 1216226031Sstas return ret; 1217226031Sstas } 1218226031Sstas 1219226031Sstas ret = asprintf(&str, "SELECT name FROM %s", name); 1220226031Sstas free(name); 1221226031Sstas if (ret < 0 || str == NULL) { 1222226031Sstas exec_stmt(context, ctx->db, ctx->drop, 0); 1223226031Sstas sqlite3_close(ctx->db); 1224226031Sstas free(name); 1225226031Sstas free(ctx->drop); 1226226031Sstas free(ctx); 1227226031Sstas return ENOMEM; 1228226031Sstas } 1229226031Sstas 1230226031Sstas ret = prepare_stmt(context, ctx->db, &ctx->stmt, str); 1231226031Sstas free(str); 1232226031Sstas if (ret) { 1233226031Sstas exec_stmt(context, ctx->db, ctx->drop, 0); 1234226031Sstas sqlite3_close(ctx->db); 1235226031Sstas free(ctx->drop); 1236226031Sstas free(ctx); 1237226031Sstas return ret; 1238226031Sstas } 1239226031Sstas 1240226031Sstas *cursor = ctx; 1241226031Sstas 1242226031Sstas return 0; 1243226031Sstas} 1244226031Sstas 1245226031Sstasstatic krb5_error_code KRB5_CALLCONV 1246226031Sstasscc_get_cache_next(krb5_context context, 1247226031Sstas krb5_cc_cursor cursor, 1248226031Sstas krb5_ccache *id) 1249226031Sstas{ 1250226031Sstas struct cache_iter *ctx = cursor; 1251226031Sstas krb5_error_code ret; 1252226031Sstas const char *name; 1253226031Sstas 1254226031Sstasagain: 1255226031Sstas ret = sqlite3_step(ctx->stmt); 1256226031Sstas if (ret == SQLITE_DONE) { 1257226031Sstas krb5_clear_error_message(context); 1258226031Sstas return KRB5_CC_END; 1259226031Sstas } else if (ret != SQLITE_ROW) { 1260226031Sstas krb5_set_error_message(context, KRB5_CC_IO, 1261226031Sstas N_("Database failed: %s", ""), 1262226031Sstas sqlite3_errmsg(ctx->db)); 1263226031Sstas return KRB5_CC_IO; 1264226031Sstas } 1265226031Sstas 1266226031Sstas if (sqlite3_column_type(ctx->stmt, 0) != SQLITE_TEXT) 1267226031Sstas goto again; 1268226031Sstas 1269226031Sstas name = (const char *)sqlite3_column_text(ctx->stmt, 0); 1270226031Sstas if (name == NULL) 1271226031Sstas goto again; 1272226031Sstas 1273226031Sstas ret = _krb5_cc_allocate(context, &krb5_scc_ops, id); 1274226031Sstas if (ret) 1275226031Sstas return ret; 1276226031Sstas 1277226031Sstas return scc_resolve(context, id, name); 1278226031Sstas} 1279226031Sstas 1280226031Sstasstatic krb5_error_code KRB5_CALLCONV 1281226031Sstasscc_end_cache_get(krb5_context context, krb5_cc_cursor cursor) 1282226031Sstas{ 1283226031Sstas struct cache_iter *ctx = cursor; 1284226031Sstas 1285226031Sstas exec_stmt(context, ctx->db, ctx->drop, 0); 1286226031Sstas sqlite3_finalize(ctx->stmt); 1287226031Sstas sqlite3_close(ctx->db); 1288226031Sstas free(ctx->drop); 1289226031Sstas free(ctx); 1290226031Sstas return 0; 1291226031Sstas} 1292226031Sstas 1293226031Sstasstatic krb5_error_code KRB5_CALLCONV 1294226031Sstasscc_move(krb5_context context, krb5_ccache from, krb5_ccache to) 1295226031Sstas{ 1296226031Sstas krb5_scache *sfrom = SCACHE(from); 1297226031Sstas krb5_scache *sto = SCACHE(to); 1298226031Sstas krb5_error_code ret; 1299226031Sstas 1300226031Sstas if (strcmp(sfrom->file, sto->file) != 0) { 1301226031Sstas krb5_set_error_message(context, KRB5_CC_BADNAME, 1302226031Sstas N_("Can't handle cross database " 1303226031Sstas "credential move: %s -> %s", ""), 1304226031Sstas sfrom->file, sto->file); 1305226031Sstas return KRB5_CC_BADNAME; 1306226031Sstas } 1307226031Sstas 1308226031Sstas ret = make_database(context, sfrom); 1309226031Sstas if (ret) 1310226031Sstas return ret; 1311226031Sstas 1312226031Sstas ret = exec_stmt(context, sfrom->db, 1313226031Sstas "BEGIN IMMEDIATE TRANSACTION", KRB5_CC_IO); 1314226031Sstas if (ret) return ret; 1315226031Sstas 1316226031Sstas if (sto->cid != SCACHE_INVALID_CID) { 1317226031Sstas /* drop old cache entry */ 1318226031Sstas 1319226031Sstas sqlite3_bind_int(sfrom->dcache, 1, sto->cid); 1320226031Sstas do { 1321226031Sstas ret = sqlite3_step(sfrom->dcache); 1322226031Sstas } while (ret == SQLITE_ROW); 1323226031Sstas sqlite3_reset(sfrom->dcache); 1324226031Sstas if (ret != SQLITE_DONE) { 1325226031Sstas krb5_set_error_message(context, KRB5_CC_IO, 1326226031Sstas N_("Failed to delete old cache: %d", ""), 1327226031Sstas (int)ret); 1328226031Sstas goto rollback; 1329226031Sstas } 1330226031Sstas } 1331226031Sstas 1332226031Sstas sqlite3_bind_text(sfrom->ucachen, 1, sto->name, -1, NULL); 1333226031Sstas sqlite3_bind_int(sfrom->ucachen, 2, sfrom->cid); 1334226031Sstas 1335226031Sstas do { 1336226031Sstas ret = sqlite3_step(sfrom->ucachen); 1337226031Sstas } while (ret == SQLITE_ROW); 1338226031Sstas sqlite3_reset(sfrom->ucachen); 1339226031Sstas if (ret != SQLITE_DONE) { 1340226031Sstas krb5_set_error_message(context, KRB5_CC_IO, 1341226031Sstas N_("Failed to update new cache: %d", ""), 1342226031Sstas (int)ret); 1343226031Sstas goto rollback; 1344226031Sstas } 1345226031Sstas 1346226031Sstas sto->cid = sfrom->cid; 1347226031Sstas 1348226031Sstas ret = exec_stmt(context, sfrom->db, "COMMIT", KRB5_CC_IO); 1349226031Sstas if (ret) return ret; 1350226031Sstas 1351226031Sstas scc_free(sfrom); 1352226031Sstas 1353226031Sstas return 0; 1354226031Sstas 1355226031Sstasrollback: 1356226031Sstas exec_stmt(context, sfrom->db, "ROLLBACK", 0); 1357226031Sstas scc_free(sfrom); 1358226031Sstas 1359226031Sstas return KRB5_CC_IO; 1360226031Sstas} 1361226031Sstas 1362226031Sstasstatic krb5_error_code KRB5_CALLCONV 1363226031Sstasscc_get_default_name(krb5_context context, char **str) 1364226031Sstas{ 1365226031Sstas krb5_error_code ret; 1366226031Sstas char *name; 1367226031Sstas 1368226031Sstas *str = NULL; 1369226031Sstas 1370226031Sstas ret = get_def_name(context, &name); 1371226031Sstas if (ret) 1372226031Sstas return _krb5_expand_default_cc_name(context, KRB5_SCACHE_NAME, str); 1373226031Sstas 1374226031Sstas ret = asprintf(str, "SCC:%s", name); 1375226031Sstas free(name); 1376226031Sstas if (ret < 0 || *str == NULL) { 1377226031Sstas krb5_set_error_message(context, ENOMEM, 1378226031Sstas N_("malloc: out of memory", "")); 1379226031Sstas return ENOMEM; 1380226031Sstas } 1381226031Sstas return 0; 1382226031Sstas} 1383226031Sstas 1384226031Sstasstatic krb5_error_code KRB5_CALLCONV 1385226031Sstasscc_set_default(krb5_context context, krb5_ccache id) 1386226031Sstas{ 1387226031Sstas krb5_scache *s = SCACHE(id); 1388226031Sstas krb5_error_code ret; 1389226031Sstas 1390226031Sstas if (s->cid == SCACHE_INVALID_CID) { 1391226031Sstas krb5_set_error_message(context, KRB5_CC_IO, 1392226031Sstas N_("Trying to set a invalid cache " 1393226031Sstas "as default %s", ""), 1394226031Sstas s->name); 1395226031Sstas return KRB5_CC_IO; 1396226031Sstas } 1397226031Sstas 1398226031Sstas ret = sqlite3_bind_text(s->umaster, 1, s->name, -1, NULL); 1399226031Sstas if (ret) { 1400226031Sstas sqlite3_reset(s->umaster); 1401226031Sstas krb5_set_error_message(context, KRB5_CC_IO, 1402226031Sstas N_("Failed to set name of default cache", "")); 1403226031Sstas return KRB5_CC_IO; 1404226031Sstas } 1405226031Sstas 1406226031Sstas do { 1407226031Sstas ret = sqlite3_step(s->umaster); 1408226031Sstas } while (ret == SQLITE_ROW); 1409226031Sstas sqlite3_reset(s->umaster); 1410226031Sstas if (ret != SQLITE_DONE) { 1411226031Sstas krb5_set_error_message(context, KRB5_CC_IO, 1412226031Sstas N_("Failed to update default cache", "")); 1413226031Sstas return KRB5_CC_IO; 1414226031Sstas } 1415226031Sstas 1416226031Sstas return 0; 1417226031Sstas} 1418226031Sstas 1419226031Sstas/** 1420226031Sstas * Variable containing the SCC based credential cache implemention. 1421226031Sstas * 1422226031Sstas * @ingroup krb5_ccache 1423226031Sstas */ 1424226031Sstas 1425226031SstasKRB5_LIB_VARIABLE const krb5_cc_ops krb5_scc_ops = { 1426226031Sstas KRB5_CC_OPS_VERSION, 1427226031Sstas "SCC", 1428226031Sstas scc_get_name, 1429226031Sstas scc_resolve, 1430226031Sstas scc_gen_new, 1431226031Sstas scc_initialize, 1432226031Sstas scc_destroy, 1433226031Sstas scc_close, 1434226031Sstas scc_store_cred, 1435226031Sstas NULL, /* scc_retrieve */ 1436226031Sstas scc_get_principal, 1437226031Sstas scc_get_first, 1438226031Sstas scc_get_next, 1439226031Sstas scc_end_get, 1440226031Sstas scc_remove_cred, 1441226031Sstas scc_set_flags, 1442226031Sstas NULL, 1443226031Sstas scc_get_cache_first, 1444226031Sstas scc_get_cache_next, 1445226031Sstas scc_end_cache_get, 1446226031Sstas scc_move, 1447226031Sstas scc_get_default_name, 1448226031Sstas scc_set_default 1449226031Sstas}; 1450226031Sstas 1451226031Sstas#endif 1452