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