]> git.saurik.com Git - apple/security.git/blob - libsecurity_transform/lib/SecCustomTransform.cpp
Security-55471.14.tar.gz
[apple/security.git] / libsecurity_transform / lib / SecCustomTransform.cpp
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
20 static const CFStringRef kSecCustom = CFSTR("CustomTransform");
21 const CFStringRef kSecTransformPreviousErrorKey = CFSTR("PreviousError");
22 const CFStringRef kSecTransformAbortOriginatorKey = CFSTR("Originating Transform");
23 const CFStringRef kSecTransformActionCanExecute = CFSTR("CanExecute");
24 const CFStringRef kSecCustomTransformWhatIsRequired = CFSTR("WhatIsRequired");
25 const CFStringRef kSecCustomTransformAttributesToExternalize = CFSTR("AttributesToExternalize");
26 const CFStringRef kSecTransformActionStartingExecution = CFSTR("ExecuteStarting");
27 const CFStringRef kSecTransformActionProcessData = CFSTR("TransformProcessData");
28 const CFStringRef kSecTransformActionAttributeNotification = CFSTR("GenericAttributeSetNotification");
29 const CFStringRef kSecTransformActionFinalize = CFSTR("Finalize");
30 const CFStringRef kSecTransformActionExternalizeExtraData = CFSTR("ExternalizeExtraData");
31 const CFStringRef kSecTransformActionInternalizeExtraData = CFSTR("InternalizeExtraData");
32 const 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 */
58 typedef 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 */
85 typedef 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 */
131 typedef 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 */
155 typedef 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 */
180 typedef 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 */
219 typedef 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 */
229 enum
230 {
231 kSecTransformCreateBlockParametersVersion = 1
232 };
233
234 extern "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 */
264 struct 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
282 class CustomTransformFactory : public TransformFactory
283 {
284 protected:
285 SecTransformCreateFP createFuncPtr;
286 public:
287 CustomTransformFactory(CFStringRef name, SecTransformCreateFP createFP, CFErrorRef *error);
288 virtual ~CustomTransformFactory() {};
289 virtual CFTypeRef Make();
290 };
291
292
293 static SecTransformActionBlock default_can_run = ^{ return (CFTypeRef)NULL; };
294 static SecTransformActionBlock default_execute_starting = default_can_run;
295 static SecTransformActionBlock default_finalize = default_execute_starting;
296 static SecTransformActionBlock default_externalize_data = default_finalize;
297
298 static SecTransformDataBlock default_process_data = ^(CFTypeRef value) { return value; };
299 //static SecTransformDataBlock default_validate = ^(CFTypeRef value) { return (CFTypeRef)NULL; };
300 static SecTransformAttributeActionBlock default_generic_attribute_set_notification =
301 ^(SecTransformAttributeRef ah, CFTypeRef value) { return value; };
302
303 static SecTransformAttributeActionBlock default_generic_attribute_validation =
304 ^(SecTransformAttributeRef ah, CFTypeRef value)
305 {
306 return (CFTypeRef)NULL;
307 };
308
309 static SecTransformDataBlock default_internalize_data =
310 ^(CFTypeRef value)
311 {
312 return (CFTypeRef)NULL;
313 };
314
315 class CustomTransform : public Transform
316 {
317 protected:
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
484 public:
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
514 CustomTransformFactory::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
557 CFTypeRef 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
566 extern "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
611 Boolean 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
631 SecTransformRef SecTransformCreate(CFStringRef name, CFErrorRef *error)
632 {
633 SecTransformRef tr = TransformFactory::MakeTransformWithType(name, error);
634 return tr;
635 }
636
637 extern "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
661 class NoDataClass : public CoreFoundationObject
662 {
663 protected:
664 NoDataClass();
665
666 public:
667 virtual ~NoDataClass();
668 std::string FormattingDescription(CFDictionaryRef options);
669 std::string DebugDescription();
670 static CFTypeRef Make();
671 };
672
673 CFTypeRef NoDataClass::Make() {
674 NoDataClass* obj = new NoDataClass();
675 return CoreFoundationHolder::MakeHolder(gInternalProtectedCFObjectName, obj);
676 }
677
678
679 NoDataClass::NoDataClass() : CoreFoundationObject(gInternalProtectedCFObjectName) {
680 }
681
682 NoDataClass::~NoDataClass()
683 {
684 }
685
686 std::string NoDataClass::DebugDescription()
687 {
688 return CoreFoundationObject::DebugDescription() + " | SecTransformNoData";
689 }
690
691 std::string NoDataClass::FormattingDescription(CFDictionaryRef options)
692 {
693 return CoreFoundationObject::FormattingDescription(options) + " | SecTransformNoData";
694 }
695
696 CFTypeRef 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
715 void 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
725 void 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
805 CFTypeRef 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
833 CFTypeRef 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
865 CFTypeRef 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
891 CustomTransform::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
959 void CustomTransform::Create()
960 {
961 (void)instanceBlock();
962 }
963
964
965 CustomTransform::~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
994 CFErrorRef CustomTransform::TransformStartingExecution()
995 {
996 CFTypeRef result = execute_starting();
997 return (CFErrorRef)result;
998 }
999
1000
1001 CFDictionaryRef 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
1027 void CustomTransform::SetCustomExternalData(CFDictionaryRef customData)
1028 {
1029 if (NULL != customData)
1030 {
1031 internalize_data(customData);
1032 }
1033 return;
1034 }
1035
1036 CFErrorRef 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
1052 CFErrorRef 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
1067 CFErrorRef 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
1082 CFTypeRef 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
1097 CFTypeRef 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
1114 CFTypeRef 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 }