]> git.saurik.com Git - apple/security.git/blob - keychain/SecureObjectSync/SOSTransport.m
Security-59754.41.1.tar.gz
[apple/security.git] / keychain / SecureObjectSync / SOSTransport.m
1
2 #include "keychain/SecureObjectSync/SOSInternal.h"
3 #include "keychain/SecureObjectSync/SOSKVSKeys.h"
4 #include "keychain/SecureObjectSync/SOSAccountPriv.h"
5 #include "keychain/SecureObjectSync/SOSTransport.h"
6 #include "keychain/SecureObjectSync/SOSTransportKeyParameter.h"
7 #include "keychain/SecureObjectSync/SOSTransportCircleKVS.h"
8 #include "keychain/SecureObjectSync/SOSTransportMessageKVS.h"
9 #include "keychain/SecureObjectSync/SOSTransportMessage.h"
10 #include "keychain/SecureObjectSync/SOSRing.h"
11
12 #include "keychain/SecureObjectSync/CKBridge/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
105
106 void SOSUpdateKeyInterest(SOSAccount* account)
107 {
108 CFMutableArrayRef alwaysKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
109 CFMutableArrayRef afterFirstUnlockKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
110 CFMutableArrayRef whenUnlockedKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
111 CFMutableDictionaryRef keyDict = CFDictionaryCreateMutableForCFTypes (kCFAllocatorDefault);
112
113 NSMutableArray *temp = (__bridge NSMutableArray *)(SOSGetTransportKeyParameters());
114
115 [temp enumerateObjectsUsingBlock:^(CKKeyParameter *value, NSUInteger idx, BOOL * _Nonnull stop) {
116 CKKeyParameter* tKP = (CKKeyParameter*) value;
117 if ([tKP SOSTransportKeyParameterGetAccount:tKP] == account && [tKP SOSTransportKeyParameterGetTransportType:tKP err:NULL] == kKVS) {
118 CKKeyParameter* tkvs = (CKKeyParameter*) value;
119 CFErrorRef localError = NULL;
120
121 if (![tkvs SOSTransportKeyParameterKVSAppendKeyInterests:tkvs ak:alwaysKeys firstUnLock:afterFirstUnlockKeys unlocked:whenUnlockedKeys err:&localError]) {
122 secerror("Error getting key parameters interests %@", localError);
123 }
124 CFReleaseNull(localError);
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 CFReleaseNull(localError);
158 }
159
160 });
161 CFMutableDictionaryRef circleDict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
162 CFDictionarySetValue(circleDict, kAlwaysKeys, alwaysKeys);
163 CFDictionarySetValue(circleDict, kFirstUnlocked, afterFirstUnlockKeys);
164 CFDictionarySetValue(circleDict, kUnlocked, whenUnlockedKeys);
165 CFDictionarySetValue(keyDict, kCircle, circleDict);
166
167 CFReleaseNull(alwaysKeys);
168 CFReleaseNull(afterFirstUnlockKeys);
169 CFReleaseNull(whenUnlockedKeys);
170 alwaysKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
171 afterFirstUnlockKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
172 whenUnlockedKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
173
174 CFArrayForEach(SOSGetTransportMessages(), ^(const void *value) {
175 SOSMessage* transport = (__bridge SOSMessage*)value;
176 if ([transport SOSTransportMessageGetAccount] == account && [transport SOSTransportMessageGetTransportType] == kKVS) {
177 CFErrorRef localError = NULL;
178 SOSMessageKVS* tks = (__bridge SOSMessageKVS*)value;
179 if(![tks SOSTransportMessageKVSAppendKeyInterest:tks ak:alwaysKeys firstUnlock:afterFirstUnlockKeys unlocked:whenUnlockedKeys err:&localError]){
180 secerror("Error getting message interests %@", localError);
181 }
182 CFReleaseNull(localError);
183 }
184 });
185
186 CFMutableDictionaryRef messageDict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
187 CFDictionarySetValue(messageDict, kAlwaysKeys, alwaysKeys);
188 CFDictionarySetValue(messageDict, kFirstUnlocked, afterFirstUnlockKeys);
189 CFDictionarySetValue(messageDict, kUnlocked, whenUnlockedKeys);
190 CFDictionarySetValue(keyDict, kMessage, messageDict);
191
192 //
193 // Log what we are about to do.
194 //
195 NSUInteger itemCount = 0;
196 for (NSString *subsystem in @[(__bridge id)kMessage, (__bridge id)kCircle, (__bridge id)kKeyParameter]) {
197 secnotice("key-interests", "Updating interests: %@", subsystem);
198 for (NSString *lockState in @[(__bridge id)kAlwaysKeys, (__bridge id)kFirstUnlocked, (__bridge id)kUnlocked]) {
199 NSArray *items = ((__bridge NSDictionary *)keyDict)[subsystem][lockState];
200 itemCount += items.count;
201 for (NSString *item in items) {
202 secnotice("key-interests", " key-intrest: %@->%@: %@", subsystem, lockState, item);
203 }
204 }
205 }
206 secnotice("key-interests", "Updating interests done: %lu", (unsigned long)itemCount);
207
208 CFStringRef uuid = SOSAccountCopyUUID(account);
209 SOSCloudKeychainUpdateKeys(keyDict, uuid, dispatch_get_global_queue(SOS_TRANSPORT_PRIORITY, 0), ^(CFDictionaryRef returnedValues, CFErrorRef error) {
210 if (error) {
211 secerror("Error updating keys: %@", error);
212 account.key_interests_need_updating = true;
213 } else {
214 account.key_interests_need_updating = false;
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 CFStringRef circle_name = NULL;
314 CFStringRef ring_name = NULL;
315 CFStringRef peer_info_name = NULL;
316 CFStringRef from_name = NULL;
317 CFStringRef to_name = NULL;
318 CFStringRef backup_name = NULL;
319
320 require_quiet(isString(key), errOut);
321 switch (SOSKVSKeyGetKeyTypeAndParse(key, &circle_name, &peer_info_name, &ring_name, &backup_name, &from_name, &to_name)) {
322 case kCircleKey:
323 CFDictionarySetValue(circle_circle_messages_table, circle_name, value);
324 break;
325 case kInitialSyncKey:
326 initial_sync = true;
327 break;
328 case kParametersKey:
329 if (isData(value)) {
330 newParameters = (CFDataRef) CFRetainSafe(value);
331 }
332 break;
333 case kMessageKey: {
334 CFMutableDictionaryRef circle_messages = CFDictionaryEnsureCFDictionaryAndGetCurrentValue(circle_peer_messages_table, circle_name);
335 CFDictionarySetValue(circle_messages, from_name, value);
336 break;
337 }
338 case kRetirementKey: {
339 CFMutableDictionaryRef circle_retirements = CFDictionaryEnsureCFDictionaryAndGetCurrentValue(circle_retirement_messages_table, circle_name);
340 CFDictionarySetValue(circle_retirements, from_name, value);
341 break;
342 }
343 case kAccountChangedKey:
344 new_account = true;
345 break;
346 case kRingKey:
347 if(isString(ring_name))
348 CFDictionarySetValue(ring_update_message_table, ring_name, value);
349 break;
350 case kDebugInfoKey:
351 CFDictionarySetValue(debug_info_message_table, peer_info_name, value);
352 break;
353 case kLastCircleKey:
354 case kLastKeyParameterKey:
355 case kUnknownKey:
356 secnotice("updates", "Unknown key '%@', ignoring", key);
357 break;
358 }
359
360 errOut:
361 CFReleaseNull(circle_name);
362 CFReleaseNull(from_name);
363 CFReleaseNull(to_name);
364 CFReleaseNull(ring_name);
365 CFReleaseNull(peer_info_name);
366 CFReleaseNull(backup_name);
367
368 if (error && *error)
369 secerror("Peer message processing error for: %@ -> %@ (%@)", key, value, *error);
370 });
371
372
373 if (newParameters) {
374 CFArrayForEach(SOSGetTransportKeyParameters(), ^(const void *value) {
375 CKKeyParameter* tkvs = (__bridge CKKeyParameter*) value;
376 CFErrorRef localError = NULL;
377 if([[tkvs SOSTransportKeyParameterGetAccount:tkvs] isEqual:account]){
378 if(![tkvs SOSTransportKeyParameterHandleKeyParameterChanges:tkvs data:newParameters err:localError])
379 secerror("Transport failed to handle new key parameters: %@", localError);
380 }
381 });
382 CFArrayAppendValue(handledKeys, kSOSKVSKeyParametersKey);
383 }
384 CFReleaseNull(newParameters);
385
386 if(initial_sync){
387 CFArrayAppendValue(handledKeys, kSOSKVSInitialSyncKey);
388 }
389
390 if(CFDictionaryGetCount(debug_info_message_table)) {
391 /* check for a newly set circle debug scope */
392 CFTypeRef debugScope = CFDictionaryGetValue(debug_info_message_table, kSOSAccountDebugScope);
393 if (debugScope) {
394 if(isString(debugScope)){
395 ApplyScopeListForID(debugScope, kScopeIDCircle);
396 }else if(isDictionary(debugScope)){
397 ApplyScopeDictionaryForID(debugScope, kScopeIDCircle);
398 }
399 }
400 CFStringRef debugInfoKey = SOSDebugInfoKeyCreateWithTypeName(kSOSAccountDebugScope);
401 CFArrayAppendValue(handledKeys, debugInfoKey);
402 CFReleaseNull(debugInfoKey);
403 }
404
405 if(CFDictionaryGetCount(circle_retirement_messages_table)) {
406 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value) {
407 SOSKVSCircleStorageTransport* tkvs = (__bridge SOSKVSCircleStorageTransport*) value;
408 if([[tkvs getAccount] isEqual:account]){
409 CFErrorRef localError = NULL;
410 CFDictionaryRef handledRetirementKeys = [tkvs handleRetirementMessages:circle_retirement_messages_table err:error];
411 if(handledRetirementKeys == NULL){
412 secerror("Transport failed to handle retirement messages: %@", localError);
413 } else {
414 CFDictionaryForEach(handledRetirementKeys, ^(const void *key, const void *value) {
415 CFStringRef circle_name = (CFStringRef)key;
416 CFArrayRef handledPeerIDs = (CFArrayRef)value;
417 CFArrayForEach(handledPeerIDs, ^(const void *value) {
418 CFStringRef peer_id = (CFStringRef)value;
419 CFStringRef keyHandled = SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name, peer_id);
420 CFArrayAppendValue(handledKeys, keyHandled);
421 CFReleaseNull(keyHandled);
422 });
423 });
424 }
425 CFReleaseNull(handledRetirementKeys);
426 CFReleaseNull(localError);
427 }
428 });
429 }
430 if(CFDictionaryGetCount(circle_peer_messages_table)) {
431 CFArrayForEach(SOSGetTransportMessages(), ^(const void *value) {
432 SOSMessage* tmsg = (__bridge SOSMessage*) value;
433 CFDictionaryRef circleToPeersHandled = NULL;
434 CFErrorRef handleMessagesError = NULL;
435 CFErrorRef flushError = NULL;
436
437 if(!([([tmsg SOSTransportMessageGetAccount]) isEqual:account])){
438 CFReleaseNull(flushError);
439 CFReleaseNull(circleToPeersHandled);
440 CFReleaseNull(handleMessagesError);
441 return;
442 }
443 circleToPeersHandled = [tmsg SOSTransportMessageHandlePeerMessageReturnsHandledCopy:tmsg peerMessages:circle_peer_messages_table err:&handleMessagesError];
444 if(!circleToPeersHandled){
445 secnotice("msg", "No messages handled: %@", handleMessagesError);
446 CFReleaseNull(flushError);
447 CFReleaseNull(circleToPeersHandled);
448 CFReleaseNull(handleMessagesError);
449 return;
450 }
451 CFArrayRef handledPeers = asArray(CFDictionaryGetValue(circleToPeersHandled, [tmsg SOSTransportMessageGetCircleName]), NULL);
452
453 if (handledPeers) {
454 CFArrayForEach(handledPeers, ^(const void *value) {
455 CFStringRef peerID = asString(value, NULL);
456 if (peerID) {
457 CFStringRef kvsHandledKey = SOSMessageKeyCreateFromPeerToTransport(tmsg, (__bridge CFStringRef) account.peerID, peerID);
458 if (kvsHandledKey) {
459 CFArrayAppendValue(handledKeys, kvsHandledKey);
460 }
461 CFReleaseNull(kvsHandledKey);
462 }
463 });
464 }
465
466 if(![tmsg SOSTransportMessageFlushChanges:tmsg err:&flushError])
467 secnotice("msg", "Flush failed: %@", flushError);
468
469 CFReleaseNull(flushError);
470 CFReleaseNull(circleToPeersHandled);
471 CFReleaseNull(handleMessagesError);
472 });
473 }
474 if(CFDictionaryGetCount(circle_circle_messages_table)) {
475 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value) {
476 SOSKVSCircleStorageTransport* tkvs = (__bridge SOSKVSCircleStorageTransport*) value;
477 if([[tkvs getAccount] isEqual: account]){
478 CFArrayRef handleCircleMessages = [tkvs handleCircleMessagesAndReturnHandledCopy:circle_circle_messages_table err:error];
479 CFErrorRef localError = NULL;
480 if(handleCircleMessages == NULL){
481 secerror("Transport failed to handle circle messages: %@", localError);
482 } else if(CFArrayGetCount(handleCircleMessages) == 0) {
483 if(CFDictionaryGetCount(circle_circle_messages_table) != 0) {
484 secerror("Transport failed to process all circle messages: (%ld/%ld) %@",
485 CFArrayGetCount(handleCircleMessages),
486 CFDictionaryGetCount(circle_circle_messages_table), localError);
487 } else {
488 secnotice("circle", "Transport handled no circle messages");
489 }
490 } else {
491 CFArrayForEach(handleCircleMessages, ^(const void *value) {
492 CFStringRef keyHandled = SOSCircleKeyCreateWithName((CFStringRef)value, error);
493 CFArrayAppendValue(handledKeys, keyHandled);
494 CFReleaseNull(keyHandled);
495 });
496 }
497
498 CFReleaseNull(handleCircleMessages);
499 CFReleaseNull(localError);
500 }
501
502 });
503 }
504 if(CFDictionaryGetCount(ring_update_message_table)){
505 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value) {
506 SOSKVSCircleStorageTransport* tkvs = (__bridge SOSKVSCircleStorageTransport*) value;
507 if([[tkvs getAccount] isEqual:account]){
508 CFErrorRef localError = NULL;
509 CFMutableArrayRef handledRingMessages = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
510
511 CFDictionaryForEach(ring_update_message_table, ^(const void *key, const void *value) {
512 CFDataRef ringData = asData(value, NULL);
513 SOSRingRef ring = SOSRingCreateFromData(error, ringData);
514
515 if(SOSAccountUpdateRingFromRemote(account, ring, error)){
516 CFArrayAppendValue(handledRingMessages, key);
517 }
518 CFReleaseNull(ring);
519 });
520 if(CFArrayGetCount(handledRingMessages) == 0){
521 secerror("Transport failed to handle ring messages: %@", localError);
522 } else {
523 CFArrayForEach(handledRingMessages, ^(const void *value) {
524 CFStringRef ring_name = (CFStringRef)value;
525 CFStringRef keyHandled = SOSRingKeyCreateWithRingName(ring_name);
526 CFArrayAppendValue(handledKeys, keyHandled);
527 CFReleaseNull(keyHandled);
528 });
529 }
530 CFReleaseNull(handledRingMessages);
531 CFReleaseNull(localError);
532 }
533 });
534 }
535
536 CFReleaseNull(circle_retirement_messages_table);
537 CFReleaseNull(circle_circle_messages_table);
538 CFReleaseNull(circle_peer_messages_table);
539 CFReleaseNull(debug_info_message_table);
540 CFReleaseNull(ring_update_message_table);
541 CFReleaseNull(debug_info_message_table);
542 CFReleaseNull(config_message_table);
543 showWhatWasHandled(updates, handledKeys);
544
545 return handledKeys;
546 }
547