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, CFErrorRef *error) {
462 SOSAccountForEachBackupView(account, ^(const void *value) {
463 CFStringRef viewName = (CFStringRef)value;
464 SOSAccountUpdateBackupRing(account, viewName, error, ^SOSRingRef(SOSRingRef existing, CFErrorRef *error) {
465 SOSRingRef newRing = SOSAccountCreateBackupRingForView(account, viewName, error);
471 bool SOSAccountValidateBackupRingForView(SOSAccount* account, CFStringRef viewName, CFErrorRef *error) {
472 bool fixBackupRing = false;
473 CFStringRef ringName = NULL;
474 SOSRingRef ring = NULL;
475 CFDataRef recoveryKeyData = NULL;
476 SOSBackupSliceKeyBagRef currentBSKB = NULL;
477 CFMutableSetRef filteredPeerIDs = NULL;
478 CFMutableSetRef filteredPeerInfos = NULL;
479 CFSetRef ringPeerIDSet = NULL;
481 require_action_quiet(account && viewName, errOut, SecError(errSecParam, error, CFSTR("NULL account or viewName parameter")));
482 ringName = SOSBackupCopyRingNameForView(viewName);
483 require_action_quiet(ringName, errOut, CFSTR("No RingName for View"));
484 ring = SOSAccountCopyRingNamed(account, ringName, error);
485 require_quiet(ring, errOut);
486 recoveryKeyData = SOSAccountCopyRecoveryPublic(kCFAllocatorDefault, account, NULL);
487 currentBSKB = SOSRingCopyBackupSliceKeyBag(ring, NULL);
488 filteredPeerIDs = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
489 filteredPeerInfos = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault);
491 SOSCircleForEachBackupCapablePeerForView(account.trust.trustedCircle, account.accountKey, viewName, ^(SOSPeerInfoRef peer) {
492 CFSetAddValue(filteredPeerIDs, SOSPeerInfoGetPeerID(peer));
493 CFSetAddValue(filteredPeerInfos, peer);
496 ringPeerIDSet = SOSRingCopyPeerIDs(ring);
497 if(!CFEqual(filteredPeerIDs, ringPeerIDSet)) {
498 fixBackupRing = true;
501 fixBackupRing &= !currentBSKB ||
502 !SOSBSKBAllPeersBackupKeysAreInKeyBag(currentBSKB, filteredPeerInfos) ||
503 !SOSBSKBHasThisRecoveryKey(currentBSKB, recoveryKeyData);
506 CFReleaseNull(ringName);
508 CFReleaseNull(ringPeerIDSet);
509 CFReleaseNull(recoveryKeyData);
510 CFReleaseNull(currentBSKB);
511 CFReleaseNull(filteredPeerIDs);
512 CFReleaseNull(filteredPeerInfos);
513 return fixBackupRing;
516 bool SOSAccountSetBackupPublicKey(SOSAccountTransaction* aTxn, CFDataRef cfBackupKey, CFErrorRef *error)
518 SOSAccount* account = aTxn.account;
519 __block bool result = false;
521 account.backup_key = nil;
522 if(!SOSAccountUpdatePeerInfo(account, CFSTR("Backup public key"), error, ^bool(SOSFullPeerInfoRef fpi, CFErrorRef *error) {
523 return SOSFullPeerInfoUpdateBackupKey(fpi, cfBackupKey, error);
527 SOSAccountProcessBackupRings(account, NULL);
533 bool SOSAccountRemoveBackupPublickey(SOSAccountTransaction* aTxn, CFErrorRef *error)
535 return SOSAccountSetBackupPublicKey(aTxn, NULL, error);
538 bool SOSAccountSetBSKBagForAllSlices(SOSAccount* account, CFDataRef aks_bag, bool setupV0Only, CFErrorRef *error){
539 __block bool result = false;
540 SOSBackupSliceKeyBagRef backup_slice = NULL;
542 if(![account isInCircle:error]) {
547 result = SOSSaveV0Keybag(aks_bag, error);
548 require_action_quiet(result, exit, secnotice("keybag", "failed to set V0 keybag (%@)", *error));
552 backup_slice = SOSBackupSliceKeyBagCreateDirect(kCFAllocatorDefault, aks_bag, error);
554 SOSAccountForEachBackupView(account, ^(const void *value) {
555 CFStringRef viewname = (CFStringRef) value;
556 result &= SOSAccountSetKeybagForViewBackupRing(account, viewname, backup_slice, error);
561 CFReleaseNull(backup_slice);
565 static CF_RETURNS_RETAINED CFMutableArrayRef SOSAccountIsRetiredPeerIDInBackupPeerList(SOSAccount* account, CFArrayRef peers, CFSetRef peersInBackup){
566 CFMutableArrayRef removals = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
568 CFSetForEach(peersInBackup, ^(const void *value) {
569 SOSPeerInfoRef peer = (SOSPeerInfoRef)value;
570 CFArrayForEach(peers, ^(const void *value) {
571 CFStringRef peerID = SOSPeerInfoGetPeerID((SOSPeerInfoRef)value);
572 CFStringRef piPeerID = SOSPeerInfoGetPeerID(peer);
573 if (peerID && piPeerID && CFStringCompare(piPeerID, peerID, 0) == 0){
574 CFArrayAppendValue(removals, peer);
583 bool SOSAccountRemoveBackupPeers(SOSAccount* account, CFArrayRef peers, CFErrorRef *error){
584 __block bool result = true;
586 SOSFullPeerInfoRef fpi = account.fullPeerInfo;
587 SOSPeerInfoRef myPeer = SOSFullPeerInfoGetPeerInfo(fpi);
589 CFSetRef permittedViews = SOSPeerInfoGetPermittedViews(myPeer);
590 CFSetForEach(permittedViews, ^(const void *value) {
591 CFStringRef viewName = (CFStringRef)value;
592 if(SOSPeerInfoIsViewBackupEnabled(myPeer, viewName)){
593 //grab current peers list
594 CFSetRef peersInBackup = SOSAccountCopyBackupPeersForView(account, viewName);
595 //get peer infos that have retired but are still in the backup peer list
596 CFMutableArrayRef removals = SOSAccountIsRetiredPeerIDInBackupPeerList(account, peers, peersInBackup);
597 result = SOSAccountWithBSKBAndPeerInfosForView(account, removals, viewName, error, ^(SOSBackupSliceKeyBagRef bskb, CFErrorRef *error) {
598 bool result = SOSAccountSetKeybagForViewBackupRing(account, viewName, bskb, error);
601 CFReleaseNull(removals);
602 CFReleaseNull(peersInBackup);
610 SOSBackupSliceKeyBagRef SOSAccountBackupSliceKeyBagForView(SOSAccount* account, CFStringRef viewName, CFErrorRef* error){
611 CFDataRef backupSliceData = NULL;
612 CFStringRef ringName = NULL;
613 SOSRingRef ring = NULL;
614 SOSBackupSliceKeyBagRef bskb = NULL;
616 ringName = SOSBackupCopyRingNameForView(viewName);
617 ring = [account.trust copyRing:ringName err:NULL];
618 require_action_quiet(ring, exit, SOSCreateErrorWithFormat(kSOSErrorNoCircle, NULL, error, NULL, CFSTR("failed to get ring")));
620 //grab the backup slice from the ring
621 backupSliceData = SOSRingGetPayload(ring, error);
622 require_action_quiet(backupSliceData, exit, secnotice("backup", "failed to get backup slice (%@)", *error));
624 bskb = SOSBackupSliceKeyBagCreateFromData(kCFAllocatorDefault, backupSliceData, error);
628 CFReleaseNull(ringName);
633 bool SOSAccountIsLastBackupPeer(SOSAccount* account, CFErrorRef *error) {
634 __block bool retval = false;
635 SOSPeerInfoRef pi = account.peerInfo;
637 if(![account isInCircle:error]) {
641 if(!SOSPeerInfoHasBackupKey(pi))
644 SOSCircleRef circle = [account.trust getCircle:error];
646 if(SOSCircleCountValidSyncingPeers(circle, SOSAccountGetTrustedPublicCredential(account, error)) == 1){
650 // We're in a circle with more than 1 ActiveValidPeers - are they in the backups?
651 SOSAccountForEachBackupView(account, ^(const void *value) {
652 CFStringRef viewname = (CFStringRef) value;
653 SOSBackupSliceKeyBagRef keybag = SOSAccountBackupSliceKeyBagForView(account, viewname, error);
654 require_quiet(keybag, inner_errOut);
655 retval |= ((SOSBSKBCountPeers(keybag) == 1) && (SOSBSKBPeerIsInKeyBag(keybag, pi)));
657 CFReleaseNull(keybag);