2 #include <SecureObjectSync/SOSInternal.h>
3 #include <SecureObjectSync/SOSKVSKeys.h>
4 #include <SecureObjectSync/SOSAccountPriv.h>
5 #include <SecureObjectSync/SOSTransport.h>
6 #include <SecureObjectSync/SOSTransportKeyParameterKVS.h>
7 #include <SecureObjectSync/SOSTransportCircleKVS.h>
8 #include <SecureObjectSync/SOSTransportMessageKVS.h>
9 #include <SOSCloudKeychainClient.h>
10 #include <utilities/debugging.h>
12 CFStringRef kKeyParameter
= CFSTR("KeyParameter");
13 CFStringRef kCircle
= CFSTR("Circle");
14 CFStringRef kMessage
= CFSTR("Message");
15 CFStringRef kAlwaysKeys
= CFSTR("AlwaysKeys");
16 CFStringRef kFirstUnlocked
= CFSTR("FirstUnlockKeys");
17 CFStringRef kUnlocked
= CFSTR("UnlockedKeys");
21 CFStringRef
SOSInterestListCopyDescription(CFArrayRef interests
)
23 CFMutableStringRef description
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
24 CFStringAppendFormat(description
, NULL
, CFSTR("<Interest: "));
26 CFArrayForEach(interests
, ^(const void* string
) {
28 CFStringAppendFormat(description
, NULL
, CFSTR(" '%@'"), string
);
30 CFStringAppend(description
, CFSTR(">"));
37 // MARK: Key Interest Processing
40 CFGiblisGetSingleton(CFMutableArrayRef
, SOSGetTransportMessages
, sTransportMessages
, ^{
41 *sTransportMessages
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, NULL
);
44 CFGiblisGetSingleton(CFMutableArrayRef
, SOSGetTransportKeyParameters
, sTransportKeyParameters
, ^{
45 *sTransportKeyParameters
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, NULL
);
48 CFGiblisGetSingleton(CFMutableArrayRef
, SOSGetTransportCircles
, sTransportCircles
, ^{
49 *sTransportCircles
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, NULL
);
53 void SOSRegisterTransportMessage(SOSTransportMessageRef additional
) {
54 CFArrayAppendValue(SOSGetTransportMessages(), additional
);
57 void SOSUnregisterTransportMessage(SOSTransportMessageRef removal
) {
58 CFArrayRemoveAllValue(SOSGetTransportMessages(), removal
);
61 void SOSUnregisterAllTransportMessages() {
62 CFArrayRemoveAllValues(SOSGetTransportMessages());
65 void SOSRegisterTransportCircle(SOSTransportCircleRef additional
) {
66 CFArrayAppendValue(SOSGetTransportCircles(), additional
);
69 void SOSUnregisterTransportCircle(SOSTransportCircleRef removal
) {
70 CFArrayRemoveAllValue(SOSGetTransportCircles(), removal
);
73 void SOSUnregisterAllTransportCircles() {
74 CFArrayRemoveAllValues(SOSGetTransportCircles());
77 void SOSRegisterTransportKeyParameter(SOSTransportKeyParameterRef additional
) {
78 CFArrayAppendValue(SOSGetTransportKeyParameters(), additional
);
81 void SOSUnregisterTransportKeyParameter(SOSTransportKeyParameterRef removal
) {
82 CFArrayRemoveAllValue(SOSGetTransportKeyParameters(), removal
);
85 void SOSUnregisterAllTransportKeyParameters() {
86 CFArrayRemoveAllValues(SOSGetTransportKeyParameters());
90 // Should we be dispatching back to our queue to handle later
92 void SOSUpdateKeyInterest(void)
94 CFMutableArrayRef alwaysKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
95 CFMutableArrayRef afterFirstUnlockKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
96 CFMutableArrayRef whenUnlockedKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
97 CFMutableDictionaryRef keyDict
= CFDictionaryCreateMutableForCFTypes (kCFAllocatorDefault
);
99 CFArrayForEach(SOSGetTransportKeyParameters(), ^(const void *value
) {
100 SOSTransportKeyParameterKVSRef tkvs
= (SOSTransportKeyParameterKVSRef
) value
;
101 CFErrorRef localError
= NULL
;
103 if (!SOSTransportKeyParameterKVSAppendKeyInterests(tkvs
, alwaysKeys
, afterFirstUnlockKeys
, whenUnlockedKeys
, &localError
)) {
104 secerror("Error getting key parameters interests %@", localError
);
106 CFReleaseNull(localError
);
108 CFMutableDictionaryRef keyParamsDict
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
109 CFDictionarySetValue(keyParamsDict
, kAlwaysKeys
, alwaysKeys
);
110 CFDictionarySetValue(keyParamsDict
, kFirstUnlocked
, afterFirstUnlockKeys
);
111 CFDictionarySetValue(keyParamsDict
, kUnlocked
, whenUnlockedKeys
);
112 CFDictionarySetValue(keyDict
, kKeyParameter
, keyParamsDict
);
113 CFErrorRef updateError
= NULL
;
114 CFReleaseNull(alwaysKeys
);
115 CFReleaseNull(afterFirstUnlockKeys
);
116 CFReleaseNull(whenUnlockedKeys
);
117 alwaysKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
118 afterFirstUnlockKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
119 whenUnlockedKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
121 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value
) {
122 SOSTransportCircleKVSRef tkvs
= (SOSTransportCircleKVSRef
) value
;
123 CFErrorRef localError
= NULL
;
125 if(!SOSTransportCircleKVSAppendKeyInterest(tkvs
, alwaysKeys
, afterFirstUnlockKeys
, whenUnlockedKeys
, &localError
)){
126 secerror("Error getting circle interests %@", localError
);
128 CFReleaseNull(localError
);
131 CFMutableDictionaryRef circleDict
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
132 CFDictionarySetValue(circleDict
, kAlwaysKeys
, alwaysKeys
);
133 CFDictionarySetValue(circleDict
, kFirstUnlocked
, afterFirstUnlockKeys
);
134 CFDictionarySetValue(circleDict
, kUnlocked
, whenUnlockedKeys
);
135 CFDictionarySetValue(keyDict
, kCircle
, circleDict
);
137 CFReleaseNull(alwaysKeys
);
138 CFReleaseNull(afterFirstUnlockKeys
);
139 CFReleaseNull(whenUnlockedKeys
);
140 alwaysKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
141 afterFirstUnlockKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
142 whenUnlockedKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
144 CFArrayForEach(SOSGetTransportMessages(), ^(const void *value
) {
145 SOSTransportMessageKVSRef tkvs
= (SOSTransportMessageKVSRef
) value
;
146 CFErrorRef localError
= NULL
;
148 if(!SOSTransportMessageKVSAppendKeyInterest(tkvs
, alwaysKeys
, afterFirstUnlockKeys
, whenUnlockedKeys
, &localError
)){
149 secerror("Error getting message interests %@", localError
);
151 CFReleaseNull(localError
);
155 CFMutableDictionaryRef messageDict
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
156 CFDictionarySetValue(messageDict
, kAlwaysKeys
, alwaysKeys
);
157 CFDictionarySetValue(messageDict
, kFirstUnlocked
, afterFirstUnlockKeys
);
158 CFDictionarySetValue(messageDict
, kUnlocked
, whenUnlockedKeys
);
159 CFDictionarySetValue(keyDict
, kMessage
, messageDict
);
161 CFReleaseNull(alwaysKeys
);
162 CFReleaseNull(afterFirstUnlockKeys
);
163 CFReleaseNull(whenUnlockedKeys
);
164 alwaysKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
165 afterFirstUnlockKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
166 whenUnlockedKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
169 if (!SOSCloudKeychainUpdateKeys(keyDict
, &updateError
))
171 secerror("Error updating keys: %@", updateError
);
172 // TODO: propagate error(s) to callers.
174 if (CFArrayGetCount(whenUnlockedKeys
) == 0) {
175 secnotice("sync", "Unlocked keys were empty!");
177 // This leaks 3 CFStringRefs in DEBUG builds.
178 CFStringRef alwaysKeysDesc
= SOSInterestListCopyDescription(alwaysKeys
);
179 CFStringRef afterFirstUnlockKeysDesc
= SOSInterestListCopyDescription(afterFirstUnlockKeys
);
180 CFStringRef unlockedKeysDesc
= SOSInterestListCopyDescription(whenUnlockedKeys
);
181 secdebug("sync", "Updating interest: always: %@,\nfirstUnlock: %@,\nunlockedKeys: %@",
183 afterFirstUnlockKeysDesc
,
185 CFReleaseNull(alwaysKeysDesc
);
186 CFReleaseNull(afterFirstUnlockKeysDesc
);
187 CFReleaseNull(unlockedKeysDesc
);
190 CFReleaseNull(updateError
);
191 CFReleaseNull(alwaysKeys
);
192 CFReleaseNull(afterFirstUnlockKeys
);
193 CFReleaseNull(whenUnlockedKeys
);
194 CFReleaseNull(keyParamsDict
);
195 CFReleaseNull(circleDict
);
196 CFReleaseNull(messageDict
);
197 CFReleaseNull(keyDict
);
201 static void showWhatWasHandled(CFDictionaryRef updates
, CFMutableArrayRef handledKeys
) {
203 CFMutableStringRef updateStr
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
204 CFMutableStringRef handledKeysStr
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
206 CFDictionaryForEach(updates
, ^(const void *key
, const void *value
) {
208 CFStringAppendFormat(updateStr
, NULL
, CFSTR("%@ "), (CFStringRef
)key
);
211 CFArrayForEach(handledKeys
, ^(const void *value
) {
212 if (isString(value
)) {
213 CFStringAppendFormat(handledKeysStr
, NULL
, CFSTR("%@ "), (CFStringRef
)value
);
216 secnotice("updates", "Updates [%ld]: %@\n", CFDictionaryGetCount(updates
), updateStr
);
217 secnotice("updates", "Handled [%ld]: %@\n", CFArrayGetCount(handledKeys
), handledKeysStr
);
218 // secnotice("updates", "Updates: %@\n", updates);
219 // secnotice("updates", "Handled: %@\n", handledKeys);
221 CFReleaseSafe(updateStr
);
222 CFReleaseSafe(handledKeysStr
);
226 CFMutableArrayRef
SOSTransportDispatchMessages(SOSAccountRef account
, CFDictionaryRef updates
, CFErrorRef
*error
){
228 CFMutableArrayRef handledKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
230 if(CFDictionaryContainsKey(updates
, kSOSKVSAccountChangedKey
)){
231 secnotice("accountChange", "SOSTransportDispatchMessages received kSOSKVSAccountChangedKey");
232 // While changing accounts we may modify the key params array. To avoid stepping on ourselves we
233 // copy the list for iteration.
234 CFArrayRef originalKeyParams
= CFArrayCreateCopy(kCFAllocatorDefault
, SOSGetTransportKeyParameters());
235 CFArrayForEach(originalKeyParams
, ^(const void *value
) {
236 SOSTransportKeyParameterRef tkvs
= (SOSTransportKeyParameterRef
) value
;
237 if( (SOSTransportKeyParameterGetAccount((SOSTransportKeyParameterRef
)value
), account
)){
238 SOSTransportKeyParameterHandleNewAccount(tkvs
);
241 CFReleaseNull(originalKeyParams
);
242 CFArrayAppendValue(handledKeys
, kSOSKVSAccountChangedKey
);
245 // Iterate through keys in updates. Perform circle change update.
246 // Then instantiate circles and engines and peers for all peers that
247 // are receiving a message in updates.
248 CFMutableDictionaryRef circle_peer_messages_table
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
249 CFMutableDictionaryRef circle_circle_messages_table
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
250 CFMutableDictionaryRef circle_retirement_messages_table
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
251 __block CFDataRef newParameters
= NULL
;
252 __block
bool initial_sync
= false;
253 __block
bool new_account
= false;
255 CFDictionaryForEach(updates
, ^(const void *key
, const void *value
) {
256 CFErrorRef localError
= NULL
;
257 CFStringRef circle_name
= NULL
;
258 CFStringRef from_name
= NULL
;
259 CFStringRef to_name
= NULL
;
260 switch (SOSKVSKeyGetKeyTypeAndParse(key
, &circle_name
, &from_name
, &to_name
)) {
262 CFDictionarySetValue(circle_circle_messages_table
, circle_name
, value
);
264 case kInitialSyncKey
:
269 newParameters
= (CFDataRef
) CFRetainSafe(value
);
273 CFMutableDictionaryRef circle_messages
= CFDictionaryEnsureCFDictionaryAndGetCurrentValue(circle_peer_messages_table
, circle_name
);
274 CFDictionarySetValue(circle_messages
, from_name
, value
);
277 case kRetirementKey
: {
278 CFMutableDictionaryRef circle_retirements
= CFDictionaryEnsureCFDictionaryAndGetCurrentValue(circle_retirement_messages_table
, circle_name
);
279 CFDictionarySetValue(circle_retirements
, from_name
, value
);
282 case kAccountChangedKey
:
287 secnotice("updates", "Unknown key '%@', ignoring", key
);
292 CFReleaseNull(circle_name
);
293 CFReleaseNull(from_name
);
294 CFReleaseNull(to_name
);
297 secerror("Peer message processing error for: %@ -> %@ (%@)", key
, value
, *error
);
299 secerror("Peer message local processing error for: %@ -> %@ (%@)", key
, value
, localError
);
301 CFReleaseNull(localError
);
306 CFArrayForEach(SOSGetTransportKeyParameters(), ^(const void *value
) {
307 SOSTransportKeyParameterRef tkvs
= (SOSTransportKeyParameterRef
) value
;
308 CFErrorRef localError
= NULL
;
309 if(CFEqualSafe(SOSTransportKeyParameterGetAccount(tkvs
), account
)){
310 if(!SOSTransportKeyParameterHandleKeyParameterChanges(tkvs
, newParameters
, localError
))
311 secerror("Transport failed to handle new key parameters: %@", localError
);
314 CFArrayAppendValue(handledKeys
, kSOSKVSKeyParametersKey
);
316 CFReleaseNull(newParameters
);
319 CFArrayAppendValue(handledKeys
, kSOSKVSInitialSyncKey
);
323 if(CFDictionaryGetCount(circle_retirement_messages_table
)) {
324 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value
) {
325 SOSTransportCircleRef tkvs
= (SOSTransportCircleRef
) value
;
326 if(CFEqualSafe(SOSTransportCircleGetAccount((SOSTransportCircleRef
)value
), account
)){
327 CFErrorRef localError
= NULL
;
328 CFDictionaryRef handledRetirementKeys
= SOSTransportCircleHandleRetirementMessages(tkvs
, circle_retirement_messages_table
, error
);
329 if(handledRetirementKeys
== NULL
){
330 secerror("Transport failed to handle retirement messages: %@", localError
);
332 CFDictionaryForEach(handledRetirementKeys
, ^(const void *key
, const void *value
) {
333 CFStringRef circle_name
= (CFStringRef
)key
;
334 CFArrayRef handledPeerIDs
= (CFArrayRef
)value
;
335 CFArrayForEach(handledPeerIDs
, ^(const void *value
) {
336 CFStringRef peer_id
= (CFStringRef
)value
;
337 CFStringRef keyHandled
= SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name
, peer_id
);
338 CFArrayAppendValue(handledKeys
, keyHandled
);
339 CFReleaseNull(keyHandled
);
343 CFReleaseNull(handledRetirementKeys
);
344 CFReleaseNull(localError
);
349 if(CFDictionaryGetCount(circle_circle_messages_table
)) {
350 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value
) {
351 SOSTransportCircleRef tkvs
= (SOSTransportCircleRef
) value
;
352 if(CFEqualSafe(SOSTransportCircleGetAccount((SOSTransportCircleRef
)value
), account
)){
353 CFArrayRef handleCircleMessages
= SOSTransportCircleHandleCircleMessages(tkvs
, circle_circle_messages_table
, error
);
354 CFErrorRef localError
= NULL
;
355 if(handleCircleMessages
== NULL
){
356 secerror("Transport failed to handle circle messages: %@", localError
);
357 } else if(CFArrayGetCount(handleCircleMessages
) == 0) {
358 if(CFDictionaryGetCount(circle_circle_messages_table
) != 0) {
359 secerror("Transport failed to process all circle messages: (%ld/%ld) %@",
360 CFArrayGetCount(handleCircleMessages
),
361 CFDictionaryGetCount(circle_circle_messages_table
), localError
);
363 secnotice("circle", "Transport handled no circle messages");
366 CFArrayForEach(handleCircleMessages
, ^(const void *value
) {
367 CFStringRef keyHandled
= SOSCircleKeyCreateWithName((CFStringRef
)value
, error
);
368 CFArrayAppendValue(handledKeys
, keyHandled
);
369 CFReleaseNull(keyHandled
);
372 CFReleaseNull(localError
);
374 if (!SOSTransportCircleFlushChanges(tkvs
, &localError
))
375 secerror("error flushing changes: %@", localError
);
377 CFReleaseNull(localError
);
378 CFReleaseNull(handleCircleMessages
);
383 // TODO: These should all produce circle -> messageTypeHandled messages
384 // That probably needs to wait for separation of transport types.
385 if(CFDictionaryGetCount(circle_peer_messages_table
)) {
386 CFArrayForEach(SOSGetTransportMessages(), ^(const void *value
) {
387 SOSTransportMessageRef tkvs
= (SOSTransportMessageRef
) value
;
388 if(CFEqualSafe(SOSTransportMessageGetAccount((SOSTransportMessageRef
)value
), account
)){
389 CFErrorRef handleMessagesError
= NULL
;
390 CFDictionaryRef handledPeers
= SOSTransportMessageHandleMessages(tkvs
, circle_peer_messages_table
, &handleMessagesError
);
393 // We need to look for and send responses.
395 CFErrorRef syncError
= NULL
;
396 if (!SOSTransportMessageSyncWithPeers((SOSTransportMessageRef
)tkvs
, handledPeers
, &syncError
)) {
397 secerror("Sync with peers failed: %@", syncError
);
400 CFDictionaryForEach(handledPeers
, ^(const void *key
, const void *value
) {
401 if (isString(key
) && isArray(value
)) {
402 CFArrayForEach(value
, ^(const void *value
) {
403 if (isString(value
)) {
404 CFStringRef peerID
= (CFStringRef
) value
;
406 CFStringRef kvsHandledKey
= SOSMessageKeyCreateFromPeerToTransport((SOSTransportMessageKVSRef
)tkvs
, peerID
);
407 CFArrayAppendValue(handledKeys
, kvsHandledKey
);
408 CFReleaseSafe(kvsHandledKey
);
414 CFErrorRef flushError
= NULL
;
415 if (!SOSTransportMessageFlushChanges((SOSTransportMessageRef
)tkvs
, &flushError
)) {
416 secerror("Flush failed: %@", flushError
);
420 secerror("Didn't handle? : %@", handleMessagesError
);
422 CFReleaseNull(handledPeers
);
423 CFReleaseNull(handleMessagesError
);
427 CFReleaseNull(circle_retirement_messages_table
);
428 CFReleaseNull(circle_circle_messages_table
);
429 CFReleaseNull(circle_peer_messages_table
);
433 showWhatWasHandled(updates
, handledKeys
);