File indexing completed on 2024-05-05 05:48:46

0001 /*
0002     SPDX-FileCopyrightText: 2017-2019 Andrius Štikonas <andrius@stikonas.eu>
0003     SPDX-FileCopyrightText: 2020 Arnaud Ferraris <arnaud.ferraris@collabora.com>
0004     SPDX-FileCopyrightText: 2020 Gaël PORTAY <gael.portay@collabora.com>
0005 
0006     SPDX-License-Identifier: GPL-3.0-or-later
0007 */
0008 
0009 #include "fs/luks2.h"
0010 
0011 #include "util/externalcommand.h"
0012 #include "util/report.h"
0013 
0014 #include <QRegularExpression>
0015 
0016 #include <KLocalizedString>
0017 
0018 namespace FS
0019 {
0020 
0021 luks2::luks2(qint64 firstsector, qint64 lastsector, qint64 sectorsused, const QString& label, const QVariantMap& features)
0022     : luks(firstsector, lastsector, sectorsused, label, features, FileSystem::Type::Luks2)
0023 {
0024 }
0025 
0026 luks2::~luks2()
0027 {
0028 }
0029 
0030 FileSystem::Type luks2::type() const
0031 {
0032     if (m_isCryptOpen && m_innerFs)
0033         return m_innerFs->type();
0034     return FileSystem::Type::Luks2;
0035 }
0036 
0037 bool luks2::create(Report& report, const QString& deviceNode)
0038 {
0039     Q_ASSERT(m_innerFs);
0040     Q_ASSERT(!m_passphrase.isEmpty());
0041 
0042     ExternalCommand createCmd(report, QStringLiteral("cryptsetup"),
0043                               { QStringLiteral("-s"),
0044                                 QStringLiteral("512"),
0045                                 QStringLiteral("--batch-mode"),
0046                                 QStringLiteral("--force-password"),
0047                                 QStringLiteral("--type"), QStringLiteral("luks2"),
0048                                 QStringLiteral("luksFormat"),
0049                                 deviceNode });
0050     if (!( createCmd.write(m_passphrase.toLocal8Bit() + '\n') &&
0051                 createCmd.start(-1) && createCmd.exitCode() == 0))
0052     {
0053         return false;
0054     }
0055 
0056     ExternalCommand openCmd(report, QStringLiteral("cryptsetup"),
0057                               { QStringLiteral("open"),
0058                                 deviceNode,
0059                                 suggestedMapperName(deviceNode) });
0060 
0061     if (!( openCmd.write(m_passphrase.toLocal8Bit() + '\n') && openCmd.start(-1)))
0062         return false;
0063 
0064     setPayloadSize();
0065     scan(deviceNode);
0066 
0067     if (mapperName().isEmpty())
0068         return false;
0069 
0070     if (!m_innerFs->create(report, mapperName()))
0071         return false;
0072 
0073     return true;
0074 }
0075 
0076 bool luks2::resize(Report& report, const QString& deviceNode, qint64 newLength) const
0077 {
0078     Q_ASSERT(m_innerFs);
0079 
0080     if (mapperName().isEmpty())
0081         return false;
0082 
0083     const qint64 sizeDiff = newLength - length() * sectorSize();
0084     const qint64 newPayloadSize = m_PayloadSize + sizeDiff;
0085     if ( sizeDiff > 0 ) // grow
0086     {
0087         ExternalCommand cryptResizeCmd(report, QStringLiteral("cryptsetup"), { QStringLiteral("resize"), mapperName() });
0088         report.line() << xi18nc("@info:progress", "Resizing LUKS crypt on partition <filename>%1</filename>.", deviceNode);
0089 
0090         if (m_KeyLocation == KeyLocation::keyring) {
0091             if (m_passphrase.isEmpty())
0092                 return false;
0093             cryptResizeCmd.write(m_passphrase.toLocal8Bit() + '\n');
0094         }
0095         if (!cryptResizeCmd.start(-1))
0096             return false;
0097         if ( cryptResizeCmd.exitCode() == 0 )
0098             return m_innerFs->resize(report, mapperName(), newPayloadSize);
0099     }
0100     else if (m_innerFs->resize(report, mapperName(), newPayloadSize))
0101     {
0102         ExternalCommand cryptResizeCmd(report, QStringLiteral("cryptsetup"),
0103                 {  QStringLiteral("--size"), QString::number(newPayloadSize / 512), // FIXME, LUKS2 can have different sector sizes
0104                    QStringLiteral("resize"), mapperName() });
0105         report.line() << xi18nc("@info:progress", "Resizing LUKS crypt on partition <filename>%1</filename>.", deviceNode);
0106         if (m_KeyLocation == KeyLocation::keyring) {
0107             if (m_passphrase.isEmpty())
0108                 return false;
0109             cryptResizeCmd.write(m_passphrase.toLocal8Bit() + '\n');
0110         }
0111         if (!cryptResizeCmd.start(-1))
0112             return false;
0113         if ( cryptResizeCmd.exitCode() == 0 )
0114             return true;
0115     }
0116     report.line() << xi18nc("@info:progress", "Resizing encrypted file system on partition <filename>%1</filename> failed.", deviceNode);
0117     return false;
0118 }
0119 
0120 luks::KeyLocation luks2::keyLocation()
0121 {
0122     m_KeyLocation = KeyLocation::unknown;
0123     ExternalCommand statusCmd(QStringLiteral("cryptsetup"), { QStringLiteral("status"), mapperName() });
0124     if (statusCmd.run(-1) && statusCmd.exitCode() == 0) {
0125         QRegularExpression re(QStringLiteral("key location:\\s+(\\w+)"));
0126         QRegularExpressionMatch rem = re.match(statusCmd.output());
0127         if (rem.hasMatch()) {
0128             if (rem.captured(1) == QStringLiteral("keyring"))
0129                 m_KeyLocation = KeyLocation::keyring;
0130             else if (rem.captured(1) == QStringLiteral("dm-crypt"))
0131                 m_KeyLocation = KeyLocation::dmcrypt;
0132         }
0133     }
0134 
0135     return m_KeyLocation;
0136 }
0137 
0138 }