]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/SOSCloudCircleServer.c
Security-57336.1.9.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
72 #if TARGET_OS_EMBEDDED || TARGET_IPHONE_SIMULATOR
73 #include <MobileGestalt.h>
74 #else
75 #include <AppleSystemInfo/AppleSystemInfo.h>
76
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
80 // as if it's on iOS.
81 typedef const struct AuthorizationOpaqueRef * AuthorizationRef;
82 #endif
83
84 #define SOSCKCSCOPE "sync"
85 #define RUN_AS_ROOT_ERROR 550
86
87 #define USE_SYSTEMCONFIGURATION_PRIVATE_HEADERS
88 #import <SystemConfiguration/SystemConfiguration.h>
89
90 #include <notify.h>
91
92 static SOSCCAccountDataSourceFactoryBlock accountDataSourceOverride = NULL;
93
94 bool SOSKeychainAccountSetFactoryForAccount(SOSCCAccountDataSourceFactoryBlock block)
95 {
96 accountDataSourceOverride = Block_copy(block);
97
98 return true;
99 }
100
101 //
102 // Forward declared
103 //
104
105 static void do_with_account(void (^action)(SOSAccountRef account));
106 static void do_with_account_async(void (^action)(SOSAccountRef account));
107
108 //
109 // Constants
110 //
111 CFStringRef kSOSInternalAccessGroup = CFSTR("com.apple.security.sos");
112
113 CFStringRef kSOSAccountLabel = CFSTR("iCloud Keychain Account Meta-data");
114
115 static CFStringRef accountFileName = CFSTR("PersistedAccount.plist");
116
117 static CFDictionaryRef SOSItemCopyQueryForSyncItems(CFStringRef service, bool returnData)
118 {
119 return CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
120 kSecClass, kSecClassGenericPassword,
121 kSecAttrService, service,
122 kSecAttrAccessGroup, kSOSInternalAccessGroup,
123 kSecReturnData, returnData ? kCFBooleanTrue : kCFBooleanFalse,
124 NULL);
125 }
126
127 CFDataRef SOSItemCopy(CFStringRef service, CFErrorRef* error)
128 {
129 CFDictionaryRef query = SOSItemCopyQueryForSyncItems(service, true);
130
131 CFDataRef result = NULL;
132
133 OSStatus copyResult = SecItemCopyMatching(query, (CFTypeRef*) &result);
134
135 CFReleaseNull(query);
136
137 if (copyResult != noErr) {
138 SecError(copyResult, error, CFSTR("Error %@ reading for service '%@'"), result, service);
139 CFReleaseNull(result);
140 return NULL;
141 }
142
143 if (!isData(result)) {
144 SOSCreateErrorWithFormat(kSOSErrorProcessingFailure, NULL, error, NULL, CFSTR("SecItemCopyMatching returned non-data in '%@'"), service);
145 CFReleaseNull(result);
146 return NULL;
147 }
148
149 return result;
150 }
151
152 static CFDataRef SOSKeychainCopySavedAccountData()
153 {
154 CFErrorRef error = NULL;
155 CFDataRef accountData = SOSItemCopy(kSOSAccountLabel, &error);
156 if (!accountData) {
157 secnotice("account", "Failed to load account: %@", error);
158 secerror("Failed to load account: %@", error);
159 }
160 CFReleaseNull(error);
161
162 return accountData;
163 }
164
165 bool SOSItemUpdateOrAdd(CFStringRef service, CFStringRef accessibility, CFDataRef data, CFErrorRef *error)
166 {
167 CFDictionaryRef query = SOSItemCopyQueryForSyncItems(service, false);
168
169 CFDictionaryRef update = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
170 kSecValueData, data,
171 kSecAttrAccessible, accessibility,
172 NULL);
173 OSStatus saveStatus = SecItemUpdate(query, update);
174
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);
179 });
180 saveStatus = SecItemAdd(add, NULL);
181 CFReleaseNull(add);
182 }
183
184 CFReleaseNull(query);
185 CFReleaseNull(update);
186
187 return SecError(saveStatus, error, CFSTR("Error saving %@ to service '%@'"), data, service);
188 }
189
190 static void SOSKeychainAccountEnsureSaved(SOSAccountRef account)
191 {
192 static CFDataRef sLastSavedAccountData = NULL;
193
194 CFErrorRef saveError = NULL;
195 CFDataRef accountAsData = NULL;
196
197 accountAsData = SOSAccountCopyEncodedData(account, kCFAllocatorDefault, &saveError);
198
199 require_action_quiet(accountAsData, exit, secerror("Failed to transform account into data, error: %@", saveError));
200 require_quiet(!CFEqualSafe(sLastSavedAccountData, accountAsData), exit);
201
202 if (!SOSItemUpdateOrAdd(kSOSAccountLabel, kSecAttrAccessibleAlwaysThisDeviceOnly, accountAsData, &saveError)) {
203 secerror("Can't save account: %@", saveError);
204 goto exit;
205 }
206
207 CFReleaseNull(sLastSavedAccountData);
208 sLastSavedAccountData = accountAsData;
209 accountAsData = NULL;
210
211 exit:
212 CFReleaseNull(saveError);
213 CFReleaseNull(accountAsData);
214 }
215
216
217 /*
218 Stolen from keychain_sync.c
219 */
220
221 static bool clearAllKVS(CFErrorRef *error)
222 {
223 return true;
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);
229
230 SOSCloudKeychainClearAll(processQueue, ^(CFDictionaryRef returnedValues, CFErrorRef cerror)
231 {
232 result = (cerror != NULL);
233 dispatch_semaphore_signal(waitSemaphore);
234 });
235
236 dispatch_semaphore_wait(waitSemaphore, finishTime);
237 dispatch_release(waitSemaphore);
238
239 return result;
240 }
241
242 static SOSAccountRef SOSKeychainAccountCreateSharedAccount(CFDictionaryRef our_gestalt)
243 {
244 secdebug("account", "Created account");
245
246 CFDataRef savedAccount = SOSKeychainCopySavedAccountData();
247 SOSAccountRef account = NULL;
248 SOSDataSourceFactoryRef factory = accountDataSourceOverride ? accountDataSourceOverride()
249 : SecItemDataSourceFactoryGetDefault();
250
251 if (savedAccount) {
252 CFErrorRef inflationError = NULL;
253
254 account = SOSAccountCreateFromData(kCFAllocatorDefault, savedAccount, factory, &inflationError);
255
256 if (account){
257 SOSAccountUpdateGestalt(account, our_gestalt);
258 } else {
259 secerror("Got error inflating account: %@", inflationError);
260 }
261
262 CFReleaseNull(inflationError);
263
264 }
265 CFReleaseSafe(savedAccount);
266
267 if (!account) {
268 account = SOSAccountCreate(kCFAllocatorDefault, our_gestalt, factory);
269
270 if (!account)
271 secerror("Got NULL creating account");
272 }
273
274 return account;
275 }
276
277 //
278 // Mark: Gestalt Handling
279 //
280
281 CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
282 CF_EXPORT CFStringRef _kCFSystemVersionBuildVersionKey;
283
284 CFStringRef CopyOSVersion(void)
285 {
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);
291 #else
292 CFDictionaryRef versions = _CFCopySystemVersionDictionary();
293
294 if (versions) {
295 CFTypeRef versionValue = CFDictionaryGetValue(versions, _kCFSystemVersionBuildVersionKey);
296
297 if (isString(versionValue))
298 osVersion = CFRetainSafe((CFStringRef) versionValue);
299 }
300
301 CFReleaseNull(versions);
302 #endif
303 // What to do on MacOS.
304 if (osVersion == NULL)
305 osVersion = CFSTR("Unknown model");
306 });
307 return CFRetainSafe(osVersion);
308 }
309
310
311 static CFStringRef CopyModelName(void)
312 {
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);
318 #else
319 modelName = ASI_CopyComputerModelName(FALSE);
320 #endif
321 if (modelName == NULL)
322 modelName = CFSTR("Unknown model");
323 });
324 return CFStringCreateCopy(kCFAllocatorDefault, modelName);
325 }
326
327 static CFStringRef CopyComputerName(SCDynamicStoreRef store)
328 {
329 CFStringRef deviceName = SCDynamicStoreCopyComputerName(store, NULL);
330 if (deviceName == NULL) {
331 deviceName = CFSTR("Unknown name");
332 }
333 return deviceName;
334 }
335
336 static bool _EngineMessageProtocolV2Enabled(void)
337 {
338 #if DEBUG
339 //sudo rhr
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);
344
345 if (v2Pref && CFGetTypeID(v2Pref) == CFBooleanGetTypeID()) {
346 v2_enabled = CFBooleanGetValue((CFBooleanRef)v2Pref);
347 secinfo("server", "Engine v2 : %s", v2_enabled ? "enabled":"disabled");
348 }
349 CFReleaseSafe(v2Pref);
350 });
351
352 return v2_enabled;
353 #else
354 return false;
355 #endif
356 }
357
358
359 static CFDictionaryRef CreateDeviceGestaltDictionary(SCDynamicStoreRef store, CFArrayRef keys, void *context)
360 {
361 CFStringRef modelName = CopyModelName();
362 CFStringRef computerName = CopyComputerName(store);
363 CFStringRef osVersion = CopyOSVersion();
364
365 SInt32 version = _EngineMessageProtocolV2Enabled() ? kEngineMessageProtocolVersion : 0;
366 CFNumberRef protocolVersion = CFNumberCreate(0, kCFNumberSInt32Type, &version);
367
368 CFDictionaryRef gestalt = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
369 kPIUserDefinedDeviceNameKey, computerName,
370 kPIDeviceModelNameKey, modelName,
371 kPIMessageProtocolVersionKey, protocolVersion,
372 kPIOSVersionKey, osVersion,
373 NULL);
374 CFReleaseSafe(modelName);
375 CFReleaseSafe(computerName);
376 CFReleaseSafe(protocolVersion);
377
378 return gestalt;
379 }
380
381 static void SOSCCProcessGestaltUpdate(SCDynamicStoreRef store, CFArrayRef keys, void *context)
382 {
383 do_with_account(^(SOSAccountRef account) {
384 if(account){
385 CFDictionaryRef gestalt = CreateDeviceGestaltDictionary(store, keys, context);
386 if (SOSAccountUpdateGestalt(account, gestalt)) {
387 notify_post(kSOSCCCircleChangedNotification);
388 }
389 CFReleaseSafe(gestalt);
390 }
391 });
392 }
393
394
395 static CFDictionaryRef CreateDeviceGestaltDictionaryAndRegisterForUpdate(dispatch_queue_t queue, void *info)
396 {
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;
402
403 if (store == NULL || computerKey == NULL) {
404 goto done;
405 }
406 keys = CFArrayCreate(NULL, (const void **)&computerKey, 1, &kCFTypeArrayCallBacks);
407 if (keys == NULL) {
408 goto done;
409 }
410 gestalt = CreateDeviceGestaltDictionary(store, keys, info);
411 SCDynamicStoreSetNotificationKeys(store, keys, NULL);
412 SCDynamicStoreSetDispatchQueue(store, queue);
413
414 done:
415 if (store) CFRelease(store);
416 if (computerKey) CFRelease(computerKey);
417 if (keys) CFRelease(keys);
418 return gestalt;
419 }
420
421 static void do_with_account(void (^action)(SOSAccountRef account));
422 static void do_with_account_async(void (^action)(SOSAccountRef account));
423
424 static SOSAccountRef GetSharedAccount(void) {
425 static SOSAccountRef sSharedAccount = NULL;
426 static dispatch_once_t onceToken;
427
428 #if !(TARGET_OS_EMBEDDED)
429 if(geteuid() == 0){
430 secerror("Cannot inflate account object as root");
431 return NULL;
432 }
433 #endif
434
435 dispatch_once(&onceToken, ^{
436 secdebug("account", "Account Creation start");
437
438 CFDictionaryRef gestalt = CreateDeviceGestaltDictionaryAndRegisterForUpdate(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
439
440 if (!gestalt) {
441 #if TARGET_OS_IPHONE && TARGET_IPHONE_SIMULATOR
442 gestalt = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, NULL);
443 #else
444 secerror("Didn't get machine gestalt! This is going to be ugly.");
445 #endif
446 }
447
448 sSharedAccount = SOSKeychainAccountCreateSharedAccount(gestalt);
449
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);
455 if (!me) {
456 secerror("Error finding me for change: %@", pi_error);
457 } else {
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);
462 } else {
463 secinfo("updates", "Not requesting Ensure Peer Registration, since it's not needed");
464 }
465
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();
470 }
471 }
472
473 CFReleaseNull(pi_error);
474
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) {
480
481 notify_post(kSOSCCCircleChangedNotification);
482 }
483 });
484
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);
492
493 CFErrorRef error = NULL;
494 handledKeys = SOSTransportDispatchMessages(account, changes, &error);
495 if (!handledKeys) {
496 secerror("Error handling updates: %@", error);
497 CFReleaseNull(error);
498 }
499 });
500 CFReleaseSafe(changes);
501 return handledKeys;
502 });
503 CFReleaseSafe(gestalt);
504
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);
507 });
508
509
510 return sSharedAccount;
511 }
512
513 static void do_with_account_dynamic(void (^action)(SOSAccountRef account), bool sync) {
514 SOSAccountRef account = GetSharedAccount();
515
516 if(account){
517 dispatch_block_t do_action_and_save = ^{
518 SOSPeerInfoRef mpi = SOSAccountGetMyPeerInfo(account);
519 CFSetRef beforeViews = mpi ? SOSPeerInfoCopyEnabledViews(mpi) : NULL;
520
521 action(account);
522
523 // Fake transaction around using the account object
524 SOSAccountFinishTransaction(account);
525
526 mpi = SOSAccountGetMyPeerInfo(account); // Update the peer
527 CFSetRef afterViews = mpi ? SOSPeerInfoCopyEnabledViews(mpi) : NULL;
528
529 if(!CFEqualSafe(beforeViews, afterViews)) {
530 notify_post(kSOSCCViewMembershipChangedNotification);
531 }
532
533 CFReleaseNull(beforeViews);
534 CFReleaseNull(afterViews);
535
536 SOSKeychainAccountEnsureSaved(account);
537 };
538
539 if (sync) {
540 dispatch_sync(SOSAccountGetQueue(account), do_action_and_save);
541 } else {
542 dispatch_async(SOSAccountGetQueue(account), do_action_and_save);
543 }
544 }
545 }
546
547 __unused static void do_with_account_async(void (^action)(SOSAccountRef account)) {
548 do_with_account_dynamic(action, false);
549 }
550
551 static void do_with_account(void (^action)(SOSAccountRef account)) {
552 do_with_account_dynamic(action, true);
553 }
554
555 static bool do_if_after_first_unlock(CFErrorRef *error, dispatch_block_t action)
556 {
557 #if TARGET_IPHONE_SIMULATOR
558 action();
559 return true;
560 #else
561 bool beenUnlocked = false;
562 require_quiet(SecAKSGetHasBeenUnlocked(&beenUnlocked, error), fail);
563
564 require_action_quiet(beenUnlocked, fail,
565 SOSCreateErrorWithFormat(kSOSErrorNotReady, NULL, error, NULL,
566 CFSTR("Keybag never unlocked, ask after first unlock")));
567
568 action();
569 return true;
570
571 fail:
572 return false;
573 #endif
574 }
575
576 static bool do_with_account_if_after_first_unlock(CFErrorRef *error, bool (^action)(SOSAccountRef account, CFErrorRef* error))
577 {
578 __block bool action_result = false;
579
580 #if !(TARGET_OS_EMBEDDED)
581 if(geteuid() == 0){
582 secerror("Cannot inflate account object as root");
583 if(error)
584 *error = CFErrorCreate(kCFAllocatorDefault, CFSTR("com.apple.security"), RUN_AS_ROOT_ERROR, NULL);
585 return false;
586 }
587 #endif
588 return do_if_after_first_unlock(error, ^{
589 do_with_account(^(SOSAccountRef account) {
590 action_result = action(account, error);
591 });
592
593 }) && action_result;
594 }
595
596 static bool do_with_account_while_unlocked(CFErrorRef *error, bool (^action)(SOSAccountRef account, CFErrorRef* error))
597 {
598 __block bool action_result = false;
599
600 #if !(TARGET_OS_EMBEDDED)
601 if(geteuid() == 0){
602 secerror("Cannot inflate account object as root");
603 if(error)
604 *error = CFErrorCreate(kCFAllocatorDefault, CFSTR("com.apple.security"), RUN_AS_ROOT_ERROR, NULL);
605 return false;
606 }
607 #endif
608
609 return SecAKSDoWhileUserBagLocked(error, ^{
610 do_with_account(^(SOSAccountRef account) {
611 action_result = action(account, error);
612 });
613
614 }) && action_result;
615 }
616
617 SOSAccountRef SOSKeychainAccountGetSharedAccount()
618 {
619 __block SOSAccountRef result = NULL;
620
621 do_with_account(^(SOSAccountRef account) {
622 result = account;
623 });
624
625 return result;
626 }
627
628 //
629 // Mark: Credential processing
630 //
631
632
633 bool SOSCCTryUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFErrorRef *error)
634 {
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);
637 });
638 }
639
640
641 SOSViewResultCode SOSCCView_Server(CFStringRef viewname, SOSViewActionCode action, CFErrorRef *error) {
642 __block SOSViewResultCode status = kSOSCCGeneralViewError;
643
644 do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
645 switch(action) {
646 case kSOSCCViewQuery:
647 status = SOSAccountViewStatus(account, viewname, error);
648 break;
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);
653 break;
654 default:
655 secnotice("views", "Bad SOSViewActionCode - %d", (int) action);
656 return false;
657 break;
658 }
659 return true;
660 });
661 return status;
662 }
663
664
665 bool SOSCCViewSet_Server(CFSetRef enabledViews, CFSetRef disabledViews) {
666 __block bool status = false;
667
668 do_with_account_if_after_first_unlock(NULL, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
669 status = SOSAccountUpdateViewSets(account, enabledViews, disabledViews);
670 return true;
671 });
672 return status;
673 }
674
675
676
677 SOSSecurityPropertyResultCode SOSCCSecurityProperty_Server(CFStringRef property, SOSSecurityPropertyActionCode action, CFErrorRef *error) {
678
679 __block SOSViewResultCode status = kSOSCCGeneralSecurityPropertyError;
680 do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
681 switch(action) {
682 case kSOSCCSecurityPropertyQuery:
683 status = SOSAccountSecurityPropertyStatus(account, property, error);
684 break;
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);
689 break;
690 default:
691 secnotice("secprop", "Bad SOSSecurityPropertyActionCode - %d", (int) action);
692 return false;
693 break;
694 }
695 return true;
696 });
697 return status;
698 }
699
700 void sync_the_last_data_to_kvs(SOSAccountRef account){
701
702 dispatch_semaphore_t wait_for = dispatch_semaphore_create(0);
703 dispatch_retain(wait_for); // Both this scope and the block own it.
704
705 __block bool success = false;
706
707 secnoticeq("force-push", "calling SOSCloudKeychainSynchronizeAndWait");
708
709 CFMutableArrayRef keysToGet = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
710
711 SOSCloudKeychainSynchronizeAndWait(keysToGet, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) {
712
713 if (sync_error) {
714 secerrorq("SOSCloudKeychainSynchronizeAndWait: %@", sync_error);
715 } else {
716 secnoticeq("force-push", "returned from call; in callback to SOSCloudKeychainSynchronizeAndWait: results: %@", returnedValues);
717
718 success = true;
719 }
720
721 dispatch_semaphore_signal(wait_for);
722 dispatch_release(wait_for);
723 });
724
725 CFReleaseNull(keysToGet);
726 dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER);
727 dispatch_release(wait_for);
728 }
729
730 #define kWAIT2MINID "EFRESH"
731
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.
735
736 CFMutableArrayRef keysToGet = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
737 CFArrayAppendValue(keysToGet, kSOSKVSKeyParametersKey);
738 AppendCircleKeyName(keysToGet, SOSCircleGetName(account->trusted_circle));
739
740 __block CFDictionaryRef valuesToUpdate = NULL;
741 __block bool success = false;
742
743 secnoticeq("fresh", "%s calling SOSCloudKeychainSynchronizeAndWait", kWAIT2MINID);
744
745 SOSCloudKeychainSynchronizeAndWait(keysToGet, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) {
746
747 if (sync_error) {
748 secerrorq("%s SOSCloudKeychainSynchronizeAndWait: %@", kWAIT2MINID, sync_error);
749 if (error) {
750 *error = sync_error;
751 CFRetainSafe(*error);
752 }
753 } else {
754 secnoticeq("fresh", "%s returned from call; in callback to SOSCloudKeychainSynchronizeAndWait: results: %@", kWAIT2MINID, returnedValues);
755 valuesToUpdate = returnedValues;
756 CFRetainSafe(valuesToUpdate);
757 success = true;
758 }
759
760 dispatch_semaphore_signal(wait_for);
761 dispatch_release(wait_for);
762 });
763
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);
770 if (!handledKeys) {
771 secerrorq("%s Freshness update failed: %@", kWAIT2MINID, error ? *error : NULL);
772 success = false;
773 }
774 }
775 CFReleaseNull(handledKeys);
776 CFReleaseNull(valuesToUpdate);
777 CFReleaseNull(keysToGet);
778
779 return success;
780 }
781
782 static bool Flush(CFErrorRef *error) {
783 __block bool success = false;
784
785 dispatch_semaphore_t wait_for = dispatch_semaphore_create(0);
786 dispatch_retain(wait_for); // Both this scope and the block own it.
787
788 secnotice("flush", "Starting");
789
790 SOSCloudKeychainFlush(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) {
791 success = (sync_error == NULL);
792 if (error) {
793 CFRetainAssign(*error, sync_error);
794 }
795
796 dispatch_semaphore_signal(wait_for);
797 dispatch_release(wait_for);
798 });
799
800 dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER);
801 dispatch_release(wait_for);
802
803 secnotice("flush", "Returned %s", success? "Success": "Failure");
804
805 return success;
806 }
807
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);
816 }
817 else if(CFStringCompare(dsid, accountDSID, 0) != kCFCompareEqualTo){
818 secnotice("updates", "Changing DSID from: %@ to %@", accountDSID, dsid);
819
820 //DSID has changed, blast the account!
821 SOSAccountSetToNew(account);
822
823 //update DSID to the new DSID
824 SOSAccountUpdateDSID(account, dsid);
825 }
826 else {
827 secnotice("updates", "Not Changing DSID: %@ to %@", accountDSID, dsid);
828 }
829
830 }
831
832 if (!EnsureFreshParameters(account, block_error)) {
833 return false;
834 }
835 if (!SOSAccountAssertUserCredentials(account, user_label, user_password, block_error)) {
836 secnotice("updates", "EnsureFreshParameters/SOSAccountAssertUserCredentials error: %@", *block_error);
837 return false;
838 }
839 return true;
840 });
841
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);
845 });
846 }
847
848 return result;
849 }
850
851 bool SOSCCSetUserCredentialsAndDSID_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error)
852 {
853 // TODO: Return error if DSID is NULL to insist our callers provide one?
854 return SOSCCAssertUserCredentialsAndOptionalDSID(user_label, user_password, dsid, error);
855 }
856
857 bool SOSCCSetUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFErrorRef *error)
858 {
859 return SOSCCAssertUserCredentialsAndOptionalDSID(user_label, user_password, NULL, error);
860 }
861
862 bool SOSCCCanAuthenticate_Server(CFErrorRef *error)
863 {
864 bool result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
865 return SOSAccountGetPrivateCredential(account, block_error) != NULL;
866 });
867
868 if (!result && error && *error && CFErrorGetDomain(*error) == kSOSErrorDomain) {
869 CFIndex code = CFErrorGetCode(*error);
870 if (code == kSOSErrorPrivateKeyAbsent || code == kSOSErrorPublicKeyAbsent) {
871 CFReleaseNull(*error);
872 }
873 }
874
875 return result;
876 }
877
878 bool SOSCCPurgeUserCredentials_Server(CFErrorRef *error)
879 {
880 return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
881 SOSAccountPurgePrivateCredential(account);
882 return true;
883 });
884 }
885
886 SOSCCStatus SOSCCThisDeviceIsInCircle_Server(CFErrorRef *error)
887 {
888 __block SOSCCStatus status;
889
890 return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
891 status = SOSAccountGetCircleStatus(account, block_error);
892 return true;
893 }) ? status : kSOSCCError;
894 }
895
896 bool SOSCCRequestToJoinCircle_Server(CFErrorRef* error)
897 {
898 __block bool result = true;
899
900 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
901 result = SOSAccountJoinCircles(account, block_error);
902 return result;
903 });
904 }
905
906 bool SOSCCRequestToJoinCircleAfterRestore_Server(CFErrorRef* error)
907 {
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);
913 return result;
914 });
915 return returned;
916
917 }
918
919 bool SOSCCRequestEnsureFreshParameters_Server(CFErrorRef* error)
920 {
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);
925 return result;
926 });
927 return returned;
928 }
929
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);
936 if(fpi && ring)
937 result = SOSRingApply(ring, account->user_public, fpi , error);
938 return result;
939 });
940 return returned;
941 }
942
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);
949 if(fpi && ring)
950 result = SOSRingWithdraw(ring, account->user_public, fpi , error);
951 return result;
952 });
953 return returned;
954 }
955
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);
962 if(fpi && ring)
963 result = SOSRingResetToOffering(ring, NULL, fpi, error); ;
964 return result;
965 });
966 return returned;
967 }
968
969 CFStringRef SOSCCGetAllTheRings_Server(CFErrorRef *error){
970 __block CFMutableDictionaryRef result = NULL;
971 __block CFMutableStringRef description = CFStringCreateMutable(kCFAllocatorDefault, 0);
972
973 (void) do_with_account_while_unlocked(error, ^bool(SOSAccountRef account, CFErrorRef *error) {
974 result = SOSAccountGetRings(account, error);
975
976 if(isDictionary(result)){
977 CFDictionaryForEach(result, ^(const void *key, const void *value) {
978 CFStringAppendFormat(description, NULL, CFSTR("%@"), value);
979 });
980 }
981 if(result)
982 return true;
983 return false;
984 });
985
986 return description;
987 }
988
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);
995
996 SOSRingRef ring = SOSAccountGetRing(account, ringName, error);
997 if(myPeer && ring)
998 result = SOSRingDeviceIsInRing(ring, SOSPeerInfoGetPeerID(myPeer));
999 return result;
1000 });
1001 return returned;
1002 }
1003
1004 CFStringRef SOSCCRequestDeviceID_Server(CFErrorRef *error)
1005 {
1006 __block CFStringRef result = NULL;
1007
1008 (void) do_with_account_while_unlocked(error, ^bool(SOSAccountRef account, CFErrorRef *error) {
1009 result = SOSAccountCopyDeviceID(account, error);
1010 return (!isNull(result));
1011 });
1012 return result;
1013 }
1014
1015 bool SOSCCSetDeviceID_Server(CFStringRef IDS, CFErrorRef *error){
1016
1017 bool didSetID = false;
1018 __block bool result = false;
1019 __block CFErrorRef blockError = NULL;
1020
1021 didSetID = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1022 result = SOSAccountSetMyDSID(account, IDS, block_error);
1023 if(block_error)
1024 blockError = CFRetainSafe(*block_error);
1025 return result;
1026 });
1027
1028 if(error){
1029 *error = blockError;
1030 }
1031 return didSetID;
1032 }
1033
1034 HandleIDSMessageReason SOSCCHandleIDSMessage_Server(CFDictionaryRef messageDict, CFErrorRef* error)
1035 {
1036 // TODO: Locking flow:
1037 /*
1038 COMMON:
1039 - Get PeerCoder instance from SOSPeerCoderManager(Currently Engine)
1040 - Get Account lock and Initialize PeerCoder instance if it isn't valid yet.
1041 INCOMING:
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?)
1045 - save coder state.
1046
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
1051
1052 OUTGOING:
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
1056 - save coder state
1057 - send reply to ckd for transporting
1058 */
1059
1060 __block HandleIDSMessageReason result = kHandleIDSMessageSuccess;
1061 CFErrorRef action_error = NULL;
1062
1063 if (!do_with_account_while_unlocked(&action_error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1064 result = SOSTransportMessageIDSHandleMessage(account, messageDict, error);
1065 return result;
1066 })) {
1067 if (action_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);
1072 } else {
1073 secerror("Unexpected error: %@", action_error);
1074 }
1075
1076 if (error && *error == NULL) {
1077 *error = action_error;
1078 action_error = NULL;
1079 }
1080
1081 CFReleaseNull(action_error);
1082 }
1083 }
1084 return result;
1085 }
1086
1087 bool SOSCCIDSPingTest_Server(CFStringRef message, CFErrorRef *error){
1088 bool didSendTestMessages = false;
1089 __block bool result = true;
1090 __block CFErrorRef blockError = NULL;
1091
1092 didSendTestMessages = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1093 result = SOSAccountStartPingTest(account, message, block_error);
1094 if(block_error)
1095 blockError = CFRetainSafe(*block_error);
1096 return result;
1097 });
1098 if(blockError && error != NULL)
1099 *error = blockError;
1100
1101 return didSendTestMessages;
1102 }
1103
1104 bool SOSCCIDSServiceRegistrationTest_Server(CFStringRef message, CFErrorRef *error){
1105 bool didSendTestMessages = false;
1106 __block bool result = true;
1107 __block CFErrorRef blockError = NULL;
1108
1109 didSendTestMessages = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1110 result = SOSAccountSendIDSTestMessage(account, message, block_error);
1111 if(block_error)
1112 blockError = CFRetainSafe(*block_error);
1113 return result;
1114 });
1115 if(blockError && error != NULL)
1116 *error = blockError;
1117
1118 return didSendTestMessages;
1119 }
1120
1121 bool SOSCCIDSDeviceIDIsAvailableTest_Server(CFErrorRef *error){
1122 bool didSendTestMessages = false;
1123 __block bool result = true;
1124 __block CFErrorRef blockError = NULL;
1125
1126 didSendTestMessages = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1127 result = SOSAccountRetrieveDeviceIDFromIDSKeychainSyncingProxy(account, block_error);
1128 if(block_error)
1129 blockError = CFRetainSafe(*block_error);
1130 return result;
1131 });
1132 if(blockError && error != NULL)
1133 *error = blockError;
1134
1135 return didSendTestMessages;
1136 }
1137
1138 bool SOSCCAccountSetToNew_Server(CFErrorRef *error)
1139 {
1140 __block bool result = true;
1141
1142 return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1143 clearAllKVS(NULL);
1144 SOSAccountSetToNew(account);
1145 return result;
1146 });
1147 }
1148
1149 bool SOSCCResetToOffering_Server(CFErrorRef* error)
1150 {
1151 __block bool result = true;
1152
1153 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1154 clearAllKVS(NULL);
1155 result = SOSAccountResetToOffering(account, block_error);
1156 return result;
1157 });
1158
1159 }
1160
1161 bool SOSCCResetToEmpty_Server(CFErrorRef* error)
1162 {
1163 __block bool result = true;
1164
1165 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1166 result = SOSAccountResetToEmpty(account, block_error);
1167 return result;
1168 });
1169
1170 }
1171
1172 bool SOSCCRemoveThisDeviceFromCircle_Server(CFErrorRef* error)
1173 {
1174 __block bool result = true;
1175
1176 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1177 result = SOSAccountLeaveCircle(account, block_error);
1178 return result;
1179 });
1180 }
1181
1182 bool SOSCCLoggedOutOfAccount_Server(CFErrorRef *error)
1183 {
1184 __block bool result = true;
1185
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);
1189
1190 SOSAccountFinishTransaction(account); // Make sure this gets finished before we set to new.
1191
1192 SOSAccountSetToNew(account);
1193
1194 sync_the_last_data_to_kvs(account);
1195
1196 return result;
1197 });
1198 }
1199
1200 bool SOSCCBailFromCircle_Server(uint64_t limit_in_seconds, CFErrorRef* error)
1201 {
1202 __block bool result = true;
1203
1204 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1205 result = SOSAccountBail(account, limit_in_seconds, block_error);
1206
1207 SOSAccountFinishTransaction(account); // Make sure this gets finished before we set to new.
1208
1209 sync_the_last_data_to_kvs(account);
1210
1211 return result;
1212 });
1213
1214 }
1215
1216 CFArrayRef SOSCCCopyApplicantPeerInfo_Server(CFErrorRef* error)
1217 {
1218 __block CFArrayRef result = NULL;
1219
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;
1223 });
1224
1225 return result;
1226 }
1227
1228 CFArrayRef SOSCCCopyGenerationPeerInfo_Server(CFErrorRef* error)
1229 {
1230 __block CFArrayRef result = NULL;
1231
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;
1235 });
1236
1237 return result;
1238 }
1239
1240 CFArrayRef SOSCCCopyValidPeerPeerInfo_Server(CFErrorRef* error)
1241 {
1242 __block CFArrayRef result = NULL;
1243
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;
1247 });
1248
1249 return result;
1250 }
1251
1252 bool SOSCCValidateUserPublic_Server(CFErrorRef* error)
1253 {
1254 __block bool result = NULL;
1255
1256 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1257 result = SOSValidateUserPublic(account, block_error);
1258 return result;
1259 });
1260
1261 return result;
1262 }
1263
1264 CFArrayRef SOSCCCopyNotValidPeerPeerInfo_Server(CFErrorRef* error)
1265 {
1266 __block CFArrayRef result = NULL;
1267
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;
1271 });
1272
1273 return result;
1274 }
1275
1276 CFArrayRef SOSCCCopyRetirementPeerInfo_Server(CFErrorRef* error)
1277 {
1278 __block CFArrayRef result = NULL;
1279
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;
1283 });
1284
1285 return result;
1286 }
1287
1288 CFArrayRef SOSCCCopyEngineState_Server(CFErrorRef* error)
1289 {
1290 CFArrayRef result = NULL;
1291 SOSDataSourceFactoryRef dsf = SecItemDataSourceFactoryGetDefault();
1292 SOSDataSourceRef ds = SOSDataSourceFactoryCreateDataSource(dsf, kSecAttrAccessibleWhenUnlocked, error);
1293 if (ds) {
1294 SOSEngineRef engine = SOSDataSourceGetSharedEngine(ds, error);
1295 result = SOSEngineCopyPeerConfirmedDigests(engine, error);
1296 SOSDataSourceRelease(ds, error);
1297 }
1298
1299 return result;
1300 }
1301
1302 bool SOSCCWaitForInitialSync_Server(CFErrorRef* error) {
1303 __block dispatch_semaphore_t inSyncSema = NULL;
1304
1305 bool result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1306 bool alreadyInSync = SOSAccountCheckHasBeenInSync(account);
1307 int token = -1;
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);
1315
1316 notify_cancel(token);
1317 });
1318 }
1319 return true;
1320 });
1321
1322 if (result && inSyncSema != NULL) {
1323 dispatch_semaphore_wait(inSyncSema, DISPATCH_TIME_FOREVER);
1324 dispatch_release(inSyncSema);
1325 }
1326
1327 return result;
1328 }
1329
1330 static CFArrayRef SOSAccountCopyYetToSyncViews(SOSAccountRef account, CFErrorRef *error) {
1331 CFArrayRef result = NULL;
1332
1333 CFTypeRef valueFetched = SOSAccountGetValue(account, kSOSUnsyncedViewsKey, error);
1334 if (valueFetched == kCFBooleanTrue) {
1335 SOSPeerInfoRef myPI = SOSAccountGetMyPeerInfo(account);
1336 if (myPI) {
1337 SOSPeerInfoWithEnabledViewSet(myPI, ^(CFSetRef enabled) {
1338 CFSetCopyValues(enabled);
1339 });
1340 }
1341 } else if (isSet(valueFetched)) {
1342 result = CFSetCopyValues((CFSetRef)valueFetched);
1343 }
1344
1345 if (result == NULL) {
1346 result = CFArrayCreateForCFTypes(kCFAllocatorDefault, NULL);
1347 }
1348
1349 return result;
1350 }
1351
1352 CFArrayRef SOSCCCopyYetToSyncViewsList_Server(CFErrorRef* error) {
1353
1354 __block CFArrayRef views = NULL;
1355
1356 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1357 views = SOSAccountCopyYetToSyncViews(account, error);
1358
1359 return true;
1360 });
1361
1362 return views;
1363 }
1364
1365
1366 bool SOSCCAcceptApplicants_Server(CFArrayRef applicants, CFErrorRef* error)
1367 {
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);
1371 return result;
1372 });
1373
1374 }
1375
1376 bool SOSCCRejectApplicants_Server(CFArrayRef applicants, CFErrorRef* error)
1377 {
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);
1381 return result;
1382 });
1383 }
1384
1385 CFArrayRef SOSCCCopyPeerPeerInfo_Server(CFErrorRef* error)
1386 {
1387 __block CFArrayRef result = NULL;
1388
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;
1392 });
1393
1394 return result;
1395 }
1396
1397 CFArrayRef SOSCCCopyConcurringPeerPeerInfo_Server(CFErrorRef* error)
1398 {
1399 __block CFArrayRef result = NULL;
1400
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;
1404 });
1405
1406 return result;
1407 }
1408
1409 SOSPeerInfoRef SOSCCCopyMyPeerInfo_Server(CFErrorRef* error)
1410 {
1411 __block SOSPeerInfoRef result = NULL;
1412
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;
1417 });
1418
1419 return result;
1420 }
1421
1422 SOSPeerInfoRef SOSCCSetNewPublicBackupKey_Server(CFDataRef newPublicBackup, CFErrorRef *error){
1423 __block SOSPeerInfoRef result = NULL;
1424
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");
1430 }
1431 else
1432 {
1433 secerror("SOSCCSetNewPublicBackupKey_Server, could not set new public backup");
1434 }
1435 return result != NULL;
1436 });
1437
1438 return result;
1439 }
1440
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);
1444 });
1445 }
1446
1447 CFStringRef SOSCCCopyIncompatibilityInfo_Server(CFErrorRef* error)
1448 {
1449 __block CFStringRef result = NULL;
1450
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;
1454 });
1455
1456 return result;
1457 }
1458
1459 enum DepartureReason SOSCCGetLastDepartureReason_Server(CFErrorRef* error)
1460 {
1461 __block enum DepartureReason result = kSOSDepartureReasonError;
1462
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;
1466 });
1467
1468 return result;
1469 }
1470
1471 bool SOSCCSetLastDepartureReason_Server(enum DepartureReason reason, CFErrorRef *error){
1472 __block bool result = true;
1473
1474 return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1475 SOSAccountSetLastDepartureReason(account, reason);
1476 return result;
1477 });
1478 }
1479
1480 bool SOSCCSetHSA2AutoAcceptInfo_Server(CFDataRef pubKey, CFErrorRef *error) {
1481 __block bool result = true;
1482
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;
1487 });
1488 }
1489
1490 bool SOSCCProcessEnsurePeerRegistration_Server(CFErrorRef* error)
1491 {
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);
1495 });
1496 }
1497
1498 SyncWithAllPeersReason SOSCCProcessSyncWithAllPeers_Server(CFErrorRef* error)
1499 {
1500 /*
1501 #define kIOReturnLockedRead iokit_common_err(0x2c3) // device read locked
1502 #define kIOReturnLockedWrite iokit_common_err(0x2c4) // device write locked
1503 */
1504 __block SyncWithAllPeersReason result = kSyncWithAllPeersSuccess;
1505 CFErrorRef action_error = NULL;
1506
1507 if (!do_with_account_while_unlocked(&action_error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1508 CFErrorRef localError = NULL;
1509
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;
1516 return false;
1517 }
1518 return true;
1519 })) {
1520 if (action_error) {
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);
1525 } else {
1526 secerror("Unexpected error: %@", action_error);
1527 }
1528
1529 if (error && *error == NULL) {
1530 *error = action_error;
1531 action_error = NULL;
1532 }
1533
1534 CFReleaseNull(action_error);
1535 }
1536 }
1537
1538 return result;
1539 }
1540
1541 void SOSCCSyncWithAllPeers(void)
1542 {
1543 SOSCloudKeychainRequestSyncWithAllPeers(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
1544 }
1545
1546 CF_RETURNS_RETAINED CFArrayRef SOSCCHandleUpdateMessage(CFDictionaryRef updates)
1547 {
1548 CFArrayRef result = NULL;
1549 SOSAccountRef account = SOSKeychainAccountGetSharedAccount(); //HACK to make sure itemsChangedBlock is set
1550
1551 (account) ? (result = SOSCloudKeychainHandleUpdateMessage(updates)) : (result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault));
1552 return result;
1553 }