mirror of
https://github.com/chris2511/xca.git
synced 2026-09-14 11:06:19 +05:00
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
This commit is contained in:
parent
848a78f352
commit
aaf9339eab
20
Makefile
20
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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 $@
|
||||
|
||||
278
lib/db.cpp
278
lib/db.cpp
@ -10,6 +10,8 @@
|
||||
#include "func.h"
|
||||
#include "exception.h"
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QDateTime>
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
@ -24,6 +26,8 @@
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#define XNUM(n) CCHAR(QString::number((n), 16))
|
||||
|
||||
db::db(QString filename, QFlags<QFile::Permission> 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<enum pki_type> 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
|
||||
}
|
||||
|
||||
|
||||
5
lib/db.h
5
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<QFile::Permission> perm = QFile::ReadOwner | QFile::WriteOwner);
|
||||
~db();
|
||||
bool eof();
|
||||
|
||||
@ -5,6 +5,11 @@
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include "db_base.h"
|
||||
#include "func.h"
|
||||
@ -13,6 +18,7 @@
|
||||
#include <QtGui/QListView>
|
||||
#include <QtGui/QClipboard>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QDebug>
|
||||
#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) {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
#include "db.h"
|
||||
#include "exception.h"
|
||||
#include <stdlib.h>
|
||||
#include <qbytearray.h>
|
||||
#include <QtCore/QByteArray>
|
||||
|
||||
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());
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#include "lib/pki_evp.h"
|
||||
#include "lib/pki_scard.h"
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtGui/QStatusBar>
|
||||
#include <QtGui/QMessageBox>
|
||||
#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);
|
||||
|
||||
@ -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();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user