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