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