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