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
); 
 168 #pragma clang diagnostic push 
 169 #pragma clang diagnostic ignored "-Wunused-function" 
 170 static inline GroupTransform
* MakeGroupTransformFromTransformRef(SecTransformRef tr
) 
 172         GroupTransform
* gt 
= (GroupTransform
*) CoreFoundationHolder::ObjectFromCFType(tr
); 
 175 #pragma clang diagnostic pop 
 177 static CFTypeRef 
InternalSecTransformExecute(SecTransformRef transformRef
, 
 178                                                         CFErrorRef
* errorRef
, 
 179                                                         dispatch_queue_t deliveryQueue
, 
 180                                                         SecMessageBlock deliveryBlock
) 
 182         if (NULL 
== transformRef 
|| (deliveryBlock 
&& !deliveryQueue
)) 
 184                 CFErrorRef localError 
= CFErrorCreate(kCFAllocatorDefault
, kSecTransformErrorDomain
, 
 185                         kSecTransformInvalidArgument
, NULL
); 
 187                 if (NULL 
!= errorRef
) 
 189                         *errorRef 
= localError
; 
 193                         CFRelease(localError
); 
 196                 return (CFTypeRef
)NULL
; 
 199         // if our transform is a group, connect to its first member instead 
 200         if (CFGetTypeID(transformRef
) == GroupTransform::GetCFTypeID()) 
 202                 GroupTransform
* gtsrc 
= (GroupTransform
*) CoreFoundationHolder::ObjectFromCFType(transformRef
); 
 203                 transformRef 
= gtsrc
->GetAnyMember(); 
 206         Transform
* transform 
= (Transform
*) CoreFoundationHolder::ObjectFromCFType(transformRef
); 
 207         return transform
->Execute(deliveryQueue
, deliveryBlock
, errorRef
); 
 210 CFTypeRef 
SecTransformExecute(SecTransformRef transformRef
, CFErrorRef
* errorRef
) 
 212         if (NULL 
== transformRef
) 
 216                         *errorRef 
= CreateSecTransformErrorRef(kSecTransformInvalidArgument
, "NULL transform can not be executed"); 
 221         Transform
* transform 
= (Transform
*) CoreFoundationHolder::ObjectFromCFType(transformRef
); 
 223         // transform->Execute will check this, but by then we have attached a collector which causes all manner of issues. 
 224         if (transform
->mIsActive
) 
 228                         *errorRef 
= CreateSecTransformErrorRef(kSecTransformTransformIsExecuting
, "The %@ transform has already executed, it may not be executed again.", transform
->GetName()); 
 233         SecTransformRef collectTransform 
= transforms_assume(SecCreateCollectTransform(errorRef
)); 
 234         SecGroupTransformRef theGroup 
= NULL
; 
 235         Boolean releaseTheGroup 
= false; 
 236         GroupTransform
* myGroup 
= NULL
; 
 237         Boolean needConnection 
= true; 
 239         // Sniff the type of the transformRef to see if it is a group 
 240         if (SecGroupTransformGetTypeID() == CFGetTypeID(transformRef
)) 
 242                 theGroup 
= (SecGroupTransformRef
)transformRef
; 
 246                 // Ok TransformRef is a TransformRef so get's it group 
 248                 myGroup 
= transform
->mGroup
; 
 252                         theGroup 
= SecTransformCreateGroupTransform(); 
 253                         if (NULL 
== theGroup
) 
 255                                 if (NULL 
!= errorRef
) 
 257                                         *errorRef 
= GetNoMemoryErrorAndRetain(); 
 260                                 return (CFTypeRef
)NULL
; 
 264                         releaseTheGroup 
= true; 
 266                         SecGroupTransformRef connectResult 
= 
 267                                 SecTransformConnectTransforms(transformRef
, 
 268                                                                                   kSecTransformOutputAttributeName
, 
 270                                                                                   kSecTransformInputAttributeName
, 
 273                         if (NULL 
== connectResult
) 
 275                                 return (CFTypeRef
)NULL
; 
 278                         needConnection 
= false; 
 283                         theGroup 
= (SecGroupTransformRef
)myGroup
->GetCFObject(); 
 287         if (NULL 
== theGroup 
|| (SecGroupTransformGetTypeID() != CFGetTypeID(theGroup
))) 
 289                 if (NULL 
!= errorRef
) 
 291                         *errorRef 
= GetNoMemoryErrorAndRetain(); 
 294                 return (CFTypeRef
)NULL
; 
 301                 // Connect the collectTransform to the group 
 302                 myGroup 
= ((GroupTransform
*)CoreFoundationHolder::ObjectFromCFType(theGroup
))->GetRootGroup(); 
 305             if (NULL 
!= errorRef
) 
 307                 *errorRef 
= GetNoMemoryErrorAndRetain(); 
 310             return (CFTypeRef
)NULL
; 
 313                 SecTransformRef outputTransform 
= myGroup
->FindLastTransform(); 
 315                 SecGroupTransformRef connectResult 
= 
 316                 SecTransformConnectTransforms(outputTransform
, 
 317                                                                           kSecTransformOutputAttributeName
, 
 319                                                                           kSecTransformInputAttributeName
, 
 320                                                                           myGroup
->GetCFObject(), errorRef
); 
 322                 if (NULL 
== connectResult
) 
 324                         CFRelease(collectTransform
); 
 329                         return (CFTypeRef
)NULL
; 
 333         __block CFTypeRef myResult 
= NULL
; 
 334         dispatch_semaphore_t mySem 
= dispatch_semaphore_create(0L); 
 335         dispatch_queue_t myQueue 
= dispatch_queue_create("com.apple.security.sectransfrom.SecTransformExecute", NULL
); 
 336         SecMessageBlock myBlock 
= ^(CFTypeRef message
, CFErrorRef error
, Boolean isFinal
) 
 340                         if (NULL 
!= errorRef
) 
 346                         if (NULL 
!= myResult
) 
 361                         dispatch_semaphore_signal(mySem
); 
 365         SecTransformExecuteAsync(theGroup
, myQueue
, myBlock
); 
 366         dispatch_semaphore_wait(mySem
, DISPATCH_TIME_FOREVER
); 
 367         dispatch_release(mySem
); 
 368         dispatch_release(myQueue
); 
 375         CFRelease(collectTransform
); 
 380 void SecTransformExecuteAsync(SecTransformRef transformRef
, 
 381                                                           dispatch_queue_t deliveryQueue
, 
 382                                                           SecMessageBlock deliveryBlock
) 
 384         CFErrorRef localError 
= NULL
; 
 385         InternalSecTransformExecute(transformRef
, &localError
, deliveryQueue
, deliveryBlock
); 
 387         // if we got an error (usually a transform startup error), we must deliver it 
 388         if (localError 
!= NULL
) 
 390                 // The monitor treats a NULL queue as running on it's own queue, which from an appication's point of view is 
 391                 // the same as a default global queue.   Chances are there is no monitor at this point, so it is best to just use the 
 392                 //  global queue for this. 
 393                 dispatch_queue_t effectiveQueue 
= deliveryQueue 
? deliveryQueue 
: dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, NULL
); 
 394                 dispatch_async(effectiveQueue
, ^{ 
 395                         deliveryBlock(NULL
, localError
, true); 
 400 CFDictionaryRef 
SecTransformCopyExternalRepresentation(SecTransformRef transformRef
) 
 403         Transform
* tr 
= (Transform
*) CoreFoundationHolder::ObjectFromCFType(transformRef
); 
 404         return tr
->Externalize(NULL
); 
 407 CFStringRef 
SecTransformDotForDebugging(SecTransformRef transformRef
) 
 409     if (CFGetTypeID(transformRef
) == SecGroupTransformGetTypeID()) { 
 410         GroupTransform
* tr 
= (GroupTransform
*) CoreFoundationHolder::ObjectFromCFType(transformRef
); 
 411         return tr
->DotForDebugging(); 
 413         return CFSTR("Can only dot debug a group"); 
 417 SecTransformRef 
SecTransformCreateFromExternalRepresentation( 
 418                                                                 CFDictionaryRef dictionary
, 
 421         // The incoming dictionary consists of a list of transforms and 
 422         // a list of connections.  We start by making the individual 
 423         // transforms and storing them in a dictionary so that we can 
 424         // efficiently make connections 
 426         CFArrayRef transforms 
= (CFArrayRef
) CFDictionaryGetValue(dictionary
, EXTERN_TRANSFORM_TRANSFORM_ARRAY
); 
 427         if (transforms 
== NULL
) 
 429                 // The dictionary we got is massively malformed! 
 430                 *error 
= CreateSecTransformErrorRef(kSecTransformErrorInvalidInputDictionary
, "%@ is missing from the dictionary.  The dictionary is malformed.", EXTERN_TRANSFORM_TRANSFORM_ARRAY
); 
 434         CFArrayRef connections 
= (CFArrayRef
) CFDictionaryGetValue(dictionary
, EXTERN_TRANSFORM_CONNECTION_ARRAY
); 
 435         if (connections 
== NULL
) 
 437                 // The dictionary we got is massively malformed! 
 438                 *error 
= CreateSecTransformErrorRef(kSecTransformErrorInvalidInputDictionary
, "%@ is missing from the dictionary.  The dictionary is malformed.", EXTERN_TRANSFORM_CONNECTION_ARRAY
); 
 442         CFMutableDictionaryRef transformHolder 
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
 443         CFTypeRefHolder 
_(transformHolder
); 
 445         CFIndex numTransforms 
= CFArrayGetCount(transforms
); 
 448         SecTransformRef aTransform
; 
 450         for (n 
= 0; n 
< numTransforms
; ++n
) 
 452                 // get the basic info we need 
 453                 CFDictionaryRef xTransform 
= (CFDictionaryRef
) CFArrayGetValueAtIndex(transforms
, n
); 
 455                 CFStringRef xName 
= (CFStringRef
) CFDictionaryGetValue(xTransform
, EXTERN_TRANSFORM_NAME
); 
 457                 CFStringRef xType 
= (CFStringRef
) CFDictionaryGetValue(xTransform
, EXTERN_TRANSFORM_TYPE
); 
 459                 // reconstruct the transform 
 460                 aTransform 
= TransformFactory::MakeTransformWithType(xType
, error
); 
 461                 SecTransformSetAttribute(aTransform
, kSecTransformTransformName
, xName
, NULL
); 
 463                 // restore the transform state 
 464                 Transform
* tr 
= (Transform
*) CoreFoundationHolder::ObjectFromCFType(aTransform
); 
 465                 tr
->RestoreState((CFDictionaryRef
) CFDictionaryGetValue(xTransform
, EXTERN_TRANSFORM_STATE
)); 
 466                 tr
->SetCustomExternalData((CFDictionaryRef
) CFDictionaryGetValue(xTransform
, EXTERN_TRANSFORM_CUSTOM_EXPORTS_DICTIONARY
)); 
 468                 CFIndex cnt 
= CFDictionaryGetCount(transformHolder
); 
 470                 // add the transform to the dictionary 
 471                 CFDictionaryAddValue(transformHolder
, xName
, aTransform
); 
 473                 if (CFDictionaryGetCount(transformHolder
) <= cnt
) 
 477                                 *error 
= CreateSecTransformErrorRef(kSecTransformErrorInvalidInputDictionary
, 
 478                                                         "Out of memory, or damaged input dictonary (duplicate label %@?)", xName
); 
 484         CFIndex numConnections 
= CFArrayGetCount(connections
); 
 485         if (numConnections 
== 0) 
 490         SecGroupTransformRef gt 
= SecTransformCreateGroupTransform(); 
 492         for (n 
= 0; n 
< numConnections
; ++n
) 
 494                 CFDictionaryRef connection 
= (CFDictionaryRef
) CFArrayGetValueAtIndex(connections
, n
); 
 495                 CFStringRef fromTransformName 
= (CFStringRef
) CFDictionaryGetValue(connection
, EXTERN_TRANSFORM_FROM_NAME
); 
 496                 CFStringRef fromAttribute 
= (CFStringRef
) CFDictionaryGetValue(connection
, EXTERN_TRANSFORM_FROM_ATTRIBUTE
); 
 497                 CFStringRef toTransformName 
= (CFStringRef
) CFDictionaryGetValue(connection
, EXTERN_TRANSFORM_TO_NAME
); 
 498                 CFStringRef toAttribute 
= (CFStringRef
) CFDictionaryGetValue(connection
, EXTERN_TRANSFORM_TO_ATTRIBUTE
); 
 500                 SecTransformRef fromTransform 
= (SecTransformRef
) CFDictionaryGetValue(transformHolder
, fromTransformName
); 
 501                 if (!fromTransform
) { 
 503                                 *error 
= CreateSecTransformErrorRef(kSecTransformErrorInvalidInputDictionary
, "Can't connect %@ to %@ because %@ was not found", fromTransformName
, toTransformName
, fromTransformName
); 
 507                 SecTransformRef toTransform 
= (SecTransformRef
) CFDictionaryGetValue(transformHolder
, toTransformName
); 
 510                                 *error 
= CreateSecTransformErrorRef(kSecTransformErrorInvalidInputDictionary
, "Can't connect %@ to %@ because %@ was not found", fromTransformName
, toTransformName
, toTransformName
); 
 515                 aTransform 
= SecTransformConnectTransforms(fromTransform
, fromAttribute
, toTransform
, toAttribute
, gt
, error
); 
 523 SecTransformRef 
SecTransformFindByName(SecTransformRef transform
, CFStringRef name
) 
 525         Transform 
*t 
= (Transform
*)CoreFoundationHolder::ObjectFromCFType(transform
); 
 526     GroupTransform 
*g 
= t
->GetRootGroup(); 
 529         return g
->FindByName(name
); 
 531         // There is no group, so if transform isn't our guy nobody is. 
 532         return (CFStringCompare(name
, t
->GetName(), 0) == kCFCompareEqualTo
) ? transform 
: NULL
; 
 538 CFTypeID 
SecGroupTransformGetTypeID() 
 540         return GroupTransform::GetCFTypeID(); 
 543 CFTypeID 
SecTransformGetTypeID() 
 545         // Obviously this is wrong (returns same CFTypeID as SecTransformGetTypeID) Needs to be fixed 
 546         return GroupTransform::GetCFTypeID();