6 #include "SOSAccountPriv.h"
7 #include <Security/SecureObjectSync/SOSTransport.h>
8 #include <Security/SecureObjectSync/SOSRingUtils.h>
11 // MARK: Ring management
14 const CFStringRef kSOSRingCircleV2
= CFSTR("Ring-CircleV2");
15 const CFStringRef kSOSRingKeychainV0
= CFSTR("Ring-KeychainV0");
16 const CFStringRef kSOSRingPCSHyperion
= CFSTR("Ring-PCS-Photos");
17 const CFStringRef kSOSRingPCSBladerunner
= CFSTR("Ring-PCS-iCloudDrive");
18 const CFStringRef kSOSRingPCSLiverpool
= CFSTR("Ring-PCS-CloudKit");
19 const CFStringRef kSOSRingPCSEscrow
= CFSTR("Ring-PCS-Escrow");
20 const CFStringRef kSOSRingPCSPianoMover
= CFSTR("Ring-PCS-Maildrop");
21 const CFStringRef kSOSRingPCSNotes
= CFSTR("Ring-PCS-Notes");
22 const CFStringRef kSOSRingPCSFeldspar
= CFSTR("Ring-PCS-Feldspar");
23 const CFStringRef kSOSRingAppleTV
= CFSTR("Ring-AppleTV");
24 const CFStringRef kSOSRingHomeKit
= CFSTR("Ring-HomeKit");
25 const CFStringRef kSOSRingWifi
= CFSTR("Ring-WiFi");
26 const CFStringRef kSOSRingPasswords
= CFSTR("Ring-Passwords");
27 const CFStringRef kSOSRingCreditCards
= CFSTR("Ring-CreditCards");
28 const CFStringRef kSOSRingiCloudIdentity
= CFSTR("Ring-iCloudIdentity");
29 const CFStringRef kSOSRingOtherSyncable
= CFSTR("Ring-OtherSyncable");
31 const CFStringRef kSOSRingKey
= CFSTR("trusted_rings");
33 static CFSetRef
allCurrentRings(void) {
34 static dispatch_once_t dot
;
35 static CFMutableSetRef allRings
= NULL
;
36 dispatch_once(&dot
, ^{
37 allRings
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
38 CFSetAddValue(allRings
, kSOSRingCircleV2
);
39 CFSetAddValue(allRings
, kSOSRingKeychainV0
);
40 CFSetAddValue(allRings
, kSOSRingPCSHyperion
);
41 CFSetAddValue(allRings
, kSOSRingPCSBladerunner
);
42 CFSetAddValue(allRings
, kSOSRingPCSLiverpool
);
43 CFSetAddValue(allRings
, kSOSRingPCSEscrow
);
44 CFSetAddValue(allRings
, kSOSRingPCSPianoMover
);
45 CFSetAddValue(allRings
, kSOSRingPCSNotes
);
46 CFSetAddValue(allRings
, kSOSRingPCSFeldspar
);
47 CFSetAddValue(allRings
, kSOSRingAppleTV
);
48 CFSetAddValue(allRings
, kSOSRingHomeKit
);
49 CFSetAddValue(allRings
, kSOSRingWifi
);
50 CFSetAddValue(allRings
, kSOSRingPasswords
);
51 CFSetAddValue(allRings
, kSOSRingCreditCards
);
52 CFSetAddValue(allRings
, kSOSRingiCloudIdentity
);
53 CFSetAddValue(allRings
, kSOSRingOtherSyncable
);
58 typedef struct ringDef_t
{
62 } ringDef
, *ringDefPtr
;
64 static ringDefPtr
getRingDef(CFStringRef ringName
) {
65 static ringDef retval
;
68 retval
.name
= ringName
;
69 retval
.dropWhenLeaving
= true;
70 retval
.ringType
= kSOSRingEntropyKeyed
;
73 if(CFSetContainsValue(allCurrentRings(), ringName
)) {
74 retval
.ringType
= kSOSRingBase
;
75 retval
.dropWhenLeaving
= false;
77 retval
.ringType
= kSOSRingBackup
;
78 retval
.dropWhenLeaving
= false;
83 __unused
static inline void SOSAccountRingForEachRingMatching(SOSAccountRef a
, void (^action
)(SOSRingRef ring
), bool (^condition
)(SOSRingRef ring
)) {
84 CFSetRef allRings
= allCurrentRings();
85 CFSetForEach(allRings
, ^(const void *value
) {
86 CFStringRef ringName
= (CFStringRef
) value
;
87 SOSRingRef ring
= SOSAccountCopyRing(a
, ringName
, NULL
);
88 if (condition(ring
)) {
95 void SOSAccountAddRingDictionary(SOSAccountRef a
) {
97 if(!CFDictionaryGetValue(a
->expansion
, kSOSRingKey
)) {
98 CFMutableDictionaryRef rings
= CFDictionaryCreateMutableForCFTypes(NULL
);
99 CFDictionarySetValue(a
->expansion
, kSOSRingKey
, rings
);
100 CFReleaseNull(rings
);
105 static CFMutableDictionaryRef
SOSAccountGetRings(SOSAccountRef a
, CFErrorRef
*error
){
106 CFMutableDictionaryRef rings
= (CFMutableDictionaryRef
) CFDictionaryGetValue(a
->expansion
, kSOSRingKey
);
108 SOSAccountAddRingDictionary(a
);
109 rings
= SOSAccountGetRings(a
, error
);
114 static void SOSAccountSetRings(SOSAccountRef a
, CFMutableDictionaryRef newrings
){
115 CFDictionarySetValue(a
->expansion
, newrings
, kSOSRingKey
);
118 bool SOSAccountForEachRing(SOSAccountRef account
, SOSRingRef (^action
)(CFStringRef name
, SOSRingRef ring
)) {
120 __block
bool changed
= false;
121 CFMutableDictionaryRef rings
= SOSAccountGetRings(account
, NULL
);
122 CFMutableDictionaryRef ringscopy
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
123 require_quiet(rings
, errOut
);
124 require_quiet(ringscopy
, errOut
);
125 CFDictionaryForEach(rings
, ^(const void *key
, const void *value
) {
126 CFStringRef ringname
= (CFStringRef
) key
;
127 CFDataRef ringder
= CFDataCreateCopy(kCFAllocatorDefault
, (CFDataRef
) value
);
128 CFDictionaryAddValue(ringscopy
, key
, ringder
);
129 SOSRingRef ring
= SOSRingCreateFromData(NULL
, ringder
);
130 SOSRingRef newring
= action(ringname
, ring
);
132 CFDataRef newringder
= SOSRingCopyEncodedData(newring
, NULL
);
133 CFDictionaryReplaceValue(ringscopy
, key
, newringder
);
134 CFReleaseNull(newringder
);
138 CFReleaseNull(ringder
);
139 CFReleaseNull(newring
);
142 SOSAccountSetRings(account
, ringscopy
);
146 CFReleaseNull(ringscopy
);
150 CFMutableDictionaryRef
SOSAccountGetBackups(SOSAccountRef a
, CFErrorRef
*error
){
154 SOSRingRef
SOSAccountCopyRing(SOSAccountRef a
, CFStringRef ringName
, CFErrorRef
*error
) {
155 CFMutableDictionaryRef rings
= SOSAccountGetRings(a
, error
);
156 require_action_quiet(rings
, errOut
, SOSCreateError(kSOSErrorNoRing
, CFSTR("No Rings found"), NULL
, error
));
157 CFTypeRef ringder
= CFDictionaryGetValue(rings
, ringName
);
158 require_action_quiet(ringder
, errOut
, SOSCreateError(kSOSErrorNoRing
, CFSTR("No Ring found"), NULL
, error
));
159 SOSRingRef ring
= SOSRingCreateFromData(NULL
, ringder
);
160 return (SOSRingRef
) ring
;
166 bool SOSAccountSetRing(SOSAccountRef a
, SOSRingRef addRing
, CFStringRef ringName
, CFErrorRef
*error
) {
167 require_quiet(addRing
, errOut
);
168 CFMutableDictionaryRef rings
= SOSAccountGetRings(a
, error
);
169 require_action_quiet(rings
, errOut
, SOSCreateError(kSOSErrorNoRing
, CFSTR("No Rings found"), NULL
, error
));
170 CFDataRef ringder
= SOSRingCopyEncodedData(addRing
, error
);
171 require_quiet(ringder
, errOut
);
172 CFDictionarySetValue(rings
, ringName
, ringder
);
173 CFReleaseNull(ringder
);
179 void SOSAccountRemoveRing(SOSAccountRef a
, CFStringRef ringName
) {
180 CFMutableDictionaryRef rings
= SOSAccountGetRings(a
, NULL
);
181 require_quiet(rings
, fail
);
182 CFDictionaryRemoveValue(rings
, ringName
);
188 SOSRingRef
SOSAccountCopyRingNamed(SOSAccountRef a
, CFStringRef ringName
, CFErrorRef
*error
) {
189 SOSRingRef found
= SOSAccountCopyRing(a
, ringName
, error
);
190 if (isSOSRing(found
)) return found
;
192 secerror("Non ring in ring table: %@, purging!", found
);
193 SOSAccountRemoveRing(a
, ringName
);
199 CFStringRef
SOSAccountGetMyPeerID(SOSAccountRef a
) {
200 SOSFullPeerInfoRef fpi
= SOSAccountGetMyFullPeerInfo(a
);
201 require_quiet(fpi
, errOut
);
202 SOSPeerInfoRef pi
= SOSFullPeerInfoGetPeerInfo(fpi
);
203 require_quiet(pi
, errOut
);
204 return SOSPeerInfoGetPeerID(pi
);
209 SOSRingRef
SOSAccountRingCreateForName(SOSAccountRef a
, CFStringRef ringName
, CFErrorRef
*error
) {
210 ringDefPtr rdef
= getRingDef(ringName
);
211 if(!rdef
) return NULL
;
212 SOSRingRef retval
= SOSRingCreate(rdef
->name
, SOSAccountGetMyPeerID(a
), rdef
->ringType
, error
);
216 bool SOSAccountCheckForRings(SOSAccountRef a
, CFErrorRef
*error
) {
217 __block
bool retval
= true;
218 CFMutableDictionaryRef rings
= SOSAccountGetRings(a
, error
);
219 if(rings
&& isDictionary(rings
)) {
220 SOSAccountForEachRing(a
, ^SOSRingRef(CFStringRef ringname
, SOSRingRef ring
) {
222 if(!SOSRingIsStable(ring
)) {
224 secnotice("ring", "Ring %@ not stable", ringname
);
230 SOSCreateError(kSOSErrorNotReady
, CFSTR("Rings not present"), NULL
, error
);
236 bool SOSAccountUpdateRingFromRemote(SOSAccountRef account
, SOSRingRef newRing
, CFErrorRef
*error
) {
237 return SOSAccountHandleUpdateRing(account
, newRing
, false, error
);
240 bool SOSAccountUpdateRing(SOSAccountRef account
, SOSRingRef newRing
, CFErrorRef
*error
) {
241 return SOSAccountHandleUpdateRing(account
, newRing
, true, error
);
244 bool SOSAccountModifyRing(SOSAccountRef account
, CFStringRef ringName
, CFErrorRef
* error
, bool (^action
)(SOSRingRef ring
)) {
245 bool success
= false;
247 SOSRingRef ring
= SOSAccountCopyRing(account
, ringName
, error
);
248 require_action_quiet(ring
, fail
, SOSErrorCreate(kSOSErrorNoRing
, error
, NULL
, CFSTR("No Ring to get peer key from")));
251 require_quiet(action(ring
), fail
);
253 success
= SOSAccountUpdateRing(account
, ring
, error
);
260 CFDataRef
SOSAccountRingCopyPayload(SOSAccountRef account
, CFStringRef ringName
, CFErrorRef
*error
) {
261 SOSRingRef ring
= SOSAccountCopyRing(account
, ringName
, error
);
262 CFDataRef payload
= SOSRingGetPayload(ring
, error
);
263 CFDataRef retval
= CFDataCreateCopy(kCFAllocatorDefault
, payload
);
268 SOSRingRef
SOSAccountRingCopyWithPayload(SOSAccountRef account
, CFStringRef ringName
, CFDataRef payload
, CFErrorRef
*error
) {
269 SOSRingRef ring
= SOSAccountCopyRing(account
, ringName
, error
);
270 require_quiet(ring
, errOut
);
271 CFDataRef oldpayload
= SOSRingGetPayload(ring
, error
);
272 require_quiet(!CFEqualSafe(oldpayload
, payload
), errOut
);
273 require_quiet(SOSRingSetPayload(ring
, NULL
, payload
, account
->my_identity
, error
), errOut
);
278 bool SOSAccountResetRing(SOSAccountRef account
, CFStringRef ringName
, CFErrorRef
*error
) {
280 SOSRingRef ring
= SOSAccountCopyRing(account
, ringName
, error
);
281 SOSRingRef newring
= SOSRingCreate(ringName
, NULL
, SOSRingGetType(ring
), error
);
282 SOSRingGenerationCreateWithBaseline(newring
, ring
);
283 SOSBackupRingSetViews(newring
, account
->my_identity
, SOSBackupRingGetViews(ring
, NULL
), error
);
284 require_quiet(newring
, errOut
);
286 retval
= SOSAccountUpdateRing(account
, newring
, error
);
288 CFReleaseNull(newring
);
292 bool SOSAccountResetAllRings(SOSAccountRef account
, CFErrorRef
*error
) {
293 __block
bool retval
= true;
294 CFMutableSetRef ringList
= CFSetCreateMutableForCFTypes(kCFAllocatorDefault
);
295 require_quiet(ringList
, errOut
);
297 SOSAccountForEachRing(account
, ^SOSRingRef(CFStringRef name
, SOSRingRef ring
) {
298 CFSetAddValue(ringList
, name
);
299 return NULL
; // just using this to grab names.
302 CFSetForEach(ringList
, ^(const void *value
) {
303 CFStringRef ringName
= (CFStringRef
) value
;
304 retval
= retval
&& SOSAccountResetRing(account
, ringName
, error
);
308 CFReleaseNull(ringList
);