/ keychain / securityd / SecDbItem.c
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  #if defined(TARGET_DARWINOS) && TARGET_DARWINOS
  30  #undef OCTAGON
  31  #undef SECUREOBJECTSYNC
  32  #undef SHAREDWEBCREDENTIALS
  33  #endif
  34  
  35  #include "keychain/securityd/SecDbItem.h"
  36  #include "keychain/securityd/SecDbKeychainItem.h"
  37  #include "keychain/securityd/SecItemDb.h"
  38  #include <utilities/SecCFWrappers.h>
  39  #include <utilities/SecCFCCWrappers.h>
  40  #include <utilities/der_date.h>
  41  #include <utilities/der_plist.h>
  42  #include <utilities/debugging.h>
  43  
  44  #include <Security/SecBasePriv.h>
  45  #include <Security/SecInternal.h>
  46  #include <corecrypto/ccsha1.h>
  47  #include <Security/SecItem.h>
  48  #include <Security/SecItemPriv.h>
  49  #include <Security/SecAccessControl.h>
  50  #include <Security/SecAccessControlPriv.h>
  51  #include "keychain/securityd/SecItemSchema.h"
  52  
  53  #include <keychain/ckks/CKKS.h>
  54  
  55  // MARK: type converters
  56  
  57  CFStringRef copyString(CFTypeRef obj) {
  58      CFTypeID tid = CFGetTypeID(obj);
  59      if (tid == CFStringGetTypeID()) {
  60          return CFStringCreateCopy(0, obj);
  61      }else if (tid == CFDataGetTypeID()) {
  62          return CFStringCreateFromExternalRepresentation(0, obj, kCFStringEncodingUTF8);
  63      } else if (tid == CFUUIDGetTypeID()) {
  64          return CFUUIDCreateString(NULL, obj);
  65      } else {
  66          return NULL;
  67      }
  68  }
  69  
  70  CFDataRef copyData(CFTypeRef obj) {
  71      CFTypeID tid = CFGetTypeID(obj);
  72      if (tid == CFDataGetTypeID()) {
  73          return CFDataCreateCopy(0, obj);
  74      } else if (tid == CFStringGetTypeID()) {
  75          return CFStringCreateExternalRepresentation(0, obj, kCFStringEncodingUTF8, 0);
  76      } else if (tid == CFNumberGetTypeID()) {
  77          SInt32 value;
  78          CFNumberGetValue(obj, kCFNumberSInt32Type, &value);
  79          return CFDataCreate(0, (const UInt8 *)&value, sizeof(value));
  80      } else {
  81          return NULL;
  82      }
  83  }
  84  
  85  CFTypeRef copyUUID(CFTypeRef obj) {
  86      CFTypeID tid = CFGetTypeID(obj);
  87      if (tid == CFDataGetTypeID()) {
  88          CFIndex length = CFDataGetLength(obj);
  89          if (length != 0 && length != 16)
  90              return NULL;
  91          return CFDataCreateCopy(NULL, obj);
  92      } else if (tid == CFNullGetTypeID()) {
  93          return CFDataCreate(NULL, NULL, 0);
  94      } else if (tid == CFUUIDGetTypeID()) {
  95          CFUUIDBytes uuidbytes = CFUUIDGetUUIDBytes(obj);
  96          CFDataRef uuiddata = CFDataCreate(NULL, (void*) &uuidbytes, sizeof(uuidbytes));
  97          return uuiddata;
  98      } else {
  99          return NULL;
 100      }
 101  }
 102  
 103  
 104  CFTypeRef copyBlob(CFTypeRef obj) {
 105      CFTypeID tid = CFGetTypeID(obj);
 106      if (tid == CFDataGetTypeID()) {
 107          return CFDataCreateCopy(0, obj);
 108      } else if (tid == CFStringGetTypeID()) {
 109          return CFStringCreateCopy(0, obj);
 110      } else if (tid == CFNumberGetTypeID()) {
 111          CFRetain(obj);
 112          return obj;
 113      } else {
 114          return NULL;
 115      }
 116  }
 117  
 118  CFDataRef copySHA1(CFTypeRef obj) {
 119      CFTypeID tid = CFGetTypeID(obj);
 120      if (tid == CFDataGetTypeID() && CFDataGetLength(obj) == CCSHA1_OUTPUT_SIZE) {
 121          return CFDataCreateCopy(CFGetAllocator(obj), obj);
 122      } else {
 123          return NULL;
 124      }
 125  }
 126  
 127  CFTypeRef copyNumber(CFTypeRef obj) {
 128      CFTypeID tid = CFGetTypeID(obj);
 129      if (tid == CFNumberGetTypeID()) {
 130          CFRetain(obj);
 131          return obj;
 132      } else if (tid == CFBooleanGetTypeID()) {
 133          SInt32 value = CFBooleanGetValue(obj);
 134          return CFNumberCreate(0, kCFNumberSInt32Type, &value);
 135      } else if (tid == CFStringGetTypeID()) {
 136          SInt32 value = CFStringGetIntValue(obj);
 137          CFStringRef t = CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long) value);
 138          /* If a string converted to an int isn't equal to the int printed as
 139             a string, return a CFStringRef instead. */
 140          if (!CFEqual(t, obj)) {
 141              CFRelease(t);
 142              return CFStringCreateCopy(0, obj);
 143          }
 144          CFRelease(t);
 145          return CFNumberCreate(0, kCFNumberSInt32Type, &value);
 146      } else
 147          return NULL;
 148  }
 149  
 150  CFDateRef copyDate(CFTypeRef obj) {
 151      CFTypeID tid = CFGetTypeID(obj);
 152      if (tid == CFDateGetTypeID()) {
 153          CFRetain(obj);
 154          return obj;
 155      } else
 156          return NULL;
 157  }
 158  
 159  // MARK: SecDbColumn accessors, to retrieve values as CF types in SecDbStep.
 160  
 161  static CFDataRef SecDbColumnCopyData(CFAllocatorRef allocator, sqlite3_stmt *stmt, int col, CFErrorRef *error) {
 162      return CFDataCreate(allocator, sqlite3_column_blob(stmt, col),
 163                          sqlite3_column_bytes(stmt, col));
 164      //return CFDataCreateWithBytesNoCopy(0, sqlite3_column_blob(stmt, col),
 165      //                                   sqlite3_column_bytes(stmt, col),
 166      //                                   kCFAllocatorNull);
 167  }
 168  
 169  static CFDateRef SecDbColumnCopyDate(CFAllocatorRef allocator, sqlite3_stmt *stmt, int col, CFErrorRef *error) {
 170      return CFDateCreate(allocator, sqlite3_column_double(stmt, col));
 171  }
 172  
 173  static CFNumberRef SecDbColumnCopyDouble(CFAllocatorRef allocator, sqlite3_stmt *stmt, int col, CFErrorRef *error) {
 174      double number = sqlite3_column_double(stmt, col);
 175      return CFNumberCreate(allocator, kCFNumberDoubleType, &number);
 176  }
 177  
 178  static CFNumberRef SecDbColumnCopyNumber64(CFAllocatorRef allocator, sqlite3_stmt *stmt, int col, CFErrorRef *error) {
 179      sqlite_int64 number = sqlite3_column_int64(stmt, col);
 180      return CFNumberCreate(allocator, kCFNumberSInt64Type, &number);
 181  }
 182  
 183  static CFNumberRef SecDbColumnCopyNumber(CFAllocatorRef allocator, sqlite3_stmt *stmt, int col, CFErrorRef *error) {
 184      sqlite_int64 number = sqlite3_column_int64(stmt, col);
 185      if (INT32_MIN <= number && number <= INT32_MAX) {
 186          int32_t num32 = (int32_t)number;
 187          return CFNumberCreate(allocator, kCFNumberSInt32Type, &num32);
 188      } else {
 189          return CFNumberCreate(allocator, kCFNumberSInt64Type, &number);
 190      }
 191  }
 192  
 193  static CFTypeRef SecDbColumnCopyString(CFAllocatorRef allocator, sqlite3_stmt *stmt, int col, CFErrorRef *error,
 194                                         CFOptionFlags flags) {
 195      const unsigned char *text = sqlite3_column_text(stmt, col);
 196      if (!text || 0 == strlen((const char *)text)) {
 197          if (flags & kSecDbDefaultEmptyFlag) {
 198              return CFSTR("");
 199          } else if (flags & kSecDbDefault0Flag) {
 200              return CFSTR("0");
 201          } else {
 202              return kCFNull;
 203          }
 204      }
 205      return CFStringCreateWithBytes(allocator, text, strlen((const char *)text), kCFStringEncodingUTF8, false);
 206  }
 207  
 208  // MARK: SecDbClass helpers
 209  
 210  const SecDbAttr *SecDbClassAttrWithKind(const SecDbClass *class, SecDbAttrKind kind, CFErrorRef *error) {
 211      const SecDbAttr *result = NULL;
 212      SecDbForEachAttr(class, desc) {
 213          if (desc->kind == kind)
 214              result = desc;
 215      }
 216  
 217      if (!result)
 218          SecError(errSecInternal, error, CFSTR("Can't find attribute of kind %d in class %@"), kind, class->name);
 219  
 220      return result;
 221  }
 222  
 223  // MARK: SecDbAttr helpers
 224  
 225  static bool SecDbIsTombstoneDbSelectAttr(const SecDbAttr *attr) {
 226      return attr->flags & kSecDbPrimaryKeyFlag || attr->kind == kSecDbTombAttr;
 227  }
 228  
 229  #if 0
 230  static bool SecDbIsTombstoneDbInsertAttr(const SecDbAttr *attr) {
 231      return SecDbIsTombstoneDbSelectAttr(attr) || attr->kind == kSecDbAccessAttr || attr->kind == kSecDbCreationDateAttr || attr->kind == kSecDbModificationDateAttr;
 232  }
 233  #endif
 234  
 235  static bool SecDbIsTombstoneDbUpdateAttr(const SecDbAttr *attr) {
 236      // We add AuthenticatedData to include UUIDs, which can't be primary keys
 237      return SecDbIsTombstoneDbSelectAttr(attr) || attr->kind == kSecDbAccessAttr || attr->kind == kSecDbCreationDateAttr || attr->kind == kSecDbRowIdAttr || (attr->flags & kSecDbInAuthenticatedDataFlag);
 238  }
 239  
 240  CFTypeRef SecDbAttrCopyDefaultValue(const SecDbAttr *attr, CFErrorRef *error) {
 241      CFTypeRef value = NULL;
 242      switch (attr->kind) {
 243          case kSecDbAccessAttr:
 244          case kSecDbStringAttr:
 245          case kSecDbAccessControlAttr:
 246              value = CFSTR("");
 247              break;
 248          case kSecDbBlobAttr:
 249          case kSecDbDataAttr:
 250              value = CFDataCreate(kCFAllocatorDefault, NULL, 0);
 251              break;
 252          case kSecDbUUIDAttr:
 253              value = CFDataCreate(kCFAllocatorDefault, NULL, 0);
 254              break;
 255          case kSecDbNumberAttr:
 256          case kSecDbSyncAttr:
 257          case kSecDbTombAttr:
 258          {
 259              int32_t zero = 0;
 260              value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &zero);
 261              break;
 262          }
 263          case kSecDbDateAttr:
 264              value = CFDateCreate(kCFAllocatorDefault, 0.0);
 265              break;
 266          case kSecDbCreationDateAttr:
 267          case kSecDbModificationDateAttr:
 268              value = CFDateCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent());
 269              break;
 270          default:
 271              SecError(errSecInternal, error, CFSTR("attr %@ has no default value"), attr->name);
 272              value = NULL;
 273      }
 274  
 275      return value;
 276  }
 277  
 278  static CFTypeRef SecDbAttrCopyValueForDb(const SecDbAttr *attr, CFTypeRef value, CFErrorRef *error) {
 279      CFDataRef data = NULL;
 280      CFTypeRef result = NULL;
 281  
 282      if (value == NULL)
 283          value = kCFNull;
 284  
 285      if (CFEqual(value, kCFNull) && attr->flags & kSecDbPrimaryKeyFlag) {
 286          // SQLITE3 doesn't like NULL for primary key attributes, pretend kSecDbDefaultEmptyFlag was specified
 287          require_quiet(result = SecDbAttrCopyDefaultValue(attr, error), out);
 288      } else {
 289          result = CFRetain(value);
 290      }
 291  
 292      if (attr->flags & kSecDbSHA1ValueInFlag && !CFEqual(result, kCFNull)) {
 293          require_action_quiet(data = copyData(result), out,
 294                               SecError(errSecInternal, error, CFSTR("failed to get attribute %@ data"), attr->name);
 295                               CFReleaseNull(result));
 296          CFAssignRetained(result, CFDataCopySHA1Digest(data, error));
 297      }
 298  
 299  out:
 300      CFReleaseSafe(data);
 301      return result;
 302  }
 303  
 304  static CFStringRef SecDbAttrGetHashName(const SecDbAttr *attr) {
 305      if ((attr->flags & kSecDbSHA1ValueInFlag) == 0) {
 306          return attr->name;
 307      }
 308  
 309      static dispatch_once_t once;
 310      static CFMutableDictionaryRef hash_store;
 311      static dispatch_queue_t queue;
 312      dispatch_once(&once, ^{
 313          queue = dispatch_queue_create("secd-hash-name", NULL);
 314          hash_store = CFDictionaryCreateMutableForCFTypes(NULL);
 315      });
 316  
 317      __block CFStringRef name;
 318      dispatch_sync(queue, ^{
 319          name = CFDictionaryGetValue(hash_store, attr->name);
 320          if (name == NULL) {
 321              name = CFStringCreateWithFormat(NULL, NULL, CFSTR("#%@"), attr->name);
 322              CFDictionarySetValue(hash_store, attr->name, name);
 323              CFRelease(name);
 324          }
 325      });
 326      return name;
 327  }
 328  
 329  // MARK: SecDbItem
 330  
 331  CFTypeRef SecDbItemGetCachedValueWithName(SecDbItemRef item, CFStringRef name) {
 332      return CFDictionaryGetValue(item->attributes, name);
 333  }
 334  
 335  static CFTypeRef SecDbItemGetCachedValue(SecDbItemRef item, const SecDbAttr *desc) {
 336      return CFDictionaryGetValue(item->attributes, desc->name);
 337  }
 338  
 339  CFMutableDictionaryRef SecDbItemCopyPListWithMask(SecDbItemRef item, CFOptionFlags mask, CFErrorRef *error) {
 340      return SecDbItemCopyPListWithFlagAndSkip(item, mask, 0, error);
 341  }
 342  
 343  CFMutableDictionaryRef SecDbItemCopyPListWithFlagAndSkip(SecDbItemRef item,
 344                                                           CFOptionFlags mask,
 345                                                           CFOptionFlags flagsToSkip,
 346                                                           CFErrorRef *error)
 347  {
 348      CFMutableDictionaryRef dict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
 349      SecDbForEachAttrWithMask(item->class, desc, mask) {
 350          if((desc->flags & flagsToSkip) != 0) {
 351              break;
 352          }
 353  
 354          CFTypeRef value = SecDbItemGetValue(item, desc, error);
 355          if (value) {
 356              if (!CFEqual(kCFNull, value)) {
 357                  CFDictionarySetValue(dict, desc->name, value);
 358              } else if (desc->flags & kSecDbNotNullFlag) {
 359                  SecError(errSecDecode, error, CFSTR("attribute %@ has NULL value"), desc->name);
 360                  secerror("%@", error ? *error : (CFErrorRef)CFSTR("error == NULL"));
 361                  CFReleaseNull(dict);
 362                  break;
 363              }
 364          } else {
 365              CFReleaseNull(dict);
 366              break;
 367          }
 368      }
 369      return dict;
 370  }
 371  
 372  void SecDbItemSetCredHandle(SecDbItemRef item, CFTypeRef cred_handle) {
 373      CFRetainAssign(item->credHandle, cred_handle);
 374  }
 375  
 376  void SecDbItemSetCallerAccessGroups(SecDbItemRef item, CFArrayRef caller_access_groups) {
 377      CFRetainAssign(item->callerAccessGroups, caller_access_groups);
 378  }
 379  
 380  CFDataRef SecDbItemCopyEncryptedDataToBackup(SecDbItemRef item, uint64_t handle, CFErrorRef *error) {
 381      CFDataRef edata = NULL;
 382      keybag_handle_t keybag = (keybag_handle_t)handle;
 383      CFMutableDictionaryRef attributes = SecDbItemCopyPListWithMask(item, kSecDbInCryptoDataFlag, error);
 384      CFMutableDictionaryRef auth_attributes = SecDbItemCopyPListWithMask(item, kSecDbInAuthenticatedDataFlag, error);
 385      if (attributes || auth_attributes) {
 386          SecAccessControlRef access_control = SecDbItemCopyAccessControl(item, error);
 387          if (access_control) {
 388              if (ks_encrypt_data_legacy(keybag, access_control, item->credHandle, attributes, auth_attributes, &edata, false, error)) {
 389                  item->_edataState = kSecDbItemEncrypting;
 390              } else {
 391                  seccritical("ks_encrypt_data (db): failed: %@", error ? *error : (CFErrorRef)CFSTR(""));
 392              }
 393              CFRelease(access_control);
 394          }
 395          CFReleaseNull(attributes);
 396          CFReleaseNull(auth_attributes);
 397      }
 398  
 399      return edata;
 400  }
 401  
 402  bool SecDbItemEnsureDecrypted(SecDbItemRef item, bool decryptSecretData, CFErrorRef *error) {
 403  
 404      // If we haven't yet decrypted the item, make sure we do so now
 405      bool result = true;
 406      if (item->_edataState == kSecDbItemEncrypted || (decryptSecretData && item->_edataState == kSecDbItemSecretEncrypted)) {
 407          const SecDbAttr *attr = SecDbClassAttrWithKind(item->class, kSecDbEncryptedDataAttr, error);
 408          if (attr) {
 409              CFDataRef edata = SecDbItemGetCachedValue(item, attr);
 410              if (!edata)
 411                  return SecError(errSecInternal, error, CFSTR("state= encrypted but edata is NULL"));
 412              // Decrypt calls set value a bunch of times which clears our edata and changes our state.
 413              item->_edataState = kSecDbItemDecrypting;
 414              result = SecDbItemDecrypt(item, decryptSecretData, edata, error);
 415              if (result)
 416                  item->_edataState = decryptSecretData ? kSecDbItemClean : kSecDbItemSecretEncrypted;
 417              else
 418                  item->_edataState = kSecDbItemEncrypted;
 419          }
 420      }
 421      return result;
 422  }
 423  
 424  // Only called if cached value is not found.
 425  static CFTypeRef SecDbItemCopyValue(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error) {
 426      if (attr->copyValue) {
 427          return attr->copyValue(item, attr, error);
 428      }
 429  
 430      CFTypeRef value = NULL;
 431      switch (attr->kind) {
 432              // These have an explicit copyValue; here to shut up compiler
 433          case kSecDbSHA1Attr:
 434          case kSecDbEncryptedDataAttr:
 435          case kSecDbPrimaryKeyAttr:
 436              value = NULL;
 437              break;
 438          case kSecDbAccessAttr:
 439          case kSecDbStringAttr:
 440          case kSecDbBlobAttr:
 441          case kSecDbAccessControlAttr:
 442              if (attr->flags & kSecDbNotNullFlag) {
 443                  if (attr->flags & kSecDbDefault0Flag) {
 444                      value = CFSTR("0");
 445                      break;
 446                  } else if (attr->kind != kSecDbBlobAttr && attr->flags & kSecDbDefaultEmptyFlag) {
 447                      // blob drops through to data everything else is empty string
 448                      value = CFSTR("");
 449                      break;
 450                  }
 451              }
 452              //DROPTHROUGH
 453          case kSecDbDataAttr:
 454              if (attr->flags & kSecDbNotNullFlag && attr->flags & kSecDbDefaultEmptyFlag) {
 455                  value = CFDataCreate(CFGetAllocator(item), NULL, 0);
 456              } else {
 457                  value = kCFNull;
 458              }
 459              break;
 460          case kSecDbUUIDAttr:
 461              value = CFDataCreate(CFGetAllocator(item), NULL, 0);
 462              break;
 463          case kSecDbNumberAttr:
 464          case kSecDbSyncAttr:
 465          case kSecDbTombAttr:
 466              if (attr->flags & kSecDbNotNullFlag) {
 467                  int32_t zero = 0;
 468                  value = CFNumberCreate(CFGetAllocator(item), kCFNumberSInt32Type, &zero);
 469              } else {
 470                  value = kCFNull;
 471              }
 472              break;
 473          case kSecDbDateAttr:
 474              if (attr->flags & kSecDbNotNullFlag && attr->flags & kSecDbDefault0Flag) {
 475                  value = CFDateCreate(kCFAllocatorDefault, 0.0);
 476              } else {
 477                  value = kCFNull;
 478              }
 479              break;
 480          case kSecDbRowIdAttr:
 481              if (attr->flags & kSecDbNotNullFlag) {
 482                  // No can do, error?
 483              }
 484              value = kCFNull;
 485              break;
 486          case kSecDbCreationDateAttr:
 487          case kSecDbModificationDateAttr:
 488              value = CFDateCreate(CFGetAllocator(item), CFAbsoluteTimeGetCurrent());
 489              break;
 490          case kSecDbUTombAttr:
 491              value = kCFNull;
 492              break;
 493      }
 494  
 495      return value;
 496  }
 497  
 498  // SecDbItemGetValue will return kCFNull if there is no value for an attribute and this was not
 499  // an error.  It will return NULL and optionally set *error if there was an error computing an
 500  // attribute, or if a required attribute was missing a value and had no known way to compute
 501  // it's value.
 502  CFTypeRef SecDbItemGetValue(SecDbItemRef item, const SecDbAttr *desc, CFErrorRef *error) {
 503      // Propagate chained errors
 504      if (!desc)
 505          return NULL;
 506  
 507      if (desc->flags & kSecDbInCryptoDataFlag || desc->flags & kSecDbInAuthenticatedDataFlag || desc->flags & kSecDbReturnDataFlag) {
 508          if (!SecDbItemEnsureDecrypted(item, desc->flags & kSecDbReturnDataFlag, error))
 509              return NULL;
 510      }
 511  
 512      CFTypeRef value = SecDbItemGetCachedValue(item, desc);
 513      if (!value) {
 514          value = SecDbItemCopyValue(item, desc, error);
 515          if (value) {
 516              if (CFEqual(kCFNull, value)) {
 517                  CFRelease(value); // This is redundant but it shuts clang's static analyzer up.
 518                  value = kCFNull;
 519              } else {
 520                  SecDbItemSetValue(item, desc, value, error);
 521                  CFRelease(value);
 522                  value = SecDbItemGetCachedValue(item, desc);
 523              }
 524          }
 525      }
 526      return value;
 527  }
 528  
 529  CFTypeRef SecDbItemGetValueKind(SecDbItemRef item, SecDbAttrKind descKind, CFErrorRef *error) {
 530      CFTypeRef result = NULL;
 531  
 532      const SecDbClass * itemClass = SecDbItemGetClass(item);
 533      const SecDbAttr * desc = SecDbClassAttrWithKind(itemClass, descKind, error);
 534  
 535      if (desc) {
 536          result = SecDbItemGetValue(item, desc, error);
 537      }
 538  
 539      return result;
 540  }
 541  
 542  
 543  // Similar as SecDbItemGetValue, but if attr represents attribute stored into DB field as hash, returns
 544  // hashed value for the attribute.
 545  static CFTypeRef SecDbItemCopyValueForDb(SecDbItemRef item, const SecDbAttr *desc, CFErrorRef *error) {
 546      CFTypeRef value = NULL;
 547      CFStringRef hash_name = NULL;
 548      hash_name = SecDbAttrGetHashName(desc);
 549      if ((desc->flags & kSecDbSHA1ValueInFlag) && (desc->flags & kSecDbInFlag)) {
 550          value = CFRetainSafe(CFDictionaryGetValue(item->attributes, hash_name));
 551      }
 552  
 553      if (value == NULL) {
 554          require_quiet(value = SecDbItemGetValue(item, desc, error), out);
 555          require_action_quiet(value = SecDbAttrCopyValueForDb(desc, value, error), out, CFReleaseNull(value));
 556          if ((desc->flags & kSecDbSHA1ValueInFlag) != 0) {
 557              CFDictionarySetValue(item->attributes, hash_name, value);
 558          }
 559      }
 560  
 561  out:
 562      return value;
 563  }
 564  
 565  static bool SecDbItemGetBoolValue(SecDbItemRef item, const SecDbAttr *desc, bool *bvalue, CFErrorRef *error) {
 566      CFTypeRef value = SecDbItemGetValue(item, desc, error);
 567      if (!value)
 568          return false;
 569      char cvalue;
 570      *bvalue = (isNumber(value) && CFNumberGetValue(value, kCFNumberCharType, &cvalue) && cvalue == 1);
 571      return true;
 572  }
 573  
 574  static void SecDbItemAppendAttributeToDescription(SecDbItemRef item, const SecDbAttr *attr, CFMutableStringRef mdesc)
 575  {
 576      // In non-debug builds, the following attributes aren't very useful.
 577  #ifndef DEBUG
 578      if (CFEqual(CFSTR("data"), attr->name)||
 579          CFEqual(CFSTR("v_pk"), attr->name)) {
 580          return;
 581      }
 582  #endif
 583  
 584      CFTypeRef value = SecDbItemGetValue(item, attr, NULL);
 585      if (value && value != kCFNull) {
 586          CFStringAppend(mdesc, CFSTR(","));
 587          CFStringAppend(mdesc, attr->name);
 588          CFStringAppend(mdesc, CFSTR("="));
 589          if (CFEqual(CFSTR("data"), attr->name)) {
 590              CFStringAppendEncryptedData(mdesc, value);
 591          } else if (CFEqual(CFSTR("v_Data"), attr->name)) {
 592              CFStringAppend(mdesc, CFSTR("<?>"));
 593          } else if (isData(value)) {
 594              CFStringAppendHexData(mdesc, value);
 595          } else {
 596              CFStringAppendFormat(mdesc, 0, CFSTR("%@"), value);
 597          }
 598      }
 599  }
 600  
 601  static CFStringRef SecDbItemCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
 602      CFStringRef desc;
 603      if (isDictionary(formatOptions) && CFDictionaryContainsKey(formatOptions, kSecDebugFormatOption)) {
 604          SecDbItemRef item = (SecDbItemRef)cf;
 605          CFMutableStringRef mdesc = CFStringCreateMutable(CFGetAllocator(cf), 0);
 606          CFStringAppendFormat(mdesc, NULL, CFSTR("<%@"), item->class->name);
 607  
 608          // First, the primary key attributes
 609          SecDbForEachAttrWithMask(item->class, attr, kSecDbPrimaryKeyFlag) {
 610              SecDbItemAppendAttributeToDescription(item, attr, mdesc);
 611          }
 612  
 613          CFStringAppend(mdesc, CFSTR(", |otherAttr"));
 614          // tombstone values are very important, and should print next
 615          SecDbForEachAttr(item->class, attr) {
 616              if(CFEqualSafe(CFSTR("tomb"), attr->name)) {
 617                  SecDbItemAppendAttributeToDescription(item, attr, mdesc);
 618              }
 619          }
 620  
 621          // And finally, everything else
 622          SecDbForEachAttr(item->class, attr) {
 623              if((attr->flags & kSecDbPrimaryKeyFlag) != 0) {
 624                  continue;
 625              }
 626              if(CFEqualSafe(CFSTR("tomb"), attr->name)) {
 627                  continue;
 628              }
 629              SecDbItemAppendAttributeToDescription(item, attr, mdesc);
 630          }
 631          CFStringAppend(mdesc, CFSTR(">"));
 632          desc = mdesc;
 633      } else {
 634          SecDbItemRef item = (SecDbItemRef)cf;
 635          const UInt8 zero4[4] = {};
 636          const UInt8 *pk = &zero4[0], *sha1 = &zero4[0];
 637          char sync = 0;
 638          char tomb = 0;
 639          SInt64 rowid = 0;
 640          CFStringRef access = NULL;
 641          uint8_t mdatbuf[32] = {};
 642          uint8_t *mdat = &mdatbuf[0];
 643          CFMutableStringRef attrs = CFStringCreateMutable(kCFAllocatorDefault, 0);
 644          CFStringRef agrp = NULL;
 645          CFBooleanRef utomb = NULL;
 646  
 647          SecDbForEachAttr(item->class, attr) {
 648              CFTypeRef value;
 649              switch (attr->kind) {
 650                  case kSecDbBlobAttr:
 651                  case kSecDbDataAttr:
 652                  case kSecDbStringAttr:
 653                  case kSecDbNumberAttr:
 654                  case kSecDbDateAttr:
 655                  case kSecDbEncryptedDataAttr:
 656                      if (attr->flags & (kSecDbReturnAttrFlag | kSecDbReturnDataFlag) && (value = SecDbItemGetValue(item, attr, NULL)) && !CFEqual(value, kCFNull)) {
 657                          if (isString(value) && CFEqual(attr->name, kSecAttrAccessGroup)) {
 658                              agrp = value;
 659                          } else {
 660                              // We don't log these, just record that we saw the attribute.
 661                              CFStringAppend(attrs, CFSTR(","));
 662                              CFStringAppend(attrs, attr->name);
 663                          }
 664                      }
 665                      break;
 666                  case kSecDbUUIDAttr:
 667                      if ((value = SecDbItemGetValue(item, attr, NULL))) {
 668                          if (CFEqual(attr->name, kSecAttrMultiUser)) {
 669                              if (isData(value)) {
 670                                  CFStringAppend(attrs, CFSTR(","));
 671                                  if (CFDataGetLength(value)) {
 672                                      CFStringAppendHexData(attrs, value);
 673                                  } else {
 674                                      CFStringAppend(attrs, attr->name);
 675                                  }
 676                              }
 677                          }
 678                      }
 679                      break;
 680                  case kSecDbCreationDateAttr:
 681                      // We don't care about this and every object has one.
 682                      break;
 683                  case kSecDbModificationDateAttr:
 684                      value = SecDbItemGetValue(item, attr, NULL);
 685                      if (isDate(value))
 686                          mdat = der_encode_generalizedtime_body(CFDateGetAbsoluteTime(value), NULL, mdat, &mdatbuf[31]);
 687                      break;
 688                  case kSecDbSHA1Attr:
 689                      value = SecDbItemGetValue(item, attr, NULL);
 690                      if (isData(value) && CFDataGetLength(value) >= (CFIndex)sizeof(zero4))
 691                          sha1 = CFDataGetBytePtr(value);
 692                      break;
 693                  case kSecDbRowIdAttr:
 694                      value = SecDbItemGetValue(item, attr, NULL);
 695                      if (isNumber(value))
 696                          CFNumberGetValue(value, kCFNumberSInt64Type, &rowid);
 697                      break;
 698                  case kSecDbPrimaryKeyAttr:
 699                      value = SecDbItemGetValue(item, attr, NULL);
 700                      if (isData(value))
 701                          pk = CFDataGetBytePtr(value);
 702                      break;
 703                  case kSecDbSyncAttr:
 704                      value = SecDbItemGetValue(item, attr, NULL);
 705                      if (isNumber(value))
 706                          CFNumberGetValue(value, kCFNumberCharType, &sync);
 707                      break;
 708                  case kSecDbTombAttr:
 709                      value = SecDbItemGetValue(item, attr, NULL);
 710                      if (isNumber(value))
 711                          CFNumberGetValue(value, kCFNumberCharType, &tomb);
 712                      break;
 713                  case kSecDbAccessAttr:
 714                      value = SecDbItemGetValue(item, attr, NULL);
 715                      if (isString(value))
 716                          access = value;
 717                      break;
 718                  case kSecDbUTombAttr:
 719                      value = SecDbItemGetValue(item, attr, NULL);
 720                      if (isBoolean(value))
 721                          utomb = value;
 722                  case kSecDbAccessControlAttr:
 723                      /* TODO: Add formatting of ACLs. */
 724                      break;
 725              }
 726          }
 727  
 728          desc = CFStringCreateWithFormat(CFGetAllocator(cf), NULL,
 729              CFSTR(
 730                    "%s,"
 731                    "%@,"
 732                    "%02X%02X%02X%02X,"
 733                    "%s,"
 734                    "%@,"
 735                    "%@,"
 736                    "%"PRId64
 737                    "%@,"
 738                    "%s,"
 739                    "%s"
 740                    "%02X%02X%02X%02X"),
 741              tomb ? "T" : "O",
 742              item->class->name,
 743              pk[0], pk[1], pk[2], pk[3],
 744              sync ? "S" : "L",
 745              access,
 746              agrp,
 747              rowid,
 748              attrs,
 749              mdat,
 750              utomb ? (CFEqual(utomb, kCFBooleanFalse) ? "F," : "T,") : "",
 751              sha1[0], sha1[1], sha1[2], sha1[3]);
 752          CFReleaseSafe(attrs);
 753      }
 754  
 755      return desc;
 756  }
 757  
 758  static void SecDbItemDestroy(CFTypeRef cf) {
 759      SecDbItemRef item = (SecDbItemRef)cf;
 760      CFReleaseSafe(item->attributes);
 761      CFReleaseSafe(item->credHandle);
 762      CFReleaseSafe(item->callerAccessGroups);
 763      CFReleaseSafe(item->cryptoOp);
 764  }
 765  
 766  static CFHashCode SecDbItemHash(CFTypeRef cf) {
 767      SecDbItemRef item = (SecDbItemRef)cf;
 768      CFDataRef digest = SecDbItemGetSHA1(item, NULL);
 769      CFHashCode code;
 770      const UInt8 *p = CFDataGetBytePtr(digest);
 771      // Read first 8 bytes of digest in order
 772      code = p[0] + ((p[1] + ((p[2] + ((p[3] + ((p[4] + ((p[5] + ((p[6] + (p[7] << 8)) << 8)) << 8)) << 8)) << 8)) << 8)) << 8);
 773      return code;
 774  }
 775  
 776  static Boolean SecDbItemCompare(CFTypeRef cf1, CFTypeRef cf2) {
 777      SecDbItemRef item1 = (SecDbItemRef)cf1;
 778      SecDbItemRef item2 = (SecDbItemRef)cf2;
 779      CFDataRef digest1 = NULL;
 780      CFDataRef digest2 = NULL;
 781      if (item1)
 782          digest1 = SecDbItemGetSHA1(item1, NULL);
 783      if (item2)
 784          digest2 = SecDbItemGetSHA1(item2, NULL);
 785      Boolean equal = CFEqual(digest1, digest2);
 786      return equal;
 787  }
 788  
 789  CFGiblisWithHashFor(SecDbItem)
 790  
 791  static SecDbItemRef SecDbItemCreate(CFAllocatorRef allocator, const SecDbClass *class, keybag_handle_t keybag) {
 792      SecDbItemRef item = CFTypeAllocate(SecDbItem, struct SecDbItem, allocator);
 793      item->class = class;
 794      item->attributes = CFDictionaryCreateMutableForCFTypes(allocator);
 795      item->keybag = keybag;
 796      item->_edataState = kSecDbItemDirty;
 797      item->cryptoOp = kAKSKeyOpDecrypt;
 798  
 799      return item;
 800  }
 801  
 802  const SecDbClass *SecDbItemGetClass(SecDbItemRef item) {
 803      return item->class;
 804  }
 805  
 806  keybag_handle_t SecDbItemGetKeybag(SecDbItemRef item) {
 807      return item->keybag;
 808  }
 809  
 810  bool SecDbItemSetKeybag(SecDbItemRef item, keybag_handle_t keybag, CFErrorRef *error) {
 811      if (!SecDbItemEnsureDecrypted(item, true, error))
 812          return false;
 813      if (item->keybag != keybag) {
 814          item->keybag = keybag;
 815          if (item->_edataState == kSecDbItemClean) {
 816              SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbEncryptedDataAttr, NULL), kCFNull, NULL);
 817          }
 818      }
 819  
 820      return true;
 821  }
 822  
 823  bool SecDbItemSetValue(SecDbItemRef item, const SecDbAttr *desc, CFTypeRef value, CFErrorRef *error) {
 824      // Propagate chained errors.
 825      if (!desc)
 826          return false;
 827  
 828      if (!value)
 829          value = kCFNull;
 830  
 831      if (desc->setValue)
 832          return desc->setValue(item, desc, value, error);
 833  
 834      if (desc->flags & kSecDbInCryptoDataFlag || desc->flags & kSecDbInAuthenticatedDataFlag) {
 835          if (!SecDbItemEnsureDecrypted(item, true, error)) {
 836              return false;
 837          }
 838      }
 839  
 840      bool changed = false;
 841      CFTypeRef attr = NULL;
 842      switch (desc->kind) {
 843          case kSecDbPrimaryKeyAttr:
 844          case kSecDbDataAttr:
 845              attr = copyData(value);
 846              break;
 847          case kSecDbEncryptedDataAttr:
 848              attr = copyData(value);
 849              if (attr) {
 850                  if (item->_edataState == kSecDbItemEncrypting)
 851                      item->_edataState = kSecDbItemClean;
 852                  else
 853                      item->_edataState = kSecDbItemEncrypted;
 854              } else if (!value || CFEqual(kCFNull, value)) {
 855                  item->_edataState = kSecDbItemDirty;
 856              }
 857              break;
 858          case kSecDbBlobAttr:
 859          case kSecDbAccessControlAttr:
 860              attr = copyBlob(value);
 861              break;
 862          case kSecDbDateAttr:
 863          case kSecDbCreationDateAttr:
 864          case kSecDbModificationDateAttr:
 865              attr = copyDate(value);
 866              break;
 867          case kSecDbNumberAttr:
 868          case kSecDbSyncAttr:
 869          case kSecDbTombAttr:
 870          case kSecDbRowIdAttr:
 871              attr = copyNumber(value);
 872              break;
 873          case kSecDbAccessAttr:
 874          case kSecDbStringAttr:
 875              attr = copyString(value);
 876              break;
 877          case kSecDbSHA1Attr:
 878              attr = copySHA1(value);
 879              break;
 880          case kSecDbUTombAttr:
 881              attr = CFRetainSafe(asBoolean(value, NULL));
 882              break;
 883          case kSecDbUUIDAttr:
 884              attr = copyUUID(value);
 885              break;
 886      }
 887  
 888      if (attr) {
 889          CFTypeRef ovalue = CFDictionaryGetValue(item->attributes, desc->name);
 890          changed = (!ovalue || !CFEqual(ovalue, attr));
 891          CFDictionarySetValue(item->attributes, desc->name, attr);
 892          CFRelease(attr);
 893      } else {
 894          if (value && !CFEqual(kCFNull, value)) {
 895              SecError(errSecItemInvalidValue, error, CFSTR("attribute %@: value: %@ failed to convert"), desc->name, value);
 896              return false;
 897          }
 898          CFTypeRef ovalue = CFDictionaryGetValue(item->attributes, desc->name);
 899          changed = (ovalue && !CFEqual(ovalue, kCFNull));
 900          CFDictionaryRemoveValue(item->attributes, desc->name);
 901      }
 902  
 903      if (changed) {
 904          if (desc->flags & kSecDbInHashFlag)
 905              SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbSHA1Attr, NULL), kCFNull, NULL);
 906          if (desc->flags & kSecDbPrimaryKeyFlag)
 907              SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbPrimaryKeyAttr, NULL), kCFNull, NULL);
 908          if ((desc->flags & kSecDbInCryptoDataFlag || desc->flags & kSecDbInAuthenticatedDataFlag) && (item->_edataState == kSecDbItemClean || (item->_edataState == kSecDbItemSecretEncrypted && (desc->flags & kSecDbReturnDataFlag) == 0)))
 909              SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbEncryptedDataAttr, NULL), kCFNull, NULL);
 910          if (desc->flags & kSecDbSHA1ValueInFlag)
 911              CFDictionaryRemoveValue(item->attributes, SecDbAttrGetHashName(desc));
 912      }
 913  
 914      return true;
 915  }
 916  
 917  bool SecDbItemSetValues(SecDbItemRef item, CFDictionaryRef values, CFErrorRef *error) {
 918      SecDbForEachAttr(item->class, attr) {
 919          CFTypeRef value = CFDictionaryGetValue(values, attr->name);
 920          if (value && !SecDbItemSetValue(item, attr, value, error))
 921              return false;
 922      }
 923      return true;
 924  }
 925  
 926  bool SecDbItemSetValueWithName(SecDbItemRef item, CFStringRef name, CFTypeRef value, CFErrorRef *error) {
 927      SecDbForEachAttr(item->class, attr) {
 928          if (CFEqual(attr->name, name)) {
 929              return SecDbItemSetValue(item, attr, value, error);
 930          }
 931      }
 932      return false;
 933  }
 934  
 935  bool SecItemPreserveAttribute(SecDbItemRef target, SecDbItemRef source, const SecDbAttr* attr) {
 936      CFErrorRef cferror = nil;
 937      CFTypeRef v = SecDbItemGetValue(source, attr, &cferror);
 938      if(cferror) {
 939          secnotice("secitem", "Merging: unable to get attribute (%@) : %@", attr->name, cferror);
 940          CFReleaseNull(cferror);
 941          return false;
 942      }
 943      if(!v || CFEqualSafe(v, kCFNull)) {
 944          return true;
 945      }
 946      secnotice("secitem", "Preserving existing data for %@", attr->name);
 947      SecDbItemSetValue(target, attr, v, &cferror);
 948      if(cferror) {
 949          secnotice("secitem", "Unable to set attribute (%@) : %@", attr->name, cferror);
 950          CFReleaseNull(cferror);
 951          return false;
 952      }
 953      return true;
 954  }
 955  
 956  
 957  bool SecDbItemSetAccessControl(SecDbItemRef item, SecAccessControlRef access_control, CFErrorRef *error) {
 958      bool ok = true;
 959      if (item->_edataState == kSecDbItemClean)
 960          ok = SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbEncryptedDataAttr, error), kCFNull, error);
 961      if (ok && access_control) { //added check for access_control because ks_decrypt_data can leave NULL in access_control in case of error
 962          item->_edataState = kSecDbItemDirty;
 963          CFDataRef data = SecAccessControlCopyData(access_control);
 964          ok = SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbAccessControlAttr, error), data, error);
 965          CFRelease(data);
 966      }
 967      return ok;
 968  }
 969  
 970  SecDbItemRef SecDbItemCreateWithAttributes(CFAllocatorRef allocator, const SecDbClass *class, CFDictionaryRef attributes, keybag_handle_t keybag, CFErrorRef *error) {
 971      SecDbItemRef item = SecDbItemCreate(kCFAllocatorDefault, class, keybag);
 972      if (item && !SecDbItemSetValues(item, attributes, error))
 973          CFReleaseNull(item);
 974      return item;
 975  }
 976  
 977  static CFTypeRef
 978  SecDbColumnCopyValueWithAttr(CFAllocatorRef allocator, sqlite3_stmt *stmt, const SecDbAttr *attr, int col, CFErrorRef *error) {
 979      CFTypeRef value = NULL;
 980      switch (attr->kind) {
 981          case kSecDbDateAttr:
 982          case kSecDbCreationDateAttr:
 983          case kSecDbModificationDateAttr:
 984              value = SecDbColumnCopyDate(allocator, stmt, col, error);
 985              break;
 986          case kSecDbBlobAttr:
 987          case kSecDbNumberAttr:
 988              switch (sqlite3_column_type(stmt, col)) {
 989                  case SQLITE_INTEGER:
 990                      value = SecDbColumnCopyNumber(allocator, stmt, col, error);
 991                      break;
 992                  case SQLITE_FLOAT:
 993                      value = SecDbColumnCopyDouble(allocator, stmt, col, error);
 994                      break;
 995                  case SQLITE_TEXT:
 996                      value = SecDbColumnCopyString(allocator, stmt, col, error,
 997                                                    attr->flags);
 998                      break;
 999                  case SQLITE_BLOB:
1000                      value = SecDbColumnCopyData(allocator, stmt, col, error);
1001                      break;
1002                  case SQLITE_NULL:
1003                      value = kCFNull;
1004                      break;
1005              }
1006              break;
1007          case kSecDbAccessAttr:
1008          case kSecDbStringAttr:
1009              value = SecDbColumnCopyString(allocator, stmt, col, error,
1010                                            attr->flags);
1011              break;
1012          case kSecDbDataAttr:
1013          case kSecDbUUIDAttr:
1014          case kSecDbSHA1Attr:
1015          case kSecDbPrimaryKeyAttr:
1016          case kSecDbEncryptedDataAttr:
1017              value = SecDbColumnCopyData(allocator, stmt, col, error);
1018              break;
1019          case kSecDbSyncAttr:
1020          case kSecDbTombAttr:
1021              value = SecDbColumnCopyNumber(allocator, stmt, col, error);
1022              break;
1023          case kSecDbRowIdAttr:
1024              value = SecDbColumnCopyNumber64(allocator, stmt, col, error);
1025              break;
1026          case kSecDbAccessControlAttr:
1027          case kSecDbUTombAttr:
1028              /* This attributes does not have any database column associated, exists only inside encrypted blob as metadata. */
1029              break;
1030      }
1031      return value;
1032  }
1033  
1034  SecDbItemRef SecDbItemCreateWithStatement(CFAllocatorRef allocator, const SecDbClass *class, sqlite3_stmt *stmt, keybag_handle_t keybag, CFErrorRef *error, bool (^return_attr)(const SecDbAttr *attr)) {
1035      SecDbItemRef item = SecDbItemCreate(allocator, class, keybag);
1036      int col = 0;
1037      SecDbForEachAttr(class, attr) {
1038          if (return_attr(attr)) {
1039              CFTypeRef value = SecDbColumnCopyValueWithAttr(allocator, stmt, attr, col++, error);
1040              require_action_quiet(value, errOut, CFReleaseNull(item));
1041  
1042              CFDictionarySetValue(item->attributes, SecDbAttrGetHashName(attr), value);
1043              CFRelease(value);
1044          }
1045  
1046          const SecDbAttr *data_attr = SecDbClassAttrWithKind(class, kSecDbEncryptedDataAttr, NULL);
1047          if (data_attr != NULL && CFDictionaryGetValue(item->attributes, data_attr->name) != NULL) {
1048              item->_edataState = kSecDbItemEncrypted;
1049          }
1050      }
1051  
1052  errOut:
1053      return item;
1054  }
1055  
1056  SecDbItemRef SecDbItemCreateWithEncryptedData(CFAllocatorRef allocator, const SecDbClass *class,
1057                                                CFDataRef edata, keybag_handle_t keybag, CFErrorRef *error) {
1058      SecDbItemRef item = SecDbItemCreate(allocator, class, keybag);
1059      const SecDbAttr *edata_attr = SecDbClassAttrWithKind(class, kSecDbEncryptedDataAttr, error);
1060      if (edata_attr) {
1061          if (!SecDbItemSetValue(item, edata_attr, edata, error))
1062              CFReleaseNull(item);
1063      }
1064      return item;
1065  }
1066  
1067  // TODO: Hack -- Replace with real filtering
1068  
1069  // Return true iff an item for which SecDbItemIsSyncable() already returns true should be part of the v2 view.
1070  bool SecDbItemInV2(SecDbItemRef item) {
1071      const SecDbClass *iclass = SecDbItemGetClass(item);
1072      return  (SecDbItemGetCachedValueWithName(item, kSecAttrSyncViewHint) == NULL &&
1073               (iclass == genp_class() || iclass == inet_class() || iclass == keys_class() || iclass == cert_class()));
1074  }
1075  
1076  // Return true iff an item for which SecDbItemIsSyncable() and SecDbItemInV2() already return true should be part of the v0 view.
1077  bool SecDbItemInV2AlsoInV0(SecDbItemRef item) {
1078      return  (SecDbItemGetCachedValueWithName(item, kSecAttrTokenID) == NULL && SecDbItemGetClass(item) != cert_class());
1079  }
1080  
1081  SecDbItemRef SecDbItemCopyWithUpdates(SecDbItemRef item, CFDictionaryRef updates, CFErrorRef *error) {
1082      SecDbItemRef new_item = SecDbItemCreate(CFGetAllocator(item), item->class, item->keybag);
1083      SecDbItemSetCredHandle(new_item, item->credHandle);
1084      SecDbForEachAttr(item->class, attr) {
1085          // Copy each attribute, except the mod date attribute (it will be reset to now when needed),
1086          // from the updates dict unless it's not there in which case we copy the attribute from the passed in item.
1087          if (attr->kind != kSecDbModificationDateAttr && attr->kind != kSecDbEncryptedDataAttr && attr->kind != kSecDbSHA1Attr && attr->kind != kSecDbPrimaryKeyAttr) {
1088              CFTypeRef value = NULL;
1089              if (CFDictionaryGetValueIfPresent(updates, attr->name, &value)) {
1090                  if (!value)
1091                      SecError(errSecParam, error, CFSTR("NULL value in dictionary"));
1092              } else {
1093                  value = SecDbItemGetValue(item, attr, error);
1094              }
1095              if (!value || !SecDbItemSetValue(new_item, attr, value, error)) {
1096                  CFReleaseNull(new_item);
1097                  break;
1098              }
1099          }
1100      }
1101      return new_item;
1102  }
1103  
1104  // Ensure that the date value of attr of new_item is greater than that of old_item.
1105  static bool SecDbItemMakeAttrYounger(SecDbItemRef new_item, SecDbItemRef old_item, const SecDbAttr *attr, CFErrorRef *error) {
1106      CFDateRef old_date = SecDbItemGetValue(old_item, attr, error);
1107      if (!old_date)
1108          return false;
1109      CFDateRef new_date = SecDbItemGetValue(new_item, attr, error);
1110      if (!new_date)
1111          return false;
1112      bool ok = true;
1113      if (CFDateCompare(new_date, old_date, NULL) != kCFCompareGreaterThan) {
1114          CFDateRef adjusted_date = CFDateCreate(kCFAllocatorDefault, CFDateGetAbsoluteTime(old_date) + 0.001);
1115          if (adjusted_date) {
1116              ok = SecDbItemSetValue(new_item, attr, adjusted_date, error);
1117              CFRelease(adjusted_date);
1118          }
1119      }
1120      return ok;
1121  }
1122  
1123  // Ensure that the mod date of new_item is greater than that of old_item.
1124  static bool SecDbItemMakeYounger(SecDbItemRef new_item, SecDbItemRef old_item, CFErrorRef *error) {
1125      const SecDbAttr *attr = SecDbClassAttrWithKind(new_item->class, kSecDbModificationDateAttr, error);
1126      return attr && SecDbItemMakeAttrYounger(new_item, old_item, attr, error);
1127  }
1128  
1129  static SecDbItemRef SecDbItemCopyTombstone(SecDbItemRef item, CFBooleanRef makeTombStone, bool tombstone_time_from_item, CFErrorRef *error) {
1130      SecDbItemRef new_item = SecDbItemCreate(CFGetAllocator(item), item->class, item->keybag);
1131      SecDbForEachAttr(item->class, attr) {
1132          if (attr->kind == kSecDbTombAttr) {
1133              // Set the tomb attr to true to indicate a tombstone.
1134              if (!SecDbItemSetValue(new_item, attr, kCFBooleanTrue, error)) {
1135                  CFReleaseNull(new_item);
1136                  break;
1137              }
1138          } else if (SecDbIsTombstoneDbUpdateAttr(attr)) {
1139              // Copy all primary key attributes and creation timestamps from the original item.
1140              CFTypeRef value = SecDbItemGetValue(item, attr, error);
1141              if (!value || (!CFEqual(kCFNull, value) && !SecDbItemSetValue(new_item, attr, value, error))) {
1142                  CFReleaseNull(new_item);
1143                  break;
1144              }
1145          } else if (attr->kind == kSecDbModificationDateAttr) {
1146              if(tombstone_time_from_item) {
1147                  SecItemPreserveAttribute(new_item, item, attr);
1148              }
1149  
1150              if (!SecDbItemMakeAttrYounger(new_item, item, attr, error)) {
1151                  CFReleaseNull(new_item);
1152                  break;
1153              }
1154          } else if (makeTombStone && attr->kind == kSecDbUTombAttr) {
1155              if (makeTombStone)
1156                  SecDbItemSetValue(new_item, attr, makeTombStone, error);
1157          }
1158      }
1159  
1160      return new_item;
1161  }
1162  
1163  bool SecDbItemIsEngineInternalState(SecDbItemRef itemObject) {
1164      // Only used for controlling logging
1165      // Use agrp=com.apple.security.sos, since it is not encrypted
1166      if (!itemObject) {
1167          return false;
1168      }
1169      const SecDbAttr *agrp = SecDbAttrWithKey(SecDbItemGetClass(itemObject), kSecAttrAccessGroup, NULL);
1170      CFTypeRef cfval = SecDbItemGetValue(itemObject, agrp, NULL);
1171      return cfval && CFStringCompareSafe(cfval, kSOSInternalAccessGroup, NULL) == kCFCompareEqualTo;
1172  }
1173  
1174  
1175  // MARK: -
1176  // MARK: SQL Construction helpers -- These should become private in the future
1177  
1178  void SecDbAppendElement(CFMutableStringRef sql, CFStringRef value, bool *needComma) {
1179      assert(needComma);
1180      if (*needComma) {
1181          CFStringAppend(sql, CFSTR(","));
1182      } else {
1183          *needComma = true;
1184      }
1185      CFStringAppend(sql, value);
1186  }
1187  
1188  static void SecDbAppendElementEquals(CFMutableStringRef sql, CFStringRef value, bool *needComma) {
1189      SecDbAppendElement(sql, value, needComma);
1190      CFStringAppend(sql, CFSTR("=?"));
1191  }
1192  
1193  /* Append AND is needWhere is NULL or *needWhere is false.  Append WHERE
1194   otherwise.  Upon return *needWhere will be false.  */
1195  void
1196  SecDbAppendWhereOrAnd(CFMutableStringRef sql, bool *needWhere) {
1197      if (!needWhere || !*needWhere) {
1198          CFStringAppend(sql, CFSTR(" AND "));
1199      } else {
1200          CFStringAppend(sql, CFSTR(" WHERE "));
1201          *needWhere = false;
1202      }
1203  }
1204  
1205  void
1206  SecDbAppendWhereOrAndEquals(CFMutableStringRef sql, CFStringRef col, bool *needWhere) {
1207      SecDbAppendWhereOrAnd(sql, needWhere);
1208      CFStringAppend(sql, col);
1209      CFStringAppend(sql, CFSTR("=?"));
1210  }
1211  
1212  void
1213  SecDbAppendWhereOrAndNotEquals(CFMutableStringRef sql, CFStringRef col, bool *needWhere) {
1214      SecDbAppendWhereOrAnd(sql, needWhere);
1215      CFStringAppend(sql, col);
1216      CFStringAppend(sql, CFSTR("!=?"));
1217  }
1218  
1219  static void SecDbAppendCountArgsAndCloseParen(CFMutableStringRef sql, CFIndex count) {
1220      bool needComma = false;
1221      while (count-- > 0)
1222          SecDbAppendElement(sql, CFSTR("?"), &needComma);
1223      CFStringAppend(sql, CFSTR(")"));
1224  }
1225  
1226  void
1227  SecDbAppendWhereOrAndIn(CFMutableStringRef sql, CFStringRef col, bool *needWhere, CFIndex count) {
1228      if (count == 1)
1229          return SecDbAppendWhereOrAndEquals(sql, col, needWhere);
1230      SecDbAppendWhereOrAnd(sql, needWhere);
1231      CFStringAppend(sql, col);
1232      CFStringAppend(sql, CFSTR(" IN ("));
1233      SecDbAppendCountArgsAndCloseParen(sql, count);
1234  }
1235  
1236  void
1237  SecDbAppendWhereOrAndNotIn(CFMutableStringRef sql, CFStringRef col, bool *needWhere, CFIndex count) {
1238      if (count == 1)
1239          return SecDbAppendWhereOrAndNotEquals(sql, col, needWhere);
1240      SecDbAppendWhereOrAnd(sql, needWhere);
1241      CFStringAppend(sql, col);
1242      CFStringAppend(sql, CFSTR(" NOT IN ("));
1243      SecDbAppendCountArgsAndCloseParen(sql, count);
1244  }
1245  
1246  static CFStringRef SecDbItemCopyInsertSQL(SecDbItemRef item, bool(^use_attr)(const SecDbAttr *attr)) {
1247      CFMutableStringRef sql = CFStringCreateMutable(CFGetAllocator(item), 0);
1248      CFStringAppend(sql, CFSTR("INSERT INTO "));
1249      CFStringAppend(sql, item->class->name);
1250      CFStringAppend(sql, CFSTR("("));
1251      bool needComma = false;
1252      CFIndex used_attr = 0;
1253      SecDbForEachAttr(item->class, attr) {
1254          if (use_attr(attr)) {
1255              ++used_attr;
1256              SecDbAppendElement(sql, attr->name, &needComma);
1257          }
1258      }
1259      CFStringAppend(sql, CFSTR(")VALUES(?"));
1260      while (used_attr-- > 1) {
1261          CFStringAppend(sql, CFSTR(",?"));
1262      }
1263      CFStringAppend(sql, CFSTR(")"));
1264      return sql;
1265  
1266  }
1267  
1268  static bool SecDbItemInsertBind(SecDbItemRef item, sqlite3_stmt *stmt, CFErrorRef *error, bool(^use_attr)(const SecDbAttr *attr)) {
1269      bool ok = true;
1270      int param = 0;
1271      SecDbForEachAttr(item->class, attr) {
1272          if (use_attr(attr)) {
1273              CFTypeRef value = SecDbItemCopyValueForDb(item, attr, error);
1274              ok = value && SecDbBindObject(stmt, ++param, value, error);
1275              CFReleaseSafe(value);
1276              if (!ok)
1277                  break;
1278          }
1279      }
1280      return ok;
1281  }
1282  
1283  sqlite3_int64 SecDbItemGetRowId(SecDbItemRef item, CFErrorRef *error) {
1284      sqlite3_int64 row_id = 0;
1285      const SecDbAttr *attr = SecDbClassAttrWithKind(item->class, kSecDbRowIdAttr, error);
1286      if (attr) {
1287          CFNumberRef number = SecDbItemGetValue(item, attr, error);
1288          if (!isNumber(number)|| !CFNumberGetValue(number, kCFNumberSInt64Type, &row_id))
1289              SecDbError(SQLITE_ERROR, error, CFSTR("rowid %@ is not a 64 bit number"), number);
1290      }
1291  
1292      return row_id;
1293  }
1294  
1295  static CFNumberRef SecDbItemCreateRowId(SecDbItemRef item, sqlite3_int64 rowid, CFErrorRef *error) {
1296      return CFNumberCreate(CFGetAllocator(item), kCFNumberSInt64Type, &rowid);
1297  }
1298  
1299  bool SecDbItemSetRowId(SecDbItemRef item, sqlite3_int64 rowid, CFErrorRef *error) {
1300      bool ok = true;
1301      const SecDbAttr *attr = SecDbClassAttrWithKind(item->class, kSecDbRowIdAttr, error);
1302      if (attr) {
1303          CFNumberRef value = SecDbItemCreateRowId(item, rowid, error);
1304          if (!value)
1305              return false;
1306  
1307          ok = SecDbItemSetValue(item, attr, value, error);
1308          CFRelease(value);
1309      }
1310      return ok;
1311  }
1312  
1313  bool SecDbItemClearRowId(SecDbItemRef item, CFErrorRef *error) {
1314      bool ok = true;
1315      const SecDbAttr *attr = SecDbClassAttrWithKind(item->class, kSecDbRowIdAttr, error);
1316      if (attr) {
1317          CFDictionaryRemoveValue(item->attributes, attr->name);
1318          //ok = SecDbItemSetValue(item, attr, kCFNull, error);
1319      }
1320      return ok;
1321  }
1322  
1323  static bool SecDbItemSetLastInsertRowId(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error) {
1324      sqlite3_int64 rowid = sqlite3_last_insert_rowid(SecDbHandle(dbconn));
1325      return SecDbItemSetRowId(item, rowid, error);
1326  }
1327  
1328  bool SecDbItemIsSyncableOrCorrupted(SecDbItemRef item) {
1329      bool is_syncable_or_corrupted = false;
1330      CFErrorRef localError = NULL;
1331      if (!SecDbItemGetBoolValue(item, SecDbClassAttrWithKind(item->class, kSecDbSyncAttr, &localError),
1332                                 &is_syncable_or_corrupted, &localError)) {
1333          is_syncable_or_corrupted = SecErrorGetOSStatus(localError) == errSecDecode;
1334      }
1335      CFReleaseSafe(localError);
1336      return is_syncable_or_corrupted;
1337  }
1338  
1339  bool SecDbItemIsSyncable(SecDbItemRef item) {
1340      bool is_syncable;
1341      if (SecDbItemGetBoolValue(item, SecDbClassAttrWithKind(item->class, kSecDbSyncAttr, NULL), &is_syncable, NULL))
1342          return is_syncable;
1343      return false;
1344  }
1345  
1346  bool SecDbItemSetSyncable(SecDbItemRef item, bool sync, CFErrorRef *error)
1347  {
1348      return SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbSyncAttr, error), sync ? kCFBooleanTrue : kCFBooleanFalse, error);
1349  }
1350  
1351  bool SecDbItemIsTombstone(SecDbItemRef item) {
1352      bool is_tomb;
1353      if (SecDbItemGetBoolValue(item, SecDbClassAttrWithKind(item->class, kSecDbTombAttr, NULL), &is_tomb, NULL))
1354          return is_tomb;
1355      return false;
1356  }
1357  
1358  CFDataRef SecDbItemGetPrimaryKey(SecDbItemRef item, CFErrorRef *error) {
1359      return SecDbItemGetValue(item, SecDbClassAttrWithKind(item->class, kSecDbPrimaryKeyAttr, error), error);
1360  }
1361  
1362  CFDataRef SecDbItemGetSHA1(SecDbItemRef item, CFErrorRef *error) {
1363      return SecDbItemGetValue(item, SecDbClassAttrWithKind(item->class, kSecDbSHA1Attr, error), error);
1364  }
1365  
1366  static SecDbQueryRef SecDbQueryCreateWithItemPrimaryKey(SecDbItemRef item, CFErrorRef *error) {
1367      CFMutableDictionaryRef dict = SecDbItemCopyPListWithMask(item, kSecDbPrimaryKeyFlag, error);
1368      if (!dict)
1369          return NULL;
1370  
1371      SecDbQueryRef query = query_create(item->class, NULL, NULL, NULL, error);
1372      if (query) {
1373          CFReleaseSafe(query->q_item);
1374          query->q_item = dict;
1375      }
1376      else
1377          CFRelease(dict);
1378  
1379      return query;
1380  }
1381  
1382  static bool SecDbItemIsCorrupt(SecDbItemRef item, bool *is_corrupt, CFErrorRef *error) {
1383      CFErrorRef localError = NULL;
1384      // Cache the storedSHA1 digest so we use the one from the db not the recomputed one for notifications.
1385      const struct SecDbAttr *sha1attr = SecDbClassAttrWithKind(item->class, kSecDbSHA1Attr, &localError);
1386      CFDataRef storedSHA1 = CFRetainSafe(SecDbItemGetValue(item, sha1attr, &localError));
1387      bool akpu = false;
1388      
1389      if (localError || !SecDbItemEnsureDecrypted(item, true, &localError)) {
1390          if (SecErrorGetOSStatus(localError) == errSecDecode) {
1391              // We failed to decrypt the item
1392              const SecDbAttr *desc = SecDbClassAttrWithKind(item->class, kSecDbAccessControlAttr, &localError);
1393              SecAccessControlRef accc = NULL;
1394              CFDataRef acccData = NULL;
1395  
1396              acccData = (CFDataRef)SecDbItemGetValue(item, desc, &localError);
1397              if (isData(acccData)) {
1398                  accc = SecAccessControlCreateFromData(CFGetAllocator(item), acccData, &localError);
1399              }
1400  
1401              if (accc && CFEqualSafe(SecAccessControlGetProtection(accc), kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly)) {
1402                  akpu = true;
1403                  secwarning("cannot decrypt item %@, item is irrecoverably lost with older passcode (error %@)", item, localError);
1404              } else {
1405                  secerror("error %@ reading item %@ (corrupted)", localError, item);
1406                  __security_simulatecrash(CFSTR("Corrupted item found in keychain"), __sec_exception_code_CorruptItem);
1407              }
1408              CFReleaseNull(localError);
1409              *is_corrupt = true;
1410          }
1411      }
1412  
1413      // Recompute sha1 hash attribute and compare with the cached one.
1414      CFDataRef computedSHA1 = SecDbItemCopyValue(item, sha1attr, &localError);
1415      if (storedSHA1 && computedSHA1 && !CFEqual(storedSHA1, computedSHA1)) {
1416          CFStringRef storedHex = CFDataCopyHexString(storedSHA1), computedHex = CFDataCopyHexString(computedSHA1);
1417          secerror("error %@ %@ != %@ item %@ (corrupted)", sha1attr->name, storedHex, computedHex, item);
1418          // Do not simulate crash for this condition.
1419          // The keychain hashes floating point numbers which causes many false positives, this is not fixable except by major surgery
1420          CFReleaseSafe(storedHex);
1421          CFReleaseSafe(computedHex);
1422          *is_corrupt = true;
1423      }
1424  
1425      // Sanity check that all attributes that must not be NULL actually aren't
1426      if (!localError) SecDbForEachAttr(item->class, attr) {
1427          if (attr->flags & (kSecDbInCryptoDataFlag | kSecDbInAuthenticatedDataFlag)) {
1428              CFTypeRef value = SecDbItemGetValue(item, attr, &localError);
1429              if (value) {
1430                  if (CFEqual(kCFNull, value) && attr->flags & kSecDbNotNullFlag) {
1431                      secerror("error attribute %@ has NULL value in item %@ (corrupted)", attr->name, item);
1432                      __security_simulatecrash(CFSTR("Corrupted item (attr NULL) found in keychain"), __sec_exception_code_CorruptItem);
1433                      *is_corrupt = true;
1434                      break;
1435                  }
1436              } else {
1437                  if (SecErrorGetOSStatus(localError) == errSecDecode) {
1438                      // We failed to decrypt the item
1439                      if (akpu) {
1440                          secwarning("attribute %@: %@ item %@ (item lost with older passcode)", attr->name, localError, item);
1441                      } else {
1442                          secerror("error attribute %@: %@ item %@ (corrupted)", attr->name, localError, item);
1443                          __security_simulatecrash(CFSTR("Corrupted item found in keychain"), __sec_exception_code_CorruptItem);
1444                      }
1445                      *is_corrupt = true;
1446                      CFReleaseNull(localError);
1447                  }
1448                  break;
1449              }
1450          }
1451      }
1452  
1453      CFReleaseSafe(computedSHA1);
1454      CFReleaseSafe(storedSHA1);
1455      return SecErrorPropagate(localError, error);
1456  }
1457  
1458  static void SecDbItemRecordUpdate(SecDbConnectionRef dbconn, SecDbItemRef deleted, SecDbItemRef inserted) {
1459      SecDbRecordChange(dbconn, deleted, inserted);
1460  }
1461  
1462  static bool SecDbItemDoInsert(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error) {
1463      bool (^use_attr)(const SecDbAttr *attr) = ^bool(const SecDbAttr *attr) {
1464          return (attr->flags & kSecDbInFlag);
1465      };
1466  
1467      if (!SecDbItemEnsureDecrypted(item, true, error)) {
1468          return false;
1469      }
1470  
1471      CFStringRef sql = SecDbItemCopyInsertSQL(item, use_attr);
1472      __block bool ok = sql;
1473      if (sql) {
1474          ok &= SecDbPrepare(dbconn, sql, error, ^(sqlite3_stmt *stmt) {
1475              ok = (SecDbItemInsertBind(item, stmt, error, use_attr) &&
1476                    SecDbStep(dbconn, stmt, error, NULL) &&
1477                    SecDbItemSetLastInsertRowId(item, dbconn, error));
1478          });
1479          CFRelease(sql);
1480      }
1481      if (ok) {
1482          secnotice("item", "inserted %@", item);
1483          SecDbItemRecordUpdate(dbconn, NULL, item);
1484      } else {
1485          if (SecDbItemIsEngineInternalState(item)) {
1486              secdebug ("item", "insert failed for item %@ with %@", item, error ? *error : NULL);
1487          } else {
1488              secnotice("item", "insert failed for item %@ with %@", item, error ? *error : NULL);
1489          }
1490      }
1491  
1492      return ok;
1493  }
1494  
1495  bool SecErrorIsSqliteDuplicateItemError(CFErrorRef error) {
1496      return error && CFErrorGetCode(error) == SQLITE_CONSTRAINT && CFEqual(kSecDbErrorDomain, CFErrorGetDomain(error));
1497  }
1498  
1499  bool SecDbItemInsertOrReplace(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error, void(^duplicate)(SecDbItemRef item, SecDbItemRef *replace)) {
1500      __block CFErrorRef localError = NULL;
1501      __block bool ok = SecDbItemDoInsert(item, dbconn, &localError);
1502      if (!ok && localError && CFErrorGetCode(localError) == SQLITE_CONSTRAINT && CFEqual(kSecDbErrorDomain, CFErrorGetDomain(localError))) {
1503          SecDbQueryRef query = SecDbQueryCreateWithItemPrimaryKey(item, error);
1504          if (query) {
1505              CFRetainAssign(query->q_use_cred_handle, item->credHandle);
1506              SecDbItemSelect(query, dbconn, error, NULL, ^bool(const SecDbAttr *attr) {
1507                  return attr->flags & kSecDbPrimaryKeyFlag;
1508              }, NULL, NULL, ^(SecDbItemRef old_item, bool *stop) {
1509                  bool is_corrupt = false;
1510                  ok = SecDbItemIsCorrupt(old_item, &is_corrupt, error);
1511                  SecDbItemRef replace = NULL;
1512                  if (is_corrupt) {
1513                      // If old_item is corrupted pretend it's not there and just replace it.
1514                      replace = item;
1515                      CFRetain(replace);
1516                      if(error)
1517                          CFReleaseNull(*error);  //item is corrupted and will be replaced, so drop the error
1518                  } else if (ok && duplicate) {
1519                      duplicate(old_item, &replace);
1520                  }
1521                  if (replace) {
1522                      const SecDbAttr *rowid_attr = SecDbClassAttrWithKind(old_item->class, kSecDbRowIdAttr, error);
1523                      CFNumberRef oldrowid = SecDbItemGetCachedValue(old_item, rowid_attr);
1524                      if (oldrowid) {
1525                          ok = SecDbItemSetValue(replace, rowid_attr, oldrowid, &localError);
1526                          if (ok && !is_corrupt) {
1527                              ok = SecDbItemMakeYounger(replace, old_item, error);
1528                          }
1529                          ok = ok && SecDbItemDoUpdate(old_item, replace, dbconn, &localError, ^bool (const SecDbAttr *attr) {
1530                              return attr->kind == kSecDbRowIdAttr;
1531                          });
1532                      } else {
1533                          ok = SecError(errSecInternal, &localError, CFSTR("no rowid for %@"), old_item);
1534                      }
1535                      CFRelease(replace);
1536                      if (ok)
1537                          CFReleaseNull(localError); // Clear the error, since we replaced the item.
1538                  }
1539              });
1540              SecDbItemSetCredHandle(item, query->q_use_cred_handle);
1541              ok &= query_destroy(query, error);
1542          }
1543      }
1544  
1545      return ok & SecErrorPropagate(localError, error); // Don't use && here!
1546  }
1547  
1548  bool SecDbItemInsert(SecDbItemRef item, SecDbConnectionRef dbconn, bool always_use_uuid_from_new_item, CFErrorRef *error) {
1549      return SecDbItemInsertOrReplace(item, dbconn, error, ^(SecDbItemRef old_item, SecDbItemRef *replace) {
1550          if (SecDbItemIsTombstone(old_item)) {
1551              CFRetain(item);
1552              *replace = item;
1553  
1554              // If the caller doesn't care about the UUID, then use old_item's UUID
1555              // Note: this will modify item!
1556              if(!always_use_uuid_from_new_item) {
1557                  SecDbForEachAttr(SecDbItemGetClass(item), attr) {
1558                      if(CFEqual(attr->name, v10itemuuid.name)) {
1559                          SecItemPreserveAttribute(item, old_item, attr);
1560                      }
1561                  }
1562              }
1563          }
1564      });
1565  }
1566  
1567  static CFStringRef SecDbItemCopyUpdateSQL(SecDbItemRef old_item, SecDbItemRef new_item, bool(^use_attr_in_where)(const SecDbAttr *attr)) {
1568      CFMutableStringRef sql = CFStringCreateMutable(CFGetAllocator(new_item), 0);
1569      CFStringAppend(sql, CFSTR("UPDATE "));
1570      CFStringAppend(sql, new_item->class->name);
1571      CFStringAppend(sql, CFSTR(" SET "));
1572      bool needComma = false;
1573      CFIndex used_attr = 0;
1574      SecDbForEachAttrWithMask(new_item->class, attr, kSecDbInFlag) {
1575          ++used_attr;
1576          SecDbAppendElementEquals(sql, attr->name, &needComma);
1577      }
1578  
1579      bool needWhere = true;
1580      SecDbForEachAttr(old_item->class, attr) {
1581          if (use_attr_in_where(attr)) {
1582              SecDbAppendWhereOrAndEquals(sql, attr->name, &needWhere);
1583          }
1584      }
1585  
1586      return sql;
1587  }
1588  
1589  static bool SecDbItemUpdateBind(SecDbItemRef old_item, SecDbItemRef new_item, sqlite3_stmt *stmt, CFErrorRef *error, bool(^use_attr_in_where)(const SecDbAttr *attr)) {
1590      bool ok = true;
1591      int param = 0;
1592      SecDbForEachAttrWithMask(new_item->class, attr, kSecDbInFlag) {
1593          CFTypeRef value = SecDbItemCopyValueForDb(new_item, attr, error);
1594          ok &= value && SecDbBindObject(stmt, ++param, value, error);
1595          CFReleaseSafe(value);
1596          if (!ok)
1597              break;
1598      }
1599      SecDbForEachAttr(old_item->class, attr) {
1600          if (use_attr_in_where(attr)) {
1601              CFTypeRef value = SecDbItemCopyValueForDb(old_item, attr, error);
1602              ok &= value && SecDbBindObject(stmt, ++param, value, error);
1603              CFReleaseSafe(value);
1604              if (!ok)
1605                  break;
1606          }
1607      }
1608      return ok;
1609  }
1610  
1611  // Primary keys are the same -- do an update
1612  bool SecDbItemDoUpdate(SecDbItemRef old_item, SecDbItemRef new_item, SecDbConnectionRef dbconn, CFErrorRef *error, bool (^use_attr_in_where)(const SecDbAttr *attr)) {
1613      CFStringRef sql = SecDbItemCopyUpdateSQL(old_item, new_item, use_attr_in_where);
1614      __block bool ok = sql;
1615      if (sql) {
1616          ok &= SecDbPrepare(dbconn, sql, error, ^(sqlite3_stmt *stmt) {
1617              ok = SecDbItemUpdateBind(old_item, new_item, stmt, error, use_attr_in_where) && SecDbStep(dbconn, stmt, error, NULL);
1618          });
1619          CFRelease(sql);
1620      }
1621      if (ok) {
1622          if (SecDbItemIsEngineInternalState(old_item)) {
1623              secdebug ("item", "replaced %@ in %@", old_item, dbconn);
1624              secdebug ("item", "    with %@ in %@", new_item, dbconn);
1625          } else {
1626              secnotice("item", "replaced %@ in %@", old_item, dbconn);
1627              secnotice("item", "    with %@ in %@", new_item, dbconn);
1628          }
1629          SecDbItemRecordUpdate(dbconn, old_item, new_item);
1630      }
1631      return ok;
1632  }
1633  
1634  static CFStringRef SecDbItemCopyDeleteSQL(SecDbItemRef item, bool(^use_attr_in_where)(const SecDbAttr *attr)) {
1635      CFMutableStringRef sql = CFStringCreateMutable(CFGetAllocator(item), 0);
1636      CFStringAppend(sql, CFSTR("DELETE FROM "));
1637      CFStringAppend(sql, item->class->name);
1638      bool needWhere = true;
1639      SecDbForEachAttr(item->class, attr) {
1640          if (use_attr_in_where(attr)) {
1641              SecDbAppendWhereOrAndEquals(sql, attr->name, &needWhere);
1642          }
1643      }
1644  
1645      return sql;
1646  }
1647  
1648  static bool SecDbItemDeleteBind(SecDbItemRef item, sqlite3_stmt *stmt, CFErrorRef *error, bool(^use_attr_in_where)(const SecDbAttr *attr)) {
1649      bool ok = true;
1650      int param = 0;
1651      SecDbForEachAttr(item->class, attr) {
1652          if (use_attr_in_where(attr)) {
1653              CFTypeRef value = SecDbItemCopyValueForDb(item, attr, error);
1654              ok &= value && SecDbBindObject(stmt, ++param, value, error);
1655              CFReleaseSafe(value);
1656              if (!ok)
1657                  break;
1658          }
1659      }
1660      return ok;
1661  }
1662  
1663  static bool SecDbItemDoDeleteOnly(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error, bool (^use_attr_in_where)(const SecDbAttr *attr)) {
1664      CFStringRef sql = SecDbItemCopyDeleteSQL(item, use_attr_in_where);
1665      __block bool ok = sql;
1666      if (sql) {
1667          ok &= SecDbPrepare(dbconn, sql, error, ^(sqlite3_stmt *stmt) {
1668              ok = SecDbItemDeleteBind(item, stmt, error, use_attr_in_where) && SecDbStep(dbconn, stmt, error, NULL);
1669          });
1670          CFRelease(sql);
1671      }
1672      return ok;
1673  }
1674  
1675  bool SecDbItemDoDeleteSilently(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error) {
1676      return SecDbItemDoDeleteOnly(item, dbconn, error, ^bool(const SecDbAttr *attr) {
1677          return attr->kind == kSecDbRowIdAttr;
1678      });
1679  }
1680  
1681  static bool SecDbItemDoDelete(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error, bool (^use_attr_in_where)(const SecDbAttr *attr)) {
1682      bool ok = SecDbItemDoDeleteOnly(item, dbconn, error, use_attr_in_where);
1683      if (ok) {
1684          secnotice("item", "deleted %@ from %@", item, dbconn);
1685          SecDbItemRecordUpdate(dbconn, item, NULL);
1686      }
1687      return ok;
1688  }
1689  
1690  #if 0
1691  static bool SecDbItemDeleteTombstone(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error) {
1692      bool ok = true;
1693      // TODO: Treat non decryptable items like tombstones here too and delete them
1694      SecDbItemRef tombstone = SecDbItemCopyTombstone(item, error);
1695      ok = tombstone;
1696      if (tombstone) {
1697          ok = SecDbItemClearRowId(tombstone, error);
1698          if (ok) {
1699              ok = SecDbItemDoDelete(tombstone, dbconn, error, ^bool (const SecDbAttr *attr) {
1700                  return SecDbIsTombstoneDbSelectAttr(attr);
1701              });
1702          }
1703          CFRelease(tombstone);
1704      }
1705      return ok;
1706  }
1707  #endif
1708  
1709  static bool
1710  isCKKSEnabled(void)
1711  {
1712  #if OCTAGON
1713      return SecCKKSIsEnabled();
1714  #else
1715      return false;
1716  #endif
1717  }
1718  
1719  // Replace old_item with new_item.  If primary keys are the same this does an update otherwise it does a delete + add
1720  bool SecDbItemUpdate(SecDbItemRef old_item, SecDbItemRef new_item, SecDbConnectionRef dbconn, CFBooleanRef makeTombstone, bool uuid_from_primary_key, CFErrorRef *error) {
1721      __block bool ok = true;
1722      __block CFErrorRef localError = NULL;
1723  
1724      CFDataRef old_pk = SecDbItemGetPrimaryKey(old_item, error);
1725      CFDataRef new_pk = SecDbItemGetPrimaryKey(new_item, error);
1726  
1727      ok = old_pk && new_pk;
1728  
1729      bool pk_equal = ok && CFEqual(old_pk, new_pk);
1730      if (pk_equal) {
1731          ok = SecDbItemMakeYounger(new_item, old_item, error);
1732      } else if(!CFEqualSafe(makeTombstone, kCFBooleanFalse) && isCKKSEnabled()) {
1733          // The primary keys aren't equal, and we're going to make a tombstone.
1734          // Help CKKS out: the tombstone should have the existing item's UUID, and the newly updated item should have a new UUID.
1735  
1736          s3dl_item_make_new_uuid(new_item, uuid_from_primary_key, error);
1737      }
1738      ok = ok && SecDbItemDoUpdate(old_item, new_item, dbconn, &localError, ^bool(const SecDbAttr *attr) {
1739          return attr->kind == kSecDbRowIdAttr;
1740      });
1741  
1742      if (localError) {
1743          if(CFErrorGetCode(localError) == SQLITE_CONSTRAINT && CFEqual(kSecDbErrorDomain, CFErrorGetDomain(localError))) {
1744              /* Update failed because we changed the PrimaryKey and there was a dup.
1745                 Find the dup and see if it is a tombstone or corrupted item. */
1746              SecDbQueryRef query = SecDbQueryCreateWithItemPrimaryKey(new_item, error);
1747              ok = query;
1748              if (query) {
1749                  ok &= SecDbItemSelect(query, dbconn, error, NULL, ^bool(const SecDbAttr *attr) {
1750                      return attr->flags & kSecDbPrimaryKeyFlag;
1751                  }, NULL, NULL, ^(SecDbItemRef duplicate_item, bool *stop) {
1752                      bool is_corrupt = false;
1753                      bool is_tomb = false;
1754                      ok = SecDbItemIsCorrupt(duplicate_item, &is_corrupt, error);
1755                      if (ok && !is_corrupt) {
1756                          if ((is_tomb = SecDbItemIsTombstone(duplicate_item)))
1757                              ok = SecDbItemMakeYounger(new_item, duplicate_item, error);
1758                      }
1759                      if (ok && (is_corrupt || is_tomb)) {
1760                          ok = SecDbItemDoDelete(old_item, dbconn, error, ^bool (const SecDbAttr *attr) {
1761                              return attr->kind == kSecDbRowIdAttr;
1762                          });
1763                          ok = ok && SecDbItemDoUpdate(duplicate_item, new_item, dbconn, error, ^bool (const SecDbAttr *attr) {
1764                              return attr->kind == kSecDbRowIdAttr;
1765                          });
1766                          CFReleaseNull(localError);
1767                      }
1768                  });
1769                  ok &= query_destroy(query, error);
1770              }
1771          }
1772  
1773          if (localError) {
1774              ok = false;
1775              if (error && *error == NULL) {
1776                  *error = localError;
1777                  localError = NULL;
1778              }
1779              CFReleaseSafe(localError);
1780          }
1781      }
1782  
1783      if (ok && !pk_equal && !CFEqualSafe(makeTombstone, kCFBooleanFalse)) {
1784          /* The primary key of new_item is different than that of old_item, we
1785             have been asked to make a tombstone so leave one for the old_item. */
1786          SecDbItemRef tombstone = SecDbItemCopyTombstone(old_item, makeTombstone, false, error);
1787          ok = tombstone;
1788          if (tombstone) {
1789              ok = (SecDbItemClearRowId(tombstone, error) &&
1790                    SecDbItemDoInsert(tombstone, dbconn, error));
1791              CFRelease(tombstone);
1792          }
1793      }
1794  
1795      return ok;
1796  }
1797  
1798  // Replace the object with a tombstone
1799  bool SecDbItemDelete(SecDbItemRef item, SecDbConnectionRef dbconn, CFBooleanRef makeTombstone, bool tombstone_time_from_item, CFErrorRef *error) {
1800      bool ok = false;
1801      if (!CFEqualSafe(makeTombstone, kCFBooleanFalse)) {
1802          SecDbItemRef tombstone = SecDbItemCopyTombstone(item, makeTombstone, tombstone_time_from_item, error);
1803          if (tombstone) {
1804              ok = SecDbItemDoUpdate(item, tombstone, dbconn, error, ^bool(const SecDbAttr *attr) {
1805                  return attr->kind == kSecDbRowIdAttr;
1806              });
1807              CFRelease(tombstone);
1808          }
1809      } else {
1810          ok = SecDbItemDoDelete(item, dbconn, error, ^bool(const SecDbAttr *attr) {
1811              return attr->kind == kSecDbRowIdAttr;
1812          });
1813      }
1814      return ok;
1815  }
1816  
1817  CFStringRef SecDbItemCopySelectSQL(SecDbQueryRef query,
1818                                     bool (^return_attr)(const SecDbAttr *attr),
1819                                     bool (^use_attr_in_where)(const SecDbAttr *attr),
1820                                     bool (^add_where_sql)(CFMutableStringRef sql, bool *needWhere)) {
1821      CFMutableStringRef sql = CFStringCreateMutable(kCFAllocatorDefault, 0);
1822      CFStringAppend(sql, CFSTR("SELECT "));
1823      // What are we selecting?
1824      bool needComma = false;
1825      SecDbForEachAttr(query->q_class, attr) {
1826          if (return_attr(attr))
1827              SecDbAppendElement(sql, attr->name, &needComma);
1828      }
1829  
1830      // From which table?
1831      CFStringAppend(sql, CFSTR(" FROM "));
1832      CFStringAppend(sql, query->q_class->name);
1833  
1834      // And which elements do we want to select
1835      bool needWhere = true;
1836      SecDbForEachAttr(query->q_class, attr) {
1837          if (use_attr_in_where(attr)) {
1838              CFTypeRef value = CFDictionaryGetValue(query->q_item, attr->name);
1839              if (isArray(value)) {
1840                  CFArrayRef array = (CFArrayRef)value;
1841                  CFIndex length = CFArrayGetCount(array);
1842                  if (length > 0) {
1843                      CFTypeRef head = CFArrayGetValueAtIndex(array, 0);
1844                      if (CFEqualSafe(head, kCFNull)) {
1845                          SecDbAppendWhereOrAndNotIn(sql, attr->name, &needWhere, length - 1);
1846                      } else {
1847                          SecDbAppendWhereOrAndIn(sql, attr->name, &needWhere, length);
1848                      }
1849                  }
1850              } else {
1851                  SecDbAppendWhereOrAndEquals(sql, attr->name, &needWhere);
1852              }
1853          }
1854      }
1855      // Append SQL for access groups and limits.
1856      if (add_where_sql)
1857          add_where_sql(sql, &needWhere);
1858  
1859      return sql;
1860  }
1861  
1862  static bool SecDbItemSelectBindValue(SecDbQueryRef query, sqlite3_stmt *stmt, int param, const SecDbAttr *attr, CFTypeRef inValue, CFErrorRef *error) {
1863      bool ok = true;
1864      CFTypeRef value = NULL;
1865      if (attr->kind == kSecDbRowIdAttr) {
1866          // TODO: Ignores inValue and uses rowid directly instead HACK should go
1867          value = CFNumberCreate(NULL, kCFNumberSInt64Type, &query->q_row_id);
1868      } else {
1869          value = SecDbAttrCopyValueForDb(attr, inValue, error);
1870      }
1871      ok = ok && value != NULL && SecDbBindObject(stmt, ++param, value, error);
1872      CFReleaseSafe(value);
1873      return ok;
1874  }
1875  
1876  bool SecDbItemSelectBind(SecDbQueryRef query, sqlite3_stmt *stmt, CFErrorRef *error,
1877                           bool (^use_attr_in_where)(const SecDbAttr *attr),
1878                           bool (^bind_added_where)(sqlite3_stmt *stmt, int col)) {
1879      __block bool ok = true;
1880      __block int param = 0;
1881      SecDbForEachAttr(query->q_class, attr) {
1882          if (use_attr_in_where(attr)) {
1883              CFTypeRef value = CFDictionaryGetValue(query->q_item, attr->name);
1884              if (isArray(value)) {
1885                  CFArrayRef array = (CFArrayRef)value;
1886                  CFRange range = {.location = 0, .length = CFArrayGetCount(array) };
1887                  if (range.length > 0) {
1888                      CFTypeRef head = CFArrayGetValueAtIndex(array, 0);
1889                      if (CFEqualSafe(head, kCFNull)) {
1890                          range.length--;
1891                          range.location++;
1892                      }
1893                  }
1894                  CFArrayApplyFunction(array, range, apply_block_1, (void (^)(const void *value)) ^(const void *arrayValue) {
1895                      ok = SecDbItemSelectBindValue(query, stmt, param++, attr, arrayValue, error);
1896                  });
1897              } else {
1898                  ok = SecDbItemSelectBindValue(query, stmt, param++, attr, value, error);
1899              }
1900  
1901              if (!ok)
1902                  break;
1903          }
1904      }
1905      // TODO: Bind arguments for access groups and limits.
1906      if (bind_added_where)
1907          bind_added_where(stmt, ++param);
1908  
1909      return ok;
1910  }
1911  
1912  bool SecDbItemSelect(SecDbQueryRef query, SecDbConnectionRef dbconn, CFErrorRef *error,
1913                       bool (^return_attr)(const SecDbAttr *attr),
1914                       bool (^use_attr_in_where)(const SecDbAttr *attr),
1915                       bool (^add_where_sql)(CFMutableStringRef sql, bool *needWhere),
1916                       bool (^bind_added_where)(sqlite3_stmt *stmt, int col),
1917                       void (^handle_row)(SecDbItemRef item, bool *stop)) {
1918      __block bool ok = true;
1919      if (return_attr == NULL) {
1920          return_attr = ^bool (const SecDbAttr * attr) {
1921              return attr->kind == kSecDbRowIdAttr || attr->kind == kSecDbEncryptedDataAttr || attr->kind == kSecDbSHA1Attr;
1922          };
1923      }
1924      if (use_attr_in_where == NULL) {
1925          use_attr_in_where = ^bool (const SecDbAttr* attr) { return false; };
1926      }
1927      
1928      CFStringRef sql = SecDbItemCopySelectSQL(query, return_attr, use_attr_in_where, add_where_sql);
1929      if (sql) {
1930          ok &= SecDbPrepare(dbconn, sql, error, ^(sqlite3_stmt *stmt) {
1931              ok = (SecDbItemSelectBind(query, stmt, error, use_attr_in_where, bind_added_where) &&
1932                    SecDbStep(dbconn, stmt, error, ^(bool *stop) {
1933                  SecDbItemRef item = SecDbItemCreateWithStatement(kCFAllocatorDefault, query->q_class, stmt, query->q_keybag, error, return_attr);
1934                  if (item) {
1935                      CFRetainAssign(item->credHandle, query->q_use_cred_handle);
1936                      handle_row(item, stop);
1937                      CFRelease(item);
1938                  } else {
1939                      //*stop = true;
1940                      //ok = false;
1941                  }
1942              }));
1943          });
1944          CFRelease(sql);
1945      } else {
1946          ok = false;
1947      }
1948      return ok;
1949  }
1950