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