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