xca/lib/main.cpp
Christian Hohnstaedt 4b3ee2c705 Switch database format to SQL(ite)
This is a large squash of many small commits.

Allow porting data from the legacy format to SQL.
Store Binaries base64 encoded and use db->transaction
Update password hash to be 8000 x SHA512 with 8 byte Salt
Add revocations table and fixup CRL generation
Add comment and insertion date columns

Fix column saving, remove trust, add XcaDialog
Allow changing the internal name and comment in Cert/Req details view
Extend Comment functionality, Replace About.ui by XcaDialog.ui
2018-03-05 07:42:36 +01:00

330 lines
6.7 KiB
C++

/* vi: set sw=4 ts=4:
*
* Copyright (C) 2001 - 2015 Christian Hohnstaedt.
*
* All rights reserved.
*/
#include <signal.h>
#include <QApplication>
#include <QClipboard>
#include <QTranslator>
#include <QTextCodec>
#include <QDir>
#include <QDirIterator>
#include <QFile>
#include <QDebug>
#include <openssl/rand.h>
#include "widgets/MainWindow.h"
#include "lib/func.h"
#include "lib/db.h"
#include "lib/main.h"
#include "lib/entropy.h"
#if defined(Q_OS_WIN32)
//For the segfault handler
#include <windows.h>
#endif
QLocale XCA_application::lang = QLocale::system();
QFont XCA_application::tableFont;
QList<QLocale> XCA_application::langAvail;
void XCA_application::setMainwin(MainWindow *m)
{
mainw = m;
}
bool XCA_application::languageAvailable(QLocale l)
{
return langAvail.contains(l);
}
XCA_application::XCA_application(int &argc, char *argv[])
:QApplication(argc, argv)
{
qtTr = NULL;
xcaTr = NULL;
mainw = NULL;
QFile file(getUserSettingsDir() +
QDir::separator() + "defaultlang");
if (file.open(QIODevice::ReadOnly)) {
lang = QLocale(QString(file.read(128)));
}
langAvail << QLocale::system();
langAvail << QString("en");
QDirIterator qmIt(getPrefix(), QStringList() << "*.qm", QDir::Files);
while (qmIt.hasNext()) {
XcaTranslator t;
qmIt.next();
QString language = qmIt.fileInfo().baseName().mid(4, -1);
if (t.load(language, "xca", getPrefix()))
langAvail << QLocale(language);
}
setupLanguage(lang);
#ifdef Q_OS_MAC
QStringList libp = libraryPaths();
libp.prepend(applicationDirPath() + "/../Plugins");
setLibraryPaths(libp);
#endif
tableFont = QFont("Courier", QApplication::font().pointSize()
#if defined (Q_OS_WIN32)
+1
#else
+2
#endif
);
installEventFilter(this);
}
void XCA_application::setupLanguage(QLocale l)
{
QStringList dirs;
lang = l;
if (qtTr) {
removeTranslator(qtTr);
delete qtTr;
}
qtTr = new XcaTranslator();
if (xcaTr) {
removeTranslator(xcaTr);
delete xcaTr;
}
xcaTr = new XcaTranslator();
dirs
#ifdef XCA_DEFAULT_QT_TRANSLATE
<< XCA_DEFAULT_QT_TRANSLATE
#endif
<< getPrefix()
#ifndef WIN32
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
<< "/usr/local/share/qt5/translations/"
<< "/usr/share/qt5/translations/"
#else
<< "/usr/local/share/qt4/translations/"
<< "/usr/share/qt4/translations/"
#endif
<< "/usr/share/qt/translations/"
#endif
;
foreach(QString dir, dirs) {
if (qtTr->load(lang, "qt", dir)) {
break;
}
}
xcaTr->load(lang, "xca", getPrefix());
QLocale::setDefault(l);
installTranslator(qtTr);
installTranslator(xcaTr);
if (mainw)
mainw->initResolver();
}
void XCA_application::switchLanguage(QAction* a)
{
QLocale lang = a->data().toLocale();
setupLanguage(lang);
QString dir = getUserSettingsDir();
QFile file(dir +QDir::separator() +"defaultlang");
if (lang == QLocale::system()) {
file.remove();
return;
}
QDir d;
d.mkpath(dir);
if (file.open(QIODevice::WriteOnly)) {
file.write(lang.name().toUtf8());
}
}
bool XCA_application::eventFilter(QObject *watched, QEvent *ev)
{
static int mctr;
QMouseEvent *me;
QStringList l;
XcaTreeView *treeview;
int key;
switch (ev->type()) {
case QEvent::FileOpen:
l << static_cast<QFileOpenEvent *>(ev)->file();
mainw->openURLs(l);
return true;
case QEvent::MouseMove:
case QEvent::NonClientAreaMouseMove:
if (mctr++ > 8) {
me = static_cast<QMouseEvent *>(ev);
entropy.add(me->globalX());
entropy.add(me->globalY());
mctr = 0;
}
break;
case QEvent::KeyPress:
key = static_cast<QKeyEvent *>(ev)->key();
if (key < 0x100) {
entropy.add(key);
}
break;
case QEvent::MouseButtonPress:
me = static_cast<QMouseEvent *>(ev);
treeview = watched ?
dynamic_cast<XcaTreeView*>(watched->parent()) : NULL;
if ((watched == mainw || treeview) &&
me->button() == Qt::MidButton &&
QApplication::clipboard()->supportsSelection())
{
mainw->pastePem();
return true;
}
break;
default:
break;
}
return false;
}
XCA_application::~XCA_application()
{
}
int usage_extract(char *argv[])
{
fprintf(stderr,
"Usage: %s %s <database> <type> <name>\n"
" database : the filename of the database\n"
" type : one of 'crl' 'cert' 'req'\n",
argv[0], argv[1]);
return 1;
}
int main_extract(int argc, char *argv[])
{
QFile dbfile;
enum pki_type pkitype = none;
unsigned char *p;
db_header_t head;
QString pkiname, name, fname;
pki_base *pki;
BIO *b;
Entropy e;
if (argc != 5) {
fprintf(stderr, "Wrong number of arguments\n");
return usage_extract(argv);
}
fname = filename2QString(argv[2]);
dbfile.setFileName(fname);
if (!dbfile.exists()) {
fprintf(stderr, "Database '%s' not found\n",argv[2]);
return usage_extract(argv);
}
pkiname = argv[3];
if (pkiname == "cert")
pkitype = x509;
else if (pkiname == "crl")
pkitype = revocation;
else if (pkiname == "req")
pkitype = x509_req;
else {
fprintf(stderr, "Invalid type: '%s'\n", argv[3]);
return usage_extract(argv);
}
db mydb(fname);
name = argv[4];
if (mydb.find(pkitype, name)) {
fprintf(stderr, "Item of type %s with name '%s' not found.\n",
argv[3], argv[4]);
return usage_extract(argv);
}
p = mydb.load(&head);
if (!p) {
fprintf(stderr, "Load was empty !");
return usage_extract(argv);
}
name = QString::fromUtf8(head.name);
switch (pkitype) {
case x509: pki = new pki_x509(name); break;
case x509_req: pki = new pki_x509req(name); break;
case revocation: pki = new pki_crl(name); break;
default: return usage_extract(argv);
}
pki->setIntName(QString::fromUtf8(head.name));
try {
pki->fromData(p, &head);
} catch (errorEx &err) {
fprintf(stderr, "Failed to load item from database: %s",
CCHAR(err.getString()));
}
b = BIO_new_fp(stdout, BIO_NOCLOSE);
pki->pem(b);
BIO_free(b);
return 0;
}
char segv_data[1024];
#if defined(Q_OS_WIN32)
static LONG CALLBACK w32_segfault(LPEXCEPTION_POINTERS e)
{
if (e->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
if (segv_data[0]) {
XCA_WARN(QString(segv_data));
abort();
}
return EXCEPTION_CONTINUE_EXECUTION;
} else
return EXCEPTION_CONTINUE_SEARCH;
}
#else
static void segv_handler_gui(int)
{
if (segv_data[0])
XCA_WARN(QString(segv_data));
abort();
}
#endif
int main( int argc, char *argv[] )
{
int ret = 0;
MainWindow *mw;
QDir d;
#if defined(Q_OS_WIN32)
SetUnhandledExceptionFilter(w32_segfault);
#else
signal(SIGSEGV, segv_handler_gui);
#endif
if (QString(argv[1]) == "extract") {
return main_extract(argc, argv);
}
d.mkpath(getUserSettingsDir());
XCA_application a(argc, argv);
mw = new MainWindow(NULL);
try {
a.setMainwin(mw);
mw->read_cmdline(argc, argv);
if (mw->exitApp == 0) {
mw->load_history();
if (mw->open_default_db() != 2) {
mw->show();
ret = a.exec();
}
}
} catch (errorEx &ex) {
mw->Error(ex);
}
delete mw;
return ret;
}