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