00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "kwalletd.h"
00025
00026 #include "kbetterthankdialog.h"
00027 #include "kwalletwizard.h"
00028 #include "ktimeout.h"
00029
00030 #include <kuniqueapplication.h>
00031 #include <ktoolinvocation.h>
00032 #include <kconfig.h>
00033 #include <kconfiggroup.h>
00034 #include <kdebug.h>
00035 #include <kdirwatch.h>
00036 #include <kglobal.h>
00037 #include <klocale.h>
00038 #include <kmessagebox.h>
00039 #include <kpassworddialog.h>
00040 #include <knewpassworddialog.h>
00041 #include <kstandarddirs.h>
00042 #include <kwalletentry.h>
00043 #include <kwindowsystem.h>
00044 #include <kpluginfactory.h>
00045 #include <kpluginloader.h>
00046
00047 #include <QtCore/QDir>
00048 #include <QtGui/QTextDocument>
00049 #include <QtCore/QRegExp>
00050 #include <QtCore/QTimer>
00051
00052 #include <assert.h>
00053
00054 #include "kwalletdadaptor.h"
00055 #include "kwalletsynctimer.h"
00056
00057 class KWalletTransaction {
00058 public:
00059 KWalletTransaction() {
00060 tType = Unknown;
00061 }
00062
00063 ~KWalletTransaction() {
00064 }
00065
00066 enum Type { Unknown, Open, ChangePassword, OpenFail };
00067 QDBusMessage msg;
00068 Type tType;
00069 QString appid;
00070 qlonglong wId;
00071 QString wallet;
00072 bool modal;
00073 };
00074
00075 KWalletD::KWalletD()
00076 : QObject(0), _failed(0) {
00077 srand(time(0));
00078 _showingFailureNotify = false;
00079 _timeouts = new KTimeout();
00080 _closeIdle = false;
00081 _idleTime = 0;
00082 connect(_timeouts, SIGNAL(timedOut(int)), this, SLOT(timedOut(int)));
00083
00084 (void)new KWalletDAdaptor(this);
00085
00086 QDBusConnection::sessionBus().registerService(QLatin1String("org.kde.kwalletd"));
00087 QDBusConnection::sessionBus().registerObject(QLatin1String("/modules/kwalletd"), this);
00088
00089 #ifdef Q_WS_X11
00090 screensaver = new QDBusInterface("org.freedesktop.ScreenSaver", "/ScreenSaver", "org.freedesktop.ScreenSaver");
00091 #endif
00092
00093 reconfigure();
00094 KGlobal::dirs()->addResourceType("kwallet", 0, "share/apps/kwallet");
00095 connect(QDBusConnection::sessionBus().interface(), SIGNAL(serviceUnregistered(QString)),
00096 SLOT(slotServiceUnregistered(QString)));
00097 _dw = new KDirWatch(this );
00098 _dw->setObjectName( "KWallet Directory Watcher" );
00099 _dw->addDir(KGlobal::dirs()->saveLocation("kwallet"));
00100 _dw->startScan(true);
00101 connect(_dw, SIGNAL(dirty(const QString&)), this, SLOT(emitWalletListDirty()));
00102 }
00103
00104
00105 KWalletD::~KWalletD() {
00106 delete _timeouts;
00107 _timeouts = 0;
00108 #ifdef Q_WS_X11
00109 delete screensaver;
00110 screensaver = 0;
00111 #endif
00112 closeAllWallets();
00113 qDeleteAll(_synctimers);
00114 qDeleteAll(_transactions);
00115 }
00116
00117
00118 int KWalletD::generateHandle() {
00119 int rc;
00120
00121
00122 do {
00123 rc = rand();
00124 } while (_wallets.contains(rc) || rc == 0);
00125
00126 return rc;
00127 }
00128
00129 QPair<int, KWallet::Backend*> KWalletD::findWallet(const QString& walletName) const
00130 {
00131 Wallets::const_iterator it = _wallets.begin();
00132 const Wallets::const_iterator end = _wallets.end();
00133 for (; it != end; ++it) {
00134 if (it.value()->walletName() == walletName) {
00135 return qMakePair(it.key(), it.value());
00136 }
00137 }
00138 return qMakePair(-1, static_cast<KWallet::Backend*>(0));
00139 }
00140
00141 void KWalletD::processTransactions() {
00142 static bool processing = false;
00143
00144 if (processing) {
00145 return;
00146 }
00147
00148 processing = true;
00149
00150
00151 KWalletTransaction *xact;
00152 while (!_transactions.isEmpty()) {
00153 xact = _transactions.first();
00154 int res;
00155
00156 assert(xact->tType != KWalletTransaction::Unknown);
00157
00158 switch (xact->tType) {
00159 case KWalletTransaction::Open:
00160 res = doTransactionOpen(xact->appid, xact->wallet, xact->wId, xact->modal);
00161
00162
00163
00164
00165 if (res < 0) {
00166 QList<KWalletTransaction *>::iterator it = _transactions.begin();
00167 Q_ASSERT(*it == xact);
00168 ++it;
00169 for (; it != _transactions.end(); ++it) {
00170 KWalletTransaction *x = *it;
00171 if (xact->appid == x->appid && x->tType == KWalletTransaction::Open
00172 && x->wallet == xact->wallet && x->wId == xact->wId) {
00173 x->tType = KWalletTransaction::OpenFail;
00174 }
00175 }
00176 }
00177 break;
00178 case KWalletTransaction::OpenFail:
00179 res = -1;
00180 break;
00181 case KWalletTransaction::ChangePassword:
00182 doTransactionChangePassword(xact->appid, xact->wallet, xact->wId);
00183
00184 default:
00185 _transactions.removeAll(xact);
00186 continue;
00187 }
00188
00189 if (xact->tType != KWalletTransaction::ChangePassword) {
00190 QDBusConnection::sessionBus().send(xact->msg.createReply(res));
00191 }
00192 _transactions.removeAll(xact);
00193 }
00194
00195 processing = false;
00196 }
00197
00198 #if 0
00199 void KWalletD::openAsynchronous(const QString& wallet, const QByteArray& returnObject, uint wId, const QString& appid) {
00200 DCOPClient *dc = callingDcopClient();
00201 if (!dc) {
00202 return;
00203 }
00204
00205 if (!_enabled ||
00206 !QRegExp("^[A-Za-z0-9]+[A-Za-z0-9\\s\\-_]*$").exactMatch(wallet)) {
00207 DCOPRef(appid, returnObject).send("walletOpenResult", -1);
00208 return;
00209 }
00210
00211 KWalletTransaction *xact = new KWalletTransaction;
00212
00213 xact->appid = appid;
00214 xact->wallet = wallet;
00215 xact->wId = wId;
00216 xact->modal = false;
00217 xact->tType = KWalletTransaction::Open;
00218 xact->returnObject = returnObject;
00219 _transactions.append(xact);
00220
00221 DCOPRef(appid, returnObject).send("walletOpenResult", 0);
00222
00223 QTimer::singleShot(0, this, SLOT(processTransactions()));
00224 }
00225 #endif
00226
00227 int KWalletD::openPath(const QString& path, qlonglong wId, const QString& appid) {
00228 if (!_enabled) {
00229 return -1;
00230 }
00231
00232
00233 int rc = internalOpen(appid, path, true, (WId)wId, false);
00234 return rc;
00235 }
00236
00237
00238 int KWalletD::open(const QString& wallet, qlonglong wId, const QString& appid, const QDBusMessage &msg) {
00239 if (!_enabled) {
00240 return -1;
00241 }
00242
00243 if (!QRegExp("^[A-Za-z0-9]+[A-Za-z0-9\\s\\-_]*$").exactMatch(wallet)) {
00244 return -1;
00245 }
00246
00247 KWalletTransaction *xact = new KWalletTransaction;
00248 _transactions.append(xact);
00249
00250 msg.setDelayedReply(true);
00251 xact->msg = msg;
00252 xact->appid = appid;
00253 xact->wallet = wallet;
00254 xact->wId = wId;
00255 xact->modal = true;
00256 xact->tType = KWalletTransaction::Open;
00257 QTimer::singleShot(0, this, SLOT(processTransactions()));
00258 checkActiveDialog();
00259 return 0;
00260 }
00261
00262
00263 void KWalletD::setupDialog( QWidget* dialog, WId wId, const QString& appid, bool modal ) {
00264 #ifdef Q_WS_X11
00265 if( wId != 0 )
00266 KWindowSystem::setMainWindow( dialog, wId );
00267 else {
00268 #endif
00269 if( appid.isEmpty())
00270 kWarning() << "Using kwallet without parent window!";
00271 else
00272 kWarning() << "Application '" << appid << "' using kwallet without parent window!";
00273
00274
00275 kapp->updateUserTimestamp();
00276 #ifdef Q_WS_X11
00277 }
00278 if( modal )
00279 KWindowSystem::setState( dialog->winId(), NET::Modal );
00280 else
00281 KWindowSystem::clearState( dialog->winId(), NET::Modal );
00282 #endif
00283 activeDialog = dialog;
00284 }
00285
00286
00287
00288
00289
00290
00291
00292 void KWalletD::checkActiveDialog() {
00293 if( !activeDialog || activeDialog->isHidden())
00294 return;
00295 kapp->updateUserTimestamp();
00296 #ifdef Q_WS_X11
00297 KWindowSystem::setState( activeDialog->winId(), NET::KeepAbove );
00298 KWindowSystem::setOnAllDesktops( activeDialog->winId(), true );
00299 KWindowSystem::forceActiveWindow( activeDialog->winId());
00300 #endif
00301 }
00302
00303
00304 int KWalletD::doTransactionOpen(const QString& appid, const QString& wallet, qlonglong wId, bool modal) {
00305 if (_firstUse && !wallets().contains(KWallet::Wallet::LocalWallet())) {
00306
00307 KWalletWizard *wiz = new KWalletWizard(0);
00308 wiz->setWindowTitle(i18n("KDE Wallet Service"));
00309 setupDialog( wiz, (WId)wId, appid, modal );
00310 int rc = wiz->exec();
00311 if (rc == QDialog::Accepted) {
00312 bool useWallet = wiz->field("useWallet").toBool();
00313 KConfig kwalletrc("kwalletrc");
00314 KConfigGroup cfg(&kwalletrc, "Wallet");
00315 cfg.writeEntry("First Use", false);
00316 cfg.writeEntry("Enabled", useWallet);
00317 cfg.writeEntry("Close When Idle", wiz->field("closeWhenIdle").toBool());
00318 cfg.writeEntry("Use One Wallet", !wiz->field("networkWallet").toBool());
00319 cfg.sync();
00320 reconfigure();
00321
00322 if (!useWallet) {
00323 delete wiz;
00324 return -1;
00325 }
00326
00327
00328 KWallet::Backend *b = new KWallet::Backend(KWallet::Wallet::LocalWallet());
00329 QString pass = wiz->field("pass1").toString();
00330 QByteArray p(pass.toUtf8(), pass.length());
00331 b->open(p);
00332 b->createFolder(KWallet::Wallet::PasswordFolder());
00333 b->createFolder(KWallet::Wallet::FormDataFolder());
00334 b->close(p);
00335 p.fill(0);
00336 delete b;
00337 delete wiz;
00338 } else {
00339 delete wiz;
00340 return -1;
00341 }
00342 } else if (_firstUse) {
00343 KConfig kwalletrc("kwalletrc");
00344 KConfigGroup cfg(&kwalletrc, "Wallet");
00345 _firstUse = false;
00346 cfg.writeEntry("First Use", false);
00347 }
00348
00349 int rc = internalOpen(appid, wallet, false, WId(wId), modal);
00350 return rc;
00351 }
00352
00353
00354 int KWalletD::internalOpen(const QString& appid, const QString& wallet, bool isPath, WId w, bool modal) {
00355 bool brandNew = false;
00356
00357 QString thisApp;
00358 if (appid.isEmpty()) {
00359 thisApp = "KDE System";
00360 } else {
00361 thisApp = appid;
00362 }
00363
00364 if (implicitDeny(wallet, thisApp)) {
00365 return -1;
00366 }
00367
00368 const QPair<int, KWallet::Backend*> walletInfo = findWallet(wallet);
00369 int rc = walletInfo.first;
00370 if (rc == -1) {
00371 if (_wallets.count() > 20) {
00372 kDebug() << "Too many wallets open.";
00373 return -1;
00374 }
00375
00376 KWallet::Backend *b = new KWallet::Backend(wallet, isPath);
00377 QString password;
00378 bool emptyPass = false;
00379 if ((isPath && QFile::exists(wallet)) || (!isPath && KWallet::Backend::exists(wallet))) {
00380 int pwless = b->open(QByteArray());
00381 if (0 != pwless || !b->isOpen()) {
00382 if (pwless == 0) {
00383
00384 delete b;
00385 b = new KWallet::Backend(wallet, isPath);
00386 }
00387 KPasswordDialog *kpd = new KPasswordDialog();
00388 if (appid.isEmpty()) {
00389 kpd->setPrompt(i18n("<qt>KDE has requested to open the wallet '<b>%1</b>'. Please enter the password for this wallet below.</qt>", Qt::escape(wallet)));
00390 } else {
00391 kpd->setPrompt(i18n("<qt>The application '<b>%1</b>' has requested to open the wallet '<b>%2</b>'. Please enter the password for this wallet below.</qt>", Qt::escape(appid), Qt::escape(wallet)));
00392 }
00393 brandNew = false;
00394
00395 kpd->setButtonGuiItem(KDialog::Ok,KGuiItem( i18n( "&Open" ), "document-open"));
00396 kpd->setCaption(i18n("KDE Wallet Service"));
00397 while (!b->isOpen()) {
00398 setupDialog( kpd, w, appid, modal );
00399 if (kpd->exec() == KDialog::Accepted) {
00400 password = kpd->password();
00401 int rc = b->open(password.toUtf8());
00402 if (!b->isOpen()) {
00403 kpd->setPrompt(i18n("<qt>Error opening the wallet '<b>%1</b>'. Please try again.<br />(Error code %2: %3)</qt>", Qt::escape(wallet), rc, KWallet::Backend::openRCToString(rc)));
00404 }
00405 } else {
00406 break;
00407 }
00408 }
00409 delete kpd;
00410 } else {
00411 emptyPass = true;
00412 }
00413 } else {
00414 KNewPasswordDialog *kpd = new KNewPasswordDialog();
00415 if (wallet == KWallet::Wallet::LocalWallet() ||
00416 wallet == KWallet::Wallet::NetworkWallet())
00417 {
00418
00419 if (appid.isEmpty()) {
00420 kpd->setPrompt(i18n("KDE has requested to open the wallet. This is used to store sensitive data in a secure fashion. Please enter a password to use with this wallet or click cancel to deny the application's request."));
00421 } else {
00422 kpd->setPrompt(i18n("<qt>The application '<b>%1</b>' has requested to open the KDE wallet. This is used to store sensitive data in a secure fashion. Please enter a password to use with this wallet or click cancel to deny the application's request.</qt>", Qt::escape(appid)));
00423 }
00424 } else {
00425 if (appid.length() == 0) {
00426 kpd->setPrompt(i18n("<qt>KDE has requested to create a new wallet named '<b>%1</b>'. Please choose a password for this wallet, or cancel to deny the application's request.</qt>", Qt::escape(wallet)));
00427 } else {
00428 kpd->setPrompt(i18n("<qt>The application '<b>%1</b>' has requested to create a new wallet named '<b>%2</b>'. Please choose a password for this wallet, or cancel to deny the application's request.</qt>", Qt::escape(appid), Qt::escape(wallet)));
00429 }
00430 }
00431 brandNew = true;
00432 kpd->setCaption(i18n("KDE Wallet Service"));
00433 kpd->setButtonGuiItem(KDialog::Ok,KGuiItem(i18n("C&reate"),"document-new"));
00434 while (!b->isOpen()) {
00435 setupDialog( kpd, w, appid, modal );
00436 if (kpd->exec() == KDialog::Accepted) {
00437 password = kpd->password();
00438 int rc = b->open(password.toUtf8());
00439 if (!b->isOpen()) {
00440 kpd->setPrompt(i18n("<qt>Error opening the wallet '<b>%1</b>'. Please try again.<br />(Error code %2: %3)</qt>", Qt::escape(wallet), rc, KWallet::Backend::openRCToString(rc)));
00441 }
00442 } else {
00443 break;
00444 }
00445 }
00446 delete kpd;
00447 }
00448
00449
00450
00451 if (!emptyPass && (password.isNull() || !b->isOpen())) {
00452 delete b;
00453 return -1;
00454 }
00455
00456 if (emptyPass && _openPrompt && !isAuthorizedApp(appid, wallet, w)) {
00457 delete b;
00458 return -1;
00459 }
00460
00461 _wallets.insert(rc = generateHandle(), b);
00462 if (emptyPass) {
00463 _passwords[wallet] = "";
00464 } else {
00465 _passwords[wallet] = password.toUtf8();
00466 }
00467 _handles[appid].append(rc);
00468 _synctimers[wallet] = new KWalletSyncTimer(this, wallet);
00469 connect(_synctimers[wallet], SIGNAL(timeoutSync(const QString&)), this, SLOT(doTransactionSync(const QString&)));
00470
00471 if (brandNew) {
00472 createFolder(rc, KWallet::Wallet::PasswordFolder(), appid);
00473 createFolder(rc, KWallet::Wallet::FormDataFolder(), appid);
00474 }
00475
00476 b->ref();
00477 if (_closeIdle && _timeouts) {
00478 _timeouts->addTimer(rc, _idleTime);
00479 }
00480 if (brandNew)
00481 emit walletCreated(wallet);
00482 emit walletOpened(wallet);
00483 if (_wallets.count() == 1 && _launchManager) {
00484 KToolInvocation::startServiceByDesktopName("kwalletmanager-kwalletd");
00485 }
00486 } else {
00487 if (!_handles[appid].contains(rc) && _openPrompt && !isAuthorizedApp(appid, wallet, w)) {
00488 return -1;
00489 }
00490 _handles[appid].append(rc);
00491 _wallets.value(rc)->ref();
00492 }
00493
00494 return rc;
00495 }
00496
00497
00498 bool KWalletD::isAuthorizedApp(const QString& appid, const QString& wallet, WId w) {
00499 int response = 0;
00500
00501 QString thisApp;
00502 if (appid.isEmpty()) {
00503 thisApp = "KDE System";
00504 } else {
00505 thisApp = appid;
00506 }
00507
00508 if (!implicitAllow(wallet, thisApp)) {
00509 KConfigGroup cfg = KSharedConfig::openConfig("kwalletrc")->group("Auto Allow");
00510 if (!cfg.isEntryImmutable(wallet)) {
00511 KBetterThanKDialog *dialog = new KBetterThanKDialog;
00512 if (appid.isEmpty()) {
00513 dialog->setLabel(i18n("<qt>KDE has requested access to the open wallet '<b>%1</b>'.</qt>", Qt::escape(wallet)));
00514 } else {
00515 dialog->setLabel(i18n("<qt>The application '<b>%1</b>' has requested access to the open wallet '<b>%2</b>'.</qt>", Qt::escape(QString(appid)), Qt::escape(wallet)));
00516 }
00517 setupDialog( dialog, w, appid, false );
00518 response = dialog->exec();
00519 delete dialog;
00520 }
00521 }
00522
00523 if (response == 0 || response == 1) {
00524 if (response == 1) {
00525 KConfigGroup cfg = KSharedConfig::openConfig("kwalletrc")->group("Auto Allow");
00526 QStringList apps = cfg.readEntry(wallet, QStringList());
00527 if (!apps.contains(thisApp)) {
00528 if (cfg.isEntryImmutable(wallet)) {
00529 return false;
00530 }
00531 apps += thisApp;
00532 _implicitAllowMap[wallet] += thisApp;
00533 cfg.writeEntry(wallet, apps);
00534 cfg.sync();
00535 }
00536 }
00537 } else if (response == 3) {
00538 KConfigGroup cfg = KSharedConfig::openConfig("kwalletrc")->group("Auto Deny");
00539 QStringList apps = cfg.readEntry(wallet, QStringList());
00540 if (!apps.contains(thisApp)) {
00541 apps += thisApp;
00542 _implicitDenyMap[wallet] += thisApp;
00543 cfg.writeEntry(wallet, apps);
00544 cfg.sync();
00545 }
00546 return false;
00547 } else {
00548 return false;
00549 }
00550 return true;
00551 }
00552
00553
00554 int KWalletD::deleteWallet(const QString& wallet) {
00555 QString path = KGlobal::dirs()->saveLocation("kwallet") + QDir::separator() + wallet + ".kwl";
00556
00557 if (QFile::exists(path)) {
00558 close(wallet, true);
00559 QFile::remove(path);
00560 emit walletDeleted(wallet);
00561 return 0;
00562 }
00563
00564 return -1;
00565 }
00566
00567
00568 void KWalletD::changePassword(const QString& wallet, qlonglong wId, const QString& appid, const QDBusMessage& msg) {
00569 KWalletTransaction *xact = new KWalletTransaction;
00570
00571
00572 xact->msg = msg;
00573 xact->appid = appid;
00574 xact->wallet = wallet;
00575 xact->wId = wId;
00576 xact->modal = false;
00577 xact->tType = KWalletTransaction::ChangePassword;
00578
00579 _transactions.append(xact);
00580
00581 QTimer::singleShot(0, this, SLOT(processTransactions()));
00582 checkActiveDialog();
00583 checkActiveDialog();
00584 }
00585
00586 void KWalletD::initiateSync(const QString& wallet) {
00587 assert(_synctimers.contains(wallet));
00588
00589 _synctimers[wallet]->start();
00590 }
00591
00592 void KWalletD::doTransactionChangePassword(const QString& appid, const QString& wallet, qlonglong wId) {
00593
00594 const QPair<int, KWallet::Backend*> walletInfo = findWallet(wallet);
00595 int handle = walletInfo.first;
00596 KWallet::Backend* w = walletInfo.second;
00597
00598 bool reclose = false;
00599 if (!w) {
00600 handle = doTransactionOpen(appid, wallet, wId, false);
00601 if (-1 == handle) {
00602 KMessageBox::sorryWId((WId)wId, i18n("Unable to open wallet. The wallet must be opened in order to change the password."), i18n("KDE Wallet Service"));
00603 return;
00604 }
00605
00606 w = _wallets.value(handle);
00607 reclose = true;
00608 }
00609
00610 assert(w);
00611
00612 KNewPasswordDialog *kpd = new KNewPasswordDialog();
00613 kpd->setPrompt(i18n("<qt>Please choose a new password for the wallet '<b>%1</b>'.</qt>", Qt::escape(wallet)));
00614 kpd->setCaption(i18n("KDE Wallet Service"));
00615 kpd->setAllowEmptyPasswords(true);
00616 setupDialog( kpd, (WId)wId, appid, false );
00617 if (kpd->exec() == KDialog::Accepted) {
00618 QString p = kpd->password();
00619 if (!p.isNull()) {
00620 _passwords[wallet] = p.toUtf8();
00621 int rc = w->close(p.toUtf8());
00622 if (rc < 0) {
00623 KMessageBox::sorryWId((WId)wId, i18n("Error re-encrypting the wallet. Password was not changed."), i18n("KDE Wallet Service"));
00624 reclose = true;
00625 } else {
00626 rc = w->open(p.toUtf8());
00627 if (rc < 0) {
00628 KMessageBox::sorryWId((WId)wId, i18n("Error reopening the wallet. Data may be lost."), i18n("KDE Wallet Service"));
00629 reclose = true;
00630 }
00631 }
00632 }
00633 }
00634
00635 delete kpd;
00636
00637 if (reclose) {
00638 close(handle, true, appid);
00639 }
00640 }
00641
00642
00643 int KWalletD::close(const QString& wallet, bool force) {
00644 const QPair<int, KWallet::Backend*> walletInfo = findWallet(wallet);
00645 int handle = walletInfo.first;
00646 KWallet::Backend* w = walletInfo.second;
00647
00648 return closeWallet(w, handle, force);
00649 }
00650
00651
00652 int KWalletD::closeWallet(KWallet::Backend *w, int handle, bool force) {
00653 if (w) {
00654 const QString& wallet = w->walletName();
00655 assert(_passwords.contains(wallet));
00656 assert(_synctimers.contains(wallet));
00657 if (w->refCount() == 0 || force) {
00658 invalidateHandle(handle);
00659 if (_closeIdle && _timeouts) {
00660 _timeouts->removeTimer(handle);
00661 }
00662 _wallets.remove(handle);
00663 delete _synctimers.take(wallet);
00664 if (_passwords.contains(wallet)) {
00665 w->close(QByteArray(_passwords[wallet].data(), _passwords[wallet].length()));
00666 _passwords[wallet].fill(0);
00667 _passwords.remove(wallet);
00668 }
00669 doCloseSignals(handle, wallet);
00670 delete w;
00671 return 0;
00672 }
00673 return 1;
00674 }
00675
00676 return -1;
00677 }
00678
00679
00680 int KWalletD::close(int handle, bool force, const QString& appid) {
00681 KWallet::Backend *w = _wallets.value(handle);
00682 bool contains = false;
00683
00684 if (w) {
00685 if (_handles.contains(appid)) {
00686 if (_handles[appid].contains(handle)) {
00687
00688 _handles[appid].removeAt(_handles[appid].indexOf(handle));
00689 contains = true;
00690 if (_handles[appid].isEmpty()) {
00691 _handles.remove(appid);
00692 }
00693 }
00694 }
00695
00696
00697 if ((contains && w->deref() == 0 && !_leaveOpen) || force) {
00698 if (_closeIdle && _timeouts) {
00699 _timeouts->removeTimer(handle);
00700 }
00701 _wallets.remove(handle);
00702 if (_synctimers.contains(w->walletName())) {
00703 delete _synctimers.take(w->walletName());
00704 }
00705 if (force) {
00706 invalidateHandle(handle);
00707 }
00708 if (_passwords.contains(w->walletName())) {
00709 w->close(QByteArray(_passwords[w->walletName()].data(), _passwords[w->walletName()].length()));
00710 _passwords[w->walletName()].fill(0);
00711 _passwords.remove(w->walletName());
00712 }
00713 doCloseSignals(handle, w->walletName());
00714 delete w;
00715 return 0;
00716 }
00717 return 1;
00718 }
00719
00720 return -1;
00721 }
00722
00723
00724 bool KWalletD::isOpen(const QString& wallet) {
00725 const QPair<int, KWallet::Backend*> walletInfo = findWallet(wallet);
00726 return walletInfo.second != 0;
00727 }
00728
00729
00730 bool KWalletD::isOpen(int handle) {
00731 if (handle == 0) {
00732 return false;
00733 }
00734
00735 KWallet::Backend *rc = _wallets.value(handle);
00736
00737 if (rc == 0 && ++_failed > 5) {
00738 _failed = 0;
00739 QTimer::singleShot(0, this, SLOT(notifyFailures()));
00740 } else if (rc != 0) {
00741 _failed = 0;
00742 }
00743
00744 return rc != 0;
00745 }
00746
00747
00748 QStringList KWalletD::wallets() const {
00749 QString path = KGlobal::dirs()->saveLocation("kwallet");
00750 QDir dir(path, "*.kwl");
00751 QStringList rc;
00752
00753 dir.setFilter(QDir::Files | QDir::NoSymLinks);
00754
00755 foreach (const QFileInfo &fi, dir.entryInfoList()) {
00756 QString fn = fi.fileName();
00757 if (fn.endsWith(".kwl")) {
00758 fn.truncate(fn.length()-4);
00759 }
00760 rc += fn;
00761 }
00762 return rc;
00763 }
00764
00765
00766 void KWalletD::sync(int handle, const QString& appid) {
00767 KWallet::Backend *b;
00768
00769
00770 if ((b = getWallet(appid, handle)) && _passwords.contains(b->walletName())) {
00771 QByteArray p;
00772 QString wallet = b->walletName();
00773 p = QByteArray(_passwords[wallet].data(), _passwords[wallet].length());
00774 b->sync(p);
00775 p.fill(0);
00776 }
00777 }
00778
00779 void KWalletD::doTransactionSync(const QString& wallet) {
00780 if (_synctimers.contains(wallet)) {
00781 _synctimers[wallet]->stop();
00782 }
00783 const QPair<int, KWallet::Backend*> walletInfo = findWallet(wallet);
00784
00785
00786 if (walletInfo.second && _passwords.contains(wallet)) {
00787 QByteArray p = QByteArray(_passwords[wallet].data(), _passwords[wallet].length());
00788 walletInfo.second->sync(p);
00789 p.fill(0);
00790 }
00791 }
00792
00793
00794 QStringList KWalletD::folderList(int handle, const QString& appid) {
00795 KWallet::Backend *b;
00796
00797 if ((b = getWallet(appid, handle))) {
00798 return b->folderList();
00799 }
00800
00801 return QStringList();
00802 }
00803
00804
00805 bool KWalletD::hasFolder(int handle, const QString& f, const QString& appid) {
00806 KWallet::Backend *b;
00807
00808 if ((b = getWallet(appid, handle))) {
00809 return b->hasFolder(f);
00810 }
00811
00812 return false;
00813 }
00814
00815
00816 bool KWalletD::removeFolder(int handle, const QString& f, const QString& appid) {
00817 KWallet::Backend *b;
00818
00819 if ((b = getWallet(appid, handle))) {
00820 bool rc = b->removeFolder(f);
00821 initiateSync(b->walletName());
00822 emit folderListUpdated(b->walletName());
00823 return rc;
00824 }
00825
00826 return false;
00827 }
00828
00829
00830 bool KWalletD::createFolder(int handle, const QString& f, const QString& appid) {
00831 KWallet::Backend *b;
00832
00833 if ((b = getWallet(appid, handle))) {
00834 bool rc = b->createFolder(f);
00835 initiateSync(b->walletName());
00836 emit folderListUpdated(b->walletName());
00837 return rc;
00838 }
00839
00840 return false;
00841 }
00842
00843
00844 QByteArray KWalletD::readMap(int handle, const QString& folder, const QString& key, const QString& appid) {
00845 KWallet::Backend *b;
00846
00847 if ((b = getWallet(appid, handle))) {
00848 b->setFolder(folder);
00849 KWallet::Entry *e = b->readEntry(key);
00850 if (e && e->type() == KWallet::Wallet::Map) {
00851 return e->map();
00852 }
00853 }
00854
00855 return QByteArray();
00856 }
00857
00858
00859 QVariantMap KWalletD::readMapList(int handle, const QString& folder, const QString& key, const QString& appid) {
00860 KWallet::Backend *b;
00861
00862 if ((b = getWallet(appid, handle))) {
00863 b->setFolder(folder);
00864 QVariantMap rc;
00865 foreach (KWallet::Entry *entry, b->readEntryList(key)) {
00866 if (entry->type() == KWallet::Wallet::Map) {
00867 rc.insert(entry->key(), entry->map());
00868 }
00869 }
00870 return rc;
00871 }
00872
00873 return QVariantMap();
00874 }
00875
00876
00877 QByteArray KWalletD::readEntry(int handle, const QString& folder, const QString& key, const QString& appid) {
00878 KWallet::Backend *b;
00879
00880 if ((b = getWallet(appid, handle))) {
00881 b->setFolder(folder);
00882 KWallet::Entry *e = b->readEntry(key);
00883 if (e) {
00884 return e->value();
00885 }
00886 }
00887
00888 return QByteArray();
00889 }
00890
00891
00892 QVariantMap KWalletD::readEntryList(int handle, const QString& folder, const QString& key, const QString& appid) {
00893 KWallet::Backend *b;
00894
00895 if ((b = getWallet(appid, handle))) {
00896 b->setFolder(folder);
00897 QVariantMap rc;
00898 foreach (KWallet::Entry *entry, b->readEntryList(key)) {
00899 rc.insert(entry->key(), entry->value());
00900 }
00901 return rc;
00902 }
00903
00904 return QVariantMap();
00905 }
00906
00907
00908 QStringList KWalletD::entryList(int handle, const QString& folder, const QString& appid) {
00909 KWallet::Backend *b;
00910
00911 if ((b = getWallet(appid, handle))) {
00912 b->setFolder(folder);
00913 return b->entryList();
00914 }
00915
00916 return QStringList();
00917 }
00918
00919
00920 QString KWalletD::readPassword(int handle, const QString& folder, const QString& key, const QString& appid) {
00921 KWallet::Backend *b;
00922
00923 if ((b = getWallet(appid, handle))) {
00924 b->setFolder(folder);
00925 KWallet::Entry *e = b->readEntry(key);
00926 if (e && e->type() == KWallet::Wallet::Password) {
00927 return e->password();
00928 }
00929 }
00930
00931 return QString();
00932 }
00933
00934
00935 QVariantMap KWalletD::readPasswordList(int handle, const QString& folder, const QString& key, const QString& appid) {
00936 KWallet::Backend *b;
00937
00938 if ((b = getWallet(appid, handle))) {
00939 b->setFolder(folder);
00940 QVariantMap rc;
00941 foreach (KWallet::Entry *entry, b->readEntryList(key)) {
00942 if (entry->type() == KWallet::Wallet::Password) {
00943 rc.insert(entry->key(), entry->password());
00944 }
00945 }
00946 return rc;
00947 }
00948
00949 return QVariantMap();
00950 }
00951
00952
00953 int KWalletD::writeMap(int handle, const QString& folder, const QString& key, const QByteArray& value, const QString& appid) {
00954 KWallet::Backend *b;
00955
00956 if ((b = getWallet(appid, handle))) {
00957 b->setFolder(folder);
00958 KWallet::Entry e;
00959 e.setKey(key);
00960 e.setValue(value);
00961 e.setType(KWallet::Wallet::Map);
00962 b->writeEntry(&e);
00963 initiateSync(b->walletName());
00964 emitFolderUpdated(b->walletName(), folder);
00965 return 0;
00966 }
00967
00968 return -1;
00969 }
00970
00971
00972 int KWalletD::writeEntry(int handle, const QString& folder, const QString& key, const QByteArray& value, int entryType, const QString& appid) {
00973 KWallet::Backend *b;
00974
00975 if ((b = getWallet(appid, handle))) {
00976 b->setFolder(folder);
00977 KWallet::Entry e;
00978 e.setKey(key);
00979 e.setValue(value);
00980 e.setType(KWallet::Wallet::EntryType(entryType));
00981 b->writeEntry(&e);
00982 initiateSync(b->walletName());
00983 emitFolderUpdated(b->walletName(), folder);
00984 return 0;
00985 }
00986
00987 return -1;
00988 }
00989
00990
00991 int KWalletD::writeEntry(int handle, const QString& folder, const QString& key, const QByteArray& value, const QString& appid) {
00992 KWallet::Backend *b;
00993
00994 if ((b = getWallet(appid, handle))) {
00995 b->setFolder(folder);
00996 KWallet::Entry e;
00997 e.setKey(key);
00998 e.setValue(value);
00999 e.setType(KWallet::Wallet::Stream);
01000 b->writeEntry(&e);
01001 initiateSync(b->walletName());
01002 emitFolderUpdated(b->walletName(), folder);
01003 return 0;
01004 }
01005
01006 return -1;
01007 }
01008
01009
01010 int KWalletD::writePassword(int handle, const QString& folder, const QString& key, const QString& value, const QString& appid) {
01011 KWallet::Backend *b;
01012
01013 if ((b = getWallet(appid, handle))) {
01014 b->setFolder(folder);
01015 KWallet::Entry e;
01016 e.setKey(key);
01017 e.setValue(value);
01018 e.setType(KWallet::Wallet::Password);
01019 b->writeEntry(&e);
01020 initiateSync(b->walletName());
01021 emitFolderUpdated(b->walletName(), folder);
01022 return 0;
01023 }
01024
01025 return -1;
01026 }
01027
01028
01029 int KWalletD::entryType(int handle, const QString& folder, const QString& key, const QString& appid) {
01030 KWallet::Backend *b;
01031
01032 if ((b = getWallet(appid, handle))) {
01033 if (!b->hasFolder(folder)) {
01034 return KWallet::Wallet::Unknown;
01035 }
01036 b->setFolder(folder);
01037 if (b->hasEntry(key)) {
01038 return b->readEntry(key)->type();
01039 }
01040 }
01041
01042 return KWallet::Wallet::Unknown;
01043 }
01044
01045
01046 bool KWalletD::hasEntry(int handle, const QString& folder, const QString& key, const QString& appid) {
01047 KWallet::Backend *b;
01048
01049 if ((b = getWallet(appid, handle))) {
01050 if (!b->hasFolder(folder)) {
01051 return false;
01052 }
01053 b->setFolder(folder);
01054 return b->hasEntry(key);
01055 }
01056
01057 return false;
01058 }
01059
01060
01061 int KWalletD::removeEntry(int handle, const QString& folder, const QString& key, const QString& appid) {
01062 KWallet::Backend *b;
01063
01064 if ((b = getWallet(appid, handle))) {
01065 if (!b->hasFolder(folder)) {
01066 return 0;
01067 }
01068 b->setFolder(folder);
01069 bool rc = b->removeEntry(key);
01070 initiateSync(b->walletName());
01071 emitFolderUpdated(b->walletName(), folder);
01072 return rc ? 0 : -3;
01073 }
01074
01075 return -1;
01076 }
01077
01078
01079 void KWalletD::slotServiceUnregistered(const QString& app) {
01080 if (_handles.contains(app)) {
01081 QList<int> l = _handles[app];
01082 for (QList<int>::Iterator i = l.begin(); i != l.end(); ++i) {
01083 _handles[app].removeAll(*i);
01084 KWallet::Backend *w = _wallets.value(*i);
01085 if (w && !_leaveOpen && 0 == w->deref()) {
01086 close(w->walletName(), true);
01087 }
01088 }
01089 _handles.remove(app);
01090 }
01091 }
01092
01093
01094 void KWalletD::invalidateHandle(int handle) {
01095 for (QHash<QString,QList<int> >::Iterator i = _handles.begin();
01096 i != _handles.end();
01097 ++i) {
01098 i.value().removeAll(handle);
01099 }
01100 }
01101
01102
01103 KWallet::Backend *KWalletD::getWallet(const QString& appid, int handle) {
01104 if (handle == 0) {
01105 return 0L;
01106 }
01107
01108 KWallet::Backend *w = _wallets.value(handle);
01109
01110 if (w) {
01111 if (_handles.contains(appid)) {
01112 if (_handles[appid].contains(handle)) {
01113
01114 _failed = 0;
01115 if (_closeIdle && _timeouts) {
01116 _timeouts->resetTimer(handle, _idleTime);
01117 }
01118 return w;
01119 }
01120 }
01121 }
01122
01123 if (++_failed > 5) {
01124 _failed = 0;
01125 QTimer::singleShot(0, this, SLOT(notifyFailures()));
01126 }
01127
01128 return 0L;
01129 }
01130
01131
01132 void KWalletD::notifyFailures() {
01133 if (!_showingFailureNotify) {
01134 _showingFailureNotify = true;
01135 KMessageBox::information(0, i18n("There have been repeated failed attempts to gain access to a wallet. An application may be misbehaving."), i18n("KDE Wallet Service"));
01136 _showingFailureNotify = false;
01137 }
01138 }
01139
01140
01141 void KWalletD::doCloseSignals(int handle, const QString& wallet) {
01142 emit walletClosed(handle);
01143 emit walletClosed(wallet);
01144 if (_wallets.isEmpty()) {
01145 emit allWalletsClosed();
01146 }
01147 }
01148
01149
01150 int KWalletD::renameEntry(int handle, const QString& folder, const QString& oldName, const QString& newName, const QString& appid) {
01151 KWallet::Backend *b;
01152
01153 if ((b = getWallet(appid, handle))) {
01154 b->setFolder(folder);
01155 int rc = b->renameEntry(oldName, newName);
01156 initiateSync(b->walletName());
01157 emitFolderUpdated(b->walletName(), folder);
01158 return rc;
01159 }
01160
01161 return -1;
01162 }
01163
01164
01165 QStringList KWalletD::users(const QString& wallet) const {
01166 QStringList rc;
01167
01168 const QPair<int, KWallet::Backend*> walletInfo = findWallet(wallet);
01169 int handle = walletInfo.first;
01170 KWallet::Backend* w = walletInfo.second;
01171
01172 if (w) {
01173 for (QHash<QString,QList<int> >::ConstIterator hit = _handles.begin(); hit != _handles.end(); ++hit) {
01174 if (hit.value().contains(handle)) {
01175 rc.append(hit.key());
01176 }
01177 }
01178 }
01179
01180 return rc;
01181 }
01182
01183
01184 bool KWalletD::disconnectApplication(const QString& wallet, const QString& application) {
01185 const QPair<int, KWallet::Backend*> walletInfo = findWallet(wallet);
01186 int handle = walletInfo.first;
01187 KWallet::Backend* backend = walletInfo.second;
01188
01189 if (handle != -1 && _handles[application].contains(handle)) {
01190 _handles[application].removeAll(handle);
01191
01192 if (_handles[application].isEmpty()) {
01193 _handles.remove(application);
01194 }
01195
01196 if (backend->deref() == 0) {
01197 close(backend->walletName(), true);
01198 }
01199
01200 emit applicationDisconnected(wallet, application);
01201 return true;
01202 }
01203
01204 return false;
01205 }
01206
01207
01208 void KWalletD::emitFolderUpdated(const QString& wallet, const QString& folder) {
01209 emit folderUpdated(wallet, folder);
01210 }
01211
01212
01213 void KWalletD::emitWalletListDirty() {
01214 emit walletListDirty();
01215 }
01216
01217
01218 void KWalletD::reconfigure() {
01219 KConfig cfg("kwalletrc");
01220 KConfigGroup walletGroup(&cfg, "Wallet");
01221 _firstUse = walletGroup.readEntry("First Use", true);
01222 _enabled = walletGroup.readEntry("Enabled", true);
01223 _launchManager = walletGroup.readEntry("Launch Manager", true);
01224 _leaveOpen = walletGroup.readEntry("Leave Open", false);
01225 bool idleSave = _closeIdle;
01226 _closeIdle = walletGroup.readEntry("Close When Idle", false);
01227 _openPrompt = walletGroup.readEntry("Prompt on Open", true);
01228 int timeSave = _idleTime;
01229
01230 _idleTime = walletGroup.readEntry("Idle Timeout", 10) * 60 * 1000;
01231 #ifdef Q_WS_X11
01232 if ( screensaver->isValid() ) {
01233 if (walletGroup.readEntry("Close on Screensaver", false)) {
01234 connect(screensaver, SIGNAL(ActiveChanged(bool)), SLOT(screenSaverChanged(bool)));
01235 } else {
01236 screensaver->disconnect(SIGNAL(ActiveChanged(bool)), this, SLOT(screenSaverChanged(bool)));
01237 }
01238 }
01239 #endif
01240
01241 if (_closeIdle) {
01242 if (_idleTime != timeSave) {
01243 Wallets::const_iterator it = _wallets.begin();
01244 const Wallets::const_iterator end = _wallets.end();
01245 for (; it != end; ++it) {
01246 _timeouts->resetTimer(it.key(), _idleTime);
01247 }
01248 }
01249
01250 if (!idleSave) {
01251 Wallets::const_iterator it = _wallets.begin();
01252 const Wallets::const_iterator end = _wallets.end();
01253 for (; it != end; ++it) {
01254 _timeouts->addTimer(it.key(), _idleTime);
01255 }
01256 }
01257 } else {
01258 _timeouts->clear();
01259 }
01260
01261
01262 _implicitAllowMap.clear();
01263 const KConfigGroup autoAllowGroup(&cfg, "Auto Allow");
01264 QStringList entries = autoAllowGroup.entryMap().keys();
01265 for (QStringList::Iterator i = entries.begin(); i != entries.end(); ++i) {
01266 _implicitAllowMap[*i] = autoAllowGroup.readEntry(*i, QStringList());
01267 }
01268
01269
01270 _implicitDenyMap.clear();
01271 const KConfigGroup autoDenyGroup(&cfg, "Auto Deny");
01272 entries = autoDenyGroup.entryMap().keys();
01273 for (QStringList::Iterator i = entries.begin(); i != entries.end(); ++i) {
01274 _implicitDenyMap[*i] = autoDenyGroup.readEntry(*i, QStringList());
01275 }
01276
01277
01278 if (!_enabled) {
01279 while (!_wallets.isEmpty()) {
01280 Wallets::const_iterator it = _wallets.begin();
01281 closeWallet(it.value(), it.key(), true);
01282 }
01283 KUniqueApplication::exit(0);
01284 }
01285 }
01286
01287
01288 bool KWalletD::isEnabled() const {
01289 return _enabled;
01290 }
01291
01292
01293 bool KWalletD::folderDoesNotExist(const QString& wallet, const QString& folder) {
01294 if (!wallets().contains(wallet)) {
01295 return true;
01296 }
01297
01298 const QPair<int, KWallet::Backend*> walletInfo = findWallet(wallet);
01299 if (walletInfo.second) {
01300 return walletInfo.second->folderDoesNotExist(folder);
01301 }
01302
01303 KWallet::Backend *b = new KWallet::Backend(wallet);
01304 b->open(QByteArray());
01305 bool rc = b->folderDoesNotExist(folder);
01306 delete b;
01307 return rc;
01308 }
01309
01310
01311 bool KWalletD::keyDoesNotExist(const QString& wallet, const QString& folder, const QString& key) {
01312 if (!wallets().contains(wallet)) {
01313 return true;
01314 }
01315
01316 const QPair<int, KWallet::Backend*> walletInfo = findWallet(wallet);
01317 if (walletInfo.second) {
01318 return walletInfo.second->entryDoesNotExist(folder, key);
01319 }
01320
01321 KWallet::Backend *b = new KWallet::Backend(wallet);
01322 b->open(QByteArray());
01323 bool rc = b->entryDoesNotExist(folder, key);
01324 delete b;
01325 return rc;
01326 }
01327
01328
01329 bool KWalletD::implicitAllow(const QString& wallet, const QString& app) {
01330 return _implicitAllowMap[wallet].contains(app);
01331 }
01332
01333
01334 bool KWalletD::implicitDeny(const QString& wallet, const QString& app) {
01335 return _implicitDenyMap[wallet].contains(app);
01336 }
01337
01338
01339 void KWalletD::timedOut(int id) {
01340 KWallet::Backend *w = _wallets.value(id);
01341 if (w) {
01342 closeWallet(w, id, true);
01343 }
01344 }
01345
01346
01347 void KWalletD::closeAllWallets() {
01348 Wallets walletsCopy = _wallets;
01349
01350 Wallets::const_iterator it = walletsCopy.begin();
01351 const Wallets::const_iterator end = walletsCopy.end();
01352 for (; it != end; ++it) {
01353 closeWallet(it.value(), it.key(), true);
01354 }
01355
01356 walletsCopy.clear();
01357
01358
01359 _wallets.clear();
01360
01361 for (QMap<QString,QByteArray>::Iterator it = _passwords.begin();
01362 it != _passwords.end();
01363 ++it) {
01364 it.value().fill(0);
01365 }
01366 _passwords.clear();
01367 }
01368
01369
01370 QString KWalletD::networkWallet() {
01371 return KWallet::Wallet::NetworkWallet();
01372 }
01373
01374
01375 QString KWalletD::localWallet() {
01376 return KWallet::Wallet::LocalWallet();
01377 }
01378
01379 void KWalletD::screenSaverChanged(bool s)
01380 {
01381 if (s)
01382 closeAllWallets();
01383 }
01384
01385 #include "kwalletd.moc"
01386 #include "kwalletdadaptor.moc"