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