2  * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved. 
   4  * The contents of this file constitute Original Code as defined in and are 
   5  * subject to the Apple Public Source License Version 1.2 (the 'License'). 
   6  * You may not use this file except in compliance with the License. Please obtain 
   7  * a copy of the License at http://www.apple.com/publicsource and read it before 
  10  * This Original Code and all software distributed under the License are 
  11  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS 
  12  * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT 
  13  * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
  14  * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the 
  15  * specific language governing rights and limitations under the License. 
  23  *    Copyright:  (c) 2000 by Apple Computer, Inc., all rights reserved 
  28 #include <Security/SecKeychainAPI.h> 
  29 #include "SecKeychainAPIPriv.h" 
  30 #include "Keychains.h" 
  32 #include "KCUtilities.h" 
  33 #include "KCEventNotifier.h" 
  35 #include "CCallbackMgr.h" 
  36 #include "KCExceptions.h" 
  38 #include <Security/globalizer.h> 
  40 using namespace Security
; 
  42 using namespace KeychainCore
; 
  45 // API boilerplate macros. These provide a frame for C++ code that is impermeable to exceptions. 
  48 //              ... your C++ code here ... 
  49 //  END_API             // returns CSSM_RETURN on exception 
  50 //      END_API0        // returns nothing (void) on exception 
  51 //      END_API1(bad) // return (bad) on exception 
  53 #define BEGIN_SECAPI \ 
  55                 StLock<Mutex> _(globals().apiLock); 
  58         catch (const MacOSError &err) { return err.osStatus(); } \ 
  59         catch (const CssmCommonError &err) { return GetKeychainErrFromCSSMErr(err.cssmError())/*err.cssmError(CSSM_CSSM_BASE_ERROR)*/; } \ 
  60         catch (::std::bad_alloc) { return memFullErr; } \ 
  61         catch (...) { return internalComponentErr; } \ 
  63 #define END_SECAPI0             } catch (...) { return; } 
  64 #define END_SECAPI1(bad)        } catch (...) { return bad; } 
  67 OSStatus 
SecKeychainGetVersion(UInt32 
*returnVers
) 
  69     if (!returnVers
) return noErr
; 
  71         *returnVers
=0x02028000; 
  76 OSStatus 
SecKeychainOpen(const char *pathName
, SecKeychainRef 
*keychainRef
) 
  79                 RequiredParam(keychainRef
)=KeychainRef::handle(globals().storageManager
.make(pathName
)); 
  83 OSStatus 
SecKeychainCreateNew(const char *pathName
, SecKeychainRef 
*keychainRef
, UInt32 passwordLength
, const void *password
, Boolean promptUser
) 
  87                 KCThrowParamErrIf_(!pathName
); 
  89                 Keychain keychain 
= globals().storageManager
.make(pathName
); 
  97             KCThrowParamErrIf_(!password
); 
  99                         keychain
->create(passwordLength
, password
); 
 101         RequiredParam(keychainRef
)=KeychainRef::handle(keychain
); 
 106 OSStatus 
SecKeychainDelete(SecKeychainRef keychainRef
) 
 110                 Keychain keychain 
= Keychain::optional(keychainRef
); 
 111                 keychain
->database()->deleteDb(); 
 113         list
<SecKeychainRef
> SecKeychainRefToRemove
; 
 114                 SecKeychainRefToRemove
.push_back(keychainRef
); 
 115                 KeychainCore::StorageManager 
&smgr
=KeychainCore::globals().storageManager
; 
 116                 smgr
.remove(SecKeychainRefToRemove
); 
 123 OSStatus 
SecKeychainSetSettings(SecKeychainRef keychainRef
, const SecKeychainSettings 
*newSettings
) 
 126         Keychain keychain 
= Keychain::optional(keychainRef
); 
 127                 if(newSettings
->version
==SEC_KEYCHAIN_SETTINGS_VERS1
) 
 129                         UInt32 lockInterval
=newSettings
->lockInterval
; 
 130                         bool lockOnSleep
=newSettings
->lockOnSleep
; 
 132                         keychain
->setSettings(lockInterval
, lockOnSleep
); 
 138 OSStatus 
SecKeychainCopySettings(SecKeychainRef keychainRef
, SecKeychainSettings 
*outSettings
) 
 141         Keychain keychain 
= Keychain::optional(keychainRef
); 
 142                 if(outSettings
->version
==SEC_KEYCHAIN_SETTINGS_VERS1
) 
 147                         keychain
->getSettings(lockInterval
, lockOnSleep
); 
 148                         outSettings
->lockInterval
=lockInterval
; 
 149                         outSettings
->lockOnSleep
=lockOnSleep
; 
 155 OSStatus 
SecKeychainUnlock(SecKeychainRef keychainRef
, UInt32 passwordLength
, void *password
, Boolean usePassword
) 
 158         Keychain keychain 
= Keychain::optional(keychainRef
); 
 161                         keychain
->unlock(CssmData(password
,passwordLength
)); 
 168 OSStatus 
SecKeychainLock(SecKeychainRef keychainRef
) 
 171         Keychain keychain 
= Keychain::optional(keychainRef
); 
 177 OSStatus 
SecKeychainLockAll() 
 180                 globals().storageManager
.lockAll(); 
 185 OSStatus 
SecKeychainRelease(SecKeychainRef keychainRef
) 
 188                 KeychainRef::release(keychainRef
); 
 193 OSStatus 
SecKeychainCopyDefault(SecKeychainRef 
*keychainRef
) 
 196         RequiredParam(keychainRef
)=KeychainRef::handle(globals().defaultKeychain
.keychain()); 
 201 OSStatus 
SecKeychainSetDefault(SecKeychainRef keychainRef
) 
 204                 globals().defaultKeychain
.keychain(Keychain::optional(keychainRef
)); 
 209 OSStatus 
SecKeychainGetStatus(SecKeychainRef keychainRef
, SecKeychainStatus 
*keychainStatus
) 
 212                 RequiredParam(keychainStatus
) = (SecKeychainStatus
)Keychain::optional(keychainRef
)->status(); 
 217 OSStatus 
SecKeychainGetPath(SecKeychainRef keychainRef
, UInt32 
* ioPathLength
, char *pathName
) 
 220                 RequiredParam(pathName
); 
 221                 const char *name 
= Keychain::optional(keychainRef
)->name(); 
 222                 UInt32 nameLen 
= strlen(name
); 
 223                 memcpy(pathName
, name
, *ioPathLength
); 
 224                 if(nameLen 
< *ioPathLength
)  // if the size is smaller then the buffer 
 225                         *ioPathLength
=nameLen
;   // set the length.  otherwise the size is clipped because 
 226                                                                          // the buffer is too small. 
 232 UInt16 
SecKeychainListGetCount(void) 
 235                 return globals().storageManager
.size(); 
 240 OSStatus 
SecKeychainListCopyKeychainAtIndex(UInt16 index
, SecKeychainRef 
*keychainRef
) 
 243                 KeychainCore::StorageManager 
&smgr
=KeychainCore::globals().storageManager
; 
 244                 RequiredParam(keychainRef
)=KeychainRef::handle(smgr
[index
]); 
 248 OSStatus 
SecKeychainItemCreateFromContent(SecItemClass itemClass
, SecKeychainAttributeList 
*attrList
, UInt32 length
, const void *data
, SecKeychainRef keychainRef
, SecKeychainItemRef 
*itemRef
) 
 251                 KCThrowParamErrIf_(length
!=0 && data
==NULL
); 
 252         Item 
item(itemClass
, attrList
, length
, data
); 
 253         Keychain::optional(keychainRef
)->add(item
); 
 255                 *itemRef 
= ItemRef::handle(item
); 
 259 OSStatus 
SecKeychainItemModifyContent(SecKeychainItemRef itemRef
, const SecKeychainAttributeList 
*attrList
, UInt32 length
, const void *data
) 
 262                 Item item 
= ItemRef::required(itemRef
); 
 263                 item
->modifyContent(attrList
, length
, data
); 
 268 OSStatus 
SecKeychainItemCopyContent(SecKeychainItemRef itemRef
, SecItemClass 
*itemClass
, SecKeychainAttributeList 
*attrList
, UInt32 
*length
, void **outData
) 
 271                 Item item 
= ItemRef::required(itemRef
); 
 272                 item
->getContent(itemClass
, attrList
, length
, outData
); 
 276 OSStatus 
SecKeychainItemFreeContent(SecKeychainAttributeList 
*attrList
, void *data
) 
 279                 ItemImpl::freeContent(attrList
, data
); 
 284 OSStatus 
SecKeychainAttributeInfoForItemID(SecKeychainRef keychainRef
, UInt32 itemID
, SecKeychainAttributeInfo 
**info
) 
 287                 Keychain keychain 
= Keychain::optional(keychainRef
); 
 288                 keychain
->getAttributeInfoForItemID(itemID
, info
); 
 292 OSStatus 
SecKeychainFreeAttributeInfo(SecKeychainAttributeInfo 
*info
) 
 295                 KeychainImpl::freeAttributeInfo(info
); 
 299 OSStatus 
SecKeychainItemModifyAttributesAndData(SecKeychainItemRef itemRef
, const SecKeychainAttributeList 
*attrList
, UInt32 length
, const void *data
) 
 302                 Item item 
= ItemRef::required(itemRef
); 
 303                 item
->modifyAttributesAndData(attrList
, length
, data
); 
 307 OSStatus 
SecKeychainItemCopyAttributesAndData(SecKeychainItemRef itemRef
, SecKeychainAttributeInfo 
*info
, SecItemClass 
*itemClass
, SecKeychainAttributeList 
**attrList
, UInt32 
*length
, void **outData
) 
 310                 Item item 
= ItemRef::required(itemRef
); 
 311                 item
->getAttributesAndData(info
, itemClass
, attrList
, length
, outData
); 
 315 OSStatus 
SecKeychainItemFreeAttributesAndData(SecKeychainAttributeList 
*attrList
, void *data
) 
 318                 ItemImpl::freeAttributesAndData(attrList
, data
); 
 322 OSStatus 
SecKeychainItemDelete(SecKeychainItemRef itemRef
) 
 325                 Item item 
= ItemRef::required( itemRef 
); 
 326                 Keychain keychain 
= item
->keychain(); 
 327                 KCThrowIf_( !keychain
, errSecInvalidItemRef 
); 
 329         keychain
->deleteItem( item 
); // item must be persistant. 
 334 OSStatus 
SecKeychainItemCopyKeychain(SecKeychainItemRef itemRef
, SecKeychainRef
* keychainRef
) 
 337                 Required(keychainRef
) = KeychainRef::handle(ItemRef::required(itemRef
)->keychain()); 
 342 OSStatus 
SecKeychainItemCreateCopy(SecKeychainItemRef itemRef
, SecKeychainItemRef 
*itemCopy
, SecKeychainRef destKeychainRef
) 
 345                 Item copy 
= ItemRef::required(itemRef
)->copyTo(Keychain::optional(destKeychainRef
)); 
 347                         *itemCopy 
= ItemRef::handle(copy
); 
 352 OSStatus 
SecKeychainItemRelease(SecKeychainItemRef itemRef
) 
 355                 ItemRef::release(itemRef
); 
 359 OSStatus 
SecKeychainSearchCreateFromAttributes(SecKeychainRef keychainRef
, SecItemClass itemClass
, const SecKeychainAttributeList 
*attrList
, SecKeychainSearchRef 
*searchRef
) 
 363                 Required(searchRef
); // Make sure that searchRef is an invalid SearchRef 
 367                         cursor 
= Keychain::optional(keychainRef
)->createCursor(itemClass
, attrList
); 
 369                         cursor 
= globals().storageManager
.createCursor(itemClass
, attrList
); 
 371         *searchRef 
= KCCursorRef::handle(cursor
); 
 377 OSStatus 
SecKeychainCopySearchNextItem(SecKeychainSearchRef searchRef
, SecKeychainItemRef 
*itemRef
) 
 380         RequiredParam(itemRef
); 
 382         if (!KCCursorRef::required(searchRef
)->next(item
)) 
 383             return errSecItemNotFound
; 
 385         *itemRef
=ItemRef::handle(item
); 
 389 OSStatus 
SecKeychainSearchRelease(SecKeychainSearchRef searchRef
) 
 392                 KCCursorRef::release(searchRef
); 
 397 OSStatus 
SecKeychainListRemoveKeychain(SecKeychainRef 
*keychainRef
) 
 400         list
<SecKeychainRef
> SecKeychainRefToRemove
; 
 401                 SecKeychainRefToRemove
.push_back(RequiredParam(keychainRef
)); 
 402                 StorageManager 
&smgr 
= globals().storageManager
; 
 403                 smgr
.remove(SecKeychainRefToRemove
); 
 409 pascal OSStatus 
SecKeychainAddCallback(SecKeychainCallbackProcPtr callbackFunction
, SecKeychainEventMask eventMask
, void* userContext
) 
 412                 RequiredParam(callbackFunction
); 
 413                 CCallbackMgr::AddCallback(callbackFunction
,eventMask
,userContext
); 
 417 OSStatus 
SecKeychainRemoveCallback(SecKeychainCallbackProcPtr callbackFunction
) 
 420                 RequiredParam(callbackFunction
); 
 421         CCallbackMgr::RemoveCallback(callbackFunction
); 
 428 OSStatus 
SecKeychainChangePassword(SecKeychainRef keychainRef
, UInt32 oldPasswordLength
, const void *oldPassword
,  UInt32 newPasswordLength
, const void *newPassword
) 
 431         globals().storageManager
.changeLoginPassword(oldPasswordLength
, oldPassword
,  newPasswordLength
, newPassword
); 
 435 OSStatus 
SecKeychainCopyLogin(SecKeychainRef 
*keychainRef
) 
 438         // NOTE: operates on default Keychain!  It shouldn't... we want to  
 439         //               have code that operates of a login keychain. 
 440         RequiredParam(keychainRef
)=KeychainRef::handle(globals().defaultKeychain
.keychain()); 
 445 OSStatus 
SecKeychainAddInternetPassword(SecKeychainRef keychainRef
, UInt32 serverNameLength
, char *serverName
,  
 446                                                                                 UInt32 securityDomainLength
, char *securityDomain
, UInt32 accountNameLength
, char *accountName
,  
 447                                                                                 UInt32 pathLength
, char *path
, UInt16 port
, OSType protocol
, OSType authType
, 
 448                                                                                 UInt32 passwordLength
, const void *passwordData
, SecKeychainItemRef 
*itemRef
) 
 451                 KCThrowParamErrIf_(passwordLength
!=0 && passwordData
==NULL
); 
 452                 // @@@ Get real itemClass 
 453         Item 
item(kSecInternetPasswordItemClass
, 'aapl', passwordLength
, passwordData
); 
 455                 if (serverName 
&& serverNameLength
) 
 456                         item
->setAttribute(Schema::attributeInfo(kSecServerItemAttr
), 
 457                                 CssmData(serverName
, serverNameLength
)); 
 459                 if (accountName 
&& accountNameLength
) 
 461                         CssmData 
account(accountName
, accountNameLength
); 
 462                         item
->setAttribute(Schema::attributeInfo(kSecAccountItemAttr
), account
); 
 463                          // @@@ We should probably leave setting of label up to lower level code. 
 464                         item
->setAttribute(Schema::attributeInfo(kSecLabelItemAttr
), account
); 
 467                 if (securityDomain 
&& securityDomainLength
) 
 468                         item
->setAttribute(Schema::attributeInfo(kSecSecurityDomainItemAttr
), 
 469                                 CssmData(securityDomain
, securityDomainLength
)); 
 471                 item
->setAttribute(Schema::attributeInfo(kSecPortItemAttr
), UInt32(port
)); 
 472                 item
->setAttribute(Schema::attributeInfo(kSecProtocolItemAttr
), protocol
); 
 473                 item
->setAttribute(Schema::attributeInfo(kSecAuthTypeItemAttr
), authType
); 
 475                 if (path 
&& pathLength
) 
 476                         item
->setAttribute(Schema::attributeInfo(kSecPathItemAttr
), 
 477                                 CssmData(path
, pathLength
)); 
 479                 Keychain::optional(keychainRef
)->add(item
); 
 481                 *itemRef 
= ItemRef::handle(item
); 
 486 OSStatus 
SecKeychainFindInternetPassword(SecKeychainRef keychainRef
, UInt32 serverNameLength
, char *serverName
,  
 487                                                                                 UInt32 securityDomainLength
, char *securityDomain
, UInt32 accountNameLength
, char *accountName
, 
 488                                                                                 UInt32 pathLength
, char *path
, UInt16 port
, OSType protocol
, OSType authType
, 
 489                                                                                 UInt32 
*passwordLength
, void **passwordData
, SecKeychainItemRef 
*itemRef
) 
 495                 UInt32 attrCount 
= 0; 
 497                 // The number of attributes to search on depends on what was passed in 
 498                 if ( serverName 
&& serverNameLength
) 
 501                 if ( securityDomain 
&& securityDomainLength 
) 
 504                 if ( accountName 
&& accountNameLength
) 
 516                 if ( path 
&& pathLength 
) 
 519                 auto_array
<SecKeychainAttribute
> attrs(attrCount
); 
 522                 if ( serverName 
&& serverNameLength 
) 
 524                         attrs
[attrCount
].tag 
= kSecServerItemAttr
; 
 525                         attrs
[attrCount
].length 
= serverNameLength
; 
 526                         attrs
[attrCount
].data 
= serverName
; 
 529                 if ( securityDomain 
&& securityDomainLength 
) 
 531                         attrs
[attrCount
].tag 
= kSecSecurityDomainItemAttr
; 
 532                         attrs
[attrCount
].length 
= securityDomainLength
; 
 533                         attrs
[attrCount
].data 
= securityDomain
; 
 536                 if ( accountName 
&& accountNameLength 
) 
 538                         attrs
[attrCount
].tag 
= kSecAccountItemAttr
; 
 539                         attrs
[attrCount
].length 
= accountNameLength
; 
 540                         attrs
[attrCount
].data 
= accountName
; 
 546                         attrs
[attrCount
].tag 
= kSecPortItemAttr
; 
 547                         attrs
[attrCount
].length 
= sizeof( port 
); 
 548                         attrs
[attrCount
].data 
= &port
; 
 553                         attrs
[attrCount
].tag 
= kSecProtocolItemAttr
; 
 554                         attrs
[attrCount
].length 
= sizeof( protocol 
); 
 555                         attrs
[attrCount
].data 
= &protocol
; 
 560                         attrs
[attrCount
].tag 
= kSecAuthTypeItemAttr
; 
 561                         attrs
[attrCount
].length 
= sizeof( authType 
); 
 562                         attrs
[attrCount
].data 
= &authType
; 
 566                 if ( path  
&& pathLength 
) 
 568                         attrs
[attrCount
].tag 
= kSecPathItemAttr
; 
 569                         attrs
[attrCount
].length 
= pathLength
; 
 570                         attrs
[attrCount
].data 
= path
; 
 574         SecKeychainAttributeList attrList
; 
 575                 attrList
.count 
= attrCount
; 
 576                 attrList
.attr 
= attrs
.get(); 
 582                         cursor 
= Keychain::optional(keychainRef
)->createCursor(kSecInternetPasswordItemClass
, &attrList
); 
 584                         cursor 
= globals().storageManager
.createCursor(kSecInternetPasswordItemClass
, &attrList
); 
 586                 if (!cursor
->next(item
)) 
 587                         return errSecItemNotFound
; 
 590                 // Get its data (only if necessary) 
 591                 if ( passwordData 
|| passwordLength 
) 
 593                         CssmDataContainer outData
; 
 594                         item
->getData(outData
); 
 595                         *passwordLength
=outData
.length(); 
 597                         *passwordData
=outData
.data(); 
 602                         *itemRef
=ItemRef::handle(item
); 
 611 OSStatus 
SecKeychainAddGenericPassword(SecKeychainRef keychainRef
, UInt32 serviceNameLength
, char *serviceName
, 
 612                                                                            UInt32 accountNameLength
, char *accountName
,  
 613                                                                            UInt32 passwordLength
, const void *passwordData
, SecKeychainItemRef 
*itemRef
) 
 618                 KCThrowParamErrIf_(passwordLength
!=0 && passwordData
==NULL
); 
 619                 // @@@ Get real itemClass 
 620         Item 
item(kSecGenericPasswordItemClass
, 'aapl', passwordLength
, passwordData
); 
 622                 if (serviceName 
&& serviceNameLength
) 
 623                         item
->setAttribute(Schema::attributeInfo(kSecServiceItemAttr
), CssmData(serviceName
, serviceNameLength
)); 
 625                 if (accountName 
&& accountNameLength
) 
 627                         CssmData 
account(accountName
, accountNameLength
); 
 628                         item
->setAttribute(Schema::attributeInfo(kSecAccountItemAttr
), account
); 
 629                          // @@@ We should probably leave setting of label up to lower level code. 
 630                         item
->setAttribute(Schema::attributeInfo(kSecLabelItemAttr
), account
); 
 633         Keychain::optional(keychainRef
)->add(item
); 
 635                 *itemRef 
= ItemRef::handle(item
); 
 640 OSStatus 
SecKeychainFindGenericPassword(SecKeychainRef keychainRef
,  UInt32 serviceNameLength
, char *serviceName
, 
 641                                                                                 UInt32 accountNameLength
, char *accountName
, 
 642                                                                                 UInt32 
*passwordLength
, void **passwordData
, SecKeychainItemRef 
*itemRef
) 
 646                 UInt32 attrCount 
= 0; 
 648                 // The number of attributes to search on depends on what was passed in 
 649                 if (serviceName 
&& serviceNameLength
) 
 652                 if (accountName 
&& accountNameLength
) 
 655                 auto_array
<SecKeychainAttribute
> attrs(attrCount
); 
 658                 if (serviceName 
&& serviceNameLength
) 
 660                         attrs
[attrCount
].tag 
= kSecServiceItemAttr
; 
 661                         attrs
[attrCount
].length 
= serviceNameLength
; 
 662                         attrs
[attrCount
].data 
= serviceName
; 
 665                 if (accountName 
&& accountNameLength
) 
 667                         attrs
[attrCount
].tag 
= kSecAccountItemAttr
; 
 668                         attrs
[attrCount
].length 
= accountNameLength
; 
 669                         attrs
[attrCount
].data 
= accountName
; 
 673         SecKeychainAttributeList attrList
; 
 674                 attrList
.count 
= attrCount
; 
 675                 attrList
.attr 
= attrs
.get(); 
 681                         cursor 
= Keychain::optional(keychainRef
)->createCursor(kSecGenericPasswordItemClass
, &attrList
); 
 683                         cursor 
= globals().storageManager
.createCursor(kSecGenericPasswordItemClass
, &attrList
); 
 685                 if (!cursor
->next(item
)) 
 686                         return errSecItemNotFound
; 
 689                 // Get its data (only if necessary) 
 690                 if ( passwordData 
|| passwordLength 
) 
 692                         CssmDataContainer outData
; 
 693                         item
->getData(outData
); 
 694                         *passwordLength
=outData
.length(); 
 696                         *passwordData
=outData
.data(); 
 701                         *itemRef
=ItemRef::handle(item
); 
 707 OSStatus 
SecKeychainLogin(UInt32 nameLength
, void* name
, UInt32 passwordLength
, void* password
) 
 710         globals().storageManager
.login(nameLength
, name
,  passwordLength
, password
); 
 714 OSStatus 
SecKeychainLogout() 
 717         globals().storageManager
.logout(); 
 721 OSStatus 
SecKeychainSetUserInteractionAllowed(Boolean state
)  
 724         globals().setUserInteractionAllowed(state
); 
 729 OSStatus 
SecKeychainGetUserInteractionAllowed(Boolean 
*state
)  
 732         Required(state
)=globals().getUserInteractionAllowed();