]> git.saurik.com Git - apple/security.git/blame - OSX/sec/SOSCircle/SecureObjectSync/SOSAccountRings.c
Security-57740.1.18.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSAccountRings.c
CommitLineData
5c19dc3a
A
1//
2// SOSAccountRings.c
3// sec
4//
5
6#include "SOSAccountPriv.h"
7#include <Security/SecureObjectSync/SOSTransport.h>
8#include <Security/SecureObjectSync/SOSRingUtils.h>
9
10//
11// MARK: Ring management
12//
13
14const CFStringRef kSOSRingCircleV2 = CFSTR("Ring-CircleV2");
15const CFStringRef kSOSRingKeychainV0 = CFSTR("Ring-KeychainV0");
16const CFStringRef kSOSRingPCSHyperion = CFSTR("Ring-PCS-Photos");
17const CFStringRef kSOSRingPCSBladerunner = CFSTR("Ring-PCS-iCloudDrive");
18const CFStringRef kSOSRingPCSLiverpool = CFSTR("Ring-PCS-CloudKit");
19const CFStringRef kSOSRingPCSEscrow = CFSTR("Ring-PCS-Escrow");
20const CFStringRef kSOSRingPCSPianoMover = CFSTR("Ring-PCS-Maildrop");
21const CFStringRef kSOSRingPCSNotes = CFSTR("Ring-PCS-Notes");
22const CFStringRef kSOSRingPCSFeldspar = CFSTR("Ring-PCS-Feldspar");
23const CFStringRef kSOSRingAppleTV = CFSTR("Ring-AppleTV");
24const CFStringRef kSOSRingHomeKit = CFSTR("Ring-HomeKit");
25const CFStringRef kSOSRingWifi = CFSTR("Ring-WiFi");
26const CFStringRef kSOSRingPasswords = CFSTR("Ring-Passwords");
27const CFStringRef kSOSRingCreditCards = CFSTR("Ring-CreditCards");
28const CFStringRef kSOSRingiCloudIdentity = CFSTR("Ring-iCloudIdentity");
29const CFStringRef kSOSRingOtherSyncable = CFSTR("Ring-OtherSyncable");
30
fa7225c8 31const CFStringRef kSOSRingKey = CFSTR("trusted_rings");
5c19dc3a
A
32
33static 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);
54 });
55 return allRings;
56}
57
58typedef struct ringDef_t {
59 CFStringRef name;
60 SOSRingType ringType;
61 bool dropWhenLeaving;
62} ringDef, *ringDefPtr;
63
64static ringDefPtr getRingDef(CFStringRef ringName) {
65 static ringDef retval;
66
67 // Defaults
68 retval.name = ringName;
69 retval.dropWhenLeaving = true;
70 retval.ringType = kSOSRingEntropyKeyed;
71
72
fa7225c8 73 if(CFSetContainsValue(allCurrentRings(), ringName)) {
5c19dc3a
A
74 retval.ringType = kSOSRingBase;
75 retval.dropWhenLeaving = false;
fa7225c8
A
76 } else {
77 retval.ringType = kSOSRingBackup;
78 retval.dropWhenLeaving = false;
79 }
5c19dc3a
A
80 return &retval;
81}
82
fa7225c8 83__unused static inline void SOSAccountRingForEachRingMatching(SOSAccountRef a, void (^action)(SOSRingRef ring), bool (^condition)(SOSRingRef ring)) {
5c19dc3a
A
84 CFSetRef allRings = allCurrentRings();
85 CFSetForEach(allRings, ^(const void *value) {
86 CFStringRef ringName = (CFStringRef) value;
fa7225c8
A
87 SOSRingRef ring = SOSAccountCopyRing(a, ringName, NULL);
88 if (condition(ring)) {
89 action(ring);
90 }
91 CFReleaseNull(ring);
5c19dc3a
A
92 });
93}
94
fa7225c8
A
95void SOSAccountAddRingDictionary(SOSAccountRef a) {
96 if(a->expansion) {
97 if(!CFDictionaryGetValue(a->expansion, kSOSRingKey)) {
98 CFMutableDictionaryRef rings = CFDictionaryCreateMutableForCFTypes(NULL);
99 CFDictionarySetValue(a->expansion, kSOSRingKey, rings);
100 CFReleaseNull(rings);
101 }
102 }
103}
5c19dc3a 104
fa7225c8
A
105static CFMutableDictionaryRef SOSAccountGetRings(SOSAccountRef a, CFErrorRef *error){
106 CFMutableDictionaryRef rings = (CFMutableDictionaryRef) CFDictionaryGetValue(a->expansion, kSOSRingKey);
107 if(!rings) {
108 SOSAccountAddRingDictionary(a);
109 rings = SOSAccountGetRings(a, error);
110 }
111 return rings;
5c19dc3a
A
112}
113
fa7225c8
A
114static void SOSAccountSetRings(SOSAccountRef a, CFMutableDictionaryRef newrings){
115 CFDictionarySetValue(a->expansion, newrings, kSOSRingKey);
116}
117
118bool SOSAccountForEachRing(SOSAccountRef account, SOSRingRef (^action)(CFStringRef name, SOSRingRef ring)) {
119 bool retval = false;
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);
131 if(newring) {
132 CFDataRef newringder = SOSRingCopyEncodedData(newring, NULL);
133 CFDictionaryReplaceValue(ringscopy, key, newringder);
134 CFReleaseNull(newringder);
135 changed = true;
136 }
137 CFReleaseNull(ring);
138 CFReleaseNull(ringder);
139 CFReleaseNull(newring);
140 });
141 if(changed) {
142 SOSAccountSetRings(account, ringscopy);
143 }
144 retval = true;
145errOut:
146 CFReleaseNull(ringscopy);
147 return retval;
5c19dc3a
A
148}
149
150CFMutableDictionaryRef SOSAccountGetBackups(SOSAccountRef a, CFErrorRef *error){
151 return a->backups;
152}
153
fa7225c8
A
154SOSRingRef 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;
5c19dc3a 161
fa7225c8 162errOut:
5c19dc3a
A
163 return NULL;
164}
165
fa7225c8
A
166bool 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);
174 return true;
175errOut:
176 return false;
177}
178
179void SOSAccountRemoveRing(SOSAccountRef a, CFStringRef ringName) {
180 CFMutableDictionaryRef rings = SOSAccountGetRings(a, NULL);
181 require_quiet(rings, fail);
182 CFDictionaryRemoveValue(rings, ringName);
183fail:
184 return;
185}
186
187
188SOSRingRef SOSAccountCopyRingNamed(SOSAccountRef a, CFStringRef ringName, CFErrorRef *error) {
189 SOSRingRef found = SOSAccountCopyRing(a, ringName, error);
190 if (isSOSRing(found)) return found;
191 if (found) {
192 secerror("Non ring in ring table: %@, purging!", found);
193 SOSAccountRemoveRing(a, ringName);
194 }
195 found = NULL;
196 return found;
197}
198
5c19dc3a
A
199CFStringRef 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);
205errOut:
206 return NULL;
207}
208
209SOSRingRef 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);
213 return retval;
214}
215
216bool SOSAccountCheckForRings(SOSAccountRef a, CFErrorRef *error) {
fa7225c8
A
217 __block bool retval = true;
218 CFMutableDictionaryRef rings = SOSAccountGetRings(a, error);
219 if(rings && isDictionary(rings)) {
220 SOSAccountForEachRing(a, ^SOSRingRef(CFStringRef ringname, SOSRingRef ring) {
221 if(retval == true) {
222 if(!SOSRingIsStable(ring)) {
223 retval = false;
224 secnotice("ring", "Ring %@ not stable", ringname);
225 }
5c19dc3a 226 }
fa7225c8
A
227 return NULL;
228 });
229 } else {
230 SOSCreateError(kSOSErrorNotReady, CFSTR("Rings not present"), NULL, error);
231 retval = false;
232 }
233 return retval;
5c19dc3a
A
234}
235
236bool SOSAccountUpdateRingFromRemote(SOSAccountRef account, SOSRingRef newRing, CFErrorRef *error) {
237 return SOSAccountHandleUpdateRing(account, newRing, false, error);
238}
239
240bool SOSAccountUpdateRing(SOSAccountRef account, SOSRingRef newRing, CFErrorRef *error) {
241 return SOSAccountHandleUpdateRing(account, newRing, true, error);
242}
243
244bool SOSAccountModifyRing(SOSAccountRef account, CFStringRef ringName, CFErrorRef* error, bool (^action)(SOSRingRef ring)) {
245 bool success = false;
246
fa7225c8 247 SOSRingRef ring = SOSAccountCopyRing(account, ringName, error);
5c19dc3a
A
248 require_action_quiet(ring, fail, SOSErrorCreate(kSOSErrorNoRing, error, NULL, CFSTR("No Ring to get peer key from")));
249
5c19dc3a
A
250 success = true;
251 require_quiet(action(ring), fail);
252
253 success = SOSAccountUpdateRing(account, ring, error);
254
255fail:
256 CFReleaseSafe(ring);
257 return success;
258}
259
fa7225c8
A
260CFDataRef 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);
264 CFReleaseNull(ring);
265 return retval;
5c19dc3a
A
266}
267
268SOSRingRef SOSAccountRingCopyWithPayload(SOSAccountRef account, CFStringRef ringName, CFDataRef payload, CFErrorRef *error) {
fa7225c8 269 SOSRingRef ring = SOSAccountCopyRing(account, ringName, error);
5c19dc3a 270 require_quiet(ring, errOut);
5c19dc3a
A
271 CFDataRef oldpayload = SOSRingGetPayload(ring, error);
272 require_quiet(!CFEqualSafe(oldpayload, payload), errOut);
fa7225c8 273 require_quiet(SOSRingSetPayload(ring, NULL, payload, account->my_identity, error), errOut);
5c19dc3a 274errOut:
fa7225c8 275 return ring;
5c19dc3a
A
276}
277
e0e0d90e
A
278bool SOSAccountResetRing(SOSAccountRef account, CFStringRef ringName, CFErrorRef *error) {
279 bool retval = false;
fa7225c8 280 SOSRingRef ring = SOSAccountCopyRing(account, ringName, error);
e0e0d90e
A
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);
fa7225c8 285 CFReleaseNull(ring);
e0e0d90e
A
286 retval = SOSAccountUpdateRing(account, newring, error);
287errOut:
288 CFReleaseNull(newring);
289 return retval;
290}
291
292bool SOSAccountResetAllRings(SOSAccountRef account, CFErrorRef *error) {
293 __block bool retval = true;
fa7225c8
A
294 CFMutableSetRef ringList = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
295 require_quiet(ringList, errOut);
296
297 SOSAccountForEachRing(account, ^SOSRingRef(CFStringRef name, SOSRingRef ring) {
298 CFSetAddValue(ringList, name);
299 return NULL; // just using this to grab names.
300 });
301
302 CFSetForEach(ringList, ^(const void *value) {
303 CFStringRef ringName = (CFStringRef) value;
e0e0d90e
A
304 retval = retval && SOSAccountResetRing(account, ringName, error);
305 });
fa7225c8
A
306
307errOut:
308 CFReleaseNull(ringList);
e0e0d90e
A
309 return retval;
310}
5c19dc3a 311