diff --git a/src/fs/fat12.cpp b/src/fs/fat12.cpp
index 8124c4a..dbad427 100644
--- a/src/fs/fat12.cpp
+++ b/src/fs/fat12.cpp
@@ -157,7 +157,7 @@ bool fat12::create(Report& report, const QString& deviceNode)
bool fat12::updateUUID(Report& report, const QString& deviceNode) const
{
- qint64 t = time(nullptr);
+ long int t = time(nullptr);
char uuid[4];
for (auto &u : uuid) {
@@ -165,9 +165,7 @@ bool fat12::updateUUID(Report& report, const QString& deviceNode) const
t >>= 8;
}
- ExternalCommand cmd(report, QStringLiteral("dd"), { QStringLiteral("of=") + deviceNode , QStringLiteral("bs=1"), QStringLiteral("count=4"), QStringLiteral("seek=39") });
-
- cmd.write(QByteArray(uuid, sizeof(uuid)));
- return cmd.start();
+ ExternalCommand cmd;
+ return cmd.writeData(report, QByteArray(uuid, sizeof(uuid)), deviceNode, 39);
}
}
diff --git a/src/fs/fat32.cpp b/src/fs/fat32.cpp
index b54e4fa..2bb6b34 100644
--- a/src/fs/fat32.cpp
+++ b/src/fs/fat32.cpp
@@ -14,6 +14,7 @@
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see .*
*************************************************************************/
+
#include "fs/fat32.h"
#include "util/externalcommand.h"
@@ -48,7 +49,8 @@ bool fat32::create(Report& report, const QString& deviceNode)
bool fat32::updateUUID(Report& report, const QString& deviceNode) const
{
- qint64 t = time(nullptr);
+ // HACK: replace this hack with fatlabel "-i" (dosfstools 4.2)
+ long int t = time(nullptr);
char uuid[4];
for (auto &u : uuid) {
@@ -56,10 +58,7 @@ bool fat32::updateUUID(Report& report, const QString& deviceNode) const
t >>= 8;
}
- // HACK: replace this hack with fatlabel "-i" (dosfstools 4.2)
- ExternalCommand cmd(report, QStringLiteral("dd"), { QStringLiteral("of=") + deviceNode, QStringLiteral("bs=1"), QStringLiteral("count=4"), QStringLiteral("seek=67") });
-
- cmd.write(QByteArray(uuid, sizeof(uuid)));
- return cmd.start();
+ ExternalCommand cmd;
+ return cmd.writeData(report, QByteArray(uuid, sizeof(uuid)), deviceNode, 67);
}
}
diff --git a/src/fs/ntfs.cpp b/src/fs/ntfs.cpp
index 471638a..0c08c6c 100644
--- a/src/fs/ntfs.cpp
+++ b/src/fs/ntfs.cpp
@@ -29,7 +29,6 @@
#include
#include
#include
-#include
#include
#include
@@ -188,10 +187,8 @@ bool ntfs::updateBootSector(Report& report, const QString& deviceNode) const
std::swap(s[1], s[2]);
#endif
- ExternalCommand cmd(report, QStringLiteral("dd"), { QStringLiteral("of=") + deviceNode , QStringLiteral("bs=1"), QStringLiteral("count=4"), QStringLiteral("seek=28") });
-
- cmd.write(QByteArray(s, sizeof(s)));
- if (!cmd.start()) {
+ ExternalCommand cmd;
+ if (!cmd.writeData(report, QByteArray(s, sizeof(s)), deviceNode, 28)) {
Log() << xi18nc("@info:progress", "Could not write new start sector to partition %1 when trying to update the NTFS boot sector.", deviceNode);
return false;
}
diff --git a/src/util/externalcommand.cpp b/src/util/externalcommand.cpp
index 76b480c..72b1b14 100644
--- a/src/util/externalcommand.cpp
+++ b/src/util/externalcommand.cpp
@@ -241,6 +241,55 @@ bool ExternalCommand::copyBlocks(CopySource& source, CopyTarget& target)
return rval;
}
+bool ExternalCommand::writeData(Report& commandReport, const QByteArray& buffer, const QString& deviceNode, const quint64 firstByte)
+{
+ d->m_Report = commandReport.newChild();
+ if (report())
+ report()->setCommand(xi18nc("@info:status", "Command: %1 %2", command(), args().join(QStringLiteral(" "))));
+
+ bool rval = true;
+
+ if (!QDBusConnection::systemBus().isConnected()) {
+ qWarning() << "Could not connect to DBus system bus";
+ return false;
+ }
+
+ auto *interface = new org::kde::kpmcore::externalcommand(QStringLiteral("org.kde.kpmcore.externalcommand"),
+ QStringLiteral("/Helper"), QDBusConnection::systemBus(), this);
+ interface->setTimeout(10 * 24 * 3600 * 1000); // 10 days
+ QByteArray request;
+
+ const quint64 nonce = interface->getNonce();
+ request.setNum(nonce);
+ request.append(buffer);
+ request.append(deviceNode.toUtf8());
+ request.append(QByteArray::number(firstByte));
+
+ QByteArray hash = QCryptographicHash::hash(request, QCryptographicHash::Sha512);
+
+ QDBusPendingCall pcall = interface->writeData(privateKey->signMessage(hash, QCA::EMSA3_Raw), nonce,
+ buffer, deviceNode, firstByte);
+
+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this);
+ QEventLoop loop;
+
+ auto exitLoop = [&] (QDBusPendingCallWatcher *watcher) {
+ loop.exit();
+ if (watcher->isError())
+ qWarning() << watcher->error();
+ else {
+ QDBusPendingReply reply = *watcher;
+ rval = reply.argumentAt<0>();
+ }
+ setExitCode(!rval);
+ };
+
+ connect(watcher, &QDBusPendingCallWatcher::finished, exitLoop);
+ loop.exec();
+
+ return rval;
+}
+
bool ExternalCommand::write(const QByteArray& input)
{
diff --git a/src/util/externalcommand.h b/src/util/externalcommand.h
index 35b1a81..c1abba2 100644
--- a/src/util/externalcommand.h
+++ b/src/util/externalcommand.h
@@ -69,6 +69,7 @@ public:
public:
bool copyBlocks(CopySource& source, CopyTarget& target);
+ bool writeData(Report& report, const QByteArray& buffer, const QString& deviceNode, const quint64 firstByte); // same as copyBlocks but from QByteArray
/**< @param cmd the command to run */
void setCommand(const QString& cmd);
diff --git a/src/util/externalcommand_whitelist.h b/src/util/externalcommand_whitelist.h
index 79160aa..7ae4240 100644
--- a/src/util/externalcommand_whitelist.h
+++ b/src/util/externalcommand_whitelist.h
@@ -21,7 +21,6 @@
QString allowedCommands[] = {
// TODO try to remove these later
QStringLiteral("mv"),
-QStringLiteral("dd"),
// TODO no root needed
QStringLiteral("lsblk"),
diff --git a/src/util/externalcommandhelper.cpp b/src/util/externalcommandhelper.cpp
index 87edade..c5687cf 100644
--- a/src/util/externalcommandhelper.cpp
+++ b/src/util/externalcommandhelper.cpp
@@ -152,6 +152,7 @@ bool ExternalCommandHelper::writeData(const QString &targetDevice, const QByteAr
return true;
}
+// If targetDevice is empty then return QByteArray with data that was read from disk.
QVariantMap ExternalCommandHelper::copyblocks(const QByteArray& signature, const quint64 nonce, const QString& sourceDevice, const qint64 sourceFirstByte, const qint64 sourceLength, const QString& targetDevice, const qint64 targetFirstByte, const qint64 blockSize)
{
QVariantMap reply;
@@ -213,7 +214,7 @@ QVariantMap ExternalCommandHelper::copyblocks(const QByteArray& signature, const
bool rval = true;
- while (blocksCopied < blocksToCopy) {
+ while (blocksCopied < blocksToCopy && !targetDevice.isEmpty()) {
if (!(rval = readData(sourceDevice, buffer, readOffset + blockSize * blocksCopied * copyDirection, blockSize)))
break;
@@ -265,6 +266,33 @@ QVariantMap ExternalCommandHelper::copyblocks(const QByteArray& signature, const
return reply;
}
+bool ExternalCommandHelper::writeData(const QByteArray& signature, const quint64 nonce, const QByteArray buffer, const QString& targetDevice, const qint64 targetFirstByte)
+{
+ if (m_Nonces.find(nonce) != m_Nonces.end())
+ m_Nonces.erase( nonce );
+ else
+ return false;
+
+ QByteArray request;
+ request.setNum(nonce);
+ request.append(buffer);
+ request.append(targetDevice.toUtf8());
+ request.append(QByteArray::number(targetFirstByte));
+
+ // Do not allow using this helper for writing to arbitrary location
+ if ( targetDevice.left(5) != QStringLiteral("/dev/") && !targetDevice.contains(QStringLiteral("/etc/fstab")))
+ return false;
+
+ QByteArray hash = QCryptographicHash::hash(request, QCryptographicHash::Sha512);
+ if (!m_publicKey.verifyMessage(hash, signature, QCA::EMSA3_Raw)) {
+ qCritical() << xi18n("Invalid cryptographic signature");
+ return false;
+ }
+
+ return writeData(targetDevice, buffer, targetFirstByte);
+}
+
+
QVariantMap ExternalCommandHelper::start(const QByteArray& signature, const quint64 nonce, const QString& command, const QStringList& arguments, const QByteArray& input, const int processChannelMode)
{
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
diff --git a/src/util/externalcommandhelper.h b/src/util/externalcommandhelper.h
index 3f7959c..d73d085 100644
--- a/src/util/externalcommandhelper.h
+++ b/src/util/externalcommandhelper.h
@@ -50,6 +50,7 @@ public Q_SLOTS:
Q_SCRIPTABLE quint64 getNonce();
Q_SCRIPTABLE QVariantMap start(const QByteArray& signature, const quint64 nonce, const QString& command, const QStringList& arguments, const QByteArray& input, const int processChannelMode);
Q_SCRIPTABLE QVariantMap copyblocks(const QByteArray& signature, const quint64 nonce, const QString& sourceDevice, const qint64 sourceFirstByte, const qint64 sourceLength, const QString& targetDevice, const qint64 targetFirstByte, const qint64 blockSize);
+ Q_SCRIPTABLE bool writeData(const QByteArray& signature, const quint64 nonce, const QByteArray buffer, const QString& targetDevice, const qint64 targetFirstByte);
Q_SCRIPTABLE void exit(const QByteArray& signature, const quint64 nonce);
private: