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 35static const CFStringRef kSecCustom = CFSTR("CustomTransform"); 36const CFStringRef kSecTransformPreviousErrorKey = CFSTR("PreviousError"); 37const CFStringRef kSecTransformAbortOriginatorKey = CFSTR("Originating Transform"); 38const CFStringRef kSecTransformActionCanExecute = CFSTR("CanExecute"); 39const CFStringRef kSecCustomTransformWhatIsRequired = CFSTR("WhatIsRequired"); 40const CFStringRef kSecCustomTransformAttributesToExternalize = CFSTR("AttributesToExternalize"); 41const CFStringRef kSecTransformActionStartingExecution = CFSTR("ExecuteStarting"); 42const CFStringRef kSecTransformActionProcessData = CFSTR("TransformProcessData"); 43const CFStringRef kSecTransformActionAttributeNotification = CFSTR("GenericAttributeSetNotification"); 44const CFStringRef kSecTransformActionFinalize = CFSTR("Finalize"); 45const CFStringRef kSecTransformActionExternalizeExtraData = CFSTR("ExternalizeExtraData"); 46const CFStringRef kSecTransformActionInternalizeExtraData = CFSTR("InternalizeExtraData"); 47const 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*/ 73typedef 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*/ 100typedef 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*/ 146typedef 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*/ 170typedef 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*/ 195typedef 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*/ 234typedef 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*/ 244enum 245{ 246 kSecTransformCreateBlockParametersVersion = 1 247}; 248 249extern "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*/ 279struct 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 297class CustomTransformFactory : public TransformFactory 298{ 299protected: 300 SecTransformCreateFP createFuncPtr; 301public: 302 CustomTransformFactory(CFStringRef name, SecTransformCreateFP createFP, CFErrorRef *error); 303 virtual ~CustomTransformFactory() {}; 304 virtual CFTypeRef Make(); 305}; 306 307 308static SecTransformActionBlock default_can_run = ^{ return (CFTypeRef)NULL; }; 309static SecTransformActionBlock default_execute_starting = default_can_run; 310static SecTransformActionBlock default_finalize = default_execute_starting; 311static SecTransformActionBlock default_externalize_data = default_finalize; 312 313static SecTransformDataBlock default_process_data = ^(CFTypeRef value) { return value; }; 314//static SecTransformDataBlock default_validate = ^(CFTypeRef value) { return (CFTypeRef)NULL; }; 315static SecTransformAttributeActionBlock default_generic_attribute_set_notification = 316 ^(SecTransformAttributeRef ah, CFTypeRef value) { return value; }; 317 318static SecTransformAttributeActionBlock default_generic_attribute_validation = 319^(SecTransformAttributeRef ah, CFTypeRef value) 320{ 321 return (CFTypeRef)NULL; 322}; 323 324static SecTransformDataBlock default_internalize_data = 325 ^(CFTypeRef value) 326{ 327 return (CFTypeRef)NULL; 328}; 329 330class CustomTransform : public Transform 331{ 332protected: 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 499public: 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 529CustomTransformFactory::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 572CFTypeRef 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 581extern "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 626Boolean 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 646SecTransformRef SecTransformCreate(CFStringRef name, CFErrorRef *error) 647{ 648 SecTransformRef tr = TransformFactory::MakeTransformWithType(name, error); 649 return tr; 650} 651 652extern "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 676class NoDataClass : public CoreFoundationObject 677{ 678protected: 679 NoDataClass(); 680 681public: 682 virtual ~NoDataClass(); 683 std::string FormattingDescription(CFDictionaryRef options); 684 std::string DebugDescription(); 685 static CFTypeRef Make(); 686}; 687 688CFTypeRef NoDataClass::Make() { 689 NoDataClass* obj = new NoDataClass(); 690 return CoreFoundationHolder::MakeHolder(gInternalProtectedCFObjectName, obj); 691} 692 693 694NoDataClass::NoDataClass() : CoreFoundationObject(gInternalProtectedCFObjectName) { 695} 696 697NoDataClass::~NoDataClass() 698{ 699} 700 701std::string NoDataClass::DebugDescription() 702{ 703 return CoreFoundationObject::DebugDescription() + " | SecTransformNoData"; 704} 705 706std::string NoDataClass::FormattingDescription(CFDictionaryRef options) 707{ 708 return CoreFoundationObject::FormattingDescription(options) + " | SecTransformNoData"; 709} 710 711CFTypeRef 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 730void 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 740void 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 820CFTypeRef 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 848CFTypeRef 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 880CFTypeRef 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 906CustomTransform::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, ¶meters); 972} 973 974void CustomTransform::Create() 975{ 976 (void)instanceBlock(); 977} 978 979 980CustomTransform::~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 1009CFErrorRef CustomTransform::TransformStartingExecution() 1010{ 1011 CFTypeRef result = execute_starting(); 1012 return (CFErrorRef)result; 1013} 1014 1015 1016CFDictionaryRef 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 1042void CustomTransform::SetCustomExternalData(CFDictionaryRef customData) 1043{ 1044 if (NULL != customData) 1045 { 1046 internalize_data(customData); 1047 } 1048 return; 1049} 1050 1051CFErrorRef 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 1067CFErrorRef 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 1082CFErrorRef 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 1097CFTypeRef 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 1112CFTypeRef 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 1129CFTypeRef 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} 1143