2 * Copyright (c) 2000-2002 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.
18 #include <Security/SecKeychainAPIPriv.h>
19 #include <Security/SecKeychain.h>
20 #include <Security/KCCursor.h>
21 #include <Security/cssmdata.h>
22 #include <Security/KCExceptions.h>
23 #include "SecBridge.h"
24 #include "CCallbackMgr.h"
26 #include <Security/ktracecodes.h>
30 SecKeychainGetTypeID(void)
34 secdebug("kc", "SecKeychainGetTypeID()");
35 return gTypes().KeychainImpl
.typeID
;
37 END_SECAPI1(_kCFRuntimeNotATypeID
)
42 SecKeychainGetVersion(UInt32
*returnVers
)
44 secdebug("kc", "SecKeychainGetVersion(%p)", returnVers
);
48 *returnVers
= 0x02028000;
54 SecKeychainOpen(const char *pathName
, SecKeychainRef
*keychainRef
)
58 secdebug("kc", "SecKeychainOpen(\"%s\", %p)", pathName
, keychainRef
);
59 RequiredParam(keychainRef
)=globals().storageManager
.make(pathName
, false)->handle();
66 SecKeychainCreate(const char *pathName
, UInt32 passwordLength
, const void *password
,
67 Boolean promptUser
, SecAccessRef initialAccess
, SecKeychainRef
*keychainRef
)
71 secdebug("kc", "SecKeychainCreate(\"%s\", %lu, %p, %d, %p, %p)", pathName
, passwordLength
, password
, promptUser
, initialAccess
, keychainRef
);
72 KCThrowParamErrIf_(!pathName
);
73 Keychain keychain
= globals().storageManager
.make(pathName
);
75 // @@@ the call to StorageManager::make above leaves keychain the the cache.
76 // If the create below fails we should probably remove it.
81 KCThrowParamErrIf_(!password
);
82 keychain
->create(passwordLength
, password
);
84 RequiredParam(keychainRef
)=keychain
->handle();
91 SecKeychainDelete(SecKeychainRef keychainOrArray
)
95 secdebug("kc", "SecKeychainDelete(%p)", keychainOrArray
);
96 KCThrowIf_(!keychainOrArray
, errSecInvalidKeychain
);
97 StorageManager::KeychainList keychains
;
98 globals().storageManager
.optionalSearchList(keychainOrArray
, keychains
);
99 globals().storageManager
.remove(keychains
, true);
106 SecKeychainSetSettings(SecKeychainRef keychainRef
, const SecKeychainSettings
*newSettings
)
110 secdebug("kc", "SecKeychainSetSettings(%p, %p)", keychainRef
, newSettings
);
111 Keychain keychain
= Keychain::optional(keychainRef
);
112 if (newSettings
->version
==SEC_KEYCHAIN_SETTINGS_VERS1
)
114 UInt32 lockInterval
=newSettings
->lockInterval
;
115 bool lockOnSleep
=newSettings
->lockOnSleep
;
116 keychain
->setSettings(lockInterval
, lockOnSleep
);
124 SecKeychainCopySettings(SecKeychainRef keychainRef
, SecKeychainSettings
*outSettings
)
128 secdebug("kc", "SecKeychainCopySettings(%p, %p)", keychainRef
, outSettings
);
129 Keychain keychain
= Keychain::optional(keychainRef
);
130 if (outSettings
->version
==SEC_KEYCHAIN_SETTINGS_VERS1
)
135 keychain
->getSettings(lockInterval
, lockOnSleep
);
136 outSettings
->lockInterval
=lockInterval
;
137 outSettings
->lockOnSleep
=lockOnSleep
;
145 SecKeychainUnlock(SecKeychainRef keychainRef
, UInt32 passwordLength
, void *password
, Boolean usePassword
)
149 secdebug("kc", "SecKeychainUnlock(%p, %lu, %p, %d)", keychainRef
, passwordLength
, password
, usePassword
);
150 Keychain keychain
= Keychain::optional(keychainRef
);
153 keychain
->unlock(CssmData(password
,passwordLength
));
162 SecKeychainLock(SecKeychainRef keychainRef
)
166 secdebug("kc", "SecKeychainLock(%p)", keychainRef
);
167 Keychain keychain
= Keychain::optional(keychainRef
);
175 SecKeychainLockAll(void)
179 secdebug("kc", "SecKeychainLockAll()");
180 globals().storageManager
.lockAll();
186 OSStatus
SecKeychainResetLogin(UInt32 passwordLength
, const void* password
, Boolean resetSearchList
)
189 KCThrowParamErrIf_(password
==NULL
);
191 // Get the current user (using fallback method if necessary)
193 char* uName
= getenv("USER");
194 string userName
= uName
? uName
: "";
195 if ( userName
.length() == 0 )
197 uid_t uid
= geteuid();
198 if (!uid
) uid
= getuid();
199 struct passwd
*pw
= getpwuid(uid
); // fallback case...
201 userName
= pw
->pw_name
;
204 if ( userName
.length() == 0 ) // did we ultimately get one?
205 MacOSError::throwMe(errAuthorizationInternal
);
207 // Clears the plist and moves aside (renames) an existing login.keychain
209 globals().storageManager
.resetKeychain(resetSearchList
);
211 // Creates a login keychain and sets it to the default.
213 globals().storageManager
.login(userName
.length(), userName
.c_str(), passwordLength
, password
);
214 Keychain keychain
= globals().storageManager
.loginKeychain();
215 globals().storageManager
.defaultKeychain(keychain
);
220 SecKeychainCopyDefault(SecKeychainRef
*keychainRef
)
224 secdebug("kc", "SecKeychainCopyDefault(%p)", keychainRef
);
225 RequiredParam(keychainRef
)=globals().storageManager
.defaultKeychain()->handle();
232 SecKeychainSetDefault(SecKeychainRef keychainRef
)
236 secdebug("kc", "SecKeychainSetDefault(%p)", keychainRef
);
237 globals().storageManager
.defaultKeychain(Keychain::optional(keychainRef
));
242 OSStatus
SecKeychainCopySearchList(CFArrayRef
*searchList
)
246 secdebug("kc", "SecKeychainCopySearchList(%p)", searchList
);
247 RequiredParam(searchList
);
248 StorageManager
&smr
= globals().storageManager
;
249 StorageManager::KeychainList keychainList
;
250 smr
.getSearchList(keychainList
);
251 *searchList
= smr
.convertFromKeychainList(keychainList
);
256 OSStatus
SecKeychainSetSearchList(CFArrayRef searchList
)
260 secdebug("kc", "SecKeychainSetSearchList(%p)", searchList
);
261 RequiredParam(searchList
);
262 StorageManager
&smr
= globals().storageManager
;
263 StorageManager::KeychainList keychainList
;
264 smr
.convertToKeychainList(searchList
, keychainList
);
265 smr
.setSearchList(keychainList
);
270 OSStatus
SecKeychainCopyDomainDefault(SecPreferencesDomain domain
, SecKeychainRef
*keychainRef
)
274 secdebug("kc", "SecKeychainCopyDefault(%p)", keychainRef
);
275 RequiredParam(keychainRef
)=globals().storageManager
.defaultKeychain(domain
)->handle();
280 OSStatus
SecKeychainSetDomainDefault(SecPreferencesDomain domain
, SecKeychainRef keychainRef
)
284 secdebug("kc", "SecKeychainSetDefault(%p)", keychainRef
);
285 globals().storageManager
.defaultKeychain(domain
, Keychain::optional(keychainRef
));
290 OSStatus
SecKeychainCopyDomainSearchList(SecPreferencesDomain domain
, CFArrayRef
*searchList
)
294 secdebug("kc", "SecKeychainCopyDomainSearchList(%p)", searchList
);
295 RequiredParam(searchList
);
296 StorageManager
&smr
= globals().storageManager
;
297 StorageManager::KeychainList keychainList
;
298 smr
.getSearchList(domain
, keychainList
);
299 *searchList
= smr
.convertFromKeychainList(keychainList
);
304 OSStatus
SecKeychainSetDomainSearchList(SecPreferencesDomain domain
, CFArrayRef searchList
)
308 secdebug("kc", "SecKeychainSetDomainSearchList(%p)", searchList
);
309 RequiredParam(searchList
);
310 StorageManager
&smr
= globals().storageManager
;
311 StorageManager::KeychainList keychainList
;
312 smr
.convertToKeychainList(searchList
, keychainList
);
313 smr
.setSearchList(domain
, keychainList
);
318 OSStatus
SecKeychainSetPreferenceDomain(SecPreferencesDomain domain
)
322 globals().storageManager
.domain(domain
);
327 OSStatus
SecKeychainGetPreferenceDomain(SecPreferencesDomain
*domain
)
331 *domain
= globals().storageManager
.domain();
338 SecKeychainGetStatus(SecKeychainRef keychainRef
, SecKeychainStatus
*keychainStatus
)
342 secdebug("kc", "SecKeychainGetStatus(%p): %p", keychainRef
, keychainStatus
);
343 RequiredParam(keychainStatus
) = (SecKeychainStatus
)Keychain::optional(keychainRef
)->status();
350 SecKeychainGetPath(SecKeychainRef keychainRef
, UInt32
*ioPathLength
, char *pathName
)
354 secdebug("kc", "SecKeychainGetPath(%p, %p, %p)", keychainRef
, ioPathLength
, pathName
);
355 RequiredParam(pathName
);
356 RequiredParam(ioPathLength
);
358 const char *name
= Keychain::optional(keychainRef
)->name();
359 UInt32 nameLen
= strlen(name
);
360 if (nameLen
+1 > *ioPathLength
) // if the client's buffer is too small (including null-termination), throw
361 CssmError::throwMe(CSSMERR_CSSM_BUFFER_TOO_SMALL
);
362 strncpy(pathName
, name
, nameLen
);
363 pathName
[nameLen
] = 0;
364 *ioPathLength
= nameLen
; // set the length.
372 SecKeychainListGetCount(void)
376 secdebug("kc", "SecKeychainListGetCount()");
377 return globals().storageManager
.size();
385 SecKeychainListCopyKeychainAtIndex(UInt16 index
, SecKeychainRef
*keychainRef
)
389 secdebug("kc", "SecKeychainListCopyKeychainAtIndex(%d, %p)", index
, keychainRef
);
390 KeychainCore::StorageManager
&smgr
=KeychainCore::globals().storageManager
;
391 RequiredParam(keychainRef
)=smgr
[index
]->handle();
399 SecKeychainListRemoveKeychain(SecKeychainRef
*keychainRef
)
403 secdebug("kc", "SecKeychainListRemoveKeychain(%p)", keychainRef
);
404 Required(keychainRef
);
405 Keychain keychain
= Keychain::optional(*keychainRef
);
406 StorageManager::KeychainList keychainList
;
407 keychainList
.push_back(keychain
);
408 globals().storageManager
.remove(keychainList
);
416 SecKeychainAttributeInfoForItemID(SecKeychainRef keychainRef
, UInt32 itemID
, SecKeychainAttributeInfo
**info
)
420 secdebug("kc", "SecKeychainAttributeInfoForItemID(%p, %lu, %p)", keychainRef
, itemID
, info
);
421 Keychain keychain
= Keychain::optional(keychainRef
);
422 keychain
->getAttributeInfoForItemID(itemID
, info
);
429 SecKeychainFreeAttributeInfo(SecKeychainAttributeInfo
*info
)
433 secdebug("kc", "SecKeychainFreeAttributeInfo(%p)", info
);
434 KeychainImpl::freeAttributeInfo(info
);
441 SecKeychainAddCallback(SecKeychainCallback callbackFunction
, SecKeychainEventMask eventMask
, void* userContext
)
445 secdebug("kc", "SecKeychainAddCallback(%p, %08lx, %p)", callbackFunction
, eventMask
, userContext
);
446 RequiredParam(callbackFunction
);
447 CCallbackMgr::AddCallback(callbackFunction
,eventMask
,userContext
);
454 SecKeychainRemoveCallback(SecKeychainCallback callbackFunction
)
458 secdebug("kc", "SecKeychainRemoveCallback(%p)", callbackFunction
);
459 RequiredParam(callbackFunction
);
460 CCallbackMgr::RemoveCallback(callbackFunction
);
466 SecKeychainAddInternetPassword(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
)
470 secdebug("kc", "SecKeychainAddInternetPassword(%p)", keychainRef
);
471 KCThrowParamErrIf_(passwordLength
!=0 && passwordData
==NULL
);
472 // @@@ Get real itemClass
473 Item
item(kSecInternetPasswordItemClass
, 'aapl', passwordLength
, passwordData
);
475 if (serverName
&& serverNameLength
)
477 CssmData
server(const_cast<void *>(reinterpret_cast<const void *>(serverName
)), serverNameLength
);
478 item
->setAttribute(Schema::attributeInfo(kSecServerItemAttr
), server
);
479 // use server name as default label
480 item
->setAttribute(Schema::attributeInfo(kSecLabelItemAttr
), server
);
483 if (accountName
&& accountNameLength
)
485 CssmData
account(const_cast<void *>(reinterpret_cast<const void *>(accountName
)), accountNameLength
);
486 item
->setAttribute(Schema::attributeInfo(kSecAccountItemAttr
), account
);
489 if (securityDomain
&& securityDomainLength
)
490 item
->setAttribute(Schema::attributeInfo(kSecSecurityDomainItemAttr
),
491 CssmData(const_cast<void *>(reinterpret_cast<const void *>(securityDomain
)), securityDomainLength
));
493 item
->setAttribute(Schema::attributeInfo(kSecPortItemAttr
), UInt32(port
));
494 item
->setAttribute(Schema::attributeInfo(kSecProtocolItemAttr
), protocol
);
495 item
->setAttribute(Schema::attributeInfo(kSecAuthenticationTypeItemAttr
), authenticationType
);
497 if (path
&& pathLength
)
498 item
->setAttribute(Schema::attributeInfo(kSecPathItemAttr
),
499 CssmData(const_cast<void *>(reinterpret_cast<const void *>(path
)), pathLength
));
501 Keychain keychain
= nil
;
504 keychain
= Keychain::optional(keychainRef
);
505 if ( !keychain
->exists() )
507 MacOSError::throwMe(errSecNoSuchKeychain
); // Might be deleted or not available at this time.
512 keychain
= globals().storageManager
.defaultKeychainUI(item
);
518 *itemRef
= item
->handle();
525 SecKeychainFindInternetPassword(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
)
530 secdebug("kc", "SecKeychainFindInternetPassword(%p)", keychainOrArray
);
531 StorageManager::KeychainList keychains
;
532 globals().storageManager
.optionalSearchList(keychainOrArray
, keychains
);
533 KCCursor
cursor(keychains
, kSecInternetPasswordItemClass
, NULL
);
535 if (serverName
&& serverNameLength
)
537 cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecServerItemAttr
),
538 CssmData(const_cast<char *>(serverName
), serverNameLength
));
541 if (securityDomain
&& securityDomainLength
)
543 cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecSecurityDomainItemAttr
),
544 CssmData (const_cast<char*>(securityDomain
), securityDomainLength
));
547 if (accountName
&& accountNameLength
)
549 cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecAccountItemAttr
),
550 CssmData (const_cast<char*>(accountName
), accountNameLength
));
555 cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecPortItemAttr
),
561 cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecProtocolItemAttr
),
565 if (authenticationType
)
567 cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecAuthenticationTypeItemAttr
),
571 if (path
&& pathLength
)
573 cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecPathItemAttr
), path
);
577 if (!cursor
->next(item
))
578 return errSecItemNotFound
;
580 // Get its data (only if necessary)
581 if (passwordData
|| passwordLength
)
583 CssmDataContainer outData
;
584 item
->getData(outData
);
585 *passwordLength
=outData
.length();
587 *passwordData
=outData
.data();
592 *itemRef
=item
->handle();
599 SecKeychainAddGenericPassword(SecKeychainRef keychainRef
, UInt32 serviceNameLength
, const char *serviceName
, UInt32 accountNameLength
, const char *accountName
, UInt32 passwordLength
, const void *passwordData
, SecKeychainItemRef
*itemRef
)
603 secdebug("kc", "SecKeychainAddGenericPassword(%p)", keychainRef
);
604 KCThrowParamErrIf_(passwordLength
!=0 && passwordData
==NULL
);
605 // @@@ Get real itemClass
606 Item
item(kSecGenericPasswordItemClass
, 'aapl', passwordLength
, passwordData
);
608 if (serviceName
&& serviceNameLength
)
610 CssmData
service(const_cast<void *>(reinterpret_cast<const void *>(serviceName
)), serviceNameLength
);
611 item
->setAttribute(Schema::attributeInfo(kSecServiceItemAttr
), service
);
612 // use service name as default label
613 item
->setAttribute(Schema::attributeInfo(kSecLabelItemAttr
), service
);
616 if (accountName
&& accountNameLength
)
618 CssmData
account(const_cast<void *>(reinterpret_cast<const void *>(accountName
)), accountNameLength
);
619 item
->setAttribute(Schema::attributeInfo(kSecAccountItemAttr
), account
);
622 Keychain keychain
= nil
;
625 keychain
= Keychain::optional(keychainRef
);
626 if ( !keychain
->exists() )
628 MacOSError::throwMe(errSecNoSuchKeychain
); // Might be deleted or not available at this time.
633 keychain
= globals().storageManager
.defaultKeychainUI(item
);
638 *itemRef
= item
->handle();
645 SecKeychainFindGenericPassword(CFTypeRef keychainOrArray
, UInt32 serviceNameLength
, const char *serviceName
, UInt32 accountNameLength
, const char *accountName
, UInt32
*passwordLength
, void **passwordData
, SecKeychainItemRef
*itemRef
)
648 Debug::trace (kSecTraceSecurityFrameworkSecKeychainFindGenericPasswordBegin
);
652 secdebug("kc", "SecKeychainFindGenericPassword(%p)", keychainOrArray
);
653 StorageManager::KeychainList keychains
;
654 globals().storageManager
.optionalSearchList(keychainOrArray
, keychains
);
655 KCCursor
cursor(keychains
, kSecGenericPasswordItemClass
, NULL
);
657 if (serviceName
&& serviceNameLength
)
659 cursor
->add (CSSM_DB_EQUAL
, Schema::attributeInfo(kSecServiceItemAttr
),
660 const_cast<char*>(serviceName
));
663 if (accountName
&& accountNameLength
)
665 cursor
->add (CSSM_DB_EQUAL
, Schema::attributeInfo(kSecAccountItemAttr
),
666 const_cast<char*>(accountName
));
670 if (!cursor
->next(item
))
671 return errSecItemNotFound
;
673 // Get its data (only if necessary)
674 if (passwordData
|| passwordLength
)
676 CssmDataContainer outData
;
677 item
->getData(outData
);
678 *passwordLength
=outData
.length();
680 *passwordData
=outData
.data();
685 *itemRef
=item
->handle();
692 SecKeychainSetUserInteractionAllowed(Boolean state
)
696 secdebug("kc", "SecKeychainSetUserInteractionAllowed(%d)", state
);
697 globals().setUserInteractionAllowed(state
);
704 SecKeychainGetUserInteractionAllowed(Boolean
*state
)
708 secdebug("kc", "SecKeychainGetUserInteractionAllowed()");
709 Required(state
)=globals().getUserInteractionAllowed();
716 SecKeychainGetDLDBHandle(SecKeychainRef keychainRef
, CSSM_DL_DB_HANDLE
*dldbHandle
)
720 secdebug("kc", "SecKeychainGetDLDBHandle(%p, %p)", keychainRef
, dldbHandle
);
721 RequiredParam(dldbHandle
);
723 Keychain keychain
= Keychain::optional(keychainRef
);
724 *dldbHandle
= keychain
->database()->handle();
731 SecKeychainGetCSPHandle(SecKeychainRef keychainRef
, CSSM_CSP_HANDLE
*cspHandle
)
735 secdebug("kc", "SecKeychainGetCSPHandle(%p, %p)", keychainRef
, cspHandle
);
736 RequiredParam(cspHandle
);
738 Keychain keychain
= Keychain::optional(keychainRef
);
739 *cspHandle
= keychain
->csp()->handle();
746 SecKeychainCopyAccess(SecKeychainRef keychainRef
, SecAccessRef
*accessRef
)
750 secdebug("kc", "SecKeychainCopyAccess(%p, %p)", keychainRef
, accessRef
);
751 MacOSError::throwMe(unimpErr
);//%%%for now
758 SecKeychainSetAccess(SecKeychainRef keychainRef
, SecAccessRef accessRef
)
762 secdebug("kc", "SecKeychainSetAccess(%p, %p)", keychainRef
, accessRef
);
763 MacOSError::throwMe(unimpErr
);//%%%for now
769 #pragma mark ---- Private API ----
773 SecKeychainChangePassword(SecKeychainRef keychainRef
, UInt32 oldPasswordLength
, const void *oldPassword
, UInt32 newPasswordLength
, const void *newPassword
)
777 secdebug("kc", "SecKeychainChangePassword(%p, %lu, %p, %lu, %p)", keychainRef
,
778 oldPasswordLength
, oldPassword
, newPasswordLength
, newPassword
);
779 Keychain keychain
= Keychain::optional(keychainRef
);
780 keychain
->changePassphrase (oldPasswordLength
, oldPassword
, newPasswordLength
, newPassword
);
787 SecKeychainCopyLogin(SecKeychainRef
*keychainRef
)
791 secdebug("kc", "SecKeychainCopyLogin(%p)", keychainRef
);
792 RequiredParam(keychainRef
)=globals().storageManager
.loginKeychain()->handle();
799 SecKeychainLogin(UInt32 nameLength
, void* name
, UInt32 passwordLength
, void* password
)
803 secdebug("kc", "SecKeychainLogin(%lu, %p, %lu, %p)", nameLength
, name
, passwordLength
, password
);
804 globals().storageManager
.login(nameLength
, name
, passwordLength
, password
);
815 secdebug("kc", "SecKeychainLogout()");
816 globals().storageManager
.logout();
821 static CFStringRef
copyErrorMessageFromBundle(OSStatus status
,CFStringRef tableName
);
823 // caller MUST release the string, since it is gotten with "CFCopyLocalizedStringFromTableInBundle"
824 // intended use of reserved param is to pass in CFStringRef with name of the Table for lookup
825 // Will look by default in "SecErrorMessages.strings" in the resources of Security.framework.
828 CFStringRef
SecCopyErrorMessageString(OSStatus status
, void *reserved
)
832 return copyErrorMessageFromBundle(status
,CFSTR("SecErrorMessages"));
837 CFStringRef
copyErrorMessageFromBundle(OSStatus status
,CFStringRef tableName
)
839 CFStringRef errorString
= nil
;
840 CFStringRef keyString
= nil
;
841 CFURLRef bundleURL
= NULL
;
842 CFBundleRef secBundle
= NULL
;
844 // Make a CFURLRef from the CFString representation of the bundleĆs path.
845 bundleURL
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
,
846 CFSTR("/System/Library/Frameworks/Security.framework/"),kCFURLPOSIXPathStyle
,true); // Resources/
850 // Make a bundle instance using the URLRef.
851 secBundle
= CFBundleCreate(kCFAllocatorDefault
,bundleURL
);
855 // Convert status to Int32 string representation, e.g. "-25924"
856 keyString
= CFStringCreateWithFormat (kCFAllocatorDefault
,NULL
,CFSTR("%d"),status
);
860 errorString
= CFCopyLocalizedStringFromTableInBundle(keyString
,tableName
,secBundle
,NULL
);
864 CFRelease(bundleURL
);
866 CFRelease(secBundle
);
868 CFRelease(keyString
);