]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/SOSCloudCircleServer.c
Security-57337.20.44.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 CFStringRef kSOSBurnedRecoveryAttemptCount = CFSTR("Burned Recovery Attempt Count");
116
117 CFStringRef kSOSBurnedRecoveryAttemptAttestationDate = CFSTR("Burned Recovery Attempt Attestation Date");
118
119 static CFStringRef accountFileName = CFSTR("PersistedAccount.plist");
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 SOSAccountRef account = GetSharedAccount();
535
536 if(account){
537 dispatch_block_t do_action_and_save = ^{
538 SOSPeerInfoRef mpi = SOSAccountGetMyPeerInfo(account);
539 bool wasInCircle = SOSAccountIsInCircle(account, NULL);
540 CFSetRef beforeViews = mpi ? SOSPeerInfoCopyEnabledViews(mpi) : NULL;
541
542 action(account);
543
544 // Fake transaction around using the account object
545 SOSAccountFinishTransaction(account);
546
547 mpi = SOSAccountGetMyPeerInfo(account); // Update the peer
548 bool isInCircle = SOSAccountIsInCircle(account, NULL);
549
550 CFSetRef afterViews = mpi ? SOSPeerInfoCopyEnabledViews(mpi) : NULL;
551
552 if(!CFEqualSafe(beforeViews, afterViews) || wasInCircle != isInCircle) {
553 notify_post(kSOSCCViewMembershipChangedNotification);
554 }
555
556 CFReleaseNull(beforeViews);
557 CFReleaseNull(afterViews);
558
559 SOSKeychainAccountEnsureSaved(account);
560 };
561
562 if (sync) {
563 dispatch_sync(SOSAccountGetQueue(account), do_action_and_save);
564 } else {
565 dispatch_async(SOSAccountGetQueue(account), do_action_and_save);
566 }
567 }
568 }
569
570 __unused static void do_with_account_async(void (^action)(SOSAccountRef account)) {
571 do_with_account_dynamic(action, false);
572 }
573
574 static void do_with_account(void (^action)(SOSAccountRef account)) {
575 do_with_account_dynamic(action, true);
576 }
577
578 static bool do_if_after_first_unlock(CFErrorRef *error, dispatch_block_t action)
579 {
580 #if TARGET_IPHONE_SIMULATOR
581 action();
582 return true;
583 #else
584 bool beenUnlocked = false;
585 require_quiet(SecAKSGetHasBeenUnlocked(&beenUnlocked, error), fail);
586
587 require_action_quiet(beenUnlocked, fail,
588 SOSCreateErrorWithFormat(kSOSErrorNotReady, NULL, error, NULL,
589 CFSTR("Keybag never unlocked, ask after first unlock")));
590
591 action();
592 return true;
593
594 fail:
595 return false;
596 #endif
597 }
598
599 static bool do_with_account_if_after_first_unlock(CFErrorRef *error, bool (^action)(SOSAccountRef account, CFErrorRef* error))
600 {
601 __block bool action_result = false;
602
603 #if !(TARGET_OS_EMBEDDED)
604 if(geteuid() == 0){
605 secerror("Cannot inflate account object as root");
606 if(error)
607 *error = CFErrorCreate(kCFAllocatorDefault, CFSTR("com.apple.security"), RUN_AS_ROOT_ERROR, NULL);
608 return false;
609 }
610 #endif
611 return do_if_after_first_unlock(error, ^{
612 do_with_account(^(SOSAccountRef account) {
613 action_result = action(account, error);
614 });
615
616 }) && action_result;
617 }
618
619 static bool do_with_account_while_unlocked(CFErrorRef *error, bool (^action)(SOSAccountRef account, CFErrorRef* error))
620 {
621 __block bool action_result = false;
622
623 #if !(TARGET_OS_EMBEDDED)
624 if(geteuid() == 0){
625 secerror("Cannot inflate account object as root");
626 if(error)
627 *error = CFErrorCreate(kCFAllocatorDefault, CFSTR("com.apple.security"), RUN_AS_ROOT_ERROR, NULL);
628 return false;
629 }
630 #endif
631
632 return SecAKSDoWhileUserBagLocked(error, ^{
633 do_with_account(^(SOSAccountRef account) {
634 action_result = action(account, error);
635 });
636
637 }) && action_result;
638 }
639
640 SOSAccountRef SOSKeychainAccountGetSharedAccount()
641 {
642 __block SOSAccountRef result = NULL;
643
644 do_with_account(^(SOSAccountRef account) {
645 result = account;
646 });
647
648 return result;
649 }
650
651 //
652 // Mark: Credential processing
653 //
654
655
656 bool SOSCCTryUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFErrorRef *error)
657 {
658 return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
659 return SOSAccountTryUserCredentials(account, user_label, user_password, block_error);
660 });
661 }
662
663
664 SOSViewResultCode SOSCCView_Server(CFStringRef viewname, SOSViewActionCode action, CFErrorRef *error) {
665 __block SOSViewResultCode status = kSOSCCGeneralViewError;
666
667 do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
668 switch(action) {
669 case kSOSCCViewQuery:
670 status = SOSAccountViewStatus(account, viewname, error);
671 break;
672 case kSOSCCViewEnable:
673 case kSOSCCViewDisable: // fallthrough
674 status = SOSAccountUpdateView(account, viewname, action, error);
675 secnotice("views", "HEY!!!!!! I'm Changing VIEWS- %d", (int) status);
676 break;
677 default:
678 secnotice("views", "Bad SOSViewActionCode - %d", (int) action);
679 return false;
680 break;
681 }
682 return true;
683 });
684 return status;
685 }
686
687
688 bool SOSCCViewSet_Server(CFSetRef enabledViews, CFSetRef disabledViews) {
689 __block bool status = false;
690
691 do_with_account_if_after_first_unlock(NULL, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
692 status = SOSAccountUpdateViewSets(account, enabledViews, disabledViews);
693 return true;
694 });
695 return status;
696 }
697
698
699
700 SOSSecurityPropertyResultCode SOSCCSecurityProperty_Server(CFStringRef property, SOSSecurityPropertyActionCode action, CFErrorRef *error) {
701
702 __block SOSViewResultCode status = kSOSCCGeneralSecurityPropertyError;
703 do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
704 switch(action) {
705 case kSOSCCSecurityPropertyQuery:
706 status = SOSAccountSecurityPropertyStatus(account, property, error);
707 break;
708 case kSOSCCSecurityPropertyEnable:
709 case kSOSCCSecurityPropertyDisable: // fallthrough
710 status = SOSAccountUpdateSecurityProperty(account, property, action, error);
711 secnotice("secprop", "HEY!!!!!! I'm Changing SecurityProperties- %d", (int) status);
712 break;
713 default:
714 secnotice("secprop", "Bad SOSSecurityPropertyActionCode - %d", (int) action);
715 return false;
716 break;
717 }
718 return true;
719 });
720 return status;
721 }
722
723 void sync_the_last_data_to_kvs(SOSAccountRef account, bool waitForeverForSynchronization){
724
725 dispatch_semaphore_t wait_for = dispatch_semaphore_create(0);
726 dispatch_retain(wait_for); // Both this scope and the block own it.
727
728 __block bool success = false;
729
730 secnoticeq("force-push", "calling SOSCloudKeychainSynchronizeAndWait");
731
732 CFMutableArrayRef keysToGet = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
733
734 SOSCloudKeychainSynchronizeAndWait(keysToGet, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) {
735
736 if (sync_error) {
737 secerrorq("SOSCloudKeychainSynchronizeAndWait: %@", sync_error);
738 } else {
739 secnoticeq("force-push", "returned from call; in callback to SOSCloudKeychainSynchronizeAndWait: results: %@", returnedValues);
740
741 success = true;
742 }
743
744 dispatch_semaphore_signal(wait_for);
745 dispatch_release(wait_for);
746 });
747
748 CFReleaseNull(keysToGet);
749
750 if(waitForeverForSynchronization)
751 dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER);
752 else
753 dispatch_semaphore_wait(wait_for, dispatch_time(DISPATCH_TIME_NOW, 60ull * NSEC_PER_SEC));
754
755 dispatch_release(wait_for);
756 }
757
758 #define kWAIT2MINID "EFRESH"
759
760 static bool EnsureFreshParameters(SOSAccountRef account, CFErrorRef *error) {
761 dispatch_semaphore_t wait_for = dispatch_semaphore_create(0);
762 dispatch_retain(wait_for); // Both this scope and the block own it.
763
764 CFMutableArrayRef keysToGet = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
765 CFArrayAppendValue(keysToGet, kSOSKVSKeyParametersKey);
766 // Only get key parameters due to: <rdar://problem/22794892> Upgrading from Donner with an iCDP enabled account resets iCloud keychain on devices in circle
767
768 __block CFDictionaryRef valuesToUpdate = NULL;
769 __block bool success = false;
770
771 secnoticeq("fresh", "%s calling SOSCloudKeychainSynchronizeAndWait", kWAIT2MINID);
772
773 SOSCloudKeychainSynchronizeAndWait(keysToGet, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) {
774
775 if (sync_error) {
776 secerrorq("%s SOSCloudKeychainSynchronizeAndWait: %@", kWAIT2MINID, sync_error);
777 if (error) {
778 *error = sync_error;
779 CFRetainSafe(*error);
780 }
781 } else {
782 secnoticeq("fresh", "%s returned from call; in callback to SOSCloudKeychainSynchronizeAndWait: results: %@", kWAIT2MINID, returnedValues);
783 valuesToUpdate = returnedValues;
784 CFRetainSafe(valuesToUpdate);
785 success = true;
786 }
787
788 dispatch_semaphore_signal(wait_for);
789 dispatch_release(wait_for);
790 });
791
792 dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER);
793 // TODO: Maybe we timeout here... used to dispatch_time(DISPATCH_TIME_NOW, 30ull * NSEC_PER_SEC));
794 dispatch_release(wait_for);
795 CFMutableArrayRef handledKeys = NULL;
796 if ((valuesToUpdate) && (account)) {
797 handledKeys = SOSTransportDispatchMessages(account, valuesToUpdate, error);
798 if (!handledKeys) {
799 secerrorq("%s Freshness update failed: %@", kWAIT2MINID, error ? *error : NULL);
800 success = false;
801 }
802 }
803 CFReleaseNull(handledKeys);
804 CFReleaseNull(valuesToUpdate);
805 CFReleaseNull(keysToGet);
806
807 return success;
808 }
809
810 static bool Flush(CFErrorRef *error) {
811 __block bool success = false;
812
813 dispatch_semaphore_t wait_for = dispatch_semaphore_create(0);
814 dispatch_retain(wait_for); // Both this scope and the block own it.
815
816 secnotice("flush", "Starting");
817
818 SOSCloudKeychainFlush(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) {
819 success = (sync_error == NULL);
820 if (error) {
821 CFRetainAssign(*error, sync_error);
822 }
823
824 dispatch_semaphore_signal(wait_for);
825 dispatch_release(wait_for);
826 });
827
828 dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER);
829 dispatch_release(wait_for);
830
831 secnotice("flush", "Returned %s", success? "Success": "Failure");
832
833 return success;
834 }
835
836 static bool SOSCCAssertUserCredentialsAndOptionalDSID(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error) {
837 secnotice("updates", "Setting credentials and dsid (%@) for %@", dsid, user_label);
838 bool result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
839 if (dsid != NULL && CFStringCompare(dsid, CFSTR(""), 0) != 0) {
840 CFStringRef accountDSID = SOSAccountGetValue(account, kSOSDSIDKey, NULL);
841 if( accountDSID == NULL){
842 SOSAccountUpdateDSID(account, dsid);
843 secdebug("updates", "Setting dsid, current dsid is empty for this account: %@", dsid);
844 }
845 else if(CFStringCompare(dsid, accountDSID, 0) != kCFCompareEqualTo){
846 secnotice("updates", "Changing DSID from: %@ to %@", accountDSID, dsid);
847
848 //DSID has changed, blast the account!
849 SOSAccountSetToNew(account);
850
851 //update DSID to the new DSID
852 SOSAccountUpdateDSID(account, dsid);
853 }
854 else {
855 secnotice("updates", "Not Changing DSID: %@ to %@", accountDSID, dsid);
856 }
857
858 }
859
860 // Short Circuit if this passes, return immediately.
861 if(SOSAccountTryUserCredentials(account, user_label, user_password, NULL)) {
862 return true;
863 }
864
865 if (!EnsureFreshParameters(account, block_error)) {
866 return false;
867 }
868 if (!SOSAccountAssertUserCredentials(account, user_label, user_password, block_error)) {
869 secnotice("updates", "EnsureFreshParameters/SOSAccountAssertUserCredentials error: %@", *block_error);
870 return false;
871 }
872 return true;
873 });
874
875 if (result && Flush(error)) {
876 result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
877 return SOSAccountGenerationSignatureUpdate(account, error);
878 });
879 }
880
881 return result;
882 }
883
884 bool SOSCCSetUserCredentialsAndDSID_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error)
885 {
886 // TODO: Return error if DSID is NULL to insist our callers provide one?
887 return SOSCCAssertUserCredentialsAndOptionalDSID(user_label, user_password, dsid, error);
888 }
889
890 bool SOSCCSetUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFErrorRef *error)
891 {
892 return SOSCCAssertUserCredentialsAndOptionalDSID(user_label, user_password, NULL, error);
893 }
894
895 bool SOSCCCanAuthenticate_Server(CFErrorRef *error)
896 {
897 bool result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
898 return SOSAccountGetPrivateCredential(account, block_error) != NULL;
899 });
900
901 if (!result && error && *error && CFErrorGetDomain(*error) == kSOSErrorDomain) {
902 CFIndex code = CFErrorGetCode(*error);
903 if (code == kSOSErrorPrivateKeyAbsent || code == kSOSErrorPublicKeyAbsent) {
904 CFReleaseNull(*error);
905 }
906 }
907
908 return result;
909 }
910
911 bool SOSCCPurgeUserCredentials_Server(CFErrorRef *error)
912 {
913 return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
914 SOSAccountPurgePrivateCredential(account);
915 return true;
916 });
917 }
918
919 SOSCCStatus SOSCCThisDeviceIsInCircle_Server(CFErrorRef *error)
920 {
921 __block SOSCCStatus status;
922
923 return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
924 status = SOSAccountGetCircleStatus(account, block_error);
925 return true;
926 }) ? status : kSOSCCError;
927 }
928
929 bool SOSCCRequestToJoinCircle_Server(CFErrorRef* error)
930 {
931 __block bool result = true;
932
933 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
934 result = SOSAccountJoinCircles(account, block_error);
935 return result;
936 });
937 }
938
939 bool SOSCCRequestToJoinCircleAfterRestore_Server(CFErrorRef* error)
940 {
941 __block bool result = true;
942 bool returned = false;
943 returned = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
944 SOSAccountEnsurePeerRegistration(account, block_error);
945 result = SOSAccountJoinCirclesAfterRestore(account, block_error);
946 return result;
947 });
948 return returned;
949
950 }
951
952 bool SOSCCRequestEnsureFreshParameters_Server(CFErrorRef* error)
953 {
954 __block bool result = true;
955 bool returned = false;
956 returned = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
957 result = EnsureFreshParameters(account, NULL);
958 return result;
959 });
960 return returned;
961 }
962
963 bool SOSCCApplyToARing_Server(CFStringRef ringName, CFErrorRef *error){
964 __block bool result = true;
965 bool returned = false;
966 returned = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
967 SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInfo(account);
968 SOSRingRef ring = SOSAccountGetRing(account, ringName, error);
969 if(fpi && ring)
970 result = SOSRingApply(ring, account->user_public, fpi , error);
971 return result;
972 });
973 return returned;
974 }
975
976 bool SOSCCWithdrawlFromARing_Server(CFStringRef ringName, CFErrorRef *error){
977 __block bool result = true;
978 bool returned = false;
979 returned = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
980 SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInfo(account);
981 SOSRingRef ring = SOSAccountGetRing(account, ringName, error);
982 if(fpi && ring)
983 result = SOSRingWithdraw(ring, account->user_public, fpi , error);
984 return result;
985 });
986 return returned;
987 }
988
989 bool SOSCCEnableRing_Server(CFStringRef ringName, CFErrorRef *error){
990 __block bool result = true;
991 bool returned = false;
992 returned = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
993 SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInfo(account);
994 SOSRingRef ring = SOSAccountGetRing(account, ringName, error);
995 if(fpi && ring)
996 result = SOSRingResetToOffering(ring, NULL, fpi, error); ;
997 return result;
998 });
999 return returned;
1000 }
1001
1002 CFStringRef SOSCCGetAllTheRings_Server(CFErrorRef *error){
1003 __block CFMutableDictionaryRef result = NULL;
1004 __block CFMutableStringRef description = CFStringCreateMutable(kCFAllocatorDefault, 0);
1005
1006 (void) do_with_account_while_unlocked(error, ^bool(SOSAccountRef account, CFErrorRef *error) {
1007 result = SOSAccountGetRings(account, error);
1008
1009 if(isDictionary(result)){
1010 CFDictionaryForEach(result, ^(const void *key, const void *value) {
1011 CFStringAppendFormat(description, NULL, CFSTR("%@"), value);
1012 });
1013 }
1014 if(result)
1015 return true;
1016 return false;
1017 });
1018
1019 return description;
1020 }
1021
1022 SOSRingStatus SOSCCRingStatus_Server(CFStringRef ringName, CFErrorRef *error){
1023 __block bool result = true;
1024 SOSRingStatus returned;
1025 returned = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1026 SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInfo(account);
1027 SOSPeerInfoRef myPeer = SOSFullPeerInfoGetPeerInfo(fpi);
1028
1029 SOSRingRef ring = SOSAccountGetRing(account, ringName, error);
1030 if(myPeer && ring)
1031 result = SOSRingDeviceIsInRing(ring, SOSPeerInfoGetPeerID(myPeer));
1032 return result;
1033 });
1034 return returned;
1035 }
1036
1037 CFStringRef SOSCCCopyDeviceID_Server(CFErrorRef *error)
1038 {
1039 __block CFStringRef result = NULL;
1040
1041 (void) do_with_account_while_unlocked(error, ^bool(SOSAccountRef account, CFErrorRef *error) {
1042 result = SOSAccountCopyDeviceID(account, error);
1043 return (!isNull(result));
1044 });
1045 return result;
1046 }
1047
1048 bool SOSCCSetDeviceID_Server(CFStringRef IDS, CFErrorRef *error){
1049
1050 bool didSetID = false;
1051 __block bool result = false;
1052 __block CFErrorRef blockError = NULL;
1053
1054 didSetID = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1055 result = SOSAccountSetMyDSID(account, IDS, block_error);
1056 if(block_error)
1057 blockError = CFRetainSafe(*block_error);
1058 return result;
1059 });
1060
1061 if(error){
1062 *error = blockError;
1063 }
1064 return didSetID;
1065 }
1066
1067 HandleIDSMessageReason SOSCCHandleIDSMessage_Server(CFDictionaryRef messageDict, CFErrorRef* error)
1068 {
1069 // TODO: Locking flow:
1070 /*
1071 COMMON:
1072 - Get PeerCoder instance from SOSPeerCoderManager(Currently Engine)
1073 - Get Account lock and Initialize PeerCoder instance if it isn't valid yet.
1074 INCOMING:
1075 - Decode incoming msg on coder.
1076 - Pass msg along to SOSPeerRef if decoding is done.
1077 - Force reply from coder while in handshake mode. (or ask ckd to ask us later?)
1078 - save coder state.
1079
1080 - Lookup SOSPeerRef in SOSEngineRef (getting engine lock temporarily to get peer.
1081 - Ask peer to handle decoded message
1082 - be notified of changed objects in all peers and update peer/engine states
1083 - save peer/engine state
1084
1085 OUTGOING:
1086 - Ask coder to send an outgoing message if it is negotiating
1087 - Ask peer to create a message if needed
1088 - Encode peer msg with coder
1089 - save coder state
1090 - send reply to ckd for transporting
1091 */
1092
1093 __block HandleIDSMessageReason result = kHandleIDSMessageSuccess;
1094 CFErrorRef action_error = NULL;
1095
1096 if (!do_with_account_while_unlocked(&action_error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1097 result = SOSTransportMessageIDSHandleMessage(account, messageDict, error);
1098 return result;
1099 })) {
1100 if (action_error) {
1101 if (SecErrorGetOSStatus(action_error) == errSecInteractionNotAllowed) {
1102 secnotice("updates", "SOSCCHandleIDSMessage_Server failed because device is locked; letting IDSKeychainSyncingProxy know");
1103 result = kHandleIDSMessageLocked; // tell IDSKeychainSyncingProxy to call us back when device unlocks
1104 CFReleaseNull(action_error);
1105 } else {
1106 secerror("Unexpected error: %@", action_error);
1107 }
1108
1109 if (error && *error == NULL) {
1110 *error = action_error;
1111 action_error = NULL;
1112 }
1113
1114 CFReleaseNull(action_error);
1115 }
1116 }
1117 return result;
1118 }
1119
1120 bool SOSCCIDSPingTest_Server(CFStringRef message, CFErrorRef *error){
1121 bool didSendTestMessages = false;
1122 __block bool result = true;
1123 __block CFErrorRef blockError = NULL;
1124
1125 didSendTestMessages = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1126 result = SOSAccountStartPingTest(account, message, block_error);
1127 if(block_error)
1128 blockError = CFRetainSafe(*block_error);
1129 return result;
1130 });
1131 if(blockError && error != NULL)
1132 *error = blockError;
1133
1134 return didSendTestMessages;
1135 }
1136
1137 bool SOSCCIDSServiceRegistrationTest_Server(CFStringRef message, CFErrorRef *error){
1138 bool didSendTestMessages = false;
1139 __block bool result = true;
1140 __block CFErrorRef blockError = NULL;
1141
1142 didSendTestMessages = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1143 result = SOSAccountSendIDSTestMessage(account, message, &blockError);
1144 return result;
1145 });
1146 if(blockError != NULL && error != NULL)
1147 *error = blockError;
1148
1149 return didSendTestMessages;
1150 }
1151
1152 bool SOSCCIDSDeviceIDIsAvailableTest_Server(CFErrorRef *error){
1153 bool didSendTestMessages = false;
1154 __block bool result = true;
1155 __block CFErrorRef blockError = NULL;
1156
1157 didSendTestMessages = do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1158 result = SOSAccountRetrieveDeviceIDFromIDSKeychainSyncingProxy(account, &blockError);
1159 return result;
1160 });
1161 if(blockError && error != NULL)
1162 *error = blockError;
1163
1164 return didSendTestMessages;
1165 }
1166
1167 bool SOSCCAccountSetToNew_Server(CFErrorRef *error)
1168 {
1169 __block bool result = true;
1170
1171 return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1172 clearAllKVS(NULL);
1173 SOSAccountSetToNew(account);
1174 return result;
1175 });
1176 }
1177
1178 bool SOSCCResetToOffering_Server(CFErrorRef* error)
1179 {
1180 __block bool result = true;
1181
1182 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1183 clearAllKVS(NULL);
1184 result = SOSAccountResetToOffering(account, block_error);
1185 return result;
1186 });
1187
1188 }
1189
1190 bool SOSCCResetToEmpty_Server(CFErrorRef* error)
1191 {
1192 __block bool result = true;
1193
1194 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1195 result = SOSAccountResetToEmpty(account, block_error);
1196 return result;
1197 });
1198
1199 }
1200
1201 bool SOSCCRemoveThisDeviceFromCircle_Server(CFErrorRef* error)
1202 {
1203 __block bool result = true;
1204
1205 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1206 result = SOSAccountLeaveCircle(account, block_error);
1207 return result;
1208 });
1209 }
1210
1211 bool SOSCCRemovePeersFromCircle_Server(CFArrayRef peers, CFErrorRef* error)
1212 {
1213 __block bool result = true;
1214
1215 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1216 result = SOSAccountRemovePeersFromCircle(account, peers, block_error);
1217 return result;
1218 });
1219 }
1220
1221
1222 bool SOSCCLoggedOutOfAccount_Server(CFErrorRef *error)
1223 {
1224 __block bool result = true;
1225
1226 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1227 secnotice("sosops", "Signed out of account!");
1228
1229 bool waitForeverForSynchronization = true;
1230
1231 result = SOSAccountLeaveCircle(account, block_error);
1232
1233 SOSAccountFinishTransaction(account); // Make sure this gets finished before we set to new.
1234
1235 SOSAccountSetToNew(account);
1236
1237 sync_the_last_data_to_kvs(account, waitForeverForSynchronization);
1238
1239 return result;
1240 });
1241 }
1242
1243 bool SOSCCBailFromCircle_Server(uint64_t limit_in_seconds, CFErrorRef* error)
1244 {
1245 __block bool result = true;
1246
1247 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1248 bool waitForeverForSynchronization = false;
1249
1250 result = SOSAccountBail(account, limit_in_seconds, block_error);
1251
1252 SOSAccountFinishTransaction(account); // Make sure this gets finished before we set to new.
1253
1254 sync_the_last_data_to_kvs(account, waitForeverForSynchronization);
1255
1256 return result;
1257 });
1258
1259 }
1260
1261 CFArrayRef SOSCCCopyApplicantPeerInfo_Server(CFErrorRef* error)
1262 {
1263 __block CFArrayRef result = NULL;
1264
1265 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1266 result = SOSAccountCopyApplicants(account, block_error);
1267 return result != NULL;
1268 });
1269
1270 return result;
1271 }
1272
1273 CFArrayRef SOSCCCopyGenerationPeerInfo_Server(CFErrorRef* error)
1274 {
1275 __block CFArrayRef result = NULL;
1276
1277 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1278 result = SOSAccountCopyGeneration(account, block_error);
1279 return result != NULL;
1280 });
1281
1282 return result;
1283 }
1284
1285 CFArrayRef SOSCCCopyValidPeerPeerInfo_Server(CFErrorRef* error)
1286 {
1287 __block CFArrayRef result = NULL;
1288
1289 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1290 result = SOSAccountCopyValidPeers(account, block_error);
1291 return result != NULL;
1292 });
1293
1294 return result;
1295 }
1296
1297 bool SOSCCValidateUserPublic_Server(CFErrorRef* error)
1298 {
1299 __block bool result = NULL;
1300
1301 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1302 result = SOSValidateUserPublic(account, block_error);
1303 return result;
1304 });
1305
1306 return result;
1307 }
1308
1309 CFArrayRef SOSCCCopyNotValidPeerPeerInfo_Server(CFErrorRef* error)
1310 {
1311 __block CFArrayRef result = NULL;
1312
1313 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1314 result = SOSAccountCopyNotValidPeers(account, block_error);
1315 return result != NULL;
1316 });
1317
1318 return result;
1319 }
1320
1321 CFArrayRef SOSCCCopyRetirementPeerInfo_Server(CFErrorRef* error)
1322 {
1323 __block CFArrayRef result = NULL;
1324
1325 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1326 result = SOSAccountCopyRetired(account, block_error);
1327 return result != NULL;
1328 });
1329
1330 return result;
1331 }
1332
1333 CFArrayRef SOSCCCopyViewUnawarePeerInfo_Server(CFErrorRef* error)
1334 {
1335 __block CFArrayRef result = NULL;
1336
1337 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1338 result = SOSAccountCopyViewUnaware(account, block_error);
1339 return result != NULL;
1340 });
1341
1342 return result;
1343 }
1344
1345 CFArrayRef SOSCCCopyEngineState_Server(CFErrorRef* error)
1346 {
1347 CFArrayRef result = NULL;
1348 SOSDataSourceFactoryRef dsf = SecItemDataSourceFactoryGetDefault();
1349 SOSDataSourceRef ds = SOSDataSourceFactoryCreateDataSource(dsf, kSecAttrAccessibleWhenUnlocked, error);
1350 if (ds) {
1351 SOSEngineRef engine = SOSDataSourceGetSharedEngine(ds, error);
1352 result = SOSEngineCopyPeerConfirmedDigests(engine, error);
1353 SOSDataSourceRelease(ds, error);
1354 }
1355
1356 return result;
1357 }
1358
1359 bool SOSCCWaitForInitialSync_Server(CFErrorRef* error) {
1360 __block dispatch_semaphore_t inSyncSema = NULL;
1361
1362 bool result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1363 bool alreadyInSync = SOSAccountCheckHasBeenInSync(account);
1364 int token = -1;
1365 if (!alreadyInSync) {
1366 inSyncSema = dispatch_semaphore_create(0);
1367 dispatch_retain(inSyncSema);
1368 notify_register_dispatch(kSOSCCInitialSyncChangedNotification, &token,
1369 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(int token) {
1370 dispatch_semaphore_signal(inSyncSema);
1371 dispatch_release(inSyncSema);
1372
1373 notify_cancel(token);
1374 });
1375 }
1376 return true;
1377 });
1378
1379 if (result && inSyncSema != NULL) {
1380 dispatch_semaphore_wait(inSyncSema, DISPATCH_TIME_FOREVER);
1381 dispatch_release(inSyncSema);
1382 }
1383
1384 return result;
1385 }
1386
1387 static CFArrayRef SOSAccountCopyYetToSyncViews(SOSAccountRef account, CFErrorRef *error) {
1388 __block CFArrayRef result = NULL;
1389
1390 CFTypeRef valueFetched = SOSAccountGetValue(account, kSOSUnsyncedViewsKey, error);
1391 if (valueFetched == kCFBooleanTrue) {
1392 SOSPeerInfoRef myPI = SOSAccountGetMyPeerInfo(account);
1393 if (myPI) {
1394 SOSPeerInfoWithEnabledViewSet(myPI, ^(CFSetRef enabled) {
1395 result = CFSetCopyValues(enabled);
1396 });
1397 }
1398 } else if (isSet(valueFetched)) {
1399 result = CFSetCopyValues((CFSetRef)valueFetched);
1400 }
1401
1402 if (result == NULL) {
1403 result = CFArrayCreateForCFTypes(kCFAllocatorDefault, NULL);
1404 }
1405
1406 return result;
1407 }
1408
1409 CFArrayRef SOSCCCopyYetToSyncViewsList_Server(CFErrorRef* error) {
1410
1411 __block CFArrayRef views = NULL;
1412
1413 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1414 views = SOSAccountCopyYetToSyncViews(account, error);
1415
1416 return true;
1417 });
1418
1419 return views;
1420 }
1421
1422 CFDictionaryRef SOSCCCopyEscrowRecord_Server(CFErrorRef *error){
1423
1424 __block CFDictionaryRef result = NULL;
1425 __block CFErrorRef block_error = NULL;
1426
1427 (void) do_with_account_if_after_first_unlock(error, ^bool(SOSAccountRef account, CFErrorRef *error) {
1428 SOSCCStatus status = SOSAccountGetCircleStatus(account, &block_error);
1429 CFStringRef dsid = SOSAccountGetValue(account, kSOSDSIDKey, error);
1430 CFDictionaryRef escrowRecords = NULL;
1431 CFDictionaryRef record = NULL;
1432 switch(status) {
1433 case kSOSCCInCircle:
1434 //get the escrow record in the peer info!
1435 escrowRecords = SOSPeerInfoCopyEscrowRecord(SOSAccountGetMyPeerInfo(account));
1436 if(escrowRecords){
1437 record = CFDictionaryGetValue(escrowRecords, dsid);
1438 if(record)
1439 result = CFRetainSafe(record);
1440 }
1441 CFReleaseNull(escrowRecords);
1442 break;
1443 case kSOSCCRequestPending:
1444 //set the escrow record in the peer info/application?
1445 break;
1446 case kSOSCCNotInCircle:
1447 case kSOSCCCircleAbsent:
1448 //set the escrow record in the account expansion!
1449 escrowRecords = SOSAccountGetValue(account, kSOSEscrowRecord, error);
1450 if(escrowRecords){
1451 record = CFDictionaryGetValue(escrowRecords, dsid);
1452 if(record)
1453 result = CFRetainSafe(record);
1454 }
1455 break;
1456 default:
1457 secdebug("account", "no circle status!");
1458 break;
1459 }
1460 return true;
1461 });
1462
1463 return result;
1464 }
1465
1466 bool SOSCCSetEscrowRecord_Server(CFStringRef escrow_label, uint64_t tries, CFErrorRef *error){
1467
1468 __block bool result = true;
1469 __block CFErrorRef block_error = NULL;
1470
1471 (void) do_with_account_if_after_first_unlock(error, ^bool(SOSAccountRef account, CFErrorRef *error) {
1472 SOSCCStatus status = SOSAccountGetCircleStatus(account, &block_error);
1473 CFStringRef dsid = SOSAccountGetValue(account, kSOSDSIDKey, error);
1474
1475 CFMutableStringRef timeDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("["));
1476 CFAbsoluteTime currentTimeAndDate = CFAbsoluteTimeGetCurrent();
1477
1478 withStringOfAbsoluteTime(currentTimeAndDate, ^(CFStringRef decription) {
1479 CFStringAppend(timeDescription, decription);
1480 });
1481 CFStringAppend(timeDescription, CFSTR("]"));
1482
1483 CFNumberRef attempts = CFNumberCreate(kCFAllocatorDefault, kCFNumberLongLongType, (const void*)&tries);
1484
1485 CFMutableDictionaryRef escrowTimeAndTries = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
1486 CFDictionaryAddValue(escrowTimeAndTries, kSOSBurnedRecoveryAttemptCount, attempts);
1487 CFDictionaryAddValue(escrowTimeAndTries, kSOSBurnedRecoveryAttemptAttestationDate, timeDescription);
1488
1489 CFMutableDictionaryRef escrowRecord = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
1490 CFDictionaryAddValue(escrowRecord, escrow_label, escrowTimeAndTries);
1491
1492 switch(status) {
1493 case kSOSCCInCircle:
1494 //set the escrow record in the peer info!
1495 if(!SOSFullPeerInfoAddEscrowRecord(SOSAccountGetMyFullPeerInfo(account), dsid, escrowRecord, error)){
1496 secdebug("accout", "Could not set escrow record in the full peer info");
1497 result = false;
1498 }
1499 break;
1500 case kSOSCCRequestPending:
1501 //set the escrow record in the peer info/application?
1502 break;
1503 case kSOSCCNotInCircle:
1504 case kSOSCCCircleAbsent:
1505 //set the escrow record in the account expansion!
1506
1507 if(!SOSAccountAddEscrowRecords(account, dsid, escrowRecord, error)) {
1508 secdebug("account", "Could not set escrow record in expansion data");
1509 result = false;
1510 }
1511 break;
1512 default:
1513 secdebug("account", "no circle status!");
1514 break;
1515 }
1516 CFReleaseNull(attempts);
1517 CFReleaseNull(timeDescription);
1518 CFReleaseNull(escrowTimeAndTries);
1519 CFReleaseNull(escrowRecord);
1520
1521 return true;
1522 });
1523
1524 return result;
1525 }
1526
1527 bool SOSCCAcceptApplicants_Server(CFArrayRef applicants, CFErrorRef* error)
1528 {
1529 __block bool result = true;
1530 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1531 result = SOSAccountAcceptApplicants(account, applicants, block_error);
1532 return result;
1533 });
1534
1535 }
1536
1537 bool SOSCCRejectApplicants_Server(CFArrayRef applicants, CFErrorRef* error)
1538 {
1539 __block bool result = true;
1540 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1541 result = SOSAccountRejectApplicants(account, applicants, block_error);
1542 return result;
1543 });
1544 }
1545
1546 CFArrayRef SOSCCCopyPeerPeerInfo_Server(CFErrorRef* error)
1547 {
1548 __block CFArrayRef result = NULL;
1549
1550 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1551 result = SOSAccountCopyPeers(account, block_error);
1552 return result != NULL;
1553 });
1554
1555 return result;
1556 }
1557
1558 CFArrayRef SOSCCCopyConcurringPeerPeerInfo_Server(CFErrorRef* error)
1559 {
1560 __block CFArrayRef result = NULL;
1561
1562 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1563 result = SOSAccountCopyConcurringPeers(account, block_error);
1564 return result != NULL;
1565 });
1566
1567 return result;
1568 }
1569
1570 SOSPeerInfoRef SOSCCCopyMyPeerInfo_Server(CFErrorRef* error)
1571 {
1572 __block SOSPeerInfoRef result = NULL;
1573
1574 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1575 // Create a copy to be DERed/sent back to client
1576 result = SOSPeerInfoCreateCopy(kCFAllocatorDefault, SOSAccountGetMyPeerInfo(account), block_error);
1577 return result != NULL;
1578 });
1579
1580 return result;
1581 }
1582
1583 SOSPeerInfoRef SOSCCSetNewPublicBackupKey_Server(CFDataRef newPublicBackup, CFErrorRef *error){
1584 __block SOSPeerInfoRef result = NULL;
1585
1586 (void) do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1587 if(SOSAccountSetBackupPublicKey(account,newPublicBackup, error)){
1588 // Create a copy to be DERed/sent back to client
1589 result = SOSPeerInfoCreateCopy(kCFAllocatorDefault, SOSAccountGetMyPeerInfo(account), block_error);
1590 secdebug("backup", "SOSCCSetNewPublicBackupKey_Server, new public backup is set");
1591 }
1592 else
1593 {
1594 secerror("SOSCCSetNewPublicBackupKey_Server, could not set new public backup");
1595 }
1596 return result != NULL;
1597 });
1598
1599 return result;
1600 }
1601
1602 bool SOSCCRegisterSingleRecoverySecret_Server(CFDataRef aks_bag, bool setupV0Only, CFErrorRef *error){
1603 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1604 return SOSAccountSetBSKBagForAllSlices(account, aks_bag, setupV0Only, error);
1605 });
1606 }
1607
1608 CFStringRef SOSCCCopyIncompatibilityInfo_Server(CFErrorRef* error)
1609 {
1610 __block CFStringRef result = NULL;
1611
1612 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1613 result = SOSAccountCopyIncompatibilityInfo(account, block_error);
1614 return result != NULL;
1615 });
1616
1617 return result;
1618 }
1619
1620 bool SOSCCCheckPeerAvailability_Server(CFErrorRef *error)
1621 {
1622 __block bool pingedPeersInCircle = false;
1623 __block dispatch_semaphore_t peerSemaphore = NULL;
1624 __block bool peerIsAvailable = false;
1625
1626 static dispatch_queue_t time_out;
1627 static dispatch_once_t once;
1628 dispatch_once(&once, ^{
1629 time_out = dispatch_queue_create("peersAvailableTimeout", DISPATCH_QUEUE_SERIAL);
1630 });
1631 __block int token = -1;
1632
1633 bool result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1634
1635 peerSemaphore = dispatch_semaphore_create(0);
1636 dispatch_retain(peerSemaphore);
1637 notify_register_dispatch(kSOSCCPeerAvailable, &token, time_out, ^(int token) {
1638 if(peerSemaphore != NULL){
1639 dispatch_semaphore_signal(peerSemaphore);
1640 dispatch_release(peerSemaphore);
1641 peerIsAvailable = true;
1642 notify_cancel(token);
1643 }
1644 });
1645
1646 pingedPeersInCircle = SOSAccountCheckPeerAvailability(account, block_error);
1647 return pingedPeersInCircle;
1648 });
1649
1650 if (result) {
1651 dispatch_semaphore_wait(peerSemaphore, dispatch_time(DISPATCH_TIME_NOW, 7ull * NSEC_PER_SEC));
1652 }
1653
1654 if(peerSemaphore != NULL)
1655 dispatch_release(peerSemaphore);
1656
1657 if(time_out != NULL && peerSemaphore != NULL){
1658 dispatch_sync(time_out, ^{
1659 if(!peerIsAvailable){
1660 dispatch_release(peerSemaphore);
1661 peerSemaphore = NULL;
1662 notify_cancel(token);
1663 secnotice("peer available", "checking peer availability timed out, releasing semaphore");
1664 }
1665 });
1666 }
1667 if(!peerIsAvailable){
1668 CFStringRef errorMessage = CFSTR("There are no peers in the circle currently available");
1669 CFDictionaryRef userInfo = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, kCFErrorLocalizedDescriptionKey, errorMessage, NULL);
1670 if(error != NULL){
1671 *error =CFErrorCreate(kCFAllocatorDefault, CFSTR("com.apple.security.ids.error"), kSecIDSErrorNoPeersAvailable, userInfo);
1672 secerror("%@", *error);
1673 }
1674 CFReleaseNull(userInfo);
1675 return false;
1676 }
1677 else
1678 return true;
1679 }
1680
1681
1682
1683 enum DepartureReason SOSCCGetLastDepartureReason_Server(CFErrorRef* error)
1684 {
1685 __block enum DepartureReason result = kSOSDepartureReasonError;
1686
1687 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1688 result = SOSAccountGetLastDepartureReason(account, block_error);
1689 return result != kSOSDepartureReasonError;
1690 });
1691
1692 return result;
1693 }
1694
1695 bool SOSCCSetLastDepartureReason_Server(enum DepartureReason reason, CFErrorRef *error){
1696 __block bool result = true;
1697
1698 return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1699 SOSAccountSetLastDepartureReason(account, reason);
1700 return result;
1701 });
1702 }
1703
1704 bool SOSCCSetHSA2AutoAcceptInfo_Server(CFDataRef pubKey, CFErrorRef *error) {
1705 __block bool result = true;
1706
1707 return do_with_account_if_after_first_unlock(error, ^(SOSAccountRef account,
1708 CFErrorRef *block_error) {
1709 result = SOSAccountSetHSAPubKeyExpected(account, pubKey, error);
1710 return (bool)result;
1711 });
1712 }
1713
1714 bool SOSCCProcessEnsurePeerRegistration_Server(CFErrorRef* error)
1715 {
1716 secnotice("updates", "Request for registering peers");
1717 return do_with_account_while_unlocked(error, ^bool(SOSAccountRef account, CFErrorRef *error) {
1718 return SOSAccountEnsurePeerRegistration(account, error);
1719 });
1720 }
1721
1722 SyncWithAllPeersReason SOSCCProcessSyncWithAllPeers_Server(CFErrorRef* error)
1723 {
1724 /*
1725 #define kIOReturnLockedRead iokit_common_err(0x2c3) // device read locked
1726 #define kIOReturnLockedWrite iokit_common_err(0x2c4) // device write locked
1727 */
1728 __block SyncWithAllPeersReason result = kSyncWithAllPeersSuccess;
1729 CFErrorRef action_error = NULL;
1730
1731 if (!do_with_account_while_unlocked(&action_error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1732 CFErrorRef localError = NULL;
1733
1734 if (!SOSAccountSyncWithAllPeers(account, &localError)) {
1735 secerror("sync with all peers failed: %@", localError);
1736 CFReleaseSafe(localError);
1737 // This isn't a device-locked error, but returning false will
1738 // have CloudKeychainProxy ask us to try sync again after next unlock
1739 result = kSyncWithAllPeersOtherFail;
1740 return false;
1741 }
1742 return true;
1743 })) {
1744 if (action_error) {
1745 if (SecErrorGetOSStatus(action_error) == errSecInteractionNotAllowed) {
1746 secnotice("updates", "SOSAccountSyncWithAllPeers failed because device is locked; letting CloudKeychainProxy know");
1747 result = kSyncWithAllPeersLocked; // tell CloudKeychainProxy to call us back when device unlocks
1748 CFReleaseNull(action_error);
1749 } else {
1750 secerror("Unexpected error: %@", action_error);
1751 }
1752
1753 if (error && *error == NULL) {
1754 *error = action_error;
1755 action_error = NULL;
1756 }
1757
1758 CFReleaseNull(action_error);
1759 }
1760 }
1761
1762 return result;
1763 }
1764
1765 void SOSCCSyncWithAllPeers(void)
1766 {
1767 SOSCloudKeychainRequestSyncWithAllPeers(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
1768 }
1769
1770 CF_RETURNS_RETAINED CFArrayRef SOSCCHandleUpdateMessage(CFDictionaryRef updates)
1771 {
1772 CFArrayRef result = NULL;
1773 SOSAccountRef account = SOSKeychainAccountGetSharedAccount(); //HACK to make sure itemsChangedBlock is set
1774
1775 (account) ? (result = SOSCloudKeychainHandleUpdateMessage(updates)) : (result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault));
1776 return result;
1777 }