]> git.saurik.com Git - apple/security.git/blobdiff - Security/libsecurity_transform/lib/CoreFoundationBasics.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / Security / libsecurity_transform / lib / CoreFoundationBasics.cpp
diff --git a/Security/libsecurity_transform/lib/CoreFoundationBasics.cpp b/Security/libsecurity_transform/lib/CoreFoundationBasics.cpp
new file mode 100644 (file)
index 0000000..cb1bb51
--- /dev/null
@@ -0,0 +1,283 @@
+#include <libkern/OSAtomic.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+#include "CoreFoundationBasics.h"
+#include "Block.h"
+#include "TransformFactory.h"
+#include "Utilities.h"
+#include "syslog.h"
+#include "misc.h"
+
+using namespace std;
+
+
+const CFStringRef gInternalCFObjectName = CFSTR("SecTransform Internal Object");
+const CFStringRef gInternalProtectedCFObjectName = CFSTR("SecTransform Internal Object (protected)");
+
+struct RegisteredClassInfo
+{
+       CFRuntimeClass mClass;
+       CFTypeID mClassID;
+       RegisteredClassInfo();
+    void Register(CFStringRef name);
+
+    static const RegisteredClassInfo *Find(CFStringRef name);
+    static dispatch_queue_t readWriteLock;
+    static dispatch_once_t initializationGuard;
+    static CFMutableDictionaryRef registeredInfos;
+};
+
+dispatch_queue_t RegisteredClassInfo::readWriteLock;
+dispatch_once_t RegisteredClassInfo::initializationGuard;
+CFMutableDictionaryRef RegisteredClassInfo::registeredInfos;
+
+/*
+       THE FOLLOWING FUNCTION REGISTERS YOUR CLASS.  YOU MUST CALL YOUR CLASS INITIALIZER HERE!
+*/
+
+static CFErrorRef gNoMemory;
+
+CFErrorRef GetNoMemoryError()
+{
+       return gNoMemory;
+}
+
+
+
+CFErrorRef GetNoMemoryErrorAndRetain()
+{
+       return (CFErrorRef) CFRetain(gNoMemory);
+}
+
+
+
+static void CoreFoundationObjectRegister()
+{
+       static dispatch_once_t gate = 0;
+
+       dispatch_once(&gate,
+       ^{
+               // Init NoMemory here, so other places we can safely return it (otherwise we might
+               // not have enough memory to allocate the CFError)
+               gNoMemory = CreateGenericErrorRef(kCFErrorDomainPOSIX, ENOMEM, "Out of memory.");
+               
+        // only one registration for internal objects, cuts down on how many objects
+        // we register in the CF type table
+        CoreFoundationObject::RegisterObject(gInternalCFObjectName, false);
+        CoreFoundationObject::RegisterObject(gInternalProtectedCFObjectName, true);
+
+        // register any objects which may be exposed as API here
+        
+        // call for externalizable transforms.
+        TransformFactory::Setup();
+       });
+}
+
+
+
+RegisteredClassInfo::RegisteredClassInfo()
+{
+       memset(&mClass, 0, sizeof(mClass));
+    dispatch_once(&RegisteredClassInfo::initializationGuard, ^(void) {
+        RegisteredClassInfo::readWriteLock = dispatch_queue_create("com.apple.security.transform.cfobject.RegisteredClassInfo", DISPATCH_QUEUE_CONCURRENT);
+        RegisteredClassInfo::registeredInfos = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, NULL);
+    });
+}
+
+
+
+CoreFoundationObject::CoreFoundationObject(CFStringRef name) : mHolder(NULL), mObjectType(name)
+{
+}
+
+
+
+CoreFoundationObject::~CoreFoundationObject()
+{
+}
+
+
+
+CFHashCode CoreFoundationObject::Hash()
+{
+       // Valid for address equality only, overload for something else.
+       return (CFHashCode)mHolder;
+}
+
+void CoreFoundationObject::Finalize()
+{
+       delete this;
+}
+
+
+std::string CoreFoundationObject::FormattingDescription(CFDictionaryRef options)
+{
+       return "CoreFoundationObject";
+}
+
+
+
+std::string CoreFoundationObject::DebugDescription()
+{
+       return "CoreFoundationObject";
+}
+
+
+
+Boolean CoreFoundationObject::Equal(const CoreFoundationObject* obj)
+{
+       return mHolder == obj->mHolder;
+}
+
+
+
+static void FinalizeStub(CFTypeRef typeRef)
+{
+       CoreFoundationHolder::ObjectFromCFType(typeRef)->Finalize();
+}
+
+
+
+static Boolean IsEqualTo(CFTypeRef ref1, CFTypeRef ref2)
+{
+       if (CFGetTypeID(ref1) != CFGetTypeID(ref2)) {
+        // If ref2 isn't a CoreFoundatonHolder treating
+        // it like one is likely to crash.  (One could
+        // argue that we should check to see if ref2
+        // is *any* CoreFoundationHolder registered
+        // type)
+        return false;
+    }
+    
+    CoreFoundationHolder* tr1 = (CoreFoundationHolder*) ref1;
+       CoreFoundationHolder* tr2 = (CoreFoundationHolder*) ref2;
+       return tr1->mObject->Equal(tr2->mObject);
+}
+
+
+
+static CFHashCode MakeHash(CFTypeRef typeRef)
+{
+       CoreFoundationHolder* tr = (CoreFoundationHolder*) typeRef;
+       return tr->mObject->Hash();
+}
+
+
+
+static CFStringRef MakeFormattingDescription(CFTypeRef typeRef, CFDictionaryRef formatOptions)
+{
+       // get the string
+       CoreFoundationHolder* tr = (CoreFoundationHolder*) typeRef;
+       string desc = tr->mObject->FormattingDescription(formatOptions);
+       
+       if (desc.length() == 0)
+       {
+               return NULL;
+       }
+       
+       // convert it to a CFString
+       return CFStringCreateWithCString(NULL, desc.c_str(), kCFStringEncodingMacRoman);
+}
+
+
+static CFStringRef MakeDebugDescription(CFTypeRef typeRef)
+{
+       // get the string
+       CoreFoundationHolder* tr = (CoreFoundationHolder*) typeRef;
+       string desc = tr->mObject->DebugDescription();
+       
+       if (desc.length() == 0)
+       {
+               return NULL;
+       }
+       
+       // convert it to a CFString
+       return CFStringCreateWithCString(NULL, desc.c_str(), kCFStringEncodingMacRoman);
+}
+
+
+
+
+void CoreFoundationObject::RegisterObject(CFStringRef name, bool protectDelete)
+{
+       RegisteredClassInfo *classRecord = new RegisteredClassInfo;
+       
+    classRecord->mClass.version = 0;
+    // XXX: this is kind of lame, "name" is almost always a CFSTR, so it would
+    // be best to use the CFStringGetPtr result AND hold a reference to the
+    // name string, but fall back to utf8...   (note there is no unRegisterObject)
+    char *utf8_name = utf8(name);
+    classRecord->mClass.className = strdup(utf8_name);
+    free(utf8_name);
+    classRecord->mClass.init = NULL;
+    classRecord->mClass.copy = NULL;
+    classRecord->mClass.finalize = protectDelete ? NULL : FinalizeStub;
+    classRecord->mClass.equal = IsEqualTo;
+    classRecord->mClass.hash = MakeHash;
+    classRecord->mClass.copyFormattingDesc = MakeFormattingDescription;
+    classRecord->mClass.copyDebugDesc = MakeDebugDescription;
+    classRecord->mClassID = _CFRuntimeRegisterClass((const CFRuntimeClass * const)&classRecord->mClass);
+    classRecord->Register(name);
+}
+
+
+
+CFTypeID CoreFoundationObject::FindObjectType(CFStringRef name)
+{
+    const RegisteredClassInfo *classInfo = RegisteredClassInfo::Find(name);
+    if (classInfo) {
+        return classInfo->mClassID;
+    } else {
+        return _kCFRuntimeNotATypeID;
+    }
+}
+
+const RegisteredClassInfo *RegisteredClassInfo::Find(CFStringRef name)
+{
+    __block const RegisteredClassInfo *ret = NULL;
+    dispatch_sync(RegisteredClassInfo::readWriteLock, ^(void) {
+        ret = (const RegisteredClassInfo *)CFDictionaryGetValue(RegisteredClassInfo::registeredInfos, name);
+    });
+    
+    return ret;
+}
+
+void RegisteredClassInfo::Register(CFStringRef name)
+{
+    dispatch_barrier_sync(RegisteredClassInfo::readWriteLock, ^(void) {
+        CFDictionarySetValue(RegisteredClassInfo::registeredInfos, name, this);
+    });
+}
+
+CFStringRef CoreFoundationObject::GetTypeAsCFString()
+{
+       return mObjectType;
+}
+
+
+
+CoreFoundationHolder* CoreFoundationHolder::MakeHolder(CFStringRef name, CoreFoundationObject* object)
+{
+       // setup the CoreFoundation registry, just in case we need it.
+
+       CoreFoundationObjectRegister();
+       
+       CoreFoundationHolder* data = (CoreFoundationHolder*) _CFRuntimeCreateInstance(kCFAllocatorDefault,
+                                                                                                                       CoreFoundationObject::FindObjectType(name),
+                                                                                                                       sizeof(CoreFoundationHolder) - sizeof(CFRuntimeBase),
+                                                                                                                       NULL);
+       data->mObject = object;
+       object->SetHolder(data);
+
+       return data;
+}
+
+
+
+CoreFoundationObject* CoreFoundationHolder::ObjectFromCFType(CFTypeRef type)
+{
+       return ((CoreFoundationHolder*) type)->mObject;
+}
+
+
+