From fc7fc357ac0fb34ecbe4eafdea85786a1f98026d Mon Sep 17 00:00:00 2001 From: Christian Hohnstaedt Date: Mon, 26 Jun 2017 05:32:59 +0200 Subject: [PATCH] Support opening remote databases MySQL and PostgreSQL --- lib/db_base.cpp | 19 ++-- lib/db_crl.cpp | 11 +- lib/db_key.cpp | 10 +- lib/db_temp.cpp | 8 +- lib/db_x509.cpp | 12 +-- lib/pki_base.h | 2 +- lib/pki_key.cpp | 9 +- lib/pki_x509super.cpp | 4 +- lib/x509rev.cpp | 4 + ui/Makefile | 2 +- ui/OpenDb.ui | 217 ++++++++++++++++++++++++++++++++++++++++ widgets/ItemCombo.h | 2 +- widgets/MW_database.cpp | 156 ++++++++++++++++------------- widgets/MW_menu.cpp | 8 +- widgets/MainWindow.cpp | 23 ++--- widgets/MainWindow.h | 17 ++-- widgets/Makefile | 2 +- widgets/OpenDb.cpp | 125 +++++++++++++++++++++++ widgets/OpenDb.h | 28 ++++++ 19 files changed, 521 insertions(+), 138 deletions(-) create mode 100644 ui/OpenDb.ui create mode 100644 widgets/OpenDb.cpp create mode 100644 widgets/OpenDb.h diff --git a/lib/db_base.cpp b/lib/db_base.cpp index dbada2cf..5b107be1 100644 --- a/lib/db_base.cpp +++ b/lib/db_base.cpp @@ -155,8 +155,7 @@ dbheaderList db_base::getHeaders() void db_base::saveHeaderState() { - QSqlDatabase *db = mainwin->getDb(); - if (db->isOpen()) + if (QSqlDatabase::database().isOpen()) mainwin->storeSetting(class_name + "_hdView", allHeaders.toData()); } @@ -221,13 +220,13 @@ QSqlError db_base::insertPKI_noTransaction(pki_base *pki) void db_base::insertPKI(pki_base *pki) { - QSqlDatabase *db = mainwin->getDb(); - if (db->transaction()) { + QSqlDatabase db = QSqlDatabase::database(); + if (db.transaction()) { QSqlError e = insertPKI_noTransaction(pki); if (e.isValid()) - db->rollback(); + db.rollback(); else - db->commit(); + db.commit(); } emit columnsContentChanged(); } @@ -268,7 +267,7 @@ void db_base::pem2clipboard(QModelIndexList indexes) const void db_base::deletePKI(QModelIndex idx) { pki_base *pki = static_cast(idx.internalPointer()); - QSqlDatabase *db = mainwin->getDb(); + QSqlDatabase db = QSqlDatabase::database(); try { try { pki->deleteFromToken(); @@ -276,14 +275,14 @@ void db_base::deletePKI(QModelIndex idx) MainWindow::Error(err); } - if (db->transaction()) { + if (db.transaction()) { QSqlError e = pki->deleteSql(); remFromCont(idx); mainwin->dbSqlError(e); if (e.isValid()) - db->rollback(); + db.rollback(); else - db->commit(); + db.commit(); mainwin->dbSqlError(e); } } catch (errorEx &err) { diff --git a/lib/db_crl.cpp b/lib/db_crl.cpp index 1099a7ba..a40b8fdc 100644 --- a/lib/db_crl.cpp +++ b/lib/db_crl.cpp @@ -72,7 +72,6 @@ void db_crl::revokeCerts(pki_crl *crl) void db_crl::removeSigner(pki_base *signer) { -#warning FIXME ...... FOR_ALL_pki(crl, pki_crl) { if (crl->getIssuer() == signer) { crl->setIssuer(NULL); @@ -248,7 +247,7 @@ void db_crl::newItem(pki_x509 *cert) delete dlg; return; } - QSqlDatabase *db = mainwin->getDb(); + QSqlDatabase db = QSqlDatabase::database(); try { x509v3ext e; X509V3_CTX ext_ctx; @@ -285,7 +284,7 @@ void db_crl::newItem(pki_x509 *cert) crl->setLastUpdate(widget->lastUpdate->getDate()); crl->setNextUpdate(widget->nextUpdate->getDate()); crl->sign(cert->getRefKey(), widget->hashAlgo->currentHash()); - if (!db->transaction()) + if (!db.transaction()) throw errorEx(tr("Failed to initiate DB transaction")); transact = true; cert->setCrlExpire(widget->nextUpdate->getDate()); @@ -306,15 +305,15 @@ void db_crl::newItem(pki_x509 *cert) if (err.isValid()) throw errorEx(tr("Database error: ").arg(err.text())); insertPKI_noTransaction(crl); - err = db->lastError(); + err = db.lastError(); if (err.isValid()) throw errorEx(tr("Database error: ").arg(err.text())); - db->commit(); + db.commit(); createSuccess((crl)); } catch (errorEx &err) { if (transact) - db->rollback(); + db.rollback(); MainWindow::Error(err); if (crl) delete crl; diff --git a/lib/db_key.cpp b/lib/db_key.cpp index 6b514977..eec78a79 100644 --- a/lib/db_key.cpp +++ b/lib/db_key.cpp @@ -66,7 +66,7 @@ QList db_key::getAllKeys() QList db_key::getUnusedKeys() { return sqlSELECTpki("SELECT public_keys.item FROM public_keys " - "LEFT OUTER JOIN x509super ON x509super.key = public_keys.item " + "LEFT OUTER JOIN x509super ON x509super.pkey= public_keys.item " "WHERE x509super.item IS NULL"); } @@ -77,14 +77,14 @@ void db_key::remFromCont(QModelIndex &idx) pki_key *pki = static_cast(idx.internalPointer()); QList items = sqlSELECTpki( - "SELECT item FROM x509super WHERE key=?", + "SELECT item FROM x509super WHERE pkey=?", QList() << QVariant(pki->getSqlItemId())); foreach(pki_base *b, items) { pki_x509super *x509s = static_cast(b); x509s->setRefKey(NULL); } - SQL_PREPARE(q, "UPDATE x509super SET key=NULL WHERE item=?"); + SQL_PREPARE(q, "UPDATE x509super SET pkey=NULL WHERE item=?"); q.bindValue(0, pki->getSqlItemId()); q.exec(); mainwin->dbSqlError(q.lastError()); @@ -96,10 +96,10 @@ void db_key::inToCont(pki_base *pki) pki_key *key = static_cast(pki); unsigned hash = key->hash(); QList items = sqlSELECTpki( - "SELECT item FROM x509super WHERE key IS NULL AND key_hash=?", + "SELECT item FROM x509super WHERE pkey IS NULL AND key_hash=?", QList() << QVariant(hash)); XSqlQuery q; - SQL_PREPARE(q, "UPDATE x509super SET key=? WHERE item=?"); + SQL_PREPARE(q, "UPDATE x509super SET pkey=? WHERE item=?"); q.bindValue(0, key->getSqlItemId()); foreach(pki, items) { pki_x509super *x509s = static_cast(pki); diff --git a/lib/db_temp.cpp b/lib/db_temp.cpp index 366885f9..7b084d01 100644 --- a/lib/db_temp.cpp +++ b/lib/db_temp.cpp @@ -151,12 +151,12 @@ bool db_temp::alterTemp(pki_temp *temp) { XSqlQuery q; QSqlError e; - QSqlDatabase *db = mainwin->getDb(); + QSqlDatabase db = QSqlDatabase::database(); if (!runTempDlg(temp)) return false; - if (!db->transaction()) + if (!db.transaction()) return false; SQL_PREPARE(q, "UPDATE templates SET version=?, template=? WHERE item=?"); q.bindValue(0, TMPL_VERSION); @@ -166,10 +166,10 @@ bool db_temp::alterTemp(pki_temp *temp) e = q.lastError(); mainwin->dbSqlError(e); if (e.isValid()) { - db->rollback(); + db.rollback(); return false; } updateItem(temp, temp->getIntName(), temp->getComment()); - db->commit(); + db.commit(); return true; } diff --git a/lib/db_x509.cpp b/lib/db_x509.cpp index 68244f8c..af807181 100644 --- a/lib/db_x509.cpp +++ b/lib/db_x509.cpp @@ -89,7 +89,7 @@ QList db_x509::getAllIssuers() { /* Select X509 CA certificates with available private key */ return sqlSELECTpki("SELECT x509super.item FROM x509super " - "JOIN private_keys ON x509super.key = private_keys.item " + "JOIN private_keys ON x509super.pkey = private_keys.item " "JOIN certs ON certs.item = x509super.item " "WHERE certs.ca=1"); } @@ -185,7 +185,7 @@ void db_x509::inToCont(pki_base *pki) * and use its childs if we are newer */ items = sqlSELECTpki( "SELECT x509super.item FROM x509super " - "JOIN public_keys ON x509super.key = public_keys.item " + "JOIN public_keys ON x509super.pkey = public_keys.item " "JOIN certs ON certs.item = x509super.item " "WHERE certs.ca=1 AND x509super.subj_hash=? " "AND x509super.key_hash=?", @@ -782,14 +782,14 @@ void db_x509::writePKCS7(pki_x509 *cert, QString s, exportType::etype type, void db_x509::storeRevocations(pki_x509 *cert) { - QSqlDatabase *db = mainwin->getDb(); - if (db->transaction()) { + QSqlDatabase db = QSqlDatabase::database(); + if (db.transaction()) { QSqlError e; e = cert->revList.sqlUpdate(cert->getSqlItemId()); if (e.isValid()) - db->rollback(); + db.rollback(); else - db->commit(); + db.commit(); } cert->revList.merged = false; } diff --git a/lib/pki_base.h b/lib/pki_base.h index 6b4ab0e3..e7f275fd 100644 --- a/lib/pki_base.h +++ b/lib/pki_base.h @@ -25,7 +25,7 @@ #define SQL_PREPARE(q,cmd) do { \ (q).prepare(cmd); \ (q).location(__FILE__,__LINE__); \ -} while (0); +} while (0) enum pki_source { unknown, diff --git a/lib/pki_key.cpp b/lib/pki_key.cpp index 9a51882a..4bafde2c 100644 --- a/lib/pki_key.cpp +++ b/lib/pki_key.cpp @@ -237,7 +237,7 @@ int pki_key::getUcount() { XSqlQuery q; int size = -1; - SQL_PREPARE(q, "SELECT COUNT(*) FROM x509super WHERE key=?"); + SQL_PREPARE(q, "SELECT COUNT(*) FROM x509super WHERE pkey=?"); q.bindValue(0, sqlItemId); q.exec(); if (q.first()) @@ -450,7 +450,8 @@ QSqlError pki_key::insertSqlData() XSqlQuery q; QList list; - SQL_PREPARE(q, "SELECT item FROM x509super WHERE key_hash=? AND key IS NULL"); + SQL_PREPARE(q, "SELECT item FROM x509super WHERE key_hash=? AND " + "pkey IS NULL"); q.bindValue(0, myhash); q.exec(); if (q.lastError().isValid()) @@ -470,7 +471,7 @@ QSqlError pki_key::insertSqlData() } q.finish(); - SQL_PREPARE(q, "UPDATE x509super SET key=? WHERE item=?"); + SQL_PREPARE(q, "UPDATE x509super SET pkey=? WHERE item=?"); q.bindValue(0, sqlItemId); foreach(pki_x509super* x, list) { q.bindValue(1, x->getSqlItemId()); @@ -524,7 +525,7 @@ QSqlError pki_key::deleteSqlData() e = q.lastError(); if (e.isValid()) return e; - SQL_PREPARE(q, "UPDATE x509super SET key=NULL WHERE key=?"); + SQL_PREPARE(q, "UPDATE x509super SET pkey=NULL WHERE key=?"); q.bindValue(0, sqlItemId); q.exec(); return q.lastError(); diff --git a/lib/pki_x509super.cpp b/lib/pki_x509super.cpp index 9cd22976..4812efe2 100644 --- a/lib/pki_x509super.cpp +++ b/lib/pki_x509super.cpp @@ -44,7 +44,7 @@ QSqlError pki_x509super::insertSqlData() } } - SQL_PREPARE(q, "INSERT INTO x509super (item, subj_hash, key, key_hash) " + SQL_PREPARE(q, "INSERT INTO x509super (item, subj_hash, pkey, key_hash) " "VALUES (?, ?, ?, ?)"); q.bindValue(0, sqlItemId); q.bindValue(1, (uint)getSubject().hashNum()); @@ -62,7 +62,7 @@ QSqlError pki_x509super::restoreSql(QVariant sqlId) e = pki_base::restoreSql(sqlId); if (e.isValid()) return e; - SQL_PREPARE(q, "SELECT key FROM x509super WHERE item=?"); + SQL_PREPARE(q, "SELECT pkey FROM x509super WHERE item=?"); q.bindValue(0, sqlId); q.exec(); e = q.lastError(); diff --git a/lib/x509rev.cpp b/lib/x509rev.cpp index 71b74112..9526dfa3 100644 --- a/lib/x509rev.cpp +++ b/lib/x509rev.cpp @@ -268,5 +268,9 @@ QSqlError x509revList::sqlUpdate(QVariant caId) for (int i=0; i + + OpenDb + + + + 0 + 0 + 441 + 325 + + + + Dialog + + + + + + 6 + + + 0 + + + + + + Arial + 14 + 50 + false + false + false + false + + + + Open remote database + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + 95 + 40 + + + + + 95 + 40 + + + + + + + true + + + + + + + + + Qt::Vertical + + + + 20 + 20 + + + + + + + + + + Database type + + + + + + + + + + Hostname + + + + + + + + + + Username + + + + + + + + + + Password + + + + + + + + + + Database name + + + + + + + + + + + + Qt::Vertical + + + + 20 + 21 + + + + + + + + Qt::Horizontal + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + Dialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + Dialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/widgets/ItemCombo.h b/widgets/ItemCombo.h index d2464e3f..0632c756 100644 --- a/widgets/ItemCombo.h +++ b/widgets/ItemCombo.h @@ -28,7 +28,7 @@ class itemCombo : public QComboBox void setNullItem(QString text) { if (itemData(0).value() == NULL) removeItem(0); - insertItem(0, text, QVariant::fromValue(NULL)); + insertItem(0, text, QVariant()); } int setCurrentPkiItem(pki_base *p) { int idx = findData(QVariant::fromValue(p)); diff --git a/widgets/MW_database.cpp b/widgets/MW_database.cpp index 10bdc2a9..5c4e0fdd 100644 --- a/widgets/MW_database.cpp +++ b/widgets/MW_database.cpp @@ -19,8 +19,9 @@ #include "lib/db_base.h" #include "lib/func.h" #include "lib/db.h" -#include "widgets/ImportMulti.h" -#include "widgets/NewKey.h" +#include "ImportMulti.h" +#include "NewKey.h" +#include "OpenDb.h" QSqlError MainWindow::initSqlDB() { @@ -55,9 +56,9 @@ QSqlError MainWindow::initSqlDB() * table column (position, sort order, visibility) */ << "CREATE TABLE settings (" - "key CHAR(20) UNIQUE, " + "key_ CHAR(20) UNIQUE, " /* mySql does not like "key" or "option" */ "value VARCHAR(1024))" -<< "INSERT INTO settings (key, value) VALUES ('schema', '1')" +<< "INSERT INTO settings (key_, value) VALUES ('schema', '1')" /* * All items (keys, tokens, requests, certs, crls, templates) @@ -66,7 +67,7 @@ QSqlError MainWindow::initSqlDB() * as FOREIGN KEY. */ << "CREATE TABLE items(" - "id SERIAL PRIMARY KEY, " + "id INTEGER PRIMARY KEY, " "name VARCHAR(128), " /* Internal name of the item */ "type INTEGER, " /* enum pki_type */ "source INTEGER, " /* enum pki_source */ @@ -124,15 +125,15 @@ QSqlError MainWindow::initSqlDB() * - hash of the public key, used for lookups if there * is no key to reference * used by Requests and certificates and the use-counter of keys: - * "SELECT from x509super WHERE key=?" + * "SELECT from x509super WHERE pkey=?" */ << "CREATE TABLE x509super (" "item INTEGER, " /* reference to items(id) */ "subj_hash INTEGER, " /* 32 bit hash of the Distinguished name */ - "key INTEGER, " /* reference to the key items(id) */ + "pkey INTEGER, " /* reference to the key items(id) */ "key_hash INTEGER, " /* 32 bit hash of the public key */ "FOREIGN KEY (item) REFERENCES items (id), " - "FOREIGN KEY (key) REFERENCES items (id)) " + "FOREIGN KEY (pkey) REFERENCES items (id)) " /* * PKCS#10 Certificate request details @@ -172,7 +173,7 @@ QSqlError MainWindow::initSqlDB() "crlExpire "DB_DATE", " /* CRL expiry date */ "crlNo INTEGER, " /* Last CRL Number */ "crlDays INTEGER, " /* CRL days until renewal */ - "dnPolicy, " /* DistinguishedName policy */ + "dnPolicy VARCHAR(1024), " /* DistinguishedName policy */ "FOREIGN KEY (item) REFERENCES items (id), " "FOREIGN KEY (template) REFERENCES items (id)) " @@ -213,8 +214,15 @@ QSqlError MainWindow::initSqlDB() ; XSqlQuery q; + QSqlDatabase db = QSqlDatabase::database(); + QStringList tables = db.tables(); + + if (tables.contains("items")) { + return QSqlError(); + } if (!db.transaction()) return db.lastError(); + foreach(QString sql, sl) { fprintf(stderr, "EXEC: '%s'\n", CCHAR(sql)); if (!q.exec(sql)) { @@ -226,33 +234,28 @@ QSqlError MainWindow::initSqlDB() return QSqlError(); } -QSqlError MainWindow::openSqlDB() +QString MainWindow::openSqlDB(QString dbName) { -//#define POSTGRES 1 -#ifndef POSTGRES - db.setDatabaseName(dbfile); -#else - db.setDatabaseName("xca_pg"); - db.setHostName("192.168.140.7"); - db.setUserName("xca"); - db.setPassword("xca"); -#endif - if (db.driverName() == "QSQLITE") { - // chmod 0600 - if (!QFile::exists(dbfile)) { - QFile f(dbfile); - f.open(QIODevice::WriteOnly); - f.setPermissions(QFile::WriteOwner | QFile::ReadOwner); - f.close(); + OpenDb *opendb = new OpenDb(this, dbName); + if (opendb->exec()) { + opendb->openDatabase(); + QSqlError e = initSqlDB(); + printf("DB-DESC: '%s'\n", CCHAR(opendb->getDescriptor())); + if (e.isValid()) { + dbSqlError(); + dbName = QString(); + } else { + dbName = opendb->getDescriptor(); } } - if (!db.open()) - return db.lastError(); - QStringList tables = db.tables(); - if (!tables.contains("items")) { - return initSqlDB(); - } - return QSqlError(); + delete opendb; + return dbName; +} + +void MainWindow::openRemoteSqlDB() +{ + close_database(); + init_database("@/QPSQL7:"); } void MainWindow::set_geometry(QString geo) @@ -277,7 +280,7 @@ void MainWindow::dbSqlError(QSqlError err) } } -bool MainWindow::checkForOldDbFormat() +bool MainWindow::checkForOldDbFormat(QString dbfile) { // 0x ca db 19 69 static const unsigned char magic[] = { 0xca, 0xdb, 0x19, 0x69 }; @@ -304,7 +307,7 @@ int MainWindow::verifyOldDbPass(QString dbname) if ((p = (char *)mydb.load(&head))) { passhash = p; free(p); - return initPass(passhash); + return initPass(dbname, passhash); } } return 2; @@ -402,41 +405,43 @@ next: } } -int MainWindow::init_database() +int MainWindow::init_database(QString dbName) { int ret = 2; QSqlError err; QString oldDbFile; - qDebug("Opening database: %s", QString2filename(dbfile)); + qDebug("Opening database: %s", QString2filename(dbName)); keys = NULL; reqs = NULL; certs = NULL; temps = NULL; crls = NULL; - if (checkForOldDbFormat()) { - QString newname = dbfile; + if (checkForOldDbFormat(dbName)) { + QString newname = dbName; if (newname.endsWith(".xdb")) newname = newname.left(newname.length() -4); newname += "_backup_" + QDateTime::currentDateTime() .toString("yyyyMMdd_hhmmss") + ".xdb"; if (!XCA_OKCANCEL(tr("Found an old version of the XCA database. I will make a backup copy called: '%1' and convert the database into the new format").arg(newname))) { - dbfile = ""; return 1; } - if (verifyOldDbPass(dbfile) != 1) + if (verifyOldDbPass(dbName) != 1) return 1; - if (!QFile::rename(dbfile, newname)) { + if (!QFile::rename(dbName, newname)) { XCA_WARN(tr("Failed to rename the database file, because the target already exists")); return 1; } oldDbFile = newname; } Entropy::seed_rng(); - err = openSqlDB(); - dbSqlError(err); + dbName = openSqlDB(dbName); + if (!QSqlDatabase::database().isOpen()) { + dbSqlError(); + return 1; + } certView->setRootIsDecorated(db_x509::treeview); try { if (pki_evp::passwd.isEmpty()) { - ret = initPass(); + ret = initPass(dbName); if (ret == 2) return ret; } @@ -448,7 +453,6 @@ int MainWindow::init_database() } catch (errorEx &err) { Error(err); - dbfile = ""; return ret; } @@ -492,7 +496,7 @@ int MainWindow::init_database() if (!oldDbFile.isEmpty()) importOldDatabase(oldDbFile); - XSqlQuery query("SELECT key, value FROM settings"); + XSqlQuery query("SELECT key_, value FROM settings"); while (query.next()) { QString key = query.value(0).toString(); QString value = query.value(1).toString(); @@ -523,13 +527,14 @@ int MainWindow::init_database() if (pki_evp::passwd.isNull()) XCA_INFO(tr("Using or exporting private keys will not be possible without providing the correct password")); - dbindex->setText(tr("Database") + ": " + dbfile); load_engine(); hashBox hb(this); if (hb.isInsecure()) { XCA_WARN(tr("The currently used default hash '%1' is insecure. Please select at least 'SHA 224' for security reasons.").arg(hb.currentHashName())); setOptions(); } + dbindex->setText(tr("Database") + ": " + dbName); + currentDB = dbName; return ret; } @@ -608,7 +613,7 @@ void MainWindow::undelete() int MainWindow::open_default_db() { - if (!dbfile.isEmpty()) + if (QSqlDatabase::database().isOpen()) return 0; FILE *fp = fopen_read(getUserSettingsDir() + QDir::separator() + "defaultdb"); @@ -619,22 +624,21 @@ int MainWindow::open_default_db() size_t len = fread(buff, 1, 255, fp); fclose(fp); buff[len] = 0; - dbfile = filename2QString(buff).trimmed(); + QString dbfile = filename2QString(buff).trimmed(); if (QFile::exists(dbfile)) - return init_database(); - dbfile = QString(); + return init_database(dbfile); return 0; } void MainWindow::default_database() { - QFileInfo fi(dbfile); + QFileInfo fi(currentDB); QString dir = getUserSettingsDir(); QString file = dir +QDir::separator() +"defaultdb"; FILE *fp; QDir d; - if (dbfile.isEmpty()) { + if (currentDB.isEmpty()) { QFile::remove(file); return; } @@ -655,7 +659,7 @@ void MainWindow::default_database() QString MainWindow::getSetting(QString key) { XSqlQuery q; - SQL_PREPARE(q, "SELECT value FROM settings WHERE key=?"); + SQL_PREPARE(q, "SELECT value FROM settings WHERE key_=?"); q.bindValue(0, key); q.exec(); if (q.first()) { @@ -668,16 +672,18 @@ QString MainWindow::getSetting(QString key) void MainWindow::storeSetting(QString key, QString value) { XSqlQuery q; - SQL_PREPARE(q, "UPDATE settings SET value=? WHERE key=?"); - q.bindValue(0, value); - q.bindValue(1, key); + QSqlError e; + + SQL_PREPARE(q, "SELECT COUNT(key_) FROM settings WHERE key_=?"); + q.bindValue(0, key); q.exec(); dbSqlError(q.lastError()); - if (q.numRowsAffected() == 1) - return; - SQL_PREPARE(q, "INSERT INTO settings (key, value) VALUES (?, ?)"); - q.bindValue(0, key); - q.bindValue(1, value); + if (q.first() && q.value(0).toInt() == 1) + SQL_PREPARE(q, "UPDATE settings SET value=? WHERE key_=?"); + else + SQL_PREPARE(q, "INSERT INTO settings (value, key_) VALUES (?,?)"); + q.bindValue(0, value); + q.bindValue(1, key); q.exec(); dbSqlError(q.lastError()); } @@ -685,10 +691,21 @@ void MainWindow::storeSetting(QString key, QString value) void MainWindow::close_database() { QByteArray ba; - if (!db.isOpen()) - return; + QString connName; + bool dbopen; - qDebug("Closing database: %s", QString2filename(dbfile)); + { + /* Destroy "db" at the end of the block */ + QSqlDatabase db = QSqlDatabase::database(); + connName= db.connectionName(); + dbopen = db.isOpen(); + } + + if (!dbopen) { + QSqlDatabase::removeDatabase(connName); + return; + } + qDebug("Closing database: %s", QString2filename(currentDB)); QString s = QString("%1,%2,%3") .arg(size().width()).arg(size().height()) .arg(tabView->currentIndex()); @@ -721,7 +738,7 @@ void MainWindow::close_database() temps = NULL; keys = NULL; - db.close(); + QSqlDatabase::database().close(); pki_evp::passwd.cleanse(); pki_evp::passwd = QByteArray(); @@ -729,10 +746,11 @@ void MainWindow::close_database() return; crls = NULL; - update_history(dbfile); + update_history(currentDB); pkcs11::remove_libs(); enableTokenMenu(pkcs11::loaded()); - dbfile.clear(); + QSqlDatabase::removeDatabase(connName); + currentDB.clear(); } void MainWindow::load_history() diff --git a/widgets/MW_menu.cpp b/widgets/MW_menu.cpp index fc8ef053..a84709f3 100644 --- a/widgets/MW_menu.cpp +++ b/widgets/MW_menu.cpp @@ -93,6 +93,7 @@ void MainWindow::init_menu() QKeySequence::New); file->addAction(tr("&Open DataBase"), this, SLOT(load_database()), QKeySequence::Open); + file->addAction(tr("Open Remote DataBase"), this, SLOT(openRemoteSqlDB())); file->addMenu(historyMenu); file->addAction(tr("Set as default DataBase"), this, SLOT(default_database())); @@ -160,7 +161,7 @@ void MainWindow::init_menu() wdMenuList += import; scardList += token; - setItemEnabled(!dbfile.isEmpty()); + setItemEnabled(!currentDB.isEmpty()); } int MainWindow::changeDB(QString fname) @@ -169,8 +170,7 @@ int MainWindow::changeDB(QString fname) return 1; close_database(); homedir = fname.mid(0, fname.lastIndexOf(QDir::separator())); - dbfile = fname; - return init_database(); + return init_database(fname); } void MainWindow::update_history_menu() @@ -218,7 +218,7 @@ void MainWindow::load_database() void MainWindow::setOptions() { - if (dbfile.isEmpty()) + if (!QSqlDatabase::database().isOpen()) return; Options *opt = new Options(this); diff --git a/widgets/MainWindow.cpp b/widgets/MainWindow.cpp index cef0d32a..c7807c08 100644 --- a/widgets/MainWindow.cpp +++ b/widgets/MainWindow.cpp @@ -119,12 +119,6 @@ MainWindow::MainWindow(QWidget *parent) fprintf(stderr, "DB driver: '%s'\n", CCHAR(driver)); } -//#define POSTGRES 1 -#ifndef POSTGRES - db = QSqlDatabase::addDatabase("QSQLITE"); -#else - db = QSqlDatabase::addDatabase("QPSQL7"); -#endif historyMenu = NULL; init_menu(); setItemEnabled(false); @@ -649,6 +643,7 @@ void MainWindow::changeDbPass() { Passwd pass; XSqlQuery q; + QSqlDatabase db = QSqlDatabase::database(); if (!checkOldGetNewPass(pass)) return; @@ -682,13 +677,13 @@ void MainWindow::changeDbPass() pki_evp::passwd = pass; } -int MainWindow::initPass() +int MainWindow::initPass(QString dbName) { QString passhash = getSetting("pwhash"); - return initPass(passhash); + return initPass(dbName, passhash); } -int MainWindow::initPass(QString passhash) +int MainWindow::initPass(QString dbName, QString passhash) { pki_evp::passHash = QString(); QString salt, pass; @@ -696,8 +691,8 @@ int MainWindow::initPass(QString passhash) pass_info p(tr("New Password"), tr("Please enter a password, " "that will be used to encrypt your private keys " - "in the database file:\n%1"). - arg(compressFilename(dbfile)), this); + "in the database:\n%1"). + arg(compressFilename(dbName)), this); pki_evp::passHash = passhash; if (pki_evp::passHash.isEmpty()) { @@ -716,7 +711,7 @@ int MainWindow::initPass(QString passhash) XCA_WARN( tr("Password verify error, please try again")); p.setTitle(tr("Password")); - p.setDescription(tr("Please enter the password for unlocking the database:\n%1").arg(compressFilename(dbfile))); + p.setDescription(tr("Please enter the password for unlocking the database:\n%1").arg(compressFilename(dbName))); ret = PwDialog::execute(&p, &pki_evp::passwd, false, true); if (ret != 1) { @@ -944,8 +939,8 @@ void MainWindow::changeEvent(QEvent *event) if (model) model->updateHeaders(); } - if (!dbfile.isEmpty()) - dbindex->setText(tr("Database") + ": " + dbfile); + if (!currentDB.isEmpty()) + dbindex->setText(tr("Database") + ": " + currentDB); } QMainWindow::changeEvent(event); } diff --git a/widgets/MainWindow.h b/widgets/MainWindow.h index f294617c..0feca790 100644 --- a/widgets/MainWindow.h +++ b/widgets/MainWindow.h @@ -87,8 +87,8 @@ class MainWindow: public QMainWindow, public Ui::MainWindow int exportIndex(QString fname, bool hierarchy); void checkDB(); QSqlError initSqlDB(); - QSqlError openSqlDB(); - QSqlDatabase db; + QString openSqlDB(QString dbName); + QString currentDB; protected: void init_images(); @@ -117,19 +117,14 @@ class MainWindow: public QMainWindow, public Ui::MainWindow static QString explicit_dn; static QString explicit_dn_default; int exitApp; - QSqlDatabase *getDb() - { - return &db; - } - QString dbfile; QLabel *dbindex; MainWindow(QWidget *parent); virtual ~MainWindow(); void loadSettings(); void saveSettings(); - int initPass(); - int initPass(QString passhash); + int initPass(QString dbName); + int initPass(QString dbName, QString passhash); void read_cmdline(int argc, char *argv[]); void load_engine(); static OidResolver *getResolver() @@ -158,11 +153,12 @@ class MainWindow: public QMainWindow, public Ui::MainWindow void update_history(QString file); void initResolver(); bool checkForOldDbFormat(); + bool checkForOldDbFormat(QString dbfile); int verifyOldDbPass(QString dbname); void importOldDatabase(QString dbname); public slots: - int init_database(); + int init_database(QString dbName); void new_database(); void load_database(); void close_database(); @@ -181,6 +177,7 @@ class MainWindow: public QMainWindow, public Ui::MainWindow void changeEvent(QEvent *event); void exportIndex(); void exportIndexHierarchy(); + void openRemoteSqlDB(); protected slots: void closeEvent(QCloseEvent * event); diff --git a/widgets/Makefile b/widgets/Makefile index 83babf28..3201f448 100644 --- a/widgets/Makefile +++ b/widgets/Makefile @@ -9,7 +9,7 @@ MOC_NAMES=MainWindow KeyDetail clicklabel XcaTreeView NewX509 \ ImportMulti CrlDetail ExportDialog hashBox Options NewKey kvView \ NewCrl SearchPkcs11 RevocationList XcaProxyModel XcaHeaderView \ KeyTreeView TempTreeView ReqTreeView X509SuperTreeView CertTreeView \ - OidResolver + OidResolver OpenDb NAMES=$(MOC_NAMES) NewX509_ext MW_menu MW_help MW_database OBJS=$(patsubst %,moc_%.o,$(MOC_NAMES)) $(patsubst %,%.o,$(NAMES)) diff --git a/widgets/OpenDb.cpp b/widgets/OpenDb.cpp new file mode 100644 index 00000000..8f87141b --- /dev/null +++ b/widgets/OpenDb.cpp @@ -0,0 +1,125 @@ +/* vi: set sw=4 ts=4: + * + * Copyright (C) 2017 Christian Hohnstaedt. + * + * All rights reserved. + */ + +#include +#include +#include + +#include "OpenDb.h" +#include "PwDialog.h" +#include "lib/base.h" + +OpenDb::OpenDb(QWidget *parent, QString db) + :QDialog(parent) +{ + QMap databases; + QString dbTypeName; + + setupUi(this); + setWindowTitle(XCA_TITLE); + + QRegExp rx("(.*)@(.*)/(.*):(.*)"); + int pos = rx.indexIn(db); + QStringList list = rx.capturedTexts(); + foreach(QString s, list) + printf("OpenDB: '%s'\n", CCHAR(s)); + + if (pos != -1 && list.size() == 5) { + userName->setText(list[1]); + hostName->setText(list[2]); + dbTypeName = list[3]; + dbName->setText(list[4]); + } else { + dbName->setText(db); + dbTypeName = "QSQLITE"; + } + + databases["QPSQL7"] = "PostgreSQL version 6 and 7"; + databases["QMYSQL3"] = "MySQL 3.x and 4.x"; + databases["QSQLITE" ] = "SQLite version 3 or above"; + + list = QSqlDatabase::drivers(); + foreach (QString driver, list) { + if (!databases.contains(driver)) + continue; + dbType->insertItem(0, databases[driver], driver); + if (driver == dbTypeName) + dbType->setCurrentIndex(0); + } +} + +void OpenDb::openDatabase() const +{ + QString type = dbType->itemData(dbType->currentIndex()).toString(); + QString pass = dbPassword->text(); + + if (type == "QSQLITE" && !QFile::exists(dbName->text())) { + QFile f(dbName->text()); + f.open(QIODevice::WriteOnly); + f.setPermissions(QFile::WriteOwner | QFile::ReadOwner); + f.close(); + } + while (true) { + QString connName = QSqlDatabase::addDatabase(type).connectionName(); + if (_openDatabase(connName, pass)) + break; + Passwd pwd; + pass_info p(XCA_TITLE, + tr("Please enter the password to access the database server %2 as user '%1'.") + .arg(userName->text()).arg(hostName->text())); + if (PwDialog::execute(&p, &pwd) != 1) + break; + pass =QString(pwd); + QSqlDatabase::removeDatabase(connName); + } +} + +bool OpenDb::_openDatabase(QString connName, QString pass) const +{ + QSqlDatabase db = QSqlDatabase::database(connName, false); + + QStringList hostport = hostName->text().split(":"); + db.setDatabaseName(dbName->text()); + printf("hostport.size(): %d\n", hostport.size()); + if (hostport.size() > 0) + db.setHostName(hostport[0]); + if (hostport.size() > 1) + db.setPort(hostport[1].toInt()); + + db.setUserName(userName->text()); + db.setPassword(pass); + + db.open(); + QSqlError e = db.lastError(); + if (!e.isValid() || e.type() != QSqlError::ConnectionError || + db.driverName() == "QSQLITE" || db.isOpen()) + return true; + + db.close(); + return false; +}; + +QString OpenDb::getDescriptor() const +{ + QString type = dbType->itemData(dbType->currentIndex()).toString(); + if (type == "QSQLITE") + return dbName->text(); + + return QString("%1@%2/%3:%4") + .arg(userName->text()) + .arg(hostName->text()) + .arg(type) + .arg(dbName->text()); +} + +int OpenDb::exec() +{ + QString type = dbType->itemData(dbType->currentIndex()).toString(); + if (type != "QSQLITE") + return QDialog::exec(); + return 1; +} diff --git a/widgets/OpenDb.h b/widgets/OpenDb.h new file mode 100644 index 00000000..ee6b73f3 --- /dev/null +++ b/widgets/OpenDb.h @@ -0,0 +1,28 @@ +/* vi: set sw=4 ts=4: + * + * Copyright (C) 2017 Christian Hohnstaedt. + * + * All rights reserved. + */ + +#ifndef __OPENDB_H +#define __OPENDB_H + +#include "ui_OpenDb.h" +#include + +class OpenDb: public QDialog, public Ui::OpenDb +{ + Q_OBJECT + + public: + OpenDb(QWidget *parent, QString db); + void openDatabase() const; + bool _openDatabase(QString connName, QString pass) const; + QString getDescriptor() const; + + public slots: + int exec(); +}; + +#endif