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