]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSAccountBackup.c
Security-57337.50.23.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 newRing = NULL;
131 SOSRingRef found = (SOSRingRef) CFDictionaryGetValue(account->trusted_rings, ringName);
132 if (isSOSRing(found)) {
133 found = SOSRingCopyRing(found, error);
134 } else {
135 if (found) {
136 secerror("Non ring in ring table: %@, purging!", found);
137 CFDictionaryRemoveValue(account->trusted_rings, ringName);
138 }
139 found = create(ringName, error);
140 }
141
142 require_quiet(found, exit);
143 newRing = copyModified(found, error);
144 CFReleaseNull(found);
145
146 require_quiet(newRing, exit);
147
148 result = SOSAccountHandleUpdateRing(account, newRing, true, error);
149
150 exit:
151 CFReleaseNull(found);
152 CFReleaseNull(newRing);
153 return result;
154 }
155
156 static bool SOSAccountUpdateBackupRing(SOSAccountRef account, CFStringRef viewName, CFErrorRef *error,
157 SOSRingRef (^modify)(SOSRingRef existing, CFErrorRef *error)) {
158
159 CFStringRef ringName = SOSBackupCopyRingNameForView(viewName);
160
161 bool result = SOSAccountUpdateNamedRing(account, ringName, error, ^SOSRingRef(CFStringRef ringName, CFErrorRef *error) {
162 return SOSRingCreate(ringName, SOSAccountGetMyPeerID(account), kSOSRingBackup, error);
163 }, modify);
164
165 CFReleaseNull(ringName);
166
167 return result;
168 }
169
170 static CFSetRef SOSAccountCopyPeerSetForView(SOSAccountRef account, CFStringRef viewName) {
171 CFMutableSetRef result = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault);
172
173 if (account->trusted_circle) {
174 SOSCircleForEachPeer(account->trusted_circle, ^(SOSPeerInfoRef peer) {
175 if (CFSetContainsValue(SOSPeerInfoGetPermittedViews(peer), viewName)) {
176 CFSetAddValue(result, peer);
177 }
178 });
179 }
180
181 return result;
182 }
183
184 static bool SOSAccountSetKeybagForViewBackupRing(SOSAccountRef account, CFStringRef viewName, SOSBackupSliceKeyBagRef keyBag, CFErrorRef *error) {
185 CFMutableSetRef backupViewSet = CFSetCreateMutableForCFTypes(NULL);
186 bool result = false;
187 require_quiet(SecAllocationError(backupViewSet, error, CFSTR("No backup view set created")), errOut);
188 CFSetAddValue(backupViewSet, viewName);
189
190 result = SOSAccountUpdateBackupRing(account, viewName, error, ^SOSRingRef(SOSRingRef existing, CFErrorRef *error) {
191 SOSRingRef newRing = NULL;
192 CFSetRef viewPeerSet = SOSAccountCopyPeerSetForView(account, viewName);
193 CFMutableSetRef cleared = CFSetCreateMutableForCFTypes(NULL);
194
195 SOSRingSetPeerIDs(existing, cleared);
196 SOSRingAddAll(existing, viewPeerSet);
197
198 require_quiet(SOSRingSetBackupKeyBag(existing, SOSAccountGetMyFullPeerInfo(account), backupViewSet, keyBag, error), exit);
199
200 newRing = CFRetainSafe(existing);
201 exit:
202 CFReleaseNull(viewPeerSet);
203 CFReleaseNull(cleared);
204 return newRing;
205 });
206
207 errOut:
208
209 if (result && NULL != error && NULL != *error) {
210 secerror("Got Success and Error (dropping error): %@", *error);
211 CFReleaseNull(*error);
212 }
213
214 if (!result) {
215 secnotice("backupring", "Got error setting keybag for backup view '%@': %@", viewName, error ? (CFTypeRef) *error : (CFTypeRef) CFSTR("No error space."));
216 }
217
218 CFReleaseNull(backupViewSet);
219 return result;
220 }
221
222 bool SOSAccountStartNewBackup(SOSAccountRef account, CFStringRef viewName, CFErrorRef *error)
223 {
224 return SOSAccountWithBSKBForView(account, viewName, error, ^(SOSBackupSliceKeyBagRef bskb, CFErrorRef *error) {
225 bool result = SOSAccountSetKeybagForViewBackupRing(account, viewName, bskb, error);
226 return result;
227 });
228 }
229
230 bool SOSAccountIsBackupRingEmpty(SOSAccountRef account, CFStringRef viewName) {
231 CFStringRef backupRing = SOSBackupCopyRingNameForView(viewName);
232 SOSRingRef ring = SOSAccountGetRing(account, backupRing, NULL);
233 CFReleaseNull(backupRing);
234 int peercnt = 0;
235 if(ring) peercnt = SOSRingCountPeers(ring);
236 return peercnt == 0;
237 }
238
239 bool SOSAccountUpdatePeerInfo(SOSAccountRef account, CFStringRef updateDescription, CFErrorRef *error, bool (^update)(SOSFullPeerInfoRef fpi, CFErrorRef *error)) {
240 if (account->my_identity == NULL)
241 return true;
242
243 bool result = update(account->my_identity, error);
244
245 if (result && SOSAccountHasCircle(account, NULL)) {
246 return SOSAccountModifyCircle(account, error, ^(SOSCircleRef circle_to_change) {
247 secnotice("circleChange", "Calling SOSCircleUpdatePeerInfo for %@", updateDescription);
248 return SOSCircleUpdatePeerInfo(circle_to_change, SOSAccountGetMyPeerInfo(account));
249 });
250 }
251
252 return result;
253 }
254
255 bool SOSAccountIsMyPeerInBackupAndCurrentInView(SOSAccountRef account, CFStringRef viewname){
256 bool result = false;
257 CFErrorRef bsError = NULL;
258 CFDataRef backupSliceData = NULL;
259 SOSBackupSliceKeyBagRef backupSlice = NULL;
260
261 require_quiet(SOSPeerInfoIsViewBackupEnabled(SOSAccountGetMyPeerInfo(account), viewname), exit);
262
263 CFMutableDictionaryRef trusted_rings = SOSAccountGetRings(account, &bsError);
264 require_quiet(trusted_rings, exit);
265
266 CFStringRef ringName = SOSBackupCopyRingNameForView(viewname);
267 SOSRingRef ring = (SOSRingRef)CFDictionaryGetValue(trusted_rings, ringName);
268 CFReleaseNull(ringName);
269
270 require_quiet(ring, exit);
271
272 //grab the backup slice from the ring
273 backupSliceData = SOSRingGetPayload(ring, &bsError);
274 require_quiet(backupSliceData, exit);
275
276 backupSlice = SOSBackupSliceKeyBagCreateFromData(kCFAllocatorDefault, backupSliceData, &bsError);
277 require_quiet(backupSlice, exit);
278
279 CFSetRef peers = SOSBSKBGetPeers(backupSlice);
280 SOSPeerInfoRef myPeer = SOSAccountGetMyPeerInfo(account);
281
282 SOSPeerInfoRef myPeerInBSKB = (SOSPeerInfoRef) CFSetGetValue(peers, myPeer);
283 require_quiet(isSOSPeerInfo(myPeerInBSKB), exit);
284
285 CFDataRef myBK = SOSPeerInfoCopyBackupKey(myPeer);
286 CFDataRef myPeerInBSKBBK = SOSPeerInfoCopyBackupKey(myPeerInBSKB);
287 result = CFEqualSafe(myBK, myPeerInBSKBBK);
288 CFReleaseNull(myBK);
289 CFReleaseNull(myPeerInBSKBBK);
290
291 exit:
292 if (bsError) {
293 secnotice("backup", "Failed to find BKSB: %@, %@ (%@)", backupSliceData, backupSlice, bsError);
294 }
295 CFReleaseNull(bsError);
296 return result;
297 }
298
299 bool SOSAccountIsPeerInBackupAndCurrentInView(SOSAccountRef account, SOSPeerInfoRef testPeer, CFStringRef viewname){
300 bool result = false;
301 CFErrorRef bsError = NULL;
302 CFDataRef backupSliceData = NULL;
303 SOSBackupSliceKeyBagRef backupSlice = NULL;
304
305 require_quiet(testPeer, exit);
306
307 CFMutableDictionaryRef trusted_rings = SOSAccountGetRings(account, &bsError);
308 require_quiet(trusted_rings, exit);
309
310 CFStringRef ringName = SOSBackupCopyRingNameForView(viewname);
311 SOSRingRef ring = (SOSRingRef)CFDictionaryGetValue(trusted_rings, ringName);
312 CFReleaseNull(ringName);
313
314 require_quiet(ring, exit);
315
316 //grab the backup slice from the ring
317 backupSliceData = SOSRingGetPayload(ring, &bsError);
318 require_quiet(backupSliceData, exit);
319
320 backupSlice = SOSBackupSliceKeyBagCreateFromData(kCFAllocatorDefault, backupSliceData, &bsError);
321 require_quiet(backupSlice, exit);
322
323 CFSetRef peers = SOSBSKBGetPeers(backupSlice);
324
325 SOSPeerInfoRef peerInBSKB = (SOSPeerInfoRef) CFSetGetValue(peers, testPeer);
326 require_quiet(isSOSPeerInfo(peerInBSKB), exit);
327
328 result = CFEqualSafe(testPeer, peerInBSKB);
329
330 exit:
331 if (bsError) {
332 secnotice("backup", "Failed to find BKSB: %@, %@ (%@)", backupSliceData, backupSlice, bsError);
333 }
334 CFReleaseNull(bsError);
335 return result;
336
337 }
338
339 bool SOSAccountUpdateOurPeerInBackup(SOSAccountRef account, SOSRingRef oldRing, CFErrorRef *error){
340 bool result = false;
341 CFSetRef viewNames = SOSBackupRingGetViews(oldRing, error);
342 __block CFStringRef viewName = NULL;
343 require_quiet(viewNames, fail);
344 require_quiet(SecRequirementError(1 == CFSetGetCount(viewNames), error, CFSTR("Only support single view backup rings")), fail);
345
346 CFSetForEach(viewNames, ^(const void *value) {
347 if (isString(value)) {
348 viewName = CFRetainSafe((CFStringRef) value);
349 }
350 });
351
352 result = SOSAccountStartNewBackup(account, viewName, error);
353
354 fail:
355 CFReleaseNull(viewName);
356 return result;
357 }
358
359 void SOSAccountForEachBackupRingName(SOSAccountRef account, void (^operation)(CFStringRef value)) {
360 SOSPeerInfoRef myPeer = SOSAccountGetMyPeerInfo(account);
361 if (myPeer) {
362 CFMutableSetRef myBackupViews = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, SOSPeerInfoGetPermittedViews(myPeer));
363
364 CFSetRemoveValue(myBackupViews, kSOSViewKeychainV0);
365
366 CFSetForEach(myBackupViews, ^(const void *value) {
367 CFStringRef viewName = asString(value, NULL);
368
369 if (viewName) {
370 CFStringRef ringName = SOSBackupCopyRingNameForView(viewName);
371 operation(ringName);
372 CFReleaseNull(ringName);
373 }
374 });
375
376 CFReleaseNull(myBackupViews);
377 }
378 }
379
380 void SOSAccountForEachBackupView(SOSAccountRef account, void (^operation)(const void *value)) {
381 SOSPeerInfoRef myPeer = SOSAccountGetMyPeerInfo(account);
382
383 if (myPeer) {
384 CFMutableSetRef myBackupViews = CFSetCreateMutableCopy(kCFAllocatorDefault, 0, SOSPeerInfoGetPermittedViews(myPeer));
385
386 CFSetRemoveValue(myBackupViews, kSOSViewKeychainV0);
387
388 CFSetForEach(myBackupViews, operation);
389
390 CFReleaseNull(myBackupViews);
391 }
392 }
393
394 bool SOSAccountSetBackupPublicKey(SOSAccountRef account, CFDataRef backupKey, CFErrorRef *error)
395 {
396 __block bool result = false;
397
398 secnotice("backup", "setting backup public key");
399 require_quiet(SOSAccountIsInCircle(account, error), exit);
400
401 if (CFEqualSafe(backupKey, account->backup_key))
402 return true;
403
404 CFRetainAssign(account->backup_key, backupKey);
405
406 SOSAccountEnsureBackupStarts(account);
407
408 result = true;
409
410 exit:
411 if (!result) {
412 secnotice("backupkey", "Failed to setup backup public key: %@", error ? (CFTypeRef) *error : (CFTypeRef) CFSTR("No error space provided"));
413 }
414 return result;
415 }
416
417 static bool SOSAccountWithBSKBAndPeerInfosForView(SOSAccountRef account, CFArrayRef retiree, CFStringRef viewName, CFErrorRef *error,
418 bool (^action)(SOSBackupSliceKeyBagRef bskb, CFErrorRef *error)) {
419 __block SOSBackupSliceKeyBagRef bskb = NULL;
420 bool result = false;
421
422 SOSAccountWithBackupPeersForView(account, viewName, ^(CFSetRef peers) {
423 CFMutableSetRef newPeerList = CFSetCreateMutableCopy(kCFAllocatorDefault, CFSetGetCount(peers), peers);
424 CFArrayForEach(retiree, ^(const void *value) {
425 if (!isSOSPeerInfo(value)) {
426 secerror("Peer list contains a non-peerInfo element");
427 } else {
428 SOSPeerInfoRef retiringPeer = (SOSPeerInfoRef)value;
429 CFStringRef retiringPeerID = SOSPeerInfoGetPeerID(retiringPeer);
430
431 CFSetForEach(newPeerList, ^(const void *peerFromAccount) {
432 CFStringRef peerFromAccountID = SOSPeerInfoGetPeerID((SOSPeerInfoRef)peerFromAccount);
433 if (peerFromAccountID && retiringPeerID && CFStringCompare(peerFromAccountID, retiringPeerID, 0) == 0){
434 CFSetRemoveValue(newPeerList, peerFromAccount);
435 }
436 });
437 }
438 });
439 bskb = SOSBackupSliceKeyBagCreate(kCFAllocatorDefault, newPeerList, error);
440 CFReleaseNull(newPeerList);
441 });
442
443 require_quiet(bskb, exit);
444
445 action(bskb, error);
446
447 result = true;
448
449 exit:
450 CFReleaseNull(bskb);
451 return result;
452 }
453
454 bool SOSAccountRemoveBackupPublickey(SOSAccountRef account, CFErrorRef *error)
455 {
456 __block bool result = false;
457 __block CFMutableArrayRef removals = NULL;
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 CFReleaseNull(account->backup_key);
465
466 removals = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
467 CFArrayAppendValue(removals, SOSAccountGetMyPeerInfo(account));
468
469 SOSAccountForEachBackupView(account, ^(const void *value) {
470 CFStringRef viewName = (CFStringRef)value;
471 result = SOSAccountWithBSKBAndPeerInfosForView(account, removals, viewName, error, ^(SOSBackupSliceKeyBagRef bskb, CFErrorRef *error) {
472 bool result = SOSAccountSetKeybagForViewBackupRing(account, viewName, bskb, error);
473 return result;
474 });
475 });
476
477
478 result = true;
479
480 exit:
481 return result;
482
483 }
484
485 bool SOSAccountSetBSKBagForAllSlices(SOSAccountRef account, CFDataRef aks_bag, bool setupV0Only, CFErrorRef *error){
486 __block bool result = false;
487 SOSBackupSliceKeyBagRef backup_slice = NULL;
488
489 require_quiet(SOSAccountIsInCircle(account, error), exit);
490
491 if (setupV0Only) {
492 result = SOSSaveV0Keybag(aks_bag, error);
493 require_action_quiet(result, exit, secnotice("keybag", "failed to set V0 keybag (%@)", *error));
494 } else {
495 result = true;
496
497 backup_slice = SOSBackupSliceKeyBagCreateDirect(kCFAllocatorDefault, aks_bag, error);
498
499 SOSAccountForEachBackupView(account, ^(const void *value) {
500 CFStringRef viewname = (CFStringRef) value;
501 result &= SOSAccountSetKeybagForViewBackupRing(account, viewname, backup_slice, error);
502 });
503 }
504
505 exit:
506 CFReleaseNull(backup_slice);
507 return result;
508 }
509
510 static CFMutableArrayRef SOSAccountIsRetiredPeerIDInBackupPeerList(SOSAccountRef account, CFArrayRef peers, CFSetRef peersInBackup){
511 CFMutableArrayRef removals = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
512
513 CFSetForEach(peersInBackup, ^(const void *value) {
514 SOSPeerInfoRef peer = (SOSPeerInfoRef)value;
515 CFArrayForEach(peers, ^(const void *value) {
516 CFStringRef peerID = SOSPeerInfoGetPeerID((SOSPeerInfoRef)value);
517 CFStringRef piPeerID = SOSPeerInfoGetPeerID(peer);
518 if (peerID && piPeerID && CFStringCompare(piPeerID, peerID, 0) == 0){
519 CFArrayAppendValue(removals, peer);
520 }
521 });
522
523 });
524
525 return removals;
526
527 }
528
529 bool SOSAccountRemoveBackupPeers(SOSAccountRef account, CFArrayRef peers, CFErrorRef *error){
530 __block bool result = true;
531
532 SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInfo(account);
533 SOSPeerInfoRef myPeer = SOSFullPeerInfoGetPeerInfo(fpi);
534
535 CFSetRef permittedViews = SOSPeerInfoGetPermittedViews(myPeer);
536 CFSetForEach(permittedViews, ^(const void *value) {
537 CFStringRef viewName = (CFStringRef)value;
538 if(SOSPeerInfoIsViewBackupEnabled(myPeer, viewName)){
539 //grab current peers list
540 CFSetRef peersInBackup = SOSAccountCopyBackupPeersForView(account, viewName);
541 //get peer infos that have retired but are still in the backup peer list
542 CFMutableArrayRef removals = SOSAccountIsRetiredPeerIDInBackupPeerList(account, peers, peersInBackup);
543 result = SOSAccountWithBSKBAndPeerInfosForView(account, removals, viewName, error, ^(SOSBackupSliceKeyBagRef bskb, CFErrorRef *error) {
544 bool result = SOSAccountSetKeybagForViewBackupRing(account, viewName, bskb, error);
545 return result;
546 });
547 }
548 });
549
550 return result;
551
552 }
553
554 SOSBackupSliceKeyBagRef SOSAccountBackupSliceKeyBagForView(SOSAccountRef account, CFStringRef viewName, CFErrorRef* error){
555 CFMutableDictionaryRef trusted_rings = NULL;
556 CFDataRef backupSliceData = NULL;
557 CFStringRef ringName = NULL;
558 SOSRingRef ring = NULL;
559 SOSBackupSliceKeyBagRef bskb = NULL;
560
561 trusted_rings = SOSAccountGetRings(account, error);
562 require_action_quiet(trusted_rings, exit, secnotice("keybag", "failed to get trusted rings (%@)", *error));
563
564 ringName = SOSBackupCopyRingNameForView(viewName);
565
566 ring = (SOSRingRef)CFDictionaryGetValue(trusted_rings, ringName);
567 require_action_quiet(ring, exit, SOSCreateErrorWithFormat(kSOSErrorNoCircle, NULL, error, NULL, CFSTR("failed to get ring")));
568
569 //grab the backup slice from the ring
570 backupSliceData = SOSRingGetPayload(ring, error);
571 require_action_quiet(backupSliceData, exit, secnotice("backup", "failed to get backup slice (%@)", *error));
572
573 bskb = SOSBackupSliceKeyBagCreateFromData(kCFAllocatorDefault, backupSliceData, error);
574
575 exit:
576 CFReleaseNull(ringName);
577
578 return bskb;
579 }
580