s4:torture: Adapt KDC canon test to Heimdal upstream changes
[Samba.git] / source4 / heimdal / lib / hdb / hdb-sqlite.c
blob3cab9178965ed08a6f34f8f1452979782dfa0033
1 /*
2 * Copyright (c) 2009 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #include "hdb_locl.h"
35 #include "sqlite3.h"
37 #define MAX_RETRIES 10
39 typedef struct hdb_sqlite_db {
40 double version;
41 sqlite3 *db;
42 char *db_file;
44 sqlite3_stmt *connect;
45 sqlite3_stmt *get_version;
46 sqlite3_stmt *fetch;
47 sqlite3_stmt *get_ids;
48 sqlite3_stmt *add_entry;
49 sqlite3_stmt *add_principal;
50 sqlite3_stmt *add_alias;
51 sqlite3_stmt *delete_aliases;
52 sqlite3_stmt *update_entry;
53 sqlite3_stmt *remove;
54 sqlite3_stmt *get_all_entries;
56 } hdb_sqlite_db;
58 /* This should be used to mark updates which make the code incompatible
59 * with databases created with previous versions. Don't update it if
60 * compatibility is not broken. */
61 #define HDBSQLITE_VERSION 0.1
63 #define _HDBSQLITE_STRINGIFY(x) #x
64 #define HDBSQLITE_STRINGIFY(x) _HDBSQLITE_STRINGIFY(x)
66 #define HDBSQLITE_CREATE_TABLES \
67 " BEGIN TRANSACTION;" \
68 " CREATE TABLE Version (number REAL);" \
69 " INSERT INTO Version (number)" \
70 " VALUES (" HDBSQLITE_STRINGIFY(HDBSQLITE_VERSION) ");" \
71 " CREATE TABLE Principal" \
72 " (id INTEGER PRIMARY KEY," \
73 " principal TEXT UNIQUE NOT NULL," \
74 " canonical INTEGER," \
75 " entry INTEGER);" \
76 " CREATE TABLE Entry" \
77 " (id INTEGER PRIMARY KEY," \
78 " data BLOB);" \
79 " COMMIT"
80 #define HDBSQLITE_CREATE_TRIGGERS \
81 " CREATE TRIGGER remove_principals AFTER DELETE ON Entry" \
82 " BEGIN" \
83 " DELETE FROM Principal" \
84 " WHERE entry = OLD.id;" \
85 " END"
86 #define HDBSQLITE_CONNECT \
87 " PRAGMA journal_mode = WAL"
88 #define HDBSQLITE_GET_VERSION \
89 " SELECT number FROM Version"
90 #define HDBSQLITE_FETCH \
91 " SELECT Entry.data FROM Principal, Entry" \
92 " WHERE Principal.principal = ? AND" \
93 " Entry.id = Principal.entry"
94 #define HDBSQLITE_GET_IDS \
95 " SELECT id, entry FROM Principal" \
96 " WHERE principal = ?"
97 #define HDBSQLITE_ADD_ENTRY \
98 " INSERT INTO Entry (data) VALUES (?)"
99 #define HDBSQLITE_ADD_PRINCIPAL \
100 " INSERT INTO Principal (principal, entry, canonical)" \
101 " VALUES (?, last_insert_rowid(), 1)"
102 #define HDBSQLITE_ADD_ALIAS \
103 " INSERT INTO Principal (principal, entry, canonical)" \
104 " VALUES(?, ?, 0)"
105 #define HDBSQLITE_DELETE_ALIASES \
106 " DELETE FROM Principal" \
107 " WHERE entry = ? AND canonical = 0"
108 #define HDBSQLITE_UPDATE_ENTRY \
109 " UPDATE Entry SET data = ?" \
110 " WHERE id = ?"
111 #define HDBSQLITE_REMOVE \
112 " DELETE FROM ENTRY WHERE id = " \
113 " (SELECT entry FROM Principal" \
114 " WHERE principal = ?)"
115 #define HDBSQLITE_GET_ALL_ENTRIES \
116 " SELECT data FROM Entry"
119 * Wrapper around sqlite3_prepare_v2.
121 * @param context The current krb5 context
122 * @param statement Where to store the pointer to the statement
123 * after preparing it
124 * @param str SQL code for the statement
126 * @return 0 if OK, an error code if not
128 static krb5_error_code
129 hdb_sqlite_prepare_stmt(krb5_context context,
130 sqlite3 *db,
131 sqlite3_stmt **statement,
132 const char *str)
134 int ret, tries = 0;
136 ret = sqlite3_prepare_v2(db, str, -1, statement, NULL);
137 while((tries++ < MAX_RETRIES) &&
138 ((ret == SQLITE_BUSY) ||
139 (ret == SQLITE_IOERR_BLOCKED) ||
140 (ret == SQLITE_LOCKED))) {
141 krb5_warnx(context, "hdb-sqlite: prepare busy");
142 sleep(1);
143 ret = sqlite3_prepare_v2(db, str, -1, statement, NULL);
146 if (ret != SQLITE_OK) {
147 krb5_set_error_message(context, HDB_ERR_UK_RERROR,
148 "Failed to prepare stmt %s: %s",
149 str, sqlite3_errmsg(db));
150 return HDB_ERR_UK_RERROR;
153 return 0;
156 static krb5_error_code
157 prep_stmts(krb5_context context, hdb_sqlite_db *hsdb)
159 int ret;
161 ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
162 &hsdb->connect,
163 HDBSQLITE_CONNECT);
164 if (ret)
165 return ret;
166 ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
167 &hsdb->get_version,
168 HDBSQLITE_GET_VERSION);
169 if (ret)
170 return ret;
171 ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
172 &hsdb->fetch,
173 HDBSQLITE_FETCH);
174 if (ret)
175 return ret;
176 ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
177 &hsdb->get_ids,
178 HDBSQLITE_GET_IDS);
179 if (ret)
180 return ret;
181 ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
182 &hsdb->add_entry,
183 HDBSQLITE_ADD_ENTRY);
184 if (ret)
185 return ret;
186 ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
187 &hsdb->add_principal,
188 HDBSQLITE_ADD_PRINCIPAL);
189 if (ret)
190 return ret;
191 ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
192 &hsdb->add_alias,
193 HDBSQLITE_ADD_ALIAS);
194 if (ret)
195 return ret;
196 ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
197 &hsdb->delete_aliases,
198 HDBSQLITE_DELETE_ALIASES);
199 if (ret)
200 return ret;
201 ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
202 &hsdb->update_entry,
203 HDBSQLITE_UPDATE_ENTRY);
204 if (ret)
205 return ret;
206 ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
207 &hsdb->remove,
208 HDBSQLITE_REMOVE);
209 if (ret)
210 return ret;
211 ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
212 &hsdb->get_all_entries,
213 HDBSQLITE_GET_ALL_ENTRIES);
214 return ret;
217 static void
218 finalize_stmts(krb5_context context, hdb_sqlite_db *hsdb)
220 if (hsdb->connect != NULL)
221 sqlite3_finalize(hsdb->connect);
222 hsdb->connect = NULL;
224 if (hsdb->get_version != NULL)
225 sqlite3_finalize(hsdb->get_version);
226 hsdb->get_version = NULL;
228 if (hsdb->fetch != NULL)
229 sqlite3_finalize(hsdb->fetch);
230 hsdb->fetch = NULL;
232 if (hsdb->get_ids != NULL)
233 sqlite3_finalize(hsdb->get_ids);
234 hsdb->get_ids = NULL;
236 if (hsdb->add_entry != NULL)
237 sqlite3_finalize(hsdb->add_entry);
238 hsdb->add_entry = NULL;
240 if (hsdb->add_principal != NULL)
241 sqlite3_finalize(hsdb->add_principal);
242 hsdb->add_principal = NULL;
244 if (hsdb->add_alias != NULL)
245 sqlite3_finalize(hsdb->add_alias);
246 hsdb->add_alias = NULL;
248 if (hsdb->delete_aliases != NULL)
249 sqlite3_finalize(hsdb->delete_aliases);
250 hsdb->delete_aliases = NULL;
252 if (hsdb->update_entry != NULL)
253 sqlite3_finalize(hsdb->update_entry);
254 hsdb->update_entry = NULL;
256 if (hsdb->remove != NULL)
257 sqlite3_finalize(hsdb->remove);
258 hsdb->remove = NULL;
260 if (hsdb->get_all_entries != NULL)
261 sqlite3_finalize(hsdb->get_all_entries);
262 hsdb->get_all_entries = NULL;
266 * A wrapper around sqlite3_exec.
268 * @param context The current krb5 context
269 * @param database An open sqlite3 database handle
270 * @param statement SQL code to execute
271 * @param error_code What to return if the statement fails
273 * @return 0 if OK, else error_code
275 static krb5_error_code
276 hdb_sqlite_exec_stmt(krb5_context context,
277 hdb_sqlite_db *hsdb,
278 const char *statement,
279 krb5_error_code error_code)
281 int ret;
282 int reinit_stmts = 0;
283 sqlite3 *database = hsdb->db;
285 ret = sqlite3_exec(database, statement, NULL, NULL, NULL);
287 while(((ret == SQLITE_BUSY) ||
288 (ret == SQLITE_IOERR_BLOCKED) ||
289 (ret == SQLITE_LOCKED))) {
290 if (reinit_stmts == 0 && ret == SQLITE_BUSY) {
291 finalize_stmts(context, hsdb);
292 reinit_stmts = 1;
294 krb5_warnx(context, "hdb-sqlite: exec busy: %d", (int)getpid());
295 sleep(1);
296 ret = sqlite3_exec(database, statement, NULL, NULL, NULL);
299 if (ret != SQLITE_OK && error_code) {
300 krb5_set_error_message(context, error_code,
301 "Execute %s: %s", statement,
302 sqlite3_errmsg(database));
303 return error_code;
306 if (reinit_stmts)
307 return prep_stmts(context, hsdb);
309 return 0;
316 static krb5_error_code
317 bind_principal(krb5_context context, krb5_const_principal principal, sqlite3_stmt *stmt, int key)
319 krb5_error_code ret;
320 char *str = NULL;
322 ret = krb5_unparse_name(context, principal, &str);
323 if (ret)
324 return ret;
326 sqlite3_bind_text(stmt, key, str, -1, SQLITE_TRANSIENT);
327 free(str);
328 return 0;
331 static int hdb_sqlite_step(krb5_context, sqlite3 *, sqlite3_stmt *);
334 * Opens an sqlite3 database handle to a file, may create the
335 * database file depending on flags.
337 * @param context The current krb5 context
338 * @param db Heimdal database handle
339 * @param flags Controls whether or not the file may be created,
340 * may be 0 or SQLITE_OPEN_CREATE
342 static krb5_error_code
343 hdb_sqlite_open_database(krb5_context context, HDB *db, int flags)
345 int ret;
346 hdb_sqlite_db *hsdb = (hdb_sqlite_db*) db->hdb_db;
348 ret = sqlite3_open_v2(hsdb->db_file, &hsdb->db,
349 SQLITE_OPEN_READWRITE | flags, NULL);
351 if (ret) {
352 if (hsdb->db) {
353 ret = ENOENT;
354 krb5_set_error_message(context, ret,
355 "Error opening sqlite database %s: %s",
356 hsdb->db_file, sqlite3_errmsg(hsdb->db));
357 sqlite3_close(hsdb->db);
358 hsdb->db = NULL;
359 } else
360 ret = krb5_enomem(context);
361 return ret;
363 return 0;
366 static int
367 hdb_sqlite_step(krb5_context context, sqlite3 *db, sqlite3_stmt *stmt)
369 int ret;
371 ret = sqlite3_step(stmt);
372 while(((ret == SQLITE_BUSY) ||
373 (ret == SQLITE_IOERR_BLOCKED) ||
374 (ret == SQLITE_LOCKED))) {
375 krb5_warnx(context, "hdb-sqlite: step busy: %d", (int)getpid());
376 sleep(1);
377 ret = sqlite3_step(stmt);
379 return ret;
383 * Closes the database and frees memory allocated for statements.
385 * @param context The current krb5 context
386 * @param db Heimdal database handle
388 static krb5_error_code
389 hdb_sqlite_close_database(krb5_context context, HDB *db)
391 hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db;
393 finalize_stmts(context, hsdb);
395 /* XXX Use sqlite3_close_v2() when we upgrade SQLite3 */
396 if (sqlite3_close(hsdb->db) != SQLITE_OK) {
397 krb5_set_error_message(context, HDB_ERR_UK_SERROR,
398 "SQLite BEGIN TRANSACTION failed: %s",
399 sqlite3_errmsg(hsdb->db));
400 return HDB_ERR_UK_SERROR;
403 return 0;
407 * Opens an sqlite database file and prepares it for use.
408 * If the file does not exist it will be created.
410 * @param context The current krb5_context
411 * @param db The heimdal database handle
412 * @param filename Where to store the database file
414 * @return 0 if everything worked, an error code if not
416 static krb5_error_code
417 hdb_sqlite_make_database(krb5_context context, HDB *db, const char *filename)
419 int ret;
420 int created_file = 0;
421 hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db;
423 hsdb->db_file = strdup(filename);
424 if(hsdb->db_file == NULL)
425 return ENOMEM;
427 ret = hdb_sqlite_open_database(context, db, 0);
428 if (ret) {
429 ret = hdb_sqlite_open_database(context, db, SQLITE_OPEN_CREATE);
430 if (ret) goto out;
432 created_file = 1;
434 hdb_sqlite_exec_stmt(context, hsdb,
435 "PRAGMA main.page_size = 8192",
436 HDB_ERR_UK_SERROR);
438 ret = hdb_sqlite_exec_stmt(context, hsdb,
439 HDBSQLITE_CREATE_TABLES,
440 HDB_ERR_UK_SERROR);
441 if (ret) goto out;
443 ret = hdb_sqlite_exec_stmt(context, hsdb,
444 HDBSQLITE_CREATE_TRIGGERS,
445 HDB_ERR_UK_SERROR);
446 if (ret) goto out;
449 ret = prep_stmts(context, hsdb);
450 if (ret) goto out;
452 sqlite3_reset(hsdb->connect);
453 (void) hdb_sqlite_step(context, hsdb->db, hsdb->connect);
454 sqlite3_reset(hsdb->connect);
456 ret = hdb_sqlite_step(context, hsdb->db, hsdb->get_version);
457 if(ret == SQLITE_ROW) {
458 hsdb->version = sqlite3_column_double(hsdb->get_version, 0);
460 sqlite3_reset(hsdb->get_version);
461 ret = 0;
463 if(hsdb->version != HDBSQLITE_VERSION) {
464 ret = HDB_ERR_UK_SERROR;
465 krb5_set_error_message(context, ret, "HDBSQLITE_VERSION mismatch");
468 if(ret) goto out;
470 return 0;
472 out:
473 if (hsdb->db)
474 sqlite3_close(hsdb->db);
475 if (created_file)
476 unlink(hsdb->db_file);
477 free(hsdb->db_file);
478 hsdb->db_file = NULL;
480 return ret;
484 * Retrieves an entry by searching for the given
485 * principal in the Principal database table, both
486 * for canonical principals and aliases.
488 * @param context The current krb5_context
489 * @param db Heimdal database handle
490 * @param principal The principal whose entry to search for
491 * @param flags Currently only for HDB_F_DECRYPT
492 * @param kvno kvno to fetch is HDB_F_KVNO_SPECIFIED use used
494 * @return 0 if everything worked, an error code if not
496 static krb5_error_code
497 hdb_sqlite_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal,
498 unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry)
500 int sqlite_error;
501 krb5_error_code ret;
502 hdb_sqlite_db *hsdb = (hdb_sqlite_db*)(db->hdb_db);
503 sqlite3_stmt *fetch = hsdb->fetch;
504 krb5_data value;
505 krb5_principal enterprise_principal = NULL;
507 if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
508 if (principal->name.name_string.len != 1) {
509 ret = KRB5_PARSE_MALFORMED;
510 krb5_set_error_message(context, ret, "malformed principal: "
511 "enterprise name with %d name components",
512 principal->name.name_string.len);
513 return ret;
515 ret = krb5_parse_name(context, principal->name.name_string.val[0],
516 &enterprise_principal);
517 if (ret)
518 return ret;
519 principal = enterprise_principal;
522 ret = bind_principal(context, principal, fetch, 1);
523 krb5_free_principal(context, enterprise_principal);
524 if (ret)
525 return ret;
527 sqlite_error = hdb_sqlite_step(context, hsdb->db, fetch);
528 if (sqlite_error != SQLITE_ROW) {
529 if(sqlite_error == SQLITE_DONE) {
530 ret = HDB_ERR_NOENTRY;
531 goto out;
532 } else {
533 ret = HDB_ERR_UK_RERROR;
534 krb5_set_error_message(context, ret,
535 "sqlite fetch failed: %d",
536 sqlite_error);
537 goto out;
541 value.length = sqlite3_column_bytes(fetch, 0);
542 value.data = (void *) sqlite3_column_blob(fetch, 0);
544 ret = hdb_value2entry(context, &value, &entry->entry);
545 if(ret)
546 goto out;
548 if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
549 ret = hdb_unseal_keys(context, db, &entry->entry);
550 if(ret) {
551 hdb_free_entry(context, entry);
552 goto out;
556 ret = 0;
558 out:
560 sqlite3_clear_bindings(fetch);
561 sqlite3_reset(fetch);
564 return ret;
568 * Convenience function to step a prepared statement with no
569 * value once.
571 * @param context The current krb5_context
572 * @param statement A prepared sqlite3 statement
574 * @return 0 if everything worked, an error code if not
576 static krb5_error_code
577 hdb_sqlite_step_once(krb5_context context, HDB *db, sqlite3_stmt *statement)
579 int ret;
580 hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db;
582 ret = hdb_sqlite_step(context, hsdb->db, statement);
583 sqlite3_clear_bindings(statement);
584 sqlite3_reset(statement);
586 return ret;
591 * Stores an hdb_entry in the database. If flags contains HDB_F_REPLACE
592 * a previous entry may be replaced.
594 * @param context The current krb5_context
595 * @param db Heimdal database handle
596 * @param flags May currently only contain HDB_F_REPLACE
597 * @param entry The data to store
599 * @return 0 if everything worked, an error code if not
601 static krb5_error_code
602 hdb_sqlite_store(krb5_context context, HDB *db, unsigned flags,
603 hdb_entry_ex *entry)
605 int ret;
606 int i;
607 sqlite_int64 entry_id;
608 const HDB_Ext_Aliases *aliases;
610 hdb_sqlite_db *hsdb = (hdb_sqlite_db *)(db->hdb_db);
611 krb5_data value;
612 sqlite3_stmt *get_ids = hsdb->get_ids;
614 krb5_data_zero(&value);
616 ret = hdb_sqlite_exec_stmt(context, hsdb,
617 "BEGIN IMMEDIATE TRANSACTION",
618 HDB_ERR_UK_SERROR);
619 if(ret != SQLITE_OK) {
620 ret = HDB_ERR_UK_SERROR;
621 krb5_set_error_message(context, ret,
622 "SQLite BEGIN TRANSACTION failed: %s",
623 sqlite3_errmsg(hsdb->db));
624 goto rollback;
627 ret = hdb_seal_keys(context, db, &entry->entry);
628 if(ret) {
629 goto rollback;
632 ret = hdb_entry2value(context, &entry->entry, &value);
633 if(ret) {
634 goto rollback;
637 ret = bind_principal(context, entry->entry.principal, get_ids, 1);
638 if (ret)
639 goto rollback;
641 ret = hdb_sqlite_step(context, hsdb->db, get_ids);
643 if(ret == SQLITE_DONE) { /* No such principal */
645 sqlite3_bind_blob(hsdb->add_entry, 1,
646 value.data, value.length, SQLITE_STATIC);
647 ret = hdb_sqlite_step(context, hsdb->db, hsdb->add_entry);
648 sqlite3_clear_bindings(hsdb->add_entry);
649 sqlite3_reset(hsdb->add_entry);
650 if (ret != SQLITE_DONE && ret != SQLITE_CONSTRAINT) {
651 ret = HDB_ERR_UK_SERROR;
652 goto rollback;
654 if (ret == SQLITE_CONSTRAINT) {
655 ret = HDB_ERR_EXISTS;
656 goto rollback;
659 ret = bind_principal(context, entry->entry.principal, hsdb->add_principal, 1);
660 if (ret)
661 goto rollback;
663 ret = hdb_sqlite_step(context, hsdb->db, hsdb->add_principal);
664 sqlite3_clear_bindings(hsdb->add_principal);
665 sqlite3_reset(hsdb->add_principal);
666 if (ret != SQLITE_DONE && ret != SQLITE_CONSTRAINT) {
667 ret = HDB_ERR_UK_SERROR;
668 goto rollback;
670 if (ret == SQLITE_CONSTRAINT) {
671 ret = HDB_ERR_EXISTS;
672 goto rollback;
675 /* Now let's learn what Entry ID we got for the new principal */
676 sqlite3_reset(get_ids);
677 ret = hdb_sqlite_step(context, hsdb->db, get_ids);
678 if (ret != SQLITE_ROW) {
679 ret = HDB_ERR_UK_SERROR;
680 goto rollback;
683 entry_id = sqlite3_column_int64(get_ids, 1);
685 } else if(ret == SQLITE_ROW) { /* Found a principal */
687 if(! (flags & HDB_F_REPLACE)) /* Not allowed to replace it */
688 goto rollback;
690 entry_id = sqlite3_column_int64(get_ids, 1);
692 sqlite3_bind_int64(hsdb->delete_aliases, 1, entry_id);
693 ret = hdb_sqlite_step_once(context, db, hsdb->delete_aliases);
694 if (ret != SQLITE_DONE) {
695 ret = HDB_ERR_UK_SERROR;
696 goto rollback;
699 sqlite3_bind_blob(hsdb->update_entry, 1,
700 value.data, value.length, SQLITE_STATIC);
701 sqlite3_bind_int64(hsdb->update_entry, 2, entry_id);
702 ret = hdb_sqlite_step_once(context, db, hsdb->update_entry);
703 if (ret != SQLITE_DONE) {
704 ret = HDB_ERR_UK_SERROR;
705 goto rollback;
708 } else {
709 /* Error! */
710 ret = HDB_ERR_UK_SERROR;
711 goto rollback;
714 ret = hdb_entry_get_aliases(&entry->entry, &aliases);
715 if(ret || aliases == NULL)
716 goto commit;
718 for(i = 0; i < aliases->aliases.len; i++) {
720 ret = bind_principal(context, &aliases->aliases.val[i], hsdb->add_alias, 1);
721 if (ret)
722 goto rollback;
724 sqlite3_bind_int64(hsdb->add_alias, 2, entry_id);
725 ret = hdb_sqlite_step_once(context, db, hsdb->add_alias);
726 if (ret == SQLITE_CONSTRAINT) {
727 ret = HDB_ERR_EXISTS;
728 goto rollback;
730 if (ret != SQLITE_DONE) {
731 ret = HDB_ERR_UK_SERROR;
732 goto rollback;
736 commit:
737 krb5_data_free(&value);
738 sqlite3_clear_bindings(get_ids);
739 sqlite3_reset(get_ids);
741 if ((flags & HDB_F_PRECHECK)) {
742 (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0);
743 return 0;
746 ret = hdb_sqlite_exec_stmt(context, hsdb, "COMMIT", HDB_ERR_UK_SERROR);
747 if(ret != SQLITE_OK)
748 krb5_warnx(context, "hdb-sqlite: COMMIT problem: %ld: %s",
749 (long)HDB_ERR_UK_SERROR, sqlite3_errmsg(hsdb->db));
751 return ret == SQLITE_OK ? 0 : HDB_ERR_UK_SERROR;
753 rollback:
754 krb5_data_free(&value);
755 sqlite3_clear_bindings(get_ids);
756 sqlite3_reset(get_ids);
757 krb5_warnx(context, "hdb-sqlite: store rollback problem: %d: %s",
758 ret, sqlite3_errmsg(hsdb->db));
760 (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0);
761 return ret;
765 * This may be called often by other code, since the BDB backends
766 * can not have several open connections. SQLite can handle
767 * many processes with open handles to the database file
768 * and closing/opening the handle is an expensive operation.
769 * Hence, this function does nothing.
771 * @param context The current krb5 context
772 * @param db Heimdal database handle
774 * @return Always returns 0
776 static krb5_error_code
777 hdb_sqlite_close(krb5_context context, HDB *db)
779 return 0;
783 * The opposite of hdb_sqlite_close. Since SQLite accepts
784 * many open handles to the database file the handle does not
785 * need to be closed, or reopened.
787 * @param context The current krb5 context
788 * @param db Heimdal database handle
789 * @param flags
790 * @param mode_t
792 * @return Always returns 0
794 static krb5_error_code
795 hdb_sqlite_open(krb5_context context, HDB *db, int flags, mode_t mode)
797 return 0;
801 * Closes the databse and frees all resources.
803 * @param context The current krb5 context
804 * @param db Heimdal database handle
806 * @return 0 on success, an error code if not
808 static krb5_error_code
809 hdb_sqlite_destroy(krb5_context context, HDB *db)
811 int ret, ret2;
812 hdb_sqlite_db *hsdb;
814 ret = hdb_clear_master_key(context, db);
816 ret2 = hdb_sqlite_close_database(context, db);
818 hsdb = (hdb_sqlite_db*)(db->hdb_db);
820 krb5_config_free_strings(db->virtual_hostbased_princ_svcs);
821 free(hsdb->db_file);
822 free(db->hdb_name);
823 free(db->hdb_db);
824 free(db);
826 return ret ? ret : ret2;
829 static krb5_error_code
830 hdb_sqlite_set_sync(krb5_context context, HDB *db, int on)
832 return hdb_sqlite_exec_stmt(context, (hdb_sqlite_db*)(db->hdb_db),
833 on ? "PRAGMA main.synchronous = NORMAL" :
834 "PRAGMA main.synchronous = OFF",
835 HDB_ERR_UK_SERROR);
839 * Not sure if this is needed.
841 static krb5_error_code
842 hdb_sqlite_lock(krb5_context context, HDB *db, int operation)
844 krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB,
845 "lock not implemented");
846 return HDB_ERR_CANT_LOCK_DB;
850 * Not sure if this is needed.
852 static krb5_error_code
853 hdb_sqlite_unlock(krb5_context context, HDB *db)
855 krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB,
856 "unlock not implemented");
857 return HDB_ERR_CANT_LOCK_DB;
861 * Should get the next entry, to allow iteration over all entries.
863 static krb5_error_code
864 hdb_sqlite_nextkey(krb5_context context, HDB *db, unsigned flags,
865 hdb_entry_ex *entry)
867 krb5_error_code ret = 0;
868 int sqlite_error;
869 krb5_data value;
871 hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db;
873 sqlite_error = hdb_sqlite_step(context, hsdb->db, hsdb->get_all_entries);
874 if(sqlite_error == SQLITE_ROW) {
875 /* Found an entry */
876 value.length = sqlite3_column_bytes(hsdb->get_all_entries, 0);
877 value.data = (void *) sqlite3_column_blob(hsdb->get_all_entries, 0);
878 memset(entry, 0, sizeof(*entry));
879 ret = hdb_value2entry(context, &value, &entry->entry);
881 else if(sqlite_error == SQLITE_DONE) {
882 /* No more entries */
883 ret = HDB_ERR_NOENTRY;
884 sqlite3_reset(hsdb->get_all_entries);
886 else {
887 ret = HDB_ERR_UK_RERROR;
888 krb5_set_error_message(context, HDB_ERR_UK_RERROR,
889 "SELECT failed after returning one or "
890 "more rows: %s", sqlite3_errmsg(hsdb->db));
894 return ret;
898 * Should get the first entry in the database.
899 * What is flags used for?
901 static krb5_error_code
902 hdb_sqlite_firstkey(krb5_context context, HDB *db, unsigned flags,
903 hdb_entry_ex *entry)
905 hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db;
906 krb5_error_code ret;
908 sqlite3_reset(hsdb->get_all_entries);
910 ret = hdb_sqlite_nextkey(context, db, flags, entry);
911 if(ret)
912 return ret;
914 return 0;
918 * Renames the database file.
920 static krb5_error_code
921 hdb_sqlite_rename(krb5_context context, HDB *db, const char *new_name)
923 krb5_error_code ret, ret2;
924 hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db;
926 krb5_warnx(context, "hdb_sqlite_rename");
928 if (strncasecmp(new_name, "sqlite:", 7) == 0)
929 new_name += 7;
931 ret = hdb_sqlite_close_database(context, db);
933 if (rename(hsdb->db_file, new_name) == -1)
934 return errno;
936 free(hsdb->db_file);
937 ret2 = hdb_sqlite_make_database(context, db, new_name);
938 return ret ? ret : ret2;
942 * Removes a principal, including aliases and associated entry.
944 static krb5_error_code
945 hdb_sqlite_remove(krb5_context context, HDB *db,
946 unsigned flags, krb5_const_principal principal)
948 krb5_error_code ret;
949 hdb_sqlite_db *hsdb = (hdb_sqlite_db*)(db->hdb_db);
950 sqlite3_stmt *get_ids = hsdb->get_ids;
951 sqlite3_stmt *rm = hsdb->remove;
953 bind_principal(context, principal, rm, 1);
955 ret = hdb_sqlite_exec_stmt(context, hsdb,
956 "BEGIN IMMEDIATE TRANSACTION",
957 HDB_ERR_UK_SERROR);
958 if (ret != SQLITE_OK) {
959 ret = HDB_ERR_UK_SERROR;
960 (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0);
961 krb5_set_error_message(context, ret,
962 "SQLite BEGIN TRANSACTION failed: %s",
963 sqlite3_errmsg(hsdb->db));
964 return ret;
967 if ((flags & HDB_F_PRECHECK)) {
968 ret = bind_principal(context, principal, get_ids, 1);
969 if (ret)
970 return ret;
972 ret = hdb_sqlite_step(context, hsdb->db, get_ids);
973 sqlite3_clear_bindings(get_ids);
974 sqlite3_reset(get_ids);
975 if (ret == SQLITE_DONE) {
976 (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0);
977 return HDB_ERR_NOENTRY;
981 ret = hdb_sqlite_step(context, hsdb->db, rm);
982 sqlite3_clear_bindings(rm);
983 sqlite3_reset(rm);
984 if (ret != SQLITE_DONE) {
985 (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0);
986 ret = HDB_ERR_UK_SERROR;
987 krb5_set_error_message(context, ret, "sqlite remove failed: %d", ret);
988 return ret;
991 if ((flags & HDB_F_PRECHECK)) {
992 (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0);
993 return 0;
996 ret = hdb_sqlite_exec_stmt(context, hsdb, "COMMIT", HDB_ERR_UK_SERROR);
997 if (ret != SQLITE_OK)
998 krb5_warnx(context, "hdb-sqlite: COMMIT problem: %ld: %s",
999 (long)HDB_ERR_UK_SERROR, sqlite3_errmsg(hsdb->db));
1001 return 0;
1005 * Create SQLITE object, and creates the on disk database if its doesn't exists.
1007 * @param context A Kerberos 5 context.
1008 * @param db a returned database handle.
1009 * @param filename filename
1011 * @return 0 on success, an error code if not
1014 krb5_error_code
1015 hdb_sqlite_create(krb5_context context, HDB **db, const char *filename)
1017 krb5_error_code ret;
1018 hdb_sqlite_db *hsdb;
1020 *db = calloc(1, sizeof (**db));
1021 if (*db == NULL)
1022 return krb5_enomem(context);
1024 (*db)->hdb_name = strdup(filename);
1025 if ((*db)->hdb_name == NULL) {
1026 free(*db);
1027 *db = NULL;
1028 return krb5_enomem(context);
1031 hsdb = (hdb_sqlite_db*) calloc(1, sizeof (*hsdb));
1032 if (hsdb == NULL) {
1033 free((*db)->hdb_name);
1034 free(*db);
1035 *db = NULL;
1036 return krb5_enomem(context);
1039 (*db)->hdb_db = hsdb;
1041 /* XXX make_database should make sure everything else is freed on error */
1042 ret = hdb_sqlite_make_database(context, *db, filename);
1043 if (ret) {
1044 free((*db)->hdb_db);
1045 free(*db);
1046 *db = NULL;
1047 return ret;
1050 (*db)->hdb_master_key_set = 0;
1051 (*db)->hdb_openp = 0;
1052 (*db)->hdb_capability_flags = HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL;
1054 (*db)->hdb_open = hdb_sqlite_open;
1055 (*db)->hdb_close = hdb_sqlite_close;
1057 (*db)->hdb_lock = hdb_sqlite_lock;
1058 (*db)->hdb_unlock = hdb_sqlite_unlock;
1059 (*db)->hdb_firstkey = hdb_sqlite_firstkey;
1060 (*db)->hdb_nextkey = hdb_sqlite_nextkey;
1061 (*db)->hdb_fetch_kvno = hdb_sqlite_fetch_kvno;
1062 (*db)->hdb_store = hdb_sqlite_store;
1063 (*db)->hdb_remove = hdb_sqlite_remove;
1064 (*db)->hdb_destroy = hdb_sqlite_destroy;
1065 (*db)->hdb_rename = hdb_sqlite_rename;
1066 (*db)->hdb_set_sync = hdb_sqlite_set_sync;
1067 (*db)->hdb__get = NULL;
1068 (*db)->hdb__put = NULL;
1069 (*db)->hdb__del = NULL;
1071 return 0;