5 // Created by Michael Brouwer on 11/12/12.
6 // Copyright (c) 2012-2013 Apple Inc. All rights reserved.
10 #include "debugging.h"
13 #include <sqlite3_private.h>
14 #include <CoreFoundation/CoreFoundation.h>
17 #include <AssertMacros.h>
18 #include "SecCFWrappers.h"
19 #include "SecCFError.h"
20 #include "SecIOFormat.h"
22 #include "Security/SecBase.h"
24 #define LOGE(ARG,...) secerror(ARG, ## __VA_ARGS__)
25 #define LOGV(ARG,...) secdebug("secdb", ARG, ## __VA_ARGS__)
26 #define LOGD(ARG,...) secdebug("secdb", ARG, ## __VA_ARGS__)
28 #define HAVE_UNLOCK_NOTIFY 0
29 #define USE_BUSY_HANDLER 1
31 struct __OpaqueSecDbStatement
{
34 SecDbConnectionRef dbconn
;
38 struct __OpaqueSecDbConnection
{
41 //CFMutableDictionaryRef statements;
43 SecDbRef db
; // NONRETAINED, since db or block retains us
50 struct __OpaqueSecDb
{
54 dispatch_queue_t queue
;
55 CFMutableArrayRef connections
;
56 dispatch_semaphore_t write_semaphore
;
57 dispatch_semaphore_t read_semaphore
;
59 bool (^opened
)(SecDbConnectionRef dbconn
, bool did_create
, CFErrorRef
*error
);
62 // MARK: Error domains and error helper functions
64 CFStringRef kSecDbErrorDomain
= CFSTR("com.apple.utilities.sqlite3");
66 bool SecDbError(int sql_code
, CFErrorRef
*error
, CFStringRef format
, ...) {
67 if (sql_code
== SQLITE_OK
) return true;
70 CFIndex code
= sql_code
;
71 CFErrorRef previousError
= *error
;
74 va_start(args
, format
);
75 SecCFCreateErrorWithFormatAndArguments(code
, kSecDbErrorDomain
, previousError
, error
, NULL
, format
, args
);
81 bool SecDbErrorWithDb(int sql_code
, sqlite3
*db
, CFErrorRef
*error
, CFStringRef format
, ...) {
82 if (sql_code
== SQLITE_OK
) return true;
85 va_start(args
, format
);
86 CFStringRef message
= CFStringCreateWithFormatAndArguments(kCFAllocatorDefault
, NULL
, format
, args
);
89 int extended_code
= sqlite3_extended_errcode(db
);
90 if (sql_code
== extended_code
)
91 SecDbError(sql_code
, error
, CFSTR("%@: [%d] %s"), message
, sql_code
, sqlite3_errmsg(db
));
93 SecDbError(sql_code
, error
, CFSTR("%@: [%d->%d] %s"), message
, sql_code
, extended_code
, sqlite3_errmsg(db
));
94 CFReleaseSafe(message
);
99 bool SecDbErrorWithStmt(int sql_code
, sqlite3_stmt
*stmt
, CFErrorRef
*error
, CFStringRef format
, ...) {
100 if (sql_code
== SQLITE_OK
) return true;
103 va_start(args
, format
);
104 CFStringRef message
= CFStringCreateWithFormatAndArguments(kCFAllocatorDefault
, NULL
, format
, args
);
107 sqlite3
*db
= sqlite3_db_handle(stmt
);
108 const char *sql
= sqlite3_sql(stmt
);
109 int extended_code
= sqlite3_extended_errcode(db
);
110 if (sql_code
== extended_code
)
111 SecDbError(sql_code
, error
, CFSTR("%@: [%d] %s sql: %s"), message
, sql_code
, sqlite3_errmsg(db
), sql
);
113 SecDbError(sql_code
, error
, CFSTR("%@: [%d->%d] %s sql: %s"), message
, sql_code
, extended_code
, sqlite3_errmsg(db
), sql
);
114 CFReleaseSafe(message
);
121 // MARK: Static helper functions
123 static bool SecDbOpenHandle(SecDbConnectionRef dbconn
, bool *created
, CFErrorRef
*error
);
124 static bool SecDbHandleCorrupt(SecDbConnectionRef dbconn
, int rc
, CFErrorRef
*error
);
127 #pragma mark SecDbRef
130 SecDbCopyDescription(CFTypeRef value
)
132 SecDbRef db
= (SecDbRef
)value
;
133 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("<SecDb path:%@ connections: %@>"), db
->db_path
, db
->connections
);
138 SecDbDestroy(CFTypeRef value
)
140 SecDbRef db
= (SecDbRef
)value
;
141 CFReleaseSafe(db
->connections
);
142 CFReleaseSafe(db
->db_path
);
143 dispatch_release(db
->queue
);
144 dispatch_release(db
->read_semaphore
);
145 dispatch_release(db
->write_semaphore
);
151 SecDbCreate(CFStringRef dbName
,
152 bool (^opened
)(SecDbConnectionRef dbconn
, bool did_create
, CFErrorRef
*error
))
156 db
= CFTypeAllocate(SecDb
, struct __OpaqueSecDb
, kCFAllocatorDefault
);
157 require(db
!= NULL
, done
);
159 CFStringPerformWithCString(dbName
, ^(const char *dbNameStr
) {
160 db
->queue
= dispatch_queue_create(dbNameStr
, DISPATCH_QUEUE_SERIAL
);
162 db
->read_semaphore
= dispatch_semaphore_create(kSecDbMaxReaders
);
163 db
->write_semaphore
= dispatch_semaphore_create(kSecDbMaxWriters
);
164 db
->connections
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
166 if (getenv("__OSINSTALL_ENVIRONMENT") != NULL
) {
167 // TODO: Move this code out of this layer
168 LOGV("sqlDb: running from installer");
169 db
->db_path
= CFSTR("file::memory:?cache=shared");
171 db
->db_path
= CFStringCreateCopy(kCFAllocatorDefault
, dbName
);
178 SecDbIdleConnectionCount(SecDbRef db
) {
179 __block CFIndex count
= 0;
180 dispatch_sync(db
->queue
, ^{
181 count
= CFArrayGetCount(db
->connections
);
188 #pragma mark SecDbConnectionRef
190 static bool SecDbCheckCorrupted(SecDbConnectionRef dbconn
)
192 __block
bool isCorrupted
= true;
193 __block CFErrorRef error
= NULL
;
194 SecDbPrepare(dbconn
, CFSTR("PRAGMA integrity_check"), &error
, ^(sqlite3_stmt
*stmt
) {
195 SecDbStep(dbconn
, stmt
, &error
, ^(bool *stop
) {
196 const char * result
= (const char*)sqlite3_column_text(stmt
, 0);
197 if (result
&& strncasecmp(result
, "ok", 3) == 0) {
203 LOGV("sqlDb: warning error %@ when running integrity check", error
);
209 static bool SecDbDidCreateFirstConnection(SecDbConnectionRef dbconn
, bool didCreate
, CFErrorRef
*error
)
211 LOGD("sqlDb: starting maintenance");
214 if (!didCreate
&& !dbconn
->isCorrupted
) {
215 dbconn
->isCorrupted
= SecDbCheckCorrupted(dbconn
);
216 if (dbconn
->isCorrupted
)
217 secerror("integrity check=fail");
219 LOGD("sqlDb: integrity check=pass");
222 if (!dbconn
->isCorrupted
&& dbconn
->db
->opened
) {
223 CFErrorRef localError
= NULL
;
225 ok
= dbconn
->db
->opened(dbconn
, didCreate
, &localError
);
228 secerror("opened block failed: %@", localError
);
230 if (!dbconn
->isCorrupted
&& error
&& *error
== NULL
) {
234 secerror("opened block failed: error is released and lost");
235 CFReleaseNull(localError
);
239 if (dbconn
->isCorrupted
) {
240 ok
= SecDbHandleCorrupt(dbconn
, 0, error
);
243 LOGD("sqlDb: finished maintenance");
247 void SecDbCorrupt(SecDbConnectionRef dbconn
)
249 dbconn
->isCorrupted
= true;
253 static uint8_t knownDbPathIndex(SecDbConnectionRef dbconn
)
256 if(CFEqual(dbconn
->db
->db_path
, CFSTR("/Library/Keychains/keychain-2.db")))
258 if(CFEqual(dbconn
->db
->db_path
, CFSTR("/Library/Keychains/ocspcache.sqlite3")))
260 if(CFEqual(dbconn
->db
->db_path
, CFSTR("/Library/Keychains/TrustStore.sqlite3")))
262 if(CFEqual(dbconn
->db
->db_path
, CFSTR("/Library/Keychains/caissuercache.sqlite3")))
265 /* Unknown DB path */
270 // Return true if there was no error, returns false otherwise and set *error to an appropriate CFErrorRef.
271 static bool SecDbConnectionCheckCode(SecDbConnectionRef dbconn
, int code
, CFErrorRef
*error
, CFStringRef desc
, ...) {
272 if (code
== SQLITE_OK
|| code
== SQLITE_DONE
)
277 va_start(args
, desc
);
278 CFStringRef msg
= CFStringCreateWithFormatAndArguments(kCFAllocatorDefault
, NULL
, desc
, args
);
280 SecDbErrorWithDb(code
, dbconn
->handle
, error
, msg
);
284 /* If it's already corrupted, don't try to recover */
285 if (dbconn
->isCorrupted
) {
286 CFStringRef reason
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("SQL DB %@ is corrupted already. Not trying to recover"), dbconn
->db
->db_path
);
287 secerror("%@",reason
);
288 __security_simulatecrash(reason
, __sec_exception_code_TwiceCorruptDb(knownDbPathIndex(dbconn
)));
289 CFReleaseSafe(reason
);
293 dbconn
->isCorrupted
= (SQLITE_CORRUPT
== code
) || (SQLITE_NOTADB
== code
) || (SQLITE_IOERR
== code
) || (SQLITE_CANTOPEN
== code
);
294 if (dbconn
->isCorrupted
) {
295 /* Run integrity check and only make dbconn->isCorrupted true and
296 run the corruption handler if the integrity check conclusively fails. */
297 dbconn
->isCorrupted
= SecDbCheckCorrupted(dbconn
);
298 if (dbconn
->isCorrupted
) {
299 secerror("operation returned code: %d integrity check=fail", code
);
300 SecDbHandleCorrupt(dbconn
, code
, error
);
302 secerror("operation returned code: %d: integrity check=pass", code
);
309 #if HAVE_UNLOCK_NOTIFY
311 static void SecDbUnlockNotify(void **apArg
, int nArg
) {
313 for(i
=0; i
<nArg
; i
++) {
314 dispatch_semaphore_t dsema
= (dispatch_semaphore_t
)apArg
[i
];
315 dispatch_semaphore_signal(dsema
);
319 static bool SecDbWaitForUnlockNotify(SecDbConnectionRef dbconn
, sqlite3_stmt
*stmt
, CFErrorRef
*error
) {
321 dispatch_semaphore_t dsema
= dispatch_semaphore_create(0);
322 rc
= sqlite3_unlock_notify(dbconn
->handle
, SecDbUnlockNotify
, dsema
);
323 assert(rc
== SQLITE_LOCKED
|| rc
== SQLITE_OK
);
324 if (rc
== SQLITE_OK
) {
325 dispatch_semaphore_wait(dsema
, DISPATCH_TIME_FOREVER
);
327 dispatch_release(dsema
);
328 return (rc
== SQLITE_OK
331 ? SecDbErrorWithStmt(rc
, stmt
, error
, CFSTR("sqlite3_unlock_notify"))
332 : SecDbErrorWithDb(rc
, dbconn
->handle
, error
, CFSTR("sqlite3_unlock_notify"))));
339 // Return 0 to stop retrying.
340 static int SecDbHandleBusy(void *ctx
, int retryCount
) {
341 SecDbConnectionRef dbconn __unused
= ctx
;
342 struct timespec sleeptime
= { .tv_sec
= 0, .tv_nsec
= 10000 };
343 while (retryCount
--) {
344 // Double sleeptime until we hit one second then add one
345 // second more every time we sleep.
346 if (sleeptime
.tv_sec
) {
349 sleeptime
.tv_nsec
*= 2;
350 if (sleeptime
.tv_nsec
> NSEC_PER_SEC
) {
351 sleeptime
.tv_nsec
= 0;
356 struct timespec unslept
= {};
357 nanosleep(&sleeptime
, &unslept
);
362 static bool SecDbBusyHandler(SecDbConnectionRef dbconn
, CFErrorRef
*error
) {
363 return SecDbErrorWithDb(sqlite3_busy_handler(dbconn
->handle
, SecDbHandleBusy
, dbconn
), dbconn
->handle
, error
, CFSTR("busy_handler"));
366 #endif // USE_BUSY_HANDLER
368 // Return true causes the operation to be tried again.
369 static bool SecDbWaitIfNeeded(SecDbConnectionRef dbconn
, int s3e
, sqlite3_stmt
*stmt
, CFStringRef desc
, struct timespec
*sleeptime
, CFErrorRef
*error
) {
370 #if HAVE_UNLOCK_NOTIFY
371 if (s3e
== SQLITE_LOCKED
) { // Optionally check for extended code being SQLITE_LOCKED_SHAREDCACHE
372 return SecDbWaitForUnlockNotify(dbconn
, stmt
, error
))
376 #if !USE_BUSY_HANDLER
377 if (s3e
== SQLITE_LOCKED
|| s3e
== SQLITE_BUSY
) {
378 LOGV("sqlDb: %s", sqlite3_errmsg(dbconn
->handle
));
379 while (s3e
== SQLITE_LOCKED
|| s3e
== SQLITE_BUSY
) {
380 struct timespec unslept
= {};
381 nanosleep(sleeptime
, &unslept
);
384 s3e
= sqlite3_reset(stmt
);
386 // Double sleeptime until we hit one second the add one
387 // second more every time we sleep.
388 if (sleeptime
->tv_sec
) {
391 sleeptime
->tv_nsec
*= 2;
392 if (sleeptime
->tv_nsec
> NSEC_PER_SEC
) {
393 sleeptime
->tv_nsec
= 0;
399 return SecDbErrorWithStmt(s3e
, stmt
, error
, CFSTR("reset"));
401 #endif // !USE_BUSY_HANDLER
403 return SecDbConnectionCheckCode(dbconn
, s3e
, error
, desc
);
408 enum SecDbStepResult
{
413 typedef enum SecDbStepResult SecDbStepResult
;
415 static SecDbStepResult
_SecDbStep(SecDbConnectionRef dbconn
, sqlite3_stmt
*stmt
, CFErrorRef
*error
) {
416 assert(stmt
!= NULL
);
418 struct timespec sleeptime
= { .tv_sec
= 0, .tv_nsec
= 10000 };
420 s3e
= sqlite3_step(stmt
);
421 if (s3e
== SQLITE_ROW
)
422 return kSecDbRowStep
;
423 else if (s3e
== SQLITE_DONE
)
424 return kSecDbDoneStep
;
425 else if (!SecDbWaitIfNeeded(dbconn
, s3e
, stmt
, CFSTR("step"), &sleeptime
, error
))
426 return kSecDbErrorStep
;
431 SecDbExec(SecDbConnectionRef dbconn
, CFStringRef sql
, CFErrorRef
*error
)
436 CFStringRef tail
= NULL
;
438 sqlite3_stmt
*stmt
= SecDbCopyStmt(dbconn
, sql
, &tail
, error
);
442 while ((sr
= _SecDbStep(dbconn
, stmt
, error
)) == kSecDbRowStep
);
443 if (sr
== kSecDbErrorStep
)
445 ok
&= SecDbReleaseCachedStmt(dbconn
, sql
, stmt
, error
);
448 // TODO We already have an error here we really just want the left over sql in it's userData
449 ok
= SecDbError(SQLITE_ERROR
, error
, CFSTR("Error with unexecuted sql remaining %@"), sql
);
457 static bool SecDbBeginTransaction(SecDbConnectionRef dbconn
, SecDbTransactionType type
, CFErrorRef
*error
)
462 case kSecDbImmediateTransactionType
:
463 query
= CFSTR("BEGIN IMMEDATE");
465 case kSecDbExclusiveTransactionType
:
466 query
= CFSTR("BEGIN EXCLUSIVE");
468 case kSecDbNormalTransactionType
:
469 query
= CFSTR("BEGIN");
472 ok
= SecDbError(SQLITE_ERROR
, error
, CFSTR("invalid transaction type %" PRIu32
), type
);
477 if (query
!= NULL
&& sqlite3_get_autocommit(dbconn
->handle
) != 0) {
478 ok
= SecDbExec(dbconn
, query
, error
);
484 static bool SecDbEndTransaction(SecDbConnectionRef dbconn
, bool commit
, CFErrorRef
*error
)
487 return SecDbExec(dbconn
, CFSTR("END"), error
);
489 return SecDbExec(dbconn
, CFSTR("ROLLBACK"), error
);
493 bool SecDbTransaction(SecDbConnectionRef dbconn
, SecDbTransactionType type
,
494 CFErrorRef
*error
, void (^transaction
)(bool *commit
))
499 if (dbconn
->inTransaction
) {
500 transaction(&commit
);
502 LOGV("sqlDb: nested transaction asked to not be committed");
505 ok
= SecDbBeginTransaction(dbconn
, type
, error
);
507 dbconn
->inTransaction
= true;
508 transaction(&commit
);
509 dbconn
->inTransaction
= false;
510 ok
= SecDbEndTransaction(dbconn
, commit
, error
);
518 sqlite3
*SecDbHandle(SecDbConnectionRef dbconn
) {
519 return dbconn
->handle
;
522 bool SecDbStep(SecDbConnectionRef dbconn
, sqlite3_stmt
*stmt
, CFErrorRef
*error
, void (^row
)(bool *stop
)) {
524 switch (_SecDbStep(dbconn
, stmt
, error
)) {
525 case kSecDbErrorStep
:
535 SecDbError(SQLITE_ERROR
, error
, CFSTR("SecDbStep SQLITE_ROW returned without a row handler"));
543 bool SecDbCheckpoint(SecDbConnectionRef dbconn
, CFErrorRef
*error
)
545 return SecDbConnectionCheckCode(dbconn
, sqlite3_wal_checkpoint(dbconn
->handle
, NULL
), error
, CFSTR("wal_checkpoint"));
548 static bool SecDbFileControl(SecDbConnectionRef dbconn
, int op
, void *arg
, CFErrorRef
*error
) {
549 return SecDbConnectionCheckCode(dbconn
, sqlite3_file_control(dbconn
->handle
, NULL
, op
, arg
), error
, CFSTR("file_control"));
552 static sqlite3
*_SecDbOpenV2(const char *path
, int flags
, CFErrorRef
*error
) {
553 #if HAVE_UNLOCK_NOTIFY
554 flags
|= SQLITE_OPEN_SHAREDCACHE
;
556 sqlite3
*handle
= NULL
;
557 int s3e
= sqlite3_open_v2(path
, &handle
, flags
, NULL
);
560 SecDbErrorWithDb(s3e
, handle
, error
, CFSTR("open_v2 \"%s\" 0x%X"), path
, flags
);
561 sqlite3_close(handle
);
564 SecDbError(s3e
, error
, CFSTR("open_v2 \"%s\" 0x%X"), path
, flags
);
570 static bool SecDbOpenV2(SecDbConnectionRef dbconn
, const char *path
, int flags
, CFErrorRef
*error
) {
571 return (dbconn
->handle
= _SecDbOpenV2(path
, flags
, error
)) != NULL
;
574 static bool SecDbTruncate(SecDbConnectionRef dbconn
, CFErrorRef
*error
)
576 int flags
= SQLITE_TRUNCATE_JOURNALMODE_WAL
| SQLITE_TRUNCATE_AUTOVACUUM_FULL
;
577 __block
bool ok
= SecDbFileControl(dbconn
, SQLITE_TRUNCATE_DATABASE
, &flags
, error
);
579 sqlite3_close(dbconn
->handle
);
580 dbconn
->handle
= NULL
;
581 CFStringPerformWithCString(dbconn
->db
->db_path
, ^(const char *path
) {
583 CFReleaseNull(*error
);
584 if (SecCheckErrno(unlink(path
), error
, CFSTR("unlink %s"), path
)) {
585 ok
= SecDbOpenHandle(dbconn
, NULL
, error
);
589 secerror("Failed to delete db handle: %@", error
? *error
: NULL
);
597 static bool SecDbHandleCorrupt(SecDbConnectionRef dbconn
, int rc
, CFErrorRef
*error
)
599 CFStringRef reason
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("SQL DB %@ is corrupted, trying to recover (rc=%d)"), dbconn
->db
->db_path
, rc
);
600 __security_simulatecrash(reason
, __sec_exception_code_CorruptDb(knownDbPathIndex(dbconn
), rc
));
601 CFReleaseSafe(reason
);
603 // Backup current db.
604 __block
bool didRename
= false;
605 CFStringPerformWithCString(dbconn
->db
->db_path
, ^(const char *db_path
) {
606 sqlite3
*corrupt_db
= NULL
;
607 char buf
[PATH_MAX
+1];
608 snprintf(buf
, sizeof(buf
), "%s-corrupt", db_path
);
609 if (dbconn
->handle
&& (corrupt_db
= _SecDbOpenV2(buf
, SQLITE_OPEN_READWRITE
, error
))) {
611 didRename
= SecDbErrorWithDb(sqlite3_file_control(corrupt_db
, NULL
, SQLITE_FCNTL_PERSIST_WAL
, &on
), corrupt_db
, error
, CFSTR("persist wal"));
612 didRename
&= SecDbErrorWithDb(sqlite3_file_control(corrupt_db
, NULL
, SQLITE_REPLACE_DATABASE
, (void *)dbconn
->handle
), corrupt_db
, error
, CFSTR("replace database"));
613 sqlite3_close(corrupt_db
);
617 secerror("Tried to rename corrupt database at path %@, but we failed: %@, trying explicit rename", dbconn
->db
->db_path
, error
? *error
: NULL
);
619 CFReleaseNull(*error
);
621 didRename
= SecCheckErrno(rename(db_path
, buf
), error
, CFSTR("rename %s %s"), db_path
, buf
) &&
622 (!dbconn
->handle
|| SecDbError(sqlite3_close(dbconn
->handle
), error
, CFSTR("close"))) &&
623 SecDbOpenHandle(dbconn
, NULL
, error
);
626 secerror("Database at path %@ is corrupt. Copied it to %s for further investigation.", dbconn
->db
->db_path
, buf
);
628 seccritical("Tried to copy corrupt database at path %@, but we failed: %@", dbconn
->db
->db_path
, error
? *error
: NULL
);
632 bool ok
= (didRename
&&
633 (dbconn
->handle
|| SecDbOpenHandle(dbconn
, NULL
, error
)) &&
634 SecDbTruncate(dbconn
, error
));
636 // Mark the db as not corrupted, even if something failed.
637 // Always note we are no longer in the corruption handler
638 dbconn
->isCorrupted
= false;
640 // Invoke our callers opened callback, since we just created a new database
641 if (ok
&& dbconn
->db
->opened
)
642 ok
= dbconn
->db
->opened(dbconn
, true, error
);
647 static bool SecDbProfileEnabled(void)
650 static dispatch_once_t onceToken
;
651 static bool profile_enabled
= false;
654 //sudo defaults write /Library/Preferences/com.apple.security.auth profile -bool true
655 dispatch_once(&onceToken
, ^{
656 CFTypeRef profile
= (CFNumberRef
)CFPreferencesCopyValue(CFSTR("profile"), CFSTR(SECURITY_AUTH_NAME
), kCFPreferencesAnyUser
, kCFPreferencesCurrentHost
);
658 if (profile
&& CFGetTypeID(profile
) == CFBooleanGetTypeID()) {
659 profile_enabled
= CFBooleanGetValue((CFBooleanRef
)profile
);
662 LOGV("sqlDb: sql profile: %s", profile_enabled
? "enabled" : "disabled");
664 CFReleaseSafe(profile
);
668 return profile_enabled
;
679 static void SecDbProfile(void *context __unused
, const char *sql
, sqlite3_uint64 ns
) {
680 LOGV("==\nsqlDb: %s\nTime: %llu ms\n", sql
, ns
>> 20);
683 static void SecDbProfile(void *context
, const char *sql
, sqlite3_uint64 ns
) {
684 sqlite3
*s3h
= context
;
685 int code
= sqlite3_extended_errcode(s3h
);
686 if (code
== SQLITE_OK
|| code
== SQLITE_DONE
) {
687 secdebug("profile", "==\nsqlDb: %s\nTime: %llu ms\n", sql
, ns
>> 20);
689 secdebug("profile", "==error[%d]: %s==\nsqlDb: %s\nTime: %llu ms \n", code
, sqlite3_errmsg(s3h
), sql
, ns
>> 20);
694 static bool SecDbTraceEnabled(void)
703 static void SecDbTrace(void *ctx
, const char *trace
) {
704 SecDbConnectionRef dbconn __unused
= ctx
;
705 static dispatch_queue_t queue
;
706 static dispatch_once_t once
;
707 dispatch_once(&once
, ^{
708 queue
= dispatch_queue_create("trace_queue", DISPATCH_QUEUE_SERIAL
);
710 dispatch_sync(queue
, ^{
711 __security_debug(CFSTR("trace"), "", "", 0, CFSTR("%s"), trace
);
715 static bool SecDbOpenHandle(SecDbConnectionRef dbconn
, bool *created
, CFErrorRef
*error
)
717 __block
bool ok
= true;
718 CFStringPerformWithCString(dbconn
->db
->db_path
, ^(const char *db_path
) {
719 ok
= created
&& SecDbOpenV2(dbconn
, db_path
, SQLITE_OPEN_READWRITE
, NULL
);
723 char *tmp
= dirname((char *)db_path
);
725 int errnum
= mkpath_np(tmp
, 0700);
726 if (errnum
!= 0 && errnum
!= EEXIST
) {
727 SecCFCreateErrorWithFormat(errnum
, kSecErrnoDomain
, NULL
, error
, NULL
,
728 CFSTR("mkpath_np %s: [%d] %s"), tmp
, errnum
, strerror(errnum
));
733 ok
= ok
&& SecDbOpenV2(dbconn
, db_path
, SQLITE_OPEN_READWRITE
| SQLITE_OPEN_CREATE
, error
);
735 chmod(db_path
, S_IRUSR
| S_IWUSR
);
741 if (ok
&& SecDbProfileEnabled()) {
742 sqlite3_profile(dbconn
->handle
, SecDbProfile
, dbconn
->handle
);
744 if (ok
&& SecDbTraceEnabled()) {
745 sqlite3_trace(dbconn
->handle
, SecDbTrace
, dbconn
);
748 ok
= ok
&& SecDbBusyHandler(dbconn
, error
);
756 static SecDbConnectionRef
757 SecDbConnectionCreate(SecDbRef db
, bool readOnly
, CFErrorRef
*error
)
759 SecDbConnectionRef dbconn
= NULL
;
761 dbconn
= CFTypeAllocate(SecDbConnection
, struct __OpaqueSecDbConnection
, kCFAllocatorDefault
);
762 require(dbconn
!= NULL
, done
);
765 dbconn
->readOnly
= readOnly
;
771 static bool SecDbConnectionIsReadOnly(SecDbConnectionRef dbconn
) {
772 return dbconn
->readOnly
;
775 static void SecDbConectionSetReadOnly(SecDbConnectionRef dbconn
, bool readOnly
) {
776 dbconn
->readOnly
= readOnly
;
779 /* Read only connections go to the end of the queue, writeable connections
780 go to the start of the queue. */
781 SecDbConnectionRef
SecDbConnectionAquire(SecDbRef db
, bool readOnly
, CFErrorRef
*error
) {
783 secdebug("dbconn", "aquire %s connection", readOnly
? "ro" : "rw");
784 dispatch_semaphore_wait(readOnly
? db
->read_semaphore
: db
->write_semaphore
, DISPATCH_TIME_FOREVER
);
785 __block SecDbConnectionRef dbconn
= NULL
;
786 __block
bool ok
= true;
787 dispatch_sync(db
->queue
, ^{
788 if (!db
->didFirstOpen
) {
789 bool didCreate
= false;
790 ok
= dbconn
= SecDbConnectionCreate(db
, false, error
);
791 CFErrorRef localError
= NULL
;
792 if (ok
&& !SecDbOpenHandle(dbconn
, &didCreate
, &localError
)) {
793 secerror("Unable to create database: %@", localError
);
794 if (localError
&& CFEqual(CFErrorGetDomain(localError
), kSecDbErrorDomain
)) {
795 int code
= (int)CFErrorGetCode(localError
);
796 dbconn
->isCorrupted
= (SQLITE_CORRUPT
== code
) || (SQLITE_NOTADB
== code
) || (SQLITE_IOERR
== code
) || (SQLITE_CANTOPEN
== code
);
798 // If the open failure isn't due to corruption, propagte the error.
799 ok
= dbconn
->isCorrupted
;
800 if (!ok
&& error
&& *error
== NULL
) {
805 CFReleaseNull(localError
);
808 db
->didFirstOpen
= ok
= SecDbDidCreateFirstConnection(dbconn
, didCreate
, error
);
810 CFReleaseNull(dbconn
);
812 /* Try to get one from the cache */
813 CFIndex count
= CFArrayGetCount(db
->connections
);
814 while (count
&& !dbconn
) {
815 CFIndex ix
= readOnly
? count
- 1 : 0;
816 dbconn
= (SecDbConnectionRef
)CFArrayGetValueAtIndex(db
->connections
, ix
);
820 secerror("got NULL dbconn at index: %" PRIdCFIndex
" skipping", ix
);
821 CFArrayRemoveValueAtIndex(db
->connections
, ix
);
827 /* Make sure the connection we found has the right access */
828 if (SecDbConnectionIsReadOnly(dbconn
) != readOnly
) {
829 SecDbConectionSetReadOnly(dbconn
, readOnly
);
832 /* Nothing found in cache, create a new connection */
833 bool created
= false;
834 dbconn
= SecDbConnectionCreate(db
, readOnly
, error
);
835 if (dbconn
&& !SecDbOpenHandle(dbconn
, &created
, error
)) {
836 CFReleaseNull(dbconn
);
841 // If aquire fails we need to signal the semaphore again.
842 dispatch_semaphore_signal(readOnly
? db
->read_semaphore
: db
->write_semaphore
);
849 void SecDbConnectionRelease(SecDbConnectionRef dbconn
) {
851 secerror("called with NULL dbconn");
854 SecDbRef db
= dbconn
->db
;
855 secdebug("dbconn", "release %@", dbconn
);
856 dispatch_sync(db
->queue
, ^{
857 CFIndex count
= CFArrayGetCount(db
->connections
);
858 // Add back possible writable dbconn to the pool.
859 bool readOnly
= SecDbConnectionIsReadOnly(dbconn
);
860 CFArrayInsertValueAtIndex(db
->connections
, readOnly
? count
: 0, dbconn
);
861 // Remove the last (probably read-only) dbconn from the pool.
862 if (count
>= kSecDbMaxIdleHandles
) {
863 CFArrayRemoveValueAtIndex(db
->connections
, count
);
865 // Signal after we have put the connection back in the pool of connections
866 dispatch_semaphore_signal(readOnly
? db
->read_semaphore
: db
->write_semaphore
);
872 bool SecDbPerformRead(SecDbRef db
, CFErrorRef
*error
, void (^perform
)(SecDbConnectionRef dbconn
)) {
873 SecDbConnectionRef dbconn
= SecDbConnectionAquire(db
, true, error
);
874 bool success
= false;
878 SecDbConnectionRelease(dbconn
);
883 bool SecDbPerformWrite(SecDbRef db
, CFErrorRef
*error
, void (^perform
)(SecDbConnectionRef dbconn
)) {
884 SecDbConnectionRef dbconn
= SecDbConnectionAquire(db
, false, error
);
885 bool success
= false;
889 SecDbConnectionRelease(dbconn
);
895 SecDbConnectionCopyDescription(CFTypeRef value
)
897 SecDbConnectionRef dbconn
= (SecDbConnectionRef
)value
;
898 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("<SecDbConnection %s %s>"),
899 dbconn
->readOnly
? "ro" : "rw", dbconn
->handle
? "open" : "closed");
903 SecDbConnectionDestroy(CFTypeRef value
)
905 SecDbConnectionRef dbconn
= (SecDbConnectionRef
)value
;
906 if (dbconn
->handle
) {
907 sqlite3_close(dbconn
->handle
);
914 // MARK: Bind helpers
917 bool SecDbBindNull(sqlite3_stmt
*stmt
, int param
, CFErrorRef
*error
) {
918 bool ok
= SecDbErrorWithStmt(sqlite3_bind_null(stmt
, param
),
919 stmt
, error
, CFSTR("bind_null[%d]"), param
);
920 secdebug("bind", "bind_null[%d]: %@", param
, error
? *error
: NULL
);
925 bool SecDbBindBlob(sqlite3_stmt
*stmt
, int param
, const void *zData
, size_t n
, void(*xDel
)(void*), CFErrorRef
*error
) {
927 return SecDbErrorWithStmt(SQLITE_TOOBIG
, stmt
, error
,
928 CFSTR("bind_blob[%d]: blob bigger than INT_MAX"), param
);
930 bool ok
= SecDbErrorWithStmt(sqlite3_bind_blob(stmt
, param
, zData
, (int)n
, xDel
),
931 stmt
, error
, CFSTR("bind_blob[%d]"), param
);
932 secdebug("bind", "bind_blob[%d]: %.*s: %@", param
, (int)n
, zData
, error
? *error
: NULL
);
936 bool SecDbBindText(sqlite3_stmt
*stmt
, int param
, const char *zData
, size_t n
, void(*xDel
)(void*), CFErrorRef
*error
) {
938 return SecDbErrorWithStmt(SQLITE_TOOBIG
, stmt
, error
,
939 CFSTR("bind_text[%d]: text bigger than INT_MAX"), param
);
941 bool ok
= SecDbErrorWithStmt(sqlite3_bind_text(stmt
, param
, zData
, (int)n
, xDel
), stmt
, error
,
942 CFSTR("bind_text[%d]"), param
);
943 secdebug("bind", "bind_text[%d]: \"%s\": %@", param
, zData
, error
? *error
: NULL
);
947 bool SecDbBindDouble(sqlite3_stmt
*stmt
, int param
, double value
, CFErrorRef
*error
) {
948 bool ok
= SecDbErrorWithStmt(sqlite3_bind_double(stmt
, param
, value
), stmt
, error
,
949 CFSTR("bind_double[%d]"), param
);
950 secdebug("bind", "bind_double[%d]: %f: %@", param
, value
, error
? *error
: NULL
);
954 bool SecDbBindInt(sqlite3_stmt
*stmt
, int param
, int value
, CFErrorRef
*error
) {
955 bool ok
= SecDbErrorWithStmt(sqlite3_bind_int(stmt
, param
, value
), stmt
, error
,
956 CFSTR("bind_int[%d]"), param
);
957 secdebug("bind", "bind_int[%d]: %d: %@", param
, value
, error
? *error
: NULL
);
961 bool SecDbBindInt64(sqlite3_stmt
*stmt
, int param
, sqlite3_int64 value
, CFErrorRef
*error
) {
962 bool ok
= SecDbErrorWithStmt(sqlite3_bind_int64(stmt
, param
, value
), stmt
, error
,
963 CFSTR("bind_int64[%d]"), param
);
964 secdebug("bind", "bind_int64[%d]: %lld: %@", param
, value
, error
? *error
: NULL
);
969 /* AUDIT[securityd](done):
970 value (ok) is a caller provided, non NULL CFTypeRef.
972 bool SecDbBindObject(sqlite3_stmt
*stmt
, int param
, CFTypeRef value
, CFErrorRef
*error
) {
974 __block
bool result
= false;
976 /* TODO: Can we use SQLITE_STATIC below everwhere we currently use
977 SQLITE_TRANSIENT since we finalize the statement before the value
978 goes out of scope? */
979 if (!value
|| (valueId
= CFGetTypeID(value
)) == CFNullGetTypeID()) {
980 /* Skip bindings for NULL values. sqlite3 will interpret unbound
981 params as NULL which is exactly what we want. */
985 result
= SecDbBindNull(stmt
, param
, error
);
987 } else if (valueId
== CFStringGetTypeID()) {
988 CFStringPerformWithCStringAndLength(value
, ^(const char *cstr
, size_t clen
) {
989 result
= SecDbBindText(stmt
, param
, cstr
, clen
, SQLITE_TRANSIENT
, error
);
991 } else if (valueId
== CFDataGetTypeID()) {
992 CFIndex len
= CFDataGetLength(value
);
994 result
= SecDbBindBlob(stmt
, param
, CFDataGetBytePtr(value
),
995 len
, SQLITE_TRANSIENT
, error
);
997 result
= SecDbBindText(stmt
, param
, "", 0, SQLITE_TRANSIENT
, error
);
999 } else if (valueId
== CFDateGetTypeID()) {
1000 CFAbsoluteTime abs_time
= CFDateGetAbsoluteTime(value
);
1001 result
= SecDbBindDouble(stmt
, param
, abs_time
, error
);
1002 } else if (valueId
== CFBooleanGetTypeID()) {
1003 int bval
= CFBooleanGetValue(value
);
1004 result
= SecDbBindInt(stmt
, param
, bval
, error
);
1005 } else if (valueId
== CFNumberGetTypeID()) {
1007 if (CFNumberIsFloatType(value
)) {
1009 convertOk
= CFNumberGetValue(value
, kCFNumberDoubleType
, &nval
);
1010 result
= SecDbBindDouble(stmt
, param
, nval
, error
);
1013 convertOk
= CFNumberGetValue(value
, kCFNumberSInt32Type
, &nval
);
1015 result
= SecDbBindInt(stmt
, param
, nval
, error
);
1017 sqlite_int64 nval64
;
1018 convertOk
= CFNumberGetValue(value
, kCFNumberSInt64Type
, &nval64
);
1020 result
= SecDbBindInt64(stmt
, param
, nval64
, error
);
1024 result
= SecDbError(SQLITE_INTERNAL
, error
, CFSTR("bind CFNumberGetValue failed for %@"), value
);
1028 CFStringRef valueDesc
= CFCopyTypeIDDescription(valueId
);
1029 SecDbError(SQLITE_MISMATCH
, error
, CFSTR("bind unsupported type %@"), valueDesc
);
1030 CFReleaseSafe(valueDesc
);
1038 // MARK: SecDbStatementRef
1040 bool SecDbReset(sqlite3_stmt
*stmt
, CFErrorRef
*error
) {
1041 return SecDbErrorWithStmt(sqlite3_reset(stmt
), stmt
, error
, CFSTR("reset"));
1044 bool SecDbClearBindings(sqlite3_stmt
*stmt
, CFErrorRef
*error
) {
1045 return SecDbErrorWithStmt(sqlite3_clear_bindings(stmt
), stmt
, error
, CFSTR("clear bindings"));
1048 bool SecDbFinalize(sqlite3_stmt
*stmt
, CFErrorRef
*error
) {
1049 int s3e
= sqlite3_finalize(stmt
);
1050 return s3e
== SQLITE_OK
? true : SecDbErrorWithDb(s3e
, sqlite3_db_handle(stmt
), error
, CFSTR("finalize: %p"), stmt
);
1053 sqlite3_stmt
*SecDbPrepareV2(SecDbConnectionRef dbconn
, const char *sql
, size_t sqlLen
, const char **sqlTail
, CFErrorRef
*error
) {
1054 sqlite3
*db
= SecDbHandle(dbconn
);
1055 if (sqlLen
> INT_MAX
) {
1056 SecDbErrorWithDb(SQLITE_TOOBIG
, db
, error
, CFSTR("prepare_v2: sql bigger than INT_MAX"));
1059 struct timespec sleeptime
= { .tv_sec
= 0, .tv_nsec
= 10000 };
1061 sqlite3_stmt
*stmt
= NULL
;
1062 int s3e
= sqlite3_prepare_v2(db
, sql
, (int)sqlLen
, &stmt
, sqlTail
);
1063 if (s3e
== SQLITE_OK
)
1065 else if (!SecDbWaitIfNeeded(dbconn
, s3e
, NULL
, CFSTR("preparev2"), &sleeptime
, error
))
1070 static sqlite3_stmt
*SecDbCopyStatementWithTailRange(SecDbConnectionRef dbconn
, CFStringRef sql
, CFRange
*sqlTail
, CFErrorRef
*error
) {
1071 __block sqlite3_stmt
*stmt
= NULL
;
1072 if (sql
) CFStringPerformWithCStringAndLength(sql
, ^(const char *sqlStr
, size_t sqlLen
) {
1073 const char *tail
= NULL
;
1074 stmt
= SecDbPrepareV2(dbconn
, sqlStr
, sqlLen
, &tail
, error
);
1075 if (sqlTail
&& sqlStr
< tail
&& tail
< sqlStr
+ sqlLen
) {
1076 sqlTail
->location
= tail
- sqlStr
;
1077 sqlTail
->length
= sqlLen
- sqlTail
->location
;
1084 sqlite3_stmt
*SecDbCopyStmt(SecDbConnectionRef dbconn
, CFStringRef sql
, CFStringRef
*tail
, CFErrorRef
*error
) {
1085 // TODO: Add caching and cache lookup of statements
1086 CFRange sqlTail
= {};
1087 sqlite3_stmt
*stmt
= SecDbCopyStatementWithTailRange(dbconn
, sql
, &sqlTail
, error
);
1088 if (sqlTail
.length
> 0) {
1089 CFStringRef excess
= CFStringCreateWithSubstring(CFGetAllocator(sql
), sql
, sqlTail
);
1093 SecDbError(SQLITE_INTERNAL
, error
,
1094 CFSTR("prepare_v2: %@ unused sql: %@"),
1096 CFReleaseSafe(excess
);
1097 SecDbFinalize(stmt
, error
);
1105 TODO: Could do a hack here with a custom kCFAllocatorNULL allocator for a second CFRuntimeBase inside a SecDbStatement,
1106 TODO: Better yet make a full blow SecDbStatement instance whenever SecDbCopyStmt is called. Then, when the statement is released, in the Dispose method, we Reset and ClearBindings the sqlite3_stmt * and hand it back to the SecDb with the original CFStringRef for the sql (or hash thereof) as an argument. */
1107 bool SecDbReleaseCachedStmt(SecDbConnectionRef dbconn
, CFStringRef sql
, sqlite3_stmt
*stmt
, CFErrorRef
*error
) {
1109 return SecDbReset(stmt
, error
) && SecDbClearBindings(stmt
, error
) && SecDbFinalize(stmt
, error
);
1114 bool SecDbPrepare(SecDbConnectionRef dbconn
, CFStringRef sql
, CFErrorRef
*error
, void(^exec
)(sqlite3_stmt
*stmt
)) {
1115 assert(sql
!= NULL
);
1116 sqlite3_stmt
*stmt
= SecDbCopyStmt(dbconn
, sql
, NULL
, error
);
1121 return SecDbReleaseCachedStmt(dbconn
, sql
, stmt
, error
);
1124 bool SecDbWithSQL(SecDbConnectionRef dbconn
, CFStringRef sql
, CFErrorRef
*error
, bool(^perform
)(sqlite3_stmt
*stmt
)) {
1128 CFStringRef tail
= NULL
;
1130 sqlite3_stmt
*stmt
= SecDbCopyStmt(dbconn
, sql
, &tail
, error
);
1136 // TODO: Use a different error scope here.
1137 ok
= SecError(-50 /* errSecParam */, error
, CFSTR("SecDbWithSQL perform block missing"));
1139 ok
&= SecDbReleaseCachedStmt(dbconn
, sql
, stmt
, error
);
1142 // TODO We already have an error here we really just want the left over sql in it's userData
1143 ok
= SecDbError(SQLITE_ERROR
, error
, CFSTR("Error with unexecuted sql remaining %@"), sql
);
1152 /* SecDbForEach returns true if all SQLITE_ROW returns of sqlite3_step() return true from the row block.
1153 If the row block returns false and doesn't set an error (to indicate it has reached a limit),
1154 this entire function returns false. In that case no error will be set. */
1155 bool SecDbForEach(sqlite3_stmt
*stmt
, CFErrorRef
*error
, bool(^row
)(int row_index
)) {
1156 bool result
= false;
1157 for (int row_ix
= 0;;++row_ix
) {
1158 int s3e
= sqlite3_step(stmt
);
1159 if (s3e
== SQLITE_ROW
) {
1165 // If we have no row block then getting SQLITE_ROW is an error
1166 SecDbError(s3e
, error
,
1167 CFSTR("step[%d]: %s returned SQLITE_ROW with NULL row block"),
1168 row_ix
, sqlite3_sql(stmt
));
1171 if (s3e
== SQLITE_DONE
) {
1174 SecDbErrorWithStmt(s3e
, stmt
, error
, CFSTR("step[%d]"), row_ix
);
1182 bool SecDbForEach(sqlite3_stmt
*stmt
, CFErrorRef
*error
, bool(^row
)(int row_index
)) {
1185 switch (_SecDbStep(dbconn
, stmt
, error
)) {
1186 case kSecDbErrorStep
:
1193 SecDbError(SQLITE_ERROR
, error
, CFSTR("SecDbStep SQLITE_ROW returned without a row handler"));
1196 case kSecDbDoneStep
:
1203 CFGiblisFor(SecDbConnection
)