1/* 2 * Copyright (c) 2000-2004,2011-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#include <Security/SecKeychain.h> 25#include <Security/SecKeychainPriv.h> 26#include <security_keychain/KCCursor.h> 27#include <security_cdsa_utilities/cssmdata.h> 28#include <security_cdsa_client/wrapkey.h> 29#include <security_keychain/KCExceptions.h> 30#include <securityd_client/ssblob.h> 31#include <Security/SecAccess.h> 32#include <Security/SecTrustedApplicationPriv.h> 33#include "SecBridge.h" 34#include "CCallbackMgr.h" 35#include <security_cdsa_utilities/Schema.h> 36#include <security_cdsa_client/mdsclient.h> 37#include <pwd.h> 38 39OSStatus 40SecKeychainMDSInstall() 41{ 42 BEGIN_SECAPI 43 44 Security::MDSClient::Directory d; 45 d.install(); 46 47 END_SECAPI 48} 49 50CFTypeID 51SecKeychainGetTypeID(void) 52{ 53 BEGIN_SECAPI 54 55 return gTypes().KeychainImpl.typeID; 56 57 END_SECAPI1(_kCFRuntimeNotATypeID) 58} 59 60 61OSStatus 62SecKeychainGetVersion(UInt32 *returnVers) 63{ 64 if (!returnVers) 65 return errSecSuccess; 66 67 *returnVers = 0x02028000; 68 return errSecSuccess; 69} 70 71 72OSStatus 73SecKeychainOpen(const char *pathName, SecKeychainRef *keychainRef) 74{ 75 BEGIN_SECAPI 76 77 RequiredParam(keychainRef)=globals().storageManager.make(pathName, false)->handle(); 78 79 END_SECAPI 80} 81 82 83OSStatus 84SecKeychainOpenWithGuid(const CSSM_GUID *guid, uint32 subserviceId, uint32 subserviceType, const char* dbName, 85 const CSSM_NET_ADDRESS *dbLocation, SecKeychainRef *keychain) 86{ 87 BEGIN_SECAPI 88 89 // range check parameters 90 RequiredParam (guid); 91 RequiredParam (dbName); 92 93 // create a DLDbIdentifier that describes what should be opened 94 const CSSM_VERSION *version = NULL; 95 const CssmSubserviceUid ssuid(*guid, version, subserviceId, subserviceType); 96 DLDbIdentifier dLDbIdentifier(ssuid, dbName, dbLocation); 97 98 // make a keychain from the supplied info 99 RequiredParam(keychain) = globals().storageManager.makeKeychain(dLDbIdentifier, false)->handle (); 100 101 END_SECAPI 102} 103 104 105OSStatus 106SecKeychainCreate(const char *pathName, UInt32 passwordLength, const void *password, 107 Boolean promptUser, SecAccessRef initialAccess, SecKeychainRef *keychainRef) 108{ 109 BEGIN_SECAPI 110 111 KCThrowParamErrIf_(!pathName); 112 Keychain keychain = globals().storageManager.make(pathName); 113 114 // @@@ the call to StorageManager::make above leaves keychain the the cache. 115 // If the create below fails we should probably remove it. 116 if(promptUser) 117 keychain->create(); 118 else 119 { 120 KCThrowParamErrIf_(!password); 121 keychain->create(passwordLength, password); 122 } 123 124 RequiredParam(keychainRef)=keychain->handle(); 125 126 END_SECAPI 127} 128 129 130OSStatus 131SecKeychainDelete(SecKeychainRef keychainOrArray) 132{ 133 BEGIN_SECAPI 134 135 KCThrowIf_(!keychainOrArray, errSecInvalidKeychain); 136 StorageManager::KeychainList keychains; 137 globals().storageManager.optionalSearchList(keychainOrArray, keychains); 138 139 globals().storageManager.remove(keychains, true); 140 141 END_SECAPI 142} 143 144 145OSStatus 146SecKeychainSetSettings(SecKeychainRef keychainRef, const SecKeychainSettings *newSettings) 147{ 148 BEGIN_SECAPI 149 150 Keychain keychain = Keychain::optional(keychainRef); 151 if (newSettings->version==SEC_KEYCHAIN_SETTINGS_VERS1) 152 { 153 UInt32 lockInterval=newSettings->lockInterval; 154 bool lockOnSleep=newSettings->lockOnSleep; 155 keychain->setSettings(lockInterval, lockOnSleep); 156 } 157 158 END_SECAPI 159} 160 161 162OSStatus 163SecKeychainCopySettings(SecKeychainRef keychainRef, SecKeychainSettings *outSettings) 164{ 165 BEGIN_SECAPI 166 167 Keychain keychain = Keychain::optional(keychainRef); 168 if (outSettings->version==SEC_KEYCHAIN_SETTINGS_VERS1) 169 { 170 uint32 lockInterval; 171 bool lockOnSleep; 172 173 keychain->getSettings(lockInterval, lockOnSleep); 174 outSettings->lockInterval=lockInterval; 175 outSettings->lockOnSleep=lockOnSleep; 176 } 177 178 END_SECAPI 179} 180 181 182OSStatus 183SecKeychainUnlock(SecKeychainRef keychainRef, UInt32 passwordLength, const void *password, Boolean usePassword) 184{ 185 BEGIN_SECAPI 186 187 Keychain keychain = Keychain::optional(keychainRef); 188 189 if (usePassword) 190 keychain->unlock(CssmData(const_cast<void *>(password), passwordLength)); 191 else 192 keychain->unlock(); 193 194 END_SECAPI 195} 196 197 198OSStatus 199SecKeychainLock(SecKeychainRef keychainRef) 200{ 201 BEGIN_SECAPI 202 203 Keychain keychain = Keychain::optional(keychainRef); 204 keychain->lock(); 205 206 END_SECAPI 207} 208 209 210OSStatus 211SecKeychainLockAll(void) 212{ 213 BEGIN_SECAPI 214 215 globals().storageManager.lockAll(); 216 217 END_SECAPI 218} 219 220 221OSStatus SecKeychainResetLogin(UInt32 passwordLength, const void* password, Boolean resetSearchList) 222{ 223 BEGIN_SECAPI 224 // 225 // Get the current user (using fallback method if necessary) 226 // 227 char* uName = getenv("USER"); 228 string userName = uName ? uName : ""; 229 if ( userName.length() == 0 ) 230 { 231 uid_t uid = geteuid(); 232 if (!uid) uid = getuid(); 233 struct passwd *pw = getpwuid(uid); // fallback case... 234 if (pw) 235 userName = pw->pw_name; 236 endpwent(); 237 } 238 if ( userName.length() == 0 ) // did we ultimately get one? 239 MacOSError::throwMe(errAuthorizationInternal); 240 241 SecurityServer::ClientSession().resetKeyStorePassphrase(password ? CssmData(const_cast<void *>(password), passwordLength) : CssmData()); 242 243 if (password) 244 { 245 // Clear the plist and move aside (rename) the existing login.keychain 246 globals().storageManager.resetKeychain(resetSearchList); 247 248 // Create the login keychain without UI 249 globals().storageManager.login((UInt32)userName.length(), userName.c_str(), passwordLength, password); 250 251 // Set it as the default 252 Keychain keychain = globals().storageManager.loginKeychain(); 253 globals().storageManager.defaultKeychain(keychain); 254 } 255 else 256 { 257 // Create the login keychain, prompting for password 258 // (implicitly calls resetKeychain, login, and defaultKeychain) 259 globals().storageManager.makeLoginAuthUI(NULL); 260 } 261 262 // Post a "list changed" event after a reset, so apps can refresh their list. 263 // Make sure we are not holding mLock when we post this event. 264 KCEventNotifier::PostKeychainEvent(kSecKeychainListChangedEvent); 265 266 END_SECAPI 267} 268 269OSStatus 270SecKeychainCopyDefault(SecKeychainRef *keychainRef) 271{ 272 BEGIN_SECAPI 273 274 RequiredParam(keychainRef)=globals().storageManager.defaultKeychain()->handle(); 275 276 END_SECAPI 277} 278 279 280OSStatus 281SecKeychainSetDefault(SecKeychainRef keychainRef) 282{ 283 BEGIN_SECAPI 284 285 globals().storageManager.defaultKeychain(Keychain::optional(keychainRef)); 286 287 END_SECAPI 288} 289 290OSStatus SecKeychainCopySearchList(CFArrayRef *searchList) 291{ 292 BEGIN_SECAPI 293 294 RequiredParam(searchList); 295 StorageManager &smr = globals().storageManager; 296 StorageManager::KeychainList keychainList; 297 smr.getSearchList(keychainList); 298 *searchList = smr.convertFromKeychainList(keychainList); 299 300 END_SECAPI 301} 302 303OSStatus SecKeychainSetSearchList(CFArrayRef searchList) 304{ 305 BEGIN_SECAPI 306 307 RequiredParam(searchList); 308 StorageManager &smr = globals().storageManager; 309 StorageManager::KeychainList keychainList; 310 smr.convertToKeychainList(searchList, keychainList); 311 smr.setSearchList(keychainList); 312 313 END_SECAPI 314} 315 316OSStatus SecKeychainCopyDomainDefault(SecPreferencesDomain domain, SecKeychainRef *keychainRef) 317{ 318 BEGIN_SECAPI 319 320 RequiredParam(keychainRef)=globals().storageManager.defaultKeychain(domain)->handle(); 321 322 END_SECAPI 323} 324 325OSStatus SecKeychainSetDomainDefault(SecPreferencesDomain domain, SecKeychainRef keychainRef) 326{ 327 BEGIN_SECAPI 328 329 globals().storageManager.defaultKeychain(domain, Keychain::optional(keychainRef)); 330 331 END_SECAPI 332} 333 334OSStatus SecKeychainCopyDomainSearchList(SecPreferencesDomain domain, CFArrayRef *searchList) 335{ 336 BEGIN_SECAPI 337 338 RequiredParam(searchList); 339 StorageManager &smr = globals().storageManager; 340 StorageManager::KeychainList keychainList; 341 smr.getSearchList(domain, keychainList); 342 *searchList = smr.convertFromKeychainList(keychainList); 343 344 END_SECAPI 345} 346 347OSStatus SecKeychainSetDomainSearchList(SecPreferencesDomain domain, CFArrayRef searchList) 348{ 349 BEGIN_SECAPI 350 351 RequiredParam(searchList); 352 StorageManager &smr = globals().storageManager; 353 StorageManager::KeychainList keychainList; 354 smr.convertToKeychainList(searchList, keychainList); 355 smr.setSearchList(domain, keychainList); 356 357 END_SECAPI 358} 359 360OSStatus SecKeychainSetPreferenceDomain(SecPreferencesDomain domain) 361{ 362 BEGIN_SECAPI 363 364 globals().storageManager.domain(domain); 365 366 END_SECAPI 367} 368 369OSStatus SecKeychainGetPreferenceDomain(SecPreferencesDomain *domain) 370{ 371 BEGIN_SECAPI 372 373 *domain = globals().storageManager.domain(); 374 375 END_SECAPI 376} 377 378 379OSStatus 380SecKeychainGetStatus(SecKeychainRef keychainRef, SecKeychainStatus *keychainStatus) 381{ 382 BEGIN_SECAPI 383 384 RequiredParam(keychainStatus) = (SecKeychainStatus)Keychain::optional(keychainRef)->status(); 385 386 END_SECAPI 387} 388 389 390OSStatus 391SecKeychainGetPath(SecKeychainRef keychainRef, UInt32 *ioPathLength, char *pathName) 392{ 393 BEGIN_SECAPI 394 395 RequiredParam(pathName); 396 RequiredParam(ioPathLength); 397 398 const char *name = Keychain::optional(keychainRef)->name(); 399 UInt32 nameLen = (UInt32)strlen(name); 400 UInt32 callersLen = *ioPathLength; 401 *ioPathLength = nameLen; 402 if (nameLen+1 > callersLen) // if the client's buffer is too small (including null-termination), throw 403 return errSecBufferTooSmall; 404 strncpy(pathName, name, nameLen); 405 pathName[nameLen] = 0; 406 *ioPathLength = nameLen; // set the length. 407 408 END_SECAPI 409} 410 411 412// @@@ Deprecated 413UInt16 414SecKeychainListGetCount(void) 415{ 416 BEGIN_SECAPI 417 418 return globals().storageManager.size(); 419 420 END_SECAPI1(0) 421} 422 423 424// @@@ Deprecated 425OSStatus 426SecKeychainListCopyKeychainAtIndex(UInt16 index, SecKeychainRef *keychainRef) 427{ 428 BEGIN_SECAPI 429 430 KeychainCore::StorageManager &smgr=KeychainCore::globals().storageManager; 431 RequiredParam(keychainRef)=smgr[index]->handle(); 432 433 END_SECAPI 434} 435 436 437// @@@ Deprecated 438OSStatus 439SecKeychainListRemoveKeychain(SecKeychainRef *keychainRef) 440{ 441 BEGIN_SECAPI 442 443 Required(keychainRef); 444 Keychain keychain = Keychain::optional(*keychainRef); 445 StorageManager::KeychainList keychainList; 446 keychainList.push_back(keychain); 447 globals().storageManager.remove(keychainList); 448 *keychainRef = NULL; 449 450 END_SECAPI 451} 452 453 454OSStatus 455SecKeychainAttributeInfoForItemID(SecKeychainRef keychainRef, UInt32 itemID, SecKeychainAttributeInfo **info) 456{ 457 BEGIN_SECAPI 458 459 Keychain keychain = Keychain::optional(keychainRef); 460 keychain->getAttributeInfoForItemID(itemID, info); 461 462 END_SECAPI 463} 464 465 466OSStatus 467SecKeychainFreeAttributeInfo(SecKeychainAttributeInfo *info) 468{ 469 BEGIN_SECAPI 470 471 KeychainImpl::freeAttributeInfo(info); 472 473 END_SECAPI 474} 475 476 477pascal OSStatus 478SecKeychainAddCallback(SecKeychainCallback callbackFunction, SecKeychainEventMask eventMask, void* userContext) 479{ 480 BEGIN_SECAPI 481 482 RequiredParam(callbackFunction); 483 CCallbackMgr::AddCallback(callbackFunction,eventMask,userContext); 484 485 END_SECAPI 486} 487 488 489OSStatus 490SecKeychainRemoveCallback(SecKeychainCallback callbackFunction) 491{ 492 BEGIN_SECAPI 493 494 RequiredParam(callbackFunction); 495 CCallbackMgr::RemoveCallback(callbackFunction); 496 497 END_SECAPI 498} 499 500OSStatus 501SecKeychainAddInternetPassword(SecKeychainRef keychainRef, UInt32 serverNameLength, const char *serverName, UInt32 securityDomainLength, const char *securityDomain, UInt32 accountNameLength, const char *accountName, UInt32 pathLength, const char *path, UInt16 port, SecProtocolType protocol, SecAuthenticationType authenticationType, UInt32 passwordLength, const void *passwordData, SecKeychainItemRef *itemRef) 502{ 503 BEGIN_SECAPI 504 505 KCThrowParamErrIf_(passwordLength!=0 && passwordData==NULL); 506 // @@@ Get real itemClass 507 Item item(kSecInternetPasswordItemClass, 'aapl', passwordLength, passwordData, false); 508 509 if (serverName && serverNameLength) 510 { 511 CssmData server(const_cast<void *>(reinterpret_cast<const void *>(serverName)), serverNameLength); 512 item->setAttribute(Schema::attributeInfo(kSecServerItemAttr), server); 513 // use server name as default label 514 item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), server); 515 } 516 517 if (accountName && accountNameLength) 518 { 519 CssmData account(const_cast<void *>(reinterpret_cast<const void *>(accountName)), accountNameLength); 520 item->setAttribute(Schema::attributeInfo(kSecAccountItemAttr), account); 521 } 522 523 if (securityDomain && securityDomainLength) 524 item->setAttribute(Schema::attributeInfo(kSecSecurityDomainItemAttr), 525 CssmData(const_cast<void *>(reinterpret_cast<const void *>(securityDomain)), securityDomainLength)); 526 527 item->setAttribute(Schema::attributeInfo(kSecPortItemAttr), UInt32(port)); 528 item->setAttribute(Schema::attributeInfo(kSecProtocolItemAttr), protocol); 529 item->setAttribute(Schema::attributeInfo(kSecAuthenticationTypeItemAttr), authenticationType); 530 531 if (path && pathLength) 532 item->setAttribute(Schema::attributeInfo(kSecPathItemAttr), 533 CssmData(const_cast<void *>(reinterpret_cast<const void *>(path)), pathLength)); 534 535 Keychain keychain = nil; 536 try 537 { 538 keychain = Keychain::optional(keychainRef); 539 if ( !keychain->exists() ) 540 { 541 MacOSError::throwMe(errSecNoSuchKeychain); // Might be deleted or not available at this time. 542 } 543 } 544 catch(...) 545 { 546 keychain = globals().storageManager.defaultKeychainUI(item); 547 } 548 549 keychain->add(item); 550 551 if (itemRef) 552 *itemRef = item->handle(); 553 554 END_SECAPI 555} 556 557 558OSStatus 559SecKeychainFindInternetPassword(CFTypeRef keychainOrArray, UInt32 serverNameLength, const char *serverName, UInt32 securityDomainLength, const char *securityDomain, UInt32 accountNameLength, const char *accountName, UInt32 pathLength, const char *path, UInt16 port, SecProtocolType protocol, SecAuthenticationType authenticationType, UInt32 *passwordLength, void **passwordData, SecKeychainItemRef *itemRef) 560 561{ 562 BEGIN_SECAPI 563 564 StorageManager::KeychainList keychains; 565 globals().storageManager.optionalSearchList(keychainOrArray, keychains); 566 KCCursor cursor(keychains, kSecInternetPasswordItemClass, NULL); 567 568 if (serverName && serverNameLength) 569 { 570 cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServerItemAttr), 571 CssmData(const_cast<char *>(serverName), serverNameLength)); 572 } 573 574 if (securityDomain && securityDomainLength) 575 { 576 cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecSecurityDomainItemAttr), 577 CssmData (const_cast<char*>(securityDomain), securityDomainLength)); 578 } 579 580 if (accountName && accountNameLength) 581 { 582 cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecAccountItemAttr), 583 CssmData (const_cast<char*>(accountName), accountNameLength)); 584 } 585 586 if (port) 587 { 588 cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecPortItemAttr), 589 UInt32(port)); 590 } 591 592 if (protocol) 593 { 594 cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecProtocolItemAttr), 595 protocol); 596 } 597 598 if (authenticationType) 599 { 600 cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecAuthenticationTypeItemAttr), 601 authenticationType); 602 } 603 604 if (path && pathLength) 605 { 606 cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecPathItemAttr), path); 607 } 608 609 Item item; 610 if (!cursor->next(item)) 611 return errSecItemNotFound; 612 613 // Get its data (only if necessary) 614 if (passwordData || passwordLength) 615 { 616 CssmDataContainer outData; 617 item->getData(outData); 618 *passwordLength=(UInt32)outData.length(); 619 outData.Length=0; 620 *passwordData=outData.data(); 621 outData.Data=NULL; 622 } 623 624 if (itemRef) 625 *itemRef=item->handle(); 626 627 END_SECAPI 628} 629 630 631OSStatus 632SecKeychainAddGenericPassword(SecKeychainRef keychainRef, UInt32 serviceNameLength, const char *serviceName, UInt32 accountNameLength, const char *accountName, UInt32 passwordLength, const void *passwordData, SecKeychainItemRef *itemRef) 633{ 634 BEGIN_SECAPI 635 636 KCThrowParamErrIf_(passwordLength!=0 && passwordData==NULL); 637 // @@@ Get real itemClass 638 639 Item item(kSecGenericPasswordItemClass, 'aapl', passwordLength, passwordData, false); 640 641 if (serviceName && serviceNameLength) 642 { 643 CssmData service(const_cast<void *>(reinterpret_cast<const void *>(serviceName)), serviceNameLength); 644 item->setAttribute(Schema::attributeInfo(kSecServiceItemAttr), service); 645 // use service name as default label (UNLESS the service is iTools and we have an account name [3787371]) 646 const char *iTools = "iTools"; 647 if (accountNameLength && serviceNameLength==strlen(iTools) && !memcmp(serviceName, iTools, serviceNameLength)) 648 { 649 CssmData account(const_cast<void *>(reinterpret_cast<const void *>(accountName)), accountNameLength); 650 item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), account); 651 } 652 else 653 { 654 item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), service); 655 } 656 } 657 658 if (accountName && accountNameLength) 659 { 660 CssmData account(const_cast<void *>(reinterpret_cast<const void *>(accountName)), accountNameLength); 661 item->setAttribute(Schema::attributeInfo(kSecAccountItemAttr), account); 662 } 663 664 Keychain keychain = nil; 665 try 666 { 667 keychain = Keychain::optional(keychainRef); 668 if ( !keychain->exists() ) 669 { 670 MacOSError::throwMe(errSecNoSuchKeychain); // Might be deleted or not available at this time. 671 } 672 } 673 catch(...) 674 { 675 keychain = globals().storageManager.defaultKeychainUI(item); 676 } 677 678 keychain->add(item); 679 if (itemRef) 680 *itemRef = item->handle(); 681 682 END_SECAPI 683} 684 685 686OSStatus 687SecKeychainFindGenericPassword(CFTypeRef keychainOrArray, UInt32 serviceNameLength, const char *serviceName, UInt32 accountNameLength, const char *accountName, UInt32 *passwordLength, void **passwordData, SecKeychainItemRef *itemRef) 688 689{ 690 BEGIN_SECAPI 691 692 StorageManager::KeychainList keychains; 693 globals().storageManager.optionalSearchList(keychainOrArray, keychains); 694 KCCursor cursor(keychains, kSecGenericPasswordItemClass, NULL); 695 696 if (serviceName && serviceNameLength) 697 { 698 cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServiceItemAttr), 699 CssmData(const_cast<char *>(serviceName), serviceNameLength)); 700 } 701 702 if (accountName && accountNameLength) 703 { 704 cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecAccountItemAttr), 705 CssmData(const_cast<char *>(accountName), accountNameLength)); 706 } 707 708 Item item; 709 if (!cursor->next(item)) 710 return errSecItemNotFound; 711 712 // Get its data (only if necessary) 713 if (passwordData || passwordLength) 714 { 715 CssmDataContainer outData; 716 item->getData(outData); 717 *passwordLength=(UInt32)outData.length(); 718 outData.Length=0; 719 *passwordData=outData.data(); 720 outData.Data=NULL; 721 } 722 723 if (itemRef) 724 *itemRef=item->handle(); 725 726 END_SECAPI 727} 728 729 730OSStatus 731SecKeychainSetUserInteractionAllowed(Boolean state) 732{ 733 BEGIN_SECAPI 734 735 globals().setUserInteractionAllowed(state); 736 737 END_SECAPI 738} 739 740 741OSStatus 742SecKeychainGetUserInteractionAllowed(Boolean *state) 743{ 744 BEGIN_SECAPI 745 746 Required(state)=globals().getUserInteractionAllowed(); 747 748 END_SECAPI 749} 750 751 752OSStatus 753SecKeychainGetDLDBHandle(SecKeychainRef keychainRef, CSSM_DL_DB_HANDLE *dldbHandle) 754{ 755 BEGIN_SECAPI 756 757 RequiredParam(dldbHandle); 758 759 Keychain keychain = Keychain::optional(keychainRef); 760 *dldbHandle = keychain->database()->handle(); 761 762 END_SECAPI 763} 764 765 766OSStatus 767SecKeychainGetCSPHandle(SecKeychainRef keychainRef, CSSM_CSP_HANDLE *cspHandle) 768{ 769 BEGIN_SECAPI 770 771 RequiredParam(cspHandle); 772 773 Keychain keychain = Keychain::optional(keychainRef); 774 *cspHandle = keychain->csp()->handle(); 775 776 END_SECAPI 777} 778 779 780OSStatus 781SecKeychainCopyAccess(SecKeychainRef keychainRef, SecAccessRef *accessRef) 782{ 783 BEGIN_SECAPI 784 785 MacOSError::throwMe(errSecUnimplemented);//%%%for now 786 787 END_SECAPI 788} 789 790 791OSStatus 792SecKeychainSetAccess(SecKeychainRef keychainRef, SecAccessRef accessRef) 793{ 794 BEGIN_SECAPI 795 796 MacOSError::throwMe(errSecUnimplemented);//%%%for now 797 798 END_SECAPI 799} 800 801 802#pragma mark ---- Private API ---- 803 804 805OSStatus 806SecKeychainChangePassword(SecKeychainRef keychainRef, UInt32 oldPasswordLength, const void *oldPassword, UInt32 newPasswordLength, const void *newPassword) 807{ 808 BEGIN_SECAPI 809 810 Keychain keychain = Keychain::optional(keychainRef); 811 keychain->changePassphrase (oldPasswordLength, oldPassword, newPasswordLength, newPassword); 812 813 END_SECAPI 814} 815 816 817OSStatus 818SecKeychainCopyLogin(SecKeychainRef *keychainRef) 819{ 820 BEGIN_SECAPI 821 822 RequiredParam(keychainRef)=globals().storageManager.loginKeychain()->handle(); 823 824 END_SECAPI 825} 826 827 828OSStatus 829SecKeychainLogin(UInt32 nameLength, const void* name, UInt32 passwordLength, const void* password) 830{ 831 BEGIN_SECAPI 832 833 try 834 { 835 if (password) { 836 globals().storageManager.login(nameLength, name, passwordLength, password); 837 } else { 838 globals().storageManager.stashLogin(); 839 } 840 } 841 catch (CommonError &e) 842 { 843 if (e.osStatus() == CSSMERR_DL_OPERATION_AUTH_DENIED) 844 { 845 return errSecAuthFailed; 846 } 847 else 848 { 849 return e.osStatus(); 850 } 851 } 852 853 END_SECAPI 854} 855 856OSStatus SecKeychainStash() 857{ 858 BEGIN_SECAPI 859 860 try 861 { 862 globals().storageManager.stashKeychain(); 863 } 864 catch (CommonError &e) 865 { 866 if (e.osStatus() == CSSMERR_DL_OPERATION_AUTH_DENIED) 867 { 868 return errSecAuthFailed; 869 } 870 else 871 { 872 return e.osStatus(); 873 } 874 } 875 876 END_SECAPI 877} 878 879OSStatus 880SecKeychainLogout() 881{ 882 BEGIN_SECAPI 883 884 globals().storageManager.logout(); 885 886 END_SECAPI 887} 888 889/* (non-exported C utility routine) 'Makes' a keychain based on a full path 890*/ 891static Keychain make(const char *name) 892{ 893 return globals().storageManager.make(name); 894} 895 896/* 'Makes' a keychain based on a full path for legacy "KC" CoreServices APIs. 897 Note this version doesn't take an accessRef or password. 898 The "KC" create API takes a keychainRef... 899*/ 900OSStatus SecKeychainMakeFromFullPath(const char *fullPathName, SecKeychainRef *keychainRef) 901{ 902 BEGIN_SECAPI 903 RequiredParam(fullPathName); 904 RequiredParam(keychainRef)=make(fullPathName)->handle(); 905 END_SECAPI 906} 907 908 909/* Determines if the keychainRef is a valid keychain. 910*/ 911OSStatus SecKeychainIsValid(SecKeychainRef keychainRef, Boolean* isValid) 912{ 913 BEGIN_SECAPI 914 *isValid = false; 915 if (KeychainImpl::optional(keychainRef)->dlDbIdentifier().ssuid().guid() == gGuidAppleCSPDL) 916 *isValid = true; 917 END_SECAPI 918} 919 920/* Removes a keychain from the keychain search list for legacy "KC" CoreServices APIs. 921*/ 922OSStatus SecKeychainRemoveFromSearchList(SecKeychainRef keychainRef) 923{ 924 BEGIN_SECAPI 925 StorageManager::KeychainList singleton; 926 singleton.push_back(KeychainImpl::required(keychainRef)); 927 globals().storageManager.remove(singleton); 928 END_SECAPI 929} 930 931/* Create a keychain based on a keychain Ref for legacy "KC" CoreServices APIs. 932*/ 933OSStatus SecKeychainCreateNew(SecKeychainRef keychainRef, UInt32 passwordLength, const char* inPassword) 934{ 935 BEGIN_SECAPI 936 RequiredParam(inPassword); 937 KeychainImpl::required(keychainRef)->create(passwordLength, inPassword); 938 END_SECAPI 939} 940 941/* Modify a keychain so that it can be synchronized. 942*/ 943OSStatus SecKeychainRecodeKeychain(SecKeychainRef keychainRef, CFArrayRef dbBlobArray, CFDataRef extraData) 944{ 945 BEGIN_SECAPI 946 947 // do error checking for required parameters 948 RequiredParam(dbBlobArray); 949 RequiredParam(extraData); 950 951 const CssmData extraCssmData(const_cast<UInt8 *>(CFDataGetBytePtr(extraData)), 952 CFDataGetLength(extraData)); 953 954 CFIndex dbBlobArrayCount = CFArrayGetCount(dbBlobArray); 955 size_t space = sizeof(uint8) + (dbBlobArrayCount * sizeof(SecurityServer::DbHandle)); 956 void *dataPtr = (void*)malloc(space); 957 if ( !dataPtr ) 958 return errSecAllocate; 959 // 960 // Get a DbHandle(IPCDbHandle) from securityd for each blob in the array that we'll authenticate with. 961 // 962 uint8* sizePtr = (uint8*)dataPtr; 963 *sizePtr = dbBlobArrayCount; 964 SecurityServer::DbHandle *currDbHandle = (SecurityServer::DbHandle *)(sizePtr+1); 965 CFIndex index; 966 SecurityServer::ClientSession ss(Allocator::standard(), Allocator::standard()); 967 for (index=0; index < dbBlobArrayCount; index++) 968 { 969 CFDataRef cfBlobData = (CFDataRef)CFArrayGetValueAtIndex(dbBlobArray, index); 970 const CssmData thisKCData(const_cast<UInt8 *>(CFDataGetBytePtr(cfBlobData)), CFDataGetLength(cfBlobData)); 971 // 972 // Since it's to a DbHandle that's not on our disk (it came from user's iDisk), 973 // it's OK to use the mIdentifier and access credentials of the keychain we're recoding. 974 // 975 Keychain kc = KeychainImpl::required(keychainRef); 976 *currDbHandle = ss.decodeDb(kc->dlDbIdentifier(), kc->defaultCredentials(), thisKCData); /* returns a DbHandle (IPCDbHandle) */ 977 978 currDbHandle++; 979 } 980 // do the work 981 Keychain keychain = Keychain::optional(keychainRef); 982 const CssmData data(const_cast<UInt8 *>((uint8*)dataPtr), space); 983 Boolean recodeFailed = false; 984 985 int errCode=errSecSuccess; 986 987 try 988 { 989 keychain->recode(data, extraCssmData); 990 } 991 catch (MacOSError e) 992 { 993 errCode = e.osStatus(); 994 recodeFailed = true; 995 } 996 catch (UnixError ue) 997 { 998 errCode = ue.unixError(); 999 } 1000 1001 currDbHandle = (SecurityServer::DbHandle *)(sizePtr+1); 1002 for (index=0; index < dbBlobArrayCount; index++) 1003 { 1004 ss.releaseDb(*currDbHandle); 1005 currDbHandle++; 1006 } 1007 if ( dataPtr ) 1008 free(dataPtr); 1009 1010 if ( recodeFailed ) 1011 { 1012 return errCode; 1013 } 1014 1015 END_SECAPI 1016} 1017 1018OSStatus SecKeychainCopySignature(SecKeychainRef keychainRef, CFDataRef *keychainSignature) 1019{ 1020 BEGIN_SECAPI 1021 1022 // do error checking for required parameters 1023 RequiredParam(keychainSignature); 1024 1025 // make a keychain object "wrapper" for this keychain ref 1026 Keychain keychain = Keychain::optional(keychainRef); 1027 CssmAutoData data(keychain->database()->allocator()); 1028 keychain->copyBlob(data.get()); 1029 1030 // get the cssmDBBlob 1031 const SecurityServer::DbBlob *cssmDBBlob = 1032 data.get().interpretedAs<const SecurityServer::DbBlob>(); 1033 1034 // convert from CDSA standards to CF standards 1035 *keychainSignature = CFDataCreate(kCFAllocatorDefault, 1036 cssmDBBlob->randomSignature.bytes, 1037 sizeof(SecurityServer::DbBlob::Signature)); 1038 1039 END_SECAPI 1040} 1041 1042OSStatus SecKeychainCopyBlob(SecKeychainRef keychainRef, CFDataRef *dbBlob) 1043{ 1044 BEGIN_SECAPI 1045 1046 // do error checking for required parameters 1047 RequiredParam(dbBlob); 1048 1049 // make a keychain object "wrapper" for this keychain ref 1050 Keychain keychain = Keychain::optional(keychainRef); 1051 CssmAutoData data(keychain->database()->allocator()); 1052 keychain->copyBlob(data.get()); 1053 1054 // convert from CDSA standards to CF standards 1055 *dbBlob = CFDataCreate(kCFAllocatorDefault, data, data.length()); 1056 1057 END_SECAPI 1058} 1059 1060// make a new keychain with pre-existing secrets 1061OSStatus SecKeychainCreateWithBlob(const char* fullPathName, CFDataRef dbBlob, SecKeychainRef *kcRef) 1062{ 1063 BEGIN_SECAPI 1064 1065 KCThrowParamErrIf_(!fullPathName); 1066 KCThrowParamErrIf_(!dbBlob); 1067 1068 Keychain keychain = globals().storageManager.make(fullPathName); 1069 1070 CssmData blob(const_cast<unsigned char *>(CFDataGetBytePtr(dbBlob)), CFDataGetLength(dbBlob)); 1071 1072 // @@@ the call to StorageManager::make above leaves keychain the the cache. 1073 // If the create below fails we should probably remove it. 1074 keychain->createWithBlob(blob); 1075 1076 RequiredParam(kcRef)=keychain->handle(); 1077 1078 // 1079 1080 END_SECAPI 1081} 1082 1083// add a non-file based DB to the keychain list 1084OSStatus SecKeychainAddDBToKeychainList (SecPreferencesDomain domain, const char* dbName, 1085 const CSSM_GUID *guid, uint32 subServiceType) 1086{ 1087 BEGIN_SECAPI 1088 1089 RequiredParam(dbName); 1090 StorageManager &smr = globals().storageManager; 1091 smr.addToDomainList(domain, dbName, *guid, subServiceType); 1092 1093 END_SECAPI 1094} 1095 1096// determine if a non-file based DB is in the keychain list 1097OSStatus SecKeychainDBIsInKeychainList (SecPreferencesDomain domain, const char* dbName, 1098 const CSSM_GUID *guid, uint32 subServiceType) 1099{ 1100 BEGIN_SECAPI 1101 RequiredParam(dbName); 1102 StorageManager &smr = globals().storageManager; 1103 smr.isInDomainList(domain, dbName, *guid, subServiceType); 1104 END_SECAPI 1105} 1106 1107// remove a non-file based DB from the keychain list 1108OSStatus SecKeychainRemoveDBFromKeychainList (SecPreferencesDomain domain, const char* dbName, 1109 const CSSM_GUID *guid, uint32 subServiceType) 1110{ 1111 BEGIN_SECAPI 1112 RequiredParam(dbName); 1113 StorageManager &smr = globals().storageManager; 1114 smr.removeFromDomainList(domain, dbName, *guid, subServiceType); 1115 END_SECAPI 1116} 1117 1118 1119// set server mode -- must be called before any other Sec* etc. call 1120void SecKeychainSetServerMode() 1121{ 1122 gServerMode = true; 1123} 1124 1125 1126 1127OSStatus SecKeychainSetBatchMode (SecKeychainRef kcRef, Boolean mode, Boolean rollback) 1128{ 1129 BEGIN_SECAPI 1130 RequiredParam(kcRef); 1131 Keychain keychain = Keychain::optional(kcRef); 1132 keychain->setBatchMode(mode, rollback); 1133 END_SECAPI 1134} 1135 1136 1137 1138OSStatus SecKeychainCleanupHandles() 1139{ 1140 BEGIN_SECAPI 1141 END_SECAPI // which causes the handle cache cleanup routine to run 1142} 1143 1144OSStatus SecKeychainVerifyKeyStorePassphrase(uint32_t retries) 1145{ 1146 BEGIN_SECAPI 1147 SecurityServer::ClientSession().verifyKeyStorePassphrase(retries); 1148 END_SECAPI 1149} 1150 1151OSStatus SecKeychainChangeKeyStorePassphrase() 1152{ 1153 BEGIN_SECAPI 1154 SecurityServer::ClientSession().changeKeyStorePassphrase(); 1155 END_SECAPI 1156} 1157 1158static OSStatus SecKeychainGetMasterKey(SecKeychainRef userKeychainRef, CFDataRef *masterKey, CFStringRef password) 1159{ 1160 BEGIN_SECAPI 1161 1162 // make a keychain object "wrapper" for this keychain ref 1163 Keychain keychain = Keychain::optional(userKeychainRef); 1164 1165 CssmClient::Db db = keychain->database(); 1166 1167 // create the keychain, using appropriate credentials 1168 Allocator &alloc = db->allocator(); 1169 AutoCredentials cred(alloc); // will leak, but we're quitting soon :-) 1170 1171 char passphrase[1024]; 1172 CFStringGetCString(password, passphrase, sizeof(passphrase), kCFStringEncodingUTF8); 1173 1174 // use this passphrase 1175 cred += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK, 1176 new(alloc) ListElement(CSSM_SAMPLE_TYPE_PASSWORD), 1177 new(alloc) ListElement(StringData(passphrase))); 1178 db->accessCredentials(&cred); 1179 1180 CSSM_DL_DB_HANDLE dlDb = db->handle(); 1181 CssmData dlDbData = CssmData::wrap(dlDb); 1182 CssmKey refKey; 1183 KeySpec spec(CSSM_KEYUSE_ANY, 1184 CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE); 1185 1186 DeriveKey derive(keychain->csp(), CSSM_ALGID_KEYCHAIN_KEY, CSSM_ALGID_3DES_3KEY, 3 * 64); 1187 derive(&dlDbData, spec, refKey); 1188 1189 // now extract the raw keybits 1190 CssmKey rawKey; 1191 WrapKey wrap(keychain->csp(), CSSM_ALGID_NONE); 1192 wrap(refKey, rawKey); 1193 1194 *masterKey = CFDataCreate(kCFAllocatorDefault, rawKey.keyData(), rawKey.length()); 1195 1196 END_SECAPI 1197} 1198 1199 1200OSStatus SecKeychainStoreUnlockKey(SecKeychainRef userKeychainRef, SecKeychainRef systemKeychainRef, CFStringRef username, CFStringRef password) { 1201 SecTrustedApplicationRef itemPath; 1202 SecAccessRef ourAccessRef = NULL; 1203 1204 OSStatus result = errSecParam; 1205 1206 CFDataRef masterKey = NULL; 1207 result = SecKeychainGetMasterKey(userKeychainRef, &masterKey, password); 1208 if (errSecSuccess != result) { 1209 return result; 1210 } 1211 1212 result = SecKeychainStash(); 1213 if (errSecSuccess != result) { 1214 if (NULL != masterKey) CFRelease(masterKey); 1215 return result; 1216 } 1217 1218 CFMutableArrayRef trustedApplications = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 1219 if ( noErr == SecTrustedApplicationCreateApplicationGroup("com.apple.security.auto-login", NULL, &itemPath) && itemPath ) 1220 CFArrayAppendValue(trustedApplications, itemPath); 1221 1222 if ( trustedApplications && (CFArrayGetCount(trustedApplications) > 0)) { 1223 if (errSecSuccess == (result = SecAccessCreate(CFSTR("Auto-Login applications"), trustedApplications, &ourAccessRef))) { 1224 if (NULL == systemKeychainRef) { 1225 SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, &systemKeychainRef); 1226 } 1227 1228 const void *queryKeys[] = { kSecClass, 1229 kSecAttrService, 1230 kSecAttrAccount, 1231 kSecUseKeychain, 1232 }; 1233 const void *queryValues[] = { kSecClassGenericPassword, 1234 CFSTR("com.apple.loginwindow.auto-login"), 1235 username, 1236 systemKeychainRef, 1237 }; 1238 1239 const void *updateKeys[] = { kSecAttrAccess, 1240 kSecValueData, 1241 }; 1242 const void *updateValues[] = { ourAccessRef, 1243 masterKey, 1244 }; 1245 1246 CFDictionaryRef query = CFDictionaryCreate(kCFAllocatorDefault, queryKeys, queryValues, sizeof(queryValues)/sizeof(*queryValues), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1247 CFDictionaryRef update = CFDictionaryCreate(kCFAllocatorDefault, updateKeys, updateValues, sizeof(updateValues)/sizeof(*updateValues), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1248 1249 result = SecItemUpdate(query, update); 1250 1251 if (errSecSuccess != result) { 1252 const void *addKeys[] = { kSecClass, 1253 kSecAttrService, 1254 kSecAttrAccount, 1255 kSecUseKeychain, 1256 kSecAttrAccess, 1257 kSecValueData, 1258 }; 1259 const void *addValues[] = { kSecClassGenericPassword, 1260 CFSTR("com.apple.loginwindow.auto-login"), 1261 username, 1262 systemKeychainRef, 1263 ourAccessRef, 1264 masterKey, 1265 }; 1266 1267 CFDictionaryRef add = CFDictionaryCreate(kCFAllocatorDefault, addKeys, addValues, sizeof(addValues)/sizeof(*addValues), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1268 result = SecItemAdd(add, NULL); 1269 if (NULL != add) CFRelease(add); 1270 } 1271 1272 if (NULL != query) CFRelease(query); 1273 if (NULL != update) CFRelease(update); 1274 } 1275 } 1276 1277 if (NULL != masterKey) CFRelease(masterKey); 1278 if (NULL != trustedApplications) CFRelease(trustedApplications); 1279 if (NULL != ourAccessRef) CFRelease(ourAccessRef); 1280 if (NULL != systemKeychainRef) CFRelease(systemKeychainRef); 1281 1282 return result; 1283} 1284