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