]>
Commit | Line | Data |
---|---|---|
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 | ||
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 | ||
fa7225c8 | 31 | const CFStringRef kSOSRingKey = CFSTR("trusted_rings"); |
5c19dc3a A |
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 | ||
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 |
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 | } | |
5c19dc3a | 104 | |
fa7225c8 A |
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; | |
5c19dc3a A |
112 | } |
113 | ||
fa7225c8 A |
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; | |
5c19dc3a A |
148 | } |
149 | ||
150 | CFMutableDictionaryRef SOSAccountGetBackups(SOSAccountRef a, CFErrorRef *error){ | |
151 | return a->backups; | |
152 | } | |
153 | ||
fa7225c8 A |
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; | |
5c19dc3a | 161 | |
fa7225c8 | 162 | errOut: |
5c19dc3a A |
163 | return NULL; |
164 | } | |
165 | ||
fa7225c8 A |
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 | ||
5c19dc3a A |
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) { | |
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 | ||
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 | ||
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 | ||
255 | fail: | |
256 | CFReleaseSafe(ring); | |
257 | return success; | |
258 | } | |
259 | ||
fa7225c8 A |
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; | |
5c19dc3a A |
266 | } |
267 | ||
268 | SOSRingRef 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 | 274 | errOut: |
fa7225c8 | 275 | return ring; |
5c19dc3a A |
276 | } |
277 | ||
e0e0d90e A |
278 | bool 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); |
287 | errOut: | |
288 | CFReleaseNull(newring); | |
289 | return retval; | |
290 | } | |
291 | ||
292 | bool 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 | |
307 | errOut: | |
308 | CFReleaseNull(ringList); | |
e0e0d90e A |
309 | return retval; |
310 | } | |
5c19dc3a | 311 |