]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_transform/lib/SecCustomTransform.cpp
Security-58286.200.222.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 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 const SecTransformActionBlock default_can_run = ^{ return (CFTypeRef)NULL; };
307 static const SecTransformActionBlock default_execute_starting = default_can_run;
308 static const SecTransformActionBlock default_finalize = default_execute_starting;
309 static const SecTransformActionBlock default_externalize_data = default_finalize;
310
311 static const SecTransformDataBlock default_process_data = ^(CFTypeRef value) { return value; };
312 //static SecTransformDataBlock default_validate = ^(CFTypeRef value) { return (CFTypeRef)NULL; };
313 static const SecTransformAttributeActionBlock default_generic_attribute_set_notification =
314 ^(SecTransformAttributeRef ah, CFTypeRef value) { return value; };
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 // clang cannot possibly reason about the way in which we turn Transforms into CFRefs, and it just looks like a leak
571 #ifndef __clang_analyzer__
572 CFTypeRef CustomTransformFactory::Make() CF_RETURNS_RETAINED
573 {
574 CustomTransform *ct = new CustomTransform(this->GetTypename(), createFuncPtr);
575 ct->Create();
576 return ct->get_ref();
577 }
578 #endif
579
580 #pragma mark MISC
581
582 extern "C" {
583 SecTransformAttributeActionBlock SecTransformCreateValidatorForCFtype(CFTypeID expected_type, Boolean null_allowed) {
584 SecTransformAttributeActionBlock validate = NULL;
585 CFErrorRef (^make_error_message)(SecTransformAttributeRef attr, CFTypeRef value, CFTypeID expected_type, Boolean null_allowed) =
586 ^(SecTransformAttributeRef attr, CFTypeRef value, CFTypeID expected_type, Boolean null_allowed) {
587 CFStringRef expected_type_name = CFCopyTypeIDDescription(expected_type);
588 CFErrorRef error = NULL;
589 if (value) {
590 CFStringRef value_type_name = CFCopyTypeIDDescription(CFGetTypeID(value));
591 error = CreateSecTransformErrorRef(kSecTransformErrorInvalidType, "%@ received value of type %@ (%@), expected%@ a %@%@",
592 attr, value_type_name, value,
593 null_allowed ? CFSTR(" either") : CFSTR(""),
594 expected_type_name,
595 null_allowed ? CFSTR(" or a NULL") : CFSTR(""));
596 CFReleaseNull(value_type_name);
597 } else {
598 error = CreateSecTransformErrorRef(kSecTransformErrorInvalidType, "%@ received NULL value, expected a %@",
599 attr, expected_type_name);
600 }
601 CFReleaseNull(expected_type_name);
602
603 return error;
604 };
605
606
607 if (null_allowed) {
608 validate = ^(SecTransformAttributeRef attr, CFTypeRef value) {
609 if (value == NULL || CFGetTypeID(value) == expected_type) {
610 return (CFTypeRef)NULL;
611 }
612 return (CFTypeRef)make_error_message(attr, value, expected_type, null_allowed);
613 };
614 } else {
615 validate = ^(SecTransformAttributeRef attr, CFTypeRef value) {
616 if (value != NULL && CFGetTypeID(value) == expected_type) {
617 return (CFTypeRef)NULL;
618 }
619 return (CFTypeRef)make_error_message(attr, value, expected_type, null_allowed);
620 };
621 }
622
623 return Block_copy(validate);
624 }
625 }
626
627 // clang cannot reason about this business of creating an object for the side-effects of doing so
628 #ifndef __clang_analyzer__
629 Boolean SecTransformRegister(CFStringRef uniqueName, SecTransformCreateFP createFP, CFErrorRef *caller_error)
630 {
631 CFErrorRef error = NULL;
632
633 CustomTransformFactory *tf = new CustomTransformFactory(uniqueName, createFP, &error);
634 if (error)
635 {
636 delete tf;
637 if (caller_error)
638 {
639 *caller_error = error;
640 }
641 return FALSE;
642 }
643 else
644 {
645 return TRUE;
646 }
647 }
648 #endif
649
650 SecTransformRef SecTransformCreate(CFStringRef name, CFErrorRef *error)
651 {
652 SecTransformRef tr = TransformFactory::MakeTransformWithType(name, error);
653 return tr;
654 }
655
656 extern "C" {
657 Boolean SecExternalSourceSetValue(SecTransformRef xst, CFTypeRef value, CFErrorRef *error)
658 {
659 CustomTransform *ct = (CustomTransform *)CoreFoundationHolder::ObjectFromCFType(xst);
660 extern CFStringRef external_source_name;
661 if (CFEqual(ct->mTypeName, external_source_name)) {
662 ct->SetAttribute(ct->input_ah, value);
663 return true;
664 } else {
665 if (error) {
666 *error = CreateSecTransformErrorRef(kSecTransformErrorInvalidType, "SecExternalSourceSetValue called for %@, you need to pass in an ExternalSource transform not a %@", ct->GetName(), ct->mTypeName);
667 }
668 return false;
669 }
670 }
671 }
672
673 /* ==========================================================================
674 class: NoDataClass
675 description: A Special CFType that signifies that no data is being
676 returned
677 ==========================================================================*/
678 #pragma mark NoDataClass
679
680 class NoDataClass : public CoreFoundationObject
681 {
682 protected:
683 NoDataClass();
684
685 public:
686 virtual ~NoDataClass();
687 std::string FormattingDescription(CFDictionaryRef options);
688 std::string DebugDescription();
689 static CFTypeRef Make();
690 };
691
692 CFTypeRef NoDataClass::Make() {
693 NoDataClass* obj = new NoDataClass();
694 return CoreFoundationHolder::MakeHolder(gInternalProtectedCFObjectName, obj);
695 }
696
697
698 NoDataClass::NoDataClass() : CoreFoundationObject(gInternalProtectedCFObjectName) {
699 }
700
701 NoDataClass::~NoDataClass()
702 {
703 }
704
705 std::string NoDataClass::DebugDescription()
706 {
707 return CoreFoundationObject::DebugDescription() + " | SecTransformNoData";
708 }
709
710 std::string NoDataClass::FormattingDescription(CFDictionaryRef options)
711 {
712 return CoreFoundationObject::FormattingDescription(options) + " | SecTransformNoData";
713 }
714
715 CFTypeRef SecTransformNoData()
716 {
717 static dispatch_once_t inited;
718 static CFTypeRef no_data;
719
720 dispatch_once(&inited,
721 ^{
722 no_data = NoDataClass::Make();
723 });
724
725 return no_data;
726 }
727
728 /* ==========================================================================
729 class Implementation CustomTransform
730 ==========================================================================*/
731
732 #pragma mark CustomTransform
733
734 void CustomTransform::AttributeChanged(CFStringRef name, CFTypeRef value) {
735 #ifndef NDEBUG
736 // We really shouldn't get here, and this is the debug build so we can blow up on the spot so it is easy to look at the stack trace
737 abort();
738 #else
739 // We really shouldn't get here, but this is a production build and recovery is easy to code (but costly to execute)
740 AttributeChanged(getAH(name, false), value);
741 #endif
742 }
743
744 void CustomTransform::AttributeChanged(SecTransformAttributeRef ah, CFTypeRef value)
745 {
746 transform_attribute *ta = ah2ta(ah);
747 SecTransformAttributeActionBlock attribute_set_notification = NULL;
748
749 SecTransformAttributeActionBlock attribute_validate = NULL;
750
751 attribute_validate = (SecTransformAttributeActionBlock)ta->attribute_validate_block;
752 if (!attribute_validate) {
753 attribute_validate = generic_attribute_validation;
754 }
755 CFTypeRef vr = attribute_validate(ah, value);
756 if (vr) {
757 if (CFGetTypeID(vr) == CFErrorGetTypeID()) {
758 SendAttribute(AbortAH, vr);
759 CFReleaseNull(vr);
760 } else {
761 CFStringRef idDescription = CFCopyTypeIDDescription(CFGetTypeID(vr));
762 CFErrorRef e = CreateSecTransformErrorRef(kSecTransformErrorInvalidType, "Invalid return type from a validate action, expected a CFErrorRef got a %@ (%@)", idDescription, vr);
763 SendAttribute(AbortAH, e);
764 CFReleaseNull(vr);
765 CFReleaseNull(e);
766 CFReleaseNull(idDescription);
767 // XXX: this causes a core dump -- I think AbortAH doesn't take it's own reference!! CFReleaseNull(e);
768 }
769 return;
770 }
771
772 attribute_set_notification = (SecTransformAttributeActionBlock)ta->attribute_changed_block;
773
774 if ((!attribute_set_notification) && ah == input_ah)
775 {
776 CFTypeID vtype = value ? CFGetTypeID(value) : CFDataGetTypeID();
777 if (vtype == CFDataGetTypeID())
778 {
779 CFTypeRef output = process_data(value);
780 if (output == NULL || output != SecTransformNoData())
781 {
782 SendAttribute(output_ah, output);
783
784 // if output == value, we are being asked to just
785 // forward the existing value. No need to release.
786 // If they are different, we are being asked to
787 // send a new value which must be released.
788
789 if (output != value && output != NULL)
790 {
791 CFReleaseNull(output);
792 }
793 }
794 }
795 else if (vtype == CFErrorGetTypeID() && !ah2ta(ah)->direct_error_handling)
796 {
797 SendAttribute(output_ah, value);
798 } else
799 {
800 attribute_set_notification = attribute_set_notification ? attribute_set_notification : generic_attribute_set_notification;
801 CFTypeRef new_value = attribute_set_notification(ah, value);
802 if (new_value != value)
803 {
804 SendAttribute(ah, new_value);
805 }
806 }
807 }
808 else
809 {
810 CFTypeID vtype = value ? CFGetTypeID(value) : CFDataGetTypeID();
811 if (vtype != CFErrorGetTypeID() || ah2ta(ah)->direct_error_handling)
812 {
813 attribute_set_notification = attribute_set_notification ? attribute_set_notification : generic_attribute_set_notification;
814 CFTypeRef new_value = attribute_set_notification(ah, value);
815 if (new_value != value)
816 {
817 SendAttribute(ah, new_value);
818 }
819 }
820 else
821 {
822 SendAttribute(output_ah, value);
823 }
824 }
825 }
826
827 CFTypeRef CustomTransform::rebind_data_action(CFStringRef action,
828 SecTransformDataBlock new_action)
829 {
830 CFTypeRef result = NULL;
831 if (kCFCompareEqualTo == CFStringCompare(kSecTransformActionProcessData, action, 0))
832 {
833 SetProcessData(new_action);
834 }
835 else if (kCFCompareEqualTo == CFStringCompare(kSecTransformActionInternalizeExtraData, action, 0))
836 {
837 SetInternalizeExtraData(new_action);
838 }
839 else
840 {
841 result = (CFTypeRef)CreateSecTransformErrorRef(kSecTransformInvalidOverride, "Unkown override type");
842
843 // XXX: can we get a stackdump here too?
844 CFStringRef msg = CFStringCreateWithFormat(NULL, NULL,
845 CFSTR("rebind_data_action (action %@, new_action %p, transform %s)"),
846 action, (void*)new_action, DebugDescription().c_str());
847 char *utf8_message = utf8(msg);
848 syslog(LOG_ERR, "%s", utf8_message);
849 free(utf8_message);
850 CFReleaseNull(msg);
851 }
852 return result;
853 }
854
855 CFTypeRef CustomTransform::rebind_transform_action(CFStringRef action, SecTransformActionBlock new_action)
856 {
857 CFErrorRef result = NULL;
858
859 if (kCFCompareEqualTo == CFStringCompare(action, kSecTransformActionCanExecute, 0))
860 {
861 SetCanExecute(new_action);
862 }
863 else if (kCFCompareEqualTo == CFStringCompare(action, kSecTransformActionStartingExecution, 0))
864 {
865 SetExecuteStarting(new_action);
866 }
867 else if (kCFCompareEqualTo == CFStringCompare(action, kSecTransformActionFinalize, 0))
868 {
869 SetFinalize(new_action);
870 }
871 else if (kCFCompareEqualTo == CFStringCompare(action, kSecTransformActionExternalizeExtraData, 0))
872 {
873 SetExternalizeExtraData(new_action);
874 }
875 else
876 {
877 result = CreateSecTransformErrorRef(kSecTransformInvalidOverride, "Unkown override type");
878
879 char *action_utf8 = utf8(action);
880 syslog(LOG_ERR, "rebind_transform_action (action %s, all-attributes, block %p, transform %s)\n", action_utf8, (void*)new_action, DebugDescription().c_str());
881 free(action_utf8);
882 }
883
884 return result;
885 }
886
887 CFTypeRef CustomTransform::rebind_attribute_action(
888 CFStringRef action,
889 SecTransformStringOrAttributeRef attribute,
890 SecTransformAttributeActionBlock new_action)
891 {
892 CFErrorRef result = NULL;
893
894 if (kCFCompareEqualTo == CFStringCompare(action, kSecTransformActionAttributeNotification, 0))
895 {
896 SetNotficationBlock(attribute, new_action);
897 }
898 else if (kCFCompareEqualTo == CFStringCompare(action, kSecTransformActionAttributeValidation, 0))
899 {
900 SetVerifyBlock(attribute, new_action);
901 }
902 else
903 {
904 result = CreateSecTransformErrorRef(kSecTransformInvalidOverride, "Unkown override type");
905 char *action_utf8 = utf8(action);
906 syslog(LOG_ERR, "rebind_attribute_action (action %s, all-attributes, block %p, transform %s)\n", action_utf8, (void*)new_action, DebugDescription().c_str());
907 free(action_utf8);
908 }
909
910 return result;
911 }
912
913 CustomTransform::CustomTransform(CFStringRef cfname, SecTransformCreateFP createFP) :
914 Transform(cfname),
915 createFuncPtr(createFP),
916 instanceBlock(NULL),
917 can_run(Block_copy(default_can_run)),
918 execute_starting(Block_copy(default_execute_starting)),
919 finalize(Block_copy(default_finalize)),
920 generic_attribute_set_notification(Block_copy(default_generic_attribute_set_notification)),
921 generic_attribute_validation(Block_copy(default_generic_attribute_validation)),
922 process_data(Block_copy(default_process_data)),
923 externalize_data(Block_copy(default_externalize_data)),
924 internalize_data(Block_copy(default_internalize_data))
925 {
926 mAlwaysSelfNotify = true;
927
928 input_ah = getAH(kSecTransformInputAttributeName, true);
929 output_ah = getAH(kSecTransformOutputAttributeName, true);
930
931 parameters.version = kSecTransformCreateBlockParametersVersion;
932 parameters.send = Block_copy(^(SecTransformStringOrAttributeRef attribute, SecTransformMetaAttributeType type, CFTypeRef value)
933 {
934 return SendMetaAttribute(attribute, type, value);
935 });
936
937 parameters.pushback = Block_copy(^(SecTransformStringOrAttributeRef attribute, CFTypeRef value)
938 {
939 return Pushback(getAH(attribute), value);
940 });
941
942 parameters.get = Block_copy(^(SecTransformStringOrAttributeRef attribute, SecTransformMetaAttributeType type)
943 {
944 return GetMetaAttribute(attribute, type);
945 });
946
947 parameters.overrideTransform = Block_copy(^(CFStringRef action, SecTransformActionBlock new_action)
948 {
949 return rebind_transform_action(action, new_action);
950 });
951
952 parameters.overrideData = Block_copy(^(CFStringRef action,
953 SecTransformDataBlock new_action)
954 {
955 return rebind_data_action(action, new_action);
956 });
957
958 /*
959 CFTypeRef (^SecTransformOverrideAttributeAction)(
960 CFStringRef action,
961 SecTransformStringOrAttributeRef attribute,
962 SecTransformAttributeActionBlock newAction);
963 */
964 parameters.overrideAttribute =
965 Block_copy(^(CFStringRef action, SecTransformStringOrAttributeRef attribute, SecTransformAttributeActionBlock new_action)
966 {
967 return rebind_attribute_action(action, attribute, new_action);
968 });
969
970 char *tname = const_cast<char*>(CFStringGetCStringPtr(cfname, kCFStringEncodingUTF8));
971 if (!tname) {
972 CFIndex sz = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfname), kCFStringEncodingUTF8);
973 tname = static_cast<typeof(tname)>(alloca(sz));
974 CFStringGetCString(cfname, tname, sz, kCFStringEncodingUTF8);
975 }
976 tr = CoreFoundationHolder::MakeHolder(kSecCustom, (CoreFoundationObject*)this);
977
978 instanceBlock = (*createFuncPtr)(cfname, tr, &parameters);
979 }
980
981 void CustomTransform::Create()
982 {
983 (void)instanceBlock();
984 }
985
986
987 CustomTransform::~CustomTransform() {
988 finalize();
989
990 if (instanceBlock)
991 {
992 Block_release(instanceBlock);
993 }
994
995 Block_release(can_run);
996 Block_release(execute_starting);
997 Block_release(finalize);
998 Block_release(generic_attribute_set_notification);
999 Block_release(process_data);
1000 Block_release(externalize_data);
1001 Block_release(internalize_data);
1002
1003 Block_release(parameters.send);
1004 Block_release(parameters.pushback);
1005 Block_release(parameters.get);
1006 Block_release(parameters.overrideTransform);
1007 Block_release(parameters.overrideData);
1008 Block_release(parameters.overrideAttribute);
1009
1010 // strictly speaking this isn't needed, but it can help track down some "use after free" bugs
1011 tr = NULL;
1012 createFuncPtr = NULL;
1013 process_data = NULL;
1014 }
1015
1016 CFErrorRef CustomTransform::TransformStartingExecution()
1017 {
1018 CFTypeRef result = execute_starting();
1019 return (CFErrorRef)result;
1020 }
1021
1022
1023 CFDictionaryRef CustomTransform::GetCustomExternalData()
1024 {
1025 CFTypeRef result = externalize_data();
1026 if (NULL == result)
1027 {
1028 return NULL;
1029 }
1030
1031 if (CFGetTypeID(result) == CFErrorGetTypeID())
1032 {
1033 // Ouch! we should deal with this
1034 CFReleaseNull(result);
1035 return NULL;
1036 }
1037
1038 if (CFGetTypeID(result) == CFDictionaryGetTypeID())
1039 {
1040 return (CFDictionaryRef)result;
1041 }
1042
1043 CFReleaseNull(result);
1044 result = NULL;
1045 return (CFDictionaryRef)result;
1046 }
1047
1048
1049 void CustomTransform::SetCustomExternalData(CFDictionaryRef customData)
1050 {
1051 if (NULL != customData)
1052 {
1053 internalize_data(customData);
1054 }
1055 return;
1056 }
1057
1058 CFErrorRef SecTransformSetAttributeAction(SecTransformImplementationRef ref,
1059 CFStringRef action,
1060 SecTransformStringOrAttributeRef attribute,
1061 SecTransformAttributeActionBlock newAction)
1062 {
1063 if (NULL == ref)
1064 {
1065 CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput,
1066 "SecTransformSetAttributeNotificationAction called with a NULL SecTransformImplementationRef ref");
1067 CFAutorelease(result);
1068 return result;
1069 }
1070
1071 return (CFErrorRef)ref->overrideAttribute(action, attribute, newAction);
1072 }
1073
1074 CFErrorRef SecTransformSetDataAction(SecTransformImplementationRef ref,
1075 CFStringRef action,
1076 SecTransformDataBlock newAction)
1077 {
1078 if (NULL == ref)
1079 {
1080 CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput,
1081 "SecTransformSetAttributeNotificationAction called with a NULL SecTransformImplementationRef ref");
1082 CFAutorelease(result);
1083 return result;
1084 }
1085
1086 return (CFErrorRef)ref->overrideData(action, newAction);
1087 }
1088
1089 CFErrorRef SecTransformSetTransformAction(SecTransformImplementationRef ref,
1090 CFStringRef action,
1091 SecTransformActionBlock newAction)
1092 {
1093 if (NULL == ref)
1094 {
1095 CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput,
1096 "SecTransformSetAttributeNotificationAction called with a NULL SecTransformImplementationRef ref");
1097 CFAutorelease(result);
1098 return result;
1099 }
1100
1101 return (CFErrorRef)ref->overrideTransform(action, newAction);
1102 }
1103
1104 CFTypeRef SecTranformCustomGetAttribute(SecTransformImplementationRef ref,
1105 SecTransformStringOrAttributeRef attribute,
1106 SecTransformMetaAttributeType type)
1107 {
1108 if (NULL == ref)
1109 {
1110 CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput,
1111 "SecTransformCustomGetAttribute called with a NULL SecTransformImplementationRef ref");
1112 CFAutorelease(result);
1113 return result;
1114 }
1115
1116 return (CFErrorRef)ref->get(attribute, type);
1117 }
1118
1119 CFTypeRef SecTransformCustomSetAttribute(SecTransformImplementationRef ref,
1120 SecTransformStringOrAttributeRef attribute,
1121 SecTransformMetaAttributeType type,
1122 CFTypeRef value)
1123 {
1124 if (NULL == ref)
1125 {
1126 CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput,
1127 "SecTransformCustomSetAttribute called with a NULL SecTransformImplementationRef ref");
1128 CFAutorelease(result);
1129 return result;
1130 }
1131
1132 return (CFErrorRef)ref->send(attribute, type, value);
1133
1134 }
1135
1136 CFTypeRef SecTransformPushbackAttribute(SecTransformImplementationRef ref,
1137 SecTransformStringOrAttributeRef attribute,
1138 CFTypeRef value)
1139 {
1140 if (NULL == ref)
1141 {
1142 CFErrorRef result = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput,
1143 "SecTransformPushbackAttribute called with a NULL SecTransformImplementationRef ref");
1144 CFAutorelease(result);
1145 return (CFTypeRef)result;
1146 }
1147
1148 return ref->pushback(attribute, value);
1149 }