6 #include "SOSAccount.h"
7 #include "SOSCloudKeychainClient.h"
9 #include <Security/SecureObjectSync/SOSBackupSliceKeyBag.h>
11 #include "keychain/SecureObjectSync/SOSPeerInfoCollections.h"
12 #include "keychain/SecureObjectSync/SOSPeerInfoV2.h"
13 #include <Security/SecureObjectSync/SOSViews.h>
14 #include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h"
15 #include "keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.h"
17 #include "keychain/SecureObjectSync/SOSInternal.h"
22 // MARK: V0 Keybag keychain stuff
24 static bool SecItemUpdateOrAdd(CFDictionaryRef query, CFDictionaryRef update, CFErrorRef *error)
26 OSStatus saveStatus = SecItemUpdate(query, update);
28 if (errSecItemNotFound == saveStatus) {
29 CFMutableDictionaryRef add = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, query);
30 CFDictionaryForEach(update, ^(const void *key, const void *value) {
31 CFDictionaryAddValue(add, key, value);
33 saveStatus = SecItemAdd(add, NULL);
37 return SecError(saveStatus, error, CFSTR("Error saving %@"), query);
40 static CFDictionaryRef SOSCopyV0Attributes() {
41 return CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
42 kSecClass, kSecClassGenericPassword,
43 kSecAttrAccessGroup, CFSTR("com.apple.sbd"),
44 kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked,
45 kSecAttrAccount, CFSTR("SecureBackupPublicKeybag"),
46 kSecAttrService, CFSTR("SecureBackupService"),
47 kSecAttrSynchronizable, kCFBooleanTrue,
51 bool SOSDeleteV0Keybag(CFErrorRef *error) {
52 CFDictionaryRef attributes = SOSCopyV0Attributes();
54 OSStatus result = SecItemDelete(attributes);
56 CFReleaseNull(attributes);
58 return SecError(result != errSecItemNotFound ? result : errSecSuccess, error, CFSTR("Deleting V0 Keybag failed - %d"), (int)result);
61 static bool SOSSaveV0Keybag(CFDataRef v0Keybag, CFErrorRef *error) {
62 CFDictionaryRef attributes = SOSCopyV0Attributes();
64 CFDictionaryRef update = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
65 kSecValueData, v0Keybag,
69 bool result = SecItemUpdateOrAdd(attributes, update, error);
70 CFReleaseNull(attributes);
71 CFReleaseNull(update);
77 static bool SOSPeerInfoIsViewBackupEnabled(SOSPeerInfoRef peerInfo, CFStringRef viewName) {
78 if (CFEqualSafe(kSOSViewKeychainV0, viewName))
81 return SOSPeerInfoHasBackupKey(peerInfo) && SOSPeerInfoIsViewPermitted(peerInfo, viewName);
84 static CFSetRef SOSAccountCopyBackupPeersForView(SOSAccount* account, CFStringRef viewName) {
85 CFMutableSetRef backupPeers = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault);
87 SOSCircleRef circle = [account.trust getCircle:NULL];
89 require_quiet(circle, exit);
91 SOSCircleForEachValidPeer(circle, account.accountKey, ^(SOSPeerInfoRef peer) {
92 if (SOSPeerInfoIsViewBackupEnabled(peer, viewName))
93 CFSetAddValue(backupPeers, peer);
100 static void SOSAccountWithBackupPeersForView(SOSAccount* account, CFStringRef viewName, void (^action)(CFSetRef peers)) {
101 CFSetRef backupPeersForView = SOSAccountCopyBackupPeersForView(account, viewName);
103 action(backupPeersForView);
105 CFReleaseNull(backupPeersForView);
109 static bool SOSAccountWithBSKBForView(SOSAccount* account, CFStringRef viewName, CFErrorRef *error,
110 bool (^action)(SOSBackupSliceKeyBagRef bskb, CFErrorRef *error)) {
111 __block SOSBackupSliceKeyBagRef bskb = NULL;
113 CFDataRef rkbg = SOSAccountCopyRecoveryPublic(kCFAllocatorDefault, account, NULL);
115 SOSAccountWithBackupPeersForView(account, viewName, ^(CFSetRef peers) {
117 bskb = SOSBackupSliceKeyBagCreate(kCFAllocatorDefault, peers, error);
119 CFMutableDictionaryRef additionalKeys = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
120 CFDictionaryAddValue(additionalKeys, bskbRkbgPrefix, rkbg);
121 bskb = SOSBackupSliceKeyBagCreateWithAdditionalKeys(kCFAllocatorDefault, peers, additionalKeys, error);
122 CFReleaseNull(additionalKeys);
127 require_quiet(bskb, exit);
138 CFStringRef SOSBackupCopyRingNameForView(CFStringRef viewName) {
139 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@-tomb"), viewName);
142 bool SOSAccountUpdateBackupRing(SOSAccount* account, CFStringRef viewName, CFErrorRef *error,
143 SOSRingRef (^modify)(SOSRingRef existing, CFErrorRef *error)) {
145 CFStringRef ringName = SOSBackupCopyRingNameForView(viewName);
147 bool result = SOSAccountUpdateNamedRing(account, ringName, error, ^SOSRingRef(CFStringRef ringName, CFErrorRef *error) {
148 return SOSRingCreate(ringName, (__bridge CFStringRef) account.peerID, kSOSRingBackup, error);
151 CFReleaseNull(ringName);
156 static bool SOSAccountSetKeybagForViewBackupRing(SOSAccount* account, CFStringRef viewName, SOSBackupSliceKeyBagRef keyBag, CFErrorRef *error) {
157 CFMutableSetRef backupViewSet = CFSetCreateMutableForCFTypes(NULL);
160 if(!SecAllocationError(backupViewSet, error, CFSTR("No backup view set created"))){
161 secnotice("backupring", "Got error setting keybag for backup view '%@': %@", viewName, error ? (CFTypeRef) *error : (CFTypeRef) CFSTR("No error space."));
165 CFSetAddValue(backupViewSet, viewName);
167 result = SOSAccountUpdateBackupRing(account, viewName, error, ^SOSRingRef(SOSRingRef existing, CFErrorRef *error) {
168 SOSRingRef newRing = NULL;
169 CFSetRef viewPeerSet = [account.trust copyPeerSetForView:viewName];
170 CFMutableSetRef cleared = CFSetCreateMutableForCFTypes(NULL);
172 SOSRingSetPeerIDs(existing, cleared);
173 SOSRingAddAll(existing, viewPeerSet);
175 require_quiet(SOSRingSetBackupKeyBag(existing, account.fullPeerInfo, backupViewSet, keyBag, error), exit);
177 newRing = CFRetainSafe(existing);
179 CFReleaseNull(viewPeerSet);
180 CFReleaseNull(cleared);
184 if (result && NULL != error && NULL != *error) {
185 secerror("Got Success and Error (dropping error): %@", *error);
186 CFReleaseNull(*error);
190 secnotice("backupring", "Got error setting keybag for backup view '%@': %@", viewName, error ? (CFTypeRef) *error : (CFTypeRef) CFSTR("No error space."));
193 CFReleaseNull(backupViewSet);
197 bool SOSAccountNewBKSBForView(SOSAccount* account, CFStringRef viewName, CFErrorRef *error)
199 return SOSAccountWithBSKBForView(account, viewName, error, ^(SOSBackupSliceKeyBagRef bskb, CFErrorRef *error) {
200 bool result = SOSAccountSetKeybagForViewBackupRing(account, viewName, bskb, error);
205 bool SOSAccountIsBackupRingEmpty(SOSAccount* account, CFStringRef viewName) {
206 CFStringRef backupRing = SOSBackupCopyRingNameForView(viewName);
207 SOSRingRef ring = [account.trust copyRing:backupRing err:NULL];
208 CFReleaseNull(backupRing);
210 if(ring) peercnt = SOSRingCountPeers(ring);
215 bool SOSAccountIsMyPeerInBackupAndCurrentInView(SOSAccount* account, CFStringRef viewname){
217 CFErrorRef bsError = NULL;
218 CFDataRef backupSliceData = NULL;
219 SOSRingRef ring = NULL;
220 SOSBackupSliceKeyBagRef backupSlice = NULL;
222 require_quiet(SOSPeerInfoIsViewBackupEnabled(account.peerInfo, viewname), errOut);
224 CFStringRef ringName = SOSBackupCopyRingNameForView(viewname);
225 ring = [account.trust copyRing:ringName err:&bsError];
226 CFReleaseNull(ringName);
228 require_quiet(ring, errOut);
230 //grab the backup slice from the ring
231 backupSliceData = SOSRingGetPayload(ring, &bsError);
232 require_quiet(backupSliceData, errOut);
234 backupSlice = SOSBackupSliceKeyBagCreateFromData(kCFAllocatorDefault, backupSliceData, &bsError);
235 require_quiet(backupSlice, errOut);
237 CFSetRef peers = SOSBSKBGetPeers(backupSlice);
238 SOSPeerInfoRef myPeer = account.peerInfo;
240 SOSPeerInfoRef myPeerInBSKB = (SOSPeerInfoRef) CFSetGetValue(peers, myPeer);
241 require_quiet(isSOSPeerInfo(myPeerInBSKB), errOut);
243 CFDataRef myBK = SOSPeerInfoCopyBackupKey(myPeer);
244 CFDataRef myPeerInBSKBBK = SOSPeerInfoCopyBackupKey(myPeerInBSKB);
245 result = CFEqualSafe(myBK, myPeerInBSKBBK);
247 CFReleaseNull(myPeerInBSKBBK);
251 CFReleaseNull(backupSlice);
254 secnotice("backup", "Failed to find BKSB: %@, %@ (%@)", backupSliceData, backupSlice, bsError);
256 CFReleaseNull(bsError);
260 bool SOSAccountIsPeerInBackupAndCurrentInView(SOSAccount* account, SOSPeerInfoRef testPeer, CFStringRef viewname){
262 CFErrorRef bsError = NULL;
263 CFDataRef backupSliceData = NULL;
264 SOSRingRef ring = NULL;
265 SOSBackupSliceKeyBagRef backupSlice = NULL;
267 require_quiet(testPeer, errOut);
269 CFStringRef ringName = SOSBackupCopyRingNameForView(viewname);
271 ring = [account.trust copyRing:ringName err:&bsError];
272 CFReleaseNull(ringName);
274 require_quiet(ring, errOut);
276 //grab the backup slice from the ring
277 backupSliceData = SOSRingGetPayload(ring, &bsError);
278 require_quiet(backupSliceData, errOut);
280 backupSlice = SOSBackupSliceKeyBagCreateFromData(kCFAllocatorDefault, backupSliceData, &bsError);
281 require_quiet(backupSlice, errOut);
283 CFSetRef peers = SOSBSKBGetPeers(backupSlice);
285 SOSPeerInfoRef peerInBSKB = (SOSPeerInfoRef) CFSetGetValue(peers, testPeer);
286 require_quiet(isSOSPeerInfo(peerInBSKB), errOut);
288 result = CFEqualSafe(testPeer, peerInBSKB);
292 CFReleaseNull(backupSlice);
295 secnotice("backup", "Failed to find BKSB: %@, %@ (%@)", backupSliceData, backupSlice, bsError);
297 CFReleaseNull(bsError);
302 bool SOSAccountUpdateOurPeerInBackup(SOSAccount* account, SOSRingRef oldRing, CFErrorRef *error){
304 CFSetRef viewNames = SOSBackupRingGetViews(oldRing, error);
305 __block CFStringRef viewName = NULL;
306 require_quiet(viewNames, fail);
307 require_quiet(SecRequirementError(1 == CFSetGetCount(viewNames), error, CFSTR("Only support single view backup rings")), fail);
309 CFSetForEach(viewNames, ^(const void *value) {
310 if (isString(value)) {
311 viewName = CFRetainSafe((CFStringRef) value);
315 result = SOSAccountNewBKSBForView(account, viewName, error);
318 CFReleaseNull(viewName);
322 void SOSAccountForEachBackupRingName(SOSAccount* account, void (^operation)(CFStringRef value)) {
323 SOSPeerInfoRef myPeer = account.peerInfo;
325 CFSetRef allViews = SOSViewCopyViewSet(kViewSetAll); // All non virtual views.
327 CFSetForEach(allViews, ^(const void *value) {
328 CFStringRef viewName = asString(value, NULL);
331 CFStringRef ringName = SOSBackupCopyRingNameForView(viewName);
333 CFReleaseNull(ringName);
336 CFReleaseNull(allViews);
337 // Only one "ring" now (other than backup rings) when there's more this will need to be modified.
338 operation(kSOSRecoveryRing);
343 void SOSAccountForEachRingName(SOSAccount* account, void (^operation)(CFStringRef value)) {
344 SOSPeerInfoRef myPeer = account.peerInfo;
346 CFSetRef allViews = SOSViewCopyViewSet(kViewSetAll); // All non virtual views.
348 CFSetForEach(allViews, ^(const void *value) {
349 CFStringRef viewName = asString(value, NULL);
352 CFStringRef ringName = SOSBackupCopyRingNameForView(viewName);
354 CFReleaseNull(ringName);
357 CFReleaseNull(allViews);
358 // Only one "ring" now (other than backup rings) when there's more this will need to be modified.
359 operation(kSOSRecoveryRing);
363 void SOSAccountForEachBackupView(SOSAccount* account, void (^operation)(const void *value)) {
364 SOSPeerInfoRef myPeer = account.peerInfo;
367 CFMutableSetRef myBackupViews = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, SOSPeerInfoGetPermittedViews(myPeer));
368 CFSetRemoveValue(myBackupViews, kSOSViewKeychainV0);
369 CFSetForEach(myBackupViews, operation);
370 CFReleaseNull(myBackupViews);
375 static bool SOSAccountWithBSKBAndPeerInfosForView(SOSAccount* account, CFArrayRef retiree, CFStringRef viewName, CFErrorRef *error,
376 bool (^action)(SOSBackupSliceKeyBagRef bskb, CFErrorRef *error)) {
377 __block SOSBackupSliceKeyBagRef bskb = NULL;
380 SOSAccountWithBackupPeersForView(account, viewName, ^(CFSetRef peers) {
381 CFMutableSetRef newPeerList = CFSetCreateMutableCopy(kCFAllocatorDefault, CFSetGetCount(peers), peers);
382 CFArrayForEach(retiree, ^(const void *value) {
383 if (!isSOSPeerInfo(value)) {
384 secerror("Peer list contains a non-peerInfo element");
386 SOSPeerInfoRef retiringPeer = (SOSPeerInfoRef)value;
387 CFStringRef retiringPeerID = SOSPeerInfoGetPeerID(retiringPeer);
389 CFSetForEach(newPeerList, ^(const void *peerFromAccount) {
390 CFStringRef peerFromAccountID = SOSPeerInfoGetPeerID((SOSPeerInfoRef)peerFromAccount);
391 if (peerFromAccountID && retiringPeerID && CFStringCompare(peerFromAccountID, retiringPeerID, 0) == 0){
392 CFSetRemoveValue(newPeerList, peerFromAccount);
397 bskb = SOSBackupSliceKeyBagCreate(kCFAllocatorDefault, newPeerList, error);
398 CFReleaseNull(newPeerList);
401 require_quiet(bskb, exit);
413 SOSRingRef SOSAccountCreateBackupRingForView(SOSAccount* account, CFStringRef ringBackupViewName, CFErrorRef *error) {
414 if(!account) return NULL;
415 if(!ringBackupViewName) return NULL;
416 SOSPeerInfoRef myPeerInfo = account.trust.peerInfo;
417 if(!myPeerInfo || !SOSPeerInfoHasBackupKey(myPeerInfo)) return NULL;
418 if(!SOSPeerInfoIsEnabledView(myPeerInfo, ringBackupViewName)) return NULL;
419 CFStringRef ringName = SOSBackupCopyRingNameForView(ringBackupViewName);
420 if(!ringName) return NULL;
422 SOSRingRef newRing = SOSRingCreate(ringName, (__bridge CFStringRef) account.peerID, kSOSRingBackup, error);
423 CFReleaseNull(ringName);
424 CFMutableSetRef filteredPeerIDs = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
425 CFMutableSetRef filteredPeerInfos = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault);
427 SOSCircleForEachBackupCapablePeerForView(account.trust.trustedCircle, account.accountKey, ringBackupViewName, ^(SOSPeerInfoRef peer) {
428 CFSetAddValue(filteredPeerIDs, SOSPeerInfoGetPeerID(peer));
429 CFSetAddValue(filteredPeerInfos, peer);
432 CFMutableSetRef viewSet = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
433 CFSetAddValue(viewSet, ringBackupViewName);
435 SOSBackupSliceKeyBagRef bskb = NULL;
436 CFDataRef recoveryKeyData = SOSAccountCopyRecoveryPublic(kCFAllocatorDefault, account, NULL);
437 if(recoveryKeyData) {
438 CFMutableDictionaryRef additionalKeys = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
439 CFDictionaryAddValue(additionalKeys, bskbRkbgPrefix, recoveryKeyData);
440 bskb = SOSBackupSliceKeyBagCreateWithAdditionalKeys(kCFAllocatorDefault, filteredPeerInfos, additionalKeys, error);
441 CFReleaseNull(additionalKeys);
443 bskb = SOSBackupSliceKeyBagCreate(kCFAllocatorDefault, filteredPeerInfos, error);
446 SOSRingSetPeerIDs(newRing, filteredPeerIDs);
447 SOSRingSetBackupKeyBag(newRing, account.fullPeerInfo, viewSet, bskb, error);
448 SOSBackupRingSetViews(newRing, account.fullPeerInfo, viewSet, error);
450 CFReleaseNull(newRing);
453 CFReleaseNull(viewSet);
454 CFReleaseNull(filteredPeerIDs);
455 CFReleaseNull(filteredPeerInfos);
457 CFReleaseNull(recoveryKeyData);
461 void SOSAccountProcessBackupRings(SOSAccount* account) {
462 SOSAccountForEachBackupView(account, ^(const void *value) {
463 CFErrorRef localError = NULL;
464 CFStringRef viewName = (CFStringRef)value;
465 SOSAccountUpdateBackupRing(account, viewName, &localError, ^SOSRingRef(SOSRingRef existing, CFErrorRef *error) {
466 SOSRingRef newRing = SOSAccountCreateBackupRingForView(account, viewName, error);
470 secnotice("ring", "Error during SOSAccountProcessBackupRings (%@)", localError);
471 CFReleaseNull(localError);
476 bool SOSAccountValidateBackupRingForView(SOSAccount* account, CFStringRef viewName, CFErrorRef *error) {
477 bool fixBackupRing = false;
478 CFStringRef ringName = NULL;
479 SOSRingRef ring = NULL;
480 CFDataRef recoveryKeyData = NULL;
481 SOSBackupSliceKeyBagRef currentBSKB = NULL;
482 CFMutableSetRef filteredPeerIDs = NULL;
483 CFMutableSetRef filteredPeerInfos = NULL;
484 CFSetRef ringPeerIDSet = NULL;
486 require_action_quiet(account && viewName, errOut, SecError(errSecParam, error, CFSTR("NULL account or viewName parameter")));
487 ringName = SOSBackupCopyRingNameForView(viewName);
488 require_action_quiet(ringName, errOut, CFSTR("No RingName for View"));
489 ring = SOSAccountCopyRingNamed(account, ringName, error);
490 require_quiet(ring, errOut);
491 recoveryKeyData = SOSAccountCopyRecoveryPublic(kCFAllocatorDefault, account, NULL);
492 currentBSKB = SOSRingCopyBackupSliceKeyBag(ring, NULL);
493 filteredPeerIDs = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
494 filteredPeerInfos = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault);
496 SOSCircleForEachBackupCapablePeerForView(account.trust.trustedCircle, account.accountKey, viewName, ^(SOSPeerInfoRef peer) {
497 CFSetAddValue(filteredPeerIDs, SOSPeerInfoGetPeerID(peer));
498 CFSetAddValue(filteredPeerInfos, peer);
501 ringPeerIDSet = SOSRingCopyPeerIDs(ring);
502 if(!CFEqual(filteredPeerIDs, ringPeerIDSet)) {
503 fixBackupRing = true;
506 fixBackupRing &= !currentBSKB ||
507 !SOSBSKBAllPeersBackupKeysAreInKeyBag(currentBSKB, filteredPeerInfos) ||
508 !SOSBSKBHasThisRecoveryKey(currentBSKB, recoveryKeyData);
511 CFReleaseNull(ringName);
513 CFReleaseNull(ringPeerIDSet);
514 CFReleaseNull(recoveryKeyData);
515 CFReleaseNull(currentBSKB);
516 CFReleaseNull(filteredPeerIDs);
517 CFReleaseNull(filteredPeerInfos);
518 return fixBackupRing;
521 bool SOSAccountSetBackupPublicKey(SOSAccountTransaction* aTxn, CFDataRef cfBackupKey, CFErrorRef *error)
523 SOSAccount* account = aTxn.account;
524 __block bool result = false;
526 account.backup_key = nil;
527 if(!SOSAccountUpdatePeerInfo(account, CFSTR("Backup public key"), error, ^bool(SOSFullPeerInfoRef fpi, CFErrorRef *error) {
528 return SOSFullPeerInfoUpdateBackupKey(fpi, cfBackupKey, error);
532 SOSAccountProcessBackupRings(account);
533 account.need_backup_peers_created_after_backup_key_set = true;
534 account.circle_rings_retirements_need_attention = true;
540 bool SOSAccountRemoveBackupPublickey(SOSAccountTransaction* aTxn, CFErrorRef *error)
542 return SOSAccountSetBackupPublicKey(aTxn, NULL, error);
545 bool SOSAccountSetBSKBagForAllSlices(SOSAccount* account, CFDataRef aks_bag, bool setupV0Only, CFErrorRef *error){
546 __block bool result = false;
547 SOSBackupSliceKeyBagRef backup_slice = NULL;
549 if(![account isInCircle:error]) {
554 result = SOSSaveV0Keybag(aks_bag, error);
555 require_action_quiet(result, exit, secnotice("keybag", "failed to set V0 keybag (%@)", *error));
559 backup_slice = SOSBackupSliceKeyBagCreateDirect(kCFAllocatorDefault, aks_bag, error);
561 SOSAccountForEachBackupView(account, ^(const void *value) {
562 CFStringRef viewname = (CFStringRef) value;
563 result &= SOSAccountSetKeybagForViewBackupRing(account, viewname, backup_slice, error);
568 CFReleaseNull(backup_slice);
572 static CF_RETURNS_RETAINED CFMutableArrayRef SOSAccountIsRetiredPeerIDInBackupPeerList(SOSAccount* account, CFArrayRef peers, CFSetRef peersInBackup){
573 CFMutableArrayRef removals = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
575 CFSetForEach(peersInBackup, ^(const void *value) {
576 SOSPeerInfoRef peer = (SOSPeerInfoRef)value;
577 CFArrayForEach(peers, ^(const void *value) {
578 CFStringRef peerID = SOSPeerInfoGetPeerID((SOSPeerInfoRef)value);
579 CFStringRef piPeerID = SOSPeerInfoGetPeerID(peer);
580 if (peerID && piPeerID && CFStringCompare(piPeerID, peerID, 0) == 0){
581 CFArrayAppendValue(removals, peer);
590 bool SOSAccountRemoveBackupPeers(SOSAccount* account, CFArrayRef peers, CFErrorRef *error){
591 __block bool result = true;
593 SOSFullPeerInfoRef fpi = account.fullPeerInfo;
594 SOSPeerInfoRef myPeer = SOSFullPeerInfoGetPeerInfo(fpi);
596 CFSetRef permittedViews = SOSPeerInfoGetPermittedViews(myPeer);
597 CFSetForEach(permittedViews, ^(const void *value) {
598 CFStringRef viewName = (CFStringRef)value;
599 if(SOSPeerInfoIsViewBackupEnabled(myPeer, viewName)){
600 //grab current peers list
601 CFSetRef peersInBackup = SOSAccountCopyBackupPeersForView(account, viewName);
602 //get peer infos that have retired but are still in the backup peer list
603 CFMutableArrayRef removals = SOSAccountIsRetiredPeerIDInBackupPeerList(account, peers, peersInBackup);
604 result = SOSAccountWithBSKBAndPeerInfosForView(account, removals, viewName, error, ^(SOSBackupSliceKeyBagRef bskb, CFErrorRef *error) {
605 bool result = SOSAccountSetKeybagForViewBackupRing(account, viewName, bskb, error);
608 CFReleaseNull(removals);
609 CFReleaseNull(peersInBackup);
617 SOSBackupSliceKeyBagRef SOSAccountBackupSliceKeyBagForView(SOSAccount* account, CFStringRef viewName, CFErrorRef* error){
618 CFDataRef backupSliceData = NULL;
619 CFStringRef ringName = NULL;
620 SOSRingRef ring = NULL;
621 SOSBackupSliceKeyBagRef bskb = NULL;
623 ringName = SOSBackupCopyRingNameForView(viewName);
624 ring = [account.trust copyRing:ringName err:NULL];
625 require_action_quiet(ring, exit, SOSCreateErrorWithFormat(kSOSErrorNoCircle, NULL, error, NULL, CFSTR("failed to get ring")));
627 //grab the backup slice from the ring
628 backupSliceData = SOSRingGetPayload(ring, error);
629 require_action_quiet(backupSliceData, exit, secnotice("backup", "failed to get backup slice (%@)", *error));
631 bskb = SOSBackupSliceKeyBagCreateFromData(kCFAllocatorDefault, backupSliceData, error);
635 CFReleaseNull(ringName);