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