xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/hdb/hdb-sqlite.c (revision d3273b5b76f5afaafe308cead5511dbb8df8c5e9)
1 /*	$NetBSD: hdb-sqlite.c,v 1.2 2017/01/28 21:31:48 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 
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, 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 
155 static krb5_error_code
156 prep_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 
211 static void
212 finalize_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  */
265 static krb5_error_code
266 hdb_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 
306 static krb5_error_code
307 bind_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  */
330 static krb5_error_code
331 hdb_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 
355 static int
356 hdb_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  */
377 static krb5_error_code
378 hdb_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  */
405 static krb5_error_code
406 hdb_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         ret = hdb_sqlite_exec_stmt(context, hsdb,
424                                    HDBSQLITE_CREATE_TABLES,
425                                    HDB_ERR_UK_SERROR);
426         if (ret) goto out;
427 
428         ret = hdb_sqlite_exec_stmt(context, hsdb,
429                                    HDBSQLITE_CREATE_TRIGGERS,
430                                    HDB_ERR_UK_SERROR);
431         if (ret) goto out;
432     }
433 
434     ret = prep_stmts(context, hsdb);
435     if (ret) goto out;
436 
437     ret = hdb_sqlite_step(context, hsdb->db, hsdb->get_version);
438     if(ret == SQLITE_ROW) {
439         hsdb->version = sqlite3_column_double(hsdb->get_version, 0);
440     }
441     sqlite3_reset(hsdb->get_version);
442     ret = 0;
443 
444     if(hsdb->version != HDBSQLITE_VERSION) {
445         ret = HDB_ERR_UK_SERROR;
446         krb5_set_error_message(context, ret, "HDBSQLITE_VERSION mismatch");
447     }
448 
449     if(ret) goto out;
450 
451     return 0;
452 
453  out:
454     if (hsdb->db)
455         sqlite3_close(hsdb->db);
456     if (created_file)
457         unlink(hsdb->db_file);
458     free(hsdb->db_file);
459     hsdb->db_file = NULL;
460 
461     return ret;
462 }
463 
464 /**
465  * Retrieves an entry by searching for the given
466  * principal in the Principal database table, both
467  * for canonical principals and aliases.
468  *
469  * @param context   The current krb5_context
470  * @param db        Heimdal database handle
471  * @param principal The principal whose entry to search for
472  * @param flags     Currently only for HDB_F_DECRYPT
473  * @param kvno	    kvno to fetch is HDB_F_KVNO_SPECIFIED use used
474  *
475  * @return          0 if everything worked, an error code if not
476  */
477 static krb5_error_code
478 hdb_sqlite_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal,
479 		      unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry)
480 {
481     int sqlite_error;
482     krb5_error_code ret;
483     hdb_sqlite_db *hsdb = (hdb_sqlite_db*)(db->hdb_db);
484     sqlite3_stmt *fetch = hsdb->fetch;
485     krb5_data value;
486     krb5_principal enterprise_principal = NULL;
487 
488     if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
489 	if (principal->name.name_string.len != 1) {
490 	    ret = KRB5_PARSE_MALFORMED;
491 	    krb5_set_error_message(context, ret, "malformed principal: "
492 				   "enterprise name with %d name components",
493 				   principal->name.name_string.len);
494 	    return ret;
495 	}
496 	ret = krb5_parse_name(context, principal->name.name_string.val[0],
497 			      &enterprise_principal);
498 	if (ret)
499 	    return ret;
500 	principal = enterprise_principal;
501     }
502 
503     ret = bind_principal(context, principal, fetch, 1);
504     krb5_free_principal(context, enterprise_principal);
505     if (ret)
506 	return ret;
507 
508     sqlite_error = hdb_sqlite_step(context, hsdb->db, fetch);
509     if (sqlite_error != SQLITE_ROW) {
510         if(sqlite_error == SQLITE_DONE) {
511             ret = HDB_ERR_NOENTRY;
512             goto out;
513         } else {
514             ret = HDB_ERR_UK_RERROR;
515             krb5_set_error_message(context, ret,
516                                   "sqlite fetch failed: %d",
517                                   sqlite_error);
518             goto out;
519         }
520     }
521 
522     value.length = sqlite3_column_bytes(fetch, 0);
523     value.data = (void *) sqlite3_column_blob(fetch, 0);
524 
525     ret = hdb_value2entry(context, &value, &entry->entry);
526     if(ret)
527         goto out;
528 
529     if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
530         ret = hdb_unseal_keys(context, db, &entry->entry);
531         if(ret) {
532            hdb_free_entry(context, entry);
533            goto out;
534         }
535     }
536 
537     ret = 0;
538 
539 out:
540 
541     sqlite3_clear_bindings(fetch);
542     sqlite3_reset(fetch);
543 
544 
545     return ret;
546 }
547 
548 /**
549  * Convenience function to step a prepared statement with no
550  * value once.
551  *
552  * @param context   The current krb5_context
553  * @param statement A prepared sqlite3 statement
554  *
555  * @return        0 if everything worked, an error code if not
556  */
557 static krb5_error_code
558 hdb_sqlite_step_once(krb5_context context, HDB *db, sqlite3_stmt *statement)
559 {
560     int ret;
561     hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db;
562 
563     ret = hdb_sqlite_step(context, hsdb->db, statement);
564     sqlite3_clear_bindings(statement);
565     sqlite3_reset(statement);
566 
567     return ret;
568 }
569 
570 
571 /**
572  * Stores an hdb_entry in the database. If flags contains HDB_F_REPLACE
573  * a previous entry may be replaced.
574  *
575  * @param context The current krb5_context
576  * @param db      Heimdal database handle
577  * @param flags   May currently only contain HDB_F_REPLACE
578  * @param entry   The data to store
579  *
580  * @return        0 if everything worked, an error code if not
581  */
582 static krb5_error_code
583 hdb_sqlite_store(krb5_context context, HDB *db, unsigned flags,
584                  hdb_entry_ex *entry)
585 {
586     int ret;
587     int i;
588     sqlite_int64 entry_id;
589     const HDB_Ext_Aliases *aliases;
590 
591     hdb_sqlite_db *hsdb = (hdb_sqlite_db *)(db->hdb_db);
592     krb5_data value;
593     sqlite3_stmt *get_ids = hsdb->get_ids;
594 
595     krb5_data_zero(&value);
596 
597     ret = hdb_sqlite_exec_stmt(context, hsdb,
598                                "BEGIN IMMEDIATE TRANSACTION",
599                                HDB_ERR_UK_SERROR);
600     if(ret != SQLITE_OK) {
601 	ret = HDB_ERR_UK_SERROR;
602         krb5_set_error_message(context, ret,
603 			       "SQLite BEGIN TRANSACTION failed: %s",
604 			       sqlite3_errmsg(hsdb->db));
605         goto rollback;
606     }
607 
608     ret = hdb_seal_keys(context, db, &entry->entry);
609     if(ret) {
610         goto rollback;
611     }
612 
613     ret = hdb_entry2value(context, &entry->entry, &value);
614     if(ret) {
615         goto rollback;
616     }
617 
618     ret = bind_principal(context, entry->entry.principal, get_ids, 1);
619     if (ret)
620 	goto rollback;
621 
622     ret = hdb_sqlite_step(context, hsdb->db, get_ids);
623 
624     if(ret == SQLITE_DONE) { /* No such principal */
625 
626         sqlite3_bind_blob(hsdb->add_entry, 1,
627                           value.data, value.length, SQLITE_STATIC);
628         ret = hdb_sqlite_step(context, hsdb->db, hsdb->add_entry);
629         sqlite3_clear_bindings(hsdb->add_entry);
630         sqlite3_reset(hsdb->add_entry);
631         if (ret != SQLITE_DONE && ret != SQLITE_CONSTRAINT) {
632             ret = HDB_ERR_UK_SERROR;
633             goto rollback;
634         }
635         if (ret == SQLITE_CONSTRAINT) {
636             ret = HDB_ERR_EXISTS;
637             goto rollback;
638         }
639 
640 	ret = bind_principal(context, entry->entry.principal, hsdb->add_principal, 1);
641 	if (ret)
642 	    goto rollback;
643 
644         ret = hdb_sqlite_step(context, hsdb->db, hsdb->add_principal);
645         sqlite3_clear_bindings(hsdb->add_principal);
646         sqlite3_reset(hsdb->add_principal);
647         if (ret != SQLITE_DONE && ret != SQLITE_CONSTRAINT) {
648             ret = HDB_ERR_UK_SERROR;
649             goto rollback;
650         }
651         if (ret == SQLITE_CONSTRAINT) {
652             ret = HDB_ERR_EXISTS;
653             goto rollback;
654         }
655 
656         /* Now let's learn what Entry ID we got for the new principal */
657         sqlite3_reset(get_ids);
658         ret = hdb_sqlite_step(context, hsdb->db, get_ids);
659         if (ret != SQLITE_ROW) {
660             ret = HDB_ERR_UK_SERROR;
661             goto rollback;
662         }
663 
664         entry_id = sqlite3_column_int64(get_ids, 1);
665 
666     } else if(ret == SQLITE_ROW) { /* Found a principal */
667 
668         if(! (flags & HDB_F_REPLACE)) /* Not allowed to replace it */
669             goto rollback;
670 
671         entry_id = sqlite3_column_int64(get_ids, 1);
672 
673         sqlite3_bind_int64(hsdb->delete_aliases, 1, entry_id);
674         ret = hdb_sqlite_step_once(context, db, hsdb->delete_aliases);
675         if (ret != SQLITE_DONE) {
676             ret = HDB_ERR_UK_SERROR;
677             goto rollback;
678         }
679 
680         sqlite3_bind_blob(hsdb->update_entry, 1,
681                           value.data, value.length, SQLITE_STATIC);
682         sqlite3_bind_int64(hsdb->update_entry, 2, entry_id);
683         ret = hdb_sqlite_step_once(context, db, hsdb->update_entry);
684         if (ret != SQLITE_DONE) {
685             ret = HDB_ERR_UK_SERROR;
686             goto rollback;
687         }
688 
689     } else {
690 	/* Error! */
691         ret = HDB_ERR_UK_SERROR;
692         goto rollback;
693     }
694 
695     ret = hdb_entry_get_aliases(&entry->entry, &aliases);
696     if(ret || aliases == NULL)
697         goto commit;
698 
699     for(i = 0; i < aliases->aliases.len; i++) {
700 
701 	ret = bind_principal(context, &aliases->aliases.val[i], hsdb->add_alias, 1);
702         if (ret)
703             goto rollback;
704 
705         sqlite3_bind_int64(hsdb->add_alias, 2, entry_id);
706         ret = hdb_sqlite_step_once(context, db, hsdb->add_alias);
707         if (ret == SQLITE_CONSTRAINT) {
708             ret = HDB_ERR_EXISTS;
709             goto rollback;
710         }
711         if (ret != SQLITE_DONE) {
712             ret = HDB_ERR_UK_SERROR;
713             goto rollback;
714         }
715     }
716 
717 commit:
718     krb5_data_free(&value);
719     sqlite3_clear_bindings(get_ids);
720     sqlite3_reset(get_ids);
721 
722     if ((flags & HDB_F_PRECHECK)) {
723         (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0);
724         return 0;
725     }
726 
727     ret = hdb_sqlite_exec_stmt(context, hsdb, "COMMIT", HDB_ERR_UK_SERROR);
728     if(ret != SQLITE_OK)
729 	krb5_warnx(context, "hdb-sqlite: COMMIT problem: %ld: %s",
730 		   (long)HDB_ERR_UK_SERROR, sqlite3_errmsg(hsdb->db));
731 
732     return ret == SQLITE_OK ? 0 : HDB_ERR_UK_SERROR;
733 
734 rollback:
735     krb5_data_free(&value);
736     sqlite3_clear_bindings(get_ids);
737     sqlite3_reset(get_ids);
738     krb5_warnx(context, "hdb-sqlite: store rollback problem: %d: %s",
739 	       ret, sqlite3_errmsg(hsdb->db));
740 
741     (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0);
742     return ret;
743 }
744 
745 /**
746  * This may be called often by other code, since the BDB backends
747  * can not have several open connections. SQLite can handle
748  * many processes with open handles to the database file
749  * and closing/opening the handle is an expensive operation.
750  * Hence, this function does nothing.
751  *
752  * @param context The current krb5 context
753  * @param db      Heimdal database handle
754  *
755  * @return        Always returns 0
756  */
757 static krb5_error_code
758 hdb_sqlite_close(krb5_context context, HDB *db)
759 {
760     return 0;
761 }
762 
763 /**
764  * The opposite of hdb_sqlite_close. Since SQLite accepts
765  * many open handles to the database file the handle does not
766  * need to be closed, or reopened.
767  *
768  * @param context The current krb5 context
769  * @param db      Heimdal database handle
770  * @param flags
771  * @param mode_t
772  *
773  * @return        Always returns 0
774  */
775 static krb5_error_code
776 hdb_sqlite_open(krb5_context context, HDB *db, int flags, mode_t mode)
777 {
778     return 0;
779 }
780 
781 /**
782  * Closes the databse and frees all resources.
783  *
784  * @param context The current krb5 context
785  * @param db      Heimdal database handle
786  *
787  * @return        0 on success, an error code if not
788  */
789 static krb5_error_code
790 hdb_sqlite_destroy(krb5_context context, HDB *db)
791 {
792     int ret, ret2;
793     hdb_sqlite_db *hsdb;
794 
795     ret = hdb_clear_master_key(context, db);
796 
797     ret2 = hdb_sqlite_close_database(context, db);
798 
799     hsdb = (hdb_sqlite_db*)(db->hdb_db);
800 
801     free(hsdb->db_file);
802     free(db->hdb_db);
803     free(db);
804 
805     return ret ? ret : ret2;
806 }
807 
808 /*
809  * Not sure if this is needed.
810  */
811 static krb5_error_code
812 hdb_sqlite_lock(krb5_context context, HDB *db, int operation)
813 {
814     krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB,
815 			   "lock not implemented");
816     return HDB_ERR_CANT_LOCK_DB;
817 }
818 
819 /*
820  * Not sure if this is needed.
821  */
822 static krb5_error_code
823 hdb_sqlite_unlock(krb5_context context, HDB *db)
824 {
825     krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB,
826 			  "unlock not implemented");
827     return HDB_ERR_CANT_LOCK_DB;
828 }
829 
830 /*
831  * Should get the next entry, to allow iteration over all entries.
832  */
833 static krb5_error_code
834 hdb_sqlite_nextkey(krb5_context context, HDB *db, unsigned flags,
835                    hdb_entry_ex *entry)
836 {
837     krb5_error_code ret = 0;
838     int sqlite_error;
839     krb5_data value;
840 
841     hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db;
842 
843     sqlite_error = hdb_sqlite_step(context, hsdb->db, hsdb->get_all_entries);
844     if(sqlite_error == SQLITE_ROW) {
845 	/* Found an entry */
846         value.length = sqlite3_column_bytes(hsdb->get_all_entries, 0);
847         value.data = (void *) sqlite3_column_blob(hsdb->get_all_entries, 0);
848         memset(entry, 0, sizeof(*entry));
849         ret = hdb_value2entry(context, &value, &entry->entry);
850     }
851     else if(sqlite_error == SQLITE_DONE) {
852 	/* No more entries */
853         ret = HDB_ERR_NOENTRY;
854         sqlite3_reset(hsdb->get_all_entries);
855     }
856     else {
857         ret = HDB_ERR_UK_RERROR;
858         krb5_set_error_message(context, HDB_ERR_UK_RERROR,
859                                "SELECT failed after returning one or "
860                                "more rows: %s", sqlite3_errmsg(hsdb->db));
861 
862     }
863 
864     return ret;
865 }
866 
867 /*
868  * Should get the first entry in the database.
869  * What is flags used for?
870  */
871 static krb5_error_code
872 hdb_sqlite_firstkey(krb5_context context, HDB *db, unsigned flags,
873                     hdb_entry_ex *entry)
874 {
875     hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db;
876     krb5_error_code ret;
877 
878     sqlite3_reset(hsdb->get_all_entries);
879 
880     ret = hdb_sqlite_nextkey(context, db, flags, entry);
881     if(ret)
882         return ret;
883 
884     return 0;
885 }
886 
887 /*
888  * Renames the database file.
889  */
890 static krb5_error_code
891 hdb_sqlite_rename(krb5_context context, HDB *db, const char *new_name)
892 {
893     krb5_error_code ret, ret2;
894     hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db;
895 
896     krb5_warnx(context, "hdb_sqlite_rename");
897 
898     if (strncasecmp(new_name, "sqlite:", 7) == 0)
899 	new_name += 7;
900 
901     ret = hdb_sqlite_close_database(context, db);
902 
903     if (rename(hsdb->db_file, new_name) == -1)
904         return errno;
905 
906     free(hsdb->db_file);
907     ret2 = hdb_sqlite_make_database(context, db, new_name);
908     return ret ? ret : ret2;
909 }
910 
911 /*
912  * Removes a principal, including aliases and associated entry.
913  */
914 static krb5_error_code
915 hdb_sqlite_remove(krb5_context context, HDB *db,
916                   unsigned flags, krb5_const_principal principal)
917 {
918     krb5_error_code ret;
919     hdb_sqlite_db *hsdb = (hdb_sqlite_db*)(db->hdb_db);
920     sqlite3_stmt *get_ids = hsdb->get_ids;
921     sqlite3_stmt *rm = hsdb->remove;
922 
923     bind_principal(context, principal, rm, 1);
924 
925     ret = hdb_sqlite_exec_stmt(context, hsdb,
926                                "BEGIN IMMEDIATE TRANSACTION",
927                                HDB_ERR_UK_SERROR);
928     if (ret != SQLITE_OK) {
929 	ret = HDB_ERR_UK_SERROR;
930         (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0);
931         krb5_set_error_message(context, ret,
932 			       "SQLite BEGIN TRANSACTION failed: %s",
933 			       sqlite3_errmsg(hsdb->db));
934         return ret;
935     }
936 
937     if ((flags & HDB_F_PRECHECK)) {
938         ret = bind_principal(context, principal, get_ids, 1);
939         if (ret)
940             return ret;
941 
942         ret = hdb_sqlite_step(context, hsdb->db, get_ids);
943         sqlite3_clear_bindings(get_ids);
944         sqlite3_reset(get_ids);
945         if (ret == SQLITE_DONE) {
946             (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0);
947             return HDB_ERR_NOENTRY;
948         }
949     }
950 
951     ret = hdb_sqlite_step(context, hsdb->db, rm);
952     sqlite3_clear_bindings(rm);
953     sqlite3_reset(rm);
954     if (ret != SQLITE_DONE) {
955         (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0);
956 	ret = HDB_ERR_UK_SERROR;
957         krb5_set_error_message(context, ret, "sqlite remove failed: %d", ret);
958         return ret;
959     }
960 
961     if ((flags & HDB_F_PRECHECK)) {
962         (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0);
963         return 0;
964     }
965 
966     ret = hdb_sqlite_exec_stmt(context, hsdb, "COMMIT", HDB_ERR_UK_SERROR);
967     if (ret != SQLITE_OK)
968 	krb5_warnx(context, "hdb-sqlite: COMMIT problem: %ld: %s",
969 		   (long)HDB_ERR_UK_SERROR, sqlite3_errmsg(hsdb->db));
970 
971     return 0;
972 }
973 
974 /**
975  * Create SQLITE object, and creates the on disk database if its doesn't exists.
976  *
977  * @param context A Kerberos 5 context.
978  * @param db a returned database handle.
979  * @param filename filename
980  *
981  * @return        0 on success, an error code if not
982  */
983 
984 krb5_error_code
985 hdb_sqlite_create(krb5_context context, HDB **db, const char *filename)
986 {
987     krb5_error_code ret;
988     hdb_sqlite_db *hsdb;
989 
990     *db = calloc(1, sizeof (**db));
991     if (*db == NULL)
992 	return krb5_enomem(context);
993 
994     (*db)->hdb_name = strdup(filename);
995     if ((*db)->hdb_name == NULL) {
996         free(*db);
997         *db = NULL;
998         return krb5_enomem(context);
999     }
1000 
1001     hsdb = (hdb_sqlite_db*) calloc(1, sizeof (*hsdb));
1002     if (hsdb == NULL) {
1003         free((*db)->hdb_name);
1004         free(*db);
1005         *db = NULL;
1006 	return krb5_enomem(context);
1007     }
1008 
1009     (*db)->hdb_db = hsdb;
1010 
1011     /* XXX make_database should make sure everything else is freed on error */
1012     ret = hdb_sqlite_make_database(context, *db, filename);
1013     if (ret) {
1014         free((*db)->hdb_db);
1015         free(*db);
1016 
1017         return ret;
1018     }
1019 
1020     (*db)->hdb_master_key_set = 0;
1021     (*db)->hdb_openp = 0;
1022     (*db)->hdb_capability_flags = 0;
1023 
1024     (*db)->hdb_open = hdb_sqlite_open;
1025     (*db)->hdb_close = hdb_sqlite_close;
1026 
1027     (*db)->hdb_lock = hdb_sqlite_lock;
1028     (*db)->hdb_unlock = hdb_sqlite_unlock;
1029     (*db)->hdb_firstkey = hdb_sqlite_firstkey;
1030     (*db)->hdb_nextkey = hdb_sqlite_nextkey;
1031     (*db)->hdb_fetch_kvno = hdb_sqlite_fetch_kvno;
1032     (*db)->hdb_store = hdb_sqlite_store;
1033     (*db)->hdb_remove = hdb_sqlite_remove;
1034     (*db)->hdb_destroy = hdb_sqlite_destroy;
1035     (*db)->hdb_rename = hdb_sqlite_rename;
1036     (*db)->hdb__get = NULL;
1037     (*db)->hdb__put = NULL;
1038     (*db)->hdb__del = NULL;
1039 
1040     return 0;
1041 }
1042