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 16 years ago
parent df17d76ce7
commit 139078801c
  1. 2
      src/Database.h
  2. 31
      src/Kdb3Database.cpp
  3. 4
      src/Kdb3Database.h
  4. 3
      src/crypto/twofish.cpp
  5. 4
      src/lib/SecString.cpp
  6. 17
      src/lib/tools.cpp
  7. 2
      src/main.cpp
  8. 109
      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,6 +511,15 @@ bool Kdb3Database::loadReal(QString filename, bool differentEncoding) {
quint8 EncryptionIV[16];
File = new QFile(filename);
if (readOnly) {
if(!File->open(QIODevice::ReadOnly)){
error=tr("Could not open file.");
delete File;
File = NULL;
return false;
}
}
else {
if(!File->open(QIODevice::ReadWrite)){
if(!File->open(QIODevice::ReadOnly)){
error=tr("Could not open file.");
@ -518,7 +527,12 @@ bool Kdb3Database::loadReal(QString filename, bool differentEncoding) {
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,14 +1332,9 @@ 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.");
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;
}

@ -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")){
if (!dbReadOnly && !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;
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,10 +516,15 @@ 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 (dbReadOnly) {
if(!OnFileSaveAs()) return false;
}
else {
if(!OnFileSave()) return false;
}
}
}
}
db->close();
delete db;
db=NULL;
@ -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
@ -1040,19 +1060,8 @@ void KeepassMainWindow::closeEvent(QCloseEvent* e){
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