KDEUI
kwallet_mac.cpp
Go to the documentation of this file.
00001 /* This file is part of the KDE project 00002 * 00003 * Copyright (C) 2002-2004 George Staikos <staikos@kde.org> 00004 * Copyright (C) 2008 Michael Leupold <lemma@confuego.org> 00005 * Copyright (C) 2010 Frank Osterfeld <osterfeld@kde.org> 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Library General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Library General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Library General Public License 00018 * along with this library; see the file COPYING.LIB. If not, write to 00019 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00020 * Boston, MA 02110-1301, USA. 00021 */ 00022 00023 #include "kwallet.h" 00024 #include <ksharedconfig.h> 00025 #include <kdebug.h> 00026 #include <kdeversion.h> 00027 #include <QtGui/QApplication> 00028 #include <QtCore/QPointer> 00029 #include <QtGui/QWidget> 00030 #include <ktoolinvocation.h> 00031 00032 #include <kglobal.h> 00033 #include <kcomponentdata.h> 00034 #include <kaboutdata.h> 00035 #include <kconfiggroup.h> 00036 00037 #include <cassert> 00038 00039 #include <Carbon/Carbon.h> 00040 #include <Security/Security.h> 00041 #include <Security/SecKeychain.h> 00042 00043 using namespace KWallet; 00044 00045 typedef QMap<QString, QString> StringStringMap; 00046 Q_DECLARE_METATYPE(StringStringMap) 00047 typedef QMap<QString, StringStringMap> StringToStringStringMapMap; 00048 Q_DECLARE_METATYPE(StringToStringStringMapMap) 00049 typedef QMap<QString, QByteArray> StringByteArrayMap; 00050 Q_DECLARE_METATYPE(StringByteArrayMap) 00051 00052 namespace { 00053 template <typename T> 00054 struct CFReleaser { 00055 explicit CFReleaser( const T& r ) : ref( r ) {} 00056 ~CFReleaser() { CFRelease( ref ); } 00057 T ref; 00058 }; 00059 } 00060 00061 static QString asQString( CFStringRef sr ) { 00062 return QString::fromLatin1( CFStringGetCStringPtr( sr, NULL ) ); //TODO Latin1 correct? 00063 } 00064 00065 static QString errorString( OSStatus s ) { 00066 const CFReleaser<CFStringRef> ref( SecCopyErrorMessageString( s, NULL ) ); 00067 return asQString( ref.ref ); 00068 } 00069 00070 static bool isError( OSStatus s, QString* errMsg ) { 00071 if ( errMsg ) 00072 *errMsg = errorString( s ); 00073 return s != 0; 00074 } 00075 00076 static QString appid() 00077 { 00078 KComponentData cData = KGlobal::mainComponent(); 00079 if (cData.isValid()) { 00080 const KAboutData* aboutData = cData.aboutData(); 00081 if (aboutData) { 00082 return aboutData->programName(); 00083 } 00084 return cData.componentName(); 00085 } 00086 return qApp->applicationName(); 00087 } 00088 00089 00090 const QString Wallet::LocalWallet() { 00091 KConfigGroup cfg(KSharedConfig::openConfig("kwalletrc")->group("Wallet")); 00092 if (!cfg.readEntry("Use One Wallet", true)) { 00093 QString tmp = cfg.readEntry("Local Wallet", "localwallet"); 00094 if (tmp.isEmpty()) { 00095 return "localwallet"; 00096 } 00097 return tmp; 00098 } 00099 00100 QString tmp = cfg.readEntry("Default Wallet", "kdewallet"); 00101 if (tmp.isEmpty()) { 00102 return "kdewallet"; 00103 } 00104 return tmp; 00105 } 00106 00107 const QString Wallet::NetworkWallet() { 00108 KConfigGroup cfg(KSharedConfig::openConfig("kwalletrc")->group("Wallet")); 00109 00110 QString tmp = cfg.readEntry("Default Wallet", "kdewallet"); 00111 if (tmp.isEmpty()) { 00112 return "kdewallet"; 00113 } 00114 return tmp; 00115 } 00116 00117 const QString Wallet::PasswordFolder() { 00118 return "Passwords"; 00119 } 00120 00121 const QString Wallet::FormDataFolder() { 00122 return "Form Data"; 00123 } 00124 00125 class Wallet::WalletPrivate 00126 { 00127 public: 00128 explicit WalletPrivate(const QString &n) 00129 : name(n) 00130 {} 00131 00132 // needed for compilation reasons 00133 void walletServiceUnregistered() { 00134 } 00135 00136 QString name; 00137 QString folder; 00138 }; 00139 00140 Wallet::Wallet(int handle, const QString& name) 00141 : QObject(0L), d(new WalletPrivate(name)) { 00142 Q_UNUSED(handle); 00143 } 00144 00145 Wallet::~Wallet() { 00146 delete d; 00147 } 00148 00149 00150 QStringList Wallet::walletList() { 00151 #ifdef OSX_KEYCHAIN_PORT_DISABLED 00152 return walletLauncher->getInterface().wallets(); 00153 #else 00154 return QStringList(); 00155 #endif 00156 } 00157 00158 00159 void Wallet::changePassword(const QString& name, WId w) { 00160 #ifdef OSX_KEYCHAIN_PORT_DISABLED 00161 if( w == 0 ) 00162 kDebug(285) << "Pass a valid window to KWallet::Wallet::changePassword()."; 00163 walletLauncher->getInterface().changePassword(name, (qlonglong)w, appid()); 00164 #endif 00165 } 00166 00167 00168 bool Wallet::isEnabled() { 00169 //PENDING(frank) check 00170 return true; 00171 } 00172 00173 00174 bool Wallet::isOpen(const QString& name) { 00175 #ifdef OSX_KEYCHAIN_PORT_DISABLED 00176 return walletLauncher->getInterface().isOpen(name); // default is false 00177 #else 00178 return true; 00179 #endif 00180 } 00181 00182 00183 int Wallet::closeWallet(const QString& name, bool force) { 00184 #ifdef OSX_KEYCHAIN_PORT_DISABLED 00185 QDBusReply<int> r = walletLauncher->getInterface().close(name, force); 00186 return r.isValid() ? r : -1; 00187 #else 00188 return 0; 00189 #endif 00190 } 00191 00192 00193 int Wallet::deleteWallet(const QString& name) { 00194 #ifdef OSX_KEYCHAIN_PORT_DISABLED 00195 QDBusReply<int> r = walletLauncher->getInterface().deleteWallet(name); 00196 return r.isValid() ? r : -1; 00197 #else 00198 return -1; 00199 #endif 00200 } 00201 00202 00203 Wallet *Wallet::openWallet(const QString& name, WId w, OpenType ot) { 00204 Q_UNUSED(w); 00205 Q_UNUSED(ot); 00206 Wallet *wallet = new Wallet(-1, name); 00207 QMetaObject::invokeMethod( wallet, "emitWalletOpened", Qt::QueuedConnection ); 00208 return wallet; 00209 } 00210 00211 00212 bool Wallet::disconnectApplication(const QString& wallet, const QString& app) { 00213 #ifdef OSX_KEYCHAIN_PORT_DISABLED 00214 return walletLauncher->getInterface().disconnectApplication(wallet, app); // default is false 00215 #else 00216 return true; 00217 #endif 00218 } 00219 00220 00221 QStringList Wallet::users(const QString& name) { 00222 #ifdef OSX_KEYCHAIN_PORT_DISABLED 00223 return walletLauncher->getInterface().users(name); // default is QStringList() 00224 #else 00225 return QStringList(); 00226 #endif 00227 } 00228 00229 00230 int Wallet::sync() { 00231 #ifdef OSX_KEYCHAIN_PORT_DISABLED 00232 if (d->handle == -1) { 00233 return -1; 00234 } 00235 00236 walletLauncher->getInterface().sync(d->handle, appid()); 00237 #endif 00238 return 0; 00239 } 00240 00241 00242 int Wallet::lockWallet() { 00243 #ifdef OSX_KEYCHAIN_PORT_DISABLED 00244 if (d->handle == -1) { 00245 return -1; 00246 } 00247 00248 QDBusReply<int> r = walletLauncher->getInterface().close(d->handle, true, appid()); 00249 d->handle = -1; 00250 d->folder.clear(); 00251 d->name.clear(); 00252 if (r.isValid()) { 00253 return r; 00254 } 00255 #endif 00256 return -1; 00257 } 00258 00259 00260 const QString& Wallet::walletName() const { 00261 return d->name; 00262 } 00263 00264 00265 bool Wallet::isOpen() const { 00266 #ifdef OSX_KEYCHAIN_PORT_DISABLED 00267 return d->handle != -1; 00268 #else 00269 return true; 00270 #endif 00271 } 00272 00273 00274 void Wallet::requestChangePassword(WId w) { 00275 #ifdef OSX_KEYCHAIN_PORT_DISABLED 00276 if( w == 0 ) 00277 kDebug(285) << "Pass a valid window to KWallet::Wallet::requestChangePassword()."; 00278 if (d->handle == -1) { 00279 return; 00280 } 00281 00282 walletLauncher->getInterface().changePassword(d->name, (qlonglong)w, appid()); 00283 #endif 00284 } 00285 00286 00287 void Wallet::slotWalletClosed(int handle) { 00288 #ifdef OSX_KEYCHAIN_PORT_DISABLED 00289 if (d->handle == handle) { 00290 d->handle = -1; 00291 d->folder.clear(); 00292 d->name.clear(); 00293 emit walletClosed(); 00294 } 00295 #endif 00296 } 00297 00298 00299 QStringList Wallet::folderList() { 00300 #ifdef OSX_KEYCHAIN_PORT_DISABLED 00301 if (d->handle == -1) { 00302 return QStringList(); 00303 } 00304 00305 QDBusReply<QStringList> r = walletLauncher->getInterface().folderList(d->handle, appid()); 00306 return r; 00307 #else 00308 return QStringList(); 00309 #endif 00310 } 00311 00312 00313 QStringList Wallet::entryList() { 00314 #ifdef OSX_KEYCHAIN_PORT_DISABLED 00315 if (d->handle == -1) { 00316 return QStringList(); 00317 } 00318 00319 QDBusReply<QStringList> r = walletLauncher->getInterface().entryList(d->handle, d->folder, appid()); 00320 return r; 00321 #else 00322 return QStringList(); 00323 #endif 00324 } 00325 00326 00327 bool Wallet::hasFolder(const QString& f) { 00328 #ifdef OSX_KEYCHAIN_PORT_DISABLED 00329 if (d->handle == -1) { 00330 return false; 00331 } 00332 00333 QDBusReply<bool> r = walletLauncher->getInterface().hasFolder(d->handle, f, appid()); 00334 return r; // default is false 00335 #else 00336 return true; 00337 #endif 00338 } 00339 00340 00341 bool Wallet::createFolder(const QString& f) { 00342 #ifdef OSX_KEYCHAIN_PORT_DISABLED 00343 if (d->handle == -1) { 00344 return false; 00345 } 00346 00347 if (!hasFolder(f)) { 00348 QDBusReply<bool> r = walletLauncher->getInterface().createFolder(d->handle, f, appid()); 00349 return r; 00350 } 00351 00352 return true; // folder already exists 00353 #else 00354 return true; 00355 #endif 00356 } 00357 00358 00359 bool Wallet::setFolder(const QString& f) { 00360 #ifdef OSX_KEYCHAIN_PORT_DISABLED 00361 bool rc = false; 00362 00363 if (d->handle == -1) { 00364 return rc; 00365 } 00366 00367 // Don't do this - the folder could have disappeared? 00368 #if 0 00369 if (f == d->folder) { 00370 return true; 00371 } 00372 #endif 00373 00374 if (hasFolder(f)) { 00375 d->folder = f; 00376 rc = true; 00377 } 00378 00379 return rc; 00380 #else 00381 return true; 00382 #endif 00383 } 00384 00385 00386 bool Wallet::removeFolder(const QString& f) { 00387 #ifdef OSX_KEYCHAIN_PORT_DISABLED 00388 if (d->handle == -1) { 00389 return false; 00390 } 00391 00392 QDBusReply<bool> r = walletLauncher->getInterface().removeFolder(d->handle, f, appid()); 00393 if (d->folder == f) { 00394 setFolder(QString()); 00395 } 00396 00397 return r; // default is false 00398 #else 00399 return true; 00400 #endif 00401 } 00402 00403 00404 const QString& Wallet::currentFolder() const { 00405 return d->folder; 00406 } 00407 00408 00409 int Wallet::readEntry(const QString& key, QByteArray& value) { 00410 const QByteArray serviceName( walletName().toUtf8() ); 00411 const QByteArray accountName( key.toUtf8() ); 00412 UInt32 passwordSize = 0; 00413 void* passwordData = 0; 00414 QString errMsg; 00415 if ( isError( SecKeychainFindGenericPassword( NULL, serviceName.size(), serviceName.constData(), accountName.size(), accountName.constData(), &passwordSize, &passwordData, NULL ), &errMsg ) ) { 00416 qWarning() << "Could not retrieve password:" << qPrintable(errMsg); 00417 return -1; 00418 } 00419 00420 value = QByteArray( reinterpret_cast<const char*>( passwordData ), passwordSize ); 00421 SecKeychainItemFreeContent( NULL, passwordData ); 00422 return 0; 00423 } 00424 00425 00426 int Wallet::readEntryList(const QString& key, QMap<QString, QByteArray>& value) { 00427 #ifdef OSX_KEYCHAIN_PORT_DISABLED 00428 registerTypes(); 00429 00430 int rc = -1; 00431 00432 if (d->handle == -1) { 00433 return rc; 00434 } 00435 00436 QDBusReply<QVariantMap> r = walletLauncher->getInterface().readEntryList(d->handle, d->folder, key, appid()); 00437 if (r.isValid()) { 00438 rc = 0; 00439 // convert <QString, QVariant> to <QString, QByteArray> 00440 const QVariantMap val = r.value(); 00441 for( QVariantMap::const_iterator it = val.begin(); it != val.end(); ++it ) { 00442 value.insert(it.key(), it.value().toByteArray()); 00443 } 00444 } 00445 00446 return rc; 00447 #else 00448 return -1; 00449 #endif 00450 } 00451 00452 00453 int Wallet::renameEntry(const QString& oldName, const QString& newName) { 00454 #ifdef OSX_KEYCHAIN_PORT_DISABLED 00455 int rc = -1; 00456 00457 if (d->handle == -1) { 00458 return rc; 00459 } 00460 00461 QDBusReply<int> r = walletLauncher->getInterface().renameEntry(d->handle, d->folder, oldName, newName, appid()); 00462 if (r.isValid()) { 00463 rc = r; 00464 } 00465 00466 return rc; 00467 #else 00468 return -1; 00469 #endif 00470 } 00471 00472 00473 int Wallet::readMap(const QString& key, QMap<QString,QString>& value) { 00474 QByteArray v; 00475 const int ret = readEntry( key, v ); 00476 if ( ret != 0 ) 00477 return ret; 00478 if ( !v.isEmpty() ) { 00479 QDataStream ds( &v, QIODevice::ReadOnly ); 00480 ds >> value; 00481 } 00482 return 0; 00483 } 00484 00485 00486 int Wallet::readMapList(const QString& key, QMap<QString, QMap<QString, QString> >& value) { 00487 #ifdef OSX_KEYCHAIN_PORT_DISABLED 00488 registerTypes(); 00489 00490 int rc = -1; 00491 00492 if (d->handle == -1) { 00493 return rc; 00494 } 00495 00496 QDBusReply<QVariantMap> r = 00497 walletLauncher->getInterface().readMapList(d->handle, d->folder, key, appid()); 00498 if (r.isValid()) { 00499 rc = 0; 00500 const QVariantMap val = r.value(); 00501 for( QVariantMap::const_iterator it = val.begin(); it != val.end(); ++it ) { 00502 QByteArray mapData = it.value().toByteArray(); 00503 if (!mapData.isEmpty()) { 00504 QDataStream ds(&mapData, QIODevice::ReadOnly); 00505 QMap<QString,QString> v; 00506 ds >> v; 00507 value.insert(it.key(), v); 00508 } 00509 } 00510 } 00511 00512 return rc; 00513 #else 00514 return -1; 00515 #endif 00516 } 00517 00518 00519 int Wallet::readPassword(const QString& key, QString& value) { 00520 QByteArray ba; 00521 const int ret = readEntry( key, ba ); 00522 if ( ret == 0 ) 00523 value = QString::fromUtf8( ba.constData() ); 00524 return ret; 00525 } 00526 00527 00528 int Wallet::readPasswordList(const QString& key, QMap<QString, QString>& value) { 00529 return -1; 00530 } 00531 00532 00533 int Wallet::writeEntry(const QString& key, const QByteArray& password, EntryType entryType) { 00534 const QByteArray serviceName( walletName().toUtf8() ); 00535 const QByteArray accountName( key.toUtf8() ); 00536 QString errMsg; 00537 if ( isError( SecKeychainAddGenericPassword( NULL, serviceName.size(), serviceName.constData(), accountName.size(), accountName.constData(), password.size(), password.constData(), NULL ), &errMsg ) ) { 00538 kWarning() << "Could not store password in keychain: " << qPrintable(errMsg); 00539 return -1; 00540 } 00541 return 0; 00542 } 00543 00544 00545 int Wallet::writeEntry(const QString& key, const QByteArray& value) { 00546 const QByteArray serviceName( walletName().toUtf8() ); 00547 const QByteArray accountName( key.toUtf8() ); 00548 QString errMsg; 00549 if ( isError( SecKeychainAddGenericPassword( NULL, serviceName.size(), serviceName.constData(), accountName.size(), accountName.constData(), value.size(), value.constData(), NULL ), &errMsg ) ) { 00550 kWarning() << "Could not store password in keychain: " << qPrintable(errMsg); 00551 return -1; 00552 } 00553 return 0; 00554 } 00555 00556 00557 int Wallet::writeMap(const QString& key, const QMap<QString,QString>& value) { 00558 QByteArray mapData; 00559 QDataStream ds(&mapData, QIODevice::WriteOnly); 00560 ds << value; 00561 return writeEntry( key, mapData ); 00562 } 00563 00564 00565 int Wallet::writePassword(const QString& key, const QString& value) { 00566 return writeEntry( key, value.toUtf8() ); 00567 } 00568 00569 00570 bool Wallet::hasEntry(const QString& key) { 00571 const QByteArray serviceName( walletName().toUtf8() ); 00572 const QByteArray accountName( key.toUtf8() ); 00573 return !isError( SecKeychainFindGenericPassword( NULL, serviceName.size(), serviceName.constData(), accountName.size(), accountName.constData(), NULL, NULL, NULL ), 0 ); 00574 } 00575 00576 00577 int Wallet::removeEntry(const QString& key) { 00578 const QByteArray serviceName( walletName().toUtf8() ); 00579 const QByteArray accountName( key.toUtf8() ); 00580 SecKeychainItemRef itemRef; 00581 QString errMsg; 00582 if ( isError( SecKeychainFindGenericPassword( NULL, serviceName.size(), serviceName.constData(), accountName.size(), accountName.constData(), NULL, NULL, &itemRef ), &errMsg ) ) { 00583 qWarning() << "Could not retrieve password:" << qPrintable(errMsg); 00584 return -1; 00585 } 00586 const CFReleaser<SecKeychainItemRef> itemReleaser( itemRef ); 00587 if ( isError( SecKeychainItemDelete( itemRef ), &errMsg ) ) { 00588 qWarning() << "Could not delete password:" << qPrintable(errMsg); 00589 return -1; 00590 } 00591 return 0; 00592 } 00593 00594 00595 Wallet::EntryType Wallet::entryType(const QString& key) { 00596 #ifdef OSX_KEYCHAIN_PORT_DISABLED 00597 int rc = 0; 00598 00599 if (d->handle == -1) { 00600 return Wallet::Unknown; 00601 } 00602 00603 QDBusReply<int> r = walletLauncher->getInterface().entryType(d->handle, d->folder, key, appid()); 00604 if (r.isValid()) { 00605 rc = r; 00606 } 00607 00608 return static_cast<EntryType>(rc); 00609 #else 00610 return Wallet::Unknown; 00611 #endif 00612 } 00613 00614 00615 void Wallet::slotFolderUpdated(const QString& wallet, const QString& folder) { 00616 if (d->name == wallet) { 00617 emit folderUpdated(folder); 00618 } 00619 } 00620 00621 00622 void Wallet::slotFolderListUpdated(const QString& wallet) { 00623 if (d->name == wallet) { 00624 emit folderListUpdated(); 00625 } 00626 } 00627 00628 00629 void Wallet::slotApplicationDisconnected(const QString& wallet, const QString& application) { 00630 #ifdef OSX_KEYCHAIN_PORT_DISABLED 00631 if (d->handle >= 0 00632 && d->name == wallet 00633 && application == appid()) { 00634 slotWalletClosed(d->handle); 00635 } 00636 #endif 00637 } 00638 00639 void Wallet::walletAsyncOpened(int tId, int handle) { 00640 #ifdef OSX_KEYCHAIN_PORT_DISABLED 00641 // ignore responses to calls other than ours 00642 if (d->transactionId != tId || d->handle != -1) { 00643 return; 00644 } 00645 00646 // disconnect the async signal 00647 disconnect(this, SLOT(walletAsyncOpened(int, int))); 00648 00649 d->handle = handle; 00650 emit walletOpened(handle > 0); 00651 #endif 00652 } 00653 00654 void Wallet::emitWalletAsyncOpenError() { 00655 emit walletOpened(false); 00656 } 00657 00658 void Wallet::emitWalletOpened() { 00659 emit walletOpened(true); 00660 } 00661 00662 00663 bool Wallet::folderDoesNotExist(const QString& wallet, const QString& folder) 00664 { 00665 #ifdef OSX_KEYCHAIN_PORT_DISABLED 00666 QDBusReply<bool> r = walletLauncher->getInterface().folderDoesNotExist(wallet, folder); 00667 return r; 00668 #else 00669 return false; 00670 #endif 00671 } 00672 00673 00674 bool Wallet::keyDoesNotExist(const QString& wallet, const QString& folder, const QString& key) 00675 { 00676 #ifdef OSX_KEYCHAIN_PORT_DISABLED 00677 QDBusReply<bool> r = walletLauncher->getInterface().keyDoesNotExist(wallet, folder, key); 00678 return r; 00679 #else 00680 return false; 00681 #endif 00682 } 00683 00684 void Wallet::virtual_hook(int, void*) { 00685 //BASE::virtual_hook( id, data ); 00686 } 00687 00688 #include "kwallet.moc"
KDE 4.7 API Reference