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/CFURL.h>
28 #include <Security/SecureObjectSync/SOSAccountTransaction.h>
30 #include <securityd/SOSCloudCircleServer.h>
31 #include <Security/SecureObjectSync/SOSCloudCircle.h>
32 #include <Security/SecureObjectSync/SOSCloudCircleInternal.h>
33 #include <Security/SecureObjectSync/SOSCircle.h>
34 #include <Security/SecureObjectSync/SOSAccount.h>
35 #include <Security/SecureObjectSync/SOSAccountPriv.h>
36 #include <Security/SecureObjectSync/SOSFullPeerInfo.h>
37 #include <Security/SecureObjectSync/SOSPeerInfoV2.h>
39 #include <Security/SecureObjectSync/SOSPeerInfoInternal.h>
40 #include <Security/SecureObjectSync/SOSInternal.h>
41 #include <Security/SecureObjectSync/SOSUserKeygen.h>
42 #include <Security/SecureObjectSync/SOSMessage.h>
43 #include <Security/SecureObjectSync/SOSTransport.h>
44 #include <Security/SecureObjectSync/SOSTransportMessageIDS.h>
45 #include <Security/SecureObjectSync/SOSAccountHSAJoin.h>
47 #include <Security/SecureObjectSync/SOSKVSKeys.h>
49 #include <utilities/SecCFWrappers.h>
50 #include <utilities/SecCFRelease.h>
51 #include <utilities/SecCFError.h>
52 #include <utilities/debugging.h>
53 #include <utilities/SecCoreCrypto.h>
54 #include <SOSCircle/CKBridge/SOSCloudKeychainClient.h>
56 #include <corecrypto/ccrng.h>
57 #include <corecrypto/ccrng_pbkdf2_prng.h>
58 #include <corecrypto/ccec.h>
59 #include <corecrypto/ccdigest.h>
60 #include <corecrypto/ccsha2.h>
61 #include <CommonCrypto/CommonRandomSPI.h>
62 #include <Security/SecKeyPriv.h>
63 #include <Security/SecFramework.h>
65 #include <utilities/SecFileLocations.h>
66 #include <utilities/SecAKSWrappers.h>
67 #include <securityd/SecItemServer.h>
68 #include <Security/SecItemPriv.h>
69 #include <Security/SecureObjectSync/SOSCloudCircleInternal.h>
71 #include <TargetConditionals.h>
73 #include <utilities/iCloudKeychainTrace.h>
74 #include <Security/SecAccessControlPriv.h>
75 #include <securityd/SecDbKeychainItem.h>
77 #include <os/activity.h>
78 #include <os/state_private.h>
80 #if TARGET_OS_EMBEDDED || TARGET_IPHONE_SIMULATOR
81 #include <MobileGestalt.h>
83 #include <AppleSystemInfo/AppleSystemInfo.h>
86 #define SOSCKCSCOPE "sync"
87 #define RUN_AS_ROOT_ERROR 550
89 #define USE_SYSTEMCONFIGURATION_PRIVATE_HEADERS
90 #import <SystemConfiguration/SystemConfiguration.h>
94 static SOSCCAccountDataSourceFactoryBlock accountDataSourceOverride
= NULL
;
96 bool SOSKeychainAccountSetFactoryForAccount(SOSCCAccountDataSourceFactoryBlock block
)
98 accountDataSourceOverride
= Block_copy(block
);
107 static void do_with_account(void (^action
)(SOSAccountRef account
, SOSAccountTransactionRef txn
));
108 static void do_with_account_async(void (^action
)(SOSAccountRef account
, SOSAccountTransactionRef txn
));
113 CFStringRef kSOSInternalAccessGroup
= CFSTR("com.apple.security.sos");
115 CFStringRef kSOSAccountLabel
= CFSTR("iCloud Keychain Account Meta-data");
117 CFStringRef kSOSBurnedRecoveryAttemptCount
= CFSTR("Burned Recovery Attempt Count");
119 CFStringRef kSOSBurnedRecoveryAttemptAttestationDate
= CFSTR("Burned Recovery Attempt Attestation Date");
121 static CFDictionaryRef
SOSItemCopyQueryForSyncItems(CFStringRef service
, bool returnData
)
123 return CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
124 kSecClass
, kSecClassGenericPassword
,
125 kSecAttrService
, service
,
126 kSecAttrAccessGroup
, kSOSInternalAccessGroup
,
127 kSecReturnData
, returnData
? kCFBooleanTrue
: kCFBooleanFalse
,
131 CFDataRef
SOSItemCopy(CFStringRef service
, CFErrorRef
* error
)
133 CFDictionaryRef query
= SOSItemCopyQueryForSyncItems(service
, true);
135 CFDataRef result
= NULL
;
137 OSStatus copyResult
= SecItemCopyMatching(query
, (CFTypeRef
*) &result
);
139 CFReleaseNull(query
);
141 if (copyResult
!= noErr
) {
142 SecError(copyResult
, error
, CFSTR("Error %@ reading for service '%@'"), result
, service
);
143 CFReleaseNull(result
);
147 if (!isData(result
)) {
148 SOSCreateErrorWithFormat(kSOSErrorProcessingFailure
, NULL
, error
, NULL
, CFSTR("SecItemCopyMatching returned non-data in '%@'"), service
);
149 CFReleaseNull(result
);
156 static CFDataRef
SOSKeychainCopySavedAccountData()
158 CFErrorRef error
= NULL
;
159 CFDataRef accountData
= SOSItemCopy(kSOSAccountLabel
, &error
);
161 secnotice("account", "Failed to load account: %@", error
);
162 secerror("Failed to load account: %@", error
);
164 CFReleaseNull(error
);
169 bool SOSItemUpdateOrAdd(CFStringRef service
, CFStringRef accessibility
, CFDataRef data
, CFErrorRef
*error
)
171 CFDictionaryRef query
= SOSItemCopyQueryForSyncItems(service
, false);
173 CFDictionaryRef update
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
175 kSecAttrAccessible
, accessibility
,
177 OSStatus saveStatus
= SecItemUpdate(query
, update
);
179 if (errSecItemNotFound
== saveStatus
) {
180 CFMutableDictionaryRef add
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, query
);
181 CFDictionaryForEach(update
, ^(const void *key
, const void *value
) {
182 CFDictionaryAddValue(add
, key
, value
);
184 saveStatus
= SecItemAdd(add
, NULL
);
188 CFReleaseNull(query
);
189 CFReleaseNull(update
);
191 return SecError(saveStatus
, error
, CFSTR("Error saving %@ to service '%@'"), data
, service
);
194 static void SOSKeychainAccountEnsureSaved(CFDataRef accountAsData
)
196 static CFDataRef sLastSavedAccountData
= NULL
;
198 CFErrorRef saveError
= NULL
;
199 require_quiet(!CFEqualSafe(sLastSavedAccountData
, accountAsData
), exit
);
201 if (!SOSItemUpdateOrAdd(kSOSAccountLabel
, kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate
, accountAsData
, &saveError
)) {
202 secerror("Can't save account: %@", saveError
);
206 CFAssignRetained(sLastSavedAccountData
, CFRetainSafe(accountAsData
));
209 CFReleaseNull(saveError
);
214 Stolen from keychain_sync.c
217 static bool clearAllKVS(CFErrorRef
*error
)
220 __block
bool result
= false;
221 const uint64_t maxTimeToWaitInSeconds
= 30ull * NSEC_PER_SEC
;
222 dispatch_queue_t processQueue
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0);
223 dispatch_semaphore_t waitSemaphore
= dispatch_semaphore_create(0);
224 dispatch_time_t finishTime
= dispatch_time(DISPATCH_TIME_NOW
, maxTimeToWaitInSeconds
);
226 SOSCloudKeychainClearAll(processQueue
, ^(CFDictionaryRef returnedValues
, CFErrorRef cerror
)
228 result
= (cerror
!= NULL
);
229 dispatch_semaphore_signal(waitSemaphore
);
232 dispatch_semaphore_wait(waitSemaphore
, finishTime
);
233 dispatch_release(waitSemaphore
);
238 static SOSAccountRef
SOSKeychainAccountCreateSharedAccount(CFDictionaryRef our_gestalt
)
240 secdebug("account", "Created account");
242 CFDataRef savedAccount
= SOSKeychainCopySavedAccountData();
243 SOSAccountRef account
= NULL
;
244 SOSDataSourceFactoryRef factory
= accountDataSourceOverride
? accountDataSourceOverride()
245 : SecItemDataSourceFactoryGetDefault();
248 CFErrorRef inflationError
= NULL
;
250 account
= SOSAccountCreateFromData(kCFAllocatorDefault
, savedAccount
, factory
, &inflationError
);
253 SOSAccountUpdateGestalt(account
, our_gestalt
);
255 secerror("Got error inflating account: %@", inflationError
);
258 CFReleaseNull(inflationError
);
261 CFReleaseSafe(savedAccount
);
264 account
= SOSAccountCreate(kCFAllocatorDefault
, our_gestalt
, factory
);
267 secerror("Got NULL creating account");
274 // Mark: Gestalt Handling
277 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
278 CF_EXPORT CFStringRef _kCFSystemVersionBuildVersionKey
;
280 CFStringRef
CopyOSVersion(void)
282 static dispatch_once_t once
;
283 static CFStringRef osVersion
= NULL
;
284 dispatch_once(&once
, ^{
285 #if TARGET_OS_EMBEDDED || TARGET_IPHONE_SIMULATOR
286 osVersion
= MGCopyAnswer(kMGQBuildVersion
, NULL
);
288 CFDictionaryRef versions
= _CFCopySystemVersionDictionary();
291 CFTypeRef versionValue
= CFDictionaryGetValue(versions
, _kCFSystemVersionBuildVersionKey
);
293 if (isString(versionValue
))
294 osVersion
= CFRetainSafe((CFStringRef
) versionValue
);
297 CFReleaseNull(versions
);
299 // What to do on MacOS.
300 if (osVersion
== NULL
)
301 osVersion
= CFSTR("Unknown model");
303 return CFRetainSafe(osVersion
);
307 static CFStringRef
CopyModelName(void)
309 static dispatch_once_t once
;
310 static CFStringRef modelName
= NULL
;
311 dispatch_once(&once
, ^{
312 #if TARGET_OS_EMBEDDED || TARGET_IPHONE_SIMULATOR
313 modelName
= MGCopyAnswer(kMGQDeviceName
, NULL
);
315 modelName
= ASI_CopyComputerModelName(FALSE
);
317 if (modelName
== NULL
)
318 modelName
= CFSTR("Unknown model");
320 return CFStringCreateCopy(kCFAllocatorDefault
, modelName
);
323 static CFStringRef
CopyComputerName(SCDynamicStoreRef store
)
325 CFStringRef deviceName
= SCDynamicStoreCopyComputerName(store
, NULL
);
326 if (deviceName
== NULL
) {
327 deviceName
= CFSTR("Unknown name");
332 static bool _EngineMessageProtocolV2Enabled(void)
336 static dispatch_once_t onceToken
;
337 static bool v2_enabled
= false;
338 dispatch_once(&onceToken
, ^{
339 CFTypeRef v2Pref
= (CFNumberRef
)CFPreferencesCopyValue(CFSTR("engineV2"), CFSTR("com.apple.security"), kCFPreferencesAnyUser
, kCFPreferencesCurrentHost
);
341 if (v2Pref
&& CFGetTypeID(v2Pref
) == CFBooleanGetTypeID()) {
342 v2_enabled
= CFBooleanGetValue((CFBooleanRef
)v2Pref
);
343 secinfo("server", "Engine v2 : %s", v2_enabled
? "enabled":"disabled");
345 CFReleaseSafe(v2Pref
);
355 static CFDictionaryRef
CreateDeviceGestaltDictionary(SCDynamicStoreRef store
, CFArrayRef keys
, void *context
)
357 CFStringRef modelName
= CopyModelName();
358 CFStringRef computerName
= CopyComputerName(store
);
359 CFStringRef osVersion
= CopyOSVersion();
361 SInt32 version
= _EngineMessageProtocolV2Enabled() ? kEngineMessageProtocolVersion
: 0;
362 CFNumberRef protocolVersion
= CFNumberCreate(0, kCFNumberSInt32Type
, &version
);
364 CFDictionaryRef gestalt
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
365 kPIUserDefinedDeviceNameKey
, computerName
,
366 kPIDeviceModelNameKey
, modelName
,
367 kPIMessageProtocolVersionKey
, protocolVersion
,
368 kPIOSVersionKey
, osVersion
,
370 CFReleaseSafe(modelName
);
371 CFReleaseSafe(computerName
);
372 CFReleaseSafe(protocolVersion
);
377 static void SOSCCProcessGestaltUpdate(SCDynamicStoreRef store
, CFArrayRef keys
, void *context
)
379 do_with_account(^(SOSAccountRef account
, SOSAccountTransactionRef txn
) {
381 CFDictionaryRef gestalt
= CreateDeviceGestaltDictionary(store
, keys
, context
);
382 if (SOSAccountUpdateGestalt(account
, gestalt
)) {
383 notify_post(kSOSCCCircleChangedNotification
);
385 CFReleaseSafe(gestalt
);
391 static CFDictionaryRef
CreateDeviceGestaltDictionaryAndRegisterForUpdate(dispatch_queue_t queue
, void *info
)
393 SCDynamicStoreContext context
= { .info
= info
};
394 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("com.apple.securityd.cloudcircleserver"), SOSCCProcessGestaltUpdate
, &context
);
395 CFStringRef computerKey
= SCDynamicStoreKeyCreateComputerName(NULL
);
396 CFArrayRef keys
= NULL
;
397 CFDictionaryRef gestalt
= NULL
;
399 if (store
== NULL
|| computerKey
== NULL
) {
402 keys
= CFArrayCreate(NULL
, (const void **)&computerKey
, 1, &kCFTypeArrayCallBacks
);
406 gestalt
= CreateDeviceGestaltDictionary(store
, keys
, info
);
407 SCDynamicStoreSetNotificationKeys(store
, keys
, NULL
);
408 SCDynamicStoreSetDispatchQueue(store
, queue
);
411 if (store
) CFRelease(store
);
412 if (computerKey
) CFRelease(computerKey
);
413 if (keys
) CFRelease(keys
);
417 os_state_block_t accountStateBlock
= ^os_state_data_t(os_state_hints_t hints
) {
418 os_state_data_t retval
= NULL
;
419 CFDataRef savedAccount
= NULL
;
420 if(hints
->osh_api
!= OS_STATE_API_REQUEST
) return NULL
;
422 /* Get account DER */
423 savedAccount
= SOSKeychainCopySavedAccountData();
424 require_quiet(savedAccount
, errOut
);
426 /* make a os_state_data_t object to return. */
427 size_t statelen
= CFDataGetLength(savedAccount
);
428 retval
= (os_state_data_t
)calloc(1, OS_STATE_DATA_SIZE_NEEDED(statelen
));
429 require_quiet(retval
, errOut
);
431 retval
->osd_type
= OS_STATE_DATA_PROTOCOL_BUFFER
;
432 memcpy(retval
->osd_data
, CFDataGetBytePtr(savedAccount
), statelen
);
433 retval
->osd_size
= statelen
;
434 strlcpy(retval
->osd_title
, "CloudCircle Account Object", sizeof(retval
->osd_title
));
437 CFReleaseNull(savedAccount
);
443 static SOSAccountRef
GetSharedAccount(void) {
444 static SOSAccountRef sSharedAccount
= NULL
;
445 static dispatch_once_t onceToken
;
447 #if !(TARGET_OS_EMBEDDED)
449 secerror("Cannot inflate account object as root");
454 dispatch_once(&onceToken
, ^{
455 secdebug("account", "Account Creation start");
457 CFDictionaryRef gestalt
= CreateDeviceGestaltDictionaryAndRegisterForUpdate(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), NULL
);
460 #if TARGET_OS_IPHONE && TARGET_IPHONE_SIMULATOR
461 gestalt
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
, NULL
);
463 secerror("Didn't get machine gestalt! This is going to be ugly.");
467 sSharedAccount
= SOSKeychainAccountCreateSharedAccount(gestalt
);
469 SOSAccountAddChangeBlock(sSharedAccount
, ^(SOSCircleRef circle
,
470 CFSetRef peer_additions
, CFSetRef peer_removals
,
471 CFSetRef applicant_additions
, CFSetRef applicant_removals
) {
472 CFErrorRef pi_error
= NULL
;
473 SOSPeerInfoRef me
= SOSFullPeerInfoGetPeerInfo(sSharedAccount
->my_identity
);
475 secerror("Error finding me for change: %@", pi_error
);
477 // TODO: Figure out why peer_additions isn't right in some cases (like when joining a v2 circle with a v0 peer.
478 if (SOSCircleHasPeer(circle
, me
, NULL
) /* && CFSetGetCount(peer_additions) != 0 */) {
479 secnotice("updates", "Requesting Ensure Peer Registration.");
480 SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), NULL
);
482 secinfo("updates", "Not requesting Ensure Peer Registration, since it's not needed");
485 if (CFSetContainsValue(peer_additions
, me
)) {
486 // TODO: Potentially remove from here and move this to the engine
487 // TODO: We also need to do this when our views change.
488 SOSCCSyncWithAllPeers();
492 CFReleaseNull(pi_error
);
494 // TODO: We should notify the engine of these changes here
495 if (CFSetGetCount(peer_additions
) != 0 ||
496 CFSetGetCount(peer_removals
) != 0 ||
497 CFSetGetCount(applicant_additions
) != 0 ||
498 CFSetGetCount(applicant_removals
) != 0) {
500 if(CFSetGetCount(peer_removals
) != 0)
502 CFErrorRef localError
= NULL
;
503 CFMutableArrayRef removed
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
504 CFSetForEach(peer_removals
, ^(const void *value
) {
505 CFArrayAppendValue(removed
, value
);
507 SOSAccountRemoveBackupPeers(sSharedAccount
, removed
, &localError
);
509 secerror("Had trouble removing: %@, error: %@", removed
, localError
);
510 CFReleaseNull(localError
);
511 CFReleaseNull(removed
);
513 notify_post(kSOSCCCircleChangedNotification
);
514 // This might be a bit chatty for now, but it will get things moving for clients.
515 notify_post(kSOSCCViewMembershipChangedNotification
);
520 SOSCloudKeychainSetItemsChangedBlock(^CFArrayRef(CFDictionaryRef changes
) {
521 CFRetainSafe(changes
);
522 __block CFMutableArrayRef handledKeys
= NULL
;
523 do_with_account(^(SOSAccountRef account
, SOSAccountTransactionRef txn
) {
524 CFStringRef changeDescription
= SOSItemsChangedCopyDescription(changes
, false);
525 secdebug(SOSCKCSCOPE
, "Received: %@", changeDescription
);
526 CFReleaseSafe(changeDescription
);
528 CFErrorRef error
= NULL
;
529 handledKeys
= SOSTransportDispatchMessages(account
, changes
, &error
);
531 secerror("Error handling updates: %@", error
);
532 CFReleaseNull(error
);
535 CFReleaseSafe(changes
);
538 CFReleaseSafe(gestalt
);
540 SOSAccountSetSaveBlock(sSharedAccount
, ^(CFDataRef flattenedAccount
, CFErrorRef flattenFailError
) {
541 if (flattenedAccount
) {
542 SOSKeychainAccountEnsureSaved(flattenedAccount
);
544 secerror("Failed to transform account into data, error: %@", flattenFailError
);
548 // TODO: We should not be doing extra work whenever securityd is launched, let's see if we can eliminate this call
549 SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), NULL
);
551 // provide state handler to sysdiagnose and logging
552 os_state_add_handler(dispatch_get_global_queue(0, 0), accountStateBlock
);
557 return sSharedAccount
;
560 static void do_with_account_dynamic(bool sync
, void (^action
)(SOSAccountRef account
, SOSAccountTransactionRef txn
)) {
562 SOSAccountRef account
= GetSharedAccount();
565 SOSAccountWithTransaction(account
, sync
, action
);
569 __unused
static void do_with_account_async(void (^action
)(SOSAccountRef account
, SOSAccountTransactionRef txn
)) {
570 do_with_account_dynamic(false, action
);
573 static void do_with_account(void (^action
)(SOSAccountRef account
, SOSAccountTransactionRef txn
)) {
574 do_with_account_dynamic(true, action
);
577 static bool isValidUser(CFErrorRef
* error
) {
578 #if !(TARGET_OS_EMBEDDED)
580 secerror("Cannot inflate account object as root");
581 SOSErrorCreate(kSOSErrorUnsupported
, error
, NULL
, CFSTR("Cannot inflate account object as root"));
589 static bool do_if_after_first_unlock(CFErrorRef
*error
, dispatch_block_t action
)
591 #if TARGET_IPHONE_SIMULATOR
595 bool beenUnlocked
= false;
596 require_quiet(SecAKSGetHasBeenUnlocked(&beenUnlocked
, error
), fail
);
598 require_action_quiet(beenUnlocked
, fail
,
599 SOSCreateErrorWithFormat(kSOSErrorNotReady
, NULL
, error
, NULL
,
600 CFSTR("Keybag never unlocked, ask after first unlock")));
610 static bool do_with_account_if_after_first_unlock(CFErrorRef
*error
, bool (^action
)(SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* error
))
612 __block
bool action_result
= false;
614 return isValidUser(error
) && do_if_after_first_unlock(error
, ^{
615 do_with_account(^(SOSAccountRef account
, SOSAccountTransactionRef txn
) {
616 action_result
= action(account
, txn
, error
);
622 static bool isAssertionLockAcquireError(CFErrorRef error
) {
623 return (CFErrorGetCode(error
) == kIOReturnNotPermitted
) && (CFEqualSafe(CFErrorGetDomain(error
), kSecKernDomain
));
626 static bool do_with_account_while_unlocked(CFErrorRef
*error
, bool (^action
)(SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* error
))
630 CFErrorRef statusError
= NULL
;
632 __block
bool action_result
= false;
633 __block
bool attempted_action
= false;
634 __block CFErrorRef localError
= NULL
;
637 require_quiet(isValidUser(error
), done
);
639 result
= SecAKSDoWhileUserBagLocked(&localError
, ^{
640 do_with_account(^(SOSAccountRef account
, SOSAccountTransactionRef txn
) {
641 attempted_action
= true;
642 action_result
= action(account
, txn
, error
);
646 // For <rdar://problem/24355048> 13E196: Circle join fails after successful recovery with a mach error if performed while device is locked
647 // 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.
648 // we assume our caller will hold the lock assertion for us to finsh our job.
649 // to be extra paranoid we track if we tried the caller's block. If we did we don't do it again.
651 require_quiet(result
== false && isAssertionLockAcquireError(localError
), done
);
652 require_quiet(!attempted_action
, done
);
654 bool isUnlocked
= false;
655 (void) SecAKSGetIsUnlocked(&isUnlocked
, &statusError
);
656 require_action_quiet(isUnlocked
, done
, secnotice("while-unlocked-hack", "Not trying action, aks bag locked (%@)", statusError
));
658 CFReleaseNull(localError
);
660 secnotice("while-unlocked-hack", "Trying action while unlocked without assertion");
663 do_with_account(^(SOSAccountRef account
, SOSAccountTransactionRef txn
) {
664 action_result
= action(account
, txn
, &localError
);
667 secnotice("while-unlocked-hack", "Action %s (%@)", action_result
? "succeeded" : "failed", localError
);
670 if (error
&& !*error
&& localError
) {
671 CFTransferRetained(*error
, localError
);
673 CFReleaseNull(localError
);
674 CFReleaseNull(statusError
);
676 return result
&& action_result
;
679 SOSAccountRef
SOSKeychainAccountGetSharedAccount()
681 __block SOSAccountRef result
= NULL
;
683 do_with_account(^(SOSAccountRef account
, SOSAccountTransactionRef txn
) {
691 // Mark: Credential processing
695 bool SOSCCTryUserCredentials_Server(CFStringRef user_label
, CFDataRef user_password
, CFErrorRef
*error
)
697 return do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
698 return SOSAccountTryUserCredentials(account
, user_label
, user_password
, block_error
);
702 SOSViewResultCode
SOSCCView_Server(CFStringRef viewname
, SOSViewActionCode action
, CFErrorRef
*error
) {
703 __block SOSViewResultCode status
= kSOSCCGeneralViewError
;
705 do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
709 case kSOSCCViewQuery
:
710 status
= SOSAccountViewStatus(account
, viewname
, error
);
713 case kSOSCCViewEnable
:
714 status
= SOSAccountUpdateView(account
, viewname
, action
, error
);
718 case kSOSCCViewDisable
:
719 status
= SOSAccountUpdateView(account
, viewname
, action
, error
);
723 secnotice("views", "Bad SOSViewActionCode - %d", (int) action
);
733 bool SOSCCViewSet_Server(CFSetRef enabledViews
, CFSetRef disabledViews
) {
734 __block
bool status
= false;
736 do_with_account_if_after_first_unlock(NULL
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
737 status
= SOSAccountUpdateViewSets(account
, enabledViews
, disabledViews
);
743 SOSSecurityPropertyResultCode
SOSCCSecurityProperty_Server(CFStringRef property
, SOSSecurityPropertyActionCode action
, CFErrorRef
*error
) {
745 __block SOSViewResultCode status
= kSOSCCGeneralSecurityPropertyError
;
746 do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
748 case kSOSCCSecurityPropertyQuery
:
749 status
= SOSAccountSecurityPropertyStatus(account
, property
, error
);
751 case kSOSCCSecurityPropertyEnable
:
752 case kSOSCCSecurityPropertyDisable
: // fallthrough
753 status
= SOSAccountUpdateSecurityProperty(account
, property
, action
, error
);
756 secnotice("secprop", "Bad SOSSecurityPropertyActionCode - %d", (int) action
);
765 void sync_the_last_data_to_kvs(SOSAccountRef account
, bool waitForeverForSynchronization
){
767 dispatch_semaphore_t wait_for
= dispatch_semaphore_create(0);
768 dispatch_retain(wait_for
); // Both this scope and the block own it.
770 secnoticeq("force-push", "calling SOSCloudKeychainSynchronizeAndWait");
772 SOSCloudKeychainSynchronizeAndWait(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^(CFDictionaryRef returnedValues
, CFErrorRef sync_error
) {
774 secerrorq("SOSCloudKeychainSynchronizeAndWait: %@", sync_error
);
776 secnoticeq("force-push", "returned from call; in callback to SOSCloudKeychainSynchronizeAndWait: results: %@", returnedValues
);
779 dispatch_semaphore_signal(wait_for
);
780 dispatch_release(wait_for
);
783 if(waitForeverForSynchronization
)
784 dispatch_semaphore_wait(wait_for
, DISPATCH_TIME_FOREVER
);
786 dispatch_semaphore_wait(wait_for
, dispatch_time(DISPATCH_TIME_NOW
, 60ull * NSEC_PER_SEC
));
788 dispatch_release(wait_for
);
791 #define kWAIT2MINID "EFRESH"
793 static bool SyncKVSAndWait(CFErrorRef
*error
) {
794 dispatch_semaphore_t wait_for
= dispatch_semaphore_create(0);
795 dispatch_retain(wait_for
); // Both this scope and the block own it.
797 __block
bool success
= false;
799 secnoticeq("fresh", "EFP calling SOSCloudKeychainSynchronizeAndWait");
801 os_activity_initiate("CloudCircle EFRESH", OS_ACTIVITY_FLAG_DEFAULT
, ^(void) {
802 SOSCloudKeychainSynchronizeAndWait(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^(__unused CFDictionaryRef returnedValues
, CFErrorRef sync_error
) {
803 secnotice("fresh", "EFP returned, callback error: %@", sync_error
);
805 success
= (sync_error
== NULL
);
807 CFRetainAssign(*error
, sync_error
);
810 dispatch_semaphore_signal(wait_for
);
811 dispatch_release(wait_for
);
815 dispatch_semaphore_wait(wait_for
, DISPATCH_TIME_FOREVER
);
816 dispatch_release(wait_for
);
818 secnotice("fresh", "EFP complete: %s %@", success
? "success" : "failure", error
? *error
: NULL
);
824 static bool Flush(CFErrorRef
*error
) {
825 __block
bool success
= false;
827 dispatch_semaphore_t wait_for
= dispatch_semaphore_create(0);
828 dispatch_retain(wait_for
); // Both this scope and the block own it.
830 secnotice("flush", "Starting");
832 SOSCloudKeychainFlush(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^(CFDictionaryRef returnedValues
, CFErrorRef sync_error
) {
833 success
= (sync_error
== NULL
);
835 CFRetainAssign(*error
, sync_error
);
838 dispatch_semaphore_signal(wait_for
);
839 dispatch_release(wait_for
);
842 dispatch_semaphore_wait(wait_for
, DISPATCH_TIME_FOREVER
);
843 dispatch_release(wait_for
);
845 secnotice("flush", "Returned %s", success
? "Success": "Failure");
850 static bool SOSCCAssertUserCredentialsAndOptionalDSID(CFStringRef user_label
, CFDataRef user_password
, CFStringRef dsid
, CFErrorRef
*error
) {
851 secnotice("updates", "Setting credentials and dsid (%@) for %@", dsid
, user_label
);
853 bool result
= do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
854 if (dsid
!= NULL
&& CFStringCompare(dsid
, CFSTR(""), 0) != 0) {
855 SOSAccountAssertDSID(account
, dsid
);
860 require_quiet(result
, done
);
862 require_quiet(SyncKVSAndWait(error
), done
); // Make sure we've seen what the server has
863 require_quiet(Flush(error
), done
); // And processed it already...before asserting
865 result
= do_with_account_while_unlocked(error
, ^bool(SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
*block_error
) {
866 return SOSAccountAssertUserCredentials(account
, user_label
, user_password
, block_error
);
869 require_quiet(result
, done
);
870 require_quiet(Flush(error
), done
); // Process any incoming information..circles et.al. before fixing our signature
872 result
= do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
873 return SOSAccountGenerationSignatureUpdate(account
, error
);
880 bool SOSCCSetUserCredentialsAndDSID_Server(CFStringRef user_label
, CFDataRef user_password
, CFStringRef dsid
, CFErrorRef
*error
)
882 // TODO: Return error if DSID is NULL to insist our callers provide one?
883 return SOSCCAssertUserCredentialsAndOptionalDSID(user_label
, user_password
, dsid
, error
);
886 bool SOSCCSetUserCredentials_Server(CFStringRef user_label
, CFDataRef user_password
, CFErrorRef
*error
)
888 return SOSCCAssertUserCredentialsAndOptionalDSID(user_label
, user_password
, NULL
, error
);
891 bool SOSCCCanAuthenticate_Server(CFErrorRef
*error
)
893 bool result
= do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
894 return SOSAccountGetPrivateCredential(account
, block_error
) != NULL
;
897 if (!result
&& error
&& *error
&& CFErrorGetDomain(*error
) == kSOSErrorDomain
) {
898 CFIndex code
= CFErrorGetCode(*error
);
899 if (code
== kSOSErrorPrivateKeyAbsent
|| code
== kSOSErrorPublicKeyAbsent
) {
900 CFReleaseNull(*error
);
907 bool SOSCCPurgeUserCredentials_Server(CFErrorRef
*error
)
909 return do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
910 SOSAccountPurgePrivateCredential(account
);
915 SOSCCStatus
SOSCCThisDeviceIsInCircle_Server(CFErrorRef
*error
)
917 __block SOSCCStatus status
;
919 return do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
920 status
= SOSAccountGetCircleStatus(account
, block_error
);
922 }) ? status
: kSOSCCError
;
925 bool SOSCCRequestToJoinCircle_Server(CFErrorRef
* error
)
927 __block
bool result
= true;
929 return do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
930 result
= SOSAccountJoinCircles(txn
, block_error
);
935 bool SOSCCAccountHasPublicKey_Server(CFErrorRef
*error
)
937 __block
bool result
= true;
938 __block CFErrorRef localError
= NULL
;
940 bool hasPublicKey
= do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
941 result
= SOSAccountHasPublicKey(account
, &localError
);
945 if(error
!= NULL
&& localError
!= NULL
)
951 bool SOSCCAccountIsNew_Server(CFErrorRef
*error
)
953 __block
bool result
= true;
954 __block CFErrorRef localError
= NULL
;
956 (void) do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
957 result
= SOSAccountIsNew(account
, &localError
);
961 if(error
!= NULL
&& localError
!= NULL
)
966 bool SOSCCRequestToJoinCircleAfterRestore_Server(CFErrorRef
* error
)
968 __block
bool result
= true;
969 bool returned
= false;
970 returned
= do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
971 SOSAccountEnsurePeerRegistration(account
, block_error
);
972 result
= SOSAccountJoinCirclesAfterRestore(txn
, block_error
);
979 bool SOSCCRequestEnsureFreshParameters_Server(CFErrorRef
* error
)
981 bool returned
= false;
982 returned
= do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
983 return SyncKVSAndWait(block_error
);
986 returned
= Flush(error
);
991 bool SOSCCApplyToARing_Server(CFStringRef ringName
, CFErrorRef
*error
){
992 __block
bool result
= true;
993 bool returned
= false;
994 returned
= do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
995 SOSFullPeerInfoRef fpi
= SOSAccountGetMyFullPeerInfo(account
);
996 SOSRingRef ring
= SOSAccountCopyRing(account
, ringName
, error
);
998 result
= SOSRingApply(ring
, account
->user_public
, fpi
, error
);
1000 CFReleaseNull(ring
);
1006 bool SOSCCWithdrawlFromARing_Server(CFStringRef ringName
, CFErrorRef
*error
){
1007 __block
bool result
= true;
1008 bool returned
= false;
1009 returned
= do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1010 SOSFullPeerInfoRef fpi
= SOSAccountGetMyFullPeerInfo(account
);
1011 SOSRingRef ring
= SOSAccountCopyRing(account
, ringName
, error
);
1013 result
= SOSRingWithdraw(ring
, account
->user_public
, fpi
, error
);
1015 CFReleaseNull(ring
);
1021 bool SOSCCEnableRing_Server(CFStringRef ringName
, CFErrorRef
*error
){
1022 __block
bool result
= true;
1023 bool returned
= false;
1024 returned
= do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1025 SOSFullPeerInfoRef fpi
= SOSAccountGetMyFullPeerInfo(account
);
1026 SOSRingRef ring
= SOSAccountCopyRing(account
, ringName
, error
);
1028 result
= SOSRingResetToOffering(ring
, NULL
, fpi
, error
);
1030 CFReleaseNull(ring
);
1036 CFStringRef
SOSCCGetAllTheRings_Server(CFErrorRef
*error
){
1037 __block CFMutableDictionaryRef result
= NULL
;
1038 __block CFMutableStringRef description
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
1040 (void) do_with_account_while_unlocked(error
, ^bool(SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
*error
) {
1041 SOSAccountForEachRing(account
, ^SOSRingRef(CFStringRef name
, SOSRingRef ring
) {
1042 CFStringAppendFormat(description
, NULL
, CFSTR("%@\n"), ring
);
1053 SOSRingStatus
SOSCCRingStatus_Server(CFStringRef ringName
, CFErrorRef
*error
){
1054 __block
bool result
= true;
1055 SOSRingStatus returned
;
1056 returned
= do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1057 SOSFullPeerInfoRef fpi
= SOSAccountGetMyFullPeerInfo(account
);
1058 SOSPeerInfoRef myPeer
= SOSFullPeerInfoGetPeerInfo(fpi
);
1060 SOSRingRef ring
= SOSAccountCopyRing(account
, ringName
, error
);
1061 if(myPeer
&& ring
) {
1062 result
= SOSRingDeviceIsInRing(ring
, SOSPeerInfoGetPeerID(myPeer
));
1064 CFReleaseNull(ring
);
1071 CFStringRef
SOSCCCopyDeviceID_Server(CFErrorRef
*error
)
1073 __block CFStringRef result
= NULL
;
1075 (void) do_with_account_while_unlocked(error
, ^bool(SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
*error
) {
1076 result
= SOSAccountCopyDeviceID(account
, error
);
1077 return (!isNull(result
));
1082 bool SOSCCSetDeviceID_Server(CFStringRef IDS
, CFErrorRef
*error
){
1084 bool didSetID
= false;
1085 __block
bool result
= false;
1087 didSetID
= do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1088 result
= SOSAccountSetMyDSID(account
, IDS
, error
);
1090 if(block_error
&& error
!= NULL
){
1091 *error
= *block_error
;
1099 bool SOSCCRequestSyncWithPeerOverKVS_Server(CFStringRef deviceID
, CFErrorRef
*error
)
1101 __block
bool result
= NULL
;
1103 result
= do_with_account_while_unlocked(error
, ^bool(SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
*error
) {
1104 result
= SOSAccountSyncWithKVSUsingIDSID(account
, deviceID
, error
);
1110 bool SOSCCRequestSyncWithPeerOverIDS_Server(CFStringRef deviceID
, CFErrorRef
*error
)
1112 __block
bool result
= NULL
;
1114 result
= do_with_account_while_unlocked(error
, ^bool(SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
*error
) {
1115 result
= SOSAccountSyncWithIDSPeer(account
, deviceID
, error
);
1121 HandleIDSMessageReason
SOSCCHandleIDSMessage_Server(CFDictionaryRef messageDict
, CFErrorRef
* error
)
1123 __block HandleIDSMessageReason result
= kHandleIDSMessageSuccess
;
1124 CFErrorRef action_error
= NULL
;
1126 if (!do_with_account_while_unlocked(&action_error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1127 result
= SOSTransportMessageIDSHandleMessage(account
, messageDict
, error
);
1131 CFStringRef errorMessage
= CFErrorCopyDescription(action_error
);
1132 if (CFEqualSafe(errorMessage
, CFSTR("The operation couldn’t be completed. (Mach error -536870174 - Kern return error)")) ) {
1133 secnotice("updates", "SOSCCHandleIDSMessage_Server failed because device is locked; letting IDSKeychainSyncingProxy know");
1134 result
= kHandleIDSMessageLocked
; // tell IDSKeychainSyncingProxy to call us back when device unlocks
1136 secerror("Unexpected error: %@", action_error
);
1139 if (error
&& *error
== NULL
) {
1140 *error
= action_error
;
1141 action_error
= NULL
;
1143 CFReleaseNull(errorMessage
);
1144 CFReleaseNull(action_error
);
1150 bool SOSCCIDSPingTest_Server(CFStringRef message
, CFErrorRef
*error
){
1151 bool didSendTestMessages
= false;
1152 __block
bool result
= true;
1153 __block CFErrorRef blockError
= NULL
;
1155 didSendTestMessages
= do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1156 result
= SOSAccountStartPingTest(account
, message
, &blockError
);
1159 if(blockError
&& error
!= NULL
)
1160 *error
= blockError
;
1162 return didSendTestMessages
;
1165 bool SOSCCIDSServiceRegistrationTest_Server(CFStringRef message
, CFErrorRef
*error
){
1166 bool didSendTestMessages
= false;
1167 __block
bool result
= true;
1168 __block CFErrorRef blockError
= NULL
;
1170 didSendTestMessages
= do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1171 result
= SOSAccountSendIDSTestMessage(account
, message
, &blockError
);
1174 if(blockError
!= NULL
&& error
!= NULL
)
1175 *error
= blockError
;
1177 return didSendTestMessages
;
1180 bool SOSCCIDSDeviceIDIsAvailableTest_Server(CFErrorRef
*error
){
1181 bool didSendTestMessages
= false;
1182 __block
bool result
= true;
1183 __block CFErrorRef blockError
= NULL
;
1185 didSendTestMessages
= do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1186 result
= SOSAccountRetrieveDeviceIDFromIDSKeychainSyncingProxy(account
, &blockError
);
1189 if(blockError
!= NULL
&& error
!= NULL
)
1190 *error
= blockError
;
1192 return didSendTestMessages
;
1195 bool SOSCCAccountSetToNew_Server(CFErrorRef
*error
)
1197 __block
bool result
= true;
1199 return do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1201 SOSAccountSetToNew(account
);
1206 bool SOSCCResetToOffering_Server(CFErrorRef
* error
)
1208 __block
bool result
= true;
1210 return do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1212 result
= SOSAccountResetToOffering(txn
, block_error
);
1218 bool SOSCCResetToEmpty_Server(CFErrorRef
* error
)
1220 __block
bool result
= true;
1222 return do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1223 result
= SOSAccountResetToEmpty(account
, block_error
);
1229 bool SOSCCRemoveThisDeviceFromCircle_Server(CFErrorRef
* error
)
1231 __block
bool result
= true;
1233 return do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1234 result
= SOSAccountLeaveCircle(account
, block_error
);
1239 bool SOSCCRemovePeersFromCircle_Server(CFArrayRef peers
, CFErrorRef
* error
)
1241 __block
bool result
= true;
1243 return do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1244 result
= SOSAccountRemovePeersFromCircle(account
, peers
, block_error
);
1250 bool SOSCCLoggedOutOfAccount_Server(CFErrorRef
*error
)
1252 __block
bool result
= true;
1254 return do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1255 secnotice("sosops", "Signed out of account!");
1257 bool waitForeverForSynchronization
= true;
1259 result
= SOSAccountLeaveCircle(account
, block_error
);
1261 SOSAccountTransactionFinishAndRestart(txn
); // Make sure this gets finished before we set to new.
1263 sync_the_last_data_to_kvs(account
, waitForeverForSynchronization
);
1265 SOSAccountSetToNew(account
);
1271 bool SOSCCBailFromCircle_Server(uint64_t limit_in_seconds
, CFErrorRef
* error
)
1273 __block
bool result
= true;
1275 return do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1276 bool waitForeverForSynchronization
= false;
1278 result
= SOSAccountBail(account
, limit_in_seconds
, block_error
);
1280 SOSAccountTransactionFinishAndRestart(txn
); // Make sure this gets finished before we push our data.
1282 sync_the_last_data_to_kvs(account
, waitForeverForSynchronization
);
1289 CFArrayRef
SOSCCCopyApplicantPeerInfo_Server(CFErrorRef
* error
)
1291 __block CFArrayRef result
= NULL
;
1293 (void) do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1294 result
= SOSAccountCopyApplicants(account
, block_error
);
1295 return result
!= NULL
;
1301 CFArrayRef
SOSCCCopyGenerationPeerInfo_Server(CFErrorRef
* error
)
1303 __block CFArrayRef result
= NULL
;
1305 (void) do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1306 result
= SOSAccountCopyGeneration(account
, block_error
);
1307 return result
!= NULL
;
1313 CFArrayRef
SOSCCCopyValidPeerPeerInfo_Server(CFErrorRef
* error
)
1315 __block CFArrayRef result
= NULL
;
1317 (void) do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1318 result
= SOSAccountCopyValidPeers(account
, block_error
);
1319 return result
!= NULL
;
1325 bool SOSCCValidateUserPublic_Server(CFErrorRef
* error
)
1327 __block
bool result
= NULL
;
1329 (void) do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1330 result
= SOSValidateUserPublic(account
, block_error
);
1337 CFArrayRef
SOSCCCopyNotValidPeerPeerInfo_Server(CFErrorRef
* error
)
1339 __block CFArrayRef result
= NULL
;
1341 (void) do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1342 result
= SOSAccountCopyNotValidPeers(account
, block_error
);
1343 return result
!= NULL
;
1349 CFArrayRef
SOSCCCopyRetirementPeerInfo_Server(CFErrorRef
* error
)
1351 __block CFArrayRef result
= NULL
;
1353 (void) do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1354 result
= SOSAccountCopyRetired(account
, block_error
);
1355 return result
!= NULL
;
1361 CFArrayRef
SOSCCCopyViewUnawarePeerInfo_Server(CFErrorRef
* error
)
1363 __block CFArrayRef result
= NULL
;
1365 (void) do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1366 result
= SOSAccountCopyViewUnaware(account
, block_error
);
1367 return result
!= NULL
;
1373 CFArrayRef
SOSCCCopyEngineState_Server(CFErrorRef
* error
)
1375 CFArrayRef result
= NULL
;
1376 SOSDataSourceFactoryRef dsf
= SecItemDataSourceFactoryGetDefault();
1377 SOSDataSourceRef ds
= SOSDataSourceFactoryCreateDataSource(dsf
, kSecAttrAccessibleWhenUnlocked
, error
);
1379 SOSEngineRef engine
= SOSDataSourceGetSharedEngine(ds
, error
);
1380 result
= SOSEngineCopyPeerConfirmedDigests(engine
, error
);
1381 SOSDataSourceRelease(ds
, error
);
1387 bool SOSCCWaitForInitialSync_Server(CFErrorRef
* error
) {
1389 __block dispatch_semaphore_t inSyncSema
= NULL
;
1390 __block
bool result
= false;
1391 __block
bool synced
= false;
1392 bool timed_out
= false;
1393 __block CFStringRef inSyncCallID
= NULL
;
1395 secnotice("initial sync", "Wait for initial sync start!");
1397 result
= do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1398 bool alreadyInSync
= SOSAccountHasCompletedInitialSync(account
);
1400 if (!alreadyInSync
) {
1401 inSyncSema
= dispatch_semaphore_create(0);
1402 dispatch_retain(inSyncSema
); // For the block
1404 inSyncCallID
= SOSAccountCallWhenInSync(account
, ^bool(SOSAccountRef mightBeSynced
) {
1408 dispatch_semaphore_signal(inSyncSema
);
1410 dispatch_release(inSyncSema
);
1421 require_quiet(result
, fail
);
1423 timed_out
= dispatch_semaphore_wait(inSyncSema
, dispatch_time(DISPATCH_TIME_NOW
, 300ull * NSEC_PER_SEC
));
1426 do_with_account(^(SOSAccountRef account
, SOSAccountTransactionRef txn
) {
1427 if (SOSAccountUnregisterCallWhenInSync(account
, inSyncCallID
)) {
1429 dispatch_release(inSyncSema
); // if we unregistered we release the sema
1430 inSyncSema
= NULL
; // We've canceled the timeout so we must be the last.
1436 secerror("waiting for initial sync timed out");
1438 SOSErrorCreate(kSOSInitialSyncFailed
, error
, NULL
, CFSTR("InitialSyncTimedOut"));
1442 require_quiet(result
, fail
);
1445 secerror("waiting for initial sync failed");
1448 SOSErrorCreate(kSOSInitialSyncFailed
, error
, NULL
, CFSTR("Initial sync timed out."));
1450 secnotice("initial sync", "Finished!: %d", result
);
1453 CFReleaseNull(inSyncCallID
);
1458 static CFArrayRef
SOSAccountCopyYetToSyncViews(SOSAccountRef account
, CFErrorRef
*error
) {
1459 __block CFArrayRef result
= NULL
;
1461 CFTypeRef valueFetched
= SOSAccountGetValue(account
, kSOSUnsyncedViewsKey
, error
);
1462 if (valueFetched
== kCFBooleanTrue
) {
1463 SOSPeerInfoRef myPI
= SOSAccountGetMyPeerInfo(account
);
1465 SOSPeerInfoWithEnabledViewSet(myPI
, ^(CFSetRef enabled
) {
1466 result
= CFSetCopyValues(enabled
);
1469 } else if (isSet(valueFetched
)) {
1470 result
= CFSetCopyValues((CFSetRef
)valueFetched
);
1473 if (result
== NULL
) {
1474 result
= CFArrayCreateForCFTypes(kCFAllocatorDefault
, NULL
);
1480 CFArrayRef
SOSCCCopyYetToSyncViewsList_Server(CFErrorRef
* error
) {
1482 __block CFArrayRef views
= NULL
;
1484 (void) do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1485 views
= SOSAccountCopyYetToSyncViews(account
, error
);
1493 bool SOSWrapToBackupSliceKeyBagForView_Server(CFStringRef viewName
, CFDataRef input
, CFDataRef
* output
, CFDataRef
* bskbEncoded
, CFErrorRef
* error
) {
1494 CFErrorRef localerror
= NULL
;
1495 SOSBackupSliceKeyBagRef bskb
= SOSBackupSliceKeyBagForView(viewName
, &localerror
);
1497 if(bskbEncoded
&& bskb
) {
1498 *bskbEncoded
= SOSBSKBCopyEncoded(bskb
, &localerror
);
1502 *output
= SOSWrapToBackupSliceKeyBag(bskb
, input
, &localerror
);
1506 *error
= localerror
;
1508 return localerror
== NULL
;
1511 SOSBackupSliceKeyBagRef
SOSBackupSliceKeyBagForView(CFStringRef viewName
, CFErrorRef
* error
){
1512 __block SOSBackupSliceKeyBagRef bskb
= NULL
;
1513 (void) do_with_account(^ (SOSAccountRef account
, SOSAccountTransactionRef txn
) {
1514 bskb
= SOSAccountBackupSliceKeyBagForView(account
, viewName
, error
);
1519 CFDataRef
SOSWrapToBackupSliceKeyBag(SOSBackupSliceKeyBagRef bskb
, CFDataRef input
, CFErrorRef
* error
) {
1520 CFDataRef encrypted
= NULL
;
1521 bskb_keybag_handle_t bskb_handle
= 0;
1523 require_quiet(bskb
, exit
);
1525 bskb_handle
= SOSBSKBLoadLocked(bskb
, error
);
1526 require_quiet(bskb_handle
, exit
);
1528 SecAccessControlRef access
= NULL
;
1529 require_quiet(access
= SecAccessControlCreate(kCFAllocatorDefault
, error
), exit
);
1530 require_quiet(SecAccessControlSetProtection(access
, kSecAttrAccessibleWhenUnlocked
, error
), exit
);
1532 // ks_encrypt_data takes a dictionary as its plaintext.
1533 CFMutableDictionaryRef plaintext
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1534 CFDictionarySetValue(plaintext
, CFSTR("data"), input
);
1536 require_quiet(ks_encrypt_data(bskb_handle
, access
, NULL
, plaintext
, NULL
, &encrypted
, false, error
), exit
);
1539 CFReleaseNull(bskb
);
1540 if(bskb_handle
!= 0) {
1541 ks_close_keybag(bskb_handle
, error
);
1543 if(error
&& *error
) {
1544 secnotice("backup", "Failed to wrap to a BKSB: %@", *error
);
1550 CFDictionaryRef
SOSCCCopyEscrowRecord_Server(CFErrorRef
*error
){
1552 __block CFDictionaryRef result
= NULL
;
1553 __block CFErrorRef block_error
= NULL
;
1555 (void) do_with_account_if_after_first_unlock(error
, ^bool(SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
*error
) {
1556 SOSCCStatus status
= SOSAccountGetCircleStatus(account
, &block_error
);
1557 CFStringRef dsid
= SOSAccountGetValue(account
, kSOSDSIDKey
, error
);
1558 CFDictionaryRef escrowRecords
= NULL
;
1559 CFDictionaryRef record
= NULL
;
1561 case kSOSCCInCircle
:
1562 //get the escrow record in the peer info!
1563 escrowRecords
= SOSPeerInfoCopyEscrowRecord(SOSAccountGetMyPeerInfo(account
));
1565 record
= CFDictionaryGetValue(escrowRecords
, dsid
);
1567 result
= CFRetainSafe(record
);
1569 CFReleaseNull(escrowRecords
);
1571 case kSOSCCRequestPending
:
1572 //set the escrow record in the peer info/application?
1574 case kSOSCCNotInCircle
:
1575 case kSOSCCCircleAbsent
:
1576 //set the escrow record in the account expansion!
1577 escrowRecords
= SOSAccountGetValue(account
, kSOSEscrowRecord
, error
);
1579 record
= CFDictionaryGetValue(escrowRecords
, dsid
);
1581 result
= CFRetainSafe(record
);
1585 secdebug("account", "no circle status!");
1594 bool SOSCCSetEscrowRecord_Server(CFStringRef escrow_label
, uint64_t tries
, CFErrorRef
*error
){
1596 __block
bool result
= true;
1597 __block CFErrorRef block_error
= NULL
;
1599 (void) do_with_account_if_after_first_unlock(error
, ^bool(SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
*error
) {
1600 SOSCCStatus status
= SOSAccountGetCircleStatus(account
, &block_error
);
1601 CFStringRef dsid
= SOSAccountGetValue(account
, kSOSDSIDKey
, error
);
1603 CFMutableStringRef timeDescription
= CFStringCreateMutableCopy(kCFAllocatorDefault
, 0, CFSTR("["));
1604 CFAbsoluteTime currentTimeAndDate
= CFAbsoluteTimeGetCurrent();
1606 withStringOfAbsoluteTime(currentTimeAndDate
, ^(CFStringRef decription
) {
1607 CFStringAppend(timeDescription
, decription
);
1609 CFStringAppend(timeDescription
, CFSTR("]"));
1611 CFNumberRef attempts
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberLongLongType
, (const void*)&tries
);
1613 CFMutableDictionaryRef escrowTimeAndTries
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
1614 CFDictionaryAddValue(escrowTimeAndTries
, kSOSBurnedRecoveryAttemptCount
, attempts
);
1615 CFDictionaryAddValue(escrowTimeAndTries
, kSOSBurnedRecoveryAttemptAttestationDate
, timeDescription
);
1617 CFMutableDictionaryRef escrowRecord
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
1618 CFDictionaryAddValue(escrowRecord
, escrow_label
, escrowTimeAndTries
);
1621 case kSOSCCInCircle
:
1622 //set the escrow record in the peer info!
1623 if(!SOSFullPeerInfoAddEscrowRecord(SOSAccountGetMyFullPeerInfo(account
), dsid
, escrowRecord
, error
)){
1624 secdebug("accout", "Could not set escrow record in the full peer info");
1628 case kSOSCCRequestPending
:
1629 //set the escrow record in the peer info/application?
1631 case kSOSCCNotInCircle
:
1632 case kSOSCCCircleAbsent
:
1633 //set the escrow record in the account expansion!
1635 if(!SOSAccountAddEscrowRecords(account
, dsid
, escrowRecord
, error
)) {
1636 secdebug("account", "Could not set escrow record in expansion data");
1641 secdebug("account", "no circle status!");
1644 CFReleaseNull(attempts
);
1645 CFReleaseNull(timeDescription
);
1646 CFReleaseNull(escrowTimeAndTries
);
1647 CFReleaseNull(escrowRecord
);
1655 bool SOSCCAcceptApplicants_Server(CFArrayRef applicants
, CFErrorRef
* error
)
1657 __block
bool result
= true;
1658 return do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1659 result
= SOSAccountAcceptApplicants(account
, applicants
, block_error
);
1665 bool SOSCCRejectApplicants_Server(CFArrayRef applicants
, CFErrorRef
* error
)
1667 __block
bool result
= true;
1668 return do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1669 result
= SOSAccountRejectApplicants(account
, applicants
, block_error
);
1674 CFArrayRef
SOSCCCopyPeerPeerInfo_Server(CFErrorRef
* error
)
1676 __block CFArrayRef result
= NULL
;
1678 (void) do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1679 result
= SOSAccountCopyPeers(account
, block_error
);
1680 return result
!= NULL
;
1686 CFArrayRef
SOSCCCopyConcurringPeerPeerInfo_Server(CFErrorRef
* error
)
1688 __block CFArrayRef result
= NULL
;
1690 (void) do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1691 result
= SOSAccountCopyConcurringPeers(account
, block_error
);
1692 return result
!= NULL
;
1698 SOSPeerInfoRef
SOSCCCopyMyPeerInfo_Server(CFErrorRef
* error
)
1700 __block SOSPeerInfoRef result
= NULL
;
1702 (void) do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1703 // Create a copy to be DERed/sent back to client
1704 result
= SOSPeerInfoCreateCopy(kCFAllocatorDefault
, SOSAccountGetMyPeerInfo(account
), block_error
);
1705 return result
!= NULL
;
1711 CFDataRef
SOSCCCopyAccountState_Server(CFErrorRef
* error
)
1713 __block CFDataRef accountState
= NULL
;
1715 (void) do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1716 // Copy account state from the keychain
1717 accountState
= SOSAccountCopyAccountStateFromKeychain(block_error
);
1718 return accountState
!= NULL
;
1721 return accountState
;
1724 bool SOSCCDeleteAccountState_Server(CFErrorRef
* error
)
1726 __block
bool result
= NULL
;
1728 (void) do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1729 // Delete account state from the keychain
1730 result
= SOSAccountDeleteAccountStateFromKeychain(block_error
);
1737 CFDataRef
SOSCCCopyEngineData_Server(CFErrorRef
* error
)
1739 __block CFDataRef engineState
= NULL
;
1741 (void) do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1742 // Copy engine state from the keychain
1743 engineState
= SOSAccountCopyEngineStateFromKeychain(block_error
);
1744 return engineState
!= NULL
;
1750 bool SOSCCDeleteEngineState_Server(CFErrorRef
* error
)
1752 __block
bool result
= NULL
;
1754 (void) do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1755 // Delete engine state from the keychain
1756 result
= SOSAccountDeleteEngineStateFromKeychain(block_error
);
1765 SOSPeerInfoRef
SOSCCSetNewPublicBackupKey_Server(CFDataRef newPublicBackup
, CFErrorRef
*error
){
1766 __block SOSPeerInfoRef result
= NULL
;
1768 (void) do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1769 if(SOSAccountSetBackupPublicKey(txn
,newPublicBackup
, error
)){
1770 SOSAccountTransactionFinishAndRestart(txn
); // Finish the transaction to update any changes to the peer info.
1772 // Create a copy to be DERed/sent back to client
1773 result
= SOSPeerInfoCreateCopy(kCFAllocatorDefault
, SOSAccountGetMyPeerInfo(account
), block_error
);
1774 secdebug("backup", "SOSCCSetNewPublicBackupKey_Server, new public backup is set");
1778 secerror("SOSCCSetNewPublicBackupKey_Server, could not set new public backup");
1780 return result
!= NULL
;
1786 bool SOSCCRegisterSingleRecoverySecret_Server(CFDataRef aks_bag
, bool setupV0Only
, CFErrorRef
*error
){
1787 return do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1788 return SOSAccountSetBSKBagForAllSlices(account
, aks_bag
, setupV0Only
, error
);
1792 CFStringRef
SOSCCCopyIncompatibilityInfo_Server(CFErrorRef
* error
)
1794 __block CFStringRef result
= NULL
;
1796 (void) do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1797 result
= SOSAccountCopyIncompatibilityInfo(account
, block_error
);
1798 return result
!= NULL
;
1804 bool SOSCCCheckPeerAvailability_Server(CFErrorRef
*error
)
1806 __block
bool pingedPeersInCircle
= false;
1807 __block dispatch_semaphore_t peerSemaphore
= NULL
;
1808 __block
bool peerIsAvailable
= false;
1810 static dispatch_queue_t time_out
;
1811 static dispatch_once_t once
;
1812 dispatch_once(&once
, ^{
1813 time_out
= dispatch_queue_create("peersAvailableTimeout", DISPATCH_QUEUE_SERIAL
);
1815 __block
int token
= -1;
1817 bool result
= do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1819 peerSemaphore
= dispatch_semaphore_create(0);
1820 dispatch_retain(peerSemaphore
);
1821 notify_register_dispatch(kSOSCCPeerAvailable
, &token
, time_out
, ^(int token
) {
1822 if(peerSemaphore
!= NULL
){
1823 dispatch_semaphore_signal(peerSemaphore
);
1824 dispatch_release(peerSemaphore
);
1825 peerIsAvailable
= true;
1826 notify_cancel(token
);
1830 pingedPeersInCircle
= SOSAccountCheckPeerAvailability(account
, block_error
);
1831 return pingedPeersInCircle
;
1835 dispatch_semaphore_wait(peerSemaphore
, dispatch_time(DISPATCH_TIME_NOW
, 7ull * NSEC_PER_SEC
));
1838 if(peerSemaphore
!= NULL
)
1839 dispatch_release(peerSemaphore
);
1841 if(time_out
!= NULL
&& peerSemaphore
!= NULL
){
1842 dispatch_sync(time_out
, ^{
1843 if(!peerIsAvailable
){
1844 dispatch_release(peerSemaphore
);
1845 peerSemaphore
= NULL
;
1846 notify_cancel(token
);
1847 secnotice("peer available", "checking peer availability timed out, releasing semaphore");
1851 if(!peerIsAvailable
){
1852 CFStringRef errorMessage
= CFSTR("There are no peers in the circle currently available");
1853 CFDictionaryRef userInfo
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
, kCFErrorLocalizedDescriptionKey
, errorMessage
, NULL
);
1855 *error
=CFErrorCreate(kCFAllocatorDefault
, CFSTR("com.apple.security.ids.error"), kSecIDSErrorNoPeersAvailable
, userInfo
);
1856 secerror("%@", *error
);
1858 CFReleaseNull(userInfo
);
1866 bool SOSCCkSecXPCOpIsThisDeviceLastBackup_Server(CFErrorRef
*error
) {
1867 bool result
= do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1868 return SOSAccountIsLastBackupPeer(account
, block_error
);
1875 enum DepartureReason
SOSCCGetLastDepartureReason_Server(CFErrorRef
* error
)
1877 __block
enum DepartureReason result
= kSOSDepartureReasonError
;
1879 (void) do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1880 result
= SOSAccountGetLastDepartureReason(account
, block_error
);
1881 return result
!= kSOSDepartureReasonError
;
1887 bool SOSCCSetLastDepartureReason_Server(enum DepartureReason reason
, CFErrorRef
*error
){
1888 __block
bool result
= true;
1890 return do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1891 SOSAccountSetLastDepartureReason(account
, reason
);
1896 bool SOSCCSetHSA2AutoAcceptInfo_Server(CFDataRef pubKey
, CFErrorRef
*error
) {
1897 __block
bool result
= true;
1899 return do_with_account_if_after_first_unlock(error
, ^(SOSAccountRef account
,
1900 SOSAccountTransactionRef txn
, CFErrorRef
*block_error
) {
1901 result
= SOSAccountSetHSAPubKeyExpected(account
, pubKey
, error
);
1902 return (bool)result
;
1906 bool SOSCCProcessEnsurePeerRegistration_Server(CFErrorRef
* error
)
1908 secnotice("updates", "Request for registering peers");
1909 return do_with_account_while_unlocked(error
, ^bool(SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
*error
) {
1910 return SOSAccountEnsurePeerRegistration(account
, error
);
1914 SyncWithAllPeersReason
SOSCCProcessSyncWithAllPeers_Server(CFErrorRef
* error
)
1917 #define kIOReturnLockedRead iokit_common_err(0x2c3) // device read locked
1918 #define kIOReturnLockedWrite iokit_common_err(0x2c4) // device write locked
1920 __block SyncWithAllPeersReason result
= kSyncWithAllPeersSuccess
;
1921 CFErrorRef action_error
= NULL
;
1923 if (!do_with_account_while_unlocked(&action_error
, ^bool (SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
* block_error
) {
1924 CFErrorRef localError
= NULL
;
1926 SOSAccountSendIKSPSyncList(account
, &localError
);
1928 if (!SOSAccountSyncWithAllKVSPeers(account
, &localError
)) {
1929 secerror("sync with all peers failed: %@", localError
);
1930 CFReleaseSafe(localError
);
1931 // This isn't a device-locked error, but returning false will
1932 // have CloudKeychainProxy ask us to try sync again after next unlock
1933 result
= kSyncWithAllPeersOtherFail
;
1939 if (SecErrorGetOSStatus(action_error
) == errSecInteractionNotAllowed
) {
1940 secnotice("updates", "SOSAccountSyncWithAllKVSPeers failed because device is locked; letting CloudKeychainProxy know");
1941 result
= kSyncWithAllPeersLocked
; // tell CloudKeychainProxy to call us back when device unlocks
1942 CFReleaseNull(action_error
);
1944 secerror("Unexpected error: %@", action_error
);
1947 if (error
&& *error
== NULL
) {
1948 *error
= action_error
;
1949 action_error
= NULL
;
1952 CFReleaseNull(action_error
);
1959 void SOSCCSyncWithAllPeers(void)
1961 os_activity_initiate("CloudCircle SyncWithAllPeers", OS_ACTIVITY_FLAG_DEFAULT
, ^(void) {
1963 SOSCloudKeychainRequestSyncWithAllPeers(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), NULL
);
1968 void SOSCCEnsurePeerRegistration(void)
1970 os_activity_initiate("CloudCircle EnsurePeerRegistration", OS_ACTIVITY_FLAG_DEFAULT
, ^(void) {
1972 SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), NULL
);
1977 CF_RETURNS_RETAINED CFArrayRef
SOSCCHandleUpdateMessage(CFDictionaryRef updates
)
1979 CFArrayRef result
= NULL
;
1980 SOSAccountRef account
= SOSKeychainAccountGetSharedAccount(); //HACK to make sure itemsChangedBlock is set
1982 (account
) ? (result
= SOSCloudKeychainHandleUpdateMessage(updates
)) : (result
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
));
1986 SOSPeerInfoRef
SOSCCCopyApplication_Server(CFErrorRef
*error
) {
1987 __block SOSPeerInfoRef application
= NULL
;
1988 do_with_account_while_unlocked(error
, ^bool(SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
*error
) {
1989 application
= SOSAccountCopyApplication(account
, error
);
1990 return application
!= NULL
;
1995 CFDataRef
SOSCCCopyCircleJoiningBlob_Server(SOSPeerInfoRef applicant
, CFErrorRef
*error
) {
1996 __block CFDataRef pbblob
= NULL
;
1997 do_with_account_while_unlocked(error
, ^bool(SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
*error
) {
1998 pbblob
= SOSAccountCopyCircleJoiningBlob(account
, applicant
, error
);
1999 return pbblob
!= NULL
;
2004 bool SOSCCJoinWithCircleJoiningBlob_Server(CFDataRef joiningBlob
, CFErrorRef
*error
) {
2005 return do_with_account_while_unlocked(error
, ^bool(SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
*error
) {
2006 return SOSAccountJoinWithCircleJoiningBlob(account
, joiningBlob
, error
);
2011 CFBooleanRef
SOSCCPeersHaveViewsEnabled_Server(CFArrayRef viewNames
, CFErrorRef
*error
) {
2012 __block CFBooleanRef result
= NULL
;
2013 do_with_account_if_after_first_unlock(error
, ^bool(SOSAccountRef account
, SOSAccountTransactionRef txn
, CFErrorRef
*error
) {
2014 result
= SOSAccountPeersHaveViewsEnabled(account
, viewNames
, error
);
2015 return result
!= NULL
;