]>
Commit | Line | Data |
---|---|---|
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 | // | |
20 | static 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 | ||
36 | static 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 | 47 | bool 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 | ||
57 | static 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 | ||
73 | static bool SOSPeerInfoIsViewBackupEnabled(SOSPeerInfoRef peerInfo, CFStringRef viewName) { | |
74 | if (CFEqualSafe(kSOSViewKeychainV0, viewName)) | |
75 | return false; | |
76 | ||
77 | return SOSPeerInfoHasBackupKey(peerInfo) && SOSPeerInfoIsViewPermitted(peerInfo, viewName); | |
78 | } | |
79 | ||
80 | static 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 | ||
92 | exit: | |
93 | return backupPeers; | |
94 | } | |
95 | ||
96 | static 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 |
105 | static 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 | ||
129 | exit: | |
130 | CFReleaseNull(bskb); | |
131 | return result; | |
132 | } | |
133 | ||
134 | CFStringRef SOSBackupCopyRingNameForView(CFStringRef viewName) { | |
135 | return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@-tomb"), viewName); | |
136 | } | |
137 | ||
5c19dc3a A |
138 | static 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 | ||
152 | static 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 | ||
166 | static 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 | ||
189 | errOut: | |
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 | 204 | bool 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 |
212 | bool 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 | 222 | bool 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 | ||
238 | bool 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 |
272 | errOut: |
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 | ||
282 | bool 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 |
311 | errOut: |
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 | ||
322 | bool 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 | |
337 | fail: | |
338 | CFReleaseNull(viewName); | |
339 | return result; | |
340 | } | |
341 | ||
6b200bc3 | 342 | void 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 |
362 | void 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 | 374 | bool 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 |
397 | exit: |
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 | ||
404 | static 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 | ||
436 | exit: | |
437 | CFReleaseNull(bskb); | |
438 | return result; | |
439 | } | |
440 | ||
fa7225c8 | 441 | bool 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 | ||
469 | exit: | |
470 | return result; | |
471 | ||
472 | } | |
473 | ||
e0e0d90e | 474 | bool 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 |
494 | exit: |
495 | CFReleaseNull(backup_slice); | |
496 | return result; | |
497 | } | |
498 | ||
e0e0d90e | 499 | static 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 | 518 | bool 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 | 543 | SOSBackupSliceKeyBagRef 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 | ||
560 | exit: | |
fa7225c8 | 561 | CFReleaseNull(ring); |
e3d460c9 A |
562 | CFReleaseNull(ringName); |
563 | ||
564 | return bskb; | |
565 | } | |
566 | ||
fa7225c8 A |
567 | bool 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 | ||
584 | errOut: | |
585 | return retval; | |
586 | } |