-rw-r--r-- | pwmanager/pwmanager/pwmdoc.cpp | 65 | ||||
-rw-r--r-- | pwmanager/pwmanager/pwmdoc.h | 2 | ||||
-rw-r--r-- | pwmanager/pwmanager/pwmdocui.cpp | 12 |
3 files changed, 67 insertions, 12 deletions
diff --git a/pwmanager/pwmanager/pwmdoc.cpp b/pwmanager/pwmanager/pwmdoc.cpp index e9906a4..f4a1636 100644 --- a/pwmanager/pwmanager/pwmdoc.cpp +++ b/pwmanager/pwmanager/pwmdoc.cpp @@ -1,78 +1,78 @@ /*************************************************************************** * * * copyright (C) 2003, 2004 by Michael Buesch * * email: mbuesch@freenet.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License version 2 * * as published by the Free Software Foundation. * * * ***************************************************************************/ /*************************************************************************** * copyright (C) 2004 by Ulf Schenk - * This file is originaly based on version 2.0 of pwmanager + * This file is originaly based on version 1.1 of pwmanager * and was modified to run on embedded devices that run microkde * * $Id$ **************************************************************************/ #include "pwmdoc.h" #include "pwmview.h" #include "blowfish.h" #include "sha1.h" #include "globalstuff.h" #include "gpasmanfile.h" #include "serializer.h" #include "compressgzip.h" //US#include "compressbzip2.h" #include "randomizer.h" #include "pwminit.h" #include "libgcryptif.h" #ifdef PWM_EMBEDDED #include "pwmprefs.h" #include "kglobal.h" #endif #include <kmessagebox.h> #include <libkcal/syncdefines.h> #ifdef CONFIG_KWALLETIF # include "kwalletemu.h" #endif // CONFIG_KWALLETIF #include <qdatetime.h> #include <qsize.h> #include <qfileinfo.h> #include <qfile.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> //US#include <iostream> #include <algorithm> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <stdint.h> #ifdef PWM_EMBEDDED #ifndef Q_LONG #define Q_LONG long #endif #ifndef Q_ULONG #define Q_ULONG unsigned long #endif #endif //PWM_EMBEDDED //TODO: reset to its normal value. #define META_CHECK_TIMER_INTERVAL 10/*300*/ /* sek */ using namespace std; @@ -269,276 +269,318 @@ void DocTimer::metaCheckTimeout() metaCheckTimer->start(1000, true); return; } if (doc->isDeepLocked()) { metaCheckTimer->start(META_CHECK_TIMER_INTERVAL * 1000, true); return; } if (doc->isDocEmpty()) { metaCheckTimer->start(META_CHECK_TIMER_INTERVAL * 1000, true); return; } #ifdef CONFIG_KWALLETIF KWalletEmu *kwlEmu = doc->init->kwalletEmu(); if (kwlEmu) kwlEmu->suspendDocSignals(); #endif // CONFIG_KWALLETIF /* We simply trigger all views to update their * displayed values. This way they have a chance * to get notified when some meta changes over time. * (for example an entry expired). * The _view_ is responsive for not updating its * contents if nothing really changed! */ emit doc->dataChanged(doc); #ifdef CONFIG_KWALLETIF if (kwlEmu) kwlEmu->resumeDocSignals(); #endif // CONFIG_KWALLETIF metaCheckTimer->start(META_CHECK_TIMER_INTERVAL * 1000, true); } PwMDocList PwMDoc::openDocList; unsigned int PwMDocList::unnamedDocCnt = 1; PwMDoc::PwMDoc(QObject *parent, const char *name) : PwMDocUi(parent, name) , dataChangedLock (0) { deleted = false; unnamedNum = 0; getOpenDocList()->add(this, getTitle().latin1()); curDocStat = 0; setMaxNumEntries(); _timer = new DocTimer(this); timer()->start(DocTimer::id_mpwTimer); timer()->start(DocTimer::id_autoLockTimer); timer()->start(DocTimer::id_metaCheckTimer); addCategory(DEFAULT_CATEGORY, 0, false); listView = 0; emit docCreated(this); } PwMDoc::~PwMDoc() { emit docClosed(this); getOpenDocList()->del(this); delete _timer; } PwMerror PwMDoc::saveDoc(char compress, const QString *file) { PwMerror ret, e; + string serialized; + QFile f; + QString tmpFileMoved(QString::null); + bool wasDeepLocked; + QString savedFilename(filename); + if (!file) { if (filename == "") return e_filename; - } else { + if (isDeepLocked()) { + /* We don't need to save any data. + * It's already all on disk, because + * we are deeplocked. + */ + unsetDocStatFlag(DOC_STAT_DISK_DIRTY); + ret = e_success; + goto out; + } + } else { if (*file == "" && filename == "") return e_filename; if (*file != "") filename = *file; } - bool wasDeepLocked = isDeepLocked(); + wasDeepLocked = isDeepLocked(); if (wasDeepLocked) { - if (deepLock(false) != e_success) - return e_noPw; + /* We are deeplocked. That means all data is already + * on disk. BUT we need to do saving procedure, + * because *file != savedFilename. + * Additionally we need to tempoarly restore + * the old "filename", because deepLock() references it. + */ + QString newFilename(filename); + filename = savedFilename; + getDataChangedLock(); + e = deepLock(false); + putDataChangedLock(); + filename = newFilename; + switch (e) { + case e_success: + break; + case e_wrongPw: + case e_noPw: + emitDataChanged(this); + return e; + default: + emitDataChanged(this); + return e_openFile; + } } if (!isPwAvailable()) { /* password is not available. This means, the * document wasn't saved, yet. */ bool useChipcard = getDocStatFlag(DOC_STAT_USE_CHIPCARD); QString pw(requestNewMpw(&useChipcard)); if (pw != "") { currentPw = pw; } else { return e_noPw; } if (useChipcard) { setDocStatFlag(DOC_STAT_USE_CHIPCARD); } else { unsetDocStatFlag(DOC_STAT_USE_CHIPCARD); } } int _cryptAlgo = conf()->confGlobCryptAlgo(); int _hashAlgo = conf()->confGlobHashAlgo(); // sanity check for the selected algorithms if (_cryptAlgo < PWM_CRYPT_BLOWFISH || _cryptAlgo > PWM_CRYPT_TWOFISH128) { printWarn("Invalid Crypto-Algorithm selected! " "Config-file seems to be corrupt. " "Falling back to Blowfish."); _cryptAlgo = PWM_CRYPT_BLOWFISH; } if (_hashAlgo < PWM_HASH_SHA1 || _hashAlgo > PWM_HASH_TIGER) { printWarn("Invalid Hash-Algorithm selected! " "Config-file seems to be corrupt. " "Falling back to SHA1."); _hashAlgo = PWM_HASH_SHA1; } char cryptAlgo = static_cast<char>(_cryptAlgo); char hashAlgo = static_cast<char>(_hashAlgo); if (conf()->confGlobMakeFileBackup()) { if (!backupFile(filename)) return e_fileBackup; } - QString tmpFileMoved(QString::null); if (QFile::exists(filename)) { /* Move the existing file to some tmp file. * When saving file succeeds, delete tmp file. Otherwise * move tmp file back. See below. */ Randomizer *rnd = Randomizer::obj(); char rnd_buf[5]; sprintf(rnd_buf, "%X%X%X%X", rnd->genRndChar() & 0xFF, rnd->genRndChar() & 0xFF, rnd->genRndChar() & 0xFF, rnd->genRndChar() & 0xFF); tmpFileMoved = filename + "." + rnd_buf + ".mv"; if (!copyFile(filename, tmpFileMoved)) return e_openFile; if (!QFile::remove(filename)) { printWarn(string("removing orig file ") + filename.latin1() + " failed!"); } } - QFile f(filename); - string serialized; + f.setName(filename); if (!f.open(IO_ReadWrite)) { ret = e_openFile; goto out_moveback; } e = writeFileHeader(hashAlgo, hashAlgo, cryptAlgo, compress, ¤tPw, &f); if (e == e_hashNotImpl) { printDebug("PwMDoc::saveDoc(): writeFileHeader() failed: e_hashNotImpl"); f.close(); ret = e_hashNotImpl; goto out_moveback; } else if (e != e_success) { printDebug("PwMDoc::saveDoc(): writeFileHeader() failed"); f.close(); ret = e_writeHeader; goto out_moveback; } if (!serializeDta(&serialized)) { printDebug("PwMDoc::saveDoc(): serializeDta() failed"); f.close(); ret = e_serializeDta; goto out_moveback; } e = writeDataHash(hashAlgo, &serialized, &f); if (e == e_hashNotImpl) { printDebug("PwMDoc::saveDoc(): writeDataHash() failed: e_hashNotImpl"); f.close(); ret = e_hashNotImpl; goto out_moveback; } else if (e != e_success) { printDebug("PwMDoc::saveDoc(): writeDataHash() failed"); f.close(); ret = e_writeHeader; goto out_moveback; } if (!compressDta(&serialized, compress)) { printDebug("PwMDoc::saveDoc(): compressDta() failed"); f.close(); ret = e_enc; goto out_moveback; } e = encrypt(&serialized, ¤tPw, &f, cryptAlgo); if (e == e_weakPw) { printDebug("PwMDoc::saveDoc(): encrypt() failed: e_weakPw"); f.close(); ret = e_weakPw; goto out_moveback; } else if (e == e_cryptNotImpl) { printDebug("PwMDoc::saveDoc(): encrypt() failed: e_cryptNotImpl"); f.close(); ret = e_cryptNotImpl; goto out_moveback; } else if (e != e_success) { printDebug("PwMDoc::saveDoc(): encrypt() failed"); f.close(); ret = e_enc; goto out_moveback; } unsetDocStatFlag(DOC_STAT_DISK_DIRTY); f.close(); if (chmod(filename.latin1(), conf()->confGlobFilePermissions())) { printWarn(string("chmod failed: ") + strerror(errno)); } openDocList.edit(this, getTitle().latin1()); - if (wasDeepLocked) - deepLock(true); + if (wasDeepLocked) { + /* Do _not_ save the data with the deepLock() + * call, because this will recurse + * into saveDoc() + */ + deepLock(true, false); + /* We don't check return value here, because + * it won't fail. See NOTE in deepLock() + */ + } if (tmpFileMoved != QString::null) { // now remove the moved file. if (!QFile::remove(tmpFileMoved)) { printWarn(string("removing file ") + tmpFileMoved.latin1() + " failed!"); } } ret = e_success; printDebug(string("writing file { name: ") + filename.latin1() + " compress: " + tostr(static_cast<int>(compress)) + " cryptAlgo: " + tostr(static_cast<int>(cryptAlgo)) + " hashAlgo: " + tostr(static_cast<int>(hashAlgo)) + " }"); goto out; out_moveback: if (tmpFileMoved != QString::null) { if (copyFile(tmpFileMoved, filename)) { if (!QFile::remove(tmpFileMoved)) { printWarn(string("removing tmp file ") + filename.latin1() + " failed!"); } } else { printWarn(string("couldn't copy file ") + tmpFileMoved.latin1() + " back to " + filename.latin1()); } } out: return ret; } PwMerror PwMDoc::openDoc(const QString *file, int openLocked) { PWM_ASSERT(file); PWM_ASSERT(openLocked == 0 || openLocked == 1 || openLocked == 2); string decrypted, dataHash; PwMerror ret; char cryptAlgo, dataHashType, compress; unsigned int headerLen; if (*file == "") return e_readFile; filename = *file; /* check if this file is already open. * This does not catch symlinks! */ if (!isDeepLocked()) { if (getOpenDocList()->find(filename.latin1())) return e_alreadyOpen; } QFile f(filename); if (openLocked == 2) { // open deep-locked if (!QFile::exists(filename)) return e_openFile; if (deepLock(true, false) != e_success) return e_openFile; goto out_success; } @@ -1708,128 +1750,131 @@ bool PwMDoc::unlockAll_tempoary(bool revert) } ++entrI; } if (mustUnlock) break; ++catI; } } if (!mustUnlock) { // nothing to do. timer()->stop(DocTimer::id_autoLockTimer); printDebug("unlockAll_tempoary(): nothing to do."); return true; } else if (!wasDeepLocked) { if (!getDocStatFlag(DOC_STAT_UNLOCK_WITHOUT_PW) && currentPw != "") { /* we can't unlock without mpw, so * we need to ask for it. */ QString pw; while (1) { pw = requestMpw(getDocStatFlag(DOC_STAT_USE_CHIPCARD)); if (pw == "") { return false; } else if (pw == currentPw) { break; } wrongMpwMsgBox(getDocStatFlag(DOC_STAT_USE_CHIPCARD)); } } } timer()->stop(DocTimer::id_autoLockTimer); oldLockStates = new vector< vector<bool> >; vector<bool> tmp_vec; vector<PwMCategoryItem>::iterator catBegin = dti.dta.begin(), catEnd = dti.dta.end(), catI = catBegin; vector<PwMDataItem>::iterator entrBegin, entrEnd, entrI; while (catI != catEnd) { entrBegin = catI->d.begin(); entrEnd = catI->d.end(); entrI = entrBegin; while (entrI != entrEnd) { if (!wasDeepLocked) { tmp_vec.push_back(entrI->lockStat); } entrI->lockStat = false; ++entrI; } if (!wasDeepLocked) { oldLockStates->push_back(tmp_vec); tmp_vec.clear(); } ++catI; } printDebug("tempoary unlocked dta."); } return true; } PwMerror PwMDoc::deepLock(bool lock, bool saveToFile) { PwMerror ret; + /* NOTE: saveDoc() depends on this function to return + * e_success if saveToFile == false + */ if (lock) { if (isDeepLocked()) return e_lock; if (saveToFile) { if (isDocEmpty()) return e_docIsEmpty; ret = saveDoc(conf()->confGlobCompression()); if (ret == e_filename) { /* the doc wasn't saved to a file * by the user, yet. */ cantDeeplock_notSavedMsgBox(); return e_docNotSaved; } else if (ret != e_success) { return e_lock; } } timer()->stop(DocTimer::id_autoLockTimer); clearDoc(); PwMDataItem d; d.desc = IS_DEEPLOCKED_SHORTMSG.latin1(); d.comment = IS_DEEPLOCKED_MSG.latin1(); d.listViewPos = 0; addEntry(DEFAULT_CATEGORY, &d, true); lockAt(DEFAULT_CATEGORY, 0, true); unsetDocStatFlag(DOC_STAT_DISK_DIRTY); setDocStatFlag(DOC_STAT_DEEPLOCKED); } else { if (!isDeepLocked()) return e_lock; ret = openDoc(&filename, (conf()->confGlobUnlockOnOpen()) ? 0 : 1); if (ret == e_wrongPw) { return e_wrongPw; } else if (ret != e_success) { printDebug(string("PwMDoc::deepLock(false): ERR! openDoc() == ") + tostr(static_cast<int>(ret))); return e_lock; } unsetDocStatFlag(DOC_STAT_DEEPLOCKED); timer()->start(DocTimer::id_autoLockTimer); } emitDataChanged(this); return e_success; } void PwMDoc::_deepUnlock() { deepLock(false); } void PwMDoc::clearDoc() { dti.clear(); PwMCategoryItem d; d.name = DEFAULT_CATEGORY.latin1(); dti.dta.push_back(d); currentPw = ""; unsetDocStatFlag(DOC_STAT_UNLOCK_WITHOUT_PW); } void PwMDoc::changeCurrentPw() diff --git a/pwmanager/pwmanager/pwmdoc.h b/pwmanager/pwmanager/pwmdoc.h index 535fb92..a6e5f58 100644 --- a/pwmanager/pwmanager/pwmdoc.h +++ b/pwmanager/pwmanager/pwmdoc.h @@ -1,78 +1,78 @@ /*************************************************************************** * * * copyright (C) 2003, 2004 by Michael Buesch * * email: mbuesch@freenet.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License version 2 * * as published by the Free Software Foundation. * * * ***************************************************************************/ /*************************************************************************** * copyright (C) 2004 by Ulf Schenk - * This file is originaly based on version 2.0 of pwmanager + * This file is originaly based on version 1.1 of pwmanager * and was modified to run on embedded devices that run microkde * * $Id$ **************************************************************************/ #ifndef __PWMDOC_H #define __PWMDOC_H #define PWM_FILE_VER (static_cast<char>(0x05)) #define PWM_HASH_SHA1 (static_cast<char>(0x01)) #define PWM_HASH_SHA256 (static_cast<char>(0x02)) #define PWM_HASH_SHA384 (static_cast<char>(0x03)) #define PWM_HASH_SHA512 (static_cast<char>(0x04)) #define PWM_HASH_MD5 (static_cast<char>(0x05)) #define PWM_HASH_RMD160 (static_cast<char>(0x06)) #define PWM_HASH_TIGER (static_cast<char>(0x07)) #define PWM_CRYPT_BLOWFISH (static_cast<char>(0x01)) #define PWM_CRYPT_AES128 (static_cast<char>(0x02)) #define PWM_CRYPT_AES192 (static_cast<char>(0x03)) #define PWM_CRYPT_AES256 (static_cast<char>(0x04)) #define PWM_CRYPT_3DES (static_cast<char>(0x05)) #define PWM_CRYPT_TWOFISH (static_cast<char>(0x06)) #define PWM_CRYPT_TWOFISH128 (static_cast<char>(0x07)) #define PWM_COMPRESS_NONE (static_cast<char>(0x00)) #define PWM_COMPRESS_GZIP (static_cast<char>(0x01)) #define PWM_COMPRESS_BZIP2 (static_cast<char>(0x02)) #define DEFAULT_MAX_ENTRIES (~(static_cast<unsigned int>(0))) #define FILE_ID_HEADER "PWM_PASSWORD_FILE" #include "pwmexception.h" #include "pwmdocui.h" #include <qobject.h> #include <qtimer.h> #include <qdatetime.h> #include <kprocess.h> #ifndef PWM_EMBEDDED #include "configuration.h" #else #include <kapplication.h> #include <ksyncmanager.h> #endif #include <string> #include <vector> #include <utility> using std::vector; using std::string; using std::pair; /* used in findEntry() function */ #define SEARCH_IN_DESC (1) #define SEARCH_IN_NAME (1 << 1) #define SEARCH_IN_PW (1 << 2) #define SEARCH_IN_COMMENT (1 << 3) #define SEARCH_IN_URL (1 << 4) diff --git a/pwmanager/pwmanager/pwmdocui.cpp b/pwmanager/pwmanager/pwmdocui.cpp index 7b8e0ee..6ddb6f5 100644 --- a/pwmanager/pwmanager/pwmdocui.cpp +++ b/pwmanager/pwmanager/pwmdocui.cpp @@ -212,174 +212,184 @@ int PwMDocUi::dirtyAskSave(const QString &docTitle) int ret; #ifndef PWM_EMBEDDED ret = KMessageBox::questionYesNoCancel(currentView, i18n("The list \"") + docTitle + i18n ("\" has been modified.\n" "Do you want to save it?"), i18n("save?")); if (ret == KMessageBox::Yes) { return 0; } else if (ret == KMessageBox::No) { return 1; } #else ret = KMessageBox::warningYesNoCancel(currentView, i18n("The list \"") + docTitle + i18n ("\"\nhas been modified.\n" "Do you want to save it?"), i18n("save?")); if (ret == KMessageBox::Yes) { return 0; } else if (ret == KMessageBox::No) { return 1; } #endif // cancel return -1; } bool PwMDocUi::saveDocUi(PwMDoc *doc) { PWM_ASSERT(doc); doc->timer()->getLock(DocTimer::id_autoLockTimer); if (doc->isDocEmpty()) { KMessageBox::information(currentView, i18n ("Sorry, there's nothing to save.\n" "Please first add some passwords."), i18n("nothing to do")); doc->timer()->putLock(DocTimer::id_autoLockTimer); return true; } PwMerror ret = doc->saveDoc(conf()->confGlobCompression()); if (ret == e_filename) { doc->timer()->putLock(DocTimer::id_autoLockTimer); return saveAsDocUi(doc); } else if (ret == e_weakPw) { KMessageBox::error(currentView, i18n("Error: This is a weak password.\n" "Please select another password."), i18n("weak password")); doc->timer()->putLock(DocTimer::id_autoLockTimer); return false; } else if (ret == e_fileBackup) { KMessageBox::error(currentView, i18n("Error: Couldn't make backup-file!"), i18n("backup failed")); doc->timer()->putLock(DocTimer::id_autoLockTimer); return false; + } else if (ret == e_noPw || + ret == e_wrongPw || + ret == e_openFile) { + doc->timer()->putLock(DocTimer::id_autoLockTimer); + return false; } else if (ret != e_success) { KMessageBox::error(currentView, i18n("Error: Couldn't write to file.\n" "Please check if you have permission to\n" "write to the file in that directory."), i18n("error while writing")); doc->timer()->putLock(DocTimer::id_autoLockTimer); return false; } doc->timer()->putLock(DocTimer::id_autoLockTimer); return true; } bool PwMDocUi::saveAsDocUi(PwMDoc *doc) { PWM_ASSERT(doc); doc->timer()->getLock(DocTimer::id_autoLockTimer); if (doc->isDocEmpty()) { KMessageBox::information(currentView, i18n ("Sorry, there's nothing to save.\n" "Please first add some passwords."), i18n("nothing to do")); doc->timer()->putLock(DocTimer::id_autoLockTimer); return true; } #ifndef PWM_EMBEDDED QString fn(KFileDialog::getSaveFileName(QString::null, i18n("*.pwm|PwManager Password file"), currentView)); #else QString fn = locateLocal( "data", KGlobal::getAppName() + "/*.pwm" ); fn = KFileDialog::getSaveFileName(fn, i18n("password filename(*.pwm)"), currentView); #endif if (fn == "") { doc->timer()->putLock(DocTimer::id_autoLockTimer); return false; } if (fn.right(4) != ".pwm") fn += ".pwm"; PwMerror ret = doc->saveDoc(conf()->confGlobCompression(), &fn); - if (ret != e_success) { + if (ret == e_noPw || + ret == e_wrongPw || + ret == e_openFile) { + doc->timer()->putLock(DocTimer::id_autoLockTimer); + return false; + } else if (ret != e_success) { KMessageBox::error(currentView, i18n("Error: Couldn't write to file.\n" "Please check if you have permission to\n" "write to the file in that directory."), i18n("error while writing")); doc->timer()->putLock(DocTimer::id_autoLockTimer); return false; } doc->timer()->putLock(DocTimer::id_autoLockTimer); return true; } bool PwMDocUi::openDocUi(PwMDoc *doc, QString filename, bool openDeepLocked) { if (filename.isEmpty()) { #ifndef PWM_EMBEDDED filename = KFileDialog::getOpenFileName(QString::null, i18n("*.pwm|PwManager Password file\n" "*|All files"), getCurrentView()); #else filename = locateLocal( "data", KGlobal::getAppName() + "/*.pwm"); filename = KFileDialog::getOpenFileName(filename, i18n("password filename(*.pwm)"), getCurrentView()); #endif } if (filename.isEmpty()) goto cancelOpen; PwMerror ret; while (true) { int lockStat = -1; if (openDeepLocked) { lockStat = 2; } else { if (conf()->confGlobUnlockOnOpen()) { lockStat = 0; } else { lockStat = 1; } } ret = doc->openDoc(&filename, lockStat); //qDebug("pwmdocui::OpenDocui %i", ret); if (ret != e_success) { if (ret == e_readFile || ret == e_openFile) { KMessageBox::error(getCurrentView(), i18n("Could not read file!") + "\n" + filename, i18n("file error")); goto cancelOpen; } if (ret == e_alreadyOpen) { KMessageBox::error(getCurrentView(), i18n("This file is already open."), i18n("already open")); goto cancelOpen; } if (ret == e_fileVer) { KMessageBox::error(getCurrentView(), i18n ("File-version is not supported!\n" "Did you create this file with an\nolder or newer version of PwM?"), |