]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSAccountBackup.c
Security-57740.20.22.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSAccountBackup.c
1 //
2 // SOSAccountCircles.c
3 // sec
4 //
5
6 #include "SOSAccountPriv.h"
7 #include "SOSCloudKeychainClient.h"
8
9 #include <Security/SecureObjectSync/SOSBackupSliceKeyBag.h>
10 #include <Security/SecureObjectSync/SOSPeerInfoCollections.h>
11 #include <Security/SecureObjectSync/SOSViews.h>
12
13 #include "SOSInternal.h"
14
15 //
16 // MARK: V0 Keybag keychain stuff
17 //
18 static bool SecItemUpdateOrAdd(CFDictionaryRef query, CFDictionaryRef update, CFErrorRef *error)
19 {
20 OSStatus saveStatus = SecItemUpdate(query, update);
21
22 if (errSecItemNotFound == saveStatus) {
23 CFMutableDictionaryRef add = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, query);
24 CFDictionaryForEach(update, ^(const void *key, const void *value) {
25 CFDictionaryAddValue(add, key, value);
26 });
27 saveStatus = SecItemAdd(add, NULL);
28 CFReleaseNull(add);
29 }
30
31 return SecError(saveStatus, error, CFSTR("Error saving %@"), query);
32 }
33
34 static CFDictionaryRef SOSCopyV0Attributes() {
35 return CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
36 kSecClass, kSecClassGenericPassword,
37 kSecAttrAccessGroup, CFSTR("com.apple.sbd"),
38 kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked,
39 kSecAttrAccount, CFSTR("SecureBackupPublicKeybag"),
40 kSecAttrService, CFSTR("SecureBackupService"),
41 kSecAttrSynchronizable, kCFBooleanTrue,
42 NULL);
43 }
44
45 bool SOSDeleteV0Keybag(CFErrorRef *error) {
46 CFDictionaryRef attributes = SOSCopyV0Attributes();
47
48 OSStatus result = SecItemDelete(attributes);
49
50 CFReleaseNull(attributes);
51
52 return SecError(result != errSecItemNotFound ? result : errSecSuccess, error, CFSTR("Deleting V0 Keybag failed - %ld"), result);
53 }
54
55 static bool SOSSaveV0Keybag(CFDataRef v0Keybag, CFErrorRef *error) {
56 CFDictionaryRef attributes = SOSCopyV0Attributes();
57
58 CFDictionaryRef update = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
59 kSecValueData, v0Keybag,
60 NULL);
61
62
63 bool result = SecItemUpdateOrAdd(attributes, update, error);
64 CFReleaseNull(attributes);
65 CFReleaseNull(update);
66
67 return result;
68 }
69
70
71 static bool SOSPeerInfoIsViewBackupEnabled(SOSPeerInfoRef peerInfo, CFStringRef viewName) {
72 if (CFEqualSafe(kSOSViewKeychainV0, viewName))
73 return false;
74
75 return SOSPeerInfoHasBackupKey(peerInfo) && SOSPeerInfoIsViewPermitted(peerInfo, viewName);
76 }
77
78 static CFSetRef SOSAccountCopyBackupPeersForView(SOSAccountRef account, CFStringRef viewName) {
79 CFMutableSetRef backupPeers = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault);
80
81 SOSCircleRef circle = SOSAccountGetCircle(account, NULL);
82
83 require_quiet(circle, exit);
84
85 SOSCircleForEachValidPeer(circle, account->user_public, ^(SOSPeerInfoRef peer) {
86 if (SOSPeerInfoIsViewBackupEnabled(peer, viewName))
87 CFSetAddValue(backupPeers, peer);
88 });
89
90 exit:
91 return backupPeers;
92 }
93
94 static void SOSAccountWithBackupPeersForView(SOSAccountRef account, CFStringRef viewName, void (^action)(CFSetRef peers)) {
95 CFSetRef backupPeersForView = SOSAccountCopyBackupPeersForView(account, viewName);
96
97 action(backupPeersForView);
98
99 CFReleaseNull(backupPeersForView);
100 }
101
102 static bool SOSAccountWithBSKBForView(SOSAccountRef account, CFStringRef viewName, CFErrorRef *error,
103 bool (^action)(SOSBackupSliceKeyBagRef bskb, CFErrorRef *error)) {
104 __block SOSBackupSliceKeyBagRef bskb = NULL;
105 bool result = false;
106
107 SOSAccountWithBackupPeersForView(account, viewName, ^(CFSetRef peers) {
108 bskb = SOSBackupSliceKeyBagCreate(kCFAllocatorDefault, peers, error);
109 });
110
111 require_quiet(bskb, exit);
112
113 action(bskb, error);
114
115 result = true;
116
117 exit:
118 CFReleaseNull(bskb);
119 return result;
120 }
121
122 CFStringRef SOSBackupCopyRingNameForView(CFStringRef viewName) {
123 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@-tomb"), viewName);
124 }
125
126 static bool SOSAccountUpdateNamedRing(SOSAccountRef account, CFStringRef ringName, CFErrorRef *error,
127 SOSRingRef (^create)(CFStringRef ringName, CFErrorRef *error),
128 SOSRingRef (^copyModified)(SOSRingRef existing, CFErrorRef *error)) {
129 bool result = false;
130 SOSRingRef found = SOSAccountCopyRing(account, ringName, error);
131 SOSRingRef newRing = NULL;
132 if(!found) {
133 found = create(ringName, error);
134 }
135 require_quiet(found, errOut);
136 newRing = copyModified(found, error);
137 CFReleaseNull(found);
138
139 require_quiet(newRing, errOut);
140
141 result = SOSAccountHandleUpdateRing(account, newRing, true, error);
142
143 errOut:
144 CFReleaseNull(found);
145 CFReleaseNull(newRing);
146 return result;
147 }
148
149 static bool SOSAccountUpdateBackupRing(SOSAccountRef account, CFStringRef viewName, CFErrorRef *error,
150 SOSRingRef (^modify)(SOSRingRef existing, CFErrorRef *error)) {
151
152 CFStringRef ringName = SOSBackupCopyRingNameForView(viewName);
153
154 bool result = SOSAccountUpdateNamedRing(account, ringName, error, ^SOSRingRef(CFStringRef ringName, CFErrorRef *error) {
155 return SOSRingCreate(ringName, SOSAccountGetMyPeerID(account), kSOSRingBackup, error);
156 }, modify);
157
158 CFReleaseNull(ringName);
159
160 return result;
161 }
162
163 static CFSetRef SOSAccountCopyPeerSetForView(SOSAccountRef account, CFStringRef viewName) {
164 CFMutableSetRef result = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault);
165
166 if (account->trusted_circle) {
167 SOSCircleForEachPeer(account->trusted_circle, ^(SOSPeerInfoRef peer) {
168 if (CFSetContainsValue(SOSPeerInfoGetPermittedViews(peer), viewName)) {
169 CFSetAddValue(result, peer);
170 }
171 });
172 }
173
174 return result;
175 }
176
177 static bool SOSAccountSetKeybagForViewBackupRing(SOSAccountRef account, CFStringRef viewName, SOSBackupSliceKeyBagRef keyBag, CFErrorRef *error) {
178 CFMutableSetRef backupViewSet = CFSetCreateMutableForCFTypes(NULL);
179 bool result = false;
180 require_quiet(SecAllocationError(backupViewSet, error, CFSTR("No backup view set created")), errOut);
181 CFSetAddValue(backupViewSet, viewName);
182
183 result = SOSAccountUpdateBackupRing(account, viewName, error, ^SOSRingRef(SOSRingRef existing, CFErrorRef *error) {
184 SOSRingRef newRing = NULL;
185 CFSetRef viewPeerSet = SOSAccountCopyPeerSetForView(account, viewName);
186 CFMutableSetRef cleared = CFSetCreateMutableForCFTypes(NULL);
187
188 SOSRingSetPeerIDs(existing, cleared);
189 SOSRingAddAll(existing, viewPeerSet);
190
191 require_quiet(SOSRingSetBackupKeyBag(existing, SOSAccountGetMyFullPeerInfo(account), backupViewSet, keyBag, error), exit);
192
193 newRing = CFRetainSafe(existing);
194 exit:
195 CFReleaseNull(viewPeerSet);
196 CFReleaseNull(cleared);
197 return newRing;
198 });
199
200 errOut:
201
202 if (result && NULL != error && NULL != *error) {
203 secerror("Got Success and Error (dropping error): %@", *error);
204 CFReleaseNull(*error);
205 }
206
207 if (!result) {
208 secnotice("backupring", "Got error setting keybag for backup view '%@': %@", viewName, error ? (CFTypeRef) *error : (CFTypeRef) CFSTR("No error space."));
209 }
210
211 CFReleaseNull(backupViewSet);
212 return result;
213 }
214
215 bool SOSAccountNewBKSBForView(SOSAccountRef account, CFStringRef viewName, CFErrorRef *error)
216 {
217 return SOSAccountWithBSKBForView(account, viewName, error, ^(SOSBackupSliceKeyBagRef bskb, CFErrorRef *error) {
218 bool result = SOSAccountSetKeybagForViewBackupRing(account, viewName, bskb, error);
219 return result;
220 });
221 }
222
223 bool SOSAccountIsBackupRingEmpty(SOSAccountRef account, CFStringRef viewName) {
224 CFStringRef backupRing = SOSBackupCopyRingNameForView(viewName);
225 SOSRingRef ring = SOSAccountCopyRing(account, backupRing, NULL);
226 CFReleaseNull(backupRing);
227 int peercnt = 0;
228 if(ring) peercnt = SOSRingCountPeers(ring);
229 CFReleaseNull(ring);
230 return peercnt == 0;
231 }
232
233 bool SOSAccountUpdatePeerInfo(SOSAccountRef account, CFStringRef updateDescription, CFErrorRef *error, bool (^update)(SOSFullPeerInfoRef fpi, CFErrorRef *error)) {
234 if (account->my_identity == NULL)
235 return true;
236
237 bool result = update(account->my_identity, error);
238
239 if (result && SOSAccountHasCircle(account, NULL)) {
240 return SOSAccountModifyCircle(account, error, ^(SOSCircleRef circle_to_change) {
241 secnotice("circleChange", "Calling SOSCircleUpdatePeerInfo for %@", updateDescription);
242 return SOSCircleUpdatePeerInfo(circle_to_change, SOSAccountGetMyPeerInfo(account));
243 });
244 }
245
246 return result;
247 }
248
249 bool SOSAccountIsMyPeerInBackupAndCurrentInView(SOSAccountRef account, CFStringRef viewname){
250 bool result = false;
251 CFErrorRef bsError = NULL;
252 CFDataRef backupSliceData = NULL;
253 SOSRingRef ring = NULL;
254 SOSBackupSliceKeyBagRef backupSlice = NULL;
255
256 require_quiet(SOSPeerInfoIsViewBackupEnabled(SOSAccountGetMyPeerInfo(account), viewname), errOut);
257
258 CFStringRef ringName = SOSBackupCopyRingNameForView(viewname);
259 ring = SOSAccountCopyRing(account, ringName, &bsError);
260 CFReleaseNull(ringName);
261
262 require_quiet(ring, errOut);
263
264 //grab the backup slice from the ring
265 backupSliceData = SOSRingGetPayload(ring, &bsError);
266 require_quiet(backupSliceData, errOut);
267
268 backupSlice = SOSBackupSliceKeyBagCreateFromData(kCFAllocatorDefault, backupSliceData, &bsError);
269 require_quiet(backupSlice, errOut);
270
271 CFSetRef peers = SOSBSKBGetPeers(backupSlice);
272 SOSPeerInfoRef myPeer = SOSAccountGetMyPeerInfo(account);
273
274 SOSPeerInfoRef myPeerInBSKB = (SOSPeerInfoRef) CFSetGetValue(peers, myPeer);
275 require_quiet(isSOSPeerInfo(myPeerInBSKB), errOut);
276
277 CFDataRef myBK = SOSPeerInfoCopyBackupKey(myPeer);
278 CFDataRef myPeerInBSKBBK = SOSPeerInfoCopyBackupKey(myPeerInBSKB);
279 result = CFEqualSafe(myBK, myPeerInBSKBBK);
280 CFReleaseNull(myBK);
281 CFReleaseNull(myPeerInBSKBBK);
282
283 errOut:
284 CFReleaseNull(ring);
285
286 if (bsError) {
287 secnotice("backup", "Failed to find BKSB: %@, %@ (%@)", backupSliceData, backupSlice, bsError);
288 }
289 CFReleaseNull(bsError);
290 return result;
291 }
292
293 bool SOSAccountIsPeerInBackupAndCurrentInView(SOSAccountRef account, SOSPeerInfoRef testPeer, CFStringRef viewname){
294 bool result = false;
295 CFErrorRef bsError = NULL;
296 CFDataRef backupSliceData = NULL;
297 SOSRingRef ring = NULL;
298 SOSBackupSliceKeyBagRef backupSlice = NULL;
299
300 require_quiet(testPeer, errOut);
301
302 CFStringRef ringName = SOSBackupCopyRingNameForView(viewname);
303 ring = SOSAccountCopyRing(account, ringName, &bsError);
304 CFReleaseNull(ringName);
305
306 require_quiet(ring, errOut);
307
308 //grab the backup slice from the ring
309 backupSliceData = SOSRingGetPayload(ring, &bsError);
310 require_quiet(backupSliceData, errOut);
311
312 backupSlice = SOSBackupSliceKeyBagCreateFromData(kCFAllocatorDefault, backupSliceData, &bsError);
313 require_quiet(backupSlice, errOut);
314
315 CFSetRef peers = SOSBSKBGetPeers(backupSlice);
316
317 SOSPeerInfoRef peerInBSKB = (SOSPeerInfoRef) CFSetGetValue(peers, testPeer);
318 require_quiet(isSOSPeerInfo(peerInBSKB), errOut);
319
320 result = CFEqualSafe(testPeer, peerInBSKB);
321
322 errOut:
323 CFReleaseNull(ring);
324
325 if (bsError) {
326 secnotice("backup", "Failed to find BKSB: %@, %@ (%@)", backupSliceData, backupSlice, bsError);
327 }
328 CFReleaseNull(bsError);
329 return result;
330
331 }
332
333 bool SOSAccountUpdateOurPeerInBackup(SOSAccountRef account, SOSRingRef oldRing, CFErrorRef *error){
334 bool result = false;
335 CFSetRef viewNames = SOSBackupRingGetViews(oldRing, error);
336 __block CFStringRef viewName = NULL;
337 require_quiet(viewNames, fail);
338 require_quiet(SecRequirementError(1 == CFSetGetCount(viewNames), error, CFSTR("Only support single view backup rings")), fail);
339
340 CFSetForEach(viewNames, ^(const void *value) {
341 if (isString(value)) {
342 viewName = CFRetainSafe((CFStringRef) value);
343 }
344 });
345
346 result = SOSAccountNewBKSBForView(account, viewName, error);
347
348 fail:
349 CFReleaseNull(viewName);
350 return result;
351 }
352
353 void SOSAccountForEachBackupRingName(SOSAccountRef account, void (^operation)(CFStringRef value)) {
354 SOSPeerInfoRef myPeer = SOSAccountGetMyPeerInfo(account);
355 if (myPeer) {
356 CFSetRef allViews = SOSViewCopyViewSet(kViewSetAll); // All non virtual views.
357
358 CFSetForEach(allViews, ^(const void *value) {
359 CFStringRef viewName = asString(value, NULL);
360
361 if (viewName) {
362 CFStringRef ringName = SOSBackupCopyRingNameForView(viewName);
363 operation(ringName);
364 CFReleaseNull(ringName);
365 }
366 });
367
368 CFReleaseNull(allViews);
369 }
370 }
371
372 void SOSAccountForEachBackupView(SOSAccountRef account, void (^operation)(const void *value)) {
373 SOSPeerInfoRef myPeer = SOSAccountGetMyPeerInfo(account);
374
375 if (myPeer) {
376 CFMutableSetRef myBackupViews = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, SOSPeerInfoGetPermittedViews(myPeer));
377 CFSetRemoveValue(myBackupViews, kSOSViewKeychainV0);
378 CFSetForEach(myBackupViews, operation);
379 CFReleaseNull(myBackupViews);
380 }
381 }
382
383 bool SOSAccountSetBackupPublicKey(SOSAccountTransactionRef aTxn, CFDataRef backupKey, CFErrorRef *error)
384 {
385 SOSAccountRef account = aTxn->account;
386
387 __block bool result = false;
388
389 CFDataPerformWithHexString(backupKey, ^(CFStringRef backupKeyString) {
390 CFDataPerformWithHexString(account->backup_key, ^(CFStringRef oldBackupKey) {
391 secnotice("backup", "SetBackupPublic: %@ from %@", backupKeyString, oldBackupKey);
392 });
393 });
394
395 require_quiet(SOSAccountIsInCircle(account, error), exit);
396
397 if (CFEqualSafe(backupKey, account->backup_key))
398 return true;
399
400 CFRetainAssign(account->backup_key, backupKey);
401
402 account->circle_rings_retirements_need_attention = true;
403
404 result = true;
405
406 exit:
407 if (!result) {
408 secnotice("backupkey", "SetBackupPublic Failed: %@", error ? (CFTypeRef) *error : (CFTypeRef) CFSTR("No error space"));
409 }
410 return result;
411 }
412
413 static bool SOSAccountWithBSKBAndPeerInfosForView(SOSAccountRef account, CFArrayRef retiree, CFStringRef viewName, CFErrorRef *error,
414 bool (^action)(SOSBackupSliceKeyBagRef bskb, CFErrorRef *error)) {
415 __block SOSBackupSliceKeyBagRef bskb = NULL;
416 bool result = false;
417
418 SOSAccountWithBackupPeersForView(account, viewName, ^(CFSetRef peers) {
419 CFMutableSetRef newPeerList = CFSetCreateMutableCopy(kCFAllocatorDefault, CFSetGetCount(peers), peers);
420 CFArrayForEach(retiree, ^(const void *value) {
421 if (!isSOSPeerInfo(value)) {
422 secerror("Peer list contains a non-peerInfo element");
423 } else {
424 SOSPeerInfoRef retiringPeer = (SOSPeerInfoRef)value;
425 CFStringRef retiringPeerID = SOSPeerInfoGetPeerID(retiringPeer);
426
427 CFSetForEach(newPeerList, ^(const void *peerFromAccount) {
428 CFStringRef peerFromAccountID = SOSPeerInfoGetPeerID((SOSPeerInfoRef)peerFromAccount);
429 if (peerFromAccountID && retiringPeerID && CFStringCompare(peerFromAccountID, retiringPeerID, 0) == 0){
430 CFSetRemoveValue(newPeerList, peerFromAccount);
431 }
432 });
433 }
434 });
435 bskb = SOSBackupSliceKeyBagCreate(kCFAllocatorDefault, newPeerList, error);
436 CFReleaseNull(newPeerList);
437 });
438
439 require_quiet(bskb, exit);
440
441 action(bskb, error);
442
443 result = true;
444
445 exit:
446 CFReleaseNull(bskb);
447 return result;
448 }
449
450 bool SOSAccountRemoveBackupPublickey(SOSAccountTransactionRef aTxn, CFErrorRef *error)
451 {
452 SOSAccountRef account = aTxn->account;
453
454 __block bool result = false;
455 __block CFArrayRef removals = NULL;
456
457 CFReleaseNull(account->backup_key);
458
459 require_quiet(SOSAccountUpdatePeerInfo(account, CFSTR("Backup public key"), error,
460 ^bool(SOSFullPeerInfoRef fpi, CFErrorRef *error) {
461 return SOSFullPeerInfoUpdateBackupKey(fpi, NULL, error);
462 }), exit);
463
464 removals = CFArrayCreateForCFTypes(kCFAllocatorDefault,
465 SOSAccountGetMyPeerInfo(account), NULL);
466
467 SOSAccountForEachBackupView(account, ^(const void *value) {
468 CFStringRef viewName = (CFStringRef)value;
469 result = SOSAccountWithBSKBAndPeerInfosForView(account, removals, viewName, error, ^(SOSBackupSliceKeyBagRef bskb, CFErrorRef *error) {
470 bool result = SOSAccountSetKeybagForViewBackupRing(account, viewName, bskb, error);
471 return result;
472 });
473 });
474
475
476 result = true;
477
478 exit:
479 return result;
480
481 }
482
483 bool SOSAccountSetBSKBagForAllSlices(SOSAccountRef account, CFDataRef aks_bag, bool setupV0Only, CFErrorRef *error){
484 __block bool result = false;
485 SOSBackupSliceKeyBagRef backup_slice = NULL;
486
487 require_quiet(SOSAccountIsInCircle(account, error), exit);
488
489 if (setupV0Only) {
490 result = SOSSaveV0Keybag(aks_bag, error);
491 require_action_quiet(result, exit, secnotice("keybag", "failed to set V0 keybag (%@)", *error));
492 } else {
493 result = true;
494
495 backup_slice = SOSBackupSliceKeyBagCreateDirect(kCFAllocatorDefault, aks_bag, error);
496
497 SOSAccountForEachBackupView(account, ^(const void *value) {
498 CFStringRef viewname = (CFStringRef) value;
499 result &= SOSAccountSetKeybagForViewBackupRing(account, viewname, backup_slice, error);
500 });
501 }
502
503 exit:
504 CFReleaseNull(backup_slice);
505 return result;
506 }
507
508 static CFMutableArrayRef SOSAccountIsRetiredPeerIDInBackupPeerList(SOSAccountRef account, CFArrayRef peers, CFSetRef peersInBackup){
509 CFMutableArrayRef removals = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
510
511 CFSetForEach(peersInBackup, ^(const void *value) {
512 SOSPeerInfoRef peer = (SOSPeerInfoRef)value;
513 CFArrayForEach(peers, ^(const void *value) {
514 CFStringRef peerID = SOSPeerInfoGetPeerID((SOSPeerInfoRef)value);
515 CFStringRef piPeerID = SOSPeerInfoGetPeerID(peer);
516 if (peerID && piPeerID && CFStringCompare(piPeerID, peerID, 0) == 0){
517 CFArrayAppendValue(removals, peer);
518 }
519 });
520
521 });
522
523 return removals;
524
525 }
526
527 bool SOSAccountRemoveBackupPeers(SOSAccountRef account, CFArrayRef peers, CFErrorRef *error){
528 __block bool result = true;
529
530 SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInfo(account);
531 SOSPeerInfoRef myPeer = SOSFullPeerInfoGetPeerInfo(fpi);
532
533 CFSetRef permittedViews = SOSPeerInfoGetPermittedViews(myPeer);
534 CFSetForEach(permittedViews, ^(const void *value) {
535 CFStringRef viewName = (CFStringRef)value;
536 if(SOSPeerInfoIsViewBackupEnabled(myPeer, viewName)){
537 //grab current peers list
538 CFSetRef peersInBackup = SOSAccountCopyBackupPeersForView(account, viewName);
539 //get peer infos that have retired but are still in the backup peer list
540 CFMutableArrayRef removals = SOSAccountIsRetiredPeerIDInBackupPeerList(account, peers, peersInBackup);
541 result = SOSAccountWithBSKBAndPeerInfosForView(account, removals, viewName, error, ^(SOSBackupSliceKeyBagRef bskb, CFErrorRef *error) {
542 bool result = SOSAccountSetKeybagForViewBackupRing(account, viewName, bskb, error);
543 return result;
544 });
545 }
546 });
547
548 return result;
549
550 }
551
552 SOSBackupSliceKeyBagRef SOSAccountBackupSliceKeyBagForView(SOSAccountRef account, CFStringRef viewName, CFErrorRef* error){
553 CFDataRef backupSliceData = NULL;
554 CFStringRef ringName = NULL;
555 SOSRingRef ring = NULL;
556 SOSBackupSliceKeyBagRef bskb = NULL;
557
558 ringName = SOSBackupCopyRingNameForView(viewName);
559
560 ring = SOSAccountCopyRing(account, ringName, NULL);
561 require_action_quiet(ring, exit, SOSCreateErrorWithFormat(kSOSErrorNoCircle, NULL, error, NULL, CFSTR("failed to get ring")));
562
563 //grab the backup slice from the ring
564 backupSliceData = SOSRingGetPayload(ring, error);
565 require_action_quiet(backupSliceData, exit, secnotice("backup", "failed to get backup slice (%@)", *error));
566
567 bskb = SOSBackupSliceKeyBagCreateFromData(kCFAllocatorDefault, backupSliceData, error);
568
569 exit:
570 CFReleaseNull(ring);
571 CFReleaseNull(ringName);
572
573 return bskb;
574 }
575
576 bool SOSAccountIsLastBackupPeer(SOSAccountRef account, CFErrorRef *error) {
577 __block bool retval = false;
578 SOSPeerInfoRef pi = SOSAccountGetMyPeerInfo(account);
579 require_quiet(SOSPeerInfoHasBackupKey(pi), errOut);
580 SOSCircleRef circle = SOSAccountGetCircle(account, error);
581 require_quiet(SOSAccountIsInCircle(account, error), errOut);
582 require_action_quiet(SOSCircleCountValidSyncingPeers(circle, SOSAccountGetTrustedPublicCredential(account, error)) != 1, errOut, retval = true);
583 // We're in a circle with more than 1 ActiveValidPeers - are they in the backups?
584 SOSAccountForEachBackupView(account, ^(const void *value) {
585 CFStringRef viewname = (CFStringRef) value;
586 SOSBackupSliceKeyBagRef keybag = SOSAccountBackupSliceKeyBagForView(account, viewname, error);
587 require_quiet(keybag, inner_errOut);
588 retval |= ((SOSBSKBCountPeers(keybag) == 1) && (SOSBSKBPeerIsInKeyBag(keybag, pi)));
589 inner_errOut:
590 CFReleaseNull(keybag);
591 });
592
593 errOut:
594 return retval;
595 }
596