/ OSX / libsecurity_transform / lib / SecCustomTransform.cpp
SecCustomTransform.cpp
   1  /*
   2   * Copyright (c) 2010-2012,2014 Apple Inc. All Rights Reserved.
   3   *
   4   * @APPLE_LICENSE_HEADER_START@
   5   * 
   6   * This file contains Original Code and/or Modifications of Original Code
   7   * as defined in and that are subject to the Apple Public Source License
   8   * Version 2.0 (the 'License'). You may not use this file except in
   9   * compliance with the License. Please obtain a copy of the License at
  10   * http://www.opensource.apple.com/apsl/ and read it before using this
  11   * file.
  12   * 
  13   * The Original Code and all software distributed under the License are
  14   * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  15   * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  16   * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  17   * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  18   * Please see the License for the specific language governing rights and
  19   * limitations under the License.
  20   * 
  21   * @APPLE_LICENSE_HEADER_END@
  22   */
  23  
  24  
  25  #include "SecCustomTransform.h"
  26  #include "SecTransformValidator.h"
  27  
  28  #include "TransformFactory.h"
  29  #include <CoreFoundation/CoreFoundation.h>
  30  #include <Block.h>
  31  #include <syslog.h>
  32  #include "Utilities.h"
  33  #include "misc.h"
  34  
  35  const CFStringRef kSecCustom = CFSTR("CustomTransform");
  36  const CFStringRef kSecTransformPreviousErrorKey = CFSTR("PreviousError");
  37  const CFStringRef kSecTransformAbortOriginatorKey = CFSTR("Originating Transform");
  38  const CFStringRef kSecTransformActionCanExecute = CFSTR("CanExecute");
  39  const CFStringRef kSecTransformActionStartingExecution = CFSTR("ExecuteStarting");
  40  const CFStringRef kSecTransformActionProcessData = CFSTR("TransformProcessData");
  41  const CFStringRef kSecTransformActionAttributeNotification = CFSTR("GenericAttributeSetNotification");
  42  const CFStringRef kSecTransformActionFinalize = CFSTR("Finalize");
  43  const CFStringRef kSecTransformActionExternalizeExtraData = CFSTR("ExternalizeExtraData");
  44  const CFStringRef kSecTransformActionInternalizeExtraData = CFSTR("InternalizeExtraData");
  45  const CFStringRef kSecTransformActionAttributeValidation = CFSTR("AttributeValidation");
  46  
  47  /*!
  48  	@function		SecTransformOverrideTransformAction
  49  	
  50  	@abstract		Used to override the default behavior of a custom transform. 
  51  	
  52  	@param action	This should be either kSecTransformActionCanExecute, 
  53  					kSecTransformActionStartingExecution, or 
  54  					kSecTransformActionFinalize which signifies the behavior
  55  					that is being overridden.									
  56  					
  57  	@param newAction	
  58  					A SecTransformAttributeActionBlock block that implements the 
  59  					override behavior.  Please see the 
  60  					SecTransformActionBlock discussion for more 
  61  					information.
  62  				
  63  	@result			A CFErrorRef if an error occurred, NULL otherwise.
  64  					
  65  	@discussion		An action may be overridden more then once, the most
  66  					recent override will be used.Please see the example in 
  67  					the documentation for the SecTransformActionBlock 
  68  					block.
  69  					
  70  */
  71  typedef CFTypeRef (^SecTransformOverrideTransformAction)(CFStringRef action, 
  72  								SecTransformActionBlock newAction);
  73  								
  74  /*!
  75  	@function		SecTransformOverrideDataAction
  76  	
  77  	@abstract		Changes the default attribute handling for a 
  78  					specified attribute.
  79  					
  80  	@param action	This should be either kSecTransformActionProcessData, 
  81  					kSecTransformActionExternalizeExtraData which signifies  
  82  					what behavior is being overridden.
  83  															
  84  	@param newAction	 
  85  					A SecTransformDataBlock block that implements the 
  86  					override behavior. Please see the 
  87  					SecTransformDataBlock discussion for more 
  88  					information.
  89  
  90  	@result			A CFErrorRef if an error occurred. NULL otherwise.
  91  					
  92  	@discussion		An action may be overridden more then once, the most
  93  				    recent override will be used. Please see the example 
  94  					in the documentation for the SecTransformAttributeActionBlock 
  95  					block.
  96  				
  97  */
  98  typedef CFTypeRef (^SecTransformOverrideDataAction)(CFStringRef action, 
  99  								SecTransformDataBlock newAction);
 100  								
 101  /*!
 102  	@function		SecTransformOverrideAttributeAction
 103  	
 104  	@abstract		Changes the default attribute handling for a 
 105  					specified attribute.
 106  					
 107  	@param action	This should be either SecTransformSetAttributeAction, 
 108  					kSecTransformActionAttributeValidation which signifies  
 109  					what behavior is being overridden.
 110  	
 111  	@param attribute	
 112  					The attribute whose attribute default attribute handling is 
 113  					being overridden.  Passing NULL will override all attributes
 114  					that have not been specifically overridden.
 115  										
 116  	@param newAction	 
 117  					A SecTransformAttributeActionBlock block 
 118  					that implements the  override behavior. 
 119  					
 120  					If the action parameter is SecTransformSetAttributeAction
 121  					then this block is called whenever a set is called on the
 122  					attribute that this block was registered for or in the case
 123  					of a NULL attribute name any attribute that has not been specifically
 124  					overridden.  The block may transmogrify the data as needed.  It may
 125  					also send the data to any other attribue by calling 
 126  					SecTransformCustomSetAttribute.  The value returned from the block 
 127  					will be the new value for the attribute.
 128  					
 129  					If the action parameter is kSecTransformActionAttributeValidation then
 130  					this block is called to validate the new value for the
 131  					attribute that this block was registered for or in the case
 132  					of a NULL attribute name any attribute that has not been specifically
 133  					overridden.  The block should test if the new value is acceptable
 134  					and return NULL if it is valid a CFErrorRef otherwise.
 135  					
 136  	@result			A CFErrorRef if an error occurred. NULL otherwise.
 137  					
 138  	@discussion		An action may be overridden more then once, the most
 139  				    recent override will be used. Please see the example 
 140  					in the documentation for the 
 141  					SecTransformAttributeActionBlock block.
 142  				
 143  */
 144  typedef CFTypeRef (^SecTransformOverrideAttributeAction)( 
 145  								CFStringRef action,
 146  								SecTransformStringOrAttributeRef attribute, 
 147  								SecTransformAttributeActionBlock newAction);
 148  
 149  								
 150  /*!
 151  	@function		SecTransformGetAttributeBlock
 152  	
 153  	@abstract		Retrieves the value of the attribute metadata of the 
 154  					type specified.
 155  					
 156  	@param attribute	
 157  					The attribute from which to retrieve the metadata from.
 158  					
 159  	@param type		The type of the metadata to be fetched.
 160  						
 161  	@result			The value of the metadata that was retrieved or a CFErrorRef
 162  					if an error occurred
 163  	
 164  	@result 		The value of the metadata that was retrieved.
 165  	
 166  
 167  */
 168  typedef CFTypeRef (^SecTransformGetAttributeBlock)(
 169  										SecTransformStringOrAttributeRef attribute, 
 170  										SecTransformMetaAttributeType type);
 171  										
 172  /*!
 173  	@function		SecTransformSetAttributeBlock
 174  	
 175  	@abstract		This sets the value of the metadata of an attribute.  
 176  		
 177  	@param attribute	
 178  					The attribute whose value is sent
 179  					
 180  	@param type		The metadata type that specifies what metadata value
 181  					is set.
 182  					
 183  	@param value	The value of the metadata to be sent.
 184  						
 185  	@result			A CFErrorRef is an error occurred, NULL otherwise.
 186  	
 187  	@discussion		The attribute parameter specifies which attribute will 
 188  					have its data set. The type parameter specifies which of 
 189  					the metadata items is set. The value parameter is the 
 190  					new metadata value.
 191  							
 192  */
 193  typedef CFErrorRef (^SecTransformSetAttributeBlock)(
 194  	SecTransformStringOrAttributeRef attribute, 
 195  	SecTransformMetaAttributeType type, 
 196  	CFTypeRef value);
 197  	
 198  
 199  /*!
 200  	@function		SecTransformPushBackAttributeBlock
 201  
 202  	@abstract		Allows for putting a single value back for a 
 203  					specific attribute.  This will stop the flow of
 204  					data into the specified attribute until an
 205  					attribute is changed.
 206  
 207  	@param attribute	
 208  					The attribute that has its data pushed back.
 209  
 210  	@param value	The value being pushed back.
 211  
 212  
 213  	@result			A CFErrorRef is an error occurred, NULL otherwise.
 214  					Note: pushing back a second value will abort the
 215  					transform, not return an error from this call.
 216  
 217  	@discussion		A particular custom transform may need multple
 218  					values to be set before it can do the processing
 219  					that the custom transform is designed to do. For
 220  					example, it may need a key and a salt value.  The
 221  					salt value maybe supplied by another transform while
 222  					the key transform may have been set explicitly.  When
 223  					data is presented to this custom transform the salt
 224  					value may not have been sent from the upstream transform.
 225  					The custom transform can then push back the input data
 226  					which causes the transform to stall.  When any 
 227  					attribute on the custom transform is changed, such as 
 228  					the upstream transform delivers the salt value, then 
 229  					the data that was pushed back is re-delivered
 230  
 231  */
 232  typedef CFErrorRef (^SecTransformPushBackAttributeBlock)(
 233  										SecTransformStringOrAttributeRef attribute, 
 234  										CFTypeRef value);
 235  
 236  /*!
 237  	@const kSecTransformCreateBlockParametersVersion
 238  			The current version number of the SecTransformCreateBlockParameters
 239  			struct
 240  	
 241  */
 242  enum 
 243  {
 244  	kSecTransformCreateBlockParametersVersion = 1
 245  };
 246  
 247  extern "C" {
 248  	Boolean SecExternalSourceSetValue(SecTransformRef xst, CFTypeRef value, CFErrorRef *error);
 249  }
 250  
 251  /*!
 252  	@struct OpaqueSecTransformImplementation
 253  	
 254  	@field version
 255  			The version number of this structure
 256  			
 257  	@field overrideTransform
 258  			A SecTransformOverrideTransformAction block.  See
 259  			the headerdoc for this block for additional information.
 260  			
 261  	@field overrideAttribute
 262  			A SecTransformOverrideAttributeAction block. See
 263  			the headerdoc for this block for additional information.
 264  
 265  	@field get
 266  			A SecTransformGetAttributeBlock block. See
 267  			the headerdoc for this block for additional information.
 268  			
 269  	@field send
 270  		A SecTransformSetAttributeBlock block.  See
 271  		the headerdoc for this block for additional information.
 272  		
 273  	@field pushback
 274  		A SecTransformPushBackAttributeBlock block. See
 275  		the headerdoc for this block for additional information.
 276  */
 277  struct OpaqueSecTransformImplementation
 278  {
 279  	CFIndex version;	// Set to kSecTransformCreateBlockParametersVersion
 280  	
 281  	// The following two blocks allow for overriding 'standard' 
 282  	// transform behavior
 283  	SecTransformOverrideTransformAction overrideTransform;
 284  	SecTransformOverrideDataAction overrideData;
 285  	SecTransformOverrideAttributeAction overrideAttribute;
 286  	
 287  	// The following methods allow for dealing with the transform mechanism
 288  	// They are called synchronously
 289  	SecTransformGetAttributeBlock get;
 290  	SecTransformSetAttributeBlock send;
 291  	SecTransformPushBackAttributeBlock pushback;
 292  };
 293  
 294  										
 295  class CustomTransformFactory : public TransformFactory 
 296  {
 297  protected:
 298  	SecTransformCreateFP  createFuncPtr;
 299  public:
 300  	CustomTransformFactory(CFStringRef name, SecTransformCreateFP createFP, CFErrorRef *error);
 301      virtual ~CustomTransformFactory() {};
 302  	virtual CFTypeRef Make();
 303  };
 304  
 305  
 306  static const SecTransformActionBlock default_can_run = ^{ return (CFTypeRef)NULL; };
 307  static const SecTransformActionBlock default_execute_starting = default_can_run;
 308  static const SecTransformActionBlock default_finalize = default_execute_starting;
 309  static const SecTransformActionBlock default_externalize_data = default_finalize;
 310  
 311  static const SecTransformDataBlock default_process_data = ^(CFTypeRef value) { return value; };
 312  //static SecTransformDataBlock default_validate = ^(CFTypeRef value) { return (CFTypeRef)NULL; };
 313  static const SecTransformAttributeActionBlock default_generic_attribute_set_notification =
 314  	^(SecTransformAttributeRef ah, CFTypeRef value) { return value; };
 315  
 316  static SecTransformAttributeActionBlock default_generic_attribute_validation = 
 317  ^(SecTransformAttributeRef ah, CFTypeRef value) 
 318  {
 319  	 return (CFTypeRef)NULL;
 320  };
 321  
 322  static SecTransformDataBlock default_internalize_data = 
 323  			^(CFTypeRef value) 
 324  { 
 325  	return (CFTypeRef)NULL; 
 326  };
 327  
 328  class CustomTransform : public Transform 
 329  {
 330  protected:
 331  	SecTransformCreateFP					createFuncPtr;
 332  	SecTransformInstanceBlock			instanceBlock;	  
 333  			
 334  	SecTransformActionBlock 			can_run;
 335  	SecTransformActionBlock 			execute_starting;
 336  	SecTransformActionBlock 			finalize;
 337  	SecTransformAttributeActionBlock 	generic_attribute_set_notification;
 338  	SecTransformAttributeActionBlock	generic_attribute_validation;
 339  	SecTransformDataBlock 				process_data;
 340  	SecTransformActionBlock 			externalize_data;
 341  	SecTransformDataBlock 				internalize_data;
 342  		
 343  	SecTransformRef tr;	
 344  	
 345  	SecTransformAttributeRef 			input_ah;
 346  	SecTransformAttributeRef			output_ah;
 347  	
 348  	OpaqueSecTransformImplementation parameters;
 349  	
 350  	void SetCanExecute(SecTransformActionBlock CanExecuteBlock)
 351  	{
 352  		Block_release(can_run);
 353  		if (CanExecuteBlock)
 354  		{
 355  			can_run = Block_copy(CanExecuteBlock);
 356  			
 357  		}
 358  		else
 359  		{
 360  			can_run	 = Block_copy(default_can_run);
 361  		}
 362  	}
 363  	
 364  	void SetExecuteStarting(SecTransformActionBlock executeStartingBlock)
 365  	{
 366  		Block_release(execute_starting);
 367  		if (executeStartingBlock)
 368  		{
 369  			execute_starting = Block_copy(executeStartingBlock);
 370  			
 371  		}
 372  		else
 373  		{
 374  			execute_starting = Block_copy(default_execute_starting);
 375  		}
 376  	}
 377  	
 378  	void SetFinalize(SecTransformActionBlock finalizeBlock)
 379  	{
 380  		Block_release(finalize);
 381  		if (finalizeBlock)
 382  		{
 383  			finalize = Block_copy(finalizeBlock);
 384  			
 385  		}
 386  		else
 387  		{
 388  			finalize = Block_copy(default_finalize);
 389  		}
 390  	}
 391  	
 392  	void SetExternalizeExtraData(SecTransformActionBlock externalizeBlock)
 393  	{
 394  		Block_release(externalizeBlock);
 395  		if (externalizeBlock)
 396  		{
 397  			externalize_data = Block_copy(externalizeBlock);
 398  			
 399  		}
 400  		else
 401  		{
 402  			externalize_data = Block_copy(default_externalize_data);
 403  		}
 404  	}
 405  	
 406  	void SetProcessData(SecTransformDataBlock processDataBlock)
 407  	{
 408  		Block_release(process_data);
 409  		if (processDataBlock)
 410  		{
 411  			process_data = Block_copy(processDataBlock);
 412  			
 413  		}
 414  		else
 415  		{
 416  			process_data = Block_copy(default_process_data);
 417  		}
 418  	}
 419  	
 420  	void SetInternalizeExtraData(SecTransformDataBlock InternalizeExtraDataBlock)
 421  	{
 422  		Block_release(internalize_data);
 423  		if (InternalizeExtraDataBlock)
 424  		{
 425  			internalize_data = Block_copy(InternalizeExtraDataBlock);
 426  			
 427  		}
 428  		else
 429  		{
 430  			internalize_data = Block_copy(default_internalize_data);
 431  		}
 432  	}
 433  	
 434  	
 435  		
 436  	void SetNotficationBlock(SecTransformStringOrAttributeRef attribute, 
 437  							SecTransformAttributeActionBlock notificationBlock)
 438  	{
 439  		SecTransformAttributeActionBlock blockToSet = 
 440  			Block_copy((notificationBlock) ? notificationBlock : 
 441  				   default_generic_attribute_set_notification);
 442  		
 443  		if (attribute)
 444  		{
 445  			transform_attribute *ta = getTA(attribute, true);
 446  			
 447  			if (ta->attribute_changed_block) 
 448  			{
 449  				Block_release(ta->attribute_changed_block);
 450  			}
 451  			
 452  			ta->attribute_changed_block = blockToSet;
 453  		}
 454  		else		
 455  		{	
 456  			
 457  			if (generic_attribute_set_notification) 
 458  			{
 459  				Block_release(generic_attribute_set_notification);
 460  			}
 461  			
 462  			generic_attribute_set_notification = blockToSet;			
 463  		}
 464  	}
 465  
 466  	void SetVerifyBlock(SecTransformStringOrAttributeRef attribute, 
 467  							SecTransformAttributeActionBlock verifyBlock)
 468  	{
 469  		SecTransformAttributeActionBlock blockToSet = 
 470  			Block_copy((verifyBlock) ? verifyBlock : 
 471  				   generic_attribute_validation);
 472  		
 473  		if (attribute)
 474  		{
 475  			transform_attribute *ta = getTA(attribute, true);
 476  			
 477  			if (ta->attribute_validate_block) 
 478  			{
 479  				Block_release(ta->attribute_validate_block);
 480  			}
 481  			
 482  			ta->attribute_validate_block = blockToSet;
 483  		}
 484  		else		
 485  		{	
 486  			if (generic_attribute_validation) 
 487  			{
 488  				Block_release(generic_attribute_validation);
 489  			}
 490  			
 491  			generic_attribute_validation = blockToSet;			
 492  		}
 493  	}
 494  		
 495  		
 496  
 497  public:
 498  	CustomTransform(CFStringRef name, SecTransformCreateFP createFP);
 499  	virtual ~CustomTransform();
 500  	
 501  	void Create();
 502  	
 503  	CFTypeRef rebind_data_action(CFStringRef action, 
 504  		SecTransformDataBlock new_action);
 505  		
 506  	CFTypeRef rebind_transform_action(CFStringRef action, SecTransformActionBlock new_action);
 507  	
 508  	CFTypeRef rebind_attribute_action(CFStringRef action,
 509  							SecTransformStringOrAttributeRef attribute, 
 510  							SecTransformAttributeActionBlock new_action);
 511  	
 512  	SecTransformRef get_ref() { return tr; }
 513  	
 514  	virtual void AttributeChanged(CFStringRef name, CFTypeRef value);
 515  	virtual void AttributeChanged(SecTransformAttributeRef ah, CFTypeRef value);
 516  	virtual CFErrorRef TransformStartingExecution();
 517  	virtual CFDictionaryRef GetCustomExternalData();
 518  	virtual void SetCustomExternalData(CFDictionaryRef customData);
 519  	
 520  	friend Boolean SecExternalSourceSetValue(SecTransformRef xst, CFTypeRef value, CFErrorRef *error);
 521  };
 522  
 523  
 524  
 525  #pragma mark CustomTransformFactory
 526  
 527  CustomTransformFactory::CustomTransformFactory(CFStringRef uniqueName, SecTransformCreateFP createFP, CFErrorRef* error) : 
 528  	TransformFactory(uniqueName, false, kSecCustom), 
 529  	createFuncPtr(createFP) 
 530  {
 531  	TransformFactory *existing = FindTransformFactoryByType(uniqueName);
 532  	if (existing) 
 533  	{
 534  		if (error) 
 535  		{
 536  			*error = CreateSecTransformErrorRef(kSecTransformErrorNameAlreadyRegistered, 
 537  				"Custom transform type %s already exists.", uniqueName);
 538  		}
 539          return;
 540  	}
 541  	
 542      
 543      if (CFStringGetCharacterAtIndex(uniqueName, 0) == '_')
 544      {
 545          if (error)
 546          {
 547              *error = CreateSecTransformErrorRef(kSecTransformInvalidArgument, 
 548                                                  "Invalid transform type name %s -- type names must not start with an _", uniqueName);
 549          }
 550          return;
 551      }
 552      
 553      static CFCharacterSetRef invalidTypeCharactors = NULL;
 554      static dispatch_once_t setupInvalidTypeCharactors;
 555      dispatch_once(&setupInvalidTypeCharactors, ^{
 556          invalidTypeCharactors = CFCharacterSetCreateWithCharactersInString(NULL, CFSTR("/:"));
 557      });
 558      CFRange has_bad;
 559      if (CFStringFindCharacterFromSet(uniqueName, invalidTypeCharactors, CFRangeMake(0, CFStringGetLength(uniqueName)), 0, &has_bad)) {
 560          if (error)
 561          {
 562              *error = CreateSecTransformErrorRef(kSecTransformInvalidArgument, 
 563                                              "Invalid character '%c' in transform type name %s", CFStringGetCharacterAtIndex(uniqueName, has_bad.location), uniqueName);
 564          }
 565          return;
 566      }
 567      RegisterTransform(this, kSecCustom);
 568  }
 569  
 570  // clang cannot possibly reason about the way in which we turn Transforms into CFRefs, and it just looks like a leak
 571  #ifndef __clang_analyzer__
 572  CFTypeRef CustomTransformFactory::Make() CF_RETURNS_RETAINED
 573  {
 574  	CustomTransform *ct = new CustomTransform(this->GetTypename(), createFuncPtr);
 575  	ct->Create();
 576  	return ct->get_ref();
 577  }
 578  #endif
 579  
 580  #pragma mark MISC
 581  
 582  extern "C" {
 583  	SecTransformAttributeActionBlock SecTransformCreateValidatorForCFtype(CFTypeID expected_type, Boolean null_allowed) {
 584  		SecTransformAttributeActionBlock validate = NULL;
 585  		CFErrorRef (^make_error_message)(SecTransformAttributeRef attr, CFTypeRef value, CFTypeID expected_type, Boolean null_allowed) = 
 586  		^(SecTransformAttributeRef attr, CFTypeRef value, CFTypeID expected_type, Boolean null_allowed) {
 587  			CFStringRef expected_type_name = CFCopyTypeIDDescription(expected_type);
 588  			CFErrorRef error = NULL;
 589  			if (value) {
 590  				CFStringRef value_type_name = CFCopyTypeIDDescription(CFGetTypeID(value));
 591  				error = CreateSecTransformErrorRef(kSecTransformErrorInvalidType, "%@ received value of type %@ (%@), expected%@ a %@%@",
 592  															  attr, value_type_name, value,
 593  															  null_allowed ? CFSTR(" either") : CFSTR(""),
 594  															  expected_type_name,
 595  															  null_allowed ? CFSTR(" or a NULL") : CFSTR(""));
 596  				CFReleaseNull(value_type_name);
 597  			} else {
 598  				error = CreateSecTransformErrorRef(kSecTransformErrorInvalidType, "%@ received NULL value, expected a %@",
 599  												   attr, expected_type_name);
 600  			}
 601  			CFReleaseNull(expected_type_name);
 602  			
 603  			return error;
 604  		};
 605  		
 606  		
 607  		if (null_allowed) {
 608  			validate = ^(SecTransformAttributeRef attr, CFTypeRef value) {
 609  				if (value == NULL || CFGetTypeID(value) == expected_type) {
 610  					return (CFTypeRef)NULL;
 611  				}
 612  				return (CFTypeRef)make_error_message(attr, value, expected_type, null_allowed);
 613  			};
 614  		} else {
 615  			validate = ^(SecTransformAttributeRef attr, CFTypeRef value) {
 616  				if (value != NULL && CFGetTypeID(value) == expected_type) {
 617  					return (CFTypeRef)NULL;
 618  				}
 619  				return (CFTypeRef)make_error_message(attr, value, expected_type, null_allowed);
 620  			};
 621  		}
 622  		
 623  		return Block_copy(validate);
 624  	}
 625  }
 626  
 627  // clang cannot reason about this business of creating an object for the side-effects of doing so
 628  #ifndef __clang_analyzer__
 629  Boolean SecTransformRegister(CFStringRef uniqueName, SecTransformCreateFP createFP, CFErrorRef *caller_error) 
 630  {
 631  	CFErrorRef error = NULL;
 632  	
 633  	CustomTransformFactory *tf = new CustomTransformFactory(uniqueName, createFP, &error);
 634  	if (error) 
 635  	{
 636  		delete tf;
 637  		if (caller_error) 
 638  		{
 639  			*caller_error = error;
 640  		}
 641  		return FALSE;
 642  	} 
 643  	else 
 644  	{
 645  		return TRUE;
 646  	}
 647  }
 648  #endif
 649  
 650  SecTransformRef SecTransformCreate(CFStringRef name, CFErrorRef *error) 
 651  {
 652  	SecTransformRef tr = TransformFactory::MakeTransformWithType(name, error);
 653  	return tr;
 654  }
 655  
 656  extern "C" {
 657  	Boolean SecExternalSourceSetValue(SecTransformRef xst, CFTypeRef value, CFErrorRef *error)
 658  	{
 659  		CustomTransform *ct = (CustomTransform *)CoreFoundationHolder::ObjectFromCFType(xst);
 660  		extern CFStringRef external_source_name;
 661  		if (CFEqual(ct->mTypeName, external_source_name)) {
 662  			ct->SetAttribute(ct->input_ah, value);
 663  			return true;
 664  		} else {
 665  			if (error) {
 666  				*error = CreateSecTransformErrorRef(kSecTransformErrorInvalidType, "SecExternalSourceSetValue called for %@, you need to pass in an ExternalSource transform not a %@", ct->GetName(), ct->mTypeName);
 667  			}
 668  			return false;
 669  		}
 670  	}
 671  }
 672  
 673  /* ==========================================================================
 674  	class:			NoDataClass
 675  	description:	A Special CFType that signifies that no data is being 
 676  					returned
 677     ==========================================================================*/
 678  #pragma mark NoDataClass
 679  
 680  class NoDataClass : public CoreFoundationObject
 681  {
 682  protected:
 683  	NoDataClass();
 684  
 685  public:
 686  	virtual ~NoDataClass();
 687  	std::string FormattingDescription(CFDictionaryRef options);
 688  	std::string DebugDescription();
 689  	static CFTypeRef Make();
 690  };
 691  
 692  CFTypeRef NoDataClass::Make() {
 693  	NoDataClass* obj = new NoDataClass();
 694  	return CoreFoundationHolder::MakeHolder(gInternalProtectedCFObjectName, obj);
 695  }
 696  
 697  
 698  NoDataClass::NoDataClass() : CoreFoundationObject(gInternalProtectedCFObjectName) {
 699  }
 700  
 701  NoDataClass::~NoDataClass()
 702  {
 703  }
 704  
 705  std::string NoDataClass::DebugDescription() 
 706  {
 707  	return CoreFoundationObject::DebugDescription() + " | SecTransformNoData";
 708  }
 709  
 710  std::string NoDataClass::FormattingDescription(CFDictionaryRef options) 
 711  {
 712  	return CoreFoundationObject::FormattingDescription(options) + " | SecTransformNoData";
 713  }
 714  
 715  CFTypeRef SecTransformNoData() 
 716  {
 717  	static dispatch_once_t inited;
 718  	static CFTypeRef no_data;
 719  	
 720  	dispatch_once(&inited, 
 721  	^{
 722  		no_data = NoDataClass::Make();
 723  	});
 724  	
 725  	return no_data;
 726  }
 727  
 728  /* ==========================================================================
 729  	class Implementation	CustomTransform	
 730     ==========================================================================*/
 731  
 732  #pragma mark CustomTransform
 733  
 734  void CustomTransform::AttributeChanged(CFStringRef name, CFTypeRef value) {
 735  #ifndef NDEBUG
 736  	// We really shouldn't get here, and this is the debug build so we can blow up on the spot so it is easy to look at the stack trace
 737  	abort();
 738  #else
 739  	// We really shouldn't get here, but this is a production build and recovery is easy to code (but costly to execute)
 740  	AttributeChanged(getAH(name, false), value);
 741  #endif
 742  }
 743  
 744  void CustomTransform::AttributeChanged(SecTransformAttributeRef ah, CFTypeRef value) 
 745  {
 746  	transform_attribute *ta = ah2ta(ah);
 747  	SecTransformAttributeActionBlock attribute_set_notification = NULL;
 748  
 749  	SecTransformAttributeActionBlock attribute_validate = NULL;
 750  
 751  	attribute_validate = (SecTransformAttributeActionBlock)ta->attribute_validate_block;
 752  	if (!attribute_validate) {
 753  			attribute_validate = generic_attribute_validation;
 754  	}
 755  	CFTypeRef vr = attribute_validate(ah, value);
 756  	if (vr) {
 757  			if (CFGetTypeID(vr) == CFErrorGetTypeID()) {
 758  					SendAttribute(AbortAH, vr);
 759  					CFReleaseNull(vr);
 760  			} else {
 761                      CFStringRef idDescription = CFCopyTypeIDDescription(CFGetTypeID(vr));
 762  					CFErrorRef e = CreateSecTransformErrorRef(kSecTransformErrorInvalidType, "Invalid return type from a validate action, expected a CFErrorRef got a %@ (%@)", idDescription, vr);
 763  					SendAttribute(AbortAH, e);
 764  					CFReleaseNull(vr);
 765                      CFReleaseNull(e);
 766                      CFReleaseNull(idDescription);
 767  					// XXX: this causes a core dump -- I think AbortAH doesn't take it's own reference!!   CFReleaseNull(e);
 768  			}
 769  			return;
 770  	}
 771  
 772  	attribute_set_notification = (SecTransformAttributeActionBlock)ta->attribute_changed_block;
 773  
 774  	if ((!attribute_set_notification) && ah == input_ah) 
 775  	{
 776  		CFTypeID vtype = value ? CFGetTypeID(value) : CFDataGetTypeID();
 777  		if (vtype == CFDataGetTypeID()) 
 778  		{
 779  			CFTypeRef output = process_data(value);
 780  			if (output == NULL || output != SecTransformNoData()) 
 781  			{
 782  				SendAttribute(output_ah, output);
 783  
 784                  // if output == value, we are being asked to just
 785                  // forward the existing value.  No need to release.
 786                  // If they are different, we are being asked to
 787                  // send a new value which must be released.
 788  
 789                  if (output != value && output != NULL)
 790                  {
 791                      CFReleaseNull(output);
 792                  }
 793  			}
 794  		} 
 795  		else if (vtype == CFErrorGetTypeID() && !ah2ta(ah)->direct_error_handling) 
 796  		{
 797  			SendAttribute(output_ah, value);
 798  		} else 
 799  		{
 800  			attribute_set_notification = attribute_set_notification ? attribute_set_notification : generic_attribute_set_notification;
 801  			CFTypeRef new_value = attribute_set_notification(ah, value);
 802  			if (new_value != value) 
 803  			{
 804  				SendAttribute(ah, new_value);
 805  			}
 806  		}
 807  	} 
 808  	else 
 809  	{
 810  		CFTypeID vtype = value ? CFGetTypeID(value) : CFDataGetTypeID();
 811  		if (vtype != CFErrorGetTypeID() || ah2ta(ah)->direct_error_handling) 
 812  		{
 813  			attribute_set_notification = attribute_set_notification ? attribute_set_notification : generic_attribute_set_notification;
 814  			CFTypeRef new_value = attribute_set_notification(ah, value);
 815  			if (new_value != value) 
 816  			{
 817  				SendAttribute(ah, new_value);
 818  			}
 819  		} 
 820  		else 
 821  		{
 822  			SendAttribute(output_ah, value);
 823  		}
 824  	}
 825  }
 826  
 827  CFTypeRef CustomTransform::rebind_data_action(CFStringRef action, 
 828  			SecTransformDataBlock new_action) 
 829  {
 830  	CFTypeRef result = NULL;
 831  	if (kCFCompareEqualTo == CFStringCompare(kSecTransformActionProcessData, action, 0)) 
 832  	{
 833  		SetProcessData(new_action);
 834  	}
 835  	else if (kCFCompareEqualTo == CFStringCompare(kSecTransformActionInternalizeExtraData, action, 0))
 836  	{
 837  		SetInternalizeExtraData(new_action);
 838  	}
 839  	else 
 840  	{
 841  		result = (CFTypeRef)CreateSecTransformErrorRef(kSecTransformInvalidOverride, "Unkown override type");
 842  
 843          // XXX: can we get a stackdump here too?
 844          CFStringRef msg = CFStringCreateWithFormat(NULL, NULL,
 845                                                     CFSTR("rebind_data_action (action %@, new_action %p, transform %s)"),
 846                                                     action, (void*)new_action, DebugDescription().c_str());
 847          char *utf8_message = utf8(msg);
 848          syslog(LOG_ERR, "%s", utf8_message);
 849          free(utf8_message);
 850          CFReleaseNull(msg);
 851  	}
 852  	return result;
 853  }
 854  
 855  CFTypeRef CustomTransform::rebind_transform_action(CFStringRef action, SecTransformActionBlock new_action) 
 856  {
 857  	CFErrorRef result = NULL;
 858  	
 859  	if (kCFCompareEqualTo == CFStringCompare(action, kSecTransformActionCanExecute, 0)) 
 860  	{
 861  		SetCanExecute(new_action);
 862  	}
 863  	else if (kCFCompareEqualTo == CFStringCompare(action, kSecTransformActionStartingExecution, 0)) 
 864  	{
 865  		SetExecuteStarting(new_action);
 866  	}
 867  	else if (kCFCompareEqualTo == CFStringCompare(action, kSecTransformActionFinalize, 0))
 868  	{
 869  		SetFinalize(new_action);
 870  	}
 871  	else if (kCFCompareEqualTo == CFStringCompare(action, kSecTransformActionExternalizeExtraData, 0))
 872  	{
 873  		SetExternalizeExtraData(new_action);
 874  	}
 875  	else
 876  	{
 877  		result = CreateSecTransformErrorRef(kSecTransformInvalidOverride, "Unkown override type");
 878  
 879  		char *action_utf8 = utf8(action);
 880  		syslog(LOG_ERR, "rebind_transform_action (action %s, all-attributes, block %p, transform %s)\n", action_utf8, (void*)new_action, DebugDescription().c_str());
 881  		free(action_utf8);
 882  	}
 883  		
 884  	return result;
 885  }
 886  
 887  CFTypeRef CustomTransform::rebind_attribute_action(
 888  			CFStringRef action,
 889  			SecTransformStringOrAttributeRef attribute, 
 890  			SecTransformAttributeActionBlock new_action) 
 891  {
 892  	CFErrorRef result = NULL;
 893  	
 894  	if (kCFCompareEqualTo == CFStringCompare(action, kSecTransformActionAttributeNotification, 0)) 
 895  	{
 896  		SetNotficationBlock(attribute, new_action);
 897  	}
 898  	else if (kCFCompareEqualTo == CFStringCompare(action, kSecTransformActionAttributeValidation, 0))
 899  	{
 900  		SetVerifyBlock(attribute, new_action);
 901  	}
 902  	else
 903  	{
 904  		result = CreateSecTransformErrorRef(kSecTransformInvalidOverride, "Unkown override type");
 905  		char *action_utf8 = utf8(action);
 906  		syslog(LOG_ERR, "rebind_attribute_action (action %s, all-attributes, block %p, transform %s)\n", action_utf8, (void*)new_action, DebugDescription().c_str());
 907  		free(action_utf8);
 908  	}
 909  	
 910  	return result;	
 911  }
 912  
 913  CustomTransform::CustomTransform(CFStringRef cfname, SecTransformCreateFP createFP) : 
 914  	Transform(cfname), 
 915  	createFuncPtr(createFP), 
 916  	instanceBlock(NULL),
 917  	can_run(Block_copy(default_can_run)), 
 918  	execute_starting(Block_copy(default_execute_starting)), 
 919  	finalize(Block_copy(default_finalize)), 
 920  	generic_attribute_set_notification(Block_copy(default_generic_attribute_set_notification)),
 921  	generic_attribute_validation(Block_copy(default_generic_attribute_validation)),
 922  	process_data(Block_copy(default_process_data)),
 923  	externalize_data(Block_copy(default_externalize_data)),
 924  	internalize_data(Block_copy(default_internalize_data))
 925  {
 926  	mAlwaysSelfNotify = true;
 927  	
 928  	input_ah = getAH(kSecTransformInputAttributeName, true);
 929  	output_ah = getAH(kSecTransformOutputAttributeName, true);
 930  	
 931  	parameters.version = kSecTransformCreateBlockParametersVersion;
 932  	parameters.send = Block_copy(^(SecTransformStringOrAttributeRef attribute, SecTransformMetaAttributeType type, CFTypeRef value) 
 933  	{ 
 934  		return SendMetaAttribute(attribute, type, value); 
 935  	});
 936  	
 937  	parameters.pushback = Block_copy(^(SecTransformStringOrAttributeRef attribute, CFTypeRef value) 
 938  	{ 
 939  		return Pushback(getAH(attribute), value); 
 940  	});
 941  	
 942  	parameters.get = Block_copy(^(SecTransformStringOrAttributeRef attribute, SecTransformMetaAttributeType type) 
 943  	{ 
 944  		return GetMetaAttribute(attribute, type); 
 945  	});
 946  	
 947  	parameters.overrideTransform = Block_copy(^(CFStringRef action, SecTransformActionBlock new_action) 
 948  	{ 
 949  		return rebind_transform_action(action, new_action); 
 950  	});
 951  	
 952  	parameters.overrideData = Block_copy(^(CFStringRef action, 
 953  								SecTransformDataBlock new_action)
 954  	{
 955  		return rebind_data_action(action, new_action); 
 956  	});
 957  	
 958  	/*
 959  	 CFTypeRef (^SecTransformOverrideAttributeAction)( 
 960  	 CFStringRef action,
 961  	 SecTransformStringOrAttributeRef attribute, 
 962  	 SecTransformAttributeActionBlock newAction);
 963  	*/
 964  	parameters.overrideAttribute = 
 965  		Block_copy(^(CFStringRef action, SecTransformStringOrAttributeRef attribute, SecTransformAttributeActionBlock new_action) 
 966  	{ 
 967  		return rebind_attribute_action(action, attribute, new_action); 
 968  	});
 969  	
 970  	char *tname = const_cast<char*>(CFStringGetCStringPtr(cfname, kCFStringEncodingUTF8));
 971  	if (!tname) {
 972  		CFIndex sz = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfname), kCFStringEncodingUTF8);
 973  		tname = static_cast<typeof(tname)>(alloca(sz));
 974  		CFStringGetCString(cfname, tname, sz, kCFStringEncodingUTF8);
 975  	}	
 976  	tr = CoreFoundationHolder::MakeHolder(kSecCustom, (CoreFoundationObject*)this);
 977  	
 978  	instanceBlock = (*createFuncPtr)(cfname, tr, &parameters);
 979  }
 980  
 981  void CustomTransform::Create()
 982  {
 983  	(void)instanceBlock();
 984  }
 985  
 986  
 987  CustomTransform::~CustomTransform() {
 988  	finalize();
 989  	
 990  	if (instanceBlock)
 991  	{
 992  		Block_release(instanceBlock);
 993  	}
 994  	
 995  	Block_release(can_run);
 996  	Block_release(execute_starting);
 997  	Block_release(finalize);
 998  	Block_release(generic_attribute_set_notification);
 999  	Block_release(process_data);
1000  	Block_release(externalize_data);
1001  	Block_release(internalize_data);
1002  
1003  	Block_release(parameters.send);
1004  	Block_release(parameters.pushback);
1005  	Block_release(parameters.get);
1006  	Block_release(parameters.overrideTransform);
1007  	Block_release(parameters.overrideData);
1008  	Block_release(parameters.overrideAttribute);
1009  	
1010  	// strictly speaking this isn't needed, but it can help track down some "use after free" bugs
1011  	tr = NULL;
1012  	createFuncPtr = NULL;
1013  	process_data = NULL;
1014  }
1015  
1016  CFErrorRef CustomTransform::TransformStartingExecution() 
1017  {
1018  	CFTypeRef result = execute_starting();
1019  	return (CFErrorRef)result;
1020  }
1021  
1022  
1023  CFDictionaryRef CustomTransform::GetCustomExternalData()
1024  {
1025  	CFTypeRef result = externalize_data();
1026  	if (NULL == result)
1027  	{
1028  		return NULL;
1029  	}
1030  	
1031  	if (CFGetTypeID(result) == CFErrorGetTypeID())
1032  	{
1033  		// Ouch!  we should deal with this
1034  		CFReleaseNull(result);
1035  		return NULL;
1036  	}
1037  	
1038  	if (CFGetTypeID(result) == CFDictionaryGetTypeID())
1039  	{
1040  		return (CFDictionaryRef)result;
1041  	}
1042  	
1043  	CFReleaseNull(result);
1044  	result = NULL;
1045  	return (CFDictionaryRef)result;
1046  }
1047  
1048  
1049  void CustomTransform::SetCustomExternalData(CFDictionaryRef customData)
1050  {
1051  	if (NULL != customData)
1052  	{
1053  		internalize_data(customData);		
1054  	}
1055  	return;
1056  }
1057  
1058  CFErrorRef SecTransformSetAttributeAction(SecTransformImplementationRef ref, 
1059  								CFStringRef action,
1060  								SecTransformStringOrAttributeRef attribute, 
1061  								SecTransformAttributeActionBlock newAction)								
1062  {
1063  	if (NULL == ref)
1064  	{
1065          CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput,
1066  			"SecTransformSetAttributeNotificationAction called with a NULL SecTransformImplementationRef ref");
1067          CFAutorelease(result);
1068  		return result;
1069  	}
1070  	
1071  	return (CFErrorRef)ref->overrideAttribute(action, attribute, newAction);
1072  }
1073  
1074  CFErrorRef SecTransformSetDataAction(SecTransformImplementationRef ref, 
1075  									CFStringRef action, 
1076  									SecTransformDataBlock newAction)
1077  {
1078  	if (NULL == ref)
1079  	{
1080          CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput,
1081  			"SecTransformSetAttributeNotificationAction called with a NULL SecTransformImplementationRef ref");
1082          CFAutorelease(result);
1083  		return result;
1084  	}
1085  	
1086  	return (CFErrorRef)ref->overrideData(action, newAction);	
1087  }
1088  
1089  CFErrorRef SecTransformSetTransformAction(SecTransformImplementationRef ref,
1090  								CFStringRef action, 
1091  								SecTransformActionBlock newAction)
1092  {
1093  	if (NULL == ref)
1094  	{
1095          CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput,
1096  			"SecTransformSetAttributeNotificationAction called with a NULL SecTransformImplementationRef ref");
1097          CFAutorelease(result);
1098  		return result;
1099  	}
1100  	
1101  	return (CFErrorRef)ref->overrideTransform(action, newAction);
1102  }
1103  
1104  CFTypeRef SecTranformCustomGetAttribute(SecTransformImplementationRef ref,
1105                                          SecTransformStringOrAttributeRef attribute,
1106                                          SecTransformMetaAttributeType type)
1107  {
1108  	if (NULL == ref)
1109  	{
1110          CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, 
1111                                                         "SecTransformCustomGetAttribute called with a NULL SecTransformImplementationRef ref");
1112          CFAutorelease(result);
1113  		return result;
1114  	}
1115  	
1116  	return (CFErrorRef)ref->get(attribute, type);
1117  }
1118  
1119  CFTypeRef SecTransformCustomSetAttribute(SecTransformImplementationRef ref,
1120  									SecTransformStringOrAttributeRef attribute, 
1121  									SecTransformMetaAttributeType type, 
1122  									CFTypeRef value)
1123  {
1124  	if (NULL == ref)
1125  	{
1126          CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput,
1127  			"SecTransformCustomSetAttribute called with a NULL SecTransformImplementationRef ref");
1128          CFAutorelease(result);
1129  		return result;
1130  	}
1131  	
1132  	return (CFErrorRef)ref->send(attribute, type, value);
1133  	
1134  }
1135  
1136  CFTypeRef SecTransformPushbackAttribute(SecTransformImplementationRef ref,
1137  								SecTransformStringOrAttributeRef attribute, 
1138  								CFTypeRef value)
1139  {
1140  	if (NULL == ref)
1141  	{
1142          CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput,
1143  			"SecTransformPushbackAttribute called with a NULL SecTransformImplementationRef ref");
1144          CFAutorelease(result);
1145  		return (CFTypeRef)result;
1146  	}
1147  	
1148  	return ref->pushback(attribute, value);
1149  }