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 "debugging.h"
29 #include <sqlite3_private.h>
30 #include <CoreFoundation/CoreFoundation.h>
34 #include <AssertMacros.h>
35 #include "SecCFWrappers.h"
36 #include "SecCFError.h"
37 #include "SecIOFormat.h"
39 #include "Security/SecBase.h"
40 #include "SecAutorelease.h"
41 #include <os/assumes.h>
42 #include <xpc/private.h> // xpc_transaction_exit_clean()
46 // Architecturally inverted files
47 // These are in SecureObjectSync but utilities depends on them
48 // <rdar://problem/20802079> Fix layer violation (SOSDigestVector, SOSManifest, SecDB.c)
50 #include "keychain/SecureObjectSync/SOSDigestVector.h"
51 #include "keychain/SecureObjectSync/SOSManifest.h"
53 #define SECDB_DEBUGGING 0
55 struct __OpaqueSecDbStatement
{
58 SecDbConnectionRef dbconn
;
62 struct __OpaqueSecDbConnection
{
65 //CFMutableDictionaryRef statements;
67 SecDbRef db
; // NONRETAINED, since db or block retains us
70 SecDbTransactionSource source
;
72 int maybeCorruptedCode
;
74 CFErrorRef corruptionError
;
76 // Pending deletions and additions for the current transaction
77 // Entires are either:
78 // 1) a CFArrayRef of 1 element representing a deletion,
79 // 2) a CFArrayRef of 2 elements representing the element 0 having been replaced with element 1
80 // 3) a CFTypeRef that is not a CFArrayRef, representing an add of the element in question.
81 CFMutableArrayRef changes
;
84 struct __OpaqueSecDb
{
88 dispatch_queue_t queue
;
89 dispatch_queue_t commitQueue
;
90 CFMutableArrayRef connections
;
91 dispatch_semaphore_t write_semaphore
;
92 dispatch_semaphore_t read_semaphore
;
94 bool (^opened
)(SecDbRef db
, SecDbConnectionRef dbconn
, bool didCreate
, bool *callMeAgainForNextConnection
, CFErrorRef
*error
);
95 bool callOpenedHandlerForNextConnection
;
96 CFMutableArrayRef notifyPhase
; /* array of SecDBNotifyBlock */
97 mode_t mode
; /* database file permissions */
98 bool readWrite
; /* open database read-write */
99 bool allowRepair
; /* allow database repair */
100 bool useWAL
; /* use WAL mode */
101 bool useRobotVacuum
; /* use if SecDB should manage vacuum behind your back */
102 uint8_t maxIdleHandles
;
103 void (^corruptionReset
)(void);
106 // MARK: Error domains and error helper functions
108 CFStringRef kSecDbErrorDomain
= CFSTR("com.apple.utilities.sqlite3");
110 bool SecDbError(int sql_code
, CFErrorRef
*error
, CFStringRef format
, ...) {
111 if (sql_code
== SQLITE_OK
) return true;
115 CFIndex code
= sql_code
;
116 CFErrorRef previousError
= *error
;
119 va_start(args
, format
);
120 SecCFCreateErrorWithFormatAndArguments(code
, kSecDbErrorDomain
, previousError
, error
, NULL
, format
, args
);
126 bool SecDbErrorWithDb(int sql_code
, sqlite3
*db
, CFErrorRef
*error
, CFStringRef format
, ...) {
127 if (sql_code
== SQLITE_OK
) return true;
130 va_start(args
, format
);
131 CFStringRef message
= CFStringCreateWithFormatAndArguments(kCFAllocatorDefault
, NULL
, format
, args
);
133 CFStringRef errno_code
= NULL
;
135 if (sql_code
== SQLITE_CANTOPEN
) {
136 int errno_number
= sqlite3_system_errno(db
);
137 errno_code
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%d"), errno_number
);
139 errno_code
= CFRetain(CFSTR(""));
142 int extended_code
= sqlite3_extended_errcode(db
);
143 if (sql_code
== extended_code
)
144 SecDbError(sql_code
, error
, CFSTR("%@: [%d]%@ %s"), message
, sql_code
, errno_code
, sqlite3_errmsg(db
));
146 SecDbError(sql_code
, error
, CFSTR("%@: [%d->%d]%@ %s"), message
, sql_code
, extended_code
, errno_code
, sqlite3_errmsg(db
));
147 CFReleaseSafe(message
);
148 CFReleaseSafe(errno_code
);
153 bool SecDbErrorWithStmt(int sql_code
, sqlite3_stmt
*stmt
, CFErrorRef
*error
, CFStringRef format
, ...) {
154 if (sql_code
== SQLITE_OK
) return true;
157 va_start(args
, format
);
158 CFStringRef message
= CFStringCreateWithFormatAndArguments(kCFAllocatorDefault
, NULL
, format
, args
);
161 sqlite3
*db
= sqlite3_db_handle(stmt
);
162 const char *sql
= sqlite3_sql(stmt
);
163 int extended_code
= sqlite3_extended_errcode(db
);
164 if (sql_code
== extended_code
)
165 SecDbError(sql_code
, error
, CFSTR("%@: [%d] %s sql: %s"), message
, sql_code
, sqlite3_errmsg(db
), sql
);
167 SecDbError(sql_code
, error
, CFSTR("%@: [%d->%d] %s sql: %s"), message
, sql_code
, extended_code
, sqlite3_errmsg(db
), sql
);
168 CFReleaseSafe(message
);
173 // A callback for the sqlite3_log() interface.
174 static void sqlite3Log(void *pArg
, int iErrCode
, const char *zMsg
){
175 secdebug("sqlite3", "(%d) %s", iErrCode
, zMsg
);
178 void _SecDbServerSetup(void)
180 static dispatch_once_t onceToken
;
181 dispatch_once(&onceToken
, ^{
182 int rx
= sqlite3_config(SQLITE_CONFIG_LOG
, sqlite3Log
, NULL
);
183 if (SQLITE_OK
!= rx
) {
184 secwarning("Could not set up sqlite global error logging to syslog: %d", rx
);
191 // MARK: Static helper functions
193 static bool SecDbOpenHandle(SecDbConnectionRef dbconn
, bool *created
, CFErrorRef
*error
);
194 static bool SecDbHandleCorrupt(SecDbConnectionRef dbconn
, int rc
, CFErrorRef
*error
);
197 #pragma mark SecDbRef
200 SecDbCopyFormatDescription(CFTypeRef value
, CFDictionaryRef formatOptions
)
202 SecDbRef db
= (SecDbRef
)value
;
203 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("<SecDb path:%@ connections: %@>"), db
->db_path
, db
->connections
);
208 SecDbDestroy(CFTypeRef value
)
210 SecDbRef db
= (SecDbRef
)value
;
211 CFReleaseNull(db
->connections
);
212 CFReleaseNull(db
->db_path
);
214 dispatch_release(db
->queue
);
217 if (db
->commitQueue
) {
218 dispatch_release(db
->commitQueue
);
219 db
->commitQueue
= NULL
;
221 if (db
->read_semaphore
) {
222 dispatch_release(db
->read_semaphore
);
223 db
->read_semaphore
= NULL
;
225 if (db
->write_semaphore
) {
226 dispatch_release(db
->write_semaphore
);
227 db
->write_semaphore
= NULL
;
230 Block_release(db
->opened
);
233 CFReleaseNull(db
->notifyPhase
);
239 SecDbCreate(CFStringRef dbName
, mode_t mode
, bool readWrite
, bool allowRepair
, bool useWAL
, bool useRobotVacuum
, uint8_t maxIdleHandles
,
240 bool (^opened
)(SecDbRef db
, SecDbConnectionRef dbconn
, bool didCreate
, bool *callMeAgainForNextConnection
, CFErrorRef
*error
))
244 db
= CFTypeAllocate(SecDb
, struct __OpaqueSecDb
, kCFAllocatorDefault
);
245 require(db
!= NULL
, done
);
247 CFStringPerformWithCString(dbName
, ^(const char *dbNameStr
) {
248 db
->queue
= dispatch_queue_create(dbNameStr
, DISPATCH_QUEUE_SERIAL
);
250 CFStringRef commitQueueStr
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%@-commit"), dbName
);
251 CFStringPerformWithCString(commitQueueStr
, ^(const char *cqNameStr
) {
252 db
->commitQueue
= dispatch_queue_create(cqNameStr
, DISPATCH_QUEUE_CONCURRENT
);
254 CFReleaseNull(commitQueueStr
);
255 db
->read_semaphore
= dispatch_semaphore_create(kSecDbMaxReaders
);
256 db
->write_semaphore
= dispatch_semaphore_create(kSecDbMaxWriters
);
257 db
->connections
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
258 db
->opened
= opened
? Block_copy(opened
) : NULL
;
259 if (getenv("__OSINSTALL_ENVIRONMENT") != NULL
) {
260 // TODO: Move this code out of this layer
261 secinfo("#SecDB", "SecDB: running from installer");
263 db
->db_path
= CFSTR("file::memory:?cache=shared");
265 db
->db_path
= CFStringCreateCopy(kCFAllocatorDefault
, dbName
);
268 db
->readWrite
= readWrite
;
269 db
->allowRepair
= allowRepair
;
271 db
->useRobotVacuum
= useRobotVacuum
;
272 db
->maxIdleHandles
= maxIdleHandles
;
273 db
->corruptionReset
= NULL
;
280 SecDbIdleConnectionCount(SecDbRef db
) {
281 __block CFIndex count
= 0;
282 dispatch_sync(db
->queue
, ^{
283 count
= CFArrayGetCount(db
->connections
);
288 void SecDbAddNotifyPhaseBlock(SecDbRef db
, SecDBNotifyBlock notifyPhase
)
290 // SecDbNotifyPhase seems to mostly be called on the db's commitQueue, and not the db's queue. Therefore, protect the array with that queue.
291 dispatch_sync(db
->commitQueue
, ^{
292 SecDBNotifyBlock block
= Block_copy(notifyPhase
); /* Force the block off the stack */
293 if (db
->notifyPhase
== NULL
) {
294 db
->notifyPhase
= CFArrayCreateMutableForCFTypes(NULL
);
296 CFArrayAppendValue(db
->notifyPhase
, block
);
297 Block_release(block
);
301 static void SecDbNotifyPhase(SecDbConnectionRef dbconn
, SecDbTransactionPhase phase
) {
302 if (CFArrayGetCount(dbconn
->changes
)) {
303 CFArrayRef changes
= dbconn
->changes
;
304 dbconn
->changes
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
305 if (dbconn
->db
->notifyPhase
) {
306 CFArrayForEach(dbconn
->db
->notifyPhase
, ^(const void *value
) {
307 SecDBNotifyBlock notifyBlock
= (SecDBNotifyBlock
)value
;
308 notifyBlock(dbconn
, phase
, dbconn
->source
, changes
);
311 CFReleaseSafe(changes
);
315 static void SecDbOnNotify(SecDbConnectionRef dbconn
, void (^perform
)(void)) {
319 CFStringRef
SecDbGetPath(SecDbRef db
) {
328 #pragma mark SecDbConnectionRef
330 static bool SecDbCheckCorrupted(SecDbConnectionRef dbconn
)
332 __block
bool checkDidRun
= false;
333 __block
bool isCorrupted
= false;
334 __block CFErrorRef error
= NULL
;
335 SecDbPrepare(dbconn
, CFSTR("PRAGMA integrity_check"), &error
, ^(sqlite3_stmt
*stmt
) {
336 SecDbStep(dbconn
, stmt
, &error
, ^(bool *stop
) {
337 const char * result
= (const char*)sqlite3_column_text(stmt
, 0);
338 if (!result
|| strncasecmp(result
, "ok", 3) != 0) {
340 secerror("SecDBCheckCorrupted integrity_check returned %s", (result
) ? result
: "NULL");
346 // An error occurred in SecDbPrepare before we could run the block.
348 CFIndex code
= CFErrorGetCode(error
);
349 if (SQLITE_CORRUPT
== code
|| SQLITE_NOTADB
== code
) {
352 secinfo("#SecDB", "#SecDB warning error %{public}@ when running integrity check", error
);
354 // We don't have an error ref if SecDbPrepare has called SecDbConnectionCheckCode,
355 // which then called SecDbHandleCorrupt. That code path is only entered when the
356 // original error was SQLITE_CORRUPT or SQLITE_NOTADB. On other errors, the
357 // CFErrorRef is not cleared and we can just check the code above.
359 secinfo("#SecDB", "#SecDB warning: failed to run integrity check due to corruption");
364 secerror("SecDBCheckCorrupted ran integrity_check, and that didn't return ok");
366 secerror("SecDBCheckCorrupted failed to run integrity check");
369 CFReleaseNull(error
);
374 static bool SecDbDidCreateFirstConnection(SecDbConnectionRef dbconn
, bool didCreate
, CFErrorRef
*error
)
376 secinfo("#SecDB", "#SecDB starting maintenance");
379 // Historical note: this used to check for integrity but that became too slow and caused panics at boot.
380 // Now, just react to SQLite errors when doing an operation. If file on disk is borked it'll tell us right away.
382 if (!dbconn
->isCorrupted
&& dbconn
->db
->opened
) {
383 CFErrorRef localError
= NULL
;
385 dbconn
->db
->callOpenedHandlerForNextConnection
= false;
386 ok
= dbconn
->db
->opened(dbconn
->db
, dbconn
, didCreate
, &dbconn
->db
->callOpenedHandlerForNextConnection
, &localError
);
389 secerror("opened block failed: %@", localError
);
391 if (!dbconn
->isCorrupted
&& error
&& *error
== NULL
) {
396 secerror("opened block failed: error (%@) is being released and lost", localError
);
397 CFReleaseNull(localError
);
401 if (dbconn
->isCorrupted
) {
402 ok
= SecDbHandleCorrupt(dbconn
, 0, error
);
405 secinfo("#SecDB", "#SecDB starting maintenance");
409 void SecDbCorrupt(SecDbConnectionRef dbconn
, CFErrorRef error
)
411 os_log_fault(secLogObjForScope("SecEmergency"), "SecDBCorrupt: %@", error
);
412 dbconn
->isCorrupted
= true;
413 CFRetainAssign(dbconn
->corruptionError
, error
);
417 static uint8_t knownDbPathIndex(SecDbConnectionRef dbconn
)
420 if(CFEqual(dbconn
->db
->db_path
, CFSTR("/Library/Keychains/keychain-2.db")))
422 if(CFEqual(dbconn
->db
->db_path
, CFSTR("/Library/Keychains/ocspcache.sqlite3")))
424 if(CFEqual(dbconn
->db
->db_path
, CFSTR("/Library/Keychains/TrustStore.sqlite3")))
426 if(CFEqual(dbconn
->db
->db_path
, CFSTR("/Library/Keychains/caissuercache.sqlite3")))
429 /* Unknown DB path */
433 static bool SecDbConnectionCheckCode(SecDbConnectionRef dbconn
, int code
, CFErrorRef
*error
, CFStringRef desc
, ...)
434 CF_FORMAT_FUNCTION(4, 5);
436 // Return true if there was no error, returns false otherwise and set *error to an appropriate CFErrorRef.
437 static bool SecDbConnectionCheckCode(SecDbConnectionRef dbconn
, int code
, CFErrorRef
*error
, CFStringRef desc
, ...) {
438 if (code
== SQLITE_OK
|| code
== SQLITE_DONE
)
443 va_start(args
, desc
);
444 CFStringRef msg
= CFStringCreateWithFormatAndArguments(kCFAllocatorDefault
, NULL
, desc
, args
);
446 SecDbErrorWithDb(code
, dbconn
->handle
, error
, CFSTR("%@"), msg
);
450 dbconn
->hasIOFailure
|= (SQLITE_IOERR
== code
);
452 /* If it's already corrupted, don't try to recover */
453 if (dbconn
->isCorrupted
) {
454 CFStringRef reason
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
,
455 CFSTR("SQL DB %@ is corrupted already. Corruption error was: %d (previously %d)"),
456 dbconn
->db
->db_path
, code
, dbconn
->maybeCorruptedCode
);
457 secerror("%@",reason
);
458 __security_simulatecrash(reason
, __sec_exception_code_TwiceCorruptDb(knownDbPathIndex(dbconn
)));
459 CFReleaseSafe(reason
);
460 // We can't fall through to the checking case because it eventually calls SecDbConnectionCheckCode again.
461 // However, this is the second time we're seeing corruption so let's take the ultimate measure.
462 if ((SQLITE_CORRUPT
== code
) || (SQLITE_NOTADB
== code
)) {
463 secerror("SecDbConnectionCheckCode detected corruption twice: going to handle corrupt DB");
464 (void)SecDbHandleCorrupt(dbconn
, code
, error
);
469 // NOTADB means file is garbage, so it's functionally equivalent to corruption
470 dbconn
->isCorrupted
= (SQLITE_CORRUPT
== code
) || (SQLITE_NOTADB
== code
);
471 if (dbconn
->isCorrupted
) {
472 /* Run integrity check and only make dbconn->isCorrupted true and
473 run the corruption handler if the integrity check conclusively fails. */
474 dbconn
->maybeCorruptedCode
= code
;
475 dbconn
->isCorrupted
= SecDbCheckCorrupted(dbconn
);
476 if (dbconn
->isCorrupted
) {
477 secerror("operation returned code: %d integrity check=fail", code
);
478 (void)SecDbHandleCorrupt(dbconn
, code
, error
);
480 secerror("operation returned code: %d: integrity check=pass", code
);
487 #define BUSY_TIMEOUT_MS (5 * 60 * 1000) /* 5 minutes */
489 static int sleepBackoff
[] = { 10, 20, 50, 100, 250 };
490 static int sumBackoff
[] = { 10, 30, 80, 180, 430 };
491 static int NumberOfSleepBackoff
= sizeof(sleepBackoff
)/sizeof(sleepBackoff
[0]);
493 // Use these as silly hacks to encode the SQLite return code in the backtrace, for hang debugging purposes
494 static void __attribute__((noinline
)) SecDbLockSleep(int ms
) {
498 static void __attribute__((noinline
)) SecDbBusySleep(int ms
) {
502 // Return true causes the operation to be tried again.
503 // Note that we set sqlite3_busy_timeout on the connection, so anytime you're in here, it's likely due to SQLITE_LOCKED.
504 static bool SecDbWaitIfNeeded(SecDbConnectionRef dbconn
, int s3e
, sqlite3_stmt
*stmt
, CFStringRef desc
, int nTries
, CFErrorRef
*error
) {
505 if (((0xFF & s3e
) == SQLITE_BUSY
) || ((0xFF & s3e
) == SQLITE_LOCKED
)) {
506 int totaltimeout
, timeout
;
508 _Static_assert(sizeof(sumBackoff
) == sizeof(sleepBackoff
), "matching arrays not matching");
509 _Static_assert(sizeof(sumBackoff
[0]) == sizeof(sleepBackoff
[0]), "matching arrays not matching");
511 if (nTries
< NumberOfSleepBackoff
) {
512 timeout
= sleepBackoff
[nTries
];
513 totaltimeout
= sumBackoff
[nTries
];
515 timeout
= sleepBackoff
[NumberOfSleepBackoff
- 1];
516 totaltimeout
= sumBackoff
[NumberOfSleepBackoff
- 1] + (timeout
* (nTries
- NumberOfSleepBackoff
));
518 if (totaltimeout
< BUSY_TIMEOUT_MS
) {
519 secinfo("#SecDB", "sqlite busy/locked: %d ntries: %d totaltimeout: %d", s3e
, nTries
, totaltimeout
);
520 if(((0xFF & s3e
) == SQLITE_LOCKED
)) {
521 SecDbLockSleep(timeout
);
523 SecDbBusySleep(timeout
);
527 secinfo("#SecDB", "sqlite busy/locked: too long: %d ms, giving up", totaltimeout
);
531 return SecDbConnectionCheckCode(dbconn
, s3e
, error
, CFSTR("%@"), desc
);
534 enum SecDbStepResult
{
539 typedef enum SecDbStepResult SecDbStepResult
;
541 static SecDbStepResult
_SecDbStep(SecDbConnectionRef dbconn
, sqlite3_stmt
*stmt
, CFErrorRef
*error
) {
542 assert(stmt
!= NULL
);
546 if (SecDbConnectionIsReadOnly(dbconn
) && !sqlite3_stmt_readonly(stmt
)) {
547 secerror("_SecDbStep: SecDbConnection is readonly but we're about to write: %s", sqlite3_sql(stmt
));
549 s3e
= sqlite3_step(stmt
);
550 if (s3e
== SQLITE_ROW
) {
551 return kSecDbRowStep
;
552 } else if (s3e
== SQLITE_DONE
) {
554 ** ^[SQLITE_DONE] means that the statement has finished executing
555 ** successfully. sqlite3_step() should not be called again on this virtual
556 ** machine without first calling [] to reset the virtual
557 ** machine back to its initial state.
560 return kSecDbDoneStep
;
561 } else if (!SecDbWaitIfNeeded(dbconn
, s3e
, stmt
, CFSTR("step"), ntries
, error
)) {
562 return kSecDbErrorStep
;
569 SecDbExec(SecDbConnectionRef dbconn
, CFStringRef sql
, CFErrorRef
*error
)
574 CFStringRef tail
= NULL
;
576 sqlite3_stmt
*stmt
= SecDbCopyStmt(dbconn
, sql
, &tail
, error
);
580 while ((sr
= _SecDbStep(dbconn
, stmt
, error
)) == kSecDbRowStep
);
581 if (sr
== kSecDbErrorStep
)
583 ok
&= SecDbReleaseCachedStmt(dbconn
, sql
, stmt
, error
);
586 // TODO We already have an error here we really just want the left over sql in it's userData
587 ok
= SecDbError(SQLITE_ERROR
, error
, CFSTR("Error with unexecuted sql remaining %@"), sql
);
595 static int SecDBGetInteger(SecDbConnectionRef dbconn
, CFStringRef sql
)
597 __block
int number
= -1;
598 __block CFErrorRef error
= NULL
;
600 (void)SecDbWithSQL(dbconn
, sql
, &error
, ^bool(sqlite3_stmt
*sqlStmt
) {
601 (void)SecDbStep(dbconn
, sqlStmt
, &error
, ^(bool *stop
) {
602 number
= sqlite3_column_int(sqlStmt
, 0);
607 CFReleaseNull(error
);
612 void SecDBManagementTasks(SecDbConnectionRef dbconn
)
614 int64_t page_count
= SecDBGetInteger(dbconn
, CFSTR("pragma page_count"));
615 if (page_count
<= 0) {
618 int64_t free_count
= SecDBGetInteger(dbconn
, CFSTR("pragma freelist_count"));
619 if (free_count
< 0) {
623 int64_t max_free
= 8192;
625 int64_t pages_in_use
= page_count
- free_count
;
626 double loadFactor
= ((double)pages_in_use
/(double)page_count
);
627 if (0.85 < loadFactor
&& free_count
< max_free
) {
630 int64_t pages_to_free
= (int64_t)(0.2 * free_count
);
631 if (0.4 > loadFactor
) {
632 pages_to_free
= free_count
;
635 char *formatString
= NULL
;
636 asprintf(&formatString
, "pragma incremental_vacuum(%d)", (int)pages_to_free
);
638 char *sqlerror
= NULL
;
639 int rc
= sqlite3_exec(dbconn
->handle
, formatString
, NULL
, NULL
, &sqlerror
);
641 secerror("incremental_vacuum failed with: (%d) %{public}s", rc
, sqlerror
);
643 sqlite3_free(sqlerror
);
650 static bool SecDbBeginTransaction(SecDbConnectionRef dbconn
, SecDbTransactionType type
, CFErrorRef
*error
)
655 case kSecDbImmediateTransactionType
:
656 secdebug("db", "SecDbBeginTransaction SecDbBeginTransaction %p", dbconn
);
657 query
= CFSTR("BEGIN IMMEDIATE");
659 case kSecDbExclusiveRemoteSOSTransactionType
:
660 secdebug("db", "SecDbBeginTransaction kSecDbExclusiveRemoteSOSTransactionType %p", dbconn
);
661 dbconn
->source
= kSecDbSOSTransaction
;
662 query
= CFSTR("BEGIN EXCLUSIVE");
664 case kSecDbExclusiveRemoteCKKSTransactionType
:
665 secdebug("db", "SecDbBeginTransaction kSecDbExclusiveRemoteCKKSTransactionType %p", dbconn
);
666 dbconn
->source
= kSecDbCKKSTransaction
;
667 query
= CFSTR("BEGIN EXCLUSIVE");
669 case kSecDbExclusiveTransactionType
:
670 if (type
==kSecDbExclusiveTransactionType
)
671 secdebug("db", "SecDbBeginTransaction kSecDbExclusiveTransactionType %p", dbconn
);
672 query
= CFSTR("BEGIN EXCLUSIVE");
674 case kSecDbNormalTransactionType
:
675 secdebug("db", "SecDbBeginTransaction kSecDbNormalTransactionType %p", dbconn
);
676 query
= CFSTR("BEGIN");
679 secdebug("db", "SecDbBeginTransaction invalid transaction type %lu", type
);
680 ok
= SecDbError(SQLITE_ERROR
, error
, CFSTR("invalid transaction type %d"), (int)type
);
685 if (query
!= NULL
&& sqlite3_get_autocommit(dbconn
->handle
) != 0) {
686 ok
= SecDbExec(dbconn
, query
, error
);
689 dbconn
->inTransaction
= true;
694 static bool SecDbEndTransaction(SecDbConnectionRef dbconn
, bool commit
, CFErrorRef
*error
)
696 __block
bool ok
= true;
697 __block
bool commited
= false;
699 dispatch_block_t notifyAndExec
= ^{
701 //secdebug("db", "SecDbEndTransaction kSecDbTransactionWillCommit %p", dbconn);
702 SecDbNotifyPhase(dbconn
, kSecDbTransactionWillCommit
);
703 commited
= ok
= SecDbExec(dbconn
, CFSTR("END"), error
);
704 //secdebug("db", "SecDbEndTransaction kSecDbTransactionWillCommit %p (after notify)", dbconn);
706 ok
= SecDbExec(dbconn
, CFSTR("ROLLBACK"), error
);
709 dbconn
->inTransaction
= false;
710 SecDbNotifyPhase(dbconn
, commited
? kSecDbTransactionDidCommit
: kSecDbTransactionDidRollback
);
711 secdebug("db", "SecDbEndTransaction %s %p", commited
? "kSecDbTransactionDidCommit" : "kSecDbTransactionDidRollback", dbconn
);
712 dbconn
->source
= kSecDbAPITransaction
;
714 if (commit
&& dbconn
->db
->useRobotVacuum
) {
715 SecDBManagementTasks(dbconn
);
719 SecDbPerformOnCommitQueue(dbconn
, true, notifyAndExec
);
724 bool SecDbTransaction(SecDbConnectionRef dbconn
, SecDbTransactionType type
,
725 CFErrorRef
*error
, void (^transaction
)(bool *commit
))
730 if (dbconn
->inTransaction
) {
731 transaction(&commit
);
733 secinfo("#SecDB", "#SecDB nested transaction asked to not be committed");
736 ok
= SecDbBeginTransaction(dbconn
, type
, error
);
738 transaction(&commit
);
739 ok
= SecDbEndTransaction(dbconn
, commit
, error
);
746 sqlite3
*SecDbHandle(SecDbConnectionRef dbconn
) {
747 return dbconn
->handle
;
750 bool SecDbStep(SecDbConnectionRef dbconn
, sqlite3_stmt
*stmt
, CFErrorRef
*error
, void (^row
)(bool *stop
)) {
752 switch (_SecDbStep(dbconn
, stmt
, error
)) {
753 case kSecDbErrorStep
:
754 secdebug("db", "kSecDbErrorStep %@", error
? *error
: NULL
);
758 secdebug("db", "kSecDbRowStep %@", error
? *error
: NULL
);
761 __block
bool stop
= false;
762 SecAutoreleaseInvokeWithPool(^{
769 SecDbError(SQLITE_ERROR
, error
, CFSTR("SecDbStep SQLITE_ROW returned without a row handler"));
773 secdebug("db", "kSecDbDoneStep %@", error
? *error
: NULL
);
780 bool SecDbCheckpoint(SecDbConnectionRef dbconn
, CFErrorRef
*error
)
782 return SecDbConnectionCheckCode(dbconn
, sqlite3_wal_checkpoint(dbconn
->handle
, NULL
), error
, CFSTR("wal_checkpoint"));
785 static bool SecDbFileControl(SecDbConnectionRef dbconn
, int op
, void *arg
, CFErrorRef
*error
) {
786 return SecDbConnectionCheckCode(dbconn
, sqlite3_file_control(dbconn
->handle
, NULL
, op
, arg
), error
, CFSTR("file_control"));
789 static sqlite3
*_SecDbOpenV2(const char *path
,
794 sqlite3
*handle
= NULL
;
795 int s3e
= sqlite3_open_v2(path
, &handle
, flags
, NULL
);
798 SecDbErrorWithDb(s3e
, handle
, error
, CFSTR("open_v2 \"%s\" 0x%X"), path
, flags
);
799 sqlite3_close(handle
);
802 SecDbError(s3e
, error
, CFSTR("open_v2 \"%s\" 0x%X"), path
, flags
);
804 } else if (SQLITE_OPEN_READWRITE
== (flags
& SQLITE_OPEN_READWRITE
)) {
805 if (useRobotVacuum
) {
806 #define SECDB_SQLITE_AUTO_VACUUM_INCREMENTAL 2
807 sqlite3_stmt
*stmt
= NULL
;
811 * Setting auto_vacuum = incremental on a database that is not empty requires
812 * a VACCUUM, so check if the vacuum mode is not INCREMENTAL, and if its not,
813 * set it to incremental and vacuum.
816 s3e
= sqlite3_prepare_v2(handle
, "PRAGMA auto_vacuum", -1, &stmt
, NULL
);
818 s3e
= sqlite3_step(stmt
);
819 if (s3e
== SQLITE_ROW
) {
820 vacuumMode
= sqlite3_column_int(stmt
, 0);
822 (void)sqlite3_finalize(stmt
);
825 if (vacuumMode
!= SECDB_SQLITE_AUTO_VACUUM_INCREMENTAL
) {
826 (void)sqlite3_exec(handle
, "PRAGMA auto_vacuum = incremental", NULL
, NULL
, NULL
);
827 (void)sqlite3_exec(handle
, "VACUUM", NULL
, NULL
, NULL
);
831 (void)sqlite3_exec(handle
, "PRAGMA journal_mode = WAL", NULL
, NULL
, NULL
);
834 // Let SQLite handle timeouts.
835 sqlite3_busy_timeout(handle
, 5*1000);
840 static bool SecDbOpenV2(SecDbConnectionRef dbconn
, const char *path
, int flags
, CFErrorRef
*error
) {
841 return (dbconn
->handle
= _SecDbOpenV2(path
, flags
, dbconn
->db
->useWAL
, dbconn
->db
->useRobotVacuum
, error
)) != NULL
;
844 // This construction lets tests not exit here
845 static void SecDbProductionCorruptionExitHandler(void)
849 void (*SecDbCorruptionExitHandler
)(void) = SecDbProductionCorruptionExitHandler
;
851 void SecDbResetCorruptionExitHandler(void)
853 SecDbCorruptionExitHandler
= SecDbProductionCorruptionExitHandler
;
857 There's not much to do in here because we should only ever be here when
858 SQLite tells us the DB is corrupt, or the DB is unrecoverable because of
859 some fatal logic problem. But we can't shoot it dead either due to client
860 connections. So, first we create a marker to tell ourselves things are bad,
861 then we'll die. When we come back up we'll notice the marker and remove the DB.
863 static bool SecDbHandleCorrupt(SecDbConnectionRef dbconn
, int rc
, CFErrorRef
*error
)
865 if (!dbconn
->db
->allowRepair
) {
866 SecCFCreateErrorWithFormat(rc
, kSecErrnoDomain
, NULL
, error
, NULL
,
867 CFSTR("SecDbHandleCorrupt not allowed to repair, handled error: [%d] %s"), rc
, strerror(rc
));
868 dbconn
->isCorrupted
= false;
872 CFStringPerformWithCString(dbconn
->db
->db_path
, ^(const char *db_path
) {
873 char marker
[PATH_MAX
+1];
874 snprintf(marker
, sizeof(marker
), "%s-iscorrupt", db_path
);
875 struct stat info
= {};
876 if (0 == stat(marker
, &info
)) {
877 secerror("SecDbHandleCorrupt: Tried to write corruption marker %s but one already exists", marker
);
880 FILE* file
= fopen(marker
, "w");
882 secerror("SecDbHandleCorrupt: Unable (%{darwin.errno}d) to create corruption marker %{public}s", errno
, marker
);
888 secwarning("SecDbHandleCorrupt: killing self so that successor might cleanly delete corrupt db");
890 // Call through function pointer so tests can replace it and call a SecKeychainDbReset instead
891 SecDbCorruptionExitHandler();
895 static bool SecDbProcessCorruptionMarker(CFStringRef db_path
) {
896 __block
bool ok
= true;
897 CFStringPerformWithCString(db_path
, ^(const char *db_path
) {
898 char marker
[PATH_MAX
+1];
899 snprintf(marker
, sizeof(marker
), "%s-iscorrupt", db_path
);
900 struct stat info
= {};
901 int result
= stat(marker
, &info
);
902 if (result
!= 0 && errno
== ENOENT
) {
904 } else if (result
!= 0) {
905 secerror("SecDbSecDbProcessCorruptionMarker: Unable to check for corruption marker: %{darwin.errno}d", errno
);
909 secwarning("SecDbSecDbProcessCorruptionMarker: found corruption marker %s", marker
);
910 if (remove(marker
)) {
911 secerror("SecDbSecDbProcessCorruptionMarker: Unable (%{darwin.errno}d) to delete corruption marker", errno
);
913 } else if (remove(db_path
) && errno
!= ENOENT
) { // Not sure how we'd get ENOENT but it would suit us just fine
914 secerror("SecDbSecDbProcessCorruptionMarker: Unable (%{darwin.errno}d) to delete db %{public}s", errno
, db_path
);
917 secwarning("SecDbSecDbProcessCorruptionMarker: deleted corrupt db %{public}s", db_path
);
924 SecDbSetCorruptionReset(SecDbRef db
, void (^corruptionReset
)(void))
926 if (db
->corruptionReset
) {
927 Block_release(db
->corruptionReset
);
928 db
->corruptionReset
= NULL
;
930 if (corruptionReset
) {
931 db
->corruptionReset
= Block_copy(corruptionReset
);
935 static bool SecDbLoggingEnabled(CFStringRef type
)
937 CFTypeRef profile
= NULL
;
938 bool enabled
= false;
940 if (csr_check(CSR_ALLOW_APPLE_INTERNAL
) != 0)
943 profile
= (CFNumberRef
)CFPreferencesCopyValue(CFSTR("SQLProfile"), CFSTR("com.apple.security"), kCFPreferencesAnyUser
, kCFPreferencesAnyHost
);
948 if (CFGetTypeID(profile
) == CFBooleanGetTypeID()) {
949 enabled
= CFBooleanGetValue((CFBooleanRef
)profile
);
950 } else if (CFGetTypeID(profile
) == CFNumberGetTypeID()) {
952 CFNumberGetValue(profile
, kCFNumberSInt32Type
, &num
);
956 CFReleaseSafe(profile
);
962 SecDbProfileMask(void)
964 static dispatch_once_t onceToken
;
965 static unsigned profile_mask
= 0;
967 // sudo defaults write /Library/Preferences/com.apple.security SQLProfile -bool true
968 dispatch_once(&onceToken
, ^{
969 if (SecDbLoggingEnabled(CFSTR("SQLProfile")))
970 profile_mask
= SQLITE_TRACE_PROFILE
;
972 profile_mask
|= SQLITE_TRACE_STMT
;
974 if (SecDbLoggingEnabled(CFSTR("SQLTrace")))
975 profile_mask
= SQLITE_TRACE_STMT
;
977 if (SecDbLoggingEnabled(CFSTR("SQLRow")))
978 profile_mask
= SQLITE_TRACE_ROW
;
979 secinfo("#SecDB", "sqlDb: sql trace mask: 0x%08x", profile_mask
);
985 SecDbTraceV2(unsigned mask
, void *ctx
, void *p
, void *x
) {
986 SecDbConnectionRef dbconn __unused
= ctx
;
987 const char *trace
= "unknown";
989 if (mask
== SQLITE_TRACE_PROFILE
)
990 trace
= sqlite3_sql(p
);
991 else if (mask
== SQLITE_TRACE_STMT
) {
992 trace
= sqlite3_sql(p
);
993 } else if (mask
== SQLITE_TRACE_ROW
) {
994 trace
= sqlite3_expanded_sql(p
);
998 secinfo("#SecDB", "#SecDB %{public}s", trace
);
1004 static bool SecDbOpenHandle(SecDbConnectionRef dbconn
, bool *created
, CFErrorRef
*error
)
1006 __block
bool ok
= true;
1008 // This is pretty terrible because now what? We know we have a corrupt DB
1009 // and now we can't get rid of it.
1010 if (!SecDbProcessCorruptionMarker(dbconn
->db
->db_path
)) {
1011 SecCFCreateErrorWithFormat(errno
, kSecErrnoDomain
, NULL
, error
, NULL
, CFSTR("Unable to process corruption marker: %{darwin.errno}d"), errno
);
1015 CFStringPerformWithCString(dbconn
->db
->db_path
, ^(const char *db_path
) {
1016 int flags
= (dbconn
->db
->readWrite
) ? SQLITE_OPEN_READWRITE
: SQLITE_OPEN_READONLY
;
1017 ok
= created
&& SecDbOpenV2(dbconn
, db_path
, flags
, NULL
);
1021 char *tmp
= dirname((char *)db_path
);
1023 mode_t omode
= dbconn
->db
->mode
;
1024 if (omode
& S_IRUSR
) { omode
|= S_IXUSR
; } // owner can read
1025 if (omode
& S_IRGRP
) { omode
|= S_IXGRP
; } // group can read
1026 if (omode
& S_IROTH
) { omode
|= S_IXOTH
; } // other can read
1027 int errnum
= mkpath_np(tmp
, omode
);
1028 if (errnum
!= 0 && errnum
!= EEXIST
) {
1029 SecCFCreateErrorWithFormat(errnum
, kSecErrnoDomain
, NULL
, error
, NULL
,
1030 CFSTR("mkpath_np %s: [%d] %s"), tmp
, errnum
, strerror(errnum
));
1035 // if the enclosing directory is ok, try to create the database.
1036 // this forces us to open it read-write, so we'll need to be the owner here.
1037 ok
= ok
&& SecDbOpenV2(dbconn
, db_path
, SQLITE_OPEN_READWRITE
| SQLITE_OPEN_CREATE
, error
);
1039 chmod(db_path
, dbconn
->db
->mode
); // default: 0600 (S_IRUSR | S_IWUSR)
1046 unsigned mask
= SecDbProfileMask();
1048 (void)sqlite3_trace_v2(dbconn
->handle
,
1059 static SecDbConnectionRef
1060 SecDbConnectionCreate(SecDbRef db
, bool readOnly
, CFErrorRef
*error
)
1062 SecDbConnectionRef dbconn
= NULL
;
1064 dbconn
= CFTypeAllocate(SecDbConnection
, struct __OpaqueSecDbConnection
, kCFAllocatorDefault
);
1065 require(dbconn
!= NULL
, done
);
1068 dbconn
->readOnly
= readOnly
;
1069 dbconn
->inTransaction
= false;
1070 dbconn
->source
= kSecDbInvalidTransaction
;
1071 dbconn
->isCorrupted
= false;
1072 dbconn
->maybeCorruptedCode
= 0;
1073 dbconn
->hasIOFailure
= false;
1074 dbconn
->corruptionError
= NULL
;
1075 dbconn
->handle
= NULL
;
1076 dbconn
->changes
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
1082 bool SecDbConnectionIsReadOnly(SecDbConnectionRef dbconn
) {
1083 return dbconn
->readOnly
;
1086 static void SecDbConectionSetReadOnly(SecDbConnectionRef dbconn
, bool readOnly
) {
1087 dbconn
->readOnly
= readOnly
;
1090 /* Read only connections go to the end of the queue, writeable connections
1091 go to the start of the queue. */
1092 SecDbConnectionRef
SecDbConnectionAcquire(SecDbRef db
, bool readOnly
, CFErrorRef
*error
) {
1093 SecDbConnectionRef dbconn
= NULL
;
1094 SecDbConnectionAcquireRefMigrationSafe(db
, readOnly
, &dbconn
, error
);
1098 bool SecDbConnectionAcquireRefMigrationSafe(SecDbRef db
, bool readOnly
, SecDbConnectionRef
* dbconnRef
, CFErrorRef
*error
)
1102 secinfo("dbconn", "acquire %s connection", readOnly
? "ro" : "rw");
1104 dispatch_semaphore_wait(readOnly
? db
->read_semaphore
: db
->write_semaphore
, DISPATCH_TIME_FOREVER
);
1105 __block SecDbConnectionRef dbconn
= NULL
;
1106 __block
bool ok
= true;
1107 __block
bool ranOpenedHandler
= false;
1109 bool (^assignDbConn
)(SecDbConnectionRef
) = ^bool(SecDbConnectionRef connection
) {
1110 dbconn
= connection
;
1112 *dbconnRef
= connection
;
1115 return dbconn
!= NULL
;
1118 dispatch_sync(db
->queue
, ^{
1119 if (!db
->didFirstOpen
) {
1120 bool didCreate
= false;
1121 ok
= assignDbConn(SecDbConnectionCreate(db
, false, error
));
1122 CFErrorRef localError
= NULL
;
1123 if (ok
&& !SecDbOpenHandle(dbconn
, &didCreate
, &localError
)) {
1124 secerror("Unable to create database: %@", localError
);
1125 if (localError
&& CFEqual(CFErrorGetDomain(localError
), kSecDbErrorDomain
)) {
1126 int code
= (int)CFErrorGetCode(localError
);
1127 dbconn
->isCorrupted
= (SQLITE_CORRUPT
== code
) || (SQLITE_NOTADB
== code
);
1129 // If the open failure isn't due to corruption, propagate the error.
1130 ok
= dbconn
->isCorrupted
;
1131 if (!ok
&& error
&& *error
== NULL
) {
1132 *error
= localError
;
1136 CFReleaseNull(localError
);
1139 db
->didFirstOpen
= ok
= SecDbDidCreateFirstConnection(dbconn
, didCreate
, error
);
1140 ranOpenedHandler
= true;
1143 CFReleaseNull(dbconn
);
1145 /* Try to get one from the cache */
1146 CFIndex count
= CFArrayGetCount(db
->connections
);
1147 while (count
&& !dbconn
) {
1148 CFIndex ix
= readOnly
? count
- 1 : 0;
1149 if (assignDbConn((SecDbConnectionRef
)CFArrayGetValueAtIndex(db
->connections
, ix
)))
1150 CFRetainSafe(dbconn
);
1152 secerror("got NULL dbconn at index: %" PRIdCFIndex
" skipping", ix
);
1153 CFArrayRemoveValueAtIndex(db
->connections
, ix
);
1159 /* Make sure the connection we found has the right access */
1160 if (SecDbConnectionIsReadOnly(dbconn
) != readOnly
) {
1161 SecDbConectionSetReadOnly(dbconn
, readOnly
);
1164 /* Nothing found in cache, create a new connection */
1165 bool created
= false;
1166 if (assignDbConn(SecDbConnectionCreate(db
, readOnly
, error
)) && !SecDbOpenHandle(dbconn
, &created
, error
)) {
1167 CFReleaseNull(dbconn
);
1172 if (dbconn
&& !ranOpenedHandler
&& dbconn
->db
->opened
) {
1173 dispatch_sync(db
->queue
, ^{
1174 if (dbconn
->db
->callOpenedHandlerForNextConnection
) {
1175 dbconn
->db
->callOpenedHandlerForNextConnection
= false;
1176 if (!dbconn
->db
->opened(db
, dbconn
, false, &dbconn
->db
->callOpenedHandlerForNextConnection
, error
)) {
1177 if (!dbconn
->isCorrupted
|| !SecDbHandleCorrupt(dbconn
, 0, error
)) {
1178 CFReleaseNull(dbconn
);
1186 *dbconnRef
= dbconn
;
1190 // If acquire fails we need to signal the semaphore again.
1191 dispatch_semaphore_signal(readOnly
? db
->read_semaphore
: db
->write_semaphore
);
1195 return dbconn
? true : false;
1198 void SecDbConnectionRelease(SecDbConnectionRef dbconn
) {
1200 secerror("called with NULL dbconn");
1203 SecDbRef db
= dbconn
->db
;
1205 secinfo("dbconn", "release %@", dbconn
);
1207 dispatch_sync(db
->queue
, ^{
1208 bool readOnly
= SecDbConnectionIsReadOnly(dbconn
);
1209 if (dbconn
->hasIOFailure
) {
1210 // Something wrong on the file layer (e.g. revoked file descriptor for networked home)
1211 // so we don't trust our existing connections anymore.
1212 CFArrayRemoveAllValues(db
->connections
);
1214 CFIndex count
= CFArrayGetCount(db
->connections
);
1215 // Add back possible writable dbconn to the pool.
1216 CFArrayInsertValueAtIndex(db
->connections
, readOnly
? count
: 0, dbconn
);
1217 // Remove the last (probably read-only) dbconn from the pool.
1218 if (count
>= db
->maxIdleHandles
) {
1219 CFArrayRemoveValueAtIndex(db
->connections
, count
);
1222 // Signal after we have put the connection back in the pool of connections
1223 dispatch_semaphore_signal(readOnly
? db
->read_semaphore
: db
->write_semaphore
);
1229 void SecDbReleaseAllConnections(SecDbRef db
) {
1230 // Force all connections to be removed (e.g. file descriptor no longer valid)
1232 secerror("called with NULL db");
1235 dispatch_sync(db
->queue
, ^{
1236 CFArrayRemoveAllValues(db
->connections
);
1237 dispatch_semaphore_signal(db
->write_semaphore
);
1238 dispatch_semaphore_signal(db
->read_semaphore
);
1242 bool SecDbPerformRead(SecDbRef db
, CFErrorRef
*error
, void (^perform
)(SecDbConnectionRef dbconn
)) {
1243 SecDbConnectionRef dbconn
= SecDbConnectionAcquire(db
, true, error
);
1244 bool success
= false;
1248 SecDbConnectionRelease(dbconn
);
1253 bool SecDbPerformWrite(SecDbRef db
, CFErrorRef
*error
, void (^perform
)(SecDbConnectionRef dbconn
)) {
1255 SecError(errSecNotAvailable
, error
, CFSTR("failed to get a db handle"));
1258 SecDbConnectionRef dbconn
= SecDbConnectionAcquire(db
, false, error
);
1259 bool success
= false;
1263 SecDbConnectionRelease(dbconn
);
1269 SecDbConnectionCopyFormatDescription(CFTypeRef value
, CFDictionaryRef formatOptions
)
1271 SecDbConnectionRef dbconn
= (SecDbConnectionRef
)value
;
1272 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("<SecDbConnection %s %s>"),
1273 dbconn
->readOnly
? "ro" : "rw", dbconn
->handle
? "open" : "closed");
1277 SecDbConnectionDestroy(CFTypeRef value
)
1279 SecDbConnectionRef dbconn
= (SecDbConnectionRef
)value
;
1280 if (dbconn
->handle
) {
1281 int s3e
= sqlite3_close(dbconn
->handle
);
1282 if (s3e
!= SQLITE_OK
) {
1283 secerror("failed to close database connection (%d) for %@: %s", s3e
, dbconn
->db
->db_path
, sqlite3_errmsg(dbconn
->handle
));
1285 os_assert(s3e
== SQLITE_OK
); // Crash now or jetsam later
1288 CFReleaseNull(dbconn
->changes
);
1289 CFReleaseNull(dbconn
->corruptionError
);
1293 void SecDbPerformOnCommitQueue(SecDbConnectionRef dbconn
, bool barrier
, dispatch_block_t perform
) {
1295 dispatch_barrier_sync(dbconn
->db
->commitQueue
, ^{
1299 dispatch_sync(dbconn
->db
->commitQueue
, ^{
1306 // MARK: Bind helpers
1308 // Logging binds is very spammy when debug logging is on (~90% of log lines), and isn't often useful.
1309 // Enable this in your local build if you actually want every single SQL variable bind logged for debugging.
1310 #define LOG_SECDB_BINDS 0
1312 bool SecDbBindBlob(sqlite3_stmt
*stmt
, int param
, const void *zData
, size_t n
, void(*xDel
)(void*), CFErrorRef
*error
) {
1314 return SecDbErrorWithStmt(SQLITE_TOOBIG
, stmt
, error
,
1315 CFSTR("bind_blob[%d]: blob bigger than INT_MAX"), param
);
1317 bool ok
= SecDbErrorWithStmt(sqlite3_bind_blob(stmt
, param
, zData
, (int)n
, xDel
),
1318 stmt
, error
, CFSTR("bind_blob[%d]"), param
);
1320 secinfo("bind", "bind_blob[%d]: %.*P: %@", param
, (int)n
, zData
, error
? *error
: NULL
);
1325 bool SecDbBindText(sqlite3_stmt
*stmt
, int param
, const char *zData
, size_t n
, void(*xDel
)(void*), CFErrorRef
*error
) {
1327 return SecDbErrorWithStmt(SQLITE_TOOBIG
, stmt
, error
,
1328 CFSTR("bind_text[%d]: text bigger than INT_MAX"), param
);
1330 bool ok
= SecDbErrorWithStmt(sqlite3_bind_text(stmt
, param
, zData
, (int)n
, xDel
), stmt
, error
,
1331 CFSTR("bind_text[%d]"), param
);
1333 secinfo("bind", "bind_text[%d]: \"%s\" error: %@", param
, zData
, error
? *error
: NULL
);
1338 bool SecDbBindDouble(sqlite3_stmt
*stmt
, int param
, double value
, CFErrorRef
*error
) {
1339 bool ok
= SecDbErrorWithStmt(sqlite3_bind_double(stmt
, param
, value
), stmt
, error
,
1340 CFSTR("bind_double[%d]"), param
);
1342 secinfo("bind", "bind_double[%d]: %f error: %@", param
, value
, error
? *error
: NULL
);
1347 bool SecDbBindInt(sqlite3_stmt
*stmt
, int param
, int value
, CFErrorRef
*error
) {
1348 bool ok
= SecDbErrorWithStmt(sqlite3_bind_int(stmt
, param
, value
), stmt
, error
,
1349 CFSTR("bind_int[%d]"), param
);
1351 secinfo("bind", "bind_int[%d]: %d error: %@", param
, value
, error
? *error
: NULL
);
1356 bool SecDbBindInt64(sqlite3_stmt
*stmt
, int param
, sqlite3_int64 value
, CFErrorRef
*error
) {
1357 bool ok
= SecDbErrorWithStmt(sqlite3_bind_int64(stmt
, param
, value
), stmt
, error
,
1358 CFSTR("bind_int64[%d]"), param
);
1360 secinfo("bind", "bind_int64[%d]: %lld error: %@", param
, value
, error
? *error
: NULL
);
1366 /* AUDIT[securityd](done):
1367 value (ok) is a caller provided, non NULL CFTypeRef.
1369 bool SecDbBindObject(sqlite3_stmt
*stmt
, int param
, CFTypeRef value
, CFErrorRef
*error
) {
1371 __block
bool result
= false;
1373 /* TODO: Can we use SQLITE_STATIC below everwhere we currently use
1374 SQLITE_TRANSIENT since we finalize the statement before the value
1375 goes out of scope? */
1376 if (!value
|| (valueId
= CFGetTypeID(value
)) == CFNullGetTypeID()) {
1377 /* Skip bindings for NULL values. sqlite3 will interpret unbound
1378 params as NULL which is exactly what we want. */
1380 } else if (valueId
== CFStringGetTypeID()) {
1381 CFStringPerformWithCStringAndLength(value
, ^(const char *cstr
, size_t clen
) {
1382 result
= SecDbBindText(stmt
, param
, cstr
, clen
, SQLITE_TRANSIENT
, error
);
1384 } else if (valueId
== CFDataGetTypeID()) {
1385 CFIndex len
= CFDataGetLength(value
);
1387 result
= SecDbBindBlob(stmt
, param
, CFDataGetBytePtr(value
),
1388 len
, SQLITE_TRANSIENT
, error
);
1390 result
= SecDbBindText(stmt
, param
, "", 0, SQLITE_TRANSIENT
, error
);
1392 } else if (valueId
== CFDateGetTypeID()) {
1393 CFAbsoluteTime abs_time
= CFDateGetAbsoluteTime(value
);
1394 result
= SecDbBindDouble(stmt
, param
, abs_time
, error
);
1395 } else if (valueId
== CFBooleanGetTypeID()) {
1396 int bval
= CFBooleanGetValue(value
);
1397 result
= SecDbBindInt(stmt
, param
, bval
, error
);
1398 } else if (valueId
== CFNumberGetTypeID()) {
1400 if (CFNumberIsFloatType(value
)) {
1402 convertOk
= CFNumberGetValue(value
, kCFNumberDoubleType
, &nval
);
1403 result
= SecDbBindDouble(stmt
, param
, nval
, error
);
1405 sqlite_int64 nval64
;
1406 convertOk
= CFNumberGetValue(value
, kCFNumberSInt64Type
, &nval64
);
1408 result
= SecDbBindInt64(stmt
, param
, nval64
, error
);
1412 result
= SecDbError(SQLITE_INTERNAL
, error
, CFSTR("bind CFNumberGetValue failed for %@"), value
);
1416 CFStringRef valueDesc
= CFCopyTypeIDDescription(valueId
);
1417 SecDbError(SQLITE_MISMATCH
, error
, CFSTR("bind unsupported type %@"), valueDesc
);
1418 CFReleaseSafe(valueDesc
);
1426 // MARK: SecDbStatementRef
1428 bool SecDbReset(sqlite3_stmt
*stmt
, CFErrorRef
*error
) {
1429 return SecDbErrorWithStmt(sqlite3_reset(stmt
), stmt
, error
, CFSTR("reset"));
1432 bool SecDbClearBindings(sqlite3_stmt
*stmt
, CFErrorRef
*error
) {
1433 return SecDbErrorWithStmt(sqlite3_clear_bindings(stmt
), stmt
, error
, CFSTR("clear bindings"));
1436 bool SecDbFinalize(sqlite3_stmt
*stmt
, CFErrorRef
*error
) {
1437 sqlite3
*handle
= sqlite3_db_handle(stmt
);
1438 int s3e
= sqlite3_finalize(stmt
);
1439 return s3e
== SQLITE_OK
? true : SecDbErrorWithDb(s3e
, handle
, error
, CFSTR("finalize: %p"), stmt
);
1442 sqlite3_stmt
*SecDbPrepareV2(SecDbConnectionRef dbconn
, const char *sql
, size_t sqlLen
, const char **sqlTail
, CFErrorRef
*error
) {
1443 sqlite3
*db
= SecDbHandle(dbconn
);
1444 if (sqlLen
> INT_MAX
) {
1445 SecDbErrorWithDb(SQLITE_TOOBIG
, db
, error
, CFSTR("prepare_v2: sql bigger than INT_MAX"));
1450 sqlite3_stmt
*stmt
= NULL
;
1451 int s3e
= sqlite3_prepare_v2(db
, sql
, (int)sqlLen
, &stmt
, sqlTail
);
1452 if (s3e
== SQLITE_OK
)
1454 else if (!SecDbWaitIfNeeded(dbconn
, s3e
, NULL
, CFSTR("preparev2"), ntries
, error
))
1460 static sqlite3_stmt
*SecDbCopyStatementWithTailRange(SecDbConnectionRef dbconn
, CFStringRef sql
, CFRange
*sqlTail
, CFErrorRef
*error
) {
1461 __block sqlite3_stmt
*stmt
= NULL
;
1462 if (sql
) CFStringPerformWithCStringAndLength(sql
, ^(const char *sqlStr
, size_t sqlLen
) {
1463 const char *tail
= NULL
;
1464 stmt
= SecDbPrepareV2(dbconn
, sqlStr
, sqlLen
, &tail
, error
);
1465 if (sqlTail
&& sqlStr
< tail
&& tail
< sqlStr
+ sqlLen
) {
1466 sqlTail
->location
= tail
- sqlStr
;
1467 sqlTail
->length
= sqlLen
- sqlTail
->location
;
1474 sqlite3_stmt
*SecDbCopyStmt(SecDbConnectionRef dbconn
, CFStringRef sql
, CFStringRef
*tail
, CFErrorRef
*error
) {
1475 // TODO: Add caching and cache lookup of statements
1476 CFRange sqlTail
= {};
1477 sqlite3_stmt
*stmt
= SecDbCopyStatementWithTailRange(dbconn
, sql
, &sqlTail
, error
);
1478 if (sqlTail
.length
> 0) {
1479 CFStringRef excess
= CFStringCreateWithSubstring(CFGetAllocator(sql
), sql
, sqlTail
);
1483 SecDbError(SQLITE_INTERNAL
, error
,
1484 CFSTR("prepare_v2: %@ unused sql: %@"),
1486 CFReleaseSafe(excess
);
1487 SecDbFinalize(stmt
, error
);
1495 TODO: Could do a hack here with a custom kCFAllocatorNULL allocator for a second CFRuntimeBase inside a SecDbStatement,
1496 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. */
1497 bool SecDbReleaseCachedStmt(SecDbConnectionRef dbconn
, CFStringRef sql
, sqlite3_stmt
*stmt
, CFErrorRef
*error
) {
1499 return SecDbFinalize(stmt
, error
);
1504 bool SecDbPrepare(SecDbConnectionRef dbconn
, CFStringRef sql
, CFErrorRef
*error
, void(^exec
)(sqlite3_stmt
*stmt
)) {
1505 assert(sql
!= NULL
);
1506 sqlite3_stmt
*stmt
= SecDbCopyStmt(dbconn
, sql
, NULL
, error
);
1511 return SecDbReleaseCachedStmt(dbconn
, sql
, stmt
, error
);
1514 bool SecDbWithSQL(SecDbConnectionRef dbconn
, CFStringRef sql
, CFErrorRef
*error
, bool(^perform
)(sqlite3_stmt
*stmt
)) {
1518 CFStringRef tail
= NULL
;
1520 sqlite3_stmt
*stmt
= SecDbCopyStmt(dbconn
, sql
, &tail
, error
);
1526 // TODO: Use a different error scope here.
1527 ok
= SecError(-50 /* errSecParam */, error
, CFSTR("SecDbWithSQL perform block missing"));
1529 ok
&= SecDbReleaseCachedStmt(dbconn
, sql
, stmt
, error
);
1532 // TODO We already have an error here we really just want the left over sql in it's userData
1533 ok
= SecDbError(SQLITE_ERROR
, error
, CFSTR("Error with unexecuted sql remaining %@"), sql
);
1541 /* SecDbForEach returns true if all SQLITE_ROW returns of sqlite3_step() return true from the row block.
1542 If the row block returns false and doesn't set an error (to indicate it has reached a limit),
1543 this entire function returns false. In that case no error will be set. */
1544 bool SecDbForEach(SecDbConnectionRef dbconn
, sqlite3_stmt
*stmt
, CFErrorRef
*error
, bool(^row
)(int row_index
)) {
1545 bool result
= false;
1546 for (int row_ix
= 0;;++row_ix
) {
1547 if (SecDbConnectionIsReadOnly(dbconn
) && !sqlite3_stmt_readonly(stmt
)) {
1548 secerror("SecDbForEach: SecDbConnection is readonly but we're about to write: %s", sqlite3_sql(stmt
));
1550 int s3e
= sqlite3_step(stmt
);
1551 if (s3e
== SQLITE_ROW
) {
1557 // If we have no row block then getting SQLITE_ROW is an error
1558 SecDbError(s3e
, error
,
1559 CFSTR("step[%d]: %s returned SQLITE_ROW with NULL row block"),
1560 row_ix
, sqlite3_sql(stmt
));
1563 if (s3e
== SQLITE_DONE
) {
1566 SecDbConnectionCheckCode(dbconn
, s3e
, error
, CFSTR("SecDbForEach step[%d]"), row_ix
);
1574 void SecDbRecordChange(SecDbConnectionRef dbconn
, CFTypeRef deleted
, CFTypeRef inserted
) {
1575 if (!dbconn
->db
->notifyPhase
) return;
1576 CFTypeRef entry
= SecDbEventCreateWithComponents(deleted
, inserted
);
1578 CFArrayAppendValue(dbconn
->changes
, entry
);
1581 if (!dbconn
->inTransaction
) {
1582 secerror("db %@ changed outside txn", dbconn
);
1583 // Only notify of DidCommit, since WillCommit code assumes
1585 SecDbOnNotify(dbconn
, ^{
1586 SecDbNotifyPhase(dbconn
, kSecDbTransactionDidCommit
);
1593 CFGiblisFor(SecDbConnection
)
1596 // SecDbEvent Creation and consumption
1599 static SecDbEventRef
SecDbEventCreateInsert(CFTypeRef inserted
) {
1600 return CFRetainSafe(inserted
);
1603 static SecDbEventRef
SecDbEventCreateDelete(CFTypeRef deleted
) {
1604 return CFArrayCreate(kCFAllocatorDefault
, &deleted
, 1, &kCFTypeArrayCallBacks
);
1607 static SecDbEventRef
SecDbEventCreateUpdate(CFTypeRef deleted
, CFTypeRef inserted
) {
1608 const void *values
[2] = { deleted
, inserted
};
1609 return CFArrayCreate(kCFAllocatorDefault
, values
, 2, &kCFTypeArrayCallBacks
);
1612 SecDbEventRef
SecDbEventCreateWithComponents(CFTypeRef deleted
, CFTypeRef inserted
) {
1613 if (deleted
&& inserted
)
1614 return SecDbEventCreateUpdate(deleted
, inserted
);
1616 return SecDbEventCreateDelete(deleted
);
1618 return SecDbEventCreateInsert(inserted
);
1623 void SecDbEventTranslateComponents(SecDbEventRef item
, CFTypeRef
* deleted
, CFTypeRef
* inserted
) {
1624 if(CFGetTypeID(item
) == CFArrayGetTypeID()) {
1625 // One item: deletion. Two: update.
1626 CFIndex arraySize
= CFArrayGetCount(item
);
1627 if(arraySize
== 1) {
1628 if(deleted
) { *deleted
= CFArrayGetValueAtIndex(item
, 0); }
1629 if(inserted
) { *inserted
= NULL
; }
1630 } else if(arraySize
== 2) {
1631 if(deleted
) { *deleted
= CFArrayGetValueAtIndex(item
, 0); }
1632 if(inserted
) { *inserted
= CFArrayGetValueAtIndex(item
, 1); }
1634 if(deleted
) { *deleted
= NULL
; }
1635 if(inserted
) { *inserted
= NULL
; }
1638 if(deleted
) { *deleted
= NULL
; }
1639 if(inserted
) { *inserted
= item
; }
1644 bool SecDbEventGetComponents(SecDbEventRef event
, CFTypeRef
*deleted
, CFTypeRef
*inserted
, CFErrorRef
*error
) {
1645 if (isArray(event
)) {
1646 CFArrayRef array
= event
;
1647 switch (CFArrayGetCount(array
)) {
1649 *deleted
= CFArrayGetValueAtIndex(array
, 0);
1650 *inserted
= CFArrayGetValueAtIndex(array
, 1);
1653 *deleted
= CFArrayGetValueAtIndex(array
, 0);
1657 SecError(errSecParam
, error
, NULL
, CFSTR("invalid entry in changes array: %@"), array
);