]> git.saurik.com Git - apple/security.git/blobdiff - Security/sec/securityd/SecItemServer.c
Security-57336.1.9.tar.gz
[apple/security.git] / Security / sec / securityd / SecItemServer.c
diff --git a/Security/sec/securityd/SecItemServer.c b/Security/sec/securityd/SecItemServer.c
deleted file mode 100644 (file)
index d776366..0000000
+++ /dev/null
@@ -1,1885 +0,0 @@
-/*
- * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
- */
-
-/*
- * SecItemServer.c - CoreFoundation-based constants and functions for
-    access to Security items (certificates, keys, identities, and
-    passwords.)
- */
-
-#include <securityd/SecItemServer.h>
-
-#include <notify.h>
-#include <securityd/SecItemDataSource.h>
-#include <securityd/SecItemDb.h>
-#include <securityd/SecItemSchema.h>
-#include <securityd/SOSCloudCircleServer.h>
-#include <Security/SecBasePriv.h>
-#include <Security/SecItemPriv.h>
-#include <Security/SecItemInternal.h>
-#include <SecureObjectSync/SOSDigestVector.h>
-
-// TODO: Make this include work on both platforms. rdar://problem/16526848
-#if TARGET_OS_EMBEDDED
-#include <Security/SecEntitlements.h>
-#else
-/* defines from <Security/SecEntitlements.h> */
-#define kSecEntitlementAssociatedDomains CFSTR("com.apple.developer.associated-domains")
-#define kSecEntitlementPrivateAssociatedDomains CFSTR("com.apple.private.associated-domains")
-#endif
-
-#include <utilities/array_size.h>
-#include <utilities/SecFileLocations.h>
-#include <Security/SecuritydXPC.h>
-#include "swcagent_client.h"
-
-#if TARGET_OS_IPHONE
-#include <SharedWebCredentials/SharedWebCredentials.h>
-#else
-typedef uint32_t SWCFlags;
-#define kSWCFlags_None                         0
-#define kSWCFlag_Pending                       ( 1U << 0 )
-#define kSWCFlag_SiteApproved          ( 1U << 1 )
-#define kSWCFlag_SiteDenied                    ( 1U << 2 )
-#define kSWCFlag_UserApproved          ( 1U << 3 )
-#define kSWCFlag_UserDenied                    ( 1U << 4 )
-#define kSWCFlag_ExternalMask          ( kSWCFlag_UserApproved | kSWCFlag_UserDenied )
-#endif
-
-/* Changed the name of the keychain changed notification, for testing */
-static const char *g_keychain_changed_notification = kSecServerKeychainChangedNotification;
-
-void SecItemServerSetKeychainChangedNotification(const char *notification_name)
-{
-    g_keychain_changed_notification = notification_name;
-}
-
-void SecKeychainChanged(bool syncWithPeers) {
-    uint32_t result = notify_post(g_keychain_changed_notification);
-    if (syncWithPeers)
-        SOSCCSyncWithAllPeers();
-    if (result == NOTIFY_STATUS_OK)
-        secnotice("item", "Sent %s%s", syncWithPeers ? "SyncWithAllPeers and " : "", g_keychain_changed_notification);
-    else
-        secerror("%snotify_post %s returned: %" PRIu32, syncWithPeers ? "Sent SyncWithAllPeers, " : "", g_keychain_changed_notification, result);
-    }
-
-static const char * const s3dl_upgrade_sql[] = {
-    /* 0 */
-    "",
-
-    /* 1 */
-    /* Create indices. */
-    "CREATE INDEX igsha ON genp(sha1);"
-    "CREATE INDEX iisha ON inet(sha1);"
-    "CREATE INDEX icsha ON cert(sha1);"
-    "CREATE INDEX iksha ON keys(sha1);"
-    "CREATE INDEX ialis ON cert(alis);"
-    "CREATE INDEX isubj ON cert(subj);"
-    "CREATE INDEX iskid ON cert(skid);"
-    "CREATE INDEX ipkhh ON cert(pkhh);"
-    "CREATE INDEX ikcls ON keys(kcls);"
-    "CREATE INDEX iklbl ON keys(klbl);"
-    "CREATE INDEX iencr ON keys(encr);"
-    "CREATE INDEX idecr ON keys(decr);"
-    "CREATE INDEX idrve ON keys(drve);"
-    "CREATE INDEX isign ON keys(sign);"
-    "CREATE INDEX ivrfy ON keys(vrfy);"
-    "CREATE INDEX iwrap ON keys(wrap);"
-    "CREATE INDEX iunwp ON keys(unwp);",
-
-    /* 2 */
-    "",
-
-    /* 3 */
-    /* Rename version 2 or version 3 tables and drop version table since
-       step 0 creates it. */
-    "ALTER TABLE genp RENAME TO ogenp;"
-    "ALTER TABLE inet RENAME TO oinet;"
-    "ALTER TABLE cert RENAME TO ocert;"
-    "ALTER TABLE keys RENAME TO okeys;"
-    "DROP TABLE tversion;",
-
-    /* 4 */
-    "",
-
-    /* 5 */
-    "",
-
-    /* 6 */
-    "",
-
-    /* 7 */
-    /* Move data from version 5 tables to new ones and drop old ones. */
-    "INSERT INTO genp (rowid,cdat,mdat,desc,icmt,crtr,type,scrp,labl,alis,invi,nega,cusi,prot,acct,svce,gena,data,agrp,pdmn) SELECT rowid,cdat,mdat,desc,icmt,crtr,type,scrp,labl,alis,invi,nega,cusi,prot,acct,svce,gena,data,agrp,pdmn from ogenp;"
-    "INSERT INTO inet (rowid,cdat,mdat,desc,icmt,crtr,type,scrp,labl,alis,invi,nega,cusi,prot,acct,sdmn,srvr,ptcl,atyp,port,path,data,agrp,pdmn) SELECT rowid,cdat,mdat,desc,icmt,crtr,type,scrp,labl,alis,invi,nega,cusi,prot,acct,sdmn,srvr,ptcl,atyp,port,path,data,agrp,pdmn from oinet;"
-    "INSERT INTO cert (rowid,cdat,mdat,ctyp,cenc,labl,alis,subj,issr,slnr,skid,pkhh,data,agrp,pdmn) SELECT rowid,cdat,mdat,ctyp,cenc,labl,alis,subj,issr,slnr,skid,pkhh,data,agrp,pdmn from ocert;"
-    "INSERT INTO keys (rowid,cdat,mdat,kcls,labl,alis,perm,priv,modi,klbl,atag,crtr,type,bsiz,esiz,sdat,edat,sens,asen,extr,next,encr,decr,drve,sign,vrfy,snrc,vyrc,wrap,unwp,data,agrp,pdmn) SELECT rowid,cdat,mdat,kcls,labl,alis,perm,priv,modi,klbl,atag,crtr,type,bsiz,esiz,sdat,edat,sens,asen,extr,next,encr,decr,drve,sign,vrfy,snrc,vyrc,wrap,unwp,data,agrp,pdmn from okeys;"
-    "DROP TABLE ogenp;"
-    "DROP TABLE oinet;"
-    "DROP TABLE ocert;"
-    "DROP TABLE okeys;"
-    "CREATE INDEX igsha ON genp(sha1);"
-    "CREATE INDEX iisha ON inet(sha1);"
-    "CREATE INDEX icsha ON cert(sha1);"
-    "CREATE INDEX iksha ON keys(sha1);",
-};
-
-struct sql_stages {
-    int pre;
-    int main;
-    int post;
-    bool init_pdmn; // If true do a full export followed by an import of the entire database so all items are re-encoded.
-};
-
-/* On disk database format version upgrade scripts.
-   If pre is 0, version is unsupported and db is considered corrupt for having that version.
-   First entry creates the current db, each susequent entry upgrade to current from the version
-   represented by the index of the slot.  Each script is either -1 (disabled) of the number of
-   the script in the main table.
-    {pre,main,post, reencode} */
-
-
-static struct sql_stages s3dl_upgrade_script[] = {
-    { -1, 0, 1, false },/* 0->current: Create version 6*/
-    {},                 /* 1->current: Upgrade to version 6 from version 1 -- Unsupported. */
-    {},                 /* 2->current: Upgrade to version 6 from version 2 -- Unsupported */
-    {},                 /* 3->current: Upgrade to version 6 from version 3 -- Unsupported */
-    {},                 /* 4->current: Upgrade to version 6 from version 4 -- Unsupported */
-    { 3, 0, 7, true },  /* 5->current: Upgrade to version 6 from version 5 */
-};
-
-static bool sql_run_script(SecDbConnectionRef dbt, int number, CFErrorRef *error)
-{
-    /* Script -1 == skip this step. */
-    if (number < 0)
-        return true;
-
-    /* If we are attempting to run a script we don't have, fail. */
-    if ((size_t)number >= array_size(s3dl_upgrade_sql))
-        return SecDbError(SQLITE_CORRUPT, error, CFSTR("script %d exceeds maximum %d"),
-                                number, (int)(array_size(s3dl_upgrade_sql)));
-    __block bool ok = true;
-    if (number == 0) {
-        CFMutableStringRef sql = CFStringCreateMutable(0, 0);
-        SecDbAppendCreateTableWithClass(sql, &genp_class);
-        SecDbAppendCreateTableWithClass(sql, &inet_class);
-        SecDbAppendCreateTableWithClass(sql, &cert_class);
-        SecDbAppendCreateTableWithClass(sql, &keys_class);
-        CFStringAppend(sql, CFSTR("CREATE TABLE tversion(version INTEGER);INSERT INTO tversion(version) VALUES(6);"));
-        CFStringPerformWithCString(sql, ^(const char *sql_string) {
-            ok = SecDbErrorWithDb(sqlite3_exec(SecDbHandle(dbt), sql_string, NULL, NULL, NULL),
-                                     SecDbHandle(dbt), error, CFSTR("sqlite3_exec: %s"), sql_string);
-        });
-        CFReleaseSafe(sql);
-    } else {
-        ok = SecDbErrorWithDb(sqlite3_exec(SecDbHandle(dbt), s3dl_upgrade_sql[number], NULL, NULL, NULL),
-                                 SecDbHandle(dbt), error, CFSTR("sqlite3_exec: %s"), s3dl_upgrade_sql[number]);
-    }
-    return ok;
-}
-
-/* Return the current database version in *version.  Returns a
- SQLITE error. */
-static bool s3dl_dbt_get_version(SecDbConnectionRef dbt, int *version, CFErrorRef *error)
-{
-    CFStringRef sql = CFSTR("SELECT version FROM tversion LIMIT 1");
-    return SecDbWithSQL(dbt, sql, error, ^(sqlite3_stmt *stmt) {
-        __block bool found_version = false;
-        bool step_ok = SecDbForEach(stmt, error, ^(int row_index __unused) {
-            if (!found_version) {
-                *version = sqlite3_column_int(stmt, 0);
-                found_version = true;
-            }
-            return found_version;
-        });
-        if (!found_version) {
-            /* We have a tversion table but we didn't find a single version
-             value, now what? I suppose we pretend the db is corrupted
-             since this isn't supposed to ever happen. */
-            step_ok = SecDbError(SQLITE_CORRUPT, error, CFSTR("Failed to read version: database corrupt"));
-            secwarning("SELECT version step: %@", error ? *error : NULL);
-        }
-        return step_ok;
-    });
-}
-
-
-static bool s3dl_dbt_upgrade_from_version(SecDbConnectionRef dbt, int version, CFErrorRef *error)
-{
-    /* We need to go from db version to CURRENT_DB_VERSION, let's do so. */
-    __block bool ok = true;
-    /* O, guess we're done already. */
-    if (version == CURRENT_DB_VERSION)
-        return ok;
-
-    if (ok && version < 6) {
-        // Pre v6 keychains need to have WAL enabled, since SecDb only
-        // does this at db creation time.
-        // NOTE: This has to be run outside of a transaction.
-        ok = (SecDbExec(dbt, CFSTR("PRAGMA auto_vacuum = FULL"), error) &&
-              SecDbExec(dbt, CFSTR("PRAGMA journal_mode = WAL"), error));
-    }
-
-    // Start a transaction to do the upgrade within
-    if (ok) { ok = SecDbTransaction(dbt, kSecDbExclusiveTransactionType, error, ^(bool *commit) {
-        // Be conservative and get the version again once we start a transaction.
-        int cur_version = version;
-        s3dl_dbt_get_version(dbt, &cur_version, NULL);
-
-        /* If we are attempting to upgrade to a version greater than what we have
-         an upgrade script for, fail. */
-        if (ok && (cur_version < 0 ||
-            (size_t)cur_version >= array_size(s3dl_upgrade_script))) {
-            ok = SecDbError(SQLITE_CORRUPT, error, CFSTR("no upgrade script for version: %d"), cur_version);
-            secerror("no upgrade script for version %d", cur_version);
-        }
-
-        struct sql_stages *script;
-        if (ok) {
-            script = &s3dl_upgrade_script[cur_version];
-            if (script->pre == 0)
-                ok = SecDbError(SQLITE_CORRUPT, error, CFSTR("unsupported db version %d"), cur_version);
-        }
-        if (ok)
-            ok = sql_run_script(dbt, script->pre, error);
-        if (ok)
-            ok = sql_run_script(dbt, script->main, error);
-        if (ok)
-            ok = sql_run_script(dbt, script->post, error);
-        if (ok && script->init_pdmn) {
-            CFErrorRef localError = NULL;
-            CFDictionaryRef backup = SecServerExportKeychainPlist(dbt,
-                                                                  KEYBAG_DEVICE, KEYBAG_NONE, kSecNoItemFilter, &localError);
-            if (backup) {
-                if (localError) {
-                    secerror("Ignoring export error: %@ during upgrade export", localError);
-                    CFReleaseNull(localError);
-                }
-                ok = SecServerImportKeychainInPlist(dbt, KEYBAG_NONE,
-                                                    KEYBAG_DEVICE, backup, kSecNoItemFilter, &localError);
-                CFRelease(backup);
-            } else {
-                ok = false;
-
-                if (localError && SecErrorGetOSStatus(localError) == errSecInteractionNotAllowed) {
-                    SecError(errSecUpgradePending, error,
-                         CFSTR("unable to complete upgrade due to device lock state"));
-                    secerror("unable to complete upgrade due to device lock state");
-                } else {
-                    secerror("unable to complete upgrade for unknown reason, marking DB as corrupt: %@", localError);
-                    SecDbCorrupt(dbt);
-                }
-            }
-
-            if (localError) {
-                if (error && !*error)
-                    *error = localError;
-                else
-                    CFRelease(localError);
-            }
-        } else if (!ok) {
-            secerror("unable to complete upgrade scripts, marking DB as corrupt: %@", error ? *error : NULL);
-            SecDbCorrupt(dbt);
-        }
-        *commit = ok;
-    }); } else {
-        secerror("unable to complete upgrade scripts, marking DB as corrupt: %@", error ? *error : NULL);
-        SecDbCorrupt(dbt);
-    }
-
-    return ok;
-}
-
-
-/* This function is called if the db doesn't have the proper version.  We
-   start an exclusive transaction and recheck the version, and then perform
-   the upgrade within that transaction. */
-static bool s3dl_dbt_upgrade(SecDbConnectionRef dbt, CFErrorRef *error)
-{
-    // Already in a transaction
-    //return kc_transaction(dbt, error, ^{
-        int version = 0; // Upgrade from version 0 == create new db
-        s3dl_dbt_get_version(dbt, &version, NULL);
-        return s3dl_dbt_upgrade_from_version(dbt, version, error);
-    //});
-}
-
-/* AUDIT[securityd](done):
-   accessGroup (ok) is a caller provided, non NULL CFTypeRef.
-
-   Return true iff accessGroup is allowable according to accessGroups.
- */
-static bool accessGroupsAllows(CFArrayRef accessGroups,
-    CFStringRef accessGroup) {
-    /* NULL accessGroups is wildcard. */
-    if (!accessGroups)
-        return true;
-    /* Make sure we have a string. */
-    if (!isString(accessGroup))
-        return false;
-
-    /* Having the special accessGroup "*" allows access to all accessGroups. */
-    CFRange range = { 0, CFArrayGetCount(accessGroups) };
-    if (range.length &&
-        (CFArrayContainsValue(accessGroups, range, accessGroup) ||
-         CFArrayContainsValue(accessGroups, range, CFSTR("*"))))
-        return true;
-
-    return false;
-}
-
-bool itemInAccessGroup(CFDictionaryRef item, CFArrayRef accessGroups) {
-    return accessGroupsAllows(accessGroups,
-                              CFDictionaryGetValue(item, kSecAttrAccessGroup));
-}
-
-
-static CF_RETURNS_RETAINED CFDataRef SecServerExportKeychain(SecDbConnectionRef dbt,
-    keybag_handle_t src_keybag, keybag_handle_t dest_keybag, CFErrorRef *error) {
-    CFDataRef data_out = NULL;
-    /* Export everything except the items for which SecItemIsSystemBound()
-       returns true. */
-    CFDictionaryRef keychain = SecServerExportKeychainPlist(dbt,
-        src_keybag, dest_keybag, kSecBackupableItemFilter,
-        error);
-    if (keychain) {
-        data_out = CFPropertyListCreateData(kCFAllocatorDefault, keychain,
-                                             kCFPropertyListBinaryFormat_v1_0,
-                                             0, error);
-        CFRelease(keychain);
-    }
-
-    return data_out;
-}
-
-static bool SecServerImportKeychain(SecDbConnectionRef dbt,
-    keybag_handle_t src_keybag,
-    keybag_handle_t dest_keybag, CFDataRef data, CFErrorRef *error) {
-    return kc_transaction(dbt, error, ^{
-        bool ok = false;
-        CFDictionaryRef keychain;
-        keychain = CFPropertyListCreateWithData(kCFAllocatorDefault, data,
-                                                kCFPropertyListImmutable, NULL,
-                                                error);
-        if (keychain) {
-            if (isDictionary(keychain)) {
-                ok = SecServerImportKeychainInPlist(dbt, src_keybag,
-                                                    dest_keybag, keychain,
-                                                    kSecBackupableItemFilter,
-                                                    error);
-            } else {
-                ok = SecError(errSecParam, error, CFSTR("import: keychain is not a dictionary"));
-            }
-            CFRelease(keychain);
-        }
-        return ok;
-    });
-}
-
-static CF_RETURNS_RETAINED CFDataRef SecServerKeychainBackup(SecDbConnectionRef dbt, CFDataRef keybag,
-    CFDataRef password, CFErrorRef *error) {
-    CFDataRef backup = NULL;
-    keybag_handle_t backup_keybag;
-    if (ks_open_keybag(keybag, password, &backup_keybag, error)) {
-        /* Export from system keybag to backup keybag. */
-        backup = SecServerExportKeychain(dbt, KEYBAG_DEVICE, backup_keybag, error);
-        if (!ks_close_keybag(backup_keybag, error)) {
-            CFReleaseNull(backup);
-        }
-    }
-    return backup;
-}
-
-static bool SecServerKeychainRestore(SecDbConnectionRef dbt, CFDataRef backup,
-    CFDataRef keybag, CFDataRef password, CFErrorRef *error) {
-    keybag_handle_t backup_keybag;
-    if (!ks_open_keybag(keybag, password, &backup_keybag, error))
-        return false;
-
-    /* Import from backup keybag to system keybag. */
-    bool ok = SecServerImportKeychain(dbt, backup_keybag, KEYBAG_DEVICE,
-                                      backup, error);
-    ok &= ks_close_keybag(backup_keybag, error);
-
-    return ok;
-}
-
-
-// MARK - External SPI support code.
-
-CFStringRef __SecKeychainCopyPath(void) {
-    CFStringRef kcRelPath = NULL;
-    if (use_hwaes()) {
-        kcRelPath = CFSTR("keychain-2.db");
-    } else {
-        kcRelPath = CFSTR("keychain-2-debug.db");
-    }
-
-    CFStringRef kcPath = NULL;
-    CFURLRef kcURL = SecCopyURLForFileInKeychainDirectory(kcRelPath);
-    if (kcURL) {
-        kcPath = CFURLCopyFileSystemPath(kcURL, kCFURLPOSIXPathStyle);
-        CFRelease(kcURL);
-    }
-    return kcPath;
-
-}
-
-// MARK; -
-// MARK: kc_dbhandle init and reset
-
-SecDbRef SecKeychainDbCreate(CFStringRef path) {
-    return SecDbCreate(path, ^bool (SecDbConnectionRef dbconn, bool didCreate, CFErrorRef *localError) {
-        bool ok;
-        if (didCreate)
-            ok = s3dl_dbt_upgrade_from_version(dbconn, 0, localError);
-        else
-            ok = s3dl_dbt_upgrade(dbconn, localError);
-
-        if (!ok)
-            secerror("Upgrade %sfailed: %@", didCreate ? "from v0 " : "", localError ? *localError : NULL);
-
-        return ok;
-    });
-}
-
-static SecDbRef _kc_dbhandle = NULL;
-
-static void kc_dbhandle_init(void) {
-    SecDbRef oldHandle = _kc_dbhandle;
-    _kc_dbhandle = NULL;
-    CFStringRef dbPath = __SecKeychainCopyPath();
-    if (dbPath) {
-        _kc_dbhandle = SecKeychainDbCreate(dbPath);
-        CFRelease(dbPath);
-    } else {
-        secerror("no keychain path available");
-    }
-    if (oldHandle) {
-        secerror("replaced %@ with %@", oldHandle, _kc_dbhandle);
-        CFRelease(oldHandle);
-    }
-}
-
-static dispatch_once_t _kc_dbhandle_once;
-
-static SecDbRef kc_dbhandle(void) {
-    dispatch_once(&_kc_dbhandle_once, ^{
-        kc_dbhandle_init();
-    });
-    return _kc_dbhandle;
-}
-
-/* For whitebox testing only */
-void kc_dbhandle_reset(void);
-void kc_dbhandle_reset(void)
-{
-    __block bool done = false;
-    dispatch_once(&_kc_dbhandle_once, ^{
-        kc_dbhandle_init();
-        done = true;
-    });
-    // TODO: Not thread safe at all! - FOR DEBUGGING ONLY
-    if (!done)
-        kc_dbhandle_init();
-}
-
-static SecDbConnectionRef kc_aquire_dbt(bool writeAndRead, CFErrorRef *error) {
-    SecDbRef db = kc_dbhandle();
-    if (db == NULL) {
-        SecError(errSecDataNotAvailable, error, CFSTR("failed to get a db handle"));
-        return NULL;
-    }
-    return SecDbConnectionAquire(db, !writeAndRead, error);
-}
-
-/* Return a per thread dbt handle for the keychain.  If create is true create
- the database if it does not yet exist.  If it is false, just return an
- error if it fails to auto-create. */
-static bool kc_with_dbt(bool writeAndRead, CFErrorRef *error, bool (^perform)(SecDbConnectionRef dbt))
-{
-    // Make sure we initialize our engines before writing to the keychain
-    if (writeAndRead)
-        SecItemDataSourceFactoryGetDefault();
-
-    bool ok = false;
-    SecDbConnectionRef dbt = kc_aquire_dbt(writeAndRead, error);
-    if (dbt) {
-        ok = perform(dbt);
-        SecDbConnectionRelease(dbt);
-    }
-    return ok;
-}
-
-static bool
-items_matching_issuer_parent(SecDbConnectionRef dbt, CFArrayRef accessGroups,
-                             CFDataRef issuer, CFArrayRef issuers, int recurse)
-{
-    Query *q;
-    CFArrayRef results = NULL;
-    CFIndex i, count;
-    bool found = false;
-
-    if (CFArrayContainsValue(issuers, CFRangeMake(0, CFArrayGetCount(issuers)), issuer))
-        return true;
-
-    const void *keys[] = { kSecClass, kSecReturnRef, kSecAttrSubject };
-    const void *vals[] = { kSecClassCertificate, kCFBooleanTrue, issuer };
-    CFDictionaryRef query = CFDictionaryCreate(kCFAllocatorDefault, keys, vals, array_size(keys), NULL, NULL);
-
-    if (!query)
-        return false;
-
-    CFErrorRef localError = NULL;
-    q = query_create_with_limit(query, kSecMatchUnlimited, &localError);
-    CFRelease(query);
-    if (q) {
-        s3dl_copy_matching(dbt, q, (CFTypeRef*)&results, accessGroups, &localError);
-        query_destroy(q, &localError);
-    }
-    if (localError) {
-        secerror("items matching issuer parent: %@", localError);
-        CFReleaseNull(localError);
-        return false;
-    }
-
-    count = CFArrayGetCount(results);
-    for (i = 0; (i < count) && !found; i++) {
-        CFDictionaryRef cert_dict = (CFDictionaryRef)CFArrayGetValueAtIndex(results, i);
-        CFDataRef cert_issuer = CFDictionaryGetValue(cert_dict, kSecAttrIssuer);
-        if (CFEqual(cert_issuer, issuer))
-            continue;
-        if (recurse-- > 0)
-            found = items_matching_issuer_parent(dbt, accessGroups, cert_issuer, issuers, recurse);
-    }
-    CFReleaseSafe(results);
-
-    return found;
-}
-
-bool match_item(SecDbConnectionRef dbt, Query *q, CFArrayRef accessGroups, CFDictionaryRef item)
-{
-    if (q->q_match_issuer) {
-        CFDataRef issuer = CFDictionaryGetValue(item, kSecAttrIssuer);
-        if (!items_matching_issuer_parent(dbt, accessGroups, issuer, q->q_match_issuer, 10 /*max depth*/))
-            return false;
-    }
-
-    /* Add future match checks here. */
-
-    return true;
-}
-
-/****************************************************************************
- **************** Beginning of Externally Callable Interface ****************
- ****************************************************************************/
-
-#if 0
-// TODO Use as a safety wrapper
-static bool SecErrorWith(CFErrorRef *in_error, bool (^perform)(CFErrorRef *error)) {
-    CFErrorRef error = in_error ? *in_error : NULL;
-    bool ok;
-    if ((ok = perform(&error))) {
-        assert(error == NULL);
-        if (error)
-            secerror("error + success: %@", error);
-    } else {
-        assert(error);
-        OSStatus status = SecErrorGetOSStatus(error);
-        if (status != errSecItemNotFound)           // Occurs in normal operation, so exclude
-            secerror("error:[%" PRIdOSStatus "] %@", status, error);
-        if (in_error) {
-            *in_error = error;
-        } else {
-            CFReleaseNull(error);
-        }
-    }
-    return ok;
-}
-#endif
-
-/* AUDIT[securityd](done):
-   query (ok) is a caller provided dictionary, only its cf type has been checked.
- */
-static bool
-SecItemServerCopyMatching(CFDictionaryRef query, CFTypeRef *result,
-    CFArrayRef accessGroups, CFErrorRef *error)
-{
-    CFIndex ag_count;
-    if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups))) {
-        return SecError(errSecMissingEntitlement, error,
-                         CFSTR("client has neither application-identifier nor keychain-access-groups entitlements"));
-    }
-
-    if (CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), CFSTR("*"))) {
-        /* Having the special accessGroup "*" allows access to all accessGroups. */
-        accessGroups = NULL;
-    }
-
-    bool ok = false;
-    Query *q = query_create_with_limit(query, 1, error);
-    if (q) {
-        CFStringRef agrp = CFDictionaryGetValue(q->q_item, kSecAttrAccessGroup);
-        if (agrp && accessGroupsAllows(accessGroups, agrp)) {
-            // TODO: Return an error if agrp is not NULL and accessGroupsAllows() fails above.
-            const void *val = agrp;
-            accessGroups = CFArrayCreate(0, &val, 1, &kCFTypeArrayCallBacks);
-        } else {
-            CFRetainSafe(accessGroups);
-        }
-
-        query_enable_interactive(q);
-        query_set_caller_access_groups(q, accessGroups);
-
-        /* Sanity check the query. */
-        if (q->q_use_item_list) {
-            ok = SecError(errSecUseItemListUnsupported, error, CFSTR("use item list unsupported"));
-#if defined(MULTIPLE_KEYCHAINS)
-        } else if (q->q_use_keychain) {
-            ok = SecError(errSecUseKeychainUnsupported, error, CFSTR("use keychain list unsupported"));
-#endif
-        } else if (q->q_match_issuer && ((q->q_class != &cert_class) &&
-                    (q->q_class != &identity_class))) {
-            ok = SecError(errSecUnsupportedOperation, error, CFSTR("unsupported match attribute"));
-        } else if (q->q_return_type != 0 && result == NULL) {
-            ok = SecError(errSecReturnMissingPointer, error, CFSTR("missing pointer"));
-        } else if (!q->q_error) {
-            do {
-                ok = kc_with_dbt(false, error, ^(SecDbConnectionRef dbt) {
-                    return s3dl_copy_matching(dbt, q, result, accessGroups, error);
-                });
-            } while (query_needs_authentication(q) && (ok = query_authenticate(q, &error)));
-        }
-
-        CFReleaseSafe(accessGroups);
-        if (!query_destroy(q, error))
-            ok = false;
-    }
-
-       return ok;
-}
-
-bool
-_SecItemCopyMatching(CFDictionaryRef query, CFArrayRef accessGroups, CFTypeRef *result, CFErrorRef *error) {
-    return SecItemServerCopyMatching(query, result, accessGroups, error);
-}
-
-/* AUDIT[securityd](done):
-   attributes (ok) is a caller provided dictionary, only its cf type has
-       been checked.
- */
-bool
-_SecItemAdd(CFDictionaryRef attributes, CFArrayRef accessGroups,
-            CFTypeRef *result, CFErrorRef *error)
-{
-    bool ok = true;
-    CFIndex ag_count;
-    if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups)))
-        return SecError(errSecMissingEntitlement, error,
-                           CFSTR("client has neither application-identifier nor keychain-access-groups entitlements"));
-
-    Query *q = query_create_with_limit(attributes, 0, error);
-    if (q) {
-        /* Access group sanity checking. */
-        CFStringRef agrp = (CFStringRef)CFDictionaryGetValue(attributes,
-            kSecAttrAccessGroup);
-
-        CFArrayRef ag = accessGroups;
-        /* Having the special accessGroup "*" allows access to all accessGroups. */
-        if (CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), CFSTR("*")))
-            accessGroups = NULL;
-
-        if (agrp) {
-            /* The user specified an explicit access group, validate it. */
-            if (!accessGroupsAllows(accessGroups, agrp))
-                return SecError(errSecNoAccessForItem, error, CFSTR("NoAccessForItem"));
-        } else {
-            agrp = (CFStringRef)CFArrayGetValueAtIndex(ag, 0);
-
-            /* We are using an implicit access group, add it as if the user
-               specified it as an attribute. */
-            query_add_attribute(kSecAttrAccessGroup, agrp, q);
-        }
-
-        query_ensure_access_control(q, agrp);
-        query_enable_interactive(q);
-
-        if (q->q_row_id)
-            ok = SecError(errSecValuePersistentRefUnsupported, error, CFSTR("q_row_id"));  // TODO: better error string
-    #if defined(MULTIPLE_KEYCHAINS)
-        else if (q->q_use_keychain_list)
-            ok = SecError(errSecUseKeychainListUnsupported, error, CFSTR("q_use_keychain_list"));  // TODO: better error string;
-    #endif
-        else if (!q->q_error) {
-            do {
-                ok = kc_with_dbt(true, error, ^(SecDbConnectionRef dbt){
-                    return kc_transaction(dbt, error, ^{
-                        query_pre_add(q, true);
-                        return s3dl_query_add(dbt, q, result, error);
-                    });
-                });
-            } while (query_needs_authentication(q) && (ok = query_authenticate(q, &error)));
-        }
-        ok = query_notify_and_destroy(q, ok, error);
-    } else {
-        ok = false;
-    }
-    return ok;
-}
-
-/* AUDIT[securityd](done):
-   query (ok) and attributesToUpdate (ok) are a caller provided dictionaries,
-       only their cf types have been checked.
- */
-bool
-_SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate,
-               CFArrayRef accessGroups, CFErrorRef *error)
-{
-    CFIndex ag_count;
-    if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups))) {
-        return SecError(errSecMissingEntitlement, error,
-                         CFSTR("client has neither application-identifier nor keychain-access-groups entitlements"));
-    }
-
-    if (CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), CFSTR("*"))) {
-        /* Having the special accessGroup "*" allows access to all accessGroups. */
-        accessGroups = NULL;
-    }
-
-    bool ok = true;
-    Query *q = query_create_with_limit(query, kSecMatchUnlimited, error);
-    if (!q) {
-        ok = false;
-    }
-    if (ok) {
-        /* Sanity check the query. */
-        query_set_caller_access_groups(q, accessGroups);
-        if (q->q_use_item_list) {
-            ok = SecError(errSecUseItemListUnsupported, error, CFSTR("use item list not supported"));
-        } else if (q->q_return_type & kSecReturnDataMask) {
-            /* Update doesn't return anything so don't ask for it. */
-            ok = SecError(errSecReturnDataUnsupported, error, CFSTR("return data not supported by update"));
-        } else if (q->q_return_type & kSecReturnAttributesMask) {
-            ok = SecError(errSecReturnAttributesUnsupported, error, CFSTR("return attributes not supported by update"));
-        } else if (q->q_return_type & kSecReturnRefMask) {
-            ok = SecError(errSecReturnRefUnsupported, error, CFSTR("return ref not supported by update"));
-        } else if (q->q_return_type & kSecReturnPersistentRefMask) {
-            ok = SecError(errSecReturnPersistentRefUnsupported, error, CFSTR("return persistent ref not supported by update"));
-        } else {
-            /* Access group sanity checking. */
-            CFStringRef agrp = (CFStringRef)CFDictionaryGetValue(attributesToUpdate,
-                kSecAttrAccessGroup);
-            if (agrp) {
-                /* The user is attempting to modify the access group column,
-                   validate it to make sure the new value is allowable. */
-                if (!accessGroupsAllows(accessGroups, agrp)) {
-                    ok = SecError(errSecNoAccessForItem, error, CFSTR("accessGroup %@ not in %@"), agrp, accessGroups);
-                }
-            }
-        }
-    }
-    if (ok) {
-        if (!q->q_use_tomb && SOSCCThisDeviceDefinitelyNotActiveInCircle()) {
-            q->q_use_tomb = kCFBooleanFalse;
-        }
-        query_enable_interactive(q);
-        do {
-            ok = kc_with_dbt(true, error, ^(SecDbConnectionRef dbt) {
-                return s3dl_query_update(dbt, q, attributesToUpdate, accessGroups, error);
-            });
-        } while (query_needs_authentication(q) && (ok = query_authenticate(q, &error)));
-    }
-    if (q) {
-        ok = query_notify_and_destroy(q, ok, error);
-    }
-    return ok;
-}
-
-
-/* AUDIT[securityd](done):
-   query (ok) is a caller provided dictionary, only its cf type has been checked.
- */
-bool
-_SecItemDelete(CFDictionaryRef query, CFArrayRef accessGroups, CFErrorRef *error)
-{
-    CFIndex ag_count;
-    if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups))) {
-        return SecError(errSecMissingEntitlement, error,
-                           CFSTR("client has neither application-identifier nor keychain-access-groups entitlements"));
-    }
-
-    if (CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), CFSTR("*"))) {
-        /* Having the special accessGroup "*" allows access to all accessGroups. */
-        accessGroups = NULL;
-    }
-
-    Query *q = query_create_with_limit(query, kSecMatchUnlimited, error);
-    bool ok;
-    if (q) {
-        q->q_crypto_op = kSecKsDelete;
-        query_set_caller_access_groups(q, accessGroups);
-        /* Sanity check the query. */
-        if (q->q_limit != kSecMatchUnlimited)
-            ok = SecError(errSecMatchLimitUnsupported, error, CFSTR("match limit not supported by delete"));
-        else if (query_match_count(q) != 0)
-            ok = SecError(errSecItemMatchUnsupported, error, CFSTR("match not supported by delete"));
-        else if (q->q_ref)
-            ok = SecError(errSecValueRefUnsupported, error, CFSTR("value ref not supported by delete"));
-        else if (q->q_row_id && query_attr_count(q))
-            ok = SecError(errSecItemIllegalQuery, error, CFSTR("rowid and other attributes are mutually exclusive"));
-        else {
-            if (!q->q_use_tomb && SOSCCThisDeviceDefinitelyNotActiveInCircle()) {
-                q->q_use_tomb = kCFBooleanFalse;
-            }
-            query_enable_interactive(q);
-            do {
-                ok = kc_with_dbt(true, error, ^(SecDbConnectionRef dbt) {
-                    return s3dl_query_delete(dbt, q, accessGroups, error);
-                });
-            } while (query_needs_authentication(q) && (ok = query_authenticate(q, &error)));
-        }
-        ok = query_notify_and_destroy(q, ok, error);
-    } else {
-        ok = false;
-    }
-    return ok;
-}
-
-
-/* AUDIT[securityd](done):
-   No caller provided inputs.
- */
-static bool
-SecItemServerDeleteAll(CFErrorRef *error) {
-    return kc_with_dbt(true, error, ^bool (SecDbConnectionRef dbt) {
-        return (kc_transaction(dbt, error, ^bool {
-            return (SecDbExec(dbt, CFSTR("DELETE from genp;"), error) &&
-                    SecDbExec(dbt, CFSTR("DELETE from inet;"), error) &&
-                    SecDbExec(dbt, CFSTR("DELETE from cert;"), error) &&
-                    SecDbExec(dbt, CFSTR("DELETE from keys;"), error));
-        }) && SecDbExec(dbt, CFSTR("VACUUM;"), error));
-    });
-}
-
-bool
-_SecItemDeleteAll(CFErrorRef *error) {
-    return SecItemServerDeleteAll(error);
-}
-
-
-// MARK: -
-// MARK: Shared web credentials
-
-/* constants */
-#define SEC_CONST_DECL(k,v) CFTypeRef k = (CFTypeRef)(CFSTR(v));
-
-SEC_CONST_DECL (kSecSafariAccessGroup, "com.apple.cfnetwork");
-SEC_CONST_DECL (kSecSafariDefaultComment, "default");
-SEC_CONST_DECL (kSecSafariPasswordsNotSaved, "Passwords not saved");
-SEC_CONST_DECL (kSecSharedCredentialUrlScheme, "https://");
-SEC_CONST_DECL (kSecSharedWebCredentialsService, "webcredentials");
-
-#if !TARGET_IPHONE_SIMULATOR
-static SWCFlags
-_SecAppDomainApprovalStatus(CFStringRef appID, CFStringRef fqdn, CFErrorRef *error)
-{
-    __block SWCFlags flags = kSWCFlags_None;
-
-#if TARGET_OS_IPHONE
-    CFRetainSafe(appID);
-    CFRetainSafe(fqdn);
-    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
-    dispatch_retain(semaphore);
-    if (0 == SWCCheckService(kSecSharedWebCredentialsService, appID, fqdn,
-        ^void (OSStatus inStatus, SWCFlags inFlags, CFDictionaryRef inDetails) {
-            if (!inStatus) { flags = inFlags; }
-            CFReleaseSafe(appID);
-            CFReleaseSafe(fqdn);
-            dispatch_semaphore_signal(semaphore);
-            dispatch_release(semaphore);
-            //secerror("SWCCheckService: inStatus=%d, flags=%0X", inStatus, flags);
-        }))
-    {
-        // wait for the block to complete, as we need its answer
-        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
-    }
-    else // didn't queue the block
-    {
-        CFReleaseSafe(appID);
-        CFReleaseSafe(fqdn);
-        dispatch_release(semaphore);
-    }
-    dispatch_release(semaphore);
-#else
-    flags |= (kSWCFlag_SiteApproved);
-#endif
-
-    if (!error) { return flags; }
-    *error = NULL;
-
-    // check website approval status
-    if (!(flags & kSWCFlag_SiteApproved)) {
-        if (flags & kSWCFlag_Pending) {
-            SecError(errSecAuthFailed, error, CFSTR("Approval is pending for \"%@\", try later"), fqdn);
-        } else {
-            SecError(errSecAuthFailed, error, CFSTR("\"%@\" failed to approve \"%@\""), fqdn, appID);
-        }
-        return flags;
-    }
-
-    // check user approval status
-    if (flags & kSWCFlag_UserDenied) {
-        SecError(errSecAuthFailed, error, CFSTR("User denied access to \"%@\" by \"%@\""), fqdn, appID);
-    }
-    return flags;
-}
-#endif
-
-#if !TARGET_IPHONE_SIMULATOR
-static bool
-_SecEntitlementContainsDomainForService(CFArrayRef domains, CFStringRef domain, CFStringRef service)
-{
-    bool result = false;
-    CFIndex idx, count = (domains) ? CFArrayGetCount(domains) : (CFIndex) 0;
-    if (!count || !domain || !service) {
-        return result;
-    }
-    for (idx=0; idx < count; idx++) {
-        CFStringRef str = (CFStringRef) CFArrayGetValueAtIndex(domains, idx);
-        if (str && CFStringHasPrefix(str, kSecSharedWebCredentialsService)) {
-            CFIndex prefix_len = CFStringGetLength(kSecSharedWebCredentialsService)+1;
-            CFIndex substr_len = CFStringGetLength(str) - prefix_len;
-            CFRange range = { prefix_len, substr_len };
-            CFStringRef substr = CFStringCreateWithSubstring(kCFAllocatorDefault, str, range);
-            if (substr && CFEqual(substr, domain)) {
-                result = true;
-            }
-            CFReleaseSafe(substr);
-            if (result) {
-                break;
-            }
-        }
-    }
-    return result;
-}
-#endif
-
-static bool
-_SecAddNegativeWebCredential(CFStringRef fqdn, CFStringRef appID, bool forSafari)
-{
-    bool result = false;
-    if (!fqdn) { return result; }
-
-#if TARGET_OS_IPHONE
-    // update our database
-    CFRetainSafe(appID);
-    CFRetainSafe(fqdn);
-    if (0 == SWCSetServiceFlags(kSecSharedWebCredentialsService,
-        appID, fqdn, kSWCFlag_ExternalMask, kSWCFlag_UserDenied,
-        ^void(OSStatus inStatus, SWCFlags inNewFlags){
-            CFReleaseSafe(appID);
-            CFReleaseSafe(fqdn);
-        }))
-    {
-        result = true;
-    }
-    else // didn't queue the block
-    {
-        CFReleaseSafe(appID);
-        CFReleaseSafe(fqdn);
-    }
-#endif
-    if (!forSafari) { return result; }
-
-    // below this point: create a negative Safari web credential item
-
-    CFMutableDictionaryRef attrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-    if (!attrs) { return result; }
-
-    CFErrorRef error = NULL;
-    CFStringRef accessGroup = CFSTR("*");
-    CFArrayRef accessGroups = CFArrayCreate(kCFAllocatorDefault, (const void **)&accessGroup, 1, &kCFTypeArrayCallBacks);
-
-    CFDictionaryAddValue(attrs, kSecClass, kSecClassInternetPassword);
-    CFDictionaryAddValue(attrs, kSecAttrAccessGroup, kSecSafariAccessGroup);
-    CFDictionaryAddValue(attrs, kSecAttrAuthenticationType, kSecAttrAuthenticationTypeHTMLForm);
-    CFDictionaryAddValue(attrs, kSecAttrProtocol, kSecAttrProtocolHTTPS);
-    CFDictionaryAddValue(attrs, kSecAttrServer, fqdn);
-    CFDictionaryAddValue(attrs, kSecAttrSynchronizable, kCFBooleanTrue);
-
-    (void)_SecItemDelete(attrs, accessGroups, &error);
-    CFReleaseNull(error);
-
-    CFDictionaryAddValue(attrs, kSecAttrAccount, kSecSafariPasswordsNotSaved);
-    CFDictionaryAddValue(attrs, kSecAttrComment, kSecSafariDefaultComment);
-
-    CFStringRef label = CFStringCreateWithFormat(kCFAllocatorDefault,
-                                                 NULL, CFSTR("%@ (%@)"), fqdn, kSecSafariPasswordsNotSaved);
-    if (label) {
-        CFDictionaryAddValue(attrs, kSecAttrLabel, label);
-        CFReleaseSafe(label);
-    }
-
-    UInt8 space = ' ';
-    CFDataRef data = CFDataCreate(kCFAllocatorDefault, &space, 1);
-    if (data) {
-        CFDictionarySetValue(attrs, kSecValueData, data);
-        CFReleaseSafe(data);
-    }
-
-    CFTypeRef addResult = NULL;
-    result = _SecItemAdd(attrs, accessGroups, &addResult, &error);
-
-    CFReleaseSafe(addResult);
-    CFReleaseSafe(error);
-    CFReleaseSafe(attrs);
-    CFReleaseSafe(accessGroups);
-
-    return result;
-}
-
-/* Specialized version of SecItemAdd for shared web credentials */
-bool
-_SecAddSharedWebCredential(CFDictionaryRef attributes,
-    const audit_token_t *clientAuditToken,
-    CFStringRef appID,
-    CFArrayRef domains,
-    CFTypeRef *result,
-    CFErrorRef *error) {
-
-    CFStringRef fqdn = CFDictionaryGetValue(attributes, kSecAttrServer);
-    CFStringRef account = CFDictionaryGetValue(attributes, kSecAttrAccount);
-#if TARGET_OS_IPHONE
-    CFStringRef password = CFDictionaryGetValue(attributes, kSecSharedPassword);
-#else
-    CFStringRef password = CFDictionaryGetValue(attributes, CFSTR("spwd"));
-#endif
-    CFStringRef accessGroup = CFSTR("*");
-    CFArrayRef accessGroups = NULL;
-    CFMutableDictionaryRef query = NULL, attrs = NULL;
-    SInt32 port = -1;
-    bool ok = false, update = false;
-    //bool approved = false;
-
-    // check autofill enabled status
-    if (!swca_autofill_enabled(clientAuditToken)) {
-        SecError(errSecBadReq, error, CFSTR("Autofill is not enabled in Safari settings"));
-        goto cleanup;
-    }
-
-    // parse fqdn with CFURL here, since it could be specified as domain:port
-    if (fqdn) {
-        CFRetainSafe(fqdn);
-        CFStringRef urlStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@%@"), kSecSharedCredentialUrlScheme, fqdn);
-        if (urlStr) {
-            CFURLRef url = CFURLCreateWithString(kCFAllocatorDefault, urlStr, nil);
-            if (url) {
-                CFStringRef hostname = CFURLCopyHostName(url);
-                if (hostname) {
-                    CFReleaseSafe(fqdn);
-                    fqdn = hostname;
-                    port = CFURLGetPortNumber(url);
-                }
-                CFReleaseSafe(url);
-            }
-            CFReleaseSafe(urlStr);
-        }
-    }
-
-    if (!account) {
-        SecError(errSecParam, error, CFSTR("No account provided"));
-        goto cleanup;
-    }
-    if (!fqdn) {
-        SecError(errSecParam, error, CFSTR("No domain provided"));
-        goto cleanup;
-    }
-
-#if TARGET_IPHONE_SIMULATOR
-    secerror("app/site association entitlements not checked in Simulator");
-#else
-    OSStatus status = errSecMissingEntitlement;
-    // validate that fqdn is part of caller's shared credential domains entitlement
-    if (!appID) {
-        SecError(status, error, CFSTR("Missing application-identifier entitlement"));
-        goto cleanup;
-    }
-    if (_SecEntitlementContainsDomainForService(domains, fqdn, kSecSharedWebCredentialsService)) {
-        status = errSecSuccess;
-    }
-    if (errSecSuccess != status) {
-        CFStringRef msg = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
-                                                   CFSTR("%@ not found in %@ entitlement"), fqdn, kSecEntitlementAssociatedDomains);
-        if (!msg) {
-            msg = CFRetain(CFSTR("Requested domain not found in entitlement"));
-        }
-        SecError(status, error, CFSTR("%@"), msg);
-        CFReleaseSafe(msg);
-        goto cleanup;
-    }
-#endif
-
-#if TARGET_IPHONE_SIMULATOR
-    secerror("Ignoring app/site approval state in the Simulator.");
-#else
-    // get approval status for this app/domain pair
-    SWCFlags flags = _SecAppDomainApprovalStatus(appID, fqdn, error);
-    //approved = ((flags & kSWCFlag_SiteApproved) && (flags & kSWCFlag_UserApproved));
-    if (!(flags & kSWCFlag_SiteApproved)) {
-        goto cleanup;
-    }
-#endif
-
-    // give ourselves access to see matching items for kSecSafariAccessGroup
-    accessGroups = CFArrayCreate(kCFAllocatorDefault, (const void **)&accessGroup, 1, &kCFTypeArrayCallBacks);
-
-    // create lookup query
-    query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-    if (!query) {
-        SecError(errSecAllocate, error, CFSTR("Unable to create query dictionary"));
-        goto cleanup;
-    }
-    CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword);
-    CFDictionaryAddValue(query, kSecAttrAccessGroup, kSecSafariAccessGroup);
-    CFDictionaryAddValue(query, kSecAttrAuthenticationType, kSecAttrAuthenticationTypeHTMLForm);
-    CFDictionaryAddValue(query, kSecAttrServer, fqdn);
-    CFDictionaryAddValue(query, kSecAttrSynchronizable, kCFBooleanTrue);
-
-    // check for presence of Safari's negative entry ('passwords not saved')
-    CFDictionarySetValue(query, kSecAttrAccount, kSecSafariPasswordsNotSaved);
-    ok = _SecItemCopyMatching(query, accessGroups, result, error);
-    CFReleaseNull(*result);
-    CFReleaseNull(*error);
-    if (ok) {
-        SecError(errSecDuplicateItem, error, CFSTR("Item already exists for this server"));
-        goto cleanup;
-    }
-
-    // now use the provided account (and optional port number, if one was present)
-    CFDictionarySetValue(query, kSecAttrAccount, account);
-    if (port < -1 || port > 0) {
-        SInt16 portValueShort = (port & 0xFFFF);
-        CFNumberRef portNumber = CFNumberCreate(NULL, kCFNumberSInt16Type, &portValueShort);
-        CFDictionaryAddValue(query, kSecAttrPort, portNumber);
-        CFReleaseSafe(portNumber);
-    }
-
-    // look up existing password
-    if (_SecItemCopyMatching(query, accessGroups, result, error)) {
-        // found it, so this becomes either an "update password" or "delete password" operation
-        CFReleaseNull(*result);
-        CFReleaseNull(*error);
-        update = (password != NULL);
-        if (update) {
-            attrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-            CFDataRef credential = CFStringCreateExternalRepresentation(kCFAllocatorDefault, password, kCFStringEncodingUTF8, 0);
-            CFDictionaryAddValue(attrs, kSecValueData, credential);
-            CFReleaseSafe(credential);
-            CFDictionaryAddValue(attrs, kSecAttrComment, kSecSafariDefaultComment);
-
-            // confirm the update
-            // (per rdar://16676310 we always prompt, even if there was prior user approval)
-            ok = /*approved ||*/ swca_confirm_operation(swca_update_request_id, clientAuditToken, query, error,
-                ^void (CFStringRef fqdn) { _SecAddNegativeWebCredential(fqdn, appID, false); });
-            if (ok) {
-                ok = _SecItemUpdate(query, attrs, accessGroups, error);
-            }
-        }
-        else {
-            // confirm the delete
-            // (per rdar://16676288 we always prompt, even if there was prior user approval)
-            ok = /*approved ||*/ swca_confirm_operation(swca_delete_request_id, clientAuditToken, query, error,
-                ^void (CFStringRef fqdn) { _SecAddNegativeWebCredential(fqdn, appID, false); });
-            if (ok) {
-                ok = _SecItemDelete(query, accessGroups, error);
-            }
-        }
-        if (ok) {
-            CFReleaseNull(*error);
-        }
-        goto cleanup;
-    }
-    CFReleaseNull(*result);
-    CFReleaseNull(*error);
-
-    // password does not exist, so prepare to add it
-    if (true) {
-        CFStringRef label = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ (%@)"), fqdn, account);
-        if (label) {
-            CFDictionaryAddValue(query, kSecAttrLabel, label);
-            CFReleaseSafe(label);
-        }
-        // NOTE: we always expect to use HTTPS for web forms.
-        CFDictionaryAddValue(query, kSecAttrProtocol, kSecAttrProtocolHTTPS);
-
-        CFDataRef credential = CFStringCreateExternalRepresentation(kCFAllocatorDefault, password, kCFStringEncodingUTF8, 0);
-        CFDictionarySetValue(query, kSecValueData, credential);
-        CFReleaseSafe(credential);
-        CFDictionarySetValue(query, kSecAttrComment, kSecSafariDefaultComment);
-
-        CFReleaseSafe(accessGroups);
-        accessGroups = CFArrayCreate(kCFAllocatorDefault, (const void **)&kSecSafariAccessGroup, 1, &kCFTypeArrayCallBacks);
-
-        // mark the item as created by this function
-        const int32_t creator_value = 'swca';
-        CFNumberRef creator = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &creator_value);
-        if (creator) {
-            CFDictionarySetValue(query, kSecAttrCreator, creator);
-            CFReleaseSafe(creator);
-            ok = true;
-        }
-        else {
-            // confirm the add
-            // (per rdar://16680019, we won't prompt here in the normal case)
-            ok = /*approved ||*/ swca_confirm_operation(swca_add_request_id, clientAuditToken, query, error,
-                ^void (CFStringRef fqdn) { _SecAddNegativeWebCredential(fqdn, appID, false); });
-        }
-    }
-    if (ok) {
-        ok = _SecItemAdd(query, accessGroups, result, error);
-    }
-
-cleanup:
-#if 0 /* debugging */
-{
-    const char *op_str = (password) ? ((update) ? "updated" : "added") : "deleted";
-    const char *result_str = (ok) ? "true" : "false";
-    secerror("result=%s, %s item %@, error=%@", result_str, op_str, *result, *error);
-}
-#else
-    (void)update;
-#endif
-    CFReleaseSafe(attrs);
-    CFReleaseSafe(query);
-    CFReleaseSafe(accessGroups);
-    CFReleaseSafe(fqdn);
-    return ok;
-}
-
-/* Specialized version of SecItemCopyMatching for shared web credentials */
-bool
-_SecCopySharedWebCredential(CFDictionaryRef query,
-    const audit_token_t *clientAuditToken,
-    CFStringRef appID,
-    CFArrayRef domains,
-    CFTypeRef *result,
-    CFErrorRef *error) {
-
-    CFMutableArrayRef credentials = NULL;
-    CFMutableArrayRef foundItems = NULL;
-    CFMutableArrayRef fqdns = NULL;
-    CFArrayRef accessGroups = NULL;
-    CFStringRef fqdn = NULL;
-    CFStringRef account = NULL;
-    CFIndex idx, count;
-    SInt32 port = -1;
-    bool ok = false;
-
-    require_quiet(result, cleanup);
-    credentials = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
-    foundItems = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
-    fqdns = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
-
-    // give ourselves access to see matching items for kSecSafariAccessGroup
-    CFStringRef accessGroup = CFSTR("*");
-    accessGroups = CFArrayCreate(kCFAllocatorDefault, (const void **)&accessGroup, 1, &kCFTypeArrayCallBacks);
-
-    // On input, the query dictionary contains optional fqdn and account entries.
-    fqdn = CFDictionaryGetValue(query, kSecAttrServer);
-    account = CFDictionaryGetValue(query, kSecAttrAccount);
-
-    // Check autofill enabled status
-    if (!swca_autofill_enabled(clientAuditToken)) {
-        SecError(errSecBadReq, error, CFSTR("Autofill is not enabled in Safari settings"));
-        goto cleanup;
-    }
-
-    // Check fqdn; if NULL, add domains from caller's entitlement.
-    if (fqdn) {
-        CFArrayAppendValue(fqdns, fqdn);
-    }
-    else if (domains) {
-        CFIndex idx, count = CFArrayGetCount(domains);
-        for (idx=0; idx < count; idx++) {
-            CFStringRef str = (CFStringRef) CFArrayGetValueAtIndex(domains, idx);
-            // Parse the entry for our service label prefix
-            if (str && CFStringHasPrefix(str, kSecSharedWebCredentialsService)) {
-                CFIndex prefix_len = CFStringGetLength(kSecSharedWebCredentialsService)+1;
-                CFIndex substr_len = CFStringGetLength(str) - prefix_len;
-                CFRange range = { prefix_len, substr_len };
-                fqdn = CFStringCreateWithSubstring(kCFAllocatorDefault, str, range);
-                if (fqdn) {
-                    CFArrayAppendValue(fqdns, fqdn);
-                    CFRelease(fqdn);
-                }
-            }
-        }
-    }
-    count = CFArrayGetCount(fqdns);
-    if (count < 1) {
-        SecError(errSecParam, error, CFSTR("No domain provided"));
-        goto cleanup;
-    }
-
-    // Aggregate search results for each domain
-    for (idx = 0; idx < count; idx++) {
-        CFMutableArrayRef items = NULL;
-        CFMutableDictionaryRef attrs = NULL;
-        fqdn = (CFStringRef) CFArrayGetValueAtIndex(fqdns, idx);
-        CFRetainSafe(fqdn);
-        port = -1;
-
-        // Parse the fqdn for a possible port specifier.
-        if (fqdn) {
-            CFStringRef urlStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@%@"), kSecSharedCredentialUrlScheme, fqdn);
-            if (urlStr) {
-                CFURLRef url = CFURLCreateWithString(kCFAllocatorDefault, urlStr, nil);
-                if (url) {
-                    CFStringRef hostname = CFURLCopyHostName(url);
-                    if (hostname) {
-                        CFReleaseSafe(fqdn);
-                        fqdn = hostname;
-                        port = CFURLGetPortNumber(url);
-                    }
-                    CFReleaseSafe(url);
-                }
-                CFReleaseSafe(urlStr);
-            }
-        }
-
-    #if TARGET_IPHONE_SIMULATOR
-        secerror("app/site association entitlements not checked in Simulator");
-    #else
-           OSStatus status = errSecMissingEntitlement;
-        if (!appID) {
-            SecError(status, error, CFSTR("Missing application-identifier entitlement"));
-            CFReleaseSafe(fqdn);
-            goto cleanup;
-        }
-        // validate that fqdn is part of caller's entitlement
-        if (_SecEntitlementContainsDomainForService(domains, fqdn, kSecSharedWebCredentialsService)) {
-            status = errSecSuccess;
-        }
-        if (errSecSuccess != status) {
-            CFStringRef msg = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
-                CFSTR("%@ not found in %@ entitlement"), fqdn, kSecEntitlementAssociatedDomains);
-            if (!msg) {
-                msg = CFRetain(CFSTR("Requested domain not found in entitlement"));
-            }
-            SecError(status, error, CFSTR("%@"), msg);
-            CFReleaseSafe(msg);
-            CFReleaseSafe(fqdn);
-            goto cleanup;
-        }
-    #endif
-
-        attrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-        if (!attrs) {
-            SecError(errSecAllocate, error, CFSTR("Unable to create query dictionary"));
-            CFReleaseSafe(fqdn);
-            goto cleanup;
-        }
-        CFDictionaryAddValue(attrs, kSecClass, kSecClassInternetPassword);
-        CFDictionaryAddValue(attrs, kSecAttrAccessGroup, kSecSafariAccessGroup);
-        CFDictionaryAddValue(attrs, kSecAttrAuthenticationType, kSecAttrAuthenticationTypeHTMLForm);
-        CFDictionaryAddValue(attrs, kSecAttrServer, fqdn);
-        if (account) {
-            CFDictionaryAddValue(attrs, kSecAttrAccount, account);
-        }
-        if (port < -1 || port > 0) {
-            SInt16 portValueShort = (port & 0xFFFF);
-            CFNumberRef portNumber = CFNumberCreate(NULL, kCFNumberSInt16Type, &portValueShort);
-            CFDictionaryAddValue(attrs, kSecAttrPort, portNumber);
-            CFReleaseSafe(portNumber);
-        }
-        CFDictionaryAddValue(attrs, kSecAttrSynchronizable, kCFBooleanTrue);
-        CFDictionaryAddValue(attrs, kSecMatchLimit, kSecMatchLimitAll);
-        CFDictionaryAddValue(attrs, kSecReturnAttributes, kCFBooleanTrue);
-        CFDictionaryAddValue(attrs, kSecReturnData, kCFBooleanTrue);
-
-        ok = _SecItemCopyMatching(attrs, accessGroups, (CFTypeRef*)&items, error);
-        if (count > 1) {
-            // ignore interim error since we have multiple domains to search
-            CFReleaseNull(*error);
-        }
-        if (ok && items && CFGetTypeID(items) == CFArrayGetTypeID()) {
-    #if TARGET_IPHONE_SIMULATOR
-            secerror("Ignoring app/site approval state in the Simulator.");
-            bool approved = true;
-    #else
-            // get approval status for this app/domain pair
-            SWCFlags flags = _SecAppDomainApprovalStatus(appID, fqdn, error);
-            if (count > 1) {
-                // ignore interim error since we have multiple domains to check
-                CFReleaseNull(*error);
-            }
-            bool approved = (flags & kSWCFlag_SiteApproved);
-    #endif
-            if (approved) {
-                CFArrayAppendArray(foundItems, items, CFRangeMake(0, CFArrayGetCount(items)));
-            }
-        }
-        CFReleaseSafe(items);
-        CFReleaseSafe(attrs);
-        CFReleaseSafe(fqdn);
-    }
-
-//  If matching credentials are found, the credentials provided to the completionHandler
-//  will be a CFArrayRef containing CFDictionaryRef entries. Each dictionary entry will
-//  contain the following pairs (see Security/SecItem.h):
-//  key: kSecAttrServer     value: CFStringRef (the website)
-//  key: kSecAttrAccount    value: CFStringRef (the account)
-//  key: kSecSharedPassword value: CFStringRef (the password)
-//  Optional keys:
-//  key: kSecAttrPort       value: CFNumberRef (the port number, if non-standard for https)
-
-    count = CFArrayGetCount(foundItems);
-    for (idx = 0; idx < count; idx++) {
-        CFDictionaryRef dict = (CFDictionaryRef) CFArrayGetValueAtIndex(foundItems, idx);
-        CFMutableDictionaryRef newdict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-        if (newdict && dict && CFGetTypeID(dict) == CFDictionaryGetTypeID()) {
-            CFStringRef srvr = CFDictionaryGetValue(dict, kSecAttrServer);
-            CFStringRef acct = CFDictionaryGetValue(dict, kSecAttrAccount);
-            CFNumberRef pnum = CFDictionaryGetValue(dict, kSecAttrPort);
-            CFStringRef icmt = CFDictionaryGetValue(dict, kSecAttrComment);
-            CFDataRef data = CFDictionaryGetValue(dict, kSecValueData);
-            if (srvr) {
-                CFDictionaryAddValue(newdict, kSecAttrServer, srvr);
-            }
-            if (acct) {
-                CFDictionaryAddValue(newdict, kSecAttrAccount, acct);
-            }
-            if (pnum) {
-                SInt16 pval = -1;
-                if (CFNumberGetValue(pnum, kCFNumberSInt16Type, &pval) &&
-                    (pval < -1 || pval > 0)) {
-                    CFDictionaryAddValue(newdict, kSecAttrPort, pnum);
-                }
-            }
-            if (data) {
-                CFStringRef password = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, data, kCFStringEncodingUTF8);
-                if (password) {
-                #if TARGET_OS_IPHONE
-                    CFDictionaryAddValue(newdict, kSecSharedPassword, password);
-                #else
-                    CFDictionaryAddValue(newdict, CFSTR("spwd"), password);
-                #endif
-                    CFReleaseSafe(password);
-                }
-            }
-            if (icmt && CFEqual(icmt, kSecSafariDefaultComment)) {
-                CFArrayInsertValueAtIndex(credentials, 0, newdict);
-            } else {
-                CFArrayAppendValue(credentials, newdict);
-            }
-        }
-        CFReleaseSafe(newdict);
-    }
-
-    if (count) {
-
-        ok = false;
-
-        // create a new array of dictionaries (without the actual password) for picker UI
-        count = CFArrayGetCount(credentials);
-        CFMutableArrayRef items = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
-        for (idx = 0; idx < count; idx++) {
-            CFDictionaryRef dict = (CFDictionaryRef) CFArrayGetValueAtIndex(credentials, idx);
-            CFMutableDictionaryRef newdict = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, dict);
-        #if TARGET_OS_IPHONE
-            CFDictionaryRemoveValue(newdict, kSecSharedPassword);
-        #else
-            CFDictionaryRemoveValue(newdict, CFSTR("spwd"));
-        #endif
-            CFArrayAppendValue(items, newdict);
-            CFReleaseSafe(newdict);
-        }
-
-        // prompt user to select one of the dictionary items
-        CFDictionaryRef selected = swca_copy_selected_dictionary(swca_select_request_id,
-                                                                 clientAuditToken, items, error);
-        if (selected) {
-            // find the matching item in our credentials array
-            CFStringRef srvr = CFDictionaryGetValue(selected, kSecAttrServer);
-            CFStringRef acct = CFDictionaryGetValue(selected, kSecAttrAccount);
-            CFNumberRef pnum = CFDictionaryGetValue(selected, kSecAttrPort);
-            for (idx = 0; idx < count; idx++) {
-                CFDictionaryRef dict = (CFDictionaryRef) CFArrayGetValueAtIndex(credentials, idx);
-                CFStringRef srvr1 = CFDictionaryGetValue(dict, kSecAttrServer);
-                CFStringRef acct1 = CFDictionaryGetValue(dict, kSecAttrAccount);
-                CFNumberRef pnum1 = CFDictionaryGetValue(dict, kSecAttrPort);
-
-                if (!srvr || !srvr1 || !CFEqual(srvr, srvr1)) continue;
-                if (!acct || !acct1 || !CFEqual(acct, acct1)) continue;
-                if ((pnum && pnum1) && !CFEqual(pnum, pnum1)) continue;
-
-                // we have a match!
-                CFReleaseSafe(selected);
-                CFRetainSafe(dict);
-                selected = dict;
-                ok = true;
-                break;
-            }
-        }
-        CFReleaseSafe(items);
-        CFArrayRemoveAllValues(credentials);
-        if (selected && ok) {
-#if TARGET_OS_IPHONE
-            fqdn = CFDictionaryGetValue(selected, kSecAttrServer);
-#endif
-            CFArrayAppendValue(credentials, selected);
-        }
-
-#if 0
-        // confirm the access
-        ok = swca_confirm_operation(swca_copy_request_id, clientAuditToken, query, error,
-                    ^void (CFStringRef fqdn) { _SecAddNegativeWebCredential(fqdn, appID, false); });
-#endif
-        if (ok) {
-            #if TARGET_OS_IPHONE
-            // register confirmation with database
-            CFRetainSafe(appID);
-            CFRetainSafe(fqdn);
-            if (0 != SWCSetServiceFlags(kSecSharedWebCredentialsService,
-                appID, fqdn, kSWCFlag_ExternalMask, kSWCFlag_UserApproved,
-                ^void(OSStatus inStatus, SWCFlags inNewFlags){
-                    CFReleaseSafe(appID);
-                    CFReleaseSafe(fqdn);
-                }))
-            {
-                 // we didn't queue the block
-                CFReleaseSafe(appID);
-                CFReleaseSafe(fqdn);
-            }
-            #endif
-        }
-        CFReleaseSafe(selected);
-    }
-    else if (NULL == *error) {
-        // found no items, and we haven't already filled in the error
-        SecError(errSecItemNotFound, error, CFSTR("no matching items found"));
-    }
-
-cleanup:
-    if (!ok) {
-        CFArrayRemoveAllValues(credentials);
-    }
-    CFReleaseSafe(foundItems);
-    *result = credentials;
-    CFReleaseSafe(accessGroups);
-    CFReleaseSafe(fqdns);
-#if 0 /* debugging */
-    secerror("result=%s, copied items %@, error=%@", (ok) ? "true" : "false", *result, *error);
-#endif
-    return ok;
-}
-
-// MARK: -
-// MARK: Keychain backup
-
-CF_RETURNS_RETAINED CFDataRef
-_SecServerKeychainBackup(CFDataRef keybag, CFDataRef passcode, CFErrorRef *error) {
-    CFDataRef backup;
-       SecDbConnectionRef dbt = SecDbConnectionAquire(kc_dbhandle(), false, error);
-
-       if (!dbt)
-               return NULL;
-
-    if (keybag == NULL && passcode == NULL) {
-#if USE_KEYSTORE
-        backup = SecServerExportKeychain(dbt, KEYBAG_DEVICE, backup_keybag_handle, error);
-#else /* !USE_KEYSTORE */
-        SecError(errSecParam, error, CFSTR("Why are you doing this?"));
-        backup = NULL;
-#endif /* USE_KEYSTORE */
-    } else {
-        backup = SecServerKeychainBackup(dbt, keybag, passcode, error);
-    }
-
-    SecDbConnectionRelease(dbt);
-
-    return backup;
-}
-
-bool
-_SecServerKeychainRestore(CFDataRef backup, CFDataRef keybag, CFDataRef passcode, CFErrorRef *error) {
-    if (backup == NULL || keybag == NULL)
-        return SecError(errSecParam, error, CFSTR("backup or keybag missing"));
-
-    __block bool ok = true;
-    ok &= SecDbPerformWrite(kc_dbhandle(), error, ^(SecDbConnectionRef dbconn) {
-        ok = SecServerKeychainRestore(dbconn, backup, keybag, passcode, error);
-    });
-
-    if (ok) {
-        SecKeychainChanged(true);
-    }
-
-    return ok;
-}
-
-// MARK: -
-// MARK: SecItemDataSource
-
-// Make sure to call this before any writes to the keychain, so that we fire
-// up the engines to monitor manifest changes.
-SOSDataSourceFactoryRef SecItemDataSourceFactoryGetDefault(void) {
-    return SecItemDataSourceFactoryGetShared(kc_dbhandle());
-        }
-
-/* AUDIT[securityd]:
-   args_in (ok) is a caller provided, CFDictionaryRef.
- */
-
-CF_RETURNS_RETAINED CFArrayRef
-_SecServerKeychainSyncUpdateKeyParameter(CFDictionaryRef updates, CFErrorRef *error) {
-    // This never fails, trust us!
-    return SOSCCHandleUpdateKeyParameter(updates);
-}
-
-
-CF_RETURNS_RETAINED CFArrayRef
-_SecServerKeychainSyncUpdateCircle(CFDictionaryRef updates, CFErrorRef *error) {
-    // This never fails, trust us!
-    return SOSCCHandleUpdateCircle(updates);
-}
-
-CF_RETURNS_RETAINED CFArrayRef
-_SecServerKeychainSyncUpdateMessage(CFDictionaryRef updates, CFErrorRef *error) {
-    // This never fails, trust us!
-    return SOSCCHandleUpdateMessage(updates);
-}
-
-
-//
-// Truthiness in the cloud backup/restore support.
-//
-
-static CFDictionaryRef
-_SecServerCopyTruthInTheCloud(CFDataRef keybag, CFDataRef password,
-    CFDictionaryRef backup, CFErrorRef *error)
-{
-    SOSManifestRef mold = NULL, mnow = NULL, mdelete = NULL, madd = NULL;
-    __block CFMutableDictionaryRef backup_new = NULL;
-    keybag_handle_t bag_handle;
-    if (!ks_open_keybag(keybag, password, &bag_handle, error))
-        return backup_new;
-
-    // We need to have a datasource singleton for protection domain
-    // kSecAttrAccessibleWhenUnlocked and keep a single shared engine
-    // instance around which we create in the datasource constructor as well.
-    SOSDataSourceFactoryRef dsf = SecItemDataSourceFactoryGetDefault();
-    SOSDataSourceRef ds = dsf->create_datasource(dsf, kSecAttrAccessibleWhenUnlocked, error);
-    if (ds) {
-        backup_new = backup ? CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, backup) : CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-        mold = SOSCreateManifestWithBackup(backup, error);
-        SOSEngineRef engine = SOSDataSourceGetSharedEngine(ds, error);
-        mnow = SOSEngineCopyManifest(engine, error);
-        if (!mnow) {
-            mnow = SOSDataSourceCopyManifest(ds, error);
-        }
-        if (!mnow) {
-            CFReleaseNull(backup_new);
-            secerror("failed to obtain manifest for keychain: %@", error ? *error : NULL);
-        } else {
-            SOSManifestDiff(mold, mnow, &mdelete, &madd, error);
-        }
-
-        // Delete everything from the new_backup that is no longer in the datasource according to the datasources manifest.
-        SOSManifestForEach(mdelete, ^(CFDataRef digest_data, bool *stop) {
-            CFStringRef deleted_item_key = CFDataCopyHexString(digest_data);
-            CFDictionaryRemoveValue(backup_new, deleted_item_key);
-            CFRelease(deleted_item_key);
-        });
-
-        __block struct SOSDigestVector dvdel = SOSDigestVectorInit;
-        SOSDataSourceForEachObject(ds, madd, error, ^void(CFDataRef digest, SOSObjectRef object, bool *stop) {
-            CFErrorRef localError = NULL;
-            CFDataRef digest_data = NULL;
-            CFTypeRef value = NULL;
-            if (!object) {
-                // Key in our manifest can't be found in db, remove it from our manifest
-                SOSDigestVectorAppend(&dvdel, CFDataGetBytePtr(digest));
-            } else if (!(digest_data = SOSObjectCopyDigest(ds, object, &localError))
-                || !(value = SOSObjectCopyBackup(ds, object, bag_handle, &localError))) {
-                if (SecErrorGetOSStatus(localError) == errSecDecode) {
-                    // Ignore decode errors, pretend the objects aren't there
-                    CFRelease(localError);
-                    // Object undecodable, remove it from our manifest
-                    SOSDigestVectorAppend(&dvdel, CFDataGetBytePtr(digest));
-                } else {
-                    // Stop iterating and propagate out all other errors.
-                    *stop = true;
-                    *error = localError;
-                    CFReleaseNull(backup_new);
-                }
-            } else {
-                // TODO: Should we skip tombstones here?
-                CFStringRef key = CFDataCopyHexString(digest_data);
-                CFDictionarySetValue(backup_new, key, value);
-                CFReleaseSafe(key);
-            }
-            CFReleaseSafe(digest_data);
-            CFReleaseSafe(value);
-        }) || CFReleaseNull(backup_new);
-
-        if (dvdel.count) {
-            struct SOSDigestVector dvadd = SOSDigestVectorInit;
-            if (!SOSEngineUpdateLocalManifest(engine, kSOSDataSourceSOSTransaction, &dvdel, &dvadd, error)) {
-                CFReleaseNull(backup_new);
-            }
-            SOSDigestVectorFree(&dvdel);
-        }
-
-        SOSDataSourceRelease(ds, error) || CFReleaseNull(backup_new);
-    }
-
-    CFReleaseSafe(mold);
-    CFReleaseSafe(mnow);
-    CFReleaseSafe(madd);
-    CFReleaseSafe(mdelete);
-    ks_close_keybag(bag_handle, error) || CFReleaseNull(backup_new);
-
-    return backup_new;
-}
-
-static bool
-_SecServerRestoreTruthInTheCloud(CFDataRef keybag, CFDataRef password, CFDictionaryRef backup_in, CFErrorRef *error) {
-    __block bool ok = true;
-    keybag_handle_t bag_handle;
-    if (!ks_open_keybag(keybag, password, &bag_handle, error))
-        return false;
-
-    SOSManifestRef mbackup = SOSCreateManifestWithBackup(backup_in, error);
-    if (mbackup) {
-        SOSDataSourceFactoryRef dsf = SecItemDataSourceFactoryGetDefault();
-        SOSDataSourceRef ds = dsf->create_datasource(dsf, kSecAttrAccessibleWhenUnlocked, error);
-        if (ds) {
-            ok = SOSDataSourceWith(ds, error, ^(SOSTransactionRef txn, bool *commit) {
-                SOSManifestRef mnow = SOSDataSourceCopyManifest(ds, error);
-            SOSManifestRef mdelete = NULL, madd = NULL;
-            SOSManifestDiff(mnow, mbackup, &mdelete, &madd, error);
-
-            // Don't delete everything in datasource not in backup.
-
-            // Add items from the backup
-                SOSManifestForEach(madd, ^void(CFDataRef e, bool *stop) {
-                CFDictionaryRef item = NULL;
-                CFStringRef sha1 = CFDataCopyHexString(e);
-                if (sha1) {
-                    item = CFDictionaryGetValue(backup_in, sha1);
-                    CFRelease(sha1);
-                }
-                if (item) {
-                    CFErrorRef localError = NULL;
-
-                        if (!SOSObjectRestoreObject(ds, txn, bag_handle, item, &localError)) {
-                            OSStatus status = SecErrorGetOSStatus(localError);
-                            if (status == errSecDuplicateItem) {
-                            // Log and ignore duplicate item errors during restore
-                            secnotice("titc", "restore %@ not replacing existing item", item);
-                        } else {
-                                if (status == errSecInteractionNotAllowed)
-                                    *stop = true;
-                            // Propagate the first other error upwards (causing the restore to fail).
-                            secerror("restore %@ failed %@", item, localError);
-                            ok = false;
-                            if (error && !*error) {
-                                *error = localError;
-                                localError = NULL;
-                            }
-                        }
-                        CFReleaseSafe(localError);
-                    }
-                }
-            });
-                ok &= SOSDataSourceRelease(ds, error);
-            CFReleaseNull(mdelete);
-            CFReleaseNull(madd);
-            CFReleaseNull(mnow);
-            });
-        } else {
-            ok = false;
-        }
-        CFRelease(mbackup);
-    }
-
-    ok &= ks_close_keybag(bag_handle, error);
-
-    return ok;
-}
-
-
-CF_RETURNS_RETAINED CFDictionaryRef
-_SecServerBackupSyncable(CFDictionaryRef backup, CFDataRef keybag, CFDataRef password, CFErrorRef *error) {
-    require_action_quiet(isData(keybag), errOut, SecError(errSecParam, error, CFSTR("keybag %@ not a data"), keybag));
-    require_action_quiet(!backup || isDictionary(backup), errOut, SecError(errSecParam, error, CFSTR("backup %@ not a dictionary"), backup));
-    require_action_quiet(!password || isData(password), errOut, SecError(errSecParam, error, CFSTR("password %@ not a data"), password));
-
-    return _SecServerCopyTruthInTheCloud(keybag, password, backup, error);
-
-errOut:
-    return NULL;
-}
-
-bool
-_SecServerRestoreSyncable(CFDictionaryRef backup, CFDataRef keybag, CFDataRef password, CFErrorRef *error) {
-    bool ok;
-    require_action_quiet(isData(keybag), errOut, ok = SecError(errSecParam, error, CFSTR("keybag %@ not a data"), keybag));
-    require_action_quiet(isDictionary(backup), errOut, ok = SecError(errSecParam, error, CFSTR("backup %@ not a dictionary"), backup));
-    if (password) {
-        require_action_quiet(isData(password), errOut, ok = SecError(errSecParam, error, CFSTR("password not a data")));
-    }
-
-    ok = _SecServerRestoreTruthInTheCloud(keybag, password, backup, error);
-
-errOut:
-    return ok;
-}
-
-bool _SecServerRollKeys(bool force, CFErrorRef *error) {
-#if USE_KEYSTORE
-    uint32_t keystore_generation_status = 0;
-    if (aks_generation(KEYBAG_DEVICE, generation_noop, &keystore_generation_status))
-        return false;
-    uint32_t current_generation = keystore_generation_status & generation_current;
-
-    return kc_with_dbt(true, error, ^(SecDbConnectionRef dbt) {
-        bool up_to_date = s3dl_dbt_keys_current(dbt, current_generation, NULL);
-
-        if (force && !up_to_date) {
-            up_to_date = s3dl_dbt_update_keys(dbt, error);
-            if (up_to_date) {
-                secerror("Completed roll keys.");
-                up_to_date = s3dl_dbt_keys_current(dbt, current_generation, NULL);
-            }
-            if (!up_to_date)
-                secerror("Failed to roll keys.");
-        }
-        return up_to_date;
-    });
-#else
-    return true;
-#endif
-}