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
master
sniperbeamer 15 years ago
parent df17d76ce7
commit 139078801c
  1. 2
      src/Database.h
  2. 35
      src/Kdb3Database.cpp
  3. 4
      src/Kdb3Database.h
  4. 3
      src/crypto/twofish.cpp
  5. 4
      src/lib/SecString.cpp
  6. 47
      src/lib/tools.cpp
  7. 2
      src/main.cpp
  8. 121
      src/mainwindow.cpp
  9. 10
      src/mainwindow.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.

@ -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;

@ -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);

@ -477,8 +477,7 @@
void Twofish_fatal(const char* msg){
qCritical("Twofish: Fatal Error: %s",msg);
exit(1);
qFatal("Twofish: Fatal Error: %s", msg);
}

@ -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;
}

@ -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 QHash<QString,QIcon*>IconCache;
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);

@ -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

@ -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<Kdb3Database*>(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);
}

@ -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