]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSAccountRings.c
ff2e4ac50cc95ea3d253c68343b31d9da379eba9
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSAccountRings.c
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
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");
30
31 const CFStringRef kSOSRingKey = CFSTR("trusted_rings");
32
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);
54 });
55 return allRings;
56 }
57
58 typedef struct ringDef_t {
59 CFStringRef name;
60 SOSRingType ringType;
61 bool dropWhenLeaving;
62 } ringDef, *ringDefPtr;
63
64 static 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
73 if(CFSetContainsValue(allCurrentRings(), ringName)) {
74 retval.ringType = kSOSRingBase;
75 retval.dropWhenLeaving = false;
76 } else {
77 retval.ringType = kSOSRingBackup;
78 retval.dropWhenLeaving = false;
79 }
80 return &retval;
81 }
82
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)) {
89 action(ring);
90 }
91 CFReleaseNull(ring);
92 });
93 }
94
95 void 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 }
104
105 static 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;
112 }
113
114 static void SOSAccountSetRings(SOSAccountRef a, CFMutableDictionaryRef newrings){
115 CFDictionarySetValue(a->expansion, newrings, kSOSRingKey);
116 }
117
118 bool 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;
145 errOut:
146 CFReleaseNull(ringscopy);
147 return retval;
148 }
149
150 CFMutableDictionaryRef SOSAccountGetBackups(SOSAccountRef a, CFErrorRef *error){
151 return a->backups;
152 }
153
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;
161
162 errOut:
163 return NULL;
164 }
165
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);
174 return true;
175 errOut:
176 return false;
177 }
178
179 void SOSAccountRemoveRing(SOSAccountRef a, CFStringRef ringName) {
180 CFMutableDictionaryRef rings = SOSAccountGetRings(a, NULL);
181 require_quiet(rings, fail);
182 CFDictionaryRemoveValue(rings, ringName);
183 fail:
184 return;
185 }
186
187
188 SOSRingRef 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
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);
205 errOut:
206 return NULL;
207 }
208
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);
213 return retval;
214 }
215
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) {
221 if(retval == true) {
222 if(!SOSRingIsStable(ring)) {
223 retval = false;
224 secnotice("ring", "Ring %@ not stable", ringname);
225 }
226 }
227 return NULL;
228 });
229 } else {
230 SOSCreateError(kSOSErrorNotReady, CFSTR("Rings not present"), NULL, error);
231 retval = false;
232 }
233 return retval;
234 }
235
236 bool SOSAccountUpdateRingFromRemote(SOSAccountRef account, SOSRingRef newRing, CFErrorRef *error) {
237 return SOSAccountHandleUpdateRing(account, newRing, false, error);
238 }
239
240 bool SOSAccountUpdateRing(SOSAccountRef account, SOSRingRef newRing, CFErrorRef *error) {
241 return SOSAccountHandleUpdateRing(account, newRing, true, error);
242 }
243
244 bool SOSAccountModifyRing(SOSAccountRef account, CFStringRef ringName, CFErrorRef* error, bool (^action)(SOSRingRef ring)) {
245 bool success = false;
246
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")));
249
250 success = true;
251 require_quiet(action(ring), fail);
252
253 success = SOSAccountUpdateRing(account, ring, error);
254
255 fail:
256 CFReleaseSafe(ring);
257 return success;
258 }
259
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);
264 CFReleaseNull(ring);
265 return retval;
266 }
267
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);
274 errOut:
275 return ring;
276 }
277
278 bool SOSAccountResetRing(SOSAccountRef account, CFStringRef ringName, CFErrorRef *error) {
279 bool retval = false;
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);
285 CFReleaseNull(ring);
286 retval = SOSAccountUpdateRing(account, newring, error);
287 errOut:
288 CFReleaseNull(newring);
289 return retval;
290 }
291
292 bool SOSAccountResetAllRings(SOSAccountRef account, CFErrorRef *error) {
293 __block bool retval = true;
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;
304 retval = retval && SOSAccountResetRing(account, ringName, error);
305 });
306
307 errOut:
308 CFReleaseNull(ringList);
309 return retval;
310 }
311