]>
Commit | Line | Data |
---|---|---|
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 |
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 | ||
866f8763 | 104 | typedef SOSDataSourceFactoryRef (^SOSCCAccountDataSourceFactoryBlock)(); |
6b200bc3 | 105 | |
427c49bc A |
106 | static SOSCCAccountDataSourceFactoryBlock accountDataSourceOverride = NULL; |
107 | ||
d8f41ccd A |
108 | // |
109 | // Forward declared | |
110 | // | |
427c49bc | 111 | |
866f8763 | 112 | static void do_with_account(void (^action)(SOSAccountTransaction* txn)); |
427c49bc A |
113 | |
114 | // | |
115 | // Constants | |
116 | // | |
427c49bc A |
117 | |
118 | CFStringRef kSOSAccountLabel = CFSTR("iCloud Keychain Account Meta-data"); | |
427c49bc | 119 | |
e0e0d90e A |
120 | CFStringRef kSOSBurnedRecoveryAttemptCount = CFSTR("Burned Recovery Attempt Count"); |
121 | ||
122 | CFStringRef kSOSBurnedRecoveryAttemptAttestationDate = CFSTR("Burned Recovery Attempt Attestation Date"); | |
123 | ||
427c49bc A |
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 | ||
d8f41ccd | 134 | CFDataRef 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 | ||
159 | static 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 |
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 | ||
fa7225c8 | 197 | static 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 |
211 | exit: |
212 | CFReleaseNull(saveError); | |
427c49bc A |
213 | } |
214 | ||
866f8763 | 215 | static 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 | |
250 | done: | |
251 | CFReleaseNull(savedAccount); | |
427c49bc A |
252 | return account; |
253 | } | |
254 | ||
255 | // | |
256 | // Mark: Gestalt Handling | |
257 | // | |
258 | ||
5c19dc3a A |
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 | ||
427c49bc A |
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 | ||
d8f41ccd A |
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); | |
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 | 337 | static 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 | ||
360 | static 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 | 375 | static 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 | ||
394 | done: | |
395 | if (store) CFRelease(store); | |
396 | if (computerKey) CFRelease(computerKey); | |
397 | if (keys) CFRelease(keys); | |
398 | return gestalt; | |
399 | } | |
400 | ||
fa7225c8 A |
401 | os_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 | ||
420 | errOut: | |
421 | CFReleaseNull(savedAccount); | |
422 | return retval; | |
423 | }; | |
424 | ||
425 | ||
427c49bc | 426 | |
866f8763 A |
427 | static 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 |
551 | CFTypeRef GetSharedAccountRef(void) |
552 | { | |
553 | return (__bridge CFTypeRef)GetSharedAccount(); | |
427c49bc A |
554 | } |
555 | ||
866f8763 | 556 | static 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 |
568 | static 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 |
580 | static 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 | ||
597 | fail: | |
598 | return false; | |
5c19dc3a | 599 | #endif |
427c49bc A |
600 | } |
601 | ||
866f8763 | 602 | static 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 |
633 | static bool isAssertionLockAcquireError(CFErrorRef error) { |
634 | return (CFErrorGetCode(error) == kIOReturnNotPermitted) && (CFEqualSafe(CFErrorGetDomain(error), kSecKernDomain)); | |
635 | } | |
636 | ||
866f8763 | 637 | static 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 | 722 | CFTypeRef 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 |
737 | bool 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 |
748 | SOSViewResultCode 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 | ||
779 | bool 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 |
789 | SOSSecurityPropertyResultCode 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 | 811 | void 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 | 837 | static 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 |
864 | static 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 |
886 | static 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 | ||
912 | done: | |
5c19dc3a A |
913 | return result; |
914 | } | |
915 | ||
916 | bool 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 |
922 | bool SOSCCSetUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFErrorRef *error) |
923 | { | |
924 | return SOSCCAssertUserCredentialsAndOptionalDSID(user_label, user_password, NULL, error); | |
427c49bc A |
925 | } |
926 | ||
927 | bool 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 | ||
946 | bool 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 |
954 | SOSCCStatus 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 | ||
965 | bool 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 |
975 | bool 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 | ||
991 | bool 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 |
1006 | bool 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 | ||
1019 | bool 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 |
1031 | bool 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 | ||
1047 | bool 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 | ||
1062 | bool 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 | ||
1077 | CFStringRef 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 | ||
1094 | SOSRingStatus 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 | 1112 | CFStringRef 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 | ||
1123 | bool 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 | 1130 | bool 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 | ||
1140 | HandleIDSMessageReason 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 |
1171 | bool 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 | 1182 | bool 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 | |
1188 | bool 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 | ||
1194 | bool 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 | ||
1200 | bool 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 |
1208 | bool 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 | ||
1219 | bool 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 | ||
1229 | bool 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 |
1236 | bool 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 |
1244 | bool 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 | ||
1263 | bool 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 | ||
1279 | CFArrayRef 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 |
1291 | CFArrayRef 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 | ||
1303 | CFArrayRef 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 | ||
1320 | bool 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 | ||
1332 | CFArrayRef 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 | ||
1344 | CFArrayRef 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 | ||
1356 | CFArrayRef 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 |
1368 | CFArrayRef 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 |
1382 | static 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 | |
1394 | static 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 | 1408 | bool 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 |
1485 | fail: |
1486 | CFReleaseNull(inSyncCallID); | |
5c19dc3a A |
1487 | return result; |
1488 | } | |
1489 | ||
e3d460c9 | 1490 | |
866f8763 | 1491 | static 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 | ||
1513 | CFArrayRef 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 |
1526 | bool 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 | ||
1544 | SOSBackupSliceKeyBagRef 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 | ||
1552 | CFDataRef 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 | |
1571 | exit: | |
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 |
1583 | CFDictionaryRef 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 |
1628 | CFDictionaryRef 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 |
1638 | bool 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 |
1704 | bool 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 | ||
1712 | bool 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 | ||
1719 | CFArrayRef 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 | ||
1731 | CFArrayRef 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 |
1743 | SOSPeerInfoRef 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 |
1756 | CFDataRef 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 | ||
1769 | bool 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 | ||
1782 | CFDataRef 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 | ||
1795 | bool 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 |
1810 | SOSPeerInfoRef 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 | 1834 | bool 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 |
1840 | CFStringRef 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 |
1852 | bool 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 | 1908 | bool 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 |
1917 | enum 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 | 1929 | bool 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 | |
1936 | bool 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 |
1944 | CF_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 |
1957 | SyncWithAllPeersReason 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 | ||
1990 | void SOSCCRequestSyncWithPeer(CFStringRef peerID) { | |
1991 | CFArrayRef peers = CFArrayCreateForCFTypes(kCFAllocatorDefault, peerID, NULL); | |
1992 | ||
1993 | SOSCCRequestSyncWithPeersList(peers); | |
1994 | ||
1995 | CFReleaseNull(peers); | |
1996 | } | |
1997 | ||
1998 | bool 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 | ||
2005 | void 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 | ||
2024 | void 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 | ||
2038 | void 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 |
2055 | bool SOSCCIsSyncPendingFor(CFStringRef peerID, CFErrorRef *error) { |
2056 | return SOSCloudKeychainHasPendingSyncWithPeer(peerID, error); | |
2057 | } | |
2058 | ||
fa7225c8 A |
2059 | void 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 |
2068 | CF_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 | |
2077 | SOSPeerInfoRef 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 | |
2087 | bool 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 | ||
2097 | bool 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 |
2105 | CFDataRef 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 |
2114 | CFDataRef 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 | ||
2123 | bool 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 | ||
2130 | CFBooleanRef 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 | 2140 | bool 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 | ||
2149 | CFDataRef 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 | ||
2160 | bool 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 | ||
2166 | bool 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 | |
2172 | void 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 | ||
2185 | void 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 | 2198 | void 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 | 2212 | void 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 | |
2226 | void 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 |
2240 | void 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 | ||
2254 | void 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 |
2286 | void 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 |
2302 | void 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 | } |