hdb: Fix SQLite3 backend EXISTS error
[heimdal.git] / lib / hdb / hdb-sqlite.c
blob968edf4e00d7fa449674aa46ed50340bb5d1d9bc
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 *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);
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);
550 if(ret) {
551 hdb_free_entry(context, db, 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 *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);
628 if(ret) {
629 goto rollback;
632 ret = hdb_entry2value(context, entry, &value);
633 if(ret) {
634 goto rollback;
637 ret = bind_principal(context, 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->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)) {
688 ret = HDB_ERR_EXISTS;
689 goto rollback;
692 entry_id = sqlite3_column_int64(get_ids, 1);
694 sqlite3_bind_int64(hsdb->delete_aliases, 1, entry_id);
695 ret = hdb_sqlite_step_once(context, db, hsdb->delete_aliases);
696 if (ret != SQLITE_DONE) {
697 ret = HDB_ERR_UK_SERROR;
698 goto rollback;
701 sqlite3_bind_blob(hsdb->update_entry, 1,
702 value.data, value.length, SQLITE_STATIC);
703 sqlite3_bind_int64(hsdb->update_entry, 2, entry_id);
704 ret = hdb_sqlite_step_once(context, db, hsdb->update_entry);
705 if (ret != SQLITE_DONE) {
706 ret = HDB_ERR_UK_SERROR;
707 goto rollback;
710 } else {
711 /* Error! */
712 ret = HDB_ERR_UK_SERROR;
713 goto rollback;
716 ret = hdb_entry_get_aliases(entry, &aliases);
717 if(ret || aliases == NULL)
718 goto commit;
720 for(i = 0; i < aliases->aliases.len; i++) {
722 ret = bind_principal(context, &aliases->aliases.val[i], hsdb->add_alias, 1);
723 if (ret)
724 goto rollback;
726 sqlite3_bind_int64(hsdb->add_alias, 2, entry_id);
727 ret = hdb_sqlite_step_once(context, db, hsdb->add_alias);
728 if (ret == SQLITE_CONSTRAINT) {
729 ret = HDB_ERR_EXISTS;
730 goto rollback;
732 if (ret != SQLITE_DONE) {
733 ret = HDB_ERR_UK_SERROR;
734 goto rollback;
738 commit:
739 krb5_data_free(&value);
740 sqlite3_clear_bindings(get_ids);
741 sqlite3_reset(get_ids);
743 if ((flags & HDB_F_PRECHECK)) {
744 (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0);
745 return 0;
748 ret = hdb_sqlite_exec_stmt(context, hsdb, "COMMIT", HDB_ERR_UK_SERROR);
749 if(ret != SQLITE_OK)
750 krb5_warnx(context, "hdb-sqlite: COMMIT problem: %ld: %s",
751 (long)HDB_ERR_UK_SERROR, sqlite3_errmsg(hsdb->db));
753 return ret == SQLITE_OK ? 0 : HDB_ERR_UK_SERROR;
755 rollback:
756 krb5_data_free(&value);
757 sqlite3_clear_bindings(get_ids);
758 sqlite3_reset(get_ids);
759 krb5_warnx(context, "hdb-sqlite: store rollback problem: %d: %s",
760 ret, sqlite3_errmsg(hsdb->db));
762 (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0);
763 return ret;
767 * This may be called often by other code, since the BDB backends
768 * can not have several open connections. SQLite can handle
769 * many processes with open handles to the database file
770 * and closing/opening the handle is an expensive operation.
771 * Hence, this function does nothing.
773 * @param context The current krb5 context
774 * @param db Heimdal database handle
776 * @return Always returns 0
778 static krb5_error_code
779 hdb_sqlite_close(krb5_context context, HDB *db)
781 return 0;
785 * The opposite of hdb_sqlite_close. Since SQLite accepts
786 * many open handles to the database file the handle does not
787 * need to be closed, or reopened.
789 * @param context The current krb5 context
790 * @param db Heimdal database handle
791 * @param flags
792 * @param mode_t
794 * @return Always returns 0
796 static krb5_error_code
797 hdb_sqlite_open(krb5_context context, HDB *db, int flags, mode_t mode)
799 return 0;
803 * Closes the databse and frees all resources.
805 * @param context The current krb5 context
806 * @param db Heimdal database handle
808 * @return 0 on success, an error code if not
810 static krb5_error_code
811 hdb_sqlite_destroy(krb5_context context, HDB *db)
813 int ret, ret2;
814 hdb_sqlite_db *hsdb;
816 ret = hdb_clear_master_key(context, db);
818 ret2 = hdb_sqlite_close_database(context, db);
820 hsdb = (hdb_sqlite_db*)(db->hdb_db);
822 krb5_config_free_strings(db->virtual_hostbased_princ_svcs);
823 free(hsdb->db_file);
824 free(db->hdb_name);
825 free(db->hdb_db);
826 free(db);
828 return ret ? ret : ret2;
831 static krb5_error_code
832 hdb_sqlite_set_sync(krb5_context context, HDB *db, int on)
834 return hdb_sqlite_exec_stmt(context, (hdb_sqlite_db*)(db->hdb_db),
835 on ? "PRAGMA main.synchronous = NORMAL" :
836 "PRAGMA main.synchronous = OFF",
837 HDB_ERR_UK_SERROR);
841 * Not sure if this is needed.
843 static krb5_error_code
844 hdb_sqlite_lock(krb5_context context, HDB *db, int operation)
846 krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB,
847 "lock not implemented");
848 return HDB_ERR_CANT_LOCK_DB;
852 * Not sure if this is needed.
854 static krb5_error_code
855 hdb_sqlite_unlock(krb5_context context, HDB *db)
857 krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB,
858 "unlock not implemented");
859 return HDB_ERR_CANT_LOCK_DB;
863 * Should get the next entry, to allow iteration over all entries.
865 static krb5_error_code
866 hdb_sqlite_nextkey(krb5_context context, HDB *db, unsigned flags,
867 hdb_entry *entry)
869 krb5_error_code ret = 0;
870 int sqlite_error;
871 krb5_data value;
873 hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db;
875 sqlite_error = hdb_sqlite_step(context, hsdb->db, hsdb->get_all_entries);
876 if(sqlite_error == SQLITE_ROW) {
877 /* Found an entry */
878 value.length = sqlite3_column_bytes(hsdb->get_all_entries, 0);
879 value.data = (void *) sqlite3_column_blob(hsdb->get_all_entries, 0);
880 memset(entry, 0, sizeof(*entry));
881 ret = hdb_value2entry(context, &value, entry);
883 else if(sqlite_error == SQLITE_DONE) {
884 /* No more entries */
885 ret = HDB_ERR_NOENTRY;
886 sqlite3_reset(hsdb->get_all_entries);
888 else {
889 ret = HDB_ERR_UK_RERROR;
890 krb5_set_error_message(context, HDB_ERR_UK_RERROR,
891 "SELECT failed after returning one or "
892 "more rows: %s", sqlite3_errmsg(hsdb->db));
896 return ret;
900 * Should get the first entry in the database.
901 * What is flags used for?
903 static krb5_error_code
904 hdb_sqlite_firstkey(krb5_context context, HDB *db, unsigned flags,
905 hdb_entry *entry)
907 hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db;
908 krb5_error_code ret;
910 sqlite3_reset(hsdb->get_all_entries);
912 ret = hdb_sqlite_nextkey(context, db, flags, entry);
913 if(ret)
914 return ret;
916 return 0;
920 * Renames the database file.
922 static krb5_error_code
923 hdb_sqlite_rename(krb5_context context, HDB *db, const char *new_name)
925 krb5_error_code ret, ret2;
926 hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db;
928 krb5_warnx(context, "hdb_sqlite_rename");
930 if (strncasecmp(new_name, "sqlite:", 7) == 0)
931 new_name += 7;
933 ret = hdb_sqlite_close_database(context, db);
935 if (rename(hsdb->db_file, new_name) == -1)
936 return errno;
938 free(hsdb->db_file);
939 ret2 = hdb_sqlite_make_database(context, db, new_name);
940 return ret ? ret : ret2;
944 * Removes a principal, including aliases and associated entry.
946 static krb5_error_code
947 hdb_sqlite_remove(krb5_context context, HDB *db,
948 unsigned flags, krb5_const_principal principal)
950 krb5_error_code ret;
951 hdb_sqlite_db *hsdb = (hdb_sqlite_db*)(db->hdb_db);
952 sqlite3_stmt *get_ids = hsdb->get_ids;
953 sqlite3_stmt *rm = hsdb->remove;
955 bind_principal(context, principal, rm, 1);
957 ret = hdb_sqlite_exec_stmt(context, hsdb,
958 "BEGIN IMMEDIATE TRANSACTION",
959 HDB_ERR_UK_SERROR);
960 if (ret != SQLITE_OK) {
961 ret = HDB_ERR_UK_SERROR;
962 (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0);
963 krb5_set_error_message(context, ret,
964 "SQLite BEGIN TRANSACTION failed: %s",
965 sqlite3_errmsg(hsdb->db));
966 return ret;
969 if ((flags & HDB_F_PRECHECK)) {
970 ret = bind_principal(context, principal, get_ids, 1);
971 if (ret)
972 return ret;
974 ret = hdb_sqlite_step(context, hsdb->db, get_ids);
975 sqlite3_clear_bindings(get_ids);
976 sqlite3_reset(get_ids);
977 if (ret == SQLITE_DONE) {
978 (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0);
979 return HDB_ERR_NOENTRY;
983 ret = hdb_sqlite_step(context, hsdb->db, rm);
984 sqlite3_clear_bindings(rm);
985 sqlite3_reset(rm);
986 if (ret != SQLITE_DONE) {
987 (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0);
988 ret = HDB_ERR_UK_SERROR;
989 krb5_set_error_message(context, ret, "sqlite remove failed: %d", ret);
990 return ret;
993 if ((flags & HDB_F_PRECHECK)) {
994 (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0);
995 return 0;
998 ret = hdb_sqlite_exec_stmt(context, hsdb, "COMMIT", HDB_ERR_UK_SERROR);
999 if (ret != SQLITE_OK)
1000 krb5_warnx(context, "hdb-sqlite: COMMIT problem: %ld: %s",
1001 (long)HDB_ERR_UK_SERROR, sqlite3_errmsg(hsdb->db));
1003 return 0;
1007 * Create SQLITE object, and creates the on disk database if its doesn't exists.
1009 * @param context A Kerberos 5 context.
1010 * @param db a returned database handle.
1011 * @param filename filename
1013 * @return 0 on success, an error code if not
1016 krb5_error_code
1017 hdb_sqlite_create(krb5_context context, HDB **db, const char *filename)
1019 krb5_error_code ret;
1020 hdb_sqlite_db *hsdb;
1022 *db = calloc(1, sizeof (**db));
1023 if (*db == NULL)
1024 return krb5_enomem(context);
1026 (*db)->hdb_name = strdup(filename);
1027 if ((*db)->hdb_name == NULL) {
1028 free(*db);
1029 *db = NULL;
1030 return krb5_enomem(context);
1033 hsdb = (hdb_sqlite_db*) calloc(1, sizeof (*hsdb));
1034 if (hsdb == NULL) {
1035 free((*db)->hdb_name);
1036 free(*db);
1037 *db = NULL;
1038 return krb5_enomem(context);
1041 (*db)->hdb_db = hsdb;
1043 /* XXX make_database should make sure everything else is freed on error */
1044 ret = hdb_sqlite_make_database(context, *db, filename);
1045 if (ret) {
1046 free((*db)->hdb_db);
1047 free(*db);
1048 *db = NULL;
1049 return ret;
1052 (*db)->hdb_master_key_set = 0;
1053 (*db)->hdb_openp = 0;
1054 (*db)->hdb_capability_flags = HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL;
1056 (*db)->hdb_open = hdb_sqlite_open;
1057 (*db)->hdb_close = hdb_sqlite_close;
1059 (*db)->hdb_lock = hdb_sqlite_lock;
1060 (*db)->hdb_unlock = hdb_sqlite_unlock;
1061 (*db)->hdb_firstkey = hdb_sqlite_firstkey;
1062 (*db)->hdb_nextkey = hdb_sqlite_nextkey;
1063 (*db)->hdb_fetch_kvno = hdb_sqlite_fetch_kvno;
1064 (*db)->hdb_store = hdb_sqlite_store;
1065 (*db)->hdb_remove = hdb_sqlite_remove;
1066 (*db)->hdb_destroy = hdb_sqlite_destroy;
1067 (*db)->hdb_rename = hdb_sqlite_rename;
1068 (*db)->hdb_set_sync = hdb_sqlite_set_sync;
1069 (*db)->hdb__get = NULL;
1070 (*db)->hdb__put = NULL;
1071 (*db)->hdb__del = NULL;
1073 return 0;