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