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