Compare commits

...

No commits in common. "imports/c8-beta/scap-workbench-1.2.0-3.el8" and "c8" have entirely different histories.

8 changed files with 2316 additions and 1 deletions

View File

@ -0,0 +1,51 @@
From 9a85a7dd795112a53a04e5552a350ca2e1effbb0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com>
Date: Wed, 24 Oct 2018 15:04:18 +0200
Subject: [PATCH] Fix SCAP Workbench errors shown in Diagnostics Windows
This patch addresses the follwong part of messages chunk. Even if it
says that "oscap" process has written the content, it's the wrapper
script in fact.
```
14:34:53 | error | The 'oscap' process has written the following
content to stderr:
chown: cannot access '/tmp/SCAP': No such file or directory
14:34:53 | error | The 'oscap' process has written the following
content to stderr:
chown: cannot access 'Workbench.h22666': No such file or directory
14:34:53 | error | The 'oscap' process has written the following
content to stderr:
chown: cannot access '/tmp/SCAP': No such file or directory
14:34:53 | error | The 'oscap' process has written the following
content to stderr:
chown: cannot access 'Workbench.M22666': No such file or directory
14:34:53 | error | The 'oscap' process has written the following
content to stderr:
chown: cannot access '/tmp/SCAP': No such file or directory
14:34:53 | error | The 'oscap' process has written the following
content to stderr:
chown: cannot access 'Workbench.X22666': No such file or directory
```
---
scap-workbench-oscap.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scap-workbench-oscap.sh b/scap-workbench-oscap.sh
index 216376f2..90664446 100755
--- a/scap-workbench-oscap.sh
+++ b/scap-workbench-oscap.sh
@@ -93,7 +93,7 @@ function chown_copy
# chown only required if wrapper_{uid,gid} differs from real_{uid,gid}
if [ $wrapper_uid -ne $real_uid ] || [ $wrapper_gid -ne $real_gid ]; then
- chown $wrapper_uid:$wrapper_gid $where
+ chown $wrapper_uid:$wrapper_gid "$where"
fi
}

View File

@ -0,0 +1,773 @@
From 8a7aade15b48402403604f17d6cf7690d1a7c752 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com>
Date: Fri, 13 Dec 2019 13:52:52 +0100
Subject: [PATCH 1/2] Remove space from temporary file names
We use QTemporaryFile to create temporary files. According to
https://doc.qt.io/qt-5/qtemporaryfile.html, the default filename
is determined from QCoreApplication::applicationName(). It returns
"SCAP Workbench" which leads to creating temporary files with a space
character in their name, eg. "/tmp/SCAP Workbench.XM8663". The space
can cause problems with missing quotes s.a. the problems described in
https://github.com/OpenSCAP/scap-workbench/issues/196.
To avoid these problems, it's probably better to create the temporary
files without the space.
We will create 2 temporary classes: SpacelessQTemporaryFile and
SpacelessQTemporaryDir which are derived from QTemporaryFile and
QTemporaryDir and call the constructor with a filename template.
The QTemporaryDir replaces usage of our custom TemporaryDir class.
We don't need this class anymore because since version 1.2.0 we
require Qt version 5 where QTemporaryDir is present.
---
include/Exceptions.h | 3 -
include/ForwardDecls.h | 1 -
include/OscapScannerLocal.h | 5 +-
include/RPMOpenHelper.h | 4 +-
include/RemediationRoleSaver.h | 4 +-
include/RemoteSsh.h | 4 +-
include/ResultViewer.h | 4 +-
include/ScanningSession.h | 9 +-
include/TemporaryDir.h | 74 ----------------
include/Utils.h | 12 +++
src/OscapScannerBase.cpp | 1 -
src/OscapScannerLocal.cpp | 17 ++--
src/OscapScannerRemoteSsh.cpp | 5 +-
src/RPMOpenHelper.cpp | 4 +-
src/RemediationRoleSaver.cpp | 6 +-
src/RemoteSsh.cpp | 4 +-
src/ResultViewer.cpp | 2 +-
src/SaveAsRPMDialog.cpp | 5 +-
src/ScanningSession.cpp | 4 +-
src/TemporaryDir.cpp | 149 ---------------------------------
src/Utils.cpp | 6 ++
src/main.cpp | 3 -
22 files changed, 53 insertions(+), 273 deletions(-)
delete mode 100644 include/TemporaryDir.h
delete mode 100644 src/TemporaryDir.cpp
diff --git a/include/Exceptions.h b/include/Exceptions.h
index 84bee42d..1b876895 100644
--- a/include/Exceptions.h
+++ b/include/Exceptions.h
@@ -57,9 +57,6 @@ SCAP_WORKBENCH_SIMPLE_EXCEPTION(SshConnectionException,
SCAP_WORKBENCH_SIMPLE_EXCEPTION(TailoringWindowException,
"There was a problem with TailoringWindow!\n");
-SCAP_WORKBENCH_SIMPLE_EXCEPTION(TemporaryDirException,
- "There was a problem with TemporaryDir!\n");
-
SCAP_WORKBENCH_SIMPLE_EXCEPTION(OscapScannerRemoteSshException,
"There was a problem with OscapScannerRemoteSsh!\n");
diff --git a/include/ForwardDecls.h b/include/ForwardDecls.h
index b9735476..3059a1c3 100644
--- a/include/ForwardDecls.h
+++ b/include/ForwardDecls.h
@@ -50,7 +50,6 @@ class SyncProcess;
class SSGIntegrationDialog;
class TailoringWindow;
class TailorProfileDialog;
-class TemporaryDir;
class XCCDFItemPropertiesDockWidget;
class XCCDFItemSelectUndoCommand;
class XCCDFValueChangeUndoCommand;
diff --git a/include/OscapScannerLocal.h b/include/OscapScannerLocal.h
index 4370744b..00b5ab39 100644
--- a/include/OscapScannerLocal.h
+++ b/include/OscapScannerLocal.h
@@ -22,10 +22,9 @@
#ifndef SCAP_WORKBENCH_OSCAP_SCANNER_LOCAL_H_
#define SCAP_WORKBENCH_OSCAP_SCANNER_LOCAL_H_
-#include <QTemporaryFile>
-
#include "ForwardDecls.h"
#include "OscapScannerBase.h"
+#include "Utils.h"
class OscapScannerLocal : public OscapScannerBase
@@ -54,7 +53,7 @@ class OscapScannerLocal : public OscapScannerBase
void evaluateWithOfflineRemediation();
void evaluateWithOtherSettings();
- static void setFilenameToTempFile(QTemporaryFile& file);
+ static void setFilenameToTempFile(SpacelessQTemporaryFile& file);
};
#endif
diff --git a/include/RPMOpenHelper.h b/include/RPMOpenHelper.h
index 18d1bad1..b6bd606c 100644
--- a/include/RPMOpenHelper.h
+++ b/include/RPMOpenHelper.h
@@ -23,7 +23,7 @@
#define SCAP_WORKBENCH_RPM_OPEN_HELPER_H_
#include "ForwardDecls.h"
-#include "TemporaryDir.h"
+#include "Utils.h"
#include <QWidget>
/**
@@ -66,7 +66,7 @@ class RPMOpenHelper
private:
static QString getRPMExtractPath();
- TemporaryDir mTempDir;
+ SpacelessQTemporaryDir mTempDir;
QString mInputPath;
QString mTailoringPath;
diff --git a/include/RemediationRoleSaver.h b/include/RemediationRoleSaver.h
index c668739e..1681b901 100644
--- a/include/RemediationRoleSaver.h
+++ b/include/RemediationRoleSaver.h
@@ -103,7 +103,7 @@ class ResultBasedProcessRemediationSaver : public RemediationSaverBase
private:
virtual void saveToFile(const QString& filename);
- QTemporaryFile mArfFile;
+ SpacelessQTemporaryFile mArfFile;
};
@@ -138,7 +138,7 @@ class ResultBasedLibraryRemediationSaver : public RemediationSaverBase
private:
virtual void saveToFile(const QString& filename);
- QTemporaryFile mArfFile;
+ SpacelessQTemporaryFile mArfFile;
};
diff --git a/include/RemoteSsh.h b/include/RemoteSsh.h
index 7971a0e7..8ae8ba7b 100644
--- a/include/RemoteSsh.h
+++ b/include/RemoteSsh.h
@@ -24,7 +24,7 @@
#include "ForwardDecls.h"
#include "ProcessHelpers.h"
-#include "TemporaryDir.h"
+#include "Utils.h"
#include <QObject>
class SshConnection : public QObject
@@ -57,7 +57,7 @@ class SshConnection : public QObject
QString mTarget;
unsigned short mPort;
- TemporaryDir* mSocketDir;
+ SpacelessQTemporaryDir* mSocketDir;
QString mMasterSocket;
QProcessEnvironment mEnvironment;
diff --git a/include/ResultViewer.h b/include/ResultViewer.h
index 978a23a4..a6da89da 100644
--- a/include/ResultViewer.h
+++ b/include/ResultViewer.h
@@ -23,9 +23,9 @@
#define SCAP_WORKBENCH_RESULT_VIEWER_H_
#include "ForwardDecls.h"
+#include "Utils.h"
#include <QWidget>
-#include <QTemporaryFile>
#include <QUrl>
#include <QMenu>
#include <QLabel>
@@ -97,7 +97,7 @@ class ResultViewer : public QWidget
QByteArray mResults;
QByteArray mReport;
/// If user requests to open the file via desktop services
- QTemporaryFile* mReportFile;
+ SpacelessQTemporaryFile* mReportFile;
QByteArray mARF;
};
diff --git a/include/ScanningSession.h b/include/ScanningSession.h
index c1d2b490..25ccc604 100644
--- a/include/ScanningSession.h
+++ b/include/ScanningSession.h
@@ -23,9 +23,8 @@
#define SCAP_WORKBENCH_SCANNING_SESSION_H_
#include "ForwardDecls.h"
+#include "Utils.h"
-#include <QTemporaryDir>
-#include <QTemporaryFile>
#include <QSet>
#include <QDir>
#include <map>
@@ -292,7 +291,7 @@ class ScanningSession
mutable struct xccdf_tailoring* mTailoring;
/// Temporary copy of opened DS or XCCDF file
- QTemporaryDir* mTempOpenDir;
+ SpacelessQTemporaryDir* mTempOpenDir;
/// Path to temporary DS or XCCDF file
QString mTempOpenPath;
/// Path to original DS or XCCDF file
@@ -301,9 +300,9 @@ class ScanningSession
QSet<QString> mClosureOfOriginalFile;
/// Temporary file provides auto deletion and a valid temp file path
- QTemporaryFile mTailoringFile;
+ SpacelessQTemporaryFile mTailoringFile;
/// Temporary file provides auto deletion and a valid temp file path
- QTemporaryFile mGuideFile;
+ SpacelessQTemporaryFile mGuideFile;
/// Whether or not validation should be skipped
bool mSkipValid;
diff --git a/include/TemporaryDir.h b/include/TemporaryDir.h
deleted file mode 100644
index fadabeca..00000000
--- a/include/TemporaryDir.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc., Durham, North Carolina.
- * All Rights Reserved.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * Authors:
- * Martin Preisler <mpreisle@redhat.com>
- */
-
-#ifndef SCAP_WORKBENCH_TEMPORARY_DIR_H_
-#define SCAP_WORKBENCH_TEMPORARY_DIR_H_
-
-#include "ForwardDecls.h"
-#include <QString>
-
-/**
- * @brief Creates a (LOCAL!) temporary directory and auto destroys it if told so
- *
- * This structure is lazy, it only creates the temp directory when asked about
- * its path. Before you query the path the directory won't be created.
- *
- * @note Default setting is to auto-remove the directory on destruction.
- * @internal We should replace this with QTemporaryDir when scap-workbench moves to Qt5
- */
-class TemporaryDir
-{
- public:
- TemporaryDir();
- ~TemporaryDir();
-
- /**
- * @brief Changes the auto-remove settings
- *
- * If autoRemove is true the structure will recursively remove the entire
- * temporary directory (that is the default setting). Else it will just
- * create it and it's up to the user to destroy it.
- */
- void setAutoRemove(const bool autoRemove);
-
- /// @see TemporaryDir::setAutoRemove
- bool getAutoRemove() const;
-
- /**
- * @brief Returns absolute path of created temporary directory
- *
- * @exception TemporaryDirException Failed to create temporary directory (nonzero exit code from mktemp -d)
- */
- const QString& getPath() const;
-
- private:
- /**
- * Ensures that temporary directory has been created and the stored path is valid.
- */
- void ensurePath() const;
-
- /// Holds absolute path of the created temporary directory
- mutable QString mPath;
- /// @see TemporaryDir::setAutoRemove
- bool mAutoRemove;
-};
-
-#endif
diff --git a/include/Utils.h b/include/Utils.h
index c3b6f013..fb9c1507 100644
--- a/include/Utils.h
+++ b/include/Utils.h
@@ -28,6 +28,8 @@
#include <QDir>
#include <QIcon>
#include <QUrl>
+#include <QTemporaryFile>
+#include <QTemporaryDir>
/**
* @brief Retrieves QDir representing the share directory
@@ -115,4 +117,14 @@ void openUrlGuarded(const QUrl& url);
*/
const QString& getSetSidPath();
+class SpacelessQTemporaryFile: public QTemporaryFile {
+ public:
+ SpacelessQTemporaryFile ();
+};
+
+class SpacelessQTemporaryDir: public QTemporaryDir {
+ public:
+ SpacelessQTemporaryDir ();
+};
+
#endif
diff --git a/src/OscapScannerBase.cpp b/src/OscapScannerBase.cpp
index 3d4075cf..daf08b9c 100644
--- a/src/OscapScannerBase.cpp
+++ b/src/OscapScannerBase.cpp
@@ -24,7 +24,6 @@
#include <QThread>
#include <QAbstractEventDispatcher>
-#include <QTemporaryFile>
#include <cassert>
extern "C"
diff --git a/src/OscapScannerLocal.cpp b/src/OscapScannerLocal.cpp
index 48687f25..dd9891fa 100644
--- a/src/OscapScannerLocal.cpp
+++ b/src/OscapScannerLocal.cpp
@@ -22,7 +22,6 @@
#include "OscapScannerLocal.h"
#include "ProcessHelpers.h"
#include "ScanningSession.h"
-#include "TemporaryDir.h"
#include <stdexcept>
#include <QThread>
@@ -33,7 +32,7 @@ extern "C"
#include <xccdf_session.h>
}
-void OscapScannerLocal::setFilenameToTempFile(QTemporaryFile& file)
+void OscapScannerLocal::setFilenameToTempFile(SpacelessQTemporaryFile& file)
{
file.open();
file.close();
@@ -97,21 +96,21 @@ void OscapScannerLocal::evaluate()
// This is mainly for check-engine-results and oval-results, to ensure
// we get a full report, including info from these files. openscap's XSLT
// uses info in the check engine results if it can find them.
- TemporaryDir workingDir;
- process.setWorkingDirectory(workingDir.getPath());
+ SpacelessQTemporaryDir workingDir;
+ process.setWorkingDirectory(workingDir.path());
QStringList args;
- QTemporaryFile inputARFFile;
+ SpacelessQTemporaryFile inputARFFile;
- QTemporaryFile arfFile;
+ SpacelessQTemporaryFile arfFile;
arfFile.setAutoRemove(true);
setFilenameToTempFile(arfFile);
- QTemporaryFile reportFile;
+ SpacelessQTemporaryFile reportFile;
reportFile.setAutoRemove(true);
setFilenameToTempFile(reportFile);
- QTemporaryFile resultFile;
+ SpacelessQTemporaryFile resultFile;
resultFile.setAutoRemove(true);
setFilenameToTempFile(resultFile);
@@ -223,7 +222,7 @@ QStringList OscapScannerLocal::getCommandLineArgs() const
if (mScannerMode == SM_OFFLINE_REMEDIATION)
{
- QTemporaryFile inputARFFile;
+ SpacelessQTemporaryFile inputARFFile;
inputARFFile.setAutoRemove(true);
inputARFFile.open();
inputARFFile.write(getARFForRemediation());
diff --git a/src/OscapScannerRemoteSsh.cpp b/src/OscapScannerRemoteSsh.cpp
index 44611a77..dcfd6d5f 100644
--- a/src/OscapScannerRemoteSsh.cpp
+++ b/src/OscapScannerRemoteSsh.cpp
@@ -25,7 +25,6 @@
#include <QThread>
#include <QAbstractEventDispatcher>
-#include <QTemporaryFile>
#include <QFileInfo>
#include <QDir>
#include <cassert>
@@ -105,7 +104,7 @@ QStringList OscapScannerRemoteSsh::getCommandLineArgs() const
if (mScannerMode == SM_OFFLINE_REMEDIATION)
{
- QTemporaryFile inputARFFile;
+ SpacelessQTemporaryFile inputARFFile;
inputARFFile.setAutoRemove(true);
inputARFFile.open();
inputARFFile.write(getARFForRemediation());
@@ -381,7 +380,7 @@ QString OscapScannerRemoteSsh::copyInputFileOver()
QString localPath = "";
- QTemporaryFile inputARFFile;
+ SpacelessQTemporaryFile inputARFFile;
inputARFFile.setAutoRemove(true);
if (mScannerMode == SM_OFFLINE_REMEDIATION)
{
diff --git a/src/RPMOpenHelper.cpp b/src/RPMOpenHelper.cpp
index 565eaa16..b12f109d 100644
--- a/src/RPMOpenHelper.cpp
+++ b/src/RPMOpenHelper.cpp
@@ -33,12 +33,12 @@ RPMOpenHelper::RPMOpenHelper(const QString& path)
const QFileInfo pathInfo(path);
proc.setCommand(getRPMExtractPath());
proc.setArguments(QStringList(pathInfo.absoluteFilePath()));
- proc.setWorkingDirectory(mTempDir.getPath());
+ proc.setWorkingDirectory(mTempDir.path());
}
proc.run();
- const QDir tempDir(mTempDir.getPath());
+ const QDir tempDir(mTempDir.path());
if (proc.getExitCode() != 0)
{
diff --git a/src/RemediationRoleSaver.cpp b/src/RemediationRoleSaver.cpp
index 247475e0..900a221d 100644
--- a/src/RemediationRoleSaver.cpp
+++ b/src/RemediationRoleSaver.cpp
@@ -27,6 +27,7 @@
#include "RemediationRoleSaver.h"
#include "DiagnosticsDialog.h"
+#include "Utils.h"
extern "C"
{
@@ -41,7 +42,6 @@ extern "C"
#endif
}
-#include "TemporaryDir.h"
const QString bashSaveMessage = QObject::tr("Save remediation role as a bash script");
@@ -197,8 +197,8 @@ void ResultBasedProcessRemediationSaver::saveToFile(const QString& filename)
// This is a lightweight launch though.
QProcess process(mParentWindow);
- TemporaryDir workingDir;
- process.setWorkingDirectory(workingDir.getPath());
+ SpacelessQTemporaryDir workingDir;
+ process.setWorkingDirectory(workingDir.path());
QString program(SCAP_WORKBENCH_LOCAL_OSCAP_PATH);
process.start(program, args);
diff --git a/src/RemoteSsh.cpp b/src/RemoteSsh.cpp
index 36c359ff..9f737b8a 100644
--- a/src/RemoteSsh.cpp
+++ b/src/RemoteSsh.cpp
@@ -109,8 +109,8 @@ void SshConnection::connect()
mSocketDir = 0;
}
- mSocketDir = new TemporaryDir();
- mMasterSocket = mSocketDir->getPath() + "/ssh_socket";
+ mSocketDir = new SpacelessQTemporaryDir();
+ mMasterSocket = mSocketDir->path() + "/ssh_socket";
}
catch (const SyncProcessException& e)
{
diff --git a/src/ResultViewer.cpp b/src/ResultViewer.cpp
index c65be2d2..1e730e99 100644
--- a/src/ResultViewer.cpp
+++ b/src/ResultViewer.cpp
@@ -158,7 +158,7 @@ void ResultViewer::openReport()
mReportFile = 0;
}
- mReportFile = new QTemporaryFile();
+ mReportFile = new SpacelessQTemporaryFile();
mReportFile->setFileTemplate(mReportFile->fileTemplate() + ".html");
mReportFile->open();
mReportFile->write(mReport);
diff --git a/src/SaveAsRPMDialog.cpp b/src/SaveAsRPMDialog.cpp
index 6c537444..611d15fd 100644
--- a/src/SaveAsRPMDialog.cpp
+++ b/src/SaveAsRPMDialog.cpp
@@ -21,7 +21,6 @@
#include "SaveAsRPMDialog.h"
#include "MainWindow.h"
-#include "TemporaryDir.h"
#include "ScanningSession.h"
#include "ProcessHelpers.h"
@@ -128,7 +127,7 @@ void SaveAsRPMDialog::slotFinished(int result)
args.append(cwd.relativeFilePath(*it));
}
- TemporaryDir tailoringDir;
+ SpacelessQTemporaryDir tailoringDir;
// Tailoring file is a special case since it may be in memory only.
// In case it is memory only we don't want it to cause our common ancestor dir to be /
@@ -138,7 +137,7 @@ void SaveAsRPMDialog::slotFinished(int result)
QFileInfo tailoringFile(mScanningSession->getTailoringFilePath());
assert(tailoringFile.exists());
- const QString tailoringFilePath = QString("%1/%2").arg(tailoringDir.getPath(), "tailoring-xccdf.xml");
+ const QString tailoringFilePath = QString("%1/%2").arg(tailoringDir.path(), "tailoring-xccdf.xml");
ScanningSession::copyOrReplace(tailoringFile.absoluteFilePath(),
tailoringFilePath);
diff --git a/src/ScanningSession.cpp b/src/ScanningSession.cpp
index a486761d..20ce501f 100644
--- a/src/ScanningSession.cpp
+++ b/src/ScanningSession.cpp
@@ -34,8 +34,6 @@ extern "C" {
#include <cassert>
#include <ctime>
-#include <QTemporaryDir>
-#include <QTemporaryFile>
#include <QFileInfo>
#include <QBuffer>
#include <QXmlQuery>
@@ -161,7 +159,7 @@ void ScanningSession::cloneToTemporaryFile(const QString& path)
// Clean the temporary directory if it is open already, then create
// a new one.
cleanTmpDir();
- mTempOpenDir = new QTemporaryDir();
+ mTempOpenDir = new SpacelessQTemporaryDir();
// Recalling is unlikely to succeed, so throw a fatal exception
if (!mTempOpenDir->isValid())
diff --git a/src/TemporaryDir.cpp b/src/TemporaryDir.cpp
deleted file mode 100644
index 0fed2556..00000000
--- a/src/TemporaryDir.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc., Durham, North Carolina.
- * All Rights Reserved.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * Authors:
- * Martin Preisler <mpreisle@redhat.com>
- */
-
-#include "TemporaryDir.h"
-#include "ProcessHelpers.h"
-#include "Exceptions.h"
-
-#include <QDir>
-#include <iostream>
-
-static bool recursiveRemoveDir(const QString& dirName)
-{
- // Adapted code from:
- // http://john.nachtimwald.com/2010/06/08/qt-remove-directory-and-its-contents/
-
- bool result = true;
- QDir dir(dirName);
-
- if (dir.exists(dirName))
- {
- for (QFileInfo info : dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden | QDir::AllDirs | QDir::Files, QDir::DirsFirst))
- {
- if (info.isDir())
- result = recursiveRemoveDir(info.absoluteFilePath());
- else
- result = QFile::remove(info.absoluteFilePath());
-
- if (!result)
- return result;
- }
- result = dir.rmdir(dirName);
- }
-
- return result;
-}
-
-TemporaryDir::TemporaryDir():
- mAutoRemove(true)
-{}
-
-TemporaryDir::~TemporaryDir()
-{
- if (!mPath.isEmpty() && mAutoRemove)
- {
- if (!recursiveRemoveDir(mPath))
- {
- // We don't throw on destruction! The worst thing that can happen
- // is leftover files which is not a big deal anyway.
-
- std::cerr << "Failed to remove temporary directory '" << mPath.toUtf8().constData() << "'." << std::endl;
- }
- }
-}
-
-void TemporaryDir::setAutoRemove(const bool autoRemove)
-{
- mAutoRemove = autoRemove;
-}
-
-bool TemporaryDir::getAutoRemove() const
-{
- return mAutoRemove;
-}
-
-const QString& TemporaryDir::getPath() const
-{
- ensurePath();
- return mPath;
-}
-
-// nextRand adapted from from QTemporaryDir from Qt5, licensed under LGPL2.1+
-
-// Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-// Contact: http://www.qt-project.org/legal
-//
-// GNU Lesser General Public License Usage
-// Alternatively, this file may be used under the terms of the GNU Lesser
-// General Public License version 2.1 or version 3 as published by the Free
-// Software Foundation and appearing in the file LICENSE.LGPLv21 and
-// LICENSE.LGPLv3 included in the packaging of this file. Please review the
-// following information to ensure the GNU Lesser General Public License
-// requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-// http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-//
-// In addition, as a special exception, Digia gives you certain additional
-// rights. These rights are described in the Digia Qt LGPL Exception
-// version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-
-static int nextRand(int& v)
-{
- int r = v % 62;
- v /= 62;
- if (v < 62)
- v = qrand();
- return r;
-}
-
-void TemporaryDir::ensurePath() const
-{
- static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
-
- if (mPath.isEmpty())
- {
- QString dirName;
- while (true)
- {
- dirName = "";
-
- int v = qrand();
- dirName += letters[nextRand(v)];
- dirName += letters[nextRand(v)];
- dirName += letters[nextRand(v)];
- dirName += letters[nextRand(v)];
- dirName += letters[nextRand(v)];
- dirName += letters[nextRand(v)];
-
- if (QDir::temp().mkdir(dirName))
- break;
- }
-
- const QDir dir(QDir::temp().absoluteFilePath(dirName));
-
- if (!dir.exists())
- throw TemporaryDirException(
- QString("Failed to create temporary directory. mkdir succeeded "
- "but the directory does not exist!")
- );
-
- mPath = dir.absolutePath();
- }
-}
diff --git a/src/Utils.cpp b/src/Utils.cpp
index 802cd503..d3562fac 100644
--- a/src/Utils.cpp
+++ b/src/Utils.cpp
@@ -217,3 +217,9 @@ const QString& getSetSidPath()
return ret;
#endif
}
+
+SpacelessQTemporaryFile::SpacelessQTemporaryFile () :
+ QTemporaryFile(QDir::cleanPath(QDir::tempPath() + "/" + "XXXXXX")) {}
+
+SpacelessQTemporaryDir::SpacelessQTemporaryDir () :
+ QTemporaryDir(QDir::cleanPath(QDir::tempPath() + "/" + "XXXXXX")) {}
diff --git a/src/main.cpp b/src/main.cpp
index ebc7b4ba..5f6480a8 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -35,9 +35,6 @@ int main(int argc, char** argv)
FreeConsole();
#endif
- // Needed for TemporaryDir
- qsrand(QTime::currentTime().msec());
-
Application app(argc, argv);
return app.exec();
}
From c8b9c4a7e57a01293e4f622f18f139b29ea544d8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com>
Date: Mon, 6 Jan 2020 17:54:04 +0100
Subject: [PATCH 2/2] Add scap-workbench to temporary file name template
This way it will be obvious that the files have been created by
SCAP Workbench.
---
src/Utils.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/Utils.cpp b/src/Utils.cpp
index d3562fac..fbeb809c 100644
--- a/src/Utils.cpp
+++ b/src/Utils.cpp
@@ -219,7 +219,7 @@ const QString& getSetSidPath()
}
SpacelessQTemporaryFile::SpacelessQTemporaryFile () :
- QTemporaryFile(QDir::cleanPath(QDir::tempPath() + "/" + "XXXXXX")) {}
+ QTemporaryFile(QDir::cleanPath(QDir::tempPath() + "/" + "scap-workbench-XXXXXX")) {}
SpacelessQTemporaryDir::SpacelessQTemporaryDir () :
- QTemporaryDir(QDir::cleanPath(QDir::tempPath() + "/" + "XXXXXX")) {}
+ QTemporaryDir(QDir::cleanPath(QDir::tempPath() + "/" + "scap-workbench-XXXXXX")) {}

View File

@ -0,0 +1,94 @@
From 03391003a5b6f63988b0687625d85c0060b1a932 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com>
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?= <jcerny@redhat.com>
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:

View File

@ -0,0 +1,519 @@
From 69e988df963cb184062814e75c737fe080f303df Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com>
Date: Tue, 25 Feb 2020 10:50:46 +0100
Subject: [PATCH] Generate result-based remediation from tailored profile
Users can generate remediation script from scan results
of a tailored profile.
Unfortunately, the current design of SCAP Workbench doesn't allow
a clear way of doing this. The scan is run in a separated oscap
process. SCAP Workbench doesn't have access to oscap internal
xccdf_session which creates the ARF. It can't obtain the Tailoring
component reference ID.
Instead, we will save the tailoring document to a temporary file
and use the temporary file when generating the remediation.
Resolves: RHBZ#1640715
---
include/RemediationRoleSaver.h | 19 +++++++++-------
include/ResultViewer.h | 2 ++
src/RemediationRoleSaver.cpp | 40 ++++++++++++++++++++++------------
src/ResultViewer.cpp | 9 +++++---
4 files changed, 45 insertions(+), 25 deletions(-)
diff --git a/include/RemediationRoleSaver.h b/include/RemediationRoleSaver.h
index 1681b901..dfeea0c9 100644
--- a/include/RemediationRoleSaver.h
+++ b/include/RemediationRoleSaver.h
@@ -98,33 +98,35 @@ class PuppetProfileRemediationSaver : public ProfileBasedRemediationSaver
class ResultBasedProcessRemediationSaver : public RemediationSaverBase
{
public:
- ResultBasedProcessRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents,
+ ResultBasedProcessRemediationSaver(
+ QWidget* parentWindow, const QByteArray& arfContents, const QString& tailoringFilePath,
const QString& saveMessage, const QString& filetypeExtension, const QString& filetypeTemplate, const QString& fixType);
private:
virtual void saveToFile(const QString& filename);
SpacelessQTemporaryFile mArfFile;
+ QString tailoring;
};
class BashResultRemediationSaver : public ResultBasedProcessRemediationSaver
{
public:
- BashResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents);
+ BashResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents, const QString& tailoringFilePath);
};
class AnsibleResultRemediationSaver : public ResultBasedProcessRemediationSaver
{
public:
- AnsibleResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents);
+ AnsibleResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents, const QString& tailoringFilePath);
};
class PuppetResultRemediationSaver : public ResultBasedProcessRemediationSaver
{
public:
- PuppetResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents);
+ PuppetResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents, const QString& tailoringFilePath);
};
#else // i.e. SCAP_WORKBENCH_USE_LIBRARY_FOR_RESULT_BASED_REMEDIATION_ROLES_GENERATION is defined
@@ -133,33 +135,34 @@ class PuppetResultRemediationSaver : public ResultBasedProcessRemediationSaver
class ResultBasedLibraryRemediationSaver : public RemediationSaverBase
{
public:
- ResultBasedLibraryRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents,
+ ResultBasedLibraryRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents, const QString& tailoringFilePath,
const QString& saveMessage, const QString& filetypeExtension, const QString& filetypeTemplate, const QString& fixType);
private:
virtual void saveToFile(const QString& filename);
SpacelessQTemporaryFile mArfFile;
+ QString tailoring;
};
class BashResultRemediationSaver : public ResultBasedLibraryRemediationSaver
{
public:
- BashResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents);
+ BashResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents, const QString& tailoringFilePath);
};
class AnsibleResultRemediationSaver : public ResultBasedLibraryRemediationSaver
{
public:
- AnsibleResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents);
+ AnsibleResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents, const QString& tailoringFilePath);
};
class PuppetResultRemediationSaver : public ResultBasedLibraryRemediationSaver
{
public:
- PuppetResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents);
+ PuppetResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents, const QString& tailoringFilePath);
};
#endif // SCAP_WORKBENCH_USE_LIBRARY_FOR_RESULT_BASED_REMEDIATION_ROLES_GENERATION
diff --git a/include/ResultViewer.h b/include/ResultViewer.h
index a6da89da..2ec8d576 100644
--- a/include/ResultViewer.h
+++ b/include/ResultViewer.h
@@ -99,6 +99,8 @@ class ResultViewer : public QWidget
/// If user requests to open the file via desktop services
SpacelessQTemporaryFile* mReportFile;
QByteArray mARF;
+
+ QString tailoringFilePath;
};
#endif
diff --git a/src/RemediationRoleSaver.cpp b/src/RemediationRoleSaver.cpp
index 900a221d..28389dbb 100644
--- a/src/RemediationRoleSaver.cpp
+++ b/src/RemediationRoleSaver.cpp
@@ -164,7 +164,8 @@ PuppetProfileRemediationSaver::PuppetProfileRemediationSaver(QWidget* parentWind
{}
#ifndef SCAP_WORKBENCH_USE_LIBRARY_FOR_RESULT_BASED_REMEDIATION_ROLES_GENERATION
-ResultBasedProcessRemediationSaver::ResultBasedProcessRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents,
+ResultBasedProcessRemediationSaver::ResultBasedProcessRemediationSaver(
+ QWidget* parentWindow, const QByteArray& arfContents, const QString& tailoringFilePath,
const QString& saveMessage, const QString& filetypeExtension, const QString& filetypeTemplate, const QString& fixType):
RemediationSaverBase(parentWindow, saveMessage, filetypeExtension, filetypeTemplate, fixType)
{
@@ -172,6 +173,7 @@ ResultBasedProcessRemediationSaver::ResultBasedProcessRemediationSaver(QWidget*
mArfFile.open();
mArfFile.write(arfContents);
mArfFile.close();
+ tailoring = tailoringFilePath;
}
void ResultBasedProcessRemediationSaver::saveToFile(const QString& filename)
@@ -191,6 +193,11 @@ void ResultBasedProcessRemediationSaver::saveToFile(const QString& filename)
args.append("--result-id");
args.append("");
+ if (!tailoring.isNull()) {
+ args.append("--tailoring-file");
+ args.append(tailoring.toUtf8().constData());
+ }
+
args.append(mArfFile.fileName());
// Launching a process and going through its output is something we do already in OscapScannerLocal::evaluate()
@@ -222,23 +229,24 @@ void ResultBasedProcessRemediationSaver::saveToFile(const QString& filename)
}
}
-BashResultRemediationSaver::BashResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents):
- ResultBasedProcessRemediationSaver(parentWindow, arfContents,
+BashResultRemediationSaver::BashResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents, const QString& tailoringFilePath):
+ ResultBasedProcessRemediationSaver(parentWindow, arfContents, tailoringFilePath,
bashSaveMessage, bashFiletypeExtension, bashFiletypeTemplate, bashFixTemplate)
{}
-AnsibleResultRemediationSaver::AnsibleResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents):
- ResultBasedProcessRemediationSaver(parentWindow, arfContents,
+AnsibleResultRemediationSaver::AnsibleResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents, const QString& tailoringFilePath):
+ ResultBasedProcessRemediationSaver(parentWindow, arfContents, tailoringFilePath,
ansibleSaveMessage, ansibleFiletypeExtension, ansibleFiletypeTemplate, ansibleFixType)
{}
-PuppetResultRemediationSaver::PuppetResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents):
- ResultBasedProcessRemediationSaver(parentWindow, arfContents,
+PuppetResultRemediationSaver::PuppetResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents, const QString& tailoringFilePath):
+ ResultBasedProcessRemediationSaver(parentWindow, arfContents, tailoringFilePath,
puppetSaveMessage, puppetFiletypeExtension, puppetFiletypeTemplate, puppetFixType)
{}
#else // i.e. SCAP_WORKBENCH_USE_LIBRARY_FOR_RESULT_BASED_REMEDIATION_ROLES_GENERATION is defined
-ResultBasedLibraryRemediationSaver::ResultBasedLibraryRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents,
+ResultBasedLibraryRemediationSaver::ResultBasedLibraryRemediationSaver(
+ QWidget* parentWindow, const QByteArray& arfContents, const QString& tailoringFilePath,
const QString& saveMessage, const QString& filetypeExtension, const QString& filetypeTemplate, const QString& fixType):
RemediationSaverBase(parentWindow, saveMessage, filetypeExtension, filetypeTemplate, fixType)
{
@@ -246,6 +254,7 @@ ResultBasedLibraryRemediationSaver::ResultBasedLibraryRemediationSaver(QWidget*
mArfFile.open();
mArfFile.write(arfContents);
mArfFile.close();
+ tailoring = tailoringFilePath;
}
void ResultBasedLibraryRemediationSaver::saveToFile(const QString& filename)
@@ -282,6 +291,9 @@ void ResultBasedLibraryRemediationSaver::saveToFile(const QString& filename)
if (session == NULL)
throw std::runtime_error("Couldn't get XCCDF session from the report source");
+ if (!tailoring.isNull()) {
+ xccdf_session_set_user_tailoring_file(session, tailoring.toUtf8().constData());
+ }
xccdf_session_set_loading_flags(session, XCCDF_SESSION_LOAD_XCCDF);
if (xccdf_session_load(session) != 0)
@@ -316,18 +328,18 @@ void ResultBasedLibraryRemediationSaver::saveToFile(const QString& filename)
}
}
-BashResultRemediationSaver::BashResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents):
- ResultBasedLibraryRemediationSaver(parentWindow, arfContents,
+BashResultRemediationSaver::BashResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents, const QString& tailoringFilePath):
+ ResultBasedLibraryRemediationSaver(parentWindow, arfContents, tailoringFilePath,
bashSaveMessage, bashFiletypeExtension, bashFiletypeTemplate, bashFixTemplate)
{}
-AnsibleResultRemediationSaver::AnsibleResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents):
- ResultBasedLibraryRemediationSaver(parentWindow, arfContents,
+AnsibleResultRemediationSaver::AnsibleResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents, const QString& tailoringFilePath):
+ ResultBasedLibraryRemediationSaver(parentWindow, arfContents, tailoringFilePath,
ansibleSaveMessage, ansibleFiletypeExtension, ansibleFiletypeTemplate, ansibleFixType)
{}
-PuppetResultRemediationSaver::PuppetResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents):
- ResultBasedLibraryRemediationSaver(parentWindow, arfContents,
+PuppetResultRemediationSaver::PuppetResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents, const QString& tailoringFilePath):
+ ResultBasedLibraryRemediationSaver(parentWindow, arfContents, tailoringFilePath,
puppetSaveMessage, puppetFiletypeExtension, puppetFiletypeTemplate, puppetFixType)
{}
diff --git a/src/ResultViewer.cpp b/src/ResultViewer.cpp
index 1e730e99..c5444746 100644
--- a/src/ResultViewer.cpp
+++ b/src/ResultViewer.cpp
@@ -114,6 +114,9 @@ void ResultViewer::loadContent(Scanner* scanner)
if (mInputBaseName.endsWith("-xccdf"))
mInputBaseName.chop(QString("-xccdf").length());
}
+ if (session->isSelectedProfileTailoring()) {
+ tailoringFilePath = session->getTailoringFilePath();
+ }
mReport.clear();
scanner->getReport(mReport);
@@ -173,19 +176,19 @@ void ResultViewer::openReport()
void ResultViewer::generateBashRemediationRole()
{
- BashResultRemediationSaver remediation(this, mARF);
+ BashResultRemediationSaver remediation(this, mARF, tailoringFilePath);
remediation.selectFilenameAndSaveRole();
}
void ResultViewer::generateAnsibleRemediationRole()
{
- AnsibleResultRemediationSaver remediation(this, mARF);
+ AnsibleResultRemediationSaver remediation(this, mARF, tailoringFilePath);
remediation.selectFilenameAndSaveRole();
}
void ResultViewer::generatePuppetRemediationRole()
{
- PuppetResultRemediationSaver remediation(this, mARF);
+ PuppetResultRemediationSaver remediation(this, mARF, tailoringFilePath);
remediation.selectFilenameAndSaveRole();
}
From e97539b824202e91c9cd551316836935046e53ca Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com>
Date: Mon, 2 Mar 2020 14:14:49 +0100
Subject: [PATCH] Use only library calls to generate remediation
Removes CMake option
SCAP_WORKBENCH_USE_LIBRARY_FOR_RESULT_BASED_REMEDIATION_ROLES_GENERATION
and removes the code that is used when this option is not set.
That means the remediations will be generated using libopenscap
library calls. The removed code executed "oscap" command to
do the same thing.
---
CMakeLists.txt | 8 +---
include/Config.h.in | 1 -
include/RemediationRoleSaver.h | 41 ----------------
src/RemediationRoleSaver.cpp | 87 ----------------------------------
4 files changed, 2 insertions(+), 135 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 060df785..8d16d3c5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -49,12 +49,8 @@ endif()
# Local scanning tools
option(SCAP_WORKBENCH_LOCAL_SCAN_ENABLED "If enabled, scanning of local machine is possible from workbench. Else the option is disabled in the GUI." TRUE)
-option(SCAP_WORKBENCH_USE_LIBRARY_FOR_RESULT_BASED_REMEDIATION_ROLES_GENERATION "If enabled, result-based remediation roles will be generated by calls to the libopenscap library (instead of being generated by the oscap subprocess). Requires openscap>=1.2.16" FALSE)
-
-if (SCAP_WORKBENCH_USE_LIBRARY_FOR_RESULT_BASED_REMEDIATION_ROLES_GENERATION)
- if(${OPENSCAP_VERSION_MAJOR} LESS 2 AND ${OPENSCAP_VERSION_MINOR} LESS 3 AND ${OPENSCAP_VERSION_PATCH} LESS 16) # i.e. oscap<1.2.16
- message(FATAL_ERROR "Library-powered generation of result-based remediation roles is supported only if you have oscap>=1.2.16, whereas you have oscap==${OPENSCAP_VERSION}")
- endif()
+if(${OPENSCAP_VERSION_MAJOR} LESS 2 AND ${OPENSCAP_VERSION_MINOR} LESS 3 AND ${OPENSCAP_VERSION_PATCH} LESS 16) # i.e. oscap<1.2.16
+ message(FATAL_ERROR "Library-powered generation of result-based remediation roles is supported only if you have oscap>=1.2.16, whereas you have oscap==${OPENSCAP_VERSION}")
endif()
find_program(NICE_EXECUTABLE NAMES nice) # fully optional, local scan still available when missing
diff --git a/include/Config.h.in b/include/Config.h.in
index 21b3f373..a9bc718f 100644
--- a/include/Config.h.in
+++ b/include/Config.h.in
@@ -40,7 +40,6 @@
#define SCAP_WORKBENCH_LOCAL_PKEXEC_OSCAP_PATH "@CMAKE_INSTALL_FULL_LIBEXECDIR@/scap-workbench-pkexec-oscap.sh"
#define SCAP_WORKBENCH_LOCAL_RPM_EXTRACT_PATH "@CMAKE_INSTALL_FULL_LIBEXECDIR@/scap-workbench-rpm-extract.sh"
#define SCAP_WORKBENCH_REMOTE_OSCAP_PATH "oscap"
-#cmakedefine SCAP_WORKBENCH_USE_LIBRARY_FOR_RESULT_BASED_REMEDIATION_ROLES_GENERATION
#cmakedefine SCAP_WORKBENCH_LOCAL_SSH_FOUND
#define SCAP_WORKBENCH_LOCAL_SSH_PATH "@SSH_EXECUTABLE@"
#cmakedefine SCAP_WORKBENCH_LOCAL_SETSID_FOUND
diff --git a/include/RemediationRoleSaver.h b/include/RemediationRoleSaver.h
index dfeea0c9..95938db8 100644
--- a/include/RemediationRoleSaver.h
+++ b/include/RemediationRoleSaver.h
@@ -93,45 +93,6 @@ class PuppetProfileRemediationSaver : public ProfileBasedRemediationSaver
};
-#ifndef SCAP_WORKBENCH_USE_LIBRARY_FOR_RESULT_BASED_REMEDIATION_ROLES_GENERATION
-/// Base for all result-based remediation generators that uses oscap process
-class ResultBasedProcessRemediationSaver : public RemediationSaverBase
-{
- public:
- ResultBasedProcessRemediationSaver(
- QWidget* parentWindow, const QByteArray& arfContents, const QString& tailoringFilePath,
- const QString& saveMessage, const QString& filetypeExtension, const QString& filetypeTemplate, const QString& fixType);
-
- private:
- virtual void saveToFile(const QString& filename);
- SpacelessQTemporaryFile mArfFile;
- QString tailoring;
-};
-
-
-class BashResultRemediationSaver : public ResultBasedProcessRemediationSaver
-{
- public:
- BashResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents, const QString& tailoringFilePath);
-};
-
-
-class AnsibleResultRemediationSaver : public ResultBasedProcessRemediationSaver
-{
- public:
- AnsibleResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents, const QString& tailoringFilePath);
-};
-
-
-class PuppetResultRemediationSaver : public ResultBasedProcessRemediationSaver
-{
- public:
- PuppetResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents, const QString& tailoringFilePath);
-};
-
-#else // i.e. SCAP_WORKBENCH_USE_LIBRARY_FOR_RESULT_BASED_REMEDIATION_ROLES_GENERATION is defined
-
-/// Base for all result-based remediation generators that uses the openscap library
class ResultBasedLibraryRemediationSaver : public RemediationSaverBase
{
public:
@@ -165,7 +126,5 @@ class PuppetResultRemediationSaver : public ResultBasedLibraryRemediationSaver
PuppetResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents, const QString& tailoringFilePath);
};
-#endif // SCAP_WORKBENCH_USE_LIBRARY_FOR_RESULT_BASED_REMEDIATION_ROLES_GENERATION
-
#endif // SCAP_WORKBENCH_REMEDIATION_ROLE_SAVER_H_
diff --git a/src/RemediationRoleSaver.cpp b/src/RemediationRoleSaver.cpp
index 28389dbb..a9866738 100644
--- a/src/RemediationRoleSaver.cpp
+++ b/src/RemediationRoleSaver.cpp
@@ -35,11 +35,7 @@ extern "C"
#include <xccdf_benchmark.h>
#include <xccdf_policy.h>
#include <xccdf_session.h>
-#ifdef SCAP_WORKBENCH_USE_LIBRARY_FOR_RESULT_BASED_REMEDIATION_ROLES_GENERATION
- // vvv This include is used only for library-based generation of result-base remediation roles
- // vvv and it requires (relatively recent) openscap 1.2.16
#include <ds_rds_session.h>
-#endif
}
@@ -163,88 +159,6 @@ PuppetProfileRemediationSaver::PuppetProfileRemediationSaver(QWidget* parentWind
puppetSaveMessage, puppetFiletypeExtension, puppetFiletypeTemplate, puppetFixType)
{}
-#ifndef SCAP_WORKBENCH_USE_LIBRARY_FOR_RESULT_BASED_REMEDIATION_ROLES_GENERATION
-ResultBasedProcessRemediationSaver::ResultBasedProcessRemediationSaver(
- QWidget* parentWindow, const QByteArray& arfContents, const QString& tailoringFilePath,
- const QString& saveMessage, const QString& filetypeExtension, const QString& filetypeTemplate, const QString& fixType):
- RemediationSaverBase(parentWindow, saveMessage, filetypeExtension, filetypeTemplate, fixType)
-{
- mArfFile.setAutoRemove(true);
- mArfFile.open();
- mArfFile.write(arfContents);
- mArfFile.close();
- tailoring = tailoringFilePath;
-}
-
-void ResultBasedProcessRemediationSaver::saveToFile(const QString& filename)
-{
- QStringList args;
- args.append("xccdf");
- args.append("generate");
- args.append("fix");
-
- args.append("--template");
- args.append(mTemplateString);
- args.append("--output");
- args.append(filename);
-
- // vvv This will work, if there is only one result ID in the ARF file, it will be picked no matter what the argument value is.
- // However, ommitting --result-id "" won't work.
- args.append("--result-id");
- args.append("");
-
- if (!tailoring.isNull()) {
- args.append("--tailoring-file");
- args.append(tailoring.toUtf8().constData());
- }
-
- args.append(mArfFile.fileName());
-
- // Launching a process and going through its output is something we do already in OscapScannerLocal::evaluate()
- // This is a lightweight launch though.
- QProcess process(mParentWindow);
-
- SpacelessQTemporaryDir workingDir;
- process.setWorkingDirectory(workingDir.path());
- QString program(SCAP_WORKBENCH_LOCAL_OSCAP_PATH);
-
- process.start(program, args);
- process.waitForStarted();
-
- const unsigned int remediationGenerationTimeout = 10000;
-
- const int process_finished_on_time = process.waitForFinished(remediationGenerationTimeout);
-
- if (!process_finished_on_time)
- {
- QString message = QObject::tr("The process that was supposed to generate remediations didn't finish on time (i.e. within %1 secs), so it was terminated.").arg(remediationGenerationTimeout / 1000);
- process.kill();
- throw std::runtime_error(message.toUtf8().constData());
- }
-
- if (process.exitCode() != 0)
- {
- QString completeErrorMessage(QObject::tr("Exit code of 'oscap' was %1: %2"));
- throw std::runtime_error(completeErrorMessage.arg(process.exitCode()).arg(QString(process.readAllStandardError())).toUtf8().constData());
- }
-}
-
-BashResultRemediationSaver::BashResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents, const QString& tailoringFilePath):
- ResultBasedProcessRemediationSaver(parentWindow, arfContents, tailoringFilePath,
- bashSaveMessage, bashFiletypeExtension, bashFiletypeTemplate, bashFixTemplate)
-{}
-
-AnsibleResultRemediationSaver::AnsibleResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents, const QString& tailoringFilePath):
- ResultBasedProcessRemediationSaver(parentWindow, arfContents, tailoringFilePath,
- ansibleSaveMessage, ansibleFiletypeExtension, ansibleFiletypeTemplate, ansibleFixType)
-{}
-
-PuppetResultRemediationSaver::PuppetResultRemediationSaver(QWidget* parentWindow, const QByteArray& arfContents, const QString& tailoringFilePath):
- ResultBasedProcessRemediationSaver(parentWindow, arfContents, tailoringFilePath,
- puppetSaveMessage, puppetFiletypeExtension, puppetFiletypeTemplate, puppetFixType)
-{}
-
-#else // i.e. SCAP_WORKBENCH_USE_LIBRARY_FOR_RESULT_BASED_REMEDIATION_ROLES_GENERATION is defined
ResultBasedLibraryRemediationSaver::ResultBasedLibraryRemediationSaver(
QWidget* parentWindow, const QByteArray& arfContents, const QString& tailoringFilePath,
const QString& saveMessage, const QString& filetypeExtension, const QString& filetypeTemplate, const QString& fixType):
@@ -343,4 +257,3 @@ PuppetResultRemediationSaver::PuppetResultRemediationSaver(QWidget* parentWindow
puppetSaveMessage, puppetFiletypeExtension, puppetFiletypeTemplate, puppetFixType)
{}
-#endif // SCAP_WORKBENCH_USE_LIBRARY_FOR_RESULT_BASED_REMEDIATION_ROLES_GENERATION
From 550fc786d2cdec391544cd7bc3a33325ba545803 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com>
Date: Tue, 3 Mar 2020 09:36:20 +0100
Subject: [PATCH] Remove known issue
This issue has been fixed by 69e988df963cb184062814e75c737fe080f303df.
---
doc/user_manual.adoc | 14 --------------
1 file changed, 14 deletions(-)
diff --git a/doc/user_manual.adoc b/doc/user_manual.adoc
index fa47d4fc..48933dd9 100644
--- a/doc/user_manual.adoc
+++ b/doc/user_manual.adoc
@@ -524,20 +524,6 @@ Both while opening the files and when scanning. This option is discouraged and
should only be used by content creators and/or people who really know what they
are doing.
-== Known issues
-
-=== Result-based remediations of tailored profiles
-
-Saving remediation roles to the disk may not work for a customized profile. Specifically, it won't work if you add additional rules to it.
-If this limitation affects you, follow these steps:
-
-Remark: You will need to use the oscap command-line utility, which is bundled together with scap-workbench.
-
-1. Save the scan results
-2. Save your profile customization to a file using the "File->Save customization only" option.
-3. Run this command: oscap xccdf generate fix --output <role filename> --result-id '' --tailoring-file <saved-customization> <saved-result>.
-Refer to oscap xccdf generate fix -h if you want other than Bash output.
-
== Where to Get Help?
You ask for help with the application using

View File

@ -0,0 +1,196 @@
From 7786cd8b020ab3aa4a9720e6fa8f60285486a48b Mon Sep 17 00:00:00 2001
From: Matej Tyc <matyc@redhat.com>
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");

View File

@ -0,0 +1,560 @@
From 0e48a7161be7fbabc02ba05407131be2595e9b6d Mon Sep 17 00:00:00 2001
From: Matej Tyc <matyc@redhat.com>
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 @@
<rect>
<x>0</x>
<y>0</y>
- <width>553</width>
- <height>29</height>
+ <width>609</width>
+ <height>42</height>
</rect>
</property>
<property name="windowTitle">
<string>RemoteMachineComboBox</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
- <property name="margin">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
<number>0</number>
</property>
<item>
@@ -73,8 +82,17 @@
</item>
<item>
<widget class="QSpinBox" name="port">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
<property name="buttonSymbols">
- <enum>QAbstractSpinBox::UpDownArrows</enum>
+ <enum>QAbstractSpinBox::NoButtons</enum>
</property>
<property name="minimum">
<number>1</number>
@@ -87,6 +105,16 @@
</property>
</widget>
</item>
+ <item>
+ <widget class="QCheckBox" name="userIsSudoer">
+ <property name="toolTip">
+ <string>Check if the remote user doesn't have root privileges, but they can perform administrative tasks using paswordless sudo.</string>
+ </property>
+ <property name="text">
+ <string>user is sudoer</string>
+ </property>
+ </widget>
+ </item>
<item>
<widget class="QComboBox" name="recentComboBox">
<property name="sizePolicy">
From 1fd9bc807f1c76452c0803436efd311000d7470b Mon Sep 17 00:00:00 2001
From: Matej Tyc <matyc@redhat.com>
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 <matyc@redhat.com>
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 <matyc@redhat.com>
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);
}

View File

@ -0,0 +1,87 @@
diff --git a/ui/SSGIntegrationDialog.ui b/ui/SSGIntegrationDialog.ui
index 2e613740..519773f1 100644
--- a/ui/SSGIntegrationDialog.ui
+++ b/ui/SSGIntegrationDialog.ui
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>889</width>
- <height>288</height>
+ <height>330</height>
</rect>
</property>
<property name="sizePolicy">
@@ -28,6 +28,9 @@
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
+ <property name="spacing">
+ <number>12</number>
+ </property>
<item>
<widget class="QLabel" name="ssgLogo">
<property name="sizePolicy">
@@ -52,15 +55,19 @@
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetMinimumSize</enum>
+ </property>
<property name="leftMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label">
- <property name="font">
- <font>
- <pointsize>11</pointsize>
- </font>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;SCAP Security Guide was found installed on this machine.&lt;/p&gt;&lt;p&gt;The content provided by SCAP Security Guide allows you to quickly scan your machine according to well stablished security baselines.&lt;/p&gt;&lt;p&gt;Also, these guides are a good starting point if you'd like to customize a policy or profile for your own needs.&lt;/p&gt;&lt;p&gt;Select one of the default guides to load, or select Other SCAP Content option to load your own content.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
@@ -111,10 +118,13 @@
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
+ <property name="sizeType">
+ <enum>QSizePolicy::MinimumExpanding</enum>
+ </property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
- <height>40</height>
+ <height>20</height>
</size>
</property>
</spacer>
@@ -157,24 +167,6 @@
</item>
</layout>
</item>
- <item>
- <widget class="QWidget" name="widget" native="true">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <layout class="QHBoxLayout" name="horizontalLayout">
- <property name="spacing">
- <number>6</number>
- </property>
- <property name="margin">
- <number>0</number>
- </property>
- </layout>
- </widget>
- </item>
</layout>
</widget>
<resources/>

View File

@ -2,13 +2,20 @@
Name: scap-workbench
Version: 1.2.0
Release: 3%{?dist}
Release: 8%{?dist}
Summary: Scanning, tailoring, editing and validation tool for SCAP content
License: GPLv3+
URL: http://www.open-scap.org/tools/scap-workbench
Source0: https://github.com/OpenSCAP/scap-workbench/releases/download/%{version}/scap-workbench-%{version}.tar.bz2
Patch1: oscap_version_suffix.patch
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
@ -17,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
@ -38,6 +47,13 @@ content. The tool is based on OpenSCAP library.
%prep
%setup -q
%patch1 -p1
%patch2 -p1
%patch3 -p1
%patch4 -p1
%patch5 -p1
%patch6 -p1
%patch7 -p1
%patch8 -p1
%build
%cmake -D CMAKE_INSTALL_DOCDIR=%{_pkgdocdir} .
@ -64,6 +80,25 @@ make install DESTDIR=%{buildroot}
%doc %{_pkgdocdir}/README.md
%changelog
* Fri Feb 12 2021 Matej Tyc <matyc@redhat.com> - 1.2.0-8
- Introduce asciidoc support instead of asciidoctor (RHBZ#1877522)
* Tue Feb 09 2021 Matej Tyc <matyc@redhat.com> - 1.2.0-7
- Enabled asciidoc support during build (RHBZ#1877522)
* Mon Feb 1 14:38:24 CET 2021 Matej Tyc <matyc@redhat.com> - 1.2.0-6
- Refactor handling of scanner messages.
- Implement passwordless sudo support (RHBZ#1877522)
* Wed May 27 2020 Matěj Týč <matyc@redhat.com> - 1.2.0-5
- Adjust the GUI dimensions, so text fits to the screen (RHBZ#1743713)
* Wed Apr 29 2020 Jan Černý <jcerny@redhat.com> - 1.2.0-5
- Generate result-based remediation from tailored profile (RHBZ#1640715)
* Tue Jan 28 2020 Jan Černý <jcerny@redhat.com> 1.2.0-4
- Fix error messages in the diagnostics window (RHBZ#1781074)
* Mon Oct 15 2018 Watson Yuuma Sato <wsato@redhat.com> - 1.2.0-3
- Rebuilt to fix openscap dependency (RHBZ#1639405)