]> git.saurik.com Git - apple/security.git/blob - Security/sec/securityd/SecDbItem.c
Security-57031.1.35.tar.gz
[apple/security.git] / Security / sec / securityd / SecDbItem.c
1 /*
2 * Copyright (c) 2012-2014 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 * SecDbItem.c - CoreFoundation-based constants and functions representing
26 * database items (certificates, keys, identities, and passwords.)
27 */
28
29 #include <securityd/SecDbItem.h>
30 #include <securityd/SecDbKeychainItem.h>
31 #include <securityd/SecItemDb.h>
32 #include <utilities/SecCFWrappers.h>
33 #include <utilities/der_date.h>
34 #include <utilities/debugging.h>
35
36 #include <Security/SecBasePriv.h>
37 #include <Security/SecInternal.h>
38 #include <corecrypto/ccsha1.h>
39 #include <Security/SecItem.h>
40 #include <Security/SecItemPriv.h>
41 #include <Security/SecAccessControl.h>
42 #include <Security/SecAccessControlPriv.h>
43
44 // MARK: type converters
45
46 CFStringRef copyString(CFTypeRef obj) {
47 CFTypeID tid = CFGetTypeID(obj);
48 if (tid == CFStringGetTypeID())
49 return CFStringCreateCopy(0, obj);
50 else if (tid == CFDataGetTypeID())
51 return CFStringCreateFromExternalRepresentation(0, obj, kCFStringEncodingUTF8);
52 else
53 return NULL;
54 }
55
56 CFDataRef copyData(CFTypeRef obj) {
57 CFTypeID tid = CFGetTypeID(obj);
58 if (tid == CFDataGetTypeID()) {
59 return CFDataCreateCopy(0, obj);
60 } else if (tid == CFStringGetTypeID()) {
61 return CFStringCreateExternalRepresentation(0, obj, kCFStringEncodingUTF8, 0);
62 } else if (tid == CFNumberGetTypeID()) {
63 SInt32 value;
64 CFNumberGetValue(obj, kCFNumberSInt32Type, &value);
65 return CFDataCreate(0, (const UInt8 *)&value, sizeof(value));
66 } else {
67 return NULL;
68 }
69 }
70
71 CFTypeRef copyBlob(CFTypeRef obj) {
72 CFTypeID tid = CFGetTypeID(obj);
73 if (tid == CFDataGetTypeID()) {
74 return CFDataCreateCopy(0, obj);
75 } else if (tid == CFStringGetTypeID()) {
76 return CFStringCreateCopy(0, obj);
77 } else if (tid == CFNumberGetTypeID()) {
78 CFRetain(obj);
79 return obj;
80 } else {
81 return NULL;
82 }
83 }
84
85 CFDataRef copySHA1(CFTypeRef obj) {
86 CFTypeID tid = CFGetTypeID(obj);
87 if (tid == CFDataGetTypeID() && CFDataGetLength(obj) == CCSHA1_OUTPUT_SIZE) {
88 return CFDataCreateCopy(CFGetAllocator(obj), obj);
89 } else {
90 return NULL;
91 }
92 }
93
94 CFTypeRef copyNumber(CFTypeRef obj) {
95 CFTypeID tid = CFGetTypeID(obj);
96 if (tid == CFNumberGetTypeID()) {
97 CFRetain(obj);
98 return obj;
99 } else if (tid == CFBooleanGetTypeID()) {
100 SInt32 value = CFBooleanGetValue(obj);
101 return CFNumberCreate(0, kCFNumberSInt32Type, &value);
102 } else if (tid == CFStringGetTypeID()) {
103 SInt32 value = CFStringGetIntValue(obj);
104 CFStringRef t = CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long) value);
105 /* If a string converted to an int isn't equal to the int printed as
106 a string, return a CFStringRef instead. */
107 if (!CFEqual(t, obj)) {
108 CFRelease(t);
109 return CFStringCreateCopy(0, obj);
110 }
111 CFRelease(t);
112 return CFNumberCreate(0, kCFNumberSInt32Type, &value);
113 } else
114 return NULL;
115 }
116
117 CFDateRef copyDate(CFTypeRef obj) {
118 CFTypeID tid = CFGetTypeID(obj);
119 if (tid == CFDateGetTypeID()) {
120 CFRetain(obj);
121 return obj;
122 } else
123 return NULL;
124 }
125
126 // MARK: SecDbColumn accessors, to retrieve values as CF types in SecDbStep.
127
128 static CFDataRef SecDbColumnCopyData(CFAllocatorRef allocator, sqlite3_stmt *stmt, int col, CFErrorRef *error) {
129 return CFDataCreate(allocator, sqlite3_column_blob(stmt, col),
130 sqlite3_column_bytes(stmt, col));
131 //return CFDataCreateWithBytesNoCopy(0, sqlite3_column_blob(stmt, col),
132 // sqlite3_column_bytes(stmt, col),
133 // kCFAllocatorNull);
134 }
135
136 static CFDateRef SecDbColumnCopyDate(CFAllocatorRef allocator, sqlite3_stmt *stmt, int col, CFErrorRef *error) {
137 return CFDateCreate(allocator, sqlite3_column_double(stmt, col));
138 }
139
140 static CFNumberRef SecDbColumnCopyDouble(CFAllocatorRef allocator, sqlite3_stmt *stmt, int col, CFErrorRef *error) {
141 double number = sqlite3_column_double(stmt, col);
142 return CFNumberCreate(allocator, kCFNumberDoubleType, &number);
143 }
144
145 static CFNumberRef SecDbColumnCopyNumber64(CFAllocatorRef allocator, sqlite3_stmt *stmt, int col, CFErrorRef *error) {
146 sqlite_int64 number = sqlite3_column_int64(stmt, col);
147 return CFNumberCreate(allocator, kCFNumberSInt64Type, &number);
148 }
149
150 static CFNumberRef SecDbColumnCopyNumber(CFAllocatorRef allocator, sqlite3_stmt *stmt, int col, CFErrorRef *error) {
151 sqlite_int64 number = sqlite3_column_int64(stmt, col);
152 if (INT32_MIN <= number && number <= INT32_MAX) {
153 int32_t num32 = (int32_t)number;
154 return CFNumberCreate(allocator, kCFNumberSInt32Type, &num32);
155 } else {
156 return CFNumberCreate(allocator, kCFNumberSInt64Type, &number);
157 }
158 }
159
160 static CFStringRef SecDbColumnCopyString(CFAllocatorRef allocator, sqlite3_stmt *stmt, int col, CFErrorRef *error) {
161 const unsigned char *text = sqlite3_column_text(stmt, col);
162 return CFStringCreateWithBytes(allocator, text, strlen((const char *)text), kCFStringEncodingUTF8, false);
163 }
164
165 // MARK: SecDbClass helpers
166
167 const SecDbAttr *SecDbClassAttrWithKind(const SecDbClass *class, SecDbAttrKind kind, CFErrorRef *error) {
168 const SecDbAttr *result = NULL;
169 SecDbForEachAttr(class, desc) {
170 if (desc->kind == kind)
171 result = desc;
172 }
173
174 if (!result)
175 SecError(errSecInternal, error, CFSTR("Can't find attribute of kind %d in class %@"), kind, class->name);
176
177 return result;
178 }
179
180 // MARK: SecDbAttr helpers
181
182 static bool SecDbIsTombstoneDbSelectAttr(const SecDbAttr *attr) {
183 return attr->flags & kSecDbPrimaryKeyFlag || attr->kind == kSecDbTombAttr;
184 }
185
186 #if 0
187 static bool SecDbIsTombstoneDbInsertAttr(const SecDbAttr *attr) {
188 return SecDbIsTombstoneDbSelectAttr(attr) || attr->kind == kSecDbAccessAttr || attr->kind == kSecDbCreationDateAttr || attr->kind == kSecDbModificationDateAttr;
189 }
190 #endif
191
192 static bool SecDbIsTombstoneDbUpdateAttr(const SecDbAttr *attr) {
193 return SecDbIsTombstoneDbSelectAttr(attr) || attr->kind == kSecDbAccessAttr || attr->kind == kSecDbCreationDateAttr || attr->kind == kSecDbRowIdAttr;
194 }
195
196 static bool SecDbAttrBind(const SecDbAttr *attr, sqlite3_stmt *stmt, int col, CFTypeRef value, CFErrorRef *error) {
197 bool ok = true;
198 if (value && !CFEqual(kCFNull, value) && attr->flags & kSecDbSHA1ValueInFlag) {
199 CFDataRef data = copyData(value);
200 if (!data) {
201 SecError(errSecInternal, error, CFSTR("failed to get attribute %@ data"), attr->name);
202 return false;
203 }
204
205 CFMutableDataRef digest = CFDataCreateMutable(kCFAllocatorDefault, CCSHA1_OUTPUT_SIZE);
206 CFDataSetLength(digest, CCSHA1_OUTPUT_SIZE);
207 /* 64 bits cast: worst case is we generate the wrong hash */
208 assert((unsigned long)CFDataGetLength(data)<UINT32_MAX); /* Debug check. Correct as long as CFIndex is long */
209 ccdigest(ccsha1_di(), CFDataGetLength(data), CFDataGetBytePtr(data), CFDataGetMutableBytePtr(digest));
210 CFRelease(data);
211 ok &= SecDbBindObject(stmt, col, digest, error);
212 CFRelease(digest);
213 } else {
214 ok &= SecDbBindObject(stmt, col, value, error);
215 }
216 return ok;
217 }
218
219 // MARK: SecDbItem
220
221 CFTypeRef SecDbItemGetCachedValueWithName(SecDbItemRef item, CFStringRef name) {
222 return CFDictionaryGetValue(item->attributes, name);
223 }
224
225 static CFTypeRef SecDbItemGetCachedValue(SecDbItemRef item, const SecDbAttr *desc) {
226 return CFDictionaryGetValue(item->attributes, desc->name);
227 }
228
229 CFMutableDictionaryRef SecDbItemCopyPListWithMask(SecDbItemRef item, CFOptionFlags mask, CFErrorRef *error) {
230 CFMutableDictionaryRef dict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
231 SecDbForEachAttrWithMask(item->class, desc, mask) {
232 CFTypeRef value = SecDbItemGetValue(item, desc, error);
233 if (value) {
234 if (!CFEqual(kCFNull, value)) {
235 CFDictionarySetValue(dict, desc->name, value);
236 } else if (desc->flags & kSecDbNotNullFlag) {
237 SecError(errSecDecode, error, CFSTR("attribute %@ has NULL value"), desc->name);
238 secerror("%@", error ? *error : (CFErrorRef)CFSTR("error == NULL"));
239 CFReleaseNull(dict);
240 break;
241 }
242 } else {
243 CFReleaseNull(dict);
244 break;
245 }
246 }
247 return dict;
248 }
249
250 static CFDataRef SecDbItemCopyDERWithMask(SecDbItemRef item, CFOptionFlags mask, CFErrorRef *error) {
251 CFDataRef der = NULL;
252 CFMutableDictionaryRef dict = SecDbItemCopyPListWithMask(item, mask, error);
253 if (dict) {
254 der = kc_plist_copy_der(dict, error);
255 CFRelease(dict);
256 }
257 return der;
258 }
259
260 static CFDataRef SecDbItemCopyDigestWithMask(SecDbItemRef item, CFOptionFlags mask, CFErrorRef *error) {
261 CFDataRef digest = NULL;
262 CFDataRef der = SecDbItemCopyDERWithMask(item, mask, error);
263 if (der) {
264 digest = kc_copy_sha1(CFDataGetLength(der), CFDataGetBytePtr(der), error);
265 CFRelease(der);
266 }
267 return digest;
268 }
269
270 static CFDataRef SecDbItemCopyPrimaryKey(SecDbItemRef item, CFErrorRef *error) {
271 return SecDbItemCopyDigestWithMask(item, kSecDbPrimaryKeyFlag, error);
272 }
273
274 static CFDataRef SecDbItemCopySHA1(SecDbItemRef item, CFErrorRef *error) {
275 return SecDbItemCopyDigestWithMask(item, kSecDbInHashFlag, error);
276 }
277
278 SecAccessControlRef SecDbItemCopyAccessControl(SecDbItemRef item, CFErrorRef *error) {
279 SecAccessControlRef accc = NULL;
280 SecAccessControlRef pdmn = NULL;
281 CFTypeRef acccData = SecDbItemGetValue(item, SecDbClassAttrWithKind(item->class, kSecDbAccessControlAttr, error), error);
282 CFTypeRef pdmnValue = SecDbItemGetValue(item, SecDbClassAttrWithKind(item->class, kSecDbAccessAttr, error), error);
283 if (!acccData || !pdmnValue)
284 return NULL;
285 if (!CFEqual(acccData, kCFNull)) {
286 accc = SecAccessControlCreateFromData(CFGetAllocator(item), acccData, error);
287 if (!accc)
288 return NULL;
289 }
290 if (!CFEqual(pdmnValue, kCFNull)) {
291 pdmn = SecAccessControlCreateWithFlags(CFGetAllocator(item), pdmnValue, 0, error);
292 if (!pdmn) {
293 CFReleaseSafe(accc);
294 return NULL;
295 }
296 }
297 if (accc && pdmn) {
298 CFTypeRef acccProt = SecAccessControlGetProtection(accc);
299 CFTypeRef pdmnProt = SecAccessControlGetProtection(pdmn);
300 if (!acccProt || !pdmnProt || !CFEqual(acccProt, pdmnProt)) {
301 secerror("SecDbItemCopyAccessControl accc %@ != pdmn %@, setting pdmn to accc value", acccProt, pdmnProt);
302 __security_simulatecrash(CFSTR("Corrupted item on decrypt accc != pdmn"), __sec_exception_code_CorruptItem);
303 // Setting pdmn to accc prot value.
304 if (!SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbAccessAttr, error), acccProt, error)) {
305 // Fixing the kSecDbAccessAttr failed, return the error.
306 CFReleaseNull(accc);
307 }
308 }
309 CFReleaseNull(pdmn);
310 } else if (!accc) {
311 accc = pdmn;
312 }
313 return accc;
314 }
315
316 void SecDbItemSetCredHandle(SecDbItemRef item, CFTypeRef cred_handle) {
317 CFRetainAssign(item->credHandle, cred_handle);
318 }
319
320 void SecDbItemSetCallerAccessGroups(SecDbItemRef item, CFArrayRef caller_access_groups) {
321 CFRetainAssign(item->callerAccessGroups, caller_access_groups);
322 }
323
324 static CFDataRef SecDbItemCopyEncryptedData(SecDbItemRef item, CFErrorRef *error) {
325 CFDataRef edata = NULL;
326 CFMutableDictionaryRef attributes = SecDbItemCopyPListWithMask(item, kSecDbInCryptoDataFlag, error);
327 CFMutableDictionaryRef auth_attributes = SecDbItemCopyPListWithMask(item, kSecDbInAuthenticatedDataFlag, error);
328 if (attributes || auth_attributes) {
329 SecAccessControlRef access_control = SecDbItemCopyAccessControl(item, error);
330 if (access_control) {
331 if (ks_encrypt_data(item->keybag, access_control, &item->credHandle, attributes, auth_attributes, &edata, error)) {
332 item->_edataState = kSecDbItemEncrypting;
333 } else {
334 seccritical("ks_encrypt_data (db): failed: %@", error ? *error : (CFErrorRef)CFSTR(""));
335 }
336 CFRelease(access_control);
337 }
338 CFReleaseSafe(attributes);
339 CFReleaseSafe(auth_attributes);
340 }
341
342 return edata;
343 }
344
345 CFDataRef SecDbItemCopyEncryptedDataToBackup(SecDbItemRef item, uint64_t handle, CFErrorRef *error) {
346 CFDataRef edata = NULL;
347 keybag_handle_t keybag = (keybag_handle_t)handle;
348 CFMutableDictionaryRef attributes = SecDbItemCopyPListWithMask(item, kSecDbInCryptoDataFlag, error);
349 CFMutableDictionaryRef auth_attributes = SecDbItemCopyPListWithMask(item, kSecDbInAuthenticatedDataFlag, error);
350 if (attributes || auth_attributes) {
351 SecAccessControlRef access_control = SecDbItemCopyAccessControl(item, error);
352 if (access_control) {
353 if (ks_encrypt_data(keybag, access_control, &item->credHandle, attributes, auth_attributes, &edata, error)) {
354 item->_edataState = kSecDbItemEncrypting;
355 } else {
356 seccritical("ks_encrypt_data (db): failed: %@", error ? *error : (CFErrorRef)CFSTR(""));
357 }
358 CFRelease(access_control);
359 }
360 CFReleaseSafe(attributes);
361 CFReleaseSafe(auth_attributes);
362 }
363 return edata;
364 }
365
366 bool SecDbItemEnsureDecrypted(SecDbItemRef item, CFDataRef *authNeeded, CFTypeRef *credHandle, CFErrorRef *error) {
367
368 // If we haven't yet decrypted the item, make sure we do so now
369 bool result = true;
370 if (item->_edataState == kSecDbItemEncrypted) {
371 const SecDbAttr *attr = SecDbClassAttrWithKind(item->class, kSecDbEncryptedDataAttr, error);
372 if (attr) {
373 CFDataRef edata = SecDbItemGetCachedValue(item, attr);
374 if (!edata)
375 return SecError(errSecInternal, error, CFSTR("state= encrypted but edata is NULL"));
376 // Decrypt calls set value a bunch of times which clears our edata and changes our state.
377 item->_edataState = kSecDbItemDecrypting;
378 if (credHandle)
379 SecDbItemSetCredHandle(item, *credHandle);
380 result = SecDbItemDecrypt(item, edata, authNeeded, error);
381 if (credHandle)
382 CFRetainAssign(*credHandle, item->credHandle);
383 if (result)
384 item->_edataState = kSecDbItemClean;
385 else
386 item->_edataState = kSecDbItemEncrypted;
387 }
388 }
389 return result;
390 }
391
392 // Only called if cached value is not found.
393 static CFTypeRef SecDbItemCopyValue(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error) {
394 CFTypeRef value = NULL;
395 switch (attr->kind) {
396 case kSecDbSHA1Attr:
397 value = SecDbItemCopySHA1(item, error);
398 break;
399 case kSecDbEncryptedDataAttr:
400 value = SecDbItemCopyEncryptedData(item, error);
401 break;
402 case kSecDbPrimaryKeyAttr:
403 value = SecDbItemCopyPrimaryKey(item, error);
404 break;
405 case kSecDbAccessAttr:
406 case kSecDbStringAttr:
407 case kSecDbBlobAttr:
408 case kSecDbAccessControlAttr:
409 if (attr->flags & kSecDbNotNullFlag) {
410 if (attr->flags & kSecDbDefault0Flag) {
411 value = CFSTR("0");
412 break;
413 } else if (attr->kind != kSecDbBlobAttr && attr->flags & kSecDbDefaultEmptyFlag) {
414 // blob drops through to data everything else is empty string
415 value = CFSTR("");
416 break;
417 }
418 }
419 //DROPTHROUGH
420 case kSecDbDataAttr:
421 if (attr->flags & kSecDbNotNullFlag && attr->flags & kSecDbDefaultEmptyFlag) {
422 value = CFDataCreate(CFGetAllocator(item), NULL, 0);
423 } else {
424 value = kCFNull;
425 }
426 break;
427 case kSecDbNumberAttr:
428 case kSecDbSyncAttr:
429 case kSecDbTombAttr:
430 if (attr->flags & kSecDbNotNullFlag) {
431 int32_t zero = 0;
432 value = CFNumberCreate(CFGetAllocator(item), kCFNumberSInt32Type, &zero);
433 } else {
434 value = kCFNull;
435 }
436 break;
437 case kSecDbDateAttr:
438 if (attr->flags & kSecDbNotNullFlag && attr->flags & kSecDbDefault0Flag) {
439 value = CFDateCreate(kCFAllocatorDefault, 0.0);
440 } else {
441 value = kCFNull;
442 }
443 break;
444 case kSecDbRowIdAttr:
445 if (attr->flags & kSecDbNotNullFlag) {
446 // No can do, error?
447 }
448 value = kCFNull;
449 break;
450 case kSecDbCreationDateAttr:
451 case kSecDbModificationDateAttr:
452 value = CFDateCreate(CFGetAllocator(item), CFAbsoluteTimeGetCurrent());
453 break;
454 }
455
456 return value;
457 }
458
459 // SecDbItemGetValue will return kCFNull if there is no value for an attribute and this was not
460 // an error. It will return NULL and optionally set *error if there was an error computing an
461 // attribute, or if a required attribute was missing a value and had no known way to compute
462 // it's value.
463 CFTypeRef SecDbItemGetValue(SecDbItemRef item, const SecDbAttr *desc, CFErrorRef *error) {
464 // Propagate chained errors
465 if (!desc)
466 return NULL;
467
468 if (desc->flags & kSecDbInCryptoDataFlag || desc->flags & kSecDbInAuthenticatedDataFlag) {
469 if (!SecDbItemEnsureDecrypted(item, NULL, NULL, error))
470 return NULL;
471 }
472
473 CFTypeRef value = SecDbItemGetCachedValue(item, desc);
474 if (!value) {
475 value = SecDbItemCopyValue(item, desc, error);
476 if (value) {
477 if (CFEqual(kCFNull, value)) {
478 CFRelease(value); // This is redundant but it shuts clang's static analyzer up.
479 value = kCFNull;
480 } else {
481 SecDbItemSetValue(item, desc, value, error);
482 CFRelease(value);
483 value = SecDbItemGetCachedValue(item, desc);
484 }
485 }
486 }
487 return value;
488 }
489
490 static bool SecDbItemGetBoolValue(SecDbItemRef item, const SecDbAttr *desc, bool *bvalue, CFErrorRef *error) {
491 CFTypeRef value = SecDbItemGetValue(item, desc, error);
492 if (!value)
493 return false;
494 char cvalue;
495 *bvalue = (isNumber(value) && CFNumberGetValue(value, kCFNumberCharType, &cvalue) && cvalue == 1);
496 return true;
497 }
498
499 static CFStringRef SecDbItemCopyDescription(CFTypeRef cf) {
500 #if 0 //defined(DEBUG) && DEBUG != 0
501 SecDbItemRef item = (SecDbItemRef)cf;
502 CFMutableStringRef desc = CFStringCreateMutable(CFGetAllocator(cf), 0);
503 CFStringAppendFormat(desc, NULL, CFSTR("<%@"), item->class->name);
504 SecDbForEachAttr(item->class, attr) {
505 CFTypeRef value = SecDbItemGetValue(item, attr, NULL);
506 if (value) {
507 CFStringAppend(desc, CFSTR(","));
508 CFStringAppend(desc, attr->name);
509 CFStringAppend(desc, CFSTR("="));
510 if (CFEqual(CFSTR("data"), attr->name)) {
511 CFStringAppendEncryptedData(desc, value);
512 } else if (CFEqual(CFSTR("v_Data"), attr->name)) {
513 CFStringAppend(desc, CFSTR("<?>"));
514 } else if (isData(value)) {
515 CFStringAppendHexData(desc, value);
516 } else {
517 CFStringAppendFormat(desc, 0, CFSTR("%@"), value);
518 }
519 }
520 }
521 CFStringAppend(desc, CFSTR(">"));
522 #else
523 SecDbItemRef item = (SecDbItemRef)cf;
524 const UInt8 zero4[4] = {};
525 const UInt8 *pk = &zero4[0], *sha1 = &zero4[0];
526 char sync = 0;
527 char tomb = 0;
528 SInt64 rowid = 0;
529 CFStringRef access = NULL;
530 uint8_t mdatbuf[32] = {};
531 uint8_t *mdat = &mdatbuf[0];
532 CFMutableStringRef attrs = CFStringCreateMutable(kCFAllocatorDefault, 0);
533 CFStringRef agrp = NULL;
534
535 SecDbForEachAttr(item->class, attr) {
536 CFTypeRef value;
537 switch (attr->kind) {
538 case kSecDbBlobAttr:
539 case kSecDbDataAttr:
540 case kSecDbStringAttr:
541 case kSecDbNumberAttr:
542 case kSecDbDateAttr:
543 case kSecDbEncryptedDataAttr:
544 if (attr->flags & (kSecDbReturnAttrFlag | kSecDbReturnDataFlag) && (value = SecDbItemGetValue(item, attr, NULL)) && !CFEqual(value, kCFNull)) {
545 if (isString(value) && CFEqual(attr->name, kSecAttrAccessGroup)) {
546 agrp = value;
547 } else {
548 // We don't log these, just record that we saw the attribute.
549 CFStringAppend(attrs, CFSTR(","));
550 CFStringAppend(attrs, attr->name);
551 }
552 }
553 break;
554 case kSecDbCreationDateAttr:
555 // We don't care about this and every object has one.
556 break;
557 case kSecDbModificationDateAttr:
558 value = SecDbItemGetValue(item, attr, NULL);
559 if (isDate(value))
560 mdat = der_encode_generalizedtime_body(CFDateGetAbsoluteTime(value), NULL, mdat, &mdatbuf[31]);
561 break;
562 case kSecDbSHA1Attr:
563 value = SecDbItemGetValue(item, attr, NULL);
564 if (isData(value))
565 sha1 = CFDataGetBytePtr(value);
566 break;
567 case kSecDbRowIdAttr:
568 value = SecDbItemGetValue(item, attr, NULL);
569 if (isNumber(value))
570 CFNumberGetValue(value, kCFNumberSInt64Type, &rowid);
571 break;
572 case kSecDbPrimaryKeyAttr:
573 value = SecDbItemGetValue(item, attr, NULL);
574 if (isData(value))
575 pk = CFDataGetBytePtr(value);
576 break;
577 case kSecDbSyncAttr:
578 value = SecDbItemGetValue(item, attr, NULL);
579 if (isNumber(value))
580 CFNumberGetValue(value, kCFNumberCharType, &sync);
581 break;
582 case kSecDbTombAttr:
583 value = SecDbItemGetValue(item, attr, NULL);
584 if (isNumber(value))
585 CFNumberGetValue(value, kCFNumberCharType, &tomb);
586 break;
587 case kSecDbAccessAttr:
588 value = SecDbItemGetValue(item, attr, NULL);
589 if (isString(value))
590 access = value;
591 break;
592 case kSecDbAccessControlAttr:
593 /* TODO: Add formatting of ACLs. */
594 break;
595 }
596 }
597
598 CFStringRef desc = CFStringCreateWithFormat(CFGetAllocator(cf), NULL,
599 CFSTR(
600 "%s,"
601 "%@,"
602 "%02X%02X%02X%02X,"
603 "%s,"
604 "%@,"
605 "%@,"
606 "%"PRId64
607 "%@,"
608 "%s,"
609 "%02X%02X%02X%02X"),
610 tomb ? "T" : "O",
611 item->class->name,
612 pk[0], pk[1], pk[2], pk[3],
613 sync ? "S" : "L",
614 access,
615 agrp,
616 rowid,
617 attrs,
618 mdat,
619 sha1[0], sha1[1], sha1[2], sha1[3]);
620 CFReleaseSafe(attrs);
621 #endif
622
623 return desc;
624 }
625
626 static void SecDbItemDestroy(CFTypeRef cf) {
627 SecDbItemRef item = (SecDbItemRef)cf;
628 CFReleaseSafe(item->attributes);
629 CFReleaseSafe(item->credHandle);
630 CFReleaseSafe(item->callerAccessGroups);
631 }
632
633 static CFHashCode SecDbItemHash(CFTypeRef cf) {
634 SecDbItemRef item = (SecDbItemRef)cf;
635 CFDataRef digest = SecDbItemGetSHA1(item, NULL);
636 CFHashCode code;
637 const UInt8 *p = CFDataGetBytePtr(digest);
638 // Read first 8 bytes of digest in order
639 code = p[0] + ((p[1] + ((p[2] + ((p[3] + ((p[4] + ((p[5] + ((p[6] + (p[7] << 8)) << 8)) << 8)) << 8)) << 8)) << 8)) << 8);
640 return code;
641 }
642
643 static Boolean SecDbItemCompare(CFTypeRef cf1, CFTypeRef cf2) {
644 SecDbItemRef item1 = (SecDbItemRef)cf1;
645 SecDbItemRef item2 = (SecDbItemRef)cf2;
646 CFDataRef digest1 = NULL;
647 CFDataRef digest2 = NULL;
648 if (item1)
649 digest1 = SecDbItemGetSHA1(item1, NULL);
650 if (item2)
651 digest2 = SecDbItemGetSHA1(item2, NULL);
652 Boolean equal = CFEqual(digest1, digest2);
653 return equal;
654 }
655
656 CFGiblisWithHashFor(SecDbItem)
657
658 static SecDbItemRef SecDbItemCreate(CFAllocatorRef allocator, const SecDbClass *class, keybag_handle_t keybag) {
659 SecDbItemRef item = CFTypeAllocate(SecDbItem, struct SecDbItem, allocator);
660 item->class = class;
661 item->attributes = CFDictionaryCreateMutableForCFTypes(allocator);
662 item->keybag = keybag;
663 item->_edataState = kSecDbItemDirty;
664 item->cryptoOp = kSecKsUnwrap;
665 return item;
666 }
667
668 const SecDbClass *SecDbItemGetClass(SecDbItemRef item) {
669 return item->class;
670 }
671
672 keybag_handle_t SecDbItemGetKeybag(SecDbItemRef item) {
673 return item->keybag;
674 }
675
676 bool SecDbItemSetKeybag(SecDbItemRef item, keybag_handle_t keybag, CFErrorRef *error) {
677 if (!SecDbItemEnsureDecrypted(item, NULL, NULL, error))
678 return false;
679 if (item->keybag != keybag) {
680 item->keybag = keybag;
681 if (item->_edataState == kSecDbItemClean) {
682 SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbEncryptedDataAttr, NULL), kCFNull, NULL);
683 }
684 }
685
686 return true;
687 }
688
689 bool SecDbItemSetValue(SecDbItemRef item, const SecDbAttr *desc, CFTypeRef value, CFErrorRef *error) {
690 // Propagate chained errors.
691 if (!desc)
692 return false;
693
694 if (!value)
695 value = kCFNull;
696
697 bool changed = false;
698 CFTypeRef attr = NULL;
699 if (desc->flags & kSecDbInCryptoDataFlag || desc->flags & kSecDbInAuthenticatedDataFlag)
700 if (!SecDbItemEnsureDecrypted(item, NULL, NULL, error))
701 return false;
702
703 switch (desc->kind) {
704 case kSecDbPrimaryKeyAttr:
705 case kSecDbDataAttr:
706 attr = copyData(value);
707 break;
708 case kSecDbEncryptedDataAttr:
709 attr = copyData(value);
710 if (attr) {
711 if (item->_edataState == kSecDbItemEncrypting)
712 item->_edataState = kSecDbItemClean;
713 else
714 item->_edataState = kSecDbItemEncrypted;
715 } else if (!value || CFEqual(kCFNull, value)) {
716 item->_edataState = kSecDbItemDirty;
717 }
718 break;
719 case kSecDbBlobAttr:
720 case kSecDbAccessControlAttr:
721 attr = copyBlob(value);
722 break;
723 case kSecDbDateAttr:
724 case kSecDbCreationDateAttr:
725 case kSecDbModificationDateAttr:
726 attr = copyDate(value);
727 break;
728 case kSecDbNumberAttr:
729 case kSecDbSyncAttr:
730 case kSecDbTombAttr:
731 case kSecDbRowIdAttr:
732 attr = copyNumber(value);
733 break;
734 case kSecDbAccessAttr:
735 case kSecDbStringAttr:
736 attr = copyString(value);
737 break;
738 case kSecDbSHA1Attr:
739 attr = copySHA1(value);
740 break;
741 }
742
743 if (attr) {
744 CFTypeRef ovalue = CFDictionaryGetValue(item->attributes, desc->name);
745 changed = (!ovalue || !CFEqual(ovalue, attr));
746 CFDictionarySetValue(item->attributes, desc->name, attr);
747 CFRelease(attr);
748 } else {
749 if (value && !CFEqual(kCFNull, value)) {
750 SecError(errSecItemInvalidValue, error, CFSTR("attribute %@: value: %@ failed to convert"), desc->name, value);
751 return false;
752 }
753 CFTypeRef ovalue = CFDictionaryGetValue(item->attributes, desc->name);
754 changed = (ovalue && !CFEqual(ovalue, kCFNull));
755 CFDictionaryRemoveValue(item->attributes, desc->name);
756 }
757
758 if (changed) {
759 if (desc->flags & kSecDbInHashFlag)
760 SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbSHA1Attr, NULL), kCFNull, NULL);
761 if (desc->flags & kSecDbPrimaryKeyFlag)
762 SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbPrimaryKeyAttr, NULL), kCFNull, NULL);
763 if ((desc->flags & kSecDbInCryptoDataFlag || desc->flags & kSecDbInAuthenticatedDataFlag) && item->_edataState == kSecDbItemClean)
764 SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbEncryptedDataAttr, NULL), kCFNull, NULL);
765 }
766
767 return true;
768 }
769
770 bool SecDbItemSetValues(SecDbItemRef item, CFDictionaryRef values, CFErrorRef *error) {
771 SecDbForEachAttr(item->class, attr) {
772 CFTypeRef value = CFDictionaryGetValue(values, attr->name);
773 if (value && !SecDbItemSetValue(item, attr, value, error))
774 return false;
775 }
776 return true;
777 }
778
779 bool SecDbItemSetValueWithName(SecDbItemRef item, CFStringRef name, CFTypeRef value, CFErrorRef *error) {
780 SecDbForEachAttr(item->class, attr) {
781 if (CFEqual(attr->name, name)) {
782 return SecDbItemSetValue(item, attr, value, error);
783 }
784 }
785 return false;
786 }
787
788 bool SecDbItemSetAccessControl(SecDbItemRef item, SecAccessControlRef access_control, CFErrorRef *error) {
789 bool ok = SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbEncryptedDataAttr, error), kCFNull, error);
790 if (ok) {
791 item->_edataState = kSecDbItemDirty;
792 CFDataRef data = SecAccessControlCopyData(access_control);
793 ok = SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbAccessControlAttr, error), data, error);
794 CFRelease(data);
795 }
796 return ok;
797 }
798
799 SecDbItemRef SecDbItemCreateWithAttributes(CFAllocatorRef allocator, const SecDbClass *class, CFDictionaryRef attributes, keybag_handle_t keybag, CFErrorRef *error) {
800 SecDbItemRef item = SecDbItemCreate(kCFAllocatorDefault, class, keybag);
801 if (item && !SecDbItemSetValues(item, attributes, error))
802 CFReleaseNull(item);
803 return item;
804 }
805
806 static CFTypeRef
807 SecDbColumnCopyValueWithAttr(CFAllocatorRef allocator, sqlite3_stmt *stmt, const SecDbAttr *attr, int col, CFErrorRef *error) {
808 CFTypeRef value = NULL;
809 switch (attr->kind) {
810 case kSecDbDateAttr:
811 case kSecDbCreationDateAttr:
812 case kSecDbModificationDateAttr:
813 value = SecDbColumnCopyDate(allocator, stmt, col, error);
814 break;
815 case kSecDbBlobAttr:
816 switch (sqlite3_column_type(stmt, col)) {
817 case SQLITE_INTEGER:
818 value = SecDbColumnCopyNumber(allocator, stmt, col, error);
819 break;
820 case SQLITE_FLOAT:
821 value = SecDbColumnCopyDouble(allocator, stmt, col, error);
822 break;
823 case SQLITE_TEXT:
824 value = SecDbColumnCopyString(allocator, stmt, col, error);
825 break;
826 case SQLITE_BLOB:
827 value = SecDbColumnCopyData(allocator, stmt, col, error);
828 break;
829 case SQLITE_NULL:
830 value = kCFNull;
831 break;
832 }
833 break;
834 case kSecDbAccessAttr:
835 case kSecDbStringAttr:
836 value = SecDbColumnCopyString(allocator, stmt, col, error);
837 break;
838 case kSecDbDataAttr:
839 case kSecDbSHA1Attr:
840 case kSecDbPrimaryKeyAttr:
841 value = SecDbColumnCopyData(allocator, stmt, col, error);
842 break;
843 case kSecDbEncryptedDataAttr:
844 value = SecDbColumnCopyData(allocator, stmt, col, error);
845 break;
846 case kSecDbSyncAttr:
847 case kSecDbTombAttr:
848 case kSecDbNumberAttr:
849 value = SecDbColumnCopyNumber(allocator, stmt, col, error);
850 break;
851 case kSecDbRowIdAttr:
852 value = SecDbColumnCopyNumber64(allocator, stmt, col, error);
853 break;
854 case kSecDbAccessControlAttr:
855 /* This attributes does not have any database column associated, exists only inside encrypted blob as metadata. */
856 break;
857 }
858 return value;
859 }
860
861 SecDbItemRef SecDbItemCreateWithStatement(CFAllocatorRef allocator, const SecDbClass *class, sqlite3_stmt *stmt, keybag_handle_t keybag, CFErrorRef *error, bool (^return_attr)(const SecDbAttr *attr)) {
862 SecDbItemRef item = SecDbItemCreate(allocator, class, keybag);
863 int col = 0;
864 SecDbForEachAttr(class, attr) {
865 if (return_attr(attr)) {
866 CFTypeRef value = SecDbColumnCopyValueWithAttr(allocator, stmt, attr, col++, error);
867 if (value) {
868 if (attr->kind == kSecDbSHA1Attr) {
869 SecDbItemSetValue(item, attr, value, NULL);
870 } else if (!SecDbItemSetValue(item, attr, value, error)) {
871 CFReleaseNull(item);
872 }
873 CFRelease(value);
874 }
875 }
876 }
877
878 return item;
879 }
880
881 SecDbItemRef SecDbItemCreateWithEncryptedData(CFAllocatorRef allocator, const SecDbClass *class,
882 CFDataRef edata, keybag_handle_t keybag, CFErrorRef *error) {
883 SecDbItemRef item = SecDbItemCreate(allocator, class, keybag);
884 const SecDbAttr *edata_attr = SecDbClassAttrWithKind(class, kSecDbEncryptedDataAttr, error);
885 if (edata_attr) {
886 if (!SecDbItemSetValue(item, edata_attr, edata, error))
887 CFReleaseNull(item);
888 }
889 return item;
890 }
891
892 #if 0
893 SecDbItemRef SecDbItemCreateWithRowId(CFAllocatorRef allocator, const SecDbClass *class, sqlite_int64 row_id, keybag_handle_t keybag, CFErrorRef *error) {
894 SecDbItemRef item = SecDbItemCreate(allocator, class, keybag);
895 if (!SecDbItemSetRowId(item, row_id, error))
896 CFReleaseNull(item);
897 return item;
898 }
899 #endif
900
901 SecDbItemRef SecDbItemCopyWithUpdates(SecDbItemRef item, CFDictionaryRef updates, CFErrorRef *error) {
902 SecDbItemRef new_item = SecDbItemCreate(CFGetAllocator(item), item->class, item->keybag);
903 SecDbForEachAttr(item->class, attr) {
904 // Copy each attribute, except the mod date attribute (it will be reset to now when needed),
905 // from the updates dict unless it's not there in which case we copy the attribute from the passed in item.
906 if (attr->kind != kSecDbModificationDateAttr && attr->kind != kSecDbEncryptedDataAttr && attr->kind != kSecDbSHA1Attr && attr->kind != kSecDbPrimaryKeyAttr) {
907 CFTypeRef value = NULL;
908 if (CFDictionaryGetValueIfPresent(updates, attr->name, &value)) {
909 if (!value)
910 SecError(errSecParam, error, CFSTR("NULL value in dictionary"));
911 } else {
912 value = SecDbItemGetValue(item, attr, error);
913 }
914 if (!value || !SecDbItemSetValue(new_item, attr, value, error)) {
915 CFReleaseNull(new_item);
916 break;
917 }
918 }
919 }
920 return new_item;
921 }
922
923 // Ensure that the date value of attr of new_item is greater than that of old_item.
924 static bool SecDbItemMakeAttrYounger(SecDbItemRef new_item, SecDbItemRef old_item, const SecDbAttr *attr, CFErrorRef *error) {
925 CFDateRef old_date = SecDbItemGetValue(old_item, attr, error);
926 if (!old_date)
927 return false;
928 CFDateRef new_date = SecDbItemGetValue(new_item, attr, error);
929 if (!new_date)
930 return false;
931 bool ok = true;
932 if (CFDateCompare(new_date, old_date, NULL) != kCFCompareGreaterThan) {
933 CFDateRef adjusted_date = CFDateCreate(kCFAllocatorDefault, CFDateGetAbsoluteTime(old_date) + 0.001);
934 if (adjusted_date) {
935 ok = SecDbItemSetValue(new_item, attr, adjusted_date, error);
936 CFRelease(adjusted_date);
937 }
938 }
939 return ok;
940 }
941
942 // Ensure that the mod date of new_item is greater than that of old_item.
943 static bool SecDbItemMakeYounger(SecDbItemRef new_item, SecDbItemRef old_item, CFErrorRef *error) {
944 const SecDbAttr *attr = SecDbClassAttrWithKind(new_item->class, kSecDbModificationDateAttr, error);
945 return attr && SecDbItemMakeAttrYounger(new_item, old_item, attr, error);
946 }
947
948 SecDbItemRef SecDbItemCopyTombstone(SecDbItemRef item, CFErrorRef *error) {
949 SecDbItemRef new_item = SecDbItemCreate(CFGetAllocator(item), item->class, item->keybag);
950 SecDbForEachAttr(item->class, attr) {
951 if (attr->kind == kSecDbTombAttr) {
952 // Set the tomb attr to true to indicate a tombstone.
953 if (!SecDbItemSetValue(new_item, attr, kCFBooleanTrue, error)) {
954 CFReleaseNull(new_item);
955 break;
956 }
957 } else if (SecDbIsTombstoneDbUpdateAttr(attr)) {
958 // Copy all primary key attributes and creation timestamps from the original item.
959 CFTypeRef value = SecDbItemGetValue(item, attr, error);
960 if (!value || (!CFEqual(kCFNull, value) && !SecDbItemSetValue(new_item, attr, value, error))) {
961 CFReleaseNull(new_item);
962 break;
963 }
964 } else if (attr->kind == kSecDbModificationDateAttr) {
965 if (!SecDbItemMakeAttrYounger(new_item, item, attr, error)) {
966 CFReleaseNull(new_item);
967 break;
968 }
969 }
970 }
971
972 return new_item;
973 }
974
975 // MARK: -
976 // MARK: SQL Construction helpers -- These should become private in the future
977
978 void SecDbAppendElement(CFMutableStringRef sql, CFStringRef value, bool *needComma) {
979 assert(needComma);
980 if (*needComma) {
981 CFStringAppend(sql, CFSTR(","));
982 } else {
983 *needComma = true;
984 }
985 CFStringAppend(sql, value);
986 }
987
988 static void SecDbAppendElementEquals(CFMutableStringRef sql, CFStringRef value, bool *needComma) {
989 SecDbAppendElement(sql, value, needComma);
990 CFStringAppend(sql, CFSTR("=?"));
991 }
992
993 /* Append AND is needWhere is NULL or *needWhere is false. Append WHERE
994 otherwise. Upon return *needWhere will be false. */
995 void
996 SecDbAppendWhereOrAnd(CFMutableStringRef sql, bool *needWhere) {
997 if (!needWhere || !*needWhere) {
998 CFStringAppend(sql, CFSTR(" AND "));
999 } else {
1000 CFStringAppend(sql, CFSTR(" WHERE "));
1001 *needWhere = false;
1002 }
1003 }
1004
1005 void
1006 SecDbAppendWhereOrAndEquals(CFMutableStringRef sql, CFStringRef col, bool *needWhere) {
1007 SecDbAppendWhereOrAnd(sql, needWhere);
1008 CFStringAppend(sql, col);
1009 CFStringAppend(sql, CFSTR("=?"));
1010 }
1011
1012 static CFStringRef SecDbItemCopyInsertSQL(SecDbItemRef item, bool(^use_attr)(const SecDbAttr *attr)) {
1013 CFMutableStringRef sql = CFStringCreateMutable(CFGetAllocator(item), 0);
1014 CFStringAppend(sql, CFSTR("INSERT INTO "));
1015 CFStringAppend(sql, item->class->name);
1016 CFStringAppend(sql, CFSTR("("));
1017 bool needComma = false;
1018 CFIndex used_attr = 0;
1019 SecDbForEachAttr(item->class, attr) {
1020 if (use_attr(attr)) {
1021 ++used_attr;
1022 SecDbAppendElement(sql, attr->name, &needComma);
1023 }
1024 }
1025 CFStringAppend(sql, CFSTR(")VALUES(?"));
1026 while (used_attr-- > 1) {
1027 CFStringAppend(sql, CFSTR(",?"));
1028 }
1029 CFStringAppend(sql, CFSTR(")"));
1030 return sql;
1031
1032 }
1033
1034 static bool SecDbItemInsertBind(SecDbItemRef item, sqlite3_stmt *stmt, CFErrorRef *error, bool(^use_attr)(const SecDbAttr *attr)) {
1035 bool ok = true;
1036 int param = 0;
1037 SecDbForEachAttr(item->class, attr) {
1038 if (use_attr(attr)) {
1039 CFTypeRef value = SecDbItemGetValue(item, attr, error);
1040 if (!value || !SecDbAttrBind(attr, stmt, ++param, value, error)) {
1041 ok = false;
1042 break;
1043 }
1044 }
1045 }
1046 return ok;
1047 }
1048
1049 sqlite3_int64 SecDbItemGetRowId(SecDbItemRef item, CFErrorRef *error) {
1050 sqlite3_int64 row_id = 0;
1051 const SecDbAttr *attr = SecDbClassAttrWithKind(item->class, kSecDbRowIdAttr, error);
1052 if (attr) {
1053 CFNumberRef number = SecDbItemGetValue(item, attr, error);
1054 if (!isNumber(number)|| !CFNumberGetValue(number, kCFNumberSInt64Type, &row_id))
1055 SecDbError(SQLITE_ERROR, error, CFSTR("rowid %@ is not a 64 bit number"), number);
1056 }
1057
1058 return row_id;
1059 }
1060
1061 static CFNumberRef SecDbItemCreateRowId(SecDbItemRef item, sqlite3_int64 rowid, CFErrorRef *error) {
1062 return CFNumberCreate(CFGetAllocator(item), kCFNumberSInt64Type, &rowid);
1063 }
1064
1065 bool SecDbItemSetRowId(SecDbItemRef item, sqlite3_int64 rowid, CFErrorRef *error) {
1066 bool ok = true;
1067 const SecDbAttr *attr = SecDbClassAttrWithKind(item->class, kSecDbRowIdAttr, error);
1068 if (attr) {
1069 CFNumberRef value = SecDbItemCreateRowId(item, rowid, error);
1070 if (!value)
1071 return false;
1072
1073 ok = SecDbItemSetValue(item, attr, value, error);
1074 CFRelease(value);
1075 }
1076 return ok;
1077 }
1078
1079 static bool SecDbItemClearRowId(SecDbItemRef item, CFErrorRef *error) {
1080 bool ok = true;
1081 const SecDbAttr *attr = SecDbClassAttrWithKind(item->class, kSecDbRowIdAttr, error);
1082 if (attr) {
1083 CFDictionaryRemoveValue(item->attributes, attr->name);
1084 //ok = SecDbItemSetValue(item, attr, kCFNull, error);
1085 }
1086 return ok;
1087 }
1088
1089 static bool SecDbItemSetLastInsertRowId(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error) {
1090 sqlite3_int64 rowid = sqlite3_last_insert_rowid(SecDbHandle(dbconn));
1091 return SecDbItemSetRowId(item, rowid, error);
1092 }
1093
1094 bool SecDbItemIsSyncableOrCorrupted(SecDbItemRef item) {
1095 bool is_syncable_or_corrupted = false;
1096 CFErrorRef localError = NULL;
1097 if (!SecDbItemGetBoolValue(item, SecDbClassAttrWithKind(item->class, kSecDbSyncAttr, &localError),
1098 &is_syncable_or_corrupted, &localError)) {
1099 is_syncable_or_corrupted = SecErrorGetOSStatus(localError) == errSecDecode;
1100 }
1101 CFReleaseSafe(localError);
1102 return is_syncable_or_corrupted;
1103 }
1104
1105 bool SecDbItemIsSyncable(SecDbItemRef item) {
1106 bool is_syncable;
1107 if (SecDbItemGetBoolValue(item, SecDbClassAttrWithKind(item->class, kSecDbSyncAttr, NULL), &is_syncable, NULL))
1108 return is_syncable;
1109 return false;
1110 }
1111
1112 bool SecDbItemSetSyncable(SecDbItemRef item, bool sync, CFErrorRef *error)
1113 {
1114 return SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbSyncAttr, error), sync ? kCFBooleanTrue : kCFBooleanFalse, error);
1115 }
1116
1117 bool SecDbItemIsTombstone(SecDbItemRef item) {
1118 bool is_tomb;
1119 if (SecDbItemGetBoolValue(item, SecDbClassAttrWithKind(item->class, kSecDbTombAttr, NULL), &is_tomb, NULL))
1120 return is_tomb;
1121 return false;
1122 }
1123
1124 CFDataRef SecDbItemGetPrimaryKey(SecDbItemRef item, CFErrorRef *error) {
1125 return SecDbItemGetValue(item, SecDbClassAttrWithKind(item->class, kSecDbPrimaryKeyAttr, error), error);
1126 }
1127
1128 CFDataRef SecDbItemGetSHA1(SecDbItemRef item, CFErrorRef *error) {
1129 return SecDbItemGetValue(item, SecDbClassAttrWithKind(item->class, kSecDbSHA1Attr, error), error);
1130 }
1131
1132 static SecDbQueryRef SecDbQueryCreateWithItemPrimaryKey(SecDbItemRef item, CFErrorRef *error) {
1133 CFMutableDictionaryRef dict = SecDbItemCopyPListWithMask(item, kSecDbPrimaryKeyFlag, error);
1134 if (!dict)
1135 return NULL;
1136
1137 SecDbQueryRef query = query_create(item->class, NULL, error);
1138 if (query) {
1139 CFReleaseSafe(query->q_item);
1140 query->q_item = dict;
1141 }
1142 else
1143 CFRelease(dict);
1144
1145 return query;
1146 }
1147
1148 static bool SecDbItemIsCorrupt(SecDbItemRef item, bool *is_corrupt, CFErrorRef *error) {
1149 CFErrorRef localError = NULL;
1150 // Cache the storedSHA1 digest so we use the one from the db not the recomputed one for notifications.
1151 const struct SecDbAttr *sha1attr = SecDbClassAttrWithKind(item->class, kSecDbSHA1Attr, &localError);
1152 CFDataRef storedSHA1 = CFRetainSafe(SecDbItemGetValue(item, sha1attr, &localError));
1153 SecDbItemSetValue(item, sha1attr, kCFNull, &localError);
1154 CFDataRef access_control_data = NULL;
1155
1156 bool akpu = false;
1157
1158 if (localError || !SecDbItemEnsureDecrypted(item, &access_control_data, NULL, &localError)) {
1159 if (SecErrorGetOSStatus(localError) == errSecDecode) {
1160 // We failed to decrypt the item
1161 SecAccessControlRef access_control = NULL;
1162 CFTypeRef access_class = NULL;
1163
1164 if (access_control_data != NULL &&
1165 (access_control =
1166 SecAccessControlCreateFromData(kCFAllocatorDefault, access_control_data, NULL)) != NULL &&
1167 (access_class = SecAccessControlGetProtection(access_control)) != NULL &&
1168 CFStringCompare(access_class, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, 0) == kCFCompareEqualTo) {
1169 akpu = true;
1170 secwarning("cannot decrypt item %@, item is irrecoverably lost with older passcode (error %@)", item, localError);
1171 } else {
1172 secerror("error %@ reading item %@ (corrupted)", localError, item);
1173 __security_simulatecrash(CFSTR("Corrupted item found in keychain"), __sec_exception_code_CorruptItem);
1174 }
1175 CFReleaseSafe(access_control);
1176 CFReleaseNull(localError);
1177 *is_corrupt = true;
1178 }
1179 }
1180 CFReleaseNull(access_control_data);
1181
1182 CFDataRef computedSHA1 = SecDbItemGetValue(item, sha1attr, NULL);
1183 if (storedSHA1 && computedSHA1) {
1184 if (!CFEqual(storedSHA1, computedSHA1)) {
1185 secerror("error %@ %@ != %@ item %@ (corrupted)", sha1attr->name, storedSHA1, computedSHA1, item);
1186 __security_simulatecrash(CFSTR("Corrupted item (sha1 mismatch) found in keychain"), __sec_exception_code_CorruptItem);
1187 *is_corrupt = true;
1188 // Restore original (bad) sha1 digest so db notifications will properly update our manifest
1189 SecDbItemSetValue(item, sha1attr, storedSHA1, NULL);
1190 CFReleaseSafe(storedSHA1);
1191 return true;
1192 }
1193 }
1194 CFReleaseSafe(storedSHA1);
1195
1196 // Sanity check that all attributes that must not be NULL actually aren't
1197 if (!localError) SecDbForEachAttr(item->class, attr) {
1198 if (attr->flags & (kSecDbInCryptoDataFlag | kSecDbInAuthenticatedDataFlag)) {
1199 CFTypeRef value = SecDbItemGetValue(item, attr, &localError);
1200 if (value) {
1201 if (CFEqual(kCFNull, value) && attr->flags & kSecDbNotNullFlag) {
1202 secerror("error attribute %@ has NULL value in item %@ (corrupted)", attr->name, item);
1203 __security_simulatecrash(CFSTR("Corrupted item (attr NULL) found in keychain"), __sec_exception_code_CorruptItem);
1204 *is_corrupt = true;
1205 break;
1206 }
1207 } else {
1208 if (SecErrorGetOSStatus(localError) == errSecDecode) {
1209 // We failed to decrypt the item
1210 if (akpu) {
1211 secwarning("attribute %@: %@ item %@ (item lost with older passcode)", attr->name, localError, item);
1212 } else {
1213 secerror("error attribute %@: %@ item %@ (corrupted)", attr->name, localError, item);
1214 __security_simulatecrash(CFSTR("Corrupted item found in keychain"), __sec_exception_code_CorruptItem);
1215 }
1216 *is_corrupt = true;
1217 CFReleaseNull(localError);
1218 }
1219 break;
1220 }
1221 }
1222 }
1223 return CFErrorPropagate(localError, error);
1224 }
1225
1226 static void SecDbItemRecordUpdate(SecDbConnectionRef dbconn, SecDbItemRef deleted, SecDbItemRef inserted) {
1227 CFDataRef deletedDigest = NULL;
1228 CFDataRef insertedDigest = NULL;
1229 if (deleted && SecDbItemIsSyncableOrCorrupted(deleted))
1230 deletedDigest = SecDbItemGetSHA1(deleted, NULL);
1231 if (inserted && SecDbItemIsSyncable(inserted))
1232 insertedDigest = SecDbItemGetSHA1(inserted, NULL);
1233 if (deletedDigest || insertedDigest)
1234 SecDbRecordChange(dbconn, deletedDigest, insertedDigest);
1235 }
1236
1237 static bool SecDbItemDoInsert(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error) {
1238 bool (^use_attr)(const SecDbAttr *attr) = ^bool(const SecDbAttr *attr) {
1239 return (attr->flags & kSecDbInFlag);
1240 };
1241 CFStringRef sql = SecDbItemCopyInsertSQL(item, use_attr);
1242 __block bool ok = sql;
1243 if (sql) {
1244 ok &= SecDbPrepare(dbconn, sql, error, ^(sqlite3_stmt *stmt) {
1245 ok = (SecDbItemInsertBind(item, stmt, error, use_attr) &&
1246 SecDbStep(dbconn, stmt, error, NULL) &&
1247 SecDbItemSetLastInsertRowId(item, dbconn, error));
1248 });
1249 CFRelease(sql);
1250 }
1251 if (ok) {
1252 secnotice("item", "inserted %@", item);
1253 SecDbItemRecordUpdate(dbconn, NULL, item);
1254 }
1255
1256 return ok;
1257 }
1258
1259 bool SecDbItemInsertOrReplace(SecDbItemRef item, SecDbConnectionRef dbconn, CFMutableArrayRef authlist, CFErrorRef *error, void(^duplicate)(SecDbItemRef item, SecDbItemRef *replace)) {
1260 __block CFErrorRef localError = NULL;
1261 __block bool ok = SecDbItemDoInsert(item, dbconn, &localError);
1262 if (!ok && localError && CFErrorGetCode(localError) == SQLITE_CONSTRAINT && CFEqual(kSecDbErrorDomain, CFErrorGetDomain(localError))) {
1263 SecDbQueryRef query = SecDbQueryCreateWithItemPrimaryKey(item, error);
1264 if (query) {
1265 CFRetainAssign(query->q_required_access_controls, authlist);
1266 CFRetainAssign(query->q_use_cred_handle, item->credHandle);
1267 SecDbItemSelect(query, dbconn, error, ^bool(const SecDbAttr *attr) {
1268 return attr->flags & kSecDbPrimaryKeyFlag;
1269 }, NULL, NULL, ^(SecDbItemRef old_item, bool *stop) {
1270 bool is_corrupt = false;
1271 ok = SecDbItemIsCorrupt(old_item, &is_corrupt, error);
1272 SecDbItemRef replace = NULL;
1273 if (is_corrupt) {
1274 // If old_item is corrupted pretend it's not there and just replace it.
1275 replace = item;
1276 CFRetain(replace);
1277 } else if (ok && duplicate) {
1278 duplicate(old_item, &replace);
1279 }
1280 if (replace) {
1281 const SecDbAttr *rowid_attr = SecDbClassAttrWithKind(old_item->class, kSecDbRowIdAttr, error);
1282 CFNumberRef oldrowid = SecDbItemGetCachedValue(old_item, rowid_attr);
1283 if (oldrowid) {
1284 ok = SecDbItemSetValue(replace, rowid_attr, oldrowid, &localError);
1285 if (ok && !is_corrupt) {
1286 ok = SecDbItemMakeYounger(replace, old_item, error);
1287 }
1288 ok = ok && SecDbItemDoUpdate(old_item, replace, dbconn, &localError, ^bool (const SecDbAttr *attr) {
1289 return attr->kind == kSecDbRowIdAttr;
1290 });
1291 } else {
1292 ok = SecError(errSecInternal, &localError, CFSTR("no rowid for %@"), old_item);
1293 }
1294 CFRelease(replace);
1295 if (ok)
1296 CFReleaseNull(localError); // Clear the error, since we replaced the item.
1297 }
1298 });
1299 SecDbItemSetCredHandle(item, query->q_use_cred_handle);
1300 ok &= query_destroy(query, error);
1301 }
1302 }
1303
1304 return ok & CFErrorPropagate(localError, error); // Don't use && here!
1305 }
1306
1307 bool SecDbItemInsert(SecDbItemRef item, SecDbConnectionRef dbconn, CFMutableArrayRef authlist, CFErrorRef *error) {
1308 return SecDbItemInsertOrReplace(item, dbconn, authlist, error, ^(SecDbItemRef old_item, SecDbItemRef *replace) {
1309 if (SecDbItemIsTombstone(old_item)) {
1310 CFRetain(item);
1311 *replace = item;
1312 }
1313 });
1314 }
1315
1316 static CFStringRef SecDbItemCopyUpdateSQL(SecDbItemRef old_item, SecDbItemRef new_item, bool(^use_attr_in_where)(const SecDbAttr *attr)) {
1317 CFMutableStringRef sql = CFStringCreateMutable(CFGetAllocator(new_item), 0);
1318 CFStringAppend(sql, CFSTR("UPDATE "));
1319 CFStringAppend(sql, new_item->class->name);
1320 CFStringAppend(sql, CFSTR(" SET "));
1321 bool needComma = false;
1322 CFIndex used_attr = 0;
1323 SecDbForEachAttrWithMask(new_item->class, attr, kSecDbInFlag) {
1324 ++used_attr;
1325 SecDbAppendElementEquals(sql, attr->name, &needComma);
1326 }
1327
1328 bool needWhere = true;
1329 SecDbForEachAttr(old_item->class, attr) {
1330 if (use_attr_in_where(attr)) {
1331 SecDbAppendWhereOrAndEquals(sql, attr->name, &needWhere);
1332 }
1333 }
1334
1335 return sql;
1336 }
1337
1338 static bool SecDbItemUpdateBind(SecDbItemRef old_item, SecDbItemRef new_item, sqlite3_stmt *stmt, CFErrorRef *error, bool(^use_attr_in_where)(const SecDbAttr *attr)) {
1339 bool ok = true;
1340 int param = 0;
1341 SecDbForEachAttrWithMask(new_item->class, attr, kSecDbInFlag) {
1342 CFTypeRef value = SecDbItemGetValue(new_item, attr, error);
1343 ok &= value && SecDbAttrBind(attr, stmt, ++param, value, error);
1344 if (!ok)
1345 break;
1346 }
1347 SecDbForEachAttr(old_item->class, attr) {
1348 if (use_attr_in_where(attr)) {
1349 CFTypeRef value = SecDbItemGetValue(old_item, attr, error);
1350 ok &= value && SecDbAttrBind(attr, stmt, ++param, value, error);
1351 if (!ok)
1352 break;
1353 }
1354 }
1355 return ok;
1356 }
1357
1358 // Primary keys are the same -- do an update
1359 bool SecDbItemDoUpdate(SecDbItemRef old_item, SecDbItemRef new_item, SecDbConnectionRef dbconn, CFErrorRef *error, bool (^use_attr_in_where)(const SecDbAttr *attr)) {
1360 CFStringRef sql = SecDbItemCopyUpdateSQL(old_item, new_item, use_attr_in_where);
1361 __block bool ok = sql;
1362 if (sql) {
1363 ok &= SecDbPrepare(dbconn, sql, error, ^(sqlite3_stmt *stmt) {
1364 ok = SecDbItemUpdateBind(old_item, new_item, stmt, error, use_attr_in_where) && SecDbStep(dbconn, stmt, error, NULL);
1365 });
1366 CFRelease(sql);
1367 }
1368 if (ok) {
1369 secnotice("item", "replaced %@ with %@ in %@", old_item, new_item, dbconn);
1370 SecDbItemRecordUpdate(dbconn, old_item, new_item);
1371 }
1372 return ok;
1373 }
1374
1375 static CFStringRef SecDbItemCopyDeleteSQL(SecDbItemRef item, bool(^use_attr_in_where)(const SecDbAttr *attr)) {
1376 CFMutableStringRef sql = CFStringCreateMutable(CFGetAllocator(item), 0);
1377 CFStringAppend(sql, CFSTR("DELETE FROM "));
1378 CFStringAppend(sql, item->class->name);
1379 bool needWhere = true;
1380 SecDbForEachAttr(item->class, attr) {
1381 if (use_attr_in_where(attr)) {
1382 SecDbAppendWhereOrAndEquals(sql, attr->name, &needWhere);
1383 }
1384 }
1385
1386 return sql;
1387 }
1388
1389 static bool SecDbItemDeleteBind(SecDbItemRef item, sqlite3_stmt *stmt, CFErrorRef *error, bool(^use_attr_in_where)(const SecDbAttr *attr)) {
1390 bool ok = true;
1391 int param = 0;
1392 SecDbForEachAttr(item->class, attr) {
1393 if (use_attr_in_where(attr)) {
1394 CFTypeRef value = SecDbItemGetValue(item, attr, error);
1395 ok &= value && SecDbAttrBind(attr, stmt, ++param, value, error);
1396 if (!ok)
1397 break;
1398 }
1399 }
1400 return ok;
1401 }
1402
1403 static bool SecDbItemDoDelete(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error, bool (^use_attr_in_where)(const SecDbAttr *attr)) {
1404 CFStringRef sql = SecDbItemCopyDeleteSQL(item, use_attr_in_where);
1405 __block bool ok = sql;
1406 if (sql) {
1407 ok &= SecDbPrepare(dbconn, sql, error, ^(sqlite3_stmt *stmt) {
1408 ok = SecDbItemDeleteBind(item, stmt, error, use_attr_in_where) && SecDbStep(dbconn, stmt, error, NULL);
1409 });
1410 CFRelease(sql);
1411 }
1412 if (ok) {
1413 secnotice("item", "deleted %@ from %@", item, dbconn);
1414 SecDbItemRecordUpdate(dbconn, item, NULL);
1415 }
1416 return ok;
1417 }
1418
1419 #if 0
1420 static bool SecDbItemDeleteTombstone(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error) {
1421 bool ok = true;
1422 // TODO: Treat non decryptable items like tombstones here too and delete them
1423 SecDbItemRef tombstone = SecDbItemCopyTombstone(item, error);
1424 ok = tombstone;
1425 if (tombstone) {
1426 ok = SecDbItemClearRowId(tombstone, error);
1427 if (ok) {
1428 ok = SecDbItemDoDelete(tombstone, dbconn, error, ^bool (const SecDbAttr *attr) {
1429 return SecDbIsTombstoneDbSelectAttr(attr);
1430 });
1431 }
1432 CFRelease(tombstone);
1433 }
1434 return ok;
1435 }
1436 #endif
1437
1438 // Replace old_item with new_item. If primary keys are the same this does an update otherwise it does a delete + add
1439 bool SecDbItemUpdate(SecDbItemRef old_item, SecDbItemRef new_item, SecDbConnectionRef dbconn, bool makeTombstone, CFErrorRef *error) {
1440 __block bool ok = true;
1441 __block CFErrorRef localError = NULL;
1442
1443 CFDataRef old_pk = SecDbItemGetPrimaryKey(old_item, error);
1444 CFDataRef new_pk = SecDbItemGetPrimaryKey(new_item, error);
1445
1446 ok = old_pk && new_pk;
1447
1448 bool pk_equal = ok && CFEqual(old_pk, new_pk);
1449 if (pk_equal) {
1450 ok = SecDbItemMakeYounger(new_item, old_item, error);
1451 }
1452 ok = ok && SecDbItemDoUpdate(old_item, new_item, dbconn, &localError, ^bool(const SecDbAttr *attr) {
1453 return attr->kind == kSecDbRowIdAttr;
1454 });
1455
1456 if (localError) {
1457 if(CFErrorGetCode(localError) == SQLITE_CONSTRAINT && CFEqual(kSecDbErrorDomain, CFErrorGetDomain(localError))) {
1458 /* Update failed because we changed the PrimaryKey and there was a dup.
1459 Find the dup and see if it is a tombstone or corrupted item. */
1460 SecDbQueryRef query = SecDbQueryCreateWithItemPrimaryKey(new_item, error);
1461 ok = query;
1462 if (query) {
1463 ok &= SecDbItemSelect(query, dbconn, error, ^bool(const SecDbAttr *attr) {
1464 return attr->flags & kSecDbPrimaryKeyFlag;
1465 }, NULL, NULL, ^(SecDbItemRef duplicate_item, bool *stop) {
1466 bool is_corrupt = false;
1467 bool is_tomb = false;
1468 ok = SecDbItemIsCorrupt(duplicate_item, &is_corrupt, error);
1469 if (ok && !is_corrupt) {
1470 if ((is_tomb = SecDbItemIsTombstone(duplicate_item)))
1471 ok = SecDbItemMakeYounger(new_item, duplicate_item, error);
1472 }
1473 if (ok && (is_corrupt || is_tomb)) {
1474 ok = SecDbItemDoDelete(old_item, dbconn, error, ^bool (const SecDbAttr *attr) {
1475 return attr->kind == kSecDbRowIdAttr;
1476 });
1477 ok = ok && SecDbItemDoUpdate(duplicate_item, new_item, dbconn, error, ^bool (const SecDbAttr *attr) {
1478 return attr->kind == kSecDbRowIdAttr;
1479 });
1480 CFReleaseNull(localError);
1481 }
1482 });
1483 ok &= query_destroy(query, error);
1484 }
1485 }
1486
1487 if (localError) {
1488 ok = false;
1489 if (error && *error == NULL) {
1490 *error = localError;
1491 localError = NULL;
1492 }
1493 CFReleaseSafe(localError);
1494 }
1495 }
1496
1497 if (ok && !pk_equal && makeTombstone) {
1498 /* The primary key of new_item is different than that of old_item, we
1499 have been asked to make a tombstone so leave one for the old_item. */
1500 SecDbItemRef tombstone = SecDbItemCopyTombstone(old_item, error);
1501 ok = tombstone;
1502 if (tombstone) {
1503 ok = (SecDbItemClearRowId(tombstone, error) &&
1504 SecDbItemDoInsert(tombstone, dbconn, error));
1505 CFRelease(tombstone);
1506 }
1507 }
1508
1509 return ok;
1510 }
1511
1512 // Replace the object with a tombstone
1513 bool SecDbItemDelete(SecDbItemRef item, SecDbConnectionRef dbconn, bool makeTombstone, CFErrorRef *error) {
1514 bool ok = false;
1515 if (makeTombstone) {
1516 SecDbItemRef tombstone = SecDbItemCopyTombstone(item, error);
1517 if (tombstone) {
1518 ok = SecDbItemDoUpdate(item, tombstone, dbconn, error, ^bool(const SecDbAttr *attr) {
1519 return attr->kind == kSecDbRowIdAttr;
1520 });
1521 CFRelease(tombstone);
1522 }
1523 } else {
1524 ok = SecDbItemDoDelete(item, dbconn, error, ^bool(const SecDbAttr *attr) {
1525 return attr->kind == kSecDbRowIdAttr;
1526 });
1527 }
1528 return ok;
1529 }
1530
1531 CFStringRef SecDbItemCopySelectSQL(SecDbQueryRef query,
1532 bool (^return_attr)(const SecDbAttr *attr),
1533 bool (^use_attr_in_where)(const SecDbAttr *attr),
1534 bool (^add_where_sql)(CFMutableStringRef sql, bool *needWhere)) {
1535 CFMutableStringRef sql = CFStringCreateMutable(kCFAllocatorDefault, 0);
1536 CFStringAppend(sql, CFSTR("SELECT "));
1537 // What are we selecting?
1538 bool needComma = false;
1539 SecDbForEachAttr(query->q_class, attr) {
1540 if (return_attr(attr))
1541 SecDbAppendElement(sql, attr->name, &needComma);
1542 }
1543
1544 // From which table?
1545 CFStringAppend(sql, CFSTR(" FROM "));
1546 CFStringAppend(sql, query->q_class->name);
1547
1548 // And which elements do we want to select
1549 bool needWhere = true;
1550 SecDbForEachAttr(query->q_class, attr) {
1551 if (use_attr_in_where(attr)) {
1552 SecDbAppendWhereOrAndEquals(sql, attr->name, &needWhere);
1553 }
1554 }
1555 // Append SQL for access groups and limits.
1556 if (add_where_sql)
1557 add_where_sql(sql, &needWhere);
1558
1559 return sql;
1560 }
1561
1562 bool SecDbItemSelectBind(SecDbQueryRef query, sqlite3_stmt *stmt, CFErrorRef *error,
1563 bool (^use_attr_in_where)(const SecDbAttr *attr),
1564 bool (^bind_added_where)(sqlite3_stmt *stmt, int col)) {
1565 bool ok = true;
1566 int param = 0;
1567 SecDbForEachAttr(query->q_class, attr) {
1568 if (use_attr_in_where(attr)) {
1569 CFTypeRef value = CFDictionaryGetValue(query->q_item, attr->name);
1570 ok &= SecDbAttrBind(attr, stmt, ++param, value, error);
1571 if (!ok)
1572 break;
1573 }
1574 }
1575 // TODO: Bind arguments for access groups and limits.
1576 if (bind_added_where)
1577 bind_added_where(stmt, ++param);
1578
1579 return ok;
1580 }
1581
1582 bool SecDbItemSelect(SecDbQueryRef query, SecDbConnectionRef dbconn, CFErrorRef *error,
1583 bool (^use_attr_in_where)(const SecDbAttr *attr),
1584 bool (^add_where_sql)(CFMutableStringRef sql, bool *needWhere),
1585 bool (^bind_added_where)(sqlite3_stmt *stmt, int col),
1586 void (^handle_row)(SecDbItemRef item, bool *stop)) {
1587 __block bool ok = true;
1588 __block bool decrypted = true;
1589 bool (^return_attr)(const SecDbAttr *attr) = ^bool (const SecDbAttr * attr) {
1590 return attr->kind == kSecDbRowIdAttr || attr->kind == kSecDbEncryptedDataAttr || attr->kind == kSecDbSHA1Attr;
1591 };
1592 CFStringRef sql = SecDbItemCopySelectSQL(query, return_attr, use_attr_in_where, add_where_sql);
1593 if (sql) {
1594 ok &= SecDbPrepare(dbconn, sql, error, ^(sqlite3_stmt *stmt) {
1595 ok = (SecDbItemSelectBind(query, stmt, error, use_attr_in_where, bind_added_where) &&
1596 SecDbStep(dbconn, stmt, error, ^(bool *stop) {
1597 SecDbItemRef item = SecDbItemCreateWithStatement(kCFAllocatorDefault, query->q_class, stmt, query->q_keybag, error, return_attr);
1598 if (item) {
1599 if (query->q_required_access_controls) {
1600 CFDataRef authNeeded = NULL;
1601 item->cryptoOp = query->q_crypto_op;
1602 SecDbItemSetCallerAccessGroups(item, query->q_caller_access_groups);
1603 decrypted = SecDbItemEnsureDecrypted(item, &authNeeded, &query->q_use_cred_handle, NULL);
1604 if (decrypted && authNeeded) {
1605 // Do not process the item right now, just remember that it will need
1606 // authentication to properly process it.
1607 CFArrayAppendValue(query->q_required_access_controls, authNeeded);
1608 CFRelease(authNeeded);
1609 CFRelease(item);
1610 return;
1611 }
1612 CFReleaseSafe(authNeeded);
1613 }
1614 handle_row(item, stop);
1615 CFRelease(item);
1616 } else {
1617 //*stop = true;
1618 //ok = false;
1619 }
1620 }));
1621 });
1622 CFRelease(sql);
1623 } else {
1624 ok = false;
1625 }
1626 return ok;
1627 }
1628