]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSTransport.m
Security-58286.31.2.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSTransport.m
1
2 #include <Security/SecureObjectSync/SOSInternal.h>
3 #include <Security/SecureObjectSync/SOSKVSKeys.h>
4 #include <Security/SecureObjectSync/SOSAccountPriv.h>
5 #include <Security/SecureObjectSync/SOSTransport.h>
6 #include <Security/SecureObjectSync/SOSTransportKeyParameter.h>
7 #include <Security/SecureObjectSync/SOSTransportCircleKVS.h>
8 #include <Security/SecureObjectSync/SOSTransportMessageKVS.h>
9 #include <Security/SecureObjectSync/SOSTransportMessageIDS.h>
10 #include <Security/SecureObjectSync/SOSTransportMessage.h>
11 #include <Security/SecureObjectSync/SOSRing.h>
12
13 #include <SOSCloudKeychainClient.h>
14 #include <utilities/debugging.h>
15 #include <utilities/SecCFWrappers.h>
16 #include <CoreFoundation/CFBase.h>
17
18 CFStringRef kKeyParameter = CFSTR("KeyParameter");
19 CFStringRef kCircle = CFSTR("Circle");
20 CFStringRef kMessage = CFSTR("Message");
21 CFStringRef kAlwaysKeys = CFSTR("AlwaysKeys");
22 CFStringRef kFirstUnlocked = CFSTR("FirstUnlockKeys");
23 CFStringRef kUnlocked = CFSTR("UnlockedKeys");
24 extern CFStringRef kSOSAccountDebugScope;
25
26 #define DATE_LENGTH 18
27
28 CFStringRef SOSInterestListCopyDescription(CFArrayRef interests)
29 {
30 CFMutableStringRef description = CFStringCreateMutable(kCFAllocatorDefault, 0);
31 CFStringAppendFormat(description, NULL, CFSTR("<Interest: "));
32
33 if (interests) {
34 CFArrayForEach(interests, ^(const void* string) {
35 if (isString(string))
36
37 CFStringAppendFormat(description, NULL, CFSTR(" '%@'"), string);
38 });
39 }
40 CFStringAppend(description, CFSTR(">"));
41
42 return description;
43 }
44
45
46 //
47 // MARK: Key Interest Processing
48 //
49
50 CFGiblisGetSingleton(CFMutableArrayRef, SOSGetTransportMessages, sTransportMessages, ^{
51 *sTransportMessages = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
52 });
53
54 CFGiblisGetSingleton(CFMutableArrayRef, SOSGetTransportKeyParameters, sTransportKeyParameters, ^{
55 *sTransportKeyParameters = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
56 });
57
58 CFGiblisGetSingleton(CFMutableArrayRef, SOSGetTransportCircles, sTransportCircles, ^{
59 *sTransportCircles = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
60 });
61
62
63 void SOSRegisterTransportMessage(SOSMessage* additional) {
64 if(additional != nil)
65 CFArrayAppendValue(SOSGetTransportMessages(), (__bridge CFTypeRef)(additional));
66 }
67
68 void SOSUnregisterTransportMessage(SOSMessage* removal) {
69 CFArrayRemoveAllValue(SOSGetTransportMessages(), (__bridge CFTypeRef)(removal));
70 }
71
72 void SOSUnregisterAllTransportMessages() {
73 CFArrayRemoveAllValues(SOSGetTransportMessages());
74 }
75
76 void SOSRegisterTransportCircle(SOSCircleStorageTransport* additional) {
77 if(additional != nil)
78 CFArrayAppendValue(SOSGetTransportCircles(), (__bridge CFTypeRef)(additional));
79 }
80
81 void SOSUnregisterTransportCircle(SOSCircleStorageTransport* removal) {
82 CFArrayRemoveAllValue(SOSGetTransportCircles(), (__bridge CFTypeRef)removal);
83 }
84
85 void SOSUnregisterAllTransportCircles() {
86 CFArrayRemoveAllValues(SOSGetTransportCircles());
87 }
88
89 void SOSRegisterTransportKeyParameter(CKKeyParameter* additional) {
90 if(additional != nil)
91 CFArrayAppendValue(SOSGetTransportKeyParameters(), (__bridge CFTypeRef)(additional));
92 }
93
94 void SOSUnregisterTransportKeyParameter(CKKeyParameter* removal) {
95 CFArrayRemoveAllValue(SOSGetTransportKeyParameters(), (__bridge CFTypeRef)(removal));
96 }
97
98 void SOSUnregisterAllTransportKeyParameters() {
99 CFArrayRemoveAllValues(SOSGetTransportKeyParameters());
100 }
101
102 //
103 // Should we be dispatching back to our queue to handle later
104 //
105 void SOSUpdateKeyInterest(SOSAccount* account)
106 {
107 CFMutableArrayRef alwaysKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
108 CFMutableArrayRef afterFirstUnlockKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
109 CFMutableArrayRef whenUnlockedKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
110 CFMutableDictionaryRef keyDict = CFDictionaryCreateMutableForCFTypes (kCFAllocatorDefault);
111
112 NSMutableArray *temp = (__bridge NSMutableArray *)(SOSGetTransportKeyParameters());
113
114 [temp enumerateObjectsUsingBlock:^(CKKeyParameter *value, NSUInteger idx, BOOL * _Nonnull stop) {
115 CKKeyParameter* tKP = (CKKeyParameter*) value;
116 if ([tKP SOSTransportKeyParameterGetAccount:tKP] == account && [tKP SOSTransportKeyParameterGetTransportType:tKP err:NULL] == kKVS) {
117 CKKeyParameter* tkvs = (CKKeyParameter*) value;
118 CFErrorRef localError = NULL;
119
120 if (![tkvs SOSTransportKeyParameterKVSAppendKeyInterests:tkvs ak:alwaysKeys firstUnLock:afterFirstUnlockKeys unlocked:whenUnlockedKeys err:&localError]) {
121 secerror("Error getting key parameters interests %@", localError);
122 }
123 CFReleaseNull(localError);
124 }
125
126 }];
127
128 CFMutableDictionaryRef keyParamsDict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
129 CFDictionarySetValue(keyParamsDict, kAlwaysKeys, alwaysKeys);
130 CFDictionarySetValue(keyParamsDict, kFirstUnlocked, afterFirstUnlockKeys);
131 CFDictionarySetValue(keyParamsDict, kUnlocked, whenUnlockedKeys);
132 CFDictionarySetValue(keyDict, kKeyParameter, keyParamsDict);
133
134 CFReleaseNull(alwaysKeys);
135 CFReleaseNull(afterFirstUnlockKeys);
136 CFReleaseNull(whenUnlockedKeys);
137 alwaysKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
138 afterFirstUnlockKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
139 whenUnlockedKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
140
141 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value) {
142 SOSKVSCircleStorageTransport *transport = (__bridge SOSKVSCircleStorageTransport*)value;
143 if ( [[transport getAccount] isEqual: account] ) {
144 SOSKVSCircleStorageTransport* tkvs = (__bridge SOSKVSCircleStorageTransport*) value;
145 CFErrorRef localError = NULL;
146
147 if(! [tkvs kvsAppendKeyInterest:alwaysKeys firstUnlock:afterFirstUnlockKeys unlocked:whenUnlockedKeys err:&localError]){
148 secerror("Error getting circle interests %@", localError);
149 }
150 if(![tkvs kvsAppendRingKeyInterest:alwaysKeys firstUnlock:afterFirstUnlockKeys unlocked:whenUnlockedKeys err:&localError]){
151 secerror("Error getting ring interests %@", localError);
152 }
153 if(![tkvs kvsAppendDebugKeyInterest:alwaysKeys firstUnlock:afterFirstUnlockKeys unlocked:whenUnlockedKeys err:&localError]) {
154 secerror("Error getting debug key interests %@", localError);
155 }
156
157 if(![tkvs kvsAppendConfigKeyInterest:alwaysKeys firstUnlock:afterFirstUnlockKeys unlocked:whenUnlockedKeys err:&localError]) {
158 secerror("Error getting config key interests %@", localError);
159 }
160 CFReleaseNull(localError);
161 }
162
163 });
164 CFMutableDictionaryRef circleDict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
165 CFDictionarySetValue(circleDict, kAlwaysKeys, alwaysKeys);
166 CFDictionarySetValue(circleDict, kFirstUnlocked, afterFirstUnlockKeys);
167 CFDictionarySetValue(circleDict, kUnlocked, whenUnlockedKeys);
168 CFDictionarySetValue(keyDict, kCircle, circleDict);
169
170 CFReleaseNull(alwaysKeys);
171 CFReleaseNull(afterFirstUnlockKeys);
172 CFReleaseNull(whenUnlockedKeys);
173 alwaysKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
174 afterFirstUnlockKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
175 whenUnlockedKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
176
177 CFArrayForEach(SOSGetTransportMessages(), ^(const void *value) {
178 SOSMessage* transport = (__bridge SOSMessage*)value;
179 if ([transport SOSTransportMessageGetAccount] == account && [transport SOSTransportMessageGetTransportType] == kKVS) {
180 CFErrorRef localError = NULL;
181 SOSMessageKVS* tks = (__bridge SOSMessageKVS*)value;
182 if(![tks SOSTransportMessageKVSAppendKeyInterest:tks ak:alwaysKeys firstUnlock:afterFirstUnlockKeys unlocked:whenUnlockedKeys err:&localError]){
183 secerror("Error getting message interests %@", localError);
184 }
185 CFReleaseNull(localError);
186 }
187 });
188
189 CFMutableDictionaryRef messageDict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
190 CFDictionarySetValue(messageDict, kAlwaysKeys, alwaysKeys);
191 CFDictionarySetValue(messageDict, kFirstUnlocked, afterFirstUnlockKeys);
192 CFDictionarySetValue(messageDict, kUnlocked, whenUnlockedKeys);
193 CFDictionarySetValue(keyDict, kMessage, messageDict);
194
195 //
196 // Log what we are about to do.
197 //
198 NSUInteger itemCount = 0;
199 for (NSString *subsystem in @[(__bridge id)kMessage, (__bridge id)kCircle, (__bridge id)kKeyParameter]) {
200 secnotice("key-interests", "Updating interests: %@", subsystem);
201 for (NSString *lockState in @[(__bridge id)kAlwaysKeys, (__bridge id)kFirstUnlocked, (__bridge id)kUnlocked]) {
202 NSArray *items = ((__bridge NSDictionary *)keyDict)[subsystem][lockState];
203 itemCount += items.count;
204 for (NSString *item in items) {
205 secnotice("key-interests", " key-intrest: %@->%@: %@", subsystem, lockState, item);
206 }
207 }
208 }
209 secnotice("key-interests", "Updating interests done: %lu", (unsigned long)itemCount);
210
211 CFStringRef uuid = SOSAccountCopyUUID(account);
212 SOSCloudKeychainUpdateKeys(keyDict, uuid, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef error) {
213 if (error) {
214 secerror("Error updating keys: %@", error);
215 }
216 });
217 CFReleaseNull(uuid);
218
219 CFReleaseNull(alwaysKeys);
220 CFReleaseNull(afterFirstUnlockKeys);
221 CFReleaseNull(whenUnlockedKeys);
222 CFReleaseNull(keyParamsDict);
223 CFReleaseNull(circleDict);
224 CFReleaseNull(messageDict);
225 CFReleaseNull(keyDict);
226 }
227
228
229 static void showWhatWasHandled(CFDictionaryRef updates, CFMutableArrayRef handledKeys) {
230
231 CFMutableStringRef updateStr = CFStringCreateMutable(kCFAllocatorDefault, 0);
232 CFMutableStringRef handledKeysStr = CFStringCreateMutable(kCFAllocatorDefault, 0);
233
234 CFDictionaryForEach(updates, ^(const void *key, const void *value) {
235 if (isString(key)) {
236 CFStringAppendFormat(updateStr, NULL, CFSTR("%@ "), (CFStringRef)key);
237 }
238 });
239 CFArrayForEach(handledKeys, ^(const void *value) {
240 if (isString(value)) {
241 CFStringAppendFormat(handledKeysStr, NULL, CFSTR("%@ "), (CFStringRef)value);
242 }
243 });
244 secinfo("updates", "Updates [%ld]: %@", CFDictionaryGetCount(updates), updateStr);
245 secinfo("updates", "Handled [%ld]: %@", CFArrayGetCount(handledKeys), handledKeysStr);
246
247 CFReleaseSafe(updateStr);
248 CFReleaseSafe(handledKeysStr);
249 }
250
251 #define KVS_STATE_INTERVAL 50
252
253 CF_RETURNS_RETAINED
254 CFMutableArrayRef SOSTransportDispatchMessages(SOSAccountTransaction* txn, CFDictionaryRef updates, CFErrorRef *error){
255 __block SOSAccount* account = txn.account;
256
257 CFMutableArrayRef handledKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
258 CFStringRef dsid = NULL;
259
260 if(CFDictionaryGetValueIfPresent(updates, kSOSKVSAccountChangedKey, (const void**)&dsid)){
261 secnotice("accountChange", "SOSTransportDispatchMessages received kSOSKVSAccountChangedKey");
262 // While changing accounts we may modify the key params array. To avoid stepping on ourselves we
263 // copy the list for iteration. Now modifying the transport outside of the list iteration.
264 CFMutableArrayRef transportsToUse = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
265
266 CFArrayForEach(SOSGetTransportKeyParameters(), ^(const void *value) {
267 CKKeyParameter* transport = (__bridge CKKeyParameter*) value;
268
269 if(CFEqualSafe((__bridge CFTypeRef)([transport SOSTransportKeyParameterGetAccount:transport]), (__bridge CFTypeRef)(account))){
270 CFArrayAppendValue(transportsToUse, (__bridge const void *)(transport));
271 }
272 });
273
274 CFArrayForEach(transportsToUse, ^(const void *value) {
275 CKKeyParameter* tempTransport = (__bridge CKKeyParameter*) value;
276
277 CFStringRef accountDSID = (CFStringRef)SOSAccountGetValue(account, kSOSDSIDKey, error);
278
279 if(accountDSID == NULL){
280 [tempTransport SOSTransportKeyParameterHandleNewAccount:tempTransport acct:account];
281 SOSAccountSetValue(account, kSOSDSIDKey, dsid, error);
282 secdebug("dsid", "Assigning new DSID: %@", dsid);
283 } else if(accountDSID != NULL && CFStringCompare(accountDSID, dsid, 0) != 0 ) {
284 [tempTransport SOSTransportKeyParameterHandleNewAccount:tempTransport acct:account];
285 SOSAccountSetValue(account, kSOSDSIDKey, dsid, error);
286 secdebug("dsid", "Assigning new DSID: %@", dsid);
287 } else {
288 secdebug("dsid", "DSIDs are the same!");
289 }
290 });
291
292 CFReleaseNull(transportsToUse);
293
294 CFArrayAppendValue(handledKeys, kSOSKVSAccountChangedKey);
295 }
296
297
298 // Iterate through keys in updates. Perform circle change update.
299 // Then instantiate circles and engines and peers for all peers that
300 // are receiving a message in updates.
301 CFMutableDictionaryRef circle_peer_messages_table = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
302 CFMutableDictionaryRef circle_circle_messages_table = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
303 CFMutableDictionaryRef circle_retirement_messages_table = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
304 CFMutableDictionaryRef ring_update_message_table = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
305 CFMutableDictionaryRef debug_info_message_table = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
306 __block CFMutableDictionaryRef config_message_table = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
307
308 __block CFDataRef newParameters = NULL;
309 __block bool initial_sync = false;
310 __block bool new_account = false;
311
312 CFDictionaryForEach(updates, ^(const void *key, const void *value) {
313 CFErrorRef localError = NULL;
314 CFStringRef circle_name = NULL;
315 CFStringRef ring_name = NULL;
316 CFStringRef peer_info_name = NULL;
317 CFStringRef from_name = NULL;
318 CFStringRef to_name = NULL;
319 CFStringRef backup_name = NULL;
320
321 require_quiet(isString(key), errOut);
322 switch (SOSKVSKeyGetKeyTypeAndParse(key, &circle_name, &peer_info_name, &ring_name, &backup_name, &from_name, &to_name)) {
323 case kCircleKey:
324 CFDictionarySetValue(circle_circle_messages_table, circle_name, value);
325 break;
326 case kInitialSyncKey:
327 initial_sync = true;
328 break;
329 case kParametersKey:
330 if (isData(value)) {
331 newParameters = (CFDataRef) CFRetainSafe(value);
332 }
333 break;
334 case kMessageKey: {
335 CFMutableDictionaryRef circle_messages = CFDictionaryEnsureCFDictionaryAndGetCurrentValue(circle_peer_messages_table, circle_name);
336 CFDictionarySetValue(circle_messages, from_name, value);
337 break;
338 }
339 case kRetirementKey: {
340 CFMutableDictionaryRef circle_retirements = CFDictionaryEnsureCFDictionaryAndGetCurrentValue(circle_retirement_messages_table, circle_name);
341 CFDictionarySetValue(circle_retirements, from_name, value);
342 break;
343 }
344 case kAccountChangedKey:
345 new_account = true;
346 break;
347 case kRingKey:
348 if(isString(ring_name))
349 CFDictionarySetValue(ring_update_message_table, ring_name, value);
350 break;
351 case kDebugInfoKey:
352 CFDictionarySetValue(debug_info_message_table, peer_info_name, value);
353 break;
354 case kOTRConfig:
355 if(isDictionary(value)){
356 config_message_table = CFRetainSafe((CFMutableDictionaryRef)(value));
357 }
358 break;
359 case kLastCircleKey:
360 case kLastKeyParameterKey:
361 case kUnknownKey:
362 secnotice("updates", "Unknown key '%@', ignoring", key);
363 break;
364 }
365
366 errOut:
367 CFReleaseNull(circle_name);
368 CFReleaseNull(from_name);
369 CFReleaseNull(to_name);
370 CFReleaseNull(ring_name);
371 CFReleaseNull(peer_info_name);
372 CFReleaseNull(backup_name);
373
374 if (error && *error)
375 secerror("Peer message processing error for: %@ -> %@ (%@)", key, value, *error);
376 if (localError)
377 secerror("Peer message local processing error for: %@ -> %@ (%@)", key, value, localError);
378
379 CFReleaseNull(localError);
380 });
381
382
383 if (newParameters) {
384 CFArrayForEach(SOSGetTransportKeyParameters(), ^(const void *value) {
385 CKKeyParameter* tkvs = (__bridge CKKeyParameter*) value;
386 CFErrorRef localError = NULL;
387 if([[tkvs SOSTransportKeyParameterGetAccount:tkvs] isEqual:account]){
388 if(![tkvs SOSTransportKeyParameterHandleKeyParameterChanges:tkvs data:newParameters err:localError])
389 secerror("Transport failed to handle new key parameters: %@", localError);
390 }
391 });
392 CFArrayAppendValue(handledKeys, kSOSKVSKeyParametersKey);
393 }
394 CFReleaseNull(newParameters);
395
396 if(initial_sync){
397 CFArrayAppendValue(handledKeys, kSOSKVSInitialSyncKey);
398 }
399
400 if(CFDictionaryGetCount(config_message_table)){
401 secnotice("otrtimer","got the config table: %@", config_message_table);
402 CFArrayAppendValue(handledKeys, kOTRConfigVersion);
403 }
404
405 if(CFDictionaryGetCount(debug_info_message_table)) {
406 /* check for a newly set circle debug scope */
407 CFTypeRef debugScope = CFDictionaryGetValue(debug_info_message_table, kSOSAccountDebugScope);
408 if (debugScope) {
409 if(isString(debugScope)){
410 ApplyScopeListForID(debugScope, kScopeIDCircle);
411 }else if(isDictionary(debugScope)){
412 ApplyScopeDictionaryForID(debugScope, kScopeIDCircle);
413 }
414 }
415 CFStringRef debugInfoKey = SOSDebugInfoKeyCreateWithTypeName(kSOSAccountDebugScope);
416 CFArrayAppendValue(handledKeys, debugInfoKey);
417 CFReleaseNull(debugInfoKey);
418 }
419
420 if(CFDictionaryGetCount(circle_retirement_messages_table)) {
421 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value) {
422 SOSKVSCircleStorageTransport* tkvs = (__bridge SOSKVSCircleStorageTransport*) value;
423 if([[tkvs getAccount] isEqual:account]){
424 CFErrorRef localError = NULL;
425 CFDictionaryRef handledRetirementKeys = [tkvs handleRetirementMessages:circle_retirement_messages_table err:error];
426 if(handledRetirementKeys == NULL){
427 secerror("Transport failed to handle retirement messages: %@", localError);
428 } else {
429 CFDictionaryForEach(handledRetirementKeys, ^(const void *key, const void *value) {
430 CFStringRef circle_name = (CFStringRef)key;
431 CFArrayRef handledPeerIDs = (CFArrayRef)value;
432 CFArrayForEach(handledPeerIDs, ^(const void *value) {
433 CFStringRef peer_id = (CFStringRef)value;
434 CFStringRef keyHandled = SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name, peer_id);
435 CFArrayAppendValue(handledKeys, keyHandled);
436 CFReleaseNull(keyHandled);
437 });
438 });
439 }
440 CFReleaseNull(handledRetirementKeys);
441 CFReleaseNull(localError);
442 }
443 });
444 }
445 if(CFDictionaryGetCount(circle_peer_messages_table)) {
446 CFArrayForEach(SOSGetTransportMessages(), ^(const void *value) {
447 SOSMessage* tmsg = (__bridge SOSMessage*) value;
448 CFDictionaryRef circleToPeersHandled = NULL;
449 CFErrorRef handleMessagesError = NULL;
450 CFErrorRef flushError = NULL;
451
452 if(!([([tmsg SOSTransportMessageGetAccount]) isEqual:account])){
453 CFReleaseNull(flushError);
454 CFReleaseNull(circleToPeersHandled);
455 CFReleaseNull(handleMessagesError);
456 return;
457 }
458 circleToPeersHandled = [tmsg SOSTransportMessageHandlePeerMessageReturnsHandledCopy:tmsg peerMessages:circle_peer_messages_table err:&handleMessagesError];
459 if(!circleToPeersHandled){
460 secnotice("msg", "No messages handled: %@", handleMessagesError);
461 CFReleaseNull(flushError);
462 CFReleaseNull(circleToPeersHandled);
463 CFReleaseNull(handleMessagesError);
464 return;
465 }
466 CFArrayRef handledPeers = asArray(CFDictionaryGetValue(circleToPeersHandled, [tmsg SOSTransportMessageGetCircleName]), NULL);
467
468 if (handledPeers) {
469 CFArrayForEach(handledPeers, ^(const void *value) {
470 CFStringRef peerID = asString(value, NULL);
471 if (peerID) {
472 CFStringRef kvsHandledKey = SOSMessageKeyCreateFromPeerToTransport(tmsg, (__bridge CFStringRef) account.peerID, peerID);
473 if (kvsHandledKey) {
474 CFArrayAppendValue(handledKeys, kvsHandledKey);
475 }
476 CFReleaseNull(kvsHandledKey);
477 }
478 });
479 }
480
481 if(![tmsg SOSTransportMessageFlushChanges:tmsg err:&flushError])
482 secnotice("msg", "Flush failed: %@", flushError);
483
484 CFReleaseNull(flushError);
485 CFReleaseNull(circleToPeersHandled);
486 CFReleaseNull(handleMessagesError);
487 });
488 }
489 if(CFDictionaryGetCount(circle_circle_messages_table)) {
490 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value) {
491 SOSKVSCircleStorageTransport* tkvs = (__bridge SOSKVSCircleStorageTransport*) value;
492 if([[tkvs getAccount] isEqual: account]){
493 CFArrayRef handleCircleMessages = [tkvs handleCircleMessagesAndReturnHandledCopy:circle_circle_messages_table err:error];
494 CFErrorRef localError = NULL;
495 if(handleCircleMessages == NULL){
496 secerror("Transport failed to handle circle messages: %@", localError);
497 } else if(CFArrayGetCount(handleCircleMessages) == 0) {
498 if(CFDictionaryGetCount(circle_circle_messages_table) != 0) {
499 secerror("Transport failed to process all circle messages: (%ld/%ld) %@",
500 CFArrayGetCount(handleCircleMessages),
501 CFDictionaryGetCount(circle_circle_messages_table), localError);
502 } else {
503 secnotice("circle", "Transport handled no circle messages");
504 }
505 } else {
506 CFArrayForEach(handleCircleMessages, ^(const void *value) {
507 CFStringRef keyHandled = SOSCircleKeyCreateWithName((CFStringRef)value, error);
508 CFArrayAppendValue(handledKeys, keyHandled);
509 CFReleaseNull(keyHandled);
510 });
511 }
512
513 CFReleaseNull(localError);
514 }
515
516 });
517 }
518 if(CFDictionaryGetCount(ring_update_message_table)){
519 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value) {
520 SOSKVSCircleStorageTransport* tkvs = (__bridge SOSKVSCircleStorageTransport*) value;
521 if([[tkvs getAccount] isEqual:account]){
522 CFErrorRef localError = NULL;
523 CFMutableArrayRef handledRingMessages = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
524
525 CFDictionaryForEach(ring_update_message_table, ^(const void *key, const void *value) {
526 CFDataRef ringData = asData(value, NULL);
527 SOSRingRef ring = SOSRingCreateFromData(error, ringData);
528
529 if(SOSAccountUpdateRingFromRemote(account, ring, error)){
530 CFArrayAppendValue(handledRingMessages, key);
531 }
532 CFReleaseNull(ring);
533 });
534 if(CFArrayGetCount(handledRingMessages) == 0){
535 secerror("Transport failed to handle ring messages: %@", localError);
536 } else {
537 CFArrayForEach(handledRingMessages, ^(const void *value) {
538 CFStringRef ring_name = (CFStringRef)value;
539 CFStringRef keyHandled = SOSRingKeyCreateWithRingName(ring_name);
540 CFArrayAppendValue(handledKeys, keyHandled);
541 CFReleaseNull(keyHandled);
542 });
543 }
544 CFReleaseNull(handledRingMessages);
545 CFReleaseNull(localError);
546 }
547 });
548 }
549
550 CFReleaseNull(circle_retirement_messages_table);
551 CFReleaseNull(circle_circle_messages_table);
552 CFReleaseNull(circle_peer_messages_table);
553 CFReleaseNull(debug_info_message_table);
554 CFReleaseNull(ring_update_message_table);
555 CFReleaseNull(debug_info_message_table);
556 CFReleaseNull(config_message_table);
557 showWhatWasHandled(updates, handledKeys);
558
559 return handledKeys;
560 }
561