]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/SOSCloudCircleServer.c
Security-57337.50.23.tar.gz
[apple/security.git] / OSX / sec / securityd / SOSCloudCircleServer.c
1 /*
2 * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 #include <AssertMacros.h>
26 #include <CoreFoundation/CFURL.h>
27
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>
36
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>
44
45 #include <Security/SecureObjectSync/SOSKVSKeys.h>
46
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>
52
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>
61
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>
67
68 #include <TargetConditionals.h>
69
70 #include <utilities/iCloudKeychainTrace.h>
71 #include <Security/SecAccessControlPriv.h>
72 #include <securityd/SecDbKeychainItem.h>
73
74 #if TARGET_OS_EMBEDDED || TARGET_IPHONE_SIMULATOR
75 #include <MobileGestalt.h>
76 #else
77 #include <AppleSystemInfo/AppleSystemInfo.h>
78
79 // We need authorization, but that doesn't exist
80 // on sec built for desktop (iOS in a process)
81 // Define AuthorizationRef here to make SystemConfiguration work
82 // as if it's on iOS.
83 typedef const struct AuthorizationOpaqueRef * AuthorizationRef;
84 #endif
85
86 #define SOSCKCSCOPE "sync"
87 #define RUN_AS_ROOT_ERROR 550
88
89 #define USE_SYSTEMCONFIGURATION_PRIVATE_HEADERS
90 #import <SystemConfiguration/SystemConfiguration.h>
91
92 #include <notify.h>
93
94 static SOSCCAccountDataSourceFactoryBlock accountDataSourceOverride = NULL;
95
96 bool SOSKeychainAccountSetFactoryForAccount(SOSCCAccountDataSourceFactoryBlock block)
97 {
98 accountDataSourceOverride = Block_copy(block);
99
100 return true;
101 }
102
103 //
104 // Forward declared
105 //
106
107 static void do_with_account(void (^action)(SOSAccountRef account));
108 static void do_with_account_async(void (^action)(SOSAccountRef account));
109
110 //
111 // Constants
112 //
113 CFStringRef kSOSInternalAccessGroup = CFSTR("com.apple.security.sos");
114
115 CFStringRef kSOSAccountLabel = CFSTR("iCloud Keychain Account Meta-data");
116
117 CFStringRef kSOSBurnedRecoveryAttemptCount = CFSTR("Burned Recovery Attempt Count");
118
119 CFStringRef kSOSBurnedRecoveryAttemptAttestationDate = CFSTR("Burned Recovery Attempt Attestation Date");
120
121 static CFDictionaryRef SOSItemCopyQueryForSyncItems(CFStringRef service, bool returnData)
122 {
123 return CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
124 kSecClass, kSecClassGenericPassword,
125 kSecAttrService, service,
126 kSecAttrAccessGroup, kSOSInternalAccessGroup,
127 kSecReturnData, returnData ? kCFBooleanTrue : kCFBooleanFalse,
128 NULL);
129 }
130
131 CFDataRef SOSItemCopy(CFStringRef service, CFErrorRef* error)
132 {
133 CFDictionaryRef query = SOSItemCopyQueryForSyncItems(service, true);
134
135 CFDataRef result = NULL;
136
137 OSStatus copyResult = SecItemCopyMatching(query, (CFTypeRef*) &result);
138
139 CFReleaseNull(query);
140
141 if (copyResult != noErr) {
142 SecError(copyResult, error, CFSTR("Error %@ reading for service '%@'"), result, service);
143 CFReleaseNull(result);
144 return NULL;
145 }
146
147 if (!isData(result)) {
148 SOSCreateErrorWithFormat(kSOSErrorProcessingFailure, NULL, error, NULL, CFSTR("SecItemCopyMatching returned non-data in '%@'"), service);
149 CFReleaseNull(result);
150 return NULL;
151 }
152
153 return result;
154 }
155
156 static CFDataRef SOSKeychainCopySavedAccountData()
157 {
158 CFErrorRef error = NULL;
159 CFDataRef accountData = SOSItemCopy(kSOSAccountLabel, &error);
160 if (!accountData) {
161 secnotice("account", "Failed to load account: %@", error);
162 secerror("Failed to load account: %@", error);
163 }
164 CFReleaseNull(error);
165
166 return accountData;
167 }
168
169 bool SOSItemUpdateOrAdd(CFStringRef service, CFStringRef accessibility, CFDataRef data, CFErrorRef *error)
170 {
171 CFDictionaryRef query = SOSItemCopyQueryForSyncItems(service, false);
172
173 CFDictionaryRef update = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
174 kSecValueData, data,
175 kSecAttrAccessible, accessibility,
176 NULL);
177 OSStatus saveStatus = SecItemUpdate(query, update);
178
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);
183 });
184 saveStatus = SecItemAdd(add, NULL);
185 CFReleaseNull(add);
186 }
187
188 CFReleaseNull(query);
189 CFReleaseNull(update);
190
191 return SecError(saveStatus, error, CFSTR("Error saving %@ to service '%@'"), data, service);
192 }
193
194 static void SOSKeychainAccountEnsureSaved(SOSAccountRef account)
195 {
196 static CFDataRef sLastSavedAccountData = NULL;
197
198 CFErrorRef saveError = NULL;
199 CFDataRef accountAsData = NULL;
200
201 accountAsData = SOSAccountCopyEncodedData(account, kCFAllocatorDefault, &saveError);
202
203 require_action_quiet(accountAsData, exit, secerror("Failed to transform account into data, error: %@", saveError));
204 require_quiet(!CFEqualSafe(sLastSavedAccountData, accountAsData), exit);
205
206 if (!SOSItemUpdateOrAdd(kSOSAccountLabel, kSecAttrAccessibleAlwaysThisDeviceOnly, accountAsData, &saveError)) {
207 secerror("Can't save account: %@", saveError);
208 goto exit;
209 }
210
211 CFReleaseNull(sLastSavedAccountData);
212 sLastSavedAccountData = accountAsData;
213 accountAsData = NULL;
214
215 exit:
216 CFReleaseNull(saveError);
217 CFReleaseNull(accountAsData);
218 }
219
220
221 /*
222 Stolen from keychain_sync.c
223 */
224
225 static bool clearAllKVS(CFErrorRef *error)
226 {
227 return true;
228 __block bool result = false;
229 const uint64_t maxTimeToWaitInSeconds = 30ull * NSEC_PER_SEC;
230 dispatch_queue_t processQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
231 dispatch_semaphore_t waitSemaphore = dispatch_semaphore_create(0);
232 dispatch_time_t finishTime = dispatch_time(DISPATCH_TIME_NOW, maxTimeToWaitInSeconds);
233
234 SOSCloudKeychainClearAll(processQueue, ^(CFDictionaryRef returnedValues, CFErrorRef cerror)
235 {
236 result = (cerror != NULL);
237 dispatch_semaphore_signal(waitSemaphore);
238 });
239
240 dispatch_semaphore_wait(waitSemaphore, finishTime);
241 dispatch_release(waitSemaphore);
242
243 return result;
244 }
245
246 static SOSAccountRef SOSKeychainAccountCreateSharedAccount(CFDictionaryRef our_gestalt)
247 {
248 secdebug("account", "Created account");
249
250 CFDataRef savedAccount = SOSKeychainCopySavedAccountData();
251 SOSAccountRef account = NULL;
252 SOSDataSourceFactoryRef factory = accountDataSourceOverride ? accountDataSourceOverride()
253 : SecItemDataSourceFactoryGetDefault();
254
255 if (savedAccount) {
256 CFErrorRef inflationError = NULL;
257
258 account = SOSAccountCreateFromData(kCFAllocatorDefault, savedAccount, factory, &inflationError);
259
260 if (account){
261 SOSAccountUpdateGestalt(account, our_gestalt);
262 } else {
263 secerror("Got error inflating account: %@", inflationError);
264 }
265
266 CFReleaseNull(inflationError);
267
268 }
269 CFReleaseSafe(savedAccount);
270
271 if (!account) {
272 account = SOSAccountCreate(kCFAllocatorDefault, our_gestalt, factory);
273
274 if (!account)
275 secerror("Got NULL creating account");
276 }
277
278 return account;
279 }
280
281 //
282 // Mark: Gestalt Handling
283 //
284
285 CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
286 CF_EXPORT CFStringRef _kCFSystemVersionBuildVersionKey;
287
288 CFStringRef CopyOSVersion(void)
289 {
290 static dispatch_once_t once;
291 static CFStringRef osVersion = NULL;
292 dispatch_once(&once, ^{
293 #if TARGET_OS_EMBEDDED || TARGET_IPHONE_SIMULATOR
294 osVersion = MGCopyAnswer(kMGQBuildVersion, NULL);
295 #else
296 CFDictionaryRef versions = _CFCopySystemVersionDictionary();
297
298 if (versions) {
299 CFTypeRef versionValue = CFDictionaryGetValue(versions, _kCFSystemVersionBuildVersionKey);
300
301 if (isString(versionValue))
302 osVersion = CFRetainSafe((CFStringRef) versionValue);
303 }
304
305 CFReleaseNull(versions);
306 #endif
307 // What to do on MacOS.
308 if (osVersion == NULL)
309 osVersion = CFSTR("Unknown model");
310 });
311 return CFRetainSafe(osVersion);
312 }
313
314
315 static CFStringRef CopyModelName(void)
316 {
317 static dispatch_once_t once;
318 static CFStringRef modelName = NULL;
319 dispatch_once(&once, ^{
320 #if TARGET_OS_EMBEDDED || TARGET_IPHONE_SIMULATOR
321 modelName = MGCopyAnswer(kMGQDeviceName, NULL);
322 #else
323 modelName = ASI_CopyComputerModelName(FALSE);
324 #endif
325 if (modelName == NULL)
326 modelName = CFSTR("Unknown model");
327 });
328 return CFStringCreateCopy(kCFAllocatorDefault, modelName);
329 }
330
331 static CFStringRef CopyComputerName(SCDynamicStoreRef store)
332 {
333 CFStringRef deviceName = SCDynamicStoreCopyComputerName(store, NULL);
334 if (deviceName == NULL) {
335 deviceName = CFSTR("Unknown name");
336 }
337 return deviceName;
338 }
339
340 static bool _EngineMessageProtocolV2Enabled(void)
341 {
342 #if DEBUG
343 //sudo rhr
344 static dispatch_once_t onceToken;
345 static bool v2_enabled = false;
346 dispatch_once(&onceToken, ^{
347 CFTypeRef v2Pref = (CFNumberRef)CFPreferencesCopyValue(CFSTR("engineV2"), CFSTR("com.apple.security"), kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
348
349 if (v2Pref && CFGetTypeID(v2Pref) == CFBooleanGetTypeID()) {
350 v2_enabled = CFBooleanGetValue((CFBooleanRef)v2Pref);
351 secinfo("server", "Engine v2 : %s", v2_enabled ? "enabled":"disabled");
352 }
353 CFReleaseSafe(v2Pref);
354 });
355
356 return v2_enabled;
357 #else
358 return false;
359 #endif
360 }
361
362
363 static CFDictionaryRef CreateDeviceGestaltDictionary(SCDynamicStoreRef store, CFArrayRef keys, void *context)
364 {
365 CFStringRef modelName = CopyModelName();
366 CFStringRef computerName = CopyComputerName(store);
367 CFStringRef osVersion = CopyOSVersion();
368
369 SInt32 version = _EngineMessageProtocolV2Enabled() ? kEngineMessageProtocolVersion : 0;
370 CFNumberRef protocolVersion = CFNumberCreate(0, kCFNumberSInt32Type, &version);
371
372 CFDictionaryRef gestalt = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
373 kPIUserDefinedDeviceNameKey, computerName,
374 kPIDeviceModelNameKey, modelName,
375 kPIMessageProtocolVersionKey, protocolVersion,
376 kPIOSVersionKey, osVersion,
377 NULL);
378 CFReleaseSafe(modelName);
379 CFReleaseSafe(computerName);
380 CFReleaseSafe(protocolVersion);
381
382 return gestalt;
383 }
384
385 static void SOSCCProcessGestaltUpdate(SCDynamicStoreRef store, CFArrayRef keys, void *context)
386 {
387 do_with_account(^(SOSAccountRef account) {
388 if(account){
389 CFDictionaryRef gestalt = CreateDeviceGestaltDictionary(store, keys, context);
390 if (SOSAccountUpdateGestalt(account, gestalt)) {
391 notify_post(kSOSCCCircleChangedNotification);
392 }
393 CFReleaseSafe(gestalt);
394 }
395 });
396 }
397
398
399 static CFDictionaryRef CreateDeviceGestaltDictionaryAndRegisterForUpdate(dispatch_queue_t queue, void *info)
400 {
401 SCDynamicStoreContext context = { .info = info };
402 SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("com.apple.securityd.cloudcircleserver"), SOSCCProcessGestaltUpdate, &context);
403 CFStringRef computerKey = SCDynamicStoreKeyCreateComputerName(NULL);
404 CFArrayRef keys = NULL;
405 CFDictionaryRef gestalt = NULL;
406
407 if (store == NULL || computerKey == NULL) {
408 goto done;
409 }
410 keys = CFArrayCreate(NULL, (const void **)&computerKey, 1, &kCFTypeArrayCallBacks);
411 if (keys == NULL) {
412 goto done;
413 }
414 gestalt = CreateDeviceGestaltDictionary(store, keys, info);
415 SCDynamicStoreSetNotificationKeys(store, keys, NULL);
416 SCDynamicStoreSetDispatchQueue(store, queue);
417
418 done:
419 if (store) CFRelease(store);
420 if (computerKey) CFRelease(computerKey);
421 if (keys) CFRelease(keys);
422 return gestalt;
423 }
424
425 static void do_with_account(void (^action)(SOSAccountRef account));
426 static void do_with_account_async(void (^action)(SOSAccountRef account));
427
428 static SOSAccountRef GetSharedAccount(void) {
429 static SOSAccountRef sSharedAccount = NULL;
430 static dispatch_once_t onceToken;
431
432 #if !(TARGET_OS_EMBEDDED)
433 if(geteuid() == 0){
434 secerror("Cannot inflate account object as root");
435 return NULL;
436 }
437 #endif
438
439 dispatch_once(&onceToken, ^{
440 secdebug("account", "Account Creation start");
441
442 CFDictionaryRef gestalt = CreateDeviceGestaltDictionaryAndRegisterForUpdate(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
443
444 if (!gestalt) {
445 #if TARGET_OS_IPHONE && TARGET_IPHONE_SIMULATOR
446 gestalt = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, NULL);
447 #else
448 secerror("Didn't get machine gestalt! This is going to be ugly.");
449 #endif
450 }
451
452 sSharedAccount = SOSKeychainAccountCreateSharedAccount(gestalt);
453
454 SOSAccountAddChangeBlock(sSharedAccount, ^(SOSCircleRef circle,
455 CFSetRef peer_additions, CFSetRef peer_removals,
456 CFSetRef applicant_additions, CFSetRef applicant_removals) {
457 CFErrorRef pi_error = NULL;
458 SOSPeerInfoRef me = SOSFullPeerInfoGetPeerInfo(sSharedAccount->my_identity);
459 if (!me) {
460 secerror("Error finding me for change: %@", pi_error);
461 } else {
462 // TODO: Figure out why peer_additions isn't right in some cases (like when joining a v2 circle with a v0 peer.
463 if (SOSCircleHasPeer(circle, me, NULL) /* && CFSetGetCount(peer_additions) != 0 */) {
464 secnotice("updates", "Requesting Ensure Peer Registration.");
465 SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
466 } else {
467 secinfo("updates", "Not requesting Ensure Peer Registration, since it's not needed");
468 }
469
470 if (CFSetContainsValue(peer_additions, me)) {
471 // TODO: Potentially remove from here and move this to the engine
472 // TODO: We also need to do this when our views change.
473 SOSCCSyncWithAllPeers();
474 }
475 }
476
477 CFReleaseNull(pi_error);
478
479 // TODO: We should notify the engine of these changes here
480 if (CFSetGetCount(peer_additions) != 0 ||
481 CFSetGetCount(peer_removals) != 0 ||
482 CFSetGetCount(applicant_additions) != 0 ||
483 CFSetGetCount(applicant_removals) != 0) {
484
485 if(CFSetGetCount(peer_removals) != 0)
486 {
487 CFErrorRef localError = NULL;
488 CFMutableArrayRef removed = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
489 CFSetForEach(peer_removals, ^(const void *value) {
490 CFArrayAppendValue(removed, value);
491 });
492 SOSAccountRemoveBackupPeers(sSharedAccount, removed, &localError);
493 if(localError)
494 secerror("Had trouble removing: %@, error: %@", removed, localError);
495 CFReleaseNull(localError);
496 CFReleaseNull(removed);
497 }
498 notify_post(kSOSCCCircleChangedNotification);
499 // This might be a bit chatty for now, but it will get things moving for clients.
500 notify_post(kSOSCCViewMembershipChangedNotification);
501
502 }
503 });
504
505 SOSCloudKeychainSetItemsChangedBlock(^CFArrayRef(CFDictionaryRef changes) {
506 CFRetainSafe(changes);
507 __block CFMutableArrayRef handledKeys = NULL;
508 do_with_account(^(SOSAccountRef account) {
509 CFStringRef changeDescription = SOSItemsChangedCopyDescription(changes, false);
510 secdebug(SOSCKCSCOPE, "Received: %@", changeDescription);
511 CFReleaseSafe(changeDescription);
512
513 CFErrorRef error = NULL;
514 handledKeys = SOSTransportDispatchMessages(account, changes, &error);
515 if (!handledKeys) {
516 secerror("Error handling updates: %@", error);
517 CFReleaseNull(error);
518 }
519 });
520 CFReleaseSafe(changes);
521 return handledKeys;
522 });
523 CFReleaseSafe(gestalt);
524
525 // TODO: We should not be doing extra work whenever securityd is launched, let's see if we can eliminate this call
526 SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
527 });
528
529
530 return sSharedAccount;
531 }
532
533 static void do_with_account_dynamic(void (^action)(SOSAccountRef account), bool sync) {
534 Boolean keyExistsAndHasValue = false;
535 whichTransportType = CFPreferencesGetAppIntegerValue(CFSTR("Transport"), CFSTR("com.apple.security"), &keyExistsAndHasValue);
536 SOSAccountRef account = GetSharedAccount();
537
538 if(account){
539 dispatch_block_t do_action_and_save = ^{
540 SOSPeerInfoRef mpi = SOSAccountGetMyPeerInfo(account);
541 bool wasInCircle = SOSAccountIsInCircle(account, NULL);
542 CFSetRef beforeViews = mpi ? SOSPeerInfoCopyEnabledViews(mpi) : NULL;
543
544 action(account);
545
546 // Fake transaction around using the account object
547 SOSAccountFinishTransaction(account);
548
549 mpi = SOSAccountGetMyPeerInfo(account); // Update the peer
550 bool isInCircle = SOSAccountIsInCircle(account, NULL);
551
552 CFSetRef afterViews = mpi ? SOSPeerInfoCopyEnabledViews(mpi) : NULL;
553
554 if(!CFEqualSafe(beforeViews, afterViews) || wasInCircle != isInCircle) {
555 notify_post(kSOSCCViewMembershipChangedNotification);
556 }
557
558 CFReleaseNull(beforeViews);
559 CFReleaseNull(afterViews);
560
561 SOSKeychainAccountEnsureSaved(account);
562 };
563
564 if (sync) {
565 dispatch_sync(SOSAccountGetQueue(account), do_action_and_save);
566 } else {
567 dispatch_async(SOSAccountGetQueue(account), do_action_and_save);
568 }
569 }
570 }
571
572 __unused static void do_with_account_async(void (^action)(SOSAccountRef account)) {
573 do_with_account_dynamic(action, false);
574 }
575
576 static void do_with_account(void (^action)(SOSAccountRef account)) {
577 do_with_account_dynamic(action, true);
578 }
579
580 static bool do_if_after_first_unlock(CFErrorRef *error, dispatch_block_t action)
581 {
582 #if TARGET_IPHONE_SIMULATOR
583 action();
584 return true;
585 #else
586 bool beenUnlocked = false;
587 require_quiet(SecAKSGetHasBeenUnlocked(&beenUnlocked, error), fail);
588
589 require_action_quiet(beenUnlocked, fail,
590 SOSCreateErrorWithFormat(kSOSErrorNotReady, NULL, error, NULL,
591 CFSTR("Keybag never unlocked, ask after first unlock")));
592
593 action();
594 return true;
595
596 fail:
597 return false;
598 #endif
599 }
600
601 static bool do_with_account_if_after_first_unlock(CFErrorRef *error, bool (^action)(SOSAccountRef account, CFErrorRef* error))
602 {
603 __block bool action_result = false;
604
605 #if !(TARGET_OS_EMBEDDED)
606 if(geteuid() == 0){
607 secerror("Cannot inflate account object as root");
608 if(error)
609 *error = CFErrorCreate(kCFAllocatorDefault, CFSTR("com.apple.security"), RUN_AS_ROOT_ERROR, NULL);
610 return false;
611 }
612 #endif
613 return do_if_after_first_unlock(error, ^{
614 do_with_account(^(SOSAccountRef account) {
615 action_result = action(account, error);
616 });
617
618 }) && action_result;
619 }
620
621 static bool do_with_account_while_unlocked(CFErrorRef *error, bool (^action)(SOSAccountRef account, CFErrorRef* error))
622 {
623 __block bool action_result = false;
624
625 #if !(TARGET_OS_EMBEDDED)
626 if(geteuid() == 0){
627 secerror("Cannot inflate account object as root");
628 if(error)
629 *error = CFErrorCreate(kCFAllocatorDefault, CFSTR("com.apple.security"), RUN_AS_ROOT_ERROR, NULL);
630 return false;
631 }
632 #endif
633
634 return SecAKSDoWhileUserBagLocked(error, ^{
635 do_with_account(^(SOSAccountRef account) {
636 action_result = action(account, error);
637 });
638
639 }) && action_result;
640 }
641
642 SOSAccountRef SOSKeychainAccountGetSharedAccount()
643 {
644 __block SOSAccountRef result = NULL;
645
646 do_with_account(^(SOSAccountRef account) {
647 result = account;
648 });
649
650 return result;
651 }
652
653 //
654 // Mark: Credential processing
655 //
656
657
658 bool SOSCCTryUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFErrorRef *error)
659 {
660 return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
661 return SOSAccountTryUserCredentials(account, user_label, user_password, block_error);
662 });
663 }
664
665
666 SOSViewResultCode SOSCCView_Server(CFStringRef viewname, SOSViewActionCode action, CFErrorRef *error) {
667 __block SOSViewResultCode status = kSOSCCGeneralViewError;
668
669 do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
670 switch(action) {
671 case kSOSCCViewQuery:
672 status = SOSAccountViewStatus(account, viewname, error);
673 break;
674 case kSOSCCViewEnable:
675 case kSOSCCViewDisable: // fallthrough
676 status = SOSAccountUpdateView(account, viewname, action, error);
677 secnotice("views", "HEY!!!!!! I'm Changing VIEWS- %d", (int) status);
678 break;
679 default:
680 secnotice("views", "Bad SOSViewActionCode - %d", (int) action);
681 return false;
682 break;
683 }
684 return true;
685 });
686 return status;
687 }
688
689
690 bool SOSCCViewSet_Server(CFSetRef enabledViews, CFSetRef disabledViews) {
691 __block bool status = false;
692
693 do_with_account_if_after_first_unlock(NULL, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
694 status = SOSAccountUpdateViewSets(account, enabledViews, disabledViews);
695 return true;
696 });
697 return status;
698 }
699
700
701
702 SOSSecurityPropertyResultCode SOSCCSecurityProperty_Server(CFStringRef property, SOSSecurityPropertyActionCode action, CFErrorRef *error) {
703
704 __block SOSViewResultCode status = kSOSCCGeneralSecurityPropertyError;
705 do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
706 switch(action) {
707 case kSOSCCSecurityPropertyQuery:
708 status = SOSAccountSecurityPropertyStatus(account, property, error);
709 break;
710 case kSOSCCSecurityPropertyEnable:
711 case kSOSCCSecurityPropertyDisable: // fallthrough
712 status = SOSAccountUpdateSecurityProperty(account, property, action, error);
713 secnotice("secprop", "HEY!!!!!! I'm Changing SecurityProperties- %d", (int) status);
714 break;
715 default:
716 secnotice("secprop", "Bad SOSSecurityPropertyActionCode - %d", (int) action);
717 return false;
718 break;
719 }
720 return true;
721 });
722 return status;
723 }
724
725 void sync_the_last_data_to_kvs(SOSAccountRef account, bool waitForeverForSynchronization){
726
727 dispatch_semaphore_t wait_for = dispatch_semaphore_create(0);
728 dispatch_retain(wait_for); // Both this scope and the block own it.
729
730 __block bool success = false;
731
732 secnoticeq("force-push", "calling SOSCloudKeychainSynchronizeAndWait");
733
734 CFMutableArrayRef keysToGet = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
735
736 SOSCloudKeychainSynchronizeAndWait(keysToGet, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) {
737
738 if (sync_error) {
739 secerrorq("SOSCloudKeychainSynchronizeAndWait: %@", sync_error);
740 } else {
741 secnoticeq("force-push", "returned from call; in callback to SOSCloudKeychainSynchronizeAndWait: results: %@", returnedValues);
742
743 success = true;
744 }
745
746 dispatch_semaphore_signal(wait_for);
747 dispatch_release(wait_for);
748 });
749
750 CFReleaseNull(keysToGet);
751
752 if(waitForeverForSynchronization)
753 dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER);
754 else
755 dispatch_semaphore_wait(wait_for, dispatch_time(DISPATCH_TIME_NOW, 60ull * NSEC_PER_SEC));
756
757 dispatch_release(wait_for);
758 }
759
760 #define kWAIT2MINID "EFRESH"
761
762 static bool EnsureFreshParameters(SOSAccountRef account, CFErrorRef *error) {
763 dispatch_semaphore_t wait_for = dispatch_semaphore_create(0);
764 dispatch_retain(wait_for); // Both this scope and the block own it.
765
766 CFMutableArrayRef keysToGet = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
767 CFArrayAppendValue(keysToGet, kSOSKVSKeyParametersKey);
768 // Only get key parameters due to: <rdar://problem/22794892> Upgrading from Donner with an iCDP enabled account resets iCloud keychain on devices in circle
769
770 __block CFDictionaryRef valuesToUpdate = NULL;
771 __block bool success = false;
772
773 secnoticeq("fresh", "%s calling SOSCloudKeychainSynchronizeAndWait", kWAIT2MINID);
774
775 SOSCloudKeychainSynchronizeAndWait(keysToGet, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) {
776
777 if (sync_error) {
778 secerrorq("%s SOSCloudKeychainSynchronizeAndWait: %@", kWAIT2MINID, sync_error);
779 if (error) {
780 *error = sync_error;
781 CFRetainSafe(*error);
782 }
783 } else {
784 secnoticeq("fresh", "%s returned from call; in callback to SOSCloudKeychainSynchronizeAndWait: results: %@", kWAIT2MINID, returnedValues);
785 valuesToUpdate = returnedValues;
786 CFRetainSafe(valuesToUpdate);
787 success = true;
788 }
789
790 dispatch_semaphore_signal(wait_for);
791 dispatch_release(wait_for);
792 });
793
794 dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER);
795 // TODO: Maybe we timeout here... used to dispatch_time(DISPATCH_TIME_NOW, 30ull * NSEC_PER_SEC));
796 dispatch_release(wait_for);
797 CFMutableArrayRef handledKeys = NULL;
798 if ((valuesToUpdate) && (account)) {
799 handledKeys = SOSTransportDispatchMessages(account, valuesToUpdate, error);
800 if (!handledKeys) {
801 secerrorq("%s Freshness update failed: %@", kWAIT2MINID, error ? *error : NULL);
802 success = false;
803 }
804 }
805 CFReleaseNull(handledKeys);
806 CFReleaseNull(valuesToUpdate);
807 CFReleaseNull(keysToGet);
808
809 return success;
810 }
811
812 static bool Flush(CFErrorRef *error) {
813 __block bool success = false;
814
815 dispatch_semaphore_t wait_for = dispatch_semaphore_create(0);
816 dispatch_retain(wait_for); // Both this scope and the block own it.
817
818 secnotice("flush", "Starting");
819
820 SOSCloudKeychainFlush(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) {
821 success = (sync_error == NULL);
822 if (error) {
823 CFRetainAssign(*error, sync_error);
824 }
825
826 dispatch_semaphore_signal(wait_for);
827 dispatch_release(wait_for);
828 });
829
830 dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER);
831 dispatch_release(wait_for);
832
833 secnotice("flush", "Returned %s", success? "Success": "Failure");
834
835 return success;
836 }
837
838 static bool SOSCCAssertUserCredentialsAndOptionalDSID(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error) {
839 secnotice("updates", "Setting credentials and dsid (%@) for %@", dsid, user_label);
840 bool result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
841 if (dsid != NULL && CFStringCompare(dsid, CFSTR(""), 0) != 0) {
842 CFStringRef accountDSID = SOSAccountGetValue(account, kSOSDSIDKey, NULL);
843 if( accountDSID == NULL){
844 SOSAccountUpdateDSID(account, dsid);
845 secdebug("updates", "Setting dsid, current dsid is empty for this account: %@", dsid);
846 }
847 else if(CFStringCompare(dsid, accountDSID, 0) != kCFCompareEqualTo){
848 secnotice("updates", "Changing DSID from: %@ to %@", accountDSID, dsid);
849
850 //DSID has changed, blast the account!
851 SOSAccountSetToNew(account);
852
853 //update DSID to the new DSID
854 SOSAccountUpdateDSID(account, dsid);
855 }
856 else {
857 secnotice("updates", "Not Changing DSID: %@ to %@", accountDSID, dsid);
858 }
859
860 }
861
862 // Short Circuit if this passes, return immediately.
863 if(SOSAccountTryUserCredentials(account, user_label, user_password, NULL)) {
864 return true;
865 }
866
867 if (!EnsureFreshParameters(account, block_error)) {
868 return false;
869 }
870 if (!SOSAccountAssertUserCredentials(account, user_label, user_password, block_error)) {
871 secnotice("updates", "EnsureFreshParameters/SOSAccountAssertUserCredentials error: %@", *block_error);
872 return false;
873 }
874 return true;
875 });
876
877 if (result && Flush(error)) {
878 result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
879 return SOSAccountGenerationSignatureUpdate(account, error);
880 });
881 }
882
883 return result;
884 }
885
886 bool SOSCCSetUserCredentialsAndDSID_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error)
887 {
888 // TODO: Return error if DSID is NULL to insist our callers provide one?
889 return SOSCCAssertUserCredentialsAndOptionalDSID(user_label, user_password, dsid, error);
890 }
891
892 bool SOSCCSetUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFErrorRef *error)
893 {
894 return SOSCCAssertUserCredentialsAndOptionalDSID(user_label, user_password, NULL, error);
895 }
896
897 bool SOSCCCanAuthenticate_Server(CFErrorRef *error)
898 {
899 bool result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
900 return SOSAccountGetPrivateCredential(account, block_error) != NULL;
901 });
902
903 if (!result && error && *error && CFErrorGetDomain(*error) == kSOSErrorDomain) {
904 CFIndex code = CFErrorGetCode(*error);
905 if (code == kSOSErrorPrivateKeyAbsent || code == kSOSErrorPublicKeyAbsent) {
906 CFReleaseNull(*error);
907 }
908 }
909
910 return result;
911 }
912
913 bool SOSCCPurgeUserCredentials_Server(CFErrorRef *error)
914 {
915 return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
916 SOSAccountPurgePrivateCredential(account);
917 return true;
918 });
919 }
920
921 SOSCCStatus SOSCCThisDeviceIsInCircle_Server(CFErrorRef *error)
922 {
923 __block SOSCCStatus status;
924
925 return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
926 status = SOSAccountGetCircleStatus(account, block_error);
927 return true;
928 }) ? status : kSOSCCError;
929 }
930
931 bool SOSCCRequestToJoinCircle_Server(CFErrorRef* error)
932 {
933 __block bool result = true;
934
935 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
936 result = SOSAccountJoinCircles(account, block_error);
937 return result;
938 });
939 }
940
941 bool SOSCCRequestToJoinCircleAfterRestore_Server(CFErrorRef* error)
942 {
943 __block bool result = true;
944 bool returned = false;
945 returned = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
946 SOSAccountEnsurePeerRegistration(account, block_error);
947 result = SOSAccountJoinCirclesAfterRestore(account, block_error);
948 return result;
949 });
950 return returned;
951
952 }
953
954 bool SOSCCRequestEnsureFreshParameters_Server(CFErrorRef* error)
955 {
956 __block bool result = true;
957 bool returned = false;
958 returned = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
959 result = EnsureFreshParameters(account, NULL);
960 return result;
961 });
962 return returned;
963 }
964
965 bool SOSCCApplyToARing_Server(CFStringRef ringName, CFErrorRef *error){
966 __block bool result = true;
967 bool returned = false;
968 returned = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
969 SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInfo(account);
970 SOSRingRef ring = SOSAccountGetRing(account, ringName, error);
971 if(fpi && ring)
972 result = SOSRingApply(ring, account->user_public, fpi , error);
973 return result;
974 });
975 return returned;
976 }
977
978 bool SOSCCWithdrawlFromARing_Server(CFStringRef ringName, CFErrorRef *error){
979 __block bool result = true;
980 bool returned = false;
981 returned = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
982 SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInfo(account);
983 SOSRingRef ring = SOSAccountGetRing(account, ringName, error);
984 if(fpi && ring)
985 result = SOSRingWithdraw(ring, account->user_public, fpi , error);
986 return result;
987 });
988 return returned;
989 }
990
991 bool SOSCCEnableRing_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, CFErrorRef* block_error) {
995 SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInfo(account);
996 SOSRingRef ring = SOSAccountGetRing(account, ringName, error);
997 if(fpi && ring)
998 result = SOSRingResetToOffering(ring, NULL, fpi, error); ;
999 return result;
1000 });
1001 return returned;
1002 }
1003
1004 CFStringRef SOSCCGetAllTheRings_Server(CFErrorRef *error){
1005 __block CFMutableDictionaryRef result = NULL;
1006 __block CFMutableStringRef description = CFStringCreateMutable(kCFAllocatorDefault, 0);
1007
1008 (void) do_with_account_while_unlocked(error, ^bool(SOSAccountRef account, CFErrorRef *error) {
1009 result = SOSAccountGetRings(account, error);
1010
1011 if(isDictionary(result)){
1012 CFDictionaryForEach(result, ^(const void *key, const void *value) {
1013 CFStringAppendFormat(description, NULL, CFSTR("%@"), value);
1014 });
1015 }
1016 if(result)
1017 return true;
1018 return false;
1019 });
1020
1021 return description;
1022 }
1023
1024 SOSRingStatus SOSCCRingStatus_Server(CFStringRef ringName, CFErrorRef *error){
1025 __block bool result = true;
1026 SOSRingStatus returned;
1027 returned = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1028 SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInfo(account);
1029 SOSPeerInfoRef myPeer = SOSFullPeerInfoGetPeerInfo(fpi);
1030
1031 SOSRingRef ring = SOSAccountGetRing(account, ringName, error);
1032 if(myPeer && ring)
1033 result = SOSRingDeviceIsInRing(ring, SOSPeerInfoGetPeerID(myPeer));
1034 return result;
1035 });
1036 return returned;
1037 }
1038
1039 CFStringRef SOSCCCopyDeviceID_Server(CFErrorRef *error)
1040 {
1041 __block CFStringRef result = NULL;
1042
1043 (void) do_with_account_while_unlocked(error, ^bool(SOSAccountRef account, CFErrorRef *error) {
1044 result = SOSAccountCopyDeviceID(account, error);
1045 return (!isNull(result));
1046 });
1047 return result;
1048 }
1049
1050 bool SOSCCSetDeviceID_Server(CFStringRef IDS, CFErrorRef *error){
1051
1052 bool didSetID = false;
1053 __block bool result = false;
1054 __block CFErrorRef blockError = NULL;
1055
1056 didSetID = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1057 result = SOSAccountSetMyDSID(account, IDS, block_error);
1058 if(block_error)
1059 blockError = CFRetainSafe(*block_error);
1060 return result;
1061 });
1062
1063 if(error){
1064 *error = blockError;
1065 }
1066 return didSetID;
1067 }
1068
1069 HandleIDSMessageReason SOSCCHandleIDSMessage_Server(CFDictionaryRef messageDict, CFErrorRef* error)
1070 {
1071 // TODO: Locking flow:
1072 /*
1073 COMMON:
1074 - Get PeerCoder instance from SOSPeerCoderManager(Currently Engine)
1075 - Get Account lock and Initialize PeerCoder instance if it isn't valid yet.
1076 INCOMING:
1077 - Decode incoming msg on coder.
1078 - Pass msg along to SOSPeerRef if decoding is done.
1079 - Force reply from coder while in handshake mode. (or ask ckd to ask us later?)
1080 - save coder state.
1081
1082 - Lookup SOSPeerRef in SOSEngineRef (getting engine lock temporarily to get peer.
1083 - Ask peer to handle decoded message
1084 - be notified of changed objects in all peers and update peer/engine states
1085 - save peer/engine state
1086
1087 OUTGOING:
1088 - Ask coder to send an outgoing message if it is negotiating
1089 - Ask peer to create a message if needed
1090 - Encode peer msg with coder
1091 - save coder state
1092 - send reply to ckd for transporting
1093 */
1094
1095 __block HandleIDSMessageReason result = kHandleIDSMessageSuccess;
1096 CFErrorRef action_error = NULL;
1097
1098 if (!do_with_account_while_unlocked(&action_error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1099 result = SOSTransportMessageIDSHandleMessage(account, messageDict, error);
1100 return result;
1101 })) {
1102 if (action_error) {
1103 if (SecErrorGetOSStatus(action_error) == errSecInteractionNotAllowed) {
1104 secnotice("updates", "SOSCCHandleIDSMessage_Server failed because device is locked; letting IDSKeychainSyncingProxy know");
1105 result = kHandleIDSMessageLocked; // tell IDSKeychainSyncingProxy to call us back when device unlocks
1106 CFReleaseNull(action_error);
1107 } else {
1108 secerror("Unexpected error: %@", action_error);
1109 }
1110
1111 if (error && *error == NULL) {
1112 *error = action_error;
1113 action_error = NULL;
1114 }
1115
1116 CFReleaseNull(action_error);
1117 }
1118 }
1119 return result;
1120 }
1121
1122 bool SOSCCIDSPingTest_Server(CFStringRef message, CFErrorRef *error){
1123 bool didSendTestMessages = false;
1124 __block bool result = true;
1125 __block CFErrorRef blockError = NULL;
1126
1127 didSendTestMessages = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1128 result = SOSAccountStartPingTest(account, message, block_error);
1129 if(block_error)
1130 blockError = CFRetainSafe(*block_error);
1131 return result;
1132 });
1133 if(blockError && error != NULL)
1134 *error = blockError;
1135
1136 return didSendTestMessages;
1137 }
1138
1139 bool SOSCCIDSServiceRegistrationTest_Server(CFStringRef message, CFErrorRef *error){
1140 bool didSendTestMessages = false;
1141 __block bool result = true;
1142 __block CFErrorRef blockError = NULL;
1143
1144 didSendTestMessages = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1145 result = SOSAccountSendIDSTestMessage(account, message, &blockError);
1146 return result;
1147 });
1148 if(blockError != NULL && error != NULL)
1149 *error = blockError;
1150
1151 return didSendTestMessages;
1152 }
1153
1154 bool SOSCCIDSDeviceIDIsAvailableTest_Server(CFErrorRef *error){
1155 bool didSendTestMessages = false;
1156 __block bool result = true;
1157 __block CFErrorRef blockError = NULL;
1158
1159 didSendTestMessages = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1160 result = SOSAccountRetrieveDeviceIDFromIDSKeychainSyncingProxy(account, &blockError);
1161 return result;
1162 });
1163 if(blockError && error != NULL)
1164 *error = blockError;
1165
1166 return didSendTestMessages;
1167 }
1168
1169 bool SOSCCAccountSetToNew_Server(CFErrorRef *error)
1170 {
1171 __block bool result = true;
1172
1173 return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1174 clearAllKVS(NULL);
1175 SOSAccountSetToNew(account);
1176 return result;
1177 });
1178 }
1179
1180 bool SOSCCResetToOffering_Server(CFErrorRef* error)
1181 {
1182 __block bool result = true;
1183
1184 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1185 clearAllKVS(NULL);
1186 result = SOSAccountResetToOffering(account, block_error);
1187 return result;
1188 });
1189
1190 }
1191
1192 bool SOSCCResetToEmpty_Server(CFErrorRef* error)
1193 {
1194 __block bool result = true;
1195
1196 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1197 result = SOSAccountResetToEmpty(account, block_error);
1198 return result;
1199 });
1200
1201 }
1202
1203 bool SOSCCRemoveThisDeviceFromCircle_Server(CFErrorRef* error)
1204 {
1205 __block bool result = true;
1206
1207 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1208 result = SOSAccountLeaveCircle(account, block_error);
1209 return result;
1210 });
1211 }
1212
1213 bool SOSCCRemovePeersFromCircle_Server(CFArrayRef peers, CFErrorRef* error)
1214 {
1215 __block bool result = true;
1216
1217 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1218 result = SOSAccountRemovePeersFromCircle(account, peers, block_error);
1219 return result;
1220 });
1221 }
1222
1223
1224 bool SOSCCLoggedOutOfAccount_Server(CFErrorRef *error)
1225 {
1226 __block bool result = true;
1227
1228 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1229 secnotice("sosops", "Signed out of account!");
1230
1231 bool waitForeverForSynchronization = true;
1232
1233 result = SOSAccountLeaveCircle(account, block_error);
1234
1235 SOSAccountFinishTransaction(account); // Make sure this gets finished before we set to new.
1236
1237 SOSAccountSetToNew(account);
1238
1239 sync_the_last_data_to_kvs(account, waitForeverForSynchronization);
1240
1241 return result;
1242 });
1243 }
1244
1245 bool SOSCCBailFromCircle_Server(uint64_t limit_in_seconds, CFErrorRef* error)
1246 {
1247 __block bool result = true;
1248
1249 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1250 bool waitForeverForSynchronization = false;
1251
1252 result = SOSAccountBail(account, limit_in_seconds, block_error);
1253
1254 SOSAccountFinishTransaction(account); // Make sure this gets finished before we set to new.
1255
1256 sync_the_last_data_to_kvs(account, waitForeverForSynchronization);
1257
1258 return result;
1259 });
1260
1261 }
1262
1263 CFArrayRef SOSCCCopyApplicantPeerInfo_Server(CFErrorRef* error)
1264 {
1265 __block CFArrayRef result = NULL;
1266
1267 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1268 result = SOSAccountCopyApplicants(account, block_error);
1269 return result != NULL;
1270 });
1271
1272 return result;
1273 }
1274
1275 CFArrayRef SOSCCCopyGenerationPeerInfo_Server(CFErrorRef* error)
1276 {
1277 __block CFArrayRef result = NULL;
1278
1279 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1280 result = SOSAccountCopyGeneration(account, block_error);
1281 return result != NULL;
1282 });
1283
1284 return result;
1285 }
1286
1287 CFArrayRef SOSCCCopyValidPeerPeerInfo_Server(CFErrorRef* error)
1288 {
1289 __block CFArrayRef result = NULL;
1290
1291 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1292 result = SOSAccountCopyValidPeers(account, block_error);
1293 return result != NULL;
1294 });
1295
1296 return result;
1297 }
1298
1299 bool SOSCCValidateUserPublic_Server(CFErrorRef* error)
1300 {
1301 __block bool result = NULL;
1302
1303 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1304 result = SOSValidateUserPublic(account, block_error);
1305 return result;
1306 });
1307
1308 return result;
1309 }
1310
1311 CFArrayRef SOSCCCopyNotValidPeerPeerInfo_Server(CFErrorRef* error)
1312 {
1313 __block CFArrayRef result = NULL;
1314
1315 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1316 result = SOSAccountCopyNotValidPeers(account, block_error);
1317 return result != NULL;
1318 });
1319
1320 return result;
1321 }
1322
1323 CFArrayRef SOSCCCopyRetirementPeerInfo_Server(CFErrorRef* error)
1324 {
1325 __block CFArrayRef result = NULL;
1326
1327 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1328 result = SOSAccountCopyRetired(account, block_error);
1329 return result != NULL;
1330 });
1331
1332 return result;
1333 }
1334
1335 CFArrayRef SOSCCCopyViewUnawarePeerInfo_Server(CFErrorRef* error)
1336 {
1337 __block CFArrayRef result = NULL;
1338
1339 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1340 result = SOSAccountCopyViewUnaware(account, block_error);
1341 return result != NULL;
1342 });
1343
1344 return result;
1345 }
1346
1347 CFArrayRef SOSCCCopyEngineState_Server(CFErrorRef* error)
1348 {
1349 CFArrayRef result = NULL;
1350 SOSDataSourceFactoryRef dsf = SecItemDataSourceFactoryGetDefault();
1351 SOSDataSourceRef ds = SOSDataSourceFactoryCreateDataSource(dsf, kSecAttrAccessibleWhenUnlocked, error);
1352 if (ds) {
1353 SOSEngineRef engine = SOSDataSourceGetSharedEngine(ds, error);
1354 result = SOSEngineCopyPeerConfirmedDigests(engine, error);
1355 SOSDataSourceRelease(ds, error);
1356 }
1357
1358 return result;
1359 }
1360
1361 static CFStringRef CreateUUIDString() {
1362 CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
1363 CFStringRef result = CFUUIDCreateString(kCFAllocatorDefault, uuid);
1364 CFReleaseNull(uuid);
1365 return result;
1366 }
1367
1368 static CFStringRef SOSAccountCallWhenInSync(SOSAccountRef account, SOSAccountWaitForInitialSyncBlock syncBlock) {
1369 //if we are not initially synced
1370 CFStringRef id = NULL;
1371 CFTypeRef unSyncedViews = SOSAccountGetValue(account, kSOSUnsyncedViewsKey, NULL);
1372 if (unSyncedViews != NULL) {
1373 id = CreateUUIDString();
1374 secnotice("initial-sync", "adding sync block [%@] to array!", id);
1375 SOSAccountWaitForInitialSyncBlock copy = Block_copy(syncBlock);
1376 CFDictionarySetValue(account->waitForInitialSync_blocks, id, copy);
1377 Block_release(copy);
1378 } else {
1379 syncBlock(account);
1380 }
1381
1382 return id;
1383 }
1384
1385 static bool SOSAccountUnregisterCallWhenInSync(SOSAccountRef account, CFStringRef id) {
1386 bool removed = CFDictionaryGetValueIfPresent(account->waitForInitialSync_blocks, id, NULL);
1387 CFDictionaryRemoveValue(account->waitForInitialSync_blocks, id);
1388 return removed;
1389 }
1390
1391 bool SOSCCWaitForInitialSync_Server(CFErrorRef* error) {
1392
1393 __block dispatch_semaphore_t inSyncSema = NULL;
1394 __block bool result = false;
1395 __block bool synced = false;
1396 bool timed_out = false;
1397
1398 __block CFStringRef inSyncCallID = NULL;
1399
1400 secnotice("initial sync", "Wait for initial sync start!");
1401
1402 result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1403 bool alreadyInSync = SOSAccountCheckHasBeenInSync(account);
1404
1405 if (!alreadyInSync) {
1406 inSyncSema = dispatch_semaphore_create(0);
1407 dispatch_retain(inSyncSema); // For the block
1408
1409 inSyncCallID = SOSAccountCallWhenInSync(account, ^bool(SOSAccountRef mightBeSynced) {
1410 secerror("might be synced!");
1411 synced = SOSAccountCheckHasBeenInSync(mightBeSynced);
1412
1413 dispatch_semaphore_signal(inSyncSema);
1414 dispatch_release(inSyncSema);
1415 SOSAccountEnsureBackupStarts(account);
1416 return true;
1417 });
1418 }
1419 else{
1420 SOSAccountEnsureBackupStarts(account);
1421 synced = true;
1422 }
1423 return true;
1424 });
1425
1426 require_quiet(result, fail);
1427 if(inSyncSema){
1428 timed_out = dispatch_semaphore_wait(inSyncSema, dispatch_time(DISPATCH_TIME_NOW, 300ull * NSEC_PER_SEC));
1429 }
1430 if (timed_out) {
1431 do_with_account(^(SOSAccountRef account) {
1432 if (SOSAccountUnregisterCallWhenInSync(account, inSyncCallID)) {
1433 dispatch_release(inSyncSema); // if we unregistered we release the sema
1434 }
1435 });
1436
1437 if (!synced) {
1438 secerror("waiting for initial sync timed out, resetting account");
1439 result = false;
1440
1441 SOSCCLoggedOutOfAccount_Server(error);
1442 SOSErrorCreate(kSOSInitialSyncFailed, error, NULL, CFSTR("InitialSyncTimedOut"));
1443 }
1444 }
1445 if(inSyncSema)
1446 dispatch_release(inSyncSema);
1447 inSyncSema = NULL; // We've canceled the timeout so we must be the last.
1448
1449 require_quiet(result, fail);
1450
1451
1452 xpc_transaction_begin();
1453
1454 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
1455 result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1456 result = SOSAccountIsInCircle(account, NULL);
1457 xpc_transaction_end();
1458 return result;
1459 });
1460 });
1461
1462 if (!synced) {
1463 secerror("waiting for initial sync: left circle");
1464 result = false;
1465
1466 SOSErrorCreate(kSOSInitialSyncFailed, error, NULL, CFSTR("Left circle before initial sync."));
1467 }
1468
1469 secnotice("initial sync", "Finished!: %d", result);
1470 fail:
1471 CFReleaseNull(inSyncCallID);
1472 return result;
1473 }
1474
1475
1476 static CFArrayRef SOSAccountCopyYetToSyncViews(SOSAccountRef account, CFErrorRef *error) {
1477 __block CFArrayRef result = NULL;
1478
1479 CFTypeRef valueFetched = SOSAccountGetValue(account, kSOSUnsyncedViewsKey, error);
1480 if (valueFetched == kCFBooleanTrue) {
1481 SOSPeerInfoRef myPI = SOSAccountGetMyPeerInfo(account);
1482 if (myPI) {
1483 SOSPeerInfoWithEnabledViewSet(myPI, ^(CFSetRef enabled) {
1484 result = CFSetCopyValues(enabled);
1485 });
1486 }
1487 } else if (isSet(valueFetched)) {
1488 result = CFSetCopyValues((CFSetRef)valueFetched);
1489 }
1490
1491 if (result == NULL) {
1492 result = CFArrayCreateForCFTypes(kCFAllocatorDefault, NULL);
1493 }
1494
1495 return result;
1496 }
1497
1498 CFArrayRef SOSCCCopyYetToSyncViewsList_Server(CFErrorRef* error) {
1499
1500 __block CFArrayRef views = NULL;
1501
1502 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1503 views = SOSAccountCopyYetToSyncViews(account, error);
1504
1505 return true;
1506 });
1507
1508 return views;
1509 }
1510
1511 bool SOSWrapToBackupSliceKeyBagForView_Server(CFStringRef viewName, CFDataRef input, CFDataRef* output, CFDataRef* bskbEncoded, CFErrorRef* error) {
1512 CFErrorRef localerror = NULL;
1513 SOSBackupSliceKeyBagRef bskb = SOSBackupSliceKeyBagForView(viewName, &localerror);
1514
1515 if(bskbEncoded && bskb) {
1516 *bskbEncoded = SOSBSKBCopyEncoded(bskb, &localerror);
1517 }
1518
1519 if(output) {
1520 *output = SOSWrapToBackupSliceKeyBag(bskb, input, &localerror);
1521 }
1522
1523 if(error) {
1524 *error = localerror;
1525 }
1526 return localerror == NULL;
1527 }
1528
1529 SOSBackupSliceKeyBagRef SOSBackupSliceKeyBagForView(CFStringRef viewName, CFErrorRef* error){
1530 __block SOSBackupSliceKeyBagRef bskb = NULL;
1531 (void) do_with_account(^ (SOSAccountRef account) {
1532 bskb = SOSAccountBackupSliceKeyBagForView(account, viewName, error);
1533 });
1534 return bskb;
1535 }
1536
1537 CFDataRef SOSWrapToBackupSliceKeyBag(SOSBackupSliceKeyBagRef bskb, CFDataRef input, CFErrorRef* error) {
1538 CFDataRef encrypted = NULL;
1539 bskb_keybag_handle_t bskb_handle = 0;
1540
1541 require_quiet(bskb, exit);
1542
1543 bskb_handle = SOSBSKBLoadLocked(bskb, error);
1544 require_quiet(bskb_handle, exit);
1545
1546 SecAccessControlRef access = NULL;
1547 require_quiet(access = SecAccessControlCreate(kCFAllocatorDefault, error), exit);
1548 require_quiet(SecAccessControlSetProtection(access, kSecAttrAccessibleWhenUnlocked, error), exit);
1549
1550 // ks_encrypt_data takes a dictionary as its plaintext.
1551 CFMutableDictionaryRef plaintext = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1552 CFDictionarySetValue(plaintext, CFSTR("data"), input);
1553
1554 require_quiet(ks_encrypt_data(bskb_handle, access, NULL, plaintext, NULL, &encrypted, error), exit);
1555
1556 exit:
1557 CFReleaseNull(bskb);
1558 if(bskb_handle != 0) {
1559 ks_close_keybag(bskb_handle, error);
1560 }
1561 if(error && *error) {
1562 secnotice("backup", "Failed to wrap to a BKSB: %@", *error);
1563 }
1564 return encrypted;
1565
1566 }
1567
1568 CFDictionaryRef SOSCCCopyEscrowRecord_Server(CFErrorRef *error){
1569
1570 __block CFDictionaryRef result = NULL;
1571 __block CFErrorRef block_error = NULL;
1572
1573 (void) do_with_account_if_after_first_unlock(error, ^bool(SOSAccountRef account, CFErrorRef *error) {
1574 SOSCCStatus status = SOSAccountGetCircleStatus(account, &block_error);
1575 CFStringRef dsid = SOSAccountGetValue(account, kSOSDSIDKey, error);
1576 CFDictionaryRef escrowRecords = NULL;
1577 CFDictionaryRef record = NULL;
1578 switch(status) {
1579 case kSOSCCInCircle:
1580 //get the escrow record in the peer info!
1581 escrowRecords = SOSPeerInfoCopyEscrowRecord(SOSAccountGetMyPeerInfo(account));
1582 if(escrowRecords){
1583 record = CFDictionaryGetValue(escrowRecords, dsid);
1584 if(record)
1585 result = CFRetainSafe(record);
1586 }
1587 CFReleaseNull(escrowRecords);
1588 break;
1589 case kSOSCCRequestPending:
1590 //set the escrow record in the peer info/application?
1591 break;
1592 case kSOSCCNotInCircle:
1593 case kSOSCCCircleAbsent:
1594 //set the escrow record in the account expansion!
1595 escrowRecords = SOSAccountGetValue(account, kSOSEscrowRecord, error);
1596 if(escrowRecords){
1597 record = CFDictionaryGetValue(escrowRecords, dsid);
1598 if(record)
1599 result = CFRetainSafe(record);
1600 }
1601 break;
1602 default:
1603 secdebug("account", "no circle status!");
1604 break;
1605 }
1606 return true;
1607 });
1608
1609 return result;
1610 }
1611
1612 bool SOSCCSetEscrowRecord_Server(CFStringRef escrow_label, uint64_t tries, CFErrorRef *error){
1613
1614 __block bool result = true;
1615 __block CFErrorRef block_error = NULL;
1616
1617 (void) do_with_account_if_after_first_unlock(error, ^bool(SOSAccountRef account, CFErrorRef *error) {
1618 SOSCCStatus status = SOSAccountGetCircleStatus(account, &block_error);
1619 CFStringRef dsid = SOSAccountGetValue(account, kSOSDSIDKey, error);
1620
1621 CFMutableStringRef timeDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("["));
1622 CFAbsoluteTime currentTimeAndDate = CFAbsoluteTimeGetCurrent();
1623
1624 withStringOfAbsoluteTime(currentTimeAndDate, ^(CFStringRef decription) {
1625 CFStringAppend(timeDescription, decription);
1626 });
1627 CFStringAppend(timeDescription, CFSTR("]"));
1628
1629 CFNumberRef attempts = CFNumberCreate(kCFAllocatorDefault, kCFNumberLongLongType, (const void*)&tries);
1630
1631 CFMutableDictionaryRef escrowTimeAndTries = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
1632 CFDictionaryAddValue(escrowTimeAndTries, kSOSBurnedRecoveryAttemptCount, attempts);
1633 CFDictionaryAddValue(escrowTimeAndTries, kSOSBurnedRecoveryAttemptAttestationDate, timeDescription);
1634
1635 CFMutableDictionaryRef escrowRecord = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
1636 CFDictionaryAddValue(escrowRecord, escrow_label, escrowTimeAndTries);
1637
1638 switch(status) {
1639 case kSOSCCInCircle:
1640 //set the escrow record in the peer info!
1641 if(!SOSFullPeerInfoAddEscrowRecord(SOSAccountGetMyFullPeerInfo(account), dsid, escrowRecord, error)){
1642 secdebug("accout", "Could not set escrow record in the full peer info");
1643 result = false;
1644 }
1645 break;
1646 case kSOSCCRequestPending:
1647 //set the escrow record in the peer info/application?
1648 break;
1649 case kSOSCCNotInCircle:
1650 case kSOSCCCircleAbsent:
1651 //set the escrow record in the account expansion!
1652
1653 if(!SOSAccountAddEscrowRecords(account, dsid, escrowRecord, error)) {
1654 secdebug("account", "Could not set escrow record in expansion data");
1655 result = false;
1656 }
1657 break;
1658 default:
1659 secdebug("account", "no circle status!");
1660 break;
1661 }
1662 CFReleaseNull(attempts);
1663 CFReleaseNull(timeDescription);
1664 CFReleaseNull(escrowTimeAndTries);
1665 CFReleaseNull(escrowRecord);
1666
1667 return true;
1668 });
1669
1670 return result;
1671 }
1672
1673 bool SOSCCAcceptApplicants_Server(CFArrayRef applicants, CFErrorRef* error)
1674 {
1675 __block bool result = true;
1676 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1677 result = SOSAccountAcceptApplicants(account, applicants, block_error);
1678 return result;
1679 });
1680
1681 }
1682
1683 bool SOSCCRejectApplicants_Server(CFArrayRef applicants, CFErrorRef* error)
1684 {
1685 __block bool result = true;
1686 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1687 result = SOSAccountRejectApplicants(account, applicants, block_error);
1688 return result;
1689 });
1690 }
1691
1692 CFArrayRef SOSCCCopyPeerPeerInfo_Server(CFErrorRef* error)
1693 {
1694 __block CFArrayRef result = NULL;
1695
1696 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1697 result = SOSAccountCopyPeers(account, block_error);
1698 return result != NULL;
1699 });
1700
1701 return result;
1702 }
1703
1704 CFArrayRef SOSCCCopyConcurringPeerPeerInfo_Server(CFErrorRef* error)
1705 {
1706 __block CFArrayRef result = NULL;
1707
1708 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1709 result = SOSAccountCopyConcurringPeers(account, block_error);
1710 return result != NULL;
1711 });
1712
1713 return result;
1714 }
1715
1716 SOSPeerInfoRef SOSCCCopyMyPeerInfo_Server(CFErrorRef* error)
1717 {
1718 __block SOSPeerInfoRef result = NULL;
1719
1720 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1721 // Create a copy to be DERed/sent back to client
1722 result = SOSPeerInfoCreateCopy(kCFAllocatorDefault, SOSAccountGetMyPeerInfo(account), block_error);
1723 return result != NULL;
1724 });
1725
1726 return result;
1727 }
1728
1729 CFDataRef SOSCCCopyAccountState_Server(CFErrorRef* error)
1730 {
1731 __block CFDataRef accountState = NULL;
1732
1733 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1734 // Copy account state from the keychain
1735 accountState = SOSAccountCopyAccountStateFromKeychain(block_error);
1736 return accountState != NULL;
1737 });
1738
1739 return accountState;
1740 }
1741
1742 bool SOSCCDeleteAccountState_Server(CFErrorRef* error)
1743 {
1744 __block bool result = NULL;
1745
1746 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1747 // Delete account state from the keychain
1748 result = SOSAccountDeleteAccountStateFromKeychain(block_error);
1749 return result;
1750 });
1751
1752 return result;
1753 }
1754
1755 CFDataRef SOSCCCopyEngineData_Server(CFErrorRef* error)
1756 {
1757 __block CFDataRef engineState = NULL;
1758
1759 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1760 // Copy engine state from the keychain
1761 engineState = SOSAccountCopyEngineStateFromKeychain(block_error);
1762 return engineState != NULL;
1763 });
1764
1765 return engineState;
1766 }
1767
1768 bool SOSCCDeleteEngineState_Server(CFErrorRef* error)
1769 {
1770 __block bool result = NULL;
1771
1772 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1773 // Delete engine state from the keychain
1774 result = SOSAccountDeleteEngineStateFromKeychain(block_error);
1775 return result;
1776 });
1777
1778 return result;
1779 }
1780
1781
1782
1783 SOSPeerInfoRef SOSCCSetNewPublicBackupKey_Server(CFDataRef newPublicBackup, CFErrorRef *error){
1784 __block SOSPeerInfoRef result = NULL;
1785
1786 (void) do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1787 if(SOSAccountSetBackupPublicKey(account,newPublicBackup, error)){
1788 // Create a copy to be DERed/sent back to client
1789 result = SOSPeerInfoCreateCopy(kCFAllocatorDefault, SOSAccountGetMyPeerInfo(account), block_error);
1790 secdebug("backup", "SOSCCSetNewPublicBackupKey_Server, new public backup is set");
1791 }
1792 else
1793 {
1794 secerror("SOSCCSetNewPublicBackupKey_Server, could not set new public backup");
1795 }
1796 return result != NULL;
1797 });
1798
1799 return result;
1800 }
1801
1802 bool SOSCCRegisterSingleRecoverySecret_Server(CFDataRef aks_bag, bool setupV0Only, CFErrorRef *error){
1803 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1804 return SOSAccountSetBSKBagForAllSlices(account, aks_bag, setupV0Only, error);
1805 });
1806 }
1807
1808 CFStringRef SOSCCCopyIncompatibilityInfo_Server(CFErrorRef* error)
1809 {
1810 __block CFStringRef result = NULL;
1811
1812 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1813 result = SOSAccountCopyIncompatibilityInfo(account, block_error);
1814 return result != NULL;
1815 });
1816
1817 return result;
1818 }
1819
1820 bool SOSCCCheckPeerAvailability_Server(CFErrorRef *error)
1821 {
1822 __block bool pingedPeersInCircle = false;
1823 __block dispatch_semaphore_t peerSemaphore = NULL;
1824 __block bool peerIsAvailable = false;
1825
1826 static dispatch_queue_t time_out;
1827 static dispatch_once_t once;
1828 dispatch_once(&once, ^{
1829 time_out = dispatch_queue_create("peersAvailableTimeout", DISPATCH_QUEUE_SERIAL);
1830 });
1831 __block int token = -1;
1832
1833 bool result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1834
1835 peerSemaphore = dispatch_semaphore_create(0);
1836 dispatch_retain(peerSemaphore);
1837 notify_register_dispatch(kSOSCCPeerAvailable, &token, time_out, ^(int token) {
1838 if(peerSemaphore != NULL){
1839 dispatch_semaphore_signal(peerSemaphore);
1840 dispatch_release(peerSemaphore);
1841 peerIsAvailable = true;
1842 notify_cancel(token);
1843 }
1844 });
1845
1846 pingedPeersInCircle = SOSAccountCheckPeerAvailability(account, block_error);
1847 return pingedPeersInCircle;
1848 });
1849
1850 if (result) {
1851 dispatch_semaphore_wait(peerSemaphore, dispatch_time(DISPATCH_TIME_NOW, 7ull * NSEC_PER_SEC));
1852 }
1853
1854 if(peerSemaphore != NULL)
1855 dispatch_release(peerSemaphore);
1856
1857 if(time_out != NULL && peerSemaphore != NULL){
1858 dispatch_sync(time_out, ^{
1859 if(!peerIsAvailable){
1860 dispatch_release(peerSemaphore);
1861 peerSemaphore = NULL;
1862 notify_cancel(token);
1863 secnotice("peer available", "checking peer availability timed out, releasing semaphore");
1864 }
1865 });
1866 }
1867 if(!peerIsAvailable){
1868 CFStringRef errorMessage = CFSTR("There are no peers in the circle currently available");
1869 CFDictionaryRef userInfo = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, kCFErrorLocalizedDescriptionKey, errorMessage, NULL);
1870 if(error != NULL){
1871 *error =CFErrorCreate(kCFAllocatorDefault, CFSTR("com.apple.security.ids.error"), kSecIDSErrorNoPeersAvailable, userInfo);
1872 secerror("%@", *error);
1873 }
1874 CFReleaseNull(userInfo);
1875 return false;
1876 }
1877 else
1878 return true;
1879 }
1880
1881
1882
1883 enum DepartureReason SOSCCGetLastDepartureReason_Server(CFErrorRef* error)
1884 {
1885 __block enum DepartureReason result = kSOSDepartureReasonError;
1886
1887 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1888 result = SOSAccountGetLastDepartureReason(account, block_error);
1889 return result != kSOSDepartureReasonError;
1890 });
1891
1892 return result;
1893 }
1894
1895 bool SOSCCSetLastDepartureReason_Server(enum DepartureReason reason, CFErrorRef *error){
1896 __block bool result = true;
1897
1898 return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1899 SOSAccountSetLastDepartureReason(account, reason);
1900 return result;
1901 });
1902 }
1903
1904 bool SOSCCSetHSA2AutoAcceptInfo_Server(CFDataRef pubKey, CFErrorRef *error) {
1905 __block bool result = true;
1906
1907 return do_with_account_if_after_first_unlock(error, ^(SOSAccountRef account,
1908 CFErrorRef *block_error) {
1909 result = SOSAccountSetHSAPubKeyExpected(account, pubKey, error);
1910 return (bool)result;
1911 });
1912 }
1913
1914 bool SOSCCProcessEnsurePeerRegistration_Server(CFErrorRef* error)
1915 {
1916 secnotice("updates", "Request for registering peers");
1917 return do_with_account_while_unlocked(error, ^bool(SOSAccountRef account, CFErrorRef *error) {
1918 return SOSAccountEnsurePeerRegistration(account, error);
1919 });
1920 }
1921
1922 SyncWithAllPeersReason SOSCCProcessSyncWithAllPeers_Server(CFErrorRef* error)
1923 {
1924 /*
1925 #define kIOReturnLockedRead iokit_common_err(0x2c3) // device read locked
1926 #define kIOReturnLockedWrite iokit_common_err(0x2c4) // device write locked
1927 */
1928 __block SyncWithAllPeersReason result = kSyncWithAllPeersSuccess;
1929 CFErrorRef action_error = NULL;
1930
1931 if (!do_with_account_while_unlocked(&action_error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1932 CFErrorRef localError = NULL;
1933
1934 if (!SOSAccountSyncWithAllPeers(account, &localError)) {
1935 secerror("sync with all peers failed: %@", localError);
1936 CFReleaseSafe(localError);
1937 // This isn't a device-locked error, but returning false will
1938 // have CloudKeychainProxy ask us to try sync again after next unlock
1939 result = kSyncWithAllPeersOtherFail;
1940 return false;
1941 }
1942 return true;
1943 })) {
1944 if (action_error) {
1945 if (SecErrorGetOSStatus(action_error) == errSecInteractionNotAllowed) {
1946 secnotice("updates", "SOSAccountSyncWithAllPeers failed because device is locked; letting CloudKeychainProxy know");
1947 result = kSyncWithAllPeersLocked; // tell CloudKeychainProxy to call us back when device unlocks
1948 CFReleaseNull(action_error);
1949 } else {
1950 secerror("Unexpected error: %@", action_error);
1951 }
1952
1953 if (error && *error == NULL) {
1954 *error = action_error;
1955 action_error = NULL;
1956 }
1957
1958 CFReleaseNull(action_error);
1959 }
1960 }
1961
1962 return result;
1963 }
1964
1965 void SOSCCSyncWithAllPeers(void)
1966 {
1967 SOSCloudKeychainRequestSyncWithAllPeers(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
1968 }
1969
1970 CF_RETURNS_RETAINED CFArrayRef SOSCCHandleUpdateMessage(CFDictionaryRef updates)
1971 {
1972 CFArrayRef result = NULL;
1973 SOSAccountRef account = SOSKeychainAccountGetSharedAccount(); //HACK to make sure itemsChangedBlock is set
1974
1975 (account) ? (result = SOSCloudKeychainHandleUpdateMessage(updates)) : (result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault));
1976 return result;
1977 }