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