X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/sec/SOSCircle/SecureObjectSync/SOSAccountCircles.c?ds=inline diff --git a/Security/sec/SOSCircle/SecureObjectSync/SOSAccountCircles.c b/Security/sec/SOSCircle/SecureObjectSync/SOSAccountCircles.c new file mode 100644 index 00000000..47cba02a --- /dev/null +++ b/Security/sec/SOSCircle/SecureObjectSync/SOSAccountCircles.c @@ -0,0 +1,170 @@ +// +// SOSAccountCircles.c +// sec +// + +#include "SOSAccountPriv.h" +#include +#include +#include +#include + +void SOSAccountForEachCircle(SOSAccountRef account, void (^process)(SOSCircleRef circle)) +{ + CFDictionaryForEach(account->circles, ^(const void* key, const void* value) { + assert(value); + process((SOSCircleRef)value); + }); +} + + +void SOSAccountForEachKnownCircle(SOSAccountRef account, + void (^handle_incompatible)(CFStringRef name), + void (^handle_no_peer)(SOSCircleRef circle), + void (^handle_peer)(SOSCircleRef circle, SOSFullPeerInfoRef full_peer)) { + CFDictionaryForEach(account->circles, ^(const void *key, const void *value) { + if (isNull(value)) { + if (handle_incompatible) + handle_incompatible((CFStringRef)key); + } else { + SOSCircleRef circle = (SOSCircleRef) value; + CFRetainSafe(circle); + SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInCircleNamedIfPresent(account, SOSCircleGetName(circle), NULL); + if (!fpi) { + if (handle_no_peer) + handle_no_peer(circle); + } else { + CFRetainSafe(fpi); + if (handle_peer) + handle_peer(circle, fpi); + CFReleaseSafe(fpi); + } + CFReleaseSafe(circle); + } + }); +} + +// +// MARK: Circle management +// + +int SOSAccountCountCircles(SOSAccountRef a) { + assert(a); + assert(a->circle_identities); + assert(a->circles); + return (int)CFDictionaryGetCount(a->circles); +} + + + +SOSCircleRef SOSAccountFindCircle(SOSAccountRef a, CFStringRef name, CFErrorRef *error) +{ + CFTypeRef entry = CFDictionaryGetValue(a->circles, name); + + require_action_quiet(!isNull(entry), fail, + SOSCreateError(kSOSErrorIncompatibleCircle, CFSTR("Incompatible circle in KVS"), NULL, error)); + + require_action_quiet(entry, fail, + SOSCreateError(kSOSErrorNoCircle, CFSTR("No circle found"), NULL, error)); + + + return (SOSCircleRef) entry; + +fail: + return NULL; +} + + +static bool SOSAccountInflateTransportsForCircle(SOSAccountRef account, CFStringRef circleName, CFErrorRef *error){ + bool success = false; + SOSTransportKeyParameterRef tKey = NULL; + SOSTransportCircleRef tCircle = NULL; + SOSTransportMessageRef tMessage = NULL; + SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInCircleNamed(account, circleName, error); + require_quiet(fpi, fail); + SOSPeerInfoRef myPeer = SOSFullPeerInfoGetPeerInfo(fpi); + require_quiet(myPeer, fail); + CFStringRef type = SOSPeerInfoGetTransportType(myPeer); + if(CFStringCompare(type, CFSTR("KVS"), 0) == kCFCompareEqualTo){ + tKey = (SOSTransportKeyParameterRef)SOSTransportKeyParameterKVSCreate(account, error); + tCircle = (SOSTransportCircleRef)SOSTransportCircleKVSCreate(account, circleName, error); + tMessage = (SOSTransportMessageRef)SOSTransportMessageKVSCreate(account, circleName, error); + require_quiet(tKey, fail); + require_quiet(tCircle, fail); + require_quiet(tMessage, fail); + + CFRetainAssign(account->key_transport, (SOSTransportKeyParameterRef)tKey); + CFDictionarySetValue(account->circle_transports, circleName, tCircle); + CFDictionarySetValue(account->message_transports, circleName, tMessage); + } + + success = true; +fail: + CFReleaseNull(tKey); + CFReleaseNull(tCircle); + CFReleaseNull(tMessage); + return success; +} + +SOSCircleRef SOSAccountEnsureCircle(SOSAccountRef a, CFStringRef name, CFErrorRef *error) +{ + CFErrorRef localError = NULL; + + SOSCircleRef circle = SOSAccountFindCircle(a, name, &localError); + + require_action_quiet(circle || !isSOSErrorCoded(localError, kSOSErrorIncompatibleCircle), fail, + if (error) { *error = localError; localError = NULL; }); + + if(NULL == circle){ + circle = SOSCircleCreate(NULL, name, NULL); + if (circle){ + CFDictionaryAddValue(a->circles, name, circle); + CFRelease(circle); + circle = SOSAccountFindCircle(a, name, &localError); + } + + SOSUpdateKeyInterest(); + } + + require_quiet(SOSAccountInflateTransportsForCircle(a, name, error), fail); + +fail: + CFReleaseNull(localError); + return circle; +} + + +bool SOSAccountUpdateCircleFromRemote(SOSAccountRef account, SOSCircleRef newCircle, CFErrorRef *error) +{ + return SOSAccountHandleUpdateCircle(account, newCircle, false, error); +} + +bool SOSAccountUpdateCircle(SOSAccountRef account, SOSCircleRef newCircle, CFErrorRef *error) +{ + return SOSAccountHandleUpdateCircle(account, newCircle, true, error); +} + +bool SOSAccountModifyCircle(SOSAccountRef account, + CFStringRef circleName, + CFErrorRef* error, + bool (^action)(SOSCircleRef circle)) +{ + bool success = false; + + SOSCircleRef circle = NULL; + SOSCircleRef accountCircle = SOSAccountFindCircle(account, circleName, error); + require_quiet(accountCircle, fail); + + circle = SOSCircleCopyCircle(kCFAllocatorDefault, accountCircle, error); + require_quiet(circle, fail); + + success = true; + require_quiet(action(circle), fail); + + success = SOSAccountUpdateCircle(account, circle, error); + +fail: + CFReleaseSafe(circle); + return success; +} +