]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/SOSCloudCircleServer.m
Security-58286.260.20.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([account isInCircle: NULL]) {
676 if(![SOSAuthKitHelpers peerinfoHasMID: account]) {
677 // This is the first good opportunity to update our FullPeerInfo and
678 // push the resulting circle.
679 [SOSAuthKitHelpers updateMIDInPeerInfo: account];
680 }
681 }
682 attempted_action = true;
683 action_result = action(txn, error);
684 });
685 });
686
687 // For <rdar://problem/24355048> 13E196: Circle join fails after successful recovery with a mach error if performed while device is locked
688 // 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.
689 // we assume our caller will hold the lock assertion for us to finsh our job.
690 // to be extra paranoid we track if we tried the caller's block. If we did we don't do it again.
691
692 if(result || !isAssertionLockAcquireError(localError)){
693 if (error && !*error && localError) {
694 CFTransferRetained(*error, localError);
695 }
696 CFReleaseNull(localError);
697 CFReleaseNull(statusError);
698
699 return (result && action_result);
700 }
701 if(attempted_action){
702 if (error && !*error && localError) {
703 CFTransferRetained(*error, localError);
704 }
705 CFReleaseNull(localError);
706 CFReleaseNull(statusError);
707
708 return (result && action_result);
709 }
710
711 bool isUnlocked = false;
712 (void) SecAKSGetIsUnlocked(&isUnlocked, &statusError);
713 if(!isUnlocked){
714 secnotice("while-unlocked-hack", "Not trying action, aks bag locked (%@)", statusError);
715 if (error && !*error && localError) {
716 CFTransferRetained(*error, localError);
717 }
718 CFReleaseNull(localError);
719 CFReleaseNull(statusError);
720
721 return result && action_result;
722 }
723
724 CFReleaseNull(localError);
725
726 secnotice("while-unlocked-hack", "Trying action while unlocked without assertion");
727
728 result = true;
729 do_with_account(^(SOSAccountTransaction* txn) {
730 action_result = action(txn, &localError);
731 });
732
733 secnotice("while-unlocked-hack", "Action %s (%@)", action_result ? "succeeded" : "failed", localError);
734
735 if (error && !*error && localError) {
736 CFTransferRetained(*error, localError);
737 }
738 CFReleaseNull(localError);
739 CFReleaseNull(statusError);
740
741 return result && action_result;
742 }
743
744
745
746 CFTypeRef SOSKeychainAccountGetSharedAccount()
747 {
748 __block SOSAccount* result = NULL;
749 CFErrorRef localError = NULL;
750
751 bool success = do_with_account_if_after_first_unlock(&localError, ^bool (SOSAccountTransaction* txn, CFErrorRef *error) {
752 result = txn.account;
753 return true;
754 });
755
756 if(!success) {
757 secnotice("secAccount", "Failed request for account object (%@)", localError);
758 CFReleaseNull(localError);
759 }
760
761 return (__bridge CFTypeRef)result;
762 }
763
764 //
765 // Mark: Credential processing
766 //
767
768 bool SOSCCTryUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error) {
769 secnotice("updates", "Trying credentials and dsid (%@) for %@", dsid, user_label);
770
771 return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
772 if (dsid != NULL && CFStringCompare(dsid, CFSTR(""), 0) != 0) {
773 SOSAccountAssertDSID(txn.account, dsid);
774 }
775 return SOSAccountTryUserCredentials(txn.account, user_label, user_password, block_error);
776 });
777 }
778
779 SOSViewResultCode SOSCCView_Server(CFStringRef viewname, SOSViewActionCode action, CFErrorRef *error) {
780 __block SOSViewResultCode status = kSOSCCGeneralViewError;
781
782 do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
783 bool retval = false;
784
785 switch(action) {
786 case kSOSCCViewQuery:
787 status = [txn.account.trust viewStatus:txn.account name:viewname err:error];
788 retval = true;
789 break;
790 case kSOSCCViewEnable:
791 status = [txn.account.trust updateView:txn.account name:viewname code:action err:error];
792 retval = true;
793 break;
794
795 case kSOSCCViewDisable:
796 status = [txn.account.trust updateView:txn.account name:viewname code:action err:error];
797 retval = true;
798 break;
799 default:
800 secnotice("views", "Bad SOSViewActionCode - %d", (int) action);
801 retval = false;
802 break;
803 }
804 return retval;
805 });
806 return status;
807 }
808
809 bool SOSCCViewSetWithAnalytics_Server(CFSetRef enabledViews, CFSetRef disabledViews, CFDataRef parentEvent) {
810 __block bool status = false;
811
812 do_with_account_if_after_first_unlock(NULL, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
813 status = [txn.account.trust updateViewSetsWithAnalytics:txn.account enabled:enabledViews disabled:disabledViews parentEvent:(__bridge NSData*)parentEvent];
814 return true;
815 });
816 return status;
817 }
818
819 bool SOSCCViewSet_Server(CFSetRef enabledViews, CFSetRef disabledViews) {
820 __block bool status = false;
821
822 do_with_account_if_after_first_unlock(NULL, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
823 status = [txn.account.trust updateViewSets:txn.account enabled:enabledViews disabled:disabledViews];
824 return true;
825 });
826 return status;
827 }
828
829
830 void sync_the_last_data_to_kvs(CFTypeRef account, bool waitForeverForSynchronization){
831
832 dispatch_semaphore_t wait_for = dispatch_semaphore_create(0);
833
834 secnoticeq("force-push", "calling SOSCloudKeychainSynchronizeAndWait");
835
836 SOSCloudKeychainSynchronizeAndWait(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) {
837 if (sync_error) {
838 secerrorq("SOSCloudKeychainSynchronizeAndWait: %@", sync_error);
839 } else {
840 secnoticeq("force-push", "returned from call; in callback to SOSCloudKeychainSynchronizeAndWait: results: %@", returnedValues);
841 }
842
843 dispatch_semaphore_signal(wait_for);
844 });
845
846 if(waitForeverForSynchronization)
847 dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER);
848 else
849 dispatch_semaphore_wait(wait_for, dispatch_time(DISPATCH_TIME_NOW, 60ull * NSEC_PER_SEC));
850
851 wait_for = nil;
852 }
853
854 #define kWAIT2MINID "EFRESH"
855
856 static bool SyncKVSAndWait(CFErrorRef *error) {
857 dispatch_semaphore_t wait_for = dispatch_semaphore_create(0);
858
859 __block bool success = false;
860
861 secnoticeq("fresh", "EFP calling SOSCloudKeychainSynchronizeAndWait");
862
863 os_activity_initiate("CloudCircle EFRESH", OS_ACTIVITY_FLAG_DEFAULT, ^(void) {
864 SOSCloudKeychainSynchronizeAndWait(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(__unused CFDictionaryRef returnedValues, CFErrorRef sync_error) {
865 secnotice("fresh", "EFP returned, callback error: %@", sync_error);
866
867 success = (sync_error == NULL);
868 if (error) {
869 CFRetainAssign(*error, sync_error);
870 }
871
872 dispatch_semaphore_signal(wait_for);
873 });
874
875
876 dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER);
877 secnotice("fresh", "EFP complete: %s %@", success ? "success" : "failure", error ? *error : NULL);
878 });
879
880 return success;
881 }
882
883 static bool Flush(CFErrorRef *error) {
884 __block bool success = false;
885
886 dispatch_semaphore_t wait_for = dispatch_semaphore_create(0);
887 secnotice("flush", "Starting");
888
889 SOSCloudKeychainFlush(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) {
890 success = (sync_error == NULL);
891 if (error) {
892 CFRetainAssign(*error, sync_error);
893 }
894
895 dispatch_semaphore_signal(wait_for);
896 });
897
898 dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER);
899
900 secnotice("flush", "Returned %s", success? "Success": "Failure");
901
902 return success;
903 }
904
905 static bool SOSCCAssertUserCredentialsAndOptionalDSID(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error) {
906 secnotice("updates", "Setting credentials and dsid (%@) for %@", dsid, user_label);
907
908 bool result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
909 if (dsid != NULL && CFStringCompare(dsid, CFSTR(""), 0) != 0) {
910 SOSAccountAssertDSID(txn.account, dsid);
911 }
912 return true;
913 });
914
915 require_quiet(result, done);
916
917 require_quiet(SyncKVSAndWait(error), done); // Make sure we've seen what the server has
918 require_quiet(Flush(error), done); // And processed it already...before asserting
919
920 result = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *block_error) {
921 return SOSAccountAssertUserCredentials(txn.account, user_label, user_password, block_error);
922 });
923
924 require_quiet(result, done);
925 require_quiet(Flush(error), done); // Process any incoming information..circles et.al. before fixing our signature
926
927 result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
928 return SOSAccountGenerationSignatureUpdate(txn.account, error);
929 });
930
931 done:
932 return result;
933 }
934
935 static bool SOSCCAssertUserCredentialsAndOptionalDSIDWithAnalytics(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, NSData* parentEvent, CFErrorRef *error) {
936 secnotice("updates", "Setting credentials and dsid (%@) for %@", dsid, user_label);
937
938 NSError* localError = nil;
939 SFSignInAnalytics* parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:parentEvent error:&localError];
940
941 SFSignInAnalytics *syncAndWaitEvent = nil;
942 SFSignInAnalytics *flushEvent = nil;
943 SFSignInAnalytics *secondFlushEvent = nil;
944 SFSignInAnalytics *generationSignatureUpdateEvent = nil;
945
946 bool result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
947 if (dsid != NULL && CFStringCompare(dsid, CFSTR(""), 0) != 0) {
948 SOSAccountAssertDSID(txn.account, dsid);
949 }
950 return true;
951 });
952
953 require_quiet(result, done);
954 syncAndWaitEvent = [parent newSubTaskForEvent:@"syncAndWaitEvent"];
955 require_quiet(SyncKVSAndWait(error), done); // Make sure we've seen what the server has
956 [syncAndWaitEvent stopWithAttributes:nil];
957
958 flushEvent = [parent newSubTaskForEvent:@"flushEvent"];
959 require_quiet(Flush(error), done); // And processed it already...before asserting
960 [flushEvent stopWithAttributes:nil];
961
962 result = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *block_error) {
963 return SOSAccountAssertUserCredentials(txn.account, user_label, user_password, block_error);
964 });
965
966 require_quiet(result, done);
967 secondFlushEvent = [parent newSubTaskForEvent:@"secondFlushEvent"];
968 require_quiet(Flush(error), done); // Process any incoming information..circles et.al. before fixing our signature
969 [secondFlushEvent stopWithAttributes:nil];
970
971 generationSignatureUpdateEvent = [parent newSubTaskForEvent:@"generationSignatureUpdateEvent"];
972 result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
973 return SOSAccountGenerationSignatureUpdate(txn.account, error);
974 });
975 [generationSignatureUpdateEvent stopWithAttributes:nil];
976
977
978 done:
979 if(syncAndWaitEvent){
980 [syncAndWaitEvent stopWithAttributes:nil];
981 }
982 if(flushEvent){
983 [flushEvent stopWithAttributes:nil];
984 }
985 if(secondFlushEvent){
986 [secondFlushEvent stopWithAttributes:nil];
987 }
988 if(generationSignatureUpdateEvent){
989 [generationSignatureUpdateEvent stopWithAttributes:nil];
990 }
991 return result;
992 }
993
994 bool SOSCCSetUserCredentialsAndDSID_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error)
995 {
996 // TODO: Return error if DSID is NULL to insist our callers provide one?
997 return SOSCCAssertUserCredentialsAndOptionalDSID(user_label, user_password, dsid, error);
998 }
999
1000 bool SOSCCSetUserCredentialsAndDSIDWithAnalytics_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFDataRef parentEvent, CFErrorRef *error)
1001 {
1002 return SOSCCAssertUserCredentialsAndOptionalDSIDWithAnalytics(user_label, user_password, dsid, (__bridge NSData*)parentEvent, error);
1003 }
1004 bool SOSCCSetUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFErrorRef *error)
1005 {
1006 return SOSCCAssertUserCredentialsAndOptionalDSID(user_label, user_password, NULL, error);
1007 }
1008
1009 bool SOSCCCanAuthenticate_Server(CFErrorRef *error)
1010 {
1011 bool result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1012 // If we reply that yes we can authenticate, then let's make sure we can authenticate for a while yet.
1013 // <rdar://problem/32732066>
1014 SOSAccountRestartPrivateCredentialTimer(txn.account);
1015 return SOSAccountGetPrivateCredential(txn.account, block_error) != NULL;
1016 });
1017
1018 if (!result && error && *error && CFErrorGetDomain(*error) == kSOSErrorDomain) {
1019 CFIndex code = CFErrorGetCode(*error);
1020 if (code == kSOSErrorPrivateKeyAbsent || code == kSOSErrorPublicKeyAbsent) {
1021 CFReleaseNull(*error);
1022 }
1023 }
1024
1025 return result;
1026 }
1027
1028 bool SOSCCPurgeUserCredentials_Server(CFErrorRef *error)
1029 {
1030 return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1031 SOSAccountPurgePrivateCredential(txn.account);
1032 return true;
1033 });
1034 }
1035
1036 SOSCCStatus SOSCCThisDeviceIsInCircle_Server(CFErrorRef *error)
1037 {
1038 __block SOSCCStatus status;
1039
1040 return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1041 status = [txn.account getCircleStatus:block_error];
1042
1043 return true;
1044 }) ? status : kSOSCCError;
1045 }
1046
1047 bool SOSCCRequestToJoinCircle_Server(CFErrorRef* error)
1048 {
1049 __block bool result = true;
1050
1051 return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1052 result = SOSAccountJoinCircles(txn, block_error);
1053 return result;
1054 });
1055 }
1056
1057 bool SOSCCRequestToJoinCircleWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error)
1058 {
1059 __block bool result = true;
1060
1061 return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1062 result = SOSAccountJoinCirclesWithAnalytics(txn, (__bridge NSData*)parentEvent, block_error);
1063 return result;
1064 });
1065 }
1066
1067 bool SOSCCAccountHasPublicKey_Server(CFErrorRef *error)
1068 {
1069 __block bool result = true;
1070 __block CFErrorRef localError = NULL;
1071
1072 bool hasPublicKey = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1073 result = SOSAccountHasPublicKey(txn.account, &localError);
1074 return result;
1075 });
1076
1077 if(error != NULL && localError != NULL)
1078 *error = localError;
1079
1080 return hasPublicKey;
1081 }
1082
1083 bool SOSCCAccountIsNew_Server(CFErrorRef *error)
1084 {
1085 __block bool result = true;
1086 __block CFErrorRef localError = NULL;
1087
1088 (void) do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1089 result = SOSAccountIsNew(txn.account, &localError);
1090 return result;
1091 });
1092
1093 if(error != NULL && localError != NULL)
1094 *error = localError;
1095
1096 return result;
1097 }
1098 bool SOSCCRequestToJoinCircleAfterRestore_Server(CFErrorRef* error)
1099 {
1100 __block bool result = true;
1101 bool returned = false;
1102 returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1103 SOSAccountEnsurePeerRegistration(txn.account, block_error);
1104 result = SOSAccountJoinCirclesAfterRestore(txn, block_error);
1105 return result;
1106 });
1107 return returned;
1108
1109 }
1110
1111 bool SOSCCRequestToJoinCircleAfterRestoreWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error)
1112 {
1113 __block bool result = true;
1114 bool returned = false;
1115 returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1116 NSError* localError = nil;
1117 SFSignInAnalytics* parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:(__bridge NSData*)parentEvent error:&localError];
1118
1119 SFSignInAnalytics *ensurePeerRegistrationEvent = [parent newSubTaskForEvent:@"ensurePeerRegistrationEvent"];
1120 SOSAccountEnsurePeerRegistration(txn.account, block_error);
1121 if(block_error && *block_error){
1122 NSError* blockError = (__bridge NSError*)*block_error;
1123 if(blockError){
1124 [ensurePeerRegistrationEvent logRecoverableError:blockError];
1125 secerror("ensure peer registration error: %@", blockError);
1126 }
1127 }
1128 [ensurePeerRegistrationEvent stopWithAttributes:nil];
1129 result = SOSAccountJoinCirclesAfterRestoreWithAnalytics(txn, (__bridge NSData*)parentEvent, block_error);
1130 return result;
1131 });
1132 return returned;
1133
1134 }
1135
1136 bool SOSCCRequestEnsureFreshParameters_Server(CFErrorRef* error)
1137 {
1138 bool returned = false;
1139 returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1140 return SyncKVSAndWait(block_error);
1141 });
1142 if (returned) {
1143 returned = Flush(error);
1144 }
1145 return returned;
1146 }
1147
1148 bool SOSCCApplyToARing_Server(CFStringRef ringName, CFErrorRef *error){
1149 __block bool result = true;
1150 bool returned = false;
1151 returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1152 SOSFullPeerInfoRef fpi = txn.account.fullPeerInfo;
1153 SOSRingRef ring = [txn.account.trust copyRing:ringName err:error];
1154
1155 if(fpi && ring) {
1156 result = SOSRingApply(ring, txn.account.accountKey, fpi , error);
1157 }
1158 CFReleaseNull(ring);
1159 return result;
1160 });
1161 return returned;
1162 }
1163
1164 bool SOSCCWithdrawlFromARing_Server(CFStringRef ringName, CFErrorRef *error){
1165 __block bool result = true;
1166 bool returned = false;
1167 returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1168 SOSFullPeerInfoRef fpi = txn.account.fullPeerInfo;
1169 SOSRingRef ring = [txn.account.trust copyRing:ringName err:error];
1170 if(fpi && ring) {
1171 result = SOSRingWithdraw(ring, txn.account.accountKey, fpi , error);
1172 }
1173 CFReleaseNull(ring);
1174 return result;
1175 });
1176 return returned;
1177 }
1178
1179 bool SOSCCEnableRing_Server(CFStringRef ringName, CFErrorRef *error){
1180 __block bool result = true;
1181 bool returned = false;
1182 returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1183 SOSFullPeerInfoRef fpi = txn.account.fullPeerInfo;
1184 SOSRingRef ring = [txn.account.trust copyRing:ringName err:error];
1185 if(fpi && ring) {
1186 result = SOSRingResetToOffering(ring, NULL, fpi, error);
1187 }
1188 CFReleaseNull(ring);
1189 return result;
1190 });
1191 return returned;
1192 }
1193
1194 CFStringRef SOSCCGetAllTheRings_Server(CFErrorRef *error){
1195 __block CFMutableDictionaryRef result = NULL;
1196 __block CFMutableStringRef description = CFStringCreateMutable(kCFAllocatorDefault, 0);
1197
1198 (void) do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
1199 SOSAccountForEachRing(txn.account, ^SOSRingRef(CFStringRef name, SOSRingRef ring) {
1200 CFStringAppendFormat(description, NULL, CFSTR("%@\n"), ring);
1201 return NULL;
1202 });
1203 if(result)
1204 return true;
1205 return false;
1206 });
1207
1208 return description;
1209 }
1210
1211 SOSRingStatus SOSCCRingStatus_Server(CFStringRef ringName, CFErrorRef *error){
1212 __block bool result = true;
1213 SOSRingStatus returned;
1214 returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1215 SOSFullPeerInfoRef fpi = txn.account.fullPeerInfo;
1216 SOSPeerInfoRef myPeer = SOSFullPeerInfoGetPeerInfo(fpi);
1217
1218 SOSRingRef ring = [txn.account.trust copyRing:ringName err:error];
1219 if(myPeer && ring) {
1220 result = SOSRingDeviceIsInRing(ring, SOSPeerInfoGetPeerID(myPeer));
1221 }
1222 CFReleaseNull(ring);
1223
1224 return result;
1225 });
1226 return returned;
1227 }
1228
1229 bool SOSCCAccountSetToNew_Server(CFErrorRef *error)
1230 {
1231 return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1232 SOSAccountSetToNew(txn.account);
1233 return true;
1234 });
1235 }
1236
1237 bool SOSCCResetToOffering_Server(CFErrorRef* error)
1238 {
1239 return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1240 SecKeyRef user_key = SOSAccountGetPrivateCredential(txn.account, error);
1241 if (!user_key)
1242 return false;
1243 return [txn.account.trust resetToOffering:txn key:user_key err:block_error];
1244 });
1245
1246 }
1247
1248 bool SOSCCResetToEmpty_Server(CFErrorRef* error)
1249 {
1250 return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1251 if (!SOSAccountHasPublicKey(txn.account, error))
1252 return false;
1253 return [txn.account.trust resetAccountToEmpty:txn.account transport:txn.account.circle_transport err:block_error];
1254 });
1255
1256 }
1257
1258 bool SOSCCResetToEmptyWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error)
1259 {
1260 return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1261 if (!SOSAccountHasPublicKey(txn.account, error))
1262 return false;
1263 return [txn.account.trust resetAccountToEmptyWithAnalytics:txn.account transport:txn.account.circle_transport parentEvent:(__bridge NSData*)parentEvent err:block_error];
1264 });
1265
1266 }
1267
1268 bool SOSCCRemoveThisDeviceFromCircleWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error)
1269 {
1270 return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1271 return [txn.account.trust leaveCircleWithAccount:txn.account withAnalytics:(__bridge NSData*)parentEvent err:error];
1272 });
1273 }
1274
1275 bool SOSCCRemoveThisDeviceFromCircle_Server(CFErrorRef* error)
1276 {
1277 return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1278 return [txn.account.trust leaveCircle:txn.account err:block_error];
1279 });
1280 }
1281
1282 bool SOSCCRemovePeersFromCircle_Server(CFArrayRef peers, CFErrorRef* error)
1283 {
1284 return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1285 return SOSAccountRemovePeersFromCircle(txn.account, peers, block_error);
1286 });
1287 }
1288
1289 bool SOSCCRemovePeersFromCircleWithAnalytics_Server(CFArrayRef peers, CFDataRef parentEvent, CFErrorRef* error)
1290 {
1291 return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1292 return SOSAccountRemovePeersFromCircleWithAnalytics(txn.account, peers, (__bridge NSData*)parentEvent, block_error);
1293 });
1294 }
1295
1296 bool SOSCCLoggedOutOfAccount_Server(CFErrorRef *error)
1297 {
1298 return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1299 secnotice("circleOps", "Signed out of account!");
1300
1301 bool waitForeverForSynchronization = true;
1302
1303 bool result = [txn.account.trust leaveCircle:txn.account err:block_error];
1304
1305 [txn restart]; // Make sure this gets finished before we set to new.
1306
1307 sync_the_last_data_to_kvs((__bridge CFTypeRef)(txn.account), waitForeverForSynchronization);
1308
1309 SOSAccountSetToNew(txn.account);
1310
1311 return result;
1312 });
1313 }
1314
1315 bool SOSCCBailFromCircle_Server(uint64_t limit_in_seconds, CFErrorRef* error)
1316 {
1317 return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1318 bool waitForeverForSynchronization = false;
1319
1320 bool result = SOSAccountBail(txn.account, limit_in_seconds, block_error);
1321
1322 [txn restart]; // Make sure this gets finished before we set to new.
1323
1324 sync_the_last_data_to_kvs((__bridge CFTypeRef)(txn.account), waitForeverForSynchronization);
1325
1326 return result;
1327 });
1328
1329 }
1330
1331 CFArrayRef SOSCCCopyApplicantPeerInfo_Server(CFErrorRef* error)
1332 {
1333 __block CFArrayRef result = NULL;
1334
1335 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1336 result = SOSAccountCopyApplicants(txn.account, block_error);
1337 return result != NULL;
1338 });
1339
1340 return result;
1341 }
1342
1343 CFArrayRef SOSCCCopyGenerationPeerInfo_Server(CFErrorRef* error)
1344 {
1345 __block CFArrayRef result = NULL;
1346
1347 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1348 result = SOSAccountCopyGeneration(txn.account, block_error);
1349 return result != NULL;
1350 });
1351
1352 return result;
1353 }
1354
1355 CFArrayRef SOSCCCopyValidPeerPeerInfo_Server(CFErrorRef* error)
1356 {
1357 __block CFArrayRef result = NULL;
1358
1359 @autoreleasepool {
1360
1361 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1362 @autoreleasepool {
1363 result = SOSAccountCopyValidPeers(txn.account, block_error);
1364 }
1365 return result != NULL;
1366 });
1367 }
1368
1369 return result;
1370 }
1371
1372 bool SOSCCValidateUserPublic_Server(CFErrorRef* error)
1373 {
1374 __block bool result = NULL;
1375
1376 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1377 result = SOSValidateUserPublic(txn.account, block_error);
1378 return result;
1379 });
1380
1381 return result;
1382 }
1383
1384 CFArrayRef SOSCCCopyNotValidPeerPeerInfo_Server(CFErrorRef* error)
1385 {
1386 __block CFArrayRef result = NULL;
1387
1388 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1389 result = SOSAccountCopyNotValidPeers(txn.account, block_error);
1390 return result != NULL;
1391 });
1392
1393 return result;
1394 }
1395
1396 CFArrayRef SOSCCCopyRetirementPeerInfo_Server(CFErrorRef* error)
1397 {
1398 __block CFArrayRef result = NULL;
1399
1400 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1401 result = SOSAccountCopyRetired(txn.account, block_error);
1402 return result != NULL;
1403 });
1404
1405 return result;
1406 }
1407
1408 CFArrayRef SOSCCCopyViewUnawarePeerInfo_Server(CFErrorRef* error)
1409 {
1410 __block CFArrayRef result = NULL;
1411
1412 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1413 result = SOSAccountCopyViewUnaware(txn.account, block_error);
1414 return result != NULL;
1415 });
1416
1417 return result;
1418 }
1419
1420 CFArrayRef SOSCCCopyEngineState_Server(CFErrorRef* error)
1421 {
1422 CFArrayRef result = NULL;
1423 SOSDataSourceFactoryRef dsf = SecItemDataSourceFactoryGetDefault();
1424 SOSDataSourceRef ds = SOSDataSourceFactoryCreateDataSource(dsf, kSecAttrAccessibleWhenUnlocked, error);
1425 if (ds) {
1426 SOSEngineRef engine = SOSDataSourceGetSharedEngine(ds, error);
1427 result = SOSEngineCopyPeerConfirmedDigests(engine, error);
1428 SOSDataSourceRelease(ds, error);
1429 }
1430
1431 return result;
1432 }
1433
1434 static int64_t getTimeDifference(time_t start)
1435 {
1436 time_t stop;
1437 int64_t duration;
1438
1439 stop = time(NULL);
1440
1441 duration = stop - start;
1442
1443 return SecBucket1Significant(duration);
1444 }
1445
1446 static uint64_t initialSyncTimeoutFromDefaultsWrite(void)
1447 {
1448 uint64_t timeout = 10;
1449
1450 //sudo defaults write /Library/Preferences/com.apple.authd enforceEntitlement -bool true
1451 CFTypeRef initialSyncTimeout = (CFNumberRef)CFPreferencesCopyValue(CFSTR("InitialSync.WaitPeriod"), CFSTR("com.apple.security"), kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
1452
1453 if (isNumber(initialSyncTimeout)) {
1454 CFNumberGetValue((CFNumberRef)initialSyncTimeout, kCFNumberSInt64Type, &timeout);
1455 }
1456 CFReleaseNull(initialSyncTimeout);
1457 return timeout;
1458 }
1459
1460 bool SOSCCWaitForInitialSyncWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error) {
1461 __block dispatch_semaphore_t inSyncSema = NULL;
1462 __block bool result = false;
1463 __block bool synced = false;
1464 bool timed_out = false;
1465 __block CFStringRef inSyncCallID = NULL;
1466 __block time_t start;
1467 __block CFBooleanRef shouldUseInitialSyncV0 = false;
1468 SFSignInAnalytics* syncingEvent = nil;
1469
1470 NSError* localError = nil;
1471 SFSignInAnalytics* parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:(__bridge NSData*)parentEvent error:&localError];
1472
1473 secnotice("initial sync", "Wait for initial sync start!");
1474
1475 result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1476 shouldUseInitialSyncV0 = (CFBooleanRef)SOSAccountGetValue(txn.account, kSOSInitialSyncTimeoutV0, error);
1477 bool alreadyInSync = (SOSAccountHasCompletedInitialSync(txn.account));
1478
1479 if (!alreadyInSync) {
1480 txn.account.isInitialSyncing = true;
1481 start = time(NULL);
1482 inSyncSema = dispatch_semaphore_create(0);
1483
1484 SFSignInAnalytics* callWhenInSyncEvent = [parent newSubTaskForEvent:@"callWhenInSync"];
1485 inSyncCallID = SOSAccountCallWhenInSync(txn.account, ^bool(SOSAccount* mightBeSynced) {
1486 synced = true;
1487
1488 if(inSyncSema){
1489 dispatch_semaphore_signal(inSyncSema);
1490 NSDictionary* attributes = @{@"finishedSyncing" : @YES};
1491 [syncingEvent stopWithAttributes:attributes];
1492 }
1493 return true;
1494 });
1495 NSDictionary* attributes = @{};
1496 [callWhenInSyncEvent stopWithAttributes:attributes];
1497 }
1498 else{
1499 synced = true;
1500 }
1501 return true;
1502 });
1503
1504 require_quiet(result, fail);
1505
1506
1507 if(inSyncSema){
1508 syncingEvent = [parent newSubTaskForEvent:@"initialSyncEvent"];
1509 if(shouldUseInitialSyncV0){
1510 secnotice("piggy","setting initial sync timeout to 5 minutes");
1511 timed_out = dispatch_semaphore_wait(inSyncSema, dispatch_time(DISPATCH_TIME_NOW, 300ull * NSEC_PER_SEC));
1512 }
1513 else{
1514 uint64_t timeoutFromDefaultsWrite = initialSyncTimeoutFromDefaultsWrite();
1515 secnotice("piggy","setting initial sync timeout to %llu seconds", timeoutFromDefaultsWrite);
1516 timed_out = dispatch_semaphore_wait(inSyncSema, dispatch_time(DISPATCH_TIME_NOW, timeoutFromDefaultsWrite * NSEC_PER_SEC));
1517 }
1518 }
1519 if (timed_out && shouldUseInitialSyncV0) {
1520 do_with_account(^(SOSAccountTransaction* txn) {
1521 if (SOSAccountUnregisterCallWhenInSync(txn.account, inSyncCallID)) {
1522 if(inSyncSema){
1523 inSyncSema = NULL; // We've canceled the timeout so we must be the last.
1524 }
1525 }
1526 });
1527 NSError* error = [NSError errorWithDomain:@"securityd" code:errSecTimedOut userInfo:@{NSLocalizedDescriptionKey: @"timed out waiting for initial sync"}];
1528 [syncingEvent logUnrecoverableError:error];
1529 NSDictionary* attributes = @{@"finishedSyncing" : @NO, @"legacyPiggybacking" : @YES};
1530 [syncingEvent stopWithAttributes:attributes];
1531 }
1532
1533 require_quiet(result, fail);
1534
1535 if(result)
1536 {
1537 SecADClientPushValueForDistributionKey(SOSAggdSyncCompletionKey, getTimeDifference(start));
1538 }
1539 else if(!result)
1540 {
1541 SecADAddValueForScalarKey(SOSAggdSyncTimeoutKey, 1);
1542 }
1543
1544 (void)do_with_account(^(SOSAccountTransaction *txn) {
1545 txn.account.isInitialSyncing = false;
1546 });
1547
1548 secnotice("initial sync", "Finished!: %d", result);
1549
1550 fail:
1551 CFReleaseNull(inSyncCallID);
1552 return result;
1553 }
1554
1555 bool SOSCCWaitForInitialSync_Server(CFErrorRef* error) {
1556
1557 __block dispatch_semaphore_t inSyncSema = NULL;
1558 __block bool result = false;
1559 __block bool synced = false;
1560 bool timed_out = false;
1561 __block CFStringRef inSyncCallID = NULL;
1562 __block time_t start;
1563 __block CFBooleanRef shouldUseInitialSyncV0 = false;
1564
1565 secnotice("initial sync", "Wait for initial sync start!");
1566
1567 result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1568 shouldUseInitialSyncV0 = (CFBooleanRef)SOSAccountGetValue(txn.account, kSOSInitialSyncTimeoutV0, error);
1569 bool alreadyInSync = (SOSAccountHasCompletedInitialSync(txn.account));
1570
1571 if (!alreadyInSync) {
1572 txn.account.isInitialSyncing = true;
1573 start = time(NULL);
1574 inSyncSema = dispatch_semaphore_create(0);
1575
1576 inSyncCallID = SOSAccountCallWhenInSync(txn.account, ^bool(SOSAccount* mightBeSynced) {
1577 synced = true;
1578
1579 if(inSyncSema){
1580 dispatch_semaphore_signal(inSyncSema);
1581
1582 }
1583 return true;
1584 });
1585 }
1586 else{
1587 synced = true;
1588 }
1589 return true;
1590 });
1591
1592 require_quiet(result, fail);
1593
1594 if(inSyncSema){
1595 if(shouldUseInitialSyncV0){
1596 secnotice("piggy","setting initial sync timeout to 5 minutes");
1597 timed_out = dispatch_semaphore_wait(inSyncSema, dispatch_time(DISPATCH_TIME_NOW, 300ull * NSEC_PER_SEC));
1598 }
1599 else{
1600 uint64_t timeoutFromDefaultsWrite = initialSyncTimeoutFromDefaultsWrite();
1601 secnotice("piggy","setting initial sync timeout to %llu seconds", timeoutFromDefaultsWrite);
1602 timed_out = dispatch_semaphore_wait(inSyncSema, dispatch_time(DISPATCH_TIME_NOW, timeoutFromDefaultsWrite * NSEC_PER_SEC));
1603 }
1604 }
1605 if (timed_out && shouldUseInitialSyncV0) {
1606 do_with_account(^(SOSAccountTransaction* txn) {
1607 if (SOSAccountUnregisterCallWhenInSync(txn.account, inSyncCallID)) {
1608 if(inSyncSema){
1609 inSyncSema = NULL; // We've canceled the timeout so we must be the last.
1610 }
1611 }
1612 });
1613 }
1614
1615 require_quiet(result, fail);
1616
1617 if(result)
1618 {
1619 SecADClientPushValueForDistributionKey(SOSAggdSyncCompletionKey, getTimeDifference(start));
1620 }
1621 else if(!result)
1622 {
1623 SecADAddValueForScalarKey(SOSAggdSyncTimeoutKey, 1);
1624 }
1625
1626 (void)do_with_account(^(SOSAccountTransaction *txn) {
1627 txn.account.isInitialSyncing = false;
1628 });
1629
1630 secnotice("initial sync", "Finished!: %d", result);
1631
1632 fail:
1633 CFReleaseNull(inSyncCallID);
1634 return result;
1635 }
1636
1637
1638 static CFArrayRef SOSAccountCopyYetToSyncViews(SOSAccount* account, CFErrorRef *error) {
1639 __block CFArrayRef result = NULL;
1640
1641 CFTypeRef valueFetched = SOSAccountGetValue(account, kSOSUnsyncedViewsKey, error);
1642 if (valueFetched == kCFBooleanTrue) {
1643 SOSPeerInfoRef myPI = account.peerInfo;
1644 if (myPI) {
1645 SOSPeerInfoWithEnabledViewSet(myPI, ^(CFSetRef enabled) {
1646 result = CFSetCopyValues(enabled);
1647 });
1648 }
1649 } else if (isSet(valueFetched)) {
1650 result = CFSetCopyValues((CFSetRef)valueFetched);
1651 }
1652
1653 if (result == NULL) {
1654 result = CFArrayCreateForCFTypes(kCFAllocatorDefault, NULL);
1655 }
1656
1657 return result;
1658 }
1659
1660 CFArrayRef SOSCCCopyYetToSyncViewsList_Server(CFErrorRef* error) {
1661
1662 __block CFArrayRef views = NULL;
1663
1664 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1665 views = SOSAccountCopyYetToSyncViews(txn.account, error);
1666
1667 return true;
1668 });
1669
1670 return views;
1671 }
1672
1673 bool SOSWrapToBackupSliceKeyBagForView_Server(CFStringRef viewName, CFDataRef input, CFDataRef* output, CFDataRef* bskbEncoded, CFErrorRef* error) {
1674 CFErrorRef localerror = NULL;
1675 SOSBackupSliceKeyBagRef bskb = SOSBackupSliceKeyBagForView(viewName, &localerror);
1676
1677 if(bskbEncoded && bskb) {
1678 *bskbEncoded = SOSBSKBCopyEncoded(bskb, &localerror);
1679 }
1680
1681 if(output) {
1682 *output = SOSWrapToBackupSliceKeyBag(bskb, input, &localerror);
1683 }
1684
1685 if(error) {
1686 *error = localerror;
1687 }
1688 return localerror == NULL;
1689 }
1690
1691 SOSBackupSliceKeyBagRef SOSBackupSliceKeyBagForView(CFStringRef viewName, CFErrorRef* error){
1692 __block SOSBackupSliceKeyBagRef bskb = NULL;
1693 (void) do_with_account(^ (SOSAccountTransaction* txn) {
1694 bskb = SOSAccountBackupSliceKeyBagForView(txn.account, viewName, error);
1695 });
1696 return bskb;
1697 }
1698
1699 CFDataRef SOSWrapToBackupSliceKeyBag(SOSBackupSliceKeyBagRef bskb, CFDataRef input, CFErrorRef* error) {
1700 CFDataRef encrypted = NULL;
1701 bskb_keybag_handle_t bskb_handle = 0;
1702
1703 require_quiet(bskb, exit);
1704
1705 bskb_handle = SOSBSKBLoadLocked(bskb, error);
1706 require_quiet(bskb_handle, exit);
1707
1708 SecAccessControlRef access = NULL;
1709 require_quiet(access = SecAccessControlCreate(kCFAllocatorDefault, error), exit);
1710 require_quiet(SecAccessControlSetProtection(access, kSecAttrAccessibleWhenUnlocked, error), exit);
1711
1712 // ks_encrypt_data takes a dictionary as its plaintext.
1713 CFMutableDictionaryRef plaintext = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1714 CFDictionarySetValue(plaintext, CFSTR("data"), input);
1715
1716 require_quiet(ks_encrypt_data_legacy(bskb_handle, access, NULL, plaintext, NULL, &encrypted, false, error), exit);
1717
1718 exit:
1719 CFReleaseNull(bskb);
1720 if(bskb_handle != 0) {
1721 ks_close_keybag(bskb_handle, error);
1722 }
1723 if(error && *error) {
1724 secnotice("backup", "Failed to wrap to a BKSB: %@", *error);
1725 }
1726 return encrypted;
1727
1728 }
1729
1730 CFDictionaryRef SOSCCCopyEscrowRecord_Server(CFErrorRef *error){
1731
1732 __block CFDictionaryRef result = NULL;
1733
1734 (void) do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
1735 CFErrorRef localError = NULL;
1736 SOSCCStatus status = [txn.account getCircleStatus:&localError];
1737
1738 CFStringRef dsid = SOSAccountGetValue(txn.account, kSOSDSIDKey, error);
1739 CFDictionaryRef escrowRecords = NULL;
1740 CFDictionaryRef record = NULL;
1741 switch(status) {
1742 case kSOSCCInCircle:
1743 //get the escrow record in the peer info!
1744 escrowRecords = SOSPeerInfoCopyEscrowRecord(txn.account.peerInfo);
1745 if(escrowRecords){
1746 record = CFDictionaryGetValue(escrowRecords, dsid);
1747 if(record)
1748 result = CFRetainSafe(record);
1749 }
1750 CFReleaseNull(escrowRecords);
1751 break;
1752 case kSOSCCRequestPending:
1753 //set the escrow record in the peer info/application?
1754 break;
1755 case kSOSCCNotInCircle:
1756 case kSOSCCCircleAbsent:
1757 //set the escrow record in the account expansion!
1758 escrowRecords = SOSAccountGetValue(txn.account, kSOSEscrowRecord, error);
1759 if(escrowRecords){
1760 record = CFDictionaryGetValue(escrowRecords, dsid);
1761 if(record)
1762 result = CFRetainSafe(record);
1763 }
1764 break;
1765 default:
1766 secdebug("account", "no circle status!");
1767 break;
1768 }
1769 return true;
1770 });
1771
1772 return result;
1773 }
1774
1775 CFDictionaryRef SOSCCCopyBackupInformation_Server(CFErrorRef *error) {
1776 __block CFDictionaryRef result = NULL;
1777
1778 (void) do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
1779 result = SOSBackupInformation(txn, error);
1780 return true;
1781 });
1782 return result;
1783 }
1784
1785 bool SOSCCSetEscrowRecord_Server(CFStringRef escrow_label, uint64_t tries, CFErrorRef *error){
1786
1787 if (escrow_label == NULL) {
1788 return false;
1789 }
1790
1791 __block bool result = true;
1792 __block CFErrorRef block_error = NULL;
1793
1794 (void) do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
1795 SOSCCStatus status = [txn.account getCircleStatus:&block_error];
1796
1797 CFStringRef dsid = SOSAccountGetValue(txn.account, kSOSDSIDKey, error);
1798
1799 CFMutableStringRef timeDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("["));
1800 CFAbsoluteTime currentTimeAndDate = CFAbsoluteTimeGetCurrent();
1801
1802 withStringOfAbsoluteTime(currentTimeAndDate, ^(CFStringRef decription) {
1803 CFStringAppend(timeDescription, decription);
1804 });
1805 CFStringAppend(timeDescription, CFSTR("]"));
1806
1807 CFNumberRef attempts = CFNumberCreate(kCFAllocatorDefault, kCFNumberLongLongType, (const void*)&tries);
1808
1809 CFMutableDictionaryRef escrowTimeAndTries = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
1810 CFDictionaryAddValue(escrowTimeAndTries, kSOSBurnedRecoveryAttemptCount, attempts);
1811 CFDictionaryAddValue(escrowTimeAndTries, kSOSBurnedRecoveryAttemptAttestationDate, timeDescription);
1812
1813 CFMutableDictionaryRef escrowRecord = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
1814 CFDictionaryAddValue(escrowRecord, escrow_label, escrowTimeAndTries);
1815
1816 switch(status) {
1817 case kSOSCCInCircle:
1818 //set the escrow record in the peer info!
1819 if(!SOSFullPeerInfoAddEscrowRecord(txn.account.fullPeerInfo, dsid, escrowRecord, error)){
1820 secdebug("accout", "Could not set escrow record in the full peer info");
1821 result = false;
1822 }
1823 break;
1824 case kSOSCCRequestPending:
1825 //set the escrow record in the peer info/application?
1826 break;
1827 case kSOSCCNotInCircle:
1828 case kSOSCCCircleAbsent:
1829 //set the escrow record in the account expansion!
1830
1831 if(!SOSAccountAddEscrowRecords(txn.account, dsid, escrowRecord, error)) {
1832 secdebug("account", "Could not set escrow record in expansion data");
1833 result = false;
1834 }
1835 break;
1836 default:
1837 secdebug("account", "no circle status!");
1838 break;
1839 }
1840 CFReleaseNull(attempts);
1841 CFReleaseNull(timeDescription);
1842 CFReleaseNull(escrowTimeAndTries);
1843 CFReleaseNull(escrowRecord);
1844
1845 return true;
1846 });
1847
1848 return result;
1849 }
1850
1851 bool SOSCCAcceptApplicants_Server(CFArrayRef applicants, CFErrorRef* error)
1852 {
1853 return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1854 return SOSAccountAcceptApplicants(txn.account, applicants, block_error);
1855 });
1856
1857 }
1858
1859 bool SOSCCRejectApplicants_Server(CFArrayRef applicants, CFErrorRef* error)
1860 {
1861 return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1862 return SOSAccountRejectApplicants(txn.account, applicants, block_error);
1863 });
1864 }
1865
1866 CFArrayRef SOSCCCopyPeerPeerInfo_Server(CFErrorRef* error)
1867 {
1868 __block CFArrayRef result = NULL;
1869
1870 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1871 result = SOSAccountCopyPeers(txn.account, block_error);
1872 return result != NULL;
1873 });
1874
1875 return result;
1876 }
1877
1878 CFArrayRef SOSCCCopyConcurringPeerPeerInfo_Server(CFErrorRef* error)
1879 {
1880 __block CFArrayRef result = NULL;
1881
1882 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1883 result = SOSAccountCopyConcurringPeers(txn.account, block_error);
1884 return result != NULL;
1885 });
1886
1887 return result;
1888 }
1889
1890 SOSPeerInfoRef SOSCCCopyMyPeerInfo_Server(CFErrorRef* error)
1891 {
1892 __block SOSPeerInfoRef result = NULL;
1893
1894 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1895 // Create a copy to be DERed/sent back to client
1896 result = SOSPeerInfoCreateCopy(kCFAllocatorDefault, txn.account.peerInfo, block_error);
1897 return result != NULL;
1898 });
1899
1900 return result;
1901 }
1902
1903 CFDataRef SOSCCCopyAccountState_Server(CFErrorRef* error)
1904 {
1905 __block CFDataRef accountState = NULL;
1906
1907 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1908 // Copy account state from the keychain
1909 accountState = SOSAccountCopyAccountStateFromKeychain(block_error);
1910 return accountState != NULL;
1911 });
1912
1913 return accountState;
1914 }
1915
1916 bool SOSCCDeleteAccountState_Server(CFErrorRef* error)
1917 {
1918 __block bool result = NULL;
1919
1920 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1921 // Delete account state from the keychain
1922 result = SOSAccountDeleteAccountStateFromKeychain(block_error);
1923 return result;
1924 });
1925
1926 return result;
1927 }
1928
1929 CFDataRef SOSCCCopyEngineData_Server(CFErrorRef* error)
1930 {
1931 __block CFDataRef engineState = NULL;
1932
1933 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1934 // Copy engine state from the keychain
1935 engineState = SOSAccountCopyEngineStateFromKeychain(block_error);
1936 return engineState != NULL;
1937 });
1938
1939 return engineState;
1940 }
1941
1942 bool SOSCCDeleteEngineState_Server(CFErrorRef* error)
1943 {
1944 __block bool result = NULL;
1945
1946 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1947 // Delete engine state from the keychain
1948 result = SOSAccountDeleteEngineStateFromKeychain(block_error);
1949 return result;
1950 });
1951
1952 return result;
1953 }
1954
1955
1956
1957 SOSPeerInfoRef SOSCCSetNewPublicBackupKey_Server(CFDataRef newPublicBackup, CFErrorRef *error){
1958 __block SOSPeerInfoRef result = NULL;
1959
1960 secnotice("devRecovery", "SOSCCSetNewPublicBackupKey_Server acquiring account lock");
1961 (void) do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1962 secnotice("devRecovery", "SOSCCSetNewPublicBackupKey_Server acquired account lock");
1963 if(SOSAccountSetBackupPublicKey(txn,newPublicBackup, error)){
1964 secnotice("devRecovery", "SOSCCSetNewPublicBackupKey_Server, new public backup is set in account");
1965 [txn restart]; // Finish the transaction to update any changes to the peer info.
1966
1967 // Create a copy to be DERed/sent back to client
1968 result = SOSPeerInfoCreateCopy(kCFAllocatorDefault, txn.account.peerInfo, block_error);
1969 secnotice("devRecovery", "SOSCCSetNewPublicBackupKey_Server, new public backup is set and pushed");
1970 }
1971 else
1972 {
1973 secnotice("devRecovery", "SOSCCSetNewPublicBackupKey_Server, could not set new public backup");
1974 }
1975 return result != NULL;
1976 });
1977
1978 return result;
1979 }
1980
1981 bool SOSCCRegisterSingleRecoverySecret_Server(CFDataRef aks_bag, bool setupV0Only, CFErrorRef *error){
1982 return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1983 return SOSAccountSetBSKBagForAllSlices(txn.account, aks_bag, setupV0Only, error);
1984 });
1985 }
1986
1987 CFStringRef SOSCCCopyIncompatibilityInfo_Server(CFErrorRef* error)
1988 {
1989 __block CFStringRef result = NULL;
1990
1991 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
1992 result = SOSAccountCopyIncompatibilityInfo(txn.account, block_error);
1993 return result != NULL;
1994 });
1995
1996 return result;
1997 }
1998
1999 bool SOSCCkSecXPCOpIsThisDeviceLastBackup_Server(CFErrorRef *error) {
2000 bool result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
2001 return SOSAccountIsLastBackupPeer(txn.account, block_error);
2002 });
2003 return result;
2004 }
2005
2006 enum DepartureReason SOSCCGetLastDepartureReason_Server(CFErrorRef* error)
2007 {
2008 __block enum DepartureReason result = kSOSDepartureReasonError;
2009
2010 (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
2011 result = SOSAccountGetLastDepartureReason(txn.account, block_error);
2012 return result != kSOSDepartureReasonError;
2013 });
2014
2015 return result;
2016 }
2017
2018 bool SOSCCSetLastDepartureReason_Server(enum DepartureReason reason, CFErrorRef *error){
2019 return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
2020 SOSAccountSetLastDepartureReason(txn.account, reason);
2021 return true;
2022 });
2023 }
2024
2025 bool SOSCCProcessEnsurePeerRegistration_Server(CFErrorRef* error)
2026 {
2027 secnotice("updates", "Request for registering peers");
2028 return do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2029 return SOSAccountEnsurePeerRegistration(txn.account, error);
2030 });
2031 }
2032
2033 CF_RETURNS_RETAINED CFSetRef SOSCCProcessSyncWithPeers_Server(CFSetRef peers, CFSetRef backupPeers, CFErrorRef *error) {
2034 __block CFSetRef result = NULL;
2035 if (!do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2036 result = SOSAccountProcessSyncWithPeers(txn, peers, backupPeers, error);
2037 return result != NULL;
2038 })) {
2039 // Be sure we don't return a result if we got an error
2040 CFReleaseNull(result);
2041 }
2042
2043 return result;
2044 }
2045
2046 SyncWithAllPeersReason SOSCCProcessSyncWithAllPeers_Server(CFErrorRef* error)
2047 {
2048 /*
2049 #define kIOReturnLockedRead iokit_common_err(0x2c3) // device read locked
2050 #define kIOReturnLockedWrite iokit_common_err(0x2c4) // device write locked
2051 */
2052 __block SyncWithAllPeersReason result = kSyncWithAllPeersSuccess;
2053
2054 CFErrorRef action_error = NULL;
2055
2056 if (!do_with_account_while_unlocked(&action_error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
2057 return SOSAccountRequestSyncWithAllPeers(txn, block_error);
2058 })) {
2059 if (action_error) {
2060 if (SecErrorGetOSStatus(action_error) == errSecInteractionNotAllowed) {
2061 secnotice("updates", "SOSAccountSyncWithAllKVSPeers failed because device is locked; letting CloudKeychainProxy know");
2062 result = kSyncWithAllPeersLocked; // tell CloudKeychainProxy to call us back when device unlocks
2063 CFReleaseNull(action_error);
2064 } else {
2065 secerror("Unexpected error: %@", action_error);
2066 }
2067 }
2068
2069 SecErrorPropagate(action_error, error);
2070 }
2071
2072 return result;
2073 }
2074
2075 //
2076 // Sync requesting
2077 //
2078
2079 void SOSCCRequestSyncWithPeer(CFStringRef peerID) {
2080 CFArrayRef peers = CFArrayCreateForCFTypes(kCFAllocatorDefault, peerID, NULL);
2081
2082 SOSCCRequestSyncWithPeersList(peers);
2083
2084 CFReleaseNull(peers);
2085 }
2086
2087 void SOSCCRequestSyncWithPeers(CFSetRef /*SOSPeerInfoRef/CFStringRef*/ peerIDs) {
2088 CFMutableArrayRef peerIDArray = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
2089
2090 CFSetForEach(peerIDs, ^(const void *value) {
2091 if (isString(value)) {
2092 CFArrayAppendValue(peerIDArray, value);
2093 } else if (isSOSPeerInfo(value)) {
2094 SOSPeerInfoRef peer = asSOSPeerInfo(value);
2095 CFArrayAppendValue(peerIDArray, SOSPeerInfoGetPeerID(peer));
2096 } else {
2097 secerror("Bad element, skipping: %@", value);
2098 }
2099 });
2100
2101 SOSCCRequestSyncWithPeersList(peerIDArray);
2102
2103 CFReleaseNull(peerIDArray);
2104 }
2105
2106 void SOSCCRequestSyncWithPeersList(CFArrayRef /*CFStringRef*/ peerIDs) {
2107 os_activity_initiate("CloudCircle RequestSyncWithPeersList", OS_ACTIVITY_FLAG_DEFAULT, ^(void) {
2108 CFArrayRef empty = CFArrayCreateForCFTypes(kCFAllocatorDefault, NULL);
2109
2110 CFStringArrayPerformWithDescription(peerIDs, ^(CFStringRef description) {
2111 secnotice("syncwith", "Request Sync With: %@", description);
2112 });
2113
2114 SOSCloudKeychainRequestSyncWithPeers(peerIDs, empty,
2115 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
2116 CFReleaseNull(empty);
2117 });
2118 }
2119
2120 void SOSCCRequestSyncWithBackupPeer(CFStringRef backupPeerId) {
2121 os_activity_initiate("CloudCircle RequestSyncWithPeersList", OS_ACTIVITY_FLAG_DEFAULT, ^(void) {
2122 CFArrayRef empty = CFArrayCreateForCFTypes(kCFAllocatorDefault, NULL);
2123 CFArrayRef backupPeerList = CFArrayCreateForCFTypes(kCFAllocatorDefault, backupPeerId, NULL);
2124
2125 CFStringArrayPerformWithDescription(backupPeerList, ^(CFStringRef description) {
2126 secnotice("syncwith", "Request backup sync With: %@", description);
2127 });
2128
2129 SOSCloudKeychainRequestSyncWithPeers(empty, backupPeerList,
2130 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
2131
2132 CFReleaseNull(empty);
2133 CFReleaseNull(backupPeerList);
2134 });
2135 }
2136
2137 bool SOSCCIsSyncPendingFor(CFStringRef peerID, CFErrorRef *error) {
2138 return SOSCloudKeychainHasPendingSyncWithPeer(peerID, error);
2139 }
2140
2141 void SOSCCEnsurePeerRegistration(void)
2142 {
2143 os_activity_initiate("CloudCircle EnsurePeerRegistration", OS_ACTIVITY_FLAG_DEFAULT, ^(void) {
2144
2145 SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
2146
2147 });
2148 }
2149
2150 CF_RETURNS_RETAINED CFArrayRef SOSCCHandleUpdateMessage(CFDictionaryRef updates)
2151 {
2152 CFArrayRef result = NULL;
2153 SOSAccount* account = (__bridge SOSAccount *)(SOSKeychainAccountGetSharedAccount()); //HACK to make sure itemsChangedBlock is set
2154
2155 (account) ? (result = SOSCloudKeychainHandleUpdateMessage(updates)) : (result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault));
2156 return result;
2157 }
2158
2159 SOSPeerInfoRef SOSCCCopyApplication_Server(CFErrorRef *error) {
2160 __block SOSPeerInfoRef application = NULL;
2161 do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2162 application = SOSAccountCopyApplication(txn.account, error);
2163 return application != NULL;
2164 });
2165 return application;
2166
2167 }
2168
2169 bool SOSCCCleanupKVSKeys_Server(CFErrorRef *error) {
2170 bool result = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2171 return SOSAccountCleanupAllKVSKeys(txn.account, error);
2172 });
2173 if(result && error && *error) {
2174 CFReleaseNull(*error);
2175 }
2176 return result;
2177 }
2178
2179 bool SOSCCTestPopulateKVSWithBadKeys_Server(CFErrorRef *error)
2180 {
2181 __block bool result = false;
2182 do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2183 return SOSAccountPopulateKVSWithBadKeys(txn.account, error);
2184 });
2185 return result;
2186 }
2187 CFDataRef SOSCCCopyCircleJoiningBlob_Server(SOSPeerInfoRef applicant, CFErrorRef *error) {
2188 __block CFDataRef pbblob = NULL;
2189 do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2190 pbblob = SOSAccountCopyCircleJoiningBlob(txn.account, applicant, error);
2191 return pbblob != NULL;
2192 });
2193 return pbblob;
2194 }
2195
2196 CFDataRef SOSCCCopyInitialSyncData_Server(CFErrorRef *error) {
2197 __block CFDataRef pbblob = NULL;
2198 do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2199 pbblob = SOSAccountCopyInitialSyncData(txn.account, error);
2200 return pbblob != NULL;
2201 });
2202 return pbblob;
2203 }
2204
2205 bool SOSCCJoinWithCircleJoiningBlob_Server(CFDataRef joiningBlob, PiggyBackProtocolVersion version, CFErrorRef *error) {
2206 return do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2207 return SOSAccountJoinWithCircleJoiningBlob(txn.account, joiningBlob, version, error);
2208 });
2209
2210 }
2211
2212 CFBooleanRef SOSCCPeersHaveViewsEnabled_Server(CFArrayRef viewNames, CFErrorRef *error) {
2213 __block CFBooleanRef result = NULL;
2214 do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2215 result = SOSAccountPeersHaveViewsEnabled(txn.account, viewNames, error);
2216 return result != NULL;
2217 });
2218
2219 return result;
2220 }
2221
2222 bool SOSCCRegisterRecoveryPublicKey_Server(CFDataRef recovery_key, CFErrorRef *error){
2223 return do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2224 if(recovery_key != NULL && CFDataGetLength(recovery_key) != 0)
2225 return SOSAccountRegisterRecoveryPublicKey(txn, recovery_key, error);
2226 else
2227 return SOSAccountClearRecoveryPublicKey(txn, recovery_key, error);
2228 });
2229 }
2230
2231 CFDataRef SOSCCCopyRecoveryPublicKey_Server(CFErrorRef *error){
2232
2233 __block CFDataRef result = NULL;
2234 do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2235 result = SOSAccountCopyRecoveryPublicKey(txn, error);
2236 return result != NULL;
2237 });
2238
2239 return result;
2240 }
2241
2242 bool SOSCCMessageFromPeerIsPending_Server(SOSPeerInfoRef peer, CFErrorRef *error) {
2243 return do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2244 return SOSAccountMessageFromPeerIsPending(txn, peer, error);
2245 });
2246 }
2247
2248 bool SOSCCSendToPeerIsPending_Server(SOSPeerInfoRef peer, CFErrorRef *error) {
2249 return do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2250 return SOSAccountSendToPeerIsPending(txn, peer, error);
2251 });
2252 }
2253
2254 void SOSCCResetOTRNegotiation_Server(CFStringRef peerid)
2255 {
2256 CFErrorRef localError = NULL;
2257 do_with_account_while_unlocked(&localError, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2258 SOSAccountResetOTRNegotiationCoder(txn.account, peerid);
2259 return true;
2260 });
2261 if(localError)
2262 {
2263 secerror("error resetting otr negotation: %@", localError);
2264 }
2265 }
2266
2267 void SOSCCPeerRateLimiterSendNextMessage_Server(CFStringRef peerid, CFStringRef accessGroup)
2268 {
2269 CFErrorRef localError = NULL;
2270 do_with_account_while_unlocked(&localError, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
2271 SOSAccountTimerFiredSendNextMessage(txn, (__bridge NSString*)peerid, (__bridge NSString*)accessGroup);
2272 return true;
2273 });
2274 if(localError)
2275 {
2276 secerror("error sending next message: %@", localError);
2277 }
2278 }
2279
2280 void SOSCCPerformWithOctagonSigningKey(void (^action)(SecKeyRef octagonPrivSigningKey, CFErrorRef error))
2281 {
2282 CFErrorRef error = NULL;
2283 do_with_account_if_after_first_unlock(&error, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) {
2284 SOSFullPeerInfoRef fpi = txn.account.trust.fullPeerInfo;
2285 SecKeyRef signingKey = SOSFullPeerInfoCopyOctagonSigningKey(fpi, err);
2286 CFErrorRef errorArg = err ? *err : NULL;
2287 action(signingKey, errorArg);
2288 CFReleaseNull(signingKey);
2289 return true;
2290 });
2291 CFReleaseNull(error);
2292 }
2293
2294 void SOSCCPerformWithOctagonSigningPublicKey(void (^action)(SecKeyRef octagonPublicKey, CFErrorRef error))
2295 {
2296 CFErrorRef error = NULL;
2297 do_with_account_if_after_first_unlock(&error, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) {
2298 SOSFullPeerInfoRef fpi = txn.account.trust.fullPeerInfo;
2299 SecKeyRef signingKey = SOSFullPeerInfoCopyOctagonPublicSigningKey(fpi, err);
2300 CFErrorRef errorArg = err ? *err : NULL;
2301 action(signingKey, errorArg);
2302 CFReleaseNull(signingKey);
2303 return true;
2304 });
2305 CFReleaseNull(error);
2306 }
2307
2308 void SOSCCPerformWithOctagonEncryptionKey(void (^action)(SecKeyRef octagonPrivEncryptionKey, CFErrorRef error))
2309 {
2310 CFErrorRef error = NULL;
2311 do_with_account_if_after_first_unlock(&error, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) {
2312 SOSFullPeerInfoRef fpi = txn.account.trust.fullPeerInfo;
2313 SecKeyRef signingKey = SOSFullPeerInfoCopyOctagonEncryptionKey(fpi, err);
2314 CFErrorRef errorArg = err ? *err : NULL;
2315 action(signingKey, errorArg);
2316 CFReleaseNull(signingKey);
2317 return true;
2318 });
2319 CFReleaseNull(error);
2320 }
2321
2322 void SOSCCPerformWithOctagonEncryptionPublicKey(void (^action)(SecKeyRef octagonPublicEncryptionKey, CFErrorRef error))
2323 {
2324 CFErrorRef error = NULL;
2325 do_with_account_if_after_first_unlock(&error, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) {
2326 SOSFullPeerInfoRef fpi = txn.account.trust.fullPeerInfo;
2327 SecKeyRef signingKey = SOSFullPeerInfoCopyOctagonPublicEncryptionKey(fpi, err);
2328 CFErrorRef errorArg = err ? *err : NULL;
2329 action(signingKey, errorArg);
2330 CFReleaseNull(signingKey);
2331 return true;
2332 });
2333 CFReleaseNull(error);
2334 }
2335
2336 void SOSCCPerformWithAllOctagonKeys(void (^action)(SecKeyRef octagonEncryptionKey, SecKeyRef octagonSigningKey, CFErrorRef error))
2337 {
2338 CFErrorRef localError = NULL;
2339 do_with_account_if_after_first_unlock(&localError, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) {
2340 SecKeyRef encryptionKey = NULL;
2341 SecKeyRef signingKey = NULL;
2342 CFErrorRef errorArg = err ? *err : NULL;
2343
2344 SOSFullPeerInfoRef fpi = txn.account.trust.fullPeerInfo;
2345 require_action_quiet(fpi, fail, secerror("device does not have a peer"); SOSCreateError(kSOSErrorPeerNotFound, CFSTR("No Peer for Account"), NULL, &errorArg));
2346
2347 signingKey = SOSFullPeerInfoCopyOctagonSigningKey(fpi, &errorArg);
2348 require_action_quiet(signingKey && !errorArg, fail, secerror("SOSCCPerformWithAllOctagonKeys signing key error: %@", errorArg));
2349 CFReleaseNull(errorArg);
2350
2351 encryptionKey = SOSFullPeerInfoCopyOctagonEncryptionKey(fpi, &errorArg);
2352 require_action_quiet(encryptionKey && !errorArg, fail, secerror("SOSCCPerformWithAllOctagonKeys encryption key error: %@", errorArg));
2353
2354 action(encryptionKey, signingKey, errorArg);
2355 CFReleaseNull(signingKey);
2356 CFReleaseNull(encryptionKey);
2357 CFReleaseNull(errorArg);
2358 return true;
2359 fail:
2360 action(NULL, NULL, errorArg);
2361 CFReleaseNull(errorArg);
2362 CFReleaseNull(signingKey);
2363 CFReleaseNull(encryptionKey);
2364 return true;
2365 });
2366 CFReleaseNull(localError);
2367 }
2368 void SOSCCPerformWithTrustedPeers(void (^action)(CFSetRef sosPeerInfoRefs, CFErrorRef error))
2369 {
2370 CFErrorRef cfAccountError = NULL;
2371 do_with_account_if_after_first_unlock(&cfAccountError, ^bool(SOSAccountTransaction *txn, CFErrorRef *cferror) {
2372 CFSetRef sosPeerSet = [txn.account.trust copyPeerSetMatching:^bool(SOSPeerInfoRef peer) {
2373 return true;
2374 }];
2375
2376 CFErrorRef errorArg = cferror ? *cferror : NULL;
2377 action(sosPeerSet, errorArg);
2378 CFReleaseNull(sosPeerSet);
2379 return true;
2380 });
2381 CFReleaseNull(cfAccountError);
2382 }
2383
2384 void SOSCCPerformWithPeerID(void (^action)(CFStringRef peerID, CFErrorRef error))
2385 {
2386 CFErrorRef cfAccountError = NULL;
2387 do_with_account_if_after_first_unlock(&cfAccountError, ^bool(SOSAccountTransaction *txn, CFErrorRef *cferror) {
2388 SOSAccount* account = txn.account;
2389 NSString* peerID = nil;
2390 CFErrorRef localError = nil;
2391
2392 if([account getCircleStatus:nil] == kSOSCCInCircle){
2393 peerID = [txn.account peerID];
2394 }
2395 else{
2396 SOSErrorCreate(kSOSErrorNoCircle, &localError, NULL, CFSTR("Not in circle"));
2397 }
2398 action((__bridge CFStringRef)peerID, localError);
2399 CFReleaseNull(localError);
2400 return true;
2401 });
2402 CFReleaseNull(cfAccountError);
2403 }