this repo has no description
at fixPythonPipStalling 1038 lines 25 kB view raw
1/* 2 * Copyright (c) 2006, 2007, 2010, 2014, 2016-2018 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 * Modification History 26 * 27 * May 24, 2006 Allan Nathanson (ajn@apple.com) 28 * - adapted (for SystemConfiguration) 29 * 30 * May 10, 2006 Dieter Siegmund (dieter@apple.com) 31 * - created (for EAP) 32 */ 33 34#include <os/availability.h> 35#include <TargetConditionals.h> 36#include <sys/param.h> 37#include <CoreFoundation/CoreFoundation.h> 38#include <CoreFoundation/CFBundlePriv.h> // for _CFBundleCopyMainBundleExecutableURL 39#include "dy_framework.h" 40 41#include "SCPreferencesInternal.h" 42 43 44#if !TARGET_OS_IPHONE 45static CFDataRef 46copyMyExecutablePath(void) 47{ 48 char fspath[MAXPATHLEN]; 49 Boolean isBundle = FALSE; 50 Boolean ok; 51 CFDataRef path = NULL; 52 CFURLRef url; 53 54 url = _CFBundleCopyMainBundleExecutableURL(&isBundle); 55 if (url == NULL) { 56 return NULL; 57 } 58 59 ok = CFURLGetFileSystemRepresentation(url, TRUE, (UInt8 *)fspath, sizeof(fspath)); 60 CFRelease(url); 61 if (!ok) { 62 return NULL; 63 } 64 fspath[sizeof(fspath) - 1] = '\0'; 65 66 if (isBundle) { 67 const char *slash; 68 69 slash = strrchr(fspath, '/'); 70 if (slash != NULL) { 71 const char *contents; 72 73 contents = strstr(fspath, "/Contents/MacOS/"); 74 if ((contents != NULL) && 75 ((contents + sizeof("/Contents/MacOS/") - 1) == slash)) { 76 path = CFDataCreate(NULL, (UInt8 *)fspath, contents - fspath); 77 goto done; 78 } 79 } 80 } 81 82 path = CFDataCreate(NULL, (UInt8 *)fspath, strlen(fspath)); 83 84 done : 85 86 return path; 87} 88 89 90#pragma mark - 91#pragma mark Keychain helper APIs 92 93 94#if (__MAC_OS_X_VERSION_MIN_REQUIRED < 1070) 95/* 96 * Create a SecAccessRef with a custom form. 97 * 98 * Both the owner and the ACL set allow free access to root, 99 * but nothing to anyone else. 100 * 101 * NOTE: This is not the easiest way to build up CSSM data structures 102 * but it is a way that does not depend on any outside software 103 * layers (other than CSSM and Security's Sec* layer, of course). 104 */ 105static SecAccessRef 106_SCSecAccessCreateForUID(uid_t uid) 107{ 108 SecAccessRef access = NULL; 109 OSStatus status; 110 111 // make the "uid/gid" ACL subject 112 // this is a CSSM_LIST_ELEMENT chain 113 114 CSSM_ACL_PROCESS_SUBJECT_SELECTOR selector = { 115 CSSM_ACL_PROCESS_SELECTOR_CURRENT_VERSION, // version 116 CSSM_ACL_MATCH_UID, // active fields mask: match uids (only) 117 uid, // effective user id to match 118 0 // effective group id to match 119 }; 120 121 CSSM_LIST_ELEMENT subject2 = { 122 NULL, // NextElement 123 0 // WordID 124 // rest is defaulted 125 }; 126 127 subject2.Element.Word.Data = (UInt8 *)&selector; 128 subject2.Element.Word.Length = sizeof(selector); 129 130 CSSM_LIST_ELEMENT subject1 = { 131 &subject2, // NextElement 132 CSSM_ACL_SUBJECT_TYPE_PROCESS, // WordID 133 CSSM_LIST_ELEMENT_WORDID // ElementType 134 // rest is defaulted 135 }; 136 137 // rights granted (replace with individual list if desired) 138 CSSM_ACL_AUTHORIZATION_TAG rights[] = { 139 CSSM_ACL_AUTHORIZATION_ANY // everything 140 }; 141 142 // owner component (right to change ACL) 143 CSSM_ACL_OWNER_PROTOTYPE owner = { 144 { // TypedSubject 145 CSSM_LIST_TYPE_UNKNOWN, // type of this list 146 &subject1, // head of the list 147 &subject2 // tail of the list 148 }, 149 FALSE // Delegate 150 }; 151 152 // ACL entries (any number, just one here) 153 CSSM_ACL_ENTRY_INFO acls[] = { 154 { 155 { // EntryPublicInfo 156 { // TypedSubject 157 CSSM_LIST_TYPE_UNKNOWN, // type of this list 158 &subject1, // head of the list 159 &subject2 // tail of the list 160 }, 161 FALSE, // Delegate 162 { // Authorization 163 sizeof(rights) / sizeof(rights[0]), // NumberOfAuthTags 164 rights // AuthTags 165 }, 166 { // TimeRange 167 }, 168 { // EntryTag 169 } 170 }, 171 0 // EntryHandle 172 } 173 }; 174 175 status = SecAccessCreateFromOwnerAndACL(&owner, 176 sizeof(acls) / sizeof(acls[0]), 177 acls, 178 &access); 179 if (status != noErr) { 180 _SCErrorSet(status); 181 } 182 183 return access; 184} 185#endif // (__MAC_OS_X_VERSION_MIN_REQUIRED < 1070) 186 187 188// one example would be to pass a URL for "/System/Library/CoreServices/SystemUIServer.app" 189static SecAccessRef 190_SCSecAccessCreateForExecutables(CFStringRef label, 191 CFArrayRef executableURLs) 192{ 193 SecAccessRef access = NULL; 194 CFIndex i; 195 CFIndex n; 196 OSStatus status; 197 SecTrustedApplicationRef trustedApplication; 198 CFMutableArrayRef trustedApplications; 199 200 trustedApplications = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 201 202 // Use default access ("confirm access") 203 204 // Next, we make an exception list of applications you want to trust. 205 // These applications will be allowed to access the item without requiring 206 // user confirmation. 207 208 // Trust the calling application 209 status = SecTrustedApplicationCreateFromPath(NULL, &trustedApplication); 210 if (status == noErr) { 211 CFArrayAppendValue(trustedApplications, trustedApplication); 212 CFRelease(trustedApplication); 213 } 214 215 n = (executableURLs != NULL) ? CFArrayGetCount(executableURLs) : 0; 216 for (i = 0; i < n; i++) { 217 Boolean ok; 218 char path[MAXPATHLEN]; 219 CFURLRef url; 220 221 url = CFArrayGetValueAtIndex(executableURLs, i); 222 ok = CFURLGetFileSystemRepresentation(url, TRUE, (UInt8 *)path, sizeof(path)); 223 if (!ok) { 224 continue; 225 } 226 227 status = SecTrustedApplicationCreateFromPath(path, &trustedApplication); 228 if (status == noErr) { 229 CFArrayAppendValue(trustedApplications, trustedApplication); 230 CFRelease(trustedApplication); 231 } 232 } 233 234 status = SecAccessCreate(label, trustedApplications, &access); 235 if (status != noErr) { 236 goto done; 237 } 238 239 done : 240 241 CFRelease(trustedApplications); 242 243 return access; 244} 245#endif // !TARGET_OS_IPHONE 246 247 248SecKeychainRef 249_SCSecKeychainCopySystemKeychain(void) 250{ 251#if !TARGET_OS_IPHONE 252 SecKeychainRef keychain = NULL; 253 OSStatus status; 254 255 status = SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, &keychain); 256 if (status != noErr) { 257 _SCErrorSet(status); 258 if (keychain != NULL) CFRelease(keychain); 259 return NULL; 260 } 261 262 return keychain; 263#else // !TARGET_OS_IPHONE 264 _SCErrorSet(kSCStatusAccessError); 265 return NULL; 266#endif // !TARGET_OS_IPHONE 267} 268 269 270#if !TARGET_OS_IPHONE 271static OSStatus 272findKeychainItem(SecKeychainRef keychain, 273 CFStringRef unique_id, 274 SecKeychainItemRef *item) 275{ 276 CFMutableDictionaryRef query; 277 OSStatus status; 278 279 query = CFDictionaryCreateMutable(NULL, 280 0, 281 &kCFTypeDictionaryKeyCallBacks, 282 &kCFTypeDictionaryValueCallBacks); 283 if (keychain != NULL) { 284 CFArrayRef keychains; 285 286 keychains = CFArrayCreate(NULL, (const void **)&keychain, 1, &kCFTypeArrayCallBacks); 287 CFDictionarySetValue(query, kSecMatchSearchList, keychains); 288 CFRelease(keychains); 289 } 290 CFDictionarySetValue(query, kSecClass , kSecClassGenericPassword); 291 CFDictionarySetValue(query, kSecAttrService, unique_id); 292 CFDictionarySetValue(query, kSecReturnRef , kCFBooleanTrue); 293 status = SecItemCopyMatching(query, (CFTypeRef *)item); 294 CFRelease(query); 295 296 return status; 297} 298#endif // !TARGET_OS_IPHONE 299 300 301CFDataRef 302_SCSecKeychainPasswordItemCopy(SecKeychainRef keychain, 303 CFStringRef unique_id) 304{ 305#if !TARGET_OS_IPHONE 306 SecKeychainItemRef item = NULL; 307 CFDataRef keychain_password = NULL; 308 OSStatus status; 309 310 status = findKeychainItem(keychain, unique_id, &item); 311 if (status == noErr) { 312 void * pw = NULL; 313 UInt32 pw_len = 0; 314 315 status = SecKeychainItemCopyContent(item, NULL, NULL, &pw_len, &pw); 316 if (status == noErr) { 317 keychain_password = CFDataCreate(NULL, pw, pw_len); 318 status = SecKeychainItemFreeContent(NULL, pw); 319 } 320 } 321 if (item != NULL) CFRelease(item); 322 if (status != noErr) { 323 _SCErrorSet(status); 324 } 325 326 return keychain_password; 327#else // !TARGET_OS_IPHONE 328#pragma unused(keychain) 329#pragma unused(unique_id) 330 _SCErrorSet(kSCStatusAccessError); 331 return NULL; 332#endif // !TARGET_OS_IPHONE 333} 334 335 336Boolean 337_SCSecKeychainPasswordItemExists(SecKeychainRef keychain, CFStringRef unique_id) 338{ 339#if !TARGET_OS_IPHONE 340 SecKeychainItemRef item; 341 OSStatus status; 342 343 status = findKeychainItem(keychain, unique_id, &item); 344 if (status != noErr) { 345 _SCErrorSet(status); 346 return FALSE; 347 } 348 349 CFRelease(item); 350 return TRUE; 351#else // !TARGET_OS_IPHONE 352#pragma unused(keychain) 353#pragma unused(unique_id) 354 _SCErrorSet(kSCStatusAccessError); 355 return FALSE; 356#endif // !TARGET_OS_IPHONE 357} 358 359 360Boolean 361_SCSecKeychainPasswordItemRemove(SecKeychainRef keychain, CFStringRef unique_id) 362{ 363#if !TARGET_OS_IPHONE 364 SecKeychainItemRef item; 365 OSStatus status; 366 367 status = findKeychainItem(keychain, unique_id, &item); 368 if (status != noErr) { 369 _SCErrorSet(status); 370 return FALSE; 371 } 372 373 status = SecKeychainItemDelete(item); 374 CFRelease(item); 375 if (status != noErr) { 376 _SCErrorSet(status); 377 return FALSE; 378 } 379 380 return TRUE; 381#else // !TARGET_OS_IPHONE 382#pragma unused(keychain) 383#pragma unused(unique_id) 384 _SCErrorSet(kSCStatusAccessError); 385 return FALSE; 386#endif // !TARGET_OS_IPHONE 387} 388 389 390Boolean 391_SCSecKeychainPasswordItemSet(SecKeychainRef keychain, 392 CFStringRef unique_id, 393 CFStringRef label, 394 CFStringRef description, 395 CFStringRef account, 396 CFDataRef password, 397 CFDictionaryRef options) 398{ 399#if !TARGET_OS_IPHONE 400 SecAccessRef access = NULL; 401 CFBooleanRef allowRoot = NULL; 402 CFArrayRef allowedExecutables = NULL; 403 SecKeychainAttribute attributes[4]; 404 SecKeychainAttributeList attributeList = { 0, attributes }; 405 CFIndex i; 406 SecKeychainItemRef item = NULL; 407 CFIndex n = 0; 408 OSStatus status; 409 410 if (options != NULL) { 411 if (isA_CFDictionary(options)) { 412 allowRoot = CFDictionaryGetValue(options, kSCKeychainOptionsAllowRoot); 413 allowedExecutables = CFDictionaryGetValue(options, kSCKeychainOptionsAllowedExecutables); 414 } else { 415 _SCErrorSet(kSCStatusInvalidArgument); 416 return FALSE; 417 } 418 } 419 420 if (!isA_CFString(unique_id) || 421 ((label != NULL) && !isA_CFString (label )) || 422 ((description != NULL) && !isA_CFString (description )) || 423 ((account != NULL) && !isA_CFString (account )) || 424 ((password != NULL) && !isA_CFData (password )) || 425 ((allowRoot != NULL) && !isA_CFBoolean(allowRoot )) || 426 ((allowedExecutables != NULL) && !isA_CFArray (allowedExecutables)) || 427 ((allowRoot != NULL) && (allowedExecutables != NULL))) { 428 _SCErrorSet(kSCStatusInvalidArgument); 429 return FALSE; 430 } 431 432 if ((allowRoot != NULL) && CFBooleanGetValue(allowRoot)) { 433#if (__MAC_OS_X_VERSION_MIN_REQUIRED < 1070) 434 access = _SCSecAccessCreateForUID(0); 435 if (access == NULL) { 436 return FALSE; 437 } 438#else // (__MAC_OS_X_VERSION_MIN_REQUIRED < 1070) 439 CFErrorRef error = NULL; 440 441 access = SecAccessCreateWithOwnerAndACL(0, 0, kSecUseOnlyUID, NULL, &error); 442 if (access == NULL) { 443 CFIndex code = kSCStatusAccessError; 444 445 if (error != NULL) { 446 447 code = CFErrorGetCode(error); 448 CFRelease(error); 449 } 450 _SCErrorSet((int)code); 451 return FALSE; 452 } 453#endif // (__MAC_OS_X_VERSION_MIN_REQUIRED < 1070) 454 } else if (allowedExecutables != NULL) { 455 access = _SCSecAccessCreateForExecutables(label, allowedExecutables); 456 if (access == NULL) { 457 return FALSE; 458 } 459 } 460 461 for (i = 0; i < 4; i++) { 462 CFStringRef str = NULL; 463 SecKeychainAttrType tag = 0; 464 465 switch (i) { 466 case 0 : 467 str = unique_id; 468 tag = kSecServiceItemAttr; 469 break; 470 case 1 : 471 str = label; 472 tag = kSecLabelItemAttr; 473 break; 474 case 2 : 475 str = description; 476 tag = kSecDescriptionItemAttr; 477 break; 478 case 3 : 479 str = account; 480 tag = kSecAccountItemAttr; 481 break; 482 } 483 484 if (str == NULL) { 485 continue; 486 } 487 488 attributes[n].tag = tag; 489 attributes[n].data = _SC_cfstring_to_cstring(str, NULL, 0, kCFStringEncodingUTF8); 490 attributes[n].length = (UInt32)strlen(attributes[n].data); 491 n++; 492 } 493 494 status = findKeychainItem(keychain, unique_id, &item); 495 switch (status) { 496 case noErr : { 497 const void *pw = NULL; 498 UInt32 pw_len = 0; 499 500 // keychain item exists 501 if (password != NULL) { 502 pw = CFDataGetBytePtr(password); 503 pw_len = (UInt32)CFDataGetLength(password); 504 } 505 506 attributeList.count = (UInt32)n; 507 status = SecKeychainItemModifyContent(item, 508 &attributeList, 509 pw_len, 510 pw); 511 break; 512 } 513 514 case errSecItemNotFound : { 515 // no keychain item 516 if (password == NULL) { 517 // creating new keychain item and password not specified 518 status = kSCStatusInvalidArgument; 519 goto done; 520 } 521 522 attributeList.count = (UInt32)n; 523 status = SecKeychainItemCreateFromContent(kSecGenericPasswordItemClass, 524 &attributeList, 525 (UInt32)CFDataGetLength(password), 526 CFDataGetBytePtr(password), 527 keychain, 528 access, 529 NULL); 530 break; 531 } 532 533 // some other error 534 default : 535 break; 536 } 537 538 done : 539 540 if (access != NULL) CFRelease(access); 541 if (item != NULL) CFRelease(item); 542 543 for (i = 0; i < n; i++) { 544 CFAllocatorDeallocate(NULL, attributes[i].data); 545 } 546 547 if (status != noErr) { 548 _SCErrorSet(status); 549 return FALSE; 550 } 551 552 return TRUE; 553#else // !TARGET_OS_IPHONE 554#pragma unused(keychain) 555#pragma unused(unique_id) 556#pragma unused(label) 557#pragma unused(description) 558#pragma unused(account) 559#pragma unused(password) 560#pragma unused(options) 561 _SCErrorSet(kSCStatusAccessError); 562 return FALSE; 563#endif // !TARGET_OS_IPHONE 564} 565 566 567#pragma mark - 568#pragma mark "System" Keychain APIs (w/SCPreferences) 569 570 571#include "SCHelper_client.h" 572 573#include <fcntl.h> 574#include <unistd.h> 575#include <sys/errno.h> 576 577 578#if !TARGET_OS_IPHONE 579static CFDataRef 580__SCPreferencesSystemKeychainPasswordItemCopy_helper(SCPreferencesRef prefs, 581 CFStringRef unique_id) 582{ 583 CFDataRef data = NULL; 584 Boolean ok; 585 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs; 586 uint32_t status = kSCStatusOK; 587 CFDataRef reply = NULL; 588 589 if (prefsPrivate->helper_port == MACH_PORT_NULL) { 590 ok = __SCPreferencesCreate_helper(prefs); 591 if (!ok) { 592 return FALSE; 593 } 594 } 595 596 ok = _SCSerializeString(unique_id, &data, NULL, NULL); 597 if (!ok) { 598 goto fail; 599 } 600 601 // have the helper set the "System" Keychain password 602 ok = _SCHelperExec(prefsPrivate->helper_port, 603 SCHELPER_MSG_KEYCHAIN_COPY, 604 data, 605 &status, 606 &reply); 607 if (data != NULL) CFRelease(data); 608 if (!ok) { 609 goto fail; 610 } 611 612 if (status != kSCStatusOK) { 613 goto error; 614 } 615 616 return reply; 617 618 fail : 619 620 // close helper 621 if (prefsPrivate->helper_port != MACH_PORT_NULL) { 622 _SCHelperClose(&prefsPrivate->helper_port); 623 } 624 625 status = kSCStatusAccessError; 626 627 error : 628 629 // return error 630 if (reply != NULL) CFRelease(reply); 631 _SCErrorSet(status); 632 return NULL; 633} 634#endif // !TARGET_OS_IPHONE 635 636 637CFDataRef 638_SCPreferencesSystemKeychainPasswordItemCopy(SCPreferencesRef prefs, 639 CFStringRef unique_id) 640{ 641#if !TARGET_OS_IPHONE 642 SecKeychainRef keychain = NULL; 643 CFDataRef password = NULL; 644 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs; 645 646 if (prefs == NULL) { 647 /* sorry, you must provide a session */ 648 _SCErrorSet(kSCStatusNoPrefsSession); 649 return NULL; 650 } 651 652 if (!isA_CFString(unique_id)) { 653 _SCErrorSet(kSCStatusInvalidArgument); 654 return NULL; 655 } 656 657 if (prefsPrivate->authorizationData != NULL) { 658 password = __SCPreferencesSystemKeychainPasswordItemCopy_helper(prefs, unique_id); 659 goto done; 660 } 661 662 keychain = _SCSecKeychainCopySystemKeychain(); 663 if (keychain == NULL) { 664 goto done; 665 } 666 667 password = _SCSecKeychainPasswordItemCopy(keychain, unique_id); 668 669 done : 670 671 if (keychain != NULL) CFRelease(keychain); 672 return password; 673#else // !TARGET_OS_IPHONE 674#pragma unused(prefs) 675#pragma unused(unique_id) 676 _SCErrorSet(kSCStatusAccessError); 677 return NULL; 678#endif // !TARGET_OS_IPHONE 679} 680 681 682Boolean 683_SCPreferencesSystemKeychainPasswordItemExists(SCPreferencesRef prefs, 684 CFStringRef unique_id) 685{ 686#if !TARGET_OS_IPHONE 687 SecKeychainRef keychain = NULL; 688 Boolean ok = FALSE; 689// SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs; 690 691 if (prefs == NULL) { 692 /* sorry, you must provide a session */ 693 _SCErrorSet(kSCStatusNoPrefsSession); 694 return FALSE; 695 } 696 697 if (!isA_CFString(unique_id)) { 698 _SCErrorSet(kSCStatusInvalidArgument); 699 return FALSE; 700 } 701 702// if (prefsPrivate->authorizationData != NULL) { 703// ok = __SCPreferencesSystemKeychainPasswordItemExists_helper(prefs, unique_id); 704// goto done; 705// } 706 707 keychain = _SCSecKeychainCopySystemKeychain(); 708 if (keychain == NULL) { 709 goto done; 710 } 711 712 ok = _SCSecKeychainPasswordItemExists(keychain, unique_id); 713 714 done : 715 716 if (keychain != NULL) CFRelease(keychain); 717 return ok; 718#else // !TARGET_OS_IPHONE 719#pragma unused(prefs) 720#pragma unused(unique_id) 721 _SCErrorSet(kSCStatusAccessError); 722 return FALSE; 723#endif // !TARGET_OS_IPHONE 724} 725 726 727#if !TARGET_OS_IPHONE 728static Boolean 729__SCPreferencesSystemKeychainPasswordItemRemove_helper(SCPreferencesRef prefs, 730 CFStringRef unique_id) 731{ 732 CFDataRef data = NULL; 733 Boolean ok; 734 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs; 735 uint32_t status = kSCStatusOK; 736 CFDataRef reply = NULL; 737 738 if (prefsPrivate->helper_port == MACH_PORT_NULL) { 739 ok = __SCPreferencesCreate_helper(prefs); 740 if (!ok) { 741 return FALSE; 742 } 743 } 744 745 ok = _SCSerializeString(unique_id, &data, NULL, NULL); 746 if (!ok) { 747 goto fail; 748 } 749 750 // have the helper set the "System" Keychain password 751 ok = _SCHelperExec(prefsPrivate->helper_port, 752 SCHELPER_MSG_KEYCHAIN_REMOVE, 753 data, 754 &status, 755 &reply); 756 if (data != NULL) CFRelease(data); 757 if (!ok) { 758 goto fail; 759 } 760 761 if (status != kSCStatusOK) { 762 goto error; 763 } 764 765 return TRUE; 766 767 fail : 768 769 // close helper 770 if (prefsPrivate->helper_port != MACH_PORT_NULL) { 771 _SCHelperClose(&prefsPrivate->helper_port); 772 } 773 774 status = kSCStatusAccessError; 775 776 error : 777 778 // return error 779 if (reply != NULL) CFRelease(reply); 780 _SCErrorSet(status); 781 return FALSE; 782} 783#endif // !TARGET_OS_IPHONE 784 785 786Boolean 787_SCPreferencesSystemKeychainPasswordItemRemove(SCPreferencesRef prefs, 788 CFStringRef unique_id) 789{ 790#if !TARGET_OS_IPHONE 791 SecKeychainRef keychain = NULL; 792 Boolean ok = FALSE; 793 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs; 794 795 if (prefs == NULL) { 796 /* sorry, you must provide a session */ 797 _SCErrorSet(kSCStatusNoPrefsSession); 798 return FALSE; 799 } 800 801 if (!isA_CFString(unique_id)) { 802 _SCErrorSet(kSCStatusInvalidArgument); 803 return FALSE; 804 } 805 806 if (prefsPrivate->authorizationData != NULL) { 807 ok = __SCPreferencesSystemKeychainPasswordItemRemove_helper(prefs, unique_id); 808 goto done; 809 } 810 811 keychain = _SCSecKeychainCopySystemKeychain(); 812 if (keychain == NULL) { 813 goto done; 814 } 815 816 ok = _SCSecKeychainPasswordItemRemove(keychain, unique_id); 817 818 done : 819 820 if (keychain != NULL) CFRelease(keychain); 821 return ok; 822#else // !TARGET_OS_IPHONE 823#pragma unused(prefs) 824#pragma unused(unique_id) 825 _SCErrorSet(kSCStatusAccessError); 826 return FALSE; 827#endif // !TARGET_OS_IPHONE 828} 829 830 831#if !TARGET_OS_IPHONE 832static Boolean 833__SCPreferencesSystemKeychainPasswordItemSet_helper(SCPreferencesRef prefs, 834 CFStringRef unique_id, 835 CFStringRef label, 836 CFStringRef description, 837 CFStringRef account, 838 CFDataRef password, 839 CFDictionaryRef options) 840{ 841 CFDataRef data = NULL; 842 CFMutableDictionaryRef newOptions = NULL; 843 Boolean ok; 844 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs; 845 uint32_t status = kSCStatusOK; 846 CFDataRef reply = NULL; 847 848 if (prefsPrivate->helper_port == MACH_PORT_NULL) { 849 ok = __SCPreferencesCreate_helper(prefs); 850 if (!ok) { 851 return FALSE; 852 } 853 } 854 855 if (isA_CFDictionary(options)) { 856 CFArrayRef executableURLs = NULL; 857 858 newOptions = CFDictionaryCreateMutableCopy(NULL, 0, options); 859 860 if (CFDictionaryGetValueIfPresent(newOptions, 861 kSCKeychainOptionsAllowedExecutables, 862 (const void **)&executableURLs)) { 863 CFMutableArrayRef executablePaths; 864 CFIndex i; 865 CFIndex n; 866 CFDataRef path; 867 868 executablePaths = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 869 870 path = copyMyExecutablePath(); 871 if (path != NULL) { 872 CFArrayAppendValue(executablePaths, path); 873 CFRelease(path); 874 } 875 876 n = CFArrayGetCount(executableURLs); 877 for (i = 0; i < n; i++) { 878 char fspath[MAXPATHLEN]; 879 CFURLRef url; 880 881 url = CFArrayGetValueAtIndex(executableURLs, i); 882 ok = CFURLGetFileSystemRepresentation(url, TRUE, (UInt8 *)fspath, sizeof(fspath)); 883 if (!ok) { 884 continue; 885 } 886 fspath[sizeof(fspath) - 1] = '\0'; 887 path = CFDataCreate(NULL, (UInt8 *)fspath, strlen(fspath)); 888 CFArrayAppendValue(executablePaths, path); 889 CFRelease(path); 890 } 891 892 CFDictionarySetValue(newOptions, kSCKeychainOptionsAllowedExecutables, executablePaths); 893 CFRelease(executablePaths); 894 } 895 } else { 896 newOptions = CFDictionaryCreateMutable(NULL, 897 0, 898 &kCFTypeDictionaryKeyCallBacks, 899 &kCFTypeDictionaryValueCallBacks); 900 } 901 902 if (unique_id != NULL) CFDictionarySetValue(newOptions, kSCKeychainOptionsUniqueID , unique_id); 903 if (label != NULL) CFDictionarySetValue(newOptions, kSCKeychainOptionsLabel , label); 904 if (description != NULL) CFDictionarySetValue(newOptions, kSCKeychainOptionsDescription, description); 905 if (account != NULL) CFDictionarySetValue(newOptions, kSCKeychainOptionsAccount , account); 906 if (password != NULL) CFDictionarySetValue(newOptions, kSCKeychainOptionsPassword , password); 907 908 // 909 // if not AllowRoot and a list of executables was not provided than 910 // pass the current executable 911 // 912 if (!CFDictionaryContainsKey(newOptions, kSCKeychainOptionsAllowRoot) && 913 !CFDictionaryContainsKey(newOptions, kSCKeychainOptionsAllowedExecutables)) { 914 CFDataRef path; 915 916 path = copyMyExecutablePath(); 917 if (path != NULL) { 918 CFArrayRef executablePaths; 919 920 executablePaths = CFArrayCreate(NULL, (const void **)&path, 1, &kCFTypeArrayCallBacks); 921 CFRelease(path); 922 CFDictionarySetValue(newOptions, kSCKeychainOptionsAllowedExecutables, executablePaths); 923 CFRelease(executablePaths); 924 } 925 } 926 927 ok = _SCSerialize(newOptions, &data, NULL, NULL); 928 CFRelease(newOptions); 929 if (!ok) { 930 goto fail; 931 } 932 933 // have the helper create the "System" Keychain password 934 ok = _SCHelperExec(prefsPrivate->helper_port, 935 SCHELPER_MSG_KEYCHAIN_SET, 936 data, 937 &status, 938 &reply); 939 if (data != NULL) CFRelease(data); 940 if (!ok) { 941 goto fail; 942 } 943 944 if (status != kSCStatusOK) { 945 goto error; 946 } 947 948 return TRUE; 949 950 fail : 951 952 // close helper 953 if (prefsPrivate->helper_port != MACH_PORT_NULL) { 954 _SCHelperClose(&prefsPrivate->helper_port); 955 } 956 957 status = kSCStatusAccessError; 958 959 error : 960 961 // return error 962 if (reply != NULL) CFRelease(reply); 963 _SCErrorSet(status); 964 return FALSE; 965} 966#endif // !TARGET_OS_IPHONE 967 968 969Boolean 970_SCPreferencesSystemKeychainPasswordItemSet(SCPreferencesRef prefs, 971 CFStringRef unique_id, 972 CFStringRef label, 973 CFStringRef description, 974 CFStringRef account, 975 CFDataRef password, 976 CFDictionaryRef options) 977{ 978#if !TARGET_OS_IPHONE 979 SecKeychainRef keychain = NULL; 980 Boolean ok = FALSE; 981 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs; 982 983 if (prefs == NULL) { 984 /* sorry, you must provide a session */ 985 _SCErrorSet(kSCStatusNoPrefsSession); 986 return FALSE; 987 } 988 989 if (!isA_CFString(unique_id) || 990 ((label != NULL) && !isA_CFString (label )) || 991 ((description != NULL) && !isA_CFString (description)) || 992 ((account != NULL) && !isA_CFString (account )) || 993 ((password != NULL) && !isA_CFData (password )) || 994 ((options != NULL) && !isA_CFDictionary(options ))) { 995 _SCErrorSet(kSCStatusInvalidArgument); 996 return FALSE; 997 } 998 999 if (prefsPrivate->authorizationData != NULL) { 1000 ok = __SCPreferencesSystemKeychainPasswordItemSet_helper(prefs, 1001 unique_id, 1002 label, 1003 description, 1004 account, 1005 password, 1006 options); 1007 goto done; 1008 } 1009 1010 keychain = _SCSecKeychainCopySystemKeychain(); 1011 if (keychain == NULL) { 1012 goto done; 1013 } 1014 1015 ok = _SCSecKeychainPasswordItemSet(keychain, 1016 unique_id, 1017 label, 1018 description, 1019 account, 1020 password, 1021 options); 1022 1023 done : 1024 1025 if (keychain != NULL) CFRelease(keychain); 1026 return ok; 1027#else // !TARGET_OS_IPHONE 1028#pragma unused(prefs) 1029#pragma unused(unique_id) 1030#pragma unused(label) 1031#pragma unused(description) 1032#pragma unused(account) 1033#pragma unused(password) 1034#pragma unused(options) 1035 _SCErrorSet(kSCStatusAccessError); 1036 return FALSE; 1037#endif // !TARGET_OS_IPHONE 1038}