2 * Copyright (c) 2010-2012,2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 #include "SecCustomTransform.h"
26 #include "SecTransformValidator.h"
28 #include "TransformFactory.h"
29 #include <CoreFoundation/CoreFoundation.h>
32 #include "Utilities.h"
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");
48 @function SecTransformOverrideTransformAction
50 @abstract Used to override the default behavior of a custom transform.
52 @param action This should be either kSecTransformActionCanExecute,
53 kSecTransformActionStartingExecution, or
54 kSecTransformActionFinalize which signifies the behavior
55 that is being overridden.
58 A SecTransformAttributeActionBlock block that implements the
59 override behavior. Please see the
60 SecTransformActionBlock discussion for more
63 @result A CFErrorRef if an error occurred, NULL otherwise.
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
71 typedef CFTypeRef (^SecTransformOverrideTransformAction
)(CFStringRef action
,
72 SecTransformActionBlock newAction
);
75 @function SecTransformOverrideDataAction
77 @abstract Changes the default attribute handling for a
80 @param action This should be either kSecTransformActionProcessData,
81 kSecTransformActionExternalizeExtraData which signifies
82 what behavior is being overridden.
85 A SecTransformDataBlock block that implements the
86 override behavior. Please see the
87 SecTransformDataBlock discussion for more
90 @result A CFErrorRef if an error occurred. NULL otherwise.
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
98 typedef CFTypeRef (^SecTransformOverrideDataAction
)(CFStringRef action
,
99 SecTransformDataBlock newAction
);
102 @function SecTransformOverrideAttributeAction
104 @abstract Changes the default attribute handling for a
107 @param action This should be either SecTransformSetAttributeAction,
108 kSecTransformActionAttributeValidation which signifies
109 what behavior is being overridden.
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.
117 A SecTransformAttributeActionBlock block
118 that implements the override behavior.
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.
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.
136 @result A CFErrorRef if an error occurred. NULL otherwise.
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.
144 typedef CFTypeRef (^SecTransformOverrideAttributeAction
)(
146 SecTransformStringOrAttributeRef attribute
,
147 SecTransformAttributeActionBlock newAction
);
151 @function SecTransformGetAttributeBlock
153 @abstract Retrieves the value of the attribute metadata of the
157 The attribute from which to retrieve the metadata from.
159 @param type The type of the metadata to be fetched.
161 @result The value of the metadata that was retrieved or a CFErrorRef
164 @result The value of the metadata that was retrieved.
168 typedef CFTypeRef (^SecTransformGetAttributeBlock
)(
169 SecTransformStringOrAttributeRef attribute
,
170 SecTransformMetaAttributeType type
);
173 @function SecTransformSetAttributeBlock
175 @abstract This sets the value of the metadata of an attribute.
178 The attribute whose value is sent
180 @param type The metadata type that specifies what metadata value
183 @param value The value of the metadata to be sent.
185 @result A CFErrorRef is an error occurred, NULL otherwise.
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
193 typedef CFErrorRef (^SecTransformSetAttributeBlock
)(
194 SecTransformStringOrAttributeRef attribute
,
195 SecTransformMetaAttributeType type
,
200 @function SecTransformPushBackAttributeBlock
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.
208 The attribute that has its data pushed back.
210 @param value The value being pushed back.
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.
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
232 typedef CFErrorRef (^SecTransformPushBackAttributeBlock
)(
233 SecTransformStringOrAttributeRef attribute
,
237 @const kSecTransformCreateBlockParametersVersion
238 The current version number of the SecTransformCreateBlockParameters
244 kSecTransformCreateBlockParametersVersion
= 1
248 Boolean
SecExternalSourceSetValue(SecTransformRef xst
, CFTypeRef value
, CFErrorRef
*error
);
252 @struct OpaqueSecTransformImplementation
255 The version number of this structure
257 @field overrideTransform
258 A SecTransformOverrideTransformAction block. See
259 the headerdoc for this block for additional information.
261 @field overrideAttribute
262 A SecTransformOverrideAttributeAction block. See
263 the headerdoc for this block for additional information.
266 A SecTransformGetAttributeBlock block. See
267 the headerdoc for this block for additional information.
270 A SecTransformSetAttributeBlock block. See
271 the headerdoc for this block for additional information.
274 A SecTransformPushBackAttributeBlock block. See
275 the headerdoc for this block for additional information.
277 struct OpaqueSecTransformImplementation
279 CFIndex version
; // Set to kSecTransformCreateBlockParametersVersion
281 // The following two blocks allow for overriding 'standard'
282 // transform behavior
283 SecTransformOverrideTransformAction overrideTransform
;
284 SecTransformOverrideDataAction overrideData
;
285 SecTransformOverrideAttributeAction overrideAttribute
;
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
;
295 class CustomTransformFactory
: public TransformFactory
298 SecTransformCreateFP createFuncPtr
;
300 CustomTransformFactory(CFStringRef name
, SecTransformCreateFP createFP
, CFErrorRef
*error
);
301 virtual ~CustomTransformFactory() {};
302 virtual CFTypeRef
Make();
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
;
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
; };
316 static SecTransformAttributeActionBlock default_generic_attribute_validation
=
317 ^(SecTransformAttributeRef ah
, CFTypeRef value
)
319 return (CFTypeRef
)NULL
;
322 static SecTransformDataBlock default_internalize_data
=
325 return (CFTypeRef
)NULL
;
328 class CustomTransform
: public Transform
331 SecTransformCreateFP createFuncPtr
;
332 SecTransformInstanceBlock instanceBlock
;
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
;
345 SecTransformAttributeRef input_ah
;
346 SecTransformAttributeRef output_ah
;
348 OpaqueSecTransformImplementation parameters
;
350 void SetCanExecute(SecTransformActionBlock CanExecuteBlock
)
352 Block_release(can_run
);
355 can_run
= Block_copy(CanExecuteBlock
);
360 can_run
= Block_copy(default_can_run
);
364 void SetExecuteStarting(SecTransformActionBlock executeStartingBlock
)
366 Block_release(execute_starting
);
367 if (executeStartingBlock
)
369 execute_starting
= Block_copy(executeStartingBlock
);
374 execute_starting
= Block_copy(default_execute_starting
);
378 void SetFinalize(SecTransformActionBlock finalizeBlock
)
380 Block_release(finalize
);
383 finalize
= Block_copy(finalizeBlock
);
388 finalize
= Block_copy(default_finalize
);
392 void SetExternalizeExtraData(SecTransformActionBlock externalizeBlock
)
394 Block_release(externalizeBlock
);
395 if (externalizeBlock
)
397 externalize_data
= Block_copy(externalizeBlock
);
402 externalize_data
= Block_copy(default_externalize_data
);
406 void SetProcessData(SecTransformDataBlock processDataBlock
)
408 Block_release(process_data
);
409 if (processDataBlock
)
411 process_data
= Block_copy(processDataBlock
);
416 process_data
= Block_copy(default_process_data
);
420 void SetInternalizeExtraData(SecTransformDataBlock InternalizeExtraDataBlock
)
422 Block_release(internalize_data
);
423 if (InternalizeExtraDataBlock
)
425 internalize_data
= Block_copy(InternalizeExtraDataBlock
);
430 internalize_data
= Block_copy(default_internalize_data
);
436 void SetNotficationBlock(SecTransformStringOrAttributeRef attribute
,
437 SecTransformAttributeActionBlock notificationBlock
)
439 SecTransformAttributeActionBlock blockToSet
=
440 Block_copy((notificationBlock
) ? notificationBlock
:
441 default_generic_attribute_set_notification
);
445 transform_attribute
*ta
= getTA(attribute
, true);
447 if (ta
->attribute_changed_block
)
449 Block_release(ta
->attribute_changed_block
);
452 ta
->attribute_changed_block
= blockToSet
;
457 if (generic_attribute_set_notification
)
459 Block_release(generic_attribute_set_notification
);
462 generic_attribute_set_notification
= blockToSet
;
466 void SetVerifyBlock(SecTransformStringOrAttributeRef attribute
,
467 SecTransformAttributeActionBlock verifyBlock
)
469 SecTransformAttributeActionBlock blockToSet
=
470 Block_copy((verifyBlock
) ? verifyBlock
:
471 generic_attribute_validation
);
475 transform_attribute
*ta
= getTA(attribute
, true);
477 if (ta
->attribute_validate_block
)
479 Block_release(ta
->attribute_validate_block
);
482 ta
->attribute_validate_block
= blockToSet
;
486 if (generic_attribute_validation
)
488 Block_release(generic_attribute_validation
);
491 generic_attribute_validation
= blockToSet
;
498 CustomTransform(CFStringRef name
, SecTransformCreateFP createFP
);
499 virtual ~CustomTransform();
503 CFTypeRef
rebind_data_action(CFStringRef action
,
504 SecTransformDataBlock new_action
);
506 CFTypeRef
rebind_transform_action(CFStringRef action
, SecTransformActionBlock new_action
);
508 CFTypeRef
rebind_attribute_action(CFStringRef action
,
509 SecTransformStringOrAttributeRef attribute
,
510 SecTransformAttributeActionBlock new_action
);
512 SecTransformRef
get_ref() { return tr
; }
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
);
520 friend Boolean
SecExternalSourceSetValue(SecTransformRef xst
, CFTypeRef value
, CFErrorRef
*error
);
525 #pragma mark CustomTransformFactory
527 CustomTransformFactory::CustomTransformFactory(CFStringRef uniqueName
, SecTransformCreateFP createFP
, CFErrorRef
* error
) :
528 TransformFactory(uniqueName
, false, kSecCustom
),
529 createFuncPtr(createFP
)
531 TransformFactory
*existing
= FindTransformFactoryByType(uniqueName
);
536 *error
= CreateSecTransformErrorRef(kSecTransformErrorNameAlreadyRegistered
,
537 "Custom transform type %s already exists.", uniqueName
);
543 if (CFStringGetCharacterAtIndex(uniqueName
, 0) == '_')
547 *error
= CreateSecTransformErrorRef(kSecTransformInvalidArgument
,
548 "Invalid transform type name %s -- type names must not start with an _", uniqueName
);
553 static CFCharacterSetRef invalidTypeCharactors
= NULL
;
554 static dispatch_once_t setupInvalidTypeCharactors
;
555 dispatch_once(&setupInvalidTypeCharactors
, ^{
556 invalidTypeCharactors
= CFCharacterSetCreateWithCharactersInString(NULL
, CFSTR("/:"));
559 if (CFStringFindCharacterFromSet(uniqueName
, invalidTypeCharactors
, CFRangeMake(0, CFStringGetLength(uniqueName
)), 0, &has_bad
)) {
562 *error
= CreateSecTransformErrorRef(kSecTransformInvalidArgument
,
563 "Invalid character '%c' in transform type name %s", CFStringGetCharacterAtIndex(uniqueName
, has_bad
.location
), uniqueName
);
567 RegisterTransform(this, kSecCustom
);
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
574 CustomTransform
*ct
= new CustomTransform(this->GetTypename(), createFuncPtr
);
576 return ct
->get_ref();
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
;
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(""),
595 null_allowed
? CFSTR(" or a NULL") : CFSTR(""));
596 CFReleaseNull(value_type_name
);
598 error
= CreateSecTransformErrorRef(kSecTransformErrorInvalidType
, "%@ received NULL value, expected a %@",
599 attr
, expected_type_name
);
601 CFReleaseNull(expected_type_name
);
608 validate
= ^(SecTransformAttributeRef attr
, CFTypeRef value
) {
609 if (value
== NULL
|| CFGetTypeID(value
) == expected_type
) {
610 return (CFTypeRef
)NULL
;
612 return (CFTypeRef
)make_error_message(attr
, value
, expected_type
, null_allowed
);
615 validate
= ^(SecTransformAttributeRef attr
, CFTypeRef value
) {
616 if (value
!= NULL
&& CFGetTypeID(value
) == expected_type
) {
617 return (CFTypeRef
)NULL
;
619 return (CFTypeRef
)make_error_message(attr
, value
, expected_type
, null_allowed
);
623 return Block_copy(validate
);
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
)
631 CFErrorRef error
= NULL
;
633 CustomTransformFactory
*tf
= new CustomTransformFactory(uniqueName
, createFP
, &error
);
639 *caller_error
= error
;
650 SecTransformRef
SecTransformCreate(CFStringRef name
, CFErrorRef
*error
)
652 SecTransformRef tr
= TransformFactory::MakeTransformWithType(name
, error
);
657 Boolean
SecExternalSourceSetValue(SecTransformRef xst
, CFTypeRef value
, CFErrorRef
*error
)
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
);
666 *error
= CreateSecTransformErrorRef(kSecTransformErrorInvalidType
, "SecExternalSourceSetValue called for %@, you need to pass in an ExternalSource transform not a %@", ct
->GetName(), ct
->mTypeName
);
673 /* ==========================================================================
675 description: A Special CFType that signifies that no data is being
677 ==========================================================================*/
678 #pragma mark NoDataClass
680 class NoDataClass
: public CoreFoundationObject
686 virtual ~NoDataClass();
687 std::string
FormattingDescription(CFDictionaryRef options
);
688 std::string
DebugDescription();
689 static CFTypeRef
Make();
692 CFTypeRef
NoDataClass::Make() {
693 NoDataClass
* obj
= new NoDataClass();
694 return CoreFoundationHolder::MakeHolder(gInternalProtectedCFObjectName
, obj
);
698 NoDataClass::NoDataClass() : CoreFoundationObject(gInternalProtectedCFObjectName
) {
701 NoDataClass::~NoDataClass()
705 std::string
NoDataClass::DebugDescription()
707 return CoreFoundationObject::DebugDescription() + " | SecTransformNoData";
710 std::string
NoDataClass::FormattingDescription(CFDictionaryRef options
)
712 return CoreFoundationObject::FormattingDescription(options
) + " | SecTransformNoData";
715 CFTypeRef
SecTransformNoData()
717 static dispatch_once_t inited
;
718 static CFTypeRef no_data
;
720 dispatch_once(&inited
,
722 no_data
= NoDataClass::Make();
728 /* ==========================================================================
729 class Implementation CustomTransform
730 ==========================================================================*/
732 #pragma mark CustomTransform
734 void CustomTransform::AttributeChanged(CFStringRef name
, CFTypeRef value
) {
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
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
);
744 void CustomTransform::AttributeChanged(SecTransformAttributeRef ah
, CFTypeRef value
)
746 transform_attribute
*ta
= ah2ta(ah
);
747 SecTransformAttributeActionBlock attribute_set_notification
= NULL
;
749 SecTransformAttributeActionBlock attribute_validate
= NULL
;
751 attribute_validate
= (SecTransformAttributeActionBlock
)ta
->attribute_validate_block
;
752 if (!attribute_validate
) {
753 attribute_validate
= generic_attribute_validation
;
755 CFTypeRef vr
= attribute_validate(ah
, value
);
757 if (CFGetTypeID(vr
) == CFErrorGetTypeID()) {
758 SendAttribute(AbortAH
, vr
);
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
);
766 CFReleaseNull(idDescription
);
767 // XXX: this causes a core dump -- I think AbortAH doesn't take it's own reference!! CFReleaseNull(e);
772 attribute_set_notification
= (SecTransformAttributeActionBlock
)ta
->attribute_changed_block
;
774 if ((!attribute_set_notification
) && ah
== input_ah
)
776 CFTypeID vtype
= value
? CFGetTypeID(value
) : CFDataGetTypeID();
777 if (vtype
== CFDataGetTypeID())
779 CFTypeRef output
= process_data(value
);
780 if (output
== NULL
|| output
!= SecTransformNoData())
782 SendAttribute(output_ah
, output
);
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.
789 if (output
!= value
&& output
!= NULL
)
791 CFReleaseNull(output
);
795 else if (vtype
== CFErrorGetTypeID() && !ah2ta(ah
)->direct_error_handling
)
797 SendAttribute(output_ah
, value
);
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
)
804 SendAttribute(ah
, new_value
);
810 CFTypeID vtype
= value
? CFGetTypeID(value
) : CFDataGetTypeID();
811 if (vtype
!= CFErrorGetTypeID() || ah2ta(ah
)->direct_error_handling
)
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
)
817 SendAttribute(ah
, new_value
);
822 SendAttribute(output_ah
, value
);
827 CFTypeRef
CustomTransform::rebind_data_action(CFStringRef action
,
828 SecTransformDataBlock new_action
)
830 CFTypeRef result
= NULL
;
831 if (kCFCompareEqualTo
== CFStringCompare(kSecTransformActionProcessData
, action
, 0))
833 SetProcessData(new_action
);
835 else if (kCFCompareEqualTo
== CFStringCompare(kSecTransformActionInternalizeExtraData
, action
, 0))
837 SetInternalizeExtraData(new_action
);
841 result
= (CFTypeRef
)CreateSecTransformErrorRef(kSecTransformInvalidOverride
, "Unkown override type");
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
);
855 CFTypeRef
CustomTransform::rebind_transform_action(CFStringRef action
, SecTransformActionBlock new_action
)
857 CFErrorRef result
= NULL
;
859 if (kCFCompareEqualTo
== CFStringCompare(action
, kSecTransformActionCanExecute
, 0))
861 SetCanExecute(new_action
);
863 else if (kCFCompareEqualTo
== CFStringCompare(action
, kSecTransformActionStartingExecution
, 0))
865 SetExecuteStarting(new_action
);
867 else if (kCFCompareEqualTo
== CFStringCompare(action
, kSecTransformActionFinalize
, 0))
869 SetFinalize(new_action
);
871 else if (kCFCompareEqualTo
== CFStringCompare(action
, kSecTransformActionExternalizeExtraData
, 0))
873 SetExternalizeExtraData(new_action
);
877 result
= CreateSecTransformErrorRef(kSecTransformInvalidOverride
, "Unkown override type");
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());
887 CFTypeRef
CustomTransform::rebind_attribute_action(
889 SecTransformStringOrAttributeRef attribute
,
890 SecTransformAttributeActionBlock new_action
)
892 CFErrorRef result
= NULL
;
894 if (kCFCompareEqualTo
== CFStringCompare(action
, kSecTransformActionAttributeNotification
, 0))
896 SetNotficationBlock(attribute
, new_action
);
898 else if (kCFCompareEqualTo
== CFStringCompare(action
, kSecTransformActionAttributeValidation
, 0))
900 SetVerifyBlock(attribute
, new_action
);
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());
913 CustomTransform::CustomTransform(CFStringRef cfname
, SecTransformCreateFP createFP
) :
915 createFuncPtr(createFP
),
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
))
926 mAlwaysSelfNotify
= true;
928 input_ah
= getAH(kSecTransformInputAttributeName
, true);
929 output_ah
= getAH(kSecTransformOutputAttributeName
, true);
931 parameters
.version
= kSecTransformCreateBlockParametersVersion
;
932 parameters
.send
= Block_copy(^(SecTransformStringOrAttributeRef attribute
, SecTransformMetaAttributeType type
, CFTypeRef value
)
934 return SendMetaAttribute(attribute
, type
, value
);
937 parameters
.pushback
= Block_copy(^(SecTransformStringOrAttributeRef attribute
, CFTypeRef value
)
939 return Pushback(getAH(attribute
), value
);
942 parameters
.get
= Block_copy(^(SecTransformStringOrAttributeRef attribute
, SecTransformMetaAttributeType type
)
944 return GetMetaAttribute(attribute
, type
);
947 parameters
.overrideTransform
= Block_copy(^(CFStringRef action
, SecTransformActionBlock new_action
)
949 return rebind_transform_action(action
, new_action
);
952 parameters
.overrideData
= Block_copy(^(CFStringRef action
,
953 SecTransformDataBlock new_action
)
955 return rebind_data_action(action
, new_action
);
959 CFTypeRef (^SecTransformOverrideAttributeAction)(
961 SecTransformStringOrAttributeRef attribute,
962 SecTransformAttributeActionBlock newAction);
964 parameters
.overrideAttribute
=
965 Block_copy(^(CFStringRef action
, SecTransformStringOrAttributeRef attribute
, SecTransformAttributeActionBlock new_action
)
967 return rebind_attribute_action(action
, attribute
, new_action
);
970 char *tname
= const_cast<char*>(CFStringGetCStringPtr(cfname
, kCFStringEncodingUTF8
));
972 CFIndex sz
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfname
), kCFStringEncodingUTF8
);
973 tname
= static_cast<typeof(tname
)>(alloca(sz
));
974 CFStringGetCString(cfname
, tname
, sz
, kCFStringEncodingUTF8
);
976 tr
= CoreFoundationHolder::MakeHolder(kSecCustom
, (CoreFoundationObject
*)this);
978 instanceBlock
= (*createFuncPtr
)(cfname
, tr
, ¶meters
);
981 void CustomTransform::Create()
983 (void)instanceBlock();
987 CustomTransform::~CustomTransform() {
992 Block_release(instanceBlock
);
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
);
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
);
1010 // strictly speaking this isn't needed, but it can help track down some "use after free" bugs
1012 createFuncPtr
= NULL
;
1013 process_data
= NULL
;
1016 CFErrorRef
CustomTransform::TransformStartingExecution()
1018 CFTypeRef result
= execute_starting();
1019 return (CFErrorRef
)result
;
1023 CFDictionaryRef
CustomTransform::GetCustomExternalData()
1025 CFTypeRef result
= externalize_data();
1031 if (CFGetTypeID(result
) == CFErrorGetTypeID())
1033 // Ouch! we should deal with this
1034 CFReleaseNull(result
);
1038 if (CFGetTypeID(result
) == CFDictionaryGetTypeID())
1040 return (CFDictionaryRef
)result
;
1043 CFReleaseNull(result
);
1045 return (CFDictionaryRef
)result
;
1049 void CustomTransform::SetCustomExternalData(CFDictionaryRef customData
)
1051 if (NULL
!= customData
)
1053 internalize_data(customData
);
1058 CFErrorRef
SecTransformSetAttributeAction(SecTransformImplementationRef ref
,
1060 SecTransformStringOrAttributeRef attribute
,
1061 SecTransformAttributeActionBlock newAction
)
1065 CFErrorRef result
= CreateSecTransformErrorRef(kSecTransformErrorInvalidInput
,
1066 "SecTransformSetAttributeNotificationAction called with a NULL SecTransformImplementationRef ref");
1067 CFAutorelease(result
);
1071 return (CFErrorRef
)ref
->overrideAttribute(action
, attribute
, newAction
);
1074 CFErrorRef
SecTransformSetDataAction(SecTransformImplementationRef ref
,
1076 SecTransformDataBlock newAction
)
1080 CFErrorRef result
= CreateSecTransformErrorRef(kSecTransformErrorInvalidInput
,
1081 "SecTransformSetAttributeNotificationAction called with a NULL SecTransformImplementationRef ref");
1082 CFAutorelease(result
);
1086 return (CFErrorRef
)ref
->overrideData(action
, newAction
);
1089 CFErrorRef
SecTransformSetTransformAction(SecTransformImplementationRef ref
,
1091 SecTransformActionBlock newAction
)
1095 CFErrorRef result
= CreateSecTransformErrorRef(kSecTransformErrorInvalidInput
,
1096 "SecTransformSetAttributeNotificationAction called with a NULL SecTransformImplementationRef ref");
1097 CFAutorelease(result
);
1101 return (CFErrorRef
)ref
->overrideTransform(action
, newAction
);
1104 CFTypeRef
SecTranformCustomGetAttribute(SecTransformImplementationRef ref
,
1105 SecTransformStringOrAttributeRef attribute
,
1106 SecTransformMetaAttributeType type
)
1110 CFErrorRef result
= CreateSecTransformErrorRef(kSecTransformErrorInvalidInput
,
1111 "SecTransformCustomGetAttribute called with a NULL SecTransformImplementationRef ref");
1112 CFAutorelease(result
);
1116 return (CFErrorRef
)ref
->get(attribute
, type
);
1119 CFTypeRef
SecTransformCustomSetAttribute(SecTransformImplementationRef ref
,
1120 SecTransformStringOrAttributeRef attribute
,
1121 SecTransformMetaAttributeType type
,
1126 CFErrorRef result
= CreateSecTransformErrorRef(kSecTransformErrorInvalidInput
,
1127 "SecTransformCustomSetAttribute called with a NULL SecTransformImplementationRef ref");
1128 CFAutorelease(result
);
1132 return (CFErrorRef
)ref
->send(attribute
, type
, value
);
1136 CFTypeRef
SecTransformPushbackAttribute(SecTransformImplementationRef ref
,
1137 SecTransformStringOrAttributeRef attribute
,
1142 CFErrorRef result
= CreateSecTransformErrorRef(kSecTransformErrorInvalidInput
,
1143 "SecTransformPushbackAttribute called with a NULL SecTransformImplementationRef ref");
1144 CFAutorelease(result
);
1145 return (CFTypeRef
)result
;
1148 return ref
->pushback(attribute
, value
);