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