6 #include "SOSAccountPriv.h"
7 #import "keychain/SecureObjectSync/SOSTransport.h"
8 #import "keychain/SecureObjectSync/SOSRingUtils.h"
9 #import "keychain/SecureObjectSync/SOSAccountTrust.h"
10 #import "keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.h"
12 #include "AssertMacros.h"
15 // MARK: Ring management
18 const CFStringRef kSOSRingCircleV2 = CFSTR("Ring-CircleV2");
19 const CFStringRef kSOSRingKeychainV0 = CFSTR("Ring-KeychainV0");
20 const CFStringRef kSOSRingPCSHyperion = CFSTR("Ring-PCS-Photos");
21 const CFStringRef kSOSRingPCSBladerunner = CFSTR("Ring-PCS-iCloudDrive");
22 const CFStringRef kSOSRingPCSLiverpool = CFSTR("Ring-PCS-CloudKit");
23 const CFStringRef kSOSRingPCSEscrow = CFSTR("Ring-PCS-Escrow");
24 const CFStringRef kSOSRingPCSPianoMover = CFSTR("Ring-PCS-Maildrop");
25 const CFStringRef kSOSRingPCSNotes = CFSTR("Ring-PCS-Notes");
26 const CFStringRef kSOSRingPCSFeldspar = CFSTR("Ring-PCS-Feldspar");
27 const CFStringRef kSOSRingAppleTV = CFSTR("Ring-AppleTV");
28 const CFStringRef kSOSRingHomeKit = CFSTR("Ring-HomeKit");
29 const CFStringRef kSOSRingWifi = CFSTR("Ring-WiFi");
30 const CFStringRef kSOSRingPasswords = CFSTR("Ring-Passwords");
31 const CFStringRef kSOSRingCreditCards = CFSTR("Ring-CreditCards");
32 const CFStringRef kSOSRingiCloudIdentity = CFSTR("Ring-iCloudIdentity");
33 const CFStringRef kSOSRingOtherSyncable = CFSTR("Ring-OtherSyncable");
35 const CFStringRef kSOSRingKey = CFSTR("trusted_rings");
37 static CFSetRef allCurrentRings(void) {
38 static dispatch_once_t dot;
39 static CFMutableSetRef allRings = NULL;
40 dispatch_once(&dot, ^{
41 allRings = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
42 CFSetAddValue(allRings, kSOSRingCircleV2);
43 CFSetAddValue(allRings, kSOSRingKeychainV0);
44 CFSetAddValue(allRings, kSOSRingPCSHyperion);
45 CFSetAddValue(allRings, kSOSRingPCSBladerunner);
46 CFSetAddValue(allRings, kSOSRingPCSLiverpool);
47 CFSetAddValue(allRings, kSOSRingPCSEscrow);
48 CFSetAddValue(allRings, kSOSRingPCSPianoMover);
49 CFSetAddValue(allRings, kSOSRingPCSNotes);
50 CFSetAddValue(allRings, kSOSRingPCSFeldspar);
51 CFSetAddValue(allRings, kSOSRingAppleTV);
52 CFSetAddValue(allRings, kSOSRingHomeKit);
53 CFSetAddValue(allRings, kSOSRingWifi);
54 CFSetAddValue(allRings, kSOSRingPasswords);
55 CFSetAddValue(allRings, kSOSRingCreditCards);
56 CFSetAddValue(allRings, kSOSRingiCloudIdentity);
57 CFSetAddValue(allRings, kSOSRingOtherSyncable);
62 typedef struct ringDef_t {
66 } ringDef, *ringDefPtr;
68 static ringDefPtr getRingDef(CFStringRef ringName) {
69 static ringDef retval;
72 retval.name = ringName;
73 retval.dropWhenLeaving = true;
74 retval.ringType = kSOSRingEntropyKeyed;
77 if(CFSetContainsValue(allCurrentRings(), ringName)) {
78 retval.ringType = kSOSRingBase;
79 retval.dropWhenLeaving = false;
81 retval.ringType = kSOSRingBackup;
82 retval.dropWhenLeaving = false;
87 __unused static inline void SOSAccountRingForEachRingMatching(SOSAccount* a, void (^action)(SOSRingRef ring), bool (^condition)(SOSRingRef ring)) {
88 CFSetRef allRings = allCurrentRings();
89 CFSetForEach(allRings, ^(const void *value) {
90 CFStringRef ringName = (CFStringRef) value;
91 SOSRingRef ring = [a.trust copyRing:ringName err:NULL];
92 if (condition(ring)) {
103 static void SOSAccountSetRings(SOSAccount* a, CFMutableDictionaryRef newrings){
104 SOSAccountTrustClassic *trust = a.trust;
105 [trust.expansion setObject:(__bridge NSMutableDictionary*)newrings forKey:(__bridge NSString* _Nonnull)(kSOSRingKey)];
108 bool SOSAccountForEachRing(SOSAccount* account, SOSRingRef (^action)(CFStringRef name, SOSRingRef ring)) {
110 __block bool changed = false;
111 __block CFStringRef ringname = NULL;
112 __block CFDataRef ringder = NULL;
113 __block SOSRingRef ring = NULL;
114 __block SOSRingRef newring = NULL;
115 __block CFDataRef newringder = NULL;
117 CFMutableDictionaryRef rings = [account.trust getRings:NULL];
118 CFMutableDictionaryRef ringscopy = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
120 CFReleaseNull(ringscopy);
124 CFReleaseNull(ringscopy);
127 CFDictionaryForEach(rings, ^(const void *key, const void *value) {
128 ringname = (CFStringRef) key;
129 ringder = CFDataCreateCopy(kCFAllocatorDefault, (CFDataRef) value);
130 CFDictionaryAddValue(ringscopy, key, ringder);
131 ring = SOSRingCreateFromData(NULL, ringder);
132 newring = action(ringname, ring);
134 newringder = SOSRingCopyEncodedData(newring, NULL);
135 CFDictionaryReplaceValue(ringscopy, key, newringder);
136 CFReleaseNull(newringder);
140 CFReleaseNull(ringder);
141 CFReleaseNull(newring);
144 SOSAccountSetRings(account, ringscopy);
148 CFReleaseNull(ringscopy);
152 void SOSAccountRemoveRing(SOSAccount* a, CFStringRef ringName) {
153 CFMutableDictionaryRef rings = [a.trust getRings:NULL];
154 require_quiet(rings, fail);
155 CFDictionaryRemoveValue(rings, ringName);
161 SOSRingRef SOSAccountCopyRingNamed(SOSAccount* a, CFStringRef ringName, CFErrorRef *error) {
166 SOSRingRef found = [a.trust copyRing:ringName err:error];
168 if (isSOSRing(found)) return found;
170 secerror("Non ring in ring table: %@, purging!", found);
171 SOSAccountRemoveRing(a, ringName);
173 CFReleaseNull(found); // I'm very skeptical of this function...
179 SOSRingRef SOSAccountRingCreateForName(SOSAccount* a, CFStringRef ringName, CFErrorRef *error) {
180 ringDefPtr rdef = getRingDef(ringName);
181 if(!rdef) return NULL;
182 SOSRingRef retval = SOSRingCreate(rdef->name, (__bridge CFStringRef) a.peerID, rdef->ringType, error);
186 bool SOSAccountUpdateRingFromRemote(SOSAccount* account, SOSRingRef newRing, CFErrorRef *error) {
187 require_quiet(SOSAccountHasPublicKey(account, error), errOut);
189 return [account.trust handleUpdateRing:account prospectiveRing:newRing transport:account.circle_transport userPublicKey:account.accountKey writeUpdate:false err:error];
194 bool SOSAccountUpdateRing(SOSAccount* account, SOSRingRef newRing, CFErrorRef *error) {
195 require_quiet(SOSAccountHasPublicKey(account, error), errOut);
197 return [account.trust handleUpdateRing:account prospectiveRing:newRing transport:account.circle_transport userPublicKey:account.accountKey writeUpdate:true err:error];
203 bool SOSAccountUpdateNamedRing(SOSAccount* account, CFStringRef ringName, CFErrorRef *error,
204 SOSRingRef (^create)(CFStringRef ringName, CFErrorRef *error),
205 SOSRingRef (^copyModified)(SOSRingRef existing, CFErrorRef *error)) {
207 SOSRingRef found = [account.trust copyRing:ringName err:error];
209 SOSRingRef newRing = NULL;
211 found = create(ringName, error);
213 require_quiet(found, errOut);
214 newRing = copyModified(found, error);
215 CFReleaseNull(found);
217 require_quiet(newRing, errOut);
219 require_quiet(SOSAccountHasPublicKey(account, error), errOut);
220 require_quiet(SOSAccountHasCircle(account, error), errOut);
222 result = [account.trust handleUpdateRing:account prospectiveRing:newRing transport:account.circle_transport userPublicKey:account.accountKey writeUpdate:true err:error];
225 CFReleaseNull(found);
226 CFReleaseNull(newRing);