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 <securityd/SOSCloudCircleServer.h>
29 #include <Security/SecureObjectSync/SOSCloudCircle.h>
30 #include <Security/SecureObjectSync/SOSCloudCircleInternal.h>
31 #include <Security/SecureObjectSync/SOSCircle.h>
32 #include <Security/SecureObjectSync/SOSAccount.h>
33 #include <Security/SecureObjectSync/SOSAccountPriv.h>
34 #include <Security/SecureObjectSync/SOSFullPeerInfo.h>
35 #include <Security/SecureObjectSync/SOSPeerInfoV2.h>
37 #include <Security/SecureObjectSync/SOSPeerInfoInternal.h>
38 #include <Security/SecureObjectSync/SOSInternal.h>
39 #include <Security/SecureObjectSync/SOSUserKeygen.h>
40 #include <Security/SecureObjectSync/SOSMessage.h>
41 #include <Security/SecureObjectSync/SOSTransport.h>
42 #include <Security/SecureObjectSync/SOSTransportMessageIDS.h>
43 #include <Security/SecureObjectSync/SOSAccountHSAJoin.h>
45 #include <Security/SecureObjectSync/SOSKVSKeys.h>
47 #include <utilities/SecCFWrappers.h>
48 #include <utilities/SecCFRelease.h>
49 #include <utilities/debugging.h>
50 #include <utilities/SecCoreCrypto.h>
51 #include <SOSCircle/CKBridge/SOSCloudKeychainClient.h>
53 #include <corecrypto/ccrng.h>
54 #include <corecrypto/ccrng_pbkdf2_prng.h>
55 #include <corecrypto/ccec.h>
56 #include <corecrypto/ccdigest.h>
57 #include <corecrypto/ccsha2.h>
58 #include <CommonCrypto/CommonRandomSPI.h>
59 #include <Security/SecKeyPriv.h>
60 #include <Security/SecFramework.h>
62 #include <utilities/SecFileLocations.h>
63 #include <utilities/SecAKSWrappers.h>
64 #include <securityd/SecItemServer.h>
65 #include <Security/SecItemPriv.h>
66 #include <Security/SecureObjectSync/SOSCloudCircleInternal.h>
68 #include <TargetConditionals.h>
70 #include <utilities/iCloudKeychainTrace.h>
72 #if TARGET_OS_EMBEDDED || TARGET_IPHONE_SIMULATOR
73 #include <MobileGestalt.h>
75 #include <AppleSystemInfo/AppleSystemInfo.h>
77 // We need authorization, but that doesn't exist
78 // on sec built for desktop (iOS in a process)
79 // Define AuthorizationRef here to make SystemConfiguration work
81 typedef const struct AuthorizationOpaqueRef
* AuthorizationRef
;
84 #define SOSCKCSCOPE "sync"
85 #define RUN_AS_ROOT_ERROR 550
87 #define USE_SYSTEMCONFIGURATION_PRIVATE_HEADERS
88 #import <SystemConfiguration/SystemConfiguration.h>
92 static SOSCCAccountDataSourceFactoryBlock accountDataSourceOverride
= NULL
;
94 bool SOSKeychainAccountSetFactoryForAccount(SOSCCAccountDataSourceFactoryBlock block
)
96 accountDataSourceOverride
= Block_copy(block
);
105 static void do_with_account(void (^action
)(SOSAccountRef account
));
106 static void do_with_account_async(void (^action
)(SOSAccountRef account
));
111 CFStringRef kSOSInternalAccessGroup
= CFSTR("com.apple.security.sos");
113 CFStringRef kSOSAccountLabel
= CFSTR("iCloud Keychain Account Meta-data");
115 static CFStringRef accountFileName
= CFSTR("PersistedAccount.plist");
117 static CFDictionaryRef
SOSItemCopyQueryForSyncItems(CFStringRef service
, bool returnData
)
119 return CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
120 kSecClass
, kSecClassGenericPassword
,
121 kSecAttrService
, service
,
122 kSecAttrAccessGroup
, kSOSInternalAccessGroup
,
123 kSecReturnData
, returnData
? kCFBooleanTrue
: kCFBooleanFalse
,
127 CFDataRef
SOSItemCopy(CFStringRef service
, CFErrorRef
* error
)
129 CFDictionaryRef query
= SOSItemCopyQueryForSyncItems(service
, true);
131 CFDataRef result
= NULL
;
133 OSStatus copyResult
= SecItemCopyMatching(query
, (CFTypeRef
*) &result
);
135 CFReleaseNull(query
);
137 if (copyResult
!= noErr
) {
138 SecError(copyResult
, error
, CFSTR("Error %@ reading for service '%@'"), result
, service
);
139 CFReleaseNull(result
);
143 if (!isData(result
)) {
144 SOSCreateErrorWithFormat(kSOSErrorProcessingFailure
, NULL
, error
, NULL
, CFSTR("SecItemCopyMatching returned non-data in '%@'"), service
);
145 CFReleaseNull(result
);
152 static CFDataRef
SOSKeychainCopySavedAccountData()
154 CFErrorRef error
= NULL
;
155 CFDataRef accountData
= SOSItemCopy(kSOSAccountLabel
, &error
);
157 secnotice("account", "Failed to load account: %@", error
);
158 secerror("Failed to load account: %@", error
);
160 CFReleaseNull(error
);
165 bool SOSItemUpdateOrAdd(CFStringRef service
, CFStringRef accessibility
, CFDataRef data
, CFErrorRef
*error
)
167 CFDictionaryRef query
= SOSItemCopyQueryForSyncItems(service
, false);
169 CFDictionaryRef update
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
171 kSecAttrAccessible
, accessibility
,
173 OSStatus saveStatus
= SecItemUpdate(query
, update
);
175 if (errSecItemNotFound
== saveStatus
) {
176 CFMutableDictionaryRef add
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, query
);
177 CFDictionaryForEach(update
, ^(const void *key
, const void *value
) {
178 CFDictionaryAddValue(add
, key
, value
);
180 saveStatus
= SecItemAdd(add
, NULL
);
184 CFReleaseNull(query
);
185 CFReleaseNull(update
);
187 return SecError(saveStatus
, error
, CFSTR("Error saving %@ to service '%@'"), data
, service
);
190 static void SOSKeychainAccountEnsureSaved(SOSAccountRef account
)
192 static CFDataRef sLastSavedAccountData
= NULL
;
194 CFErrorRef saveError
= NULL
;
195 CFDataRef accountAsData
= NULL
;
197 accountAsData
= SOSAccountCopyEncodedData(account
, kCFAllocatorDefault
, &saveError
);
199 require_action_quiet(accountAsData
, exit
, secerror("Failed to transform account into data, error: %@", saveError
));
200 require_quiet(!CFEqualSafe(sLastSavedAccountData
, accountAsData
), exit
);
202 if (!SOSItemUpdateOrAdd(kSOSAccountLabel
, kSecAttrAccessibleAlwaysThisDeviceOnly
, accountAsData
, &saveError
)) {
203 secerror("Can't save account: %@", saveError
);
207 CFReleaseNull(sLastSavedAccountData
);
208 sLastSavedAccountData
= accountAsData
;
209 accountAsData
= NULL
;
212 CFReleaseNull(saveError
);
213 CFReleaseNull(accountAsData
);
218 Stolen from keychain_sync.c
221 static bool clearAllKVS(CFErrorRef
*error
)
224 __block
bool result
= false;
225 const uint64_t maxTimeToWaitInSeconds
= 30ull * NSEC_PER_SEC
;
226 dispatch_queue_t processQueue
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0);
227 dispatch_semaphore_t waitSemaphore
= dispatch_semaphore_create(0);
228 dispatch_time_t finishTime
= dispatch_time(DISPATCH_TIME_NOW
, maxTimeToWaitInSeconds
);
230 SOSCloudKeychainClearAll(processQueue
, ^(CFDictionaryRef returnedValues
, CFErrorRef cerror
)
232 result
= (cerror
!= NULL
);
233 dispatch_semaphore_signal(waitSemaphore
);
236 dispatch_semaphore_wait(waitSemaphore
, finishTime
);
237 dispatch_release(waitSemaphore
);
242 static SOSAccountRef
SOSKeychainAccountCreateSharedAccount(CFDictionaryRef our_gestalt
)
244 secdebug("account", "Created account");
246 CFDataRef savedAccount
= SOSKeychainCopySavedAccountData();
247 SOSAccountRef account
= NULL
;
248 SOSDataSourceFactoryRef factory
= accountDataSourceOverride
? accountDataSourceOverride()
249 : SecItemDataSourceFactoryGetDefault();
252 CFErrorRef inflationError
= NULL
;
254 account
= SOSAccountCreateFromData(kCFAllocatorDefault
, savedAccount
, factory
, &inflationError
);
257 SOSAccountUpdateGestalt(account
, our_gestalt
);
259 secerror("Got error inflating account: %@", inflationError
);
262 CFReleaseNull(inflationError
);
265 CFReleaseSafe(savedAccount
);
268 account
= SOSAccountCreate(kCFAllocatorDefault
, our_gestalt
, factory
);
271 secerror("Got NULL creating account");
278 // Mark: Gestalt Handling
281 CF_EXPORT CFDictionaryRef
_CFCopySystemVersionDictionary(void);
282 CF_EXPORT CFStringRef _kCFSystemVersionBuildVersionKey
;
284 CFStringRef
CopyOSVersion(void)
286 static dispatch_once_t once
;
287 static CFStringRef osVersion
= NULL
;
288 dispatch_once(&once
, ^{
289 #if TARGET_OS_EMBEDDED || TARGET_IPHONE_SIMULATOR
290 osVersion
= MGCopyAnswer(kMGQBuildVersion
, NULL
);
292 CFDictionaryRef versions
= _CFCopySystemVersionDictionary();
295 CFTypeRef versionValue
= CFDictionaryGetValue(versions
, _kCFSystemVersionBuildVersionKey
);
297 if (isString(versionValue
))
298 osVersion
= CFRetainSafe((CFStringRef
) versionValue
);
301 CFReleaseNull(versions
);
303 // What to do on MacOS.
304 if (osVersion
== NULL
)
305 osVersion
= CFSTR("Unknown model");
307 return CFRetainSafe(osVersion
);
311 static CFStringRef
CopyModelName(void)
313 static dispatch_once_t once
;
314 static CFStringRef modelName
= NULL
;
315 dispatch_once(&once
, ^{
316 #if TARGET_OS_EMBEDDED || TARGET_IPHONE_SIMULATOR
317 modelName
= MGCopyAnswer(kMGQDeviceName
, NULL
);
319 modelName
= ASI_CopyComputerModelName(FALSE
);
321 if (modelName
== NULL
)
322 modelName
= CFSTR("Unknown model");
324 return CFStringCreateCopy(kCFAllocatorDefault
, modelName
);
327 static CFStringRef
CopyComputerName(SCDynamicStoreRef store
)
329 CFStringRef deviceName
= SCDynamicStoreCopyComputerName(store
, NULL
);
330 if (deviceName
== NULL
) {
331 deviceName
= CFSTR("Unknown name");
336 static bool _EngineMessageProtocolV2Enabled(void)
340 static dispatch_once_t onceToken
;
341 static bool v2_enabled
= false;
342 dispatch_once(&onceToken
, ^{
343 CFTypeRef v2Pref
= (CFNumberRef
)CFPreferencesCopyValue(CFSTR("engineV2"), CFSTR("com.apple.security"), kCFPreferencesAnyUser
, kCFPreferencesCurrentHost
);
345 if (v2Pref
&& CFGetTypeID(v2Pref
) == CFBooleanGetTypeID()) {
346 v2_enabled
= CFBooleanGetValue((CFBooleanRef
)v2Pref
);
347 secinfo("server", "Engine v2 : %s", v2_enabled
? "enabled":"disabled");
349 CFReleaseSafe(v2Pref
);
359 static CFDictionaryRef
CreateDeviceGestaltDictionary(SCDynamicStoreRef store
, CFArrayRef keys
, void *context
)
361 CFStringRef modelName
= CopyModelName();
362 CFStringRef computerName
= CopyComputerName(store
);
363 CFStringRef osVersion
= CopyOSVersion();
365 SInt32 version
= _EngineMessageProtocolV2Enabled() ? kEngineMessageProtocolVersion
: 0;
366 CFNumberRef protocolVersion
= CFNumberCreate(0, kCFNumberSInt32Type
, &version
);
368 CFDictionaryRef gestalt
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
369 kPIUserDefinedDeviceNameKey
, computerName
,
370 kPIDeviceModelNameKey
, modelName
,
371 kPIMessageProtocolVersionKey
, protocolVersion
,
372 kPIOSVersionKey
, osVersion
,
374 CFReleaseSafe(modelName
);
375 CFReleaseSafe(computerName
);
376 CFReleaseSafe(protocolVersion
);
381 static void SOSCCProcessGestaltUpdate(SCDynamicStoreRef store
, CFArrayRef keys
, void *context
)
383 do_with_account(^(SOSAccountRef account
) {
385 CFDictionaryRef gestalt
= CreateDeviceGestaltDictionary(store
, keys
, context
);
386 if (SOSAccountUpdateGestalt(account
, gestalt
)) {
387 notify_post(kSOSCCCircleChangedNotification
);
389 CFReleaseSafe(gestalt
);
395 static CFDictionaryRef
CreateDeviceGestaltDictionaryAndRegisterForUpdate(dispatch_queue_t queue
, void *info
)
397 SCDynamicStoreContext context
= { .info
= info
};
398 SCDynamicStoreRef store
= SCDynamicStoreCreate(NULL
, CFSTR("com.apple.securityd.cloudcircleserver"), SOSCCProcessGestaltUpdate
, &context
);
399 CFStringRef computerKey
= SCDynamicStoreKeyCreateComputerName(NULL
);
400 CFArrayRef keys
= NULL
;
401 CFDictionaryRef gestalt
= NULL
;
403 if (store
== NULL
|| computerKey
== NULL
) {
406 keys
= CFArrayCreate(NULL
, (const void **)&computerKey
, 1, &kCFTypeArrayCallBacks
);
410 gestalt
= CreateDeviceGestaltDictionary(store
, keys
, info
);
411 SCDynamicStoreSetNotificationKeys(store
, keys
, NULL
);
412 SCDynamicStoreSetDispatchQueue(store
, queue
);
415 if (store
) CFRelease(store
);
416 if (computerKey
) CFRelease(computerKey
);
417 if (keys
) CFRelease(keys
);
421 static void do_with_account(void (^action
)(SOSAccountRef account
));
422 static void do_with_account_async(void (^action
)(SOSAccountRef account
));
424 static SOSAccountRef
GetSharedAccount(void) {
425 static SOSAccountRef sSharedAccount
= NULL
;
426 static dispatch_once_t onceToken
;
428 #if !(TARGET_OS_EMBEDDED)
430 secerror("Cannot inflate account object as root");
435 dispatch_once(&onceToken
, ^{
436 secdebug("account", "Account Creation start");
438 CFDictionaryRef gestalt
= CreateDeviceGestaltDictionaryAndRegisterForUpdate(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), NULL
);
441 #if TARGET_OS_IPHONE && TARGET_IPHONE_SIMULATOR
442 gestalt
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
, NULL
);
444 secerror("Didn't get machine gestalt! This is going to be ugly.");
448 sSharedAccount
= SOSKeychainAccountCreateSharedAccount(gestalt
);
450 SOSAccountAddChangeBlock(sSharedAccount
, ^(SOSCircleRef circle
,
451 CFSetRef peer_additions
, CFSetRef peer_removals
,
452 CFSetRef applicant_additions
, CFSetRef applicant_removals
) {
453 CFErrorRef pi_error
= NULL
;
454 SOSPeerInfoRef me
= SOSFullPeerInfoGetPeerInfo(sSharedAccount
->my_identity
);
456 secerror("Error finding me for change: %@", pi_error
);
458 // TODO: Figure out why peer_additions isn't right in some cases (like when joining a v2 circle with a v0 peer.
459 if (SOSCircleHasPeer(circle
, me
, NULL
) /* && CFSetGetCount(peer_additions) != 0 */) {
460 secnotice("updates", "Requesting Ensure Peer Registration.");
461 SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), NULL
);
463 secinfo("updates", "Not requesting Ensure Peer Registration, since it's not needed");
466 if (CFSetContainsValue(peer_additions
, me
)) {
467 // TODO: Potentially remove from here and move this to the engine
468 // TODO: We also need to do this when our views change.
469 SOSCCSyncWithAllPeers();
473 CFReleaseNull(pi_error
);
475 // TODO: We should notify the engine of these changes here
476 if (CFSetGetCount(peer_additions
) != 0 ||
477 CFSetGetCount(peer_removals
) != 0 ||
478 CFSetGetCount(applicant_additions
) != 0 ||
479 CFSetGetCount(applicant_removals
) != 0) {
481 notify_post(kSOSCCCircleChangedNotification
);
485 SOSCloudKeychainSetItemsChangedBlock(^CFArrayRef(CFDictionaryRef changes
) {
486 CFRetainSafe(changes
);
487 __block CFMutableArrayRef handledKeys
= NULL
;
488 do_with_account(^(SOSAccountRef account
) {
489 CFStringRef changeDescription
= SOSItemsChangedCopyDescription(changes
, false);
490 secdebug(SOSCKCSCOPE
, "Received: %@", changeDescription
);
491 CFReleaseSafe(changeDescription
);
493 CFErrorRef error
= NULL
;
494 handledKeys
= SOSTransportDispatchMessages(account
, changes
, &error
);
496 secerror("Error handling updates: %@", error
);
497 CFReleaseNull(error
);
500 CFReleaseSafe(changes
);
503 CFReleaseSafe(gestalt
);
505 // TODO: We should not be doing extra work whenever securityd is launched, let's see if we can eliminate this call
506 SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), NULL
);
510 return sSharedAccount
;
513 static void do_with_account_dynamic(void (^action
)(SOSAccountRef account
), bool sync
) {
514 SOSAccountRef account
= GetSharedAccount();
517 dispatch_block_t do_action_and_save
= ^{
518 SOSPeerInfoRef mpi
= SOSAccountGetMyPeerInfo(account
);
519 CFSetRef beforeViews
= mpi
? SOSPeerInfoCopyEnabledViews(mpi
) : NULL
;
523 // Fake transaction around using the account object
524 SOSAccountFinishTransaction(account
);
526 mpi
= SOSAccountGetMyPeerInfo(account
); // Update the peer
527 CFSetRef afterViews
= mpi
? SOSPeerInfoCopyEnabledViews(mpi
) : NULL
;
529 if(!CFEqualSafe(beforeViews
, afterViews
)) {
530 notify_post(kSOSCCViewMembershipChangedNotification
);
533 CFReleaseNull(beforeViews
);
534 CFReleaseNull(afterViews
);
536 SOSKeychainAccountEnsureSaved(account
);
540 dispatch_sync(SOSAccountGetQueue(account
), do_action_and_save
);
542 dispatch_async(SOSAccountGetQueue(account
), do_action_and_save
);
547 __unused
static void do_with_account_async(void (^action
)(SOSAccountRef account
)) {
548 do_with_account_dynamic(action
, false);
551 static void do_with_account(void (^action
)(SOSAccountRef account
)) {
552 do_with_account_dynamic(action
, true);
555 static bool do_if_after_first_unlock(CFErrorRef
*error
, dispatch_block_t action
)
557 #if TARGET_IPHONE_SIMULATOR
561 bool beenUnlocked
= false;
562 require_quiet(SecAKSGetHasBeenUnlocked(&beenUnlocked
, error
), fail
);
564 require_action_quiet(beenUnlocked
, fail
,
565 SOSCreateErrorWithFormat(kSOSErrorNotReady
, NULL
, error
, NULL
,
566 CFSTR("Keybag never unlocked, ask after first unlock")));
576 static bool do_with_account_if_after_first_unlock(CFErrorRef
*error
, bool (^action
)(SOSAccountRef account
, CFErrorRef
* error
))
578 __block
bool action_result
= false;
580 #if !(TARGET_OS_EMBEDDED)
582 secerror("Cannot inflate account object as root");
584 *error
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("com.apple.security"), RUN_AS_ROOT_ERROR
, NULL
);
588 return do_if_after_first_unlock(error
, ^{
589 do_with_account(^(SOSAccountRef account
) {
590 action_result
= action(account
, error
);
596 static bool do_with_account_while_unlocked(CFErrorRef
*error
, bool (^action
)(SOSAccountRef account
, CFErrorRef
* error
))
598 __block
bool action_result
= false;
600 #if !(TARGET_OS_EMBEDDED)
602 secerror("Cannot inflate account object as root");
604 *error
= CFErrorCreate(kCFAllocatorDefault
, CFSTR("com.apple.security"), RUN_AS_ROOT_ERROR
, NULL
);
609 return SecAKSDoWhileUserBagLocked(error
, ^{
610 do_with_account(^(SOSAccountRef account
) {
611 action_result
= action(account
, error
);
617 SOSAccountRef
SOSKeychainAccountGetSharedAccount()
619 __block SOSAccountRef result
= NULL
;
621 do_with_account(^(SOSAccountRef account
) {
629 // Mark: Credential processing
633 bool SOSCCTryUserCredentials_Server(CFStringRef user_label
, CFDataRef user_password
, CFErrorRef
*error
)
635 return do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
636 return SOSAccountTryUserCredentials(account
, user_label
, user_password
, block_error
);
641 SOSViewResultCode
SOSCCView_Server(CFStringRef viewname
, SOSViewActionCode action
, CFErrorRef
*error
) {
642 __block SOSViewResultCode status
= kSOSCCGeneralViewError
;
644 do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
646 case kSOSCCViewQuery
:
647 status
= SOSAccountViewStatus(account
, viewname
, error
);
649 case kSOSCCViewEnable
:
650 case kSOSCCViewDisable
: // fallthrough
651 status
= SOSAccountUpdateView(account
, viewname
, action
, error
);
652 secnotice("views", "HEY!!!!!! I'm Changing VIEWS- %d", (int) status
);
655 secnotice("views", "Bad SOSViewActionCode - %d", (int) action
);
665 bool SOSCCViewSet_Server(CFSetRef enabledViews
, CFSetRef disabledViews
) {
666 __block
bool status
= false;
668 do_with_account_if_after_first_unlock(NULL
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
669 status
= SOSAccountUpdateViewSets(account
, enabledViews
, disabledViews
);
677 SOSSecurityPropertyResultCode
SOSCCSecurityProperty_Server(CFStringRef property
, SOSSecurityPropertyActionCode action
, CFErrorRef
*error
) {
679 __block SOSViewResultCode status
= kSOSCCGeneralSecurityPropertyError
;
680 do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
682 case kSOSCCSecurityPropertyQuery
:
683 status
= SOSAccountSecurityPropertyStatus(account
, property
, error
);
685 case kSOSCCSecurityPropertyEnable
:
686 case kSOSCCSecurityPropertyDisable
: // fallthrough
687 status
= SOSAccountUpdateSecurityProperty(account
, property
, action
, error
);
688 secnotice("secprop", "HEY!!!!!! I'm Changing SecurityProperties- %d", (int) status
);
691 secnotice("secprop", "Bad SOSSecurityPropertyActionCode - %d", (int) action
);
700 void sync_the_last_data_to_kvs(SOSAccountRef account
){
702 dispatch_semaphore_t wait_for
= dispatch_semaphore_create(0);
703 dispatch_retain(wait_for
); // Both this scope and the block own it.
705 __block
bool success
= false;
707 secnoticeq("force-push", "calling SOSCloudKeychainSynchronizeAndWait");
709 CFMutableArrayRef keysToGet
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
711 SOSCloudKeychainSynchronizeAndWait(keysToGet
, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^(CFDictionaryRef returnedValues
, CFErrorRef sync_error
) {
714 secerrorq("SOSCloudKeychainSynchronizeAndWait: %@", sync_error
);
716 secnoticeq("force-push", "returned from call; in callback to SOSCloudKeychainSynchronizeAndWait: results: %@", returnedValues
);
721 dispatch_semaphore_signal(wait_for
);
722 dispatch_release(wait_for
);
725 CFReleaseNull(keysToGet
);
726 dispatch_semaphore_wait(wait_for
, DISPATCH_TIME_FOREVER
);
727 dispatch_release(wait_for
);
730 #define kWAIT2MINID "EFRESH"
732 static bool EnsureFreshParameters(SOSAccountRef account
, CFErrorRef
*error
) {
733 dispatch_semaphore_t wait_for
= dispatch_semaphore_create(0);
734 dispatch_retain(wait_for
); // Both this scope and the block own it.
736 CFMutableArrayRef keysToGet
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
737 CFArrayAppendValue(keysToGet
, kSOSKVSKeyParametersKey
);
738 AppendCircleKeyName(keysToGet
, SOSCircleGetName(account
->trusted_circle
));
740 __block CFDictionaryRef valuesToUpdate
= NULL
;
741 __block
bool success
= false;
743 secnoticeq("fresh", "%s calling SOSCloudKeychainSynchronizeAndWait", kWAIT2MINID
);
745 SOSCloudKeychainSynchronizeAndWait(keysToGet
, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^(CFDictionaryRef returnedValues
, CFErrorRef sync_error
) {
748 secerrorq("%s SOSCloudKeychainSynchronizeAndWait: %@", kWAIT2MINID
, sync_error
);
751 CFRetainSafe(*error
);
754 secnoticeq("fresh", "%s returned from call; in callback to SOSCloudKeychainSynchronizeAndWait: results: %@", kWAIT2MINID
, returnedValues
);
755 valuesToUpdate
= returnedValues
;
756 CFRetainSafe(valuesToUpdate
);
760 dispatch_semaphore_signal(wait_for
);
761 dispatch_release(wait_for
);
764 dispatch_semaphore_wait(wait_for
, DISPATCH_TIME_FOREVER
);
765 // TODO: Maybe we timeout here... used to dispatch_time(DISPATCH_TIME_NOW, 30ull * NSEC_PER_SEC));
766 dispatch_release(wait_for
);
767 CFMutableArrayRef handledKeys
= NULL
;
768 if ((valuesToUpdate
) && (account
)) {
769 handledKeys
= SOSTransportDispatchMessages(account
, valuesToUpdate
, error
);
771 secerrorq("%s Freshness update failed: %@", kWAIT2MINID
, error
? *error
: NULL
);
775 CFReleaseNull(handledKeys
);
776 CFReleaseNull(valuesToUpdate
);
777 CFReleaseNull(keysToGet
);
782 static bool Flush(CFErrorRef
*error
) {
783 __block
bool success
= false;
785 dispatch_semaphore_t wait_for
= dispatch_semaphore_create(0);
786 dispatch_retain(wait_for
); // Both this scope and the block own it.
788 secnotice("flush", "Starting");
790 SOSCloudKeychainFlush(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^(CFDictionaryRef returnedValues
, CFErrorRef sync_error
) {
791 success
= (sync_error
== NULL
);
793 CFRetainAssign(*error
, sync_error
);
796 dispatch_semaphore_signal(wait_for
);
797 dispatch_release(wait_for
);
800 dispatch_semaphore_wait(wait_for
, DISPATCH_TIME_FOREVER
);
801 dispatch_release(wait_for
);
803 secnotice("flush", "Returned %s", success
? "Success": "Failure");
808 static bool SOSCCAssertUserCredentialsAndOptionalDSID(CFStringRef user_label
, CFDataRef user_password
, CFStringRef dsid
, CFErrorRef
*error
) {
809 secnotice("updates", "Setting credentials and dsid (%@) for %@", dsid
, user_label
);
810 bool result
= do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
811 if (dsid
!= NULL
&& CFStringCompare(dsid
, CFSTR(""), 0) != 0) {
812 CFStringRef accountDSID
= SOSAccountGetValue(account
, kSOSDSIDKey
, NULL
);
813 if( accountDSID
== NULL
){
814 SOSAccountUpdateDSID(account
, dsid
);
815 secdebug("updates", "Setting dsid, current dsid is empty for this account: %@", dsid
);
817 else if(CFStringCompare(dsid
, accountDSID
, 0) != kCFCompareEqualTo
){
818 secnotice("updates", "Changing DSID from: %@ to %@", accountDSID
, dsid
);
820 //DSID has changed, blast the account!
821 SOSAccountSetToNew(account
);
823 //update DSID to the new DSID
824 SOSAccountUpdateDSID(account
, dsid
);
827 secnotice("updates", "Not Changing DSID: %@ to %@", accountDSID
, dsid
);
832 if (!EnsureFreshParameters(account
, block_error
)) {
835 if (!SOSAccountAssertUserCredentials(account
, user_label
, user_password
, block_error
)) {
836 secnotice("updates", "EnsureFreshParameters/SOSAccountAssertUserCredentials error: %@", *block_error
);
842 if (result
&& Flush(error
)) {
843 result
= do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
844 return SOSAccountGenerationSignatureUpdate(account
, error
);
851 bool SOSCCSetUserCredentialsAndDSID_Server(CFStringRef user_label
, CFDataRef user_password
, CFStringRef dsid
, CFErrorRef
*error
)
853 // TODO: Return error if DSID is NULL to insist our callers provide one?
854 return SOSCCAssertUserCredentialsAndOptionalDSID(user_label
, user_password
, dsid
, error
);
857 bool SOSCCSetUserCredentials_Server(CFStringRef user_label
, CFDataRef user_password
, CFErrorRef
*error
)
859 return SOSCCAssertUserCredentialsAndOptionalDSID(user_label
, user_password
, NULL
, error
);
862 bool SOSCCCanAuthenticate_Server(CFErrorRef
*error
)
864 bool result
= do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
865 return SOSAccountGetPrivateCredential(account
, block_error
) != NULL
;
868 if (!result
&& error
&& *error
&& CFErrorGetDomain(*error
) == kSOSErrorDomain
) {
869 CFIndex code
= CFErrorGetCode(*error
);
870 if (code
== kSOSErrorPrivateKeyAbsent
|| code
== kSOSErrorPublicKeyAbsent
) {
871 CFReleaseNull(*error
);
878 bool SOSCCPurgeUserCredentials_Server(CFErrorRef
*error
)
880 return do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
881 SOSAccountPurgePrivateCredential(account
);
886 SOSCCStatus
SOSCCThisDeviceIsInCircle_Server(CFErrorRef
*error
)
888 __block SOSCCStatus status
;
890 return do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
891 status
= SOSAccountGetCircleStatus(account
, block_error
);
893 }) ? status
: kSOSCCError
;
896 bool SOSCCRequestToJoinCircle_Server(CFErrorRef
* error
)
898 __block
bool result
= true;
900 return do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
901 result
= SOSAccountJoinCircles(account
, block_error
);
906 bool SOSCCRequestToJoinCircleAfterRestore_Server(CFErrorRef
* error
)
908 __block
bool result
= true;
909 bool returned
= false;
910 returned
= do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
911 SOSAccountEnsurePeerRegistration(account
, block_error
);
912 result
= SOSAccountJoinCirclesAfterRestore(account
, block_error
);
919 bool SOSCCRequestEnsureFreshParameters_Server(CFErrorRef
* error
)
921 __block
bool result
= true;
922 bool returned
= false;
923 returned
= do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
924 result
= EnsureFreshParameters(account
, NULL
);
930 bool SOSCCApplyToARing_Server(CFStringRef ringName
, CFErrorRef
*error
){
931 __block
bool result
= true;
932 bool returned
= false;
933 returned
= do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
934 SOSFullPeerInfoRef fpi
= SOSAccountGetMyFullPeerInfo(account
);
935 SOSRingRef ring
= SOSAccountGetRing(account
, ringName
, error
);
937 result
= SOSRingApply(ring
, account
->user_public
, fpi
, error
);
943 bool SOSCCWithdrawlFromARing_Server(CFStringRef ringName
, CFErrorRef
*error
){
944 __block
bool result
= true;
945 bool returned
= false;
946 returned
= do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
947 SOSFullPeerInfoRef fpi
= SOSAccountGetMyFullPeerInfo(account
);
948 SOSRingRef ring
= SOSAccountGetRing(account
, ringName
, error
);
950 result
= SOSRingWithdraw(ring
, account
->user_public
, fpi
, error
);
956 bool SOSCCEnableRing_Server(CFStringRef ringName
, CFErrorRef
*error
){
957 __block
bool result
= true;
958 bool returned
= false;
959 returned
= do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
960 SOSFullPeerInfoRef fpi
= SOSAccountGetMyFullPeerInfo(account
);
961 SOSRingRef ring
= SOSAccountGetRing(account
, ringName
, error
);
963 result
= SOSRingResetToOffering(ring
, NULL
, fpi
, error
); ;
969 CFStringRef
SOSCCGetAllTheRings_Server(CFErrorRef
*error
){
970 __block CFMutableDictionaryRef result
= NULL
;
971 __block CFMutableStringRef description
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
973 (void) do_with_account_while_unlocked(error
, ^bool(SOSAccountRef account
, CFErrorRef
*error
) {
974 result
= SOSAccountGetRings(account
, error
);
976 if(isDictionary(result
)){
977 CFDictionaryForEach(result
, ^(const void *key
, const void *value
) {
978 CFStringAppendFormat(description
, NULL
, CFSTR("%@"), value
);
989 SOSRingStatus
SOSCCRingStatus_Server(CFStringRef ringName
, CFErrorRef
*error
){
990 __block
bool result
= true;
991 SOSRingStatus returned
;
992 returned
= do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
993 SOSFullPeerInfoRef fpi
= SOSAccountGetMyFullPeerInfo(account
);
994 SOSPeerInfoRef myPeer
= SOSFullPeerInfoGetPeerInfo(fpi
);
996 SOSRingRef ring
= SOSAccountGetRing(account
, ringName
, error
);
998 result
= SOSRingDeviceIsInRing(ring
, SOSPeerInfoGetPeerID(myPeer
));
1004 CFStringRef
SOSCCRequestDeviceID_Server(CFErrorRef
*error
)
1006 __block CFStringRef result
= NULL
;
1008 (void) do_with_account_while_unlocked(error
, ^bool(SOSAccountRef account
, CFErrorRef
*error
) {
1009 result
= SOSAccountCopyDeviceID(account
, error
);
1010 return (!isNull(result
));
1015 bool SOSCCSetDeviceID_Server(CFStringRef IDS
, CFErrorRef
*error
){
1017 bool didSetID
= false;
1018 __block
bool result
= false;
1019 __block CFErrorRef blockError
= NULL
;
1021 didSetID
= do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
1022 result
= SOSAccountSetMyDSID(account
, IDS
, block_error
);
1024 blockError
= CFRetainSafe(*block_error
);
1029 *error
= blockError
;
1034 HandleIDSMessageReason
SOSCCHandleIDSMessage_Server(CFDictionaryRef messageDict
, CFErrorRef
* error
)
1036 // TODO: Locking flow:
1039 - Get PeerCoder instance from SOSPeerCoderManager(Currently Engine)
1040 - Get Account lock and Initialize PeerCoder instance if it isn't valid yet.
1042 - Decode incoming msg on coder.
1043 - Pass msg along to SOSPeerRef if decoding is done.
1044 - Force reply from coder while in handshake mode. (or ask ckd to ask us later?)
1047 - Lookup SOSPeerRef in SOSEngineRef (getting engine lock temporarily to get peer.
1048 - Ask peer to handle decoded message
1049 - be notified of changed objects in all peers and update peer/engine states
1050 - save peer/engine state
1053 - Ask coder to send an outgoing message if it is negotiating
1054 - Ask peer to create a message if needed
1055 - Encode peer msg with coder
1057 - send reply to ckd for transporting
1060 __block HandleIDSMessageReason result
= kHandleIDSMessageSuccess
;
1061 CFErrorRef action_error
= NULL
;
1063 if (!do_with_account_while_unlocked(&action_error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
1064 result
= SOSTransportMessageIDSHandleMessage(account
, messageDict
, error
);
1068 if (SecErrorGetOSStatus(action_error
) == errSecInteractionNotAllowed
) {
1069 secnotice("updates", "SOSCCHandleIDSMessage_Server failed because device is locked; letting IDSKeychainSyncingProxy know");
1070 result
= kHandleIDSMessageLocked
; // tell IDSKeychainSyncingProxy to call us back when device unlocks
1071 CFReleaseNull(action_error
);
1073 secerror("Unexpected error: %@", action_error
);
1076 if (error
&& *error
== NULL
) {
1077 *error
= action_error
;
1078 action_error
= NULL
;
1081 CFReleaseNull(action_error
);
1087 bool SOSCCIDSPingTest_Server(CFStringRef message
, CFErrorRef
*error
){
1088 bool didSendTestMessages
= false;
1089 __block
bool result
= true;
1090 __block CFErrorRef blockError
= NULL
;
1092 didSendTestMessages
= do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
1093 result
= SOSAccountStartPingTest(account
, message
, block_error
);
1095 blockError
= CFRetainSafe(*block_error
);
1098 if(blockError
&& error
!= NULL
)
1099 *error
= blockError
;
1101 return didSendTestMessages
;
1104 bool SOSCCIDSServiceRegistrationTest_Server(CFStringRef message
, CFErrorRef
*error
){
1105 bool didSendTestMessages
= false;
1106 __block
bool result
= true;
1107 __block CFErrorRef blockError
= NULL
;
1109 didSendTestMessages
= do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
1110 result
= SOSAccountSendIDSTestMessage(account
, message
, block_error
);
1112 blockError
= CFRetainSafe(*block_error
);
1115 if(blockError
&& error
!= NULL
)
1116 *error
= blockError
;
1118 return didSendTestMessages
;
1121 bool SOSCCIDSDeviceIDIsAvailableTest_Server(CFErrorRef
*error
){
1122 bool didSendTestMessages
= false;
1123 __block
bool result
= true;
1124 __block CFErrorRef blockError
= NULL
;
1126 didSendTestMessages
= do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
1127 result
= SOSAccountRetrieveDeviceIDFromIDSKeychainSyncingProxy(account
, block_error
);
1129 blockError
= CFRetainSafe(*block_error
);
1132 if(blockError
&& error
!= NULL
)
1133 *error
= blockError
;
1135 return didSendTestMessages
;
1138 bool SOSCCAccountSetToNew_Server(CFErrorRef
*error
)
1140 __block
bool result
= true;
1142 return do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
1144 SOSAccountSetToNew(account
);
1149 bool SOSCCResetToOffering_Server(CFErrorRef
* error
)
1151 __block
bool result
= true;
1153 return do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
1155 result
= SOSAccountResetToOffering(account
, block_error
);
1161 bool SOSCCResetToEmpty_Server(CFErrorRef
* error
)
1163 __block
bool result
= true;
1165 return do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
1166 result
= SOSAccountResetToEmpty(account
, block_error
);
1172 bool SOSCCRemoveThisDeviceFromCircle_Server(CFErrorRef
* error
)
1174 __block
bool result
= true;
1176 return do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
1177 result
= SOSAccountLeaveCircle(account
, block_error
);
1182 bool SOSCCLoggedOutOfAccount_Server(CFErrorRef
*error
)
1184 __block
bool result
= true;
1186 return do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
1187 secnotice("sosops", "Signed out of account!");
1188 result
= SOSAccountLeaveCircle(account
, block_error
);
1190 SOSAccountFinishTransaction(account
); // Make sure this gets finished before we set to new.
1192 SOSAccountSetToNew(account
);
1194 sync_the_last_data_to_kvs(account
);
1200 bool SOSCCBailFromCircle_Server(uint64_t limit_in_seconds
, CFErrorRef
* error
)
1202 __block
bool result
= true;
1204 return do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
1205 result
= SOSAccountBail(account
, limit_in_seconds
, block_error
);
1207 SOSAccountFinishTransaction(account
); // Make sure this gets finished before we set to new.
1209 sync_the_last_data_to_kvs(account
);
1216 CFArrayRef
SOSCCCopyApplicantPeerInfo_Server(CFErrorRef
* error
)
1218 __block CFArrayRef result
= NULL
;
1220 (void) do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
1221 result
= SOSAccountCopyApplicants(account
, block_error
);
1222 return result
!= NULL
;
1228 CFArrayRef
SOSCCCopyGenerationPeerInfo_Server(CFErrorRef
* error
)
1230 __block CFArrayRef result
= NULL
;
1232 (void) do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
1233 result
= SOSAccountCopyGeneration(account
, block_error
);
1234 return result
!= NULL
;
1240 CFArrayRef
SOSCCCopyValidPeerPeerInfo_Server(CFErrorRef
* error
)
1242 __block CFArrayRef result
= NULL
;
1244 (void) do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
1245 result
= SOSAccountCopyValidPeers(account
, block_error
);
1246 return result
!= NULL
;
1252 bool SOSCCValidateUserPublic_Server(CFErrorRef
* error
)
1254 __block
bool result
= NULL
;
1256 (void) do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
1257 result
= SOSValidateUserPublic(account
, block_error
);
1264 CFArrayRef
SOSCCCopyNotValidPeerPeerInfo_Server(CFErrorRef
* error
)
1266 __block CFArrayRef result
= NULL
;
1268 (void) do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
1269 result
= SOSAccountCopyNotValidPeers(account
, block_error
);
1270 return result
!= NULL
;
1276 CFArrayRef
SOSCCCopyRetirementPeerInfo_Server(CFErrorRef
* error
)
1278 __block CFArrayRef result
= NULL
;
1280 (void) do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
1281 result
= SOSAccountCopyRetired(account
, block_error
);
1282 return result
!= NULL
;
1288 CFArrayRef
SOSCCCopyEngineState_Server(CFErrorRef
* error
)
1290 CFArrayRef result
= NULL
;
1291 SOSDataSourceFactoryRef dsf
= SecItemDataSourceFactoryGetDefault();
1292 SOSDataSourceRef ds
= SOSDataSourceFactoryCreateDataSource(dsf
, kSecAttrAccessibleWhenUnlocked
, error
);
1294 SOSEngineRef engine
= SOSDataSourceGetSharedEngine(ds
, error
);
1295 result
= SOSEngineCopyPeerConfirmedDigests(engine
, error
);
1296 SOSDataSourceRelease(ds
, error
);
1302 bool SOSCCWaitForInitialSync_Server(CFErrorRef
* error
) {
1303 __block dispatch_semaphore_t inSyncSema
= NULL
;
1305 bool result
= do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
1306 bool alreadyInSync
= SOSAccountCheckHasBeenInSync(account
);
1308 if (!alreadyInSync
) {
1309 inSyncSema
= dispatch_semaphore_create(0);
1310 dispatch_retain(inSyncSema
);
1311 notify_register_dispatch(kSOSCCInitialSyncChangedNotification
, &token
,
1312 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^(int token
) {
1313 dispatch_semaphore_signal(inSyncSema
);
1314 dispatch_release(inSyncSema
);
1316 notify_cancel(token
);
1322 if (result
&& inSyncSema
!= NULL
) {
1323 dispatch_semaphore_wait(inSyncSema
, DISPATCH_TIME_FOREVER
);
1324 dispatch_release(inSyncSema
);
1330 static CFArrayRef
SOSAccountCopyYetToSyncViews(SOSAccountRef account
, CFErrorRef
*error
) {
1331 CFArrayRef result
= NULL
;
1333 CFTypeRef valueFetched
= SOSAccountGetValue(account
, kSOSUnsyncedViewsKey
, error
);
1334 if (valueFetched
== kCFBooleanTrue
) {
1335 SOSPeerInfoRef myPI
= SOSAccountGetMyPeerInfo(account
);
1337 SOSPeerInfoWithEnabledViewSet(myPI
, ^(CFSetRef enabled
) {
1338 CFSetCopyValues(enabled
);
1341 } else if (isSet(valueFetched
)) {
1342 result
= CFSetCopyValues((CFSetRef
)valueFetched
);
1345 if (result
== NULL
) {
1346 result
= CFArrayCreateForCFTypes(kCFAllocatorDefault
, NULL
);
1352 CFArrayRef
SOSCCCopyYetToSyncViewsList_Server(CFErrorRef
* error
) {
1354 __block CFArrayRef views
= NULL
;
1356 (void) do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
1357 views
= SOSAccountCopyYetToSyncViews(account
, error
);
1366 bool SOSCCAcceptApplicants_Server(CFArrayRef applicants
, CFErrorRef
* error
)
1368 __block
bool result
= true;
1369 return do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
1370 result
= SOSAccountAcceptApplicants(account
, applicants
, block_error
);
1376 bool SOSCCRejectApplicants_Server(CFArrayRef applicants
, CFErrorRef
* error
)
1378 __block
bool result
= true;
1379 return do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
1380 result
= SOSAccountRejectApplicants(account
, applicants
, block_error
);
1385 CFArrayRef
SOSCCCopyPeerPeerInfo_Server(CFErrorRef
* error
)
1387 __block CFArrayRef result
= NULL
;
1389 (void) do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
1390 result
= SOSAccountCopyPeers(account
, block_error
);
1391 return result
!= NULL
;
1397 CFArrayRef
SOSCCCopyConcurringPeerPeerInfo_Server(CFErrorRef
* error
)
1399 __block CFArrayRef result
= NULL
;
1401 (void) do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
1402 result
= SOSAccountCopyConcurringPeers(account
, block_error
);
1403 return result
!= NULL
;
1409 SOSPeerInfoRef
SOSCCCopyMyPeerInfo_Server(CFErrorRef
* error
)
1411 __block SOSPeerInfoRef result
= NULL
;
1413 (void) do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
1414 // Create a copy to be DERed/sent back to client
1415 result
= SOSPeerInfoCreateCopy(kCFAllocatorDefault
, SOSAccountGetMyPeerInfo(account
), block_error
);
1416 return result
!= NULL
;
1422 SOSPeerInfoRef
SOSCCSetNewPublicBackupKey_Server(CFDataRef newPublicBackup
, CFErrorRef
*error
){
1423 __block SOSPeerInfoRef result
= NULL
;
1425 (void) do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
1426 if(SOSAccountSetBackupPublicKey(account
,newPublicBackup
, error
)){
1427 // Create a copy to be DERed/sent back to client
1428 result
= SOSPeerInfoCreateCopy(kCFAllocatorDefault
, SOSAccountGetMyPeerInfo(account
), block_error
);
1429 secdebug("backup", "SOSCCSetNewPublicBackupKey_Server, new public backup is set");
1433 secerror("SOSCCSetNewPublicBackupKey_Server, could not set new public backup");
1435 return result
!= NULL
;
1441 bool SOSCCRegisterSingleRecoverySecret_Server(CFDataRef aks_bag
, bool includeV0
, CFErrorRef
*error
){
1442 return do_with_account_while_unlocked(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
1443 return SOSAccountSetBSKBagForAllSlices(account
, aks_bag
, includeV0
, error
);
1447 CFStringRef
SOSCCCopyIncompatibilityInfo_Server(CFErrorRef
* error
)
1449 __block CFStringRef result
= NULL
;
1451 (void) do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
1452 result
= SOSAccountCopyIncompatibilityInfo(account
, block_error
);
1453 return result
!= NULL
;
1459 enum DepartureReason
SOSCCGetLastDepartureReason_Server(CFErrorRef
* error
)
1461 __block
enum DepartureReason result
= kSOSDepartureReasonError
;
1463 (void) do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
1464 result
= SOSAccountGetLastDepartureReason(account
, block_error
);
1465 return result
!= kSOSDepartureReasonError
;
1471 bool SOSCCSetLastDepartureReason_Server(enum DepartureReason reason
, CFErrorRef
*error
){
1472 __block
bool result
= true;
1474 return do_with_account_if_after_first_unlock(error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
1475 SOSAccountSetLastDepartureReason(account
, reason
);
1480 bool SOSCCSetHSA2AutoAcceptInfo_Server(CFDataRef pubKey
, CFErrorRef
*error
) {
1481 __block
bool result
= true;
1483 return do_with_account_if_after_first_unlock(error
, ^(SOSAccountRef account
,
1484 CFErrorRef
*block_error
) {
1485 result
= SOSAccountSetHSAPubKeyExpected(account
, pubKey
, error
);
1486 return (bool)result
;
1490 bool SOSCCProcessEnsurePeerRegistration_Server(CFErrorRef
* error
)
1492 secnotice("updates", "Request for registering peers");
1493 return do_with_account_while_unlocked(error
, ^bool(SOSAccountRef account
, CFErrorRef
*error
) {
1494 return SOSAccountEnsurePeerRegistration(account
, error
);
1498 SyncWithAllPeersReason
SOSCCProcessSyncWithAllPeers_Server(CFErrorRef
* error
)
1501 #define kIOReturnLockedRead iokit_common_err(0x2c3) // device read locked
1502 #define kIOReturnLockedWrite iokit_common_err(0x2c4) // device write locked
1504 __block SyncWithAllPeersReason result
= kSyncWithAllPeersSuccess
;
1505 CFErrorRef action_error
= NULL
;
1507 if (!do_with_account_while_unlocked(&action_error
, ^bool (SOSAccountRef account
, CFErrorRef
* block_error
) {
1508 CFErrorRef localError
= NULL
;
1510 if (!SOSAccountSyncWithAllPeers(account
, &localError
)) {
1511 secerror("sync with all peers failed: %@", localError
);
1512 CFReleaseSafe(localError
);
1513 // This isn't a device-locked error, but returning false will
1514 // have CloudKeychainProxy ask us to try sync again after next unlock
1515 result
= kSyncWithAllPeersOtherFail
;
1521 if (SecErrorGetOSStatus(action_error
) == errSecInteractionNotAllowed
) {
1522 secnotice("updates", "SOSAccountSyncWithAllPeers failed because device is locked; letting CloudKeychainProxy know");
1523 result
= kSyncWithAllPeersLocked
; // tell CloudKeychainProxy to call us back when device unlocks
1524 CFReleaseNull(action_error
);
1526 secerror("Unexpected error: %@", action_error
);
1529 if (error
&& *error
== NULL
) {
1530 *error
= action_error
;
1531 action_error
= NULL
;
1534 CFReleaseNull(action_error
);
1541 void SOSCCSyncWithAllPeers(void)
1543 SOSCloudKeychainRequestSyncWithAllPeers(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), NULL
);
1546 CF_RETURNS_RETAINED CFArrayRef
SOSCCHandleUpdateMessage(CFDictionaryRef updates
)
1548 CFArrayRef result
= NULL
;
1549 SOSAccountRef account
= SOSKeychainAccountGetSharedAccount(); //HACK to make sure itemsChangedBlock is set
1551 (account
) ? (result
= SOSCloudKeychainHandleUpdateMessage(updates
)) : (result
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
));