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