2 * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 #include <AssertMacros.h>
26 #include <CoreFoundation/CoreFoundation.h>
27 #include <CoreFoundation/CFPriv.h>
29 #import "keychain/SecureObjectSync/SOSAccountTransaction.h"
31 #include "keychain/securityd/SOSCloudCircleServer.h"
32 #include <Security/SecureObjectSync/SOSCloudCircle.h>
33 #include <Security/SecureObjectSync/SOSCloudCircleInternal.h>
35 #include "keychain/SecureObjectSync/SOSCircle.h"
36 #include "keychain/SecureObjectSync/SOSAccount.h"
37 #include "keychain/SecureObjectSync/SOSAccountPriv.h"
38 #include "keychain/SecureObjectSync/SOSAccountGhost.h"
40 #include "keychain/SecureObjectSync/SOSTransport.h"
41 #include "keychain/SecureObjectSync/SOSFullPeerInfo.h"
42 #include "keychain/SecureObjectSync/SOSPeerInfoV2.h"
43 #include "keychain/SecureObjectSync/SOSPeerInfoPriv.h"
44 #include "keychain/SecureObjectSync/SOSPeerInfoInternal.h"
45 #include "keychain/SecureObjectSync/SOSInternal.h"
46 #include "keychain/SecureObjectSync/SOSUserKeygen.h"
47 #include "keychain/SecureObjectSync/SOSMessage.h"
48 #include "keychain/SecureObjectSync/SOSDataSource.h"
49 #include "keychain/SecureObjectSync/SOSKVSKeys.h"
50 #import "keychain/SecureObjectSync/SOSAccountTrustClassic.h"
51 #import "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h"
52 #import "keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.h"
53 #import "keychain/SecureObjectSync/SOSAuthKitHelpers.h"
54 #import "keychain/ot/OTManager.h"
55 #import "keychain/SigninMetrics/OctagonSignPosts.h"
56 #import "NSError+UsefulConstructors.h"
58 #include <utilities/SecADWrapper.h>
59 #include <utilities/SecCFWrappers.h>
60 #include <utilities/SecCFRelease.h>
62 #include <utilities/SecCFError.h>
63 #include <utilities/debugging.h>
64 #include <utilities/SecCoreCrypto.h>
65 #include <utilities/SecTrace.h>
67 #include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h"
69 #include <corecrypto/ccrng.h>
70 #include <corecrypto/ccrng_pbkdf2_prng.h>
71 #include <corecrypto/ccec.h>
72 #include <corecrypto/ccdigest.h>
73 #include <corecrypto/ccsha2.h>
74 #include <CommonCrypto/CommonRandomSPI.h>
75 #include <Security/SecKeyPriv.h>
76 #include <Security/SecFramework.h>
78 #include <utilities/SecFileLocations.h>
79 #include <utilities/SecAKSWrappers.h>
80 #include "keychain/securityd/SecItemServer.h"
81 #include <Security/SecItemPriv.h>
83 #include <TargetConditionals.h>
85 #include <utilities/iCloudKeychainTrace.h>
86 #include <Security/SecAccessControlPriv.h>
87 #include "keychain/securityd/SecDbKeychainItem.h"
89 #include <os/activity.h>
90 #include <xpc/private.h>
92 #include <os/state_private.h>
95 #include <MobileGestalt.h>
97 #include <AppleSystemInfo/AppleSystemInfo.h>
100 #define SOSCKCSCOPE "sync"
101 #define RUN_AS_ROOT_ERROR 550
103 #define USE_SYSTEMCONFIGURATION_PRIVATE_HEADERS
104 #import <SystemConfiguration/SystemConfiguration.h>
108 static int64_t getTimeDifference(time_t start);
109 CFStringRef const SOSAggdSyncCompletionKey = CFSTR("com.apple.security.sos.synccompletion");
110 CFStringRef const SOSAggdSyncTimeoutKey = CFSTR("com.apple.security.sos.timeout");
112 typedef SOSDataSourceFactoryRef (^SOSCCAccountDataSourceFactoryBlock)(void);
114 static SOSCCAccountDataSourceFactoryBlock accountDataSourceOverride = NULL;
122 static void do_with_account(void (^action)(SOSAccountTransaction* txn));
128 CFStringRef kSOSAccountLabel = CFSTR("iCloud Keychain Account Meta-data");
130 CFStringRef kSOSBurnedRecoveryAttemptCount = CFSTR("Burned Recovery Attempt Count");
132 CFStringRef kSOSBurnedRecoveryAttemptAttestationDate = CFSTR("Burned Recovery Attempt Attestation Date");
134 static CFDictionaryRef SOSItemCopyQueryForSyncItems(CFStringRef service, bool returnData)
136 return CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
137 kSecClass, kSecClassGenericPassword,
138 kSecAttrService, service,
139 kSecAttrAccessGroup, kSOSInternalAccessGroup,
140 kSecReturnData, returnData ? kCFBooleanTrue : kCFBooleanFalse,
144 CFDataRef SOSItemCopy(CFStringRef service, CFErrorRef* error)
146 CFDictionaryRef query = SOSItemCopyQueryForSyncItems(service, true);
148 CFDataRef result = NULL;
150 OSStatus copyResult = SecItemCopyMatching(query, (CFTypeRef*) &result);
152 CFReleaseNull(query);
154 if (copyResult != noErr) {
155 SecError(copyResult, error, CFSTR("Error %@ reading for service '%@'"), result, service);
156 CFReleaseNull(result);
160 if (!isData(result)) {
161 SOSCreateErrorWithFormat(kSOSErrorProcessingFailure, NULL, error, NULL, CFSTR("SecItemCopyMatching returned non-data in '%@'"), service);
162 CFReleaseNull(result);
169 static CFDataRef SOSKeychainCopySavedAccountData()
171 CFErrorRef error = NULL;
172 CFDataRef accountData = SOSItemCopy(kSOSAccountLabel, &error);
174 secnotice("account", "Failed to load account: %@", error);
175 secerror("Failed to load account: %@", error);
177 CFReleaseNull(error);
182 bool SOSItemUpdateOrAdd(CFStringRef service, CFStringRef accessibility, CFDataRef data, CFErrorRef *error)
184 CFDictionaryRef query = SOSItemCopyQueryForSyncItems(service, false);
186 CFDictionaryRef update = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
188 kSecAttrAccessible, accessibility,
190 OSStatus saveStatus = SecItemUpdate(query, update);
192 if (errSecItemNotFound == saveStatus) {
193 CFMutableDictionaryRef add = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, query);
194 CFDictionaryForEach(update, ^(const void *key, const void *value) {
195 CFDictionaryAddValue(add, key, value);
197 saveStatus = SecItemAdd(add, NULL);
201 CFReleaseNull(query);
202 CFReleaseNull(update);
204 return SecError(saveStatus, error, CFSTR("Error saving %@ to service '%@'"), data, service);
207 static void SOSKeychainAccountEnsureSaved(CFDataRef accountAsData)
209 static CFDataRef sLastSavedAccountData = NULL;
211 CFErrorRef saveError = NULL;
212 require_quiet(!CFEqualSafe(sLastSavedAccountData, accountAsData), exit);
214 if (!SOSItemUpdateOrAdd(kSOSAccountLabel, kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate, accountAsData, &saveError)) {
215 secerror("Can't save account: %@", saveError);
219 CFAssignRetained(sLastSavedAccountData, CFRetainSafe(accountAsData));
222 CFReleaseNull(saveError);
225 static SOSAccount* SOSKeychainAccountCreateSharedAccount(CFDictionaryRef our_gestalt)
227 secdebug("account", "Created account");
229 CFDataRef savedAccount = SOSKeychainCopySavedAccountData();
230 SOSAccount* account = NULL;
232 SOSDataSourceFactoryRef factory = accountDataSourceOverride ? accountDataSourceOverride()
233 : SecItemDataSourceFactoryGetDefault();
235 require_quiet(factory, done);
238 NSError* inflationError = NULL;
240 account = [SOSAccount accountFromData:(__bridge NSData*) savedAccount
242 error:&inflationError];
245 [account.trust updateGestalt:account newGestalt:our_gestalt];
247 secerror("Got error inflating account: %@", inflationError);
251 CFReleaseNull(savedAccount);
254 account = SOSAccountCreate(kCFAllocatorDefault, our_gestalt, factory);
257 secerror("Got NULL creating account");
260 //[account startStateMachine];
263 CFReleaseNull(savedAccount);
268 // Mark: Gestalt Handling
271 CFStringRef SOSGestaltVersion = NULL;
272 CFStringRef SOSGestaltModel = NULL;
273 CFStringRef SOSGestaltDeviceName = NULL;
276 SOSCCSetGestalt_Server(CFStringRef deviceName,
281 SOSGestaltDeviceName = CFRetainSafe(deviceName);
282 SOSGestaltVersion = CFRetainSafe(version);
283 SOSGestaltModel = CFRetainSafe(model);
284 SOSGestaltSerial = CFRetainSafe(serial);
287 CFStringRef SOSCCCopyOSVersion(void)
289 static dispatch_once_t once;
290 dispatch_once(&once, ^{
291 if (SOSGestaltVersion == NULL) {
292 CFDictionaryRef versions = _CFCopySystemVersionDictionary();
294 CFTypeRef versionValue = CFDictionaryGetValue(versions, _kCFSystemVersionBuildVersionKey);
295 if (isString(versionValue))
296 SOSGestaltVersion = CFRetainSafe((CFStringRef) versionValue);
299 CFReleaseNull(versions);
300 if (SOSGestaltVersion == NULL) {
301 SOSGestaltVersion = CFSTR("Unknown model");
305 return CFRetainSafe(SOSGestaltVersion);
309 static CFStringRef CopyModelName(void)
311 static dispatch_once_t once;
312 dispatch_once(&once, ^{
313 if (SOSGestaltModel == NULL) {
315 SOSGestaltModel = MGCopyAnswer(kMGQDeviceName, NULL);
317 SOSGestaltModel = ASI_CopyComputerModelName(FALSE);
319 if (SOSGestaltModel == NULL)
320 SOSGestaltModel = CFSTR("Unknown model");
323 return CFStringCreateCopy(kCFAllocatorDefault, SOSGestaltModel);
326 static CFStringRef CopyComputerName(SCDynamicStoreRef store)
328 if (SOSGestaltDeviceName == NULL) {
329 CFStringRef deviceName = SCDynamicStoreCopyComputerName(store, NULL);
330 if (deviceName == NULL) {
331 deviceName = CFSTR("Unknown name");
335 return SOSGestaltDeviceName;
338 static bool _EngineMessageProtocolV2Enabled(void)
342 static dispatch_once_t onceToken;
343 static bool v2_enabled = false;
344 dispatch_once(&onceToken, ^{
345 CFTypeRef v2Pref = (CFNumberRef)CFPreferencesCopyValue(CFSTR("engineV2"), CFSTR("com.apple.security"), kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
347 if (v2Pref && CFGetTypeID(v2Pref) == CFBooleanGetTypeID()) {
348 v2_enabled = CFBooleanGetValue((CFBooleanRef)v2Pref);
349 secinfo("server", "Engine v2 : %s", v2_enabled ? "enabled":"disabled");
351 CFReleaseSafe(v2Pref);
361 static CFDictionaryRef CreateDeviceGestaltDictionary(SCDynamicStoreRef store, CFArrayRef keys, void *context)
363 CFStringRef modelName = CopyModelName();
364 CFStringRef computerName = CopyComputerName(store);
365 CFStringRef osVersion = SOSCCCopyOSVersion();
367 SInt32 version = _EngineMessageProtocolV2Enabled() ? kEngineMessageProtocolVersion : 0;
368 CFNumberRef protocolVersion = CFNumberCreate(0, kCFNumberSInt32Type, &version);
370 CFDictionaryRef gestalt = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
371 kPIUserDefinedDeviceNameKey, computerName,
372 kPIDeviceModelNameKey, modelName,
373 kPIMessageProtocolVersionKey, protocolVersion,
374 kPIOSVersionKey, osVersion,
376 CFReleaseSafe(osVersion);
377 CFReleaseSafe(modelName);
378 CFReleaseSafe(computerName);
379 CFReleaseSafe(protocolVersion);
384 static void SOSCCProcessGestaltUpdate(SCDynamicStoreRef store, CFArrayRef keys, void *context)
386 do_with_account(^(SOSAccountTransaction* txn) {
388 CFDictionaryRef gestalt = CreateDeviceGestaltDictionary(store, keys, context);
389 if ([txn.account.trust updateGestalt:txn.account newGestalt:gestalt]) {
390 secnotice("circleOps", "Changed our peer's gestalt information. This is not a circle change.");
392 CFReleaseSafe(gestalt);
398 static CFDictionaryRef CreateDeviceGestaltDictionaryAndRegisterForUpdate(dispatch_queue_t queue, void *info)
400 SCDynamicStoreContext context = { .info = info };
401 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("com.apple.securityd.cloudcircleserver"), SOSCCProcessGestaltUpdate, &context);
402 CFStringRef computerKey = SCDynamicStoreKeyCreateComputerName(NULL);
403 CFArrayRef keys = NULL;
404 CFDictionaryRef gestalt = NULL;
406 if (store == NULL || computerKey == NULL) {
409 keys = CFArrayCreate(NULL, (const void **)&computerKey, 1, &kCFTypeArrayCallBacks);
413 gestalt = CreateDeviceGestaltDictionary(store, keys, info);
414 SCDynamicStoreSetNotificationKeys(store, keys, NULL);
415 SCDynamicStoreSetDispatchQueue(store, queue);
418 if (store) CFRelease(store);
419 if (computerKey) CFRelease(computerKey);
420 if (keys) CFRelease(keys);
424 os_state_block_t accountStateBlock = ^os_state_data_t(os_state_hints_t hints) {
425 os_state_data_t retval = NULL;
426 CFDataRef savedAccount = NULL;
427 if(hints->osh_api != OS_STATE_API_REQUEST) return NULL;
429 /* Get account DER */
430 savedAccount = SOSKeychainCopySavedAccountData();
431 require_quiet(savedAccount, errOut);
433 /* make a os_state_data_t object to return. */
434 size_t statelen = CFDataGetLength(savedAccount);
435 retval = (os_state_data_t)calloc(1, OS_STATE_DATA_SIZE_NEEDED(statelen));
436 require_quiet(retval, errOut);
438 retval->osd_type = OS_STATE_DATA_PROTOCOL_BUFFER;
439 memcpy(retval->osd_data, CFDataGetBytePtr(savedAccount), statelen);
440 retval->osd_size = statelen;
441 strlcpy(retval->osd_title, "CloudCircle Account Object", sizeof(retval->osd_title));
444 CFReleaseNull(savedAccount);
448 #define FOR_EXISTING_ACCOUNT 1
449 #define CREATE_ACCOUNT_IF_NONE 0
451 static SOSAccount* GetSharedAccount(bool onlyIfItExists) {
452 static SOSAccount* sSharedAccount = NULL;
453 static dispatch_once_t onceToken;
455 #if !TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
457 secerror("Cannot inflate account object as root");
463 return sSharedAccount;
466 dispatch_once(&onceToken, ^{
467 secdebug("account", "Account Creation start");
469 CFDictionaryRef gestalt = CreateDeviceGestaltDictionaryAndRegisterForUpdate(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
472 #if TARGET_OS_IPHONE && TARGET_OS_SIMULATOR
473 gestalt = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, NULL);
475 secerror("Didn't get machine gestalt! This is going to be ugly.");
479 sSharedAccount = SOSKeychainAccountCreateSharedAccount(gestalt);
481 SOSAccountAddChangeBlock(sSharedAccount, ^(SOSAccount *account, SOSCircleRef circle,
482 CFSetRef peer_additions, CFSetRef peer_removals,
483 CFSetRef applicant_additions, CFSetRef applicant_removals) {
484 CFErrorRef pi_error = NULL;
485 SOSPeerInfoRef me = account.peerInfo;
487 secinfo("circleOps", "Change block called with no peerInfo");
491 if(!SOSCircleHasPeer(circle, me, NULL)) {
492 secinfo("circleOps", "Change block called while not in circle");
496 // TODO: Figure out why peer_additions isn't right in some cases (like when joining a v2 circle with a v0 peer.
497 if (CFSetGetCount(peer_additions) != 0) {
498 secnotice("updates", "Requesting Ensure Peer Registration.");
499 SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
501 secinfo("updates", "Not requesting Ensure Peer Registration, since it's not needed");
504 if (CFSetContainsValue(peer_additions, me)) {
505 // TODO: Potentially remove from here and move this to the engine
506 // TODO: We also need to do this when our views change.
507 CFMutableSetRef peers = SOSCircleCopyPeers(circle, kCFAllocatorDefault);
508 CFSetRemoveValue(peers, me);
509 if (!CFSetIsEmpty(peers)) {
510 SOSCCRequestSyncWithPeers(peers);
512 CFReleaseNull(peers);
515 CFReleaseNull(pi_error);
517 if (CFSetGetCount(peer_additions) != 0 ||
518 CFSetGetCount(peer_removals) != 0 ||
519 CFSetGetCount(applicant_additions) != 0 ||
520 CFSetGetCount(applicant_removals) != 0) {
522 if(CFSetGetCount(peer_removals) != 0)
524 CFErrorRef localError = NULL;
525 CFMutableArrayRef removed = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
526 CFSetForEach(peer_removals, ^(const void *value) {
527 CFArrayAppendValue(removed, value);
529 SOSAccountRemoveBackupPeers(account, removed, &localError);
531 secerror("Had trouble removing: %@, error: %@", removed, localError);
532 CFReleaseNull(localError);
533 CFReleaseNull(removed);
535 secnotice("circleOps", "peer counts changed, posting kSOSCCCircleChangedNotification");
536 account.notifyCircleChangeOnExit = true;
540 SOSCloudKeychainSetItemsChangedBlock(^CFArrayRef(CFDictionaryRef changes) {
541 CFRetainSafe(changes);
542 __block CFMutableArrayRef handledKeys = NULL;
543 do_with_account(^(SOSAccountTransaction* txn) {
544 CFStringRef changeDescription = SOSItemsChangedCopyDescription(changes, false);
545 secdebug(SOSCKCSCOPE, "Received: %@", changeDescription);
546 CFReleaseSafe(changeDescription);
548 CFErrorRef error = NULL;
549 handledKeys = SOSTransportDispatchMessages(txn, changes, &error);
550 if (!handledKeys || error) {
551 secerror("Error handling updates: %@", error);
553 CFReleaseNull(error);
555 CFReleaseSafe(changes);
558 CFReleaseSafe(gestalt);
560 sSharedAccount.saveBlock = ^(CFDataRef flattenedAccount, CFErrorRef flattenFailError) {
561 if (flattenedAccount) {
562 SOSKeychainAccountEnsureSaved(flattenedAccount);
564 secerror("Failed to transform account into data, error: %@", flattenFailError);
567 // TODO: We should not be doing extra work whenever securityd is launched, let's see if we can eliminate this call
568 SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
570 // provide state handler to sysdiagnose and logging
571 os_state_add_handler(dispatch_get_global_queue(0, 0), accountStateBlock);
573 [sSharedAccount ghostBustSchedule];
577 return sSharedAccount;
580 CFTypeRef GetSharedAccountRef(void)
582 return (__bridge CFTypeRef)GetSharedAccount(FOR_EXISTING_ACCOUNT);
585 static void do_with_account(void (^action)(SOSAccountTransaction* txn)) {
587 SOSAccount* account = GetSharedAccount(CREATE_ACCOUNT_IF_NONE);
590 [account performTransaction:^(SOSAccountTransaction * _Nonnull txn) {
597 static bool isValidUser(CFErrorRef* error) {
598 #if !TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
600 secerror("Cannot inflate account object as root");
601 SOSErrorCreate(kSOSErrorUnsupported, error, NULL, CFSTR("Cannot inflate account object as root"));
609 static bool do_if_after_first_unlock(CFErrorRef *error, dispatch_block_t action)
611 #if TARGET_OS_SIMULATOR
615 bool beenUnlocked = false;
616 require_quiet(SecAKSGetHasBeenUnlocked(&beenUnlocked, error), fail);
618 require_action_quiet(beenUnlocked, fail,
619 SOSCreateErrorWithFormat(kSOSErrorNotReady, NULL, error, NULL,
620 CFSTR("Keybag never unlocked, ask after first unlock")));
631 static bool do_with_account_if_after_first_unlock(CFErrorRef *error, bool (^action)(SOSAccountTransaction* txn, CFErrorRef* error))
633 __block bool action_result = false;
635 return isValidUser(error) && do_if_after_first_unlock(error, ^{
636 do_with_account(^(SOSAccountTransaction* txn) {
637 action_result = action(txn, error);
643 static bool isAssertionLockAcquireError(CFErrorRef error) {
644 return (CFErrorGetCode(error) == kIOReturnNotPermitted) && (CFEqualSafe(CFErrorGetDomain(error), kSecKernDomain));
647 static bool do_with_account_while_unlocked(CFErrorRef *error, bool (^action)(SOSAccountTransaction* txn, CFErrorRef* error))
651 CFErrorRef statusError = NULL;
653 __block bool action_result = false;
654 __block bool attempted_action = false;
655 __block CFErrorRef localError = NULL;
658 if(!isValidUser(error)){
659 if (error && !*error && localError) {
660 CFTransferRetained(*error, localError);
662 CFReleaseNull(localError);
663 CFReleaseNull(statusError);
668 result = SecAKSDoWithUserBagLockAssertion(&localError, ^{
669 // SOSAccountGhostBustingOptions need to be retrieved from RAMP while not holding the account queue
670 // yet we only want to request RAMP info if it's "time" to ghostbust.
672 #if GHOSTBUST_PERIODIC && (TARGET_OS_IOS || TARGET_OS_OSX)
673 __block bool ghostbustnow = false;
674 __block SOSAccountGhostBustingOptions gbOptions = 0;
676 // Avoid mutual deadlock for just checking date.
677 // Check to see if we're InCircle using the client API - will read cached value if available; otherwise it'll do the round trip and lock appropriately
678 SOSCCStatus circleStatus = SOSCCThisDeviceIsInCircle(NULL);
679 if(circleStatus == kSOSCCInCircle) {
680 // Only need the account object to check settings
681 SOSAccount *tmpAccount = GetSharedAccount(FOR_EXISTING_ACCOUNT);
682 if(tmpAccount.settings) {
683 ghostbustnow = [tmpAccount ghostBustCheckDate];
686 // Get ramp settings from the Cloud
688 gbOptions = [SOSAccount ghostBustGetRampSettings];
693 do_with_account(^(SOSAccountTransaction* txn) {
694 SOSAccount *account = txn.account;
695 if ([account isInCircle:(NULL)] && [SOSAuthKitHelpers accountIsHSA2]) {
696 if(![SOSAuthKitHelpers peerinfoHasMID: account]) {
697 // This is the first good opportunity to update our FullPeerInfo and
698 // push the resulting circle.
699 [SOSAuthKitHelpers updateMIDInPeerInfo: account];
702 #if GHOSTBUST_PERIODIC && (TARGET_OS_IOS || TARGET_OS_OSX)
704 [account ghostBustPeriodic:gbOptions complete:^(bool ghostBusted, NSError *error) {
705 secnotice("ghostbust", "GhostBusting: %@", ghostBusted ? CFSTR("true"): CFSTR("false"));
709 attempted_action = true;
710 action_result = action(txn, error);
716 // For <rdar://problem/24355048> 13E196: Circle join fails after successful recovery with a mach error if performed while device is locked
717 // If we fail with an error attempting to get an assertion while someone else has one and the system is unlocked, it must be trying to lock.
718 // we assume our caller will hold the lock assertion for us to finsh our job.
719 // to be extra paranoid we track if we tried the caller's block. If we did we don't do it again.
721 if(result || !isAssertionLockAcquireError(localError)){
722 if (error && !*error && localError) {
723 CFTransferRetained(*error, localError);
725 CFReleaseNull(localError);
726 CFReleaseNull(statusError);
728 return (result && action_result);
730 if(attempted_action){
731 if (error && !*error && localError) {
732 CFTransferRetained(*error, localError);
734 CFReleaseNull(localError);
735 CFReleaseNull(statusError);
737 return (result && action_result);
740 bool isUnlocked = false;
741 (void) SecAKSGetIsUnlocked(&isUnlocked, &statusError);
743 secnotice("while-unlocked-hack", "Not trying action, aks bag locked (%@)", statusError);
744 if (error && !*error && localError) {
745 CFTransferRetained(*error, localError);
747 CFReleaseNull(localError);
748 CFReleaseNull(statusError);
750 return result && action_result;
753 CFReleaseNull(localError);
755 secnotice("while-unlocked-hack", "Trying action while unlocked without assertion");
758 do_with_account(^(SOSAccountTransaction* txn) {
759 action_result = action(txn, &localError);
762 secnotice("while-unlocked-hack", "Action %s (%@)", action_result ? "succeeded" : "failed", localError);
764 if (error && !*error && localError) {
765 CFTransferRetained(*error, localError);
767 CFReleaseNull(localError);
768 CFReleaseNull(statusError);
770 return result && action_result;
775 CFTypeRef SOSKeychainAccountGetSharedAccount()
777 __block SOSAccount* result = NULL;
778 result = GetSharedAccount(FOR_EXISTING_ACCOUNT);
781 secnotice("secAccount", "Failed request for account object");
783 return (__bridge CFTypeRef)result;
787 // Mark: Credential processing
791 SOSViewResultCode SOSCCView_Server(CFStringRef viewname, SOSViewActionCode action, CFErrorRef *error) {
792 __block SOSViewResultCode status = kSOSCCGeneralViewError;
794 do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
798 case kSOSCCViewQuery:
799 status = [txn.account.trust viewStatus:txn.account name:viewname err:error];
802 case kSOSCCViewEnable:
803 status = [txn.account.trust updateView:txn.account name:viewname code:action err:error];
807 case kSOSCCViewDisable:
808 status = [txn.account.trust updateView:txn.account name:viewname code:action err:error];
812 secnotice("views", "Bad SOSViewActionCode - %d", (int) action);
821 bool SOSCCViewSetWithAnalytics_Server(CFSetRef enabledViews, CFSetRef disabledViews, CFDataRef parentEvent) {
822 __block bool status = false;
823 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCViewSet);
825 do_with_account_if_after_first_unlock(NULL, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
826 status = [txn.account.trust updateViewSetsWithAnalytics:txn.account enabled:enabledViews disabled:disabledViews parentEvent:(__bridge NSData*)parentEvent];
829 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCViewSet, OctagonSignpostNumber1(SOSSignpostNameSOSCCViewSet), (int)status);
834 bool SOSCCViewSet_Server(CFSetRef enabledViews, CFSetRef disabledViews) {
835 return SOSCCViewSetWithAnalytics_Server(enabledViews, disabledViews, NULL);
839 void sync_the_last_data_to_kvs(CFTypeRef account, bool waitForeverForSynchronization){
840 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSyncTheLastDataToKVS);
841 __block CFErrorRef localError = NULL;
843 dispatch_semaphore_t wait_for = dispatch_semaphore_create(0);
845 secnoticeq("force-push", "calling SOSCloudKeychainSynchronizeAndWait");
847 SOSCloudKeychainSynchronizeAndWait(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) {
849 secerrorq("SOSCloudKeychainSynchronizeAndWait: %@", sync_error);
850 localError = sync_error;
852 secnoticeq("force-push", "returned from call; in callback to SOSCloudKeychainSynchronizeAndWait: results: %@", returnedValues);
855 dispatch_semaphore_signal(wait_for);
858 if(waitForeverForSynchronization)
859 dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER);
861 dispatch_semaphore_wait(wait_for, dispatch_time(DISPATCH_TIME_NOW, 60ull * NSEC_PER_SEC));
864 bool subTaskSuccess = (localError == NULL) ? true : false;
865 OctagonSignpostEnd(signPost, SOSSignpostNameSyncTheLastDataToKVS, OctagonSignpostNumber1(SOSSignpostNameSyncTheLastDataToKVS), (int)subTaskSuccess);
868 #define kWAIT2MINID "EFRESH"
870 static bool SyncKVSAndWait(CFErrorRef *error) {
871 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSyncKVSAndWait);
873 dispatch_semaphore_t wait_for = dispatch_semaphore_create(0);
875 __block bool success = false;
877 secnoticeq("fresh", "EFP calling SOSCloudKeychainSynchronizeAndWait");
879 os_activity_initiate("CloudCircle EFRESH", OS_ACTIVITY_FLAG_DEFAULT, ^(void) {
880 SOSCloudKeychainSynchronizeAndWait(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(__unused CFDictionaryRef returnedValues, CFErrorRef sync_error) {
881 secnotice("fresh", "EFP returned, callback error: %@", sync_error);
883 success = (sync_error == NULL);
885 CFRetainAssign(*error, sync_error);
888 dispatch_semaphore_signal(wait_for);
892 dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER);
893 secnotice("fresh", "EFP complete: %s %@", success ? "success" : "failure", error ? *error : NULL);
895 OctagonSignpostEnd(signPost, SOSSignpostNameSyncKVSAndWait, OctagonSignpostNumber1(SOSSignpostNameSyncKVSAndWait), (int)success);
900 static bool Flush(CFErrorRef *error) {
901 __block bool success = false;
902 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameFlush);
904 dispatch_semaphore_t wait_for = dispatch_semaphore_create(0);
905 secnotice("flush", "Starting");
907 SOSCloudKeychainFlush(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) {
908 success = (sync_error == NULL);
910 CFRetainAssign(*error, sync_error);
913 dispatch_semaphore_signal(wait_for);
916 dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER);
918 secnotice("flush", "Returned %s", success? "Success": "Failure");
920 OctagonSignpostEnd(signPost, SOSSignpostNameFlush, OctagonSignpostNumber1(SOSSignpostNameFlush), (int)success);
925 bool SOSCCTryUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error) {
926 secnotice("updates", "Trying credentials and dsid (%@) for %@", dsid, user_label);
927 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCTryUserCredentials);
929 bool result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
930 if (dsid != NULL && CFStringCompare(dsid, CFSTR(""), 0) != 0) {
931 SOSAccountAssertDSID(txn.account, dsid);
936 require_quiet(result, done);
938 require_quiet(SyncKVSAndWait(error), done); // Make sure we've seen what the server has
939 require_quiet(Flush(error), done); // And processed it already...before asserting
941 result = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *block_error) {
942 return SOSAccountTryUserCredentials(txn.account, user_label, user_password, block_error);
945 require_quiet(result, done);
946 require_quiet(Flush(error), done);
949 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCTryUserCredentials, OctagonSignpostNumber1(SOSSignpostNameSOSCCTryUserCredentials), (int)result);
954 static bool SOSCCAssertUserCredentialsAndOptionalDSID(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, NSData* parentEvent, CFErrorRef *error) {
955 secnotice("updates", "Setting credentials and dsid (%@) for %@", dsid, user_label);
956 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameAssertUserCredentialsAndOptionalDSID);
958 NSError* localError = nil;
959 SFSignInAnalytics* parent = nil;
962 parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:parentEvent error:&localError];
965 SFSignInAnalytics *syncAndWaitEvent = nil;
966 SFSignInAnalytics *flushEvent = nil;
967 SFSignInAnalytics *secondFlushEvent = nil;
968 SFSignInAnalytics *generationSignatureUpdateEvent = nil;
970 bool result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
971 if (dsid != NULL && CFStringCompare(dsid, CFSTR(""), 0) != 0) {
972 SOSAccountAssertDSID(txn.account, dsid);
977 require_quiet(result, done);
980 syncAndWaitEvent = [parent newSubTaskForEvent:@"syncAndWaitEvent"];
982 require_quiet(SyncKVSAndWait(error), done); // Make sure we've seen what the server has
983 if(syncAndWaitEvent) {
984 [syncAndWaitEvent stopWithAttributes:nil];
988 flushEvent = [parent newSubTaskForEvent:@"flushEvent"];
990 require_quiet(Flush(error), done); // And processed it already...before asserting
992 [flushEvent stopWithAttributes:nil];
995 result = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *block_error) {
996 return SOSAccountAssertUserCredentials(txn.account, user_label, user_password, block_error);
999 require_quiet(result, done);
1001 secondFlushEvent = [parent newSubTaskForEvent:@"secondFlushEvent"];
1003 require_quiet(Flush(error), done); // Process any incoming information..circles et.al. before fixing our signature
1004 if(secondFlushEvent) {
1005 [secondFlushEvent stopWithAttributes:nil];
1009 generationSignatureUpdateEvent = [parent newSubTaskForEvent:@"generationSignatureUpdateEvent"];
1011 result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1012 return SOSAccountGenerationSignatureUpdate(txn.account, error);
1015 if(generationSignatureUpdateEvent) {
1016 [generationSignatureUpdateEvent stopWithAttributes:nil];
1020 if(syncAndWaitEvent){
1021 [syncAndWaitEvent stopWithAttributes:nil];
1024 [flushEvent stopWithAttributes:nil];
1026 if(secondFlushEvent){
1027 [secondFlushEvent stopWithAttributes:nil];
1029 if(generationSignatureUpdateEvent){
1030 [generationSignatureUpdateEvent stopWithAttributes:nil];
1032 secnotice("updates", "Complete credentials and dsid (%@) for %@: %d %@",
1033 dsid, user_label, result, error ? *error : NULL);
1035 OctagonSignpostEnd(signPost, SOSSignpostNameAssertUserCredentialsAndOptionalDSID, OctagonSignpostNumber1(SOSSignpostNameAssertUserCredentialsAndOptionalDSID), (int)result);
1040 bool SOSCCSetUserCredentialsAndDSID_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error)
1042 // TODO: Return error if DSID is NULL to insist our callers provide one?
1043 return SOSCCAssertUserCredentialsAndOptionalDSID(user_label, user_password, dsid, nil, error);
1046 bool SOSCCSetUserCredentialsAndDSIDWithAnalytics_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFDataRef parentEvent, CFErrorRef *error)
1048 return SOSCCAssertUserCredentialsAndOptionalDSID(user_label, user_password, dsid, (__bridge NSData*)parentEvent, error);
1051 bool SOSCCSetUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFErrorRef *error)
1053 return SOSCCAssertUserCredentialsAndOptionalDSID(user_label, user_password, NULL, nil, error);
1056 bool SOSCCCanAuthenticate_Server(CFErrorRef *error)
1058 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCCanAuthenticate);
1060 bool result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1061 // If we reply that yes we can authenticate, then let's make sure we can authenticate for a while yet.
1062 // <rdar://problem/32732066>
1063 SOSAccountRestartPrivateCredentialTimer(txn.account);
1064 return SOSAccountGetPrivateCredential(txn.account, block_error) != NULL;
1067 if (!result && error && *error && CFErrorGetDomain(*error) == kSOSErrorDomain) {
1068 CFIndex code = CFErrorGetCode(*error);
1069 if (code == kSOSErrorPrivateKeyAbsent || code == kSOSErrorPublicKeyAbsent) {
1070 CFReleaseNull(*error);
1074 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCCanAuthenticate, OctagonSignpostNumber1(SOSSignpostNameSOSCCCanAuthenticate), (int)result);
1079 bool SOSCCPurgeUserCredentials_Server(CFErrorRef *error)
1081 return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1082 SOSAccountPurgePrivateCredential(txn.account);
1087 SOSCCStatus SOSCCThisDeviceIsInCircle_Server(CFErrorRef *error)
1089 __block SOSCCStatus status;
1091 return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1092 status = [txn.account getCircleStatus:block_error];
1095 }) ? status : kSOSCCError;
1098 bool SOSCCRequestToJoinCircleWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error)
1100 __block bool result = true;
1101 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRequestToJoinCircle);
1103 bool requested = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1104 result = SOSAccountJoinCircles(txn, (__bridge NSData*)parentEvent, block_error);
1107 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRequestToJoinCircle, OctagonSignpostNumber1(SOSSignpostNameSOSCCRequestToJoinCircle), (int)requested);
1111 bool SOSCCRequestToJoinCircle_Server(CFErrorRef* error)
1113 return SOSCCRequestToJoinCircleWithAnalytics_Server(nil, error);
1116 bool SOSCCAccountHasPublicKey_Server(CFErrorRef *error)
1118 __block bool result = true;
1119 __block CFErrorRef localError = NULL;
1121 bool hasPublicKey = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1122 result = SOSAccountHasPublicKey(txn.account, &localError);
1126 if(error != NULL && localError != NULL)
1127 *error = localError;
1129 return hasPublicKey;
1132 bool SOSCCRequestToJoinCircleAfterRestoreWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error)
1134 __block bool result = true;
1135 bool returned = false;
1136 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRequestToJoinCircleAfterRestore);
1137 returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1138 NSError* localError = nil;
1139 SFSignInAnalytics* parent = nil;
1140 SFSignInAnalytics *ensurePeerRegistrationEvent = nil;
1143 parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:(__bridge NSData*)parentEvent error:&localError];
1144 ensurePeerRegistrationEvent = [parent newSubTaskForEvent:@"ensurePeerRegistrationEvent"];
1147 SOSAccountEnsurePeerRegistration(txn.account, block_error);
1148 if(block_error && *block_error){
1149 NSError* blockError = (__bridge NSError*)*block_error;
1151 if(ensurePeerRegistrationEvent) {
1152 [ensurePeerRegistrationEvent logRecoverableError:blockError];
1154 secerror("ensure peer registration error: %@", blockError);
1157 if(ensurePeerRegistrationEvent) {
1158 [ensurePeerRegistrationEvent stopWithAttributes:nil];
1160 result = SOSAccountJoinCirclesAfterRestore(txn, (__bridge NSData*)parentEvent, block_error);
1163 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRequestToJoinCircleAfterRestore, OctagonSignpostNumber1(SOSSignpostNameSOSCCRequestToJoinCircleAfterRestore), (int)result);
1168 bool SOSCCRequestToJoinCircleAfterRestore_Server(CFErrorRef* error)
1170 return SOSCCRequestToJoinCircleAfterRestoreWithAnalytics_Server(nil, error);
1173 bool SOSCCAccountSetToNew_Server(CFErrorRef *error)
1175 return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1176 SOSAccountSetToNew(txn.account);
1181 bool SOSCCResetToOffering_Server(CFErrorRef* error)
1183 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCResetToOffering);
1185 bool resetResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1186 bool result = false;
1188 SecKeyRef user_key = SOSAccountGetPrivateCredential(txn.account, error);
1192 result = [txn.account.trust resetToOffering:txn key:user_key err:block_error];
1195 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCResetToOffering, OctagonSignpostNumber1(SOSSignpostNameSOSCCResetToOffering), (int)resetResult);
1199 bool SOSCCResetToEmpty_Server(CFErrorRef* error)
1201 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCResetToEmpty);
1203 bool resetResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1204 bool result = false;
1206 if (!SOSAccountHasPublicKey(txn.account, error)) {
1209 result = [txn.account.trust resetAccountToEmpty:txn.account transport:txn.account.circle_transport err:block_error];
1212 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCResetToEmpty, OctagonSignpostNumber1(SOSSignpostNameSOSCCResetToEmpty), (int)resetResult);
1216 bool SOSCCResetToEmptyWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error)
1218 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCResetToEmpty);
1220 bool resetResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1221 bool result = false;
1223 if (!SOSAccountHasPublicKey(txn.account, error)) {
1226 result = [txn.account.trust resetAccountToEmptyWithAnalytics:txn.account transport:txn.account.circle_transport parentEvent:(__bridge NSData*)parentEvent err:block_error];
1229 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCResetToEmpty, OctagonSignpostNumber1(SOSSignpostNameSOSCCResetToEmpty), (int)resetResult);
1233 bool SOSCCRemoveThisDeviceFromCircleWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error)
1235 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRemoveThisDeviceFromCircle);
1237 bool removeResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1238 bool result = [txn.account.trust leaveCircleWithAccount:txn.account withAnalytics:(__bridge NSData*)parentEvent err:error];
1241 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRemoveThisDeviceFromCircle, OctagonSignpostNumber1(SOSSignpostNameSOSCCRemoveThisDeviceFromCircle), (int)removeResult);
1243 return removeResult;
1246 bool SOSCCRemoveThisDeviceFromCircle_Server(CFErrorRef* error)
1248 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRemoveThisDeviceFromCircle);
1250 bool removeResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1251 bool result = [txn.account.trust leaveCircle:txn.account err:block_error];
1254 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRemoveThisDeviceFromCircle, OctagonSignpostNumber1(SOSSignpostNameSOSCCRemoveThisDeviceFromCircle), (int)removeResult);
1255 return removeResult;
1258 bool SOSCCRemovePeersFromCircle_Server(CFArrayRef peers, CFErrorRef* error)
1260 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRemovePeersFromCircle);
1262 bool removeResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1263 bool result = SOSAccountRemovePeersFromCircle(txn.account, peers, nil, block_error);
1266 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRemovePeersFromCircle, OctagonSignpostNumber1(SOSSignpostNameSOSCCRemovePeersFromCircle), (int)removeResult);
1267 return removeResult;
1270 bool SOSCCRemovePeersFromCircleWithAnalytics_Server(CFArrayRef peers, CFDataRef parentEvent, CFErrorRef* error)
1272 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRemovePeersFromCircle);
1274 bool removeResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1275 bool result = SOSAccountRemovePeersFromCircle(txn.account, peers, (__bridge NSData*)parentEvent, block_error);
1278 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRemovePeersFromCircle, OctagonSignpostNumber1(SOSSignpostNameSOSCCRemovePeersFromCircle), (int)removeResult);
1279 return removeResult;
1282 bool SOSCCLoggedOutOfAccount_Server(CFErrorRef *error)
1284 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCLoggedOutOfAccount);
1286 bool loggedOutResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1287 secnotice("circleOps", "Signed out of account!");
1290 bool waitForeverForSynchronization = true;
1292 bool result = [txn.account.trust leaveCircle:txn.account err:block_error];
1294 [txn restart]; // Make sure this gets finished before we set to new.
1296 sync_the_last_data_to_kvs((__bridge CFTypeRef)(txn.account), waitForeverForSynchronization);
1298 SOSAccountSetToNew(txn.account);
1303 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCLoggedOutOfAccount, OctagonSignpostNumber1(SOSSignpostNameSOSCCLoggedOutOfAccount), (int)loggedOutResult);
1304 return loggedOutResult;
1307 bool SOSCCBailFromCircle_Server(uint64_t limit_in_seconds, CFErrorRef* error)
1309 return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1310 bool waitForeverForSynchronization = false;
1312 bool result = SOSAccountBail(txn.account, limit_in_seconds, block_error);
1314 [txn restart]; // Make sure this gets finished before we set to new.
1316 sync_the_last_data_to_kvs((__bridge CFTypeRef)(txn.account), waitForeverForSynchronization);
1323 CFArrayRef SOSCCCopyApplicantPeerInfo_Server(CFErrorRef* error)
1325 __block CFArrayRef result = NULL;
1327 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCCopyApplicantPeerInfo);
1329 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1330 result = SOSAccountCopyApplicants(txn.account, block_error);
1331 return result != NULL;
1334 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCCopyApplicantPeerInfo, OctagonSignpostNumber1(SOSSignpostNameSOSCCCopyApplicantPeerInfo), (int)(result != NULL));
1339 CFArrayRef SOSCCCopyGenerationPeerInfo_Server(CFErrorRef* error)
1341 __block CFArrayRef result = NULL;
1343 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1344 result = SOSAccountCopyGeneration(txn.account, block_error);
1345 return result != NULL;
1351 CFArrayRef SOSCCCopyValidPeerPeerInfo_Server(CFErrorRef* error)
1353 __block CFArrayRef result = NULL;
1354 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCCopyValidPeerPeerInfo);
1358 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1360 result = SOSAccountCopyValidPeers(txn.account, block_error);
1362 return result != NULL;
1365 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCCopyValidPeerPeerInfo, OctagonSignpostNumber1(SOSSignpostNameSOSCCCopyValidPeerPeerInfo), (int)(result != NULL));
1370 bool SOSCCValidateUserPublic_Server(CFErrorRef* error)
1372 __block bool result = NULL;
1373 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCValidateUserPublic);
1375 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1376 result = SOSValidateUserPublic(txn.account, block_error);
1379 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCValidateUserPublic, OctagonSignpostNumber1(SOSSignpostNameSOSCCValidateUserPublic), (int)result);
1384 CFArrayRef SOSCCCopyNotValidPeerPeerInfo_Server(CFErrorRef* error)
1386 __block CFArrayRef result = NULL;
1388 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1389 result = SOSAccountCopyNotValidPeers(txn.account, block_error);
1390 return result != NULL;
1396 CFArrayRef SOSCCCopyRetirementPeerInfo_Server(CFErrorRef* error)
1398 __block CFArrayRef result = NULL;
1400 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1401 result = SOSAccountCopyRetired(txn.account, block_error);
1402 return result != NULL;
1408 CFArrayRef SOSCCCopyViewUnawarePeerInfo_Server(CFErrorRef* error)
1410 __block CFArrayRef result = NULL;
1411 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCCopyViewUnawarePeerInfo);
1413 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1414 result = SOSAccountCopyViewUnaware(txn.account, block_error);
1415 return result != NULL;
1417 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCCopyViewUnawarePeerInfo, OctagonSignpostNumber1(SOSSignpostNameSOSCCCopyViewUnawarePeerInfo), (int)(result != NULL));
1422 CFArrayRef SOSCCCopyEngineState_Server(CFErrorRef* error)
1424 CFArrayRef result = NULL;
1425 SOSDataSourceFactoryRef dsf = SecItemDataSourceFactoryGetDefault();
1426 SOSDataSourceRef ds = SOSDataSourceFactoryCreateDataSource(dsf, kSecAttrAccessibleWhenUnlocked, error);
1428 SOSEngineRef engine = SOSDataSourceGetSharedEngine(ds, error);
1429 result = SOSEngineCopyPeerConfirmedDigests(engine, error);
1430 SOSDataSourceRelease(ds, error);
1436 static int64_t getTimeDifference(time_t start)
1443 duration = stop - start;
1445 return SecBucket1Significant(duration);
1448 static uint64_t initialSyncTimeoutFromDefaultsWrite(void)
1450 uint64_t timeout = 10;
1452 //sudo defaults write /Library/Preferences/com.apple.authd enforceEntitlement -bool true
1453 CFTypeRef initialSyncTimeout = (CFNumberRef)CFPreferencesCopyValue(CFSTR("InitialSync.WaitPeriod"), CFSTR("com.apple.security"), kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
1455 if (isNumber(initialSyncTimeout)) {
1456 CFNumberGetValue((CFNumberRef)initialSyncTimeout, kCFNumberSInt64Type, &timeout);
1458 CFReleaseNull(initialSyncTimeout);
1462 bool SOSCCWaitForInitialSyncWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error) {
1463 __block dispatch_semaphore_t inSyncSema = NULL;
1464 __block bool result = false;
1465 __block bool synced = false;
1466 bool timed_out = false;
1467 __block CFStringRef inSyncCallID = NULL;
1468 __block time_t start;
1469 __block CFBooleanRef shouldUseInitialSyncV0 = false;
1470 SFSignInAnalytics* syncingEvent = nil;
1471 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCWaitForInitialSync);
1473 NSError* localError = nil;
1474 SFSignInAnalytics* parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:(__bridge NSData*)parentEvent error:&localError];
1476 secnotice("initial sync", "Wait for initial sync start!");
1478 result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1479 shouldUseInitialSyncV0 = (CFBooleanRef)SOSAccountGetValue(txn.account, kSOSInitialSyncTimeoutV0, error);
1480 bool alreadyInSync = (SOSAccountHasCompletedInitialSync(txn.account));
1482 if (!alreadyInSync) {
1484 inSyncSema = dispatch_semaphore_create(0);
1486 SFSignInAnalytics* callWhenInSyncEvent = [parent newSubTaskForEvent:@"callWhenInSync"];
1487 inSyncCallID = SOSAccountCallWhenInSync(txn.account, ^bool(SOSAccount* mightBeSynced) {
1491 dispatch_semaphore_signal(inSyncSema);
1492 NSDictionary* attributes = @{@"finishedSyncing" : @YES};
1493 [syncingEvent stopWithAttributes:attributes];
1497 NSDictionary* attributes = @{};
1498 [callWhenInSyncEvent stopWithAttributes:attributes];
1506 require_quiet(result, fail);
1510 syncingEvent = [parent newSubTaskForEvent:@"initialSyncEvent"];
1511 if(shouldUseInitialSyncV0){
1512 secnotice("piggy","setting initial sync timeout to 5 minutes");
1513 timed_out = dispatch_semaphore_wait(inSyncSema, dispatch_time(DISPATCH_TIME_NOW, 300ull * NSEC_PER_SEC));
1516 uint64_t timeoutFromDefaultsWrite = initialSyncTimeoutFromDefaultsWrite();
1517 secnotice("piggy","setting initial sync timeout to %llu seconds", timeoutFromDefaultsWrite);
1518 timed_out = dispatch_semaphore_wait(inSyncSema, dispatch_time(DISPATCH_TIME_NOW, timeoutFromDefaultsWrite * NSEC_PER_SEC));
1521 if (timed_out && shouldUseInitialSyncV0) {
1522 do_with_account(^(SOSAccountTransaction* txn) {
1523 if (SOSAccountUnregisterCallWhenInSync(txn.account, inSyncCallID)) {
1525 inSyncSema = NULL; // We've canceled the timeout so we must be the last.
1529 NSError* error = [NSError errorWithDomain:@"securityd" code:errSecTimedOut userInfo:@{NSLocalizedDescriptionKey: @"timed out waiting for initial sync"}];
1530 [syncingEvent logUnrecoverableError:error];
1531 NSDictionary* attributes = @{@"finishedSyncing" : @NO, @"legacyPiggybacking" : @YES};
1532 [syncingEvent stopWithAttributes:attributes];
1535 require_quiet(result, fail);
1539 SecADClientPushValueForDistributionKey(SOSAggdSyncCompletionKey, getTimeDifference(start));
1543 SecADAddValueForScalarKey(SOSAggdSyncTimeoutKey, 1);
1546 secnotice("initial sync", "Finished!: %d", result);
1549 CFReleaseNull(inSyncCallID);
1550 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCWaitForInitialSync, OctagonSignpostNumber1(SOSSignpostNameSOSCCWaitForInitialSync), (int)result);
1555 bool SOSCCWaitForInitialSync_Server(CFErrorRef* error) {
1557 __block dispatch_semaphore_t inSyncSema = NULL;
1558 __block bool result = false;
1559 __block bool synced = false;
1560 bool timed_out = false;
1561 __block CFStringRef inSyncCallID = NULL;
1562 __block time_t start;
1563 __block CFBooleanRef shouldUseInitialSyncV0 = false;
1564 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCWaitForInitialSync);
1566 secnotice("initial sync", "Wait for initial sync start!");
1568 result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1569 shouldUseInitialSyncV0 = (CFBooleanRef)SOSAccountGetValue(txn.account, kSOSInitialSyncTimeoutV0, error);
1570 bool alreadyInSync = (SOSAccountHasCompletedInitialSync(txn.account));
1572 if (!alreadyInSync) {
1574 inSyncSema = dispatch_semaphore_create(0);
1576 inSyncCallID = SOSAccountCallWhenInSync(txn.account, ^bool(SOSAccount* mightBeSynced) {
1580 dispatch_semaphore_signal(inSyncSema);
1592 require_quiet(result, fail);
1595 if(shouldUseInitialSyncV0){
1596 secnotice("piggy","setting initial sync timeout to 5 minutes");
1597 timed_out = dispatch_semaphore_wait(inSyncSema, dispatch_time(DISPATCH_TIME_NOW, 300ull * NSEC_PER_SEC));
1600 uint64_t timeoutFromDefaultsWrite = initialSyncTimeoutFromDefaultsWrite();
1601 secnotice("piggy","setting initial sync timeout to %llu seconds", timeoutFromDefaultsWrite);
1602 timed_out = dispatch_semaphore_wait(inSyncSema, dispatch_time(DISPATCH_TIME_NOW, timeoutFromDefaultsWrite * NSEC_PER_SEC));
1605 if (timed_out && shouldUseInitialSyncV0) {
1606 do_with_account(^(SOSAccountTransaction* txn) {
1607 if (SOSAccountUnregisterCallWhenInSync(txn.account, inSyncCallID)) {
1609 inSyncSema = NULL; // We've canceled the timeout so we must be the last.
1615 require_quiet(result, fail);
1619 SecADClientPushValueForDistributionKey(SOSAggdSyncCompletionKey, getTimeDifference(start));
1623 SecADAddValueForScalarKey(SOSAggdSyncTimeoutKey, 1);
1626 secnotice("initial sync", "Finished!: %d", result);
1629 CFReleaseNull(inSyncCallID);
1630 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCWaitForInitialSync, OctagonSignpostNumber1(SOSSignpostNameSOSCCWaitForInitialSync), (int)result);
1635 bool SOSCCAcceptApplicants_Server(CFArrayRef applicants, CFErrorRef* error)
1637 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCAcceptApplicants);
1639 bool acceptResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1640 bool result = SOSAccountAcceptApplicants(txn.account, applicants, block_error);
1643 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCAcceptApplicants, OctagonSignpostNumber1(SOSSignpostNameSOSCCAcceptApplicants), (int)acceptResult);
1644 return acceptResult;
1647 bool SOSCCRejectApplicants_Server(CFArrayRef applicants, CFErrorRef* error)
1649 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCAcceptApplicants);
1651 bool rejectResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1652 bool result = SOSAccountRejectApplicants(txn.account, applicants, block_error);
1655 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCAcceptApplicants, OctagonSignpostNumber1(SOSSignpostNameSOSCCAcceptApplicants), (int)rejectResult);
1656 return rejectResult;
1659 CFArrayRef SOSCCCopyPeerPeerInfo_Server(CFErrorRef* error)
1661 __block CFArrayRef result = NULL;
1663 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1664 result = SOSAccountCopyPeers(txn.account, block_error);
1665 return result != NULL;
1671 CFArrayRef SOSCCCopyConcurringPeerPeerInfo_Server(CFErrorRef* error)
1673 __block CFArrayRef result = NULL;
1674 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCCopyConcurringPeerPeerInfo);
1676 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1677 result = SOSAccountCopyConcurringPeers(txn.account, block_error);
1678 return result != NULL;
1680 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCCopyConcurringPeerPeerInfo, OctagonSignpostNumber1(SOSSignpostNameSOSCCCopyConcurringPeerPeerInfo), (int)(result != NULL));
1685 SOSPeerInfoRef SOSCCCopyMyPeerInfo_Server(CFErrorRef* error)
1687 __block SOSPeerInfoRef result = NULL;
1688 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCCopyMyPeerInfo);
1690 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1691 // Create a copy to be DERed/sent back to client
1692 result = SOSPeerInfoCreateCopy(kCFAllocatorDefault, txn.account.peerInfo, block_error);
1693 return result != NULL;
1695 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCCopyMyPeerInfo, OctagonSignpostNumber1(SOSSignpostNameSOSCCCopyMyPeerInfo), (int)(result != NULL));
1700 SOSPeerInfoRef SOSCCSetNewPublicBackupKey_Server(CFDataRef newPublicBackup, CFErrorRef *error){
1701 __block SOSPeerInfoRef result = NULL;
1702 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCSetNewPublicBackupKey);
1704 secnotice("devRecovery", "SOSCCSetNewPublicBackupKey_Server acquiring account lock");
1705 (void) do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1706 secnotice("devRecovery", "SOSCCSetNewPublicBackupKey_Server acquired account lock");
1707 if(SOSAccountSetBackupPublicKey(txn,newPublicBackup, error)){
1708 secnotice("devRecovery", "SOSCCSetNewPublicBackupKey_Server, new public backup is set in account");
1709 [txn restart]; // Finish the transaction to update any changes to the peer info.
1711 // Create a copy to be DERed/sent back to client
1712 result = SOSPeerInfoCreateCopy(kCFAllocatorDefault, txn.account.peerInfo, block_error);
1713 secnotice("devRecovery", "SOSCCSetNewPublicBackupKey_Server, new public backup is set and pushed");
1717 secnotice("devRecovery", "SOSCCSetNewPublicBackupKey_Server, could not set new public backup");
1719 return result != NULL;
1722 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCSetNewPublicBackupKey, OctagonSignpostNumber1(SOSSignpostNameSOSCCSetNewPublicBackupKey), (int)(result != NULL));
1726 bool SOSCCRegisterSingleRecoverySecret_Server(CFDataRef aks_bag, bool setupV0Only, CFErrorRef *error){
1727 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRegisterSingleRecoverySecret);
1729 bool registerResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1730 bool result = SOSAccountSetBSKBagForAllSlices(txn.account, aks_bag, setupV0Only, error);
1733 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRegisterSingleRecoverySecret, OctagonSignpostNumber1(SOSSignpostNameSOSCCRegisterSingleRecoverySecret), (int)registerResult);
1734 return registerResult;
1737 enum DepartureReason SOSCCGetLastDepartureReason_Server(CFErrorRef* error)
1739 __block enum DepartureReason result = kSOSDepartureReasonError;
1741 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1742 result = SOSAccountGetLastDepartureReason(txn.account, block_error);
1743 return result != kSOSDepartureReasonError;
1749 bool SOSCCSetLastDepartureReason_Server(enum DepartureReason reason, CFErrorRef *error){
1750 return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1751 SOSAccountSetLastDepartureReason(txn.account, reason);
1756 bool SOSCCProcessEnsurePeerRegistration_Server(CFErrorRef* error)
1758 secnotice("updates", "Request for registering peers");
1759 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCProcessEnsurePeerRegistration);
1761 bool processResult = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
1762 bool result = SOSAccountEnsurePeerRegistration(txn.account, error);
1765 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCProcessEnsurePeerRegistration, OctagonSignpostNumber1(SOSSignpostNameSOSCCProcessEnsurePeerRegistration), (int)processResult);
1766 return processResult;
1769 CF_RETURNS_RETAINED CFSetRef SOSCCProcessSyncWithPeers_Server(CFSetRef peers, CFSetRef backupPeers, CFErrorRef *error) {
1770 __block CFSetRef result = NULL;
1771 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCProcessSyncWithPeers);
1773 if (!do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
1774 result = SOSAccountProcessSyncWithPeers(txn, peers, backupPeers, error);
1775 return result != NULL;
1777 // Be sure we don't return a result if we got an error
1778 CFReleaseNull(result);
1780 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCProcessSyncWithPeers, OctagonSignpostNumber1(SOSSignpostNameSOSCCProcessSyncWithPeers), (int)(result != NULL));
1785 SyncWithAllPeersReason SOSCCProcessSyncWithAllPeers_Server(CFErrorRef* error)
1788 #define kIOReturnLockedRead iokit_common_err(0x2c3) // device read locked
1789 #define kIOReturnLockedWrite iokit_common_err(0x2c4) // device write locked
1791 __block SyncWithAllPeersReason result = kSyncWithAllPeersSuccess;
1792 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCProcessSyncWithAllPeers);
1794 CFErrorRef action_error = NULL;
1796 if (!do_with_account_while_unlocked(&action_error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1797 return SOSAccountRequestSyncWithAllPeers(txn, block_error);
1800 if (SecErrorGetOSStatus(action_error) == errSecInteractionNotAllowed) {
1801 secnotice("updates", "SOSAccountSyncWithAllKVSPeers failed because device is locked; letting CloudKeychainProxy know");
1802 result = kSyncWithAllPeersLocked; // tell CloudKeychainProxy to call us back when device unlocks
1803 CFReleaseNull(action_error);
1805 secerror("Unexpected error: %@", action_error);
1809 SecErrorPropagate(action_error, error);
1812 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCProcessSyncWithAllPeers, OctagonSignpostNumber1(SOSSignpostNameSOSCCProcessSyncWithAllPeers), (int)result);
1821 void SOSCCRequestSyncWithPeer(CFStringRef peerID) {
1822 CFArrayRef peers = CFArrayCreateForCFTypes(kCFAllocatorDefault, peerID, NULL);
1824 SOSCCRequestSyncWithPeersList(peers);
1826 CFReleaseNull(peers);
1829 void SOSCCRequestSyncWithPeers(CFSetRef /*SOSPeerInfoRef/CFStringRef*/ peerIDs) {
1830 CFMutableArrayRef peerIDArray = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
1832 CFSetForEach(peerIDs, ^(const void *value) {
1833 if (isString(value)) {
1834 CFArrayAppendValue(peerIDArray, value);
1835 } else if (isSOSPeerInfo(value)) {
1836 SOSPeerInfoRef peer = asSOSPeerInfo(value);
1837 CFArrayAppendValue(peerIDArray, SOSPeerInfoGetPeerID(peer));
1839 secerror("Bad element, skipping: %@", value);
1843 SOSCCRequestSyncWithPeersList(peerIDArray);
1845 CFReleaseNull(peerIDArray);
1848 void SOSCCRequestSyncWithPeersList(CFArrayRef /*CFStringRef*/ peerIDs) {
1849 os_activity_initiate("CloudCircle RequestSyncWithPeersList", OS_ACTIVITY_FLAG_DEFAULT, ^(void) {
1850 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRequestSyncWithPeersList);
1852 CFArrayRef empty = CFArrayCreateForCFTypes(kCFAllocatorDefault, NULL);
1854 CFStringArrayPerformWithDescription(peerIDs, ^(CFStringRef description) {
1855 secnotice("syncwith", "Request Sync With: %@", description);
1858 SOSCloudKeychainRequestSyncWithPeers(peerIDs, empty,
1859 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
1860 CFReleaseNull(empty);
1861 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRequestSyncWithPeersList, OctagonSignpostNumber1(SOSSignpostNameSOSCCRequestSyncWithPeersList), (int)true);
1865 void SOSCCRequestSyncWithBackupPeerList(CFArrayRef /* CFStringRef */ backupPeerIDs) {
1866 os_activity_initiate("CloudCircle SOSCCRequestSyncWithBackupPeerList", OS_ACTIVITY_FLAG_DEFAULT, ^(void) {
1867 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRequestSyncWithBackupPeerList);
1869 CFArrayRef empty = CFArrayCreateForCFTypes(kCFAllocatorDefault, NULL);
1871 CFStringArrayPerformWithDescription(backupPeerIDs, ^(CFStringRef description) {
1872 secnotice("syncwith", "Request backup sync With: %@", description);
1875 SOSCloudKeychainRequestSyncWithPeers(empty, backupPeerIDs,
1876 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
1878 CFReleaseNull(empty);
1879 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRequestSyncWithBackupPeerList, OctagonSignpostNumber1(SOSSignpostNameSOSCCRequestSyncWithBackupPeerList), (int)true);
1884 bool SOSCCIsSyncPendingFor(CFStringRef peerID, CFErrorRef *error) {
1888 void SOSCCEnsurePeerRegistration(void)
1890 os_activity_initiate("CloudCircle EnsurePeerRegistration", OS_ACTIVITY_FLAG_DEFAULT, ^(void) {
1891 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCEnsurePeerRegistration);
1892 SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
1893 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCEnsurePeerRegistration, OctagonSignpostNumber1(SOSSignpostNameSOSCCEnsurePeerRegistration), (int)true);
1898 CF_RETURNS_RETAINED CFArrayRef SOSCCHandleUpdateMessage(CFDictionaryRef updates)
1900 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCHandleUpdateMessage);
1902 CFArrayRef result = NULL;
1903 SOSAccount* account = (__bridge SOSAccount *)(SOSKeychainAccountGetSharedAccount()); //HACK to make sure itemsChangedBlock is set
1905 result = account ? SOSCloudKeychainHandleUpdateMessage(updates) : CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
1907 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCHandleUpdateMessage, OctagonSignpostNumber1(SOSSignpostNameSOSCCHandleUpdateMessage), (int)(result != NULL));
1912 SOSPeerInfoRef SOSCCCopyApplication_Server(CFErrorRef *error) {
1913 __block SOSPeerInfoRef application = NULL;
1914 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCCopyApplication);
1916 do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
1917 application = SOSAccountCopyApplication(txn.account, error);
1918 return application != NULL;
1920 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCCopyApplication, OctagonSignpostNumber1(SOSSignpostNameSOSCCCopyApplication), (int)(application != NULL));
1925 bool SOSCCCleanupKVSKeys_Server(CFErrorRef *error) {
1926 bool result = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
1927 return SOSAccountCleanupAllKVSKeys(txn.account, error);
1929 if(result && error && *error) {
1930 CFReleaseNull(*error);
1935 CFDataRef SOSCCCopyCircleJoiningBlob_Server(SOSPeerInfoRef applicant, CFErrorRef *error) {
1936 __block CFDataRef pbblob = NULL;
1937 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCCopyCircleJoiningBlob);
1939 do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
1940 pbblob = SOSAccountCopyCircleJoiningBlob(txn.account, applicant, error);
1941 return pbblob != NULL;
1943 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCCopyCircleJoiningBlob, OctagonSignpostNumber1(SOSSignpostNameSOSCCCopyCircleJoiningBlob), (int)(pbblob != NULL));
1948 CFDataRef SOSCCCopyInitialSyncData_Server(SOSInitialSyncFlags flags, CFErrorRef *error) {
1949 __block CFDataRef pbblob = NULL;
1950 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCCopyInitialSyncData);
1952 do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
1953 pbblob = SOSAccountCopyInitialSyncData(txn.account, flags, error);
1954 return pbblob != NULL;
1956 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCCopyInitialSyncData, OctagonSignpostNumber1(SOSSignpostNameSOSCCCopyInitialSyncData), (int)(pbblob != NULL));
1961 bool SOSCCJoinWithCircleJoiningBlob_Server(CFDataRef joiningBlob, PiggyBackProtocolVersion version, CFErrorRef *error) {
1962 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCJoinWithCircleJoiningBlob);
1964 bool joinResult = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
1965 bool result = SOSAccountJoinWithCircleJoiningBlob(txn.account, joiningBlob, version, error);
1969 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCJoinWithCircleJoiningBlob, OctagonSignpostNumber1(SOSSignpostNameSOSCCJoinWithCircleJoiningBlob), (int)joinResult);
1973 CFBooleanRef SOSCCPeersHaveViewsEnabled_Server(CFArrayRef viewNames, CFErrorRef *error) {
1974 __block CFBooleanRef result = NULL;
1975 do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
1976 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCPeersHaveViewsEnabled);
1977 result = SOSAccountPeersHaveViewsEnabled(txn.account, viewNames, error);
1978 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCPeersHaveViewsEnabled, OctagonSignpostNumber1(SOSSignpostNameSOSCCPeersHaveViewsEnabled), (int)(result != NULL));
1979 return result != NULL;
1985 bool SOSCCRegisterRecoveryPublicKey_Server(CFDataRef recovery_key, CFErrorRef *error){
1986 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRegisterRecoveryPublicKey);
1988 bool registerResult = do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
1989 bool result = false;
1990 if(recovery_key != NULL && CFDataGetLength(recovery_key) != 0) {
1991 result = SOSAccountRegisterRecoveryPublicKey(txn, recovery_key, error);
1994 result = SOSAccountClearRecoveryPublicKey(txn, recovery_key, error);
1998 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRegisterRecoveryPublicKey, OctagonSignpostNumber1(SOSSignpostNameSOSCCRegisterRecoveryPublicKey), (int)registerResult);
1999 return registerResult;
2002 CFDataRef SOSCCCopyRecoveryPublicKey_Server(CFErrorRef *error){
2004 __block CFDataRef result = NULL;
2005 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCCopyRecoveryPublicKey);
2006 do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2007 result = SOSAccountCopyRecoveryPublicKey(txn, error);
2008 return result != NULL;
2010 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCCopyRecoveryPublicKey, OctagonSignpostNumber1(SOSSignpostNameSOSCCCopyRecoveryPublicKey), (int)(result != NULL));
2014 bool SOSCCMessageFromPeerIsPending_Server(SOSPeerInfoRef peer, CFErrorRef *error) {
2015 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCMessageFromPeerIsPending);
2017 bool pendingResult = do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2018 bool result = SOSAccountMessageFromPeerIsPending(txn, peer, error);
2021 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCMessageFromPeerIsPending, OctagonSignpostNumber1(SOSSignpostNameSOSCCMessageFromPeerIsPending), (int)pendingResult);
2022 return pendingResult;
2025 bool SOSCCSendToPeerIsPending_Server(SOSPeerInfoRef peer, CFErrorRef *error) {
2026 OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCSendToPeerIsPending);
2028 bool sendResult = do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2029 bool result = SOSAccountSendToPeerIsPending(txn, peer, error);
2032 OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCSendToPeerIsPending, OctagonSignpostNumber1(SOSSignpostNameSOSCCSendToPeerIsPending), (int)sendResult);
2036 void SOSCCResetOTRNegotiation_Server(CFStringRef peerid)
2038 CFErrorRef localError = NULL;
2039 do_with_account_while_unlocked(&localError, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2040 SOSAccountResetOTRNegotiationCoder(txn.account, peerid);
2045 secerror("error resetting otr negotation: %@", localError);
2049 void SOSCCPeerRateLimiterSendNextMessage_Server(CFStringRef peerid, CFStringRef accessGroup)
2051 CFErrorRef localError = NULL;
2052 do_with_account_while_unlocked(&localError, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2053 SOSAccountTimerFiredSendNextMessage(txn, (__bridge NSString*)peerid, (__bridge NSString*)accessGroup);
2058 secerror("error sending next message: %@", localError);
2062 void SOSCCPerformWithOctagonSigningKey(void (^action)(SecKeyRef octagonPrivSigningKey, CFErrorRef error))
2064 CFErrorRef error = NULL;
2065 do_with_account_if_after_first_unlock(&error, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) {
2066 SOSFullPeerInfoRef fpi = txn.account.trust.fullPeerInfo;
2067 SecKeyRef signingKey = SOSFullPeerInfoCopyOctagonSigningKey(fpi, err);
2068 CFErrorRef errorArg = err ? *err : NULL;
2069 action(signingKey, errorArg);
2070 CFReleaseNull(signingKey);
2073 CFReleaseNull(error);
2076 void SOSCCPerformWithOctagonSigningPublicKey(void (^action)(SecKeyRef octagonPublicKey, CFErrorRef error))
2078 CFErrorRef error = NULL;
2079 do_with_account_if_after_first_unlock(&error, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) {
2080 SOSFullPeerInfoRef fpi = txn.account.trust.fullPeerInfo;
2081 SecKeyRef signingKey = SOSFullPeerInfoCopyOctagonPublicSigningKey(fpi, err);
2082 CFErrorRef errorArg = err ? *err : NULL;
2083 action(signingKey, errorArg);
2084 CFReleaseNull(signingKey);
2087 CFReleaseNull(error);
2090 void SOSCCPerformWithOctagonEncryptionKey(void (^action)(SecKeyRef octagonPrivEncryptionKey, CFErrorRef error))
2092 CFErrorRef error = NULL;
2093 do_with_account_if_after_first_unlock(&error, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) {
2094 SOSFullPeerInfoRef fpi = txn.account.trust.fullPeerInfo;
2095 SecKeyRef signingKey = SOSFullPeerInfoCopyOctagonEncryptionKey(fpi, err);
2096 CFErrorRef errorArg = err ? *err : NULL;
2097 action(signingKey, errorArg);
2098 CFReleaseNull(signingKey);
2101 CFReleaseNull(error);
2104 void SOSCCPerformWithOctagonEncryptionPublicKey(void (^action)(SecKeyRef octagonPublicEncryptionKey, CFErrorRef error))
2106 CFErrorRef error = NULL;
2107 do_with_account_if_after_first_unlock(&error, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) {
2108 SOSFullPeerInfoRef fpi = txn.account.trust.fullPeerInfo;
2109 SecKeyRef signingKey = SOSFullPeerInfoCopyOctagonPublicEncryptionKey(fpi, err);
2110 CFErrorRef errorArg = err ? *err : NULL;
2111 action(signingKey, errorArg);
2112 CFReleaseNull(signingKey);
2115 CFReleaseNull(error);
2118 void SOSCCPerformWithAllOctagonKeys(void (^action)(SecKeyRef octagonEncryptionKey, SecKeyRef octagonSigningKey, CFErrorRef error))
2120 CFErrorRef localError = NULL;
2121 do_with_account_if_after_first_unlock(&localError, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) {
2122 SecKeyRef encryptionKey = NULL;
2123 SecKeyRef signingKey = NULL;
2124 CFErrorRef errorArg = err ? *err : NULL;
2126 SOSFullPeerInfoRef fpi = txn.account.trust.fullPeerInfo;
2127 require_action_quiet(fpi, fail, secerror("device does not have a peer"); SOSCreateError(kSOSErrorPeerNotFound, CFSTR("No Peer for Account"), NULL, &errorArg));
2129 signingKey = SOSFullPeerInfoCopyOctagonSigningKey(fpi, &errorArg);
2130 require_action_quiet(signingKey && !errorArg, fail, secerror("SOSCCPerformWithAllOctagonKeys signing key error: %@", errorArg));
2131 CFReleaseNull(errorArg);
2133 encryptionKey = SOSFullPeerInfoCopyOctagonEncryptionKey(fpi, &errorArg);
2134 require_action_quiet(encryptionKey && !errorArg, fail, secerror("SOSCCPerformWithAllOctagonKeys encryption key error: %@", errorArg));
2136 action(encryptionKey, signingKey, errorArg);
2137 CFReleaseNull(signingKey);
2138 CFReleaseNull(encryptionKey);
2139 CFReleaseNull(errorArg);
2142 action(NULL, NULL, errorArg);
2143 CFReleaseNull(errorArg);
2144 CFReleaseNull(signingKey);
2145 CFReleaseNull(encryptionKey);
2148 CFReleaseNull(localError);
2151 static bool saveOctagonKeysToKeychain(NSString* keyLabel, NSData* keyDataToSave, int keySize, SecKeyRef octagonPublicKey, NSError** error) {
2152 NSError* localerror = nil;
2154 CFDataRef publicKeyHash = SecKeyCopyPublicKeyHash(octagonPublicKey);
2156 NSMutableDictionary* query = [@{
2157 (id)kSecClass : (id)kSecClassKey,
2158 (id)kSecAttrKeyType : (id)kSecAttrKeyTypeEC,
2159 (id)kSecAttrKeyClass : (id)kSecAttrKeyClassPrivate,
2160 (id)kSecAttrAccessGroup : (id)kSOSInternalAccessGroup,
2161 (id)kSecAttrLabel : keyLabel,
2162 (id)kSecAttrApplicationLabel : (__bridge NSData*)(publicKeyHash),
2163 (id)kSecAttrSynchronizable : (id)kCFBooleanFalse,
2164 (id)kSecUseDataProtectionKeychain : @YES,
2165 (id)kSecValueData : keyDataToSave,
2168 CFTypeRef result = NULL;
2169 OSStatus status = SecItemAdd((__bridge CFDictionaryRef)query, &result);
2171 if(status == errSecSuccess) {
2172 CFReleaseNull(publicKeyHash);
2175 if(status == errSecDuplicateItem) {
2176 // Add every primary key attribute to this find dictionary
2177 NSMutableDictionary* findQuery = [[NSMutableDictionary alloc] init];
2178 findQuery[(id)kSecClass] = query[(id)kSecClass];
2179 findQuery[(id)kSecAttrKeyType] = query[(id)kSecAttrKeyTypeEC];
2180 findQuery[(id)kSecAttrKeyClass] = query[(id)kSecAttrKeyClassPrivate];
2181 findQuery[(id)kSecAttrAccessGroup] = query[(id)kSecAttrAccessGroup];
2182 findQuery[(id)kSecAttrLabel] = query[(id)kSecAttrLabel];
2183 findQuery[(id)kSecAttrApplicationLabel] = query[(id)kSecAttrApplicationLabel];
2184 findQuery[(id)kSecUseDataProtectionKeychain] = query[(id)kSecUseDataProtectionKeychain];
2186 NSMutableDictionary* updateQuery = [query mutableCopy];
2187 updateQuery[(id)kSecClass] = nil;
2189 status = SecItemUpdate((__bridge CFDictionaryRef)findQuery, (__bridge CFDictionaryRef)updateQuery);
2192 localerror = [NSError
2193 errorWithDomain:NSOSStatusErrorDomain
2195 description:[NSString stringWithFormat:@"SecItemUpdate: %d", (int)status]];
2198 localerror = [NSError
2199 errorWithDomain:NSOSStatusErrorDomain
2201 description:[NSString stringWithFormat:@"SecItemAdd: %d", (int)status]];
2203 if(localerror && error) {
2204 *error = localerror;
2207 CFReleaseNull(publicKeyHash);
2209 return (status == errSecSuccess);
2212 static NSString* createKeyLabel(NSDictionary *gestalt, NSString* circleName, NSString* prefix)
2214 NSString *keyName = [NSString stringWithFormat:@"ID for %@-%@",SOSPeerGestaltGetName((__bridge CFDictionaryRef)(gestalt)), circleName];
2216 NSString* octagonSigningKeyName = [prefix stringByAppendingString: keyName];
2218 return octagonSigningKeyName;
2221 static NSError* saveKeysToKeychain(SOSAccount* account, NSData* octagonSigningFullKey, NSData* octagonEncryptionFullKey, SecKeyRef octagonSigningPublicKeyRef, SecKeyRef octagonEncryptionPublicKeyRef)
2223 NSError* saveToKeychainError = nil;
2225 NSString* circleName = (__bridge NSString*)(SOSCircleGetName(account.trust.trustedCircle));
2226 NSString* signingPrefix = @"Octagon Peer Signing ";
2227 NSString* encryptionPrefix = @"Octagon Peer Encryption ";
2228 NSString* octagonSigningKeyName = createKeyLabel(account.gestalt, circleName, signingPrefix);
2229 NSString* octagonEncryptionKeyName = createKeyLabel(account.gestalt, circleName, encryptionPrefix);
2231 /* behavior mimics GeneratePermanentFullECKey_internal */
2232 saveOctagonKeysToKeychain(octagonSigningKeyName, octagonSigningFullKey, 384, octagonSigningPublicKeyRef, &saveToKeychainError);
2233 if(saveToKeychainError) {
2234 secerror("octagon: could not save signing key: %@", saveToKeychainError);
2235 return saveToKeychainError;
2237 saveOctagonKeysToKeychain(octagonEncryptionKeyName, octagonEncryptionFullKey, 384, octagonEncryptionPublicKeyRef, &saveToKeychainError);
2238 if(saveToKeychainError) {
2239 secerror("octagon: could not save encryption key: %@", saveToKeychainError);
2240 return saveToKeychainError;
2246 void SOSCCPerformUpdateOfAllOctagonKeys(CFDataRef octagonSigningFullKey, CFDataRef octagonEncryptionFullKey,
2247 CFDataRef signingPublicKey, CFDataRef encryptionPublicKey,
2248 SecKeyRef octagonSigningPublicKeyRef, SecKeyRef octagonEncryptionPublicKeyRef,
2249 void (^action)(CFErrorRef error))
2251 CFErrorRef localError = NULL;
2252 do_with_account_if_after_first_unlock(&localError, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) {
2253 CFErrorRef updateOctagonKeysError = NULL;
2254 bool updatedPeerInfo = SOSAccountUpdatePeerInfoAndPush(txn.account, CFSTR("Updating Octagon Keys in SOS"), &updateOctagonKeysError, ^bool(SOSPeerInfoRef pi, CFErrorRef *error) {
2256 //save octagon key set to the keychain
2257 NSError* saveError = nil;
2258 saveError = saveKeysToKeychain(txn.account, (__bridge NSData*)octagonSigningFullKey, (__bridge NSData*)octagonEncryptionFullKey,
2259 octagonSigningPublicKeyRef, octagonEncryptionPublicKeyRef);
2262 secerror("octagon: failed to save Octagon keys to the keychain: %@", saveError);
2263 action((__bridge CFErrorRef)saveError);
2267 //now update the peer info to contain octagon keys
2269 CFErrorRef setError = NULL;
2270 SOSPeerInfoSetOctagonKeysInDescription(pi, octagonSigningPublicKeyRef, octagonEncryptionPublicKeyRef, &setError);
2272 secerror("octagon: Failed to set Octagon Keys in peerInfo: %@", setError);
2277 secnotice("octagon", "No peer info to update?");
2278 NSError *noPIError = [NSError errorWithDomain:(__bridge NSString*)kSOSErrorDomain code:kSOSErrorPeerNotFound userInfo:@{NSLocalizedDescriptionKey : @"Device has no full peer info"}];
2279 action((__bridge CFErrorRef)noPIError);
2283 secnotice("octagon", "Success! Upated Octagon keys in SOS!");
2288 return updatedPeerInfo;
2290 CFReleaseNull(localError);
2293 void SOSCCPerformWithTrustedPeers(void (^action)(CFSetRef sosPeerInfoRefs, CFErrorRef error))
2295 CFErrorRef cfAccountError = NULL;
2296 do_with_account_if_after_first_unlock(&cfAccountError, ^bool(SOSAccountTransaction *txn, CFErrorRef *cferror) {
2297 CFSetRef sosPeerSet = [txn.account.trust copyPeerSetMatching:^bool(SOSPeerInfoRef peer) {
2301 CFErrorRef errorArg = cferror ? *cferror : NULL;
2302 action(sosPeerSet, errorArg);
2303 CFReleaseNull(sosPeerSet);
2306 CFReleaseNull(cfAccountError);
2309 void SOSCCPerformWithPeerID(void (^action)(CFStringRef peerID, CFErrorRef error))
2311 CFErrorRef cfAccountError = NULL;
2312 do_with_account_if_after_first_unlock(&cfAccountError, ^bool(SOSAccountTransaction *txn, CFErrorRef *cferror) {
2313 SOSAccount* account = txn.account;
2314 NSString* peerID = nil;
2315 CFErrorRef localError = nil;
2317 if([account getCircleStatus:nil] == kSOSCCInCircle){
2318 peerID = [txn.account peerID];
2321 SOSErrorCreate(kSOSErrorNoCircle, &localError, NULL, CFSTR("Not in circle"));
2323 action((__bridge CFStringRef)peerID, localError);
2324 CFReleaseNull(localError);
2327 CFReleaseNull(cfAccountError);
2331 SOSCCAccountTriggerSyncWithBackupPeer_server(CFStringRef peer)
2334 secnotice("syncwith", "SOSCCAccountTriggerSyncWithBackupPeer_server: %@", peer);
2338 SOSAccount* account = (__bridge SOSAccount*)GetSharedAccountRef();
2339 [account triggerBackupForPeers:@[(__bridge NSString *)peer]];