]> git.saurik.com Git - apple/security.git/blame - OSX/sec/SOSCircle/SecureObjectSync/SOSAccountBackup.c
Security-57740.1.18.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
15//
16// MARK: V0 Keybag keychain stuff
17//
18static 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
34static 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
e3d460c9 45bool SOSDeleteV0Keybag(CFErrorRef *error) {
5c19dc3a
A
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
55static 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
71static bool SOSPeerInfoIsViewBackupEnabled(SOSPeerInfoRef peerInfo, CFStringRef viewName) {
72 if (CFEqualSafe(kSOSViewKeychainV0, viewName))
73 return false;
74
75 return SOSPeerInfoHasBackupKey(peerInfo) && SOSPeerInfoIsViewPermitted(peerInfo, viewName);
76}
77
78static 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
822b670c 85 SOSCircleForEachValidPeer(circle, account->user_public, ^(SOSPeerInfoRef peer) {
5c19dc3a
A
86 if (SOSPeerInfoIsViewBackupEnabled(peer, viewName))
87 CFSetAddValue(backupPeers, peer);
88 });
89
90exit:
91 return backupPeers;
92}
93
94static 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
102static 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
117exit:
118 CFReleaseNull(bskb);
119 return result;
120}
121
122CFStringRef SOSBackupCopyRingNameForView(CFStringRef viewName) {
123 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@-tomb"), viewName);
124}
125
126static 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;
fa7225c8 130 SOSRingRef found = SOSAccountCopyRing(account, ringName, error);
5c19dc3a 131 SOSRingRef newRing = NULL;
fa7225c8 132 if(!found) {
5c19dc3a
A
133 found = create(ringName, error);
134 }
fa7225c8 135 require_quiet(found, errOut);
5c19dc3a
A
136 newRing = copyModified(found, error);
137 CFReleaseNull(found);
138
fa7225c8 139 require_quiet(newRing, errOut);
5c19dc3a
A
140
141 result = SOSAccountHandleUpdateRing(account, newRing, true, error);
142
fa7225c8 143errOut:
5c19dc3a
A
144 CFReleaseNull(found);
145 CFReleaseNull(newRing);
146 return result;
147}
148
149static 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
163static 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
177static 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
200errOut:
201
e0e0d90e 202 if (result && NULL != error && NULL != *error) {
5c19dc3a
A
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
fa7225c8 215bool SOSAccountNewBKSBForView(SOSAccountRef account, CFStringRef viewName, CFErrorRef *error)
5c19dc3a
A
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
e0e0d90e
A
223bool SOSAccountIsBackupRingEmpty(SOSAccountRef account, CFStringRef viewName) {
224 CFStringRef backupRing = SOSBackupCopyRingNameForView(viewName);
fa7225c8 225 SOSRingRef ring = SOSAccountCopyRing(account, backupRing, NULL);
e0e0d90e
A
226 CFReleaseNull(backupRing);
227 int peercnt = 0;
228 if(ring) peercnt = SOSRingCountPeers(ring);
fa7225c8 229 CFReleaseNull(ring);
e0e0d90e
A
230 return peercnt == 0;
231}
232
e3d460c9 233bool SOSAccountUpdatePeerInfo(SOSAccountRef account, CFStringRef updateDescription, CFErrorRef *error, bool (^update)(SOSFullPeerInfoRef fpi, CFErrorRef *error)) {
5c19dc3a
A
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
249bool SOSAccountIsMyPeerInBackupAndCurrentInView(SOSAccountRef account, CFStringRef viewname){
250 bool result = false;
251 CFErrorRef bsError = NULL;
252 CFDataRef backupSliceData = NULL;
fa7225c8 253 SOSRingRef ring = NULL;
5c19dc3a
A
254 SOSBackupSliceKeyBagRef backupSlice = NULL;
255
fa7225c8 256 require_quiet(SOSPeerInfoIsViewBackupEnabled(SOSAccountGetMyPeerInfo(account), viewname), errOut);
5c19dc3a 257
5c19dc3a 258 CFStringRef ringName = SOSBackupCopyRingNameForView(viewname);
fa7225c8 259 ring = SOSAccountCopyRing(account, ringName, &bsError);
5c19dc3a
A
260 CFReleaseNull(ringName);
261
fa7225c8 262 require_quiet(ring, errOut);
5c19dc3a
A
263
264 //grab the backup slice from the ring
265 backupSliceData = SOSRingGetPayload(ring, &bsError);
fa7225c8 266 require_quiet(backupSliceData, errOut);
5c19dc3a
A
267
268 backupSlice = SOSBackupSliceKeyBagCreateFromData(kCFAllocatorDefault, backupSliceData, &bsError);
fa7225c8 269 require_quiet(backupSlice, errOut);
5c19dc3a
A
270
271 CFSetRef peers = SOSBSKBGetPeers(backupSlice);
272 SOSPeerInfoRef myPeer = SOSAccountGetMyPeerInfo(account);
273
274 SOSPeerInfoRef myPeerInBSKB = (SOSPeerInfoRef) CFSetGetValue(peers, myPeer);
fa7225c8 275 require_quiet(isSOSPeerInfo(myPeerInBSKB), errOut);
5c19dc3a
A
276
277 CFDataRef myBK = SOSPeerInfoCopyBackupKey(myPeer);
278 CFDataRef myPeerInBSKBBK = SOSPeerInfoCopyBackupKey(myPeerInBSKB);
279 result = CFEqualSafe(myBK, myPeerInBSKBBK);
280 CFReleaseNull(myBK);
e0e0d90e 281 CFReleaseNull(myPeerInBSKBBK);
5c19dc3a 282
fa7225c8
A
283errOut:
284 CFReleaseNull(ring);
285
5c19dc3a
A
286 if (bsError) {
287 secnotice("backup", "Failed to find BKSB: %@, %@ (%@)", backupSliceData, backupSlice, bsError);
288 }
289 CFReleaseNull(bsError);
290 return result;
291}
292
293bool SOSAccountIsPeerInBackupAndCurrentInView(SOSAccountRef account, SOSPeerInfoRef testPeer, CFStringRef viewname){
294 bool result = false;
295 CFErrorRef bsError = NULL;
296 CFDataRef backupSliceData = NULL;
fa7225c8 297 SOSRingRef ring = NULL;
5c19dc3a
A
298 SOSBackupSliceKeyBagRef backupSlice = NULL;
299
fa7225c8 300 require_quiet(testPeer, errOut);
5c19dc3a
A
301
302 CFStringRef ringName = SOSBackupCopyRingNameForView(viewname);
fa7225c8 303 ring = SOSAccountCopyRing(account, ringName, &bsError);
5c19dc3a
A
304 CFReleaseNull(ringName);
305
fa7225c8 306 require_quiet(ring, errOut);
5c19dc3a
A
307
308 //grab the backup slice from the ring
309 backupSliceData = SOSRingGetPayload(ring, &bsError);
fa7225c8 310 require_quiet(backupSliceData, errOut);
5c19dc3a
A
311
312 backupSlice = SOSBackupSliceKeyBagCreateFromData(kCFAllocatorDefault, backupSliceData, &bsError);
fa7225c8 313 require_quiet(backupSlice, errOut);
5c19dc3a
A
314
315 CFSetRef peers = SOSBSKBGetPeers(backupSlice);
316
317 SOSPeerInfoRef peerInBSKB = (SOSPeerInfoRef) CFSetGetValue(peers, testPeer);
fa7225c8 318 require_quiet(isSOSPeerInfo(peerInBSKB), errOut);
5c19dc3a
A
319
320 result = CFEqualSafe(testPeer, peerInBSKB);
321
fa7225c8
A
322errOut:
323 CFReleaseNull(ring);
324
5c19dc3a
A
325 if (bsError) {
326 secnotice("backup", "Failed to find BKSB: %@, %@ (%@)", backupSliceData, backupSlice, bsError);
327 }
328 CFReleaseNull(bsError);
329 return result;
330
331}
332
333bool 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
fa7225c8 346 result = SOSAccountNewBKSBForView(account, viewName, error);
5c19dc3a
A
347
348fail:
349 CFReleaseNull(viewName);
350 return result;
351}
352
353void SOSAccountForEachBackupRingName(SOSAccountRef account, void (^operation)(CFStringRef value)) {
354 SOSPeerInfoRef myPeer = SOSAccountGetMyPeerInfo(account);
355 if (myPeer) {
fa7225c8 356 CFSetRef allViews = SOSViewCopyViewSet(kViewSetAll); // All non virtual views.
5c19dc3a 357
fa7225c8 358 CFSetForEach(allViews, ^(const void *value) {
5c19dc3a
A
359 CFStringRef viewName = asString(value, NULL);
360
361 if (viewName) {
362 CFStringRef ringName = SOSBackupCopyRingNameForView(viewName);
363 operation(ringName);
364 CFReleaseNull(ringName);
365 }
366 });
367
fa7225c8 368 CFReleaseNull(allViews);
5c19dc3a
A
369 }
370}
371
5c19dc3a
A
372void 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));
5c19dc3a 377 CFSetRemoveValue(myBackupViews, kSOSViewKeychainV0);
5c19dc3a 378 CFSetForEach(myBackupViews, operation);
5c19dc3a
A
379 CFReleaseNull(myBackupViews);
380 }
381}
382
fa7225c8 383bool SOSAccountSetBackupPublicKey(SOSAccountTransactionRef aTxn, CFDataRef backupKey, CFErrorRef *error)
5c19dc3a 384{
fa7225c8
A
385 SOSAccountRef account = aTxn->account;
386
5c19dc3a
A
387 __block bool result = false;
388
fa7225c8
A
389 CFDataPerformWithHexString(backupKey, ^(CFStringRef backupKeyString) {
390 CFDataPerformWithHexString(account->backup_key, ^(CFStringRef oldBackupKey) {
391 secnotice("backup", "SetBackupPublic: %@ from %@", backupKeyString, oldBackupKey);
392 });
393 });
394
5c19dc3a
A
395 require_quiet(SOSAccountIsInCircle(account, error), exit);
396
397 if (CFEqualSafe(backupKey, account->backup_key))
398 return true;
399
5c19dc3a
A
400 CFRetainAssign(account->backup_key, backupKey);
401
fa7225c8 402 account->circle_rings_retirements_need_attention = true;
e3d460c9 403
5c19dc3a
A
404 result = true;
405
5c19dc3a
A
406exit:
407 if (!result) {
fa7225c8 408 secnotice("backupkey", "SetBackupPublic Failed: %@", error ? (CFTypeRef) *error : (CFTypeRef) CFSTR("No error space"));
5c19dc3a
A
409 }
410 return result;
411}
412
413static 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) {
e0e0d90e
A
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 }
5c19dc3a
A
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
445exit:
446 CFReleaseNull(bskb);
447 return result;
448}
449
fa7225c8 450bool SOSAccountRemoveBackupPublickey(SOSAccountTransactionRef aTxn, CFErrorRef *error)
5c19dc3a 451{
fa7225c8
A
452 SOSAccountRef account = aTxn->account;
453
5c19dc3a 454 __block bool result = false;
fa7225c8
A
455 __block CFArrayRef removals = NULL;
456
457 CFReleaseNull(account->backup_key);
458
5c19dc3a
A
459 require_quiet(SOSAccountUpdatePeerInfo(account, CFSTR("Backup public key"), error,
460 ^bool(SOSFullPeerInfoRef fpi, CFErrorRef *error) {
461 return SOSFullPeerInfoUpdateBackupKey(fpi, NULL, error);
462 }), exit);
fa7225c8
A
463
464 removals = CFArrayCreateForCFTypes(kCFAllocatorDefault,
465 SOSAccountGetMyPeerInfo(account), NULL);
466
5c19dc3a
A
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
478exit:
479 return result;
480
481}
482
e0e0d90e 483bool SOSAccountSetBSKBagForAllSlices(SOSAccountRef account, CFDataRef aks_bag, bool setupV0Only, CFErrorRef *error){
5c19dc3a
A
484 __block bool result = false;
485 SOSBackupSliceKeyBagRef backup_slice = NULL;
486
487 require_quiet(SOSAccountIsInCircle(account, error), exit);
488
e0e0d90e 489 if (setupV0Only) {
5c19dc3a
A
490 result = SOSSaveV0Keybag(aks_bag, error);
491 require_action_quiet(result, exit, secnotice("keybag", "failed to set V0 keybag (%@)", *error));
e0e0d90e
A
492 } else {
493 result = true;
5c19dc3a 494
e0e0d90e 495 backup_slice = SOSBackupSliceKeyBagCreateDirect(kCFAllocatorDefault, aks_bag, error);
5c19dc3a 496
e0e0d90e
A
497 SOSAccountForEachBackupView(account, ^(const void *value) {
498 CFStringRef viewname = (CFStringRef) value;
499 result &= SOSAccountSetKeybagForViewBackupRing(account, viewname, backup_slice, error);
500 });
501 }
5c19dc3a 502
5c19dc3a
A
503exit:
504 CFReleaseNull(backup_slice);
505 return result;
506}
507
e0e0d90e 508static CFMutableArrayRef SOSAccountIsRetiredPeerIDInBackupPeerList(SOSAccountRef account, CFArrayRef peers, CFSetRef peersInBackup){
5c19dc3a
A
509 CFMutableArrayRef removals = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
510
511 CFSetForEach(peersInBackup, ^(const void *value) {
512 SOSPeerInfoRef peer = (SOSPeerInfoRef)value;
e0e0d90e
A
513 CFArrayForEach(peers, ^(const void *value) {
514 CFStringRef peerID = SOSPeerInfoGetPeerID((SOSPeerInfoRef)value);
5c19dc3a 515 CFStringRef piPeerID = SOSPeerInfoGetPeerID(peer);
e0e0d90e 516 if (peerID && piPeerID && CFStringCompare(piPeerID, peerID, 0) == 0){
5c19dc3a
A
517 CFArrayAppendValue(removals, peer);
518 }
519 });
520
521 });
522
523 return removals;
524
525}
526
e0e0d90e 527bool SOSAccountRemoveBackupPeers(SOSAccountRef account, CFArrayRef peers, CFErrorRef *error){
5c19dc3a
A
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
e0e0d90e 540 CFMutableArrayRef removals = SOSAccountIsRetiredPeerIDInBackupPeerList(account, peers, peersInBackup);
5c19dc3a
A
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
e3d460c9 552SOSBackupSliceKeyBagRef SOSAccountBackupSliceKeyBagForView(SOSAccountRef account, CFStringRef viewName, CFErrorRef* error){
e3d460c9
A
553 CFDataRef backupSliceData = NULL;
554 CFStringRef ringName = NULL;
555 SOSRingRef ring = NULL;
556 SOSBackupSliceKeyBagRef bskb = NULL;
557
e3d460c9
A
558 ringName = SOSBackupCopyRingNameForView(viewName);
559
fa7225c8 560 ring = SOSAccountCopyRing(account, ringName, NULL);
e3d460c9
A
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
569exit:
fa7225c8 570 CFReleaseNull(ring);
e3d460c9
A
571 CFReleaseNull(ringName);
572
573 return bskb;
574}
575
fa7225c8
A
576bool 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
593errOut:
594 return retval;
595}
596