SOSAccountTransaction.c [plain text]
#include "SOSAccountTransaction.h"
#include <utilities/SecCFWrappers.h>
#include <CoreFoundation/CoreFoundation.h>
#include <Security/SecureObjectSync/SOSAccount.h>
#include <Security/SecureObjectSync/SOSAccountPriv.h>
#include <Security/SecureObjectSync/SOSPeerInfoV2.h>
#include <Security/SecureObjectSync/SOSTransport.h>
#include <Security/SecureObjectSync/SOSTransportCircle.h>
#define kPublicKeyNotAvailable "com.apple.security.publickeynotavailable"
CFGiblisFor(SOSAccountTransaction);
static void SOSAccountTransactionDestroy(CFTypeRef aObj) {
SOSAccountTransactionRef at = (SOSAccountTransactionRef) aObj;
CFReleaseNull(at->initialUnsyncedViews);
CFReleaseNull(at->initialID);
CFReleaseNull(at->account);
CFReleaseNull(at->initialViews);
CFReleaseNull(at->initialKeyParameters);
}
static CFStringRef SOSAccountTransactionCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
SOSAccountTransactionRef at = (SOSAccountTransactionRef) aObj;
CFMutableStringRef description = CFStringCreateMutable(kCFAllocatorDefault, 0);
CFStringAppendFormat(description, NULL, CFSTR("<SOSAccountTransactionRef@%p %ld>"),
at, at->initialViews ? CFSetGetCount(at->initialViews) : 0);
return description;
}
static void SOSAccountTransactionRestart(SOSAccountTransactionRef txn) {
txn->initialInCircle = SOSAccountIsInCircle(txn->account, NULL);
if(txn->account)
txn->initialTrusted = (txn->account)->user_public_trusted;
if (txn->initialInCircle) {
SOSAccountEnsureSyncChecking(txn->account);
}
CFAssignRetained(txn->initialUnsyncedViews, SOSAccountCopyOutstandingViews(txn->account));
CFReleaseNull(txn->initialKeyParameters);
if(txn->account && txn->account->user_key_parameters){
CFReleaseNull(txn->initialKeyParameters);
txn->initialKeyParameters = CFDataCreateCopy(kCFAllocatorDefault, txn->account->user_key_parameters);
}
SOSPeerInfoRef mpi = SOSAccountGetMyPeerInfo(txn->account);
CFAssignRetained(txn->initialViews, mpi ? SOSPeerInfoCopyEnabledViews(mpi) : NULL);
CFRetainAssign(txn->initialID, SOSPeerInfoGetPeerID(mpi));
CFStringSetPerformWithDescription(txn->initialViews, ^(CFStringRef description) {
secnotice("acct-txn", "Starting as:%s v:%@", txn->initialInCircle ? "member" : "non-member", description);
});
}
SOSAccountTransactionRef SOSAccountTransactionCreate(SOSAccountRef account) {
SOSAccountTransactionRef at = CFTypeAllocate(SOSAccountTransaction, struct __OpaqueSOSAccountTransaction, kCFAllocatorDefault);
at->account = CFRetainSafe(account);
at->initialInCircle = false;
at->initialViews = NULL;
at->initialKeyParameters = NULL;
at->initialTrusted = false;
at->initialUnsyncedViews = NULL;
at->initialID = NULL;
SOSAccountTransactionRestart(at);
return at;
}
#define ACCOUNT_STATE_INTERVAL 20
void SOSAccountTransactionFinish(SOSAccountTransactionRef txn) {
CFErrorRef localError = NULL;
bool notifyEngines = false;
static int do_account_state_at_zero = 0;
SOSPeerInfoRef mpi = SOSAccountGetMyPeerInfo(txn->account);
bool inCircle = SOSAccountIsInCircle(txn->account, NULL);
if (inCircle) {
SOSAccountEnsureSyncChecking(txn->account);
} else {
SOSAccountCancelSyncChecking(txn->account);
}
if (!CFEqualSafe(txn->initialID, SOSPeerInfoGetPeerID(mpi))) {
CFAssignRetained(txn->initialUnsyncedViews, SOSViewCopyViewSet(kViewSetAll));
}
CFSetRef finalUnsyncedViews = SOSAccountCopyOutstandingViews(txn->account);
if (!CFEqualSafe(txn->initialUnsyncedViews, finalUnsyncedViews)) {
if (SOSAccountHandleOutOfSyncUpdate(txn->account, txn->initialUnsyncedViews, finalUnsyncedViews)) {
notifyEngines = true;
}
CFStringSetPerformWithDescription(txn->initialUnsyncedViews, ^(CFStringRef newUnsyncedDescripion) {
CFStringSetPerformWithDescription(finalUnsyncedViews, ^(CFStringRef unsyncedDescription) {
secnotice("initial-sync", "Unsynced was: %@", unsyncedDescription);
secnotice("initial-sync", "Unsynced is: %@", newUnsyncedDescripion);
});
});
}
CFReleaseNull(finalUnsyncedViews);
if (txn->account->engine_peer_state_needs_repair) {
if (!SOSAccountEnsurePeerRegistration(txn->account, &localError)) {
secerror("Ensure peer registration while repairing failed: %@", localError);
}
CFReleaseNull(localError);
notifyEngines = true;
}
if(txn->account->circle_rings_retirements_need_attention){
SOSAccountRecordRetiredPeersInCircle(txn->account);
SOSAccountEnsureInBackupRings(txn->account);
CFErrorRef localError = NULL;
if(!SOSTransportCircleFlushChanges(txn->account->circle_transport, &localError)) {
secerror("flush circle failed %@", localError);
}
CFReleaseSafe(localError);
notifyEngines = true;
}
if (notifyEngines) {
SOSAccountNotifyEngines(txn->account);
}
if(txn->account->key_interests_need_updating){
SOSUpdateKeyInterest(txn->account);
}
txn->account->key_interests_need_updating = false;
txn->account->circle_rings_retirements_need_attention = false;
txn->account->engine_peer_state_needs_repair = false;
SOSAccountFlattenToSaveBlock(txn->account);
bool isInCircle = SOSAccountIsInCircle(txn->account, NULL);
mpi = SOSAccountGetMyPeerInfo(txn->account);
CFSetRef views = mpi ? SOSPeerInfoCopyEnabledViews(mpi) : NULL;
CFStringSetPerformWithDescription(views, ^(CFStringRef description) {
secnotice("acct-txn", "Finished as:%s v:%@", isInCircle ? "member" : "non-member", description);
});
if(!CFEqualSafe(txn->initialViews, views) || txn->initialInCircle != isInCircle) {
notify_post(kSOSCCViewMembershipChangedNotification);
do_account_state_at_zero = 0;
}
if((txn->initialTrusted != (txn->account)->user_public_trusted) || (!CFEqualSafe(txn->initialKeyParameters, txn->account->user_key_parameters))){
notify_post(kPublicKeyNotAvailable);
do_account_state_at_zero = 0;
}
if(do_account_state_at_zero <= 0) {
SOSAccountLogState(txn->account);
SOSAccountLogViewState(txn->account);
do_account_state_at_zero = ACCOUNT_STATE_INTERVAL;
}
do_account_state_at_zero--;
CFReleaseNull(views);
}
void SOSAccountTransactionFinishAndRestart(SOSAccountTransactionRef txn) {
SOSAccountTransactionFinish(txn);
SOSAccountTransactionRestart(txn);
}