]>
Commit | Line | Data |
---|---|---|
6b200bc3 A |
1 | |
2 | #include "SOSAccountPriv.h" | |
866f8763 | 3 | #include "SOSAccount.h" |
6b200bc3 | 4 | |
b54c578e A |
5 | #include "keychain/SecureObjectSync/SOSKVSKeys.h" |
6 | #include "keychain/SecureObjectSync/SOSTransportCircle.h" | |
7 | #include "keychain/SecureObjectSync/SOSTransportCircleKVS.h" | |
8 | #include "keychain/SecureObjectSync/SOSTransportMessage.h" | |
9 | #include "keychain/SecureObjectSync/SOSKVSKeys.h" | |
10 | #include "keychain/SecureObjectSync/SOSTransport.h" | |
11 | #include "keychain/SecureObjectSync/SOSTransportKeyParameter.h" | |
12 | #include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h" | |
13 | ||
14 | #import "keychain/SecureObjectSync/SOSAccountTrust.h" | |
15 | #import "keychain/SecureObjectSync/SOSTransport.h" | |
16 | #import "keychain/SecureObjectSync/SOSTransportKeyParameter.h" | |
17 | #include "keychain/SecureObjectSync/SOSTransportMessage.h" | |
18 | #import "keychain/SecureObjectSync/SOSTransportMessageKVS.h" | |
19 | #include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h" | |
20 | #include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" | |
21 | #include "keychain/SecureObjectSync/SOSInternal.h" | |
6b200bc3 A |
22 | |
23 | #include <CoreFoundation/CoreFoundation.h> | |
24 | ||
25 | #include <utilities/SecCFError.h> | |
26 | ||
27 | // MARK: Engine Logging | |
28 | #define LOG_ENGINE_STATE_INTERVAL 20 | |
b54c578e A |
29 | #define LOG_CATEGORY "account-sync" |
30 | ||
31 | static bool SOSReadyToSync(SOSAccount *account, CFErrorRef *error) { | |
32 | if (![account isInCircle:error]) { | |
33 | secnotice(LOG_CATEGORY, "Not performing requested sync operation: not in circle yet"); | |
34 | return false; | |
35 | } | |
36 | return true; | |
37 | } | |
6b200bc3 | 38 | |
866f8763 | 39 | void SOSAccountConsiderLoggingEngineState(SOSAccountTransaction* txn) { |
6b200bc3 A |
40 | static int engineLogCountDown = 0; |
41 | ||
42 | if(engineLogCountDown <= 0) { | |
866f8763 | 43 | SOSAccount* acct = txn.account; |
b54c578e A |
44 | if(SOSReadyToSync(acct, NULL)) { |
45 | CFTypeRef engine = [acct.kvs_message_transport SOSTransportMessageGetEngine]; | |
46 | SOSEngineLogState((SOSEngineRef)engine); | |
47 | engineLogCountDown = LOG_ENGINE_STATE_INTERVAL; | |
48 | } | |
6b200bc3 A |
49 | } else { |
50 | engineLogCountDown--; | |
51 | } | |
52 | } | |
53 | ||
866f8763 A |
54 | bool SOSAccountInflateTransports(SOSAccount* account, CFStringRef circleName, CFErrorRef *error){ |
55 | bool success = false; | |
56 | ||
57 | if(account.key_transport) | |
58 | SOSUnregisterTransportKeyParameter(account.key_transport); | |
59 | if(account.circle_transport) | |
60 | SOSUnregisterTransportCircle(account.circle_transport); | |
866f8763 A |
61 | if(account.kvs_message_transport) |
62 | SOSUnregisterTransportMessage((SOSMessage*)account.kvs_message_transport); | |
63 | ||
64 | account.key_transport = [[CKKeyParameter alloc] initWithAccount:account]; | |
65 | account.circle_transport = [[SOSKVSCircleStorageTransport alloc]initWithAccount:account andCircleName:(__bridge NSString *)(circleName)]; | |
6b200bc3 | 66 | |
866f8763 A |
67 | require_quiet(account.key_transport, fail); |
68 | require_quiet(account.circle_transport, fail); | |
79b9da22 | 69 | |
866f8763 A |
70 | account.kvs_message_transport = [[SOSMessageKVS alloc] initWithAccount:account andName:(__bridge NSString*)circleName]; |
71 | require_quiet(account.kvs_message_transport, fail); | |
72 | ||
73 | success = true; | |
74 | ||
75 | fail: | |
76 | return success; | |
77 | } | |
78 | ||
6b200bc3 A |
79 | // |
80 | // MARK: KVS Syncing | |
81 | // | |
82 | ||
866f8763 A |
83 | static bool SOSAccountSyncWithKVSPeers(SOSAccountTransaction* txn, CFSetRef peerIDs, CFErrorRef *error) { |
84 | SOSAccount* account = txn.account; | |
6b200bc3 A |
85 | CFErrorRef localError = NULL; |
86 | bool result = false; | |
87 | ||
b54c578e A |
88 | if(SOSReadyToSync(account, error)) { |
89 | result =[account.kvs_message_transport SOSTransportMessageSyncWithPeers:account.kvs_message_transport p:peerIDs err:&localError]; | |
90 | } | |
6b200bc3 A |
91 | if (!result) { |
92 | // Tell account to update SOSEngine with current trusted peers | |
93 | if (isSOSErrorCoded(localError, kSOSErrorPeerNotFound)) { | |
b54c578e | 94 | secnotice(LOG_CATEGORY, "Arming account to update SOSEngine with current trusted peers"); |
866f8763 | 95 | account.engine_peer_state_needs_repair = true; |
6b200bc3 A |
96 | } |
97 | CFErrorPropagate(localError, error); | |
98 | localError = NULL; | |
99 | } | |
100 | return result; | |
101 | ||
102 | } | |
103 | ||
866f8763 | 104 | bool SOSAccountSyncWithKVSPeerWithMessage(SOSAccountTransaction* txn, CFStringRef peerid, CFDataRef message, CFErrorRef *error) { |
b54c578e | 105 | //murfxx protect |
866f8763 | 106 | SOSAccount* account = txn.account; |
6b200bc3 A |
107 | bool result = false; |
108 | CFErrorRef localError = NULL; | |
109 | CFDictionaryRef encapsulatedMessage = NULL; | |
110 | ||
b54c578e A |
111 | secnotice(LOG_CATEGORY,"Syncing with KVS capable peer: %@", peerid); |
112 | secnotice(LOG_CATEGORY, "message: %@", message); | |
6b200bc3 A |
113 | |
114 | require_quiet(message, xit); | |
29734401 | 115 | require_quiet(peerid && CFStringGetLength(peerid) <= kSOSPeerIDLengthMax, xit); |
b54c578e A |
116 | if(SOSReadyToSync(account, &localError)) { |
117 | encapsulatedMessage = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, peerid, message, NULL); | |
118 | result = [account.kvs_message_transport SOSTransportMessageSendMessages:account.kvs_message_transport pm:encapsulatedMessage err:&localError]; | |
119 | secnotice(LOG_CATEGORY, "KVS sync %s. (%@)", result ? "succeeded" : "failed", localError); | |
120 | SOSAccountConsiderLoggingEngineState(txn); | |
121 | } | |
6b200bc3 A |
122 | |
123 | xit: | |
124 | CFReleaseNull(encapsulatedMessage); | |
125 | CFErrorPropagate(localError, error); | |
126 | ||
127 | return result; | |
128 | } | |
129 | ||
130 | ||
866f8763 | 131 | static bool SOSAccountSyncWithKVSPeer(SOSAccountTransaction* txn, CFStringRef peerID, CFErrorRef *error) |
6b200bc3 A |
132 | { |
133 | bool result = false; | |
134 | CFErrorRef localError = NULL; | |
b54c578e | 135 | SOSAccount* account = txn.account; |
6b200bc3 | 136 | |
b54c578e A |
137 | if(SOSReadyToSync(account, error)) { |
138 | secnotice(LOG_CATEGORY,"Syncing with KVS capable peer: %@", peerID); | |
139 | CFMutableSetRef peerIDs = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); | |
140 | CFSetAddValue(peerIDs, peerID); | |
141 | result = SOSAccountSyncWithKVSPeers(txn, peerIDs, &localError); | |
142 | secnotice(LOG_CATEGORY, "KVS sync %s. (%@)", result ? "succeeded" : "failed", localError); | |
6b200bc3 | 143 | |
b54c578e A |
144 | CFReleaseNull(peerIDs); |
145 | CFErrorPropagate(localError, error); | |
146 | } | |
6b200bc3 A |
147 | |
148 | return result; | |
149 | } | |
150 | ||
6b200bc3 | 151 | |
866f8763 | 152 | CFSetRef SOSAccountSyncWithPeersOverKVS(SOSAccountTransaction* txn, CFSetRef peers) { |
6b200bc3 | 153 | CFMutableSetRef handled = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); |
b54c578e A |
154 | if(SOSReadyToSync(txn.account, NULL)) { |
155 | CFSetForEach(peers, ^(const void *value) { | |
156 | CFStringRef peerID = asString(value, NULL); | |
157 | CFErrorRef localError = NULL; | |
158 | if (peerID && SOSAccountSyncWithKVSPeer(txn, peerID, &localError)) { | |
159 | CFSetAddValue(handled, peerID); | |
160 | secnotice(LOG_CATEGORY, "synced with peer: %@", peerID); | |
161 | } else { | |
162 | secnotice(LOG_CATEGORY, "failed to sync with peer: %@ error: %@", peerID, localError); | |
163 | } | |
164 | CFReleaseNull(localError); | |
165 | }); | |
166 | } | |
6b200bc3 A |
167 | |
168 | return handled; | |
169 | } | |
170 | ||
866f8763 | 171 | CF_RETURNS_RETAINED CFMutableSetRef SOSAccountSyncWithPeers(SOSAccountTransaction* txn, CFSetRef /* CFStringRef */ peerIDs, CFErrorRef *error) { |
6b200bc3 A |
172 | CFMutableSetRef notMePeers = NULL; |
173 | CFMutableSetRef handledPeerIDs = NULL; | |
6b200bc3 A |
174 | CFMutableSetRef peersForKVS = NULL; |
175 | ||
866f8763 | 176 | SOSAccount* account = txn.account; |
b54c578e | 177 | if(!SOSReadyToSync(account, error)) { |
866f8763 A |
178 | handledPeerIDs = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, peerIDs); |
179 | CFReleaseNull(notMePeers); | |
866f8763 A |
180 | CFReleaseNull(peersForKVS); |
181 | return handledPeerIDs; | |
182 | } | |
6b200bc3 A |
183 | |
184 | handledPeerIDs = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); | |
6b200bc3 A |
185 | peersForKVS = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); |
186 | ||
866f8763 A |
187 | SOSPeerInfoRef myPeerInfo = account.peerInfo; |
188 | if(!myPeerInfo) | |
189 | { | |
190 | CFReleaseNull(notMePeers); | |
866f8763 A |
191 | CFReleaseNull(peersForKVS); |
192 | return handledPeerIDs; | |
6b200bc3 | 193 | |
866f8763 | 194 | } |
6b200bc3 A |
195 | CFStringRef myPeerID = SOSPeerInfoGetPeerID(myPeerInfo); |
196 | ||
197 | notMePeers = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, peerIDs); | |
198 | CFSetRemoveValue(notMePeers, myPeerID); | |
6b200bc3 A |
199 | |
200 | CFSetForEach(notMePeers, ^(const void *value) { | |
201 | CFErrorRef localError = NULL; | |
202 | CFStringRef peerID = asString(value, &localError); | |
203 | SOSPeerInfoRef peerInfo = NULL; | |
866f8763 A |
204 | SOSCircleRef circle = NULL; |
205 | SOSAccountTrustClassic *trust = account.trust; | |
206 | circle = trust.trustedCircle; | |
6b200bc3 A |
207 | require_quiet(peerID, skip); |
208 | ||
866f8763 | 209 | peerInfo = SOSCircleCopyPeerWithID(circle, peerID, NULL); |
79b9da22 A |
210 | if (peerInfo && SOSCircleHasValidSyncingPeer(circle, peerInfo, account.accountKey, NULL)){ |
211 | CFSetAddValue(peersForKVS, peerID); | |
6b200bc3 A |
212 | } else { |
213 | CFSetAddValue(handledPeerIDs, peerID); | |
214 | } | |
215 | ||
216 | skip: | |
217 | CFReleaseNull(peerInfo); | |
218 | if (localError) { | |
b54c578e | 219 | secnotice(LOG_CATEGORY, "Skipped peer ID: %@ due to %@", peerID, localError); |
6b200bc3 A |
220 | } |
221 | CFReleaseNull(localError); | |
222 | }); | |
223 | ||
6b200bc3 A |
224 | CFSetRef handledKVSPeerIDs = SOSAccountSyncWithPeersOverKVS(txn, peersForKVS); |
225 | CFSetUnion(handledPeerIDs, handledKVSPeerIDs); | |
226 | CFReleaseNull(handledKVSPeerIDs); | |
227 | ||
228 | SOSAccountConsiderLoggingEngineState(txn); | |
229 | ||
6b200bc3 | 230 | CFReleaseNull(notMePeers); |
6b200bc3 A |
231 | CFReleaseNull(peersForKVS); |
232 | return handledPeerIDs; | |
233 | } | |
234 | ||
866f8763 | 235 | CF_RETURNS_RETAINED CFSetRef SOSAccountProcessSyncWithPeers(SOSAccountTransaction* txn, CFSetRef /* CFStringRef */ peers, CFSetRef /* CFStringRef */ backupPeers, CFErrorRef *error) |
6b200bc3 A |
236 | { |
237 | CFErrorRef localError = NULL; | |
866f8763 A |
238 | SOSAccount* account = txn.account; |
239 | ||
b54c578e A |
240 | if(!SOSReadyToSync(account, error)) { |
241 | return CFSetCreateMutableForCFTypes(kCFAllocatorDefault); | |
242 | } | |
243 | ||
6b200bc3 A |
244 | CFMutableSetRef handled = SOSAccountSyncWithPeers(txn, peers, &localError); |
245 | ||
6b200bc3 | 246 | if (!handled) { |
b54c578e | 247 | secnotice(LOG_CATEGORY, "Peer Sync failed: %@", localError); |
6b200bc3 A |
248 | handled = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); |
249 | } | |
250 | CFReleaseNull(localError); | |
866f8763 A |
251 | |
252 | CFTypeRef engine = [account.kvs_message_transport SOSTransportMessageGetEngine]; | |
253 | CFSetRef engineHandled = SOSEngineSyncWithBackupPeers((SOSEngineRef)engine, backupPeers, false, error); | |
254 | ||
6b200bc3 A |
255 | if (engineHandled) { |
256 | CFSetUnion(handled, engineHandled); | |
257 | } else { | |
b54c578e | 258 | secnotice(LOG_CATEGORY, "Engine Backup Sync failed: %@", localError); |
6b200bc3 A |
259 | } |
260 | CFReleaseNull(localError); | |
261 | CFReleaseNull(engineHandled); | |
262 | ||
263 | return handled; | |
264 | } | |
265 | ||
866f8763 | 266 | CF_RETURNS_RETAINED CFSetRef SOSAccountCopyBackupPeersAndForceSync(SOSAccountTransaction* txn, CFErrorRef *error) |
6b200bc3 | 267 | { |
b54c578e A |
268 | SOSAccount* account = txn.account; |
269 | ||
270 | if(!SOSReadyToSync(account, error)) { | |
271 | return false; | |
272 | } | |
6b200bc3 | 273 | |
b54c578e | 274 | SOSEngineRef engine = (SOSEngineRef) [txn.account.kvs_message_transport SOSTransportMessageGetEngine]; |
866f8763 A |
275 | NSArray* backupPeersArray = (NSArray*) CFBridgingRelease(SOSEngineCopyBackupPeerNames(engine, error)); |
276 | NSSet* backupPeers = [[NSSet alloc] initWithArray: backupPeersArray]; | |
277 | return SOSEngineSyncWithBackupPeers(engine, (__bridge CFSetRef) backupPeers, true, error); | |
278 | } | |
6b200bc3 | 279 | |
866f8763 A |
280 | bool SOSAccountRequestSyncWithAllPeers(SOSAccountTransaction* txn, CFErrorRef *error) |
281 | { | |
282 | SOSAccount* account = txn.account; | |
283 | SOSAccountTrustClassic *trust = account.trust; | |
6b200bc3 | 284 | |
b54c578e | 285 | if(!SOSReadyToSync(account, error)) { |
866f8763 | 286 | return false; |
b54c578e | 287 | } |
6b200bc3 | 288 | |
866f8763 A |
289 | NSMutableSet<NSString*>* allSyncingPeers = [NSMutableSet set]; |
290 | SOSCircleRef circle = trust.trustedCircle; | |
6b200bc3 | 291 | |
866f8763 A |
292 | SOSCircleForEachValidSyncingPeer(circle, account.accountKey, ^(SOSPeerInfoRef peer) { |
293 | [allSyncingPeers addObject: (__bridge NSString*) SOSPeerInfoGetPeerID(peer)]; | |
294 | }); | |
6b200bc3 | 295 | |
866f8763 A |
296 | [txn requestSyncWithPeers:allSyncingPeers]; |
297 | ||
298 | return true; | |
6b200bc3 A |
299 | } |
300 | ||
301 | // | |
302 | // MARK: Syncing status functions | |
303 | // | |
866f8763 | 304 | bool SOSAccountMessageFromPeerIsPending(SOSAccountTransaction* txn, SOSPeerInfoRef peer, CFErrorRef *error) { |
6b200bc3 | 305 | bool success = false; |
866f8763 | 306 | SOSAccount* account = txn.account; |
b54c578e A |
307 | if(SOSReadyToSync(account, error)) { |
308 | // This translation belongs inside KVS..way down in CKD, but for now we reach over and do it here. | |
309 | CFStringRef peerMessage = SOSMessageKeyCreateFromPeerToTransport([account kvs_message_transport], (__bridge CFStringRef)(account.peerID), SOSPeerInfoGetPeerID(peer)); | |
310 | success = SOSCloudKeychainHasPendingKey(peerMessage, error); | |
311 | CFReleaseNull(peerMessage); | |
312 | } | |
6b200bc3 A |
313 | return success; |
314 | } | |
315 | ||
866f8763 | 316 | bool SOSAccountSendToPeerIsPending(SOSAccountTransaction* txn, SOSPeerInfoRef peer, CFErrorRef *error) { |
6b200bc3 | 317 | bool success = false; |
866f8763 | 318 | SOSAccount* account = txn.account; |
b54c578e A |
319 | if(SOSReadyToSync(account, error)) { |
320 | success = SOSCCIsSyncPendingFor(SOSPeerInfoGetPeerID(peer), error); | |
321 | } | |
6b200bc3 | 322 | return success; |
6b200bc3 | 323 | } |
866f8763 | 324 |