SOSAccountUpdate.c [plain text]
#include "SOSAccountPriv.h"
#include <Security/SecureObjectSync/SOSAccountHSAJoin.h>
#include <Security/SecureObjectSync/SOSTransportCircle.h>
#include <Security/SecureObjectSync/SOSTransport.h>
#include <Security/SecureObjectSync/SOSViews.h>
#include <Security/SecureObjectSync/SOSPeerInfoCollections.h>
#include <Security/SecureObjectSync/SOSPeerInfoPriv.h>
#include <Security/SecureObjectSync/SOSPeerInfoV2.h>
#include <Security/SecureObjectSync/SOSPeerInfoDER.h>
#include <Security/SecureObjectSync/SOSBackupSliceKeyBag.h>
static void DifferenceAndCall(CFSetRef old_members, CFSetRef new_members, void (^updatedCircle)(CFSetRef additions, CFSetRef removals))
{
CFMutableSetRef additions = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, new_members);
CFMutableSetRef removals = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, old_members);
CFSetForEach(old_members, ^(const void * value) {
CFSetRemoveValue(additions, value);
});
CFSetForEach(new_members, ^(const void * value) {
CFSetRemoveValue(removals, value);
});
updatedCircle(additions, removals);
CFReleaseSafe(additions);
CFReleaseSafe(removals);
}
static CFMutableSetRef SOSAccountCopyIntersectedViews(CFSetRef peerViews, CFSetRef myViews) {
__block CFMutableSetRef views = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
if (peerViews && myViews) CFSetForEach(peerViews, ^(const void *view) {
if (CFSetContainsValue(myViews, view)) {
CFSetAddValue(views, view);
}
});
return views;
}
static inline bool isSyncing(SOSPeerInfoRef peer, SecKeyRef upub) {
if(!SOSPeerInfoApplicationVerify(peer, upub, NULL)) return false;
if(SOSPeerInfoIsRetirementTicket(peer)) return false;
return true;
}
static bool isBackupSOSRing(SOSRingRef ring)
{
return isSOSRing(ring) && (kSOSRingBackup == SOSRingGetType(ring));
}
static bool CFSetIntersectionNotEmpty(CFSetRef set1, CFSetRef set2) {
__block bool intersectionEmpty = true;
CFSetForEach(set1, ^(const void *value) {
if (CFSetContainsValue(set2, value)) {
intersectionEmpty = false;
};
});
return !intersectionEmpty;
}
__unused
static void SOSAccountAppendPeerMetasForViewBackups(SOSAccountRef account, CFSetRef views, CFMutableArrayRef appendTo)
{
if (account->trusted_rings == NULL || CFDictionaryGetCount(account->trusted_rings) == 0) return;
CFMutableDictionaryRef ringToViewTable = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
CFSetForEach(views, ^(const void *value) {
CFStringRef viewName = value;
if (isString(viewName) && !CFEqualSafe(viewName, kSOSViewKeychainV0)) {
CFStringRef ringName = SOSBackupCopyRingNameForView(viewName);
viewName = ringName;
SOSRingRef ring = (SOSRingRef) CFDictionaryGetValue(account->trusted_rings, ringName);
if (isBackupSOSRing(ring)) {
CFTypeRef currentValue = (CFTypeRef) CFDictionaryGetValue(ringToViewTable, ring);
if (isSet(currentValue)) {
CFSetAddValue((CFMutableSetRef)currentValue, viewName);
} else {
CFMutableSetRef viewNameSet = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
CFSetAddValue(viewNameSet, viewName);
CFDictionarySetValue(ringToViewTable, ring, viewNameSet);
CFReleaseNull(viewNameSet);
}
} else {
secwarning("View '%@' not being backed up – ring %@:%@ not backup ring.", viewName, ringName, ring);
}
CFReleaseNull(ringName);
}
});
CFSetRef unsynced = asSet(SOSAccountGetValue(account, kSOSUnsyncedViewsKey, NULL), NULL);
CFDictionaryForEach(ringToViewTable, ^(const void *key, const void *value) {
SOSRingRef ring = (SOSRingRef) key;
CFSetRef viewNames = (CFSetRef) value;
if (isSOSRing(ring) && isSet(viewNames)) {
if (unsynced && CFSetIntersectionNotEmpty(unsynced, viewNames)) {
secnotice("engine-notify", "Haven't initially synced views, not making backup peer meta: U: %@ R: %@ Vs: %@", unsynced, SOSRingGetName(ring), viewNames);
} else {
bool meta_added = false;
CFErrorRef create_error = NULL;
SOSBackupSliceKeyBagRef key_bag = NULL;
SOSPeerMetaRef newMeta = NULL;
CFDataRef ring_payload = SOSRingGetPayload(ring, NULL);
require_quiet(isData(ring_payload), skip);
key_bag = SOSBackupSliceKeyBagCreateFromData(kCFAllocatorDefault, ring_payload, &create_error);
require_quiet(key_bag, skip);
newMeta = SOSPeerMetaCreateWithComponents(SOSRingGetName(ring), viewNames, ring_payload);
require_quiet(SecAllocationError(newMeta, &create_error, CFSTR("Didn't make peer meta for: %@"), ring), skip);
CFArrayAppendValue(appendTo, newMeta);
secnotice("engine-notify", "Backup peer meta: R: %@ Vs: %@ VD: %@", SOSRingGetName(ring), viewNames, ring_payload);
meta_added = true;
skip:
if (!meta_added) {
secerror("Failed to register backup meta from %@ for views %@. Error (%@)", ring, viewNames, create_error);
}
CFReleaseNull(newMeta);
CFReleaseNull(key_bag);
CFReleaseNull(create_error);
}
}
});
CFReleaseNull(ringToViewTable);
}
bool SOSAccountSyncingV0(SOSAccountRef account) {
__block bool syncingV0 = false;
SOSAccountForEachCirclePeerExceptMe(account, ^(SOSPeerInfoRef peer) {
if (SOSPeerInfoIsEnabledView(peer, kSOSViewKeychainV0)) {
syncingV0 = true;
}
});
return syncingV0;
}
void SOSAccountNotifyEngines(SOSAccountRef account)
{
SOSPeerInfoRef myPi = SOSFullPeerInfoGetPeerInfo(account->my_identity);
CFStringRef myPi_id = SOSPeerInfoGetPeerID(myPi);
CFMutableArrayRef syncing_peer_metas = NULL;
CFMutableArrayRef zombie_peer_metas = NULL;
CFErrorRef localError = NULL;
SOSPeerMetaRef myMeta = NULL;
if (myPi_id && isSyncing(myPi, account->user_public) && SOSCircleHasPeer(account->trusted_circle, myPi, NULL)) {
CFMutableSetRef myViews = SOSPeerInfoCopyEnabledViews(myPi);
__block bool addV0Views = SOSAccountSyncingV0(account);
syncing_peer_metas = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
zombie_peer_metas = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
SOSAccountForEachCirclePeerExceptMe(account, ^(SOSPeerInfoRef peer) {
CFMutableArrayRef arrayToAddTo = isSyncing(peer, account->user_public) ? syncing_peer_metas : zombie_peer_metas;
CFMutableSetRef peerEnabledViews = SOSPeerInfoCopyEnabledViews(peer);
CFMutableSetRef views = SOSAccountCopyIntersectedViews(peerEnabledViews, myViews);
CFReleaseNull(peerEnabledViews);
if(addV0Views) {
CFSetAddValue(views, kSOSViewKeychainV0);
}
SOSPeerMetaRef peerMeta = SOSPeerMetaCreateWithComponents(SOSPeerInfoGetPeerID(peer), views, NULL);
CFReleaseNull(views);
CFArrayAppendValue(arrayToAddTo, peerMeta);
CFReleaseNull(peerMeta);
});
SOSAccountAppendPeerMetasForViewBackups(account, myViews, syncing_peer_metas);
if (addV0Views) {
CFSetAddValue(myViews, kSOSViewKeychainV0);
}
myMeta = SOSPeerMetaCreateWithComponents(myPi_id, myViews, NULL);
CFReleaseSafe(myViews);
}
SOSEngineRef engine = SOSDataSourceFactoryGetEngineForDataSourceName(account->factory, SOSCircleGetName(account->trusted_circle), NULL);
if (engine) {
SOSEngineCircleChanged(engine, myMeta, syncing_peer_metas, zombie_peer_metas);
}
CFReleaseNull(myMeta);
CFReleaseSafe(localError);
CFReleaseNull(syncing_peer_metas);
CFReleaseNull(zombie_peer_metas);
}
static void SOSAccountNotifyOfChange(SOSAccountRef account, SOSCircleRef oldCircle, SOSCircleRef newCircle)
{
account->circle_rings_retirements_need_attention = true;
CFMutableSetRef old_members = SOSCircleCopyPeers(oldCircle, kCFAllocatorDefault);
CFMutableSetRef new_members = SOSCircleCopyPeers(newCircle, kCFAllocatorDefault);
CFMutableSetRef old_applicants = SOSCircleCopyApplicants(oldCircle, kCFAllocatorDefault);
CFMutableSetRef new_applicants = SOSCircleCopyApplicants(newCircle, kCFAllocatorDefault);
SOSPeerInfoRef me = SOSAccountGetMyPeerInfo(account);
if(me && CFSetContainsValue(new_members, me))
SOSAccountSetValue(account, kSOSEscrowRecord, kCFNull, NULL);
DifferenceAndCall(old_members, new_members, ^(CFSetRef added_members, CFSetRef removed_members) {
DifferenceAndCall(old_applicants, new_applicants, ^(CFSetRef added_applicants, CFSetRef removed_applicants) {
CFArrayForEach(account->change_blocks, ^(const void * notificationBlock) {
secnotice("updates", "calling change block");
((SOSAccountCircleMembershipChangeBlock) notificationBlock)(newCircle, added_members, removed_members, added_applicants, removed_applicants);
});
});
});
CFReleaseNull(old_applicants);
CFReleaseNull(new_applicants);
CFReleaseNull(old_members);
CFReleaseNull(new_members);
}
CF_RETURNS_RETAINED
CFDictionaryRef SOSAccountHandleRetirementMessages(SOSAccountRef account, CFDictionaryRef circle_retirement_messages, CFErrorRef *error) {
CFStringRef circle_name = SOSCircleGetName(account->trusted_circle);
CFMutableArrayRef handledRetirementIDs = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
require_quiet(account->trusted_circle, finish); CFDictionaryRef retirment_dictionary = CFDictionaryGetValue(circle_retirement_messages, circle_name);
CFDictionaryForEach(retirment_dictionary, ^(const void *key, const void *value) {
if(isData(value)) {
SOSPeerInfoRef pi = SOSPeerInfoCreateFromData(NULL, error, (CFDataRef) value);
if(pi && CFEqual(key, SOSPeerInfoGetPeerID(pi)) && SOSPeerInfoInspectRetirementTicket(pi, error)) {
CFSetAddValue(account->retirees, pi);
account->circle_rings_retirements_need_attention = true;
CFArrayAppendValue(handledRetirementIDs, key);
}
CFReleaseNull(pi);
}
});
SOSPeerInfoRef me = SOSAccountGetMyPeerInfo(account);
if (me && CFSetContainsValue(account->retirees, me)) {
SOSAccountPurgeIdentity(account);
account->departure_code = kSOSDiscoveredRetirement;
}
finish:
{
CFDictionaryRef result = (CFArrayGetCount(handledRetirementIDs) == 0) ? CFDictionaryCreateForCFTypes(kCFAllocatorDefault, NULL)
: CFDictionaryCreateForCFTypes(kCFAllocatorDefault, circle_name, handledRetirementIDs, NULL);
CFReleaseNull(handledRetirementIDs);
return result;
}
}
static SOSCircleRef SOSAccountCreateCircleFrom(CFStringRef circleName, CFTypeRef value, CFErrorRef *error) {
if (value && !isData(value) && !isNull(value)) {
secnotice("circleCreat", "Value provided not appropriate for a circle");
CFStringRef description = CFCopyTypeIDDescription(CFGetTypeID(value));
SOSCreateErrorWithFormat(kSOSErrorUnexpectedType, NULL, error, NULL,
CFSTR("Expected data or NULL got %@"), description);
CFReleaseSafe(description);
return NULL;
}
SOSCircleRef circle = NULL;
if (!value || isNull(value)) {
secnotice("circleCreat", "No circle found in data: %@", value);
circle = NULL;
} else {
circle = SOSCircleCreateFromData(NULL, (CFDataRef) value, error);
if (circle) {
CFStringRef name = SOSCircleGetName(circle);
if (!CFEqualSafe(name, circleName)) {
secnotice("circleCreat", "Expected circle named %@, got %@", circleName, name);
SOSCreateErrorWithFormat(kSOSErrorNameMismatch, NULL, error, NULL,
CFSTR("Expected circle named %@, got %@"), circleName, name);
CFReleaseNull(circle);
}
} else {
secnotice("circleCreat", "SOSCircleCreateFromData returned NULL.");
}
}
return circle;
}
bool SOSAccountHandleCircleMessage(SOSAccountRef account,
CFStringRef circleName, CFDataRef encodedCircleMessage, CFErrorRef *error) {
bool success = false;
CFErrorRef localError = NULL;
SOSCircleRef circle = SOSAccountCreateCircleFrom(circleName, encodedCircleMessage, &localError);
if (circle) {
success = SOSAccountUpdateCircleFromRemote(account, circle, &localError);
CFReleaseSafe(circle);
} else {
secerror("NULL circle found, ignoring ...");
success = true; }
if (!success) {
if (isSOSErrorCoded(localError, kSOSErrorIncompatibleCircle)) {
secerror("Incompatible circle found, abandoning membership: %@", circleName);
CFReleaseNull(account->my_identity);
CFReleaseNull(account->trusted_circle);
}
if (error) {
*error = localError;
localError = NULL;
}
}
CFReleaseNull(localError);
return success;
}
bool SOSAccountHandleParametersChange(SOSAccountRef account, CFDataRef parameters, CFErrorRef *error){
SecKeyRef newKey = NULL;
CFDataRef newParameters = NULL;
bool success = false;
if(SOSAccountRetrieveCloudParameters(account, &newKey, parameters, &newParameters, error)) {
if (CFEqualSafe(account->user_public, newKey)) {
secnotice("updates", "Got same public key sent our way. Ignoring.");
success = true;
} else if (CFEqualSafe(account->previous_public, newKey)) {
secnotice("updates", "Got previous public key repeated. Ignoring.");
success = true;
} else {
SOSAccountSetUnTrustedUserPublicKey(account, newKey);
SOSAccountSetParameters(account, newParameters);
newKey = NULL;
if(SOSAccountRetryUserCredentials(account)) {
secnotice("keygen", "Successfully used cached password with new parameters: %@", account->user_public);
SOSAccountGenerationSignatureUpdate(account, error);
} else {
SOSAccountPurgePrivateCredential(account);
secnotice("keygen", "Got new parameters for public key - failed with cached password: %@", account->user_public);
debugDumpUserParameters(CFSTR("params"), account->user_key_parameters);
}
account->circle_rings_retirements_need_attention = true;
SOSUpdateKeyInterest(account);
success = true;
}
}
CFReleaseNull(newKey);
CFReleaseNull(newParameters);
return success;
}
static inline bool SOSAccountHasLeft(SOSAccountRef account) {
switch(account->departure_code) {
case kSOSDiscoveredRetirement:
case kSOSLostPrivateKey:
case kSOSWithdrewMembership:
case kSOSMembershipRevoked:
case kSOSLeftUntrustedCircle:
return true;
case kSOSNeverAppliedToCircle:
case kSOSNeverLeftCircle:
default:
return false;
}
}
static const char *concordstring[] = {
"kSOSConcordanceTrusted",
"kSOSConcordanceGenOld", "kSOSConcordanceNoUserSig", "kSOSConcordanceNoUserKey", "kSOSConcordanceNoPeer", "kSOSConcordanceBadUserSig", "kSOSConcordanceBadPeerSig", "kSOSConcordanceNoPeerSig",
"kSOSConcordanceWeSigned",
};
bool SOSAccountHandleUpdateCircle(SOSAccountRef account, SOSCircleRef prospective_circle, bool writeUpdate, CFErrorRef *error)
{
bool success = true;
bool haveOldCircle = true;
const char *local_remote = writeUpdate ? "local": "remote";
secnotice("signing", "start:[%s] %@", local_remote, prospective_circle);
if (!account->user_public || !account->user_public_trusted) {
SOSCreateError(kSOSErrorPublicKeyAbsent, CFSTR("Can't handle updates with no trusted public key here"), NULL, error);
return false;
}
if (!prospective_circle) {
secerror("##### Can't update to a NULL circle ######");
return false; }
CFStringRef newCircleName = SOSCircleGetName(prospective_circle);
SOSCircleRef oldCircle = account->trusted_circle;
SOSCircleRef emptyCircle = NULL;
if(oldCircle == NULL) {
SOSCreateErrorWithFormat(kSOSErrorIncompatibleCircle, NULL, error, NULL, CFSTR("Current Entry is NULL; rejecting %@"), prospective_circle);
secerror("##### Can't replace circle - we don't care about %@ ######", prospective_circle);
return false;
}
if (CFGetTypeID(oldCircle) != SOSCircleGetTypeID()) {
secdebug("signing", ">>>>>>>>>>>>>>> Non-Circle Circle found <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
emptyCircle = SOSCircleCreate(kCFAllocatorDefault, newCircleName, NULL);
oldCircle = emptyCircle;
haveOldCircle = false;
}
SOSFullPeerInfoRef me_full = account->my_identity;
SOSPeerInfoRef me = SOSFullPeerInfoGetPeerInfo(me_full);
SOSTransportCircleRef transport = account->circle_transport;
SOSAccountScanForRetired(account, prospective_circle, error);
SOSCircleRef newCircle = SOSAccountCloneCircleWithRetirement(account, prospective_circle, error);
if(!newCircle) return false;
if (me && SOSCircleUpdatePeerInfo(newCircle, me)) {
writeUpdate = true; }
typedef enum {
accept,
countersign,
leave,
revert,
ignore
} circle_action_t;
static const char *actionstring[] = {
"accept", "countersign", "leave", "revert", "ignore",
};
circle_action_t circle_action = ignore;
enum DepartureReason leave_reason = kSOSNeverLeftCircle;
SecKeyRef old_circle_key = NULL;
if(SOSCircleVerify(oldCircle, account->user_public, NULL)) old_circle_key = account->user_public;
else if(account->previous_public && SOSCircleVerify(oldCircle, account->previous_public, NULL)) old_circle_key = account->previous_public;
bool userTrustedOldCircle = (old_circle_key != NULL) && haveOldCircle;
SOSConcordanceStatus concstat =
SOSCircleConcordanceTrust(oldCircle, newCircle,
old_circle_key, account->user_public,
me, error);
CFStringRef concStr = NULL;
switch(concstat) {
case kSOSConcordanceTrusted:
circle_action = countersign;
concStr = CFSTR("Trusted");
break;
case kSOSConcordanceGenOld:
circle_action = userTrustedOldCircle ? revert : ignore;
concStr = CFSTR("Generation Old");
break;
case kSOSConcordanceBadUserSig:
case kSOSConcordanceBadPeerSig:
circle_action = userTrustedOldCircle ? revert : accept;
concStr = CFSTR("Bad Signature");
break;
case kSOSConcordanceNoUserSig:
circle_action = userTrustedOldCircle ? revert : accept;
concStr = CFSTR("No User Signature");
break;
case kSOSConcordanceNoPeerSig:
circle_action = accept; concStr = CFSTR("No trusted peer signature");
secerror("##### No trusted peer signature found, accepting hoping for concordance later %@", newCircle);
break;
case kSOSConcordanceNoPeer:
circle_action = leave;
leave_reason = kSOSLeftUntrustedCircle;
concStr = CFSTR("No trusted peer left");
break;
case kSOSConcordanceNoUserKey:
secerror("##### No User Public Key Available, this shouldn't ever happen!!!");
abort();
break;
default:
secerror("##### Bad Error Return from ConcordanceTrust");
abort();
break;
}
secnotice("signing", "Decided on action [%s] based on concordance state [%s] and [%s] circle.", actionstring[circle_action], concordstring[concstat], userTrustedOldCircle ? "trusted" : "untrusted");
SOSCircleRef circleToPush = NULL;
if (circle_action == leave) {
circle_action = ignore; (void) circle_action;
if (me && SOSCircleHasPeer(oldCircle, me, NULL)) {
secnotice("account", "Leaving circle with peer %@", me);
debugDumpCircle(CFSTR("oldCircle"), oldCircle);
debugDumpCircle(CFSTR("newCircle"), newCircle);
debugDumpCircle(CFSTR("prospective_circle"), prospective_circle);
secnotice("account", "Key state: user_public %@, previous_public %@, old_circle_key %@",
account->user_public, account->previous_public, old_circle_key);
if (sosAccountLeaveCircle(account, newCircle, error)) {
circleToPush = newCircle;
} else {
secnotice("signing", "Can't leave circle %@, but dumping identities", oldCircle);
success = false;
}
account->departure_code = leave_reason;
circle_action = accept;
me = NULL;
me_full = NULL;
} else {
secnotice("signing", "We are not in this circle, but we need to update account with it");
debugDumpCircle(CFSTR("oldCircle"), oldCircle);
debugDumpCircle(CFSTR("newCircle"), newCircle);
debugDumpCircle(CFSTR("prospective_circle"), prospective_circle);
circle_action = accept;
}
}
if (circle_action == countersign) {
if (me && SOSCircleHasPeer(newCircle, me, NULL)) {
if (SOSCircleVerifyPeerSigned(newCircle, me, NULL)) {
secnotice("signing", "Already concur with: %@", newCircle);
} else {
CFErrorRef signing_error = NULL;
if (me_full && SOSCircleConcordanceSign(newCircle, me_full, &signing_error)) {
circleToPush = newCircle;
secnotice("signing", "Concurred with: %@", newCircle);
} else {
secerror("Failed to concurrence sign, error: %@ Old: %@ New: %@", signing_error, oldCircle, newCircle);
success = false;
}
CFReleaseSafe(signing_error);
}
if(SOSAccountVerifyAndAcceptHSAApplicants(account, newCircle, error)) {
circleToPush = newCircle;
writeUpdate = true;
}
} else {
secnotice("signing", "Not countersigning, not in circle: %@", newCircle);
debugDumpCircle(CFSTR("circle to countersign"), newCircle);
}
circle_action = accept;
}
if (circle_action == accept) {
if (me && SOSCircleHasActivePeer(oldCircle, me, NULL) && !SOSCircleHasPeer(newCircle, me, NULL)) {
if(!SOSAccountHasLeft(account)) account->departure_code = kSOSMembershipRevoked;
secnotice("account", "Member of old circle but not of new circle");
debugDumpCircle(CFSTR("oldCircle"), oldCircle);
debugDumpCircle(CFSTR("newCircle"), newCircle);
}
if (me
&& SOSCircleHasActivePeer(oldCircle, me, NULL)
&& !(SOSCircleCountPeers(oldCircle) == 1 && SOSCircleHasPeer(oldCircle, me, NULL)) && !SOSCircleHasPeer(newCircle, me, NULL) && !SOSCircleHasApplicant(newCircle, me, NULL)) {
secnotice("circle", "Purging my peer (ID: %@) for circle '%@'!!!", SOSPeerInfoGetPeerID(me), SOSCircleGetName(oldCircle));
if (account->my_identity)
SOSFullPeerInfoPurgePersistentKey(account->my_identity, NULL);
CFReleaseNull(account->my_identity);
me = NULL;
me_full = NULL;
}
if (me && SOSCircleHasRejectedApplicant(newCircle, me, NULL)) {
SOSPeerInfoRef reject = SOSCircleCopyRejectedApplicant(newCircle, me, NULL);
if(CFEqualSafe(reject, me) && SOSPeerInfoApplicationVerify(me, account->user_public, NULL)) {
secnotice("circle", "Rejected, Purging my applicant peer (ID: %@) for circle '%@'", SOSPeerInfoGetPeerID(me), SOSCircleGetName(oldCircle));
debugDumpCircle(CFSTR("oldCircle"), oldCircle);
debugDumpCircle(CFSTR("newCircle"), newCircle);
if (account->my_identity)
SOSFullPeerInfoPurgePersistentKey(account->my_identity, NULL);
CFReleaseNull(account->my_identity);
me = NULL;
me_full = NULL;
} else {
secnotice("circle", "Rejected, Reapplying (ID: %@) for circle '%@'", SOSPeerInfoGetPeerID(me), SOSCircleGetName(oldCircle));
debugDumpCircle(CFSTR("oldCircle"), oldCircle);
debugDumpCircle(CFSTR("newCircle"), newCircle);
SOSCircleRequestReadmission(newCircle, account->user_public, me, NULL);
writeUpdate = true;
}
}
CFRetainSafe(oldCircle);
CFRetainAssign(account->trusted_circle, newCircle);
SOSAccountSetPreviousPublic(account);
secnotice("signing", "%@, Accepting circle: %@", concStr, newCircle);
if (me && account->user_public_trusted
&& SOSCircleHasApplicant(oldCircle, me, NULL)
&& SOSCircleCountPeers(newCircle) > 0
&& !SOSCircleHasPeer(newCircle, me, NULL) && !SOSCircleHasApplicant(newCircle, me, NULL)) {
secnotice("signing", "requesting readmission to circle %@", newCircle);
if (SOSCircleRequestReadmission(newCircle, account->user_public, me, NULL))
writeUpdate = true;
}
if (me && SOSCircleHasActivePeer(oldCircle, me, NULL)) {
SOSAccountCleanupRetirementTickets(account, RETIREMENT_FINALIZATION_SECONDS, NULL);
}
SOSAccountNotifyOfChange(account, oldCircle, newCircle);
CFReleaseNull(oldCircle);
if (writeUpdate)
circleToPush = newCircle;
SOSUpdateKeyInterest(account);
}
if (circle_action == revert) {
if(haveOldCircle && me && SOSCircleHasActivePeer(oldCircle, me, NULL)) {
secnotice("signing", "%@, Rejecting: %@ re-publishing %@", concStr, newCircle, oldCircle);
debugDumpCircle(CFSTR("oldCircle"), oldCircle);
debugDumpCircle(CFSTR("newCircle"), newCircle);
circleToPush = oldCircle;
} else {
secnotice("canary", "%@, Rejecting: %@ Have no old circle - would reset", concStr, newCircle);
}
}
if (circleToPush != NULL) {
secnotice("signing", "Pushing:[%s] %@", local_remote, circleToPush);
CFDataRef circle_data = SOSCircleCopyEncodedData(circleToPush, kCFAllocatorDefault, error);
if (circle_data) {
success &= SOSTransportCircleRecordLastCirclePushedInKVS(transport, SOSCircleGetName(circleToPush), circle_data);
success &= SOSTransportCirclePostCircle(transport, SOSCircleGetName(circleToPush), circle_data, error);
} else {
success = false;
}
CFReleaseNull(circle_data);
}
CFReleaseSafe(newCircle);
CFReleaseNull(emptyCircle);
return success;
}