]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/SOSCloudCircleServer.c
Security-57336.10.29.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 != NULL && error != NULL)
1162 *error = blockError;
1163
1164
1165 return didSendTestMessages;
1166 }
1167
1168 bool SOSCCAccountSetToNew_Server(CFErrorRef *error)
1169 {
1170 __block bool result = true;
1171
1172 return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1173 clearAllKVS(NULL);
1174 SOSAccountSetToNew(account);
1175 return result;
1176 });
1177 }
1178
1179 bool SOSCCResetToOffering_Server(CFErrorRef* error)
1180 {
1181 __block bool result = true;
1182
1183 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1184 clearAllKVS(NULL);
1185 result = SOSAccountResetToOffering(account, block_error);
1186 return result;
1187 });
1188
1189 }
1190
1191 bool SOSCCResetToEmpty_Server(CFErrorRef* error)
1192 {
1193 __block bool result = true;
1194
1195 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1196 result = SOSAccountResetToEmpty(account, block_error);
1197 return result;
1198 });
1199
1200 }
1201
1202 bool SOSCCRemoveThisDeviceFromCircle_Server(CFErrorRef* error)
1203 {
1204 __block bool result = true;
1205
1206 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1207 result = SOSAccountLeaveCircle(account, block_error);
1208 return result;
1209 });
1210 }
1211
1212 bool SOSCCRemovePeersFromCircle_Server(CFArrayRef peers, CFErrorRef* error)
1213 {
1214 __block bool result = true;
1215
1216 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1217 result = SOSAccountRemovePeersFromCircle(account, peers, block_error);
1218 return result;
1219 });
1220 }
1221
1222
1223 bool SOSCCLoggedOutOfAccount_Server(CFErrorRef *error)
1224 {
1225 __block bool result = true;
1226
1227 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1228 secnotice("sosops", "Signed out of account!");
1229
1230 bool waitForeverForSynchronization = true;
1231
1232 result = SOSAccountLeaveCircle(account, block_error);
1233
1234 SOSAccountFinishTransaction(account); // Make sure this gets finished before we set to new.
1235
1236 SOSAccountSetToNew(account);
1237
1238 sync_the_last_data_to_kvs(account, waitForeverForSynchronization);
1239
1240 return result;
1241 });
1242 }
1243
1244 bool SOSCCBailFromCircle_Server(uint64_t limit_in_seconds, CFErrorRef* error)
1245 {
1246 __block bool result = true;
1247
1248 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1249 bool waitForeverForSynchronization = false;
1250
1251 result = SOSAccountBail(account, limit_in_seconds, block_error);
1252
1253 SOSAccountFinishTransaction(account); // Make sure this gets finished before we set to new.
1254
1255 sync_the_last_data_to_kvs(account, waitForeverForSynchronization);
1256
1257 return result;
1258 });
1259
1260 }
1261
1262 CFArrayRef SOSCCCopyApplicantPeerInfo_Server(CFErrorRef* error)
1263 {
1264 __block CFArrayRef result = NULL;
1265
1266 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1267 result = SOSAccountCopyApplicants(account, block_error);
1268 return result != NULL;
1269 });
1270
1271 return result;
1272 }
1273
1274 CFArrayRef SOSCCCopyGenerationPeerInfo_Server(CFErrorRef* error)
1275 {
1276 __block CFArrayRef result = NULL;
1277
1278 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1279 result = SOSAccountCopyGeneration(account, block_error);
1280 return result != NULL;
1281 });
1282
1283 return result;
1284 }
1285
1286 CFArrayRef SOSCCCopyValidPeerPeerInfo_Server(CFErrorRef* error)
1287 {
1288 __block CFArrayRef result = NULL;
1289
1290 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1291 result = SOSAccountCopyValidPeers(account, block_error);
1292 return result != NULL;
1293 });
1294
1295 return result;
1296 }
1297
1298 bool SOSCCValidateUserPublic_Server(CFErrorRef* error)
1299 {
1300 __block bool result = NULL;
1301
1302 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1303 result = SOSValidateUserPublic(account, block_error);
1304 return result;
1305 });
1306
1307 return result;
1308 }
1309
1310 CFArrayRef SOSCCCopyNotValidPeerPeerInfo_Server(CFErrorRef* error)
1311 {
1312 __block CFArrayRef result = NULL;
1313
1314 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1315 result = SOSAccountCopyNotValidPeers(account, block_error);
1316 return result != NULL;
1317 });
1318
1319 return result;
1320 }
1321
1322 CFArrayRef SOSCCCopyRetirementPeerInfo_Server(CFErrorRef* error)
1323 {
1324 __block CFArrayRef result = NULL;
1325
1326 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1327 result = SOSAccountCopyRetired(account, block_error);
1328 return result != NULL;
1329 });
1330
1331 return result;
1332 }
1333
1334 CFArrayRef SOSCCCopyViewUnawarePeerInfo_Server(CFErrorRef* error)
1335 {
1336 __block CFArrayRef result = NULL;
1337
1338 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1339 result = SOSAccountCopyViewUnaware(account, block_error);
1340 return result != NULL;
1341 });
1342
1343 return result;
1344 }
1345
1346 CFArrayRef SOSCCCopyEngineState_Server(CFErrorRef* error)
1347 {
1348 CFArrayRef result = NULL;
1349 SOSDataSourceFactoryRef dsf = SecItemDataSourceFactoryGetDefault();
1350 SOSDataSourceRef ds = SOSDataSourceFactoryCreateDataSource(dsf, kSecAttrAccessibleWhenUnlocked, error);
1351 if (ds) {
1352 SOSEngineRef engine = SOSDataSourceGetSharedEngine(ds, error);
1353 result = SOSEngineCopyPeerConfirmedDigests(engine, error);
1354 SOSDataSourceRelease(ds, error);
1355 }
1356
1357 return result;
1358 }
1359
1360 bool SOSCCWaitForInitialSync_Server(CFErrorRef* error) {
1361 __block dispatch_semaphore_t inSyncSema = NULL;
1362
1363 bool result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1364 bool alreadyInSync = SOSAccountCheckHasBeenInSync(account);
1365 int token = -1;
1366 if (!alreadyInSync) {
1367 inSyncSema = dispatch_semaphore_create(0);
1368 dispatch_retain(inSyncSema);
1369 notify_register_dispatch(kSOSCCInitialSyncChangedNotification, &token,
1370 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(int token) {
1371 dispatch_semaphore_signal(inSyncSema);
1372 dispatch_release(inSyncSema);
1373
1374 notify_cancel(token);
1375 });
1376 }
1377 return true;
1378 });
1379
1380 if (result && inSyncSema != NULL) {
1381 dispatch_semaphore_wait(inSyncSema, DISPATCH_TIME_FOREVER);
1382 dispatch_release(inSyncSema);
1383 }
1384
1385 return result;
1386 }
1387
1388 static CFArrayRef SOSAccountCopyYetToSyncViews(SOSAccountRef account, CFErrorRef *error) {
1389 CFArrayRef result = NULL;
1390
1391 CFTypeRef valueFetched = SOSAccountGetValue(account, kSOSUnsyncedViewsKey, error);
1392 if (valueFetched == kCFBooleanTrue) {
1393 SOSPeerInfoRef myPI = SOSAccountGetMyPeerInfo(account);
1394 if (myPI) {
1395 SOSPeerInfoWithEnabledViewSet(myPI, ^(CFSetRef enabled) {
1396 CFSetCopyValues(enabled);
1397 });
1398 }
1399 } else if (isSet(valueFetched)) {
1400 result = CFSetCopyValues((CFSetRef)valueFetched);
1401 }
1402
1403 if (result == NULL) {
1404 result = CFArrayCreateForCFTypes(kCFAllocatorDefault, NULL);
1405 }
1406
1407 return result;
1408 }
1409
1410 CFArrayRef SOSCCCopyYetToSyncViewsList_Server(CFErrorRef* error) {
1411
1412 __block CFArrayRef views = NULL;
1413
1414 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1415 views = SOSAccountCopyYetToSyncViews(account, error);
1416
1417 return true;
1418 });
1419
1420 return views;
1421 }
1422
1423 CFDictionaryRef SOSCCCopyEscrowRecord_Server(CFErrorRef *error){
1424
1425 __block CFDictionaryRef result = NULL;
1426 __block CFErrorRef block_error = NULL;
1427
1428 (void) do_with_account_if_after_first_unlock(error, ^bool(SOSAccountRef account, CFErrorRef *error) {
1429 SOSCCStatus status = SOSAccountGetCircleStatus(account, &block_error);
1430 CFStringRef dsid = SOSAccountGetValue(account, kSOSDSIDKey, error);
1431 CFDictionaryRef escrowRecords = NULL;
1432 CFDictionaryRef record = NULL;
1433 switch(status) {
1434 case kSOSCCInCircle:
1435 //get the escrow record in the peer info!
1436 escrowRecords = SOSPeerInfoCopyEscrowRecord(SOSAccountGetMyPeerInfo(account));
1437 if(escrowRecords){
1438 record = CFDictionaryGetValue(escrowRecords, dsid);
1439 if(record)
1440 result = CFRetainSafe(record);
1441 }
1442 CFReleaseNull(escrowRecords);
1443 break;
1444 case kSOSCCRequestPending:
1445 //set the escrow record in the peer info/application?
1446 break;
1447 case kSOSCCNotInCircle:
1448 case kSOSCCCircleAbsent:
1449 //set the escrow record in the account expansion!
1450 escrowRecords = SOSAccountGetValue(account, kSOSEscrowRecord, error);
1451 if(escrowRecords){
1452 record = CFDictionaryGetValue(escrowRecords, dsid);
1453 if(record)
1454 result = CFRetainSafe(record);
1455 }
1456 break;
1457 default:
1458 secdebug("account", "no circle status!");
1459 break;
1460 }
1461 return true;
1462 });
1463
1464 return result;
1465 }
1466
1467 bool SOSCCSetEscrowRecord_Server(CFStringRef escrow_label, uint64_t tries, CFErrorRef *error){
1468
1469 __block bool result = true;
1470 __block CFErrorRef block_error = NULL;
1471
1472 (void) do_with_account_if_after_first_unlock(error, ^bool(SOSAccountRef account, CFErrorRef *error) {
1473 SOSCCStatus status = SOSAccountGetCircleStatus(account, &block_error);
1474 CFStringRef dsid = SOSAccountGetValue(account, kSOSDSIDKey, error);
1475
1476 CFMutableStringRef timeDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("["));
1477 CFAbsoluteTime currentTimeAndDate = CFAbsoluteTimeGetCurrent();
1478
1479 withStringOfAbsoluteTime(currentTimeAndDate, ^(CFStringRef decription) {
1480 CFStringAppend(timeDescription, decription);
1481 });
1482 CFStringAppend(timeDescription, CFSTR("]"));
1483
1484 CFNumberRef attempts = CFNumberCreate(kCFAllocatorDefault, kCFNumberLongLongType, (const void*)&tries);
1485
1486 CFMutableDictionaryRef escrowTimeAndTries = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
1487 CFDictionaryAddValue(escrowTimeAndTries, kSOSBurnedRecoveryAttemptCount, attempts);
1488 CFDictionaryAddValue(escrowTimeAndTries, kSOSBurnedRecoveryAttemptAttestationDate, timeDescription);
1489
1490 CFMutableDictionaryRef escrowRecord = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
1491 CFDictionaryAddValue(escrowRecord, escrow_label, escrowTimeAndTries);
1492
1493 switch(status) {
1494 case kSOSCCInCircle:
1495 //set the escrow record in the peer info!
1496 if(!SOSFullPeerInfoAddEscrowRecord(SOSAccountGetMyFullPeerInfo(account), dsid, escrowRecord, error)){
1497 secdebug("accout", "Could not set escrow record in the full peer info");
1498 result = false;
1499 }
1500 break;
1501 case kSOSCCRequestPending:
1502 //set the escrow record in the peer info/application?
1503 break;
1504 case kSOSCCNotInCircle:
1505 case kSOSCCCircleAbsent:
1506 //set the escrow record in the account expansion!
1507
1508 if(!SOSAccountAddEscrowRecords(account, dsid, escrowRecord, error)) {
1509 secdebug("account", "Could not set escrow record in expansion data");
1510 result = false;
1511 }
1512 break;
1513 default:
1514 secdebug("account", "no circle status!");
1515 break;
1516 }
1517 CFReleaseNull(attempts);
1518 CFReleaseNull(timeDescription);
1519 CFReleaseNull(escrowTimeAndTries);
1520 CFReleaseNull(escrowRecord);
1521
1522 return true;
1523 });
1524
1525 return result;
1526 }
1527
1528 bool SOSCCAcceptApplicants_Server(CFArrayRef applicants, CFErrorRef* error)
1529 {
1530 __block bool result = true;
1531 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1532 result = SOSAccountAcceptApplicants(account, applicants, block_error);
1533 return result;
1534 });
1535
1536 }
1537
1538 bool SOSCCRejectApplicants_Server(CFArrayRef applicants, CFErrorRef* error)
1539 {
1540 __block bool result = true;
1541 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1542 result = SOSAccountRejectApplicants(account, applicants, block_error);
1543 return result;
1544 });
1545 }
1546
1547 CFArrayRef SOSCCCopyPeerPeerInfo_Server(CFErrorRef* error)
1548 {
1549 __block CFArrayRef result = NULL;
1550
1551 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1552 result = SOSAccountCopyPeers(account, block_error);
1553 return result != NULL;
1554 });
1555
1556 return result;
1557 }
1558
1559 CFArrayRef SOSCCCopyConcurringPeerPeerInfo_Server(CFErrorRef* error)
1560 {
1561 __block CFArrayRef result = NULL;
1562
1563 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1564 result = SOSAccountCopyConcurringPeers(account, block_error);
1565 return result != NULL;
1566 });
1567
1568 return result;
1569 }
1570
1571 SOSPeerInfoRef SOSCCCopyMyPeerInfo_Server(CFErrorRef* error)
1572 {
1573 __block SOSPeerInfoRef result = NULL;
1574
1575 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1576 // Create a copy to be DERed/sent back to client
1577 result = SOSPeerInfoCreateCopy(kCFAllocatorDefault, SOSAccountGetMyPeerInfo(account), block_error);
1578 return result != NULL;
1579 });
1580
1581 return result;
1582 }
1583
1584 SOSPeerInfoRef SOSCCSetNewPublicBackupKey_Server(CFDataRef newPublicBackup, CFErrorRef *error){
1585 __block SOSPeerInfoRef result = NULL;
1586
1587 (void) do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1588 if(SOSAccountSetBackupPublicKey(account,newPublicBackup, error)){
1589 // Create a copy to be DERed/sent back to client
1590 result = SOSPeerInfoCreateCopy(kCFAllocatorDefault, SOSAccountGetMyPeerInfo(account), block_error);
1591 secdebug("backup", "SOSCCSetNewPublicBackupKey_Server, new public backup is set");
1592 }
1593 else
1594 {
1595 secerror("SOSCCSetNewPublicBackupKey_Server, could not set new public backup");
1596 }
1597 return result != NULL;
1598 });
1599
1600 return result;
1601 }
1602
1603 bool SOSCCRegisterSingleRecoverySecret_Server(CFDataRef aks_bag, bool setupV0Only, CFErrorRef *error){
1604 return do_with_account_while_unlocked(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1605 return SOSAccountSetBSKBagForAllSlices(account, aks_bag, setupV0Only, error);
1606 });
1607 }
1608
1609 CFStringRef SOSCCCopyIncompatibilityInfo_Server(CFErrorRef* error)
1610 {
1611 __block CFStringRef result = NULL;
1612
1613 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1614 result = SOSAccountCopyIncompatibilityInfo(account, block_error);
1615 return result != NULL;
1616 });
1617
1618 return result;
1619 }
1620
1621 bool SOSCCCheckPeerAvailability_Server(CFErrorRef *error)
1622 {
1623 __block bool pingedPeersInCircle = false;
1624 __block dispatch_semaphore_t peerSemaphore = NULL;
1625 __block bool peerIsAvailable = false;
1626
1627 static dispatch_queue_t time_out;
1628 static dispatch_once_t once;
1629 dispatch_once(&once, ^{
1630 time_out = dispatch_queue_create("peersAvailableTimeout", DISPATCH_QUEUE_SERIAL);
1631 });
1632 __block int token = -1;
1633
1634 bool result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1635
1636 peerSemaphore = dispatch_semaphore_create(0);
1637 dispatch_retain(peerSemaphore);
1638 notify_register_dispatch(kSOSCCPeerAvailable, &token, time_out, ^(int token) {
1639 if(peerSemaphore != NULL){
1640 dispatch_semaphore_signal(peerSemaphore);
1641 dispatch_release(peerSemaphore);
1642 peerIsAvailable = true;
1643 notify_cancel(token);
1644 }
1645 });
1646
1647 pingedPeersInCircle = SOSAccountCheckPeerAvailability(account, block_error);
1648 return pingedPeersInCircle;
1649 });
1650
1651 if (result) {
1652 dispatch_semaphore_wait(peerSemaphore, dispatch_time(DISPATCH_TIME_NOW, 7ull * NSEC_PER_SEC));
1653 }
1654
1655 if(peerSemaphore != NULL)
1656 dispatch_release(peerSemaphore);
1657
1658 if(time_out != NULL && peerSemaphore != NULL){
1659 dispatch_sync(time_out, ^{
1660 if(!peerIsAvailable){
1661 dispatch_release(peerSemaphore);
1662 peerSemaphore = NULL;
1663 notify_cancel(token);
1664 secnotice("peer available", "checking peer availability timed out, releasing semaphore");
1665 }
1666 });
1667 }
1668 if(!peerIsAvailable){
1669 CFStringRef errorMessage = CFSTR("There are no peers in the circle currently available");
1670 CFDictionaryRef userInfo = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, kCFErrorLocalizedDescriptionKey, errorMessage, NULL);
1671 if(error != NULL){
1672 *error =CFErrorCreate(kCFAllocatorDefault, CFSTR("com.apple.security.ids.error"), kSecIDSErrorNoPeersAvailable, userInfo);
1673 secerror("%@", *error);
1674 }
1675 CFReleaseNull(userInfo);
1676 return false;
1677 }
1678 else
1679 return true;
1680 }
1681
1682
1683
1684 enum DepartureReason SOSCCGetLastDepartureReason_Server(CFErrorRef* error)
1685 {
1686 __block enum DepartureReason result = kSOSDepartureReasonError;
1687
1688 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1689 result = SOSAccountGetLastDepartureReason(account, block_error);
1690 return result != kSOSDepartureReasonError;
1691 });
1692
1693 return result;
1694 }
1695
1696 bool SOSCCSetLastDepartureReason_Server(enum DepartureReason reason, CFErrorRef *error){
1697 __block bool result = true;
1698
1699 return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1700 SOSAccountSetLastDepartureReason(account, reason);
1701 return result;
1702 });
1703 }
1704
1705 bool SOSCCSetHSA2AutoAcceptInfo_Server(CFDataRef pubKey, CFErrorRef *error) {
1706 __block bool result = true;
1707
1708 return do_with_account_if_after_first_unlock(error, ^(SOSAccountRef account,
1709 CFErrorRef *block_error) {
1710 result = SOSAccountSetHSAPubKeyExpected(account, pubKey, error);
1711 return (bool)result;
1712 });
1713 }
1714
1715 bool SOSCCProcessEnsurePeerRegistration_Server(CFErrorRef* error)
1716 {
1717 secnotice("updates", "Request for registering peers");
1718 return do_with_account_while_unlocked(error, ^bool(SOSAccountRef account, CFErrorRef *error) {
1719 return SOSAccountEnsurePeerRegistration(account, error);
1720 });
1721 }
1722
1723 SyncWithAllPeersReason SOSCCProcessSyncWithAllPeers_Server(CFErrorRef* error)
1724 {
1725 /*
1726 #define kIOReturnLockedRead iokit_common_err(0x2c3) // device read locked
1727 #define kIOReturnLockedWrite iokit_common_err(0x2c4) // device write locked
1728 */
1729 __block SyncWithAllPeersReason result = kSyncWithAllPeersSuccess;
1730 CFErrorRef action_error = NULL;
1731
1732 if (!do_with_account_while_unlocked(&action_error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
1733 CFErrorRef localError = NULL;
1734
1735 if (!SOSAccountSyncWithAllPeers(account, &localError)) {
1736 secerror("sync with all peers failed: %@", localError);
1737 CFReleaseSafe(localError);
1738 // This isn't a device-locked error, but returning false will
1739 // have CloudKeychainProxy ask us to try sync again after next unlock
1740 result = kSyncWithAllPeersOtherFail;
1741 return false;
1742 }
1743 return true;
1744 })) {
1745 if (action_error) {
1746 if (SecErrorGetOSStatus(action_error) == errSecInteractionNotAllowed) {
1747 secnotice("updates", "SOSAccountSyncWithAllPeers failed because device is locked; letting CloudKeychainProxy know");
1748 result = kSyncWithAllPeersLocked; // tell CloudKeychainProxy to call us back when device unlocks
1749 CFReleaseNull(action_error);
1750 } else {
1751 secerror("Unexpected error: %@", action_error);
1752 }
1753
1754 if (error && *error == NULL) {
1755 *error = action_error;
1756 action_error = NULL;
1757 }
1758
1759 CFReleaseNull(action_error);
1760 }
1761 }
1762
1763 return result;
1764 }
1765
1766 void SOSCCSyncWithAllPeers(void)
1767 {
1768 SOSCloudKeychainRequestSyncWithAllPeers(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
1769 }
1770
1771 CF_RETURNS_RETAINED CFArrayRef SOSCCHandleUpdateMessage(CFDictionaryRef updates)
1772 {
1773 CFArrayRef result = NULL;
1774 SOSAccountRef account = SOSKeychainAccountGetSharedAccount(); //HACK to make sure itemsChangedBlock is set
1775
1776 (account) ? (result = SOSCloudKeychainHandleUpdateMessage(updates)) : (result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault));
1777 return result;
1778 }