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