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