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