kio Library API Documentation

kwalletd.cpp

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