]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_transform/lib/CoreFoundationBasics.cpp
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / libsecurity_transform / lib / CoreFoundationBasics.cpp
1 #include <libkern/OSAtomic.h>
2 #include <CoreFoundation/CoreFoundation.h>
3
4 #include "CoreFoundationBasics.h"
5 #include "Block.h"
6 #include "TransformFactory.h"
7 #include "Utilities.h"
8 #include "syslog.h"
9 #include "misc.h"
10
11 using namespace std;
12
13
14 const CFStringRef gInternalCFObjectName = CFSTR("SecTransform Internal Object");
15 const CFStringRef gInternalProtectedCFObjectName = CFSTR("SecTransform Internal Object (protected)");
16
17 struct RegisteredClassInfo
18 {
19 CFRuntimeClass mClass;
20 CFTypeID mClassID;
21 RegisteredClassInfo();
22 void Register(CFStringRef name);
23
24 static const RegisteredClassInfo *Find(CFStringRef name);
25 static dispatch_queue_t readWriteLock;
26 static dispatch_once_t initializationGuard;
27 static CFMutableDictionaryRef registeredInfos;
28 };
29
30 dispatch_queue_t RegisteredClassInfo::readWriteLock;
31 dispatch_once_t RegisteredClassInfo::initializationGuard;
32 CFMutableDictionaryRef RegisteredClassInfo::registeredInfos;
33
34 /*
35 THE FOLLOWING FUNCTION REGISTERS YOUR CLASS. YOU MUST CALL YOUR CLASS INITIALIZER HERE!
36 */
37
38 static CFErrorRef gNoMemory;
39
40 CFErrorRef GetNoMemoryError()
41 {
42 return gNoMemory;
43 }
44
45
46
47 CFErrorRef GetNoMemoryErrorAndRetain()
48 {
49 return (CFErrorRef) CFRetainSafe(gNoMemory);
50 }
51
52
53
54 static void CoreFoundationObjectRegister()
55 {
56 static dispatch_once_t gate = 0;
57
58 dispatch_once(&gate,
59 ^{
60 // Init NoMemory here, so other places we can safely return it (otherwise we might
61 // not have enough memory to allocate the CFError)
62 gNoMemory = CreateGenericErrorRef(kCFErrorDomainPOSIX, ENOMEM, "Out of memory.");
63
64 // only one registration for internal objects, cuts down on how many objects
65 // we register in the CF type table
66 CoreFoundationObject::RegisterObject(gInternalCFObjectName, false);
67 CoreFoundationObject::RegisterObject(gInternalProtectedCFObjectName, true);
68
69 // register any objects which may be exposed as API here
70
71 // call for externalizable transforms.
72 TransformFactory::Setup();
73 });
74 }
75
76
77
78 RegisteredClassInfo::RegisteredClassInfo()
79 {
80 memset(&mClass, 0, sizeof(mClass));
81 dispatch_once(&RegisteredClassInfo::initializationGuard, ^(void) {
82 RegisteredClassInfo::readWriteLock = dispatch_queue_create("com.apple.security.transform.cfobject.RegisteredClassInfo", DISPATCH_QUEUE_CONCURRENT);
83 RegisteredClassInfo::registeredInfos = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, NULL);
84 });
85 }
86
87
88
89 CoreFoundationObject::CoreFoundationObject(CFStringRef name) : mHolder(NULL), mObjectType(name)
90 {
91 }
92
93
94
95 CoreFoundationObject::~CoreFoundationObject()
96 {
97 }
98
99
100
101 CFHashCode CoreFoundationObject::Hash()
102 {
103 // Valid for address equality only, overload for something else.
104 return (CFHashCode)mHolder;
105 }
106
107 void CoreFoundationObject::Finalize()
108 {
109 delete this;
110 }
111
112
113 std::string CoreFoundationObject::FormattingDescription(CFDictionaryRef options)
114 {
115 return "CoreFoundationObject";
116 }
117
118
119
120 std::string CoreFoundationObject::DebugDescription()
121 {
122 return "CoreFoundationObject";
123 }
124
125
126
127 Boolean CoreFoundationObject::Equal(const CoreFoundationObject* obj)
128 {
129 return mHolder == obj->mHolder;
130 }
131
132
133
134 static void FinalizeStub(CFTypeRef typeRef)
135 {
136 CoreFoundationHolder::ObjectFromCFType(typeRef)->Finalize();
137 }
138
139
140
141 static Boolean IsEqualTo(CFTypeRef ref1, CFTypeRef ref2)
142 {
143 if (CFGetTypeID(ref1) != CFGetTypeID(ref2)) {
144 // If ref2 isn't a CoreFoundatonHolder treating
145 // it like one is likely to crash. (One could
146 // argue that we should check to see if ref2
147 // is *any* CoreFoundationHolder registered
148 // type)
149 return false;
150 }
151
152 CoreFoundationHolder* tr1 = (CoreFoundationHolder*) ref1;
153 CoreFoundationHolder* tr2 = (CoreFoundationHolder*) ref2;
154 return tr1->mObject->Equal(tr2->mObject);
155 }
156
157
158
159 static CFHashCode MakeHash(CFTypeRef typeRef)
160 {
161 CoreFoundationHolder* tr = (CoreFoundationHolder*) typeRef;
162 return tr->mObject->Hash();
163 }
164
165
166
167 static CFStringRef MakeFormattingDescription(CFTypeRef typeRef, CFDictionaryRef formatOptions) CF_RETURNS_RETAINED
168 {
169 // get the string
170 CoreFoundationHolder* tr = (CoreFoundationHolder*) typeRef;
171 string desc = tr->mObject->FormattingDescription(formatOptions);
172
173 if (desc.length() == 0)
174 {
175 return NULL;
176 }
177
178 // convert it to a CFString
179 return CFStringCreateWithCString(NULL, desc.c_str(), kCFStringEncodingMacRoman);
180 }
181
182
183 static CFStringRef MakeDebugDescription(CFTypeRef typeRef) CF_RETURNS_RETAINED
184 {
185 // get the string
186 CoreFoundationHolder* tr = (CoreFoundationHolder*) typeRef;
187 string desc = tr->mObject->DebugDescription();
188
189 if (desc.length() == 0)
190 {
191 return NULL;
192 }
193
194 // convert it to a CFString
195 return CFStringCreateWithCString(NULL, desc.c_str(), kCFStringEncodingMacRoman);
196 }
197
198
199
200
201 void CoreFoundationObject::RegisterObject(CFStringRef name, bool protectDelete)
202 {
203 RegisteredClassInfo *classRecord = new RegisteredClassInfo;
204
205 classRecord->mClass.version = 0;
206 // XXX: this is kind of lame, "name" is almost always a CFSTR, so it would
207 // be best to use the CFStringGetPtr result AND hold a reference to the
208 // name string, but fall back to utf8... (note there is no unRegisterObject)
209 char *utf8_name = utf8(name);
210 classRecord->mClass.className = strdup(utf8_name);
211 free(utf8_name);
212 classRecord->mClass.init = NULL;
213 classRecord->mClass.copy = NULL;
214 classRecord->mClass.finalize = protectDelete ? NULL : FinalizeStub;
215 classRecord->mClass.equal = IsEqualTo;
216 classRecord->mClass.hash = MakeHash;
217 classRecord->mClass.copyFormattingDesc = MakeFormattingDescription;
218 classRecord->mClass.copyDebugDesc = MakeDebugDescription;
219 classRecord->mClassID = _CFRuntimeRegisterClass((const CFRuntimeClass * const)&classRecord->mClass);
220 classRecord->Register(name);
221 }
222
223
224
225 CFTypeID CoreFoundationObject::FindObjectType(CFStringRef name)
226 {
227 const RegisteredClassInfo *classInfo = RegisteredClassInfo::Find(name);
228 if (classInfo) {
229 return classInfo->mClassID;
230 } else {
231 return _kCFRuntimeNotATypeID;
232 }
233 }
234
235 const RegisteredClassInfo *RegisteredClassInfo::Find(CFStringRef name)
236 {
237 __block const RegisteredClassInfo *ret = NULL;
238 dispatch_sync(RegisteredClassInfo::readWriteLock, ^(void) {
239 ret = (const RegisteredClassInfo *)CFDictionaryGetValue(RegisteredClassInfo::registeredInfos, name);
240 });
241
242 return ret;
243 }
244
245 void RegisteredClassInfo::Register(CFStringRef name)
246 {
247 dispatch_barrier_sync(RegisteredClassInfo::readWriteLock, ^(void) {
248 CFDictionarySetValue(RegisteredClassInfo::registeredInfos, name, this);
249 });
250 }
251
252 CFStringRef CoreFoundationObject::GetTypeAsCFString()
253 {
254 return mObjectType;
255 }
256
257
258
259 CoreFoundationHolder* CoreFoundationHolder::MakeHolder(CFStringRef name, CoreFoundationObject* object)
260 {
261 // setup the CoreFoundation registry, just in case we need it.
262
263 CoreFoundationObjectRegister();
264
265 CoreFoundationHolder* data = (CoreFoundationHolder*) _CFRuntimeCreateInstance(kCFAllocatorDefault,
266 CoreFoundationObject::FindObjectType(name),
267 sizeof(CoreFoundationHolder) - sizeof(CFRuntimeBase),
268 NULL);
269 data->mObject = object;
270 object->SetHolder(data);
271
272 return data;
273 }
274
275
276
277 CoreFoundationObject* CoreFoundationHolder::ObjectFromCFType(CFTypeRef type)
278 {
279 return ((CoreFoundationHolder*) type)->mObject;
280 }
281
282
283