diff --git a/SOURCES/scap-workbench-1.2.1-use_asciidoc-PR_200.patch b/SOURCES/scap-workbench-1.2.1-use_asciidoc-PR_200.patch new file mode 100644 index 0000000..e75e86f --- /dev/null +++ b/SOURCES/scap-workbench-1.2.1-use_asciidoc-PR_200.patch @@ -0,0 +1,94 @@ +From 03391003a5b6f63988b0687625d85c0060b1a932 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= +Date: Wed, 25 Jul 2018 18:59:04 +0200 +Subject: [PATCH 1/2] Replace SVG logo by PNG logo in Manual + +--- + doc/user_manual.adoc | 2 +- + doc/user_manual/logo.png | Bin 0 -> 17058 bytes + doc/user_manual/logo.svg | 75 --------------------------------------- + scap-workbench.wxs.in | 6 ++-- + 4 files changed, 4 insertions(+), 79 deletions(-) + create mode 100644 doc/user_manual/logo.png + delete mode 100644 doc/user_manual/logo.svg + +From bd356e0a8dbab798db96b0d009758e8f56e3cf11 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= +Date: Wed, 25 Jul 2018 19:06:27 +0200 +Subject: [PATCH 2/2] Replace asciidoctor by asciidoc + +Asciidoc is present in many Linux Distributions. +This makes SCAP Workbench also consistent with OpenSCAP. +--- + .travis.yml | 2 +- + CMakeLists.txt | 16 ++++++++-------- + README.md | 2 +- + 3 files changed, 10 insertions(+), 10 deletions(-) + +diff --git a/.travis.yml b/.travis.yml +index f928331c..809bfd19 100644 +--- a/.travis.yml ++++ b/.travis.yml +@@ -11,7 +11,7 @@ before_install: + - brew update + - brew install jq + - brew install cartr/qt4/qt@4 +- - brew install asciidoctor ++ - brew install asciidoc + + before_script: + - git clone --depth 1 https://github.com/openscap/openscap.git -b master +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 993b949f..b4427f1f 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -89,15 +89,15 @@ if (SCAP_AS_RPM_EXECUTABLE) + endif() + + # This is optional, only required if user wants documentation rebuilt +-find_program(ASCIIDOCTOR_EXECUTABLE NAMES asciidoctor) +-option(SCAP_WORKBENCH_REBUILD_MANUAL "If enabled, user manual will be rebuilt (requires asciidoctor to be installed)" TRUE) ++find_program(ASCIIDOC_EXECUTABLE NAMES asciidoc) ++option(SCAP_WORKBENCH_REBUILD_MANUAL "If enabled, user manual will be rebuilt (requires asciidoc to be installed)" TRUE) + option(SCAP_WORKBENCH_USE_NATIVE_FILE_DIALOGS "If enabled, native desktop environment file dialogs are used (disable if you have crashes at startup)" TRUE) +-if (SCAP_WORKBENCH_REBUILD_MANUAL AND NOT ASCIIDOCTOR_EXECUTABLE) +- message("asciidoctor has not been found, user manual won't be rebuilt even though SCAP_WORKBENCH_REBUILD_MANUAL has been enabled.") ++if (SCAP_WORKBENCH_REBUILD_MANUAL AND NOT ASCIIDOC_EXECUTABLE) ++ message("asciidoc has not been found, user manual won't be rebuilt even though SCAP_WORKBENCH_REBUILD_MANUAL has been enabled.") + endif() + if (NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doc/user_manual.html") +- if (NOT ASCIIDOCTOR_EXECUTABLE) +- message(FATAL_ERROR "You seem to be using scap-workbench from the repository ('${CMAKE_SOURCE_DIR}/doc/user_manual.html' hasn't been found). Please install asciidoctor to build the manual! You can use `gem install asciidoctor` if asciidoctor is not in your distribution package repository. If you don't have access to asciidoctor and don't mind not having a manual, run `touch ${CMAKE_SOURCE_DIR}/doc/user_manual.html` and rerun cmake.") ++ if (NOT ASCIIDOC_EXECUTABLE) ++ message(FATAL_ERROR "You seem to be using scap-workbench from the repository ('${CMAKE_SOURCE_DIR}/doc/user_manual.html' hasn't been found). Please install asciidoc to build the manual! If you don't have access to asciidoc and don't mind not having a manual, run `touch ${CMAKE_SOURCE_DIR}/doc/user_manual.html` and rerun cmake.") + endif() + set(SCAP_WORKBENCH_REBUILD_MANUAL TRUE) + endif() +@@ -269,12 +269,12 @@ install(FILES "share/pixmaps/scap-workbench.svg" + install(FILES "scap-workbench.appdata.xml" + DESTINATION "${CMAKE_INSTALL_DATADIR}/appdata") + +-if (ASCIIDOCTOR_EXECUTABLE) ++if (ASCIIDOC_EXECUTABLE) + file(GLOB USER_MANUAL_SCREENSHOTS "${CMAKE_CURRENT_SOURCE_DIR}/doc/user_manual/*.png") + add_custom_command( + OUTPUT doc/user_manual.html + COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/doc +- COMMAND ${ASCIIDOCTOR_EXECUTABLE} --destination-dir ${CMAKE_CURRENT_BINARY_DIR}/doc -b html5 -a data-uri user_manual.adoc ++ COMMAND ${ASCIIDOC_EXECUTABLE} -o ${CMAKE_CURRENT_BINARY_DIR}/doc/user_manual.html -b html5 -a data-uri user_manual.adoc + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/doc/user_manual.html ${CMAKE_CURRENT_SOURCE_DIR}/doc/user_manual.html + DEPENDS doc/user_manual.adoc ${USER_MANUAL_SCREENSHOTS} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/doc +diff --git a/README.md b/README.md +index 934c8240..8cf7ec93 100644 +--- a/README.md ++++ b/README.md +@@ -24,7 +24,7 @@ required dependencies: + + required dependencies (only for the git repo, not required for released tarballs): + ```console +-# yum install rubygem-asciidoctor ++# yum install asciidoc + ``` + + optional dependencies: diff --git a/SOURCES/scap-workbench-1.2.2-refactor_messages-PR_271.patch b/SOURCES/scap-workbench-1.2.2-refactor_messages-PR_271.patch new file mode 100644 index 0000000..ff9e7f5 --- /dev/null +++ b/SOURCES/scap-workbench-1.2.2-refactor_messages-PR_271.patch @@ -0,0 +1,196 @@ +From 7786cd8b020ab3aa4a9720e6fa8f60285486a48b Mon Sep 17 00:00:00 2001 +From: Matej Tyc +Date: Wed, 27 Jan 2021 14:28:57 +0100 +Subject: [PATCH] Refactored handling of scanner messages. + +- Better detection of errors and warnings using leading E: and W: that + oscap emits. +- Possibility to expand the message filtering using inheritance. +--- + include/OscapScannerBase.h | 15 +++++ + src/OscapScannerBase.cpp | 132 ++++++++++++++++++++++++++++++++----- + 2 files changed, 130 insertions(+), 17 deletions(-) + +diff --git a/include/OscapScannerBase.h b/include/OscapScannerBase.h +index 00f67699..f82379be 100644 +--- a/include/OscapScannerBase.h ++++ b/include/OscapScannerBase.h +@@ -77,6 +77,21 @@ class OscapScannerBase : public Scanner + + ReadingState mReadingState; + ++ enum MessageType ++ { ++ MSG_INFO, MSG_WARNING, MSG_ERROR, MSG_UNKNOWN ++ }; ++ ++ virtual void filterStdErr(QString& errorText); ++ void emitMessage(MessageType kind, QString& message); ++ virtual void selectWarning(MessageType& kind, const QString& message); ++ virtual void processWarning(QString& message); ++ virtual void selectInfo(MessageType& kind, const QString& message); ++ virtual void processInfo(QString& message); ++ virtual void selectError(MessageType& kind, const QString& message); ++ virtual void processError(QString& message); ++ virtual void processUnknown(QString& message); ++ + /// We keep filling this buffer until we reach : or \n + QString mReadBuffer; + +diff --git a/src/OscapScannerBase.cpp b/src/OscapScannerBase.cpp +index bdb02e74..0ec4575e 100644 +--- a/src/OscapScannerBase.cpp ++++ b/src/OscapScannerBase.cpp +@@ -418,6 +418,117 @@ void OscapScannerBase::readStdOut(QProcess& process) + while (tryToReadStdOutChar(process)); + } + ++ ++void OscapScannerBase::emitMessage(MessageType kind, QString& message) ++{ ++ QString rawMessage = QObject::tr(message.toUtf8().constData()); ++ switch (kind) ++ { ++ case MSG_INFO: ++ { ++ emit infoMessage(message); ++ break; ++ } ++ case MSG_WARNING: ++ { ++ emit warningMessage(message); ++ break; ++ } ++ default: ++ emit errorMessage(message); ++ } ++} ++ ++ ++void OscapScannerBase::selectWarning(MessageType& kind, const QString& message) ++{ ++ if (message.contains("WARNING: ")) ++ { ++ kind = MSG_WARNING; ++ } ++ if (message.contains(QRegExp("^W:\\s"))) ++ { ++ kind = MSG_WARNING; ++ } ++} ++ ++ ++void OscapScannerBase::processWarning(QString& message) ++{ ++ message = guiFriendlyMessage(message); ++} ++ ++ ++void OscapScannerBase::selectInfo(MessageType& kind, const QString& message) ++{ ++ if (message.contains(QRegExp("^Downloading: .+ \\.{3} \\w+\\n"))) ++ { ++ kind = MSG_INFO; ++ } ++} ++ ++ ++void OscapScannerBase::processInfo(QString& message) ++{ ++ (void)message; // suppress the unused arg warning ++} ++ ++ ++void OscapScannerBase::selectError(MessageType& kind, const QString& message) ++{ ++ if (message.contains(QRegExp("^E:\\s"))) ++ { ++ kind = MSG_ERROR; ++ } ++} ++ ++ ++void OscapScannerBase::processError(QString& message) ++{ ++ message.remove(QRegExp("Error:\\s*")); ++ message.remove(QRegExp("^E:\\s*")); ++ message.remove(QRegExp("\\n")); ++} ++ ++ ++void OscapScannerBase::processUnknown(QString& message) ++{ ++ message = QString("The 'oscap' process has written the following content to stderr:\n%1").arg(message); ++} ++ ++ ++void OscapScannerBase::filterStdErr(QString& errorText) ++{ ++ MessageType type = MSG_UNKNOWN; ++ // let detection of a more severe type of message (error) overrule a benign one (info) ++ selectInfo(type, errorText); ++ selectWarning(type, errorText); ++ selectError(type, errorText); ++ switch(type) ++ { ++ case MSG_INFO: ++ { ++ processInfo(errorText); ++ break; ++ } ++ case MSG_WARNING: ++ { ++ processWarning(errorText); ++ break; ++ } ++ case MSG_ERROR: ++ { ++ processError(errorText); ++ break; ++ } ++ default: ++ { ++ processUnknown(errorText); ++ } ++ } ++ emitMessage(type, errorText); ++} ++ + void OscapScannerBase::watchStdErr(QProcess& process) + { + process.setReadChannel(QProcess::StandardError); +@@ -433,21 +544,7 @@ void OscapScannerBase::watchStdErr(QProcess& process) + + if (!stdErrOutput.isEmpty()) + { +- if (stdErrOutput.contains("WARNING: ")) +- { +- QString guiMessage = guiFriendlyMessage(stdErrOutput); +- emit warningMessage(QObject::tr(guiMessage.toUtf8().constData())); +- } +- // Openscap >= 1.2.11 (60fb9f0c98eee) sends this message through stderr +- else if (stdErrOutput.contains(QRegExp("^Downloading: .+ \\.{3} \\w+\\n"))) +- { +- emit infoMessage(stdErrOutput); +- } +- else +- { +- emit errorMessage(QObject::tr("The 'oscap' process has written the following content to stderr:\n" +- "%1").arg(stdErrOutput)); +- } ++ filterStdErr(stdErrOutput); + } + + } +@@ -458,8 +555,9 @@ QString OscapScannerBase::guiFriendlyMessage(const QString& cliMessage) + { + QString guiMessage = cliMessage; + +- // Remove "WARNING:" prefix and trailing \n +- guiMessage.remove(QRegExp("(WARNING: )|\n")); ++ guiMessage.remove(QRegExp("WARNING:\\s*")); ++ guiMessage.remove(QRegExp("^W:\\s*")); ++ guiMessage.remove(QRegExp("\\n")); + + if (cliMessage.contains("--fetch-remote-resources")) + guiMessage = QString("Remote resources might be necessary for this profile to work properly. Please select \"Fetch remote resources\" for complete scan"); diff --git a/SOURCES/scap-workbench-1.2.2-remote_sudo-PR_270.patch b/SOURCES/scap-workbench-1.2.2-remote_sudo-PR_270.patch new file mode 100644 index 0000000..3b4c198 --- /dev/null +++ b/SOURCES/scap-workbench-1.2.2-remote_sudo-PR_270.patch @@ -0,0 +1,560 @@ +From 0e48a7161be7fbabc02ba05407131be2595e9b6d Mon Sep 17 00:00:00 2001 +From: Matej Tyc +Date: Tue, 1 Dec 2020 18:46:20 +0100 +Subject: [PATCH 1/4] Implement possibility to scan by sudoers. + +- The remote scanning dialog got a "user is sudoer" checkbox. +- Dry run can make use of sudo in connection with oscap-ssh. +- The scanning procedure uses sudo invocation as part of the ssh command. +--- + include/OscapScannerRemoteSsh.h | 2 ++ + include/RemoteMachineComboBox.h | 2 ++ + src/MainWindow.cpp | 4 ++++ + src/OscapScannerRemoteSsh.cpp | 28 +++++++++++++++++++------ + src/RemoteMachineComboBox.cpp | 7 +++++++ + ui/RemoteMachineComboBox.ui | 36 +++++++++++++++++++++++++++++---- + 6 files changed, 69 insertions(+), 10 deletions(-) + +diff --git a/include/OscapScannerRemoteSsh.h b/include/OscapScannerRemoteSsh.h +index d2aa7013..69eedfe4 100644 +--- a/include/OscapScannerRemoteSsh.h ++++ b/include/OscapScannerRemoteSsh.h +@@ -36,6 +36,7 @@ class OscapScannerRemoteSsh : public OscapScannerBase + OscapScannerRemoteSsh(); + virtual ~OscapScannerRemoteSsh(); + ++ void setUserIsSudoer(bool userIsSudoer); + virtual void setTarget(const QString& target); + virtual void setSession(ScanningSession* session); + +@@ -57,6 +58,7 @@ class OscapScannerRemoteSsh : public OscapScannerBase + void removeRemoteDirectory(const QString& path, const QString& desc); + + SshConnection mSshConnection; ++ bool mUserIsSudoer; + }; + + #endif +diff --git a/include/RemoteMachineComboBox.h b/include/RemoteMachineComboBox.h +index 41a9643c..3b338127 100644 +--- a/include/RemoteMachineComboBox.h ++++ b/include/RemoteMachineComboBox.h +@@ -44,6 +44,7 @@ class RemoteMachineComboBox : public QWidget + + void setRecentMachineCount(unsigned int count); + unsigned int getRecentMachineCount() const; ++ bool userIsSudoer() const; + + public slots: + void notifyTargetUsed(const QString& target); +@@ -65,6 +66,7 @@ class RemoteMachineComboBox : public QWidget + + QStringList mRecentTargets; + QComboBox* mRecentComboBox; ++ QCheckBox* mUserIsSudoer; + }; + + #endif +diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp +index c9a0937b..236cfde1 100644 +--- a/src/MainWindow.cpp ++++ b/src/MainWindow.cpp +@@ -678,6 +678,7 @@ void MainWindow::scanAsync(ScannerMode scannerMode) + // In the OscapScannerRemoteSsh class the port will be parsed out again... + const QString target = mUI.localMachineRadioButton->isChecked() ? + "localhost" : mUI.remoteMachineDetails->getTarget(); ++ const bool userIsSudoer = mUI.remoteMachineDetails->userIsSudoer(); + + bool fetchRemoteResources = mUI.fetchRemoteResourcesCheckbox->isChecked(); + try +@@ -689,7 +690,10 @@ void MainWindow::scanAsync(ScannerMode scannerMode) + if (target == "localhost") + mScanner = new OscapScannerLocal(); + else ++ { + mScanner = new OscapScannerRemoteSsh(); ++ ((OscapScannerRemoteSsh *)mScanner)->setUserIsSudoer(userIsSudoer); ++ } + + mScanner->setTarget(target); + +diff --git a/src/OscapScannerRemoteSsh.cpp b/src/OscapScannerRemoteSsh.cpp +index dcfd6d5f..d20faf59 100644 +--- a/src/OscapScannerRemoteSsh.cpp ++++ b/src/OscapScannerRemoteSsh.cpp +@@ -37,7 +37,8 @@ extern "C" + + OscapScannerRemoteSsh::OscapScannerRemoteSsh(): + OscapScannerBase(), +- mSshConnection(this) ++ mSshConnection(this), ++ mUserIsSudoer(false) + { + mSshConnection.setCancelRequestSource(&mCancelRequested); + } +@@ -87,6 +88,11 @@ void OscapScannerRemoteSsh::setTarget(const QString& target) + mSshConnection.setPort(port); + } + ++void OscapScannerRemoteSsh::setUserIsSudoer(bool userIsSudoer) ++{ ++ mUserIsSudoer = userIsSudoer; ++} ++ + void OscapScannerRemoteSsh::setSession(ScanningSession* session) + { + OscapScannerBase::setSession(session); +@@ -99,6 +105,10 @@ void OscapScannerRemoteSsh::setSession(ScanningSession* session) + QStringList OscapScannerRemoteSsh::getCommandLineArgs() const + { + QStringList args("oscap-ssh"); ++ if (mUserIsSudoer) ++ { ++ args.append("--sudo"); ++ } + args.append(mSshConnection.getTarget()); + args.append(QString::number(mSshConnection.getPort())); + +@@ -235,19 +245,19 @@ void OscapScannerRemoteSsh::evaluate() + + if (mScannerMode == SM_OFFLINE_REMEDIATION) + { +- args = buildOfflineRemediationArgs(inputFile, ++ args.append(buildOfflineRemediationArgs(inputFile, + resultFile, + reportFile, +- arfFile); ++ arfFile)); + } + else + { +- args = buildEvaluationArgs(inputFile, ++ args.append(buildEvaluationArgs(inputFile, + tailoringFile, + resultFile, + reportFile, + arfFile, +- mScannerMode == SM_SCAN_ONLINE_REMEDIATION); ++ mScannerMode == SM_SCAN_ONLINE_REMEDIATION)); + } + + const QString sshCmd = args.join(" "); +@@ -255,8 +265,14 @@ void OscapScannerRemoteSsh::evaluate() + emit infoMessage(QObject::tr("Starting the remote process...")); + + QProcess process(this); ++ QString sudo; ++ if (mUserIsSudoer) ++ { ++ // tell sudo not to bother to read password from the terminal ++ sudo = " sudo -n"; ++ } + +- process.start(SCAP_WORKBENCH_LOCAL_SSH_PATH, baseArgs + QStringList(QString("cd '%1'; " SCAP_WORKBENCH_REMOTE_OSCAP_PATH " %2").arg(workingDir).arg(sshCmd))); ++ process.start(SCAP_WORKBENCH_LOCAL_SSH_PATH, baseArgs + QStringList(QString("cd '%1';" "%2 " SCAP_WORKBENCH_REMOTE_OSCAP_PATH " %3").arg(workingDir).arg(sudo).arg(sshCmd))); + process.waitForStarted(); + + if (process.state() != QProcess::Running) +diff --git a/src/RemoteMachineComboBox.cpp b/src/RemoteMachineComboBox.cpp +index 46d1b7d1..7b402344 100644 +--- a/src/RemoteMachineComboBox.cpp ++++ b/src/RemoteMachineComboBox.cpp +@@ -41,6 +41,8 @@ RemoteMachineComboBox::RemoteMachineComboBox(QWidget* parent): + this, SLOT(updateHostPort(int)) + ); + ++ mUserIsSudoer = mUI.userIsSudoer; ++ + setRecentMachineCount(5); + syncFromQSettings(); + +@@ -51,6 +53,11 @@ RemoteMachineComboBox::~RemoteMachineComboBox() + delete mQSettings; + } + ++bool RemoteMachineComboBox::userIsSudoer() const ++{ ++ return mUserIsSudoer->isChecked(); ++} ++ + QString RemoteMachineComboBox::getTarget() const + { + return QString("%1:%2").arg(mUI.host->text()).arg(mUI.port->value()); +diff --git a/ui/RemoteMachineComboBox.ui b/ui/RemoteMachineComboBox.ui +index 780d06ce..f9e9665c 100644 +--- a/ui/RemoteMachineComboBox.ui ++++ b/ui/RemoteMachineComboBox.ui +@@ -6,15 +6,24 @@ + + 0 + 0 +- 553 +- 29 ++ 609 ++ 42 + + + + RemoteMachineComboBox + + +- ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ + 0 + + +@@ -73,8 +82,17 @@ + + + ++ ++ true ++ ++ ++ ++ 0 ++ 0 ++ ++ + +- QAbstractSpinBox::UpDownArrows ++ QAbstractSpinBox::NoButtons + + + 1 +@@ -87,6 +105,16 @@ + + + ++ ++ ++ ++ Check if the remote user doesn't have root privileges, but they can perform administrative tasks using paswordless sudo. ++ ++ ++ user is sudoer ++ ++ ++ + + + + +From 1fd9bc807f1c76452c0803436efd311000d7470b Mon Sep 17 00:00:00 2001 +From: Matej Tyc +Date: Wed, 27 Jan 2021 14:33:04 +0100 +Subject: [PATCH 2/4] Updated message handling of sudo-related issues. + +--- + include/OscapScannerRemoteSsh.h | 5 +++++ + src/OscapScannerRemoteSsh.cpp | 23 +++++++++++++++++++++++ + 2 files changed, 28 insertions(+) + +diff --git a/include/OscapScannerRemoteSsh.h b/include/OscapScannerRemoteSsh.h +index 69eedfe4..280a69da 100644 +--- a/include/OscapScannerRemoteSsh.h ++++ b/include/OscapScannerRemoteSsh.h +@@ -43,6 +43,11 @@ class OscapScannerRemoteSsh : public OscapScannerBase + virtual QStringList getCommandLineArgs() const; + virtual void evaluate(); + ++ protected: ++ ++ virtual void selectError(MessageType& kind, const QString& message); ++ virtual void processError(QString& message); ++ + private: + void ensureConnected(); + +diff --git a/src/OscapScannerRemoteSsh.cpp b/src/OscapScannerRemoteSsh.cpp +index d20faf59..69b51373 100644 +--- a/src/OscapScannerRemoteSsh.cpp ++++ b/src/OscapScannerRemoteSsh.cpp +@@ -344,6 +344,29 @@ void OscapScannerRemoteSsh::evaluate() + signalCompletion(mCancelRequested); + } + ++void OscapScannerRemoteSsh::selectError(MessageType& kind, const QString& message) ++{ ++ OscapScannerBase::selectError(kind, message); ++ if (mUserIsSudoer) ++ { ++ if (message.contains(QRegExp("^sudo:"))) ++ { ++ kind = MSG_ERROR; ++ } ++ } ++ ++} ++ ++void OscapScannerRemoteSsh::processError(QString& message) ++{ ++ OscapScannerBase::processError(message); ++ if (mUserIsSudoer && message.contains(QRegExp("^sudo:"))) ++ { ++ message.replace(QRegExp("^sudo:"), "Error invoking sudo on the host:"); ++ message += ".\nOnly passwordless sudo setup on the remote host is supported by scap-workbench."; ++ } ++} ++ + void OscapScannerRemoteSsh::ensureConnected() + { + if (mSshConnection.isConnected()) + +From 57097b3b9d6f85caa96ab2940c29e94f16382252 Mon Sep 17 00:00:00 2001 +From: Matej Tyc +Date: Thu, 28 Jan 2021 17:12:08 +0100 +Subject: [PATCH 3/4] Added documentation about setting up passwordless sudo. + +--- + doc/user_manual.adoc | 11 +++++++++++ + src/OscapScannerRemoteSsh.cpp | 2 ++ + 2 files changed, 13 insertions(+) + +diff --git a/doc/user_manual.adoc b/doc/user_manual.adoc +index 29ebd919..2c8501a0 100644 +--- a/doc/user_manual.adoc ++++ b/doc/user_manual.adoc +@@ -363,6 +363,17 @@ files are not supported yet! + .Selecting a remote machine for scanning + image::scanning_remote_machine.png[align="center"] + ++The remote user doesn't have to be a superuser - you can setup the remote ++`/etc/sudoers` file (using `visudo`) to enable the paswordless sudo for that particular user, ++and you check the "user is sudoer" checkbox. ++ ++For example, if the scanning user is `oscap-user`, that would involve putting ++ ++ oscap-user ALL=(root) NOPASSWD: /usr/bin/oscap xccdf eval * ++ ++user specification into the `sudoers` file, or into a separate file ++that is included by `sudoers` s.a. `/etc/sudoers.d/99-oscap-user`. ++ + === Enable Online Remediation (optional) + + **** +diff --git a/src/OscapScannerRemoteSsh.cpp b/src/OscapScannerRemoteSsh.cpp +index 69b51373..7fa38b2e 100644 +--- a/src/OscapScannerRemoteSsh.cpp ++++ b/src/OscapScannerRemoteSsh.cpp +@@ -364,6 +364,8 @@ void OscapScannerRemoteSsh::processError(QString& message) + { + message.replace(QRegExp("^sudo:"), "Error invoking sudo on the host:"); + message += ".\nOnly passwordless sudo setup on the remote host is supported by scap-workbench."; ++ message += " \nTo configure a non-privileged user oscap-user to run only the oscap binary as root, " ++ "add this User Specification to your sudoers file: oscap-user ALL=(root) NOPASSWD: /usr/bin/oscap xccdf eval *"; + } + } + + +From e8daecc80ad54e95de764728f0cbe4863a67be0d Mon Sep 17 00:00:00 2001 +From: Matej Tyc +Date: Thu, 28 Jan 2021 17:45:09 +0100 +Subject: [PATCH 4/4] Added suport for the sudoers checkbox to history. + +Recent remote scans now encode the sudo mode into the "target" that is +stored in the recent remote hosts list. +--- + include/OscapScannerRemoteSsh.h | 3 ++- + include/RemoteMachineComboBox.h | 2 +- + src/MainWindow.cpp | 5 ++++- + src/OscapScannerRemoteSsh.cpp | 30 +++++++++++++++++++++++------- + src/RemoteMachineComboBox.cpp | 17 +++++++++++------ + 5 files changed, 41 insertions(+), 16 deletions(-) + +diff --git a/include/OscapScannerRemoteSsh.h b/include/OscapScannerRemoteSsh.h +index 280a69da..50214b80 100644 +--- a/include/OscapScannerRemoteSsh.h ++++ b/include/OscapScannerRemoteSsh.h +@@ -31,11 +31,12 @@ class OscapScannerRemoteSsh : public OscapScannerBase + Q_OBJECT + + public: +- static void splitTarget(const QString& in, QString& target, unsigned short& port); ++ static void splitTarget(const QString& in, QString& target, unsigned short& port, bool& userIsSudoer); + + OscapScannerRemoteSsh(); + virtual ~OscapScannerRemoteSsh(); + ++ bool getUserIsSudoer() const; + void setUserIsSudoer(bool userIsSudoer); + virtual void setTarget(const QString& target); + virtual void setSession(ScanningSession* session); +diff --git a/include/RemoteMachineComboBox.h b/include/RemoteMachineComboBox.h +index 3b338127..c2d946c9 100644 +--- a/include/RemoteMachineComboBox.h ++++ b/include/RemoteMachineComboBox.h +@@ -47,7 +47,7 @@ class RemoteMachineComboBox : public QWidget + bool userIsSudoer() const; + + public slots: +- void notifyTargetUsed(const QString& target); ++ void notifyTargetUsed(const QString& target, bool userIsSudoer); + void clearHistory(); + + protected slots: +diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp +index 236cfde1..496e1724 100644 +--- a/src/MainWindow.cpp ++++ b/src/MainWindow.cpp +@@ -763,7 +763,10 @@ void MainWindow::scanAsync(ScannerMode scannerMode) + ); + + if (target != "localhost") +- mUI.remoteMachineDetails->notifyTargetUsed(mScanner->getTarget()); ++ { ++ bool userIsSudoer = ((OscapScannerRemoteSsh *)mScanner)->getUserIsSudoer(); ++ mUI.remoteMachineDetails->notifyTargetUsed(mScanner->getTarget(), userIsSudoer); ++ } + + mScanThread->start(); + } +diff --git a/src/OscapScannerRemoteSsh.cpp b/src/OscapScannerRemoteSsh.cpp +index 7fa38b2e..b1c4426f 100644 +--- a/src/OscapScannerRemoteSsh.cpp ++++ b/src/OscapScannerRemoteSsh.cpp +@@ -46,7 +46,7 @@ OscapScannerRemoteSsh::OscapScannerRemoteSsh(): + OscapScannerRemoteSsh::~OscapScannerRemoteSsh() + {} + +-void OscapScannerRemoteSsh::splitTarget(const QString& in, QString& target, unsigned short& port) ++void OscapScannerRemoteSsh::splitTarget(const QString& in, QString& target, unsigned short& port, bool& userIsSudoer) + { + // NB: We dodge a bullet here because the editor will always pass a port + // as the last component. A lot of checking and parsing does not need +@@ -56,10 +56,19 @@ void OscapScannerRemoteSsh::splitTarget(const QString& in, QString& target, unsi + // being there and always being the last component. + + // FIXME: Ideally, this should split from the right side and stop after one split +- QStringList split = in.split(':'); ++ userIsSudoer = false; ++ QStringList sudoerSplit = in.split(' '); ++ if (sudoerSplit.size() > 1) ++ { ++ if (sudoerSplit.at(1) == "sudo") ++ { ++ userIsSudoer = true; ++ } ++ } ++ QStringList hostPortSplit = sudoerSplit.at(0).split(':'); + +- const QString portString = split.back(); +- split.removeLast(); ++ const QString portString = hostPortSplit.back(); ++ hostPortSplit.removeLast(); + + { + bool status = false; +@@ -69,25 +78,32 @@ void OscapScannerRemoteSsh::splitTarget(const QString& in, QString& target, unsi + port = status ? portCandidate : 22; + } + +- target = split.join(":"); ++ target = hostPortSplit.join(":"); + } + + void OscapScannerRemoteSsh::setTarget(const QString& target) + { +- OscapScannerBase::setTarget(target); ++ QStringList sudoerSplit = target.split(' '); ++ OscapScannerBase::setTarget(sudoerSplit.at(0)); + + if (mSshConnection.isConnected()) + mSshConnection.disconnect(); + + QString cleanTarget; + unsigned short port; ++ bool userIsSudoer; + +- splitTarget(target, cleanTarget, port); ++ splitTarget(target, cleanTarget, port, userIsSudoer); + + mSshConnection.setTarget(cleanTarget); + mSshConnection.setPort(port); + } + ++bool OscapScannerRemoteSsh::getUserIsSudoer() const ++{ ++ return mUserIsSudoer; ++} ++ + void OscapScannerRemoteSsh::setUserIsSudoer(bool userIsSudoer) + { + mUserIsSudoer = userIsSudoer; +diff --git a/src/RemoteMachineComboBox.cpp b/src/RemoteMachineComboBox.cpp +index 7b402344..127bdac7 100644 +--- a/src/RemoteMachineComboBox.cpp ++++ b/src/RemoteMachineComboBox.cpp +@@ -30,7 +30,7 @@ RemoteMachineComboBox::RemoteMachineComboBox(QWidget* parent): + + #if (QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)) + // placeholder text is only supported in Qt 4.7 onwards +- mUI.host->setPlaceholderText(QObject::tr("username@hostname")); ++ mUI.host->setPlaceholderText(QObject::tr("username@hostname [sudo]")); + #endif + + mQSettings = new QSettings(this); +@@ -77,11 +77,12 @@ unsigned int RemoteMachineComboBox::getRecentMachineCount() const + return mRecentTargets.size(); + } + +-void RemoteMachineComboBox::notifyTargetUsed(const QString& target) ++void RemoteMachineComboBox::notifyTargetUsed(const QString& target, bool userIsSudoer) + { + QString host; + unsigned short port; +- OscapScannerRemoteSsh::splitTarget(target, host, port); ++ bool placeholder; ++ OscapScannerRemoteSsh::splitTarget(target, host, port, placeholder); + + // skip invalid suggestions + if (host.isEmpty() || port == 0) +@@ -90,7 +91,8 @@ void RemoteMachineComboBox::notifyTargetUsed(const QString& target) + const unsigned int machineCount = getRecentMachineCount(); + + // this moves target to the beginning of the list if it was in the list already +- mRecentTargets.prepend(target); ++ QString targetWithSudo = target + (userIsSudoer ? " sudo" : ""); ++ mRecentTargets.prepend(targetWithSudo); + mRecentTargets.removeDuplicates(); + + setRecentMachineCount(machineCount); +@@ -106,6 +108,7 @@ void RemoteMachineComboBox::clearHistory() + { + mUI.host->setText(""); + mUI.port->setValue(22); ++ mUI.userIsSudoer->setChecked(false); + + const unsigned int machineCount = getRecentMachineCount(); + mRecentTargets.clear(); +@@ -167,6 +170,7 @@ void RemoteMachineComboBox::updateHostPort(int index) + { + mUI.host->setText(""); + mUI.port->setValue(22); ++ mUI.userIsSudoer->setChecked(false); + return; + } + +@@ -179,10 +183,11 @@ void RemoteMachineComboBox::updateHostPort(int index) + + QString host; + unsigned short port; ++ bool userIsSudoer; + +- OscapScannerRemoteSsh::splitTarget(target, host, port); ++ OscapScannerRemoteSsh::splitTarget(target, host, port, userIsSudoer); + + mUI.host->setText(host); + mUI.port->setValue(port); +- ++ mUI.userIsSudoer->setChecked(userIsSudoer); + } diff --git a/SPECS/scap-workbench.spec b/SPECS/scap-workbench.spec index 9aa78b7..5b20f58 100644 --- a/SPECS/scap-workbench.spec +++ b/SPECS/scap-workbench.spec @@ -2,7 +2,7 @@ Name: scap-workbench Version: 1.2.0 -Release: 5%{?dist} +Release: 8%{?dist} Summary: Scanning, tailoring, editing and validation tool for SCAP content License: GPLv3+ @@ -13,6 +13,9 @@ Patch2: scap-workbench-1.2.1-missing-quotes.patch Patch3: scap-workbench-1.2.1-no-spaces-in-temporary-file-names.patch Patch4: scap-workbench-1.2.2-generate-result-based-remediation-from-tailored-profile.patch Patch5: scap-workbench-1.2.2-ui_dimensions.patch +Patch6: scap-workbench-1.2.2-refactor_messages-PR_271.patch +Patch7: scap-workbench-1.2.2-remote_sudo-PR_270.patch +Patch8: scap-workbench-1.2.1-use_asciidoc-PR_200.patch Group: System Environment/Base BuildRequires: cmake >= 2.6 @@ -21,6 +24,8 @@ BuildRequires: qt5-devel >= 5.0.0 BuildRequires: openscap-devel >= 1.2.11 BuildRequires: openscap-utils >= 1.2.11 Requires: openscap-utils >= 1.2.11 +# Enables rebuild of documentation from downstream patches +BuildRequires: asciidoc # ssh to scan remote machines BuildRequires: openssh-clients Requires: openssh-clients @@ -46,6 +51,9 @@ content. The tool is based on OpenSCAP library. %patch3 -p1 %patch4 -p1 %patch5 -p1 +%patch6 -p1 +%patch7 -p1 +%patch8 -p1 %build %cmake -D CMAKE_INSTALL_DOCDIR=%{_pkgdocdir} . @@ -72,6 +80,16 @@ make install DESTDIR=%{buildroot} %doc %{_pkgdocdir}/README.md %changelog +* Fri Feb 12 2021 Matej Tyc - 1.2.0-8 +- Introduce asciidoc support instead of asciidoctor (RHBZ#1877522) + +* Tue Feb 09 2021 Matej Tyc - 1.2.0-7 +- Enabled asciidoc support during build (RHBZ#1877522) + +* Mon Feb 1 14:38:24 CET 2021 Matej Tyc - 1.2.0-6 +- Refactor handling of scanner messages. +- Implement passwordless sudo support (RHBZ#1877522) + * Wed May 27 2020 Matěj Týč - 1.2.0-5 - Adjust the GUI dimensions, so text fits to the screen (RHBZ#1743713)