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