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