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, ¶meters); 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 }