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