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