kio Library API Documentation

kwalletd.cpp

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