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