diff --git a/src/fs/luks.cpp b/src/fs/luks.cpp index eb36ad0..3d63f05 100644 --- a/src/fs/luks.cpp +++ b/src/fs/luks.cpp @@ -143,6 +143,7 @@ bool luks::create(Report& report, const QString& deviceNode) if (!( openCmd.start(-1) && openCmd.write(m_passphrase.toLocal8Bit() + '\n') == m_passphrase.toLocal8Bit().length() + 1 && openCmd.waitFor())) return false; + setPayloadSize(); scan(deviceNode); if (mapperName().isEmpty()) @@ -259,6 +260,7 @@ bool luks::cryptOpen(QWidget* parent, const QString& deviceNode) QString passphrase = dlg.password(); ExternalCommand openCmd(QStringLiteral("cryptsetup"), { QStringLiteral("open"), + QStringLiteral("--tries"), QStringLiteral("1"), deviceNode, suggestedMapperName(deviceNode) }); @@ -490,19 +492,18 @@ bool luks::resize(Report& report, const QString& deviceNode, qint64 newLength) c if (mapperName().isEmpty()) return false; - qint64 payloadLength = newLength - payloadOffset(); if ( newLength - length() * sectorSize() > 0 ) { ExternalCommand cryptResizeCmd(report, QStringLiteral("cryptsetup"), { QStringLiteral("resize"), mapperName() }); report.line() << xi18nc("@info:progress", "Resizing LUKS crypt on partition %1.", deviceNode); if (cryptResizeCmd.run(-1) && cryptResizeCmd.exitCode() == 0) - return m_innerFs->resize(report, mapperName(), payloadLength); + return m_innerFs->resize(report, mapperName(), m_PayloadSize); } - else if (m_innerFs->resize(report, mapperName(), payloadLength)) + else if (m_innerFs->resize(report, mapperName(), m_PayloadSize)) { ExternalCommand cryptResizeCmd(report, QStringLiteral("cryptsetup"), - { QStringLiteral("--size"), QString::number(payloadLength / 512), // LUKS payload length is specified in multiples of 512 bytes + { QStringLiteral("--size"), QString::number(m_PayloadSize / 512), // LUKS1 payload length is specified in multiples of 512 bytes QStringLiteral("resize"), mapperName() }); report.line() << xi18nc("@info:progress", "Resizing LUKS crypt on partition %1.", deviceNode); if (cryptResizeCmd.run(-1) && cryptResizeCmd.exitCode() == 0) @@ -589,8 +590,7 @@ void luks::getMapperName(const QString& deviceNode) void luks::getLuksInfo(const QString& deviceNode) { - ExternalCommand cmd(QStringLiteral("cryptsetup"), - { QStringLiteral("luksDump"), deviceNode }); + ExternalCommand cmd(QStringLiteral("cryptsetup"), { QStringLiteral("luksDump"), deviceNode }); if (cmd.run(-1) && cmd.exitCode() == 0) { QRegularExpression re(QStringLiteral("Cipher name:\\s+(\\w+)")); QRegularExpressionMatch rem = re.match(cmd.output()); @@ -667,6 +667,7 @@ bool luks::canEncryptType(FileSystem::Type type) void luks::initLUKS() { + setPayloadSize(); QString mapperNode = mapperName(); bool isCryptOpen = !mapperNode.isEmpty(); setCryptOpen(isCryptOpen); @@ -676,4 +677,22 @@ void luks::initLUKS() } } +void luks::setPayloadSize() +{ + ExternalCommand dmsetupCmd(QStringLiteral("dmsetup"), { QStringLiteral("table"), mapperName() }); + dmsetupCmd.run(); + QRegularExpression re(QStringLiteral("\\d+ (\\d+)")); + QRegularExpressionMatch rem = re.match(dmsetupCmd.output()); + if (rem.hasMatch()) + m_PayloadSize = rem.captured(1).toLongLong() * sectorSize(); +} + +bool luks::testPassphrase(const QString& deviceNode, const QString& passphrase) const { + ExternalCommand cmd(QStringLiteral("cryptsetup"), { QStringLiteral("open"), QStringLiteral("--tries"), QStringLiteral("1"), QStringLiteral("--test-passphrase"), deviceNode }); + if (cmd.start(-1) && cmd.write(passphrase.toLocal8Bit() + '\n') == passphrase.toLocal8Bit().length() + 1 && cmd.waitFor() && cmd.exitCode() == 0) + return true; + + return false; +} + } diff --git a/src/fs/luks.h b/src/fs/luks.h index e7221c8..9a6ea4e 100644 --- a/src/fs/luks.h +++ b/src/fs/luks.h @@ -43,6 +43,12 @@ public: luks(qint64 firstsector, qint64 lastsector, qint64 sectorsused, const QString& label, FileSystem::Type t = FileSystem::Luks); ~luks() override; + enum KeyLocation { + unknown, + dmcrypt, + keyring + }; + public: void init() override; void scan(const QString& deviceNode) override; @@ -167,9 +173,9 @@ public: QString suggestedMapperName(const QString& deviceNode) const; void getMapperName(const QString& deviceNode); - void getLuksInfo(const QString& deviceNode); + virtual void getLuksInfo(const QString& deviceNode); - FileSystem* innerFS() const { return m_innerFs; } // avoid calling this unless necessary + FileSystem* innerFS() const { return m_innerFs; } QString outerUuid() const; QString mapperName() const { return m_MapperName; } @@ -182,8 +188,12 @@ public: static bool canEncryptType(FileSystem::Type type); void initLUKS(); + virtual luks::KeyLocation keyLocation() { return luks::dmcrypt; }; + bool testPassphrase(const QString& deviceNode, const QString& passphrase) const; + protected: virtual QString readOuterUUID(const QString& deviceNode) const; + void setPayloadSize(); public: static CommandSupportType m_GetUsed; @@ -213,7 +223,10 @@ protected: QString m_HashName; qint64 m_KeySize; qint64 m_PayloadOffset; + qint64 m_PayloadSize; QString m_outerUuid; + + luks::KeyLocation m_KeyLocation = unknown; }; } diff --git a/src/fs/luks2.cpp b/src/fs/luks2.cpp index a895517..9301f17 100644 --- a/src/fs/luks2.cpp +++ b/src/fs/luks2.cpp @@ -17,6 +17,13 @@ #include "fs/luks2.h" +#include "util/externalcommand.h" +#include "util/report.h" + +#include + +#include + namespace FS { @@ -36,4 +43,64 @@ FileSystem::Type luks2::type() const return FileSystem::Luks2; } +bool luks2::resize(Report& report, const QString& deviceNode, qint64 newLength) const +{ + Q_ASSERT(m_innerFs); + + if (mapperName().isEmpty()) + return false; + + if ( newLength - length() * sectorSize() > 0 ) + { + ExternalCommand cryptResizeCmd(report, QStringLiteral("cryptsetup"), { QStringLiteral("resize"), mapperName() }); + report.line() << xi18nc("@info:progress", "Resizing LUKS crypt on partition %1.", deviceNode); + + cryptResizeCmd.start(-1); + if (m_KeyLocation == keyring) { + if (m_passphrase.isEmpty()) + return false; + cryptResizeCmd.write(m_passphrase.toLocal8Bit() + '\n'); + } + cryptResizeCmd.waitFor(); + if ( cryptResizeCmd.exitCode() == 0 ) + return m_innerFs->resize(report, mapperName(), m_PayloadSize); + } + else if (m_innerFs->resize(report, mapperName(), m_PayloadSize)) + { + ExternalCommand cryptResizeCmd(report, QStringLiteral("cryptsetup"), + { QStringLiteral("--size"), QString::number(m_PayloadSize / 512), // FIXME, LUKS2 can have different sector sizes + QStringLiteral("resize"), mapperName() }); + report.line() << xi18nc("@info:progress", "Resizing LUKS crypt on partition %1.", deviceNode); + cryptResizeCmd.start(-1); + if (m_KeyLocation == keyring) { + if (m_passphrase.isEmpty()) + return false; + cryptResizeCmd.write(m_passphrase.toLocal8Bit() + '\n'); + } + cryptResizeCmd.waitFor(); + if ( cryptResizeCmd.exitCode() == 0 ) + return true; + } + report.line() << xi18nc("@info:progress", "Resizing encrypted file system on partition %1 failed.", deviceNode); + return false; +} + +luks::KeyLocation luks2::keyLocation() +{ + m_KeyLocation = unknown; + ExternalCommand statusCmd(QStringLiteral("cryptsetup"), { QStringLiteral("status"), mapperName() }); + if (statusCmd.run(-1) && statusCmd.exitCode() == 0) { + QRegularExpression re(QStringLiteral("key location:\\s+(\\w+)")); + QRegularExpressionMatch rem = re.match(statusCmd.output()); + if (rem.hasMatch()) { + if (rem.captured(1) == QStringLiteral("keyring")) + m_KeyLocation = keyring; + else if (rem.captured(1) == QStringLiteral("dm-crypt")) + m_KeyLocation = dmcrypt; + } + } + + return m_KeyLocation; +} + } diff --git a/src/fs/luks2.h b/src/fs/luks2.h index f8151cb..5f0e12e 100644 --- a/src/fs/luks2.h +++ b/src/fs/luks2.h @@ -38,7 +38,11 @@ public: luks2(qint64 firstsector, qint64 lastsector, qint64 sectorsused, const QString& label); ~luks2() override; + bool resize(Report& report, const QString& deviceNode, qint64 length) const override; + FileSystem::Type type() const override; + + luks::KeyLocation keyLocation() override; }; } diff --git a/src/jobs/setpartgeometryjob.cpp b/src/jobs/setpartgeometryjob.cpp index 596e14a..7a4fbd7 100644 --- a/src/jobs/setpartgeometryjob.cpp +++ b/src/jobs/setpartgeometryjob.cpp @@ -73,7 +73,6 @@ bool SetPartGeometryJob::run(Report& parent) delete backendPartitionTable; } - delete backendDevice; } else report->line() << xi18nc("@info:progress", "Could not open device %1 while trying to resize/move partition %2.", device().deviceNode(), partition().deviceNode());