#include "SOSAccountPriv.h"
#include <Security/SecureObjectSync/SOSTransport.h>
#include <Security/SecureObjectSync/SOSRingUtils.h>
const CFStringRef kSOSRingCircleV2 = CFSTR("Ring-CircleV2");
const CFStringRef kSOSRingKeychainV0 = CFSTR("Ring-KeychainV0");
const CFStringRef kSOSRingPCSHyperion = CFSTR("Ring-PCS-Photos");
const CFStringRef kSOSRingPCSBladerunner = CFSTR("Ring-PCS-iCloudDrive");
const CFStringRef kSOSRingPCSLiverpool = CFSTR("Ring-PCS-CloudKit");
const CFStringRef kSOSRingPCSEscrow = CFSTR("Ring-PCS-Escrow");
const CFStringRef kSOSRingPCSPianoMover = CFSTR("Ring-PCS-Maildrop");
const CFStringRef kSOSRingPCSNotes = CFSTR("Ring-PCS-Notes");
const CFStringRef kSOSRingPCSFeldspar = CFSTR("Ring-PCS-Feldspar");
const CFStringRef kSOSRingAppleTV = CFSTR("Ring-AppleTV");
const CFStringRef kSOSRingHomeKit = CFSTR("Ring-HomeKit");
const CFStringRef kSOSRingWifi = CFSTR("Ring-WiFi");
const CFStringRef kSOSRingPasswords = CFSTR("Ring-Passwords");
const CFStringRef kSOSRingCreditCards = CFSTR("Ring-CreditCards");
const CFStringRef kSOSRingiCloudIdentity = CFSTR("Ring-iCloudIdentity");
const CFStringRef kSOSRingOtherSyncable = CFSTR("Ring-OtherSyncable");
static CFSetRef allCurrentRings(void) {
static dispatch_once_t dot;
static CFMutableSetRef allRings = NULL;
dispatch_once(&dot, ^{
allRings = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
CFSetAddValue(allRings, kSOSRingCircleV2);
CFSetAddValue(allRings, kSOSRingKeychainV0);
CFSetAddValue(allRings, kSOSRingPCSHyperion);
CFSetAddValue(allRings, kSOSRingPCSBladerunner);
CFSetAddValue(allRings, kSOSRingPCSLiverpool);
CFSetAddValue(allRings, kSOSRingPCSEscrow);
CFSetAddValue(allRings, kSOSRingPCSPianoMover);
CFSetAddValue(allRings, kSOSRingPCSNotes);
CFSetAddValue(allRings, kSOSRingPCSFeldspar);
CFSetAddValue(allRings, kSOSRingAppleTV);
CFSetAddValue(allRings, kSOSRingHomeKit);
CFSetAddValue(allRings, kSOSRingWifi);
CFSetAddValue(allRings, kSOSRingPasswords);
CFSetAddValue(allRings, kSOSRingCreditCards);
CFSetAddValue(allRings, kSOSRingiCloudIdentity);
CFSetAddValue(allRings, kSOSRingOtherSyncable);
});
return allRings;
}
typedef struct ringDef_t {
CFStringRef name;
SOSRingType ringType;
bool dropWhenLeaving;
} ringDef, *ringDefPtr;
static ringDefPtr getRingDef(CFStringRef ringName) {
static ringDef retval;
retval.name = ringName;
retval.dropWhenLeaving = true;
retval.ringType = kSOSRingEntropyKeyed;
if(CFEqual(ringName, kSOSRingKeychainV0) == 0) {
} else if(CFEqual(ringName, kSOSRingPCSHyperion) == 0) {
} else if(CFEqual(ringName, kSOSRingPCSBladerunner) == 0) {
} else if(CFEqual(ringName, kSOSRingKeychainV0) == 0) {
} else if(CFEqual(ringName, kSOSRingKeychainV0) == 0) {
} else if(CFEqual(ringName, kSOSRingKeychainV0) == 0) {
} else if(CFEqual(ringName, kSOSRingKeychainV0) == 0) {
} else if(CFEqual(ringName, kSOSRingCircleV2) == 0) {
retval.ringType = kSOSRingBase;
retval.dropWhenLeaving = false;
} else return NULL;
return &retval;
}
#if 0
static bool isRingKnown(CFStringRef ringname) {
if(getRingDef(ringname) != NULL) return true;
secnotice("rings","Not a known ring");
return false;
}
#endif
static inline void SOSAccountRingForEach(void (^action)(CFStringRef ringname)) {
CFSetRef allRings = allCurrentRings();
CFSetForEach(allRings, ^(const void *value) {
CFStringRef ringName = (CFStringRef) value;
action(ringName);
});
}
__unused static inline void SOSAccountRingForEachRingMatching(SOSAccountRef a, void (^action)(SOSRingRef ring), bool (^condition)(SOSRingRef ring)) {
CFSetRef allRings = allCurrentRings();
CFSetForEach(allRings, ^(const void *value) {
CFStringRef ringName = (CFStringRef) value;
SOSRingRef ring = SOSAccountGetRing(a, ringName, NULL);
if (condition(ring))
action(ring);
});
}
CFMutableDictionaryRef SOSAccountGetRings(SOSAccountRef a, CFErrorRef *error){
return a->trusted_rings;
}
CFMutableDictionaryRef SOSAccountGetBackups(SOSAccountRef a, CFErrorRef *error){
return a->backups;
}
SOSRingRef SOSAccountGetRing(SOSAccountRef a, CFStringRef ringName, CFErrorRef *error) {
CFTypeRef entry = CFDictionaryGetValue(a->trusted_rings, ringName);
require_action_quiet(entry, fail,
SOSCreateError(kSOSErrorNoRing, CFSTR("No Ring found"), NULL, error));
return (SOSRingRef) entry;
fail:
return NULL;
}
CFStringRef SOSAccountGetMyPeerID(SOSAccountRef a) {
SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInfo(a);
require_quiet(fpi, errOut);
SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(fpi);
require_quiet(pi, errOut);
return SOSPeerInfoGetPeerID(pi);
errOut:
return NULL;
}
SOSRingRef SOSAccountRingCreateForName(SOSAccountRef a, CFStringRef ringName, CFErrorRef *error) {
ringDefPtr rdef = getRingDef(ringName);
if(!rdef) return NULL;
SOSRingRef retval = SOSRingCreate(rdef->name, SOSAccountGetMyPeerID(a), rdef->ringType, error);
return retval;
}
bool SOSAccountCheckForRings(SOSAccountRef a, CFErrorRef *error) {
bool retval = isDictionary(a->trusted_rings);
if(!retval) SOSCreateError(kSOSErrorNotReady, CFSTR("Rings not present"), NULL, error);
return retval;
}
bool SOSAccountEnsureRings(SOSAccountRef a, CFErrorRef *error) {
bool status = false;
if(!a->trusted_rings) {
a->trusted_rings = CFDictionaryCreateMutableForCFTypes(NULL);
}
require_quiet(SOSAccountEnsureFullPeerAvailable(a, error), errOut);
SOSAccountRingForEach(^(CFStringRef ringname) {
SOSRingRef ring = SOSAccountGetRing(a, ringname, NULL);
if(!ring) {
ring = SOSAccountRingCreateForName(a, ringname, error);
if(ring) {
CFDictionaryAddValue(a->trusted_rings, ringname, ring);
SOSUpdateKeyInterest();
}
CFReleaseNull(ring);
}
});
status = true;
errOut:
return status;
}
bool SOSAccountUpdateRingFromRemote(SOSAccountRef account, SOSRingRef newRing, CFErrorRef *error) {
return SOSAccountHandleUpdateRing(account, newRing, false, error);
}
bool SOSAccountUpdateRing(SOSAccountRef account, SOSRingRef newRing, CFErrorRef *error) {
return SOSAccountHandleUpdateRing(account, newRing, true, error);
}
bool SOSAccountModifyRing(SOSAccountRef account, CFStringRef ringName, CFErrorRef* error, bool (^action)(SOSRingRef ring)) {
bool success = false;
SOSRingRef ring = SOSAccountGetRing(account, ringName, error);
require_action_quiet(ring, fail, SOSErrorCreate(kSOSErrorNoRing, error, NULL, CFSTR("No Ring to get peer key from")));
ring = SOSRingCopyRing(ring, error);
require_quiet(ring, fail);
success = true;
require_quiet(action(ring), fail);
success = SOSAccountUpdateRing(account, ring, error);
fail:
CFReleaseSafe(ring);
return success;
}
CFDataRef SOSAccountRingGetPayload(SOSAccountRef account, CFStringRef ringName, CFErrorRef *error) {
SOSRingRef ring = SOSAccountGetRing(account, ringName, error);
return SOSRingGetPayload(ring, error);
}
SOSRingRef SOSAccountRingCopyWithPayload(SOSAccountRef account, CFStringRef ringName, CFDataRef payload, CFErrorRef *error) {
SOSRingRef ring = SOSAccountGetRing(account, ringName, error);
require_quiet(ring, errOut);
SOSRingRef new = SOSRingCopyRing(ring, error);
require_quiet(new, errOut);
CFDataRef oldpayload = SOSRingGetPayload(ring, error);
require_quiet(!CFEqualSafe(oldpayload, payload), errOut);
require_quiet(SOSRingSetPayload(new, NULL, payload, account->my_identity, error), errOut);
errOut:
return NULL;
}