From 139078801cf7c002cfc6096a647f55facf2e27ff Mon Sep 17 00:00:00 2001 From: sniperbeamer Date: Tue, 3 Mar 2009 17:45:13 +0000 Subject: [PATCH] Fix: Different qm files in different paths, no overruling (Bug #2657158) Fix: Unable to open kdb from read-only location (Bug #2657228) git-svn-id: https://svn.code.sf.net/p/keepassx/code/trunk@279 b624d157-de02-0410-bad0-e51aec6abb33 --- src/Database.h | 2 +- src/Kdb3Database.cpp | 35 +++++++----- src/Kdb3Database.h | 4 +- src/crypto/twofish.cpp | 3 +- src/lib/SecString.cpp | 4 +- src/lib/tools.cpp | 47 ++++++++-------- src/main.cpp | 2 + src/mainwindow.cpp | 121 ++++++++++++++++++++++++----------------- src/mainwindow.h | 10 +++- 9 files changed, 133 insertions(+), 95 deletions(-) diff --git a/src/Database.h b/src/Database.h index 3bf30d1..4a4cbcf 100644 --- a/src/Database.h +++ b/src/Database.h @@ -246,7 +246,7 @@ public: \param identifier Normally this is the filename of the database but it can also be an IP address or something else if the database is not file based. \return TRUE if loading was successfull, otherwise FALSE. */ - virtual bool load(QString identifier)=0; + virtual bool load(QString identifier, bool readOnly)=0; //! Saves the current database. /*! It is not allowed to call this function if no database is loaded. diff --git a/src/Kdb3Database.cpp b/src/Kdb3Database.cpp index 25c06ce..75e9515 100644 --- a/src/Kdb3Database.cpp +++ b/src/Kdb3Database.cpp @@ -493,8 +493,8 @@ void Kdb3Database::restoreGroupTreeState(){ } } -bool Kdb3Database::load(QString identifier){ - return loadReal(identifier, false); +bool Kdb3Database::load(QString identifier, bool readOnly){ + return loadReal(identifier, readOnly, false); } #define LOAD_RETURN_CLEANUP \ @@ -503,7 +503,7 @@ bool Kdb3Database::load(QString identifier){ delete[] buffer; \ return false; -bool Kdb3Database::loadReal(QString filename, bool differentEncoding) { +bool Kdb3Database::loadReal(QString filename, bool readOnly, bool differentEncoding) { unsigned long total_size,crypto_size; quint32 Signature1,Signature2,Version,NumGroups,NumEntries,Flags; quint8 FinalRandomSeed[16]; @@ -511,7 +511,7 @@ bool Kdb3Database::loadReal(QString filename, bool differentEncoding) { quint8 EncryptionIV[16]; File = new QFile(filename); - if(!File->open(QIODevice::ReadWrite)){ + if (readOnly) { if(!File->open(QIODevice::ReadOnly)){ error=tr("Could not open file."); delete File; @@ -519,6 +519,20 @@ bool Kdb3Database::loadReal(QString filename, bool differentEncoding) { return false; } } + else { + if(!File->open(QIODevice::ReadWrite)){ + if(!File->open(QIODevice::ReadOnly)){ + error=tr("Could not open file."); + delete File; + File = NULL; + return false; + } + else{ + readOnly = true; + } + } + } + total_size=File->size(); char* buffer = new char[total_size]; File->read(buffer,total_size); @@ -604,7 +618,7 @@ bool Kdb3Database::loadReal(QString filename, bool differentEncoding) { RawMasterKey.copyData(RawMasterKey_Latin1); PotentialEncodingIssueLatin1 = false; qDebug("Decryption failed. Retrying with Latin-1."); - return loadReal(filename, true); // second try + return loadReal(filename, readOnly, true); // second try } if(PotentialEncodingIssueUTF8){ delete[] buffer; @@ -614,7 +628,7 @@ bool Kdb3Database::loadReal(QString filename, bool differentEncoding) { RawMasterKey.copyData(RawMasterKey_UTF8); PotentialEncodingIssueUTF8 = false; qDebug("Decryption failed. Retrying with UTF-8."); - return loadReal(filename, true); // second/third try + return loadReal(filename, readOnly, true); // second/third try } error=tr("Hash test failed.\nThe key is wrong or the file is damaged."); KeyError=true; @@ -1318,13 +1332,8 @@ bool Kdb3Database::save(){ quint8 EncryptionIV[16]; if(!(File->openMode() & QIODevice::WriteOnly)){ - File->close(); - } - if(!File->isOpen()){ - if(!File->open(QIODevice::ReadWrite)){ - error = tr("Could not open file for writing."); - return false; - } + error = tr("The database has been opened read-only."); + return false; } unsigned int FileSize; diff --git a/src/Kdb3Database.h b/src/Kdb3Database.h index 52806db..cf22477 100644 --- a/src/Kdb3Database.h +++ b/src/Kdb3Database.h @@ -135,7 +135,7 @@ public: Kdb3Database(); virtual ~Kdb3Database(){}; - virtual bool load(QString identifier); + virtual bool load(QString identifier, bool readOnly); virtual bool save(); virtual bool close(); virtual void create(); @@ -190,7 +190,7 @@ public: inline bool hasPasswordEncodingChanged() { return passwordEncodingChanged; }; private: - bool loadReal(QString filename, bool differentEncoding); + bool loadReal(QString filename, bool readOnly, bool differentEncoding); QDateTime dateFromPackedStruct5(const unsigned char* pBytes); void dateToPackedStruct5(const QDateTime& datetime, unsigned char* dst); bool isMetaStream(StdEntry& Entry); diff --git a/src/crypto/twofish.cpp b/src/crypto/twofish.cpp index f39d6e6..e00de28 100644 --- a/src/crypto/twofish.cpp +++ b/src/crypto/twofish.cpp @@ -477,8 +477,7 @@ void Twofish_fatal(const char* msg){ - qCritical("Twofish: Fatal Error: %s",msg); - exit(1); + qFatal("Twofish: Fatal Error: %s", msg); } diff --git a/src/lib/SecString.cpp b/src/lib/SecString.cpp index ae16221..6d71b6e 100644 --- a/src/lib/SecString.cpp +++ b/src/lib/SecString.cpp @@ -92,13 +92,15 @@ void SecString::overwrite(QString& str){ void SecString::generateSessionKey(){ sessionkey = new quint8[32]; - lockPage(sessionkey, 32); + if (!lockPage(sessionkey, 32)) + qDebug("Failed to lock session key page"); randomize(sessionkey, 32); RC4.setKey(sessionkey, 32); } void SecString::deleteSessionKey() { overwrite(sessionkey, 32); + unlockPage(sessionkey, 32); delete[] sessionkey; } diff --git a/src/lib/tools.cpp b/src/lib/tools.cpp index 88b6f6d..1380be8 100644 --- a/src/lib/tools.cpp +++ b/src/lib/tools.cpp @@ -56,21 +56,21 @@ void createBanner(QPixmap* Pixmap,const QPixmap* IconAlpha,const QString& Text,i QString decodeFileError(QFile::FileError Code){ switch(Code){ - case QFile::NoError: return QApplication::translate("FileErrors","No error occurred."); - case QFile::ReadError: return QApplication::translate("FileErrors","An error occurred while reading from the file."); - case QFile::WriteError: return QApplication::translate("FileErrors","An error occurred while writing to the file."); - case QFile::FatalError: return QApplication::translate("FileErrors","A fatal error occurred."); - case QFile::ResourceError: return QApplication::translate("FileErrors","An resource error occurred."); - case QFile::OpenError: return QApplication::translate("FileErrors","The file could not be opened."); - case QFile::AbortError: return QApplication::translate("FileErrors","The operation was aborted."); - case QFile::TimeOutError: return QApplication::translate("FileErrors","A timeout occurred."); - case QFile::UnspecifiedError: return QApplication::translate("FileErrors","An unspecified error occurred."); - case QFile::RemoveError: return QApplication::translate("FileErrors","The file could not be removed."); - case QFile::RenameError: return QApplication::translate("FileErrors","The file could not be renamed."); - case QFile::PositionError: return QApplication::translate("FileErrors","The position in the file could not be changed."); - case QFile::ResizeError: return QApplication::translate("FileErrors","The file could not be resized."); - case QFile::PermissionsError: return QApplication::translate("FileErrors","The file could not be accessed."); - case QFile::CopyError: return QApplication::translate("FileErrors","The file could not be copied."); + case QFile::NoError: return QApplication::translate("FileErrors","No error occurred."); + case QFile::ReadError: return QApplication::translate("FileErrors","An error occurred while reading from the file."); + case QFile::WriteError: return QApplication::translate("FileErrors","An error occurred while writing to the file."); + case QFile::FatalError: return QApplication::translate("FileErrors","A fatal error occurred."); + case QFile::ResourceError: return QApplication::translate("FileErrors","An resource error occurred."); + case QFile::OpenError: return QApplication::translate("FileErrors","The file could not be opened."); + case QFile::AbortError: return QApplication::translate("FileErrors","The operation was aborted."); + case QFile::TimeOutError: return QApplication::translate("FileErrors","A timeout occurred."); + case QFile::UnspecifiedError: return QApplication::translate("FileErrors","An unspecified error occurred."); + case QFile::RemoveError: return QApplication::translate("FileErrors","The file could not be removed."); + case QFile::RenameError: return QApplication::translate("FileErrors","The file could not be renamed."); + case QFile::PositionError: return QApplication::translate("FileErrors","The position in the file could not be changed."); + case QFile::ResizeError: return QApplication::translate("FileErrors","The file could not be resized."); + case QFile::PermissionsError: return QApplication::translate("FileErrors","The file could not be accessed."); + case QFile::CopyError: return QApplication::translate("FileErrors","The file could not be copied."); } return QString(); } @@ -134,21 +134,20 @@ QString makePathRelative(const QString& AbsDir,const QString& CurDir){ } void showErrMsg(const QString& msg,QWidget* parent){ - QMessageBox::critical(parent,QApplication::translate("Main","Error"),msg,QApplication::translate("Main","OK")); + QMessageBox::critical(parent, QApplication::translate("Main","Error"), msg); } QString getImageFile(const QString& name){ if (QFile::exists(DataDir+"/icons/"+name)) return DataDir+"/icons/"+name; else{ - QMessageBox::critical(0,QApplication::translate("Main","Error"), - QApplication::translate("Main","File '%1' could not be found.") - .arg(name),QApplication::translate("Main","OK"),0,0,2,1); - exit(1); + QString errMsg = QApplication::translate("Main","File '%1' could not be found.").arg(name); + showErrMsg(errMsg); + qFatal("File '%s' could not be found.", CSTR(errMsg)); + return QString(); } } - const QIcon& getIcon(const QString& name){ static QHashIconCache; QIcon* CachedIcon=IconCache.value(name); @@ -284,7 +283,7 @@ void installTranslator(){ } if (loadTranslation(translator,"keepassx-",language,QStringList() - << DataDir+"/i18n/" << HomeDir)) + << HomeDir << DataDir+"/i18n/")) { if (!translatorActive){ QApplication::installTranslator(translator); @@ -297,8 +296,8 @@ void installTranslator(){ } if (loadTranslation(qtTranslator,"qt_",language,QStringList() - << QLibraryInfo::location(QLibraryInfo::TranslationsPath) - << DataDir+"/i18n/" << HomeDir)) + << HomeDir << DataDir+"/i18n/" + << QLibraryInfo::location(QLibraryInfo::TranslationsPath))) { if (!qtTranslatorActive){ QApplication::installTranslator(qtTranslator); diff --git a/src/main.cpp b/src/main.cpp index ea0a733..194ddf2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -48,6 +48,8 @@ IIconTheme* IconLoader=NULL; int main(int argc, char **argv) { + QT_REQUIRE_VERSION(argc, argv, "4.3.0"); + #if defined(Q_WS_X11) && defined(GLOBAL_AUTOTYPE) QApplication* app = new KeepassApplication(argc,argv); #else diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 2b80da0..cd8d003 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -78,12 +78,12 @@ KeepassMainWindow::KeepassMainWindow(const QString& ArgFile,bool ArgMin,bool Arg setStateFileOpen(false); setupMenus(); DetailView->setVisible(config->showEntryDetails()); - statusbarState = 0; - StatusBarGeneral=new QLabel(tr("Ready"),statusBar()); + StatusBarGeneral=new QLabel(statusBar()); //StatusBarSelection=new QLabel(statusBar()); statusBar()->addWidget(StatusBarGeneral,15); //statusBar()->addWidget(StatusBarSelection,85); statusBar()->setVisible(config->showStatusbar()); + setStatusBarMsg(StatusBarReady); NormalCentralWidget=QMainWindow::centralWidget(); LockedCentralWidget=new QWidget(this); @@ -398,19 +398,27 @@ bool KeepassMainWindow::openDatabase(QString filename,bool IsAuto){ return false; } + dbReadOnly = false; + if (QFile::exists(filename+".lock")){ - QMessageBox::StandardButton buttonPressed = QMessageBox::question( - this, - tr("Database locked"), - tr("The database you are trying to open is locked.\n" + QMessageBox msgBox(this); + msgBox.setIcon(QMessageBox::Question); + msgBox.setWindowTitle(tr("Database locked")); + msgBox.setText(tr("The database you are trying to open is locked.\n" "This means that either someone else has opened the file or KeePassX crashed last time it opened the database.\n\n" "Do you want to open it anyway?" - ), - QMessageBox::Yes|QMessageBox::No, - QMessageBox::No - ); - if (buttonPressed != QMessageBox::Yes) + )); + msgBox.addButton(QMessageBox::Yes); + msgBox.addButton(QMessageBox::No); + QPushButton* readOnlyButton = new QPushButton(tr("Open read-only"), &msgBox); + msgBox.addButton(readOnlyButton, QMessageBox::AcceptRole); + msgBox.setDefaultButton(readOnlyButton); + msgBox.exec(); + + if (!msgBox.clickedButton() || msgBox.clickedButton() == msgBox.button(QMessageBox::No)) return false; + else if (msgBox.clickedButton() == readOnlyButton) + dbReadOnly = true; } if(!IsAuto){ @@ -439,18 +447,18 @@ bool KeepassMainWindow::openDatabase(QString filename,bool IsAuto){ EntryView->db=db; setupDatabaseConnections(db); QString err; - statusbarState = 1; - StatusBarGeneral->setText(tr("Loading Database...")); + setStatusBarMsg(StatusBarLoading); db->setKey(dlg.password(),dlg.keyFile()); - if(db->load(filename)){ - if (!QFile::exists(filename+".lock")){ - QFile lock(filename+".lock"); - if (!lock.open(QIODevice::WriteOnly)){ - QMessageBox::critical(this, tr("Error"), tr("Couldn't create database lock file.")); - return false; - } + + if (!dbReadOnly && !QFile::exists(filename+".lock")){ + QFile lock(filename+".lock"); + if (!lock.open(QIODevice::WriteOnly)){ + setStatusBarMsg(StatusBarReadOnlyLock); + dbReadOnly = true; } - + } + + if(db->load(filename, dbReadOnly)){ if (IsLocked) resetLock(); currentFile = filename; @@ -462,8 +470,7 @@ bool KeepassMainWindow::openDatabase(QString filename,bool IsAuto){ setStateFileModified(static_cast(db)->hasPasswordEncodingChanged()); } else{ - statusbarState = 2; - StatusBarGeneral->setText(tr("Loading Failed")); + setStatusBarMsg(StatusBarLoadingFailed); QString error=db->getError(); if(error.isEmpty())error=tr("Unknown error while loading database."); QMessageBox::critical(this,tr("Error"), @@ -478,8 +485,8 @@ bool KeepassMainWindow::openDatabase(QString filename,bool IsAuto){ return false; } } - statusbarState = 0; - StatusBarGeneral->setText(tr("Ready")); + if (statusbarState != StatusBarReadOnlyLock) + setStatusBarMsg(StatusBarReady); inactivityCounter = 0; return true; @@ -509,7 +516,12 @@ bool KeepassMainWindow::closeDatabase(bool lock){ QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel, QMessageBox::Yes); if(r==QMessageBox::Cancel) return false; //Cancel if(r==QMessageBox::Yes){ //Yes (Save file) - if(!OnFileSave()) return false; + if (dbReadOnly) { + if(!OnFileSaveAs()) return false; + } + else { + if(!OnFileSave()) return false; + } } } } @@ -1028,6 +1040,14 @@ void KeepassMainWindow::closeEvent(QCloseEvent* e){ return; } + if(FileOpen && !closeDatabase()){ + ShutingDown=false; + e->ignore(); + return; + } + + e->accept(); + #ifdef GLOBAL_AUTOTYPE autoType->unregisterGlobalShortcut(); #endif @@ -1039,20 +1059,9 @@ void KeepassMainWindow::closeEvent(QCloseEvent* e){ if (config->showEntryDetails()) config->setHSplitterPos(HSplitter->saveState()); config->setShowStatusbar(statusBar()->isVisible()); - - if(FileOpen){ - if(!closeDatabase()){ - ShutingDown=false; - e->ignore(); - return; - } - else - e->accept(); - } - else - e->accept(); + delete SysTray; - QCoreApplication::quit(); + QApplication::quit(); } void KeepassMainWindow::hideEvent(QHideEvent* event){ @@ -1101,17 +1110,7 @@ void KeepassMainWindow::OnExtrasSettings(){ else { setWindowTitle(APP_DISPLAY_NAME); } - switch (statusbarState) { - case 0: - StatusBarGeneral->setText(tr("Ready")); - break; - case 1: - StatusBarGeneral->setText(tr("Loading Database...")); - break; - case 2: - StatusBarGeneral->setText(tr("Loading Failed")); - break; - } + setStatusBarMsg(statusbarState); } EntryView->setAlternatingRowColors(config->alternatingRowColors()); @@ -1409,3 +1408,25 @@ void KeepassMainWindow::createBookmarkActions(){ menuBookmarks->addAction(action); } } + +void KeepassMainWindow::setStatusBarMsg(StatusBarMsg statusBarMsg) { + QString text; + + switch (statusBarMsg) { + case StatusBarReady: + text = tr("Ready"); + break; + case StatusBarLoading: + text = tr("Loading Database..."); + break; + case StatusBarLoadingFailed: + text = tr("Loading Failed"); + break; + case StatusBarReadOnlyLock: + text = tr("Couldn't create lock file. Opening the database read-only."); + break; + } + + statusbarState = statusBarMsg; + StatusBarGeneral->setText(text); +} diff --git a/src/mainwindow.h b/src/mainwindow.h index 373cf32..7ab04fb 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -90,6 +90,11 @@ class KeepassMainWindow : public QMainWindow, private Ui_MainWindow{ void showEvent(QShowEvent* event); void setLock(); void resetLock(); + enum StatusBarMsg { + StatusBarReady, StatusBarLoading, StatusBarLoadingFailed, + StatusBarReadOnlyLock + }; + void setStatusBarMsg(StatusBarMsg statusBarMsg); SelectionState GroupSelection, EntrySelection; bool FileOpen; bool ModFlag; @@ -115,7 +120,7 @@ class KeepassMainWindow : public QMainWindow, private Ui_MainWindow{ void createBookmarkActions(); QLineEdit* QuickSearchEdit; QLabel* StatusBarGeneral; - QLabel* StatusBarSelection; + //QLabel* StatusBarSelection; QToolBar* toolBar; QSystemTrayIcon* SysTray; QAction* ViewShowToolbarAction; @@ -131,7 +136,8 @@ class KeepassMainWindow : public QMainWindow, private Ui_MainWindow{ QString currentFile; int inactivityCounter; QTimer* inactivityTimer; - int statusbarState; + StatusBarMsg statusbarState; + bool dbReadOnly; }; #endif