1*ae771770SStanislav Sedov /* 2*ae771770SStanislav Sedov * Copyright (c) 2009 Kungliga Tekniska H�gskolan 3*ae771770SStanislav Sedov * (Royal Institute of Technology, Stockholm, Sweden). 4*ae771770SStanislav Sedov * All rights reserved. 5*ae771770SStanislav Sedov * 6*ae771770SStanislav Sedov * Redistribution and use in source and binary forms, with or without 7*ae771770SStanislav Sedov * modification, are permitted provided that the following conditions 8*ae771770SStanislav Sedov * are met: 9*ae771770SStanislav Sedov * 10*ae771770SStanislav Sedov * 1. Redistributions of source code must retain the above copyright 11*ae771770SStanislav Sedov * notice, this list of conditions and the following disclaimer. 12*ae771770SStanislav Sedov * 13*ae771770SStanislav Sedov * 2. Redistributions in binary form must reproduce the above copyright 14*ae771770SStanislav Sedov * notice, this list of conditions and the following disclaimer in the 15*ae771770SStanislav Sedov * documentation and/or other materials provided with the distribution. 16*ae771770SStanislav Sedov * 17*ae771770SStanislav Sedov * 3. Neither the name of the Institute nor the names of its contributors 18*ae771770SStanislav Sedov * may be used to endorse or promote products derived from this software 19*ae771770SStanislav Sedov * without specific prior written permission. 20*ae771770SStanislav Sedov * 21*ae771770SStanislav Sedov * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22*ae771770SStanislav Sedov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23*ae771770SStanislav Sedov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24*ae771770SStanislav Sedov * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25*ae771770SStanislav Sedov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26*ae771770SStanislav Sedov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27*ae771770SStanislav Sedov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28*ae771770SStanislav Sedov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29*ae771770SStanislav Sedov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30*ae771770SStanislav Sedov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31*ae771770SStanislav Sedov * SUCH DAMAGE. 32*ae771770SStanislav Sedov */ 33*ae771770SStanislav Sedov 34*ae771770SStanislav Sedov #include "hdb_locl.h" 35*ae771770SStanislav Sedov #include "sqlite3.h" 36*ae771770SStanislav Sedov 37*ae771770SStanislav Sedov #define MAX_RETRIES 10 38*ae771770SStanislav Sedov 39*ae771770SStanislav Sedov typedef struct hdb_sqlite_db { 40*ae771770SStanislav Sedov double version; 41*ae771770SStanislav Sedov sqlite3 *db; 42*ae771770SStanislav Sedov char *db_file; 43*ae771770SStanislav Sedov 44*ae771770SStanislav Sedov sqlite3_stmt *get_version; 45*ae771770SStanislav Sedov sqlite3_stmt *fetch; 46*ae771770SStanislav Sedov sqlite3_stmt *get_ids; 47*ae771770SStanislav Sedov sqlite3_stmt *add_entry; 48*ae771770SStanislav Sedov sqlite3_stmt *add_principal; 49*ae771770SStanislav Sedov sqlite3_stmt *add_alias; 50*ae771770SStanislav Sedov sqlite3_stmt *delete_aliases; 51*ae771770SStanislav Sedov sqlite3_stmt *update_entry; 52*ae771770SStanislav Sedov sqlite3_stmt *remove; 53*ae771770SStanislav Sedov sqlite3_stmt *get_all_entries; 54*ae771770SStanislav Sedov 55*ae771770SStanislav Sedov } hdb_sqlite_db; 56*ae771770SStanislav Sedov 57*ae771770SStanislav Sedov /* This should be used to mark updates which make the code incompatible 58*ae771770SStanislav Sedov * with databases created with previous versions. Don't update it if 59*ae771770SStanislav Sedov * compatibility is not broken. */ 60*ae771770SStanislav Sedov #define HDBSQLITE_VERSION 0.1 61*ae771770SStanislav Sedov 62*ae771770SStanislav Sedov #define _HDBSQLITE_STRINGIFY(x) #x 63*ae771770SStanislav Sedov #define HDBSQLITE_STRINGIFY(x) _HDBSQLITE_STRINGIFY(x) 64*ae771770SStanislav Sedov 65*ae771770SStanislav Sedov #define HDBSQLITE_CREATE_TABLES \ 66*ae771770SStanislav Sedov " BEGIN TRANSACTION;" \ 67*ae771770SStanislav Sedov " CREATE TABLE Version (number REAL);" \ 68*ae771770SStanislav Sedov " INSERT INTO Version (number)" \ 69*ae771770SStanislav Sedov " VALUES (" HDBSQLITE_STRINGIFY(HDBSQLITE_VERSION) ");" \ 70*ae771770SStanislav Sedov " CREATE TABLE Principal" \ 71*ae771770SStanislav Sedov " (id INTEGER PRIMARY KEY," \ 72*ae771770SStanislav Sedov " principal TEXT UNIQUE NOT NULL," \ 73*ae771770SStanislav Sedov " canonical INTEGER," \ 74*ae771770SStanislav Sedov " entry INTEGER);" \ 75*ae771770SStanislav Sedov " CREATE TABLE Entry" \ 76*ae771770SStanislav Sedov " (id INTEGER PRIMARY KEY," \ 77*ae771770SStanislav Sedov " data BLOB);" \ 78*ae771770SStanislav Sedov " COMMIT" 79*ae771770SStanislav Sedov #define HDBSQLITE_CREATE_TRIGGERS \ 80*ae771770SStanislav Sedov " CREATE TRIGGER remove_principals AFTER DELETE ON Entry" \ 81*ae771770SStanislav Sedov " BEGIN" \ 82*ae771770SStanislav Sedov " DELETE FROM Principal" \ 83*ae771770SStanislav Sedov " WHERE entry = OLD.id;" \ 84*ae771770SStanislav Sedov " END" 85*ae771770SStanislav Sedov #define HDBSQLITE_GET_VERSION \ 86*ae771770SStanislav Sedov " SELECT number FROM Version" 87*ae771770SStanislav Sedov #define HDBSQLITE_FETCH \ 88*ae771770SStanislav Sedov " SELECT Entry.data FROM Principal, Entry" \ 89*ae771770SStanislav Sedov " WHERE Principal.principal = ? AND" \ 90*ae771770SStanislav Sedov " Entry.id = Principal.entry" 91*ae771770SStanislav Sedov #define HDBSQLITE_GET_IDS \ 92*ae771770SStanislav Sedov " SELECT id, entry FROM Principal" \ 93*ae771770SStanislav Sedov " WHERE principal = ?" 94*ae771770SStanislav Sedov #define HDBSQLITE_ADD_ENTRY \ 95*ae771770SStanislav Sedov " INSERT INTO Entry (data) VALUES (?)" 96*ae771770SStanislav Sedov #define HDBSQLITE_ADD_PRINCIPAL \ 97*ae771770SStanislav Sedov " INSERT INTO Principal (principal, entry, canonical)" \ 98*ae771770SStanislav Sedov " VALUES (?, last_insert_rowid(), 1)" 99*ae771770SStanislav Sedov #define HDBSQLITE_ADD_ALIAS \ 100*ae771770SStanislav Sedov " INSERT INTO Principal (principal, entry, canonical)" \ 101*ae771770SStanislav Sedov " VALUES(?, ?, 0)" 102*ae771770SStanislav Sedov #define HDBSQLITE_DELETE_ALIASES \ 103*ae771770SStanislav Sedov " DELETE FROM Principal" \ 104*ae771770SStanislav Sedov " WHERE entry = ? AND canonical = 0" 105*ae771770SStanislav Sedov #define HDBSQLITE_UPDATE_ENTRY \ 106*ae771770SStanislav Sedov " UPDATE Entry SET data = ?" \ 107*ae771770SStanislav Sedov " WHERE id = ?" 108*ae771770SStanislav Sedov #define HDBSQLITE_REMOVE \ 109*ae771770SStanislav Sedov " DELETE FROM ENTRY WHERE id = " \ 110*ae771770SStanislav Sedov " (SELECT entry FROM Principal" \ 111*ae771770SStanislav Sedov " WHERE principal = ?)" 112*ae771770SStanislav Sedov #define HDBSQLITE_GET_ALL_ENTRIES \ 113*ae771770SStanislav Sedov " SELECT data FROM Entry" 114*ae771770SStanislav Sedov 115*ae771770SStanislav Sedov /** 116*ae771770SStanislav Sedov * Wrapper around sqlite3_prepare_v2. 117*ae771770SStanislav Sedov * 118*ae771770SStanislav Sedov * @param context The current krb5 context 119*ae771770SStanislav Sedov * @param statement Where to store the pointer to the statement 120*ae771770SStanislav Sedov * after preparing it 121*ae771770SStanislav Sedov * @param str SQL code for the statement 122*ae771770SStanislav Sedov * 123*ae771770SStanislav Sedov * @return 0 if OK, an error code if not 124*ae771770SStanislav Sedov */ 125*ae771770SStanislav Sedov static krb5_error_code 126*ae771770SStanislav Sedov hdb_sqlite_prepare_stmt(krb5_context context, 127*ae771770SStanislav Sedov sqlite3 *db, 128*ae771770SStanislav Sedov sqlite3_stmt **statement, 129*ae771770SStanislav Sedov const char *str) 130*ae771770SStanislav Sedov { 131*ae771770SStanislav Sedov int ret, tries = 0; 132*ae771770SStanislav Sedov 133*ae771770SStanislav Sedov ret = sqlite3_prepare_v2(db, str, -1, statement, NULL); 134*ae771770SStanislav Sedov while((tries++ < MAX_RETRIES) && 135*ae771770SStanislav Sedov ((ret == SQLITE_BUSY) || 136*ae771770SStanislav Sedov (ret == SQLITE_IOERR_BLOCKED) || 137*ae771770SStanislav Sedov (ret == SQLITE_LOCKED))) { 138*ae771770SStanislav Sedov krb5_warnx(context, "hdb-sqlite: prepare busy"); 139*ae771770SStanislav Sedov sleep(1); 140*ae771770SStanislav Sedov ret = sqlite3_prepare_v2(db, str, -1, statement, NULL); 141*ae771770SStanislav Sedov } 142*ae771770SStanislav Sedov 143*ae771770SStanislav Sedov if (ret != SQLITE_OK) { 144*ae771770SStanislav Sedov krb5_set_error_message(context, EINVAL, 145*ae771770SStanislav Sedov "Failed to prepare stmt %s: %s", 146*ae771770SStanislav Sedov str, sqlite3_errmsg(db)); 147*ae771770SStanislav Sedov return EINVAL; 148*ae771770SStanislav Sedov } 149*ae771770SStanislav Sedov 150*ae771770SStanislav Sedov return 0; 151*ae771770SStanislav Sedov } 152*ae771770SStanislav Sedov 153*ae771770SStanislav Sedov /** 154*ae771770SStanislav Sedov * A wrapper around sqlite3_exec. 155*ae771770SStanislav Sedov * 156*ae771770SStanislav Sedov * @param context The current krb5 context 157*ae771770SStanislav Sedov * @param database An open sqlite3 database handle 158*ae771770SStanislav Sedov * @param statement SQL code to execute 159*ae771770SStanislav Sedov * @param error_code What to return if the statement fails 160*ae771770SStanislav Sedov * 161*ae771770SStanislav Sedov * @return 0 if OK, else error_code 162*ae771770SStanislav Sedov */ 163*ae771770SStanislav Sedov static krb5_error_code 164*ae771770SStanislav Sedov hdb_sqlite_exec_stmt(krb5_context context, 165*ae771770SStanislav Sedov sqlite3 *database, 166*ae771770SStanislav Sedov const char *statement, 167*ae771770SStanislav Sedov krb5_error_code error_code) 168*ae771770SStanislav Sedov { 169*ae771770SStanislav Sedov int ret; 170*ae771770SStanislav Sedov 171*ae771770SStanislav Sedov ret = sqlite3_exec(database, statement, NULL, NULL, NULL); 172*ae771770SStanislav Sedov 173*ae771770SStanislav Sedov while(((ret == SQLITE_BUSY) || 174*ae771770SStanislav Sedov (ret == SQLITE_IOERR_BLOCKED) || 175*ae771770SStanislav Sedov (ret == SQLITE_LOCKED))) { 176*ae771770SStanislav Sedov krb5_warnx(context, "hdb-sqlite: exec busy: %d", (int)getpid()); 177*ae771770SStanislav Sedov sleep(1); 178*ae771770SStanislav Sedov ret = sqlite3_exec(database, statement, NULL, NULL, NULL); 179*ae771770SStanislav Sedov } 180*ae771770SStanislav Sedov 181*ae771770SStanislav Sedov if (ret != SQLITE_OK && error_code) { 182*ae771770SStanislav Sedov krb5_set_error_message(context, error_code, 183*ae771770SStanislav Sedov "Execute %s: %s", statement, 184*ae771770SStanislav Sedov sqlite3_errmsg(database)); 185*ae771770SStanislav Sedov return error_code; 186*ae771770SStanislav Sedov } 187*ae771770SStanislav Sedov 188*ae771770SStanislav Sedov return 0; 189*ae771770SStanislav Sedov } 190*ae771770SStanislav Sedov 191*ae771770SStanislav Sedov /** 192*ae771770SStanislav Sedov * Opens an sqlite3 database handle to a file, may create the 193*ae771770SStanislav Sedov * database file depending on flags. 194*ae771770SStanislav Sedov * 195*ae771770SStanislav Sedov * @param context The current krb5 context 196*ae771770SStanislav Sedov * @param db Heimdal database handle 197*ae771770SStanislav Sedov * @param flags Controls whether or not the file may be created, 198*ae771770SStanislav Sedov * may be 0 or SQLITE_OPEN_CREATE 199*ae771770SStanislav Sedov */ 200*ae771770SStanislav Sedov static krb5_error_code 201*ae771770SStanislav Sedov hdb_sqlite_open_database(krb5_context context, HDB *db, int flags) 202*ae771770SStanislav Sedov { 203*ae771770SStanislav Sedov int ret; 204*ae771770SStanislav Sedov hdb_sqlite_db *hsdb = (hdb_sqlite_db*) db->hdb_db; 205*ae771770SStanislav Sedov 206*ae771770SStanislav Sedov ret = sqlite3_open_v2(hsdb->db_file, &hsdb->db, 207*ae771770SStanislav Sedov SQLITE_OPEN_READWRITE | flags, NULL); 208*ae771770SStanislav Sedov 209*ae771770SStanislav Sedov if (ret) { 210*ae771770SStanislav Sedov if (hsdb->db) { 211*ae771770SStanislav Sedov ret = ENOENT; 212*ae771770SStanislav Sedov krb5_set_error_message(context, ret, 213*ae771770SStanislav Sedov "Error opening sqlite database %s: %s", 214*ae771770SStanislav Sedov hsdb->db_file, sqlite3_errmsg(hsdb->db)); 215*ae771770SStanislav Sedov sqlite3_close(hsdb->db); 216*ae771770SStanislav Sedov hsdb->db = NULL; 217*ae771770SStanislav Sedov } else 218*ae771770SStanislav Sedov ret = krb5_enomem(context); 219*ae771770SStanislav Sedov return ret; 220*ae771770SStanislav Sedov } 221*ae771770SStanislav Sedov 222*ae771770SStanislav Sedov return 0; 223*ae771770SStanislav Sedov } 224*ae771770SStanislav Sedov 225*ae771770SStanislav Sedov static int 226*ae771770SStanislav Sedov hdb_sqlite_step(krb5_context context, sqlite3 *db, sqlite3_stmt *stmt) 227*ae771770SStanislav Sedov { 228*ae771770SStanislav Sedov int ret; 229*ae771770SStanislav Sedov 230*ae771770SStanislav Sedov ret = sqlite3_step(stmt); 231*ae771770SStanislav Sedov while(((ret == SQLITE_BUSY) || 232*ae771770SStanislav Sedov (ret == SQLITE_IOERR_BLOCKED) || 233*ae771770SStanislav Sedov (ret == SQLITE_LOCKED))) { 234*ae771770SStanislav Sedov krb5_warnx(context, "hdb-sqlite: step busy: %d", (int)getpid()); 235*ae771770SStanislav Sedov sleep(1); 236*ae771770SStanislav Sedov ret = sqlite3_step(stmt); 237*ae771770SStanislav Sedov } 238*ae771770SStanislav Sedov return ret; 239*ae771770SStanislav Sedov } 240*ae771770SStanislav Sedov 241*ae771770SStanislav Sedov /** 242*ae771770SStanislav Sedov * Closes the database and frees memory allocated for statements. 243*ae771770SStanislav Sedov * 244*ae771770SStanislav Sedov * @param context The current krb5 context 245*ae771770SStanislav Sedov * @param db Heimdal database handle 246*ae771770SStanislav Sedov */ 247*ae771770SStanislav Sedov static krb5_error_code 248*ae771770SStanislav Sedov hdb_sqlite_close_database(krb5_context context, HDB *db) 249*ae771770SStanislav Sedov { 250*ae771770SStanislav Sedov hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db; 251*ae771770SStanislav Sedov 252*ae771770SStanislav Sedov sqlite3_finalize(hsdb->get_version); 253*ae771770SStanislav Sedov sqlite3_finalize(hsdb->fetch); 254*ae771770SStanislav Sedov sqlite3_finalize(hsdb->get_ids); 255*ae771770SStanislav Sedov sqlite3_finalize(hsdb->add_entry); 256*ae771770SStanislav Sedov sqlite3_finalize(hsdb->add_principal); 257*ae771770SStanislav Sedov sqlite3_finalize(hsdb->add_alias); 258*ae771770SStanislav Sedov sqlite3_finalize(hsdb->delete_aliases); 259*ae771770SStanislav Sedov sqlite3_finalize(hsdb->update_entry); 260*ae771770SStanislav Sedov sqlite3_finalize(hsdb->remove); 261*ae771770SStanislav Sedov sqlite3_finalize(hsdb->get_all_entries); 262*ae771770SStanislav Sedov 263*ae771770SStanislav Sedov sqlite3_close(hsdb->db); 264*ae771770SStanislav Sedov 265*ae771770SStanislav Sedov return 0; 266*ae771770SStanislav Sedov } 267*ae771770SStanislav Sedov 268*ae771770SStanislav Sedov /** 269*ae771770SStanislav Sedov * Opens an sqlite database file and prepares it for use. 270*ae771770SStanislav Sedov * If the file does not exist it will be created. 271*ae771770SStanislav Sedov * 272*ae771770SStanislav Sedov * @param context The current krb5_context 273*ae771770SStanislav Sedov * @param db The heimdal database handle 274*ae771770SStanislav Sedov * @param filename Where to store the database file 275*ae771770SStanislav Sedov * 276*ae771770SStanislav Sedov * @return 0 if everything worked, an error code if not 277*ae771770SStanislav Sedov */ 278*ae771770SStanislav Sedov static krb5_error_code 279*ae771770SStanislav Sedov hdb_sqlite_make_database(krb5_context context, HDB *db, const char *filename) 280*ae771770SStanislav Sedov { 281*ae771770SStanislav Sedov int ret; 282*ae771770SStanislav Sedov int created_file = 0; 283*ae771770SStanislav Sedov hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db; 284*ae771770SStanislav Sedov 285*ae771770SStanislav Sedov hsdb->db_file = strdup(filename); 286*ae771770SStanislav Sedov if(hsdb->db_file == NULL) 287*ae771770SStanislav Sedov return ENOMEM; 288*ae771770SStanislav Sedov 289*ae771770SStanislav Sedov ret = hdb_sqlite_open_database(context, db, 0); 290*ae771770SStanislav Sedov if (ret) { 291*ae771770SStanislav Sedov ret = hdb_sqlite_open_database(context, db, SQLITE_OPEN_CREATE); 292*ae771770SStanislav Sedov if (ret) goto out; 293*ae771770SStanislav Sedov 294*ae771770SStanislav Sedov created_file = 1; 295*ae771770SStanislav Sedov 296*ae771770SStanislav Sedov ret = hdb_sqlite_exec_stmt(context, hsdb->db, 297*ae771770SStanislav Sedov HDBSQLITE_CREATE_TABLES, 298*ae771770SStanislav Sedov EINVAL); 299*ae771770SStanislav Sedov if (ret) goto out; 300*ae771770SStanislav Sedov 301*ae771770SStanislav Sedov ret = hdb_sqlite_exec_stmt(context, hsdb->db, 302*ae771770SStanislav Sedov HDBSQLITE_CREATE_TRIGGERS, 303*ae771770SStanislav Sedov EINVAL); 304*ae771770SStanislav Sedov if (ret) goto out; 305*ae771770SStanislav Sedov } 306*ae771770SStanislav Sedov 307*ae771770SStanislav Sedov ret = hdb_sqlite_prepare_stmt(context, hsdb->db, 308*ae771770SStanislav Sedov &hsdb->get_version, 309*ae771770SStanislav Sedov HDBSQLITE_GET_VERSION); 310*ae771770SStanislav Sedov if (ret) goto out; 311*ae771770SStanislav Sedov ret = hdb_sqlite_prepare_stmt(context, hsdb->db, 312*ae771770SStanislav Sedov &hsdb->fetch, 313*ae771770SStanislav Sedov HDBSQLITE_FETCH); 314*ae771770SStanislav Sedov if (ret) goto out; 315*ae771770SStanislav Sedov ret = hdb_sqlite_prepare_stmt(context, hsdb->db, 316*ae771770SStanislav Sedov &hsdb->get_ids, 317*ae771770SStanislav Sedov HDBSQLITE_GET_IDS); 318*ae771770SStanislav Sedov if (ret) goto out; 319*ae771770SStanislav Sedov ret = hdb_sqlite_prepare_stmt(context, hsdb->db, 320*ae771770SStanislav Sedov &hsdb->add_entry, 321*ae771770SStanislav Sedov HDBSQLITE_ADD_ENTRY); 322*ae771770SStanislav Sedov if (ret) goto out; 323*ae771770SStanislav Sedov ret = hdb_sqlite_prepare_stmt(context, hsdb->db, 324*ae771770SStanislav Sedov &hsdb->add_principal, 325*ae771770SStanislav Sedov HDBSQLITE_ADD_PRINCIPAL); 326*ae771770SStanislav Sedov if (ret) goto out; 327*ae771770SStanislav Sedov ret = hdb_sqlite_prepare_stmt(context, hsdb->db, 328*ae771770SStanislav Sedov &hsdb->add_alias, 329*ae771770SStanislav Sedov HDBSQLITE_ADD_ALIAS); 330*ae771770SStanislav Sedov if (ret) goto out; 331*ae771770SStanislav Sedov ret = hdb_sqlite_prepare_stmt(context, hsdb->db, 332*ae771770SStanislav Sedov &hsdb->delete_aliases, 333*ae771770SStanislav Sedov HDBSQLITE_DELETE_ALIASES); 334*ae771770SStanislav Sedov if (ret) goto out; 335*ae771770SStanislav Sedov ret = hdb_sqlite_prepare_stmt(context, hsdb->db, 336*ae771770SStanislav Sedov &hsdb->update_entry, 337*ae771770SStanislav Sedov HDBSQLITE_UPDATE_ENTRY); 338*ae771770SStanislav Sedov if (ret) goto out; 339*ae771770SStanislav Sedov ret = hdb_sqlite_prepare_stmt(context, hsdb->db, 340*ae771770SStanislav Sedov &hsdb->remove, 341*ae771770SStanislav Sedov HDBSQLITE_REMOVE); 342*ae771770SStanislav Sedov if (ret) goto out; 343*ae771770SStanislav Sedov ret = hdb_sqlite_prepare_stmt(context, hsdb->db, 344*ae771770SStanislav Sedov &hsdb->get_all_entries, 345*ae771770SStanislav Sedov HDBSQLITE_GET_ALL_ENTRIES); 346*ae771770SStanislav Sedov if (ret) goto out; 347*ae771770SStanislav Sedov 348*ae771770SStanislav Sedov ret = hdb_sqlite_step(context, hsdb->db, hsdb->get_version); 349*ae771770SStanislav Sedov if(ret == SQLITE_ROW) { 350*ae771770SStanislav Sedov hsdb->version = sqlite3_column_double(hsdb->get_version, 0); 351*ae771770SStanislav Sedov } 352*ae771770SStanislav Sedov sqlite3_reset(hsdb->get_version); 353*ae771770SStanislav Sedov ret = 0; 354*ae771770SStanislav Sedov 355*ae771770SStanislav Sedov if(hsdb->version != HDBSQLITE_VERSION) { 356*ae771770SStanislav Sedov ret = EINVAL; 357*ae771770SStanislav Sedov krb5_set_error_message(context, ret, "HDBSQLITE_VERSION mismatch"); 358*ae771770SStanislav Sedov } 359*ae771770SStanislav Sedov 360*ae771770SStanislav Sedov if(ret) goto out; 361*ae771770SStanislav Sedov 362*ae771770SStanislav Sedov return 0; 363*ae771770SStanislav Sedov 364*ae771770SStanislav Sedov out: 365*ae771770SStanislav Sedov if (hsdb->db) 366*ae771770SStanislav Sedov sqlite3_close(hsdb->db); 367*ae771770SStanislav Sedov if (created_file) 368*ae771770SStanislav Sedov unlink(hsdb->db_file); 369*ae771770SStanislav Sedov 370*ae771770SStanislav Sedov return ret; 371*ae771770SStanislav Sedov } 372*ae771770SStanislav Sedov 373*ae771770SStanislav Sedov /** 374*ae771770SStanislav Sedov * Retrieves an entry by searching for the given 375*ae771770SStanislav Sedov * principal in the Principal database table, both 376*ae771770SStanislav Sedov * for canonical principals and aliases. 377*ae771770SStanislav Sedov * 378*ae771770SStanislav Sedov * @param context The current krb5_context 379*ae771770SStanislav Sedov * @param db Heimdal database handle 380*ae771770SStanislav Sedov * @param principal The principal whose entry to search for 381*ae771770SStanislav Sedov * @param flags Currently only for HDB_F_DECRYPT 382*ae771770SStanislav Sedov * @param kvno kvno to fetch is HDB_F_KVNO_SPECIFIED use used 383*ae771770SStanislav Sedov * 384*ae771770SStanislav Sedov * @return 0 if everything worked, an error code if not 385*ae771770SStanislav Sedov */ 386*ae771770SStanislav Sedov static krb5_error_code 387*ae771770SStanislav Sedov hdb_sqlite_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal, 388*ae771770SStanislav Sedov unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry) 389*ae771770SStanislav Sedov { 390*ae771770SStanislav Sedov int sqlite_error; 391*ae771770SStanislav Sedov krb5_error_code ret; 392*ae771770SStanislav Sedov char *principal_string; 393*ae771770SStanislav Sedov hdb_sqlite_db *hsdb = (hdb_sqlite_db*)(db->hdb_db); 394*ae771770SStanislav Sedov sqlite3_stmt *fetch = hsdb->fetch; 395*ae771770SStanislav Sedov krb5_data value; 396*ae771770SStanislav Sedov 397*ae771770SStanislav Sedov ret = krb5_unparse_name(context, principal, &principal_string); 398*ae771770SStanislav Sedov if (ret) { 399*ae771770SStanislav Sedov free(principal_string); 400*ae771770SStanislav Sedov return ret; 401*ae771770SStanislav Sedov } 402*ae771770SStanislav Sedov 403*ae771770SStanislav Sedov sqlite3_bind_text(fetch, 1, principal_string, -1, SQLITE_STATIC); 404*ae771770SStanislav Sedov 405*ae771770SStanislav Sedov sqlite_error = hdb_sqlite_step(context, hsdb->db, fetch); 406*ae771770SStanislav Sedov if (sqlite_error != SQLITE_ROW) { 407*ae771770SStanislav Sedov if(sqlite_error == SQLITE_DONE) { 408*ae771770SStanislav Sedov ret = HDB_ERR_NOENTRY; 409*ae771770SStanislav Sedov goto out; 410*ae771770SStanislav Sedov } else { 411*ae771770SStanislav Sedov ret = EINVAL; 412*ae771770SStanislav Sedov krb5_set_error_message(context, ret, 413*ae771770SStanislav Sedov "sqlite fetch failed: %d", 414*ae771770SStanislav Sedov sqlite_error); 415*ae771770SStanislav Sedov goto out; 416*ae771770SStanislav Sedov } 417*ae771770SStanislav Sedov } 418*ae771770SStanislav Sedov 419*ae771770SStanislav Sedov value.length = sqlite3_column_bytes(fetch, 0); 420*ae771770SStanislav Sedov value.data = (void *) sqlite3_column_blob(fetch, 0); 421*ae771770SStanislav Sedov 422*ae771770SStanislav Sedov ret = hdb_value2entry(context, &value, &entry->entry); 423*ae771770SStanislav Sedov if(ret) 424*ae771770SStanislav Sedov goto out; 425*ae771770SStanislav Sedov 426*ae771770SStanislav Sedov if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { 427*ae771770SStanislav Sedov ret = hdb_unseal_keys(context, db, &entry->entry); 428*ae771770SStanislav Sedov if(ret) { 429*ae771770SStanislav Sedov hdb_free_entry(context, entry); 430*ae771770SStanislav Sedov goto out; 431*ae771770SStanislav Sedov } 432*ae771770SStanislav Sedov } 433*ae771770SStanislav Sedov 434*ae771770SStanislav Sedov ret = 0; 435*ae771770SStanislav Sedov 436*ae771770SStanislav Sedov out: 437*ae771770SStanislav Sedov 438*ae771770SStanislav Sedov sqlite3_clear_bindings(fetch); 439*ae771770SStanislav Sedov sqlite3_reset(fetch); 440*ae771770SStanislav Sedov 441*ae771770SStanislav Sedov free(principal_string); 442*ae771770SStanislav Sedov 443*ae771770SStanislav Sedov return ret; 444*ae771770SStanislav Sedov } 445*ae771770SStanislav Sedov 446*ae771770SStanislav Sedov /** 447*ae771770SStanislav Sedov * Convenience function to step a prepared statement with no 448*ae771770SStanislav Sedov * value once. 449*ae771770SStanislav Sedov * 450*ae771770SStanislav Sedov * @param context The current krb5_context 451*ae771770SStanislav Sedov * @param statement A prepared sqlite3 statement 452*ae771770SStanislav Sedov * 453*ae771770SStanislav Sedov * @return 0 if everything worked, an error code if not 454*ae771770SStanislav Sedov */ 455*ae771770SStanislav Sedov static krb5_error_code 456*ae771770SStanislav Sedov hdb_sqlite_step_once(krb5_context context, HDB *db, sqlite3_stmt *statement) 457*ae771770SStanislav Sedov { 458*ae771770SStanislav Sedov int ret; 459*ae771770SStanislav Sedov hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db; 460*ae771770SStanislav Sedov 461*ae771770SStanislav Sedov ret = hdb_sqlite_step(context, hsdb->db, statement); 462*ae771770SStanislav Sedov sqlite3_clear_bindings(statement); 463*ae771770SStanislav Sedov sqlite3_reset(statement); 464*ae771770SStanislav Sedov 465*ae771770SStanislav Sedov return ret; 466*ae771770SStanislav Sedov } 467*ae771770SStanislav Sedov 468*ae771770SStanislav Sedov 469*ae771770SStanislav Sedov /** 470*ae771770SStanislav Sedov * Stores an hdb_entry in the database. If flags contains HDB_F_REPLACE 471*ae771770SStanislav Sedov * a previous entry may be replaced. 472*ae771770SStanislav Sedov * 473*ae771770SStanislav Sedov * @param context The current krb5_context 474*ae771770SStanislav Sedov * @param db Heimdal database handle 475*ae771770SStanislav Sedov * @param flags May currently only contain HDB_F_REPLACE 476*ae771770SStanislav Sedov * @param entry The data to store 477*ae771770SStanislav Sedov * 478*ae771770SStanislav Sedov * @return 0 if everything worked, an error code if not 479*ae771770SStanislav Sedov */ 480*ae771770SStanislav Sedov static krb5_error_code 481*ae771770SStanislav Sedov hdb_sqlite_store(krb5_context context, HDB *db, unsigned flags, 482*ae771770SStanislav Sedov hdb_entry_ex *entry) 483*ae771770SStanislav Sedov { 484*ae771770SStanislav Sedov int ret; 485*ae771770SStanislav Sedov int i; 486*ae771770SStanislav Sedov sqlite_int64 entry_id; 487*ae771770SStanislav Sedov char *principal_string = NULL; 488*ae771770SStanislav Sedov char *alias_string; 489*ae771770SStanislav Sedov const HDB_Ext_Aliases *aliases; 490*ae771770SStanislav Sedov 491*ae771770SStanislav Sedov hdb_sqlite_db *hsdb = (hdb_sqlite_db *)(db->hdb_db); 492*ae771770SStanislav Sedov krb5_data value; 493*ae771770SStanislav Sedov sqlite3_stmt *get_ids = hsdb->get_ids; 494*ae771770SStanislav Sedov 495*ae771770SStanislav Sedov ret = hdb_sqlite_exec_stmt(context, hsdb->db, 496*ae771770SStanislav Sedov "BEGIN IMMEDIATE TRANSACTION", EINVAL); 497*ae771770SStanislav Sedov if(ret != SQLITE_OK) { 498*ae771770SStanislav Sedov ret = EINVAL; 499*ae771770SStanislav Sedov krb5_set_error_message(context, ret, 500*ae771770SStanislav Sedov "SQLite BEGIN TRANSACTION failed: %s", 501*ae771770SStanislav Sedov sqlite3_errmsg(hsdb->db)); 502*ae771770SStanislav Sedov goto rollback; 503*ae771770SStanislav Sedov } 504*ae771770SStanislav Sedov 505*ae771770SStanislav Sedov ret = krb5_unparse_name(context, 506*ae771770SStanislav Sedov entry->entry.principal, &principal_string); 507*ae771770SStanislav Sedov if (ret) { 508*ae771770SStanislav Sedov goto rollback; 509*ae771770SStanislav Sedov } 510*ae771770SStanislav Sedov 511*ae771770SStanislav Sedov ret = hdb_seal_keys(context, db, &entry->entry); 512*ae771770SStanislav Sedov if(ret) { 513*ae771770SStanislav Sedov goto rollback; 514*ae771770SStanislav Sedov } 515*ae771770SStanislav Sedov 516*ae771770SStanislav Sedov ret = hdb_entry2value(context, &entry->entry, &value); 517*ae771770SStanislav Sedov if(ret) { 518*ae771770SStanislav Sedov goto rollback; 519*ae771770SStanislav Sedov } 520*ae771770SStanislav Sedov 521*ae771770SStanislav Sedov sqlite3_bind_text(get_ids, 1, principal_string, -1, SQLITE_STATIC); 522*ae771770SStanislav Sedov ret = hdb_sqlite_step(context, hsdb->db, get_ids); 523*ae771770SStanislav Sedov 524*ae771770SStanislav Sedov if(ret == SQLITE_DONE) { /* No such principal */ 525*ae771770SStanislav Sedov 526*ae771770SStanislav Sedov sqlite3_bind_blob(hsdb->add_entry, 1, 527*ae771770SStanislav Sedov value.data, value.length, SQLITE_STATIC); 528*ae771770SStanislav Sedov ret = hdb_sqlite_step(context, hsdb->db, hsdb->add_entry); 529*ae771770SStanislav Sedov sqlite3_clear_bindings(hsdb->add_entry); 530*ae771770SStanislav Sedov sqlite3_reset(hsdb->add_entry); 531*ae771770SStanislav Sedov if(ret != SQLITE_DONE) 532*ae771770SStanislav Sedov goto rollback; 533*ae771770SStanislav Sedov 534*ae771770SStanislav Sedov sqlite3_bind_text(hsdb->add_principal, 1, 535*ae771770SStanislav Sedov principal_string, -1, SQLITE_STATIC); 536*ae771770SStanislav Sedov ret = hdb_sqlite_step(context, hsdb->db, hsdb->add_principal); 537*ae771770SStanislav Sedov sqlite3_clear_bindings(hsdb->add_principal); 538*ae771770SStanislav Sedov sqlite3_reset(hsdb->add_principal); 539*ae771770SStanislav Sedov if(ret != SQLITE_DONE) 540*ae771770SStanislav Sedov goto rollback; 541*ae771770SStanislav Sedov 542*ae771770SStanislav Sedov entry_id = sqlite3_column_int64(get_ids, 1); 543*ae771770SStanislav Sedov 544*ae771770SStanislav Sedov } else if(ret == SQLITE_ROW) { /* Found a principal */ 545*ae771770SStanislav Sedov 546*ae771770SStanislav Sedov if(! (flags & HDB_F_REPLACE)) /* Not allowed to replace it */ 547*ae771770SStanislav Sedov goto rollback; 548*ae771770SStanislav Sedov 549*ae771770SStanislav Sedov entry_id = sqlite3_column_int64(get_ids, 1); 550*ae771770SStanislav Sedov 551*ae771770SStanislav Sedov sqlite3_bind_int64(hsdb->delete_aliases, 1, entry_id); 552*ae771770SStanislav Sedov ret = hdb_sqlite_step_once(context, db, hsdb->delete_aliases); 553*ae771770SStanislav Sedov if(ret != SQLITE_DONE) 554*ae771770SStanislav Sedov goto rollback; 555*ae771770SStanislav Sedov 556*ae771770SStanislav Sedov sqlite3_bind_blob(hsdb->update_entry, 1, 557*ae771770SStanislav Sedov value.data, value.length, SQLITE_STATIC); 558*ae771770SStanislav Sedov sqlite3_bind_int64(hsdb->update_entry, 2, entry_id); 559*ae771770SStanislav Sedov ret = hdb_sqlite_step_once(context, db, hsdb->update_entry); 560*ae771770SStanislav Sedov if(ret != SQLITE_DONE) 561*ae771770SStanislav Sedov goto rollback; 562*ae771770SStanislav Sedov 563*ae771770SStanislav Sedov } else { 564*ae771770SStanislav Sedov /* Error! */ 565*ae771770SStanislav Sedov goto rollback; 566*ae771770SStanislav Sedov } 567*ae771770SStanislav Sedov 568*ae771770SStanislav Sedov ret = hdb_entry_get_aliases(&entry->entry, &aliases); 569*ae771770SStanislav Sedov if(ret || aliases == NULL) 570*ae771770SStanislav Sedov goto commit; 571*ae771770SStanislav Sedov 572*ae771770SStanislav Sedov for(i = 0; i < aliases->aliases.len; i++) { 573*ae771770SStanislav Sedov 574*ae771770SStanislav Sedov ret = krb5_unparse_name(context, &aliases->aliases.val[i], 575*ae771770SStanislav Sedov &alias_string); 576*ae771770SStanislav Sedov if (ret) { 577*ae771770SStanislav Sedov free(alias_string); 578*ae771770SStanislav Sedov goto rollback; 579*ae771770SStanislav Sedov } 580*ae771770SStanislav Sedov 581*ae771770SStanislav Sedov sqlite3_bind_text(hsdb->add_alias, 1, alias_string, 582*ae771770SStanislav Sedov -1, SQLITE_STATIC); 583*ae771770SStanislav Sedov sqlite3_bind_int64(hsdb->add_alias, 2, entry_id); 584*ae771770SStanislav Sedov ret = hdb_sqlite_step_once(context, db, hsdb->add_alias); 585*ae771770SStanislav Sedov 586*ae771770SStanislav Sedov free(alias_string); 587*ae771770SStanislav Sedov 588*ae771770SStanislav Sedov if(ret != SQLITE_DONE) 589*ae771770SStanislav Sedov goto rollback; 590*ae771770SStanislav Sedov } 591*ae771770SStanislav Sedov 592*ae771770SStanislav Sedov ret = 0; 593*ae771770SStanislav Sedov 594*ae771770SStanislav Sedov commit: 595*ae771770SStanislav Sedov 596*ae771770SStanislav Sedov free(principal_string); 597*ae771770SStanislav Sedov 598*ae771770SStanislav Sedov krb5_data_free(&value); 599*ae771770SStanislav Sedov 600*ae771770SStanislav Sedov sqlite3_clear_bindings(get_ids); 601*ae771770SStanislav Sedov sqlite3_reset(get_ids); 602*ae771770SStanislav Sedov 603*ae771770SStanislav Sedov ret = hdb_sqlite_exec_stmt(context, hsdb->db, "COMMIT", EINVAL); 604*ae771770SStanislav Sedov if(ret != SQLITE_OK) 605*ae771770SStanislav Sedov krb5_warnx(context, "hdb-sqlite: COMMIT problem: %d: %s", 606*ae771770SStanislav Sedov ret, sqlite3_errmsg(hsdb->db)); 607*ae771770SStanislav Sedov 608*ae771770SStanislav Sedov return ret; 609*ae771770SStanislav Sedov 610*ae771770SStanislav Sedov rollback: 611*ae771770SStanislav Sedov 612*ae771770SStanislav Sedov krb5_warnx(context, "hdb-sqlite: store rollback problem: %d: %s", 613*ae771770SStanislav Sedov ret, sqlite3_errmsg(hsdb->db)); 614*ae771770SStanislav Sedov 615*ae771770SStanislav Sedov free(principal_string); 616*ae771770SStanislav Sedov 617*ae771770SStanislav Sedov ret = hdb_sqlite_exec_stmt(context, hsdb->db, 618*ae771770SStanislav Sedov "ROLLBACK", EINVAL); 619*ae771770SStanislav Sedov return ret; 620*ae771770SStanislav Sedov } 621*ae771770SStanislav Sedov 622*ae771770SStanislav Sedov /** 623*ae771770SStanislav Sedov * This may be called often by other code, since the BDB backends 624*ae771770SStanislav Sedov * can not have several open connections. SQLite can handle 625*ae771770SStanislav Sedov * many processes with open handles to the database file 626*ae771770SStanislav Sedov * and closing/opening the handle is an expensive operation. 627*ae771770SStanislav Sedov * Hence, this function does nothing. 628*ae771770SStanislav Sedov * 629*ae771770SStanislav Sedov * @param context The current krb5 context 630*ae771770SStanislav Sedov * @param db Heimdal database handle 631*ae771770SStanislav Sedov * 632*ae771770SStanislav Sedov * @return Always returns 0 633*ae771770SStanislav Sedov */ 634*ae771770SStanislav Sedov static krb5_error_code 635*ae771770SStanislav Sedov hdb_sqlite_close(krb5_context context, HDB *db) 636*ae771770SStanislav Sedov { 637*ae771770SStanislav Sedov return 0; 638*ae771770SStanislav Sedov } 639*ae771770SStanislav Sedov 640*ae771770SStanislav Sedov /** 641*ae771770SStanislav Sedov * The opposite of hdb_sqlite_close. Since SQLite accepts 642*ae771770SStanislav Sedov * many open handles to the database file the handle does not 643*ae771770SStanislav Sedov * need to be closed, or reopened. 644*ae771770SStanislav Sedov * 645*ae771770SStanislav Sedov * @param context The current krb5 context 646*ae771770SStanislav Sedov * @param db Heimdal database handle 647*ae771770SStanislav Sedov * @param flags 648*ae771770SStanislav Sedov * @param mode_t 649*ae771770SStanislav Sedov * 650*ae771770SStanislav Sedov * @return Always returns 0 651*ae771770SStanislav Sedov */ 652*ae771770SStanislav Sedov static krb5_error_code 653*ae771770SStanislav Sedov hdb_sqlite_open(krb5_context context, HDB *db, int flags, mode_t mode) 654*ae771770SStanislav Sedov { 655*ae771770SStanislav Sedov return 0; 656*ae771770SStanislav Sedov } 657*ae771770SStanislav Sedov 658*ae771770SStanislav Sedov /** 659*ae771770SStanislav Sedov * Closes the databse and frees all resources. 660*ae771770SStanislav Sedov * 661*ae771770SStanislav Sedov * @param context The current krb5 context 662*ae771770SStanislav Sedov * @param db Heimdal database handle 663*ae771770SStanislav Sedov * 664*ae771770SStanislav Sedov * @return 0 on success, an error code if not 665*ae771770SStanislav Sedov */ 666*ae771770SStanislav Sedov static krb5_error_code 667*ae771770SStanislav Sedov hdb_sqlite_destroy(krb5_context context, HDB *db) 668*ae771770SStanislav Sedov { 669*ae771770SStanislav Sedov int ret; 670*ae771770SStanislav Sedov hdb_sqlite_db *hsdb; 671*ae771770SStanislav Sedov 672*ae771770SStanislav Sedov ret = hdb_clear_master_key(context, db); 673*ae771770SStanislav Sedov 674*ae771770SStanislav Sedov hdb_sqlite_close_database(context, db); 675*ae771770SStanislav Sedov 676*ae771770SStanislav Sedov hsdb = (hdb_sqlite_db*)(db->hdb_db); 677*ae771770SStanislav Sedov 678*ae771770SStanislav Sedov free(hsdb->db_file); 679*ae771770SStanislav Sedov free(db->hdb_db); 680*ae771770SStanislav Sedov free(db); 681*ae771770SStanislav Sedov 682*ae771770SStanislav Sedov return ret; 683*ae771770SStanislav Sedov } 684*ae771770SStanislav Sedov 685*ae771770SStanislav Sedov /* 686*ae771770SStanislav Sedov * Not sure if this is needed. 687*ae771770SStanislav Sedov */ 688*ae771770SStanislav Sedov static krb5_error_code 689*ae771770SStanislav Sedov hdb_sqlite_lock(krb5_context context, HDB *db, int operation) 690*ae771770SStanislav Sedov { 691*ae771770SStanislav Sedov krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB, 692*ae771770SStanislav Sedov "lock not implemented"); 693*ae771770SStanislav Sedov return HDB_ERR_CANT_LOCK_DB; 694*ae771770SStanislav Sedov } 695*ae771770SStanislav Sedov 696*ae771770SStanislav Sedov /* 697*ae771770SStanislav Sedov * Not sure if this is needed. 698*ae771770SStanislav Sedov */ 699*ae771770SStanislav Sedov static krb5_error_code 700*ae771770SStanislav Sedov hdb_sqlite_unlock(krb5_context context, HDB *db) 701*ae771770SStanislav Sedov { 702*ae771770SStanislav Sedov krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB, 703*ae771770SStanislav Sedov "unlock not implemented"); 704*ae771770SStanislav Sedov return HDB_ERR_CANT_LOCK_DB; 705*ae771770SStanislav Sedov } 706*ae771770SStanislav Sedov 707*ae771770SStanislav Sedov /* 708*ae771770SStanislav Sedov * Should get the next entry, to allow iteration over all entries. 709*ae771770SStanislav Sedov */ 710*ae771770SStanislav Sedov static krb5_error_code 711*ae771770SStanislav Sedov hdb_sqlite_nextkey(krb5_context context, HDB *db, unsigned flags, 712*ae771770SStanislav Sedov hdb_entry_ex *entry) 713*ae771770SStanislav Sedov { 714*ae771770SStanislav Sedov krb5_error_code ret = 0; 715*ae771770SStanislav Sedov int sqlite_error; 716*ae771770SStanislav Sedov krb5_data value; 717*ae771770SStanislav Sedov 718*ae771770SStanislav Sedov hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db; 719*ae771770SStanislav Sedov 720*ae771770SStanislav Sedov sqlite_error = hdb_sqlite_step(context, hsdb->db, hsdb->get_all_entries); 721*ae771770SStanislav Sedov if(sqlite_error == SQLITE_ROW) { 722*ae771770SStanislav Sedov /* Found an entry */ 723*ae771770SStanislav Sedov value.length = sqlite3_column_bytes(hsdb->get_all_entries, 0); 724*ae771770SStanislav Sedov value.data = (void *) sqlite3_column_blob(hsdb->get_all_entries, 0); 725*ae771770SStanislav Sedov memset(entry, 0, sizeof(*entry)); 726*ae771770SStanislav Sedov ret = hdb_value2entry(context, &value, &entry->entry); 727*ae771770SStanislav Sedov } 728*ae771770SStanislav Sedov else if(sqlite_error == SQLITE_DONE) { 729*ae771770SStanislav Sedov /* No more entries */ 730*ae771770SStanislav Sedov ret = HDB_ERR_NOENTRY; 731*ae771770SStanislav Sedov sqlite3_reset(hsdb->get_all_entries); 732*ae771770SStanislav Sedov } 733*ae771770SStanislav Sedov else { 734*ae771770SStanislav Sedov /* XXX SQLite error. Should be handled in some way. */ 735*ae771770SStanislav Sedov ret = EINVAL; 736*ae771770SStanislav Sedov } 737*ae771770SStanislav Sedov 738*ae771770SStanislav Sedov return ret; 739*ae771770SStanislav Sedov } 740*ae771770SStanislav Sedov 741*ae771770SStanislav Sedov /* 742*ae771770SStanislav Sedov * Should get the first entry in the database. 743*ae771770SStanislav Sedov * What is flags used for? 744*ae771770SStanislav Sedov */ 745*ae771770SStanislav Sedov static krb5_error_code 746*ae771770SStanislav Sedov hdb_sqlite_firstkey(krb5_context context, HDB *db, unsigned flags, 747*ae771770SStanislav Sedov hdb_entry_ex *entry) 748*ae771770SStanislav Sedov { 749*ae771770SStanislav Sedov hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db; 750*ae771770SStanislav Sedov krb5_error_code ret; 751*ae771770SStanislav Sedov 752*ae771770SStanislav Sedov sqlite3_reset(hsdb->get_all_entries); 753*ae771770SStanislav Sedov 754*ae771770SStanislav Sedov ret = hdb_sqlite_nextkey(context, db, flags, entry); 755*ae771770SStanislav Sedov if(ret) 756*ae771770SStanislav Sedov return ret; 757*ae771770SStanislav Sedov 758*ae771770SStanislav Sedov return 0; 759*ae771770SStanislav Sedov } 760*ae771770SStanislav Sedov 761*ae771770SStanislav Sedov /* 762*ae771770SStanislav Sedov * Renames the database file. 763*ae771770SStanislav Sedov */ 764*ae771770SStanislav Sedov static krb5_error_code 765*ae771770SStanislav Sedov hdb_sqlite_rename(krb5_context context, HDB *db, const char *new_name) 766*ae771770SStanislav Sedov { 767*ae771770SStanislav Sedov hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db; 768*ae771770SStanislav Sedov int ret; 769*ae771770SStanislav Sedov 770*ae771770SStanislav Sedov krb5_warnx(context, "hdb_sqlite_rename"); 771*ae771770SStanislav Sedov 772*ae771770SStanislav Sedov if (strncasecmp(new_name, "sqlite:", 7) == 0) 773*ae771770SStanislav Sedov new_name += 7; 774*ae771770SStanislav Sedov 775*ae771770SStanislav Sedov hdb_sqlite_close_database(context, db); 776*ae771770SStanislav Sedov 777*ae771770SStanislav Sedov ret = rename(hsdb->db_file, new_name); 778*ae771770SStanislav Sedov free(hsdb->db_file); 779*ae771770SStanislav Sedov 780*ae771770SStanislav Sedov hdb_sqlite_make_database(context, db, new_name); 781*ae771770SStanislav Sedov 782*ae771770SStanislav Sedov return ret; 783*ae771770SStanislav Sedov } 784*ae771770SStanislav Sedov 785*ae771770SStanislav Sedov /* 786*ae771770SStanislav Sedov * Removes a principal, including aliases and associated entry. 787*ae771770SStanislav Sedov */ 788*ae771770SStanislav Sedov static krb5_error_code 789*ae771770SStanislav Sedov hdb_sqlite_remove(krb5_context context, HDB *db, 790*ae771770SStanislav Sedov krb5_const_principal principal) 791*ae771770SStanislav Sedov { 792*ae771770SStanislav Sedov krb5_error_code ret; 793*ae771770SStanislav Sedov char *principal_string; 794*ae771770SStanislav Sedov hdb_sqlite_db *hsdb = (hdb_sqlite_db*)(db->hdb_db); 795*ae771770SStanislav Sedov sqlite3_stmt *remove = hsdb->remove; 796*ae771770SStanislav Sedov 797*ae771770SStanislav Sedov ret = krb5_unparse_name(context, principal, &principal_string); 798*ae771770SStanislav Sedov if (ret) { 799*ae771770SStanislav Sedov free(principal_string); 800*ae771770SStanislav Sedov return ret; 801*ae771770SStanislav Sedov } 802*ae771770SStanislav Sedov 803*ae771770SStanislav Sedov sqlite3_bind_text(remove, 1, principal_string, -1, SQLITE_STATIC); 804*ae771770SStanislav Sedov 805*ae771770SStanislav Sedov ret = hdb_sqlite_step(context, hsdb->db, remove); 806*ae771770SStanislav Sedov if (ret != SQLITE_DONE) { 807*ae771770SStanislav Sedov ret = EINVAL; 808*ae771770SStanislav Sedov krb5_set_error_message(context, ret, 809*ae771770SStanislav Sedov "sqlite remove failed: %d", 810*ae771770SStanislav Sedov ret); 811*ae771770SStanislav Sedov } else 812*ae771770SStanislav Sedov ret = 0; 813*ae771770SStanislav Sedov 814*ae771770SStanislav Sedov sqlite3_clear_bindings(remove); 815*ae771770SStanislav Sedov sqlite3_reset(remove); 816*ae771770SStanislav Sedov 817*ae771770SStanislav Sedov return ret; 818*ae771770SStanislav Sedov } 819*ae771770SStanislav Sedov 820*ae771770SStanislav Sedov /** 821*ae771770SStanislav Sedov * Create SQLITE object, and creates the on disk database if its doesn't exists. 822*ae771770SStanislav Sedov * 823*ae771770SStanislav Sedov * @param context A Kerberos 5 context. 824*ae771770SStanislav Sedov * @param db a returned database handle. 825*ae771770SStanislav Sedov * @param argument filename 826*ae771770SStanislav Sedov * 827*ae771770SStanislav Sedov * @return 0 on success, an error code if not 828*ae771770SStanislav Sedov */ 829*ae771770SStanislav Sedov 830*ae771770SStanislav Sedov krb5_error_code 831*ae771770SStanislav Sedov hdb_sqlite_create(krb5_context context, HDB **db, const char *argument) 832*ae771770SStanislav Sedov { 833*ae771770SStanislav Sedov krb5_error_code ret; 834*ae771770SStanislav Sedov hdb_sqlite_db *hsdb; 835*ae771770SStanislav Sedov 836*ae771770SStanislav Sedov *db = calloc(1, sizeof (**db)); 837*ae771770SStanislav Sedov if (*db == NULL) 838*ae771770SStanislav Sedov return krb5_enomem(context); 839*ae771770SStanislav Sedov 840*ae771770SStanislav Sedov hsdb = (hdb_sqlite_db*) calloc(1, sizeof (*hsdb)); 841*ae771770SStanislav Sedov if (hsdb == NULL) { 842*ae771770SStanislav Sedov free(*db); 843*ae771770SStanislav Sedov *db = NULL; 844*ae771770SStanislav Sedov return krb5_enomem(context); 845*ae771770SStanislav Sedov } 846*ae771770SStanislav Sedov 847*ae771770SStanislav Sedov (*db)->hdb_db = hsdb; 848*ae771770SStanislav Sedov 849*ae771770SStanislav Sedov /* XXX make_database should make sure everything else is freed on error */ 850*ae771770SStanislav Sedov ret = hdb_sqlite_make_database(context, *db, argument); 851*ae771770SStanislav Sedov if (ret) { 852*ae771770SStanislav Sedov free((*db)->hdb_db); 853*ae771770SStanislav Sedov free(*db); 854*ae771770SStanislav Sedov 855*ae771770SStanislav Sedov return ret; 856*ae771770SStanislav Sedov } 857*ae771770SStanislav Sedov 858*ae771770SStanislav Sedov (*db)->hdb_master_key_set = 0; 859*ae771770SStanislav Sedov (*db)->hdb_openp = 0; 860*ae771770SStanislav Sedov (*db)->hdb_capability_flags = 0; 861*ae771770SStanislav Sedov 862*ae771770SStanislav Sedov (*db)->hdb_open = hdb_sqlite_open; 863*ae771770SStanislav Sedov (*db)->hdb_close = hdb_sqlite_close; 864*ae771770SStanislav Sedov 865*ae771770SStanislav Sedov (*db)->hdb_lock = hdb_sqlite_lock; 866*ae771770SStanislav Sedov (*db)->hdb_unlock = hdb_sqlite_unlock; 867*ae771770SStanislav Sedov (*db)->hdb_firstkey = hdb_sqlite_firstkey; 868*ae771770SStanislav Sedov (*db)->hdb_nextkey = hdb_sqlite_nextkey; 869*ae771770SStanislav Sedov (*db)->hdb_fetch_kvno = hdb_sqlite_fetch_kvno; 870*ae771770SStanislav Sedov (*db)->hdb_store = hdb_sqlite_store; 871*ae771770SStanislav Sedov (*db)->hdb_remove = hdb_sqlite_remove; 872*ae771770SStanislav Sedov (*db)->hdb_destroy = hdb_sqlite_destroy; 873*ae771770SStanislav Sedov (*db)->hdb_rename = hdb_sqlite_rename; 874*ae771770SStanislav Sedov (*db)->hdb__get = NULL; 875*ae771770SStanislav Sedov (*db)->hdb__put = NULL; 876*ae771770SStanislav Sedov (*db)->hdb__del = NULL; 877*ae771770SStanislav Sedov 878*ae771770SStanislav Sedov return 0; 879*ae771770SStanislav Sedov } 880