]> git.saurik.com Git - apple/security.git/blob - OSX/utilities/SecDb.c
Security-59306.41.2.tar.gz
[apple/security.git] / OSX / utilities / SecDb.c
1 /*
2 * Copyright (c) 2012-2017 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 #include "SecDb.h"
26 #include "debugging.h"
27
28 #include <sqlite3.h>
29 #include <sqlite3_private.h>
30 #include <CoreFoundation/CoreFoundation.h>
31 #include <libgen.h>
32 #include <sys/csr.h>
33 #include <sys/stat.h>
34 #include <AssertMacros.h>
35 #include "SecCFWrappers.h"
36 #include "SecCFError.h"
37 #include "SecIOFormat.h"
38 #include <stdio.h>
39 #include "Security/SecBase.h"
40 #include "SecAutorelease.h"
41 #include <os/assumes.h>
42 #include <xpc/private.h> // xpc_transaction_exit_clean()
43
44
45 //
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)
49 //
50 #include "keychain/SecureObjectSync/SOSDigestVector.h"
51 #include "keychain/SecureObjectSync/SOSManifest.h"
52
53 #define SECDB_DEBUGGING 0
54
55 struct __OpaqueSecDbStatement {
56 CFRuntimeBase _base;
57
58 SecDbConnectionRef dbconn;
59 sqlite3_stmt *stmt;
60 };
61
62 struct __OpaqueSecDbConnection {
63 CFRuntimeBase _base;
64
65 //CFMutableDictionaryRef statements;
66
67 SecDbRef db; // NONRETAINED, since db or block retains us
68 bool readOnly;
69 bool inTransaction;
70 SecDbTransactionSource source;
71 bool isCorrupted;
72 int maybeCorruptedCode;
73 bool hasIOFailure;
74 CFErrorRef corruptionError;
75 sqlite3 *handle;
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;
82 };
83
84 struct __OpaqueSecDb {
85 CFRuntimeBase _base;
86
87 CFStringRef db_path;
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;
93 bool didFirstOpen;
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);
104 };
105
106 // MARK: Error domains and error helper functions
107
108 CFStringRef kSecDbErrorDomain = CFSTR("com.apple.utilities.sqlite3");
109
110 bool SecDbError(int sql_code, CFErrorRef *error, CFStringRef format, ...) {
111 if (sql_code == SQLITE_OK) return true;
112
113 if (error) {
114 va_list args;
115 CFIndex code = sql_code;
116 CFErrorRef previousError = *error;
117
118 *error = NULL;
119 va_start(args, format);
120 SecCFCreateErrorWithFormatAndArguments(code, kSecDbErrorDomain, previousError, error, NULL, format, args);
121 va_end(args);
122 }
123 return false;
124 }
125
126 bool SecDbErrorWithDb(int sql_code, sqlite3 *db, CFErrorRef *error, CFStringRef format, ...) {
127 if (sql_code == SQLITE_OK) return true;
128 if (error) {
129 va_list args;
130 va_start(args, format);
131 CFStringRef message = CFStringCreateWithFormatAndArguments(kCFAllocatorDefault, NULL, format, args);
132 va_end(args);
133 CFStringRef errno_code = NULL;
134
135 if (sql_code == SQLITE_CANTOPEN) {
136 int errno_number = sqlite3_system_errno(db);
137 errno_code = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), errno_number);
138 } else {
139 errno_code = CFRetain(CFSTR(""));
140 }
141
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));
145 else
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);
149 }
150 return false;
151 }
152
153 bool SecDbErrorWithStmt(int sql_code, sqlite3_stmt *stmt, CFErrorRef *error, CFStringRef format, ...) {
154 if (sql_code == SQLITE_OK) return true;
155 if (error) {
156 va_list args;
157 va_start(args, format);
158 CFStringRef message = CFStringCreateWithFormatAndArguments(kCFAllocatorDefault, NULL, format, args);
159 va_end(args);
160
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);
166 else
167 SecDbError(sql_code, error, CFSTR("%@: [%d->%d] %s sql: %s"), message, sql_code, extended_code, sqlite3_errmsg(db), sql);
168 CFReleaseSafe(message);
169 }
170 return false;
171 }
172
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);
176 }
177
178 void _SecDbServerSetup(void)
179 {
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);
185 }
186 });
187 }
188
189
190 // MARK: -
191 // MARK: Static helper functions
192
193 static bool SecDbOpenHandle(SecDbConnectionRef dbconn, bool *created, CFErrorRef *error);
194 static bool SecDbHandleCorrupt(SecDbConnectionRef dbconn, int rc, CFErrorRef *error);
195
196 #pragma mark -
197 #pragma mark SecDbRef
198
199 static CFStringRef
200 SecDbCopyFormatDescription(CFTypeRef value, CFDictionaryRef formatOptions)
201 {
202 SecDbRef db = (SecDbRef)value;
203 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<SecDb path:%@ connections: %@>"), db->db_path, db->connections);
204 }
205
206
207 static void
208 SecDbDestroy(CFTypeRef value)
209 {
210 SecDbRef db = (SecDbRef)value;
211 CFReleaseNull(db->connections);
212 CFReleaseNull(db->db_path);
213 if (db->queue) {
214 dispatch_release(db->queue);
215 db->queue = NULL;
216 }
217 if (db->commitQueue) {
218 dispatch_release(db->commitQueue);
219 db->commitQueue = NULL;
220 }
221 if (db->read_semaphore) {
222 dispatch_release(db->read_semaphore);
223 db->read_semaphore = NULL;
224 }
225 if (db->write_semaphore) {
226 dispatch_release(db->write_semaphore);
227 db->write_semaphore = NULL;
228 }
229 if (db->opened) {
230 Block_release(db->opened);
231 db->opened = NULL;
232 }
233 CFReleaseNull(db->notifyPhase);
234 }
235
236 CFGiblisFor(SecDb)
237
238 SecDbRef
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))
241 {
242 SecDbRef db = NULL;
243
244 db = CFTypeAllocate(SecDb, struct __OpaqueSecDb, kCFAllocatorDefault);
245 require(db != NULL, done);
246
247 CFStringPerformWithCString(dbName, ^(const char *dbNameStr) {
248 db->queue = dispatch_queue_create(dbNameStr, DISPATCH_QUEUE_SERIAL);
249 });
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);
253 });
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");
262
263 db->db_path = CFSTR("file::memory:?cache=shared");
264 } else {
265 db->db_path = CFStringCreateCopy(kCFAllocatorDefault, dbName);
266 }
267 db->mode = mode;
268 db->readWrite = readWrite;
269 db->allowRepair = allowRepair;
270 db->useWAL = useWAL;
271 db->useRobotVacuum = useRobotVacuum;
272 db->maxIdleHandles = maxIdleHandles;
273 db->corruptionReset = NULL;
274
275 done:
276 return db;
277 }
278
279 CFIndex
280 SecDbIdleConnectionCount(SecDbRef db) {
281 __block CFIndex count = 0;
282 dispatch_sync(db->queue, ^{
283 count = CFArrayGetCount(db->connections);
284 });
285 return count;
286 }
287
288 void SecDbAddNotifyPhaseBlock(SecDbRef db, SecDBNotifyBlock notifyPhase)
289 {
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);
295 }
296 CFArrayAppendValue(db->notifyPhase, block);
297 Block_release(block);
298 });
299 }
300
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);
309 });
310 }
311 CFReleaseSafe(changes);
312 }
313 }
314
315 static void SecDbOnNotify(SecDbConnectionRef dbconn, void (^perform)(void)) {
316 perform();
317 }
318
319 CFStringRef SecDbGetPath(SecDbRef db) {
320 if(!db) {
321 return NULL;
322 }
323 return db->db_path;
324 }
325
326
327 #pragma mark -
328 #pragma mark SecDbConnectionRef
329
330 static bool SecDbCheckCorrupted(SecDbConnectionRef dbconn)
331 {
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) {
339 isCorrupted = true;
340 secerror("SecDBCheckCorrupted integrity_check returned %s", (result) ? result : "NULL");
341 }
342 checkDidRun = true;
343 });
344 });
345 if (!checkDidRun) {
346 // An error occurred in SecDbPrepare before we could run the block.
347 if (error) {
348 CFIndex code = CFErrorGetCode(error);
349 if (SQLITE_CORRUPT == code || SQLITE_NOTADB == code) {
350 isCorrupted = true;
351 }
352 secinfo("#SecDB", "#SecDB warning error %{public}@ when running integrity check", error);
353 } else {
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.
358 isCorrupted = true;
359 secinfo("#SecDB", "#SecDB warning: failed to run integrity check due to corruption");
360 }
361 }
362 if (isCorrupted) {
363 if (checkDidRun) {
364 secerror("SecDBCheckCorrupted ran integrity_check, and that didn't return ok");
365 } else {
366 secerror("SecDBCheckCorrupted failed to run integrity check");
367 }
368 }
369 CFReleaseNull(error);
370
371 return isCorrupted;
372 }
373
374 static bool SecDbDidCreateFirstConnection(SecDbConnectionRef dbconn, bool didCreate, CFErrorRef *error)
375 {
376 secinfo("#SecDB", "#SecDB starting maintenance");
377 bool ok = true;
378
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.
381
382 if (!dbconn->isCorrupted && dbconn->db->opened) {
383 CFErrorRef localError = NULL;
384
385 dbconn->db->callOpenedHandlerForNextConnection = false;
386 ok = dbconn->db->opened(dbconn->db, dbconn, didCreate, &dbconn->db->callOpenedHandlerForNextConnection, &localError);
387
388 if (!ok)
389 secerror("opened block failed: %@", localError);
390
391 if (!dbconn->isCorrupted && error && *error == NULL) {
392 *error = localError;
393 localError = NULL;
394 } else {
395 if (localError)
396 secerror("opened block failed: error (%@) is being released and lost", localError);
397 CFReleaseNull(localError);
398 }
399 }
400
401 if (dbconn->isCorrupted) {
402 ok = SecDbHandleCorrupt(dbconn, 0, error);
403 }
404
405 secinfo("#SecDB", "#SecDB starting maintenance");
406 return ok;
407 }
408
409 void SecDbCorrupt(SecDbConnectionRef dbconn, CFErrorRef error)
410 {
411 if (__security_simulatecrash_enabled()) {
412 os_log_fault(secLogObjForScope("SecEmergency"), "SecDBCorrupt: %@", error);
413 }
414 dbconn->isCorrupted = true;
415 CFRetainAssign(dbconn->corruptionError, error);
416 }
417
418
419 static uint8_t knownDbPathIndex(SecDbConnectionRef dbconn)
420 {
421
422 if(CFEqual(dbconn->db->db_path, CFSTR("/Library/Keychains/keychain-2.db")))
423 return 1;
424 if(CFEqual(dbconn->db->db_path, CFSTR("/Library/Keychains/ocspcache.sqlite3")))
425 return 2;
426 if(CFEqual(dbconn->db->db_path, CFSTR("/Library/Keychains/TrustStore.sqlite3")))
427 return 3;
428 if(CFEqual(dbconn->db->db_path, CFSTR("/Library/Keychains/caissuercache.sqlite3")))
429 return 4;
430
431 /* Unknown DB path */
432 return 0;
433 }
434
435 static bool SecDbConnectionCheckCode(SecDbConnectionRef dbconn, int code, CFErrorRef *error, CFStringRef desc, ...)
436 CF_FORMAT_FUNCTION(4, 5);
437
438 // Return true if there was no error, returns false otherwise and set *error to an appropriate CFErrorRef.
439 static bool SecDbConnectionCheckCode(SecDbConnectionRef dbconn, int code, CFErrorRef *error, CFStringRef desc, ...) {
440 if (code == SQLITE_OK || code == SQLITE_DONE)
441 return true;
442
443 if (error) {
444 va_list args;
445 va_start(args, desc);
446 CFStringRef msg = CFStringCreateWithFormatAndArguments(kCFAllocatorDefault, NULL, desc, args);
447 va_end(args);
448 SecDbErrorWithDb(code, dbconn->handle, error, CFSTR("%@"), msg);
449 CFRelease(msg);
450 }
451
452 dbconn->hasIOFailure |= (SQLITE_IOERR == code);
453
454 /* If it's already corrupted, don't try to recover */
455 if (dbconn->isCorrupted) {
456 CFStringRef reason = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
457 CFSTR("SQL DB %@ is corrupted already. Corruption error was: %d (previously %d)"),
458 dbconn->db->db_path, code, dbconn->maybeCorruptedCode);
459 secerror("%@",reason);
460 __security_simulatecrash(reason, __sec_exception_code_TwiceCorruptDb(knownDbPathIndex(dbconn)));
461 CFReleaseSafe(reason);
462 // We can't fall through to the checking case because it eventually calls SecDbConnectionCheckCode again.
463 // However, this is the second time we're seeing corruption so let's take the ultimate measure.
464 if ((SQLITE_CORRUPT == code) || (SQLITE_NOTADB == code)) {
465 secerror("SecDbConnectionCheckCode detected corruption twice: going to handle corrupt DB");
466 (void)SecDbHandleCorrupt(dbconn, code, error);
467 }
468 return false;
469 }
470
471 // NOTADB means file is garbage, so it's functionally equivalent to corruption
472 dbconn->isCorrupted = (SQLITE_CORRUPT == code) || (SQLITE_NOTADB == code);
473 if (dbconn->isCorrupted) {
474 /* Run integrity check and only make dbconn->isCorrupted true and
475 run the corruption handler if the integrity check conclusively fails. */
476 dbconn->maybeCorruptedCode = code;
477 dbconn->isCorrupted = SecDbCheckCorrupted(dbconn);
478 if (dbconn->isCorrupted) {
479 secerror("operation returned code: %d integrity check=fail", code);
480 (void)SecDbHandleCorrupt(dbconn, code, error);
481 } else {
482 secerror("operation returned code: %d: integrity check=pass", code);
483 }
484 }
485
486 return false;
487 }
488
489 #define BUSY_TIMEOUT_MS (5 * 60 * 1000) /* 5 minutes */
490
491 static int sleepBackoff[] = { 10, 20, 50, 100, 250 };
492 static int sumBackoff[] = { 10, 30, 80, 180, 430 };
493 static int NumberOfSleepBackoff = sizeof(sleepBackoff)/sizeof(sleepBackoff[0]);
494
495 // Use these as silly hacks to encode the SQLite return code in the backtrace, for hang debugging purposes
496 static void __attribute__((noinline)) SecDbLockSleep(int ms) {
497 sqlite3_sleep(ms);
498 }
499
500 static void __attribute__((noinline)) SecDbBusySleep(int ms) {
501 sqlite3_sleep(ms);
502 }
503
504 // Return true causes the operation to be tried again.
505 // Note that we set sqlite3_busy_timeout on the connection, so anytime you're in here, it's likely due to SQLITE_LOCKED.
506 static bool SecDbWaitIfNeeded(SecDbConnectionRef dbconn, int s3e, sqlite3_stmt *stmt, CFStringRef desc, int nTries, CFErrorRef *error) {
507 if (((0xFF & s3e) == SQLITE_BUSY) || ((0xFF & s3e) == SQLITE_LOCKED)) {
508 int totaltimeout, timeout;
509
510 _Static_assert(sizeof(sumBackoff) == sizeof(sleepBackoff), "matching arrays not matching");
511 _Static_assert(sizeof(sumBackoff[0]) == sizeof(sleepBackoff[0]), "matching arrays not matching");
512
513 if (nTries < NumberOfSleepBackoff) {
514 timeout = sleepBackoff[nTries];
515 totaltimeout = sumBackoff[nTries];
516 } else {
517 timeout = sleepBackoff[NumberOfSleepBackoff - 1];
518 totaltimeout = sumBackoff[NumberOfSleepBackoff - 1] + (timeout * (nTries - NumberOfSleepBackoff));
519 }
520 if (totaltimeout < BUSY_TIMEOUT_MS) {
521 secinfo("#SecDB", "sqlite busy/locked: %d ntries: %d totaltimeout: %d", s3e, nTries, totaltimeout);
522 if(((0xFF & s3e) == SQLITE_LOCKED)) {
523 SecDbLockSleep(timeout);
524 } else {
525 SecDbBusySleep(timeout);
526 }
527 return true;
528 } else {
529 secinfo("#SecDB", "sqlite busy/locked: too long: %d ms, giving up", totaltimeout);
530 }
531 }
532
533 return SecDbConnectionCheckCode(dbconn, s3e, error, CFSTR("%@"), desc);
534 }
535
536 enum SecDbStepResult {
537 kSecDbErrorStep = 0,
538 kSecDbRowStep = 1,
539 kSecDbDoneStep = 2,
540 };
541 typedef enum SecDbStepResult SecDbStepResult;
542
543 static SecDbStepResult _SecDbStep(SecDbConnectionRef dbconn, sqlite3_stmt *stmt, CFErrorRef *error) {
544 assert(stmt != NULL);
545 int s3e;
546 int ntries = 0;
547 for (;;) {
548 if (SecDbConnectionIsReadOnly(dbconn) && !sqlite3_stmt_readonly(stmt)) {
549 secerror("_SecDbStep: SecDbConnection is readonly but we're about to write: %s", sqlite3_sql(stmt));
550 }
551 s3e = sqlite3_step(stmt);
552 if (s3e == SQLITE_ROW) {
553 return kSecDbRowStep;
554 } else if (s3e == SQLITE_DONE) {
555 /*
556 ** ^[SQLITE_DONE] means that the statement has finished executing
557 ** successfully. sqlite3_step() should not be called again on this virtual
558 ** machine without first calling [] to reset the virtual
559 ** machine back to its initial state.
560 */
561 sqlite3_reset(stmt);
562 return kSecDbDoneStep;
563 } else if (!SecDbWaitIfNeeded(dbconn, s3e, stmt, CFSTR("step"), ntries, error)) {
564 return kSecDbErrorStep;
565 }
566 ntries++;
567 };
568 }
569
570 bool
571 SecDbExec(SecDbConnectionRef dbconn, CFStringRef sql, CFErrorRef *error)
572 {
573 bool ok = true;
574 CFRetain(sql);
575 while (sql) {
576 CFStringRef tail = NULL;
577 if (ok) {
578 sqlite3_stmt *stmt = SecDbCopyStmt(dbconn, sql, &tail, error);
579 ok = stmt != NULL;
580 if (stmt) {
581 SecDbStepResult sr;
582 while ((sr = _SecDbStep(dbconn, stmt, error)) == kSecDbRowStep);
583 if (sr == kSecDbErrorStep)
584 ok = false;
585 ok &= SecDbReleaseCachedStmt(dbconn, sql, stmt, error);
586 }
587 } else {
588 // TODO We already have an error here we really just want the left over sql in it's userData
589 ok = SecDbError(SQLITE_ERROR, error, CFSTR("Error with unexecuted sql remaining %@"), sql);
590 }
591 CFRelease(sql);
592 sql = tail;
593 }
594 return ok;
595 }
596
597 static int SecDBGetInteger(SecDbConnectionRef dbconn, CFStringRef sql)
598 {
599 __block int number = -1;
600 __block CFErrorRef error = NULL;
601
602 (void)SecDbWithSQL(dbconn, sql, &error, ^bool(sqlite3_stmt *sqlStmt) {
603 (void)SecDbStep(dbconn, sqlStmt, &error, ^(bool *stop) {
604 number = sqlite3_column_int(sqlStmt, 0);
605 *stop = true;
606 });
607 return true;
608 });
609 CFReleaseNull(error);
610 return number;
611 }
612
613
614 void SecDBManagementTasks(SecDbConnectionRef dbconn)
615 {
616 int64_t page_count = SecDBGetInteger(dbconn, CFSTR("pragma page_count"));
617 if (page_count <= 0) {
618 return;
619 }
620 int64_t free_count = SecDBGetInteger(dbconn, CFSTR("pragma freelist_count"));
621 if (free_count < 0) {
622 return;
623 }
624
625 int64_t max_free = 8192;
626
627 int64_t pages_in_use = page_count - free_count;
628 double loadFactor = ((double)pages_in_use/(double)page_count);
629 if (0.85 < loadFactor && free_count < max_free) {
630 /* no work yet */
631 } else {
632 int64_t pages_to_free = (int64_t)(0.2 * free_count);
633 if (0.4 > loadFactor) {
634 pages_to_free = free_count;
635 }
636
637 char *formatString = NULL;
638 asprintf(&formatString, "pragma incremental_vacuum(%d)", (int)pages_to_free);
639 if (formatString) {
640 char *sqlerror = NULL;
641 int rc = sqlite3_exec(dbconn->handle, formatString, NULL, NULL, &sqlerror);
642 if (rc) {
643 secerror("incremental_vacuum failed with: (%d) %{public}s", rc, sqlerror);
644 }
645 sqlite3_free(sqlerror);
646 free(formatString);
647 }
648 }
649 }
650
651
652 static bool SecDbBeginTransaction(SecDbConnectionRef dbconn, SecDbTransactionType type, CFErrorRef *error)
653 {
654 bool ok = true;
655 CFStringRef query;
656 switch (type) {
657 case kSecDbImmediateTransactionType:
658 secdebug("db", "SecDbBeginTransaction SecDbBeginTransaction %p", dbconn);
659 query = CFSTR("BEGIN IMMEDIATE");
660 break;
661 case kSecDbExclusiveRemoteSOSTransactionType:
662 secdebug("db", "SecDbBeginTransaction kSecDbExclusiveRemoteSOSTransactionType %p", dbconn);
663 dbconn->source = kSecDbSOSTransaction;
664 query = CFSTR("BEGIN EXCLUSIVE");
665 break;
666 case kSecDbExclusiveRemoteCKKSTransactionType:
667 secdebug("db", "SecDbBeginTransaction kSecDbExclusiveRemoteCKKSTransactionType %p", dbconn);
668 dbconn->source = kSecDbCKKSTransaction;
669 query = CFSTR("BEGIN EXCLUSIVE");
670 break;
671 case kSecDbExclusiveTransactionType:
672 if (type==kSecDbExclusiveTransactionType)
673 secdebug("db", "SecDbBeginTransaction kSecDbExclusiveTransactionType %p", dbconn);
674 query = CFSTR("BEGIN EXCLUSIVE");
675 break;
676 case kSecDbNormalTransactionType:
677 secdebug("db", "SecDbBeginTransaction kSecDbNormalTransactionType %p", dbconn);
678 query = CFSTR("BEGIN");
679 break;
680 default:
681 secdebug("db", "SecDbBeginTransaction invalid transaction type %lu", type);
682 ok = SecDbError(SQLITE_ERROR, error, CFSTR("invalid transaction type %d"), (int)type);
683 query = NULL;
684 break;
685 }
686
687 if (query != NULL && sqlite3_get_autocommit(dbconn->handle) != 0) {
688 ok = SecDbExec(dbconn, query, error);
689 }
690 if (ok)
691 dbconn->inTransaction = true;
692
693 return ok;
694 }
695
696 static bool SecDbEndTransaction(SecDbConnectionRef dbconn, bool commit, CFErrorRef *error)
697 {
698 __block bool ok = true;
699 __block bool commited = false;
700
701 dispatch_block_t notifyAndExec = ^{
702 if (commit) {
703 //secdebug("db", "SecDbEndTransaction kSecDbTransactionWillCommit %p", dbconn);
704 SecDbNotifyPhase(dbconn, kSecDbTransactionWillCommit);
705 commited = ok = SecDbExec(dbconn, CFSTR("END"), error);
706 //secdebug("db", "SecDbEndTransaction kSecDbTransactionWillCommit %p (after notify)", dbconn);
707 } else {
708 ok = SecDbExec(dbconn, CFSTR("ROLLBACK"), error);
709 commited = false;
710 }
711 dbconn->inTransaction = false;
712 SecDbNotifyPhase(dbconn, commited ? kSecDbTransactionDidCommit : kSecDbTransactionDidRollback);
713 secdebug("db", "SecDbEndTransaction %s %p", commited ? "kSecDbTransactionDidCommit" : "kSecDbTransactionDidRollback", dbconn);
714 dbconn->source = kSecDbAPITransaction;
715
716 if (commit && dbconn->db->useRobotVacuum) {
717 SecDBManagementTasks(dbconn);
718 }
719 };
720
721 SecDbPerformOnCommitQueue(dbconn, true, notifyAndExec);
722
723 return ok;
724 }
725
726 bool SecDbTransaction(SecDbConnectionRef dbconn, SecDbTransactionType type,
727 CFErrorRef *error, void (^transaction)(bool *commit))
728 {
729 bool ok = true;
730 bool commit = true;
731
732 if (dbconn->inTransaction) {
733 transaction(&commit);
734 if (!commit) {
735 secinfo("#SecDB", "#SecDB nested transaction asked to not be committed");
736 }
737 } else {
738 ok = SecDbBeginTransaction(dbconn, type, error);
739 if (ok) {
740 transaction(&commit);
741 ok = SecDbEndTransaction(dbconn, commit, error);
742 }
743 }
744
745 return ok && commit;
746 }
747
748 sqlite3 *SecDbHandle(SecDbConnectionRef dbconn) {
749 return dbconn->handle;
750 }
751
752 bool SecDbStep(SecDbConnectionRef dbconn, sqlite3_stmt *stmt, CFErrorRef *error, void (^row)(bool *stop)) {
753 for (;;) {
754 switch (_SecDbStep(dbconn, stmt, error)) {
755 case kSecDbErrorStep:
756 secdebug("db", "kSecDbErrorStep %@", error ? *error : NULL);
757 return false;
758 case kSecDbRowStep:
759 #if SECDB_DEBUGGING
760 secdebug("db", "kSecDbRowStep %@", error ? *error : NULL);
761 #endif
762 if (row) {
763 __block bool stop = false;
764 SecAutoreleaseInvokeWithPool(^{
765 row(&stop);
766 });
767 if (stop)
768 return true;
769 break;
770 }
771 SecDbError(SQLITE_ERROR, error, CFSTR("SecDbStep SQLITE_ROW returned without a row handler"));
772 return false;
773 case kSecDbDoneStep:
774 #if SECDB_DEBUGGING
775 secdebug("db", "kSecDbDoneStep %@", error ? *error : NULL);
776 #endif
777 return true;
778 }
779 }
780 }
781
782 bool SecDbCheckpoint(SecDbConnectionRef dbconn, CFErrorRef *error)
783 {
784 return SecDbConnectionCheckCode(dbconn, sqlite3_wal_checkpoint(dbconn->handle, NULL), error, CFSTR("wal_checkpoint"));
785 }
786
787 static bool SecDbFileControl(SecDbConnectionRef dbconn, int op, void *arg, CFErrorRef *error) {
788 return SecDbConnectionCheckCode(dbconn, sqlite3_file_control(dbconn->handle, NULL, op, arg), error, CFSTR("file_control"));
789 }
790
791 static sqlite3 *_SecDbOpenV2(const char *path,
792 int flags,
793 int useWAL,
794 int useRobotVacuum,
795 CFErrorRef *error) {
796 sqlite3 *handle = NULL;
797 int s3e = sqlite3_open_v2(path, &handle, flags, NULL);
798 if (s3e) {
799 if (handle) {
800 SecDbErrorWithDb(s3e, handle, error, CFSTR("open_v2 \"%s\" 0x%X"), path, flags);
801 sqlite3_close(handle);
802 handle = NULL;
803 } else {
804 SecDbError(s3e, error, CFSTR("open_v2 \"%s\" 0x%X"), path, flags);
805 }
806 } else if (SQLITE_OPEN_READWRITE == (flags & SQLITE_OPEN_READWRITE)) {
807 if (useRobotVacuum) {
808 #define SECDB_SQLITE_AUTO_VACUUM_INCREMENTAL 2
809 sqlite3_stmt *stmt = NULL;
810 int vacuumMode = -1;
811
812 /*
813 * Setting auto_vacuum = incremental on a database that is not empty requires
814 * a VACCUUM, so check if the vacuum mode is not INCREMENTAL, and if its not,
815 * set it to incremental and vacuum.
816 */
817
818 s3e = sqlite3_prepare_v2(handle, "PRAGMA auto_vacuum", -1, &stmt, NULL);
819 if (s3e == 0) {
820 s3e = sqlite3_step(stmt);
821 if (s3e == SQLITE_ROW) {
822 vacuumMode = sqlite3_column_int(stmt, 0);
823 }
824 (void)sqlite3_finalize(stmt);
825 }
826
827 if (vacuumMode != SECDB_SQLITE_AUTO_VACUUM_INCREMENTAL) {
828 (void)sqlite3_exec(handle, "PRAGMA auto_vacuum = incremental", NULL, NULL, NULL);
829 (void)sqlite3_exec(handle, "VACUUM", NULL, NULL, NULL);
830 }
831 }
832 if (useWAL) {
833 (void)sqlite3_exec(handle, "PRAGMA journal_mode = WAL", NULL, NULL, NULL);
834 }
835
836 // Let SQLite handle timeouts.
837 sqlite3_busy_timeout(handle, 5*1000);
838 }
839 return handle;
840 }
841
842 static bool SecDbOpenV2(SecDbConnectionRef dbconn, const char *path, int flags, CFErrorRef *error) {
843 return (dbconn->handle = _SecDbOpenV2(path, flags, dbconn->db->useWAL, dbconn->db->useRobotVacuum, error)) != NULL;
844 }
845
846 // This construction lets tests not exit here
847 static void SecDbProductionCorruptionExitHandler(void)
848 {
849 exit(EXIT_FAILURE);
850 }
851 void (*SecDbCorruptionExitHandler)(void) = SecDbProductionCorruptionExitHandler;
852
853 void SecDbResetCorruptionExitHandler(void)
854 {
855 SecDbCorruptionExitHandler = SecDbProductionCorruptionExitHandler;
856 }
857
858 /*
859 There's not much to do in here because we should only ever be here when
860 SQLite tells us the DB is corrupt, or the DB is unrecoverable because of
861 some fatal logic problem. But we can't shoot it dead either due to client
862 connections. So, first we create a marker to tell ourselves things are bad,
863 then we'll die. When we come back up we'll notice the marker and remove the DB.
864 */
865 static bool SecDbHandleCorrupt(SecDbConnectionRef dbconn, int rc, CFErrorRef *error)
866 {
867 if (!dbconn->db->allowRepair) {
868 SecCFCreateErrorWithFormat(rc, kSecErrnoDomain, NULL, error, NULL,
869 CFSTR("SecDbHandleCorrupt not allowed to repair, handled error: [%d] %s"), rc, strerror(rc));
870 dbconn->isCorrupted = false;
871 return false;
872 }
873
874 CFStringPerformWithCString(dbconn->db->db_path, ^(const char *db_path) {
875 char marker[PATH_MAX+1];
876 snprintf(marker, sizeof(marker), "%s-iscorrupt", db_path);
877 struct stat info = {};
878 if (0 == stat(marker, &info)) {
879 secerror("SecDbHandleCorrupt: Tried to write corruption marker %s but one already exists", marker);
880 }
881
882 FILE* file = fopen(marker, "w");
883 if (file == NULL) {
884 secerror("SecDbHandleCorrupt: Unable (%{darwin.errno}d) to create corruption marker %{public}s", errno, marker);
885 } else {
886 fclose(file);
887 }
888 });
889
890 secwarning("SecDbHandleCorrupt: killing self so that successor might cleanly delete corrupt db");
891
892 // Call through function pointer so tests can replace it and call a SecKeychainDbReset instead
893 SecDbCorruptionExitHandler();
894 return true;
895 }
896
897 static bool SecDbProcessCorruptionMarker(CFStringRef db_path) {
898 __block bool ok = true;
899 CFStringPerformWithCString(db_path, ^(const char *db_path) {
900 char marker[PATH_MAX+1];
901 snprintf(marker, sizeof(marker), "%s-iscorrupt", db_path);
902 struct stat info = {};
903 int result = stat(marker, &info);
904 if (result != 0 && errno == ENOENT) {
905 return;
906 } else if (result != 0) {
907 secerror("SecDbSecDbProcessCorruptionMarker: Unable to check for corruption marker: %{darwin.errno}d", errno);
908 return;
909 }
910
911 secwarning("SecDbSecDbProcessCorruptionMarker: found corruption marker %s", marker);
912 if (remove(marker)) {
913 secerror("SecDbSecDbProcessCorruptionMarker: Unable (%{darwin.errno}d) to delete corruption marker", errno);
914 ok = false;
915 } else if (remove(db_path) && errno != ENOENT) { // Not sure how we'd get ENOENT but it would suit us just fine
916 secerror("SecDbSecDbProcessCorruptionMarker: Unable (%{darwin.errno}d) to delete db %{public}s", errno, db_path);
917 ok = false;
918 } else {
919 secwarning("SecDbSecDbProcessCorruptionMarker: deleted corrupt db %{public}s", db_path);
920 }
921 });
922 return ok;
923 }
924
925 void
926 SecDbSetCorruptionReset(SecDbRef db, void (^corruptionReset)(void))
927 {
928 if (db->corruptionReset) {
929 Block_release(db->corruptionReset);
930 db->corruptionReset = NULL;
931 }
932 if (corruptionReset) {
933 db->corruptionReset = Block_copy(corruptionReset);
934 }
935 }
936
937 static bool SecDbLoggingEnabled(CFStringRef type)
938 {
939 CFTypeRef profile = NULL;
940 bool enabled = false;
941
942 if (csr_check(CSR_ALLOW_APPLE_INTERNAL) != 0)
943 return false;
944
945 profile = (CFNumberRef)CFPreferencesCopyValue(CFSTR("SQLProfile"), CFSTR("com.apple.security"), kCFPreferencesAnyUser, kCFPreferencesAnyHost);
946
947 if (profile == NULL)
948 return false;
949
950 if (CFGetTypeID(profile) == CFBooleanGetTypeID()) {
951 enabled = CFBooleanGetValue((CFBooleanRef)profile);
952 } else if (CFGetTypeID(profile) == CFNumberGetTypeID()) {
953 int32_t num = 0;
954 CFNumberGetValue(profile, kCFNumberSInt32Type, &num);
955 enabled = !!num;
956 }
957
958 CFReleaseSafe(profile);
959
960 return enabled;
961 }
962
963 static unsigned
964 SecDbProfileMask(void)
965 {
966 static dispatch_once_t onceToken;
967 static unsigned profile_mask = 0;
968
969 // sudo defaults write /Library/Preferences/com.apple.security SQLProfile -bool true
970 dispatch_once(&onceToken, ^{
971 if (SecDbLoggingEnabled(CFSTR("SQLProfile")))
972 profile_mask = SQLITE_TRACE_PROFILE;
973 #if DEBUG
974 profile_mask |= SQLITE_TRACE_STMT;
975 #else
976 if (SecDbLoggingEnabled(CFSTR("SQLTrace")))
977 profile_mask = SQLITE_TRACE_STMT;
978 #endif
979 if (SecDbLoggingEnabled(CFSTR("SQLRow")))
980 profile_mask = SQLITE_TRACE_ROW;
981 secinfo("#SecDB", "sqlDb: sql trace mask: 0x%08x", profile_mask);
982 });
983 return profile_mask;
984 }
985
986 static int
987 SecDbTraceV2(unsigned mask, void *ctx, void *p, void *x) {
988 SecDbConnectionRef dbconn __unused = ctx;
989 const char *trace = "unknown";
990
991 if (mask == SQLITE_TRACE_PROFILE)
992 trace = sqlite3_sql(p);
993 else if (mask == SQLITE_TRACE_STMT) {
994 trace = sqlite3_sql(p);
995 } else if (mask == SQLITE_TRACE_ROW) {
996 trace = sqlite3_expanded_sql(p);
997 }
998
999 #if SECDB_DEBUGGING
1000 secinfo("#SecDB", "#SecDB %{public}s", trace);
1001 #endif
1002 return 0;
1003 }
1004
1005
1006 static bool SecDbOpenHandle(SecDbConnectionRef dbconn, bool *created, CFErrorRef *error)
1007 {
1008 __block bool ok = true;
1009
1010 // This is pretty terrible because now what? We know we have a corrupt DB
1011 // and now we can't get rid of it.
1012 if (!SecDbProcessCorruptionMarker(dbconn->db->db_path)) {
1013 SecCFCreateErrorWithFormat(errno, kSecErrnoDomain, NULL, error, NULL, CFSTR("Unable to process corruption marker: %{darwin.errno}d"), errno);
1014 return false;
1015 }
1016
1017 CFStringPerformWithCString(dbconn->db->db_path, ^(const char *db_path) {
1018 int flags = (dbconn->db->readWrite) ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY;
1019 ok = created && SecDbOpenV2(dbconn, db_path, flags, NULL);
1020 if (!ok) {
1021 ok = true;
1022 if (created) {
1023 char *tmp = dirname((char *)db_path);
1024 if (tmp) {
1025 mode_t omode = dbconn->db->mode;
1026 if (omode & S_IRUSR) { omode |= S_IXUSR; } // owner can read
1027 if (omode & S_IRGRP) { omode |= S_IXGRP; } // group can read
1028 if (omode & S_IROTH) { omode |= S_IXOTH; } // other can read
1029 int errnum = mkpath_np(tmp, omode);
1030 if (errnum != 0 && errnum != EEXIST) {
1031 SecCFCreateErrorWithFormat(errnum, kSecErrnoDomain, NULL, error, NULL,
1032 CFSTR("mkpath_np %s: [%d] %s"), tmp, errnum, strerror(errnum));
1033 ok = false;
1034 }
1035 }
1036 }
1037 // if the enclosing directory is ok, try to create the database.
1038 // this forces us to open it read-write, so we'll need to be the owner here.
1039 ok = ok && SecDbOpenV2(dbconn, db_path, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, error);
1040 if (ok) {
1041 chmod(db_path, dbconn->db->mode); // default: 0600 (S_IRUSR | S_IWUSR)
1042 if (created)
1043 *created = true;
1044 }
1045 }
1046
1047 if (ok) {
1048 unsigned mask = SecDbProfileMask();
1049 if (mask) {
1050 (void)sqlite3_trace_v2(dbconn->handle,
1051 mask,
1052 SecDbTraceV2,
1053 dbconn);
1054 }
1055 }
1056 });
1057
1058 return ok;
1059 }
1060
1061 static SecDbConnectionRef
1062 SecDbConnectionCreate(SecDbRef db, bool readOnly, CFErrorRef *error)
1063 {
1064 SecDbConnectionRef dbconn = NULL;
1065
1066 dbconn = CFTypeAllocate(SecDbConnection, struct __OpaqueSecDbConnection, kCFAllocatorDefault);
1067 require(dbconn != NULL, done);
1068
1069 dbconn->db = db;
1070 dbconn->readOnly = readOnly;
1071 dbconn->inTransaction = false;
1072 dbconn->source = kSecDbInvalidTransaction;
1073 dbconn->isCorrupted = false;
1074 dbconn->maybeCorruptedCode = 0;
1075 dbconn->hasIOFailure = false;
1076 dbconn->corruptionError = NULL;
1077 dbconn->handle = NULL;
1078 dbconn->changes = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
1079
1080 done:
1081 return dbconn;
1082 }
1083
1084 bool SecDbConnectionIsReadOnly(SecDbConnectionRef dbconn) {
1085 return dbconn->readOnly;
1086 }
1087
1088 static void SecDbConectionSetReadOnly(SecDbConnectionRef dbconn, bool readOnly) {
1089 dbconn->readOnly = readOnly;
1090 }
1091
1092 /* Read only connections go to the end of the queue, writeable connections
1093 go to the start of the queue. */
1094 SecDbConnectionRef SecDbConnectionAcquire(SecDbRef db, bool readOnly, CFErrorRef *error) {
1095 SecDbConnectionRef dbconn = NULL;
1096 SecDbConnectionAcquireRefMigrationSafe(db, readOnly, &dbconn, error);
1097 return dbconn;
1098 }
1099
1100 bool SecDbConnectionAcquireRefMigrationSafe(SecDbRef db, bool readOnly, SecDbConnectionRef* dbconnRef, CFErrorRef *error)
1101 {
1102 CFRetain(db);
1103 #if SECDB_DEBUGGING
1104 secinfo("dbconn", "acquire %s connection", readOnly ? "ro" : "rw");
1105 #endif
1106 dispatch_semaphore_wait(readOnly ? db->read_semaphore : db->write_semaphore, DISPATCH_TIME_FOREVER);
1107 __block SecDbConnectionRef dbconn = NULL;
1108 __block bool ok = true;
1109 __block bool ranOpenedHandler = false;
1110
1111 bool (^assignDbConn)(SecDbConnectionRef) = ^bool(SecDbConnectionRef connection) {
1112 dbconn = connection;
1113 if (dbconnRef) {
1114 *dbconnRef = connection;
1115 }
1116
1117 return dbconn != NULL;
1118 };
1119
1120 dispatch_sync(db->queue, ^{
1121 if (!db->didFirstOpen) {
1122 bool didCreate = false;
1123 ok = assignDbConn(SecDbConnectionCreate(db, false, error));
1124 CFErrorRef localError = NULL;
1125 if (ok && !SecDbOpenHandle(dbconn, &didCreate, &localError)) {
1126 secerror("Unable to create database: %@", localError);
1127 if (localError && CFEqual(CFErrorGetDomain(localError), kSecDbErrorDomain)) {
1128 int code = (int)CFErrorGetCode(localError);
1129 dbconn->isCorrupted = (SQLITE_CORRUPT == code) || (SQLITE_NOTADB == code);
1130 }
1131 // If the open failure isn't due to corruption, propagate the error.
1132 ok = dbconn->isCorrupted;
1133 if (!ok && error && *error == NULL) {
1134 *error = localError;
1135 localError = NULL;
1136 }
1137 }
1138 CFReleaseNull(localError);
1139
1140 if (ok) {
1141 db->didFirstOpen = ok = SecDbDidCreateFirstConnection(dbconn, didCreate, error);
1142 ranOpenedHandler = true;
1143 }
1144 if (!ok)
1145 CFReleaseNull(dbconn);
1146 } else {
1147 /* Try to get one from the cache */
1148 CFIndex count = CFArrayGetCount(db->connections);
1149 while (count && !dbconn) {
1150 CFIndex ix = readOnly ? count - 1 : 0;
1151 if (assignDbConn((SecDbConnectionRef)CFArrayGetValueAtIndex(db->connections, ix)))
1152 CFRetainSafe(dbconn);
1153 else
1154 secerror("got NULL dbconn at index: %" PRIdCFIndex " skipping", ix);
1155 CFArrayRemoveValueAtIndex(db->connections, ix);
1156 }
1157 }
1158 });
1159
1160 if (dbconn) {
1161 /* Make sure the connection we found has the right access */
1162 if (SecDbConnectionIsReadOnly(dbconn) != readOnly) {
1163 SecDbConectionSetReadOnly(dbconn, readOnly);
1164 }
1165 } else if (ok) {
1166 /* Nothing found in cache, create a new connection */
1167 bool created = false;
1168 if (assignDbConn(SecDbConnectionCreate(db, readOnly, error)) && !SecDbOpenHandle(dbconn, &created, error)) {
1169 CFReleaseNull(dbconn);
1170 }
1171 }
1172
1173
1174 if (dbconn && !ranOpenedHandler && dbconn->db->opened) {
1175 dispatch_sync(db->queue, ^{
1176 if (dbconn->db->callOpenedHandlerForNextConnection) {
1177 dbconn->db->callOpenedHandlerForNextConnection = false;
1178 if (!dbconn->db->opened(db, dbconn, false, &dbconn->db->callOpenedHandlerForNextConnection, error)) {
1179 if (!dbconn->isCorrupted || !SecDbHandleCorrupt(dbconn, 0, error)) {
1180 CFReleaseNull(dbconn);
1181 }
1182 }
1183 }
1184 });
1185 }
1186
1187 if (dbconnRef) {
1188 *dbconnRef = dbconn;
1189 }
1190
1191 if (!dbconn) {
1192 // If acquire fails we need to signal the semaphore again.
1193 dispatch_semaphore_signal(readOnly ? db->read_semaphore : db->write_semaphore);
1194 CFRelease(db);
1195 }
1196
1197 return dbconn ? true : false;
1198 }
1199
1200 void SecDbConnectionRelease(SecDbConnectionRef dbconn) {
1201 if (!dbconn) {
1202 secerror("called with NULL dbconn");
1203 return;
1204 }
1205 SecDbRef db = dbconn->db;
1206 #if SECDB_DEBUGGING
1207 secinfo("dbconn", "release %@", dbconn);
1208 #endif
1209 dispatch_sync(db->queue, ^{
1210 bool readOnly = SecDbConnectionIsReadOnly(dbconn);
1211 if (dbconn->hasIOFailure) {
1212 // Something wrong on the file layer (e.g. revoked file descriptor for networked home)
1213 // so we don't trust our existing connections anymore.
1214 CFArrayRemoveAllValues(db->connections);
1215 } else {
1216 CFIndex count = CFArrayGetCount(db->connections);
1217 // Add back possible writable dbconn to the pool.
1218 CFArrayInsertValueAtIndex(db->connections, readOnly ? count : 0, dbconn);
1219 // Remove the last (probably read-only) dbconn from the pool.
1220 if (count >= db->maxIdleHandles) {
1221 CFArrayRemoveValueAtIndex(db->connections, count);
1222 }
1223 }
1224 // Signal after we have put the connection back in the pool of connections
1225 dispatch_semaphore_signal(readOnly ? db->read_semaphore : db->write_semaphore);
1226 CFRelease(dbconn);
1227 CFRelease(db);
1228 });
1229 }
1230
1231 void SecDbReleaseAllConnections(SecDbRef db) {
1232 // Force all connections to be removed (e.g. file descriptor no longer valid)
1233 if (!db) {
1234 secerror("called with NULL db");
1235 return;
1236 }
1237 dispatch_sync(db->queue, ^{
1238 CFArrayRemoveAllValues(db->connections);
1239 dispatch_semaphore_signal(db->write_semaphore);
1240 dispatch_semaphore_signal(db->read_semaphore);
1241 });
1242 }
1243
1244 bool SecDbPerformRead(SecDbRef db, CFErrorRef *error, void (^perform)(SecDbConnectionRef dbconn)) {
1245 SecDbConnectionRef dbconn = SecDbConnectionAcquire(db, true, error);
1246 bool success = false;
1247 if (dbconn) {
1248 perform(dbconn);
1249 success = true;
1250 SecDbConnectionRelease(dbconn);
1251 }
1252 return success;
1253 }
1254
1255 bool SecDbPerformWrite(SecDbRef db, CFErrorRef *error, void (^perform)(SecDbConnectionRef dbconn)) {
1256 if(!db) {
1257 SecError(errSecNotAvailable, error, CFSTR("failed to get a db handle"));
1258 return false;
1259 }
1260 SecDbConnectionRef dbconn = SecDbConnectionAcquire(db, false, error);
1261 bool success = false;
1262 if (dbconn) {
1263 perform(dbconn);
1264 success = true;
1265 SecDbConnectionRelease(dbconn);
1266 }
1267 return success;
1268 }
1269
1270 static CFStringRef
1271 SecDbConnectionCopyFormatDescription(CFTypeRef value, CFDictionaryRef formatOptions)
1272 {
1273 SecDbConnectionRef dbconn = (SecDbConnectionRef)value;
1274 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<SecDbConnection %s %s>"),
1275 dbconn->readOnly ? "ro" : "rw", dbconn->handle ? "open" : "closed");
1276 }
1277
1278 static void
1279 SecDbConnectionDestroy(CFTypeRef value)
1280 {
1281 SecDbConnectionRef dbconn = (SecDbConnectionRef)value;
1282 if (dbconn->handle) {
1283 int s3e = sqlite3_close(dbconn->handle);
1284 if (s3e != SQLITE_OK) {
1285 secerror("failed to close database connection (%d) for %@: %s", s3e, dbconn->db->db_path, sqlite3_errmsg(dbconn->handle));
1286 }
1287 os_assert(s3e == SQLITE_OK); // Crash now or jetsam later
1288 }
1289 dbconn->db = NULL;
1290 CFReleaseNull(dbconn->changes);
1291 CFReleaseNull(dbconn->corruptionError);
1292
1293 }
1294
1295 void SecDbPerformOnCommitQueue(SecDbConnectionRef dbconn, bool barrier, dispatch_block_t perform) {
1296 if (barrier) {
1297 dispatch_barrier_sync(dbconn->db->commitQueue, ^{
1298 perform();
1299 });
1300 } else {
1301 dispatch_sync(dbconn->db->commitQueue, ^{
1302 perform();
1303 });
1304 }
1305 }
1306
1307 // MARK: -
1308 // MARK: Bind helpers
1309
1310 // Logging binds is very spammy when debug logging is on (~90% of log lines), and isn't often useful.
1311 // Enable this in your local build if you actually want every single SQL variable bind logged for debugging.
1312 #define LOG_SECDB_BINDS 0
1313
1314 bool SecDbBindBlob(sqlite3_stmt *stmt, int param, const void *zData, size_t n, void(*xDel)(void*), CFErrorRef *error) {
1315 if (n > INT_MAX) {
1316 return SecDbErrorWithStmt(SQLITE_TOOBIG, stmt, error,
1317 CFSTR("bind_blob[%d]: blob bigger than INT_MAX"), param);
1318 }
1319 bool ok = SecDbErrorWithStmt(sqlite3_bind_blob(stmt, param, zData, (int)n, xDel),
1320 stmt, error, CFSTR("bind_blob[%d]"), param);
1321 #if LOG_SECDB_BINDS
1322 secinfo("bind", "bind_blob[%d]: %.*P: %@", param, (int)n, zData, error ? *error : NULL);
1323 #endif
1324 return ok;
1325 }
1326
1327 bool SecDbBindText(sqlite3_stmt *stmt, int param, const char *zData, size_t n, void(*xDel)(void*), CFErrorRef *error) {
1328 if (n > INT_MAX) {
1329 return SecDbErrorWithStmt(SQLITE_TOOBIG, stmt, error,
1330 CFSTR("bind_text[%d]: text bigger than INT_MAX"), param);
1331 }
1332 bool ok = SecDbErrorWithStmt(sqlite3_bind_text(stmt, param, zData, (int)n, xDel), stmt, error,
1333 CFSTR("bind_text[%d]"), param);
1334 #if LOG_SECDB_BINDS
1335 secinfo("bind", "bind_text[%d]: \"%s\" error: %@", param, zData, error ? *error : NULL);
1336 #endif
1337 return ok;
1338 }
1339
1340 bool SecDbBindDouble(sqlite3_stmt *stmt, int param, double value, CFErrorRef *error) {
1341 bool ok = SecDbErrorWithStmt(sqlite3_bind_double(stmt, param, value), stmt, error,
1342 CFSTR("bind_double[%d]"), param);
1343 #if LOG_SECDB_BINDS
1344 secinfo("bind", "bind_double[%d]: %f error: %@", param, value, error ? *error : NULL);
1345 #endif
1346 return ok;
1347 }
1348
1349 bool SecDbBindInt(sqlite3_stmt *stmt, int param, int value, CFErrorRef *error) {
1350 bool ok = SecDbErrorWithStmt(sqlite3_bind_int(stmt, param, value), stmt, error,
1351 CFSTR("bind_int[%d]"), param);
1352 #if LOG_SECDB_BINDS
1353 secinfo("bind", "bind_int[%d]: %d error: %@", param, value, error ? *error : NULL);
1354 #endif
1355 return ok;
1356 }
1357
1358 bool SecDbBindInt64(sqlite3_stmt *stmt, int param, sqlite3_int64 value, CFErrorRef *error) {
1359 bool ok = SecDbErrorWithStmt(sqlite3_bind_int64(stmt, param, value), stmt, error,
1360 CFSTR("bind_int64[%d]"), param);
1361 #if LOG_SECDB_BINDS
1362 secinfo("bind", "bind_int64[%d]: %lld error: %@", param, value, error ? *error : NULL);
1363 #endif
1364 return ok;
1365 }
1366
1367
1368 /* AUDIT[securityd](done):
1369 value (ok) is a caller provided, non NULL CFTypeRef.
1370 */
1371 bool SecDbBindObject(sqlite3_stmt *stmt, int param, CFTypeRef value, CFErrorRef *error) {
1372 CFTypeID valueId;
1373 __block bool result = false;
1374
1375 /* TODO: Can we use SQLITE_STATIC below everwhere we currently use
1376 SQLITE_TRANSIENT since we finalize the statement before the value
1377 goes out of scope? */
1378 if (!value || (valueId = CFGetTypeID(value)) == CFNullGetTypeID()) {
1379 /* Skip bindings for NULL values. sqlite3 will interpret unbound
1380 params as NULL which is exactly what we want. */
1381 result = true;
1382 } else if (valueId == CFStringGetTypeID()) {
1383 CFStringPerformWithCStringAndLength(value, ^(const char *cstr, size_t clen) {
1384 result = SecDbBindText(stmt, param, cstr, clen, SQLITE_TRANSIENT, error);
1385 });
1386 } else if (valueId == CFDataGetTypeID()) {
1387 CFIndex len = CFDataGetLength(value);
1388 if (len) {
1389 result = SecDbBindBlob(stmt, param, CFDataGetBytePtr(value),
1390 len, SQLITE_TRANSIENT, error);
1391 } else {
1392 result = SecDbBindText(stmt, param, "", 0, SQLITE_TRANSIENT, error);
1393 }
1394 } else if (valueId == CFDateGetTypeID()) {
1395 CFAbsoluteTime abs_time = CFDateGetAbsoluteTime(value);
1396 result = SecDbBindDouble(stmt, param, abs_time, error);
1397 } else if (valueId == CFBooleanGetTypeID()) {
1398 int bval = CFBooleanGetValue(value);
1399 result = SecDbBindInt(stmt, param, bval, error);
1400 } else if (valueId == CFNumberGetTypeID()) {
1401 Boolean convertOk;
1402 if (CFNumberIsFloatType(value)) {
1403 double nval;
1404 convertOk = CFNumberGetValue(value, kCFNumberDoubleType, &nval);
1405 result = SecDbBindDouble(stmt, param, nval, error);
1406 } else {
1407 sqlite_int64 nval64;
1408 convertOk = CFNumberGetValue(value, kCFNumberSInt64Type, &nval64);
1409 if (convertOk) {
1410 result = SecDbBindInt64(stmt, param, nval64, error);
1411 }
1412 }
1413 if (!convertOk) {
1414 result = SecDbError(SQLITE_INTERNAL, error, CFSTR("bind CFNumberGetValue failed for %@"), value);
1415 }
1416 } else {
1417 if (error) {
1418 CFStringRef valueDesc = CFCopyTypeIDDescription(valueId);
1419 SecDbError(SQLITE_MISMATCH, error, CFSTR("bind unsupported type %@"), valueDesc);
1420 CFReleaseSafe(valueDesc);
1421 }
1422 }
1423
1424 return result;
1425 }
1426
1427 // MARK: -
1428 // MARK: SecDbStatementRef
1429
1430 bool SecDbReset(sqlite3_stmt *stmt, CFErrorRef *error) {
1431 return SecDbErrorWithStmt(sqlite3_reset(stmt), stmt, error, CFSTR("reset"));
1432 }
1433
1434 bool SecDbClearBindings(sqlite3_stmt *stmt, CFErrorRef *error) {
1435 return SecDbErrorWithStmt(sqlite3_clear_bindings(stmt), stmt, error, CFSTR("clear bindings"));
1436 }
1437
1438 bool SecDbFinalize(sqlite3_stmt *stmt, CFErrorRef *error) {
1439 sqlite3 *handle = sqlite3_db_handle(stmt);
1440 int s3e = sqlite3_finalize(stmt);
1441 return s3e == SQLITE_OK ? true : SecDbErrorWithDb(s3e, handle, error, CFSTR("finalize: %p"), stmt);
1442 }
1443
1444 sqlite3_stmt *SecDbPrepareV2(SecDbConnectionRef dbconn, const char *sql, size_t sqlLen, const char **sqlTail, CFErrorRef *error) {
1445 sqlite3 *db = SecDbHandle(dbconn);
1446 if (sqlLen > INT_MAX) {
1447 SecDbErrorWithDb(SQLITE_TOOBIG, db, error, CFSTR("prepare_v2: sql bigger than INT_MAX"));
1448 return NULL;
1449 }
1450 int ntries = 0;
1451 for (;;) {
1452 sqlite3_stmt *stmt = NULL;
1453 int s3e = sqlite3_prepare_v2(db, sql, (int)sqlLen, &stmt, sqlTail);
1454 if (s3e == SQLITE_OK)
1455 return stmt;
1456 else if (!SecDbWaitIfNeeded(dbconn, s3e, NULL, CFSTR("preparev2"), ntries, error))
1457 return NULL;
1458 ntries++;
1459 }
1460 }
1461
1462 static sqlite3_stmt *SecDbCopyStatementWithTailRange(SecDbConnectionRef dbconn, CFStringRef sql, CFRange *sqlTail, CFErrorRef *error) {
1463 __block sqlite3_stmt *stmt = NULL;
1464 if (sql) CFStringPerformWithCStringAndLength(sql, ^(const char *sqlStr, size_t sqlLen) {
1465 const char *tail = NULL;
1466 stmt = SecDbPrepareV2(dbconn, sqlStr, sqlLen, &tail, error);
1467 if (sqlTail && sqlStr < tail && tail < sqlStr + sqlLen) {
1468 sqlTail->location = tail - sqlStr;
1469 sqlTail->length = sqlLen - sqlTail->location;
1470 }
1471 });
1472
1473 return stmt;
1474 }
1475
1476 sqlite3_stmt *SecDbCopyStmt(SecDbConnectionRef dbconn, CFStringRef sql, CFStringRef *tail, CFErrorRef *error) {
1477 // TODO: Add caching and cache lookup of statements
1478 CFRange sqlTail = {};
1479 sqlite3_stmt *stmt = SecDbCopyStatementWithTailRange(dbconn, sql, &sqlTail, error);
1480 if (sqlTail.length > 0) {
1481 CFStringRef excess = CFStringCreateWithSubstring(CFGetAllocator(sql), sql, sqlTail);
1482 if (tail) {
1483 *tail = excess;
1484 } else {
1485 SecDbError(SQLITE_INTERNAL, error,
1486 CFSTR("prepare_v2: %@ unused sql: %@"),
1487 sql, excess);
1488 CFReleaseSafe(excess);
1489 SecDbFinalize(stmt, error);
1490 stmt = NULL;
1491 }
1492 }
1493 return stmt;
1494 }
1495
1496 /*
1497 TODO: Could do a hack here with a custom kCFAllocatorNULL allocator for a second CFRuntimeBase inside a SecDbStatement,
1498 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. */
1499 bool SecDbReleaseCachedStmt(SecDbConnectionRef dbconn, CFStringRef sql, sqlite3_stmt *stmt, CFErrorRef *error) {
1500 if (stmt) {
1501 return SecDbFinalize(stmt, error);
1502 }
1503 return true;
1504 }
1505
1506 bool SecDbPrepare(SecDbConnectionRef dbconn, CFStringRef sql, CFErrorRef *error, void(^exec)(sqlite3_stmt *stmt)) {
1507 assert(sql != NULL);
1508 sqlite3_stmt *stmt = SecDbCopyStmt(dbconn, sql, NULL, error);
1509 if (!stmt)
1510 return false;
1511
1512 exec(stmt);
1513 return SecDbReleaseCachedStmt(dbconn, sql, stmt, error);
1514 }
1515
1516 bool SecDbWithSQL(SecDbConnectionRef dbconn, CFStringRef sql, CFErrorRef *error, bool(^perform)(sqlite3_stmt *stmt)) {
1517 bool ok = true;
1518 CFRetain(sql);
1519 while (sql) {
1520 CFStringRef tail = NULL;
1521 if (ok) {
1522 sqlite3_stmt *stmt = SecDbCopyStmt(dbconn, sql, &tail, error);
1523 ok = stmt != NULL;
1524 if (stmt) {
1525 if (perform) {
1526 ok = perform(stmt);
1527 } else {
1528 // TODO: Use a different error scope here.
1529 ok = SecError(-50 /* errSecParam */, error, CFSTR("SecDbWithSQL perform block missing"));
1530 }
1531 ok &= SecDbReleaseCachedStmt(dbconn, sql, stmt, error);
1532 }
1533 } else {
1534 // TODO We already have an error here we really just want the left over sql in it's userData
1535 ok = SecDbError(SQLITE_ERROR, error, CFSTR("Error with unexecuted sql remaining %@"), sql);
1536 }
1537 CFRelease(sql);
1538 sql = tail;
1539 }
1540 return ok;
1541 }
1542
1543 /* SecDbForEach returns true if all SQLITE_ROW returns of sqlite3_step() return true from the row block.
1544 If the row block returns false and doesn't set an error (to indicate it has reached a limit),
1545 this entire function returns false. In that case no error will be set. */
1546 bool SecDbForEach(SecDbConnectionRef dbconn, sqlite3_stmt *stmt, CFErrorRef *error, bool(^row)(int row_index)) {
1547 bool result = false;
1548 for (int row_ix = 0;;++row_ix) {
1549 if (SecDbConnectionIsReadOnly(dbconn) && !sqlite3_stmt_readonly(stmt)) {
1550 secerror("SecDbForEach: SecDbConnection is readonly but we're about to write: %s", sqlite3_sql(stmt));
1551 }
1552 int s3e = sqlite3_step(stmt);
1553 if (s3e == SQLITE_ROW) {
1554 if (row) {
1555 if (!row(row_ix)) {
1556 break;
1557 }
1558 } else {
1559 // If we have no row block then getting SQLITE_ROW is an error
1560 SecDbError(s3e, error,
1561 CFSTR("step[%d]: %s returned SQLITE_ROW with NULL row block"),
1562 row_ix, sqlite3_sql(stmt));
1563 }
1564 } else {
1565 if (s3e == SQLITE_DONE) {
1566 result = true;
1567 } else {
1568 SecDbConnectionCheckCode(dbconn, s3e, error, CFSTR("SecDbForEach step[%d]"), row_ix);
1569 }
1570 break;
1571 }
1572 }
1573 return result;
1574 }
1575
1576 void SecDbRecordChange(SecDbConnectionRef dbconn, CFTypeRef deleted, CFTypeRef inserted) {
1577 if (!dbconn->db->notifyPhase) return;
1578 CFTypeRef entry = SecDbEventCreateWithComponents(deleted, inserted);
1579 if (entry) {
1580 CFArrayAppendValue(dbconn->changes, entry);
1581 CFRelease(entry);
1582
1583 if (!dbconn->inTransaction) {
1584 secerror("db %@ changed outside txn", dbconn);
1585 // Only notify of DidCommit, since WillCommit code assumes
1586 // we are in a txn.
1587 SecDbOnNotify(dbconn, ^{
1588 SecDbNotifyPhase(dbconn, kSecDbTransactionDidCommit);
1589 });
1590 }
1591 }
1592 }
1593
1594
1595 CFGiblisFor(SecDbConnection)
1596
1597 //
1598 // SecDbEvent Creation and consumption
1599 //
1600
1601 static SecDbEventRef SecDbEventCreateInsert(CFTypeRef inserted) {
1602 return CFRetainSafe(inserted);
1603 }
1604
1605 static SecDbEventRef SecDbEventCreateDelete(CFTypeRef deleted) {
1606 return CFArrayCreate(kCFAllocatorDefault, &deleted, 1, &kCFTypeArrayCallBacks);
1607 }
1608
1609 static SecDbEventRef SecDbEventCreateUpdate(CFTypeRef deleted, CFTypeRef inserted) {
1610 const void *values[2] = { deleted, inserted };
1611 return CFArrayCreate(kCFAllocatorDefault, values, 2, &kCFTypeArrayCallBacks);
1612 }
1613
1614 SecDbEventRef SecDbEventCreateWithComponents(CFTypeRef deleted, CFTypeRef inserted) {
1615 if (deleted && inserted)
1616 return SecDbEventCreateUpdate(deleted, inserted);
1617 else if (deleted)
1618 return SecDbEventCreateDelete(deleted);
1619 else if (inserted)
1620 return SecDbEventCreateInsert(inserted);
1621 else
1622 return NULL;
1623 }
1624
1625 void SecDbEventTranslateComponents(SecDbEventRef item, CFTypeRef* deleted, CFTypeRef* inserted) {
1626 if(CFGetTypeID(item) == CFArrayGetTypeID()) {
1627 // One item: deletion. Two: update.
1628 CFIndex arraySize = CFArrayGetCount(item);
1629 if(arraySize == 1) {
1630 if(deleted) { *deleted = CFArrayGetValueAtIndex(item, 0); }
1631 if(inserted) { *inserted = NULL; }
1632 } else if(arraySize == 2) {
1633 if(deleted) { *deleted = CFArrayGetValueAtIndex(item, 0); }
1634 if(inserted) { *inserted = CFArrayGetValueAtIndex(item, 1); }
1635 } else {
1636 if(deleted) { *deleted = NULL; }
1637 if(inserted) { *inserted = NULL; }
1638 }
1639 } else {
1640 if(deleted) { *deleted = NULL; }
1641 if(inserted) { *inserted = item; }
1642 }
1643
1644 }
1645
1646 bool SecDbEventGetComponents(SecDbEventRef event, CFTypeRef *deleted, CFTypeRef *inserted, CFErrorRef *error) {
1647 if (isArray(event)) {
1648 CFArrayRef array = event;
1649 switch (CFArrayGetCount(array)) {
1650 case 2:
1651 *deleted = CFArrayGetValueAtIndex(array, 0);
1652 *inserted = CFArrayGetValueAtIndex(array, 1);
1653 break;
1654 case 1:
1655 *deleted = CFArrayGetValueAtIndex(array, 0);
1656 *inserted = NULL;
1657 break;
1658 default:
1659 SecError(errSecParam, error, NULL, CFSTR("invalid entry in changes array: %@"), array);
1660 break;
1661 }
1662 } else {
1663 *deleted = NULL;
1664 *inserted = event;
1665 }
1666 return true;
1667 }