]> git.saurik.com Git - apple/security.git/blob - libsecurity_transform/lib/SecCustomTransform.cpp
263ef9fb73d8808e3f3ef16c47d825fd54eab1d7
[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
12 #include "TransformFactory.h"
13 #include <CoreFoundation/CoreFoundation.h>
14 #include <Block.h>
15 #include <syslog.h>
16 #include "Utilities.h"
17 #include "misc.h"
18
19 static const CFStringRef kSecCustom = CFSTR("CustomTransform");
20 static const char *kSecCustom_cstr = "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 CFTypeRef Make();
289 };
290
291
292 static SecTransformActionBlock default_can_run = ^{ return (CFTypeRef)NULL; };
293 static SecTransformActionBlock default_execute_starting = default_can_run;
294 static SecTransformActionBlock default_finalize = default_execute_starting;
295 static SecTransformActionBlock default_externalize_data = default_finalize;
296
297 static SecTransformDataBlock default_process_data = ^(CFTypeRef value) { return value; };
298 //static SecTransformDataBlock default_validate = ^(CFTypeRef value) { return (CFTypeRef)NULL; };
299 static SecTransformAttributeActionBlock default_generic_attribute_set_notification =
300 ^(SecTransformAttributeRef ah, CFTypeRef value) { return value; };
301
302 static SecTransformAttributeActionBlock default_generic_attribute_validation =
303 ^(SecTransformAttributeRef ah, CFTypeRef value)
304 {
305 return (CFTypeRef)NULL;
306 };
307
308 static SecTransformDataBlock default_internalize_data =
309 ^(CFTypeRef value)
310 {
311 return (CFTypeRef)NULL;
312 };
313
314 class CustomTransform : public Transform
315 {
316 protected:
317 SecTransformCreateFP createFuncPtr;
318 SecTransformInstanceBlock instanceBlock;
319
320 SecTransformActionBlock can_run;
321 SecTransformActionBlock execute_starting;
322 SecTransformActionBlock finalize;
323 SecTransformAttributeActionBlock generic_attribute_set_notification;
324 SecTransformAttributeActionBlock generic_attribute_validation;
325 SecTransformDataBlock process_data;
326 SecTransformActionBlock externalize_data;
327 SecTransformDataBlock internalize_data;
328
329 SecTransformRef tr;
330
331 SecTransformAttributeRef input_ah;
332 SecTransformAttributeRef output_ah;
333
334 OpaqueSecTransformImplementation parameters;
335
336 void SetCanExecute(SecTransformActionBlock CanExecuteBlock)
337 {
338 Block_release(can_run);
339 if (CanExecuteBlock)
340 {
341 can_run = Block_copy(CanExecuteBlock);
342
343 }
344 else
345 {
346 can_run = Block_copy(default_can_run);
347 }
348 }
349
350 void SetExecuteStarting(SecTransformActionBlock executeStartingBlock)
351 {
352 Block_release(execute_starting);
353 if (executeStartingBlock)
354 {
355 execute_starting = Block_copy(executeStartingBlock);
356
357 }
358 else
359 {
360 execute_starting = Block_copy(default_execute_starting);
361 }
362 }
363
364 void SetFinalize(SecTransformActionBlock finalizeBlock)
365 {
366 Block_release(finalize);
367 if (finalizeBlock)
368 {
369 finalize = Block_copy(finalizeBlock);
370
371 }
372 else
373 {
374 finalize = Block_copy(default_finalize);
375 }
376 }
377
378 void SetExternalizeExtraData(SecTransformActionBlock externalizeBlock)
379 {
380 Block_release(externalizeBlock);
381 if (externalizeBlock)
382 {
383 externalize_data = Block_copy(externalizeBlock);
384
385 }
386 else
387 {
388 externalize_data = Block_copy(default_externalize_data);
389 }
390 }
391
392 void SetProcessData(SecTransformDataBlock processDataBlock)
393 {
394 Block_release(process_data);
395 if (processDataBlock)
396 {
397 process_data = Block_copy(processDataBlock);
398
399 }
400 else
401 {
402 process_data = Block_copy(default_process_data);
403 }
404 }
405
406 void SetInternalizeExtraData(SecTransformDataBlock InternalizeExtraDataBlock)
407 {
408 Block_release(internalize_data);
409 if (InternalizeExtraDataBlock)
410 {
411 internalize_data = Block_copy(InternalizeExtraDataBlock);
412
413 }
414 else
415 {
416 internalize_data = Block_copy(default_internalize_data);
417 }
418 }
419
420
421
422 void SetNotficationBlock(SecTransformStringOrAttributeRef attribute,
423 SecTransformAttributeActionBlock notificationBlock)
424 {
425 SecTransformAttributeActionBlock blockToSet =
426 Block_copy((notificationBlock) ? notificationBlock :
427 default_generic_attribute_set_notification);
428
429 if (attribute)
430 {
431 transform_attribute *ta = getTA(attribute, true);
432
433 if (ta->attribute_changed_block)
434 {
435 Block_release(ta->attribute_changed_block);
436 }
437
438 ta->attribute_changed_block = blockToSet;
439 }
440 else
441 {
442
443 if (generic_attribute_set_notification)
444 {
445 Block_release(generic_attribute_set_notification);
446 }
447
448 generic_attribute_set_notification = blockToSet;
449 }
450 }
451
452 void SetVerifyBlock(SecTransformStringOrAttributeRef attribute,
453 SecTransformAttributeActionBlock verifyBlock)
454 {
455 SecTransformAttributeActionBlock blockToSet =
456 Block_copy((verifyBlock) ? verifyBlock :
457 generic_attribute_validation);
458
459 if (attribute)
460 {
461 transform_attribute *ta = getTA(attribute, true);
462
463 if (ta->attribute_validate_block)
464 {
465 Block_release(ta->attribute_validate_block);
466 }
467
468 ta->attribute_validate_block = blockToSet;
469 }
470 else
471 {
472 if (generic_attribute_validation)
473 {
474 Block_release(generic_attribute_validation);
475 }
476
477 generic_attribute_validation = blockToSet;
478 }
479 }
480
481
482
483 public:
484 CustomTransform(CFStringRef name, SecTransformCreateFP createFP);
485 virtual ~CustomTransform();
486
487 void Create();
488
489 CFTypeRef rebind_data_action(CFStringRef action,
490 SecTransformDataBlock new_action);
491
492 CFTypeRef rebind_transform_action(CFStringRef action, SecTransformActionBlock new_action);
493
494 CFTypeRef rebind_attribute_action(CFStringRef action,
495 SecTransformStringOrAttributeRef attribute,
496 SecTransformAttributeActionBlock new_action);
497
498 SecTransformRef get_ref() { return tr; }
499
500 virtual void AttributeChanged(CFStringRef name, CFTypeRef value);
501 virtual void AttributeChanged(SecTransformAttributeRef ah, CFTypeRef value);
502 virtual CFErrorRef TransformStartingExecution();
503 virtual CFDictionaryRef GetCustomExternalData();
504 virtual void SetCustomExternalData(CFDictionaryRef customData);
505
506 friend Boolean SecExternalSourceSetValue(SecTransformRef xst, CFTypeRef value, CFErrorRef *error);
507 };
508
509
510
511 #pragma mark CustomTransformFactory
512
513 CustomTransformFactory::CustomTransformFactory(CFStringRef uniqueName, SecTransformCreateFP createFP, CFErrorRef* error) :
514 TransformFactory(uniqueName, false, kSecCustom),
515 createFuncPtr(createFP)
516 {
517 TransformFactory *existing = FindTransformFactoryByType(uniqueName);
518 if (existing)
519 {
520 if (error)
521 {
522 *error = CreateSecTransformErrorRef(kSecTransformErrorNameAlreadyRegistered,
523 "Custom transform type %s already exists.", uniqueName);
524 }
525 return;
526 }
527
528
529 if (CFStringGetCharacterAtIndex(uniqueName, 0) == '_')
530 {
531 if (error)
532 {
533 *error = CreateSecTransformErrorRef(kSecTransformInvalidArgument,
534 "Invalid transform type name %s -- type names must not start with an _", uniqueName);
535 }
536 return;
537 }
538
539 static CFCharacterSetRef invalidTypeCharactors = NULL;
540 static dispatch_once_t setupInvalidTypeCharactors;
541 dispatch_once(&setupInvalidTypeCharactors, ^{
542 invalidTypeCharactors = CFCharacterSetCreateWithCharactersInString(NULL, CFSTR("/:"));
543 });
544 CFRange has_bad;
545 if (CFStringFindCharacterFromSet(uniqueName, invalidTypeCharactors, CFRangeMake(0, CFStringGetLength(uniqueName)), 0, &has_bad)) {
546 if (error)
547 {
548 *error = CreateSecTransformErrorRef(kSecTransformInvalidArgument,
549 "Invalid character '%c' in transform type name %s", CFStringGetCharacterAtIndex(uniqueName, has_bad.location), uniqueName);
550 }
551 return;
552 }
553 RegisterTransform(this, kSecCustom);
554 }
555
556 CFTypeRef CustomTransformFactory::Make()
557 {
558 CustomTransform *ct = new CustomTransform(this->GetTypename(), createFuncPtr);
559 ct->Create();
560 return ct->get_ref();
561 }
562
563 #pragma mark MISC
564
565 const void *Block_copy_a(CFAllocatorRef allocator, const void *block) {
566 return Block_copy(block);
567 }
568
569 void Block_release_a(CFAllocatorRef allocator, const void *block) {
570 Block_release(block);
571 }
572
573 extern "C" {
574 SecTransformAttributeActionBlock SecTransformCreateValidatorForCFtype(CFTypeID expected_type, Boolean null_allowed) {
575 SecTransformAttributeActionBlock validate = NULL;
576 CFErrorRef (^make_error_message)(SecTransformAttributeRef attr, CFTypeRef value, CFTypeID expected_type, Boolean null_allowed) =
577 ^(SecTransformAttributeRef attr, CFTypeRef value, CFTypeID expected_type, Boolean null_allowed) {
578 CFStringRef expected_type_name = CFCopyTypeIDDescription(expected_type);
579 CFErrorRef error = NULL;
580 if (value) {
581 CFStringRef value_type_name = CFCopyTypeIDDescription(CFGetTypeID(value));
582 error = CreateSecTransformErrorRef(kSecTransformErrorInvalidType, "%@ received value of type %@ (%@), expected%@ a %@%@",
583 attr, value_type_name, value,
584 null_allowed ? CFSTR(" either") : CFSTR(""),
585 expected_type_name,
586 null_allowed ? CFSTR(" or a NULL") : CFSTR(""));
587 CFRelease(value_type_name);
588 } else {
589 error = CreateSecTransformErrorRef(kSecTransformErrorInvalidType, "%@ received NULL value, expected a %@",
590 attr, expected_type_name);
591 }
592 CFRelease(expected_type_name);
593
594 return error;
595 };
596
597
598 if (null_allowed) {
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 } else {
606 validate = ^(SecTransformAttributeRef attr, CFTypeRef value) {
607 if (value != NULL && CFGetTypeID(value) == expected_type) {
608 return (CFTypeRef)NULL;
609 }
610 return (CFTypeRef)make_error_message(attr, value, expected_type, null_allowed);
611 };
612 }
613
614 return Block_copy(validate);
615 }
616 }
617
618 Boolean SecTransformRegister(CFStringRef uniqueName, SecTransformCreateFP createFP, CFErrorRef *caller_error)
619 {
620 CFErrorRef error = NULL;
621
622 CustomTransformFactory *tf = new CustomTransformFactory(uniqueName, createFP, &error);
623 if (error)
624 {
625 delete tf;
626 if (caller_error)
627 {
628 *caller_error = error;
629 }
630 return FALSE;
631 }
632 else
633 {
634 return TRUE;
635 }
636 }
637
638 SecTransformRef SecTransformCreate(CFStringRef name, CFErrorRef *error)
639 {
640 SecTransformRef tr = TransformFactory::MakeTransformWithType(name, error);
641 return tr;
642 }
643
644 extern "C" {
645 Boolean SecExternalSourceSetValue(SecTransformRef xst, CFTypeRef value, CFErrorRef *error)
646 {
647 CustomTransform *ct = (CustomTransform *)CoreFoundationHolder::ObjectFromCFType(xst);
648 extern CFStringRef external_source_name;
649 if (CFEqual(ct->mTypeName, external_source_name)) {
650 ct->SetAttribute(ct->input_ah, value);
651 return true;
652 } else {
653 if (error) {
654 *error = CreateSecTransformErrorRef(kSecTransformErrorInvalidType, "SecExternalSourceSetValue called for %@, you need to pass in an ExternalSource transform not a %@", ct->GetName(), ct->mTypeName);
655 }
656 return false;
657 }
658 }
659 }
660
661 /* ==========================================================================
662 class: NoDataClass
663 description: A Special CFType that signifies that no data is being
664 returned
665 ==========================================================================*/
666 #pragma mark NoDataClass
667
668 class NoDataClass : public CoreFoundationObject
669 {
670 protected:
671 NoDataClass();
672
673 public:
674 virtual ~NoDataClass();
675 std::string FormattingDescription(CFDictionaryRef options);
676 std::string DebugDescription();
677 static CFTypeRef Make();
678 };
679
680 CFTypeRef NoDataClass::Make() {
681 NoDataClass* obj = new NoDataClass();
682 return CoreFoundationHolder::MakeHolder(gInternalProtectedCFObjectName, obj);
683 }
684
685
686 NoDataClass::NoDataClass() : CoreFoundationObject(gInternalProtectedCFObjectName) {
687 }
688
689 NoDataClass::~NoDataClass()
690 {
691 }
692
693 std::string NoDataClass::DebugDescription()
694 {
695 return CoreFoundationObject::DebugDescription() + " | SecTransformNoData";
696 }
697
698 std::string NoDataClass::FormattingDescription(CFDictionaryRef options)
699 {
700 return CoreFoundationObject::FormattingDescription(options) + " | SecTransformNoData";
701 }
702
703 CFTypeRef SecTransformNoData()
704 {
705 static dispatch_once_t inited;
706 static CFTypeRef no_data;
707
708 dispatch_once(&inited,
709 ^{
710 no_data = NoDataClass::Make();
711 });
712
713 return no_data;
714 }
715
716 /* ==========================================================================
717 class Implementation CustomTransform
718 ==========================================================================*/
719
720 #pragma mark CustomTransform
721
722 void CustomTransform::AttributeChanged(CFStringRef name, CFTypeRef value) {
723 #ifndef NDEBUG
724 // 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
725 abort();
726 #else
727 // We really shouldn't get here, but this is a production build and recovery is easy to code (but costly to execute)
728 AttributeChanged(getAH(name, false), value);
729 #endif
730 }
731
732 void CustomTransform::AttributeChanged(SecTransformAttributeRef ah, CFTypeRef value)
733 {
734 transform_attribute *ta = ah2ta(ah);
735 SecTransformAttributeActionBlock attribute_set_notification = NULL;
736
737 SecTransformAttributeActionBlock attribute_validate = NULL;
738
739 attribute_validate = (SecTransformAttributeActionBlock)ta->attribute_validate_block;
740 if (!attribute_validate) {
741 attribute_validate = generic_attribute_validation;
742 }
743 CFTypeRef vr = attribute_validate(ah, value);
744 if (vr) {
745 if (CFGetTypeID(vr) == CFErrorGetTypeID()) {
746 SendAttribute(AbortAH, vr);
747 CFRelease(vr);
748 } else {
749 CFErrorRef e = CreateSecTransformErrorRef(kSecTransformErrorInvalidType, "Invalid return type from a validate action, expected a CFErrorRef got a %@ (%@)", CFCopyTypeIDDescription(CFGetTypeID(vr)), vr);
750 SendAttribute(AbortAH, e);
751 CFRelease(vr);
752 // XXX: this causes a core dump -- I think AbortAH doesn't take it's own reference!! CFRelease(e);
753 }
754 return;
755 }
756
757 attribute_set_notification = (SecTransformAttributeActionBlock)ta->attribute_changed_block;
758
759 if ((!attribute_set_notification) && ah == input_ah)
760 {
761 CFTypeID vtype = value ? CFGetTypeID(value) : CFDataGetTypeID();
762 if (vtype == CFDataGetTypeID())
763 {
764 CFTypeRef output = process_data(value);
765 if (output == NULL || output != SecTransformNoData())
766 {
767 SendAttribute(output_ah, output);
768
769 // if output == value, we are being asked to just
770 // forward the existing value. No need to release.
771 // If they are different, we are being asked to
772 // send a new value which must be released.
773
774 if (output != value && output != NULL)
775 {
776 CFRelease(output);
777 }
778 }
779 }
780 else if (vtype == CFErrorGetTypeID() && !ah2ta(ah)->direct_error_handling)
781 {
782 SendAttribute(output_ah, value);
783 } else
784 {
785 attribute_set_notification = attribute_set_notification ? attribute_set_notification : generic_attribute_set_notification;
786 CFTypeRef new_value = attribute_set_notification(ah, value);
787 if (new_value != value)
788 {
789 SendAttribute(ah, new_value);
790 }
791 }
792 }
793 else
794 {
795 CFTypeID vtype = value ? CFGetTypeID(value) : CFDataGetTypeID();
796 if (vtype != CFErrorGetTypeID() || ah2ta(ah)->direct_error_handling)
797 {
798 attribute_set_notification = attribute_set_notification ? attribute_set_notification : generic_attribute_set_notification;
799 CFTypeRef new_value = attribute_set_notification(ah, value);
800 if (new_value != value)
801 {
802 SendAttribute(ah, new_value);
803 }
804 }
805 else
806 {
807 SendAttribute(output_ah, value);
808 }
809 }
810 }
811
812 CFTypeRef CustomTransform::rebind_data_action(CFStringRef action,
813 SecTransformDataBlock new_action)
814 {
815 CFTypeRef result = NULL;
816 if (kCFCompareEqualTo == CFStringCompare(kSecTransformActionProcessData, action, 0))
817 {
818 SetProcessData(new_action);
819 }
820 else if (kCFCompareEqualTo == CFStringCompare(kSecTransformActionInternalizeExtraData, action, 0))
821 {
822 SetInternalizeExtraData(new_action);
823 }
824 else
825 {
826 result = (CFTypeRef)CreateSecTransformErrorRef(kSecTransformInvalidOverride, "Unkown override type");
827
828 // XXX: can we get a stackdump here too?
829 CFStringRef msg = CFStringCreateWithFormat(NULL, NULL,
830 CFSTR("rebind_data_action (action %@, new_action %p, transform %s)"),
831 action, (void*)new_action, DebugDescription().c_str());
832 char *utf8_message = utf8(msg);
833 syslog(LOG_ERR, "%s", utf8_message);
834 free(utf8_message);
835 CFRelease(msg);
836 }
837 return result;
838 }
839
840 CFTypeRef CustomTransform::rebind_transform_action(CFStringRef action, SecTransformActionBlock new_action)
841 {
842 CFErrorRef result = NULL;
843
844 if (kCFCompareEqualTo == CFStringCompare(action, kSecTransformActionCanExecute, 0))
845 {
846 SetCanExecute(new_action);
847 }
848 else if (kCFCompareEqualTo == CFStringCompare(action, kSecTransformActionStartingExecution, 0))
849 {
850 SetExecuteStarting(new_action);
851 }
852 else if (kCFCompareEqualTo == CFStringCompare(action, kSecTransformActionFinalize, 0))
853 {
854 SetFinalize(new_action);
855 }
856 else if (kCFCompareEqualTo == CFStringCompare(action, kSecTransformActionExternalizeExtraData, 0))
857 {
858 SetExternalizeExtraData(new_action);
859 }
860 else
861 {
862 result = CreateSecTransformErrorRef(kSecTransformInvalidOverride, "Unkown override type");
863
864 char *action_utf8 = utf8(action);
865 syslog(LOG_ERR, "rebind_transform_action (action %s, all-attributes, block %p, transform %s)\n", action_utf8, (void*)new_action, DebugDescription().c_str());
866 free(action_utf8);
867 }
868
869 return result;
870 }
871
872 CFTypeRef CustomTransform::rebind_attribute_action(
873 CFStringRef action,
874 SecTransformStringOrAttributeRef attribute,
875 SecTransformAttributeActionBlock new_action)
876 {
877 CFErrorRef result = NULL;
878
879 if (kCFCompareEqualTo == CFStringCompare(action, kSecTransformActionAttributeNotification, 0))
880 {
881 SetNotficationBlock(attribute, new_action);
882 }
883 else if (kCFCompareEqualTo == CFStringCompare(action, kSecTransformActionAttributeValidation, 0))
884 {
885 SetVerifyBlock(attribute, new_action);
886 }
887 else
888 {
889 result = CreateSecTransformErrorRef(kSecTransformInvalidOverride, "Unkown override type");
890 char *action_utf8 = utf8(action);
891 syslog(LOG_ERR, "rebind_attribute_action (action %s, all-attributes, block %p, transform %s)\n", action_utf8, (void*)new_action, DebugDescription().c_str());
892 free(action_utf8);
893 }
894
895 return result;
896 }
897
898 CustomTransform::CustomTransform(CFStringRef cfname, SecTransformCreateFP createFP) :
899 Transform(cfname),
900 createFuncPtr(createFP),
901 instanceBlock(NULL),
902 can_run(Block_copy(default_can_run)),
903 execute_starting(Block_copy(default_execute_starting)),
904 finalize(Block_copy(default_finalize)),
905 generic_attribute_set_notification(Block_copy(default_generic_attribute_set_notification)),
906 generic_attribute_validation(Block_copy(default_generic_attribute_validation)),
907 process_data(Block_copy(default_process_data)),
908 externalize_data(Block_copy(default_externalize_data)),
909 internalize_data(Block_copy(default_internalize_data))
910 {
911 mAlwaysSelfNotify = true;
912
913 input_ah = getAH(kSecTransformInputAttributeName, true);
914 output_ah = getAH(kSecTransformOutputAttributeName, true);
915
916 parameters.version = kSecTransformCreateBlockParametersVersion;
917 parameters.send = Block_copy(^(SecTransformStringOrAttributeRef attribute, SecTransformMetaAttributeType type, CFTypeRef value)
918 {
919 return SendMetaAttribute(attribute, type, value);
920 });
921
922 parameters.pushback = Block_copy(^(SecTransformStringOrAttributeRef attribute, CFTypeRef value)
923 {
924 return Pushback(getAH(attribute), value);
925 });
926
927 parameters.get = Block_copy(^(SecTransformStringOrAttributeRef attribute, SecTransformMetaAttributeType type)
928 {
929 return GetMetaAttribute(attribute, type);
930 });
931
932 parameters.overrideTransform = Block_copy(^(CFStringRef action, SecTransformActionBlock new_action)
933 {
934 return rebind_transform_action(action, new_action);
935 });
936
937 parameters.overrideData = Block_copy(^(CFStringRef action,
938 SecTransformDataBlock new_action)
939 {
940 return rebind_data_action(action, new_action);
941 });
942
943 /*
944 CFTypeRef (^SecTransformOverrideAttributeAction)(
945 CFStringRef action,
946 SecTransformStringOrAttributeRef attribute,
947 SecTransformAttributeActionBlock newAction);
948 */
949 parameters.overrideAttribute =
950 Block_copy(^(CFStringRef action, SecTransformStringOrAttributeRef attribute, SecTransformAttributeActionBlock new_action)
951 {
952 return rebind_attribute_action(action, attribute, new_action);
953 });
954
955 char *tname = const_cast<char*>(CFStringGetCStringPtr(cfname, kCFStringEncodingUTF8));
956 if (!tname) {
957 CFIndex sz = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfname), kCFStringEncodingUTF8);
958 tname = static_cast<typeof(tname)>(alloca(sz));
959 CFStringGetCString(cfname, tname, sz, kCFStringEncodingUTF8);
960 }
961 tr = CoreFoundationHolder::MakeHolder(kSecCustom, (CoreFoundationObject*)this);
962
963 instanceBlock = (*createFuncPtr)(cfname, tr, &parameters);
964 }
965
966 void CustomTransform::Create()
967 {
968 (void)instanceBlock();
969 }
970
971
972 CustomTransform::~CustomTransform() {
973 finalize();
974
975 if (instanceBlock)
976 {
977 Block_release(instanceBlock);
978 }
979
980 Block_release(can_run);
981 Block_release(execute_starting);
982 Block_release(finalize);
983 Block_release(generic_attribute_set_notification);
984 Block_release(process_data);
985 Block_release(externalize_data);
986 Block_release(internalize_data);
987
988 Block_release(parameters.send);
989 Block_release(parameters.pushback);
990 Block_release(parameters.get);
991 Block_release(parameters.overrideTransform);
992 Block_release(parameters.overrideData);
993 Block_release(parameters.overrideAttribute);
994
995 // strictly speaking this isn't needed, but it can help track down some "use after free" bugs
996 tr = NULL;
997 createFuncPtr = NULL;
998 process_data = NULL;
999 }
1000
1001 CFErrorRef CustomTransform::TransformStartingExecution()
1002 {
1003 CFTypeRef result = execute_starting();
1004 return (CFErrorRef)result;
1005 }
1006
1007
1008 CFDictionaryRef CustomTransform::GetCustomExternalData()
1009 {
1010 CFTypeRef result = externalize_data();
1011 if (NULL == result)
1012 {
1013 return NULL;
1014 }
1015
1016 if (CFGetTypeID(result) == CFErrorGetTypeID())
1017 {
1018 // Ouch! we should deal with this
1019 CFRelease(result);
1020 return NULL;
1021 }
1022
1023 if (CFGetTypeID(result) == CFDictionaryGetTypeID())
1024 {
1025 return (CFDictionaryRef)result;
1026 }
1027
1028 CFRelease(result);
1029 result = NULL;
1030 return (CFDictionaryRef)result;
1031 }
1032
1033
1034 void CustomTransform::SetCustomExternalData(CFDictionaryRef customData)
1035 {
1036 if (NULL != customData)
1037 {
1038 internalize_data(customData);
1039 }
1040 return;
1041 }
1042
1043 CFErrorRef SecTransformSetAttributeAction(SecTransformImplementationRef ref,
1044 CFStringRef action,
1045 SecTransformStringOrAttributeRef attribute,
1046 SecTransformAttributeActionBlock newAction)
1047 {
1048 if (NULL == ref)
1049 {
1050 CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput,
1051 "SecTransformSetAttributeNotificationAction called with a NULL SecTransformImplementationRef ref");
1052
1053 return result;
1054 }
1055
1056 return (CFErrorRef)ref->overrideAttribute(action, attribute, newAction);
1057 }
1058
1059 CFErrorRef SecTransformSetDataAction(SecTransformImplementationRef ref,
1060 CFStringRef action,
1061 SecTransformDataBlock newAction)
1062 {
1063 if (NULL == ref)
1064 {
1065 CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput,
1066 "SecTransformSetAttributeNotificationAction called with a NULL SecTransformImplementationRef ref");
1067
1068 return result;
1069 }
1070
1071 return (CFErrorRef)ref->overrideData(action, newAction);
1072 }
1073
1074 CFErrorRef SecTransformSetTransformAction(SecTransformImplementationRef ref,
1075 CFStringRef action,
1076 SecTransformActionBlock newAction)
1077 {
1078 if (NULL == ref)
1079 {
1080 CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput,
1081 "SecTransformSetAttributeNotificationAction called with a NULL SecTransformImplementationRef ref");
1082
1083 return result;
1084 }
1085
1086 return (CFErrorRef)ref->overrideTransform(action, newAction);
1087 }
1088
1089 CFTypeRef SecTranformCustomGetAttribute(SecTransformImplementationRef ref,
1090 SecTransformStringOrAttributeRef attribute,
1091 SecTransformMetaAttributeType type)
1092 {
1093 if (NULL == ref)
1094 {
1095 CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput,
1096 "SecTransformCustomGetAttribute called with a NULL SecTransformImplementationRef ref");
1097
1098 return result;
1099 }
1100
1101 return (CFErrorRef)ref->get(attribute, type);
1102 }
1103
1104 CFTypeRef SecTransformCustomSetAttribute(SecTransformImplementationRef ref,
1105 SecTransformStringOrAttributeRef attribute,
1106 SecTransformMetaAttributeType type,
1107 CFTypeRef value)
1108 {
1109 if (NULL == ref)
1110 {
1111 CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput,
1112 "SecTransformCustomSetAttribute called with a NULL SecTransformImplementationRef ref");
1113
1114 return result;
1115 }
1116
1117 return (CFErrorRef)ref->send(attribute, type, value);
1118
1119 }
1120
1121 CFTypeRef SecTransformPushbackAttribute(SecTransformImplementationRef ref,
1122 SecTransformStringOrAttributeRef attribute,
1123 CFTypeRef value)
1124 {
1125 if (NULL == ref)
1126 {
1127 CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput,
1128 "SecTransformPushbackAttribute called with a NULL SecTransformImplementationRef ref");
1129
1130 return (CFTypeRef)result;
1131 }
1132
1133 return ref->pushback(attribute, value);
1134 }