]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSAccountTransaction.c
cd07404087cbb2f46f7ff2e43b0fca01b0c1fdad
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSAccountTransaction.c
1 //
2 // SOSAccountTransaction.c
3 // sec
4 //
5 //
6
7 #include "SOSAccountTransaction.h"
8
9 #include <utilities/SecCFWrappers.h>
10 #include <CoreFoundation/CoreFoundation.h>
11
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>
17
18 #define kPublicKeyNotAvailable "com.apple.security.publickeynotavailable"
19
20 CFGiblisFor(SOSAccountTransaction);
21
22 static void SOSAccountTransactionDestroy(CFTypeRef aObj) {
23 SOSAccountTransactionRef at = (SOSAccountTransactionRef) aObj;
24
25 CFReleaseNull(at->initialUnsyncedViews);
26 CFReleaseNull(at->initialID);
27 CFReleaseNull(at->account);
28 CFReleaseNull(at->initialViews);
29 CFReleaseNull(at->initialKeyParameters);
30 CFReleaseNull(at->peersToRequestSync);
31 }
32
33 static CFStringRef SOSAccountTransactionCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
34 SOSAccountTransactionRef at = (SOSAccountTransactionRef) aObj;
35
36 CFMutableStringRef description = CFStringCreateMutable(kCFAllocatorDefault, 0);
37
38 CFStringAppendFormat(description, NULL, CFSTR("<SOSAccountTransactionRef@%p %ld>"),
39 at, at->initialViews ? CFSetGetCount(at->initialViews) : 0);
40
41 return description;
42 }
43
44 static void SOSAccountTransactionRestart(SOSAccountTransactionRef txn) {
45 txn->initialInCircle = SOSAccountIsInCircle(txn->account, NULL);
46
47 if(txn->account)
48 txn->initialTrusted = (txn->account)->user_public_trusted;
49
50 if (txn->initialInCircle) {
51 SOSAccountEnsureSyncChecking(txn->account);
52 }
53
54 CFAssignRetained(txn->initialUnsyncedViews, SOSAccountCopyOutstandingViews(txn->account));
55
56 CFReleaseNull(txn->initialKeyParameters);
57
58 if(txn->account && txn->account->user_key_parameters){
59 CFReleaseNull(txn->initialKeyParameters);
60 txn->initialKeyParameters = CFDataCreateCopy(kCFAllocatorDefault, txn->account->user_key_parameters);
61 }
62 SOSPeerInfoRef mpi = SOSAccountGetMyPeerInfo(txn->account);
63 CFAssignRetained(txn->initialViews, mpi ? SOSPeerInfoCopyEnabledViews(mpi) : NULL);
64
65 CFRetainAssign(txn->initialID, SOSPeerInfoGetPeerID(mpi));
66
67 CFReleaseNull(txn->peersToRequestSync);
68
69 CFStringSetPerformWithDescription(txn->initialViews, ^(CFStringRef description) {
70 secnotice("acct-txn", "Starting as:%s v:%@", txn->initialInCircle ? "member" : "non-member", description);
71 });
72 }
73
74
75 SOSAccountTransactionRef SOSAccountTransactionCreate(SOSAccountRef account) {
76 SOSAccountTransactionRef at = CFTypeAllocate(SOSAccountTransaction, struct __OpaqueSOSAccountTransaction, kCFAllocatorDefault);
77
78 at->account = CFRetainSafe(account);
79
80 at->initialInCircle = false;
81 at->initialViews = NULL;
82 at->initialKeyParameters = NULL;
83 at->initialTrusted = false;
84 at->initialUnsyncedViews = NULL;
85 at->initialID = NULL;
86 at->peersToRequestSync = NULL;
87
88 SOSAccountTransactionRestart(at);
89
90 return at;
91 }
92
93 #define ACCOUNT_STATE_INTERVAL 20
94
95 void SOSAccountTransactionFinish(SOSAccountTransactionRef txn) {
96 CFErrorRef localError = NULL;
97 bool notifyEngines = false;
98 static int do_account_state_at_zero = 0;
99
100 SOSPeerInfoRef mpi = SOSAccountGetMyPeerInfo(txn->account);
101
102 bool isInCircle = SOSAccountIsInCircle(txn->account, NULL);
103
104 if (isInCircle && txn->peersToRequestSync) {
105 SOSCCRequestSyncWithPeers(txn->peersToRequestSync);
106 }
107 CFReleaseNull(txn->peersToRequestSync);
108
109 if (isInCircle) {
110 SOSAccountEnsureSyncChecking(txn->account);
111 } else {
112 SOSAccountCancelSyncChecking(txn->account);
113 }
114
115 // If our identity changed our inital set should be everything.
116 if (!CFEqualSafe(txn->initialID, SOSPeerInfoGetPeerID(mpi))) {
117 CFAssignRetained(txn->initialUnsyncedViews, SOSViewCopyViewSet(kViewSetAll));
118 }
119
120 CFSetRef finalUnsyncedViews = SOSAccountCopyOutstandingViews(txn->account);
121 if (!CFEqualSafe(txn->initialUnsyncedViews, finalUnsyncedViews)) {
122 if (SOSAccountHandleOutOfSyncUpdate(txn->account, txn->initialUnsyncedViews, finalUnsyncedViews)) {
123 notifyEngines = true;
124 }
125
126 CFStringSetPerformWithDescription(txn->initialUnsyncedViews, ^(CFStringRef newUnsyncedDescripion) {
127 CFStringSetPerformWithDescription(finalUnsyncedViews, ^(CFStringRef unsyncedDescription) {
128 secnotice("initial-sync", "Unsynced was: %@", unsyncedDescription);
129 secnotice("initial-sync", "Unsynced is: %@", newUnsyncedDescripion);
130 });
131 });
132 }
133 CFReleaseNull(finalUnsyncedViews);
134
135 if (txn->account->engine_peer_state_needs_repair) {
136 // We currently only get here from a failed syncwithallpeers, so
137 // that will retry. If this logic changes, force a syncwithallpeers
138 if (!SOSAccountEnsurePeerRegistration(txn->account, &localError)) {
139 secerror("Ensure peer registration while repairing failed: %@", localError);
140 }
141 CFReleaseNull(localError);
142
143 notifyEngines = true;
144 }
145
146 if(txn->account->circle_rings_retirements_need_attention){
147 SOSAccountRecordRetiredPeersInCircle(txn->account);
148
149 SOSAccountEnsureRecoveryRing(txn->account);
150 SOSAccountEnsureInBackupRings(txn->account);
151
152 CFErrorRef localError = NULL;
153 if(!SOSTransportCircleFlushChanges(txn->account->circle_transport, &localError)) {
154 secerror("flush circle failed %@", localError);
155 }
156 CFReleaseSafe(localError);
157
158 notifyEngines = true;
159 }
160
161 if (notifyEngines) {
162 SOSAccountNotifyEngines(txn->account);
163 }
164
165 if(txn->account->key_interests_need_updating){
166 SOSUpdateKeyInterest(txn->account);
167 }
168
169 txn->account->key_interests_need_updating = false;
170 txn->account->circle_rings_retirements_need_attention = false;
171 txn->account->engine_peer_state_needs_repair = false;
172
173 SOSAccountFlattenToSaveBlock(txn->account);
174
175 // Refresh isInCircle since we could have changed our mind
176 isInCircle = SOSAccountIsInCircle(txn->account, NULL);
177
178 mpi = SOSAccountGetMyPeerInfo(txn->account);
179 CFSetRef views = mpi ? SOSPeerInfoCopyEnabledViews(mpi) : NULL;
180
181 CFStringSetPerformWithDescription(views, ^(CFStringRef description) {
182 secnotice("acct-txn", "Finished as:%s v:%@", isInCircle ? "member" : "non-member", description);
183 });
184 if(!CFEqualSafe(txn->initialViews, views) || txn->initialInCircle != isInCircle) {
185 notify_post(kSOSCCViewMembershipChangedNotification);
186 do_account_state_at_zero = 0;
187 }
188
189 if((txn->initialTrusted != (txn->account)->user_public_trusted) || (!CFEqualSafe(txn->initialKeyParameters, txn->account->user_key_parameters))){
190 notify_post(kPublicKeyNotAvailable);
191 do_account_state_at_zero = 0;
192 }
193
194 if(do_account_state_at_zero <= 0) {
195 SOSAccountLogState(txn->account);
196 SOSAccountLogViewState(txn->account);
197 do_account_state_at_zero = ACCOUNT_STATE_INTERVAL;
198 }
199 do_account_state_at_zero--;
200
201 CFReleaseNull(views);
202
203 }
204
205 void SOSAccountTransactionFinishAndRestart(SOSAccountTransactionRef txn) {
206 SOSAccountTransactionFinish(txn);
207 SOSAccountTransactionRestart(txn);
208 }
209
210 void SOSAccountTransactionAddSyncRequestForPeerID(SOSAccountTransactionRef txn, CFStringRef peerID) {
211 if (!txn->peersToRequestSync) {
212 txn->peersToRequestSync = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
213 }
214
215 CFSetAddValue(txn->peersToRequestSync, peerID);
216 }
217
218 void SOSAccountTransactionAddSyncRequestForAllPeerIDs(SOSAccountTransactionRef txn, CFSetRef /* CFStringRef */ peerIDs) {
219 if (!txn->peersToRequestSync) {
220 txn->peersToRequestSync = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
221 }
222
223 CFSetUnion(txn->peersToRequestSync, peerIDs);
224 }
225
226