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();