1177633Sdfr/* 2177633Sdfr * Copyright (c) 2009 Kungliga Tekniska H�gskolan 3177633Sdfr * (Royal Institute of Technology, Stockholm, Sweden). 4177633Sdfr * All rights reserved. 5177633Sdfr * 6177633Sdfr * Redistribution and use in source and binary forms, with or without 7177633Sdfr * modification, are permitted provided that the following conditions 8177633Sdfr * are met: 9177633Sdfr * 10177633Sdfr * 1. Redistributions of source code must retain the above copyright 11177633Sdfr * notice, this list of conditions and the following disclaimer. 12177633Sdfr * 13177633Sdfr * 2. Redistributions in binary form must reproduce the above copyright 14177633Sdfr * notice, this list of conditions and the following disclaimer in the 15177633Sdfr * documentation and/or other materials provided with the distribution. 16177633Sdfr * 17177633Sdfr * 3. Neither the name of the Institute nor the names of its contributors 18177633Sdfr * may be used to endorse or promote products derived from this software 19177633Sdfr * without specific prior written permission. 20177633Sdfr * 21177633Sdfr * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22177633Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23177633Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24177633Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25177633Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26177633Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27177633Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28177633Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29177633Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30177633Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31177633Sdfr * SUCH DAMAGE. 32177633Sdfr */ 33177633Sdfr 34177633Sdfr#include "hdb_locl.h" 35177633Sdfr#include "sqlite3.h" 36177633Sdfr 37177633Sdfr#define MAX_RETRIES 10 38177633Sdfr 39177633Sdfrtypedef struct hdb_sqlite_db { 40177633Sdfr double version; 41177633Sdfr sqlite3 *db; 42177633Sdfr char *db_file; 43177633Sdfr 44177633Sdfr sqlite3_stmt *get_version; 45177633Sdfr sqlite3_stmt *fetch; 46177633Sdfr sqlite3_stmt *get_ids; 47177633Sdfr sqlite3_stmt *add_entry; 48177633Sdfr sqlite3_stmt *add_principal; 49177633Sdfr sqlite3_stmt *add_alias; 50177633Sdfr sqlite3_stmt *delete_aliases; 51177633Sdfr sqlite3_stmt *update_entry; 52177633Sdfr sqlite3_stmt *remove; 53177633Sdfr sqlite3_stmt *get_all_entries; 54177633Sdfr 55177633Sdfr} hdb_sqlite_db; 56177633Sdfr 57177633Sdfr/* This should be used to mark updates which make the code incompatible 58177633Sdfr * with databases created with previous versions. Don't update it if 59177633Sdfr * compatibility is not broken. */ 60177633Sdfr#define HDBSQLITE_VERSION 0.1 61177633Sdfr 62177633Sdfr#define _HDBSQLITE_STRINGIFY(x) #x 63177633Sdfr#define HDBSQLITE_STRINGIFY(x) _HDBSQLITE_STRINGIFY(x) 64177633Sdfr 65177633Sdfr#define HDBSQLITE_CREATE_TABLES \ 66177633Sdfr " BEGIN TRANSACTION;" \ 67177633Sdfr " CREATE TABLE Version (number REAL);" \ 68177633Sdfr " INSERT INTO Version (number)" \ 69177633Sdfr " VALUES (" HDBSQLITE_STRINGIFY(HDBSQLITE_VERSION) ");" \ 70177633Sdfr " CREATE TABLE Principal" \ 71177633Sdfr " (id INTEGER PRIMARY KEY," \ 72177633Sdfr " principal TEXT UNIQUE NOT NULL," \ 73177633Sdfr " canonical INTEGER," \ 74177633Sdfr " entry INTEGER);" \ 75177633Sdfr " CREATE TABLE Entry" \ 76177633Sdfr " (id INTEGER PRIMARY KEY," \ 77177633Sdfr " data BLOB);" \ 78177633Sdfr " COMMIT" 79177633Sdfr#define HDBSQLITE_CREATE_TRIGGERS \ 80177633Sdfr " CREATE TRIGGER remove_principals AFTER DELETE ON Entry" \ 81177633Sdfr " BEGIN" \ 82177633Sdfr " DELETE FROM Principal" \ 83177633Sdfr " WHERE entry = OLD.id;" \ 84177633Sdfr " END" 85177633Sdfr#define HDBSQLITE_GET_VERSION \ 86177633Sdfr " SELECT number FROM Version" 87177633Sdfr#define HDBSQLITE_FETCH \ 88177633Sdfr " SELECT Entry.data FROM Principal, Entry" \ 89177633Sdfr " WHERE Principal.principal = ? AND" \ 90177633Sdfr " Entry.id = Principal.entry" 91177633Sdfr#define HDBSQLITE_GET_IDS \ 92177633Sdfr " SELECT id, entry FROM Principal" \ 93177633Sdfr " WHERE principal = ?" 94177633Sdfr#define HDBSQLITE_ADD_ENTRY \ 95177633Sdfr " INSERT INTO Entry (data) VALUES (?)" 96177633Sdfr#define HDBSQLITE_ADD_PRINCIPAL \ 97177633Sdfr " INSERT INTO Principal (principal, entry, canonical)" \ 98177633Sdfr " VALUES (?, last_insert_rowid(), 1)" 99177633Sdfr#define HDBSQLITE_ADD_ALIAS \ 100240542Spfg " INSERT INTO Principal (principal, entry, canonical)" \ 101177633Sdfr " VALUES(?, ?, 0)" 102177633Sdfr#define HDBSQLITE_DELETE_ALIASES \ 103177633Sdfr " DELETE FROM Principal" \ 104240542Spfg " WHERE entry = ? AND canonical = 0" 105177633Sdfr#define HDBSQLITE_UPDATE_ENTRY \ 106240542Spfg " UPDATE Entry SET data = ?" \ 107177633Sdfr " WHERE id = ?" 108240542Spfg#define HDBSQLITE_REMOVE \ 109177633Sdfr " DELETE FROM ENTRY WHERE id = " \ 110240542Spfg " (SELECT entry FROM Principal" \ 111177633Sdfr " WHERE principal = ?)" 112240542Spfg#define HDBSQLITE_GET_ALL_ENTRIES \ 113177633Sdfr " SELECT data FROM Entry" 114240542Spfg 115177633Sdfr/** 116240542Spfg * Wrapper around sqlite3_prepare_v2. 117177633Sdfr * 118240542Spfg * @param context The current krb5 context 119240542Spfg * @param statement Where to store the pointer to the statement 120177633Sdfr * after preparing it 121177633Sdfr * @param str SQL code for the statement 122177633Sdfr * 123177633Sdfr * @return 0 if OK, an error code if not 124177633Sdfr */ 125177633Sdfrstatic krb5_error_code 126177633Sdfrhdb_sqlite_prepare_stmt(krb5_context context, 127177633Sdfr sqlite3 *db, 128177633Sdfr sqlite3_stmt **statement, 129177633Sdfr const char *str) 130177633Sdfr{ 131177633Sdfr int ret, tries = 0; 132177633Sdfr 133177633Sdfr ret = sqlite3_prepare_v2(db, str, -1, statement, NULL); 134177633Sdfr while((tries++ < MAX_RETRIES) && 135177633Sdfr ((ret == SQLITE_BUSY) || 136177633Sdfr (ret == SQLITE_IOERR_BLOCKED) || 137177633Sdfr (ret == SQLITE_LOCKED))) { 138177633Sdfr krb5_warnx(context, "hdb-sqlite: prepare busy"); 139177633Sdfr sleep(1); 140177633Sdfr ret = sqlite3_prepare_v2(db, str, -1, statement, NULL); 141177633Sdfr } 142177633Sdfr 143177633Sdfr if (ret != SQLITE_OK) { 144177633Sdfr krb5_set_error_message(context, EINVAL, 145177633Sdfr "Failed to prepare stmt %s: %s", 146177633Sdfr str, sqlite3_errmsg(db)); 147177633Sdfr return EINVAL; 148177633Sdfr } 149177633Sdfr 150177633Sdfr return 0; 151177633Sdfr} 152177633Sdfr 153177633Sdfr/** 154177633Sdfr * A wrapper around sqlite3_exec. 155177633Sdfr * 156177633Sdfr * @param context The current krb5 context 157177633Sdfr * @param database An open sqlite3 database handle 158177633Sdfr * @param statement SQL code to execute 159177633Sdfr * @param error_code What to return if the statement fails 160177633Sdfr * 161177633Sdfr * @return 0 if OK, else error_code 162177633Sdfr */ 163177633Sdfrstatic krb5_error_code 164177633Sdfrhdb_sqlite_exec_stmt(krb5_context context, 165177633Sdfr sqlite3 *database, 166177633Sdfr const char *statement, 167177633Sdfr krb5_error_code error_code) 168177633Sdfr{ 169177633Sdfr int ret; 170177633Sdfr 171177633Sdfr ret = sqlite3_exec(database, statement, NULL, NULL, NULL); 172177633Sdfr 173177633Sdfr while(((ret == SQLITE_BUSY) || 174177633Sdfr (ret == SQLITE_IOERR_BLOCKED) || 175177633Sdfr (ret == SQLITE_LOCKED))) { 176177633Sdfr krb5_warnx(context, "hdb-sqlite: exec busy: %d", (int)getpid()); 177177633Sdfr sleep(1); 178177633Sdfr ret = sqlite3_exec(database, statement, NULL, NULL, NULL); 179177633Sdfr } 180177633Sdfr 181177633Sdfr if (ret != SQLITE_OK && error_code) { 182177633Sdfr krb5_set_error_message(context, error_code, 183177633Sdfr "Execute %s: %s", statement, 184177633Sdfr sqlite3_errmsg(database)); 185177633Sdfr return error_code; 186177633Sdfr } 187177633Sdfr 188177633Sdfr return 0; 189177633Sdfr} 190177633Sdfr 191177633Sdfr/** 192177633Sdfr * Opens an sqlite3 database handle to a file, may create the 193177633Sdfr * database file depending on flags. 194177633Sdfr * 195177633Sdfr * @param context The current krb5 context 196177633Sdfr * @param db Heimdal database handle 197177633Sdfr * @param flags Controls whether or not the file may be created, 198177633Sdfr * may be 0 or SQLITE_OPEN_CREATE 199177633Sdfr */ 200177633Sdfrstatic krb5_error_code 201177633Sdfrhdb_sqlite_open_database(krb5_context context, HDB *db, int flags) 202177633Sdfr{ 203177633Sdfr int ret; 204177633Sdfr hdb_sqlite_db *hsdb = (hdb_sqlite_db*) db->hdb_db; 205177633Sdfr 206177633Sdfr ret = sqlite3_open_v2(hsdb->db_file, &hsdb->db, 207177633Sdfr SQLITE_OPEN_READWRITE | flags, NULL); 208177633Sdfr 209177633Sdfr if (ret) { 210177633Sdfr if (hsdb->db) { 211177633Sdfr ret = ENOENT; 212177633Sdfr krb5_set_error_message(context, ret, 213177633Sdfr "Error opening sqlite database %s: %s", 214177633Sdfr hsdb->db_file, sqlite3_errmsg(hsdb->db)); 215177633Sdfr sqlite3_close(hsdb->db); 216177633Sdfr hsdb->db = NULL; 217177633Sdfr } else 218177633Sdfr ret = krb5_enomem(context); 219193128Skmacy return ret; 220193128Skmacy } 221177633Sdfr 222177633Sdfr return 0; 223177633Sdfr} 224177633Sdfr 225177633Sdfrstatic int 226177633Sdfrhdb_sqlite_step(krb5_context context, sqlite3 *db, sqlite3_stmt *stmt) 227177633Sdfr{ 228177633Sdfr int ret; 229177633Sdfr 230177633Sdfr ret = sqlite3_step(stmt); 231177633Sdfr while(((ret == SQLITE_BUSY) || 232177633Sdfr (ret == SQLITE_IOERR_BLOCKED) || 233177633Sdfr (ret == SQLITE_LOCKED))) { 234177633Sdfr krb5_warnx(context, "hdb-sqlite: step busy: %d", (int)getpid()); 235177633Sdfr sleep(1); 236177633Sdfr ret = sqlite3_step(stmt); 237177633Sdfr } 238177633Sdfr return ret; 239177633Sdfr} 240177633Sdfr 241177633Sdfr/** 242177633Sdfr * Closes the database and frees memory allocated for statements. 243177633Sdfr * 244177633Sdfr * @param context The current krb5 context 245177633Sdfr * @param db Heimdal database handle 246177633Sdfr */ 247177633Sdfrstatic krb5_error_code 248177633Sdfrhdb_sqlite_close_database(krb5_context context, HDB *db) 249177633Sdfr{ 250177633Sdfr hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db; 251177633Sdfr 252177633Sdfr sqlite3_finalize(hsdb->get_version); 253177633Sdfr sqlite3_finalize(hsdb->fetch); 254177633Sdfr sqlite3_finalize(hsdb->get_ids); 255177633Sdfr sqlite3_finalize(hsdb->add_entry); 256177633Sdfr sqlite3_finalize(hsdb->add_principal); 257177633Sdfr sqlite3_finalize(hsdb->add_alias); 258177633Sdfr sqlite3_finalize(hsdb->delete_aliases); 259177633Sdfr sqlite3_finalize(hsdb->update_entry); 260177633Sdfr sqlite3_finalize(hsdb->remove); 261177633Sdfr sqlite3_finalize(hsdb->get_all_entries); 262177633Sdfr 263177633Sdfr sqlite3_close(hsdb->db); 264177633Sdfr 265177633Sdfr return 0; 266177633Sdfr} 267177633Sdfr 268177633Sdfr/** 269177633Sdfr * Opens an sqlite database file and prepares it for use. 270177633Sdfr * If the file does not exist it will be created. 271177633Sdfr * 272177633Sdfr * @param context The current krb5_context 273177633Sdfr * @param db The heimdal database handle 274177633Sdfr * @param filename Where to store the database file 275177633Sdfr * 276177633Sdfr * @return 0 if everything worked, an error code if not 277177633Sdfr */ 278177633Sdfrstatic krb5_error_code 279177633Sdfrhdb_sqlite_make_database(krb5_context context, HDB *db, const char *filename) 280177633Sdfr{ 281177633Sdfr int ret; 282177633Sdfr int created_file = 0; 283177633Sdfr hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db; 284177633Sdfr 285177633Sdfr hsdb->db_file = strdup(filename); 286177633Sdfr if(hsdb->db_file == NULL) 287177633Sdfr return ENOMEM; 288177633Sdfr 289177633Sdfr ret = hdb_sqlite_open_database(context, db, 0); 290177633Sdfr if (ret) { 291177633Sdfr ret = hdb_sqlite_open_database(context, db, SQLITE_OPEN_CREATE); 292177633Sdfr if (ret) goto out; 293177633Sdfr 294177633Sdfr created_file = 1; 295177633Sdfr 296177633Sdfr ret = hdb_sqlite_exec_stmt(context, hsdb->db, 297177633Sdfr HDBSQLITE_CREATE_TABLES, 298177633Sdfr EINVAL); 299177633Sdfr if (ret) goto out; 300177633Sdfr 301177633Sdfr ret = hdb_sqlite_exec_stmt(context, hsdb->db, 302177633Sdfr HDBSQLITE_CREATE_TRIGGERS, 303177633Sdfr EINVAL); 304177633Sdfr if (ret) goto out; 305177633Sdfr } 306177633Sdfr 307177633Sdfr ret = hdb_sqlite_prepare_stmt(context, hsdb->db, 308177633Sdfr &hsdb->get_version, 309177633Sdfr HDBSQLITE_GET_VERSION); 310177633Sdfr if (ret) goto out; 311177633Sdfr ret = hdb_sqlite_prepare_stmt(context, hsdb->db, 312177633Sdfr &hsdb->fetch, 313177633Sdfr HDBSQLITE_FETCH); 314177633Sdfr if (ret) goto out; 315177633Sdfr ret = hdb_sqlite_prepare_stmt(context, hsdb->db, 316177633Sdfr &hsdb->get_ids, 317177633Sdfr HDBSQLITE_GET_IDS); 318177633Sdfr if (ret) goto out; 319177633Sdfr ret = hdb_sqlite_prepare_stmt(context, hsdb->db, 320177633Sdfr &hsdb->add_entry, 321177633Sdfr HDBSQLITE_ADD_ENTRY); 322177633Sdfr if (ret) goto out; 323177633Sdfr ret = hdb_sqlite_prepare_stmt(context, hsdb->db, 324177633Sdfr &hsdb->add_principal, 325177633Sdfr HDBSQLITE_ADD_PRINCIPAL); 326177633Sdfr if (ret) goto out; 327177633Sdfr ret = hdb_sqlite_prepare_stmt(context, hsdb->db, 328177633Sdfr &hsdb->add_alias, 329177633Sdfr HDBSQLITE_ADD_ALIAS); 330177633Sdfr if (ret) goto out; 331177633Sdfr ret = hdb_sqlite_prepare_stmt(context, hsdb->db, 332177633Sdfr &hsdb->delete_aliases, 333177633Sdfr HDBSQLITE_DELETE_ALIASES); 334177633Sdfr if (ret) goto out; 335177633Sdfr ret = hdb_sqlite_prepare_stmt(context, hsdb->db, 336177633Sdfr &hsdb->update_entry, 337177633Sdfr HDBSQLITE_UPDATE_ENTRY); 338177633Sdfr if (ret) goto out; 339177633Sdfr ret = hdb_sqlite_prepare_stmt(context, hsdb->db, 340177633Sdfr &hsdb->remove, 341192971Skmacy HDBSQLITE_REMOVE); 342192971Skmacy if (ret) goto out; 343192971Skmacy ret = hdb_sqlite_prepare_stmt(context, hsdb->db, 344192971Skmacy &hsdb->get_all_entries, 345192971Skmacy HDBSQLITE_GET_ALL_ENTRIES); 346192971Skmacy if (ret) goto out; 347192971Skmacy 348192971Skmacy ret = hdb_sqlite_step(context, hsdb->db, hsdb->get_version); 349192971Skmacy if(ret == SQLITE_ROW) { 350192971Skmacy hsdb->version = sqlite3_column_double(hsdb->get_version, 0); 351192971Skmacy } 352192971Skmacy sqlite3_reset(hsdb->get_version); 353192971Skmacy ret = 0; 354192971Skmacy 355192971Skmacy if(hsdb->version != HDBSQLITE_VERSION) { 356192971Skmacy ret = EINVAL; 357177633Sdfr krb5_set_error_message(context, ret, "HDBSQLITE_VERSION mismatch"); 358177633Sdfr } 359177633Sdfr 360177633Sdfr if(ret) goto out; 361177633Sdfr 362177633Sdfr return 0; 363177633Sdfr 364177633Sdfr out: 365177633Sdfr if (hsdb->db) 366177633Sdfr sqlite3_close(hsdb->db); 367184588Sdfr if (created_file) 368184588Sdfr unlink(hsdb->db_file); 369177633Sdfr 370177633Sdfr return ret; 371177633Sdfr} 372177633Sdfr 373177633Sdfr/** 374177633Sdfr * Retrieves an entry by searching for the given 375177633Sdfr * principal in the Principal database table, both 376177633Sdfr * for canonical principals and aliases. 377177633Sdfr * 378177633Sdfr * @param context The current krb5_context 379177633Sdfr * @param db Heimdal database handle 380177633Sdfr * @param principal The principal whose entry to search for 381177633Sdfr * @param flags Currently only for HDB_F_DECRYPT 382177633Sdfr * @param kvno kvno to fetch is HDB_F_KVNO_SPECIFIED use used 383177633Sdfr * 384177633Sdfr * @return 0 if everything worked, an error code if not 385177633Sdfr */ 386177633Sdfrstatic krb5_error_code 387hdb_sqlite_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal, 388 unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry) 389{ 390 int sqlite_error; 391 krb5_error_code ret; 392 char *principal_string; 393 hdb_sqlite_db *hsdb = (hdb_sqlite_db*)(db->hdb_db); 394 sqlite3_stmt *fetch = hsdb->fetch; 395 krb5_data value; 396 397 ret = krb5_unparse_name(context, principal, &principal_string); 398 if (ret) { 399 free(principal_string); 400 return ret; 401 } 402 403 sqlite3_bind_text(fetch, 1, principal_string, -1, SQLITE_STATIC); 404 405 sqlite_error = hdb_sqlite_step(context, hsdb->db, fetch); 406 if (sqlite_error != SQLITE_ROW) { 407 if(sqlite_error == SQLITE_DONE) { 408 ret = HDB_ERR_NOENTRY; 409 goto out; 410 } else { 411 ret = EINVAL; 412 krb5_set_error_message(context, ret, 413 "sqlite fetch failed: %d", 414 sqlite_error); 415 goto out; 416 } 417 } 418 419 value.length = sqlite3_column_bytes(fetch, 0); 420 value.data = (void *) sqlite3_column_blob(fetch, 0); 421 422 ret = hdb_value2entry(context, &value, &entry->entry); 423 if(ret) 424 goto out; 425 426 if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { 427 ret = hdb_unseal_keys(context, db, &entry->entry); 428 if(ret) { 429 hdb_free_entry(context, entry); 430 goto out; 431 } 432 } 433 434 ret = 0; 435 436out: 437 438 sqlite3_clear_bindings(fetch); 439 sqlite3_reset(fetch); 440 441 free(principal_string); 442 443 return ret; 444} 445 446/** 447 * Convenience function to step a prepared statement with no 448 * value once. 449 * 450 * @param context The current krb5_context 451 * @param statement A prepared sqlite3 statement 452 * 453 * @return 0 if everything worked, an error code if not 454 */ 455static krb5_error_code 456hdb_sqlite_step_once(krb5_context context, HDB *db, sqlite3_stmt *statement) 457{ 458 int ret; 459 hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db; 460 461 ret = hdb_sqlite_step(context, hsdb->db, statement); 462 sqlite3_clear_bindings(statement); 463 sqlite3_reset(statement); 464 465 return ret; 466} 467 468 469/** 470 * Stores an hdb_entry in the database. If flags contains HDB_F_REPLACE 471 * a previous entry may be replaced. 472 * 473 * @param context The current krb5_context 474 * @param db Heimdal database handle 475 * @param flags May currently only contain HDB_F_REPLACE 476 * @param entry The data to store 477 * 478 * @return 0 if everything worked, an error code if not 479 */ 480static krb5_error_code 481hdb_sqlite_store(krb5_context context, HDB *db, unsigned flags, 482 hdb_entry_ex *entry) 483{ 484 int ret; 485 int i; 486 sqlite_int64 entry_id; 487 char *principal_string = NULL; 488 char *alias_string; 489 const HDB_Ext_Aliases *aliases; 490 491 hdb_sqlite_db *hsdb = (hdb_sqlite_db *)(db->hdb_db); 492 krb5_data value; 493 sqlite3_stmt *get_ids = hsdb->get_ids; 494 495 ret = hdb_sqlite_exec_stmt(context, hsdb->db, 496 "BEGIN IMMEDIATE TRANSACTION", EINVAL); 497 if(ret != SQLITE_OK) { 498 ret = EINVAL; 499 krb5_set_error_message(context, ret, 500 "SQLite BEGIN TRANSACTION failed: %s", 501 sqlite3_errmsg(hsdb->db)); 502 goto rollback; 503 } 504 505 ret = krb5_unparse_name(context, 506 entry->entry.principal, &principal_string); 507 if (ret) { 508 goto rollback; 509 } 510 511 ret = hdb_seal_keys(context, db, &entry->entry); 512 if(ret) { 513 goto rollback; 514 } 515 516 ret = hdb_entry2value(context, &entry->entry, &value); 517 if(ret) { 518 goto rollback; 519 } 520 521 sqlite3_bind_text(get_ids, 1, principal_string, -1, SQLITE_STATIC); 522 ret = hdb_sqlite_step(context, hsdb->db, get_ids); 523 524 if(ret == SQLITE_DONE) { /* No such principal */ 525 526 sqlite3_bind_blob(hsdb->add_entry, 1, 527 value.data, value.length, SQLITE_STATIC); 528 ret = hdb_sqlite_step(context, hsdb->db, hsdb->add_entry); 529 sqlite3_clear_bindings(hsdb->add_entry); 530 sqlite3_reset(hsdb->add_entry); 531 if(ret != SQLITE_DONE) 532 goto rollback; 533 534 sqlite3_bind_text(hsdb->add_principal, 1, 535 principal_string, -1, SQLITE_STATIC); 536 ret = hdb_sqlite_step(context, hsdb->db, hsdb->add_principal); 537 sqlite3_clear_bindings(hsdb->add_principal); 538 sqlite3_reset(hsdb->add_principal); 539 if(ret != SQLITE_DONE) 540 goto rollback; 541 542 entry_id = sqlite3_column_int64(get_ids, 1); 543 544 } else if(ret == SQLITE_ROW) { /* Found a principal */ 545 546 if(! (flags & HDB_F_REPLACE)) /* Not allowed to replace it */ 547 goto rollback; 548 549 entry_id = sqlite3_column_int64(get_ids, 1); 550 551 sqlite3_bind_int64(hsdb->delete_aliases, 1, entry_id); 552 ret = hdb_sqlite_step_once(context, db, hsdb->delete_aliases); 553 if(ret != SQLITE_DONE) 554 goto rollback; 555 556 sqlite3_bind_blob(hsdb->update_entry, 1, 557 value.data, value.length, SQLITE_STATIC); 558 sqlite3_bind_int64(hsdb->update_entry, 2, entry_id); 559 ret = hdb_sqlite_step_once(context, db, hsdb->update_entry); 560 if(ret != SQLITE_DONE) 561 goto rollback; 562 563 } else { 564 /* Error! */ 565 goto rollback; 566 } 567 568 ret = hdb_entry_get_aliases(&entry->entry, &aliases); 569 if(ret || aliases == NULL) 570 goto commit; 571 572 for(i = 0; i < aliases->aliases.len; i++) { 573 574 ret = krb5_unparse_name(context, &aliases->aliases.val[i], 575 &alias_string); 576 if (ret) { 577 free(alias_string); 578 goto rollback; 579 } 580 581 sqlite3_bind_text(hsdb->add_alias, 1, alias_string, 582 -1, SQLITE_STATIC); 583 sqlite3_bind_int64(hsdb->add_alias, 2, entry_id); 584 ret = hdb_sqlite_step_once(context, db, hsdb->add_alias); 585 586 free(alias_string); 587 588 if(ret != SQLITE_DONE) 589 goto rollback; 590 } 591 592 ret = 0; 593 594commit: 595 596 free(principal_string); 597 598 krb5_data_free(&value); 599 600 sqlite3_clear_bindings(get_ids); 601 sqlite3_reset(get_ids); 602 603 ret = hdb_sqlite_exec_stmt(context, hsdb->db, "COMMIT", EINVAL); 604 if(ret != SQLITE_OK) 605 krb5_warnx(context, "hdb-sqlite: COMMIT problem: %d: %s", 606 ret, sqlite3_errmsg(hsdb->db)); 607 608 return ret; 609 610rollback: 611 612 krb5_warnx(context, "hdb-sqlite: store rollback problem: %d: %s", 613 ret, sqlite3_errmsg(hsdb->db)); 614 615 free(principal_string); 616 617 ret = hdb_sqlite_exec_stmt(context, hsdb->db, 618 "ROLLBACK", EINVAL); 619 return ret; 620} 621 622/** 623 * This may be called often by other code, since the BDB backends 624 * can not have several open connections. SQLite can handle 625 * many processes with open handles to the database file 626 * and closing/opening the handle is an expensive operation. 627 * Hence, this function does nothing. 628 * 629 * @param context The current krb5 context 630 * @param db Heimdal database handle 631 * 632 * @return Always returns 0 633 */ 634static krb5_error_code 635hdb_sqlite_close(krb5_context context, HDB *db) 636{ 637 return 0; 638} 639 640/** 641 * The opposite of hdb_sqlite_close. Since SQLite accepts 642 * many open handles to the database file the handle does not 643 * need to be closed, or reopened. 644 * 645 * @param context The current krb5 context 646 * @param db Heimdal database handle 647 * @param flags 648 * @param mode_t 649 * 650 * @return Always returns 0 651 */ 652static krb5_error_code 653hdb_sqlite_open(krb5_context context, HDB *db, int flags, mode_t mode) 654{ 655 return 0; 656} 657 658/** 659 * Closes the databse and frees all resources. 660 * 661 * @param context The current krb5 context 662 * @param db Heimdal database handle 663 * 664 * @return 0 on success, an error code if not 665 */ 666static krb5_error_code 667hdb_sqlite_destroy(krb5_context context, HDB *db) 668{ 669 int ret; 670 hdb_sqlite_db *hsdb; 671 672 ret = hdb_clear_master_key(context, db); 673 674 hdb_sqlite_close_database(context, db); 675 676 hsdb = (hdb_sqlite_db*)(db->hdb_db); 677 678 free(hsdb->db_file); 679 free(db->hdb_db); 680 free(db); 681 682 return ret; 683} 684 685/* 686 * Not sure if this is needed. 687 */ 688static krb5_error_code 689hdb_sqlite_lock(krb5_context context, HDB *db, int operation) 690{ 691 krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB, 692 "lock not implemented"); 693 return HDB_ERR_CANT_LOCK_DB; 694} 695 696/* 697 * Not sure if this is needed. 698 */ 699static krb5_error_code 700hdb_sqlite_unlock(krb5_context context, HDB *db) 701{ 702 krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB, 703 "unlock not implemented"); 704 return HDB_ERR_CANT_LOCK_DB; 705} 706 707/* 708 * Should get the next entry, to allow iteration over all entries. 709 */ 710static krb5_error_code 711hdb_sqlite_nextkey(krb5_context context, HDB *db, unsigned flags, 712 hdb_entry_ex *entry) 713{ 714 krb5_error_code ret = 0; 715 int sqlite_error; 716 krb5_data value; 717 718 hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db; 719 720 sqlite_error = hdb_sqlite_step(context, hsdb->db, hsdb->get_all_entries); 721 if(sqlite_error == SQLITE_ROW) { 722 /* Found an entry */ 723 value.length = sqlite3_column_bytes(hsdb->get_all_entries, 0); 724 value.data = (void *) sqlite3_column_blob(hsdb->get_all_entries, 0); 725 memset(entry, 0, sizeof(*entry)); 726 ret = hdb_value2entry(context, &value, &entry->entry); 727 } 728 else if(sqlite_error == SQLITE_DONE) { 729 /* No more entries */ 730 ret = HDB_ERR_NOENTRY; 731 sqlite3_reset(hsdb->get_all_entries); 732 } 733 else { 734 /* XXX SQLite error. Should be handled in some way. */ 735 ret = EINVAL; 736 } 737 738 return ret; 739} 740 741/* 742 * Should get the first entry in the database. 743 * What is flags used for? 744 */ 745static krb5_error_code 746hdb_sqlite_firstkey(krb5_context context, HDB *db, unsigned flags, 747 hdb_entry_ex *entry) 748{ 749 hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db; 750 krb5_error_code ret; 751 752 sqlite3_reset(hsdb->get_all_entries); 753 754 ret = hdb_sqlite_nextkey(context, db, flags, entry); 755 if(ret) 756 return ret; 757 758 return 0; 759} 760 761/* 762 * Renames the database file. 763 */ 764static krb5_error_code 765hdb_sqlite_rename(krb5_context context, HDB *db, const char *new_name) 766{ 767 hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db; 768 int ret; 769 770 krb5_warnx(context, "hdb_sqlite_rename"); 771 772 if (strncasecmp(new_name, "sqlite:", 7) == 0) 773 new_name += 7; 774 775 hdb_sqlite_close_database(context, db); 776 777 ret = rename(hsdb->db_file, new_name); 778 free(hsdb->db_file); 779 780 hdb_sqlite_make_database(context, db, new_name); 781 782 return ret; 783} 784 785/* 786 * Removes a principal, including aliases and associated entry. 787 */ 788static krb5_error_code 789hdb_sqlite_remove(krb5_context context, HDB *db, 790 krb5_const_principal principal) 791{ 792 krb5_error_code ret; 793 char *principal_string; 794 hdb_sqlite_db *hsdb = (hdb_sqlite_db*)(db->hdb_db); 795 sqlite3_stmt *remove = hsdb->remove; 796 797 ret = krb5_unparse_name(context, principal, &principal_string); 798 if (ret) { 799 free(principal_string); 800 return ret; 801 } 802 803 sqlite3_bind_text(remove, 1, principal_string, -1, SQLITE_STATIC); 804 805 ret = hdb_sqlite_step(context, hsdb->db, remove); 806 if (ret != SQLITE_DONE) { 807 ret = EINVAL; 808 krb5_set_error_message(context, ret, 809 "sqlite remove failed: %d", 810 ret); 811 } else 812 ret = 0; 813 814 sqlite3_clear_bindings(remove); 815 sqlite3_reset(remove); 816 817 return ret; 818} 819 820/** 821 * Create SQLITE object, and creates the on disk database if its doesn't exists. 822 * 823 * @param context A Kerberos 5 context. 824 * @param db a returned database handle. 825 * @param argument filename 826 * 827 * @return 0 on success, an error code if not 828 */ 829 830krb5_error_code 831hdb_sqlite_create(krb5_context context, HDB **db, const char *argument) 832{ 833 krb5_error_code ret; 834 hdb_sqlite_db *hsdb; 835 836 *db = calloc(1, sizeof (**db)); 837 if (*db == NULL) 838 return krb5_enomem(context); 839 840 hsdb = (hdb_sqlite_db*) calloc(1, sizeof (*hsdb)); 841 if (hsdb == NULL) { 842 free(*db); 843 *db = NULL; 844 return krb5_enomem(context); 845 } 846 847 (*db)->hdb_db = hsdb; 848 849 /* XXX make_database should make sure everything else is freed on error */ 850 ret = hdb_sqlite_make_database(context, *db, argument); 851 if (ret) { 852 free((*db)->hdb_db); 853 free(*db); 854 855 return ret; 856 } 857 858 (*db)->hdb_master_key_set = 0; 859 (*db)->hdb_openp = 0; 860 (*db)->hdb_capability_flags = 0; 861 862 (*db)->hdb_open = hdb_sqlite_open; 863 (*db)->hdb_close = hdb_sqlite_close; 864 865 (*db)->hdb_lock = hdb_sqlite_lock; 866 (*db)->hdb_unlock = hdb_sqlite_unlock; 867 (*db)->hdb_firstkey = hdb_sqlite_firstkey; 868 (*db)->hdb_nextkey = hdb_sqlite_nextkey; 869 (*db)->hdb_fetch_kvno = hdb_sqlite_fetch_kvno; 870 (*db)->hdb_store = hdb_sqlite_store; 871 (*db)->hdb_remove = hdb_sqlite_remove; 872 (*db)->hdb_destroy = hdb_sqlite_destroy; 873 (*db)->hdb_rename = hdb_sqlite_rename; 874 (*db)->hdb__get = NULL; 875 (*db)->hdb__put = NULL; 876 (*db)->hdb__del = NULL; 877 878 return 0; 879} 880