diff --git a/Makefile b/Makefile index ccaa43a4..980d16cf 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,7 @@ DMGSTAGE=$(BUILD)/xca-$(VERSION) MACTARGET=$(DMGSTAGE)-$(DARWIN) APPDIR=$(DMGSTAGE)/xca.app/Contents +all: db_dump$(SUFFIX) ifeq ($(SUFFIX), .exe) all: setup$(SUFFIX) else @@ -74,9 +75,10 @@ headers: do.ui $(MAKE) -C $* -f $(TOPDIR)/$*/Makefile \ VPATH=$(TOPDIR)/$* -db_dump: lib/.build-stamp +db_dump$(SUFFIX): lib/.build-stamp $(MAKE) -C lib -f $(TOPDIR)/lib/Makefile \ - VPATH=$(TOPDIR)/lib db_dump + VPATH=$(TOPDIR)/lib $@ + cp lib/$@ $@ $(INSTTARGET): install.%: %/.build-stamp mkdir -p $* @@ -119,24 +121,20 @@ snapshot: git archive --format=tar --prefix=xca-$${HASH}/ HEAD | \ gzip -9 > xca-$${HASH}.tar.gz -install: xca$(SUFFIX) $(INSTTARGET) +install: xca$(SUFFIX) db_dump$(SUFFIX) $(INSTTARGET) install -m 755 -d $(destdir)$(bindir) install -m 755 xca $(destdir)$(bindir) + install -m 755 db_dump $(destdir)$(bindir) $(STRIP) $(destdir)$(bindir)/xca -$(MACDEPLOYQT): - -macdeployqt/macdeployqt: - $(MAKE) -C macdeployqt - -setup.exe: xca$(SUFFIX) do.doc do.lang +setup.exe: xca$(SUFFIX) db_dump$(SUFFIX) do.doc do.lang setup.exe: misc/xca.nsi $(STRIP) xca$(SUFFIX) $(MAKENSIS) -DINSTALLDIR=$(INSTALL_DIR) -DQTDIR=$(QTDIR) \ -DVERSION=$(VERSION) -DBDIR=$(BDIR) -DTOPDIR=$(TOPDIR)\ -NOCD -V2 $< -$(DMGSTAGE): xca$(SUFFIX) $(MACDEPLOYQT) +$(DMGSTAGE): xca$(SUFFIX) db_dump$(SUFFIX) rm -rf $(DMGSTAGE) mkdir -p $(DMGSTAGE)/xca.app/Contents/MacOS mkdir -p $(DMGSTAGE)/xca.app/Contents/Resources @@ -144,7 +142,9 @@ $(DMGSTAGE): xca$(SUFFIX) $(MACDEPLOYQT) ln -s /Applications $(DMGSTAGE) install -m 644 $(TOPDIR)/COPYRIGHT $(DMGSTAGE)/COPYRIGHT.txt install -m 755 xca $(DMGSTAGE)/xca.app/Contents/MacOS + install -m 755 db_dump $(DMGSTAGE)/xca.app/Contents/MacOS $(STRIP) $(DMGSTAGE)/xca.app/Contents/MacOS/xca + $(STRIP) $(DMGSTAGE)/xca.app/Contents/MacOS/db_dump $(MAKE) $(APPTARGET) cp -r $(DMGSTAGE)/xca.app/Contents/Resources/*.html $(DMGSTAGE)/manual ln -s xca.html $(DMGSTAGE)/manual/index.html diff --git a/changelog b/changelog index 0fabbc62..3be1e7c8 100644 --- a/changelog +++ b/changelog @@ -1,4 +1,13 @@ + * Database hardening + - Delete invalid items (on demand) + - Be more tolerant against database errors + - Gracefully handle and repair corrupt databases + - add "db_dump(.exe)" binary to all installations * Translation updates + * Optionally allow hash algos not supported by the token + * Select whether to translate established x509 terms + * Finish Token EC and DSA support - generate, import, export, sign + * SF Feat. Req. #57 More options for Distinguished Name * Switch to autoconf for the configure script * SF Feature Req. #76 Export private keys to clipboard * EC Keys: show Curve name in table diff --git a/lib/Makefile b/lib/Makefile index d4142414..842522cd 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -17,6 +17,6 @@ OBJS=$(patsubst %, %.o, $(NAMES)) $(patsubst %, moc_%.o, $(MOCNAMES)) include $(TOPDIR)/Rules.mak sinclude .depend -db_dump: db_dump.o db.o db.h - echo "'$(CPPFLAGS)'" +db_dump$(SUFFIX): db_dump.o db.o db.h + @$(PRINT) " LINK $@" $(CC) $(CPPFLAGS) $(LDFLAGS) $(CFLAGS) db_dump.o db.o $(LIBS) -g -o $@ diff --git a/lib/db.cpp b/lib/db.cpp index adadfd5d..57a1ad81 100644 --- a/lib/db.cpp +++ b/lib/db.cpp @@ -10,6 +10,8 @@ #include "func.h" #include "exception.h" #include +#include +#include #ifdef WIN32 #include #else @@ -24,6 +26,8 @@ #include #endif +#define XNUM(n) CCHAR(QString::number((n), 16)) + db::db(QString filename, QFlags perm) { name = filename; @@ -80,9 +84,6 @@ bool db::verify_magic(void) { if (!eof()) if (ntohl(head.magic) != XCA_MAGIC) { - throw errorEx(QString("database error '") + - file.fileName() +"'", - "at: " + QString::number(head_offset)); return false; } return true; @@ -90,7 +91,7 @@ bool db::verify_magic(void) bool db::eof() { - return (head_offset == OFF_EOF); + return head_offset == file.size(); } int db::find(enum pki_type type, QString name) @@ -121,7 +122,7 @@ void db::first(int flag) if (ret < 0 ) fileIOerr("read"); if (ret==0) { - head_offset = OFF_EOF; + head_offset = file.size(); return; } if (!verify_magic()) @@ -132,44 +133,90 @@ void db::first(int flag) int db::next(int flag) { - int ret; + qint64 ret; + qint64 garbage = -1; + int result = 1; if (eof()) return 1; head_offset += ntohl(head.len); - file.seek(head_offset); - ret = file.read((char*)&head, sizeof(db_header_t) ); - if (ret==0) { - //printf("Next: EOF at %lu\n", head_offset); - head_offset = OFF_EOF; + if (head_offset >= file.size()) { + head_offset = file.size(); return 1; } - if (ret < 0) { - fileIOerr("read"); - return -1; + while (1) { + file.seek(head_offset); + ret = file.read((char*)&head, sizeof head); + if (ret==0) { + head_offset = file.size(); + break; + } + if (ret < 0) { + fileIOerr("read"); + return -1; + } + if (ret != sizeof head) { + qWarning("next(): Short read: 0x%s of 0x%s @ 0x%s", + XNUM(ret), XNUM(sizeof head), + XNUM(head_offset)); + if (garbage != -1) { + ret += head_offset - garbage; + head_offset = garbage; + } + qWarning("next(): Truncating 0x%s garbage bytes @ 0x%s", + XNUM(ret), XNUM(head_offset)); + if (backup()) + file.resize(head_offset); + head_offset = file.size(); + return -1; + } + qint64 hlen = ntohl(head.len); + if (!verify_magic()) { + if (garbage == -1) + garbage = head_offset; + head_offset += 1; + continue; + } else { + if (garbage != -1) { + qWarning("next(): 0x%s bytes garbage skipped at 0x%s", + XNUM(head_offset - garbage), + XNUM(garbage)); + } + garbage = -1; + if (file.size() < head_offset + hlen) { + qWarning("next(): Short item (%s of %s) at 0x%s", + XNUM(ntohl(head.len)), + XNUM(file.size() - head_offset), + XNUM(head_offset)); + garbage = head_offset; + /* invalidate the header */ + qWarning("Invalidate short item @ 0x%s\n", + XNUM(head_offset)); + file.seek(head_offset); + char inval = 0xcb; // 0xca +1 + file.write(&inval, 1); + head_offset += 4; + continue; + } + } + if (!(ntohs(head.flags) & flag)) { + result = 0; + break; + } else { + head_offset += hlen; + } } - if (ret != sizeof(db_header_t)) { - printf("Length broken: %d instead of %ld\n", ret, - (long)sizeof(db_header_t) ); - //ftruncate(fd, head_offset); - head_offset = OFF_EOF; - return -1; + if (garbage != -1) { + qWarning("next(): 0x%s bytes garbage skipped at 0x%s", + XNUM(head_offset - garbage), XNUM(garbage)); } - if (!verify_magic()){ - printf("Garbage found at %lu\n", (unsigned long)head_offset); - head_offset+=4; - return next(flag); - } - if (ntohs(head.flags) & flag) - return next(flag); - - return 0; + return result; } void db::rename(enum pki_type type, QString name, QString n) { - int ret; + qint64 ret; first(); if (find(type, n) == 0) { @@ -186,7 +233,7 @@ void db::rename(enum pki_type type, QString name, QString n) if (ret < 0) { fileIOerr("write"); } - if (ret != sizeof(head)) { + if (ret != sizeof head) { throw errorEx(QObject::tr("DB: Write error %1 - %2" ).arg(ret).arg(sizeof(head))); } @@ -225,12 +272,12 @@ QString db::uniq_name(QString s, QList types) int db::add(const unsigned char *p, int len, int ver, enum pki_type type, QString name) { - db_header_t db; + db_header_t head; - init_header(&db, ver, len, type, name); + init_header(&head, ver, len, type, name); file.seek(file.size()); - if (file.write((char*)&db, sizeof(db)) != sizeof(db)) { + if (file.write((char*)&head, sizeof head) != sizeof head) { fileIOerr("write"); return -1; } @@ -244,27 +291,21 @@ int db::add(const unsigned char *p, int len, int ver, enum pki_type type, int db::set(const unsigned char *p, int len, int ver, enum pki_type type, QString name) { - int ret; + qint64 ret; first(); ret = find(type, name); - if (ret == 1) { + if (ret != 0) { return add(p, len, ver, type, name); - } - if (ret == 0) { - //printf("offs = %x, len=%d, head.len=%d name = %s flags=%x\n", - // head_offset, len, ntohl(head.len), head.name, - // ntohs(head.flags)); + } else { file.seek(head_offset); if (len != (int)(ntohl(head.len) - sizeof(db_header_t))) { - //printf("## Found and len unequal %d, %d\n", - // len, ntohl(head.len) - sizeof(db_header_t)); int flags; flags = head.flags; head.flags |= htons(DBFLAG_DELETED | DBFLAG_OUTDATED); - if (file.write((char*)&head, sizeof(db_header_t)) != - sizeof(db_header_t)) + if (file.write((char*)&head, sizeof head) != + sizeof head) { fileIOerr("write"); return -1; @@ -272,16 +313,14 @@ int db::set(const unsigned char *p, int len, int ver, enum pki_type type, if (add(p, len, ver, type, name) < 0) { file.seek(head_offset); head.flags = flags; - ret = file.write((char*)&head, sizeof(db_header_t)); - if (ret != sizeof(db_header_t)) + ret = file.write((char*)&head, sizeof head); + if (ret != sizeof head) fileIOerr("write"); } return 0; } - //printf("## Overwriting entry at %u\n", head_offset); head.version = htons(ver); - if (file.write((char*)&head, sizeof(db_header_t)) != - sizeof(db_header_t)) { + if (file.write((char*)&head, sizeof head) != sizeof head) { fileIOerr("write"); return -1; } @@ -297,7 +336,7 @@ int db::set(const unsigned char *p, int len, int ver, enum pki_type type, unsigned char *db::load(db_header_t *u_header) { uint32_t size; - unsigned ret; + qint64 ret; unsigned char *data; if (eof()) @@ -306,13 +345,14 @@ unsigned char *db::load(db_header_t *u_header) data = (unsigned char *)malloc(size); file.seek(head_offset + sizeof(db_header_t)); ret = file.read((char*)data, size); - if (ret == size) { + if (ret == (qint64)size) { if (u_header) convert_header(u_header); return data; } else { free(data); - fileIOerr("read"); + if (ret < 0) + fileIOerr("read"); return NULL; } } @@ -342,10 +382,11 @@ int db::erase(void) int db::shrink(int flags) { - int ret; + qint64 ret, garbage = -1; uint32_t offs; char buf[BUFSIZ]; QFile new_file; + int result = 0; new_file.setFileName(name + "{new}"); if (!new_file.open(QIODevice::ReadWrite)) { @@ -354,29 +395,57 @@ int db::shrink(int flags) } file.reset(); - while ((ret = file.read((char*)&head, sizeof(head))) > 0) { - if (!verify_magic()) - return 1; - head_offset = ntohl(head.len) - sizeof(head); - if ((ntohs(head.flags) & flags)) { - //printf("Skip Entry\n"); - /* FF to the next entry */ - offs = file.seek(head_offset + file.pos()); - //printf("Seeking to %d\n", offs); - if (head_offset == -1) - break; + while ((ret = file.read((char*)&head, sizeof head)) > 0) { + if (ret < sizeof head) { + qWarning("shrink(): Short read: 0x%s instead of 0x%s", + XNUM(ret), XNUM(sizeof head)); + result = 1; + break; + } + if (!verify_magic()) { + file.seek(file.pos() - sizeof(head) +1); + if (garbage == -1) + garbage = file.pos() -1; + result = 1; continue; } + if (garbage != -1) + qWarning("shrink(): 0x%s garbage found at %s", + XNUM(file.pos() - sizeof head - garbage), + XNUM(garbage)); + garbage = -1; + head_offset = ntohl(head.len) - sizeof(head); + if ((ntohs(head.flags) & flags)) { + /* FF to the next entry */ + if (!file.seek(head_offset + file.pos())) { + result = 1; + break; + } + continue; + } + if (head_offset + file.pos() > file.size()) { + file.seek(file.pos() - sizeof(head) +4); + if (garbage == -1) + garbage = file.pos() -4; + continue; + } + ret = new_file.write((char*)&head, sizeof(head)); - if (ret != sizeof(head)) + if (ret != sizeof(head)) { + result = 2; break; + } offs = head_offset; while (offs) { ret = file.read((char*)buf, (offs > BUFSIZ) ? BUFSIZ : offs); - if (ret<=0) + if (ret <= 0) { + result = 3; break; - if (new_file.write(buf, ret) != ret) + } + if (new_file.write(buf, ret) != ret) { + result = 4; break; + } offs -= ret; } if (offs) @@ -384,12 +453,71 @@ int db::shrink(int flags) } new_file.close(); - if (ret) { - unlink(QString2filename(new_file.fileName())); - return 1; - } file.close(); - return mv(new_file); + QString backup, orig; + + switch (result) { + case 0: + /* everything is fine */ + result = mv(new_file); + break; + case 1: + /* Some repaireable errors in the database occured. + * Keep the original as backup */ + backup = backup_name(); + QFile::remove(backup); + orig = file.fileName(); + if (file.rename(backup)) { + new_file.rename(orig); + } else { + QFile::remove(new_file.fileName()); + result = 2; + } + break; + case 2: + case 3: + case 4: + QFile::remove(new_file.fileName()); + result = 2; + break; + } + return result; +} + +QString db::backup_name() +{ + return file.fileName() + "_backup_" + + QDateTime::currentDateTime() + .toString("yyyyMMdd_hhmmss") + ".xdb"; +} + +bool db::backup() +{ + QFile this_file, new_file; + QString backup = backup_name(); + qint64 ret, wret; + char buf[BUFSIZ]; + + this_file.setFileName(file.fileName()); + if (!this_file.open(QIODevice::ReadOnly)) { + return false; + } + new_file.setFileName(backup); + if (!new_file.open(QIODevice::ReadWrite)) { + this_file.close(); + return false; + } + while (1) { + ret = this_file.read(buf, sizeof buf); + if (ret <= 0) + break; + wret = new_file.write(buf, ret); + if (wret != ret) + break; + } + this_file.close(); + new_file.close(); + return ret == 0; } int db::mv(QFile &new_file) @@ -406,7 +534,7 @@ int db::mv(QFile &new_file) } else { QFile::rename(tempn, name); QFile::remove(new_file.fileName()); - return 1; + return 2; } } return 0; @@ -416,7 +544,7 @@ int db::mv(QFile &new_file) check_oom(newfile); int ret = ::rename(newfile, QString2filename(name)) == -1; free(newfile); - return ret; + return ret == 0 ? 0 : 2; #endif } diff --git a/lib/db.h b/lib/db.h index 8e6260bf..4865c01a 100644 --- a/lib/db.h +++ b/lib/db.h @@ -18,7 +18,6 @@ #define XCA_MAGIC 0xcadb1969 #define NAMELEN 80 #define FNAMLEN 256 -#define OFF_EOF ((off_t)-1) #define DBFLAG_DELETED 0x1 #define DBFLAG_OUTDATED 0x2 @@ -57,10 +56,12 @@ class db QString name); void convert_header(db_header_t *h); void fileIOerr(QString s); + QString backup_name(); + bool backup(); public: bool verify_magic(void); - off_t head_offset; + qint64 head_offset; db(QString, QFlags perm = QFile::ReadOwner | QFile::WriteOwner); ~db(); bool eof(); diff --git a/lib/db_base.cpp b/lib/db_base.cpp index 6fdeb784..82080f89 100644 --- a/lib/db_base.cpp +++ b/lib/db_base.cpp @@ -5,6 +5,11 @@ * All rights reserved. */ +#ifdef WIN32 +#include +#else +#include +#endif #include "db_base.h" #include "func.h" @@ -13,6 +18,7 @@ #include #include #include +#include #include "widgets/MainWindow.h" #include "widgets/ImportMulti.h" @@ -64,6 +70,55 @@ void db_base::remFromCont(QModelIndex &idx) emit columnsContentChanged(); } +int db_base::handleBadEntry(unsigned char *p, db_header_t *head) +{ + QString name = QString::fromUtf8(head->name); + QString txt = tr("Bad database item\nName: %1\nType: %2\nSize: %3\n%4") + .arg(name).arg(class_name) + .arg(head->len - sizeof(db_header_t)) + .arg(tr("Do you want to delete the item from the database? The bad item may be extracted into a separate file.")); + + xcaWarning msg(mainwin, txt); + msg.addButton(QMessageBox::Ok)->setText(tr("Delete")); + msg.addButton(QMessageBox::Apply)->setText(tr("Delete and extract")); + msg.addButton(QMessageBox::Cancel)->setText(tr("Continue")); + + switch (msg.exec()) { + case QMessageBox::Ok: + return 1; + case QMessageBox::Cancel: + default: + return 0; + case QMessageBox::Apply: + break; + } + + QString s = QFileDialog::getSaveFileName(mainwin, QString(), name, + QString(), NULL, QFileDialog::DontConfirmOverwrite); + + size_t l; + db_header_t h; + FILE *fp = fopen(QString2filename(s), "w"); + if (!fp) { + throw errorEx(tr("Error opening file: '%1': %2"). + arg(s).arg(strerror(errno)), class_name); + } + + h.magic = ntohl(head->magic); + h.len = ntohl(head->len); + h.headver = ntohs(head->headver); + h.type = ntohs(head->type); + h.version = ntohs(head->version); + h.flags = ntohs(head->flags); + memcpy(h.name, head->name, NAMELEN); + + l = fwrite(&h, sizeof h, 1, fp); + l += fwrite(p, head->len - sizeof h, 1, fp); + fclose(fp); + + return (l == 2); +} + void db_base::loadContainer() { db mydb(dbName); @@ -77,13 +132,13 @@ void db_base::loadContainer() QString s; p = mydb.load(&head); if (!p) { - printf("Load was empty !\n"); + qWarning("Load was empty !"); goto next; } pki = newPKI(&head); if (pki->getVersion() < head.version) { - printf("Item[%s]: Version %d " - "> known version: %d -> ignored\n", + qWarning("Item[%s]: Version %d " + "> known version: %d -> ignored", head.name, head.version, pki->getVersion() ); @@ -101,6 +156,13 @@ void db_base::loadContainer() mainwin->Error(err); delete pki; pki = NULL; + try { + if (handleBadEntry(p, &head)) { + mydb.erase(); + } + } catch (errorEx &err) { + mainwin->Error(err); + } } free(p); if (pki) { diff --git a/lib/db_base.h b/lib/db_base.h index 1be3e304..8a3248a8 100644 --- a/lib/db_base.h +++ b/lib/db_base.h @@ -42,6 +42,8 @@ class db_base: public QAbstractItemModel QString class_name; dbheaderList allHeaders; int colResizing; + int handleBadEntry(unsigned char *p, db_header_t *head); + public: pki_base *rootItem; db_base(QString db, MainWindow *mw); diff --git a/lib/db_dump.cpp b/lib/db_dump.cpp index 2c840e8e..5fe14b9e 100644 --- a/lib/db_dump.cpp +++ b/lib/db_dump.cpp @@ -8,7 +8,7 @@ #include "db.h" #include "exception.h" #include -#include +#include QByteArray filename2bytearray(const QString &fname) { @@ -53,17 +53,25 @@ int main(int argc, char *argv[]) unsigned char *p; db_header_t h; int i=0; - char type[] = "NKRCLTSUXX"; + const char *type[] = { + "(none)", "Software Key", "Request", "Certificate", + "Revocation", "Template", "Setting", "Token key" + }; try { mydb.first(0); + printf("Index Type Ver Offset Flags Len Name\n"); while (!mydb.eof()) { p = mydb.load(&h); free(p); - printf("%3d: %c V%d O:%6zd, F:%x L:%5d %s\n", - i++, type[h.type], h.version, mydb.head_offset, + if (h.type > smartCard) + h.type = 0; + printf("%5d %-12s%5d%7zx%6x%6x %s\n", + i++, type[h.type], h.version, + (size_t)mydb.head_offset, h.flags, h.len, h.name); - mydb.next(0); + if (mydb.next(0)) + break; } } catch (errorEx &ex) { printf("Exception: '%s'\n", ex.getCString()); diff --git a/misc/xca.nsi b/misc/xca.nsi index fcd6c77b..832fe99e 100755 --- a/misc/xca.nsi +++ b/misc/xca.nsi @@ -60,6 +60,7 @@ Section "xca (required)" SecMain SetOutPath $INSTDIR ; Put files there File "xca.exe" + File "db_dump.exe" File "${TOPDIR}/misc\dn.txt" File "${TOPDIR}/misc\eku.txt" File "${TOPDIR}/misc\oids.txt" diff --git a/widgets/MW_database.cpp b/widgets/MW_database.cpp index 1744bb95..ebca91b6 100644 --- a/widgets/MW_database.cpp +++ b/widgets/MW_database.cpp @@ -11,6 +11,7 @@ #include "lib/pki_evp.h" #include "lib/pki_scard.h" #include +#include #include #include #include "lib/db_base.h" @@ -18,10 +19,24 @@ #include "widgets/ImportMulti.h" #include "widgets/NewKey.h" +void MainWindow::set_geometry(char *p, db_header_t *head) +{ + if (head->version != 1) + return; + QByteArray ba = QByteArray::fromRawData(p, head->len); + int w, h, i; + w = db::intFromData(ba); + h = db::intFromData(ba); + i = db::intFromData(ba); + resize(w,h); + if (i != -1) + tabView->setCurrentIndex(i); +} + int MainWindow::init_database() { int ret = 2; - fprintf(stderr, "Opening database: %s\n", QString2filename(dbfile)); + qDebug("Opening database: %s", QString2filename(dbfile)); keys = NULL; reqs = NULL; certs = NULL; temps = NULL; crls = NULL; certView->setRootIsDecorated(db_x509::treeview); @@ -44,10 +59,6 @@ int MainWindow::init_database() mandatory_dn = ""; explicit_dn = explicit_dn_default; - pki_base::suppress_messages = false; - pki_x509::dont_colorize_expiries = false; - translate_dn = false; - pki_scard::only_token_hashes = false; string_opt = QString("MASK:0x2002"); ASN1_STRING_set_default_mask_asc((char*)CCHAR(string_opt)); @@ -55,6 +66,7 @@ int MainWindow::init_database() pkcs11path = getDefaultPkcs11Lib(); workingdir = QDir::currentPath(); setOptFlags((QString())); + try { pkcs11_lib p(pkcs11path); } catch (errorEx &e) { @@ -93,115 +105,59 @@ int MainWindow::init_database() certView->setModel(certs); tempView->setModel(temps); crlView->setModel(crls); - try { db mydb(dbfile); - char *p; - if (!mydb.find(setting, "workingdir")) { - if ((p = (char *)mydb.load(NULL))) { + + while (mydb.find(setting, QString()) == 0) { + QString key; + db_header_t head; + char *p = (char *)mydb.load(&head); + if (!p) { + if (mydb.next()) + break; + continue; + } + key = head.name; + + if (key == "workingdir") workingdir = p; - free(p); - } - } - mydb.first(); - if (!mydb.find(setting, "pkcs11path")) { - if ((p = (char *)mydb.load(NULL))) { + else if (key == "pkcs11path") pkcs11path = p; - free(p); - } - } - mydb.first(); - if (!mydb.find(setting, "default_hash")) { - if ((p = (char *)mydb.load(NULL))) { + else if (key == "default_hash") hashBox::setDefault(p); - free(p); - } - } - mydb.first(); - if (!mydb.find(setting, "mandatory_dn")) { - if ((p = (char *)mydb.load(NULL))) { + else if (key == "mandatory_dn") mandatory_dn = p; - free(p); - } - } - mydb.first(); - if (!mydb.find(setting, "explicit_dn")) { - if ((p = (char *)mydb.load(NULL))) { + else if (key == "explicit_dn") explicit_dn = p; - free(p); - } - } - // what a stupid idea.... - mydb.first(); - if (!mydb.find(setting, "multiple_key_use")) { - mydb.erase(); - } - mydb.first(); - if (!mydb.find(setting, "string_opt")) { - if ((p = (char *)mydb.load(NULL))) { + /* what a stupid idea.... */ + else if (key == "multiple_key_use") + mydb.erase(); + else if (key == "string_opt") string_opt = p; - free(p); - } - } - mydb.first(); - if (!mydb.find(setting, "suppress")) { - if ((p = (char *)mydb.load(NULL))) { - QString x = p; - free(p); - if (x == "1") - pki_base::suppress_messages = 1; - } - } - mydb.first(); - if (!mydb.find(setting, "optionflags1")) { - if ((p = (char *)mydb.load(NULL))) { + else if (key == "suppress") + mydb.erase(); + else if (key == "optionflags1") setOptFlags((QString(p))); - free(p); - } - } else { /* Different optionflags, since setOptFlags() * does an abort() for unknown flags in * older versions. *Another stupid idea* * This is for backward compatibility */ - mydb.first(); - if (!mydb.find(setting, "optionflags")) { - if ((p = (char *)mydb.load(NULL))) { - setOptFlags_old((QString(p))); - free(p); - } - } - } - mydb.first(); - if (!mydb.find(setting, "defaultkey")) { - if ((p = (char *)mydb.load(NULL))) { + else if (key == "optionflags") + setOptFlags_old((QString(p))); + else if (key == "defaultkey") NewKey::setDefault((QString(p))); - free(p); - } - } - ASN1_STRING_set_default_mask_asc((char*)CCHAR(string_opt)); - mydb.first(); - if (!mydb.find(setting, "mw_geometry")) { - db_header_t h; - if ((p = (char *)mydb.load(&h))) { - if (h.version == 1) { - QByteArray ba; - ba = QByteArray::fromRawData(p, h.len); - int w, h, i; - w = db::intFromData(ba); - h = db::intFromData(ba); - i = db::intFromData(ba); - resize(w,h); - if (i != -1) - tabView->setCurrentIndex(i); - } - free(p); - } + else if (key == "mw_geometry") + set_geometry(p, &head); + free(p); + if (mydb.next()) + break; } } catch (errorEx &err) { Error(err); return ret; } + ASN1_STRING_set_default_mask_asc((char*)CCHAR(string_opt)); if (explicit_dn.isEmpty()) explicit_dn = explicit_dn_default; setWindowTitle(tr(XCA_TITLE)); @@ -367,8 +323,13 @@ void MainWindow::close_database() try { + int ret; db mydb(dbfile); - mydb.shrink( DBFLAG_OUTDATED | DBFLAG_DELETED ); + ret = mydb.shrink( DBFLAG_OUTDATED | DBFLAG_DELETED ); + if (ret == 1) + XCA_INFO(tr("Errors detected and repaired while deleting outdated items from the database. A backup file was created")); + if (ret == 2) + XCA_INFO(tr("Removing deleted or outdated items from the database failed.")); } catch (errorEx &err) { MainWindow::Error(err); diff --git a/widgets/MainWindow.h b/widgets/MainWindow.h index e9c4e85f..8ac392c6 100644 --- a/widgets/MainWindow.h +++ b/widgets/MainWindow.h @@ -76,6 +76,7 @@ class MainWindow: public QMainWindow, public Ui::MainWindow QStringList history; tipMenu *historyMenu; void update_history_menu(); + void set_geometry(char *p, db_header_t *head); protected: void init_images();