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