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;
}
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;
}
}
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);
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));
return errSecUserCanceled;
case kTKErrorCodeCorruptedData:
return errSecDecode;
+ case kTKErrorCodeTokenNotFound:
+ case kTKErrorCodeObjectNotFound:
+ return errSecItemNotFound;
default:
return errSecInternal;
}
*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);
}
// 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;
// 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,
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;
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 */
#include <Security/SecTaskPriv.h>
#include "ipc/securityd_client.h"
#include <Security/SecEntitlements.h>
+#include <utilities/SecInternalReleasePriv.h>
+#include <sys/codesign.h>
#include <Security/SecItem.h>
#include "utilities/SecCFRelease.h"
#include "utilities/SecCFWrappers.h"
}
#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) {
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
+}
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);
NSArray<NSDictionary *>* SOSAccountGetAllTLKs(void);
CF_RETURNS_RETAINED CFMutableArrayRef SOSAccountCopyiCloudIdentities(SOSAccount* account);
+bool SOSAccountEvaluateKeysAndCircle(SOSAccountTransaction *txn, CFErrorRef *block_error);
+
__END_DECLS
#endif /* !_SOSACCOUNT_H_ */
}
}
-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;
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;
CFReleaseNull(retiredError);
}
}
- [promoteToRetiredEvent stopWithAttributes:nil];
+ if(promoteToRetiredEvent) {
+ [promoteToRetiredEvent stopWithAttributes:nil];
+ }
if (!retire_peer) {
secerror("Create ticket failed for peer %@: %@", fpi, localError);
} 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);
}
}
// 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;
}
// 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);
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:
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;
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;
}
}
- success = SOSAccountJoinCircleWithAnalytics(aTxn, user_key, use_cloud_identity, parentEvent, error);
+ success = SOSAccountJoinCircle(aTxn, user_key, use_cloud_identity, parentEvent, error);
require_quiet(success, 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);
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:
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);
#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"
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;
+}
#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"
//
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);
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 {
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;
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;
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);
}
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)
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;
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
{
__block bool result = false;
[acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) {
- result = SOSAccountJoinCirclesAfterRestore(txn, error);
+ result = SOSAccountJoinCirclesAfterRestore(txn, nil, error);
}];
return result;
}
{
__block bool result = false;
[acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) {
- result = SOSAccountJoinCircles(txn, error);
+ result = SOSAccountJoinCircles(txn, nil, error);
}];
return result;
}
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);
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);
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");
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;
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();
}
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;
});
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){
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)
}) ? 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;
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;
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);
}
+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) {
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);
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);