]> git.saurik.com Git - apple/security.git/blobdiff - Security/sec/SOSCircle/SecureObjectSync/SOSAccountCircles.c
Security-57031.1.35.tar.gz
[apple/security.git] / Security / sec / SOSCircle / SecureObjectSync / SOSAccountCircles.c
diff --git a/Security/sec/SOSCircle/SecureObjectSync/SOSAccountCircles.c b/Security/sec/SOSCircle/SecureObjectSync/SOSAccountCircles.c
new file mode 100644 (file)
index 0000000..47cba02
--- /dev/null
@@ -0,0 +1,170 @@
+//
+//  SOSAccountCircles.c
+//  sec
+//
+
+#include "SOSAccountPriv.h"
+#include <SecureObjectSync/SOSTransport.h>
+#include <SecureObjectSync/SOSTransportKeyParameterKVS.h>
+#include <SecureObjectSync/SOSTransportCircleKVS.h>
+#include <SecureObjectSync/SOSTransportMessageKVS.h>
+
+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;
+}
+