1 /*	$NetBSD: hdb-sqlite.c,v 1.1.1.1 2011/04/13 18:14:42 elric 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 
41 typedef 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  */
127 static krb5_error_code
128 hdb_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, EINVAL,
147 			       "Failed to prepare stmt %s: %s",
148 			       str, sqlite3_errmsg(db));
149         return EINVAL;
150     }
151 
152     return 0;
153 }
154 
155 /**
156  * A wrapper around sqlite3_exec.
157  *
158  * @param context    The current krb5 context
159  * @param database   An open sqlite3 database handle
160  * @param statement  SQL code to execute
161  * @param error_code What to return if the statement fails
162  *
163  * @return           0 if OK, else error_code
164  */
165 static krb5_error_code
166 hdb_sqlite_exec_stmt(krb5_context context,
167                      sqlite3 *database,
168                      const char *statement,
169                      krb5_error_code error_code)
170 {
171     int ret;
172 
173     ret = sqlite3_exec(database, statement, NULL, NULL, NULL);
174 
175     while(((ret == SQLITE_BUSY) ||
176            (ret == SQLITE_IOERR_BLOCKED) ||
177            (ret == SQLITE_LOCKED))) {
178 	krb5_warnx(context, "hdb-sqlite: exec busy: %d", (int)getpid());
179         sleep(1);
180         ret = sqlite3_exec(database, statement, NULL, NULL, NULL);
181     }
182 
183     if (ret != SQLITE_OK && error_code) {
184         krb5_set_error_message(context, error_code,
185 			       "Execute %s: %s", statement,
186                               sqlite3_errmsg(database));
187         return error_code;
188     }
189 
190     return 0;
191 }
192 
193 /**
194  * Opens an sqlite3 database handle to a file, may create the
195  * database file depending on flags.
196  *
197  * @param context The current krb5 context
198  * @param db      Heimdal database handle
199  * @param flags   Controls whether or not the file may be created,
200  *                may be 0 or SQLITE_OPEN_CREATE
201  */
202 static krb5_error_code
203 hdb_sqlite_open_database(krb5_context context, HDB *db, int flags)
204 {
205     int ret;
206     hdb_sqlite_db *hsdb = (hdb_sqlite_db*) db->hdb_db;
207 
208     ret = sqlite3_open_v2(hsdb->db_file, &hsdb->db,
209                           SQLITE_OPEN_READWRITE | flags, NULL);
210 
211     if (ret) {
212         if (hsdb->db) {
213 	    ret = ENOENT;
214             krb5_set_error_message(context, ret,
215                                   "Error opening sqlite database %s: %s",
216                                   hsdb->db_file, sqlite3_errmsg(hsdb->db));
217             sqlite3_close(hsdb->db);
218             hsdb->db = NULL;
219         } else
220 	    ret = krb5_enomem(context);
221         return ret;
222     }
223 
224     return 0;
225 }
226 
227 static int
228 hdb_sqlite_step(krb5_context context, sqlite3 *db, sqlite3_stmt *stmt)
229 {
230     int ret;
231 
232     ret = sqlite3_step(stmt);
233     while(((ret == SQLITE_BUSY) ||
234            (ret == SQLITE_IOERR_BLOCKED) ||
235            (ret == SQLITE_LOCKED))) {
236 	krb5_warnx(context, "hdb-sqlite: step busy: %d", (int)getpid());
237         sleep(1);
238         ret = sqlite3_step(stmt);
239     }
240     return ret;
241 }
242 
243 /**
244  * Closes the database and frees memory allocated for statements.
245  *
246  * @param context The current krb5 context
247  * @param db      Heimdal database handle
248  */
249 static krb5_error_code
250 hdb_sqlite_close_database(krb5_context context, HDB *db)
251 {
252     hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db;
253 
254     sqlite3_finalize(hsdb->get_version);
255     sqlite3_finalize(hsdb->fetch);
256     sqlite3_finalize(hsdb->get_ids);
257     sqlite3_finalize(hsdb->add_entry);
258     sqlite3_finalize(hsdb->add_principal);
259     sqlite3_finalize(hsdb->add_alias);
260     sqlite3_finalize(hsdb->delete_aliases);
261     sqlite3_finalize(hsdb->update_entry);
262     sqlite3_finalize(hsdb->remove);
263     sqlite3_finalize(hsdb->get_all_entries);
264 
265     sqlite3_close(hsdb->db);
266 
267     return 0;
268 }
269 
270 /**
271  * Opens an sqlite database file and prepares it for use.
272  * If the file does not exist it will be created.
273  *
274  * @param context  The current krb5_context
275  * @param db       The heimdal database handle
276  * @param filename Where to store the database file
277  *
278  * @return         0 if everything worked, an error code if not
279  */
280 static krb5_error_code
281 hdb_sqlite_make_database(krb5_context context, HDB *db, const char *filename)
282 {
283     int ret;
284     int created_file = 0;
285     hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db;
286 
287     hsdb->db_file = strdup(filename);
288     if(hsdb->db_file == NULL)
289         return ENOMEM;
290 
291     ret = hdb_sqlite_open_database(context, db, 0);
292     if (ret) {
293         ret = hdb_sqlite_open_database(context, db, SQLITE_OPEN_CREATE);
294         if (ret) goto out;
295 
296         created_file = 1;
297 
298         ret = hdb_sqlite_exec_stmt(context, hsdb->db,
299                                    HDBSQLITE_CREATE_TABLES,
300                                    EINVAL);
301         if (ret) goto out;
302 
303         ret = hdb_sqlite_exec_stmt(context, hsdb->db,
304                                    HDBSQLITE_CREATE_TRIGGERS,
305                                    EINVAL);
306         if (ret) goto out;
307     }
308 
309     ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
310                                   &hsdb->get_version,
311                                   HDBSQLITE_GET_VERSION);
312     if (ret) goto out;
313     ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
314                                   &hsdb->fetch,
315                                   HDBSQLITE_FETCH);
316     if (ret) goto out;
317     ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
318                                   &hsdb->get_ids,
319                                   HDBSQLITE_GET_IDS);
320     if (ret) goto out;
321     ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
322                                   &hsdb->add_entry,
323                                   HDBSQLITE_ADD_ENTRY);
324     if (ret) goto out;
325     ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
326                                   &hsdb->add_principal,
327                                   HDBSQLITE_ADD_PRINCIPAL);
328     if (ret) goto out;
329     ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
330                                   &hsdb->add_alias,
331                                   HDBSQLITE_ADD_ALIAS);
332     if (ret) goto out;
333     ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
334                                   &hsdb->delete_aliases,
335                                   HDBSQLITE_DELETE_ALIASES);
336     if (ret) goto out;
337     ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
338                                   &hsdb->update_entry,
339                                   HDBSQLITE_UPDATE_ENTRY);
340     if (ret) goto out;
341     ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
342                                   &hsdb->remove,
343                                   HDBSQLITE_REMOVE);
344     if (ret) goto out;
345     ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
346                                   &hsdb->get_all_entries,
347                                   HDBSQLITE_GET_ALL_ENTRIES);
348     if (ret) goto out;
349 
350     ret = hdb_sqlite_step(context, hsdb->db, hsdb->get_version);
351     if(ret == SQLITE_ROW) {
352         hsdb->version = sqlite3_column_double(hsdb->get_version, 0);
353     }
354     sqlite3_reset(hsdb->get_version);
355     ret = 0;
356 
357     if(hsdb->version != HDBSQLITE_VERSION) {
358         ret = EINVAL;
359         krb5_set_error_message(context, ret, "HDBSQLITE_VERSION mismatch");
360     }
361 
362     if(ret) goto out;
363 
364     return 0;
365 
366  out:
367     if (hsdb->db)
368         sqlite3_close(hsdb->db);
369     if (created_file)
370         unlink(hsdb->db_file);
371 
372     return ret;
373 }
374 
375 /**
376  * Retrieves an entry by searching for the given
377  * principal in the Principal database table, both
378  * for canonical principals and aliases.
379  *
380  * @param context   The current krb5_context
381  * @param db        Heimdal database handle
382  * @param principal The principal whose entry to search for
383  * @param flags     Currently only for HDB_F_DECRYPT
384  * @param kvno	    kvno to fetch is HDB_F_KVNO_SPECIFIED use used
385  *
386  * @return          0 if everything worked, an error code if not
387  */
388 static krb5_error_code
389 hdb_sqlite_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal,
390 		      unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry)
391 {
392     int sqlite_error;
393     krb5_error_code ret;
394     char *principal_string;
395     hdb_sqlite_db *hsdb = (hdb_sqlite_db*)(db->hdb_db);
396     sqlite3_stmt *fetch = hsdb->fetch;
397     krb5_data value;
398 
399     ret = krb5_unparse_name(context, principal, &principal_string);
400     if (ret) {
401         free(principal_string);
402         return ret;
403     }
404 
405     sqlite3_bind_text(fetch, 1, principal_string, -1, SQLITE_STATIC);
406 
407     sqlite_error = hdb_sqlite_step(context, hsdb->db, fetch);
408     if (sqlite_error != SQLITE_ROW) {
409         if(sqlite_error == SQLITE_DONE) {
410             ret = HDB_ERR_NOENTRY;
411             goto out;
412         } else {
413             ret = EINVAL;
414             krb5_set_error_message(context, ret,
415                                   "sqlite fetch failed: %d",
416                                   sqlite_error);
417             goto out;
418         }
419     }
420 
421     if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
422         ret = hdb_unseal_keys(context, db, &entry->entry);
423         if(ret) {
424            hdb_free_entry(context, entry);
425            goto out;
426         }
427     }
428 
429     value.length = sqlite3_column_bytes(fetch, 0);
430     value.data = (void *) sqlite3_column_blob(fetch, 0);
431 
432     ret = hdb_value2entry(context, &value, &entry->entry);
433     if(ret)
434         goto out;
435 
436     ret = 0;
437 
438 out:
439 
440     sqlite3_clear_bindings(fetch);
441     sqlite3_reset(fetch);
442 
443     free(principal_string);
444 
445     return ret;
446 }
447 
448 /**
449  * Convenience function to step a prepared statement with no
450  * value once.
451  *
452  * @param context   The current krb5_context
453  * @param statement A prepared sqlite3 statement
454  *
455  * @return        0 if everything worked, an error code if not
456  */
457 static krb5_error_code
458 hdb_sqlite_step_once(krb5_context context, HDB *db, sqlite3_stmt *statement)
459 {
460     int ret;
461     hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db;
462 
463     ret = hdb_sqlite_step(context, hsdb->db, statement);
464     sqlite3_clear_bindings(statement);
465     sqlite3_reset(statement);
466 
467     return ret;
468 }
469 
470 
471 /**
472  * Stores an hdb_entry in the database. If flags contains HDB_F_REPLACE
473  * a previous entry may be replaced.
474  *
475  * @param context The current krb5_context
476  * @param db      Heimdal database handle
477  * @param flags   May currently only contain HDB_F_REPLACE
478  * @param entry   The data to store
479  *
480  * @return        0 if everything worked, an error code if not
481  */
482 static krb5_error_code
483 hdb_sqlite_store(krb5_context context, HDB *db, unsigned flags,
484                  hdb_entry_ex *entry)
485 {
486     int ret;
487     int i;
488     sqlite_int64 entry_id;
489     char *principal_string = NULL;
490     char *alias_string;
491     const HDB_Ext_Aliases *aliases;
492 
493     hdb_sqlite_db *hsdb = (hdb_sqlite_db *)(db->hdb_db);
494     krb5_data value;
495     sqlite3_stmt *get_ids = hsdb->get_ids;
496 
497     ret = hdb_sqlite_exec_stmt(context, hsdb->db,
498                                "BEGIN IMMEDIATE TRANSACTION", EINVAL);
499     if(ret != SQLITE_OK) {
500 	ret = EINVAL;
501         krb5_set_error_message(context, ret,
502 			       "SQLite BEGIN TRANSACTION failed: %s",
503 			       sqlite3_errmsg(hsdb->db));
504         goto rollback;
505     }
506 
507     ret = krb5_unparse_name(context,
508                             entry->entry.principal, &principal_string);
509     if (ret) {
510         goto rollback;
511     }
512 
513     ret = hdb_seal_keys(context, db, &entry->entry);
514     if(ret) {
515         goto rollback;
516     }
517 
518     ret = hdb_entry2value(context, &entry->entry, &value);
519     if(ret) {
520         goto rollback;
521     }
522 
523     sqlite3_bind_text(get_ids, 1, principal_string, -1, SQLITE_STATIC);
524     ret = hdb_sqlite_step(context, hsdb->db, get_ids);
525 
526     if(ret == SQLITE_DONE) { /* No such principal */
527 
528         sqlite3_bind_blob(hsdb->add_entry, 1,
529                           value.data, value.length, SQLITE_STATIC);
530         ret = hdb_sqlite_step(context, hsdb->db, hsdb->add_entry);
531         sqlite3_clear_bindings(hsdb->add_entry);
532         sqlite3_reset(hsdb->add_entry);
533         if(ret != SQLITE_DONE)
534             goto rollback;
535 
536         sqlite3_bind_text(hsdb->add_principal, 1,
537                           principal_string, -1, SQLITE_STATIC);
538         ret = hdb_sqlite_step(context, hsdb->db, hsdb->add_principal);
539         sqlite3_clear_bindings(hsdb->add_principal);
540         sqlite3_reset(hsdb->add_principal);
541         if(ret != SQLITE_DONE)
542             goto rollback;
543 
544         entry_id = sqlite3_column_int64(get_ids, 1);
545 
546     } else if(ret == SQLITE_ROW) { /* Found a principal */
547 
548         if(! (flags & HDB_F_REPLACE)) /* Not allowed to replace it */
549             goto rollback;
550 
551         entry_id = sqlite3_column_int64(get_ids, 1);
552 
553         sqlite3_bind_int64(hsdb->delete_aliases, 1, entry_id);
554         ret = hdb_sqlite_step_once(context, db, hsdb->delete_aliases);
555         if(ret != SQLITE_DONE)
556             goto rollback;
557 
558         sqlite3_bind_blob(hsdb->update_entry, 1,
559                           value.data, value.length, SQLITE_STATIC);
560         sqlite3_bind_int64(hsdb->update_entry, 2, entry_id);
561         ret = hdb_sqlite_step_once(context, db, hsdb->update_entry);
562         if(ret != SQLITE_DONE)
563             goto rollback;
564 
565     } else {
566 	/* Error! */
567         goto rollback;
568     }
569 
570     ret = hdb_entry_get_aliases(&entry->entry, &aliases);
571     if(ret || aliases == NULL)
572         goto commit;
573 
574     for(i = 0; i < aliases->aliases.len; i++) {
575 
576         ret = krb5_unparse_name(context, &aliases->aliases.val[i],
577 				&alias_string);
578         if (ret) {
579             free(alias_string);
580             goto rollback;
581         }
582 
583         sqlite3_bind_text(hsdb->add_alias, 1, alias_string,
584                           -1, SQLITE_STATIC);
585         sqlite3_bind_int64(hsdb->add_alias, 2, entry_id);
586         ret = hdb_sqlite_step_once(context, db, hsdb->add_alias);
587 
588         free(alias_string);
589 
590         if(ret != SQLITE_DONE)
591             goto rollback;
592     }
593 
594     ret = 0;
595 
596 commit:
597 
598     free(principal_string);
599 
600     krb5_data_free(&value);
601 
602     sqlite3_clear_bindings(get_ids);
603     sqlite3_reset(get_ids);
604 
605     ret = hdb_sqlite_exec_stmt(context, hsdb->db, "COMMIT", EINVAL);
606     if(ret != SQLITE_OK)
607 	krb5_warnx(context, "hdb-sqlite: COMMIT problem: %d: %s",
608 		   ret, sqlite3_errmsg(hsdb->db));
609 
610     return ret;
611 
612 rollback:
613 
614     krb5_warnx(context, "hdb-sqlite: store rollback problem: %d: %s",
615 	       ret, sqlite3_errmsg(hsdb->db));
616 
617     free(principal_string);
618 
619     ret = hdb_sqlite_exec_stmt(context, hsdb->db,
620                                "ROLLBACK", EINVAL);
621     return ret;
622 }
623 
624 /**
625  * This may be called often by other code, since the BDB backends
626  * can not have several open connections. SQLite can handle
627  * many processes with open handles to the database file
628  * and closing/opening the handle is an expensive operation.
629  * Hence, this function does nothing.
630  *
631  * @param context The current krb5 context
632  * @param db      Heimdal database handle
633  *
634  * @return        Always returns 0
635  */
636 static krb5_error_code
637 hdb_sqlite_close(krb5_context context, HDB *db)
638 {
639     return 0;
640 }
641 
642 /**
643  * The opposite of hdb_sqlite_close. Since SQLite accepts
644  * many open handles to the database file the handle does not
645  * need to be closed, or reopened.
646  *
647  * @param context The current krb5 context
648  * @param db      Heimdal database handle
649  * @param flags
650  * @param mode_t
651  *
652  * @return        Always returns 0
653  */
654 static krb5_error_code
655 hdb_sqlite_open(krb5_context context, HDB *db, int flags, mode_t mode)
656 {
657     return 0;
658 }
659 
660 /**
661  * Closes the databse and frees all resources.
662  *
663  * @param context The current krb5 context
664  * @param db      Heimdal database handle
665  *
666  * @return        0 on success, an error code if not
667  */
668 static krb5_error_code
669 hdb_sqlite_destroy(krb5_context context, HDB *db)
670 {
671     int ret;
672     hdb_sqlite_db *hsdb;
673 
674     ret = hdb_clear_master_key(context, db);
675 
676     hdb_sqlite_close_database(context, db);
677 
678     hsdb = (hdb_sqlite_db*)(db->hdb_db);
679 
680     free(hsdb->db_file);
681     free(db->hdb_db);
682     free(db);
683 
684     return ret;
685 }
686 
687 /*
688  * Not sure if this is needed.
689  */
690 static krb5_error_code
691 hdb_sqlite_lock(krb5_context context, HDB *db, int operation)
692 {
693     krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB,
694 			   "lock not implemented");
695     return HDB_ERR_CANT_LOCK_DB;
696 }
697 
698 /*
699  * Not sure if this is needed.
700  */
701 static krb5_error_code
702 hdb_sqlite_unlock(krb5_context context, HDB *db)
703 {
704     krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB,
705 			  "unlock not implemented");
706     return HDB_ERR_CANT_LOCK_DB;
707 }
708 
709 /*
710  * Should get the next entry, to allow iteration over all entries.
711  */
712 static krb5_error_code
713 hdb_sqlite_nextkey(krb5_context context, HDB *db, unsigned flags,
714                    hdb_entry_ex *entry)
715 {
716     krb5_error_code ret = 0;
717     int sqlite_error;
718     krb5_data value;
719 
720     hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db;
721 
722     sqlite_error = hdb_sqlite_step(context, hsdb->db, hsdb->get_all_entries);
723     if(sqlite_error == SQLITE_ROW) {
724 	/* Found an entry */
725         value.length = sqlite3_column_bytes(hsdb->get_all_entries, 0);
726         value.data = (void *) sqlite3_column_blob(hsdb->get_all_entries, 0);
727         memset(entry, 0, sizeof(*entry));
728         ret = hdb_value2entry(context, &value, &entry->entry);
729     }
730     else if(sqlite_error == SQLITE_DONE) {
731 	/* No more entries */
732         ret = HDB_ERR_NOENTRY;
733         sqlite3_reset(hsdb->get_all_entries);
734     }
735     else {
736 	/* XXX SQLite error. Should be handled in some way. */
737         ret = EINVAL;
738     }
739 
740     return ret;
741 }
742 
743 /*
744  * Should get the first entry in the database.
745  * What is flags used for?
746  */
747 static krb5_error_code
748 hdb_sqlite_firstkey(krb5_context context, HDB *db, unsigned flags,
749                     hdb_entry_ex *entry)
750 {
751     hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db;
752     krb5_error_code ret;
753 
754     sqlite3_reset(hsdb->get_all_entries);
755 
756     ret = hdb_sqlite_nextkey(context, db, flags, entry);
757     if(ret)
758         return ret;
759 
760     return 0;
761 }
762 
763 /*
764  * Renames the database file.
765  */
766 static krb5_error_code
767 hdb_sqlite_rename(krb5_context context, HDB *db, const char *new_name)
768 {
769     hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db;
770     int ret;
771 
772     krb5_warnx(context, "hdb_sqlite_rename");
773 
774     if (strncasecmp(new_name, "sqlite:", 7) == 0)
775 	new_name += 7;
776 
777     hdb_sqlite_close_database(context, db);
778 
779     ret = rename(hsdb->db_file, new_name);
780     free(hsdb->db_file);
781 
782     hdb_sqlite_make_database(context, db, new_name);
783 
784     return ret;
785 }
786 
787 /*
788  * Removes a principal, including aliases and associated entry.
789  */
790 static krb5_error_code
791 hdb_sqlite_remove(krb5_context context, HDB *db,
792                   krb5_const_principal principal)
793 {
794     krb5_error_code ret;
795     char *principal_string;
796     hdb_sqlite_db *hsdb = (hdb_sqlite_db*)(db->hdb_db);
797     sqlite3_stmt *remove = hsdb->remove;
798 
799     ret = krb5_unparse_name(context, principal, &principal_string);
800     if (ret) {
801         free(principal_string);
802         return ret;
803     }
804 
805     sqlite3_bind_text(remove, 1, principal_string, -1, SQLITE_STATIC);
806 
807     ret = hdb_sqlite_step(context, hsdb->db, remove);
808     if (ret != SQLITE_DONE) {
809 	ret = EINVAL;
810         krb5_set_error_message(context, ret,
811                               "sqlite remove failed: %d",
812                               ret);
813     } else
814         ret = 0;
815 
816     sqlite3_clear_bindings(remove);
817     sqlite3_reset(remove);
818 
819     return ret;
820 }
821 
822 /**
823  * Create SQLITE object, and creates the on disk database if its doesn't exists.
824  *
825  * @param context A Kerberos 5 context.
826  * @param db a returned database handle.
827  * @param argument filename
828  *
829  * @return        0 on success, an error code if not
830  */
831 
832 krb5_error_code
833 hdb_sqlite_create(krb5_context context, HDB **db, const char *argument)
834 {
835     krb5_error_code ret;
836     hdb_sqlite_db *hsdb;
837 
838     *db = calloc(1, sizeof (**db));
839     if (*db == NULL)
840 	return krb5_enomem(context);
841 
842     hsdb = (hdb_sqlite_db*) calloc(1, sizeof (*hsdb));
843     if (hsdb == NULL) {
844         free(*db);
845         *db = NULL;
846 	return krb5_enomem(context);
847     }
848 
849     (*db)->hdb_db = hsdb;
850 
851     /* XXX make_database should make sure everything else is freed on error */
852     ret = hdb_sqlite_make_database(context, *db, argument);
853     if (ret) {
854         free((*db)->hdb_db);
855         free(*db);
856 
857         return ret;
858     }
859 
860     (*db)->hdb_master_key_set = 0;
861     (*db)->hdb_openp = 0;
862     (*db)->hdb_capability_flags = 0;
863 
864     (*db)->hdb_open = hdb_sqlite_open;
865     (*db)->hdb_close = hdb_sqlite_close;
866 
867     (*db)->hdb_lock = hdb_sqlite_lock;
868     (*db)->hdb_unlock = hdb_sqlite_unlock;
869     (*db)->hdb_firstkey = hdb_sqlite_firstkey;
870     (*db)->hdb_nextkey = hdb_sqlite_nextkey;
871     (*db)->hdb_fetch_kvno = hdb_sqlite_fetch_kvno;
872     (*db)->hdb_store = hdb_sqlite_store;
873     (*db)->hdb_remove = hdb_sqlite_remove;
874     (*db)->hdb_destroy = hdb_sqlite_destroy;
875     (*db)->hdb_rename = hdb_sqlite_rename;
876     (*db)->hdb__get = NULL;
877     (*db)->hdb__put = NULL;
878     (*db)->hdb__del = NULL;
879 
880     return 0;
881 }
882