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