Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/heimdal/lib/hdb/hdb-sqlite.c
34878 views
1
/*
2
* Copyright (c) 2009 Kungliga Tekniska H�gskolan
3
* (Royal Institute of Technology, Stockholm, Sweden).
4
* All rights reserved.
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
*
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
*
13
* 2. Redistributions in binary form must reproduce the above copyright
14
* notice, this list of conditions and the following disclaimer in the
15
* documentation and/or other materials provided with the distribution.
16
*
17
* 3. Neither the name of the Institute nor the names of its contributors
18
* may be used to endorse or promote products derived from this software
19
* without specific prior written permission.
20
*
21
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31
* SUCH DAMAGE.
32
*/
33
34
#include "hdb_locl.h"
35
#include "sqlite3.h"
36
37
#define MAX_RETRIES 10
38
39
typedef struct hdb_sqlite_db {
40
double version;
41
sqlite3 *db;
42
char *db_file;
43
44
sqlite3_stmt *get_version;
45
sqlite3_stmt *fetch;
46
sqlite3_stmt *get_ids;
47
sqlite3_stmt *add_entry;
48
sqlite3_stmt *add_principal;
49
sqlite3_stmt *add_alias;
50
sqlite3_stmt *delete_aliases;
51
sqlite3_stmt *update_entry;
52
sqlite3_stmt *remove;
53
sqlite3_stmt *get_all_entries;
54
55
} hdb_sqlite_db;
56
57
/* This should be used to mark updates which make the code incompatible
58
* with databases created with previous versions. Don't update it if
59
* compatibility is not broken. */
60
#define HDBSQLITE_VERSION 0.1
61
62
#define _HDBSQLITE_STRINGIFY(x) #x
63
#define HDBSQLITE_STRINGIFY(x) _HDBSQLITE_STRINGIFY(x)
64
65
#define HDBSQLITE_CREATE_TABLES \
66
" BEGIN TRANSACTION;" \
67
" CREATE TABLE Version (number REAL);" \
68
" INSERT INTO Version (number)" \
69
" VALUES (" HDBSQLITE_STRINGIFY(HDBSQLITE_VERSION) ");" \
70
" CREATE TABLE Principal" \
71
" (id INTEGER PRIMARY KEY," \
72
" principal TEXT UNIQUE NOT NULL," \
73
" canonical INTEGER," \
74
" entry INTEGER);" \
75
" CREATE TABLE Entry" \
76
" (id INTEGER PRIMARY KEY," \
77
" data BLOB);" \
78
" COMMIT"
79
#define HDBSQLITE_CREATE_TRIGGERS \
80
" CREATE TRIGGER remove_principals AFTER DELETE ON Entry" \
81
" BEGIN" \
82
" DELETE FROM Principal" \
83
" WHERE entry = OLD.id;" \
84
" END"
85
#define HDBSQLITE_GET_VERSION \
86
" SELECT number FROM Version"
87
#define HDBSQLITE_FETCH \
88
" SELECT Entry.data FROM Principal, Entry" \
89
" WHERE Principal.principal = ? AND" \
90
" Entry.id = Principal.entry"
91
#define HDBSQLITE_GET_IDS \
92
" SELECT id, entry FROM Principal" \
93
" WHERE principal = ?"
94
#define HDBSQLITE_ADD_ENTRY \
95
" INSERT INTO Entry (data) VALUES (?)"
96
#define HDBSQLITE_ADD_PRINCIPAL \
97
" INSERT INTO Principal (principal, entry, canonical)" \
98
" VALUES (?, last_insert_rowid(), 1)"
99
#define HDBSQLITE_ADD_ALIAS \
100
" INSERT INTO Principal (principal, entry, canonical)" \
101
" VALUES(?, ?, 0)"
102
#define HDBSQLITE_DELETE_ALIASES \
103
" DELETE FROM Principal" \
104
" WHERE entry = ? AND canonical = 0"
105
#define HDBSQLITE_UPDATE_ENTRY \
106
" UPDATE Entry SET data = ?" \
107
" WHERE id = ?"
108
#define HDBSQLITE_REMOVE \
109
" DELETE FROM ENTRY WHERE id = " \
110
" (SELECT entry FROM Principal" \
111
" WHERE principal = ?)"
112
#define HDBSQLITE_GET_ALL_ENTRIES \
113
" SELECT data FROM Entry"
114
115
/**
116
* Wrapper around sqlite3_prepare_v2.
117
*
118
* @param context The current krb5 context
119
* @param statement Where to store the pointer to the statement
120
* after preparing it
121
* @param str SQL code for the statement
122
*
123
* @return 0 if OK, an error code if not
124
*/
125
static krb5_error_code
126
hdb_sqlite_prepare_stmt(krb5_context context,
127
sqlite3 *db,
128
sqlite3_stmt **statement,
129
const char *str)
130
{
131
int ret, tries = 0;
132
133
ret = sqlite3_prepare_v2(db, str, -1, statement, NULL);
134
while((tries++ < MAX_RETRIES) &&
135
((ret == SQLITE_BUSY) ||
136
(ret == SQLITE_IOERR_BLOCKED) ||
137
(ret == SQLITE_LOCKED))) {
138
krb5_warnx(context, "hdb-sqlite: prepare busy");
139
sleep(1);
140
ret = sqlite3_prepare_v2(db, str, -1, statement, NULL);
141
}
142
143
if (ret != SQLITE_OK) {
144
krb5_set_error_message(context, EINVAL,
145
"Failed to prepare stmt %s: %s",
146
str, sqlite3_errmsg(db));
147
return EINVAL;
148
}
149
150
return 0;
151
}
152
153
/**
154
* A wrapper around sqlite3_exec.
155
*
156
* @param context The current krb5 context
157
* @param database An open sqlite3 database handle
158
* @param statement SQL code to execute
159
* @param error_code What to return if the statement fails
160
*
161
* @return 0 if OK, else error_code
162
*/
163
static krb5_error_code
164
hdb_sqlite_exec_stmt(krb5_context context,
165
sqlite3 *database,
166
const char *statement,
167
krb5_error_code error_code)
168
{
169
int ret;
170
171
ret = sqlite3_exec(database, statement, NULL, NULL, NULL);
172
173
while(((ret == SQLITE_BUSY) ||
174
(ret == SQLITE_IOERR_BLOCKED) ||
175
(ret == SQLITE_LOCKED))) {
176
krb5_warnx(context, "hdb-sqlite: exec busy: %d", (int)getpid());
177
sleep(1);
178
ret = sqlite3_exec(database, statement, NULL, NULL, NULL);
179
}
180
181
if (ret != SQLITE_OK && error_code) {
182
krb5_set_error_message(context, error_code,
183
"Execute %s: %s", statement,
184
sqlite3_errmsg(database));
185
return error_code;
186
}
187
188
return 0;
189
}
190
191
/**
192
* Opens an sqlite3 database handle to a file, may create the
193
* database file depending on flags.
194
*
195
* @param context The current krb5 context
196
* @param db Heimdal database handle
197
* @param flags Controls whether or not the file may be created,
198
* may be 0 or SQLITE_OPEN_CREATE
199
*/
200
static krb5_error_code
201
hdb_sqlite_open_database(krb5_context context, HDB *db, int flags)
202
{
203
int ret;
204
hdb_sqlite_db *hsdb = (hdb_sqlite_db*) db->hdb_db;
205
206
ret = sqlite3_open_v2(hsdb->db_file, &hsdb->db,
207
SQLITE_OPEN_READWRITE | flags, NULL);
208
209
if (ret) {
210
if (hsdb->db) {
211
ret = ENOENT;
212
krb5_set_error_message(context, ret,
213
"Error opening sqlite database %s: %s",
214
hsdb->db_file, sqlite3_errmsg(hsdb->db));
215
sqlite3_close(hsdb->db);
216
hsdb->db = NULL;
217
} else
218
ret = krb5_enomem(context);
219
return ret;
220
}
221
222
return 0;
223
}
224
225
static int
226
hdb_sqlite_step(krb5_context context, sqlite3 *db, sqlite3_stmt *stmt)
227
{
228
int ret;
229
230
ret = sqlite3_step(stmt);
231
while(((ret == SQLITE_BUSY) ||
232
(ret == SQLITE_IOERR_BLOCKED) ||
233
(ret == SQLITE_LOCKED))) {
234
krb5_warnx(context, "hdb-sqlite: step busy: %d", (int)getpid());
235
sleep(1);
236
ret = sqlite3_step(stmt);
237
}
238
return ret;
239
}
240
241
/**
242
* Closes the database and frees memory allocated for statements.
243
*
244
* @param context The current krb5 context
245
* @param db Heimdal database handle
246
*/
247
static krb5_error_code
248
hdb_sqlite_close_database(krb5_context context, HDB *db)
249
{
250
hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db;
251
252
sqlite3_finalize(hsdb->get_version);
253
sqlite3_finalize(hsdb->fetch);
254
sqlite3_finalize(hsdb->get_ids);
255
sqlite3_finalize(hsdb->add_entry);
256
sqlite3_finalize(hsdb->add_principal);
257
sqlite3_finalize(hsdb->add_alias);
258
sqlite3_finalize(hsdb->delete_aliases);
259
sqlite3_finalize(hsdb->update_entry);
260
sqlite3_finalize(hsdb->remove);
261
sqlite3_finalize(hsdb->get_all_entries);
262
263
sqlite3_close(hsdb->db);
264
265
return 0;
266
}
267
268
/**
269
* Opens an sqlite database file and prepares it for use.
270
* If the file does not exist it will be created.
271
*
272
* @param context The current krb5_context
273
* @param db The heimdal database handle
274
* @param filename Where to store the database file
275
*
276
* @return 0 if everything worked, an error code if not
277
*/
278
static krb5_error_code
279
hdb_sqlite_make_database(krb5_context context, HDB *db, const char *filename)
280
{
281
int ret;
282
int created_file = 0;
283
hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db;
284
285
hsdb->db_file = strdup(filename);
286
if(hsdb->db_file == NULL)
287
return ENOMEM;
288
289
ret = hdb_sqlite_open_database(context, db, 0);
290
if (ret) {
291
ret = hdb_sqlite_open_database(context, db, SQLITE_OPEN_CREATE);
292
if (ret) goto out;
293
294
created_file = 1;
295
296
ret = hdb_sqlite_exec_stmt(context, hsdb->db,
297
HDBSQLITE_CREATE_TABLES,
298
EINVAL);
299
if (ret) goto out;
300
301
ret = hdb_sqlite_exec_stmt(context, hsdb->db,
302
HDBSQLITE_CREATE_TRIGGERS,
303
EINVAL);
304
if (ret) goto out;
305
}
306
307
ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
308
&hsdb->get_version,
309
HDBSQLITE_GET_VERSION);
310
if (ret) goto out;
311
ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
312
&hsdb->fetch,
313
HDBSQLITE_FETCH);
314
if (ret) goto out;
315
ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
316
&hsdb->get_ids,
317
HDBSQLITE_GET_IDS);
318
if (ret) goto out;
319
ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
320
&hsdb->add_entry,
321
HDBSQLITE_ADD_ENTRY);
322
if (ret) goto out;
323
ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
324
&hsdb->add_principal,
325
HDBSQLITE_ADD_PRINCIPAL);
326
if (ret) goto out;
327
ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
328
&hsdb->add_alias,
329
HDBSQLITE_ADD_ALIAS);
330
if (ret) goto out;
331
ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
332
&hsdb->delete_aliases,
333
HDBSQLITE_DELETE_ALIASES);
334
if (ret) goto out;
335
ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
336
&hsdb->update_entry,
337
HDBSQLITE_UPDATE_ENTRY);
338
if (ret) goto out;
339
ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
340
&hsdb->remove,
341
HDBSQLITE_REMOVE);
342
if (ret) goto out;
343
ret = hdb_sqlite_prepare_stmt(context, hsdb->db,
344
&hsdb->get_all_entries,
345
HDBSQLITE_GET_ALL_ENTRIES);
346
if (ret) goto out;
347
348
ret = hdb_sqlite_step(context, hsdb->db, hsdb->get_version);
349
if(ret == SQLITE_ROW) {
350
hsdb->version = sqlite3_column_double(hsdb->get_version, 0);
351
}
352
sqlite3_reset(hsdb->get_version);
353
ret = 0;
354
355
if(hsdb->version != HDBSQLITE_VERSION) {
356
ret = EINVAL;
357
krb5_set_error_message(context, ret, "HDBSQLITE_VERSION mismatch");
358
}
359
360
if(ret) goto out;
361
362
return 0;
363
364
out:
365
if (hsdb->db)
366
sqlite3_close(hsdb->db);
367
if (created_file)
368
unlink(hsdb->db_file);
369
370
return ret;
371
}
372
373
/**
374
* Retrieves an entry by searching for the given
375
* principal in the Principal database table, both
376
* for canonical principals and aliases.
377
*
378
* @param context The current krb5_context
379
* @param db Heimdal database handle
380
* @param principal The principal whose entry to search for
381
* @param flags Currently only for HDB_F_DECRYPT
382
* @param kvno kvno to fetch is HDB_F_KVNO_SPECIFIED use used
383
*
384
* @return 0 if everything worked, an error code if not
385
*/
386
static krb5_error_code
387
hdb_sqlite_fetch_kvno(krb5_context context, HDB *db, krb5_const_principal principal,
388
unsigned flags, krb5_kvno kvno, hdb_entry_ex *entry)
389
{
390
int sqlite_error;
391
krb5_error_code ret;
392
char *principal_string;
393
hdb_sqlite_db *hsdb = (hdb_sqlite_db*)(db->hdb_db);
394
sqlite3_stmt *fetch = hsdb->fetch;
395
krb5_data value;
396
397
ret = krb5_unparse_name(context, principal, &principal_string);
398
if (ret) {
399
free(principal_string);
400
return ret;
401
}
402
403
sqlite3_bind_text(fetch, 1, principal_string, -1, SQLITE_STATIC);
404
405
sqlite_error = hdb_sqlite_step(context, hsdb->db, fetch);
406
if (sqlite_error != SQLITE_ROW) {
407
if(sqlite_error == SQLITE_DONE) {
408
ret = HDB_ERR_NOENTRY;
409
goto out;
410
} else {
411
ret = EINVAL;
412
krb5_set_error_message(context, ret,
413
"sqlite fetch failed: %d",
414
sqlite_error);
415
goto out;
416
}
417
}
418
419
value.length = sqlite3_column_bytes(fetch, 0);
420
value.data = (void *) sqlite3_column_blob(fetch, 0);
421
422
ret = hdb_value2entry(context, &value, &entry->entry);
423
if(ret)
424
goto out;
425
426
if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
427
ret = hdb_unseal_keys(context, db, &entry->entry);
428
if(ret) {
429
hdb_free_entry(context, entry);
430
goto out;
431
}
432
}
433
434
ret = 0;
435
436
out:
437
438
sqlite3_clear_bindings(fetch);
439
sqlite3_reset(fetch);
440
441
free(principal_string);
442
443
return ret;
444
}
445
446
/**
447
* Convenience function to step a prepared statement with no
448
* value once.
449
*
450
* @param context The current krb5_context
451
* @param statement A prepared sqlite3 statement
452
*
453
* @return 0 if everything worked, an error code if not
454
*/
455
static krb5_error_code
456
hdb_sqlite_step_once(krb5_context context, HDB *db, sqlite3_stmt *statement)
457
{
458
int ret;
459
hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db;
460
461
ret = hdb_sqlite_step(context, hsdb->db, statement);
462
sqlite3_clear_bindings(statement);
463
sqlite3_reset(statement);
464
465
return ret;
466
}
467
468
469
/**
470
* Stores an hdb_entry in the database. If flags contains HDB_F_REPLACE
471
* a previous entry may be replaced.
472
*
473
* @param context The current krb5_context
474
* @param db Heimdal database handle
475
* @param flags May currently only contain HDB_F_REPLACE
476
* @param entry The data to store
477
*
478
* @return 0 if everything worked, an error code if not
479
*/
480
static krb5_error_code
481
hdb_sqlite_store(krb5_context context, HDB *db, unsigned flags,
482
hdb_entry_ex *entry)
483
{
484
int ret;
485
int i;
486
sqlite_int64 entry_id;
487
char *principal_string = NULL;
488
char *alias_string;
489
const HDB_Ext_Aliases *aliases;
490
491
hdb_sqlite_db *hsdb = (hdb_sqlite_db *)(db->hdb_db);
492
krb5_data value;
493
sqlite3_stmt *get_ids = hsdb->get_ids;
494
495
ret = hdb_sqlite_exec_stmt(context, hsdb->db,
496
"BEGIN IMMEDIATE TRANSACTION", EINVAL);
497
if(ret != SQLITE_OK) {
498
ret = EINVAL;
499
krb5_set_error_message(context, ret,
500
"SQLite BEGIN TRANSACTION failed: %s",
501
sqlite3_errmsg(hsdb->db));
502
goto rollback;
503
}
504
505
ret = krb5_unparse_name(context,
506
entry->entry.principal, &principal_string);
507
if (ret) {
508
goto rollback;
509
}
510
511
ret = hdb_seal_keys(context, db, &entry->entry);
512
if(ret) {
513
goto rollback;
514
}
515
516
ret = hdb_entry2value(context, &entry->entry, &value);
517
if(ret) {
518
goto rollback;
519
}
520
521
sqlite3_bind_text(get_ids, 1, principal_string, -1, SQLITE_STATIC);
522
ret = hdb_sqlite_step(context, hsdb->db, get_ids);
523
524
if(ret == SQLITE_DONE) { /* No such principal */
525
526
sqlite3_bind_blob(hsdb->add_entry, 1,
527
value.data, value.length, SQLITE_STATIC);
528
ret = hdb_sqlite_step(context, hsdb->db, hsdb->add_entry);
529
sqlite3_clear_bindings(hsdb->add_entry);
530
sqlite3_reset(hsdb->add_entry);
531
if(ret != SQLITE_DONE)
532
goto rollback;
533
534
sqlite3_bind_text(hsdb->add_principal, 1,
535
principal_string, -1, SQLITE_STATIC);
536
ret = hdb_sqlite_step(context, hsdb->db, hsdb->add_principal);
537
sqlite3_clear_bindings(hsdb->add_principal);
538
sqlite3_reset(hsdb->add_principal);
539
if(ret != SQLITE_DONE)
540
goto rollback;
541
542
entry_id = sqlite3_column_int64(get_ids, 1);
543
544
} else if(ret == SQLITE_ROW) { /* Found a principal */
545
546
if(! (flags & HDB_F_REPLACE)) /* Not allowed to replace it */
547
goto rollback;
548
549
entry_id = sqlite3_column_int64(get_ids, 1);
550
551
sqlite3_bind_int64(hsdb->delete_aliases, 1, entry_id);
552
ret = hdb_sqlite_step_once(context, db, hsdb->delete_aliases);
553
if(ret != SQLITE_DONE)
554
goto rollback;
555
556
sqlite3_bind_blob(hsdb->update_entry, 1,
557
value.data, value.length, SQLITE_STATIC);
558
sqlite3_bind_int64(hsdb->update_entry, 2, entry_id);
559
ret = hdb_sqlite_step_once(context, db, hsdb->update_entry);
560
if(ret != SQLITE_DONE)
561
goto rollback;
562
563
} else {
564
/* Error! */
565
goto rollback;
566
}
567
568
ret = hdb_entry_get_aliases(&entry->entry, &aliases);
569
if(ret || aliases == NULL)
570
goto commit;
571
572
for(i = 0; i < aliases->aliases.len; i++) {
573
574
ret = krb5_unparse_name(context, &aliases->aliases.val[i],
575
&alias_string);
576
if (ret) {
577
free(alias_string);
578
goto rollback;
579
}
580
581
sqlite3_bind_text(hsdb->add_alias, 1, alias_string,
582
-1, SQLITE_STATIC);
583
sqlite3_bind_int64(hsdb->add_alias, 2, entry_id);
584
ret = hdb_sqlite_step_once(context, db, hsdb->add_alias);
585
586
free(alias_string);
587
588
if(ret != SQLITE_DONE)
589
goto rollback;
590
}
591
592
ret = 0;
593
594
commit:
595
596
free(principal_string);
597
598
krb5_data_free(&value);
599
600
sqlite3_clear_bindings(get_ids);
601
sqlite3_reset(get_ids);
602
603
ret = hdb_sqlite_exec_stmt(context, hsdb->db, "COMMIT", EINVAL);
604
if(ret != SQLITE_OK)
605
krb5_warnx(context, "hdb-sqlite: COMMIT problem: %d: %s",
606
ret, sqlite3_errmsg(hsdb->db));
607
608
return ret;
609
610
rollback:
611
612
krb5_warnx(context, "hdb-sqlite: store rollback problem: %d: %s",
613
ret, sqlite3_errmsg(hsdb->db));
614
615
free(principal_string);
616
617
ret = hdb_sqlite_exec_stmt(context, hsdb->db,
618
"ROLLBACK", EINVAL);
619
return ret;
620
}
621
622
/**
623
* This may be called often by other code, since the BDB backends
624
* can not have several open connections. SQLite can handle
625
* many processes with open handles to the database file
626
* and closing/opening the handle is an expensive operation.
627
* Hence, this function does nothing.
628
*
629
* @param context The current krb5 context
630
* @param db Heimdal database handle
631
*
632
* @return Always returns 0
633
*/
634
static krb5_error_code
635
hdb_sqlite_close(krb5_context context, HDB *db)
636
{
637
return 0;
638
}
639
640
/**
641
* The opposite of hdb_sqlite_close. Since SQLite accepts
642
* many open handles to the database file the handle does not
643
* need to be closed, or reopened.
644
*
645
* @param context The current krb5 context
646
* @param db Heimdal database handle
647
* @param flags
648
* @param mode_t
649
*
650
* @return Always returns 0
651
*/
652
static krb5_error_code
653
hdb_sqlite_open(krb5_context context, HDB *db, int flags, mode_t mode)
654
{
655
return 0;
656
}
657
658
/**
659
* Closes the databse and frees all resources.
660
*
661
* @param context The current krb5 context
662
* @param db Heimdal database handle
663
*
664
* @return 0 on success, an error code if not
665
*/
666
static krb5_error_code
667
hdb_sqlite_destroy(krb5_context context, HDB *db)
668
{
669
int ret;
670
hdb_sqlite_db *hsdb;
671
672
ret = hdb_clear_master_key(context, db);
673
674
hdb_sqlite_close_database(context, db);
675
676
hsdb = (hdb_sqlite_db*)(db->hdb_db);
677
678
free(hsdb->db_file);
679
free(db->hdb_db);
680
free(db);
681
682
return ret;
683
}
684
685
/*
686
* Not sure if this is needed.
687
*/
688
static krb5_error_code
689
hdb_sqlite_lock(krb5_context context, HDB *db, int operation)
690
{
691
krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB,
692
"lock not implemented");
693
return HDB_ERR_CANT_LOCK_DB;
694
}
695
696
/*
697
* Not sure if this is needed.
698
*/
699
static krb5_error_code
700
hdb_sqlite_unlock(krb5_context context, HDB *db)
701
{
702
krb5_set_error_message(context, HDB_ERR_CANT_LOCK_DB,
703
"unlock not implemented");
704
return HDB_ERR_CANT_LOCK_DB;
705
}
706
707
/*
708
* Should get the next entry, to allow iteration over all entries.
709
*/
710
static krb5_error_code
711
hdb_sqlite_nextkey(krb5_context context, HDB *db, unsigned flags,
712
hdb_entry_ex *entry)
713
{
714
krb5_error_code ret = 0;
715
int sqlite_error;
716
krb5_data value;
717
718
hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db;
719
720
sqlite_error = hdb_sqlite_step(context, hsdb->db, hsdb->get_all_entries);
721
if(sqlite_error == SQLITE_ROW) {
722
/* Found an entry */
723
value.length = sqlite3_column_bytes(hsdb->get_all_entries, 0);
724
value.data = (void *) sqlite3_column_blob(hsdb->get_all_entries, 0);
725
memset(entry, 0, sizeof(*entry));
726
ret = hdb_value2entry(context, &value, &entry->entry);
727
}
728
else if(sqlite_error == SQLITE_DONE) {
729
/* No more entries */
730
ret = HDB_ERR_NOENTRY;
731
sqlite3_reset(hsdb->get_all_entries);
732
}
733
else {
734
/* XXX SQLite error. Should be handled in some way. */
735
ret = EINVAL;
736
}
737
738
return ret;
739
}
740
741
/*
742
* Should get the first entry in the database.
743
* What is flags used for?
744
*/
745
static krb5_error_code
746
hdb_sqlite_firstkey(krb5_context context, HDB *db, unsigned flags,
747
hdb_entry_ex *entry)
748
{
749
hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db;
750
krb5_error_code ret;
751
752
sqlite3_reset(hsdb->get_all_entries);
753
754
ret = hdb_sqlite_nextkey(context, db, flags, entry);
755
if(ret)
756
return ret;
757
758
return 0;
759
}
760
761
/*
762
* Renames the database file.
763
*/
764
static krb5_error_code
765
hdb_sqlite_rename(krb5_context context, HDB *db, const char *new_name)
766
{
767
hdb_sqlite_db *hsdb = (hdb_sqlite_db *) db->hdb_db;
768
int ret;
769
770
krb5_warnx(context, "hdb_sqlite_rename");
771
772
if (strncasecmp(new_name, "sqlite:", 7) == 0)
773
new_name += 7;
774
775
hdb_sqlite_close_database(context, db);
776
777
ret = rename(hsdb->db_file, new_name);
778
free(hsdb->db_file);
779
780
hdb_sqlite_make_database(context, db, new_name);
781
782
return ret;
783
}
784
785
/*
786
* Removes a principal, including aliases and associated entry.
787
*/
788
static krb5_error_code
789
hdb_sqlite_remove(krb5_context context, HDB *db,
790
krb5_const_principal principal)
791
{
792
krb5_error_code ret;
793
char *principal_string;
794
hdb_sqlite_db *hsdb = (hdb_sqlite_db*)(db->hdb_db);
795
sqlite3_stmt *remove = hsdb->remove;
796
797
ret = krb5_unparse_name(context, principal, &principal_string);
798
if (ret) {
799
free(principal_string);
800
return ret;
801
}
802
803
sqlite3_bind_text(remove, 1, principal_string, -1, SQLITE_STATIC);
804
805
ret = hdb_sqlite_step(context, hsdb->db, remove);
806
if (ret != SQLITE_DONE) {
807
ret = EINVAL;
808
krb5_set_error_message(context, ret,
809
"sqlite remove failed: %d",
810
ret);
811
} else
812
ret = 0;
813
814
sqlite3_clear_bindings(remove);
815
sqlite3_reset(remove);
816
817
return ret;
818
}
819
820
/**
821
* Create SQLITE object, and creates the on disk database if its doesn't exists.
822
*
823
* @param context A Kerberos 5 context.
824
* @param db a returned database handle.
825
* @param argument filename
826
*
827
* @return 0 on success, an error code if not
828
*/
829
830
krb5_error_code
831
hdb_sqlite_create(krb5_context context, HDB **db, const char *argument)
832
{
833
krb5_error_code ret;
834
hdb_sqlite_db *hsdb;
835
836
*db = calloc(1, sizeof (**db));
837
if (*db == NULL)
838
return krb5_enomem(context);
839
840
hsdb = (hdb_sqlite_db*) calloc(1, sizeof (*hsdb));
841
if (hsdb == NULL) {
842
free(*db);
843
*db = NULL;
844
return krb5_enomem(context);
845
}
846
847
(*db)->hdb_db = hsdb;
848
849
/* XXX make_database should make sure everything else is freed on error */
850
ret = hdb_sqlite_make_database(context, *db, argument);
851
if (ret) {
852
free((*db)->hdb_db);
853
free(*db);
854
855
return ret;
856
}
857
858
(*db)->hdb_master_key_set = 0;
859
(*db)->hdb_openp = 0;
860
(*db)->hdb_capability_flags = 0;
861
862
(*db)->hdb_open = hdb_sqlite_open;
863
(*db)->hdb_close = hdb_sqlite_close;
864
865
(*db)->hdb_lock = hdb_sqlite_lock;
866
(*db)->hdb_unlock = hdb_sqlite_unlock;
867
(*db)->hdb_firstkey = hdb_sqlite_firstkey;
868
(*db)->hdb_nextkey = hdb_sqlite_nextkey;
869
(*db)->hdb_fetch_kvno = hdb_sqlite_fetch_kvno;
870
(*db)->hdb_store = hdb_sqlite_store;
871
(*db)->hdb_remove = hdb_sqlite_remove;
872
(*db)->hdb_destroy = hdb_sqlite_destroy;
873
(*db)->hdb_rename = hdb_sqlite_rename;
874
(*db)->hdb__get = NULL;
875
(*db)->hdb__put = NULL;
876
(*db)->hdb__del = NULL;
877
878
return 0;
879
}
880
881