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