1 #include "SecTransform.h"
2 #include "SecTransformInternal.h"
6 #include "TransformFactory.h"
7 #include "GroupTransform.h"
9 #include "SecCollectTransform.h"
16 const CFStringRef kSecTransformInputAttributeName
= CFSTR("INPUT");
17 const CFStringRef kSecTransformOutputAttributeName
= CFSTR("OUTPUT");
18 const CFStringRef kSecTransformDebugAttributeName
= CFSTR("DEBUG");
19 const CFStringRef kSecTransformTransformName
= CFSTR("NAME");
20 //const CFStringRef kSecTransformErrorTransform = CFSTR("TRANSFORM");
21 const CFStringRef kSecTransformErrorDomain
= CFSTR("com.apple.security.transforms.error");
22 const CFStringRef kSecTransformAbortAttributeName
= CFSTR("ABORT");
24 CFErrorRef
SecTransformConnectTransformsInternal(SecGroupTransformRef groupRef
,
25 SecTransformRef sourceTransformRef
,
26 CFStringRef sourceAttributeName
,
27 SecTransformRef destinationTransformRef
,
28 CFStringRef destinationAttributeName
)
30 Transform
* destination
= (Transform
*) CoreFoundationHolder::ObjectFromCFType(destinationTransformRef
);
31 Transform
* source
= (Transform
*) CoreFoundationHolder::ObjectFromCFType(sourceTransformRef
);
33 GroupTransform
* group
= (GroupTransform
*) CoreFoundationHolder::ObjectFromCFType(groupRef
);
34 CFErrorRef temp
= source
->Connect(group
, destination
, destinationAttributeName
, sourceAttributeName
);
39 CFErrorRef
SecTransformDisconnectTransforms(SecTransformRef sourceTransformRef
, CFStringRef sourceAttributeName
,
40 SecTransformRef destinationTransformRef
, CFStringRef destinationAttributeName
)
42 Transform
* destination
= (Transform
*) CoreFoundationHolder::ObjectFromCFType(destinationTransformRef
);
43 Transform
* source
= (Transform
*) CoreFoundationHolder::ObjectFromCFType(sourceTransformRef
);
44 return source
->Disconnect(destination
, sourceAttributeName
, destinationAttributeName
);
47 SecGroupTransformRef
SecTransformCreateGroupTransform()
49 return (SecGroupTransformRef
) GroupTransform::Make();
52 SecGroupTransformRef
SecTransformConnectTransforms(SecTransformRef sourceTransformRef
,
53 CFStringRef sourceAttributeName
,
54 SecTransformRef destinationTransformRef
,
55 CFStringRef destinationAttributeName
,
56 SecGroupTransformRef group
,
63 *error
= CreateSecTransformErrorRef(kSecTransformErrorMissingParameter
, "Group must not be NULL.");
69 if (destinationAttributeName
== NULL
)
71 destinationAttributeName
= kSecTransformInputAttributeName
;
74 if (sourceAttributeName
== NULL
)
76 sourceAttributeName
= kSecTransformOutputAttributeName
;
79 GroupTransform
* gtr
= (GroupTransform
*) CoreFoundationHolder::ObjectFromCFType(group
);
81 CFErrorRef temp
= SecTransformConnectTransformsInternal(gtr
->GetCFObject(),
82 sourceTransformRef
, sourceAttributeName
,
83 destinationTransformRef
, destinationAttributeName
);
90 if (temp
) // an error happened?
102 Boolean
SecTransformSetAttribute(SecTransformRef transformRef
,
107 Boolean result
= false; // Guilty until proven
108 Transform
* transform
= (Transform
*) CoreFoundationHolder::ObjectFromCFType(transformRef
);
110 if (CFGetTypeID(transformRef
) == GroupTransform::GetCFTypeID() && !transform
->getAH(key
, false))
114 *error
= CreateSecTransformErrorRef(kSecTransformOperationNotSupportedOnGroup
, "SecTransformSetAttribute on non-exported attribute: %@ (exported attributes are: %@).", key
, transform
->GetAllAH());
120 // if the caller is setting the abort attribute, a value must be supplied
121 if (NULL
== value
&& CFStringCompare(key
, kSecTransformAbortAttributeName
, 0) == kCFCompareEqualTo
)
125 // XXX: "a parameter"? It has one: NULL. What it requires is a non-NULL value.
126 *error
= CreateSecTransformErrorRef(kSecTransformInvalidArgument
, "ABORT requires a parameter.");
132 CFErrorRef temp
= transform
->ExternalSetAttribute(key
, value
);
133 result
= (temp
== NULL
);
151 CFTypeRef
SecTransformGetAttribute(SecTransformRef transformRef
,
154 // if the transform is a group, we really want to operation on its first object
155 if (CFGetTypeID(transformRef
) == GroupTransform::GetCFTypeID())
160 Transform
* transform
= (Transform
*) CoreFoundationHolder::ObjectFromCFType(transformRef
);
161 if (transform
->mIsActive
) {
162 return CreateSecTransformErrorRef(kSecTransformTransformIsExecuting
, "Can not get the value of attributes during execution (attempt to fetch %@/%@)", transform
->GetName(), key
);
164 return transform
->GetAttribute(key
);
169 static inline GroupTransform
* MakeGroupTransformFromTransformRef(SecTransformRef tr
)
171 GroupTransform
* gt
= (GroupTransform
*) CoreFoundationHolder::ObjectFromCFType(tr
);
175 static CFTypeRef
InternalSecTransformExecute(SecTransformRef transformRef
,
176 CFErrorRef
* errorRef
,
177 dispatch_queue_t deliveryQueue
,
178 SecMessageBlock deliveryBlock
)
180 if (NULL
== transformRef
|| (deliveryBlock
&& !deliveryQueue
))
182 CFErrorRef localError
= CFErrorCreate(kCFAllocatorDefault
, kSecTransformErrorDomain
,
183 kSecTransformInvalidArgument
, NULL
);
185 if (NULL
!= errorRef
)
187 *errorRef
= localError
;
191 CFRelease(localError
);
194 return (CFTypeRef
)NULL
;
197 // if our transform is a group, connect to its first member instead
198 if (CFGetTypeID(transformRef
) == GroupTransform::GetCFTypeID())
200 GroupTransform
* gtsrc
= (GroupTransform
*) CoreFoundationHolder::ObjectFromCFType(transformRef
);
201 transformRef
= gtsrc
->GetAnyMember();
204 Transform
* transform
= (Transform
*) CoreFoundationHolder::ObjectFromCFType(transformRef
);
205 return transform
->Execute(deliveryQueue
, deliveryBlock
, errorRef
);
208 CFTypeRef
SecTransformExecute(SecTransformRef transformRef
, CFErrorRef
* errorRef
)
210 if (NULL
== transformRef
)
214 *errorRef
= CreateSecTransformErrorRef(kSecTransformInvalidArgument
, "NULL transform can not be executed");
219 Transform
* transform
= (Transform
*) CoreFoundationHolder::ObjectFromCFType(transformRef
);
221 // transform->Execute will check this, but by then we have attached a collector which causes all manner of issues.
222 if (transform
->mIsActive
)
226 *errorRef
= CreateSecTransformErrorRef(kSecTransformTransformIsExecuting
, "The %@ transform has already executed, it may not be executed again.", transform
->GetName());
231 SecTransformRef collectTransform
= transforms_assume(SecCreateCollectTransform(errorRef
));
232 SecGroupTransformRef theGroup
= NULL
;
233 Boolean releaseTheGroup
= false;
234 GroupTransform
* myGroup
= NULL
;
235 Boolean needConnection
= true;
237 // Sniff the type of the transformRef to see if it is a group
238 if (SecGroupTransformGetTypeID() == CFGetTypeID(transformRef
))
240 theGroup
= (SecGroupTransformRef
)transformRef
;
244 // Ok TransformRef is a TransformRef so get's it group
246 myGroup
= transform
->mGroup
;
250 theGroup
= SecTransformCreateGroupTransform();
251 if (NULL
== theGroup
)
253 if (NULL
!= errorRef
)
255 *errorRef
= GetNoMemoryErrorAndRetain();
258 return (CFTypeRef
)NULL
;
262 releaseTheGroup
= true;
264 SecGroupTransformRef connectResult
=
265 SecTransformConnectTransforms(transformRef
,
266 kSecTransformOutputAttributeName
,
268 kSecTransformInputAttributeName
,
271 if (NULL
== connectResult
)
273 return (CFTypeRef
)NULL
;
276 needConnection
= false;
281 theGroup
= (SecGroupTransformRef
)myGroup
->GetCFObject();
285 if (NULL
== theGroup
|| (SecGroupTransformGetTypeID() != CFGetTypeID(theGroup
)))
287 if (NULL
!= errorRef
)
289 *errorRef
= GetNoMemoryErrorAndRetain();
292 return (CFTypeRef
)NULL
;
299 // Connect the collectTransform to the group
300 myGroup
= ((GroupTransform
*)CoreFoundationHolder::ObjectFromCFType(theGroup
))->GetRootGroup();
303 if (NULL
!= errorRef
)
305 *errorRef
= GetNoMemoryErrorAndRetain();
308 return (CFTypeRef
)NULL
;
311 SecTransformRef outputTransform
= myGroup
->FindLastTransform();
313 SecGroupTransformRef connectResult
=
314 SecTransformConnectTransforms(outputTransform
,
315 kSecTransformOutputAttributeName
,
317 kSecTransformInputAttributeName
,
318 myGroup
->GetCFObject(), errorRef
);
320 if (NULL
== connectResult
)
322 CFRelease(collectTransform
);
327 return (CFTypeRef
)NULL
;
331 __block CFTypeRef myResult
= NULL
;
332 dispatch_semaphore_t mySem
= dispatch_semaphore_create(0L);
333 dispatch_queue_t myQueue
= dispatch_queue_create("com.apple.security.sectransfrom.SecTransformExecute", NULL
);
334 SecMessageBlock myBlock
= ^(CFTypeRef message
, CFErrorRef error
, Boolean isFinal
)
338 if (NULL
!= errorRef
)
344 if (NULL
!= myResult
)
359 dispatch_semaphore_signal(mySem
);
363 SecTransformExecuteAsync(theGroup
, myQueue
, myBlock
);
364 dispatch_semaphore_wait(mySem
, DISPATCH_TIME_FOREVER
);
365 dispatch_release(mySem
);
366 dispatch_release(myQueue
);
373 CFRelease(collectTransform
);
378 void SecTransformExecuteAsync(SecTransformRef transformRef
,
379 dispatch_queue_t deliveryQueue
,
380 SecMessageBlock deliveryBlock
)
382 CFErrorRef localError
= NULL
;
383 InternalSecTransformExecute(transformRef
, &localError
, deliveryQueue
, deliveryBlock
);
385 // if we got an error (usually a transform startup error), we must deliver it
386 if (localError
!= NULL
)
388 // The monitor treats a NULL queue as running on it's own queue, which from an appication's point of view is
389 // the same as a default global queue. Chances are there is no monitor at this point, so it is best to just use the
390 // global queue for this.
391 dispatch_queue_t effectiveQueue
= deliveryQueue
? deliveryQueue
: dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, NULL
);
392 dispatch_async(effectiveQueue
, ^{
393 deliveryBlock(NULL
, localError
, true);
398 CFDictionaryRef
SecTransformCopyExternalRepresentation(SecTransformRef transformRef
)
401 Transform
* tr
= (Transform
*) CoreFoundationHolder::ObjectFromCFType(transformRef
);
402 return tr
->Externalize(NULL
);
405 CFStringRef
SecTransformDotForDebugging(SecTransformRef transformRef
)
407 if (CFGetTypeID(transformRef
) == SecGroupTransformGetTypeID()) {
408 GroupTransform
* tr
= (GroupTransform
*) CoreFoundationHolder::ObjectFromCFType(transformRef
);
409 return tr
->DotForDebugging();
411 return CFSTR("Can only dot debug a group");
415 SecTransformRef
SecTransformCreateFromExternalRepresentation(
416 CFDictionaryRef dictionary
,
419 // The incoming dictionary consists of a list of transforms and
420 // a list of connections. We start by making the individual
421 // transforms and storing them in a dictionary so that we can
422 // efficiently make connections
424 CFArrayRef transforms
= (CFArrayRef
) CFDictionaryGetValue(dictionary
, EXTERN_TRANSFORM_TRANSFORM_ARRAY
);
425 if (transforms
== NULL
)
427 // The dictionary we got is massively malformed!
428 *error
= CreateSecTransformErrorRef(kSecTransformErrorInvalidInputDictionary
, "%@ is missing from the dictionary. The dictionary is malformed.", EXTERN_TRANSFORM_TRANSFORM_ARRAY
);
432 CFArrayRef connections
= (CFArrayRef
) CFDictionaryGetValue(dictionary
, EXTERN_TRANSFORM_CONNECTION_ARRAY
);
433 if (connections
== NULL
)
435 // The dictionary we got is massively malformed!
436 *error
= CreateSecTransformErrorRef(kSecTransformErrorInvalidInputDictionary
, "%@ is missing from the dictionary. The dictionary is malformed.", EXTERN_TRANSFORM_CONNECTION_ARRAY
);
440 CFMutableDictionaryRef transformHolder
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
441 CFTypeRefHolder
_(transformHolder
);
443 CFIndex numTransforms
= CFArrayGetCount(transforms
);
446 SecTransformRef aTransform
;
448 for (n
= 0; n
< numTransforms
; ++n
)
450 // get the basic info we need
451 CFDictionaryRef xTransform
= (CFDictionaryRef
) CFArrayGetValueAtIndex(transforms
, n
);
453 CFStringRef xName
= (CFStringRef
) CFDictionaryGetValue(xTransform
, EXTERN_TRANSFORM_NAME
);
455 CFStringRef xType
= (CFStringRef
) CFDictionaryGetValue(xTransform
, EXTERN_TRANSFORM_TYPE
);
457 // reconstruct the transform
458 aTransform
= TransformFactory::MakeTransformWithType(xType
, error
);
459 SecTransformSetAttribute(aTransform
, kSecTransformTransformName
, xName
, NULL
);
461 // restore the transform state
462 Transform
* tr
= (Transform
*) CoreFoundationHolder::ObjectFromCFType(aTransform
);
463 tr
->RestoreState((CFDictionaryRef
) CFDictionaryGetValue(xTransform
, EXTERN_TRANSFORM_STATE
));
464 tr
->SetCustomExternalData((CFDictionaryRef
) CFDictionaryGetValue(xTransform
, EXTERN_TRANSFORM_CUSTOM_EXPORTS_DICTIONARY
));
466 CFIndex cnt
= CFDictionaryGetCount(transformHolder
);
468 // add the transform to the dictionary
469 CFDictionaryAddValue(transformHolder
, xName
, aTransform
);
471 if (CFDictionaryGetCount(transformHolder
) <= cnt
)
475 *error
= CreateSecTransformErrorRef(kSecTransformErrorInvalidInputDictionary
,
476 "Out of memory, or damaged input dictonary (duplicate label %@?)", xName
);
482 CFIndex numConnections
= CFArrayGetCount(connections
);
483 if (numConnections
== 0)
488 SecGroupTransformRef gt
= SecTransformCreateGroupTransform();
490 for (n
= 0; n
< numConnections
; ++n
)
492 CFDictionaryRef connection
= (CFDictionaryRef
) CFArrayGetValueAtIndex(connections
, n
);
493 CFStringRef fromTransformName
= (CFStringRef
) CFDictionaryGetValue(connection
, EXTERN_TRANSFORM_FROM_NAME
);
494 CFStringRef fromAttribute
= (CFStringRef
) CFDictionaryGetValue(connection
, EXTERN_TRANSFORM_FROM_ATTRIBUTE
);
495 CFStringRef toTransformName
= (CFStringRef
) CFDictionaryGetValue(connection
, EXTERN_TRANSFORM_TO_NAME
);
496 CFStringRef toAttribute
= (CFStringRef
) CFDictionaryGetValue(connection
, EXTERN_TRANSFORM_TO_ATTRIBUTE
);
498 SecTransformRef fromTransform
= (SecTransformRef
) CFDictionaryGetValue(transformHolder
, fromTransformName
);
499 if (!fromTransform
) {
501 *error
= CreateSecTransformErrorRef(kSecTransformErrorInvalidInputDictionary
, "Can't connect %@ to %@ because %@ was not found", fromTransformName
, toTransformName
, fromTransformName
);
505 SecTransformRef toTransform
= (SecTransformRef
) CFDictionaryGetValue(transformHolder
, toTransformName
);
508 *error
= CreateSecTransformErrorRef(kSecTransformErrorInvalidInputDictionary
, "Can't connect %@ to %@ because %@ was not found", fromTransformName
, toTransformName
, toTransformName
);
513 aTransform
= SecTransformConnectTransforms(fromTransform
, fromAttribute
, toTransform
, toAttribute
, gt
, error
);
521 SecTransformRef
SecTransformFindByName(SecTransformRef transform
, CFStringRef name
)
523 Transform
*t
= (Transform
*)CoreFoundationHolder::ObjectFromCFType(transform
);
524 GroupTransform
*g
= t
->GetRootGroup();
527 return g
->FindByName(name
);
529 // There is no group, so if transform isn't our guy nobody is.
530 return (CFStringCompare(name
, t
->GetName(), 0) == kCFCompareEqualTo
) ? transform
: NULL
;
536 CFTypeID
SecGroupTransformGetTypeID()
538 return GroupTransform::GetCFTypeID();
541 CFTypeID
SecTransformGetTypeID()
543 // Obviously this is wrong (returns same CFTypeID as SecTransformGetTypeID) Needs to be fixed
544 return GroupTransform::GetCFTypeID();