SOSAccountTrustClassic+Expansion.m
1 // 2 // SOSAccountTrustClassicExpansion.m 3 // Security 4 // 5 6 7 #import <Foundation/Foundation.h> 8 #import "keychain/SecureObjectSync/SOSAccount.h" 9 #import "keychain/SecureObjectSync/SOSAccountTrustClassic.h" 10 #import "keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.h" 11 #import "keychain/SecureObjectSync/SOSAccountTrustClassic+Retirement.h" 12 #import "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" 13 #import "keychain/SecureObjectSync/SOSViews.h" 14 #import "keychain/SecureObjectSync/SOSPeerInfoV2.h" 15 #import "keychain/SecureObjectSync/SOSPeerInfoCollections.h" 16 #import "keychain/SecureObjectSync/SOSTransportCircleKVS.h" 17 #import "keychain/SecureObjectSync/SOSRingRecovery.h" 18 19 @implementation SOSAccountTrustClassic (Expansion) 20 typedef enum { 21 accept, 22 countersign, 23 leave, 24 revert, 25 modify, 26 ignore 27 } ringAction_t; 28 29 static const char *actionstring[] = { 30 "accept", "countersign", "leave", "revert", "modify", "ignore", 31 }; 32 static NSString* kSOSRingKey = @"trusted_rings"; 33 34 // 35 // Generic Calls to Expansion Dictionary 36 // 37 -(CFTypeRef) getValueFromExpansion:(CFStringRef)key err:(CFErrorRef*)error 38 { 39 if (!self.expansion) { 40 return NULL; 41 } 42 return (__bridge CFTypeRef)([self.expansion objectForKey:(__bridge NSString*)key]); 43 } 44 45 -(bool) ensureExpansion:(CFErrorRef *)error 46 { 47 if (!self.expansion) { 48 self.expansion = [NSMutableDictionary dictionary]; 49 } 50 51 return SecAllocationError((__bridge CFTypeRef)(self.expansion), error, CFSTR("Can't Alloc Account Expansion dictionary")); 52 } 53 54 -(bool) clearValueFromExpansion:(CFStringRef) key err:(CFErrorRef *)error 55 { 56 bool success = [self ensureExpansion:error]; 57 58 require_quiet(success, errOut); 59 60 [self.expansion removeObjectForKey: (__bridge NSString*)(key)]; 61 errOut: 62 return success; 63 } 64 65 -(bool) setValueInExpansion:(CFStringRef) key value:(CFTypeRef) value err:(CFErrorRef *)error { 66 if (value == NULL) return [self clearValueFromExpansion:key err:error]; 67 68 bool success = [self ensureExpansion:error]; 69 require_quiet(success, errOut); 70 71 [self.expansion setObject:(__bridge id _Nonnull)(value) forKey:(__bridge NSString*)key]; 72 73 errOut: 74 return success; 75 } 76 77 -(bool) valueSetContainsValue:(CFStringRef) key value:(CFTypeRef) value 78 { 79 CFSetRef foundSet = asSet([self getValueFromExpansion:key err:NULL], NULL); 80 return foundSet && CFSetContainsValue(foundSet, value); 81 } 82 83 -(void) valueUnionWith:(CFStringRef) key valuesToUnion:(CFSetRef) valuesToUnion 84 { 85 CFMutableSetRef unionedSet = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, valuesToUnion); 86 CFSetRef foundSet = asSet([self getValueFromExpansion:key err:NULL], NULL); 87 if (foundSet) { 88 CFSetUnion(unionedSet, foundSet); 89 } 90 [self setValueInExpansion:key value:unionedSet err:NULL]; 91 CFReleaseNull(unionedSet); 92 } 93 94 -(void) valueSubtractFrom:(CFStringRef) key valuesToSubtract:(CFSetRef) valuesToSubtract 95 { 96 CFSetRef foundSet = asSet([self getValueFromExpansion:key err:NULL], NULL); 97 if (foundSet) { 98 CFMutableSetRef subtractedSet = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, foundSet); 99 CFSetSubtract(subtractedSet, valuesToSubtract); 100 [self setValueInExpansion:key value:subtractedSet err:NULL]; 101 CFReleaseNull(subtractedSet); 102 } 103 } 104 105 //Views 106 -(void) pendEnableViewSet:(CFSetRef) enabledViews 107 { 108 if(CFSetGetValue(enabledViews, kSOSViewKeychainV0) != NULL) secnotice("viewChange", "Warning, attempting to Add KeychainV0"); 109 110 [self valueUnionWith:kSOSPendingEnableViewsToBeSetKey valuesToUnion:enabledViews]; 111 [self valueSubtractFrom:kSOSPendingDisableViewsToBeSetKey valuesToSubtract:enabledViews]; 112 } 113 114 // V2 Dictionary 115 -(bool) updateV2Dictionary:(SOSAccount*)account v2:(CFDictionaryRef) newV2Dict 116 { 117 if(!newV2Dict) return true; 118 119 [self setValueInExpansion:kSOSTestV2Settings value:newV2Dict err:NULL]; 120 121 if (self.trustedCircle && self.fullPeerInfo 122 && SOSFullPeerInfoUpdateV2Dictionary(self.fullPeerInfo, newV2Dict, NULL)) { 123 [self modifyCircle:account.circle_transport err:NULL action:^(SOSCircleRef circle_to_change) { 124 secnotice("circleChange", "Calling SOSCircleUpdatePeerInfo for gestalt change"); 125 return SOSCircleUpdatePeerInfo(circle_to_change, account.peerInfo); 126 }]; 127 } 128 return true; 129 } 130 131 // 132 // Rings 133 // 134 135 -(bool) forEachRing:(RingNameBlock)block 136 { 137 bool retval = false; 138 __block bool changed = false; 139 __block CFStringRef ringname = NULL; 140 __block CFDataRef ringder = NULL; 141 __block SOSRingRef ring = NULL; 142 __block SOSRingRef newring = NULL; 143 __block CFDataRef newringder = NULL; 144 145 CFMutableDictionaryRef rings = [self getRings:NULL]; 146 CFMutableDictionaryRef ringscopy = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); 147 if(!rings){ 148 CFReleaseNull(ringscopy); 149 return retval; 150 } 151 if(!ringscopy){ 152 CFReleaseNull(ringscopy); 153 return retval; 154 } 155 CFDictionaryForEach(rings, ^(const void *key, const void *value) { 156 ringname = (CFStringRef) key; 157 ringder = CFDataCreateCopy(kCFAllocatorDefault, (CFDataRef) value); 158 CFDictionaryAddValue(ringscopy, key, ringder); 159 ring = SOSRingCreateFromData(NULL, ringder); 160 newring = block(ringname, ring); 161 if(newring) { 162 newringder = SOSRingCopyEncodedData(newring, NULL); 163 CFDictionaryReplaceValue(ringscopy, key, newringder); 164 CFReleaseNull(newringder); 165 changed = true; 166 } 167 CFReleaseNull(ring); 168 CFReleaseNull(ringder); 169 CFReleaseNull(newring); 170 }); 171 if(changed) { 172 [self setRings:ringscopy]; 173 } 174 retval = true; 175 176 CFReleaseNull(ringscopy); 177 return retval; 178 } 179 180 -(bool) resetAllRings:(SOSAccount*)account err:(CFErrorRef *)error 181 { 182 __block bool retval = true; 183 CFMutableSetRef ringList = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); 184 if(!ringList){ 185 CFReleaseNull(ringList); 186 return retval; 187 } 188 189 [self forEachRing: ^SOSRingRef(CFStringRef name, SOSRingRef ring) { 190 CFSetAddValue(ringList, name); 191 return NULL; // just using this to grab names. 192 }]; 193 194 CFSetForEach(ringList, ^(const void *value) { 195 CFStringRef ringName = (CFStringRef) value; 196 retval = retval && [self resetRing:account ringName:ringName err:error]; 197 }); 198 199 CFReleaseNull(ringList); 200 return retval; 201 } 202 203 -(bool) resetAccountToEmpty:(SOSAccount*)account transport: (SOSCircleStorageTransport*)circleTransport err:(CFErrorRef*) error 204 { 205 __block bool result = true; 206 CFErrorRef resetError = NULL; 207 208 result &= [self resetAllRings:account err:&resetError]; 209 if(resetError){ 210 secerror("reset all rings error: %@", resetError); 211 if(error){ 212 *error = resetError; 213 }else{ 214 CFReleaseNull(resetError); 215 } 216 } 217 218 self.fullPeerInfo = nil; 219 220 self.departureCode = kSOSWithdrewMembership; 221 secnotice("circleOps", "Reset Rings to empty by client request"); 222 223 result &= [self modifyCircle:circleTransport err:error action:^bool(SOSCircleRef circle) { 224 result = SOSCircleResetToEmpty(circle, error); 225 return result; 226 }]; 227 228 if (!result) { 229 secerror("error: %@", error ? *error : NULL); 230 } else { 231 notify_post(kSOSCCCircleOctagonKeysChangedNotification); 232 } 233 return result; 234 } 235 236 -(void) setRings:(CFMutableDictionaryRef) newrings 237 { 238 [self.expansion setObject:(__bridge NSMutableDictionary*)newrings forKey:(kSOSRingKey)]; 239 } 240 241 -(bool) checkForRings:(CFErrorRef*)error 242 { 243 __block bool retval = true; 244 CFMutableDictionaryRef rings = [self getRings:NULL]; 245 if(rings && isDictionary(rings)) { 246 [self forEachRing:^SOSRingRef(CFStringRef ringname, SOSRingRef ring) { 247 if(retval == true) { 248 if(!SOSRingIsStable(ring)) { 249 retval = false; 250 secnotice("ring", "Ring %@ not stable", ringname); 251 } 252 } 253 return NULL; 254 }]; 255 } else { 256 SOSCreateError(kSOSErrorNotReady, CFSTR("Rings not present"), NULL, error); 257 retval = false; 258 } 259 return retval; 260 } 261 262 -(bool) setRing:(SOSRingRef) addRing ringName:(CFStringRef) ringName err:(CFErrorRef*)error 263 { 264 require_quiet(addRing, errOut); 265 CFMutableDictionaryRef rings = [self getRings:NULL]; 266 require_action_quiet(rings, errOut, SOSCreateError(kSOSErrorNoRing, CFSTR("No Rings found"), NULL, error)); 267 CFDataRef ringder = SOSRingCopyEncodedData(addRing, error); 268 require_quiet(ringder, errOut); 269 CFDictionarySetValue(rings, ringName, ringder); 270 CFReleaseNull(ringder); 271 return true; 272 errOut: 273 return false; 274 } 275 276 -(bool) handleUpdateRing:(SOSAccount*)account prospectiveRing:(SOSRingRef)prospectiveRing transport:(SOSKVSCircleStorageTransport*)circleTransport userPublicKey:(SecKeyRef)userPublic writeUpdate:(bool)localUpdate err:(CFErrorRef *)error 277 { 278 bool success = false; 279 bool haveOldRing = true; 280 static uint recRingProcessed = 0; 281 static uint bckRingProcessed = 0; 282 283 const char * __unused localRemote = localUpdate ? "local": "remote"; 284 SOSFullPeerInfoRef fpi = self.fullPeerInfo; 285 SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(fpi); 286 CFStringRef peerID = SOSPeerInfoGetPeerID(pi); 287 SecKeyRef peerPrivKey = SOSFullPeerInfoCopyDeviceKey(fpi, NULL); 288 SecKeyRef peerPubKey = SOSFullPeerInfoCopyPubKey(fpi, NULL); 289 __block bool peerActive = (fpi && pi && peerID && [self isInCircleOnly:NULL]); 290 bool ringIsBackup = SOSRingGetType(prospectiveRing) == kSOSRingBackup; 291 bool ringIsRecovery = SOSRingGetType(prospectiveRing) == kSOSRingRecovery; 292 CFStringRef ringName = SOSRingGetName(prospectiveRing); 293 CFMutableSetRef peers = SOSCircleCopyPeers(self.trustedCircle, kCFAllocatorDefault); // retirement tickets and iCloud key filtered out 294 CFMutableSetRef filteredPeerIDs = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); 295 CFMutableSetRef filteredPeerInfos = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault); 296 CFStringRef ringBackupViewName = NULL; 297 298 SOSRingRef ringToPush = NULL; 299 SOSRingRef newRing = NULL; 300 SOSRingRef oldRing = NULL; 301 302 CFStringRef modifierPeerID = CFStringCreateTruncatedCopy(SOSRingGetLastModifier(prospectiveRing), 8); 303 secnotice("ring", "start:[%s] modifier: %@", localRemote, modifierPeerID); 304 CFReleaseNull(modifierPeerID); 305 306 // don't act on our own echos from KVS (remote ring, our peerID as modifier) 307 oldRing = [self copyRing:ringName err:NULL]; 308 if(!localUpdate && CFEqualSafe(peerID, SOSRingGetLastModifier(prospectiveRing)) && CFEqualSafe(oldRing, prospectiveRing)) { 309 secnotice("ring", "Ceasing ring handling for an echo of our own posted ring"); 310 success = true; 311 goto errOut; 312 } 313 314 require_quiet(SOSAccountHasPublicKey(account, error), errOut); 315 require_action_quiet(peerPubKey, errOut, SOSCreateError(kSOSErrorPublicKeyAbsent, CFSTR("No device public key to work with"), NULL, error)); 316 require_action_quiet(peerPrivKey, errOut, SOSCreateError(kSOSErrorPrivateKeyAbsent, CFSTR("No device private key to work with"), NULL, error)); 317 require_action_quiet(prospectiveRing, errOut, SOSCreateError(kSOSErrorIncompatibleCircle, CFSTR("No Ring to work with"), NULL, error)); 318 require_action_quiet(SOSRingIsStable(prospectiveRing), errOut, SOSCreateError(kSOSErrorIncompatibleCircle, CFSTR("You give rings a bad name"), NULL, error)); 319 320 // We should at least have a sane ring system in the account object 321 require_quiet([self checkForRings:error], errOut); 322 323 if(ringIsBackup) { 324 ringBackupViewName = SOSRingGetBackupView(prospectiveRing, NULL); 325 peerActive &= ringBackupViewName && SOSPeerInfoIsViewPermitted(pi, ringBackupViewName) && SOSPeerInfoHasBackupKey(pi); 326 } 327 require_action_quiet(peerActive, errOut, success = true); 328 329 newRing = SOSRingCopyRing(prospectiveRing, NULL); 330 ringAction_t ringAction = ignore; 331 332 bool userTrustedoldRing = (oldRing) ? SOSRingVerify(oldRing, peerPubKey, NULL): false; 333 SecKeyRef oldKey = userPublic; 334 335 if (!oldRing) { 336 oldRing = CFRetainSafe(newRing); 337 } 338 339 SOSConcordanceStatus concstat = SOSRingConcordanceTrust(fpi, peers, oldRing, newRing, oldKey, userPublic, peerID, error); 340 341 CFStringRef concStr = CFSTR("NA"); 342 switch(concstat) { 343 case kSOSConcordanceTrusted: 344 ringAction = countersign; 345 concStr = CFSTR("Trusted"); 346 break; 347 case kSOSConcordanceGenOld: 348 ringAction = userTrustedoldRing ? revert : ignore; 349 concStr = CFSTR("Generation Old"); 350 break; 351 case kSOSConcordanceBadUserSig: 352 case kSOSConcordanceBadPeerSig: 353 ringAction = userTrustedoldRing ? revert : accept; 354 concStr = CFSTR("Bad Signature"); 355 break; 356 case kSOSConcordanceNoUserSig: 357 ringAction = userTrustedoldRing ? revert : accept; 358 concStr = CFSTR("No User Signature"); 359 break; 360 case kSOSConcordanceNoPeerSig: 361 ringAction = accept; // We might like this one eventually but don't countersign. 362 concStr = CFSTR("No trusted peer signature"); 363 secnotice("signing", "##### No trusted peer signature found, accepting hoping for concordance later"); 364 break; 365 case kSOSConcordanceNoPeer: 366 ringAction = leave; 367 concStr = CFSTR("No trusted peer left"); 368 break; 369 case kSOSConcordanceNoUserKey: 370 secerror("##### No User Public Key Available, this shouldn't ever happen!!!"); 371 concStr = CFSTR("No User Public Key Available"); 372 ringAction = ignore; 373 break; 374 375 case kSOSConcordanceMissingMe: 376 ringAction = modify; 377 concStr = CFSTR("Incorrect membership for me"); 378 break; 379 case kSOSConcordanceImNotWorthy: 380 ringAction = leave; 381 concStr = CFSTR("This peer shouldn't be in this ring since it isn't in view"); 382 break; 383 case kSOSConcordanceInvalidMembership: 384 ringAction = userTrustedoldRing ? revert : ignore; 385 concStr = CFSTR("Invalid Ring Membership"); 386 break; 387 default: 388 secerror("##### Bad Error Return from ConcordanceTrust"); 389 concStr = CFSTR("Bad Error Return from ConcordanceTrust"); 390 ringAction = ignore; 391 break; 392 } 393 394 secnotice("ring", "Decided on action [%s] based on concordance state [%@] and [%s] ring.", 395 actionstring[ringAction], concStr, userTrustedoldRing ? "trusted" : "untrusted"); 396 397 // if we're ignoring this ring we're done 398 require_action_quiet(ringAction != ignore, errOut, success = true); 399 // can't really remove ourselves since we can't sign when we do - need to rely on other peers to remove us 400 require_action_quiet(ringAction != leave, leaveAndAccept, ringAction = accept); 401 402 // This will take care of modify, but we're always going to do this scan if we get this far 403 CFSetRef ringPeerIDSet = SOSRingCopyPeerIDs(newRing); 404 if(CFSetGetCount(ringPeerIDSet) == 0) { // this is a reset ring 405 secnotice("ring", "changing state to accept - we have a reset ring"); 406 ringAction = accept; 407 } else { 408 // Get the peerIDs appropriate for the ring 409 if(ringIsBackup) { 410 SOSCircleForEachBackupCapablePeerForView(self.trustedCircle, userPublic, ringBackupViewName, ^(SOSPeerInfoRef peer) { 411 CFSetAddValue(filteredPeerIDs, SOSPeerInfoGetPeerID(peer)); 412 CFSetAddValue(filteredPeerInfos, peer); 413 }); 414 } else { 415 SOSCircleForEachValidSyncingPeer(self.trustedCircle, userPublic, ^(SOSPeerInfoRef peer) { 416 CFSetAddValue(filteredPeerIDs, SOSPeerInfoGetPeerID(peer)); 417 CFSetAddValue(filteredPeerInfos, peer); 418 }); 419 } 420 421 if(!CFEqual(filteredPeerIDs, ringPeerIDSet)) { 422 secnotice("ring", "mismatch between filteredPeerIDs and ringPeerIDSet, fixing ring and gensigning"); 423 secnotice("ring", "filteredPeerIDs %@", filteredPeerIDs); 424 secnotice("ring", " ringPeerIDSet %@", ringPeerIDSet); 425 SOSRingSetPeerIDs(newRing, filteredPeerIDs); 426 SOSRingRemoveSignatures(newRing, NULL); 427 ringAction = countersign; 428 } 429 } 430 CFReleaseNull(ringPeerIDSet); 431 432 if (ringAction == countersign) { 433 bool stopCountersign = false; 434 CFIndex peerCount = CFSetGetCount(filteredPeerIDs); 435 436 if(peerCount > 0) { 437 // Fix payloads if necessary 438 if (ringIsBackup && SOSPeerInfoHasBackupKey(pi)) { 439 __block bool fixBSKB = false; 440 CFDataRef recoveryKeyData = SOSAccountCopyRecoveryPublic(kCFAllocatorDefault, account, NULL); 441 SOSBackupSliceKeyBagRef currentBSKB = SOSRingCopyBackupSliceKeyBag(newRing, NULL); 442 443 if(currentBSKB == NULL) { 444 secnotice("ring", "Backup ring contains no BSKB"); 445 fixBSKB = true; 446 } 447 448 if(SOSBSKBAllPeersBackupKeysAreInKeyBag(currentBSKB, filteredPeerInfos) == false) { 449 secnotice("ring", "BSKB is missing some backup keys"); 450 fixBSKB = true; 451 } 452 453 if(SOSBSKBHasThisRecoveryKey(currentBSKB, recoveryKeyData) == false) { 454 secnotice("ring", "BSKB is missing recovery key"); 455 fixBSKB = true; 456 } 457 458 if(fixBSKB) { 459 CFErrorRef localError = NULL; 460 CFSetRef viewSet = SOSRingGetBackupViewset(newRing, NULL); 461 secnotice("ring", "Need to fix BSKB - this will prompt a gensign"); 462 463 SOSBackupSliceKeyBagRef bskb = NULL; 464 if(recoveryKeyData) { 465 CFMutableDictionaryRef additionalKeys = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); 466 CFDictionaryAddValue(additionalKeys, bskbRkbgPrefix, recoveryKeyData); 467 bskb = SOSBackupSliceKeyBagCreateWithAdditionalKeys(kCFAllocatorDefault, filteredPeerInfos, additionalKeys, error); 468 CFReleaseNull(additionalKeys); 469 } else { 470 bskb = SOSBackupSliceKeyBagCreate(kCFAllocatorDefault, filteredPeerInfos, error); 471 } 472 473 if(SOSRingSetBackupKeyBag(newRing, fpi, viewSet, bskb, &localError) == false) { 474 stopCountersign = true; 475 secnotice("ring", "Couldn't fix BSKB (%@)", localError); 476 } 477 SOSRingRemoveSignatures(newRing, NULL); 478 SOSRingGenerationSign(newRing, NULL, fpi, error); 479 ringToPush = newRing; 480 CFReleaseNull(localError); 481 CFReleaseNull(bskb); 482 } 483 CFReleaseNull(recoveryKeyData); 484 CFReleaseNull(currentBSKB); 485 } 486 } 487 488 if(stopCountersign) { 489 ringAction = ignore; 490 } else if (SOSRingPeerTrusted(newRing, fpi, NULL)) { 491 secnotice("ring", "Already concur with newRing"); 492 ringAction = accept; 493 } else { 494 CFErrorRef signingError = NULL; 495 if (fpi && SOSRingConcordanceSign(newRing, fpi, &signingError)) { 496 secnotice("ring", "concordance signed"); 497 ringToPush = newRing; 498 ringAction = accept; 499 } else { 500 secnotice("ring", "Failed to concordance sign, error: %@", signingError); 501 success = false; 502 ringAction = ignore; 503 } 504 CFReleaseSafe(signingError); 505 } 506 } 507 508 leaveAndAccept: 509 510 if (ringAction == accept) { 511 if(ringIsRecovery) { 512 if(!localUpdate) { // processing a remote ring - we accept the new recovery key here 513 if(SOSRingIsEmpty_Internal(newRing)) { // Reset ring will reset the recovery key 514 secnotice("ring", "Reset ring for recovery from remote peer"); 515 SOSRecoveryKeyBagRef ringRKBG = SOSRecoveryKeyBagCreateForAccount(kCFAllocatorDefault, (__bridge CFTypeRef)account, SOSRKNullKey(), error); 516 SOSAccountSetRecoveryKeyBagEntry(kCFAllocatorDefault, account, ringRKBG, error); 517 CFReleaseNull(ringRKBG); 518 } else { // normal ring recovery key harvest 519 secnotice("ring", "normal ring recovery key harvest"); 520 SOSRecoveryKeyBagRef ringRKBG = SOSRingCopyRecoveryKeyBag(newRing, NULL); 521 SOSAccountSetRecoveryKeyBagEntry(kCFAllocatorDefault, account, ringRKBG, error); 522 CFReleaseNull(ringRKBG); 523 } 524 } 525 } 526 if (pi && SOSRingHasRejection(newRing, peerID)) { 527 SOSRingRemoveRejection(newRing, peerID); 528 } 529 [self setRing:newRing ringName:ringName err:error]; 530 account.circle_rings_retirements_need_attention = true; 531 if (localUpdate) { 532 ringToPush = newRing; 533 } else if (ringToPush == NULL) { 534 success = true; 535 } 536 } 537 538 /* 539 * In the revert section we'll guard the KVS idea of circles by rejecting "bad" new rings 540 * and pushing our current view of the ring (oldRing). We'll only do this if we actually 541 * are a member of oldRing - never for an empty ring. 542 */ 543 544 if (ringAction == revert) { 545 if(haveOldRing && SOSRingHasPeerID(oldRing, peerID)) { 546 secnotice("ring", "Rejecting: %@", newRing); 547 secnotice("ring", " RePush: %@", oldRing); 548 ringToPush = oldRing; 549 } else { 550 secnotice("ring", "Rejecting: %@", newRing); 551 secnotice("ring", "Have no old ring - would reset"); 552 } 553 } 554 555 if (ringToPush != NULL) { 556 if(ringIsBackup) { 557 bckRingProcessed++; 558 } else if(ringIsRecovery) { 559 recRingProcessed++; 560 } 561 secnotice("ring", "Pushing:[%s] %@", localRemote, ringToPush); 562 CFDataRef ringData = SOSRingCopyEncodedData(ringToPush, error); 563 if (ringData) { 564 success = [circleTransport kvsRingPostRing:SOSRingGetName(ringToPush) ring:ringData err:error]; 565 } else { 566 success = false; 567 } 568 secnotice("ring", "Setting account.key_interests_need_updating to true in handleUpdateRing"); 569 account.key_interests_need_updating = true; 570 CFReleaseNull(ringData); 571 } 572 errOut: 573 CFReleaseNull(filteredPeerIDs); 574 CFReleaseNull(filteredPeerInfos); 575 CFReleaseNull(oldRing); 576 CFReleaseNull(newRing); 577 CFReleaseNull(peers); 578 CFReleaseNull(peerPubKey); 579 CFReleaseNull(peerPrivKey); 580 return success; 581 } 582 583 -(SOSRingRef) copyRing:(CFStringRef)ringName err:(CFErrorRef *)error 584 { 585 CFMutableDictionaryRef rings = [self getRings:error]; 586 require_action_quiet(rings, errOut, SOSCreateError(kSOSErrorNoRing, CFSTR("No Rings found"), NULL, error)); 587 CFTypeRef ringder = CFDictionaryGetValue(rings, ringName); 588 require_action_quiet(ringder, errOut, SOSCreateErrorWithFormat(kSOSErrorNoRing, NULL, error, NULL, CFSTR("No Ring found %@"), ringName)); 589 SOSRingRef ring = SOSRingCreateFromData(NULL, ringder); 590 return (SOSRingRef) ring; 591 592 errOut: 593 return NULL; 594 } 595 596 -(CFMutableDictionaryRef) getRings:(CFErrorRef *)error 597 { 598 CFMutableDictionaryRef rings = (__bridge CFMutableDictionaryRef) [self.expansion objectForKey:kSOSRingKey]; 599 if(!rings) { 600 [self addRingDictionary]; 601 rings = [self getRings:error]; 602 } 603 604 return rings; 605 } 606 607 -(bool) resetRing:(SOSAccount*)account ringName:(CFStringRef) ringName err:(CFErrorRef *)error 608 { 609 bool retval = false; 610 611 SOSRingRef ring = [self copyRing:ringName err:error]; 612 SOSRingRef newring = SOSRingCreate(ringName, NULL, SOSRingGetType(ring), error); 613 SOSRingGenerationCreateWithBaseline(newring, ring); 614 SOSBackupRingSetViews(newring, self.fullPeerInfo, SOSBackupRingGetViews(ring, NULL), error); 615 require_quiet(newring, errOut); 616 CFReleaseNull(ring); 617 retval = SOSAccountUpdateRing(account, newring, error); 618 errOut: 619 CFReleaseNull(ring); 620 CFReleaseNull(newring); 621 return retval; 622 } 623 624 625 @end