2 // SOSAccountTransaction.c
7 #include "SOSAccountTransaction.h"
9 #include <utilities/SecCFWrappers.h>
10 #include <CoreFoundation/CoreFoundation.h>
12 #include <Security/SecureObjectSync/SOSAccount.h>
13 #include <Security/SecureObjectSync/SOSAccountPriv.h>
14 #include <Security/SecureObjectSync/SOSPeerInfoV2.h>
15 #include <Security/SecureObjectSync/SOSTransport.h>
16 #include <Security/SecureObjectSync/SOSTransportCircle.h>
18 #define kPublicKeyNotAvailable "com.apple.security.publickeynotavailable"
20 CFGiblisFor(SOSAccountTransaction
);
22 static void SOSAccountTransactionDestroy(CFTypeRef aObj
) {
23 SOSAccountTransactionRef at
= (SOSAccountTransactionRef
) aObj
;
25 CFReleaseNull(at
->initialUnsyncedViews
);
26 CFReleaseNull(at
->initialID
);
27 CFReleaseNull(at
->account
);
28 CFReleaseNull(at
->initialViews
);
29 CFReleaseNull(at
->initialKeyParameters
);
32 static CFStringRef
SOSAccountTransactionCopyFormatDescription(CFTypeRef aObj
, CFDictionaryRef formatOptions
) {
33 SOSAccountTransactionRef at
= (SOSAccountTransactionRef
) aObj
;
35 CFMutableStringRef description
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
37 CFStringAppendFormat(description
, NULL
, CFSTR("<SOSAccountTransactionRef@%p %ld>"),
38 at
, at
->initialViews
? CFSetGetCount(at
->initialViews
) : 0);
43 static void SOSAccountTransactionRestart(SOSAccountTransactionRef txn
) {
44 txn
->initialInCircle
= SOSAccountIsInCircle(txn
->account
, NULL
);
47 txn
->initialTrusted
= (txn
->account
)->user_public_trusted
;
49 if (txn
->initialInCircle
) {
50 SOSAccountEnsureSyncChecking(txn
->account
);
53 CFAssignRetained(txn
->initialUnsyncedViews
, SOSAccountCopyOutstandingViews(txn
->account
));
55 CFReleaseNull(txn
->initialKeyParameters
);
57 if(txn
->account
&& txn
->account
->user_key_parameters
){
58 CFReleaseNull(txn
->initialKeyParameters
);
59 txn
->initialKeyParameters
= CFDataCreateCopy(kCFAllocatorDefault
, txn
->account
->user_key_parameters
);
61 SOSPeerInfoRef mpi
= SOSAccountGetMyPeerInfo(txn
->account
);
62 CFAssignRetained(txn
->initialViews
, mpi
? SOSPeerInfoCopyEnabledViews(mpi
) : NULL
);
64 CFRetainAssign(txn
->initialID
, SOSPeerInfoGetPeerID(mpi
));
66 CFStringSetPerformWithDescription(txn
->initialViews
, ^(CFStringRef description
) {
67 secnotice("acct-txn", "Starting as:%s v:%@", txn
->initialInCircle
? "member" : "non-member", description
);
72 SOSAccountTransactionRef
SOSAccountTransactionCreate(SOSAccountRef account
) {
73 SOSAccountTransactionRef at
= CFTypeAllocate(SOSAccountTransaction
, struct __OpaqueSOSAccountTransaction
, kCFAllocatorDefault
);
75 at
->account
= CFRetainSafe(account
);
77 at
->initialInCircle
= false;
78 at
->initialViews
= NULL
;
79 at
->initialKeyParameters
= NULL
;
80 at
->initialTrusted
= false;
81 at
->initialUnsyncedViews
= NULL
;
84 SOSAccountTransactionRestart(at
);
89 #define ACCOUNT_STATE_INTERVAL 20
91 void SOSAccountTransactionFinish(SOSAccountTransactionRef txn
) {
92 CFErrorRef localError
= NULL
;
93 bool notifyEngines
= false;
94 static int do_account_state_at_zero
= 0;
96 SOSPeerInfoRef mpi
= SOSAccountGetMyPeerInfo(txn
->account
);
98 bool inCircle
= SOSAccountIsInCircle(txn
->account
, NULL
);
101 SOSAccountEnsureSyncChecking(txn
->account
);
103 SOSAccountCancelSyncChecking(txn
->account
);
106 // If our identity changed our inital set should be everything.
107 if (!CFEqualSafe(txn
->initialID
, SOSPeerInfoGetPeerID(mpi
))) {
108 CFAssignRetained(txn
->initialUnsyncedViews
, SOSViewCopyViewSet(kViewSetAll
));
111 CFSetRef finalUnsyncedViews
= SOSAccountCopyOutstandingViews(txn
->account
);
112 if (!CFEqualSafe(txn
->initialUnsyncedViews
, finalUnsyncedViews
)) {
113 if (SOSAccountHandleOutOfSyncUpdate(txn
->account
, txn
->initialUnsyncedViews
, finalUnsyncedViews
)) {
114 notifyEngines
= true;
117 CFStringSetPerformWithDescription(txn
->initialUnsyncedViews
, ^(CFStringRef newUnsyncedDescripion
) {
118 CFStringSetPerformWithDescription(finalUnsyncedViews
, ^(CFStringRef unsyncedDescription
) {
119 secnotice("initial-sync", "Unsynced was: %@", unsyncedDescription
);
120 secnotice("initial-sync", "Unsynced is: %@", newUnsyncedDescripion
);
124 CFReleaseNull(finalUnsyncedViews
);
126 if (txn
->account
->engine_peer_state_needs_repair
) {
127 // We currently only get here from a failed syncwithallpeers, so
128 // that will retry. If this logic changes, force a syncwithallpeers
129 if (!SOSAccountEnsurePeerRegistration(txn
->account
, &localError
)) {
130 secerror("Ensure peer registration while repairing failed: %@", localError
);
132 CFReleaseNull(localError
);
134 notifyEngines
= true;
137 if(txn
->account
->circle_rings_retirements_need_attention
){
138 SOSAccountRecordRetiredPeersInCircle(txn
->account
);
140 SOSAccountEnsureInBackupRings(txn
->account
);
142 CFErrorRef localError
= NULL
;
143 if(!SOSTransportCircleFlushChanges(txn
->account
->circle_transport
, &localError
)) {
144 secerror("flush circle failed %@", localError
);
146 CFReleaseSafe(localError
);
148 notifyEngines
= true;
152 SOSAccountNotifyEngines(txn
->account
);
155 if(txn
->account
->key_interests_need_updating
){
156 SOSUpdateKeyInterest(txn
->account
);
159 txn
->account
->key_interests_need_updating
= false;
160 txn
->account
->circle_rings_retirements_need_attention
= false;
161 txn
->account
->engine_peer_state_needs_repair
= false;
163 SOSAccountFlattenToSaveBlock(txn
->account
);
165 // Check for firing view membership change. On change of view membership or circle membership
166 bool isInCircle
= SOSAccountIsInCircle(txn
->account
, NULL
);
168 mpi
= SOSAccountGetMyPeerInfo(txn
->account
);
169 CFSetRef views
= mpi
? SOSPeerInfoCopyEnabledViews(mpi
) : NULL
;
171 CFStringSetPerformWithDescription(views
, ^(CFStringRef description
) {
172 secnotice("acct-txn", "Finished as:%s v:%@", isInCircle
? "member" : "non-member", description
);
174 if(!CFEqualSafe(txn
->initialViews
, views
) || txn
->initialInCircle
!= isInCircle
) {
175 notify_post(kSOSCCViewMembershipChangedNotification
);
176 do_account_state_at_zero
= 0;
179 if((txn
->initialTrusted
!= (txn
->account
)->user_public_trusted
) || (!CFEqualSafe(txn
->initialKeyParameters
, txn
->account
->user_key_parameters
))){
180 notify_post(kPublicKeyNotAvailable
);
181 do_account_state_at_zero
= 0;
184 if(do_account_state_at_zero
<= 0) {
185 SOSAccountLogState(txn
->account
);
186 SOSAccountLogViewState(txn
->account
);
187 do_account_state_at_zero
= ACCOUNT_STATE_INTERVAL
;
189 do_account_state_at_zero
--;
191 CFReleaseNull(views
);
195 void SOSAccountTransactionFinishAndRestart(SOSAccountTransactionRef txn
) {
196 SOSAccountTransactionFinish(txn
);
197 SOSAccountTransactionRestart(txn
);