]>
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 | ||
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 | ||
e3d460c9 | 45 | bool 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 | ||
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 | ||
822b670c | 85 | SOSCircleForEachValidPeer(circle, account->user_public, ^(SOSPeerInfoRef peer) { |
5c19dc3a A |
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; | |
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 | 143 | errOut: |
5c19dc3a A |
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 | ||
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 | 215 | bool 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 |
223 | bool 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 | 233 | bool 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 | ||
249 | bool 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 |
283 | errOut: |
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 | ||
293 | bool 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 |
322 | errOut: |
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 | ||
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 | ||
fa7225c8 | 346 | result = SOSAccountNewBKSBForView(account, viewName, error); |
5c19dc3a A |
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) { | |
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 |
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)); | |
5c19dc3a | 377 | CFSetRemoveValue(myBackupViews, kSOSViewKeychainV0); |
5c19dc3a | 378 | CFSetForEach(myBackupViews, operation); |
5c19dc3a A |
379 | CFReleaseNull(myBackupViews); |
380 | } | |
381 | } | |
382 | ||
fa7225c8 | 383 | bool 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 |
406 | exit: |
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 | ||
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) { | |
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 | ||
445 | exit: | |
446 | CFReleaseNull(bskb); | |
447 | return result; | |
448 | } | |
449 | ||
fa7225c8 | 450 | bool 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 | ||
478 | exit: | |
479 | return result; | |
480 | ||
481 | } | |
482 | ||
e0e0d90e | 483 | bool 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 |
503 | exit: |
504 | CFReleaseNull(backup_slice); | |
505 | return result; | |
506 | } | |
507 | ||
e0e0d90e | 508 | static 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 | 527 | bool 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 | 552 | SOSBackupSliceKeyBagRef 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 | ||
569 | exit: | |
fa7225c8 | 570 | CFReleaseNull(ring); |
e3d460c9 A |
571 | CFReleaseNull(ringName); |
572 | ||
573 | return bskb; | |
574 | } | |
575 | ||
fa7225c8 A |
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 |