2 * Copyright (c) 2012-2017 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
26 #include "SecDbInternal.h"
27 #include "debugging.h"
30 #include <sqlite3_private.h>
31 #include <CoreFoundation/CoreFoundation.h>
35 #include <AssertMacros.h>
36 #include "SecCFWrappers.h"
37 #include "SecCFError.h"
38 #include "SecIOFormat.h"
40 #include "Security/SecBase.h"
41 #include "SecAutorelease.h"
42 #include <os/assumes.h>
43 #include <xpc/private.h> // xpc_transaction_exit_clean()
47 // Architecturally inverted files
48 // These are in SecureObjectSync but utilities depends on them
49 // <rdar://problem/20802079> Fix layer violation (SOSDigestVector, SOSManifest, SecDB.c)
51 #include "keychain/SecureObjectSync/SOSDigestVector.h"
52 #include "keychain/SecureObjectSync/SOSManifest.h"
54 #define SECDB_DEBUGGING 0
56 struct __OpaqueSecDbStatement
{
59 SecDbConnectionRef dbconn
;
63 struct __OpaqueSecDbConnection
{
66 //CFMutableDictionaryRef statements;
68 SecDbRef db
; // NONRETAINED, since db or block retains us
71 SecDbTransactionSource source
;
73 int maybeCorruptedCode
;
75 CFErrorRef corruptionError
;
77 // Pending deletions and additions for the current transaction
78 // Entires are either:
79 // 1) a CFArrayRef of 1 element representing a deletion,
80 // 2) a CFArrayRef of 2 elements representing the element 0 having been replaced with element 1
81 // 3) a CFTypeRef that is not a CFArrayRef, representing an add of the element in question.
82 CFMutableArrayRef changes
;
85 struct __OpaqueSecDb
{
89 dispatch_queue_t queue
;
90 dispatch_queue_t commitQueue
;
92 CFMutableArrayRef idleWriteConnections
; // up to kSecDbMaxWriters of them (currently 1, requires locking change for >1)
93 CFMutableArrayRef idleReadConnections
; // up to kSecDbMaxReaders of them
94 pthread_mutex_t writeMutex
;
95 // TODO: Replace after we have rdar://problem/60961964
96 dispatch_semaphore_t readSemaphore
;
99 bool (^opened
)(SecDbRef db
, SecDbConnectionRef dbconn
, bool didCreate
, bool *callMeAgainForNextConnection
, CFErrorRef
*error
);
100 bool callOpenedHandlerForNextConnection
;
101 CFMutableArrayRef notifyPhase
; /* array of SecDBNotifyBlock */
102 mode_t mode
; /* database file permissions */
103 bool readWrite
; /* open database read-write */
104 bool allowRepair
; /* allow database repair */
105 bool useWAL
; /* use WAL mode */
106 bool useRobotVacuum
; /* use if SecDB should manage vacuum behind your back */
107 uint8_t maxIdleHandles
;
108 void (^corruptionReset
)(void);
111 // MARK: Error domains and error helper functions
113 CFStringRef kSecDbErrorDomain
= CFSTR("com.apple.utilities.sqlite3");
115 bool SecDbError(int sql_code
, CFErrorRef
*error
, CFStringRef format
, ...) {
116 if (sql_code
== SQLITE_OK
) return true;
120 CFIndex code
= sql_code
;
121 CFErrorRef previousError
= *error
;
124 va_start(args
, format
);
125 SecCFCreateErrorWithFormatAndArguments(code
, kSecDbErrorDomain
, previousError
, error
, NULL
, format
, args
);
131 bool SecDbErrorWithDb(int sql_code
, sqlite3
*db
, CFErrorRef
*error
, CFStringRef format
, ...) {
132 if (sql_code
== SQLITE_OK
) return true;
135 va_start(args
, format
);
136 CFStringRef message
= CFStringCreateWithFormatAndArguments(kCFAllocatorDefault
, NULL
, format
, args
);
138 CFStringRef errno_code
= NULL
;
140 if (sql_code
== SQLITE_CANTOPEN
) {
141 int errno_number
= sqlite3_system_errno(db
);
142 errno_code
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%d"), errno_number
);
144 errno_code
= CFRetain(CFSTR(""));
147 int extended_code
= sqlite3_extended_errcode(db
);
148 if (sql_code
== extended_code
)
149 SecDbError(sql_code
, error
, CFSTR("%@: [%d]%@ %s"), message
, sql_code
, errno_code
, sqlite3_errmsg(db
));
151 SecDbError(sql_code
, error
, CFSTR("%@: [%d->%d]%@ %s"), message
, sql_code
, extended_code
, errno_code
, sqlite3_errmsg(db
));
152 CFReleaseSafe(message
);
153 CFReleaseSafe(errno_code
);
158 bool SecDbErrorWithStmt(int sql_code
, sqlite3_stmt
*stmt
, CFErrorRef
*error
, CFStringRef format
, ...) {
159 if (sql_code
== SQLITE_OK
) return true;
162 va_start(args
, format
);
163 CFStringRef message
= CFStringCreateWithFormatAndArguments(kCFAllocatorDefault
, NULL
, format
, args
);
166 sqlite3
*db
= sqlite3_db_handle(stmt
);
167 const char *sql
= sqlite3_sql(stmt
);
168 int extended_code
= sqlite3_extended_errcode(db
);
169 if (sql_code
== extended_code
)
170 SecDbError(sql_code
, error
, CFSTR("%@: [%d] %s sql: %s"), message
, sql_code
, sqlite3_errmsg(db
), sql
);
172 SecDbError(sql_code
, error
, CFSTR("%@: [%d->%d] %s sql: %s"), message
, sql_code
, extended_code
, sqlite3_errmsg(db
), sql
);
173 CFReleaseSafe(message
);
178 // A callback for the sqlite3_log() interface.
179 static void sqlite3Log(void *pArg
, int iErrCode
, const char *zMsg
){
180 secdebug("sqlite3", "(%d) %s", iErrCode
, zMsg
);
183 void _SecDbServerSetup(void)
185 static dispatch_once_t onceToken
;
186 dispatch_once(&onceToken
, ^{
187 int rx
= sqlite3_config(SQLITE_CONFIG_LOG
, sqlite3Log
, NULL
);
188 if (SQLITE_OK
!= rx
) {
189 secwarning("Could not set up sqlite global error logging to syslog: %d", rx
);
196 // MARK: Static helper functions
198 static bool SecDbOpenHandle(SecDbConnectionRef dbconn
, bool *created
, CFErrorRef
*error
);
199 static bool SecDbHandleCorrupt(SecDbConnectionRef dbconn
, int rc
, CFErrorRef
*error
);
202 #pragma mark SecDbRef
205 SecDbCopyFormatDescription(CFTypeRef value
, CFDictionaryRef formatOptions
)
207 SecDbRef db
= (SecDbRef
)value
;
208 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("<SecDb path:%@ connections: %@>"), db
->db_path
, db
->idleReadConnections
);
213 SecDbDestroy(CFTypeRef value
)
215 SecDbRef db
= (SecDbRef
)value
;
217 CFReleaseNull(db
->db_path
);
218 dispatch_sync(db
->queue
, ^{
219 CFReleaseNull(db
->idleWriteConnections
);
220 CFReleaseNull(db
->idleReadConnections
);
224 dispatch_release(db
->queue
);
227 if (db
->commitQueue
) {
228 dispatch_release(db
->commitQueue
);
229 db
->commitQueue
= NULL
;
232 pthread_mutex_destroy(&(db
->writeMutex
));
234 if (db
->readSemaphore
) {
235 dispatch_release(db
->readSemaphore
);
236 db
->readSemaphore
= NULL
;
240 Block_release(db
->opened
);
243 CFReleaseNull(db
->notifyPhase
);
249 SecDbCreate(CFStringRef dbName
, mode_t mode
, bool readWrite
, bool allowRepair
, bool useWAL
, bool useRobotVacuum
, uint8_t maxIdleHandles
,
250 bool (^opened
)(SecDbRef db
, SecDbConnectionRef dbconn
, bool didCreate
, bool *callMeAgainForNextConnection
, CFErrorRef
*error
))
254 db
= CFTypeAllocate(SecDb
, struct __OpaqueSecDb
, kCFAllocatorDefault
);
255 require(db
!= NULL
, done
);
257 CFStringPerformWithCString(dbName
, ^(const char *dbNameStr
) {
258 db
->queue
= dispatch_queue_create(dbNameStr
, DISPATCH_QUEUE_SERIAL
);
260 CFStringRef commitQueueStr
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%@-commit"), dbName
);
261 CFStringPerformWithCString(commitQueueStr
, ^(const char *cqNameStr
) {
262 db
->commitQueue
= dispatch_queue_create(cqNameStr
, DISPATCH_QUEUE_CONCURRENT
);
264 CFReleaseNull(commitQueueStr
);
265 db
->readSemaphore
= dispatch_semaphore_create(kSecDbMaxReaders
);
266 if (pthread_mutex_init(&(db
->writeMutex
), NULL
) != 0) {
267 seccritical("SecDb: SecDbCreate failed to init the write mutex, this will end badly");
269 db
->idleWriteConnections
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
270 db
->idleReadConnections
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
271 db
->opened
= opened
? Block_copy(opened
) : NULL
;
272 if (getenv("__OSINSTALL_ENVIRONMENT") != NULL
) {
273 // TODO: Move this code out of this layer
274 secinfo("#SecDB", "SecDB: running from installer");
276 db
->db_path
= CFSTR("file::memory:?cache=shared");
278 db
->db_path
= CFStringCreateCopy(kCFAllocatorDefault
, dbName
);
281 db
->readWrite
= readWrite
;
282 db
->allowRepair
= allowRepair
;
284 db
->useRobotVacuum
= useRobotVacuum
;
285 db
->maxIdleHandles
= maxIdleHandles
;
286 db
->corruptionReset
= NULL
;
293 SecDbIdleConnectionCount(SecDbRef db
) {
294 __block CFIndex count
= 0;
295 dispatch_sync(db
->queue
, ^{
296 count
= CFArrayGetCount(db
->idleReadConnections
);
297 count
+= CFArrayGetCount(db
->idleWriteConnections
);
302 void SecDbAddNotifyPhaseBlock(SecDbRef db
, SecDBNotifyBlock notifyPhase
)
304 #if !TARGET_OS_BRIDGE
305 // SecDbNotifyPhase seems to mostly be called on the db's commitQueue, and not the db's queue. Therefore, protect the array with that queue.
306 dispatch_sync(db
->commitQueue
, ^{
307 SecDBNotifyBlock block
= Block_copy(notifyPhase
); /* Force the block off the stack */
308 if (db
->notifyPhase
== NULL
) {
309 db
->notifyPhase
= CFArrayCreateMutableForCFTypes(NULL
);
311 CFArrayAppendValue(db
->notifyPhase
, block
);
312 Block_release(block
);
317 static void SecDbNotifyPhase(SecDbConnectionRef dbconn
, SecDbTransactionPhase phase
) {
318 #if !TARGET_OS_BRIDGE
319 if (CFArrayGetCount(dbconn
->changes
)) {
320 CFArrayRef changes
= dbconn
->changes
;
321 dbconn
->changes
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
322 if (dbconn
->db
->notifyPhase
) {
323 CFArrayForEach(dbconn
->db
->notifyPhase
, ^(const void *value
) {
324 SecDBNotifyBlock notifyBlock
= (SecDBNotifyBlock
)value
;
325 notifyBlock(dbconn
, phase
, dbconn
->source
, changes
);
328 CFReleaseSafe(changes
);
333 static void SecDbOnNotify(SecDbConnectionRef dbconn
, void (^perform
)(void)) {
337 CFStringRef
SecDbGetPath(SecDbRef db
) {
346 #pragma mark SecDbConnectionRef
348 static bool SecDbCheckCorrupted(SecDbConnectionRef dbconn
)
350 __block
bool checkDidRun
= false;
351 __block
bool isCorrupted
= false;
352 __block CFErrorRef error
= NULL
;
353 SecDbPrepare(dbconn
, CFSTR("PRAGMA integrity_check"), &error
, ^(sqlite3_stmt
*stmt
) {
354 SecDbStep(dbconn
, stmt
, &error
, ^(bool *stop
) {
355 const char * result
= (const char*)sqlite3_column_text(stmt
, 0);
356 if (!result
|| strncasecmp(result
, "ok", 3) != 0) {
358 secerror("SecDBCheckCorrupted integrity_check returned %s", (result
) ? result
: "NULL");
364 // An error occurred in SecDbPrepare before we could run the block.
366 CFIndex code
= CFErrorGetCode(error
);
367 if (SQLITE_CORRUPT
== code
|| SQLITE_NOTADB
== code
) {
370 secinfo("#SecDB", "#SecDB warning error %{public}@ when running integrity check", error
);
372 // We don't have an error ref if SecDbPrepare has called SecDbConnectionCheckCode,
373 // which then called SecDbHandleCorrupt. That code path is only entered when the
374 // original error was SQLITE_CORRUPT or SQLITE_NOTADB. On other errors, the
375 // CFErrorRef is not cleared and we can just check the code above.
377 secinfo("#SecDB", "#SecDB warning: failed to run integrity check due to corruption");
382 secerror("SecDBCheckCorrupted ran integrity_check, and that didn't return ok");
384 secerror("SecDBCheckCorrupted failed to run integrity check");
387 CFReleaseNull(error
);
392 static bool SecDbDidCreateFirstConnection(SecDbConnectionRef dbconn
, bool didCreate
, CFErrorRef
*error
)
394 secinfo("#SecDB", "#SecDB starting maintenance");
397 // Historical note: this used to check for integrity but that became too slow and caused panics at boot.
398 // Now, just react to SQLite errors when doing an operation. If file on disk is borked it'll tell us right away.
400 if (!dbconn
->isCorrupted
&& dbconn
->db
->opened
) {
401 CFErrorRef localError
= NULL
;
403 dbconn
->db
->callOpenedHandlerForNextConnection
= false;
404 ok
= dbconn
->db
->opened(dbconn
->db
, dbconn
, didCreate
, &dbconn
->db
->callOpenedHandlerForNextConnection
, &localError
);
407 secerror("opened block failed: %@", localError
);
409 if (!dbconn
->isCorrupted
&& error
&& *error
== NULL
) {
414 secerror("opened block failed: error (%@) is being released and lost", localError
);
415 CFReleaseNull(localError
);
419 if (dbconn
->isCorrupted
) {
420 ok
= SecDbHandleCorrupt(dbconn
, 0, error
);
423 secinfo("#SecDB", "#SecDB starting maintenance");
427 void SecDbCorrupt(SecDbConnectionRef dbconn
, CFErrorRef error
)
429 if (__security_simulatecrash_enabled()) {
430 os_log_fault(secLogObjForScope("SecEmergency"), "SecDBCorrupt: %@", error
);
432 dbconn
->isCorrupted
= true;
433 CFRetainAssign(dbconn
->corruptionError
, error
);
437 static uint8_t knownDbPathIndex(SecDbConnectionRef dbconn
)
440 if(CFEqual(dbconn
->db
->db_path
, CFSTR("/Library/Keychains/keychain-2.db")))
442 if(CFEqual(dbconn
->db
->db_path
, CFSTR("/Library/Keychains/ocspcache.sqlite3")))
444 if(CFEqual(dbconn
->db
->db_path
, CFSTR("/Library/Keychains/TrustStore.sqlite3")))
446 if(CFEqual(dbconn
->db
->db_path
, CFSTR("/Library/Keychains/caissuercache.sqlite3")))
449 /* Unknown DB path */
453 static bool SecDbConnectionCheckCode(SecDbConnectionRef dbconn
, int code
, CFErrorRef
*error
, CFStringRef desc
, ...)
454 CF_FORMAT_FUNCTION(4, 5);
456 // Return true if there was no error, returns false otherwise and set *error to an appropriate CFErrorRef.
457 static bool SecDbConnectionCheckCode(SecDbConnectionRef dbconn
, int code
, CFErrorRef
*error
, CFStringRef desc
, ...) {
458 if (code
== SQLITE_OK
|| code
== SQLITE_DONE
)
463 va_start(args
, desc
);
464 CFStringRef msg
= CFStringCreateWithFormatAndArguments(kCFAllocatorDefault
, NULL
, desc
, args
);
466 SecDbErrorWithDb(code
, dbconn
->handle
, error
, CFSTR("%@"), msg
);
470 dbconn
->hasIOFailure
|= (SQLITE_IOERR
== code
);
472 /* If it's already corrupted, don't try to recover */
473 if (dbconn
->isCorrupted
) {
474 CFStringRef reason
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
,
475 CFSTR("SQL DB %@ is corrupted already. Corruption error was: %d (previously %d)"),
476 dbconn
->db
->db_path
, code
, dbconn
->maybeCorruptedCode
);
477 secerror("%@",reason
);
478 __security_simulatecrash(reason
, __sec_exception_code_TwiceCorruptDb(knownDbPathIndex(dbconn
)));
479 CFReleaseSafe(reason
);
480 // We can't fall through to the checking case because it eventually calls SecDbConnectionCheckCode again.
481 // However, this is the second time we're seeing corruption so let's take the ultimate measure.
482 if ((SQLITE_CORRUPT
== code
) || (SQLITE_NOTADB
== code
)) {
483 secerror("SecDbConnectionCheckCode detected corruption twice: going to handle corrupt DB");
484 (void)SecDbHandleCorrupt(dbconn
, code
, error
);
489 // NOTADB means file is garbage, so it's functionally equivalent to corruption
490 dbconn
->isCorrupted
= (SQLITE_CORRUPT
== code
) || (SQLITE_NOTADB
== code
);
491 if (dbconn
->isCorrupted
) {
492 /* Run integrity check and only make dbconn->isCorrupted true and
493 run the corruption handler if the integrity check conclusively fails. */
494 dbconn
->maybeCorruptedCode
= code
;
495 dbconn
->isCorrupted
= SecDbCheckCorrupted(dbconn
);
496 if (dbconn
->isCorrupted
) {
497 secerror("operation returned code: %d integrity check=fail", code
);
498 (void)SecDbHandleCorrupt(dbconn
, code
, error
);
500 secerror("operation returned code: %d: integrity check=pass", code
);
507 #define BUSY_TIMEOUT_MS (5 * 60 * 1000) /* 5 minutes */
509 static int sleepBackoff
[] = { 10, 20, 50, 100, 250 };
510 static int sumBackoff
[] = { 10, 30, 80, 180, 430 };
511 static int NumberOfSleepBackoff
= sizeof(sleepBackoff
)/sizeof(sleepBackoff
[0]);
513 // Use these as silly hacks to encode the SQLite return code in the backtrace, for hang debugging purposes
514 static void __attribute__((noinline
)) SecDbLockSleep(int ms
) {
518 static void __attribute__((noinline
)) SecDbBusySleep(int ms
) {
522 // Return true causes the operation to be tried again.
523 // Note that we set sqlite3_busy_timeout on the connection, so anytime you're in here, it's likely due to SQLITE_LOCKED.
524 static bool SecDbWaitIfNeeded(SecDbConnectionRef dbconn
, int s3e
, sqlite3_stmt
*stmt
, CFStringRef desc
, int nTries
, CFErrorRef
*error
) {
525 if (((0xFF & s3e
) == SQLITE_BUSY
) || ((0xFF & s3e
) == SQLITE_LOCKED
)) {
526 int totaltimeout
, timeout
;
528 _Static_assert(sizeof(sumBackoff
) == sizeof(sleepBackoff
), "matching arrays not matching");
529 _Static_assert(sizeof(sumBackoff
[0]) == sizeof(sleepBackoff
[0]), "matching arrays not matching");
531 if (nTries
< NumberOfSleepBackoff
) {
532 timeout
= sleepBackoff
[nTries
];
533 totaltimeout
= sumBackoff
[nTries
];
535 timeout
= sleepBackoff
[NumberOfSleepBackoff
- 1];
536 totaltimeout
= sumBackoff
[NumberOfSleepBackoff
- 1] + (timeout
* (nTries
- NumberOfSleepBackoff
));
538 if (totaltimeout
< BUSY_TIMEOUT_MS
) {
539 secinfo("#SecDB", "sqlite busy/locked: %d ntries: %d totaltimeout: %d", s3e
, nTries
, totaltimeout
);
540 if(((0xFF & s3e
) == SQLITE_LOCKED
)) {
541 SecDbLockSleep(timeout
);
543 SecDbBusySleep(timeout
);
547 secinfo("#SecDB", "sqlite busy/locked: too long: %d ms, giving up", totaltimeout
);
551 return SecDbConnectionCheckCode(dbconn
, s3e
, error
, CFSTR("%@"), desc
);
554 enum SecDbStepResult
{
559 typedef enum SecDbStepResult SecDbStepResult
;
561 static SecDbStepResult
_SecDbStep(SecDbConnectionRef dbconn
, sqlite3_stmt
*stmt
, CFErrorRef
*error
) {
562 assert(stmt
!= NULL
);
566 if (SecDbConnectionIsReadOnly(dbconn
) && !sqlite3_stmt_readonly(stmt
)) {
567 secerror("_SecDbStep: SecDbConnection is readonly but we're about to write: %s", sqlite3_sql(stmt
));
569 s3e
= sqlite3_step(stmt
);
570 if (s3e
== SQLITE_ROW
) {
571 return kSecDbRowStep
;
572 } else if (s3e
== SQLITE_DONE
) {
574 ** ^[SQLITE_DONE] means that the statement has finished executing
575 ** successfully. sqlite3_step() should not be called again on this virtual
576 ** machine without first calling [] to reset the virtual
577 ** machine back to its initial state.
580 return kSecDbDoneStep
;
581 } else if (!SecDbWaitIfNeeded(dbconn
, s3e
, stmt
, CFSTR("step"), ntries
, error
)) {
582 return kSecDbErrorStep
;
589 SecDbExec(SecDbConnectionRef dbconn
, CFStringRef sql
, CFErrorRef
*error
)
594 CFStringRef tail
= NULL
;
596 sqlite3_stmt
*stmt
= SecDbCopyStmt(dbconn
, sql
, &tail
, error
);
600 while ((sr
= _SecDbStep(dbconn
, stmt
, error
)) == kSecDbRowStep
);
601 if (sr
== kSecDbErrorStep
)
603 ok
&= SecDbReleaseCachedStmt(dbconn
, sql
, stmt
, error
);
606 // TODO We already have an error here we really just want the left over sql in it's userData
607 ok
= SecDbError(SQLITE_ERROR
, error
, CFSTR("Error with unexecuted sql remaining %@"), sql
);
615 static int SecDBGetInteger(SecDbConnectionRef dbconn
, CFStringRef sql
)
617 __block
int number
= -1;
618 __block CFErrorRef error
= NULL
;
620 (void)SecDbWithSQL(dbconn
, sql
, &error
, ^bool(sqlite3_stmt
*sqlStmt
) {
621 (void)SecDbStep(dbconn
, sqlStmt
, &error
, ^(bool *stop
) {
622 number
= sqlite3_column_int(sqlStmt
, 0);
627 CFReleaseNull(error
);
632 void SecDBManagementTasks(SecDbConnectionRef dbconn
)
634 int64_t page_count
= SecDBGetInteger(dbconn
, CFSTR("pragma page_count"));
635 if (page_count
<= 0) {
638 int64_t free_count
= SecDBGetInteger(dbconn
, CFSTR("pragma freelist_count"));
639 if (free_count
< 0) {
643 int64_t max_free
= 8192;
645 int64_t pages_in_use
= page_count
- free_count
;
646 double loadFactor
= ((double)pages_in_use
/(double)page_count
);
647 if (0.85 < loadFactor
&& free_count
< max_free
) {
650 int64_t pages_to_free
= (int64_t)(0.2 * free_count
);
651 if (0.4 > loadFactor
) {
652 pages_to_free
= free_count
;
655 char *formatString
= NULL
;
656 asprintf(&formatString
, "pragma incremental_vacuum(%d)", (int)pages_to_free
);
658 char *sqlerror
= NULL
;
659 int rc
= sqlite3_exec(dbconn
->handle
, formatString
, NULL
, NULL
, &sqlerror
);
661 secerror("incremental_vacuum failed with: (%d) %{public}s", rc
, sqlerror
);
663 sqlite3_free(sqlerror
);
670 static bool SecDbBeginTransaction(SecDbConnectionRef dbconn
, SecDbTransactionType type
, CFErrorRef
*error
)
675 case kSecDbImmediateTransactionType
:
676 secdebug("db", "SecDbBeginTransaction SecDbBeginTransaction %p", dbconn
);
677 query
= CFSTR("BEGIN IMMEDIATE");
679 case kSecDbExclusiveRemoteSOSTransactionType
:
680 secdebug("db", "SecDbBeginTransaction kSecDbExclusiveRemoteSOSTransactionType %p", dbconn
);
681 dbconn
->source
= kSecDbSOSTransaction
;
682 query
= CFSTR("BEGIN EXCLUSIVE");
684 case kSecDbExclusiveRemoteCKKSTransactionType
:
685 secdebug("db", "SecDbBeginTransaction kSecDbExclusiveRemoteCKKSTransactionType %p", dbconn
);
686 dbconn
->source
= kSecDbCKKSTransaction
;
687 query
= CFSTR("BEGIN EXCLUSIVE");
689 case kSecDbExclusiveTransactionType
:
690 if (type
==kSecDbExclusiveTransactionType
)
691 secdebug("db", "SecDbBeginTransaction kSecDbExclusiveTransactionType %p", dbconn
);
692 query
= CFSTR("BEGIN EXCLUSIVE");
694 case kSecDbNormalTransactionType
:
695 secdebug("db", "SecDbBeginTransaction kSecDbNormalTransactionType %p", dbconn
);
696 query
= CFSTR("BEGIN");
699 secdebug("db", "SecDbBeginTransaction invalid transaction type %lu", type
);
700 ok
= SecDbError(SQLITE_ERROR
, error
, CFSTR("invalid transaction type %d"), (int)type
);
705 if (query
!= NULL
&& sqlite3_get_autocommit(dbconn
->handle
) != 0) {
706 ok
= SecDbExec(dbconn
, query
, error
);
709 dbconn
->inTransaction
= true;
714 static bool SecDbEndTransaction(SecDbConnectionRef dbconn
, bool commit
, CFErrorRef
*error
)
716 __block
bool ok
= true;
717 __block
bool commited
= false;
719 dispatch_block_t notifyAndExec
= ^{
721 //secdebug("db", "SecDbEndTransaction kSecDbTransactionWillCommit %p", dbconn);
722 SecDbNotifyPhase(dbconn
, kSecDbTransactionWillCommit
);
723 commited
= ok
= SecDbExec(dbconn
, CFSTR("END"), error
);
724 //secdebug("db", "SecDbEndTransaction kSecDbTransactionWillCommit %p (after notify)", dbconn);
726 ok
= SecDbExec(dbconn
, CFSTR("ROLLBACK"), error
);
729 dbconn
->inTransaction
= false;
730 SecDbNotifyPhase(dbconn
, commited
? kSecDbTransactionDidCommit
: kSecDbTransactionDidRollback
);
731 secdebug("db", "SecDbEndTransaction %s %p", commited
? "kSecDbTransactionDidCommit" : "kSecDbTransactionDidRollback", dbconn
);
732 dbconn
->source
= kSecDbAPITransaction
;
734 if (commit
&& dbconn
->db
->useRobotVacuum
) {
735 SecDBManagementTasks(dbconn
);
739 SecDbPerformOnCommitQueue(dbconn
, true, notifyAndExec
);
744 bool SecDbTransaction(SecDbConnectionRef dbconn
, SecDbTransactionType type
,
745 CFErrorRef
*error
, void (^transaction
)(bool *commit
))
750 if (dbconn
->inTransaction
) {
751 transaction(&commit
);
753 secinfo("#SecDB", "#SecDB nested transaction asked to not be committed");
756 ok
= SecDbBeginTransaction(dbconn
, type
, error
);
758 transaction(&commit
);
759 ok
= SecDbEndTransaction(dbconn
, commit
, error
);
766 sqlite3
*SecDbHandle(SecDbConnectionRef dbconn
) {
767 return dbconn
->handle
;
770 bool SecDbStep(SecDbConnectionRef dbconn
, sqlite3_stmt
*stmt
, CFErrorRef
*error
, void (^row
)(bool *stop
)) {
772 switch (_SecDbStep(dbconn
, stmt
, error
)) {
773 case kSecDbErrorStep
:
774 secdebug("db", "kSecDbErrorStep %@", error
? *error
: NULL
);
778 secdebug("db", "kSecDbRowStep %@", error
? *error
: NULL
);
781 __block
bool stop
= false;
782 SecAutoreleaseInvokeWithPool(^{
789 SecDbError(SQLITE_ERROR
, error
, CFSTR("SecDbStep SQLITE_ROW returned without a row handler"));
793 secdebug("db", "kSecDbDoneStep %@", error
? *error
: NULL
);
800 bool SecDbCheckpoint(SecDbConnectionRef dbconn
, CFErrorRef
*error
)
802 return SecDbConnectionCheckCode(dbconn
, sqlite3_wal_checkpoint(dbconn
->handle
, NULL
), error
, CFSTR("wal_checkpoint"));
805 static sqlite3
*_SecDbOpenV2(const char *path
,
810 sqlite3
*handle
= NULL
;
811 int s3e
= sqlite3_open_v2(path
, &handle
, flags
, NULL
);
814 SecDbErrorWithDb(s3e
, handle
, error
, CFSTR("open_v2 \"%s\" 0x%X"), path
, flags
);
815 sqlite3_close(handle
);
818 SecDbError(s3e
, error
, CFSTR("open_v2 \"%s\" 0x%X"), path
, flags
);
820 } else if (SQLITE_OPEN_READWRITE
== (flags
& SQLITE_OPEN_READWRITE
)) {
821 if (useRobotVacuum
) {
822 #define SECDB_SQLITE_AUTO_VACUUM_INCREMENTAL 2
823 sqlite3_stmt
*stmt
= NULL
;
827 * Setting auto_vacuum = incremental on a database that is not empty requires
828 * a VACCUUM, so check if the vacuum mode is not INCREMENTAL, and if its not,
829 * set it to incremental and vacuum.
832 s3e
= sqlite3_prepare_v2(handle
, "PRAGMA auto_vacuum", -1, &stmt
, NULL
);
834 s3e
= sqlite3_step(stmt
);
835 if (s3e
== SQLITE_ROW
) {
836 vacuumMode
= sqlite3_column_int(stmt
, 0);
838 (void)sqlite3_finalize(stmt
);
841 if (vacuumMode
!= SECDB_SQLITE_AUTO_VACUUM_INCREMENTAL
) {
842 (void)sqlite3_exec(handle
, "PRAGMA auto_vacuum = incremental", NULL
, NULL
, NULL
);
843 (void)sqlite3_exec(handle
, "VACUUM", NULL
, NULL
, NULL
);
847 (void)sqlite3_exec(handle
, "PRAGMA journal_mode = WAL", NULL
, NULL
, NULL
);
850 // Let SQLite handle timeouts.
851 sqlite3_busy_timeout(handle
, 5*1000);
856 static bool SecDbOpenV2(SecDbConnectionRef dbconn
, const char *path
, int flags
, CFErrorRef
*error
) {
857 return (dbconn
->handle
= _SecDbOpenV2(path
, flags
, dbconn
->db
->useWAL
, dbconn
->db
->useRobotVacuum
, error
)) != NULL
;
860 // This construction lets tests not exit here
861 static void SecDbProductionCorruptionExitHandler(void)
865 void (*SecDbCorruptionExitHandler
)(void) = SecDbProductionCorruptionExitHandler
;
867 void SecDbResetCorruptionExitHandler(void)
869 SecDbCorruptionExitHandler
= SecDbProductionCorruptionExitHandler
;
873 There's not much to do in here because we should only ever be here when
874 SQLite tells us the DB is corrupt, or the DB is unrecoverable because of
875 some fatal logic problem. But we can't shoot it dead either due to client
876 connections. So, first we create a marker to tell ourselves things are bad,
877 then we'll die. When we come back up we'll notice the marker and remove the DB.
879 static bool SecDbHandleCorrupt(SecDbConnectionRef dbconn
, int rc
, CFErrorRef
*error
)
881 if (!dbconn
->db
->allowRepair
) {
882 SecCFCreateErrorWithFormat(rc
, kSecErrnoDomain
, NULL
, error
, NULL
,
883 CFSTR("SecDbHandleCorrupt not allowed to repair, handled error: [%d] %s"), rc
, strerror(rc
));
884 dbconn
->isCorrupted
= false;
888 CFStringPerformWithCString(dbconn
->db
->db_path
, ^(const char *db_path
) {
889 char marker
[PATH_MAX
+1];
890 snprintf(marker
, sizeof(marker
), "%s-iscorrupt", db_path
);
891 struct stat info
= {};
892 if (0 == stat(marker
, &info
)) {
893 secerror("SecDbHandleCorrupt: Tried to write corruption marker %s but one already exists", marker
);
896 FILE* file
= fopen(marker
, "w");
898 secerror("SecDbHandleCorrupt: Unable (%{darwin.errno}d) to create corruption marker %{public}s", errno
, marker
);
904 secwarning("SecDbHandleCorrupt: killing self so that successor might cleanly delete corrupt db");
906 // Call through function pointer so tests can replace it and call a SecKeychainDbReset instead
907 SecDbCorruptionExitHandler();
911 static bool SecDbProcessCorruptionMarker(CFStringRef db_path
) {
912 __block
bool ok
= true;
913 CFStringPerformWithCString(db_path
, ^(const char *db_path
) {
914 char marker
[PATH_MAX
+1];
915 snprintf(marker
, sizeof(marker
), "%s-iscorrupt", db_path
);
916 struct stat info
= {};
917 int result
= stat(marker
, &info
);
918 if (result
!= 0 && errno
== ENOENT
) {
920 } else if (result
!= 0) {
921 secerror("SecDbSecDbProcessCorruptionMarker: Unable to check for corruption marker: %{darwin.errno}d", errno
);
925 secwarning("SecDbSecDbProcessCorruptionMarker: found corruption marker %s", marker
);
926 if (remove(marker
)) {
927 secerror("SecDbSecDbProcessCorruptionMarker: Unable (%{darwin.errno}d) to delete corruption marker", errno
);
929 } else if (remove(db_path
) && errno
!= ENOENT
) { // Not sure how we'd get ENOENT but it would suit us just fine
930 secerror("SecDbSecDbProcessCorruptionMarker: Unable (%{darwin.errno}d) to delete db %{public}s", errno
, db_path
);
933 secwarning("SecDbSecDbProcessCorruptionMarker: deleted corrupt db %{public}s", db_path
);
940 SecDbSetCorruptionReset(SecDbRef db
, void (^corruptionReset
)(void))
942 if (db
->corruptionReset
) {
943 Block_release(db
->corruptionReset
);
944 db
->corruptionReset
= NULL
;
946 if (corruptionReset
) {
947 db
->corruptionReset
= Block_copy(corruptionReset
);
951 static bool SecDbLoggingEnabled(CFStringRef type
)
953 CFTypeRef profile
= NULL
;
954 bool enabled
= false;
956 if (csr_check(CSR_ALLOW_APPLE_INTERNAL
) != 0)
959 profile
= (CFNumberRef
)CFPreferencesCopyValue(CFSTR("SQLProfile"), CFSTR("com.apple.security"), kCFPreferencesAnyUser
, kCFPreferencesAnyHost
);
964 if (CFGetTypeID(profile
) == CFBooleanGetTypeID()) {
965 enabled
= CFBooleanGetValue((CFBooleanRef
)profile
);
966 } else if (CFGetTypeID(profile
) == CFNumberGetTypeID()) {
968 CFNumberGetValue(profile
, kCFNumberSInt32Type
, &num
);
972 CFReleaseSafe(profile
);
978 SecDbProfileMask(void)
980 static dispatch_once_t onceToken
;
981 static unsigned profile_mask
= 0;
983 // sudo defaults write /Library/Preferences/com.apple.security SQLProfile -bool true
984 dispatch_once(&onceToken
, ^{
985 if (SecDbLoggingEnabled(CFSTR("SQLProfile")))
986 profile_mask
= SQLITE_TRACE_PROFILE
;
988 profile_mask
|= SQLITE_TRACE_STMT
;
990 if (SecDbLoggingEnabled(CFSTR("SQLTrace")))
991 profile_mask
= SQLITE_TRACE_STMT
;
993 if (SecDbLoggingEnabled(CFSTR("SQLRow")))
994 profile_mask
= SQLITE_TRACE_ROW
;
995 secinfo("#SecDB", "sqlDb: sql trace mask: 0x%08x", profile_mask
);
1001 SecDbTraceV2(unsigned mask
, void *ctx
, void *p
, void *x
) {
1002 SecDbConnectionRef dbconn __unused
= ctx
;
1005 const char *trace
= "unknown";
1006 char *tofree
= NULL
;
1008 if (mask
== SQLITE_TRACE_PROFILE
)
1009 trace
= sqlite3_sql(p
);
1010 else if (mask
== SQLITE_TRACE_STMT
) {
1011 trace
= sqlite3_sql(p
);
1012 } else if (mask
== SQLITE_TRACE_ROW
) {
1013 trace
= tofree
= sqlite3_expanded_sql(p
);
1016 secinfo("#SecDB", "#SecDB %{public}s", trace
);
1018 sqlite3_free(tofree
);
1025 static bool SecDbOpenHandle(SecDbConnectionRef dbconn
, bool *created
, CFErrorRef
*error
)
1027 __block
bool ok
= true;
1029 // This is pretty terrible because now what? We know we have a corrupt DB
1030 // and now we can't get rid of it.
1031 if (!SecDbProcessCorruptionMarker(dbconn
->db
->db_path
)) {
1032 SecCFCreateErrorWithFormat(errno
, kSecErrnoDomain
, NULL
, error
, NULL
, CFSTR("Unable to process corruption marker: %{darwin.errno}d"), errno
);
1036 CFStringPerformWithCString(dbconn
->db
->db_path
, ^(const char *db_path
) {
1037 int flags
= (dbconn
->db
->readWrite
) ? SQLITE_OPEN_READWRITE
: SQLITE_OPEN_READONLY
;
1038 ok
= created
&& SecDbOpenV2(dbconn
, db_path
, flags
, NULL
);
1042 char *tmp
= dirname((char *)db_path
);
1044 mode_t omode
= dbconn
->db
->mode
;
1045 if (omode
& S_IRUSR
) { omode
|= S_IXUSR
; } // owner can read
1046 if (omode
& S_IRGRP
) { omode
|= S_IXGRP
; } // group can read
1047 if (omode
& S_IROTH
) { omode
|= S_IXOTH
; } // other can read
1048 int errnum
= mkpath_np(tmp
, omode
);
1049 if (errnum
!= 0 && errnum
!= EEXIST
) {
1050 SecCFCreateErrorWithFormat(errnum
, kSecErrnoDomain
, NULL
, error
, NULL
,
1051 CFSTR("mkpath_np %s: [%d] %s"), tmp
, errnum
, strerror(errnum
));
1056 // if the enclosing directory is ok, try to create the database.
1057 // this forces us to open it read-write, so we'll need to be the owner here.
1058 ok
= ok
&& SecDbOpenV2(dbconn
, db_path
, SQLITE_OPEN_READWRITE
| SQLITE_OPEN_CREATE
, error
);
1060 chmod(db_path
, dbconn
->db
->mode
); // default: 0600 (S_IRUSR | S_IWUSR)
1067 unsigned mask
= SecDbProfileMask();
1069 (void)sqlite3_trace_v2(dbconn
->handle
,
1080 static SecDbConnectionRef
1081 SecDbConnectionCreate(SecDbRef db
, bool readOnly
, CFErrorRef
*error
)
1083 SecDbConnectionRef dbconn
= NULL
;
1085 dbconn
= CFTypeAllocate(SecDbConnection
, struct __OpaqueSecDbConnection
, kCFAllocatorDefault
);
1086 require(dbconn
!= NULL
, done
);
1089 dbconn
->readOnly
= readOnly
;
1090 dbconn
->inTransaction
= false;
1091 dbconn
->source
= kSecDbInvalidTransaction
;
1092 dbconn
->isCorrupted
= false;
1093 dbconn
->maybeCorruptedCode
= 0;
1094 dbconn
->hasIOFailure
= false;
1095 dbconn
->corruptionError
= NULL
;
1096 dbconn
->handle
= NULL
;
1097 dbconn
->changes
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
1103 bool SecDbConnectionIsReadOnly(SecDbConnectionRef dbconn
) {
1104 return dbconn
->readOnly
;
1107 static void SecDbConectionSetReadOnly(SecDbConnectionRef dbconn
, bool readOnly
) {
1108 dbconn
->readOnly
= readOnly
;
1111 SecDbConnectionRef
SecDbConnectionAcquire(SecDbRef db
, bool readOnly
, CFErrorRef
*error
) {
1112 SecDbConnectionRef dbconn
= NULL
;
1113 SecDbConnectionAcquireRefMigrationSafe(db
, readOnly
, &dbconn
, error
);
1117 static void SecDbConnectionConsumeResource(SecDbRef db
, bool readOnly
) {
1119 dispatch_semaphore_wait(db
->readSemaphore
, DISPATCH_TIME_FOREVER
);
1121 pthread_mutex_lock(&(db
->writeMutex
));
1125 static void SecDbConnectionMakeResourceAvailable(SecDbRef db
, bool readOnly
) {
1127 dispatch_semaphore_signal(db
->readSemaphore
);
1129 pthread_mutex_unlock(&(db
->writeMutex
));
1133 bool SecDbConnectionAcquireRefMigrationSafe(SecDbRef db
, bool readOnly
, SecDbConnectionRef
* dbconnRef
, CFErrorRef
*error
)
1137 secinfo("dbconn", "acquire %s connection", readOnly
? "ro" : "rw");
1139 SecDbConnectionConsumeResource(db
, readOnly
);
1141 __block SecDbConnectionRef dbconn
= NULL
;
1142 __block
bool ok
= true;
1143 __block
bool ranOpenedHandler
= false;
1145 bool (^assignDbConn
)(SecDbConnectionRef
) = ^bool(SecDbConnectionRef connection
) {
1146 dbconn
= connection
;
1148 *dbconnRef
= connection
;
1151 return dbconn
!= NULL
;
1154 dispatch_sync(db
->queue
, ^{
1155 if (!db
->didFirstOpen
) {
1156 bool didCreate
= false;
1157 ok
= assignDbConn(SecDbConnectionCreate(db
, false, error
));
1158 CFErrorRef localError
= NULL
;
1159 if (ok
&& !SecDbOpenHandle(dbconn
, &didCreate
, &localError
)) {
1160 secerror("Unable to create database: %@", localError
);
1161 if (localError
&& CFEqual(CFErrorGetDomain(localError
), kSecDbErrorDomain
)) {
1162 int code
= (int)CFErrorGetCode(localError
);
1163 dbconn
->isCorrupted
= (SQLITE_CORRUPT
== code
) || (SQLITE_NOTADB
== code
);
1165 // If the open failure isn't due to corruption, propagate the error.
1166 ok
= dbconn
->isCorrupted
;
1167 if (!ok
&& error
&& *error
== NULL
) {
1168 *error
= localError
;
1172 CFReleaseNull(localError
);
1175 db
->didFirstOpen
= ok
= SecDbDidCreateFirstConnection(dbconn
, didCreate
, error
);
1176 ranOpenedHandler
= true;
1177 SecDbConectionSetReadOnly(dbconn
, readOnly
); // first connection always created "rw", so set to real value
1179 CFReleaseNull(dbconn
);
1182 /* Try to get one from the cache */
1183 CFMutableArrayRef cache
= readOnly
? db
->idleReadConnections
: db
->idleWriteConnections
;
1184 if (CFArrayGetCount(cache
) && !dbconn
) {
1185 if (assignDbConn((SecDbConnectionRef
)CFArrayGetValueAtIndex(cache
, 0))) {
1186 CFRetainSafe(dbconn
);
1188 CFArrayRemoveValueAtIndex(cache
, 0);
1193 if (ok
&& !dbconn
) {
1194 /* Nothing found in cache, create a new connection */
1195 bool created
= false;
1196 if (assignDbConn(SecDbConnectionCreate(db
, readOnly
, error
)) && !SecDbOpenHandle(dbconn
, &created
, error
)) {
1197 CFReleaseNull(dbconn
);
1201 if (dbconn
&& !ranOpenedHandler
&& dbconn
->db
->opened
) {
1202 dispatch_sync(db
->queue
, ^{
1203 if (dbconn
->db
->callOpenedHandlerForNextConnection
) {
1204 dbconn
->db
->callOpenedHandlerForNextConnection
= false;
1205 if (!dbconn
->db
->opened(db
, dbconn
, false, &dbconn
->db
->callOpenedHandlerForNextConnection
, error
)) {
1206 if (!dbconn
->isCorrupted
|| !SecDbHandleCorrupt(dbconn
, 0, error
)) {
1207 CFReleaseNull(dbconn
);
1215 *dbconnRef
= dbconn
;
1219 // Caller doesn't get (to use) a connection so the backing synchronization primitive is available again
1220 SecDbConnectionMakeResourceAvailable(db
, readOnly
);
1224 return dbconn
? true : false;
1227 void SecDbConnectionRelease(SecDbConnectionRef dbconn
) {
1229 secerror("SecDbConnectionRelease called with NULL dbconn");
1232 SecDbRef db
= dbconn
->db
;
1234 secinfo("dbconn", "release %@", dbconn
);
1237 bool readOnly
= SecDbConnectionIsReadOnly(dbconn
);
1238 dispatch_sync(db
->queue
, ^{
1239 if (dbconn
->hasIOFailure
) {
1240 // Something wrong on the file layer (e.g. revoked file descriptor for networked home)
1241 secwarning("SecDbConnectionRelease: IO failure reported in connection, throwing away currently idle caches");
1242 // Any other checked-out connections are beyond our grasp. If they did not have IO failures they'll come back,
1243 // otherwise this branch gets taken more than once and gradually those connections die off
1244 CFArrayRemoveAllValues(db
->idleWriteConnections
);
1245 CFArrayRemoveAllValues(db
->idleReadConnections
);
1247 CFMutableArrayRef cache
= readOnly
? db
->idleReadConnections
: db
->idleWriteConnections
;
1248 CFIndex count
= CFArrayGetCount(cache
);
1249 if ((unsigned long)count
< (readOnly
? kSecDbMaxReaders
: kSecDbMaxWriters
)) {
1250 CFArrayAppendValue(cache
, dbconn
);
1252 secerror("dbconn: did not expect to run out of room in the %s cache when releasing connection", readOnly
? "ro" : "rw");
1257 // Signal after we have put the connection back in the pool of connections
1258 SecDbConnectionMakeResourceAvailable(db
, readOnly
);
1263 void SecDbReleaseAllConnections(SecDbRef db
) {
1264 // Force all connections to be removed (e.g. file descriptor no longer valid)
1266 secerror("called with NULL db");
1269 dispatch_sync(db
->queue
, ^{
1270 CFArrayRemoveAllValues(db
->idleReadConnections
);
1271 CFArrayRemoveAllValues(db
->idleWriteConnections
);
1275 static void onQueueSecDbForceCloseForCache(CFMutableArrayRef cache
) {
1276 CFArrayForEach(cache
, ^(const void* ptr
) {
1277 SecDbConnectionRef connection
= (SecDbConnectionRef
)ptr
;
1279 // this pointer is claimed to be nonretained
1280 connection
->db
= NULL
;
1282 if(connection
->handle
) {
1283 sqlite3_close(connection
->handle
);
1284 connection
->handle
= NULL
;
1287 CFArrayRemoveAllValues(cache
);
1290 // Please make sure you want to do this. Any use of the outstanding connections to this DB will cause a crash.
1291 void SecDbForceClose(SecDbRef db
) {
1292 dispatch_sync(db
->queue
, ^{
1293 onQueueSecDbForceCloseForCache(db
->idleReadConnections
);
1294 onQueueSecDbForceCloseForCache(db
->idleWriteConnections
);
1298 bool SecDbPerformRead(SecDbRef db
, CFErrorRef
*error
, void (^perform
)(SecDbConnectionRef dbconn
)) {
1299 SecDbConnectionRef dbconn
= SecDbConnectionAcquire(db
, true, error
);
1300 bool success
= false;
1304 SecDbConnectionRelease(dbconn
);
1309 bool SecDbPerformWrite(SecDbRef db
, CFErrorRef
*error
, void (^perform
)(SecDbConnectionRef dbconn
)) {
1311 SecError(errSecNotAvailable
, error
, CFSTR("failed to get a db handle"));
1314 SecDbConnectionRef dbconn
= SecDbConnectionAcquire(db
, false, error
);
1315 bool success
= false;
1319 SecDbConnectionRelease(dbconn
);
1325 SecDbConnectionCopyFormatDescription(CFTypeRef value
, CFDictionaryRef formatOptions
)
1327 SecDbConnectionRef dbconn
= (SecDbConnectionRef
)value
;
1328 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("<SecDbConnection %s %s>"),
1329 dbconn
->readOnly
? "ro" : "rw", dbconn
->handle
? "open" : "closed");
1333 SecDbConnectionDestroy(CFTypeRef value
)
1335 SecDbConnectionRef dbconn
= (SecDbConnectionRef
)value
;
1336 if (dbconn
->handle
) {
1337 int s3e
= sqlite3_close(dbconn
->handle
);
1338 if (s3e
!= SQLITE_OK
) {
1339 secerror("failed to close database connection (%d) for %@: %s", s3e
, dbconn
->db
->db_path
, sqlite3_errmsg(dbconn
->handle
));
1341 os_assert(s3e
== SQLITE_OK
); // Crash now or jetsam later
1344 CFReleaseNull(dbconn
->changes
);
1345 CFReleaseNull(dbconn
->corruptionError
);
1349 void SecDbPerformOnCommitQueue(SecDbConnectionRef dbconn
, bool barrier
, dispatch_block_t perform
) {
1351 dispatch_barrier_sync(dbconn
->db
->commitQueue
, ^{
1355 dispatch_sync(dbconn
->db
->commitQueue
, ^{
1362 // MARK: Bind helpers
1364 // Logging binds is very spammy when debug logging is on (~90% of log lines), and isn't often useful.
1365 // Enable this in your local build if you actually want every single SQL variable bind logged for debugging.
1366 #define LOG_SECDB_BINDS 0
1368 bool SecDbBindBlob(sqlite3_stmt
*stmt
, int param
, const void *zData
, size_t n
, void(*xDel
)(void*), CFErrorRef
*error
) {
1370 return SecDbErrorWithStmt(SQLITE_TOOBIG
, stmt
, error
,
1371 CFSTR("bind_blob[%d]: blob bigger than INT_MAX"), param
);
1373 bool ok
= SecDbErrorWithStmt(sqlite3_bind_blob(stmt
, param
, zData
, (int)n
, xDel
),
1374 stmt
, error
, CFSTR("bind_blob[%d]"), param
);
1376 secinfo("bind", "bind_blob[%d]: %.*P: %@", param
, (int)n
, zData
, error
? *error
: NULL
);
1381 bool SecDbBindText(sqlite3_stmt
*stmt
, int param
, const char *zData
, size_t n
, void(*xDel
)(void*), CFErrorRef
*error
) {
1383 return SecDbErrorWithStmt(SQLITE_TOOBIG
, stmt
, error
,
1384 CFSTR("bind_text[%d]: text bigger than INT_MAX"), param
);
1386 bool ok
= SecDbErrorWithStmt(sqlite3_bind_text(stmt
, param
, zData
, (int)n
, xDel
), stmt
, error
,
1387 CFSTR("bind_text[%d]"), param
);
1389 secinfo("bind", "bind_text[%d]: \"%s\" error: %@", param
, zData
, error
? *error
: NULL
);
1394 bool SecDbBindDouble(sqlite3_stmt
*stmt
, int param
, double value
, CFErrorRef
*error
) {
1395 bool ok
= SecDbErrorWithStmt(sqlite3_bind_double(stmt
, param
, value
), stmt
, error
,
1396 CFSTR("bind_double[%d]"), param
);
1398 secinfo("bind", "bind_double[%d]: %f error: %@", param
, value
, error
? *error
: NULL
);
1403 bool SecDbBindInt(sqlite3_stmt
*stmt
, int param
, int value
, CFErrorRef
*error
) {
1404 bool ok
= SecDbErrorWithStmt(sqlite3_bind_int(stmt
, param
, value
), stmt
, error
,
1405 CFSTR("bind_int[%d]"), param
);
1407 secinfo("bind", "bind_int[%d]: %d error: %@", param
, value
, error
? *error
: NULL
);
1412 bool SecDbBindInt64(sqlite3_stmt
*stmt
, int param
, sqlite3_int64 value
, CFErrorRef
*error
) {
1413 bool ok
= SecDbErrorWithStmt(sqlite3_bind_int64(stmt
, param
, value
), stmt
, error
,
1414 CFSTR("bind_int64[%d]"), param
);
1416 secinfo("bind", "bind_int64[%d]: %lld error: %@", param
, value
, error
? *error
: NULL
);
1422 /* AUDIT[securityd](done):
1423 value (ok) is a caller provided, non NULL CFTypeRef.
1425 bool SecDbBindObject(sqlite3_stmt
*stmt
, int param
, CFTypeRef value
, CFErrorRef
*error
) {
1427 __block
bool result
= false;
1429 /* TODO: Can we use SQLITE_STATIC below everwhere we currently use
1430 SQLITE_TRANSIENT since we finalize the statement before the value
1431 goes out of scope? */
1432 if (!value
|| (valueId
= CFGetTypeID(value
)) == CFNullGetTypeID()) {
1433 /* Skip bindings for NULL values. sqlite3 will interpret unbound
1434 params as NULL which is exactly what we want. */
1436 } else if (valueId
== CFStringGetTypeID()) {
1437 CFStringPerformWithCStringAndLength(value
, ^(const char *cstr
, size_t clen
) {
1438 result
= SecDbBindText(stmt
, param
, cstr
, clen
, SQLITE_TRANSIENT
, error
);
1440 } else if (valueId
== CFDataGetTypeID()) {
1441 CFIndex len
= CFDataGetLength(value
);
1443 result
= SecDbBindBlob(stmt
, param
, CFDataGetBytePtr(value
),
1444 len
, SQLITE_TRANSIENT
, error
);
1446 result
= SecDbBindText(stmt
, param
, "", 0, SQLITE_TRANSIENT
, error
);
1448 } else if (valueId
== CFDateGetTypeID()) {
1449 CFAbsoluteTime abs_time
= CFDateGetAbsoluteTime(value
);
1450 result
= SecDbBindDouble(stmt
, param
, abs_time
, error
);
1451 } else if (valueId
== CFBooleanGetTypeID()) {
1452 int bval
= CFBooleanGetValue(value
);
1453 result
= SecDbBindInt(stmt
, param
, bval
, error
);
1454 } else if (valueId
== CFNumberGetTypeID()) {
1456 if (CFNumberIsFloatType(value
)) {
1458 convertOk
= CFNumberGetValue(value
, kCFNumberDoubleType
, &nval
);
1459 result
= SecDbBindDouble(stmt
, param
, nval
, error
);
1461 sqlite_int64 nval64
;
1462 convertOk
= CFNumberGetValue(value
, kCFNumberSInt64Type
, &nval64
);
1464 result
= SecDbBindInt64(stmt
, param
, nval64
, error
);
1468 result
= SecDbError(SQLITE_INTERNAL
, error
, CFSTR("bind CFNumberGetValue failed for %@"), value
);
1472 CFStringRef valueDesc
= CFCopyTypeIDDescription(valueId
);
1473 SecDbError(SQLITE_MISMATCH
, error
, CFSTR("bind unsupported type %@"), valueDesc
);
1474 CFReleaseSafe(valueDesc
);
1482 // MARK: SecDbStatementRef
1484 bool SecDbReset(sqlite3_stmt
*stmt
, CFErrorRef
*error
) {
1485 return SecDbErrorWithStmt(sqlite3_reset(stmt
), stmt
, error
, CFSTR("reset"));
1488 bool SecDbClearBindings(sqlite3_stmt
*stmt
, CFErrorRef
*error
) {
1489 return SecDbErrorWithStmt(sqlite3_clear_bindings(stmt
), stmt
, error
, CFSTR("clear bindings"));
1492 bool SecDbFinalize(sqlite3_stmt
*stmt
, CFErrorRef
*error
) {
1493 sqlite3
*handle
= sqlite3_db_handle(stmt
);
1494 int s3e
= sqlite3_finalize(stmt
);
1495 return s3e
== SQLITE_OK
? true : SecDbErrorWithDb(s3e
, handle
, error
, CFSTR("finalize: %p"), stmt
);
1498 sqlite3_stmt
*SecDbPrepareV2(SecDbConnectionRef dbconn
, const char *sql
, size_t sqlLen
, const char **sqlTail
, CFErrorRef
*error
) {
1499 sqlite3
*db
= SecDbHandle(dbconn
);
1500 if (sqlLen
> INT_MAX
) {
1501 SecDbErrorWithDb(SQLITE_TOOBIG
, db
, error
, CFSTR("prepare_v2: sql bigger than INT_MAX"));
1506 sqlite3_stmt
*stmt
= NULL
;
1507 int s3e
= sqlite3_prepare_v2(db
, sql
, (int)sqlLen
, &stmt
, sqlTail
);
1508 if (s3e
== SQLITE_OK
)
1510 else if (!SecDbWaitIfNeeded(dbconn
, s3e
, NULL
, CFSTR("preparev2"), ntries
, error
))
1516 static sqlite3_stmt
*SecDbCopyStatementWithTailRange(SecDbConnectionRef dbconn
, CFStringRef sql
, CFRange
*sqlTail
, CFErrorRef
*error
) {
1517 __block sqlite3_stmt
*stmt
= NULL
;
1518 if (sql
) CFStringPerformWithCStringAndLength(sql
, ^(const char *sqlStr
, size_t sqlLen
) {
1519 const char *tail
= NULL
;
1520 stmt
= SecDbPrepareV2(dbconn
, sqlStr
, sqlLen
, &tail
, error
);
1521 if (sqlTail
&& sqlStr
< tail
&& tail
< sqlStr
+ sqlLen
) {
1522 sqlTail
->location
= tail
- sqlStr
;
1523 sqlTail
->length
= sqlLen
- sqlTail
->location
;
1530 sqlite3_stmt
*SecDbCopyStmt(SecDbConnectionRef dbconn
, CFStringRef sql
, CFStringRef
*tail
, CFErrorRef
*error
) {
1531 // TODO: Add caching and cache lookup of statements
1532 CFRange sqlTail
= {};
1533 sqlite3_stmt
*stmt
= SecDbCopyStatementWithTailRange(dbconn
, sql
, &sqlTail
, error
);
1534 if (sqlTail
.length
> 0) {
1535 CFStringRef excess
= CFStringCreateWithSubstring(CFGetAllocator(sql
), sql
, sqlTail
);
1539 SecDbError(SQLITE_INTERNAL
, error
,
1540 CFSTR("prepare_v2: %@ unused sql: %@"),
1542 CFReleaseSafe(excess
);
1543 SecDbFinalize(stmt
, error
);
1551 TODO: Could do a hack here with a custom kCFAllocatorNULL allocator for a second CFRuntimeBase inside a SecDbStatement,
1552 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. */
1553 bool SecDbReleaseCachedStmt(SecDbConnectionRef dbconn
, CFStringRef sql
, sqlite3_stmt
*stmt
, CFErrorRef
*error
) {
1555 return SecDbFinalize(stmt
, error
);
1560 bool SecDbPrepare(SecDbConnectionRef dbconn
, CFStringRef sql
, CFErrorRef
*error
, void(^exec
)(sqlite3_stmt
*stmt
)) {
1561 assert(sql
!= NULL
);
1562 sqlite3_stmt
*stmt
= SecDbCopyStmt(dbconn
, sql
, NULL
, error
);
1567 return SecDbReleaseCachedStmt(dbconn
, sql
, stmt
, error
);
1570 bool SecDbWithSQL(SecDbConnectionRef dbconn
, CFStringRef sql
, CFErrorRef
*error
, bool(^perform
)(sqlite3_stmt
*stmt
)) {
1574 CFStringRef tail
= NULL
;
1576 sqlite3_stmt
*stmt
= SecDbCopyStmt(dbconn
, sql
, &tail
, error
);
1582 // TODO: Use a different error scope here.
1583 ok
= SecError(-50 /* errSecParam */, error
, CFSTR("SecDbWithSQL perform block missing"));
1585 ok
&= SecDbReleaseCachedStmt(dbconn
, sql
, stmt
, error
);
1588 // TODO We already have an error here we really just want the left over sql in it's userData
1589 ok
= SecDbError(SQLITE_ERROR
, error
, CFSTR("Error with unexecuted sql remaining %@"), sql
);
1597 /* SecDbForEach returns true if all SQLITE_ROW returns of sqlite3_step() return true from the row block.
1598 If the row block returns false and doesn't set an error (to indicate it has reached a limit),
1599 this entire function returns false. In that case no error will be set. */
1600 bool SecDbForEach(SecDbConnectionRef dbconn
, sqlite3_stmt
*stmt
, CFErrorRef
*error
, bool(^row
)(int row_index
)) {
1601 bool result
= false;
1602 for (int row_ix
= 0;;++row_ix
) {
1603 if (SecDbConnectionIsReadOnly(dbconn
) && !sqlite3_stmt_readonly(stmt
)) {
1604 secerror("SecDbForEach: SecDbConnection is readonly but we're about to write: %s", sqlite3_sql(stmt
));
1606 int s3e
= sqlite3_step(stmt
);
1607 if (s3e
== SQLITE_ROW
) {
1613 // If we have no row block then getting SQLITE_ROW is an error
1614 SecDbError(s3e
, error
,
1615 CFSTR("step[%d]: %s returned SQLITE_ROW with NULL row block"),
1616 row_ix
, sqlite3_sql(stmt
));
1619 if (s3e
== SQLITE_DONE
) {
1622 SecDbConnectionCheckCode(dbconn
, s3e
, error
, CFSTR("SecDbForEach step[%d]"), row_ix
);
1630 void SecDbRecordChange(SecDbConnectionRef dbconn
, CFTypeRef deleted
, CFTypeRef inserted
) {
1631 if (!dbconn
->db
->notifyPhase
) return;
1632 CFTypeRef entry
= SecDbEventCreateWithComponents(deleted
, inserted
);
1634 CFArrayAppendValue(dbconn
->changes
, entry
);
1637 if (!dbconn
->inTransaction
) {
1638 secerror("db %@ changed outside txn", dbconn
);
1639 // Only notify of DidCommit, since WillCommit code assumes
1641 SecDbOnNotify(dbconn
, ^{
1642 SecDbNotifyPhase(dbconn
, kSecDbTransactionDidCommit
);
1649 CFGiblisFor(SecDbConnection
)
1652 // SecDbEvent Creation and consumption
1655 static SecDbEventRef
SecDbEventCreateInsert(CFTypeRef inserted
) {
1656 return CFRetainSafe(inserted
);
1659 static SecDbEventRef
SecDbEventCreateDelete(CFTypeRef deleted
) {
1660 return CFArrayCreate(kCFAllocatorDefault
, &deleted
, 1, &kCFTypeArrayCallBacks
);
1663 static SecDbEventRef
SecDbEventCreateUpdate(CFTypeRef deleted
, CFTypeRef inserted
) {
1664 const void *values
[2] = { deleted
, inserted
};
1665 return CFArrayCreate(kCFAllocatorDefault
, values
, 2, &kCFTypeArrayCallBacks
);
1668 SecDbEventRef
SecDbEventCreateWithComponents(CFTypeRef deleted
, CFTypeRef inserted
) {
1669 if (deleted
&& inserted
)
1670 return SecDbEventCreateUpdate(deleted
, inserted
);
1672 return SecDbEventCreateDelete(deleted
);
1674 return SecDbEventCreateInsert(inserted
);
1679 void SecDbEventTranslateComponents(SecDbEventRef item
, CFTypeRef
* deleted
, CFTypeRef
* inserted
) {
1680 if(CFGetTypeID(item
) == CFArrayGetTypeID()) {
1681 // One item: deletion. Two: update.
1682 CFIndex arraySize
= CFArrayGetCount(item
);
1683 if(arraySize
== 1) {
1684 if(deleted
) { *deleted
= CFArrayGetValueAtIndex(item
, 0); }
1685 if(inserted
) { *inserted
= NULL
; }
1686 } else if(arraySize
== 2) {
1687 if(deleted
) { *deleted
= CFArrayGetValueAtIndex(item
, 0); }
1688 if(inserted
) { *inserted
= CFArrayGetValueAtIndex(item
, 1); }
1690 if(deleted
) { *deleted
= NULL
; }
1691 if(inserted
) { *inserted
= NULL
; }
1694 if(deleted
) { *deleted
= NULL
; }
1695 if(inserted
) { *inserted
= item
; }
1700 bool SecDbEventGetComponents(SecDbEventRef event
, CFTypeRef
*deleted
, CFTypeRef
*inserted
, CFErrorRef
*error
) {
1701 if (isArray(event
)) {
1702 CFArrayRef array
= event
;
1703 switch (CFArrayGetCount(array
)) {
1705 *deleted
= CFArrayGetValueAtIndex(array
, 0);
1706 *inserted
= CFArrayGetValueAtIndex(array
, 1);
1709 *deleted
= CFArrayGetValueAtIndex(array
, 0);
1713 SecError(errSecParam
, error
, NULL
, CFSTR("invalid entry in changes array: %@"), array
);