diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index e3ea8aed..4aaaae71 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -38,6 +38,7 @@ XcaProgress.h XcaWarningCore.cpp XcaWarningCore.h PwDialogCore.cpp PwDialogCore.h digest.h digest.cpp pki_export.cpp debug_info.h func_base.cpp func_base.h debug_info.cpp +cmdline.cpp ) macro(ExpandSources target) diff --git a/lib/cmdline.cpp b/lib/cmdline.cpp new file mode 100644 index 00000000..f48d2c8a --- /dev/null +++ b/lib/cmdline.cpp @@ -0,0 +1,266 @@ +/* vi: set sw=4 ts=4: + * + * Copyright (C) 2023 Christian Hohnstaedt. + * + * All rights reserved. + */ + +#include +#include +#include + +#include "func.h" +#include "database_model.h" +#include "debug_info.h" +#include "pki_multi.h" +#include "pki_evp.h" +#include "pki_base.h" +#include "pki_x509.h" +#include "pki_crl.h" +#include "arguments.h" +#include "pki_export.h" +#include "PwDialogCore.h" +#include "BioByteArray.h" +#include "db_x509.h" +#include "db_crl.h" + +static const char *xca_name = "xca"; +static void cmd_version(FILE *fp) +{ + console_write(fp, QString(XCA_TITLE "\nVersion %1\n") + .arg(version_str(false)).toUtf8()); +} + +static int cmd_help(int exitcode = EXIT_SUCCESS, const char *msg = NULL) +{ + FILE *fp = exitcode == EXIT_SUCCESS ? stdout : stderr; + QString s; + + cmd_version(fp); + s = QString("\nUsage %1 ...\n\n%2\n") + .arg(xca_name).arg(arguments::help()); + if (msg) + s += QString("\nError: %1\n").arg(msg); + + console_write(fp, s.toUtf8()); + return exitcode; +} + +static Passwd acquire_password(QString source) +{ + Passwd pass; + pass.append(source.toUtf8()); + + if (source == "stdin") + source = "fd:0"; + if (source.startsWith("pass:")) { + pass = source.mid(5).toLatin1(); + } else if (source.startsWith("file:")) { + XFile f(source.mid(5)); + f.open_read(); + pass = f.readLine(128).trimmed(); + } else if (source.startsWith("env:")) { + pass = getenv(source.mid(4).toLocal8Bit()); + } else if (source.startsWith("fd:")) { + int fd = source.mid(3).toInt(); + QFile f; + f.open(fd, QIODevice::ReadOnly); + pass = f.readLine(128).trimmed(); + } + return pass; +} + +static bool compare_pki_base(pki_base* a, pki_base* b) +{ + return (a->getSqlItemId().toULongLong() < + b->getSqlItemId().toULongLong()); +} + +int read_cmdline(int argc, char *argv[], bool console_only, + pki_multi **_cmdline_items) +{ + pki_multi *cmdline_items; + + if (argc > 0) + xca_name = argv[0]; + arguments cmd_opts(argc, argv); + PwDialogCore::cmdline_passwd = acquire_password(cmd_opts["password"]); + Passwd sqlpw = acquire_password(cmd_opts["sqlpass"]); + + if (cmd_opts.has("verbose")) { + QString all = cmd_opts["verbose"]; + debug_info::set_debug(all.isEmpty() ? QString("all") : all); + } + if (console_only) + database_model::open_without_password = true; + + if (cmd_opts.has("database")) + Database.open(cmd_opts["database"], sqlpw); + + *_cmdline_items = cmdline_items = new pki_multi(); + + foreach(QString file, cmd_opts.getFiles()) { + qDebug() << "Probe" << file; + cmdline_items->probeAnything(file); + } + QStringList names = cmd_opts["import-names"].split(";"); + foreach(pki_base *pki, cmdline_items->get()) { + if (names.isEmpty()) + break; + QString name = names.takeFirst(); + if (!name.isEmpty()) + pki->setIntName(name); + } + if (cmdline_items->failed_files.size() > 0) { + XCA_WARN(QString("Failed to import from '%1'") + .arg(cmdline_items->failed_files.join("' '"))); + } + if (cmd_opts.needDb() && !Database.isOpen()) { + /* We need a database for the following operations + * but there is none, yet. Try the default database */ + try { + Database.open(QString()); + } catch (errorEx &err) { + return cmd_help(EXIT_FAILURE, CCHAR(err.getString())); + } catch (enum open_result opt) { + static const char * const msg[] = { + /* pw_cancel */ "Password input aborted", + /* pw_ok */ "Password accepted??", + /* pw_exit */ "Exit selected", + /* open_abort*/ "No database given", + }; + return cmd_help(EXIT_FAILURE, msg[opt]); + } + } + database_model::open_without_password = false; + + if (cmd_opts.has("list-curves")) { + QStringList list; + foreach(const builtin_curve &c, builtinCurves) { + list << QString(COL_YELL "%1" COL_RESET "%2") + .arg(OBJ_nid2sn(c.nid), -26) + .arg(c.comment); + } + console_write(stdout, list.join("\n").toUtf8() + '\n'); + } + if (cmd_opts.has("list-items")) { + QStringList list; + QList items = Store.getAll(); + std::sort(items.begin(), items.end(), compare_pki_base); + foreach(pki_base *pki, items) { + list << QString(COL_YELL "%1 " COL_GREEN "%2 " + COL_RESET "%3") + .arg(pki->getSqlItemId().toString(), 7) + .arg(pki->getTypeString(), -27) + .arg(pki->getIntName()); + } + console_write(stdout, list.join("\n").toUtf8() + '\n'); + } + if (!cmd_opts["index"].isEmpty()) { + qDebug() << cmd_opts["index"]; + db_x509 *certs = Database.model(); + certs->writeIndex(cmd_opts["index"], false); + XCA_INFO(QObject::tr("Index file written to '%1'") + .arg(cmd_opts["index"])); + } + if (!cmd_opts["hierarchy"].isEmpty()) { + qDebug() << cmd_opts["hierarchy"]; + db_x509 *certs = Database.model(); + certs->writeIndex(cmd_opts["hierarchy"], true); + XCA_INFO(QObject::tr("Index hierarchy written to '%1'") + .arg(cmd_opts["hierarchy"])); + } + if (cmd_opts.has("help")) + cmd_help(); + + if (cmd_opts.has("version")) + cmd_version(stdout); + + if (cmd_opts.has("keygen")) { + keyjob task(cmd_opts["keygen"]); + if (!task.isValid()) { + Database.close(); + throw errorEx(QObject::tr("Unknown key type %1") + .arg(cmd_opts["keygen"])); + } + db_key *keys = Database.model(); + pki_key *pki = keys->newKey(task, cmd_opts["name"]); + if (pki) + cmdline_items->append_item(pki); + } + if (cmd_opts.has("issuers")) { + QStringList out; + db_x509 *certs = Database.model(); + QListissuers = certs->getAllIssuers(); + std::sort(issuers.begin(), issuers.end(), compare_pki_base); + foreach(pki_x509 *iss, issuers) { + pki_key *key = iss->getRefKey(); + QString keytype = key ? key->getTypeString() : ""; + out << QString(COL_YELL "%1 " COL_GREEN "%2 " + COL_RESET "%3") + .arg(iss->getSqlItemId().toULongLong(), 7) + .arg(keytype, -13) + .arg(iss->getIntName()); + } + console_write(stdout, out.join("\n").toUtf8() + '\n'); + } + if (cmd_opts.has("crlgen")) { + db_crl *crls = Database.model(); + db_x509 *certs = Database.model(); + QListissuers = certs->getAllIssuers(); + pki_x509 *issuer = NULL; + QString ca = cmd_opts["crlgen"]; + foreach(pki_x509 *iss, issuers) { + if (iss->getIntName() == ca || + iss->getSqlItemId().toString() == ca) + { + issuer = iss; + break; + } + } + if (!issuer) { + XCA_ERROR(QString("Issuer '%1' not found") + .arg(cmd_opts["crlgen"])); + } else { + crljob task(issuer); + pki_crl *crl = crls->newCrl(task, cmd_opts["name"]); + if (crl) + cmdline_items->append_item(crl); + } + } + if (!cmd_opts["select"].isEmpty()) { + foreach(QString item, cmd_opts["select"].split(",")) { + bool ok; + qDebug() << "Select" << item; + qulonglong id = item.toULongLong(&ok); + pki_base *pki = Store.lookupPki(QVariant(id)); + if (pki) + cmdline_items->append_item(pki); + } + } + + BioByteArray bba; + foreach(pki_base *pki, cmdline_items->get()) { + QString filename = pki->getFilename(); + if ((cmd_opts.has("text") || cmd_opts.has("print")) && + filename.size() > 0) + { + bba += QString("\n" COL_GREEN COL_UNDER "File: %1" + COL_RESET "\n").arg(filename).toUtf8(); + } + if (cmd_opts.has("print")) + pki->print(bba, pki_base::print_coloured); + if (cmd_opts.has("text")) + pki->print(bba, pki_base::print_openssl_txt); + if (cmd_opts.has("pem")) + pki->print(bba, pki_base::print_pem); + } + if (bba.size() > 0) + console_write(stdout, bba); + if (cmd_opts.has("import")) { + Database.insert(cmdline_items); + cmdline_items = NULL; + } + return EXIT_SUCCESS; +} + diff --git a/lib/debug_info.cpp b/lib/debug_info.cpp index f940bb10..4984379e 100644 --- a/lib/debug_info.cpp +++ b/lib/debug_info.cpp @@ -7,9 +7,12 @@ #include #include +#include #include #include "debug_info.h" +#include "base.h" +#include "func.h" QList debug_info::patternlist; bool debug_info::all = false; diff --git a/lib/main.cpp b/lib/main.cpp index 24abadcd..4ed3b467 100644 --- a/lib/main.cpp +++ b/lib/main.cpp @@ -13,20 +13,13 @@ #include "widgets/MainWindow.h" #include "ui_MainWindow.h" #include "widgets/XcaApplication.h" -#include "XcaWarningCore.h" #include "func.h" -#include "xfile.h" #include "main.h" #include "entropy.h" #include "settings.h" -#include "database_model.h" #include "pki_multi.h" -#include "pki_evp.h" -#include "pki_base.h" #include "arguments.h" #include "pki_export.h" -#include "PwDialogCore.h" -#include "db_x509.h" #include "debug_info.h" #if defined(Q_OS_WIN32) //For the segfault handler @@ -63,241 +56,8 @@ static void segv_handler_gui(int) } #endif -static void cmd_version(FILE *fp) -{ - console_write(fp, QString(XCA_TITLE "\nVersion %1\n") - .arg(version_str(false)).toUtf8()); -} -const char *xca_name = "xca"; -static int cmd_help(int exitcode = EXIT_SUCCESS, const char *msg = NULL) -{ - FILE *fp = exitcode == EXIT_SUCCESS ? stdout : stderr; - QString s; - - cmd_version(fp); - s = QString("\nUsage %1 ...\n\n%2\n") - .arg(xca_name).arg(arguments::help()); - if (msg) - s += QString("\nError: %1\n").arg(msg); - - console_write(fp, s.toUtf8()); - return exitcode; -} - -static Passwd acquire_password(QString source) -{ - Passwd pass; - pass.append(source.toUtf8()); - - if (source == "stdin") - source = "fd:0"; - if (source.startsWith("pass:")) { - pass = source.mid(5).toLatin1(); - } else if (source.startsWith("file:")) { - XFile f(source.mid(5)); - f.open_read(); - pass = f.readLine(128).trimmed(); - } else if (source.startsWith("env:")) { - pass = getenv(source.mid(4).toLocal8Bit()); - } else if (source.startsWith("fd:")) { - int fd = source.mid(3).toInt(); - QFile f; - f.open(fd, QIODevice::ReadOnly); - pass = f.readLine(128).trimmed(); - } - return pass; -} - -static bool compare_pki_base(pki_base* a, pki_base* b) -{ - return (a->getSqlItemId().toULongLong() < - b->getSqlItemId().toULongLong()); -} - -static pki_multi *cmdline_items; -static int read_cmdline(int argc, char *argv[], bool console_only) -{ - arguments cmd_opts(argc, argv); - PwDialogCore::cmdline_passwd = acquire_password(cmd_opts["password"]); - Passwd sqlpw = acquire_password(cmd_opts["sqlpass"]); - - if (cmd_opts.has("verbose")) { - QString all = cmd_opts["verbose"]; - debug_info::set_debug(all.isEmpty() ? QString("all") : all); - } - if (console_only) - database_model::open_without_password = true; - - if (cmd_opts.has("database")) - Database.open(cmd_opts["database"], sqlpw); - - cmdline_items = new pki_multi(); - - foreach(QString file, cmd_opts.getFiles()) { - qDebug() << "Probe" << file; - cmdline_items->probeAnything(file); - } - QStringList names = cmd_opts["import-names"].split(";"); - foreach(pki_base *pki, cmdline_items->get()) { - if (names.isEmpty()) - break; - QString name = names.takeFirst(); - if (!name.isEmpty()) - pki->setIntName(name); - } - if (cmdline_items->failed_files.size() > 0) { - XCA_WARN(QString("Failed to import from '%1'") - .arg(cmdline_items->failed_files.join("' '"))); - } - if (cmd_opts.needDb() && !Database.isOpen()) { - /* We need a database for the following operations - * but there is none, yet. Try the default database */ - try { - Database.open(QString()); - } catch (errorEx &err) { - return cmd_help(EXIT_FAILURE, CCHAR(err.getString())); - } catch (enum open_result opt) { - static const char * const msg[] = { - /* pw_cancel */ "Password input aborted", - /* pw_ok */ "Password accepted??", - /* pw_exit */ "Exit selected", - /* open_abort*/ "No database given", - }; - return cmd_help(EXIT_FAILURE, msg[opt]); - } - } - database_model::open_without_password = false; - - if (cmd_opts.has("list-curves")) { - QStringList list; - foreach(const builtin_curve &c, builtinCurves) { - list << QString(COL_YELL "%1" COL_RESET "%2") - .arg(OBJ_nid2sn(c.nid), -26) - .arg(c.comment); - } - console_write(stdout, list.join("\n").toUtf8() + '\n'); - } - if (cmd_opts.has("list-items")) { - QStringList list; - QList items = Store.getAll(); - std::sort(items.begin(), items.end(), compare_pki_base); - foreach(pki_base *pki, items) { - list << QString(COL_YELL "%1 " COL_GREEN "%2 " - COL_RESET "%3") - .arg(pki->getSqlItemId().toString(), 7) - .arg(pki->getTypeString(), -27) - .arg(pki->getIntName()); - } - console_write(stdout, list.join("\n").toUtf8() + '\n'); - } - if (!cmd_opts["index"].isEmpty()) { - qDebug() << cmd_opts["index"]; - db_x509 *certs = Database.model(); - certs->writeIndex(cmd_opts["index"], false); - XCA_INFO(QObject::tr("Index file written to '%1'") - .arg(cmd_opts["index"])); - } - if (!cmd_opts["hierarchy"].isEmpty()) { - qDebug() << cmd_opts["hierarchy"]; - db_x509 *certs = Database.model(); - certs->writeIndex(cmd_opts["hierarchy"], true); - XCA_INFO(QObject::tr("Index hierarchy written to '%1'") - .arg(cmd_opts["hierarchy"])); - } - if (cmd_opts.has("help")) - cmd_help(); - - if (cmd_opts.has("version")) - cmd_version(stdout); - - if (cmd_opts.has("keygen")) { - keyjob task(cmd_opts["keygen"]); - if (!task.isValid()) { - Database.close(); - throw errorEx(QObject::tr("Unknown key type %1") - .arg(cmd_opts["keygen"])); - } - db_key *keys = Database.model(); - pki_key *pki = keys->newKey(task, cmd_opts["name"]); - if (pki) - cmdline_items->append_item(pki); - } - if (cmd_opts.has("issuers")) { - QStringList out; - db_x509 *certs = Database.model(); - QListissuers = certs->getAllIssuers(); - std::sort(issuers.begin(), issuers.end(), compare_pki_base); - foreach(pki_x509 *iss, issuers) { - pki_key *key = iss->getRefKey(); - QString keytype = key ? key->getTypeString() : ""; - out << QString(COL_YELL "%1 " COL_GREEN "%2 " - COL_RESET "%3") - .arg(iss->getSqlItemId().toULongLong(), 7) - .arg(keytype, -13) - .arg(iss->getIntName()); - } - console_write(stdout, out.join("\n").toUtf8() + '\n'); - } - if (cmd_opts.has("crlgen")) { - db_crl *crls = Database.model(); - db_x509 *certs = Database.model(); - QListissuers = certs->getAllIssuers(); - pki_x509 *issuer = NULL; - QString ca = cmd_opts["crlgen"]; - foreach(pki_x509 *iss, issuers) { - if (iss->getIntName() == ca || - iss->getSqlItemId().toString() == ca) - { - issuer = iss; - break; - } - } - if (!issuer) { - XCA_ERROR(QString("Issuer '%1' not found") - .arg(cmd_opts["crlgen"])); - } else { - crljob task(issuer); - pki_crl *crl = crls->newCrl(task, cmd_opts["name"]); - if (crl) - cmdline_items->append_item(crl); - } - } - if (!cmd_opts["select"].isEmpty()) { - foreach(QString item, cmd_opts["select"].split(",")) { - bool ok; - qDebug() << "Select" << item; - qulonglong id = item.toULongLong(&ok); - pki_base *pki = Store.lookupPki(QVariant(id)); - if (pki) - cmdline_items->append_item(pki); - } - } - - BioByteArray bba; - foreach(pki_base *pki, cmdline_items->get()) { - QString filename = pki->getFilename(); - if ((cmd_opts.has("text") || cmd_opts.has("print")) && - filename.size() > 0) - { - bba += QString("\n" COL_GREEN COL_UNDER "File: %1" - COL_RESET "\n").arg(filename).toUtf8(); - } - if (cmd_opts.has("print")) - pki->print(bba, pki_base::print_coloured); - if (cmd_opts.has("text")) - pki->print(bba, pki_base::print_openssl_txt); - if (cmd_opts.has("pem")) - pki->print(bba, pki_base::print_pem); - } - if (bba.size() > 0) - console_write(stdout, bba); - if (cmd_opts.has("import")) { - Database.insert(cmdline_items); - cmdline_items = NULL; - } - return EXIT_SUCCESS; -} +int read_cmdline(int, char **, bool, pki_multi **); int main(int argc, char *argv[]) { @@ -337,8 +97,6 @@ int main(int argc, char *argv[]) #else signal(SIGSEGV, segv_handler_gui); #endif - if (argc > 0) - xca_name = argv[0]; #if (OPENSSL_VERSION_NUMBER >= 0x30000000L) if (OSSL_PROVIDER_try_load(0, "legacy", 1)) @@ -368,6 +126,7 @@ int main(int argc, char *argv[]) migrateOldPaths(); + pki_multi *cmdline_items = nullptr; Entropy entropy; Settings.clear(); try { @@ -384,12 +143,13 @@ int main(int argc, char *argv[]) if (gui && !console_only) { mainwin = new MainWindow(); gui->setMainwin(mainwin); - read_cmdline(argc, argv, console_only); + read_cmdline(argc, argv, console_only, &cmdline_items); qDebug() << "CMD Items" << cmdline_items->get().size(); if (cmdline_items->get().size() > 0) { mainwin->importMulti(cmdline_items, 1); cmdline_items = nullptr; } else { + delete cmdline_items; enum open_result r = open_abort; if (!Database.isOpen()) r = mainwin->init_database(QString()); @@ -402,7 +162,7 @@ int main(int argc, char *argv[]) } } } else { - ret = read_cmdline(argc, argv, console_only); + ret = read_cmdline(argc, argv, console_only, &cmdline_items); delete cmdline_items; } } catch (errorEx &ex) {