2 // SOSTransportCircleKVS.c
5 #include "keychain/SecureObjectSync/SOSTransport.h"
6 #include "keychain/SecureObjectSync/SOSTransportCircle.h"
7 #include "keychain/SecureObjectSync/SOSTransportCircleKVS.h"
8 #include "keychain/SecureObjectSync/SOSKVSKeys.h"
9 #include "keychain/SecureObjectSync/SOSInternal.h"
10 #include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h"
11 #include <utilities/SecCFWrappers.h>
12 #import "keychain/SecureObjectSync/SOSAccountTrustClassic.h"
15 @implementation SOSKVSCircleStorageTransport
17 @synthesize pending_changes = pending_changes;
18 @synthesize circleName = circleName;
19 extern CFStringRef kSOSAccountDebugScope;
26 -(id)initWithAccount:(SOSAccount*)acct andCircleName:(NSString*)name
28 if ((self = [super init])) {
29 self.pending_changes = [NSMutableDictionary dictionary];
30 self.circleName = [[NSString alloc] initWithString:name];
32 SOSRegisterTransportCircle(self);
37 -(NSString*) getCircleName
39 return self.circleName;
42 -(CFIndex) getTransportType{
46 static bool SOSTransportCircleKVSUpdateKVS(NSDictionary *changes, CFErrorRef *error)
48 CloudKeychainReplyBlock log_error = ^(CFDictionaryRef returnedValues __unused, CFErrorRef block_error) {
50 secerror("Error putting: %@", block_error);
54 SOSCloudKeychainPutObjectsInCloud((__bridge CFDictionaryRef)(changes), dispatch_get_global_queue(SOS_TRANSPORT_PRIORITY, 0), log_error);
58 -(bool)kvsSendPendingChanges:(CFErrorRef *)error
60 CFErrorRef changeError = NULL;
62 if (self.pending_changes == NULL || [self.pending_changes count] == 0) {
66 CFTypeRef dsid = SOSAccountGetValue(account, kSOSDSIDKey, error);
70 [self.pending_changes setObject:(__bridge id _Nonnull)((void*)(dsid)) forKey:(__bridge NSString*)kSOSKVSRequiredKey];
72 bool success = SOSTransportCircleKVSUpdateKVS(self.pending_changes, &changeError);
74 [self.pending_changes removeAllObjects];
76 SOSCreateErrorWithFormat(kSOSErrorSendFailure, changeError, error, NULL,
77 CFSTR("Send changes block failed [%@]"), self.pending_changes);
83 -(void)kvsAddToPendingChanges:(CFStringRef) message_key data:(CFDataRef)message_data
85 if (self.pending_changes == NULL) {
86 self.pending_changes = [NSMutableDictionary dictionary];
88 if (message_data == NULL) {
89 [self.pending_changes setObject:[NSNull null] forKey:(__bridge NSString*)message_key];
91 [self.pending_changes setObject:(__bridge NSData*)message_data forKey:(__bridge NSString*)message_key];
95 static bool SOSTransportCircleKVSUpdateRetirementRecords(CFDictionaryRef updates, CFErrorRef* error){
96 CFErrorRef updateError = NULL;
98 if (SOSTransportCircleKVSUpdateKVS((__bridge NSDictionary*)updates, &updateError)){
101 SOSCreateErrorWithFormat(kSOSErrorSendFailure, updateError, error, NULL,
102 CFSTR("update parameters key failed [%@]"), updates);
106 -(bool) expireRetirementRecords:(CFDictionaryRef) retirements err:(CFErrorRef *)error
109 CFMutableDictionaryRef keysToWrite = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
111 CFDictionaryForEach(retirements, ^(const void *key, const void *value) {
112 if (isString(key) && isArray(value)) {
113 CFStringRef circle_name = (CFStringRef) key;
114 CFArrayRef retirees = (CFArrayRef) value;
116 CFArrayForEach(retirees, ^(const void *value) {
117 if (isString(value)) {
118 CFStringRef retiree_id = (CFStringRef) value;
120 CFStringRef kvsKey = SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name, retiree_id);
122 CFDictionaryAddValue(keysToWrite, kvsKey, kCFNull);
124 CFReleaseSafe(kvsKey);
130 if(CFDictionaryGetCount(keysToWrite)) {
131 success = SOSTransportCircleKVSUpdateRetirementRecords(keysToWrite, error);
133 CFReleaseNull(keysToWrite);
138 -(bool) flushChanges:(CFErrorRef *)error
140 return [self kvsSendPendingChanges:error];
144 -(bool) postCircle:(CFStringRef)name circleData:(CFDataRef)circle_data err:(CFErrorRef *)error
146 CFStringRef circle_key = SOSCircleKeyCreateWithName(name, error);
148 [self kvsAddToPendingChanges:circle_key data:circle_data];
150 CFReleaseNull(circle_key);
155 -(CFDictionaryRef)CF_RETURNS_RETAINED handleRetirementMessages:(CFMutableDictionaryRef) circle_retirement_messages_table err:(CFErrorRef *)error
157 return SOSAccountHandleRetirementMessages(self.account, circle_retirement_messages_table, error);
160 -(CFArrayRef)CF_RETURNS_RETAINED handleCircleMessagesAndReturnHandledCopy:(CFMutableDictionaryRef) circle_circle_messages_table err:(CFErrorRef *)error
162 CFMutableArrayRef handledKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
163 CFDictionaryForEach(circle_circle_messages_table, ^(const void *key, const void *value) {
164 CFErrorRef circleMessageError = NULL;
165 if(!isString(key) || !isData(value)) {
166 secerror("Error, Key-Value for CircleMessage was not CFString/CFData");
167 } if (!SOSAccountHandleCircleMessage(self.account, key, value, &circleMessageError)) {
168 secerror("Error handling circle message %@ (%@): %@", key, value, circleMessageError);
170 CFStringRef circle_id = (CFStringRef) key;
171 CFArrayAppendValue(handledKeys, circle_id);
173 CFReleaseNull(circleMessageError);
179 -(bool)kvsAppendKeyInterest:(CFMutableArrayRef) alwaysKeys firstUnlock:(CFMutableArrayRef) afterFirstUnlockKeys unlocked:(CFMutableArrayRef)unlockedKeys err:(CFErrorRef *)error
181 CFStringRef circle_name = NULL;
182 CFStringRef circle_key = NULL;
184 if(SOSAccountHasPublicKey(self.account, NULL)){
185 require_quiet(circle_name = (__bridge CFStringRef)self.circleName, fail);
186 require_quiet(circle_key = SOSCircleKeyCreateWithName(circle_name, error), fail);
188 require_quiet(account, fail);
189 SOSAccountTrustClassic *trust = account.trust;
190 SOSCircleRef circle = trust.trustedCircle;
191 require_quiet(circle && CFEqualSafe(circle_name, SOSCircleGetName(circle)), fail);
193 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
194 CFStringRef retirement_key = SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name, SOSPeerInfoGetPeerID(peer));
195 CFArrayAppendValue(alwaysKeys, retirement_key);
196 CFReleaseNull(retirement_key);
199 CFArrayAppendValue(unlockedKeys, circle_key); // This is where circle interest is handled
201 CFReleaseNull(circle_key);
206 CFReleaseNull(circle_key);
211 -(bool)kvsAppendRingKeyInterest:(CFMutableArrayRef) alwaysKeys firstUnlock:(CFMutableArrayRef)afterFirstUnlockKeys unlocked:(CFMutableArrayRef) unlockedKeys err:(CFErrorRef *)error
213 if(SOSAccountHasPublicKey(self.account, NULL)){
214 require_quiet(account, fail);
215 SOSAccountTrustClassic *trust = account.trust;
216 SOSCircleRef circle = trust.trustedCircle;
217 require_quiet(circle, fail);
219 // Always interested in backup rings:
220 SOSAccountForEachRingName(account, ^(CFStringRef ringName) {
221 CFStringRef ring_key = SOSRingKeyCreateWithRingName(ringName);
222 CFArrayAppendValue(unlockedKeys, ring_key);
223 CFReleaseNull(ring_key);
231 //register debug scope key
232 -(bool)kvsAppendDebugKeyInterest:(CFMutableArrayRef) alwaysKeys firstUnlock:(CFMutableArrayRef)afterFirstUnlockKeys unlocked:(CFMutableArrayRef) unlockedKeys err:(CFErrorRef *)error
234 CFStringRef key = SOSDebugInfoKeyCreateWithTypeName(kSOSAccountDebugScope);
235 CFArrayAppendValue(alwaysKeys, key);
240 //send debug info over KVS
241 -(bool) kvssendDebugInfo:(CFStringRef) type debug:(CFTypeRef) debugInfo err:(CFErrorRef *)error
243 CFStringRef key = SOSDebugInfoKeyCreateWithTypeName(type);
244 NSDictionary *changes = @{(__bridge NSString*)key:(__bridge id _Nonnull)debugInfo};
247 bool success = SOSTransportCircleKVSUpdateKVS(changes, error);
252 -(bool) kvsSendAccountChangedWithDSID:(CFStringRef) dsid err:(CFErrorRef *)error
254 NSDictionary *changes = @{(__bridge NSString*)kSOSKVSAccountChangedKey:(__bridge NSString*)dsid};
256 bool success = SOSTransportCircleKVSUpdateKVS(changes, error);
262 //send the Ring over KVS
263 -(bool) kvsRingPostRing:(CFStringRef) ringName ring:(CFDataRef) ring err:(CFErrorRef *)error
265 CFStringRef ringKey = SOSRingKeyCreateWithName(ringName, error);
268 [self kvsAddToPendingChanges:ringKey data:ring];
270 CFReleaseNull(ringKey);
275 -(bool) kvsRingFlushChanges:(CFErrorRef*) error
277 return [self kvsSendPendingChanges:error];
280 -(bool) kvsSendOfficialDSID:(CFStringRef) dsid err:(CFErrorRef *)error
282 NSDictionary *changes = @{(__bridge NSString*)kSOSKVSOfficialDSIDKey : (__bridge NSString*)dsid};
283 bool success = SOSTransportCircleKVSUpdateKVS(changes, error);
287 -(bool) postRetirement:(CFStringRef)circleName peer:(SOSPeerInfoRef)peer err:(CFErrorRef *)error
289 CFDataRef retirement_data = SOSPeerInfoCopyEncodedData(peer, kCFAllocatorDefault, error);
291 require_quiet(retirement_data, fail);
293 CFStringRef retirement_key = SOSRetirementKeyCreateWithCircleNameAndPeer((__bridge CFStringRef)(self.circleName), SOSPeerInfoGetPeerID(peer));
295 [self kvsAddToPendingChanges:retirement_key data:retirement_data];
297 CFReleaseNull(retirement_key);
298 CFReleaseNull(retirement_data);
301 CFReleaseNull(retirement_data);