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