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