+++ /dev/null
-/*
- * Copyright (c) 2012-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@
- */
-
-
-#include <AssertMacros.h>
-#include <CoreFoundation/CFURL.h>
-
-#include <securityd/SOSCloudCircleServer.h>
-#include <SecureObjectSync/SOSCloudCircle.h>
-#include <SecureObjectSync/SOSCloudCircleInternal.h>
-#include <SecureObjectSync/SOSCircle.h>
-#include <SecureObjectSync/SOSAccount.h>
-#include <SecureObjectSync/SOSAccountPriv.h>
-#include <SecureObjectSync/SOSFullPeerInfo.h>
-#include <SecureObjectSync/SOSPeerInfoInternal.h>
-#include <SecureObjectSync/SOSInternal.h>
-#include <SecureObjectSync/SOSUserKeygen.h>
-#include <SecureObjectSync/SOSMessage.h>
-#include <SecureObjectSync/SOSTransport.h>
-#include <SecureObjectSync/SOSKVSKeys.h>
-
-#include <utilities/SecCFWrappers.h>
-#include <utilities/SecCFRelease.h>
-#include <utilities/debugging.h>
-#include <CKBridge/SOSCloudKeychainClient.h>
-
-#include <corecrypto/ccrng.h>
-#include <corecrypto/ccrng_pbkdf2_prng.h>
-#include <corecrypto/ccec.h>
-#include <corecrypto/ccdigest.h>
-#include <corecrypto/ccsha2.h>
-#include <CommonCrypto/CommonRandomSPI.h>
-#include <Security/SecKeyPriv.h>
-#include <Security/SecFramework.h>
-
-#include <utilities/SecFileLocations.h>
-#include <utilities/SecAKSWrappers.h>
-#include <securityd/SecItemServer.h>
-#include <Security/SecItemPriv.h>
-
-#include <TargetConditionals.h>
-
-#include <utilities/iCloudKeychainTrace.h>
-
-#if TARGET_OS_EMBEDDED || TARGET_IPHONE_SIMULATOR
-#include <MobileGestalt.h>
-#else
-#include <AppleSystemInfo/AppleSystemInfo.h>
-
-// We need authorization, but that doesn't exist
-// on sec built for desktop (iOS in a process)
-// Define AuthorizationRef here to make SystemConfiguration work
-// as if it's on iOS.
-typedef const struct AuthorizationOpaqueRef * AuthorizationRef;
-#endif
-
-#define SOSCKCSCOPE "sync"
-
-#define USE_SYSTEMCONFIGURATION_PRIVATE_HEADERS
-#import <SystemConfiguration/SystemConfiguration.h>
-
-#include <notify.h>
-
-static SOSCCAccountDataSourceFactoryBlock accountDataSourceOverride = NULL;
-
-bool SOSKeychainAccountSetFactoryForAccount(SOSCCAccountDataSourceFactoryBlock block)
-{
- accountDataSourceOverride = Block_copy(block);
-
- return true;
-}
-
-//
-// Forward declared
-//
-
-static void do_with_account(void (^action)(SOSAccountRef account));
-static void do_with_account_async(void (^action)(SOSAccountRef account));
-
-//
-// Constants
-//
-CFStringRef kSOSInternalAccessGroup = CFSTR("com.apple.security.sos");
-
-CFStringRef kSOSAccountLabel = CFSTR("iCloud Keychain Account Meta-data");
-
-static CFStringRef accountFileName = CFSTR("PersistedAccount.plist");
-
-static CFDictionaryRef SOSItemCopyQueryForSyncItems(CFStringRef service, bool returnData)
-{
- return CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
- kSecClass, kSecClassGenericPassword,
- kSecAttrService, service,
- kSecAttrAccessGroup, kSOSInternalAccessGroup,
- kSecReturnData, returnData ? kCFBooleanTrue : kCFBooleanFalse,
- NULL);
-}
-
-CFDataRef SOSItemCopy(CFStringRef service, CFErrorRef* error)
-{
- CFDictionaryRef query = SOSItemCopyQueryForSyncItems(service, true);
-
- CFDataRef result = NULL;
-
- OSStatus copyResult = SecItemCopyMatching(query, (CFTypeRef*) &result);
-
- CFReleaseNull(query);
-
- if (copyResult != noErr) {
- SecError(copyResult, error, CFSTR("Error %@ reading for service '%@'"), result, service);
- CFReleaseNull(result);
- return NULL;
- }
-
- if (!isData(result)) {
- SOSCreateErrorWithFormat(kSOSErrorProcessingFailure, NULL, error, NULL, CFSTR("SecItemCopyMatching returned non-data in '%@'"), service);
- CFReleaseNull(result);
- return NULL;
- }
-
- return result;
-}
-
-static CFDataRef SOSKeychainCopySavedAccountData()
-{
- CFErrorRef error = NULL;
- CFDataRef accountData = SOSItemCopy(kSOSAccountLabel, &error);
- if (!accountData)
- secnotice("account", "Failed to load account: %@", error);
- CFReleaseNull(error);
-
- return accountData;
-}
-
-bool SOSItemUpdateOrAdd(CFStringRef service, CFStringRef accessibility, CFDataRef data, CFErrorRef *error)
-{
- CFDictionaryRef query = SOSItemCopyQueryForSyncItems(service, false);
-
- CFDictionaryRef update = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
- kSecValueData, data,
- kSecAttrAccessible, accessibility,
- NULL);
- OSStatus saveStatus = SecItemUpdate(query, update);
-
- if (errSecItemNotFound == saveStatus) {
- CFMutableDictionaryRef add = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, query);
- CFDictionaryForEach(update, ^(const void *key, const void *value) {
- CFDictionaryAddValue(add, key, value);
- });
- saveStatus = SecItemAdd(add, NULL);
- CFReleaseNull(add);
- }
-
- CFReleaseNull(query);
- CFReleaseNull(update);
-
- return SecError(saveStatus, error, CFSTR("Error saving %@ to service '%@'"), data, service);
-}
-
-static CFStringRef accountStatusFileName = CFSTR("accountStatus.plist");
-#include <utilities/der_plist.h>
-#include <utilities/der_plist_internal.h>
-#include <corecrypto/ccder.h>
-#if 0
-static const uint8_t* ccder_decode_bool(bool* boolean, const uint8_t* der, const uint8_t *der_end)
-{
- if (NULL == der)
- return NULL;
-
- size_t payload_size = 0;
- const uint8_t *payload = ccder_decode_tl(CCDER_BOOLEAN, &payload_size, der, der_end);
-
- if (NULL == payload || (der_end - payload) < 1 || payload_size != 1) {
- return NULL;
- }
-
- if (boolean)
- *boolean = (*payload != 0);
-
- return payload + payload_size;
-}
-#endif
-
-bool SOSCCCircleIsOn_Artifact(void) {
- bool circle_on = false;
- CFDataRef accountStatus = NULL;
- CFURLRef accountStatusFileURL = SecCopyURLForFileInKeychainDirectory(accountStatusFileName);
- require_quiet(accountStatusFileURL && CFURLResourceIsReachable(accountStatusFileURL, NULL), xit);
- accountStatus = (CFDataRef) CFPropertyListReadFromFile(accountStatusFileURL);
-
- if(isData(accountStatus)) {
- size_t size = CFDataGetLength(accountStatus);
- const uint8_t *der = CFDataGetBytePtr(accountStatus);
- const uint8_t *der_p = der;
-
- const uint8_t *sequence_end;
- der_p = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, der_p, der_p + size);
- der_p = ccder_decode_bool(&circle_on, der_p, sequence_end);
- (void) der_p;
- }
-
-xit:
- CFReleaseSafe(accountStatusFileURL);
- CFReleaseSafe(accountStatus);
-
- return circle_on;
-}
-
-#if 0
-static size_t ccder_sizeof_bool(bool value __unused, CFErrorRef *error)
-{
- return ccder_sizeof(CCDER_BOOLEAN, 1);
-}
-
-
-static uint8_t* ccder_encode_bool(bool value, const uint8_t *der, uint8_t *der_end)
-{
- uint8_t value_byte = value;
-
- return ccder_encode_tl(CCDER_BOOLEAN, 1, der,
- ccder_encode_body(1, &value_byte, der, der_end));
-}
-#endif
-
-static void SOSCCCircleIsOn_SetArtifact(bool account_on) {
- static CFDataRef sLastSavedAccountStatus = NULL;
- CFErrorRef saveError = NULL;
- size_t der_size = ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, ccder_sizeof_bool(account_on, NULL));
- uint8_t der[der_size];
- uint8_t *der_end = der + der_size;
- der_end = ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
- ccder_encode_bool(account_on, der, der_end));
-
- CFDataRef accountStatusAsData = CFDataCreate(kCFAllocatorDefault, der_end, der_size);
-
- require_quiet(accountStatusAsData, exit);
- if (sLastSavedAccountStatus && CFEqual(sLastSavedAccountStatus, accountStatusAsData)) goto exit;
-
- CFURLRef accountStatusFileURL = SecCopyURLForFileInKeychainDirectory(accountStatusFileName);
- CFPropertyListWriteToFile((CFPropertyListRef) accountStatusAsData, accountStatusFileURL);
- CFReleaseSafe(accountStatusFileURL);
-
- CFReleaseNull(sLastSavedAccountStatus);
- sLastSavedAccountStatus = accountStatusAsData;
- accountStatusAsData = NULL;
-
-exit:
- CFReleaseNull(saveError);
- CFReleaseNull(accountStatusAsData);
-}
-
-static void SOSCCCircleIsOn_UpdateArtifact(SOSCCStatus status)
-{
- switch (status) {
- case kSOSCCCircleAbsent:
- case kSOSCCNotInCircle:
- SOSCCCircleIsOn_SetArtifact(false);
- break;
- case kSOSCCInCircle:
- case kSOSCCRequestPending:
- SOSCCCircleIsOn_SetArtifact(true);
- break;
- case kSOSCCError:
- default:
- // do nothing
- break;
- }
-}
-
-static void SOSKeychainAccountEnsureSaved(SOSAccountRef account)
-{
- static CFDataRef sLastSavedAccountData = NULL;
-
- CFErrorRef saveError = NULL;
-
- if(SOSAccountGetMyFullPeerInCircleNamedIfPresent(account, CFSTR("ak"), NULL) == NULL) {
- return;
- }
-
- SOSCCCircleIsOn_UpdateArtifact(SOSAccountIsInCircles(account, NULL));
-
- CFDataRef accountAsData = SOSAccountCopyEncodedData(account, kCFAllocatorDefault, &saveError);
-
- require_action_quiet(accountAsData, exit, secerror("Failed to transform account into data, error: %@", saveError));
- require_quiet(!CFEqualSafe(sLastSavedAccountData, accountAsData), exit);
-
- if (!SOSItemUpdateOrAdd(kSOSAccountLabel, kSecAttrAccessibleAlwaysThisDeviceOnly, accountAsData, &saveError)) {
- secerror("Can't save account: %@", saveError);
- goto exit;
- }
-
- CFReleaseNull(sLastSavedAccountData);
- sLastSavedAccountData = accountAsData;
- accountAsData = NULL;
-
-exit:
- CFReleaseNull(saveError);
- CFReleaseNull(accountAsData);
-}
-
-
-/*
- Stolen from keychain_sync.c
- */
-
-static bool clearAllKVS(CFErrorRef *error)
-{
- return true;
- __block bool result = false;
- const uint64_t maxTimeToWaitInSeconds = 30ull * NSEC_PER_SEC;
- dispatch_queue_t processQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- dispatch_semaphore_t waitSemaphore = dispatch_semaphore_create(0);
- dispatch_time_t finishTime = dispatch_time(DISPATCH_TIME_NOW, maxTimeToWaitInSeconds);
-
- SOSCloudKeychainClearAll(processQueue, ^(CFDictionaryRef returnedValues, CFErrorRef cerror)
- {
- result = (cerror != NULL);
- dispatch_semaphore_signal(waitSemaphore);
- });
-
- dispatch_semaphore_wait(waitSemaphore, finishTime);
- dispatch_release(waitSemaphore);
-
- return result;
-}
-
-static SOSAccountRef SOSKeychainAccountCreateSharedAccount(CFDictionaryRef our_gestalt)
-{
- secdebug("account", "Created account");
-
- CFDataRef savedAccount = SOSKeychainCopySavedAccountData();
- SOSAccountRef account = NULL;
- SOSDataSourceFactoryRef factory = accountDataSourceOverride ? accountDataSourceOverride()
- : SecItemDataSourceFactoryGetDefault();
-
- if (savedAccount) {
- CFErrorRef inflationError = NULL;
-
- account = SOSAccountCreateFromData(kCFAllocatorDefault, savedAccount, factory, &inflationError);
-
- if(account && SOSAccountGetMyFullPeerInCircleNamedIfPresent(account, CFSTR("ak"), NULL) == NULL) {
- SOSAccountRef newAccount = SOSAccountCreate(kCFAllocatorDefault, our_gestalt, factory);
-
- if (!newAccount) {
- secnotice("repair_account", "Tried to repair bad account - got null account");
- } else {
- account = newAccount;
- }
- }
-
- if (account){
- SOSAccountUpdateGestalt(account, our_gestalt);
- } else {
- secerror("Got error inflating account: %@", inflationError);
- }
-
- CFReleaseNull(inflationError);
- }
- CFReleaseSafe(savedAccount);
-
- if (!account) {
- account = SOSAccountCreate(kCFAllocatorDefault, our_gestalt, factory);
-
- if (!account)
- secerror("Got NULL creating account");
- }
-
- return account;
-}
-
-//
-// Mark: Gestalt Handling
-//
-
-static CFStringRef CopyModelName(void)
-{
- static dispatch_once_t once;
- static CFStringRef modelName = NULL;
- dispatch_once(&once, ^{
-#if TARGET_OS_EMBEDDED || TARGET_IPHONE_SIMULATOR
- modelName = MGCopyAnswer(kMGQDeviceName, NULL);
-#else
- modelName = ASI_CopyComputerModelName(FALSE);
-#endif
- if (modelName == NULL)
- modelName = CFSTR("Unknown model");
- });
- return CFStringCreateCopy(kCFAllocatorDefault, modelName);
-}
-
-static CFStringRef CopyComputerName(SCDynamicStoreRef store)
-{
- CFStringRef deviceName = SCDynamicStoreCopyComputerName(store, NULL);
- if (deviceName == NULL) {
- deviceName = CFSTR("Unknown name");
- }
- return deviceName;
-}
-
-static bool _EngineMessageProtocolV2Enabled(void)
-{
-#if DEBUG
- //sudo rhr
- static dispatch_once_t onceToken;
- static bool v2_enabled = false;
- dispatch_once(&onceToken, ^{
- CFTypeRef v2Pref = (CFNumberRef)CFPreferencesCopyValue(CFSTR("engineV2"), CFSTR("com.apple.security"), kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
-
- if (v2Pref && CFGetTypeID(v2Pref) == CFBooleanGetTypeID()) {
- v2_enabled = CFBooleanGetValue((CFBooleanRef)v2Pref);
- secnotice("server", "Engine v2 : %s", v2_enabled ? "enabled":"disabled");
- }
- CFReleaseSafe(v2Pref);
- });
-
- return v2_enabled;
-#else
- return false;
-#endif
-}
-
-
-static CFDictionaryRef CFDictionaryCreateDeviceGestalt(SCDynamicStoreRef store, CFArrayRef keys, void *context)
-{
- CFStringRef modelName = CopyModelName();
- CFStringRef computerName = CopyComputerName(store);
- SInt32 version = _EngineMessageProtocolV2Enabled() ? kEngineMessageProtocolVersion : 0;
- CFNumberRef protocolVersion = CFNumberCreate(0, kCFNumberSInt32Type, &version);
-
-
- CFDictionaryRef gestalt = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
- kPIUserDefinedDeviceName, computerName,
- kPIDeviceModelName, modelName,
- kPIMessageProtocolVersion, protocolVersion,
- NULL);
- CFReleaseSafe(modelName);
- CFReleaseSafe(computerName);
- CFReleaseSafe(protocolVersion);
-
- return gestalt;
-}
-
-static void SOSCCProcessGestaltUpdate(SCDynamicStoreRef store, CFArrayRef keys, void *context)
-{
- do_with_account(^(SOSAccountRef account) {
- if(account){
- CFDictionaryRef gestalt = CFDictionaryCreateDeviceGestalt(store, keys, context);
- if (SOSAccountUpdateGestalt(account, gestalt)) {
- notify_post(kSOSCCCircleChangedNotification);
- }
- CFReleaseSafe(gestalt);
- }
- });
-}
-
-
-static CFDictionaryRef CFDictionaryCreateGestaltAndRegisterForUpdate(dispatch_queue_t queue, void *info)
-{
- SCDynamicStoreContext context = { .info = info };
- SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("com.apple.securityd.cloudcircleserver"), SOSCCProcessGestaltUpdate, &context);
- CFStringRef computerKey = SCDynamicStoreKeyCreateComputerName(NULL);
- CFArrayRef keys = NULL;
- CFDictionaryRef gestalt = NULL;
-
- if (store == NULL || computerKey == NULL) {
- goto done;
- }
- keys = CFArrayCreate(NULL, (const void **)&computerKey, 1, &kCFTypeArrayCallBacks);
- if (keys == NULL) {
- goto done;
- }
- gestalt = CFDictionaryCreateDeviceGestalt(store, keys, info);
- SCDynamicStoreSetNotificationKeys(store, keys, NULL);
- SCDynamicStoreSetDispatchQueue(store, queue);
-
-done:
- if (store) CFRelease(store);
- if (computerKey) CFRelease(computerKey);
- if (keys) CFRelease(keys);
- return gestalt;
-}
-
-static void do_with_account(void (^action)(SOSAccountRef account));
-static void do_with_account_async(void (^action)(SOSAccountRef account));
-
-static SOSAccountRef GetSharedAccount(void) {
- static SOSAccountRef sSharedAccount = NULL;
- static dispatch_once_t onceToken;
-
-#if !(TARGET_OS_EMBEDDED)
- if(geteuid() == 0){
- secerror("Cannot inflate account object as root");
- return NULL;
- }
-#endif
-
- dispatch_once(&onceToken, ^{
- secdebug("account", "Account Creation start");
-
- CFDictionaryRef gestalt = CFDictionaryCreateGestaltAndRegisterForUpdate(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
-
- if (!gestalt) {
-#if TARGET_OS_IPHONE && TARGET_IPHONE_SIMULATOR
- gestalt = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, NULL);
-#else
- secerror("Didn't get machine gestalt! This is going to be ugly.");
-#endif
- }
-
- sSharedAccount = SOSKeychainAccountCreateSharedAccount(gestalt);
-
- SOSCCSetThisDeviceDefinitelyNotActiveInCircle(SOSAccountIsInCircles(sSharedAccount, NULL));
-
- SOSAccountAddChangeBlock(sSharedAccount, ^(SOSCircleRef circle,
- CFSetRef peer_additions, CFSetRef peer_removals,
- CFSetRef applicant_additions, CFSetRef applicant_removals) {
- CFErrorRef pi_error = NULL;
- SOSPeerInfoRef me = SOSAccountGetMyPeerInCircle(sSharedAccount, circle, &pi_error);
- if (!me) {
- secerror("Error finding me for change: %@", pi_error);
- } else {
- if (SOSCircleHasPeer(circle, me, NULL) && CFSetGetCount(peer_additions) != 0) {
- secnotice("updates", "Requesting Ensure Peer Registration.");
- SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
- }
-
- if (CFSetContainsValue(peer_additions, me)) {
- SOSCCSyncWithAllPeers();
- }
- }
-
- CFReleaseNull(pi_error);
-
- if (CFSetGetCount(peer_additions) != 0 ||
- CFSetGetCount(peer_removals) != 0 ||
- CFSetGetCount(applicant_additions) != 0 ||
- CFSetGetCount(applicant_removals) != 0) {
-
- SOSCCSetThisDeviceDefinitelyNotActiveInCircle(SOSAccountIsInCircles(sSharedAccount, NULL));
- notify_post(kSOSCCCircleChangedNotification);
- }
- });
-
- SOSCloudKeychainSetItemsChangedBlock(^CFArrayRef(CFDictionaryRef changes) {
- CFRetainSafe(changes);
- __block CFMutableArrayRef handledKeys = NULL;
- do_with_account(^(SOSAccountRef account) {
- CFStringRef changeDescription = SOSChangesCopyDescription(changes, false);
- secdebug(SOSCKCSCOPE, "Received: %@", changeDescription);
- CFReleaseSafe(changeDescription);
-
- CFErrorRef error = NULL;
- handledKeys = SOSTransportDispatchMessages(account, changes, &error);
- if (!handledKeys) {
- secerror("Error handling updates: %@", error);
- CFReleaseNull(error);
- }
- });
- CFReleaseSafe(changes);
- return handledKeys;
- });
- CFReleaseSafe(gestalt);
-
- SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
- });
-
-
- return sSharedAccount;
-}
-
-static void do_with_account_dynamic(void (^action)(SOSAccountRef account), bool sync) {
- SOSAccountRef account = GetSharedAccount();
-
- if(account){
- dispatch_block_t do_action_and_save = ^{
- action(account);
- SOSKeychainAccountEnsureSaved(account);
- };
-
- if (sync) {
- dispatch_sync(SOSAccountGetQueue(account), do_action_and_save);
- } else {
- dispatch_async(SOSAccountGetQueue(account), do_action_and_save);
- }
- }
-}
-
-__unused static void do_with_account_async(void (^action)(SOSAccountRef account)) {
- do_with_account_dynamic(action, false);
-}
-
-static void do_with_account(void (^action)(SOSAccountRef account)) {
- do_with_account_dynamic(action, true);
-}
-
-#if TARGET_IPHONE_SIMULATOR
-#define MKBDeviceUnlockedSinceBoot() true
-#endif
-
-static bool do_if_after_first_unlock(CFErrorRef *error, dispatch_block_t action)
-{
- bool beenUnlocked = false;
- require_quiet(SecAKSGetHasBeenUnlocked(&beenUnlocked, error), fail);
-
- require_action_quiet(beenUnlocked, fail,
- SOSCreateErrorWithFormat(kSOSErrorNotReady, NULL, error, NULL,
- CFSTR("Keybag never unlocked, ask after first unlock")));
-
- action();
- return true;
-
-fail:
- return false;
-}
-
-static bool do_with_account_if_after_first_unlock(CFErrorRef *error, bool (^action)(SOSAccountRef account, CFErrorRef* error))
-{
- __block bool action_result = false;
-
-#if !(TARGET_OS_EMBEDDED)
- if(geteuid() == 0){
- secerror("Cannot inflate account object as root");
- return false;
- }
-#endif
- return do_if_after_first_unlock(error, ^{
- do_with_account(^(SOSAccountRef account) {
- action_result = action(account, error);
- });
-
- }) && action_result;
-}
-
-static bool do_with_account_while_unlocked(CFErrorRef *error, bool (^action)(SOSAccountRef account, CFErrorRef* error))
-{
- __block bool action_result = false;
-
-#if !(TARGET_OS_EMBEDDED)
- if(geteuid() == 0){
- secerror("Cannot inflate account object as root");
- return false;
- }
-#endif
-
- return SecAKSDoWhileUserBagLocked(error, ^{
- do_with_account(^(SOSAccountRef account) {
- action_result = action(account, error);
- });
-
- }) && action_result;
-}
-
-SOSAccountRef SOSKeychainAccountGetSharedAccount()
-{
- __block SOSAccountRef result = NULL;
-
- do_with_account(^(SOSAccountRef account) {
- result = account;
- });
-
- return result;
-}
-
-//
-// Mark: Credential processing
-//
-
-
-bool SOSCCTryUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFErrorRef *error)
-{
- return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
- return SOSAccountTryUserCredentials(account, user_label, user_password, block_error);
- });
-}
-
-#define kWAIT2MINID "EFRESH"
-
-static bool EnsureFreshParameters(SOSAccountRef account, CFErrorRef *error) {
- dispatch_semaphore_t wait_for = dispatch_semaphore_create(0);
- dispatch_retain(wait_for); // Both this scope and the block own it.
-
- CFMutableArrayRef keysToGet = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
- CFArrayAppendValue(keysToGet, kSOSKVSKeyParametersKey);
-
- __block CFDictionaryRef valuesToUpdate = NULL;
- __block bool success = false;
-
- secnoticeq("fresh", "%s calling SOSCloudKeychainSynchronizeAndWait", kWAIT2MINID);
-
- SOSCloudKeychainSynchronizeAndWait(keysToGet, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) {
-
- if (sync_error) {
- secerrorq("%s SOSCloudKeychainSynchronizeAndWait: %@", kWAIT2MINID, sync_error);
- if (error) {
- *error = sync_error;
- CFRetainSafe(*error);
- }
- } else {
- secnoticeq("fresh", "%s returned from call; in callback to SOSCloudKeychainSynchronizeAndWait: results: %@", kWAIT2MINID, returnedValues);
- valuesToUpdate = returnedValues;
- CFRetainSafe(valuesToUpdate);
- success = true;
- }
-
- dispatch_semaphore_signal(wait_for);
- dispatch_release(wait_for);
- });
-
- dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER);
- // TODO: Maybe we timeout here... used to dispatch_time(DISPATCH_TIME_NOW, 30ull * NSEC_PER_SEC));
- dispatch_release(wait_for);
- CFMutableArrayRef handledKeys = NULL;
- if ((valuesToUpdate) && (account)) {
- handledKeys = SOSTransportDispatchMessages(account, valuesToUpdate, error);
- if (!handledKeys) {
- secerrorq("%s Freshness update failed: %@", kWAIT2MINID, error ? *error : NULL);
- success = false;
- }
- }
- CFReleaseNull(handledKeys);
- CFReleaseNull(valuesToUpdate);
- CFReleaseNull(keysToGet);
-
- return success;
-}
-
-static bool Flush(CFErrorRef *error) {
- __block bool success = false;
-
- dispatch_semaphore_t wait_for = dispatch_semaphore_create(0);
- dispatch_retain(wait_for); // Both this scope and the block own it.
-
- secnotice("flush", "Starting");
-
- SOSCloudKeychainFlush(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) {
- success = (sync_error == NULL);
- if (error) {
- CFRetainAssign(*error, sync_error);
- }
-
- dispatch_semaphore_signal(wait_for);
- dispatch_release(wait_for);
- });
-
- dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER);
- dispatch_release(wait_for);
-
- secnotice("flush", "Returned %s", success? "Success": "Failure");
-
- return success;
-}
-
-bool SOSCCSetUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFErrorRef *error)
-{
- secnotice("updates", "Setting credentials for %@", user_label); // TODO: remove this notice
- bool result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
- if (!EnsureFreshParameters(account, block_error)) {
- return false;
- }
- if (!SOSAccountAssertUserCredentials(account, user_label, user_password, block_error)) {
- secnotice("updates", "EnsureFreshParameters/SOSAccountAssertUserCredentials error: %@", *block_error);
- return false;
- }
- return true;
- });
-
- return result && Flush(error);
-}
-
-bool SOSCCCanAuthenticate_Server(CFErrorRef *error)
-{
- bool result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
- return SOSAccountGetPrivateCredential(account, block_error) != NULL;
- });
-
- if (!result && error && *error && CFErrorGetDomain(*error) == kSOSErrorDomain) {
- CFIndex code = CFErrorGetCode(*error);
- if (code == kSOSErrorPrivateKeyAbsent || code == kSOSErrorPublicKeyAbsent) {
- CFReleaseNull(*error);
- }
- }
-
- return result;
-}
-
-bool SOSCCPurgeUserCredentials_Server(CFErrorRef *error)
-{
- return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
- SOSAccountPurgePrivateCredential(account);
- return true;
- });
-}
-
-
-#if USE_BETTER
-static bool sAccountInCircleCache = false;
-
-static void do_with_not_in_circle_bool_queue(bool start_account, dispatch_block_t action)
-{
- static dispatch_queue_t account_start_queue;
- static dispatch_queue_t not_in_circle_queue;
- static bool account_started = false;
-
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- not_in_circle_queue = dispatch_queue_create("nis queue", DISPATCH_QUEUE_SERIAL);
- account_start_queue = dispatch_queue_create("init nis queue", DISPATCH_QUEUE_SERIAL);;
- account_started = false;
- });
-
- __block bool done = false;
- dispatch_sync(not_in_circle_queue, ^{
- if (account_started) {
- done = true;
- action();
- }
- });
-
- if (!done && start_account) {
- dispatch_sync(account_start_queue, ^{
- __block bool do_start = false;
- dispatch_sync(not_in_circle_queue, ^{
- do_start = !account_started;
- account_started = true;
- });
- if (do_start)
- SOSCCThisDeviceIsInCircle(NULL); // Inflate account.
- });
-
- dispatch_sync(not_in_circle_queue, action);
- }
-}
-#endif
-
-bool SOSCCThisDeviceDefinitelyNotActiveInCircle()
-{
- return !SOSCCCircleIsOn_Artifact();
-#if USE_BETTER
- __block bool result = false;
- do_with_not_in_circle_bool_queue(true, ^{
- result = sAccountInCircleCache;
- });
-
- return result;
-#endif
-}
-
-void SOSCCSetThisDeviceDefinitelyNotActiveInCircle(SOSCCStatus currentStatus)
-{
- SOSCCCircleIsOn_UpdateArtifact(currentStatus);
-#if USE_BETTER
- do_with_not_in_circle_bool_queue(false, ^{
- sAccountInCircleCache = notActive;
- });
-#endif
-}
-
-
-SOSCCStatus SOSCCThisDeviceIsInCircle_Server(CFErrorRef *error)
-{
- __block SOSCCStatus status;
-
- return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
- status = SOSAccountIsInCircles(account, block_error);
- return true;
- }) ? status : kSOSCCError;
-}
-
-bool SOSCCRequestToJoinCircle_Server(CFErrorRef* error)
-{
- __block bool result = true;
-
- return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
- result = SOSAccountJoinCircles(account, block_error);
- return result;
- });
-}
-
-bool SOSCCRequestToJoinCircleAfterRestore_Server(CFErrorRef* error)
-{
- __block bool result = true;
- bool returned = false;
- returned = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
- SOSAccountEnsurePeerRegistration(account, block_error);
- result = SOSAccountJoinCirclesAfterRestore(account, block_error);
- return result;
- });
- return returned;
-
-}
-
-bool SOSCCRequestEnsureFreshParameters_Server(CFErrorRef* error)
-{
- __block bool result = true;
- bool returned = false;
- returned = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
- result = EnsureFreshParameters(account, NULL);
- return result;
- });
- return returned;
-}
-
-CFStringRef SOSCCRequestDeviceID_Server(CFErrorRef *error)
-{
- __block CFStringRef result = NULL;
-
- (void) do_with_account_while_unlocked(error, ^bool(SOSAccountRef account, CFErrorRef *error) {
- result = SOSAccountGetDeviceID(account, error);
- return (!isNull(result));
- });
- return result;
-}
-
-bool SOSCCSetDeviceID_Server(CFStringRef IDS, CFErrorRef *error){
- __block bool result = true;
-
- return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
- result = SOSAccountSetMyDSID(account, IDS, block_error);
- return result;
- });
-
-}
-bool SOSCCResetToOffering_Server(CFErrorRef* error)
-{
- __block bool result = true;
-
- return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
- clearAllKVS(NULL);
- result = SOSAccountResetToOffering(account, block_error);
- return result;
- });
-
-}
-
-bool SOSCCResetToEmpty_Server(CFErrorRef* error)
-{
- __block bool result = true;
-
- return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
- result = SOSAccountResetToEmpty(account, block_error);
- return result;
- });
-
-}
-
-bool SOSCCRemoveThisDeviceFromCircle_Server(CFErrorRef* error)
-{
- __block bool result = true;
-
- return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
- result = SOSAccountLeaveCircles(account, block_error);
- return result;
- });
-}
-
-bool SOSCCBailFromCircle_Server(uint64_t limit_in_seconds, CFErrorRef* error)
-{
- __block bool result = true;
-
- return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
- result = SOSAccountBail(account, limit_in_seconds, block_error);
- return result;
- });
-
-}
-
-CFArrayRef SOSCCCopyApplicantPeerInfo_Server(CFErrorRef* error)
-{
- __block CFArrayRef result = NULL;
-
- (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
- result = SOSAccountCopyApplicants(account, block_error);
- return result != NULL;
- });
-
- return result;
-}
-
-CFArrayRef SOSCCCopyGenerationPeerInfo_Server(CFErrorRef* error)
-{
- __block CFArrayRef result = NULL;
-
- (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
- result = SOSAccountCopyGeneration(account, block_error);
- return result != NULL;
- });
-
- return result;
-}
-
-CFArrayRef SOSCCCopyValidPeerPeerInfo_Server(CFErrorRef* error)
-{
- __block CFArrayRef result = NULL;
-
- (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
- result = SOSAccountCopyValidPeers(account, block_error);
- return result != NULL;
- });
-
- return result;
-}
-
-bool SOSCCValidateUserPublic_Server(CFErrorRef* error)
-{
- __block bool result = NULL;
-
- (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
- result = SOSValidateUserPublic(account, block_error);
- return result;
- });
-
- return result;
-}
-
-CFArrayRef SOSCCCopyNotValidPeerPeerInfo_Server(CFErrorRef* error)
-{
- __block CFArrayRef result = NULL;
-
- (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
- result = SOSAccountCopyNotValidPeers(account, block_error);
- return result != NULL;
- });
-
- return result;
-}
-
-CFArrayRef SOSCCCopyRetirementPeerInfo_Server(CFErrorRef* error)
-{
- __block CFArrayRef result = NULL;
-
- (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
- result = SOSAccountCopyRetired(account, block_error);
- return result != NULL;
- });
-
- return result;
-}
-
-bool SOSCCAcceptApplicants_Server(CFArrayRef applicants, CFErrorRef* error)
-{
- __block bool result = true;
- return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
- result = SOSAccountAcceptApplicants(account, applicants, block_error);
- return result;
- });
-
-}
-
-bool SOSCCRejectApplicants_Server(CFArrayRef applicants, CFErrorRef* error)
-{
- __block bool result = true;
- return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
- result = SOSAccountRejectApplicants(account, applicants, block_error);
- return result;
- });
-}
-
-CFArrayRef SOSCCCopyPeerPeerInfo_Server(CFErrorRef* error)
-{
- __block CFArrayRef result = NULL;
-
- (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
- result = SOSAccountCopyPeers(account, block_error);
- return result != NULL;
- });
-
- return result;
-}
-
-CFArrayRef SOSCCCopyConcurringPeerPeerInfo_Server(CFErrorRef* error)
-{
- __block CFArrayRef result = NULL;
-
- (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
- result = SOSAccountCopyConcurringPeers(account, block_error);
- return result != NULL;
- });
-
- return result;
-}
-
-CFStringRef SOSCCCopyIncompatibilityInfo_Server(CFErrorRef* error)
-{
- __block CFStringRef result = NULL;
-
- (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
- result = SOSAccountCopyIncompatibilityInfo(account, block_error);
- return result != NULL;
- });
-
- return result;
-}
-
-enum DepartureReason SOSCCGetLastDepartureReason_Server(CFErrorRef* error)
-{
- __block enum DepartureReason result = kSOSDepartureReasonError;
-
- (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
- result = SOSAccountGetLastDepartureReason(account, block_error);
- return result != kSOSDepartureReasonError;
- });
-
- return result;
-}
-
-
-bool SOSCCProcessEnsurePeerRegistration_Server(CFErrorRef* error)
-{
- secnotice("updates", "Request for registering peers");
- return do_with_account_while_unlocked(error, ^bool(SOSAccountRef account, CFErrorRef *error) {
- return SOSAccountEnsurePeerRegistration(account, error);
- });
-}
-
-SyncWithAllPeersReason SOSCCProcessSyncWithAllPeers_Server(CFErrorRef* error)
-{
- /*
- #define kIOReturnLockedRead iokit_common_err(0x2c3) // device read locked
- #define kIOReturnLockedWrite iokit_common_err(0x2c4) // device write locked
- */
- __block SyncWithAllPeersReason result = kSyncWithAllPeersSuccess;
- CFErrorRef action_error = NULL;
-
- if (!do_with_account_while_unlocked(&action_error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
- CFErrorRef localError = NULL;
- if (!SOSAccountSyncWithAllPeers(account, &localError)) {
- secerror("sync with all peers failed: %@", localError);
- CFReleaseSafe(localError);
- // This isn't a device-locked error, but returning false will
- // have CloudKeychainProxy ask us to try sync again after next unlock
- result = kSyncWithAllPeersOtherFail;
- return false;
- }
- return true;
- })) {
- if (action_error) {
- if (SecErrorGetOSStatus(action_error) == errSecInteractionNotAllowed) {
- secnotice("updates", "SOSAccountSyncWithAllPeers failed because device is locked; letting CloudKeychainProxy know");
- result = kSyncWithAllPeersLocked; // tell CloudKeychainProxy to call us back when device unlocks
- CFReleaseNull(action_error);
- } else {
- secerror("Unexpected error: %@", action_error);
- }
-
- if (error && *error == NULL) {
- *error = action_error;
- action_error = NULL;
- }
-
- CFReleaseNull(action_error);
- }
- }
-
- return result;
-}
-
-void SOSCCSyncWithAllPeers(void)
-{
- SOSCloudKeychainRequestSyncWithAllPeers(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
-}
-
-CF_RETURNS_RETAINED CFArrayRef SOSCCHandleUpdateKeyParameter(CFDictionaryRef updates)
-{
- CFArrayRef result = NULL;
- SOSAccountRef account = SOSKeychainAccountGetSharedAccount(); //HACK to make sure itemsChangedBlock is set
- (account) ? (result = SOSCloudKeychainHandleUpdateKeyParameter(updates)) : (result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault));
- return result;
-}
-
-CF_RETURNS_RETAINED CFArrayRef SOSCCHandleUpdateCircle(CFDictionaryRef updates)
-{
- CFArrayRef result = NULL;
- SOSAccountRef account = SOSKeychainAccountGetSharedAccount(); //HACK to make sure itemsChangedBlock is set
- (account) ? (result = SOSCloudKeychainHandleUpdateKeyParameter(updates)) : (result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault));
- return result;
-}
-
-CF_RETURNS_RETAINED CFArrayRef SOSCCHandleUpdateMessage(CFDictionaryRef updates)
-{
- CFArrayRef result = NULL;
- SOSAccountRef account = SOSKeychainAccountGetSharedAccount(); //HACK to make sure itemsChangedBlock is set
- (account) ? (result = SOSCloudKeychainHandleUpdateKeyParameter(updates)) : (result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault));
- return result;
-}
-
-