]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSTransportCircleKVS.c
Security-57336.10.29.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSTransportCircleKVS.c
1 //
2 // SOSTransportCircleKVS.c
3 // sec
4 //
5 #include <Security/SecureObjectSync/SOSTransport.h>
6 #include <Security/SecureObjectSync/SOSTransportCircle.h>
7 #include <Security/SecureObjectSync/SOSTransportCircleKVS.h>
8 #include <Security/SecureObjectSync/SOSKVSKeys.h>
9 #include <Security/SecureObjectSync/SOSInternal.h>
10 #include <Security/SecureObjectSync/SOSAccountPriv.h>
11 #include <SOSCloudKeychainClient.h>
12 #include <utilities/SecCFWrappers.h>
13
14 static bool SOSTransportCircleKVSUpdateRetirementRecords(SOSTransportCircleKVSRef transport, CFDictionaryRef updates, CFErrorRef* error);
15 static bool SOSTransportCircleKVSUpdateKVS(SOSTransportCircleRef transport, CFDictionaryRef changes, CFErrorRef *error);
16 static bool expireRetirementRecords(SOSTransportCircleRef transport, CFDictionaryRef retirements, CFErrorRef *error);
17 static CFArrayRef handleCircleMessages(SOSTransportCircleRef transport, CFMutableDictionaryRef circle_circle_messages_table, CFErrorRef *error);
18 static void destroy(SOSTransportCircleRef transport);
19 static bool postCircle(SOSTransportCircleRef transport, CFStringRef circleName, CFDataRef circle_data, CFErrorRef *error);
20 static CFDictionaryRef handleRetirementMessages(SOSTransportCircleRef transport, CFMutableDictionaryRef circle_retirement_messages_table, CFErrorRef *error);
21 static inline bool postRetirement(SOSTransportCircleRef transport, CFStringRef circleName, CFStringRef peer_id, CFDataRef retirement_data, CFErrorRef *error);
22 static inline bool flushChanges(SOSTransportCircleRef transport, CFErrorRef *error);
23 static inline CFIndex getTransportType(SOSTransportCircleRef transport, CFErrorRef *error);
24 static bool sendPeerInfo(SOSTransportCircleRef transport, CFStringRef peerID, CFDataRef peerInfoData, CFErrorRef *error);
25 static bool flushRingChanges(SOSTransportCircleRef transport, CFErrorRef* error);
26 static bool postRing(SOSTransportCircleRef transport, CFStringRef ringName, CFDataRef ring, CFErrorRef *error);
27 static bool sendAccountChangedWithDSID(SOSTransportCircleRef transport, CFStringRef dsid, CFErrorRef *error);
28 static bool sendDebugInfo(SOSTransportCircleRef transport, CFStringRef type, CFTypeRef debugInfo, CFErrorRef *error);
29
30 struct __OpaqueSOSTransportCircleKVS{
31 struct __OpaqueSOSTransportCircle c;
32 CFMutableDictionaryRef pending_changes;
33 CFStringRef circleName;
34 };
35
36
37 SOSTransportCircleKVSRef SOSTransportCircleKVSCreate(SOSAccountRef account, CFStringRef circleName, CFErrorRef *error){
38 SOSTransportCircleKVSRef t = (SOSTransportCircleKVSRef) SOSTransportCircleCreateForSubclass(sizeof(struct __OpaqueSOSTransportCircleKVS) - sizeof(CFRuntimeBase), account, error);
39 if(t){
40 t->circleName = CFRetainSafe(circleName);
41 t->c.expireRetirementRecords = expireRetirementRecords;
42 t->c.postCircle = postCircle;
43 t->c.postRetirement = postRetirement;
44 t->c.flushChanges = flushChanges;
45 t->pending_changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
46 t->c.handleRetirementMessages = handleRetirementMessages;
47 t->c.handleCircleMessages = handleCircleMessages;
48 t->c.destroy = destroy;
49 t->c.getTransportType = getTransportType;
50 t->c.sendDebugInfo = sendDebugInfo;
51 t->c.postRing = postRing;
52 t->c.sendPeerInfo = sendPeerInfo;
53 t->c.flushRingChanges = flushRingChanges;
54 t->c.sendAccountChangedWithDSID = sendAccountChangedWithDSID;
55 SOSRegisterTransportCircle((SOSTransportCircleRef)t);
56 }
57 return t;
58 }
59
60 static CFStringRef SOSTransportCircleKVSGetCircleName(SOSTransportCircleKVSRef transport){
61 return transport->circleName;
62 }
63
64 static inline CFIndex getTransportType(SOSTransportCircleRef transport, CFErrorRef *error){
65 return kKVS;
66 }
67
68
69 static void destroy(SOSTransportCircleRef transport){
70 SOSTransportCircleKVSRef tkvs = (SOSTransportCircleKVSRef)transport;
71 CFReleaseNull(tkvs->pending_changes);
72 CFReleaseNull(tkvs->circleName);
73
74 SOSUnregisterTransportCircle((SOSTransportCircleRef)tkvs);
75 }
76
77 static bool SOSTransportCircleKVSUpdateKVS(SOSTransportCircleRef transport, CFDictionaryRef changes, CFErrorRef *error){
78 CloudKeychainReplyBlock log_error = ^(CFDictionaryRef returnedValues __unused, CFErrorRef error) {
79 if (error) {
80 secerror("Error putting: %@", error);
81 CFReleaseSafe(error);
82 }
83 };
84
85 SOSCloudKeychainPutObjectsInCloud(changes, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), log_error);
86 return true;
87 }
88
89 bool SOSTransportCircleKVSSendPendingChanges(SOSTransportCircleKVSRef transport, CFErrorRef *error) {
90 CFErrorRef changeError = NULL;
91 SOSAccountRef account = SOSTransportCircleGetAccount((SOSTransportCircleRef)transport);
92
93 if (transport->pending_changes == NULL || CFDictionaryGetCount(transport->pending_changes) == 0) {
94 CFReleaseNull(transport->pending_changes);
95 return true;
96 }
97
98 CFTypeRef dsid = SOSAccountGetValue(account, kSOSDSIDKey, error);
99 if(dsid == NULL)
100 dsid = kCFNull;
101
102 CFDictionaryAddValue(transport->pending_changes, kSOSKVSRequiredKey, dsid);
103
104 bool success = SOSTransportCircleKVSUpdateKVS((SOSTransportCircleRef)transport, transport->pending_changes, &changeError);
105 if (success) {
106 CFDictionaryRemoveAllValues(transport->pending_changes);
107 } else {
108 SOSCreateErrorWithFormat(kSOSErrorSendFailure, changeError, error, NULL,
109 CFSTR("Send changes block failed [%@]"), transport->pending_changes);
110 }
111
112 return success;
113 }
114
115 void SOSTransportCircleKVSAddToPendingChanges(SOSTransportCircleKVSRef transport, CFStringRef message_key, CFDataRef message_data){
116
117 if (transport->pending_changes == NULL) {
118 transport->pending_changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
119 }
120 if (message_data == NULL) {
121 CFDictionarySetValue(transport->pending_changes, message_key, kCFNull);
122 } else {
123 CFDictionarySetValue(transport->pending_changes, message_key, message_data);
124 }
125 }
126
127 static bool expireRetirementRecords(SOSTransportCircleRef transport, CFDictionaryRef retirements, CFErrorRef *error) {
128
129 bool success = true;
130 CFMutableDictionaryRef keysToWrite = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
131
132 CFDictionaryForEach(retirements, ^(const void *key, const void *value) {
133 if (isString(key) && isArray(value)) {
134 CFStringRef circle_name = (CFStringRef) key;
135 CFArrayRef retirees = (CFArrayRef) value;
136
137 CFArrayForEach(retirees, ^(const void *value) {
138 if (isString(value)) {
139 CFStringRef retiree_id = (CFStringRef) value;
140
141 CFStringRef kvsKey = SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name, retiree_id);
142
143 CFDictionaryAddValue(keysToWrite, kvsKey, kCFNull);
144
145 CFReleaseSafe(kvsKey);
146 }
147 });
148 }
149 });
150
151 if(CFDictionaryGetCount(keysToWrite)) {
152 success = SOSTransportCircleKVSUpdateRetirementRecords((SOSTransportCircleKVSRef)transport, keysToWrite, error);
153 }
154 CFReleaseNull(keysToWrite);
155
156 return success;
157 }
158
159 static bool SOSTransportCircleKVSUpdateRetirementRecords(SOSTransportCircleKVSRef transport, CFDictionaryRef updates, CFErrorRef* error){
160 CFErrorRef updateError = NULL;
161 bool success = false;
162 if (SOSTransportCircleKVSUpdateKVS((SOSTransportCircleRef)transport, updates, &updateError)){
163 success = true;
164 } else {
165 SOSCreateErrorWithFormat(kSOSErrorSendFailure, updateError, error, NULL,
166 CFSTR("update parameters key failed [%@]"), updates);
167 }
168 return success;
169 }
170
171 static inline bool postRetirement(SOSTransportCircleRef transport, CFStringRef circleName, CFStringRef peer_id, CFDataRef retirement_data, CFErrorRef *error)
172 {
173 CFStringRef retirement_key = SOSRetirementKeyCreateWithCircleNameAndPeer(circleName, peer_id);
174 if (retirement_key)
175 SOSTransportCircleKVSAddToPendingChanges((SOSTransportCircleKVSRef)transport, retirement_key, retirement_data);
176
177 CFReleaseNull(retirement_key);
178 return true;
179 }
180
181 static inline bool flushChanges(SOSTransportCircleRef transport, CFErrorRef *error)
182 {
183 SOSTransportCircleKVSRef tkvs = (SOSTransportCircleKVSRef) transport;
184
185 return SOSTransportCircleKVSSendPendingChanges(tkvs, error);
186 }
187
188 static bool postCircle(SOSTransportCircleRef transport, CFStringRef circleName, CFDataRef circle_data, CFErrorRef *error){
189 SOSTransportCircleKVSRef tkvs = (SOSTransportCircleKVSRef)transport;
190 CFStringRef circle_key = SOSCircleKeyCreateWithName(circleName, error);
191 if (circle_key)
192 SOSTransportCircleKVSAddToPendingChanges(tkvs, circle_key, circle_data);
193 CFReleaseNull(circle_key);
194
195 return true;
196 }
197
198 static CF_RETURNS_RETAINED CFDictionaryRef handleRetirementMessages(SOSTransportCircleRef transport, CFMutableDictionaryRef circle_retirement_messages_table, CFErrorRef *error){
199 SOSAccountRef account = SOSTransportCircleGetAccount(transport);
200
201 return SOSAccountHandleRetirementMessages(account, circle_retirement_messages_table, error);
202 }
203
204
205 bool SOSTransportCircleRecordLastCirclePushedInKVS(SOSTransportCircleRef transport, CFStringRef circle_name, CFDataRef circleData){
206
207 SOSAccountRef a = SOSTransportCircleGetAccount(transport);
208 SOSTransportCircleKVSRef tkvs = (SOSTransportCircleKVSRef)transport;
209 CFStringRef myPeerID = SOSAccountGetMyPeerID(a);
210 CFDataRef timeData = NULL;
211
212 CFMutableStringRef timeDescription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("["));
213 CFAbsoluteTime currentTimeAndDate = CFAbsoluteTimeGetCurrent();
214
215 withStringOfAbsoluteTime(currentTimeAndDate, ^(CFStringRef decription) {
216 CFStringAppend(timeDescription, decription);
217 });
218 CFStringAppend(timeDescription, CFSTR("]"));
219
220 timeData = CFStringCreateExternalRepresentation(NULL,timeDescription,
221 kCFStringEncodingUTF8, '?');
222
223 CFMutableDataRef timeAndCircleMutable = CFDataCreateMutable(kCFAllocatorDefault, CFDataGetLength(timeData) + CFDataGetLength(circleData));
224 CFDataAppend(timeAndCircleMutable, timeData);
225
226 CFDataAppend(timeAndCircleMutable, circleData);
227 CFDataRef timeAndCircle = CFDataCreateCopy(kCFAllocatorDefault, timeAndCircleMutable);
228
229 if(myPeerID){
230 CFStringRef lastPushedCircleKey = SOSLastCirclePushedKeyCreateWithCircleNameAndPeerID(circle_name, SOSAccountGetMyPeerID(a));
231 SOSTransportCircleKVSAddToPendingChanges(tkvs, lastPushedCircleKey,timeAndCircle);
232 CFReleaseSafe(lastPushedCircleKey);
233 }
234 else{
235 //if we don't have a peerID (we could be retired or its too early in the system, let's use other gestalt information instead
236 CFStringRef lastPushedCircleKeyWithAccount = SOSLastCirclePushedKeyCreateWithAccountGestalt(SOSTransportCircleGetAccount(transport));
237 SOSTransportCircleKVSAddToPendingChanges(tkvs, lastPushedCircleKeyWithAccount, timeAndCircle);
238 CFReleaseNull(lastPushedCircleKeyWithAccount);
239 }
240 CFReleaseNull(timeDescription);
241 CFReleaseNull(timeAndCircleMutable);
242 CFReleaseNull(timeAndCircle);
243 CFReleaseNull(timeData);
244 return true;
245 }
246
247 CFArrayRef SOSTransportCircleKVSHandlePeerInfoV2Messages(SOSTransportCircleRef transport, CFMutableDictionaryRef peer_info_message_table, CFErrorRef *error){
248 //SOSTransportCircleKVSRef kvs_transport = (SOSTransportCircleKVSRef)transport;
249 /* TODO Handle peer info messages! */
250
251 /* assuming array of peer ids or peer infos that were handled as the return value */
252 return NULL;
253 }
254
255 static CFArrayRef handleCircleMessages(SOSTransportCircleRef transport, CFMutableDictionaryRef circle_circle_messages_table, CFErrorRef *error){
256 CFMutableArrayRef handledKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
257 CFDictionaryForEach(circle_circle_messages_table, ^(const void *key, const void *value) {
258 CFErrorRef circleMessageError = NULL;
259 if (!SOSAccountHandleCircleMessage(SOSTransportCircleGetAccount(transport), key, value, &circleMessageError)) {
260 secerror("Error handling circle message %@ (%@): %@", key, value, circleMessageError);
261 }
262 else{
263 CFStringRef circle_id = (CFStringRef) key;
264 CFArrayAppendValue(handledKeys, circle_id);
265 }
266 CFReleaseNull(circleMessageError);
267 });
268
269 return handledKeys;
270 }
271
272 bool SOSTransportCircleKVSAppendKeyInterest(SOSTransportCircleKVSRef transport, CFMutableArrayRef alwaysKeys, CFMutableArrayRef afterFirstUnlockKeys, CFMutableArrayRef unlockedKeys, CFErrorRef *error){
273
274 CFStringRef circle_name = NULL;
275 CFStringRef circle_key = NULL;
276
277 if(SOSAccountHasPublicKey(SOSTransportCircleGetAccount((SOSTransportCircleRef)transport), NULL)){
278 require_quiet(circle_name = SOSTransportCircleKVSGetCircleName(transport), fail);
279 require_quiet(circle_key = SOSCircleKeyCreateWithName(circle_name, error), fail);
280
281 SOSAccountRef account = SOSTransportCircleGetAccount((SOSTransportCircleRef)transport);
282 require_quiet(account, fail);
283 SOSCircleRef circle = account->trusted_circle;
284 require_quiet(circle && CFEqualSafe(circle_name, SOSCircleGetName(circle)), fail);
285
286 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
287 CFStringRef retirement_key = SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name, SOSPeerInfoGetPeerID(peer));
288 CFArrayAppendValue(alwaysKeys, retirement_key);
289 CFReleaseNull(retirement_key);
290 });
291
292 CFArrayAppendValue(alwaysKeys, circle_key);
293
294 CFReleaseNull(circle_key);
295 }
296 return true;
297
298 fail:
299 CFReleaseNull(circle_key);
300 return false;
301 }
302
303 //register peer infos key
304 bool SOSTransportCircleKVSAppendPeerInfoKeyInterest(SOSTransportCircleKVSRef transport, CFMutableArrayRef alwaysKeys, CFMutableArrayRef afterFirstUnlockKeys, CFMutableArrayRef unlockedKeys, CFErrorRef *error){
305
306 if(SOSAccountHasPublicKey(SOSTransportCircleGetAccount((SOSTransportCircleRef)transport), NULL)){
307
308 SOSAccountRef account = SOSTransportCircleGetAccount((SOSTransportCircleRef)transport);
309 require_quiet(account, fail);
310 SOSCircleRef circle = account->trusted_circle;
311 require_quiet(circle, fail);
312
313 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
314 CFStringRef peer_info_key = SOSPeerInfoV2KeyCreateWithPeerName(SOSPeerInfoGetPeerID(peer));
315 CFArrayAppendValue(alwaysKeys, peer_info_key);
316 CFReleaseNull(peer_info_key);
317 });
318 }
319 return true;
320
321 fail:
322 return false;
323 }
324
325 //register ring key
326 bool SOSTransportCircleKVSAppendRingKeyInterest(SOSTransportCircleKVSRef transport, CFMutableArrayRef alwaysKeys, CFMutableArrayRef afterFirstUnlockKeys, CFMutableArrayRef unlockedKeys, CFErrorRef *error){
327
328 CFMutableSetRef ringKeys = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
329
330 if(SOSAccountHasPublicKey(SOSTransportCircleGetAccount((SOSTransportCircleRef)transport), NULL)){
331 SOSAccountRef account = SOSTransportCircleGetAccount((SOSTransportCircleRef)transport);
332 require_quiet(account, fail);
333 SOSCircleRef circle = account->trusted_circle;
334 require_quiet(circle, fail);
335
336 // Always interested in backup rings:
337
338 SOSAccountForEachBackupRingName(account, ^(CFStringRef ringName) {
339 CFStringRef ring_key = SOSRingKeyCreateWithRingName(ringName);
340 CFSetAddValue(ringKeys, ring_key);
341 CFReleaseNull(ring_key);
342 });
343
344 // And any trusted rings!
345 CFMutableDictionaryRef rings = SOSAccountGetRings(account, error);
346 require_quiet(rings, fail);
347 require_quiet(CFDictionaryGetCount(rings) > 0, fail);
348 CFDictionaryForEach(rings, ^(const void *key, const void *value) {
349 CFStringRef ringName = asString(key, NULL);
350 CFStringRef ring_key = SOSRingKeyCreateWithRingName(ringName);
351 CFSetAddValue(ringKeys, ring_key);
352 CFReleaseNull(ring_key);
353 });
354
355 CFSetForEach(ringKeys, ^(const void *value) {
356 CFArrayAppendValue(alwaysKeys, value);
357 });
358 }
359 CFReleaseSafe(ringKeys);
360 return true;
361
362 fail:
363 CFReleaseNull(ringKeys);
364 return false;
365 }
366
367 extern CFStringRef kSOSAccountDebugScope;
368 //register debug scope key
369 bool SOSTransportCircleKVSAppendDebugKeyInterest(SOSTransportCircleKVSRef transport, CFMutableArrayRef alwaysKeys, CFMutableArrayRef afterFirstUnlockKeys, CFMutableArrayRef unlockedKeys, CFErrorRef *error){
370
371 CFStringRef key = SOSDebugInfoKeyCreateWithTypeName(kSOSAccountDebugScope);
372 CFArrayAppendValue(alwaysKeys, key);
373 CFRelease(key);
374 return true;
375 }
376
377 //send debug info over KVS
378 bool sendDebugInfo(SOSTransportCircleRef transport, CFStringRef type, CFTypeRef debugInfo, CFErrorRef *error)
379 {
380 CFStringRef key = SOSDebugInfoKeyCreateWithTypeName(type);
381 CFDictionaryRef changes = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
382 key,
383 debugInfo,
384 NULL);
385
386 CFReleaseNull(key);
387 bool success = SOSTransportCircleKVSUpdateKVS(transport, changes, error);
388
389 CFReleaseNull(changes);
390
391 return success;
392 }
393
394 static bool sendAccountChangedWithDSID(SOSTransportCircleRef transport, CFStringRef dsid, CFErrorRef *error){
395
396 CFDictionaryRef changes = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
397 kSOSKVSAccountChangedKey, dsid,
398 NULL);
399
400 bool success = SOSTransportCircleKVSUpdateKVS((SOSTransportCircleRef)transport, changes, error);
401
402 CFReleaseNull(changes);
403
404 return success;
405 }
406
407 //send the Ring over KVS
408 bool postRing(SOSTransportCircleRef transport, CFStringRef ringName, CFDataRef ring, CFErrorRef *error)
409 {
410 CFStringRef ringKey = SOSRingKeyCreateWithName(ringName, error);
411
412 if(ringKey)
413 SOSTransportCircleKVSAddToPendingChanges((SOSTransportCircleKVSRef)transport, ringKey, ring);
414
415 CFReleaseNull(ringKey);
416
417 return true;
418 }
419
420 bool flushRingChanges(SOSTransportCircleRef transport, CFErrorRef* error){
421
422 SOSTransportCircleKVSRef tkvs = (SOSTransportCircleKVSRef) transport;
423
424 return SOSTransportCircleKVSSendPendingChanges(tkvs, error);
425 }
426
427 //send the PeerInfo Data over KVS
428 bool sendPeerInfo(SOSTransportCircleRef transport, CFStringRef peerID, CFDataRef peerInfoData, CFErrorRef *error)
429 {
430 CFStringRef peerName = SOSPeerInfoV2KeyCreateWithPeerName(peerID);
431
432 CFDictionaryRef changes = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
433 peerName, peerInfoData,
434 NULL);
435
436 CFReleaseNull(peerName);
437 bool success = SOSTransportCircleKVSUpdateKVS(transport, changes, error);
438
439 CFReleaseNull(changes);
440
441 return success;
442 }
443
444 bool SOSTransportCircleSendOfficialDSID(SOSTransportCircleRef transport, CFStringRef dsid, CFErrorRef *error)
445 {
446 CFDictionaryRef changes = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
447 kSOSKVSOfficialDSIDKey, dsid,
448 NULL);
449 bool success = SOSTransportCircleKVSUpdateKVS(transport, changes, error);
450 CFReleaseNull(changes);
451
452 return success;
453 }
454
455
456