From 650c69f3f74fd8ed7cca83ea430e351a1c2fee04 Mon Sep 17 00:00:00 2001 From: Apple Date: Wed, 3 Jun 2020 04:21:43 +0000 Subject: [PATCH] Security-59306.120.7.tar.gz --- OSX/authd/authtoken.c | 6 +- OSX/authd/engine.c | 1 + OSX/authd/process.c | 3 + OSX/sec/Security/SecItem.c | 40 +- OSX/sec/ipc/server.c | 7 +- OSX/sec/ipc/server_security_helpers.h | 11 + OSX/sec/ipc/server_security_helpers.m | 91 +++++ keychain/SecureObjectSync/SOSAccount.h | 11 +- keychain/SecureObjectSync/SOSAccount.m | 361 ++++++------------ keychain/SecureObjectSync/SOSAccountCircles.m | 9 + .../SecureObjectSync/SOSAccountCredentials.m | 1 + keychain/SecureObjectSync/SOSAccountPriv.h | 3 +- .../SOSAccountTrustClassic+Circle.m | 6 +- keychain/SecureObjectSync/SOSCircle.c | 4 +- keychain/TrustedPeersHelper/Container.swift | 1 - keychain/ot/OTCuttlefishContext.m | 9 +- .../ot/tests/octagon/OctagonTests+Reset.swift | 88 +++++ .../securityd/Regressions/SOSAccountTesting.h | 4 +- .../Regressions/secd-100-initialsync.m | 4 +- .../Regressions/secd-55-account-circle.m | 2 +- .../Regressions/secd-58-password-change.m | 25 ++ keychain/securityd/SOSCloudCircleServer.m | 147 +++---- 22 files changed, 474 insertions(+), 360 deletions(-) diff --git a/OSX/authd/authtoken.c b/OSX/authd/authtoken.c index 6b0568aa..611d4415 100644 --- a/OSX/authd/authtoken.c +++ b/OSX/authd/authtoken.c @@ -395,7 +395,8 @@ auth_token_has_entitlement(auth_token_t auth, const char * entitlement) entitled = process_has_entitlement(auth->creator, entitlement); } }); - + os_log_debug(AUTHD_LOG, "authtoken: PID %d is%{public}s entitled for %{public}s", auth->auditInfo.pid, entitled ? "":" not", entitlement); + return entitled; } @@ -409,7 +410,8 @@ auth_token_has_entitlement_for_right(auth_token_t auth, const char * right) entitled = process_has_entitlement_for_right(auth->creator, right); } }); - + os_log_debug(AUTHD_LOG, "authtoken: PID %d is%{public}s entitled for right %{public}s", auth->auditInfo.pid, entitled ? "":" not", right); + return entitled; } diff --git a/OSX/authd/engine.c b/OSX/authd/engine.c index 1e4584db..7df8370c 100644 --- a/OSX/authd/engine.c +++ b/OSX/authd/engine.c @@ -612,6 +612,7 @@ _evaluate_mechanisms(engine_t engine, CFArrayRef mechanisms) } done: + auth_items_set_flags(context, AGENT_CONTEXT_AP_PAM_SERVICE_NAME, kAuthorizationContextFlagExtractable); if ((result == kAuthorizationResultUserCanceled) || (result == kAuthorizationResultAllow)) { // only make non-sticky context values available externally auth_items_set_flags(context, kAuthorizationEnvironmentPassword, kAuthorizationContextFlagVolatile); diff --git a/OSX/authd/process.c b/OSX/authd/process.c index 4a245757..da50d542 100644 --- a/OSX/authd/process.c +++ b/OSX/authd/process.c @@ -159,6 +159,9 @@ process_create(const audit_info_s * auditInfo, session_t session) goto done; } + status = SecCodeCheckValidity(codeRef, kSecCSDefaultFlags, NULL); + require_noerr_action(status, done, os_log_error(AUTHD_LOG, "process: PID %d SecCodeCheckValidity failed with %d", proc->auditInfo.pid, (int)status)); + status = SecCodeCopySigningInformation(codeRef, kSecCSRequirementInformation, &code_info); require_noerr_action(status, done, os_log_debug(AUTHD_LOG, "process: PID %d SecCodeCopySigningInformation failed with %d", proc->auditInfo.pid, (int)status)); diff --git a/OSX/sec/Security/SecItem.c b/OSX/sec/Security/SecItem.c index 98fb9085..22a1cdfe 100644 --- a/OSX/sec/Security/SecItem.c +++ b/OSX/sec/Security/SecItem.c @@ -219,6 +219,9 @@ static OSStatus osstatus_for_ctk_error(CFIndex ctkError) { return errSecUserCanceled; case kTKErrorCodeCorruptedData: return errSecDecode; + case kTKErrorCodeTokenNotFound: + case kTKErrorCodeObjectNotFound: + return errSecItemNotFound; default: return errSecInternal; } @@ -1130,9 +1133,16 @@ bool SecItemResultProcess(CFDictionaryRef query, CFDictionaryRef auth_params, TK *result = CFArrayCreateMutableForCFTypes(NULL); for (i = 0; i < count; i++) { CFTypeRef ref; - require_quiet(SecItemResultCopyPrepared(CFArrayGetValueAtIndex(raw_result, i), - token, query, auth_params, &ref, error), out); - if (ref != NULL) { + CFErrorRef localError = NULL; + bool prepared = SecItemResultCopyPrepared(CFArrayGetValueAtIndex(raw_result, i), + token, query, auth_params, &ref, &localError); + if (!prepared) { + // TokenNotFound or TokenObjectNotFound will just not insert failing item into resulting array, other errors abort processing. + require_action_quiet(localError != NULL && CFEqual(CFErrorGetDomain(localError), CFSTR(kTKErrorDomain)) && + (CFErrorGetCode(localError) == kTKErrorCodeTokenNotFound || CFErrorGetCode(localError) == kTKErrorCodeObjectNotFound), out, + CFErrorPropagate(localError, error)); + CFReleaseNull(localError); + } else if (ref != NULL) { CFArrayAppendValue((CFMutableArrayRef)*result, ref); CFRelease(ref); } @@ -1471,8 +1481,18 @@ bool SecItemAuthDoQuery(SecCFDictionaryCOW *query, SecCFDictionaryCOW *attribute // Prepare connection to target token if it is present. CFStringRef token_id = CFDictionaryGetValue(query->dictionary, kSecAttrTokenID); require_quiet(token_id == NULL || CFCastWithError(CFString, token_id, error) != NULL, out); - if (secItemOperation != SecItemCopyMatching && token_id != NULL) { - require_quiet(CFAssignRetained(token, SecTokenCreate(token_id, &auth_params, error)), out); + if (secItemOperation != SecItemCopyMatching && token_id != NULL && !cf_bool_value(CFDictionaryGetValue(query->dictionary, kSecUseTokenRawItems))) { + CFErrorRef localError = NULL; + CFAssignRetained(token, SecTokenCreate(token_id, &auth_params, &localError)); + if (token == NULL) { + require_action_quiet(secItemOperation == SecItemDelete && + CFEqual(CFErrorGetDomain(localError), CFSTR(kTKErrorDomain)) && + CFErrorGetCode(localError) == kTKErrorCodeTokenNotFound, + out, CFErrorPropagate(localError, error)); + + // In case that token cannot be found and deletion is required, just continue and delete item from keychain only. + CFReleaseNull(localError); + } } CFDictionaryRef attrs = (attributes != NULL) ? attributes->dictionary : NULL; @@ -1941,8 +1961,14 @@ OSStatus SecItemDelete(CFDictionaryRef inQuery) { // Delete item from the token. CFDataRef object_id = CFDictionaryGetValue(object_data, kSecTokenValueObjectIDKey); - require_action_quiet(TKTokenDeleteObject(token, object_id, error), out, - SecTokenProcessError(kAKSKeyOpDelete, token, object_id, error)); + CFErrorRef localError = NULL; + if (!TKTokenDeleteObject(token, object_id, &localError)) { + // Check whether object was not found; in this case, ignore the error. + require_action_quiet(CFEqual(CFErrorGetDomain(localError), CFSTR(kTKErrorDomain)) && + CFErrorGetCode(localError) == kTKErrorCodeObjectNotFound, out, + (CFErrorPropagate(localError, error), SecTokenProcessError(kAKSKeyOpDelete, token, object_id, error))); + CFReleaseNull(localError); + } // Delete the item from the keychain. require_quiet(SECURITYD_XPC(sec_item_delete, dict_client_to_error_request, item_query, diff --git a/OSX/sec/ipc/server.c b/OSX/sec/ipc/server.c index df744076..1a8eb59e 100644 --- a/OSX/sec/ipc/server.c +++ b/OSX/sec/ipc/server.c @@ -895,11 +895,8 @@ static void securityd_xpc_dictionary_handler(const xpc_connection_t connection, case kSecXPCOpRequestToJoinWithAnalytics: if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementKeychainCloudCircle, &error)) { CFDataRef parentEvent = NULL; - if(SecXPCDictionaryCopyDataOptional(event, kSecXPCKeySignInAnalytics, &parentEvent, &error) && parentEvent != NULL){ - xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, SOSCCRequestToJoinCircleWithAnalytics_Server(parentEvent, &error)); - }else{ - xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, SOSCCRequestToJoinCircle_Server(&error)); - } + SecXPCDictionaryCopyDataOptional(event, kSecXPCKeySignInAnalytics, &parentEvent, &error); + xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, SOSCCRequestToJoinCircleWithAnalytics_Server(parentEvent, &error)); CFReleaseNull(parentEvent); } break; diff --git a/OSX/sec/ipc/server_security_helpers.h b/OSX/sec/ipc/server_security_helpers.h index 9986b7cb..216018f9 100644 --- a/OSX/sec/ipc/server_security_helpers.h +++ b/OSX/sec/ipc/server_security_helpers.h @@ -34,6 +34,17 @@ void SecCreateSecuritydXPCServer(void); bool fill_security_client(SecurityClient * client, const uid_t uid, audit_token_t auditToken); CFArrayRef SecTaskCopyAccessGroups(SecTaskRef task); + +/*! + @function SecTaskIsEligiblePlatformBinary + @abstract Determine whether task belongs to valid platform binary and optionally has one of the allowed identifiers. + @param task The client task to be evaluated. + @param identifiers Optional array of codesigning identifiers of allowed callers. Pass NULL to permit any platform binary. + @result Client satisfies the criteria or not. + */ +bool SecTaskIsEligiblePlatformBinary(SecTaskRef task, CFArrayRef identifiers); + +// Testing support void SecAccessGroupsSetCurrent(CFArrayRef accessGroups); #endif /* server_security_helpers_h */ diff --git a/OSX/sec/ipc/server_security_helpers.m b/OSX/sec/ipc/server_security_helpers.m index cd7f0e15..b360fc43 100644 --- a/OSX/sec/ipc/server_security_helpers.m +++ b/OSX/sec/ipc/server_security_helpers.m @@ -30,6 +30,8 @@ #include #include "ipc/securityd_client.h" #include +#include +#include #include #include "utilities/SecCFRelease.h" #include "utilities/SecCFWrappers.h" @@ -66,6 +68,35 @@ device_is_multiuser(void) } #endif /* HAVE_MOBILE_KEYBAG_SUPPORT && TARGET_OS_IOS */ +static bool sanityCheckClientAccessGroups(SecurityClient* client) { + if (!client->accessGroups) { + return true; + } + + CFRange range = { 0, CFArrayGetCount(client->accessGroups) }; + if (!CFArrayContainsValue(client->accessGroups, range, CFSTR("*"))) { + return true; + } + + CFMutableArrayRef allowedIdentifiers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); +#if TARGET_OS_OSX + CFArrayAppendValue(allowedIdentifiers, CFSTR("com.apple.keychainaccess")); + CFArrayAppendValue(allowedIdentifiers, CFSTR("com.apple.KeychainMigrator")); +#endif + if (SecIsInternalRelease()) { +#if TARGET_OS_OSX + CFArrayAppendValue(allowedIdentifiers, CFSTR("com.apple.security2")); +#else + CFArrayAppendValue(allowedIdentifiers, CFSTR("com.apple.security")); +#endif + } + + bool answer = SecTaskIsEligiblePlatformBinary(client->task, allowedIdentifiers); + CFReleaseNull(allowedIdentifiers); + + return answer; +} + bool fill_security_client(SecurityClient * client, const uid_t uid, audit_token_t auditToken) { if(!client) { @@ -141,7 +172,67 @@ fill_security_client(SecurityClient * client, const uid_t uid, audit_token_t aud client->allowSyncBubbleKeychain = SecTaskGetBooleanValueForEntitlement(client->task, kSecEntitlementPrivateKeychainSyncBubble); } #endif + if (!sanityCheckClientAccessGroups(client)) { + return false; + } } return true; } +// Stolen and adapted from securityd_service +bool SecTaskIsEligiblePlatformBinary(SecTaskRef task, CFArrayRef identifiers) { +#if (DEBUG || RC_BUILDIT_YES) + secnotice("serverxpc", "Accepting client because debug"); + return true; +#else + + if (task == NULL) { + secerror("serverxpc: Client task is null, cannot verify platformness"); + return false; + } + + uint32_t flags = SecTaskGetCodeSignStatus(task); + /* check if valid and platform binary, but not platform path */ + + if ((flags & (CS_VALID | CS_PLATFORM_BINARY | CS_PLATFORM_PATH)) != (CS_VALID | CS_PLATFORM_BINARY)) { + if (SecIsInternalRelease()) { + if ((flags & (CS_DEBUGGED | CS_PLATFORM_BINARY | CS_PLATFORM_PATH)) != (CS_DEBUGGED | CS_PLATFORM_BINARY)) { + secerror("serverxpc: client is not a platform binary: 0x%08x", flags); + return false; + } + } else { + secerror("serverxpc: client is not a platform binary: 0x%08x", flags); + return false; + } + } + + CFStringRef signingIdentifier = SecTaskCopySigningIdentifier(task, NULL); + if (identifiers) { + if (signingIdentifier == NULL) { + secerror("serverxpc: client has no codesign identifier"); + return false; + } + + __block bool result = false; + CFArrayForEach(identifiers, ^(const void *value) { + if (CFEqual(value, signingIdentifier)) { + result = true; + } + }); + + if (result == true) { + secinfo("serverxpc", "client %@ is eligible platform binary", signingIdentifier); + } else { + secerror("serverxpc: client %@ is not eligible", signingIdentifier); + } + + CFReleaseNull(signingIdentifier); + return result; + } + + secinfo("serverxpc", "Client %@ is valid platform binary", signingIdentifier); + CFReleaseNull(signingIdentifier); + return true; + +#endif +} diff --git a/keychain/SecureObjectSync/SOSAccount.h b/keychain/SecureObjectSync/SOSAccount.h index f7674f30..7d888102 100644 --- a/keychain/SecureObjectSync/SOSAccount.h +++ b/keychain/SecureObjectSync/SOSAccount.h @@ -105,12 +105,9 @@ void SOSTransportEachMessage(SOSAccount* account, CFDictionaryRef updates, CFEr CFStringRef SOSAccountGetSOSCCStatusString(SOSCCStatus status); SOSCCStatus SOSAccountGetSOSCCStatusFromString(CFStringRef status); -bool SOSAccountJoinCircles(SOSAccountTransaction* aTxn, CFErrorRef* error); -bool SOSAccountJoinCirclesWithAnalytics(SOSAccountTransaction* aTxn, NSData* parentEvent, CFErrorRef* error); -bool SOSAccountJoinCirclesAfterRestore(SOSAccountTransaction* aTxn, CFErrorRef* error); -bool SOSAccountJoinCirclesAfterRestoreWithAnalytics(SOSAccountTransaction* aTxn, NSData* parentEvent, CFErrorRef* error); -bool SOSAccountRemovePeersFromCircle(SOSAccount* account, CFArrayRef peers, CFErrorRef* error); -bool SOSAccountRemovePeersFromCircleWithAnalytics(SOSAccount* account, CFArrayRef peers, NSData* parentEvent, CFErrorRef* error); +bool SOSAccountJoinCircles(SOSAccountTransaction* aTxn, NSData* parentEvent, CFErrorRef* error); +bool SOSAccountJoinCirclesAfterRestore(SOSAccountTransaction* aTxn, NSData* parentEvent, CFErrorRef* error); +bool SOSAccountRemovePeersFromCircle(SOSAccount* account, CFArrayRef peers, NSData* parentEvent, CFErrorRef* error); bool SOSAccountBail(SOSAccount* account, uint64_t limit_in_seconds, CFErrorRef* error); bool SOSAccountAcceptApplicants(SOSAccount* account, CFArrayRef applicants, CFErrorRef* error); bool SOSAccountRejectApplicants(SOSAccount* account, CFArrayRef applicants, CFErrorRef* error); @@ -286,6 +283,8 @@ void SOSAccountTimerFiredSendNextMessage(SOSAccountTransaction* txn, NSString* p NSArray* SOSAccountGetAllTLKs(void); CF_RETURNS_RETAINED CFMutableArrayRef SOSAccountCopyiCloudIdentities(SOSAccount* account); +bool SOSAccountEvaluateKeysAndCircle(SOSAccountTransaction *txn, CFErrorRef *block_error); + __END_DECLS #endif /* !_SOSACCOUNT_H_ */ diff --git a/keychain/SecureObjectSync/SOSAccount.m b/keychain/SecureObjectSync/SOSAccount.m index b75b48cf..9976962f 100644 --- a/keychain/SecureObjectSync/SOSAccount.m +++ b/keychain/SecureObjectSync/SOSAccount.m @@ -1135,14 +1135,18 @@ void SOSAccountPurgeIdentity(SOSAccount* account) { } } -bool sosAccountLeaveCircleWithAnalytics(SOSAccount* account, SOSCircleRef circle, NSData* parentData, CFErrorRef* error) { +bool sosAccountLeaveCircle(SOSAccount* account, SOSCircleRef circle, NSData* parentData, CFErrorRef* error) { SOSAccountTrustClassic *trust = account.trust; SOSFullPeerInfoRef identity = trust.fullPeerInfo; NSMutableSet* retirees = trust.retirees; NSError* localError = nil; - SFSignInAnalytics* parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:parentData error:&localError]; + SFSignInAnalytics* parent = nil; + if(parentData) { + parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:parentData error:&localError]; + } + SOSFullPeerInfoRef fpi = identity; if(!fpi) return false; @@ -1150,10 +1154,17 @@ bool sosAccountLeaveCircleWithAnalytics(SOSAccount* account, SOSCircleRef circle bool retval = false; - SFSignInAnalytics *promoteToRetiredEvent = [parent newSubTaskForEvent:@"promoteToRetiredEvent"]; + SFSignInAnalytics *promoteToRetiredEvent = nil; + + if(parent) { + promoteToRetiredEvent = [parent newSubTaskForEvent:@"promoteToRetiredEvent"]; + } + SOSPeerInfoRef retire_peer = SOSFullPeerInfoPromoteToRetiredAndCopy(fpi, &retiredError); if(retiredError){ - [promoteToRetiredEvent logRecoverableError:(__bridge NSError*)retiredError]; + if(promoteToRetiredEvent) { + [promoteToRetiredEvent logRecoverableError:(__bridge NSError*)retiredError]; + } secerror("SOSFullPeerInfoPromoteToRetiredAndCopy error: %@", retiredError); if(error){ *error = retiredError; @@ -1161,7 +1172,9 @@ bool sosAccountLeaveCircleWithAnalytics(SOSAccount* account, SOSCircleRef circle CFReleaseNull(retiredError); } } - [promoteToRetiredEvent stopWithAttributes:nil]; + if(promoteToRetiredEvent) { + [promoteToRetiredEvent stopWithAttributes:nil]; + } if (!retire_peer) { secerror("Create ticket failed for peer %@: %@", fpi, localError); @@ -1173,11 +1186,17 @@ bool sosAccountLeaveCircleWithAnalytics(SOSAccount* account, SOSCircleRef circle } else if (SOSCircleHasPeer(circle, retire_peer, NULL)) { if (SOSCircleUpdatePeerInfo(circle, retire_peer)) { CFErrorRef cleanupError = NULL; - SFSignInAnalytics *cleanupEvent = [parent newSubTaskForEvent:@"cleanupAfterPeerEvent"]; + SFSignInAnalytics *cleanupEvent = nil; + + if(parent) { + cleanupEvent = [parent newSubTaskForEvent:@"cleanupAfterPeerEvent"]; + } if (![account.trust cleanupAfterPeer:account.kvs_message_transport circleTransport:account.circle_transport seconds:RETIREMENT_FINALIZATION_SECONDS circle:circle cleanupPeer:retire_peer err:&cleanupError]) { secerror("Error cleanup up after peer (%@): %@", retire_peer, cleanupError); } - [cleanupEvent stopWithAttributes:nil]; + if(cleanupEvent) { + [cleanupEvent stopWithAttributes:nil]; + } CFReleaseSafe(cleanupError); } } @@ -1189,82 +1208,48 @@ bool sosAccountLeaveCircleWithAnalytics(SOSAccount* account, SOSCircleRef circle // Write retirement to Transport CFErrorRef postError = NULL; - SFSignInAnalytics *postRestirementEvent = [parent newSubTaskForEvent:@"postRestirementEvent"]; + SFSignInAnalytics *postRetirementEvent = nil; + + if(parent) { + postRetirementEvent = [parent newSubTaskForEvent:@"postRestirementEvent"]; + } + if(![account.circle_transport postRetirement:SOSCircleGetName(circle) peer:retire_peer err:&postError]){ - [postRestirementEvent logRecoverableError:(__bridge NSError*)postError]; + if(postRetirementEvent) { + [postRetirementEvent logRecoverableError:(__bridge NSError*)postError]; + } secwarning("Couldn't post retirement (%@)", postError); } - [postRestirementEvent stopWithAttributes:nil]; - - SFSignInAnalytics *flushChangesEvent = [parent newSubTaskForEvent:@"flushChangesEvent"]; - - if(![account.circle_transport flushChanges:&postError]){ - [flushChangesEvent logRecoverableError:(__bridge NSError*)postError]; - secwarning("Couldn't flush retirement data (%@)", postError); + if(postRetirementEvent) { + [postRetirementEvent stopWithAttributes:nil]; } - [flushChangesEvent stopWithAttributes:nil]; - CFReleaseNull(postError); - } - SFSignInAnalytics *purgeIdentityEvent = [parent newSubTaskForEvent:@"purgeIdentityEvent"]; - SOSAccountPurgeIdentity(account); - [purgeIdentityEvent stopWithAttributes:nil]; - retval = true; - CFReleaseNull(retire_peer); - return retval; -} - -bool sosAccountLeaveCircle(SOSAccount* account, SOSCircleRef circle, CFErrorRef* error) { - SOSAccountTrustClassic *trust = account.trust; - SOSFullPeerInfoRef identity = trust.fullPeerInfo; - NSMutableSet* retirees = trust.retirees; - - SOSFullPeerInfoRef fpi = identity; - if(!fpi) return false; - - CFErrorRef localError = NULL; - - bool retval = false; - - SOSPeerInfoRef retire_peer = SOSFullPeerInfoPromoteToRetiredAndCopy(fpi, &localError); - if (!retire_peer) { - secerror("Create ticket failed for peer %@: %@", fpi, localError); - } else { - // See if we need to repost the circle we could either be an applicant or a peer already in the circle - if(SOSCircleHasApplicant(circle, retire_peer, NULL)) { - // Remove our application if we have one. - SOSCircleWithdrawRequest(circle, retire_peer, NULL); - } else if (SOSCircleHasPeer(circle, retire_peer, NULL)) { - if (SOSCircleUpdatePeerInfo(circle, retire_peer)) { - CFErrorRef cleanupError = NULL; - if (![account.trust cleanupAfterPeer:account.kvs_message_transport circleTransport:account.circle_transport seconds:RETIREMENT_FINALIZATION_SECONDS circle:circle cleanupPeer:retire_peer err:&cleanupError]) { - secerror("Error cleanup up after peer (%@): %@", retire_peer, cleanupError); - } - CFReleaseSafe(cleanupError); - } + SFSignInAnalytics *flushChangesEvent = nil; + if(parent) { + flushChangesEvent = [parent newSubTaskForEvent:@"flushChangesEvent"]; } - // Store the retirement record locally. - CFSetAddValue((__bridge CFMutableSetRef)retirees, retire_peer); - - trust.retirees = retirees; - - // Write retirement to Transport - CFErrorRef postError = NULL; - if(![account.circle_transport postRetirement:SOSCircleGetName(circle) peer:retire_peer err:&postError]){ - secwarning("Couldn't post retirement (%@)", postError); - } if(![account.circle_transport flushChanges:&postError]){ + if(flushChangesEvent) { + [flushChangesEvent logRecoverableError:(__bridge NSError*)postError]; + } secwarning("Couldn't flush retirement data (%@)", postError); } + if(flushChangesEvent) { + [flushChangesEvent stopWithAttributes:nil]; + } CFReleaseNull(postError); } - + SFSignInAnalytics *purgeIdentityEvent = nil; + if(parent) { + purgeIdentityEvent = [parent newSubTaskForEvent:@"purgeIdentityEvent"]; + } SOSAccountPurgeIdentity(account); - + if(purgeIdentityEvent) { + [purgeIdentityEvent stopWithAttributes:nil]; + } retval = true; - CFReleaseNull(localError); CFReleaseNull(retire_peer); return retval; } @@ -1451,81 +1436,43 @@ CFDataRef SOSAccountCopyRecoveryPublicKey(SOSAccountTransaction* txn, CFErrorRef // MARK: Joining // -static bool SOSAccountJoinCircleWithAnalytics(SOSAccountTransaction* aTxn, SecKeyRef user_key, - bool use_cloud_peer, NSData* parentEvent, CFErrorRef* error) { +static bool SOSAccountJoinCircle(SOSAccountTransaction* aTxn, SecKeyRef user_key, bool use_cloud_peer, NSData* parentEvent, CFErrorRef* error) { SOSAccount* account = aTxn.account; SOSAccountTrustClassic *trust = account.trust; __block bool result = false; __block SOSFullPeerInfoRef cloud_full_peer = NULL; SFSignInAnalytics *ensureFullPeerAvailableEvent = nil; NSError* localError = nil; - SFSignInAnalytics* parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:parentEvent error:&localError]; - - require_action_quiet(trust.trustedCircle, fail, SOSCreateErrorWithFormat(kSOSErrorPeerNotFound, NULL, error, NULL, CFSTR("Don't have circle when joining???"))); - ensureFullPeerAvailableEvent = [parent newSubTaskForEvent:@"ensureFullPeerAvailableEvent"]; - require_quiet([account.trust ensureFullPeerAvailable:(__bridge CFDictionaryRef)account.gestalt deviceID:(__bridge CFStringRef)account.deviceID backupKey:(__bridge CFDataRef)account.backup_key err:error], fail); - [ensureFullPeerAvailableEvent stopWithAttributes:nil]; + SFSignInAnalytics* parent = nil; - SOSFullPeerInfoRef myCirclePeer = trust.fullPeerInfo; - if (SOSCircleCountPeers(trust.trustedCircle) == 0 || SOSAccountGhostResultsInReset(account)) { - secnotice("resetToOffering", "Resetting circle to offering since there are no peers"); - // this also clears initial sync data - result = [account.trust resetCircleToOffering:aTxn userKey:user_key err:error]; - } else { - SOSAccountInitializeInitialSync(account); - if (use_cloud_peer) { - cloud_full_peer = SOSCircleCopyiCloudFullPeerInfoRef(trust.trustedCircle, NULL); - } - SFSignInAnalytics *acceptApplicantEvent = [parent newSubTaskForEvent:@"acceptApplicantEvent"]; - [account.trust modifyCircle:account.circle_transport err:error action:^bool(SOSCircleRef circle) { - result = SOSAccountAddEscrowToPeerInfo(account, myCirclePeer, error); - result &= SOSCircleRequestAdmission(circle, user_key, myCirclePeer, error); - trust.departureCode = kSOSNeverLeftCircle; - if(result && cloud_full_peer) { - CFErrorRef localError = NULL; - CFStringRef cloudid = SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(cloud_full_peer)); - require_quiet(cloudid, finish); - require_quiet(SOSCircleHasActivePeerWithID(circle, cloudid, &localError), finish); - require_quiet(SOSCircleAcceptRequest(circle, user_key, cloud_full_peer, SOSFullPeerInfoGetPeerInfo(myCirclePeer), &localError), finish); - finish: - if (localError){ - [acceptApplicantEvent logRecoverableError:(__bridge NSError *)(localError)]; - secerror("Failed to join with cloud identity: %@", localError); - CFReleaseNull(localError); - } - } - return result; - }]; - [acceptApplicantEvent stopWithAttributes:nil]; - if (use_cloud_peer) { - SFSignInAnalytics *updateOutOfDateSyncViewsEvent = [acceptApplicantEvent newSubTaskForEvent:@"updateOutOfDateSyncViewsEvent"]; - SOSAccountUpdateOutOfSyncViews(aTxn, SOSViewsGetAllCurrent()); - [updateOutOfDateSyncViewsEvent stopWithAttributes:nil]; - } + if(parentEvent) { + parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:parentEvent error:&localError]; } -fail: - CFReleaseNull(cloud_full_peer); - return result; -} -static bool SOSAccountJoinCircle(SOSAccountTransaction* aTxn, SecKeyRef user_key, - bool use_cloud_peer, CFErrorRef* error) { - SOSAccount* account = aTxn.account; - SOSAccountTrustClassic *trust = account.trust; - __block bool result = false; - __block SOSFullPeerInfoRef cloud_full_peer = NULL; require_action_quiet(trust.trustedCircle, fail, SOSCreateErrorWithFormat(kSOSErrorPeerNotFound, NULL, error, NULL, CFSTR("Don't have circle when joining???"))); + if(parent) { + ensureFullPeerAvailableEvent = [parent newSubTaskForEvent:@"ensureFullPeerAvailableEvent"]; + } require_quiet([account.trust ensureFullPeerAvailable:(__bridge CFDictionaryRef)account.gestalt deviceID:(__bridge CFStringRef)account.deviceID backupKey:(__bridge CFDataRef)account.backup_key err:error], fail); + if(ensureFullPeerAvailableEvent) { + [ensureFullPeerAvailableEvent stopWithAttributes:nil]; + } + SOSFullPeerInfoRef myCirclePeer = trust.fullPeerInfo; if (SOSCircleCountPeers(trust.trustedCircle) == 0 || SOSAccountGhostResultsInReset(account)) { secnotice("resetToOffering", "Resetting circle to offering since there are no peers"); // this also clears initial sync data result = [account.trust resetCircleToOffering:aTxn userKey:user_key err:error]; } else { + SFSignInAnalytics *acceptApplicantEvent = nil; + SOSAccountInitializeInitialSync(account); if (use_cloud_peer) { cloud_full_peer = SOSCircleCopyiCloudFullPeerInfoRef(trust.trustedCircle, NULL); } + if(parent) { + acceptApplicantEvent = [parent newSubTaskForEvent:@"acceptApplicantEvent"]; + } [account.trust modifyCircle:account.circle_transport err:error action:^bool(SOSCircleRef circle) { result = SOSAccountAddEscrowToPeerInfo(account, myCirclePeer, error); result &= SOSCircleRequestAdmission(circle, user_key, myCirclePeer, error); @@ -1538,14 +1485,24 @@ static bool SOSAccountJoinCircle(SOSAccountTransaction* aTxn, SecKeyRef user_key require_quiet(SOSCircleAcceptRequest(circle, user_key, cloud_full_peer, SOSFullPeerInfoGetPeerInfo(myCirclePeer), &localError), finish); finish: if (localError){ + if(acceptApplicantEvent) { + [acceptApplicantEvent logRecoverableError:(__bridge NSError *)(localError)]; + } secerror("Failed to join with cloud identity: %@", localError); CFReleaseNull(localError); } } return result; }]; + if(acceptApplicantEvent) { + [acceptApplicantEvent stopWithAttributes:nil]; + } if (use_cloud_peer) { SOSAccountUpdateOutOfSyncViews(aTxn, SOSViewsGetAllCurrent()); + if(acceptApplicantEvent) { + SFSignInAnalytics *updateOutOfDateSyncViewsEvent = [acceptApplicantEvent newSubTaskForEvent:@"updateOutOfDateSyncViewsEvent"]; + [updateOutOfDateSyncViewsEvent stopWithAttributes:nil]; + } } } fail: @@ -1553,7 +1510,7 @@ fail: return result; } -static bool SOSAccountJoinCirclesWithAnalytics_internal(SOSAccountTransaction* aTxn, bool use_cloud_identity, NSData* parentEvent, CFErrorRef* error) { +static bool SOSAccountJoinCircles_internal(SOSAccountTransaction* aTxn, bool use_cloud_identity, NSData* parentEvent, CFErrorRef* error) { SOSAccount* account = aTxn.account; SOSAccountTrustClassic *trust = account.trust; bool success = false; @@ -1561,7 +1518,21 @@ static bool SOSAccountJoinCirclesWithAnalytics_internal(SOSAccountTransaction* a SecKeyRef user_key = SOSAccountGetPrivateCredential(account, error); require_quiet(user_key, done); // Fail if we don't get one. - require_action_quiet(trust.trustedCircle, done, SOSErrorCreate(kSOSErrorNoCircle, error, NULL, CFSTR("No circle to join"))); + if(!trust.trustedCircle || SOSCircleCountPeers(trust.trustedCircle) == 0 ) { + secnotice("resetToOffering", "Resetting circle to offering because it's empty and we're joining"); + return [account.trust resetCircleToOffering:aTxn userKey:user_key err:error]; + } + + if(SOSCircleHasPeerWithID(trust.trustedCircle, (__bridge CFStringRef)(account.peerID), NULL)) { + // We shouldn't be at this point if we're already in circle. + secnotice("circleops", "attempt to join a circle we're in - continuing."); + return true; // let things above us think we're in circle - because we are. + } + + if(!SOSCircleVerify(trust.trustedCircle, account.accountKey, NULL)) { + secnotice("resetToOffering", "Resetting circle to offering since we are new and it doesn't verify with current userKey"); + return [account.trust resetCircleToOffering:aTxn userKey:user_key err:error]; + } if (trust.fullPeerInfo != NULL) { SOSPeerInfoRef myPeer = trust.peerInfo; @@ -1577,7 +1548,7 @@ static bool SOSAccountJoinCirclesWithAnalytics_internal(SOSAccountTransaction* a } } - success = SOSAccountJoinCircleWithAnalytics(aTxn, user_key, use_cloud_identity, parentEvent, error); + success = SOSAccountJoinCircle(aTxn, user_key, use_cloud_identity, parentEvent, error); require_quiet(success, done); @@ -1587,127 +1558,26 @@ done: return success; } -static bool SOSAccountJoinCircles_internal(SOSAccountTransaction* aTxn, bool use_cloud_identity, CFErrorRef* error) { - SOSAccount* account = aTxn.account; - SOSAccountTrustClassic *trust = account.trust; - bool success = false; - - SecKeyRef user_key = SOSAccountGetPrivateCredential(account, error); - require_quiet(user_key, done); // Fail if we don't get one. - - require_action_quiet(trust.trustedCircle, done, SOSErrorCreate(kSOSErrorNoCircle, error, NULL, CFSTR("No circle to join"))); - - if (trust.fullPeerInfo != NULL) { - SOSPeerInfoRef myPeer = trust.peerInfo; - success = SOSCircleHasPeer(trust.trustedCircle, myPeer, NULL); - require_quiet(!success, done); - - SOSCircleRemoveRejectedPeer(trust.trustedCircle, myPeer, NULL); // If we were rejected we should remove it now. - - if (!SOSCircleHasApplicant(trust.trustedCircle, myPeer, NULL)) { - secerror("Resetting my peer (ID: %@) for circle '%@' during application", SOSPeerInfoGetPeerID(myPeer), SOSCircleGetName(trust.trustedCircle)); - - trust.fullPeerInfo = NULL; - } - } - - success = SOSAccountJoinCircle(aTxn, user_key, use_cloud_identity, error); - - require_quiet(success, done); - - trust.departureCode = kSOSNeverLeftCircle; - -done: - return success; -} - -bool SOSAccountJoinCirclesWithAnalytics(SOSAccountTransaction* aTxn, NSData* parentEvent, CFErrorRef* error) { - secnotice("circleOps", "Normal path circle join (SOSAccountJoinCirclesWithAnalytics)"); - return SOSAccountJoinCirclesWithAnalytics_internal(aTxn, false, parentEvent, error); +bool SOSAccountJoinCircles(SOSAccountTransaction* aTxn, NSData* parentEvent, CFErrorRef* error) { + secnotice("circleOps", "Normal path circle join (SOSAccountJoinCircles)"); + return SOSAccountJoinCircles_internal(aTxn, false, parentEvent, error); } -bool SOSAccountJoinCircles(SOSAccountTransaction* aTxn, CFErrorRef* error) { - secnotice("circleOps", "Normal path circle join (SOSAccountJoinCircles)"); - return SOSAccountJoinCircles_internal(aTxn, false, error); -} - -bool SOSAccountJoinCirclesAfterRestore(SOSAccountTransaction* aTxn, CFErrorRef* error) { - secnotice("circleOps", "Joining after restore (SOSAccountJoinCirclesAfterRestore)"); - return SOSAccountJoinCircles_internal(aTxn, true, error); -} - -bool SOSAccountJoinCirclesAfterRestoreWithAnalytics(SOSAccountTransaction* aTxn, NSData* parentEvent, CFErrorRef* error) { +bool SOSAccountJoinCirclesAfterRestore(SOSAccountTransaction* aTxn, NSData* parentEvent, CFErrorRef* error) { secnotice("circleOps", "Joining after restore (SOSAccountJoinCirclesAfterRestore)"); - return SOSAccountJoinCirclesWithAnalytics_internal(aTxn, true, parentEvent, error); + return SOSAccountJoinCircles_internal(aTxn, true, parentEvent, error); } -bool SOSAccountRemovePeersFromCircle(SOSAccount* account, CFArrayRef peers, CFErrorRef* error) +bool SOSAccountRemovePeersFromCircle(SOSAccount* account, CFArrayRef peers, NSData* parentEvent, CFErrorRef* error) { - bool result = false; - CFMutableSetRef peersToRemove = NULL; - SecKeyRef user_key = SOSAccountGetPrivateCredential(account, error); - if(!user_key){ - secnotice("circleOps", "Can't remove without userKey"); - return result; - } - SOSFullPeerInfoRef me_full = account.fullPeerInfo; - SOSPeerInfoRef me = account.peerInfo; - if(!(me_full && me)) - { - secnotice("circleOps", "Can't remove without being active peer"); - SOSErrorCreate(kSOSErrorPeerNotFound, error, NULL, CFSTR("Can't remove without being active peer")); - return result; - } - - result = true; // beyond this point failures would be rolled up in AccountModifyCircle. - - peersToRemove = CFSetCreateMutableForSOSPeerInfosByIDWithArray(kCFAllocatorDefault, peers); - if(!peersToRemove) - { - CFReleaseNull(peersToRemove); - secnotice("circleOps", "No peerSet to remove"); - return result; - } - - // If we're one of the peers expected to leave - note that and then remove ourselves from the set (different handling). - bool leaveCircle = CFSetContainsValue(peersToRemove, me); - CFSetRemoveValue(peersToRemove, me); - - result &= [account.trust modifyCircle:account.circle_transport err:error action:^(SOSCircleRef circle) { - bool success = false; - - if(CFSetGetCount(peersToRemove) != 0) { - require_quiet(SOSCircleRemovePeers(circle, user_key, me_full, peersToRemove, error), done); - success = SOSAccountGenerationSignatureUpdate(account, error); - } else success = true; - if (success && leaveCircle) { - secnotice("circleOps", "Leaving circle by client request (SOSAccountRemovePeersFromCircle)"); - success = sosAccountLeaveCircle(account, circle, error); - } - - done: - return success; - - }]; + NSError* localError = nil; + SFSignInAnalytics* parent = nil; - if(result) { - CFStringSetPerformWithDescription(peersToRemove, ^(CFStringRef description) { - secnotice("circleOps", "Removed Peers from circle %@", description); - }); + if(parentEvent) { + parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:parentEvent error:&localError]; } - CFReleaseNull(peersToRemove); - return result; -} - - -bool SOSAccountRemovePeersFromCircleWithAnalytics(SOSAccount* account, CFArrayRef peers, NSData* parentEvent, CFErrorRef* error) -{ - - NSError* localError = nil; - SFSignInAnalytics* parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:parentEvent error:&localError]; - bool result = false; CFMutableSetRef peersToRemove = NULL; SecKeyRef user_key = SOSAccountGetPrivateCredential(account, error); @@ -1743,18 +1613,27 @@ bool SOSAccountRemovePeersFromCircleWithAnalytics(SOSAccount* account, CFArrayR if(CFSetGetCount(peersToRemove) != 0) { require_quiet(SOSCircleRemovePeers(circle, user_key, me_full, peersToRemove, error), done); - SFSignInAnalytics *generationSignatureUpdateEvent = [parent newSubTaskForEvent:@"generationSignatureUpdateEvent"]; + + SFSignInAnalytics *generationSignatureUpdateEvent = nil; + if(parent) { + generationSignatureUpdateEvent = [parent newSubTaskForEvent:@"generationSignatureUpdateEvent"]; + } + success = SOSAccountGenerationSignatureUpdate(account, error); if(error && *error){ NSError* signatureUpdateError = (__bridge NSError*)*error; - [generationSignatureUpdateEvent logUnrecoverableError:signatureUpdateError]; + if(generationSignatureUpdateEvent) { + [generationSignatureUpdateEvent logUnrecoverableError:signatureUpdateError]; + } + } + if(generationSignatureUpdateEvent) { + [generationSignatureUpdateEvent stopWithAttributes:nil]; } - [generationSignatureUpdateEvent stopWithAttributes:nil]; } else success = true; if (success && leaveCircle) { secnotice("circleOps", "Leaving circle by client request (SOSAccountRemovePeersFromCircle)"); - success = sosAccountLeaveCircleWithAnalytics(account, circle, parentEvent, error); + success = sosAccountLeaveCircle(account, circle, parentEvent, error); } done: @@ -1782,7 +1661,7 @@ bool SOSAccountBail(SOSAccount* account, uint64_t limit_in_seconds, CFErrorRef* dispatch_group_async(group, queue, ^{ [trust modifyCircle:account.circle_transport err:error action:^(SOSCircleRef circle) { secnotice("circleOps", "Leaving circle by client request (Bail)"); - return sosAccountLeaveCircle(account, circle, error); + return sosAccountLeaveCircle(account, circle, nil, error); }]; }); dispatch_time_t milestone = dispatch_time(DISPATCH_TIME_NOW, limit_in_seconds * NSEC_PER_SEC); diff --git a/keychain/SecureObjectSync/SOSAccountCircles.m b/keychain/SecureObjectSync/SOSAccountCircles.m index 26e84b44..192548db 100644 --- a/keychain/SecureObjectSync/SOSAccountCircles.m +++ b/keychain/SecureObjectSync/SOSAccountCircles.m @@ -11,6 +11,8 @@ #import "keychain/SecureObjectSync/SOSTransportCircleCK.h" #import "keychain/SecureObjectSync/SOSAccountTrust.h" #import "keychain/SecureObjectSync/SOSAccountTrustClassic.h" +#import "keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.h" +#import "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" #include "keychain/SecureObjectSync/SOSPeerInfoCollections.h" #include "SOSCloudKeychainClient.h" @@ -42,3 +44,10 @@ fail: return circle; } +bool SOSAccountEvaluateKeysAndCircle(SOSAccountTransaction *txn, CFErrorRef *error) { + // if the userKey signature on the circle doesn't work with the new userkey + if([txn.account.trust isInCircleOnly:nil]) { + return SOSAccountGenerationSignatureUpdate(txn.account, error); + } + return true; +} diff --git a/keychain/SecureObjectSync/SOSAccountCredentials.m b/keychain/SecureObjectSync/SOSAccountCredentials.m index 31f28a5c..efe75070 100644 --- a/keychain/SecureObjectSync/SOSAccountCredentials.m +++ b/keychain/SecureObjectSync/SOSAccountCredentials.m @@ -29,6 +29,7 @@ #include "SOSTransport.h" #import "keychain/SecureObjectSync/SOSAccountTrust.h" #import "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" +#import "keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.h" #define kPublicKeyAvailable "com.apple.security.publickeyavailable" // diff --git a/keychain/SecureObjectSync/SOSAccountPriv.h b/keychain/SecureObjectSync/SOSAccountPriv.h index 249a8e00..d90657db 100644 --- a/keychain/SecureObjectSync/SOSAccountPriv.h +++ b/keychain/SecureObjectSync/SOSAccountPriv.h @@ -269,8 +269,7 @@ void SOSAccountSetLastDepartureReason(SOSAccount* account, enum DepartureReason void SOSAccountSetUserPublicTrustedForTesting(SOSAccount* account); void SOSAccountPurgeIdentity(SOSAccount*); -bool sosAccountLeaveCircle(SOSAccount* account, SOSCircleRef circle, CFErrorRef* error); -bool sosAccountLeaveCircleWithAnalytics(SOSAccount* account, SOSCircleRef circle, NSData* parentData, CFErrorRef* error); +bool sosAccountLeaveCircle(SOSAccount* account, SOSCircleRef circle, NSData* parentData, CFErrorRef* error); bool SOSAccountForEachRing(SOSAccount* account, SOSRingRef (^action)(CFStringRef name, SOSRingRef ring)); bool SOSAccountUpdateBackUp(SOSAccount* account, CFStringRef viewname, CFErrorRef *error); diff --git a/keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.m b/keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.m index d118ec54..ec3b5664 100644 --- a/keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.m +++ b/keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.m @@ -402,7 +402,7 @@ static bool SOSCircleHasUpdatedPeerInfoWithOctagonKey(SOSCircleRef oldCircle, SO secnotice("account", "Key state: accountKey %@, previousAccountKey %@, old_circle_key %@", account.accountKey, account.previousAccountKey, old_circle_key); - if (sosAccountLeaveCircle(account, newCircle, error)) { + if (sosAccountLeaveCircle(account, newCircle, nil, error)) { secnotice("circleOps", "Leaving circle by newcircle state"); circleToPush = newCircle; } else { @@ -701,7 +701,7 @@ fail: bool result = true; secnotice("circleOps", "leaveCircleWithAccount: Leaving circle by client request"); result &= [self modifyCircle:account.circle_transport err:error action:^(SOSCircleRef circle) { - return sosAccountLeaveCircleWithAnalytics(account, circle, parentEvent, error); + return sosAccountLeaveCircle(account, circle, parentEvent, error); }]; self.departureCode = kSOSWithdrewMembership; @@ -714,7 +714,7 @@ fail: bool result = true; secnotice("circleOps", "Leaving circle by client request"); result &= [self modifyCircle:account.circle_transport err:error action:^(SOSCircleRef circle) { - return sosAccountLeaveCircle(account, circle, error); + return sosAccountLeaveCircle(account, circle, nil, error); }]; account.backup_key = nil; self.departureCode = kSOSWithdrewMembership; diff --git a/keychain/SecureObjectSync/SOSCircle.c b/keychain/SecureObjectSync/SOSCircle.c index f953e859..b80f1e0d 100644 --- a/keychain/SecureObjectSync/SOSCircle.c +++ b/keychain/SecureObjectSync/SOSCircle.c @@ -1320,7 +1320,9 @@ void SOSCircleForEachApplicant(SOSCircleRef circle, void (^action)(SOSPeerInfoRe bool SOSCircleHasPeerWithID(SOSCircleRef circle, CFStringRef peerid, CFErrorRef *error) { SOSCircleAssertStable(circle); - + if(!peerid) { + return false; + } SOSPeerInfoRef found = asSOSPeerInfo(CFSetGetValue(circle->peers, peerid)); return found && !isHiddenPeer(found); } diff --git a/keychain/TrustedPeersHelper/Container.swift b/keychain/TrustedPeersHelper/Container.swift index b5ac7067..ad1e321b 100644 --- a/keychain/TrustedPeersHelper/Container.swift +++ b/keychain/TrustedPeersHelper/Container.swift @@ -906,7 +906,6 @@ class Container: NSObject { func onQueueDetermineLocalTrustStatus(reply: @escaping (TrustedPeersHelperEgoPeerStatus, Error?) -> Void) { let viablePeerCountsByModelID = self.model.viablePeerCountsByModelID() let peerCountsByMachineID = self.model.peerCountsByMachineID() - if let egoPeerID = self.containerMO.egoPeerID { var status = self.model.statusOfPeer(withID: egoPeerID) var isExcluded: Bool = (status == .excluded) diff --git a/keychain/ot/OTCuttlefishContext.m b/keychain/ot/OTCuttlefishContext.m index be6ecf96..a4e5c8fc 100644 --- a/keychain/ot/OTCuttlefishContext.m +++ b/keychain/ot/OTCuttlefishContext.m @@ -2557,12 +2557,15 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; else if((status&TPPeerStatusFullyReciprocated) == TPPeerStatusFullyReciprocated){ trustStatus = CliqueStatusIn; } - else if((status&TPPeerStatusUnknown) == TPPeerStatusUnknown){ - trustStatus = CliqueStatusAbsent; - } else if ((status&TPPeerStatusSelfTrust) == TPPeerStatusSelfTrust) { trustStatus = CliqueStatusIn; } + else if ((status&TPPeerStatusIgnored) == TPPeerStatusIgnored) { + trustStatus = CliqueStatusNotIn; + } + else if((status&TPPeerStatusUnknown) == TPPeerStatusUnknown){ + trustStatus = CliqueStatusAbsent; + } else { secnotice("octagon", "TPPeerStatus is empty"); trustStatus = CliqueStatusAbsent; diff --git a/keychain/ot/tests/octagon/OctagonTests+Reset.swift b/keychain/ot/tests/octagon/OctagonTests+Reset.swift index 3bc43ec7..db3fb52f 100644 --- a/keychain/ot/tests/octagon/OctagonTests+Reset.swift +++ b/keychain/ot/tests/octagon/OctagonTests+Reset.swift @@ -707,6 +707,94 @@ class OctagonResetTests: OctagonTestsBase { assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) self.verifyDatabaseMocks() } + + func testCliqueResetProtectedDataHandlingInMultiPeerCircle() throws { + OctagonSetSOSFeatureEnabled(false) + self.startCKAccountStatusMock() + + var firstCliqueIdentifier: String? + + let clique: OTClique + let cliqueContextConfiguration = OTConfigurationContext() + cliqueContextConfiguration.context = OTDefaultContext + cliqueContextConfiguration.dsid = "13453464" + cliqueContextConfiguration.altDSID = self.mockAuthKit.altDSID! + cliqueContextConfiguration.authenticationAppleID = "appleID" + cliqueContextConfiguration.passwordEquivalentToken = "petpetpetpetpet" + cliqueContextConfiguration.otControl = self.otControl + cliqueContextConfiguration.ckksControl = self.ckksControl + cliqueContextConfiguration.sbd = OTMockSecureBackup(bottleID: nil, entropy: nil) + do { + clique = try OTClique.newFriends(withContextData: cliqueContextConfiguration, resetReason: .testGenerated) + XCTAssertNotNil(clique, "Clique should not be nil") + XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") + firstCliqueIdentifier = clique.cliqueMemberIdentifier + } catch { + XCTFail("Shouldn't have errored making new friends: \(error)") + throw error + } + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.assertConsidersSelfTrusted(context: self.cuttlefishContext) + + let entropy = try self.loadSecret(label: clique.cliqueMemberIdentifier!) + XCTAssertNotNil(entropy, "entropy should not be nil") + + let bottleJoinerContextID = "bottleJoiner" + let joinerContext = self.manager.context(forContainerName: OTCKContainerName, contextID: bottleJoinerContextID) + + let bottle = self.fakeCuttlefishServer.state.bottles[0] + + joinerContext.startOctagonStateMachine() + self.startCKAccountStatusMock() + self.assertEnters(context: joinerContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + + // Before you call joinWithBottle, you need to call fetchViableBottles. + let fetchViableExpectation = self.expectation(description: "fetchViableBottles callback occurs") + joinerContext.rpcFetchAllViableBottles { viable, _, error in + XCTAssertNil(error, "should be no error fetching viable bottles") + XCTAssert(viable?.contains(bottle.bottleID) ?? false, "The bottle we're about to restore should be viable") + fetchViableExpectation.fulfill() + } + self.wait(for: [fetchViableExpectation], timeout: 10) + + let joinWithBottleExpectation = self.expectation(description: "joinWithBottle callback occurs") + joinerContext.join(withBottle: bottle.bottleID, entropy: entropy!, bottleSalt: self.mockAuthKit.altDSID!) { error in + XCTAssertNil(error, "error should be nil") + joinWithBottleExpectation.fulfill() + } + + self.wait(for: [joinWithBottleExpectation], timeout: 10) + + self.assertEnters(context: joinerContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.assertConsidersSelfTrusted(context:joinerContext) + + self.silentZoneDeletesAllowed = true + + let newClique: OTClique + do { + newClique = try OTClique.resetProtectedData(cliqueContextConfiguration) + XCTAssertNotEqual(newClique.cliqueMemberIdentifier, firstCliqueIdentifier, "clique identifiers should be different") + } catch { + XCTFail("Shouldn't have errored resetting everything: \(error)") + throw error + } + XCTAssertNotNil(newClique, "newClique should not be nil") + + self.sendContainerChangeWaitForFetchForStates(context: joinerContext, states: [OctagonStateUntrusted]) + self.sendContainerChangeWaitForFetchForStates(context: self.cuttlefishContext, states: [OctagonStateReady]) + self.assertConsidersSelfTrusted(context:self.cuttlefishContext) + + let statusExpectation = self.expectation(description: "status callback occurs") + let configuration = OTOperationConfiguration() + + joinerContext.rpcTrustStatus(configuration) { egoStatus, _, _, _, _ in + XCTAssertEqual(.notIn, egoStatus, "cliqueStatus should be 'Not In'") + statusExpectation.fulfill() + } + self.wait(for: [statusExpectation], timeout: 10) + + } } #endif // OCTAGON diff --git a/keychain/securityd/Regressions/SOSAccountTesting.h b/keychain/securityd/Regressions/SOSAccountTesting.h index 413b75cb..d3f6fd16 100644 --- a/keychain/securityd/Regressions/SOSAccountTesting.h +++ b/keychain/securityd/Regressions/SOSAccountTesting.h @@ -62,7 +62,7 @@ static inline bool SOSAccountJoinCirclesAfterRestore_wTxn(SOSAccount* acct, CFEr { __block bool result = false; [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { - result = SOSAccountJoinCirclesAfterRestore(txn, error); + result = SOSAccountJoinCirclesAfterRestore(txn, nil, error); }]; return result; } @@ -71,7 +71,7 @@ static inline bool SOSAccountJoinCircles_wTxn(SOSAccount* acct, CFErrorRef* erro { __block bool result = false; [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { - result = SOSAccountJoinCircles(txn, error); + result = SOSAccountJoinCircles(txn, nil, error); }]; return result; } diff --git a/keychain/securityd/Regressions/secd-100-initialsync.m b/keychain/securityd/Regressions/secd-100-initialsync.m index 64557741..b2391098 100644 --- a/keychain/securityd/Regressions/secd-100-initialsync.m +++ b/keychain/securityd/Regressions/secd-100-initialsync.m @@ -96,6 +96,8 @@ static void tests(void) ok(SOSAccountJoinCircles_wTxn(alice_account, &error), "Join circle: %@", error); ok(SOSAccountCheckHasBeenInSync_wTxn(alice_account), "Alice account initial sync done"); + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates"); + ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); CFReleaseNull(error); CFReleaseNull(cfpassword); @@ -105,7 +107,7 @@ static void tests(void) ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); CFReleaseNull(error); - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 4, "updates"); + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates"); { CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); diff --git a/keychain/securityd/Regressions/secd-55-account-circle.m b/keychain/securityd/Regressions/secd-55-account-circle.m index d8035f97..b11e1d31 100644 --- a/keychain/securityd/Regressions/secd-55-account-circle.m +++ b/keychain/securityd/Regressions/secd-55-account-circle.m @@ -325,7 +325,7 @@ static void tests(void) carol_account.peerInfo, NULL); - ok(SOSAccountRemovePeersFromCircle(bob_account, peers_to_remove_array, NULL)); + ok(SOSAccountRemovePeersFromCircle(bob_account, peers_to_remove_array, nil, NULL)); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 4, "Remove peers"); diff --git a/keychain/securityd/Regressions/secd-58-password-change.m b/keychain/securityd/Regressions/secd-58-password-change.m index 3135d5b7..db6ff25c 100644 --- a/keychain/securityd/Regressions/secd-58-password-change.m +++ b/keychain/securityd/Regressions/secd-58-password-change.m @@ -59,6 +59,15 @@ static bool AssertCreds(SOSAccount* account,CFStringRef acct_name, CFDataRef pas return retval; } +static inline bool SOSAccountEvaluateKeysAndCircle_wTxn(SOSAccount* acct, CFErrorRef* error) +{ + __block bool result = false; + [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) { + result = SOSAccountEvaluateKeysAndCircle(txn, NULL); + }]; + return result; +} + static bool ResetToOffering(SOSAccount* account) { CFErrorRef error = NULL; bool retval; @@ -213,11 +222,27 @@ static void tests(void) is(countPeers(alice_account), 3, "There are three peers - Alice, Carol, Bob"); is(countActivePeers(alice_account), 4, "There are four active peers - bob, alice, carol and iCloud"); is(countActiveValidPeers(alice_account), 3, "There are three active valid peers - alice, bob, and icloud"); + + /* Change Password 4 - new peer changes the password and joins ----------------------------------------------------*/ + CFReleaseNull(cfnewpassword); + cfnewpassword = CFDataCreate(NULL, (uint8_t *) "dodododod", 10); + + SOSAccount* david_account = CreateAccountForLocalChanges(CFSTR("David"), CFSTR("TestSource")); + ok(AssertCreds(david_account , cfaccount, cfnewpassword), "Credential resetting for David"); + is(ProcessChangesUntilNoChange(changes, david_account, NULL), 2, "updates"); + is(countPeers(david_account), 3, "Still 3 peers"); + + ok(JoinCircle(david_account), "David Applies"); + is(ProcessChangesUntilNoChange(changes, david_account, NULL), 2, "updates"); + is(countPeers(david_account), 1, "Only David is in circle"); + + CFReleaseNull(cfnewpassword); alice_account = nil; bob_account = nil; carol_account = nil; + david_account = nil; SOSTestCleanup(); } diff --git a/keychain/securityd/SOSCloudCircleServer.m b/keychain/securityd/SOSCloudCircleServer.m index 71677a8a..ae3a447d 100644 --- a/keychain/securityd/SOSCloudCircleServer.m +++ b/keychain/securityd/SOSCloudCircleServer.m @@ -951,47 +951,16 @@ done: return result; } -static bool SOSCCAssertUserCredentialsAndOptionalDSID(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error) { - secnotice("updates", "Setting credentials and dsid (%@) for %@", dsid, user_label); - - OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameAssertUserCredentialsAndOptionalDSID); - - bool result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - if (dsid != NULL && CFStringCompare(dsid, CFSTR(""), 0) != 0) { - SOSAccountAssertDSID(txn.account, dsid); - } - return true; - }); - - require_quiet(result, done); - - require_quiet(SyncKVSAndWait(error), done); // Make sure we've seen what the server has - require_quiet(Flush(error), done); // And processed it already...before asserting - - result = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *block_error) { - return SOSAccountAssertUserCredentials(txn.account, user_label, user_password, block_error); - }); - - require_quiet(result, done); - require_quiet(Flush(error), done); // Process any incoming information..circles et.al. before fixing our signature - - result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - return SOSAccountGenerationSignatureUpdate(txn.account, error); - }); - - secnotice("updates", "Complete credentials and dsid (%@) for %@: %d %@", - dsid, user_label, result, error ? *error : NULL); -done: - OctagonSignpostEnd(signPost, SOSSignpostNameAssertUserCredentialsAndOptionalDSID, OctagonSignpostNumber1(SOSSignpostNameAssertUserCredentialsAndOptionalDSID), (int)result); - return result; -} - -static bool SOSCCAssertUserCredentialsAndOptionalDSIDWithAnalytics(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, NSData* parentEvent, CFErrorRef *error) { +static bool SOSCCAssertUserCredentialsAndOptionalDSID(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, NSData* parentEvent, CFErrorRef *error) { secnotice("updates", "Setting credentials and dsid (%@) for %@", dsid, user_label); OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameAssertUserCredentialsAndOptionalDSID); NSError* localError = nil; - SFSignInAnalytics* parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:parentEvent error:&localError]; + SFSignInAnalytics* parent = nil; + + if(parentEvent) { + parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:parentEvent error:&localError]; + } SFSignInAnalytics *syncAndWaitEvent = nil; SFSignInAnalytics *flushEvent = nil; @@ -1006,29 +975,46 @@ static bool SOSCCAssertUserCredentialsAndOptionalDSIDWithAnalytics(CFStringRef u }); require_quiet(result, done); - syncAndWaitEvent = [parent newSubTaskForEvent:@"syncAndWaitEvent"]; + + if(parent) { + syncAndWaitEvent = [parent newSubTaskForEvent:@"syncAndWaitEvent"]; + } require_quiet(SyncKVSAndWait(error), done); // Make sure we've seen what the server has - [syncAndWaitEvent stopWithAttributes:nil]; + if(syncAndWaitEvent) { + [syncAndWaitEvent stopWithAttributes:nil]; + } - flushEvent = [parent newSubTaskForEvent:@"flushEvent"]; + if(parent) { + flushEvent = [parent newSubTaskForEvent:@"flushEvent"]; + } require_quiet(Flush(error), done); // And processed it already...before asserting - [flushEvent stopWithAttributes:nil]; + if(flushEvent) { + [flushEvent stopWithAttributes:nil]; + } result = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *block_error) { return SOSAccountAssertUserCredentials(txn.account, user_label, user_password, block_error); }); require_quiet(result, done); - secondFlushEvent = [parent newSubTaskForEvent:@"secondFlushEvent"]; + if(parent) { + secondFlushEvent = [parent newSubTaskForEvent:@"secondFlushEvent"]; + } require_quiet(Flush(error), done); // Process any incoming information..circles et.al. before fixing our signature - [secondFlushEvent stopWithAttributes:nil]; + if(secondFlushEvent) { + [secondFlushEvent stopWithAttributes:nil]; + } - generationSignatureUpdateEvent = [parent newSubTaskForEvent:@"generationSignatureUpdateEvent"]; + if(parent) { + generationSignatureUpdateEvent = [parent newSubTaskForEvent:@"generationSignatureUpdateEvent"]; + } result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { return SOSAccountGenerationSignatureUpdate(txn.account, error); }); - [generationSignatureUpdateEvent stopWithAttributes:nil]; + if(generationSignatureUpdateEvent) { + [generationSignatureUpdateEvent stopWithAttributes:nil]; + } done: if(syncAndWaitEvent){ @@ -1054,16 +1040,17 @@ done: bool SOSCCSetUserCredentialsAndDSID_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error) { // TODO: Return error if DSID is NULL to insist our callers provide one? - return SOSCCAssertUserCredentialsAndOptionalDSID(user_label, user_password, dsid, error); + return SOSCCAssertUserCredentialsAndOptionalDSID(user_label, user_password, dsid, nil, error); } bool SOSCCSetUserCredentialsAndDSIDWithAnalytics_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFDataRef parentEvent, CFErrorRef *error) { - return SOSCCAssertUserCredentialsAndOptionalDSIDWithAnalytics(user_label, user_password, dsid, (__bridge NSData*)parentEvent, error); + return SOSCCAssertUserCredentialsAndOptionalDSID(user_label, user_password, dsid, (__bridge NSData*)parentEvent, error); } + bool SOSCCSetUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFErrorRef *error) { - return SOSCCAssertUserCredentialsAndOptionalDSID(user_label, user_password, NULL, error); + return SOSCCAssertUserCredentialsAndOptionalDSID(user_label, user_password, NULL, nil, error); } bool SOSCCCanAuthenticate_Server(CFErrorRef *error) @@ -1108,33 +1095,24 @@ SOSCCStatus SOSCCThisDeviceIsInCircle_Server(CFErrorRef *error) }) ? status : kSOSCCError; } -bool SOSCCRequestToJoinCircle_Server(CFErrorRef* error) -{ - __block bool result = true; - OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRequestToJoinCircle); - - bool joined = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - result = SOSAccountJoinCircles(txn, block_error); - return result; - }); - - OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRequestToJoinCircle, OctagonSignpostNumber1(SOSSignpostNameSOSCCRequestToJoinCircle), (int)joined); - return joined; -} - bool SOSCCRequestToJoinCircleWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error) { __block bool result = true; OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRequestToJoinCircle); bool requested = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - result = SOSAccountJoinCirclesWithAnalytics(txn, (__bridge NSData*)parentEvent, block_error); + result = SOSAccountJoinCircles(txn, (__bridge NSData*)parentEvent, block_error); return result; }); OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRequestToJoinCircle, OctagonSignpostNumber1(SOSSignpostNameSOSCCRequestToJoinCircle), (int)requested); return requested; } +bool SOSCCRequestToJoinCircle_Server(CFErrorRef* error) +{ + return SOSCCRequestToJoinCircleWithAnalytics_Server(nil, error); +} + bool SOSCCAccountHasPublicKey_Server(CFErrorRef *error) { __block bool result = true; @@ -1151,21 +1129,6 @@ bool SOSCCAccountHasPublicKey_Server(CFErrorRef *error) return hasPublicKey; } -bool SOSCCRequestToJoinCircleAfterRestore_Server(CFErrorRef* error) -{ - __block bool result = true; - bool returned = false; - OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRequestToJoinCircleAfterRestore); - returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - SOSAccountEnsurePeerRegistration(txn.account, block_error); - result = SOSAccountJoinCirclesAfterRestore(txn, block_error); - return result; - }); - OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRequestToJoinCircleAfterRestore, OctagonSignpostNumber1(SOSSignpostNameSOSCCRequestToJoinCircleAfterRestore), (int)result); - return returned; - -} - bool SOSCCRequestToJoinCircleAfterRestoreWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error) { __block bool result = true; @@ -1173,19 +1136,28 @@ bool SOSCCRequestToJoinCircleAfterRestoreWithAnalytics_Server(CFDataRef parentEv OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRequestToJoinCircleAfterRestore); returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { NSError* localError = nil; - SFSignInAnalytics* parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:(__bridge NSData*)parentEvent error:&localError]; + SFSignInAnalytics* parent = nil; + SFSignInAnalytics *ensurePeerRegistrationEvent = nil; + + if(parentEvent) { + parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:(__bridge NSData*)parentEvent error:&localError]; + ensurePeerRegistrationEvent = [parent newSubTaskForEvent:@"ensurePeerRegistrationEvent"]; + } - SFSignInAnalytics *ensurePeerRegistrationEvent = [parent newSubTaskForEvent:@"ensurePeerRegistrationEvent"]; SOSAccountEnsurePeerRegistration(txn.account, block_error); if(block_error && *block_error){ NSError* blockError = (__bridge NSError*)*block_error; if(blockError){ - [ensurePeerRegistrationEvent logRecoverableError:blockError]; + if(ensurePeerRegistrationEvent) { + [ensurePeerRegistrationEvent logRecoverableError:blockError]; + } secerror("ensure peer registration error: %@", blockError); } } - [ensurePeerRegistrationEvent stopWithAttributes:nil]; - result = SOSAccountJoinCirclesAfterRestoreWithAnalytics(txn, (__bridge NSData*)parentEvent, block_error); + if(ensurePeerRegistrationEvent) { + [ensurePeerRegistrationEvent stopWithAttributes:nil]; + } + result = SOSAccountJoinCirclesAfterRestore(txn, (__bridge NSData*)parentEvent, block_error); return result; }); OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRequestToJoinCircleAfterRestore, OctagonSignpostNumber1(SOSSignpostNameSOSCCRequestToJoinCircleAfterRestore), (int)result); @@ -1193,6 +1165,11 @@ bool SOSCCRequestToJoinCircleAfterRestoreWithAnalytics_Server(CFDataRef parentEv } +bool SOSCCRequestToJoinCircleAfterRestore_Server(CFErrorRef* error) +{ + return SOSCCRequestToJoinCircleAfterRestoreWithAnalytics_Server(nil, error); +} + bool SOSCCAccountSetToNew_Server(CFErrorRef *error) { return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { @@ -1283,7 +1260,7 @@ bool SOSCCRemovePeersFromCircle_Server(CFArrayRef peers, CFErrorRef* error) OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRemovePeersFromCircle); bool removeResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - bool result = SOSAccountRemovePeersFromCircle(txn.account, peers, block_error); + bool result = SOSAccountRemovePeersFromCircle(txn.account, peers, nil, block_error); return result; }); OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRemovePeersFromCircle, OctagonSignpostNumber1(SOSSignpostNameSOSCCRemovePeersFromCircle), (int)removeResult); @@ -1295,7 +1272,7 @@ bool SOSCCRemovePeersFromCircleWithAnalytics_Server(CFArrayRef peers, CFDataRef OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRemovePeersFromCircle); bool removeResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - bool result = SOSAccountRemovePeersFromCircleWithAnalytics(txn.account, peers, (__bridge NSData*)parentEvent, block_error); + bool result = SOSAccountRemovePeersFromCircle(txn.account, peers, (__bridge NSData*)parentEvent, block_error); return result; }); OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRemovePeersFromCircle, OctagonSignpostNumber1(SOSSignpostNameSOSCCRemovePeersFromCircle), (int)removeResult); -- 2.45.2