22 #include <sys/param.h> 24 #include <QtGui/QApplication> 25 #include <QtCore/QtCore> 26 #include <QtCore/QPointer> 27 #include <QtGui/QWidget> 34 #include <CoreServices/CoreServices.h> 37 #define INTERNET_TOO 0 45 static QString
OSTStr( FourCharCode etype )
51 } __attribute__ ((packed)) value;
52 char representation[7];
53 } __attribute__ ((packed)) ltype;
54 ltype.value.four = EndianU32_BtoN(etype);
55 ltype.representation[0] = ltype.representation[5] =
'\'';
56 ltype.representation[6] =
'\0';
57 return QString::fromAscii(ltype.representation);
62 SecKeychainRef keychain;
63 if(
isError( SecKeychainCopyDefault(&keychain), &errMsg ) ){
64 kWarning() <<
"Could not retrieve reference to default keychain:" << qPrintable(errMsg);
74 static QString
keyChainName( SecKeychainRef keychain, QString *path=NULL )
77 int ext = p.lastIndexOf(
".keychain");
78 keyFile = QFileInfo( ((ext > 0)? p.left(ext) : p) );
82 return keyFile.fileName();
91 static OSStatus
openKeychain(
const QString &n, SecKeychainRef *keychain )
93 CFArrayRef list = NULL;
96 err = SecKeychainCopySearchList( &list );
98 CFIndex len = CFArrayGetCount(list), i;
99 for( i = 0 ; i < len && !*keychain ; ++i ){
100 SecKeychainRef kr = (SecKeychainRef) CFArrayGetValueAtIndex( list, i );
104 err = SecKeychainOpen( path.toUtf8(), keychain );
106 kWarning() <<
"openKeychain(" << n <<
") error" << err <<
"opening matching" << path;
109 kDebug() <<
"openKeychain(" << n <<
") opened matching" << path;
116 err = SecKeychainOpen( n.toUtf8(), keychain );
121 SecKeychainStatus status;
122 err = SecKeychainGetStatus( *keychain, &status );
127 static OSStatus
basicWriteItem(
const QByteArray *serviceName,
const QByteArray &accountName,
const QByteArray &value,
128 const SecKeychainRef keychain, SecKeychainItemRef *itemRef=NULL )
132 err = SecKeychainAddGenericPassword( keychain, serviceName->size(), serviceName->constData(),
133 accountName.size(), accountName.constData(),
134 value.size(), value.constData(), itemRef );
137 err = SecKeychainAddGenericPassword( keychain, 0, NULL,
138 accountName.size(), accountName.constData(),
139 value.size(), value.constData(), itemRef );
141 if( err != errSecDuplicateItem &&
isError( err, &errMsg ) ){
142 kWarning() <<
"Could not store password in keychain: " << qPrintable(errMsg);
153 kDebug() <<
"Retrieved reference to default keychain" << (
void*) keyChainRef <<
"in " << keyChainPath;
155 isDefaultKeychain =
true;
158 keyChainPath = QString::fromUtf8(
"<undefined>");
169 if( err == errSecNoSuchKeychain ){
170 kWarning() <<
"Keychain '" << n <<
"' does not exist: attempting to create it";
171 err = SecKeychainCreate( n.toUtf8(), 0, NULL,
true, NULL, &keyChainRef );
178 kWarning() <<
"Error opening keychain '" << n <<
"' (falling back to default keychain): " << qPrintable(errMsg);
180 isDefaultKeychain =
true;
183 isDefaultKeychain =
false;
188 kDebug() <<
"Retrieved reference to keychain" <<
name << (
void*) keyChainRef <<
"in " << keyChainPath;
191 keyChainPath = QString::fromUtf8(
"<undefined>");
200 CFRelease(keyChainRef);
212 SecKeychainItemRef itemRef = NULL;
214 if( !err && itemRef ){
215 const QByteArray accountName( newKey.toUtf8() );
217 SecKeychainAttribute attr[] = { { kSecAccountItemAttr, accountName.size(), (
void*) accountName.constData() },
218 { kSecLabelItemAttr, accountName.size(), (
void*) accountName.constData() } };
219 SecKeychainAttributeList attrList = { 2, &attr[0] };
221 if(
isError( (err = SecKeychainItemModifyAttributesAndData( itemRef, &attrList, 0, NULL )), &errMsg ) ){
222 kWarning() <<
"OSXKeychain::renameItem(" <<
currentKey <<
") couldn't change name & label to" << accountName
223 <<
":" << err <<
"=" << qPrintable(errMsg);
230 #pragma mark ========= static member functions ========= 233 { CFArrayRef list = NULL;
234 OSStatus err = SecKeychainCopySearchList( &list );
237 CFIndex len = CFArrayGetCount(list), i;
238 for( i = 0 ; i < len ; ++i ){
239 SecKeychainRef keychain = (SecKeychainRef) CFArrayGetValueAtIndex( list, i );
241 if(
name.size() > 0 ){
242 theList.append(
name);
251 {
char pathName[MAXPATHLEN];
252 UInt32 plen = MAXPATHLEN;
253 if( SecKeychainGetPath( (keychain)? keychain :
OSXKeychain().
reference(), &plen, pathName ) == errSecSuccess ){
254 return QString::fromUtf8(pathName);
263 SecKeychainStatus status;
265 if(
isError( SecKeychainGetStatus( keychain, &status ), &errMsg ) ){
267 kDebug() <<
"Could not get the status of keychain" <<
OSXKeychain::Path(keychain) <<
":" << qPrintable(errMsg);
270 kWarning() <<
"Could not get the default keychain's status:" << qPrintable(errMsg);
274 if( (status & kSecUnlockStateStatus) && (status & kSecReadPermStatus) ){
285 { SecKeychainRef keychain = NULL;
286 OSStatus err =
openKeychain( walletName.toUtf8(), &keychain );
288 if( !err && keychain ){
298 err = SecKeychainUnlock( keychain, 0, NULL,
false );
301 kDebug() <<
"Could not unlock the keychain at '" <<
OSXKeychain::Path(keychain) <<
"': " << qPrintable(errMsg);
304 kDebug() <<
"Could not unlock the default keychain:" << qPrintable(errMsg);
314 err = SecKeychainLock(keychain);
320 err = SecKeychainLockAll();
322 kDebug() <<
"Could not lock all keychains:" << qPrintable(errMsg);
329 { SecKeychainRef keychain = NULL;
331 if( !err && keychain ){
332 err =
Lock(keychain);
344 const SecKeychainRef keychain, OSStatus *errReturn, SecKeychainItemRef *itemRef)
345 {
const QByteArray accountName( key.toUtf8() );
347 SecKeychainSearchRef searchRef;
348 SecKeychainAttribute attrs = { kSecAccountItemAttr, accountName.size(), (
void*) accountName.constData() };
349 SecKeychainAttributeList attrList = { 1, &attrs };
350 err = SecKeychainSearchCreateFromAttributes( keychain, kSecGenericPasswordItemClass,
351 (
const SecKeychainAttributeList*) &attrList, &searchRef );
352 const CFReleaser<SecKeychainSearchRef> releaseSR(searchRef);
354 SecKeychainItemRef item;
359 kDebug() <<
"OSXKeychain::HasItem(" << key <<
"," << (
void*) keychain <<
"): SecKeychainSearchCreateFromAttributes failed";
362 if( !(err = SecKeychainSearchCopyNext( searchRef, &item )) ){
380 kDebug() << ((found)?
"Found" :
"Did not find") <<
"item '" << key <<
"' in keychain " << (
void*) keychain <<
", error=" << err <<
" " << qPrintable(errMsg);
385 const SecKeychainRef keychain, SecKeychainItemRef *itemRef,
OSXKeychain *osxKeyChain)
386 {
const QByteArray accountName( key.toUtf8() );
387 UInt32 passwordSize = 0;
388 void* passwordData = 0;
390 SecKeychainItemRef theItem;
391 OSStatus err = SecKeychainFindGenericPassword( keychain, 0, NULL,
392 accountName.size(), accountName.constData(),
393 &passwordSize, &passwordData, &theItem );
395 kDebug() <<
"Error" << err <<
"retrieving password for '" << accountName <<
"' :" << qPrintable(errMsg);
397 if( SecKeychainFindInternetPassword( keychain, 0, NULL,
399 accountName.size(), accountName.constData(),
401 kSecProtocolTypeAny, kSecAuthenticationTypeDefault,
402 &passwordSize, &passwordData, &theItem ) ){
414 if( !err && theItem ){
416 *value = QByteArray( reinterpret_cast<const char*>( passwordData ), passwordSize );
418 SecKeychainItemFreeContent( NULL, passwordData );
420 SecKeychainAttribute attr = { kSecServiceItemAttr, 0, NULL };
421 SecKeychainAttributeList attrList = { 1, &attr };
424 if( !SecKeychainItemCopyContent( theItem, NULL, &attrList, &len, NULL ) ){
425 if( attr.length > 0 ){
427 osxKeyChain->
lastReadService = QString::fromUtf8( (
char*)attr.data, attr.length );
429 SecKeychainItemFreeContent( &attrList, NULL );
439 kDebug() <<
"OSXKeychain::ReadItem '" << key <<
"' from keychain " <<
OSXKeychain::Path(keychain) <<
", error=" << err;
444 const SecKeychainRef keychain)
445 {
const QByteArray accountName( key.toUtf8() );
448 SecKeychainItemRef itemRef;
450 bool isInternetPW =
false;
452 OSStatus err = SecKeychainFindGenericPassword( keychain, 0, NULL,
453 accountName.size(), accountName.constData(),
454 NULL, NULL, &itemRef );
456 kDebug() <<
"Error" << err <<
"retrieving type for '" << accountName <<
"' :" << qPrintable(errMsg);
458 if( SecKeychainFindInternetPassword( keychain, 0, NULL,
460 accountName.size(), accountName.constData(),
462 kSecProtocolTypeAny, kSecAuthenticationTypeDefault,
463 0, NULL, &itemRef ) ){
477 UInt32 tags[] = { kSecTypeItemAttr };
478 UInt32 formats[] = { CSSM_DB_ATTRIBUTE_FORMAT_STRING };
479 SecKeychainAttributeInfo attrGet = { 1, tags, formats };
480 SecKeychainAttributeList *attrList = NULL;
481 err = SecKeychainItemCopyAttributesAndData( itemRef, &attrGet, NULL, &attrList, NULL, NULL );
483 if( attrList->attr[0].length ==
sizeof(
EntryType) ){
484 memcpy( &etype, attrList->attr[0].data,
sizeof(
EntryType) );
486 else if( attrList->attr[0].length ){
487 kDebug() <<
"Error: key" << key <<
"item type retrieved is of size" << attrList->attr[0].length <<
"!=" <<
sizeof(
EntryType);
490 else if( isInternetPW ){
499 SecKeychainItemFreeAttributesAndData( attrList, NULL );
502 kDebug() <<
"OSXKeychain::ItemType '" << key <<
"' from keychain " <<
OSXKeychain::Path(keychain) <<
"=" <<
OSTStr(etype) <<
", error=" << err;
507 {
const QByteArray accountName( key.toUtf8() );
508 SecKeychainItemRef itemRef;
510 OSStatus result = SecKeychainFindGenericPassword( keychain, 0, NULL,
511 accountName.size(), accountName.constData(), NULL, NULL, &itemRef );
512 if(
isError( result, &errMsg ) ){
513 kDebug() <<
"Could not find entry" << key <<
":" << qPrintable(errMsg);
516 const CFReleaser<SecKeychainItemRef> itemReleaser(itemRef);
517 result = SecKeychainItemDelete(itemRef);
518 if(
isError( result, &errMsg ) ){
519 kWarning() <<
"Could not delete entry" << key <<
":" << qPrintable(errMsg);
526 const SecKeychainRef keychain, SecKeychainItemRef *itemRef,
EntryType *entryType,
OSXKeychain *osxKeyChain )
527 {
const QByteArray accountName( key.toUtf8() );
530 SecKeychainItemRef theItem = NULL;
533 const QByteArray serviceName( osxKeyChain->
currentService.toUtf8() );
536 err =
basicWriteItem( &serviceName, accountName, value, keychain, &theItem );
542 err =
basicWriteItem( NULL, accountName, value, keychain, &theItem );
545 if( err == errSecDuplicateItem ){
548 if( !(err =
ReadItem( key, NULL, keychain, &theItem )) ){
549 err = SecKeychainItemModifyAttributesAndData( theItem, NULL, value.size(), value.constData() );
551 kDebug() <<
"Key '" << key
552 <<
"'already exists in keychain but error modifying the existing item: " << qPrintable(errMsg);
556 kDebug() <<
"Key '" << key <<
"'already existed in keychain: modified the existing item";
559 if( !err && saveLabel ){
561 SecKeychainAttribute attr = { kSecLabelItemAttr, accountName.size(), (
void*) accountName.constData() };
562 SecKeychainAttributeList attrList = { 1, &attr };
564 if(
isError( (err = SecKeychainItemModifyAttributesAndData( theItem, &attrList, 0, NULL )), &errMsg ) ){
565 kWarning() <<
"OSXKeychain::WriteItem(" << key <<
") couldn't set the desired name/label" << accountName
566 <<
":" << err <<
"=" << qPrintable(errMsg);
572 entryType = &defType;
574 SecKeychainAttribute attr = { kSecTypeItemAttr,
sizeof(
EntryType), (
void*) entryType };
575 SecKeychainAttributeList attrList = { 1, &attr };
577 if(
isError( (err = SecKeychainItemModifyAttributesAndData( theItem, &attrList, 0, NULL )), &errMsg ) ){
578 kWarning() <<
"OSXKeychain::WriteItem(" << key <<
") couldn't set type to" <<
OSTStr(*entryType)
579 <<
":" << qPrintable(errMsg);
588 kDebug() <<
"OSXKeychain::WriteItem '" << key <<
"' to keychain " << (
void*) keychain <<
", error=" << err;
593 const QString &comment,
const SecKeychainRef keychain,
EntryType *entryType,
OSXKeychain *osxKeyChain )
594 { SecKeychainItemRef itemRef = NULL;
595 OSStatus err =
WriteItem( key, value, keychain, &itemRef, entryType, osxKeyChain );
596 if( !err && itemRef ){
597 const QByteArray commentString(comment.toUtf8());
598 if( commentString.size() ){
599 SecKeychainAttribute attr = { kSecCommentItemAttr, commentString.size(), (
void*) commentString.constData() };
600 SecKeychainAttributeList attrList = { 1, &attr };
602 if(
isError( (err = SecKeychainItemModifyAttributesAndData( itemRef, &attrList, 0, NULL )), &errMsg ) ){
603 kWarning() <<
"OSXKeychain::WriteItem(" << key <<
") couldn't add comment" << comment
604 <<
":" << qPrintable(errMsg);
615 SecKeychainSearchRef searchRef[2];
616 bool generateFolderList = ( osxKeyChain && osxKeyChain->
isKDEChain && osxKeyChain->generateFolderList );
619 if( generateFolderList ){
626 err = SecKeychainSearchCreateFromAttributes( keychain, kSecGenericPasswordItemClass, NULL, &searchRef[0] );
628 if( SecKeychainSearchCreateFromAttributes( keychain, kSecInternetPasswordItemClass, NULL, &searchRef[1] ) ){
634 SecKeychainItemRef item;
637 kDebug() <<
"OSXKeychain::ItemList(" << (
void*) keychain <<
"): SecKeychainSearchCreateFromAttributes failed" << qPrintable(errMsg);
640 for(
size_t i = 0 ; i <
sizeof(searchRef)/
sizeof(SecKeychainSearchRef) && !err ; ++i ){
642 while( !(err = SecKeychainSearchCopyNext( searchRef[i], &item )) ){
646 bool listItem =
true;
647 SecKeychainAttribute attr = { kSecAccountItemAttr, 0, NULL };
648 SecKeychainAttributeList attrList = { 1, &attr };
652 attr.tag = kSecServiceItemAttr;
653 if( !SecKeychainItemCopyContent( item, NULL, &attrList, &len, NULL ) ){
654 QString lbl = QString::fromUtf8( (
char*)attr.data, attr.length );
658 if( generateFolderList ){
668 SecKeychainItemFreeContent( &attrList, NULL );
675 attr.tag = kSecAccountItemAttr;
676 if( !(err = SecKeychainItemCopyContent( item, NULL, &attrList, &len, NULL )) ){
677 if( attr.length > 0 ){
678 keyList.append(QString::fromUtf8( (
char*)attr.data, attr.length ));
680 SecKeychainItemFreeContent( &attrList, NULL );
684 kDebug() <<
"SecKeychainItemCopyContent returned" << err <<
"=" << qPrintable(errMsg);
693 CFRelease(searchRef[i]);
701 { OSStatus err = SecKeychainDelete(*keychain);
704 kWarning() <<
"OSXKeychain::Destroy " << (
void*) *keychain <<
", error " << qPrintable(errMsg);
707 kWarning() <<
"OSXKeychain::Destroy " << (
void*) *keychain <<
", error=" << err;
710 CFRelease(*keychain);
717 { SecKeychainRef keychain;
719 if( !err && keychain ){
static QString OSTStr(FourCharCode etype)
static OSStatus RemoveItem(const QString &key, const SecKeychainRef keychain)
static QString errorString(OSStatus s)
static bool isError(OSStatus s, QString *errMsg)
static OSStatus Destroy(SecKeychainRef *keychain)
static OSStatus basicWriteItem(const QByteArray *serviceName, const QByteArray &accountName, const QByteArray &value, const SecKeychainRef keychain, SecKeychainItemRef *itemRef=NULL)
static const char * currentKey
static QString Path(const SecKeychainRef keychain)
static bool HasItem(const QString &key, const SecKeychainRef keychain, OSStatus *errReturn, SecKeychainItemRef *itemRef)
use the keychain search functions to find the first matching item, if any, returning True if found...
const char * name(StandardAction id)
This will return the internal name of a given standard action.
static OSStatus openKeychain(const QString &n, SecKeychainRef *keychain)
static QDebug kDebug(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
OSStatus renameItem(const QString ¤tKey, const QString &newKey)
static OSStatus UnLock(const SecKeychainRef keychain)
static OSStatus Lock(const SecKeychainRef keychain)
static bool IsOpen(const SecKeychainRef keychain)
static QString keyChainName(SecKeychainRef keychain, QString *path=NULL)
static OSStatus WriteItem(const QString &key, const QByteArray &value, const SecKeychainRef keychain, SecKeychainItemRef *itemRef=NULL, EntryType *entryType=NULL, OSXKeychain *osxKeyChain=NULL)
static OSStatus ItemType(const QString &key, EntryType *entryType, const SecKeychainRef keychain)
static SecKeychainRef defaultChain()
static OSStatus KeychainList(QStringList &theList)
SecKeychainRef reference()
static OSStatus ItemList(const SecKeychainRef keychain, QStringList &keyList, OSXKeychain *osxKeyChain=NULL)
static OSStatus ReadItem(const QString &key, QByteArray *value, const SecKeychainRef keychain, SecKeychainItemRef *itemRef=NULL, OSXKeychain *osxKeyChain=NULL)
static QDebug kWarning(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)