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