Merge branch 'master' of https://github.com/calamares/calamares into development

This commit is contained in:
Philip Müller 2019-07-09 21:39:45 +02:00
commit 7bc8781d16
38 changed files with 1054 additions and 213 deletions

View File

@ -6,7 +6,7 @@ AllowAllParametersOfDeclarationOnNextLine: 'false'
AllowShortFunctionsOnASingleLine: Inline AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: 'false' AllowShortIfStatementsOnASingleLine: 'false'
AllowShortLoopsOnASingleLine: 'false' AllowShortLoopsOnASingleLine: 'false'
AlwaysBreakAfterDefinitionReturnType: All AlwaysBreakAfterReturnType: TopLevelDefinitions
AlwaysBreakTemplateDeclarations: Yes AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: 'false' BinPackArguments: 'false'
BinPackParameters: 'false' BinPackParameters: 'false'
@ -19,7 +19,7 @@ FixNamespaceComments: 'true'
IncludeBlocks: Preserve IncludeBlocks: Preserve
IndentWidth: '4' IndentWidth: '4'
MaxEmptyLinesToKeep: '2' MaxEmptyLinesToKeep: '2'
NamespaceIndentation: Inner NamespaceIndentation: None
PointerAlignment: Left PointerAlignment: Left
ReflowComments: 'false' ReflowComments: 'false'
SortIncludes: 'true' SortIncludes: 'true'

31
CHANGES
View File

@ -3,7 +3,7 @@ contributors are listed. Note that Calamares does not have a historical
changelog -- this log starts with version 3.2.0. The release notes on the changelog -- this log starts with version 3.2.0. The release notes on the
website will have to do for older versions. website will have to do for older versions.
# 3.2.11 (unreleased) # # 3.2.12 (unreleased) #
This release contains contributions from (alphabetically by first name): This release contains contributions from (alphabetically by first name):
@ -12,6 +12,35 @@ This release contains contributions from (alphabetically by first name):
## Modules ## ## Modules ##
# 3.2.11 (2019-07-06) #
This release contains contributions from (alphabetically by first name):
- No other contributors this time around.
This is a security release with no functional changes (except for
improved security) relative to 3.2.10. The Calamares team would like
to acknowledge the help of the following people in reporting and
understanding the issues (alphabetically by first name):
- Kevin Kofler
- Seth Arnold
- Simon Quigley
- Thomas Ward
Both CVE's have been resolved.
## Core ##
No core changes.
## Modules ##
- *initramfs* could create an initramfs with insecure permissions.
Since the keyfile is included in the initramfs, an attacker could
read the file from the initramfs. #1190 CVE-2019-13178
- *luksbootkeyfile* created a key file where a window of opportunity
existed where the key file could have too-lax file permissions.
#1191 CVE-2019-13179
# 3.2.10 (2019-06-28) # # 3.2.10 (2019-06-28) #
This release contains contributions from (alphabetically by first name): This release contains contributions from (alphabetically by first name):

View File

@ -37,7 +37,7 @@
cmake_minimum_required( VERSION 3.2 FATAL_ERROR ) cmake_minimum_required( VERSION 3.2 FATAL_ERROR )
project( CALAMARES project( CALAMARES
VERSION 3.2.11 VERSION 3.2.12
LANGUAGES C CXX ) LANGUAGES C CXX )
set( CALAMARES_VERSION_RC 1 ) # Set to 0 during release cycle, 1 during development set( CALAMARES_VERSION_RC 1 ) # Set to 0 during release cycle, 1 during development

View File

@ -9,7 +9,13 @@
set -e set -e
AS=$( which astyle ) AS=$( which astyle )
CF=$( which clang-format-7 )
for _cf in clang-format-7 clang-format-8 clang-format70 clang-format80
do
# Not an error if this particular clang-format isn't found
CF=$( which $_cf || true )
test -n "$CF" && break
done
test -n "$AS" || { echo "! No astyle found in PATH"; exit 1 ; } test -n "$AS" || { echo "! No astyle found in PATH"; exit 1 ; }
test -n "$CF" || { echo "! No clang-format-7 found in PATH"; exit 1 ; } test -n "$CF" || { echo "! No clang-format-7 found in PATH"; exit 1 ; }

View File

@ -99,12 +99,12 @@
<message> <message>
<location filename="../src/libcalamaresui/utils/DebugWindow.ui" line="106"/> <location filename="../src/libcalamaresui/utils/DebugWindow.ui" line="106"/>
<source>Reload Stylesheet</source> <source>Reload Stylesheet</source>
<translation type="unfinished"/> <translation>Znovunačíst sešit se styly</translation>
</message> </message>
<message> <message>
<location filename="../src/libcalamaresui/utils/DebugWindow.ui" line="113"/> <location filename="../src/libcalamaresui/utils/DebugWindow.ui" line="113"/>
<source>Widget Tree</source> <source>Widget Tree</source>
<translation type="unfinished"/> <translation>Strom widgetu</translation>
</message> </message>
<message> <message>
<location filename="../src/libcalamaresui/utils/DebugWindow.cpp" line="233"/> <location filename="../src/libcalamaresui/utils/DebugWindow.cpp" line="233"/>
@ -159,12 +159,12 @@
<message> <message>
<location filename="../src/libcalamares/ProcessJob.cpp" line="51"/> <location filename="../src/libcalamares/ProcessJob.cpp" line="51"/>
<source>Run command &apos;%1&apos; in target system.</source> <source>Run command &apos;%1&apos; in target system.</source>
<translation type="unfinished"/> <translation>Spustit v cílovém systému příkaz %1.</translation>
</message> </message>
<message> <message>
<location filename="../src/libcalamares/ProcessJob.cpp" line="51"/> <location filename="../src/libcalamares/ProcessJob.cpp" line="51"/>
<source> Run command &apos;%1&apos;.</source> <source> Run command &apos;%1&apos;.</source>
<translation type="unfinished"/> <translation>Spustit příkaz %1</translation>
</message> </message>
<message> <message>
<location filename="../src/libcalamares/ProcessJob.cpp" line="59"/> <location filename="../src/libcalamares/ProcessJob.cpp" line="59"/>

View File

@ -210,12 +210,12 @@
<message numerus="yes"> <message numerus="yes">
<location filename="../src/libcalamaresui/modulesystem/RequirementsChecker.cpp" line="153"/> <location filename="../src/libcalamaresui/modulesystem/RequirementsChecker.cpp" line="153"/>
<source>Waiting for %n module(s).</source> <source>Waiting for %n module(s).</source>
<translation type="unfinished"><numerusform></numerusform><numerusform></numerusform></translation> <translation><numerusform>Odotetaan %n moduuli(t).</numerusform><numerusform>Odotetaan %n moduuli(t).</numerusform></translation>
</message> </message>
<message numerus="yes"> <message numerus="yes">
<location filename="../src/libcalamaresui/modulesystem/RequirementsChecker.cpp" line="154"/> <location filename="../src/libcalamaresui/modulesystem/RequirementsChecker.cpp" line="154"/>
<source>(%n second(s))</source> <source>(%n second(s))</source>
<translation type="unfinished"><numerusform></numerusform><numerusform></numerusform></translation> <translation><numerusform>(%n sekunttia(s))</numerusform><numerusform>(%n sekunttia(s))</numerusform></translation>
</message> </message>
<message> <message>
<location filename="../src/libcalamaresui/modulesystem/RequirementsChecker.cpp" line="158"/> <location filename="../src/libcalamaresui/modulesystem/RequirementsChecker.cpp" line="158"/>

View File

@ -323,7 +323,7 @@ msgstr ""
#: src/modules/initramfs/main.py:49 #: src/modules/initramfs/main.py:49
msgid "Failed to run update-initramfs on the target" msgid "Failed to run update-initramfs on the target"
msgstr "" msgstr "Fallu al executar update-initramfs nel destín"
#: src/modules/initramfs/main.py:50 src/modules/dracut/main.py:59 #: src/modules/initramfs/main.py:50 src/modules/dracut/main.py:59
msgid "The exit code was {}" msgid "The exit code was {}"
@ -339,7 +339,7 @@ msgstr ""
#: src/modules/dracut/main.py:58 #: src/modules/dracut/main.py:58
msgid "Failed to run dracut on the target" msgid "Failed to run dracut on the target"
msgstr "" msgstr "Fallu al executar dracut nel destín"
#: src/modules/initramfscfg/main.py:41 #: src/modules/initramfscfg/main.py:41
msgid "Configuring initramfs." msgid "Configuring initramfs."

View File

@ -96,7 +96,7 @@ msgstr "Dosya sistemlerini ayırın."
#: src/modules/unpackfs/main.py:41 #: src/modules/unpackfs/main.py:41
msgid "Filling up filesystems." msgid "Filling up filesystems."
msgstr "Dosya sistemini genişlet." msgstr "Dosya sistemi genişletiliyor."
#: src/modules/unpackfs/main.py:159 #: src/modules/unpackfs/main.py:159
msgid "rsync failed with error code {}." msgid "rsync failed with error code {}."

View File

@ -71,6 +71,6 @@ Presentation
function onActivate() { function onActivate() {
presentation.currentSlide = 0; presentation.currentSlide = 0;
advanceTimer.running = true advanceTimer.running = true
console.log("Component activated"); console.log("QML Component (default slideshow) activated");
} }
} }

View File

@ -46,6 +46,7 @@ set( libSources
utils/PluginFactory.cpp utils/PluginFactory.cpp
utils/Retranslator.cpp utils/Retranslator.cpp
utils/String.cpp utils/String.cpp
utils/UMask.cpp
utils/Variant.cpp utils/Variant.cpp
utils/Yaml.cpp utils/Yaml.cpp
) )
@ -146,7 +147,7 @@ install( FILES ${utilsHeaders} DESTINATION include/libcalam
# #
if ( ECM_FOUND AND BUILD_TESTING ) if ( ECM_FOUND AND BUILD_TESTING )
ecm_add_test( ecm_add_test(
Tests.cpp utils/Tests.cpp
TEST_NAME TEST_NAME
libcalamarestest libcalamarestest
LINK_LIBRARIES LINK_LIBRARIES

View File

@ -85,8 +85,10 @@ System::System( bool doChroot, QObject* parent )
{ {
Q_ASSERT( !s_instance ); Q_ASSERT( !s_instance );
s_instance = this; s_instance = this;
if ( !doChroot ) if ( !doChroot && Calamares::JobQueue::instance() && Calamares::JobQueue::instance()->globalStorage() )
{
Calamares::JobQueue::instance()->globalStorage()->insert( "rootMountPoint", "/" ); Calamares::JobQueue::instance()->globalStorage()->insert( "rootMountPoint", "/" );
}
} }
@ -243,6 +245,69 @@ System::runCommand(
return ProcessResult(r, output); return ProcessResult(r, output);
} }
QString
System::targetPath( const QString& path ) const
{
QString completePath;
if ( doChroot() )
{
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance() ? Calamares::JobQueue::instance()->globalStorage() : nullptr;
if ( !gs || !gs->contains( "rootMountPoint" ) )
{
cWarning() << "No rootMountPoint in global storage, cannot create target file" << path;
return QString();
}
completePath = gs->value( "rootMountPoint" ).toString() + '/' + path;
}
else
{
completePath = QStringLiteral( "/" ) + path;
}
return completePath;
}
QString
System::createTargetFile( const QString& path, const QByteArray& contents ) const
{
QString completePath = targetPath( path );
if ( completePath.isEmpty() )
{
return QString();
}
QFile f( completePath );
if ( f.exists() )
{
return QString();
}
QIODevice::OpenMode m =
#if QT_VERSION >= QT_VERSION_CHECK( 5, 11, 0 )
// New flag from Qt 5.11, implies WriteOnly
QIODevice::NewOnly |
#endif
QIODevice::WriteOnly | QIODevice::Truncate;
if ( !f.open( m ) )
{
return QString();
}
if ( f.write( contents ) != contents.size() )
{
f.close();
f.remove();
return QString();
}
f.close();
return QFileInfo( f ).canonicalFilePath();
}
QPair<quint64, float> QPair<quint64, float>
System::getTotalMemoryB() const System::getTotalMemoryB() const

View File

@ -205,6 +205,40 @@ public:
return targetEnvOutput( QStringList{ command }, output, workingPath, stdInput, timeoutSec ); return targetEnvOutput( QStringList{ command }, output, workingPath, stdInput, timeoutSec );
} }
/** @brief Gets a path to a file in the target system, from the host.
*
* @param path Path to the file; this is interpreted
* from the root of the target system (whatever that may be,
* but / in the chroot, or / in OEM modes).
*
* @return The complete path to the target file, from
* the root of the host system, or empty on failure.
*
* For instance, during installation where the target root is
* mounted on /tmp/calamares-something, asking for targetPath("/etc/passwd")
* will give you /tmp/calamares-something/etc/passwd.
*
* No attempt is made to canonicalize anything, since paths might not exist.
*/
DLLEXPORT QString targetPath( const QString& path ) const;
/** @brief Create a (small-ish) file in the target system.
*
* @param path Path to the file; this is interpreted
* from the root of the target system (whatever that may be,
* but / in the chroot, or / in OEM modes).
* @param contents Actual content of the file.
*
* Will not overwrite files. Returns an empty string if the
* target file already exists.
*
* @return The complete canonical path to the target file from the
* root of the host system, or empty on failure. (Here, it is
* possible to be canonical because the file exists).
*/
DLLEXPORT QString createTargetFile( const QString& path, const QByteArray& contents ) const;
/** /**
* @brief getTotalMemoryB returns the total main memory, in bytes. * @brief getTotalMemoryB returns the total main memory, in bytes.
* *

View File

@ -18,23 +18,24 @@
#include "Tests.h" #include "Tests.h"
#include "utils/CalamaresUtilsSystem.h" #include "CalamaresUtilsSystem.h"
#include "utils/Logger.h" #include "Logger.h"
#include "utils/Yaml.h" #include "UMask.h"
#include "Yaml.h"
#include <QTemporaryFile> #include <QTemporaryFile>
#include <QtTest/QtTest> #include <QtTest/QtTest>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
QTEST_GUILESS_MAIN( LibCalamaresTests ) QTEST_GUILESS_MAIN( LibCalamaresTests )
LibCalamaresTests::LibCalamaresTests() LibCalamaresTests::LibCalamaresTests() {}
{
}
LibCalamaresTests::~LibCalamaresTests() LibCalamaresTests::~LibCalamaresTests() {}
{
}
void void
LibCalamaresTests::initTestCase() LibCalamaresTests::initTestCase()
@ -46,9 +47,9 @@ LibCalamaresTests::testDebugLevels()
{ {
Logger::setupLogLevel( Logger::LOG_DISABLE ); Logger::setupLogLevel( Logger::LOG_DISABLE );
QCOMPARE( Logger::logLevel(), static_cast<unsigned int>( Logger::LOG_DISABLE ) ); QCOMPARE( Logger::logLevel(), static_cast< unsigned int >( Logger::LOG_DISABLE ) );
for ( unsigned int level = 0; level <= Logger::LOGVERBOSE ; ++level ) for ( unsigned int level = 0; level <= Logger::LOGVERBOSE; ++level )
{ {
Logger::setupLogLevel( level ); Logger::setupLogLevel( level );
QCOMPARE( Logger::logLevel(), level ); QCOMPARE( Logger::logLevel(), level );
@ -67,7 +68,9 @@ LibCalamaresTests::testLoadSaveYaml()
QFile f( "settings.conf" ); QFile f( "settings.conf" );
// Find the nearest settings.conf to read // Find the nearest settings.conf to read
for ( unsigned int up = 0; !f.exists() && ( up < 4 ); ++up ) for ( unsigned int up = 0; !f.exists() && ( up < 4 ); ++up )
{
f.setFileName( QString( "../" ) + f.fileName() ); f.setFileName( QString( "../" ) + f.fileName() );
}
cDebug() << QDir().absolutePath() << f.fileName() << f.exists(); cDebug() << QDir().absolutePath() << f.fileName() << f.exists();
QVERIFY( f.exists() ); QVERIFY( f.exists() );
@ -75,7 +78,7 @@ LibCalamaresTests::testLoadSaveYaml()
CalamaresUtils::saveYaml( "out.yaml", map ); CalamaresUtils::saveYaml( "out.yaml", map );
auto other_map = CalamaresUtils::loadYaml( "out.yaml" ); auto other_map = CalamaresUtils::loadYaml( "out.yaml" );
CalamaresUtils::saveYaml(" out2.yaml", other_map ); CalamaresUtils::saveYaml( " out2.yaml", other_map );
QCOMPARE( map, other_map ); QCOMPARE( map, other_map );
QFile::remove( "out.yaml" ); QFile::remove( "out.yaml" );
@ -121,10 +124,7 @@ void
LibCalamaresTests::testCommands() LibCalamaresTests::testCommands()
{ {
using CalamaresUtils::System; using CalamaresUtils::System;
auto r = System::runCommand( auto r = System::runCommand( System::RunLocation::RunInHost, { "/bin/ls", "/tmp" } );
System::RunLocation::RunInHost,
{ "/bin/ls", "/tmp" }
);
QVERIFY( r.getExitCode() == 0 ); QVERIFY( r.getExitCode() == 0 );
@ -136,25 +136,41 @@ LibCalamaresTests::testCommands()
QVERIFY( !r.getOutput().contains( tfn.fileName() ) ); QVERIFY( !r.getOutput().contains( tfn.fileName() ) );
// Run ls again, now that the file exists // Run ls again, now that the file exists
r = System::runCommand( r = System::runCommand( System::RunLocation::RunInHost, { "/bin/ls", "/tmp" } );
System::RunLocation::RunInHost,
{ "/bin/ls", "/tmp" }
);
QVERIFY( r.getOutput().contains( tfn.fileName() ) ); QVERIFY( r.getOutput().contains( tfn.fileName() ) );
// .. and without a working directory set, assume builddir != /tmp // .. and without a working directory set, assume builddir != /tmp
r = System::runCommand( r = System::runCommand( System::RunLocation::RunInHost, { "/bin/ls" } );
System::RunLocation::RunInHost,
{ "/bin/ls" }
);
QVERIFY( !r.getOutput().contains( tfn.fileName() ) ); QVERIFY( !r.getOutput().contains( tfn.fileName() ) );
r = System::runCommand( r = System::runCommand( System::RunLocation::RunInHost, { "/bin/ls" }, "/tmp" );
System::RunLocation::RunInHost,
{ "/bin/ls" },
"/tmp"
);
QVERIFY( r.getOutput().contains( tfn.fileName() ) ); QVERIFY( r.getOutput().contains( tfn.fileName() ) );
}
void
LibCalamaresTests::testUmask()
{
struct stat mystat;
QTemporaryFile ft;
QVERIFY( ft.open() );
mode_t m = CalamaresUtils::setUMask( 022 );
QCOMPARE( CalamaresUtils::setUMask( m ), m );
for ( int i = 0; i <= 0777 /* octal! */; ++i )
{
QByteArray name = ( ft.fileName() + QChar( '.' ) + QString::number( i, 8 ) ).toLatin1();
CalamaresUtils::UMask um( i );
int fd = creat( name, 0777 );
QVERIFY( fd >= 0 );
close( fd );
QFileInfo fi( name );
QVERIFY( fi.exists() );
QCOMPARE( stat( name, &mystat ), 0 );
QCOMPARE( mystat.st_mode & 0777, 0777 & ~i );
QCOMPARE( unlink( name ), 0 );
}
QCOMPARE( CalamaresUtils::setUMask( 022 ), m );
QCOMPARE( CalamaresUtils::setUMask( m ), 022 );
} }

View File

@ -36,6 +36,9 @@ private Q_SLOTS:
void testLoadSaveYamlExtended(); // Do a find() in the src dir void testLoadSaveYamlExtended(); // Do a find() in the src dir
void testCommands(); void testCommands();
/** @brief Test that all the UMask objects work correctly. */
void testUmask();
}; };
#endif #endif

View File

@ -0,0 +1,44 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2019, Adriaan de Groot <groot@kde.org>
*
* Calamares 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.
*
* Calamares 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 Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#include "UMask.h"
#include <sys/stat.h>
#include <sys/types.h>
namespace CalamaresUtils
{
mode_t
setUMask( mode_t u )
{
return umask( u );
}
UMask::UMask( mode_t u )
: m_mode( setUMask( u ) )
{
}
UMask::~UMask()
{
setUMask( m_mode );
}
static_assert( UMask::Safe == ( S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH ), "Bad permissions." );
} // namespace CalamaresUtils

View File

@ -0,0 +1,55 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2019, Adriaan de Groot <groot@kde.org>
*
* Calamares 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.
*
* Calamares 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 Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef UTILS_UMASK_H
#define UTILS_UMASK_H
#include "DllMacro.h"
#include <sys/types.h>
namespace CalamaresUtils
{
/// @brief Wrapper for umask(2)
DLLEXPORT mode_t setUMask( mode_t u );
/** @brief RAII for setting and re-setting umask.
*
* Create an object of this class to set the umask,
* and the umask is reset to its original value when
* the object goes out of scope.
*/
class DLLEXPORT UMask
{
public:
UMask( mode_t u );
~UMask();
/** @brief a "safe" umask
*
* This umask will switch off group- and other- permissions for
* files, so that the file cannot be read, written, or executed
* except by the owner.
*/
static constexpr mode_t Safe = 077; // octal!
private:
mode_t m_mode;
};
} // namespace CalamaresUtils
#endif

View File

@ -223,7 +223,7 @@ DebugWindow::DebugWindow()
{ {
for ( auto* w : qApp->topLevelWidgets() ) for ( auto* w : qApp->topLevelWidgets() )
{ {
auto deb = cDebug(); Logger::CDebug deb;
dumpWidgetTree( deb, w, 0 ); dumpWidgetTree( deb, w, 0 );
} }
}); });

View File

@ -0,0 +1,26 @@
calamares_add_plugin( initcpio
TYPE job
EXPORT_MACRO PLUGINDLLEXPORT_PRO
SOURCES
InitcpioJob.cpp
LINK_PRIVATE_LIBRARIES
calamares
SHARED_LIB
)
if( ECM_FOUND AND BUILD_TESTING )
ecm_add_test(
Tests.cpp
TEST_NAME
initcpiotest
LINK_LIBRARIES
${CALAMARES_LIBRARIES}
calamares
calamares_job_initcpio # From above
${YAMLCPP_LIBRARY}
Qt5::Core
Qt5::Test
)
set_target_properties( initcpiotest PROPERTIES AUTOMOC TRUE )
target_include_directories( initcpiotest PRIVATE /usr/local/include )
endif()

View File

@ -0,0 +1,108 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2019, Adriaan de Groot <groot@kde.org>
*
* Calamares 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.
*
* Calamares 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 Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#include "InitcpioJob.h"
#include "utils/CalamaresUtilsSystem.h"
#include "utils/Logger.h"
#include "utils/UMask.h"
#include "utils/Variant.h"
#include <QDir>
#include <QFile>
InitcpioJob::InitcpioJob( QObject* parent )
: Calamares::CppJob( parent )
{
}
InitcpioJob::~InitcpioJob() {}
QString
InitcpioJob::prettyName() const
{
return tr( "Creating initramfs with mkinitcpio." );
}
void
fixPermissions( const QDir& d )
{
for ( const auto& fi : d.entryInfoList( { "initramfs*" }, QDir::Files ) )
{
QFile f( fi.absoluteFilePath() );
if ( f.exists() )
{
cDebug() << "initcpio fixing permissions for" << f.fileName();
f.setPermissions( QFileDevice::ReadOwner | QFileDevice::WriteOwner );
}
}
}
Calamares::JobResult
InitcpioJob::exec()
{
CalamaresUtils::UMask m( CalamaresUtils::UMask::Safe );
if ( m_unsafe )
{
cDebug() << "Skipping mitigations for unsafe initramfs permissions.";
}
else
{
QDir d( CalamaresUtils::System::instance()->targetPath( "/boot" ) );
if ( d.exists() )
{
fixPermissions( d );
}
}
cDebug() << "Updating initramfs with kernel" << m_kernel;
auto r = CalamaresUtils::System::instance()->targetEnvCommand(
{ "mkinitcpio", "-p", m_kernel }, QString(), QString(), 0 );
return r.explainProcess( "mkinitcpio", 10 );
}
void
InitcpioJob::setConfigurationMap( const QVariantMap& configurationMap )
{
m_kernel = CalamaresUtils::getString( configurationMap, "kernel" );
if ( m_kernel.isEmpty() )
{
m_kernel = QStringLiteral( "all" );
}
else if ( m_kernel == "$uname" )
{
auto r = CalamaresUtils::System::runCommand(
CalamaresUtils::System::RunLocation::RunInHost, { "/bin/uname", "-r" }, QString(), QString(), 3 );
if ( r.getExitCode() == 0 )
{
m_kernel = r.getOutput();
cDebug() << "*initcpio* using running kernel" << m_kernel;
}
else
{
cWarning() << "*initcpio* could not determine running kernel, using 'all'." << Logger::Continuation
<< r.getExitCode() << r.getOutput();
}
}
m_unsafe = CalamaresUtils::getBool( configurationMap, "be_unsafe", false );
}
CALAMARES_PLUGIN_FACTORY_DEFINITION( InitcpioJobFactory, registerPlugin< InitcpioJob >(); )

View File

@ -0,0 +1,50 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2019, Adriaan de Groot <groot@kde.org>
*
* Calamares 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.
*
* Calamares 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 Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INITCPIOJOB_H
#define INITCPIOJOB_H
#include "CppJob.h"
#include "PluginDllMacro.h"
#include "utils/PluginFactory.h"
#include <QObject>
#include <QVariantMap>
class PLUGINDLLEXPORT InitcpioJob : public Calamares::CppJob
{
Q_OBJECT
public:
explicit InitcpioJob( QObject* parent = nullptr );
virtual ~InitcpioJob() override;
QString prettyName() const override;
Calamares::JobResult exec() override;
void setConfigurationMap( const QVariantMap& configurationMap ) override;
private:
QString m_kernel;
bool m_unsafe = false;
};
CALAMARES_PLUGIN_FACTORY_DECLARATION( InitcpioJobFactory )
#endif // INITCPIOJOB_H

View File

@ -0,0 +1,59 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2019, Adriaan de Groot <groot@kde.org>
*
* Calamares 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.
*
* Calamares 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 Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Tests.h"
#include "GlobalStorage.h"
#include "JobQueue.h"
#include "Settings.h"
#include "utils/Logger.h"
#include "utils/Yaml.h"
#include <QtTest/QtTest>
#include <QFileInfo>
#include <QStringList>
extern void fixPermissions( const QDir& d );
QTEST_GUILESS_MAIN( InitcpioTests )
InitcpioTests::InitcpioTests()
{
}
InitcpioTests::~InitcpioTests()
{
}
void
InitcpioTests::initTestCase()
{
}
void InitcpioTests::testFixPermissions()
{
Logger::setupLogLevel( Logger::LOGDEBUG );
cDebug() << "Fixing up /boot";
fixPermissions( QDir( "/boot" ) );
cDebug() << "Fixing up /nonexistent";
fixPermissions( QDir( "/nonexistent/nonexistent" ) );
QVERIFY( true );
}

View File

@ -0,0 +1,36 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2019, Adriaan de Groot <groot@kde.org>
*
* Calamares 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.
*
* Calamares 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 Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TESTS_H
#define TESTS_H
#include <QObject>
class InitcpioTests : public QObject
{
Q_OBJECT
public:
InitcpioTests();
~InitcpioTests() override;
private Q_SLOTS:
void initTestCase();
void testFixPermissions();
};
#endif

View File

@ -1,3 +1,23 @@
# Run mkinitcpio(8) with the given preset value # Run mkinitcpio(8) with the given preset value
--- ---
# There is only one configuration item for this module,
# the kernel to be loaded. This can have the following
# values:
# - empty or unset, interpreted as "all"
# - the literal string "$uname" (without quotes, with dollar),
# which will use the output of `uname -r` to determine the
# running kernel, and use that.
# - any other string.
#
# Whatever is set, that string is passed as *preset* argument to the
# `-p` option of *mkinitcpio*. Take care that both "$uname" operates
# in the host system, and might not be correct if the target system is
# updated (to a newer kernel) as part of the installation.
#
# Note that "all" is probably not a good preset to use either.
kernel: linux312 kernel: linux312
# Set this to true to turn off mitigations for lax file
# permissions on initramfs (which, in turn, can compromise
# your LUKS encryption keys, CVS-2019-13179).
be_unsafe: false

View File

@ -1,50 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# === This file is part of Calamares - <https://github.com/calamares> ===
#
# Copyright 2014, Philip Müller <philm@manjaro.org>
# Copyright 2019, Adriaan de Groot <groot@kde.org>
#
# Calamares 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.
#
# Calamares 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 Calamares. If not, see <http://www.gnu.org/licenses/>.
import libcalamares
from libcalamares.utils import check_target_env_call
import gettext
_ = gettext.translation("calamares-python",
localedir=libcalamares.utils.gettext_path(),
languages=libcalamares.utils.gettext_languages(),
fallback=True).gettext
def pretty_name():
return _("Creating initramfs with mkinitcpio.")
def run():
""" Calls routine to create kernel initramfs image.
:return:
"""
from subprocess import CalledProcessError
kernel = libcalamares.job.configuration['kernel']
try:
check_target_env_call(['mkinitcpio', '-p', kernel])
except CalledProcessError as e:
libcalamares.utils.warning(str(e))
return ( _( "Process Failed" ),
_( "Process <pre>mkinitcpio</pre> failed with error code {!s}. The command was <pre>{!s}</pre>." ).format( e.returncode, e.cmd ) )
return None

View File

@ -1,5 +0,0 @@
---
type: "job"
name: "initcpio"
interface: "python"
script: "main.py"

View File

@ -7,3 +7,20 @@ calamares_add_plugin( initramfs
calamares calamares
SHARED_LIB SHARED_LIB
) )
if( ECM_FOUND AND BUILD_TESTING )
ecm_add_test(
Tests.cpp
TEST_NAME
initramfstest
LINK_LIBRARIES
${CALAMARES_LIBRARIES}
calamares
calamares_job_initramfs # From above
${YAMLCPP_LIBRARY}
Qt5::Core
Qt5::Test
)
set_target_properties( initramfstest PROPERTIES AUTOMOC TRUE )
target_include_directories( initramfstest PRIVATE /usr/local/include )
endif()

View File

@ -20,6 +20,7 @@
#include "utils/CalamaresUtilsSystem.h" #include "utils/CalamaresUtilsSystem.h"
#include "utils/Logger.h" #include "utils/Logger.h"
#include "utils/UMask.h"
#include "utils/Variant.h" #include "utils/Variant.h"
InitramfsJob::InitramfsJob( QObject* parent ) InitramfsJob::InitramfsJob( QObject* parent )
@ -40,9 +41,29 @@ InitramfsJob::prettyName() const
Calamares::JobResult Calamares::JobResult
InitramfsJob::exec() InitramfsJob::exec()
{ {
CalamaresUtils::UMask m( CalamaresUtils::UMask::Safe );
cDebug() << "Updating initramfs with kernel" << m_kernel; cDebug() << "Updating initramfs with kernel" << m_kernel;
if ( m_unsafe )
{
cDebug() << "Skipping mitigations for unsafe initramfs permissions.";
}
else
{
// First make sure we generate a safe initramfs with suitable permissions.
static const char confFile[] = "/etc/initramfs-tools/conf.d/calamares-safe-initramfs.conf";
static const char contents[] = "UMASK=0077\n";
if ( CalamaresUtils::System::instance()->createTargetFile( confFile, QByteArray( contents ) ).isEmpty() )
{
cWarning() << Logger::SubEntry << "Could not configure safe UMASK for initramfs.";
// But continue anyway.
}
}
// And then do the ACTUAL work.
auto r = CalamaresUtils::System::instance()->targetEnvCommand( auto r = CalamaresUtils::System::instance()->targetEnvCommand(
{ "update-initramfs", "-k", m_kernel, "-c", "-t" }, QString(), QString(), 10 ); { "update-initramfs", "-k", m_kernel, "-c", "-t" }, QString(), QString(), 0 );
return r.explainProcess( "update-initramfs", 10 ); return r.explainProcess( "update-initramfs", 10 );
} }
@ -70,6 +91,8 @@ InitramfsJob::setConfigurationMap( const QVariantMap& configurationMap )
<< r.getExitCode() << r.getOutput(); << r.getExitCode() << r.getOutput();
} }
} }
m_unsafe = CalamaresUtils::getBool( configurationMap, "be_unsafe", false );
} }
CALAMARES_PLUGIN_FACTORY_DEFINITION( InitramfsJobFactory, registerPlugin< InitramfsJob >(); ) CALAMARES_PLUGIN_FACTORY_DEFINITION( InitramfsJobFactory, registerPlugin< InitramfsJob >(); )

View File

@ -42,6 +42,7 @@ public:
private: private:
QString m_kernel; QString m_kernel;
bool m_unsafe = false;
}; };
CALAMARES_PLUGIN_FACTORY_DECLARATION( InitramfsJobFactory ) CALAMARES_PLUGIN_FACTORY_DECLARATION( InitramfsJobFactory )

View File

@ -0,0 +1,96 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2019, Adriaan de Groot <groot@kde.org>
*
* Calamares 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.
*
* Calamares 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 Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Tests.h"
#include "GlobalStorage.h"
#include "JobQueue.h"
#include "Settings.h"
#include "utils/CalamaresUtilsSystem.h"
#include "utils/Logger.h"
#include "utils/Yaml.h"
#include <QtTest/QtTest>
#include <QFileInfo>
#include <QStringList>
QTEST_GUILESS_MAIN( InitramfsTests )
InitramfsTests::InitramfsTests()
{
}
InitramfsTests::~InitramfsTests()
{
}
void
InitramfsTests::initTestCase()
{
Logger::setupLogLevel( Logger::LOGDEBUG );
}
static const char contents[] = "UMASK=0077\n";
static const char confFile[] = "/tmp/calamares-safe-umask";
void InitramfsTests::cleanup()
{
QFile::remove( confFile );
}
void InitramfsTests::testCreateHostFile()
{
CalamaresUtils::System s( false ); // don't chroot
QString path = s.createTargetFile( confFile, QByteArray( contents ) );
QVERIFY( !path.isEmpty() );
QCOMPARE( path, confFile ); // don't chroot, so path create relative to /
QVERIFY( QFile::exists( confFile ) );
QFileInfo fi( confFile );
QVERIFY( fi.exists() );
QCOMPARE( fi.size(), sizeof( contents )-1 ); // don't count trailing NUL
QFile::remove( confFile );
}
void InitramfsTests::testCreateTargetFile()
{
static const char short_confFile[] = "/calamares-safe-umask";
CalamaresUtils::System s( true );
QString path = s.createTargetFile( short_confFile, QByteArray( contents ) );
QVERIFY( path.isEmpty() ); // because no rootmountpoint is set
Calamares::JobQueue j;
j.globalStorage()->insert( "rootMountPoint", "/tmp" );
path = s.createTargetFile( short_confFile, QByteArray( contents ) );
QVERIFY( path.endsWith( short_confFile ) ); // chroot, so path create relative to
QVERIFY( path.startsWith( "/tmp/" ) );
QVERIFY( QFile::exists( path ) );
QFileInfo fi( path );
QVERIFY( fi.exists() );
QCOMPARE( fi.size(), sizeof( contents )-1 ); // don't count trailing NUL
QFile::remove( path );
}

View File

@ -0,0 +1,39 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2019, Adriaan de Groot <groot@kde.org>
*
* Calamares 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.
*
* Calamares 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 Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TESTS_H
#define TESTS_H
#include <QObject>
class InitramfsTests : public QObject
{
Q_OBJECT
public:
InitramfsTests();
~InitramfsTests() override;
private Q_SLOTS:
void initTestCase();
void cleanup();
void testCreateHostFile();
void testCreateTargetFile();
};
#endif

View File

@ -29,3 +29,8 @@
# 3.2.9 and earlier which passed "all" as version. # 3.2.9 and earlier which passed "all" as version.
kernel: "all" kernel: "all"
# Set this to true to turn off mitigations for lax file
# permissions on initramfs (which, in turn, can compromise
# your LUKS encryption keys, CVS-2019-13179).
be_unsafe: false

View File

@ -0,0 +1,9 @@
calamares_add_plugin( luksbootkeyfile
TYPE job
EXPORT_MACRO PLUGINDLLEXPORT_PRO
SOURCES
LuksBootKeyFileJob.cpp
LINK_PRIVATE_LIBRARIES
calamares
SHARED_LIB
)

View File

@ -0,0 +1,214 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2019, Adriaan de Groot <groot@kde.org>
*
* Calamares 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.
*
* Calamares 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 Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#include "LuksBootKeyFileJob.h"
#include "utils/CalamaresUtilsSystem.h"
#include "utils/Logger.h"
#include "utils/UMask.h"
#include "utils/Variant.h"
#include "GlobalStorage.h"
#include "JobQueue.h"
LuksBootKeyFileJob::LuksBootKeyFileJob( QObject* parent )
: Calamares::CppJob( parent )
{
}
LuksBootKeyFileJob::~LuksBootKeyFileJob() {}
QString
LuksBootKeyFileJob::prettyName() const
{
return tr( "Configuring LUKS key file." );
}
struct LuksDevice
{
LuksDevice( const QMap< QString, QVariant >& pinfo )
: isValid( false )
, isRoot( false )
{
if ( pinfo.contains( "luksMapperName" ) )
{
QString fs = pinfo[ "fs" ].toString();
QString mountPoint = pinfo[ "mountPoint" ].toString();
if ( !mountPoint.isEmpty() || fs == QStringLiteral( "linuxswap" ) )
{
isValid = true;
isRoot = mountPoint == '/';
device = pinfo[ "device" ].toString();
passphrase = pinfo[ "luksPassphrase" ].toString();
}
}
}
bool isValid;
bool isRoot;
QString device;
QString passphrase;
};
/** @brief Extract the luks passphrases setup.
*
* Given a list of partitions (as set up by the partitioning module,
* so there's maps with keys inside), returns just the list of
* luks passphrases for each device.
*/
static QList< LuksDevice >
getLuksDevices( const QVariantList& list )
{
QList< LuksDevice > luksItems;
for ( const auto& p : list )
{
if ( p.canConvert< QVariantMap >() )
{
LuksDevice d( p.toMap() );
if ( d.isValid )
{
luksItems.append( d );
}
}
}
return luksItems;
}
struct LuksDeviceList
{
LuksDeviceList( const QVariant& partitions )
: valid( false )
{
if ( partitions.canConvert< QVariantList >() )
{
devices = getLuksDevices( partitions.toList() );
valid = true;
}
}
QList< LuksDevice > devices;
bool valid;
};
static const char keyfile[] = "/crypto_keyfile.bin";
static bool
generateTargetKeyfile()
{
CalamaresUtils::UMask m( CalamaresUtils::UMask::Safe );
auto r = CalamaresUtils::System::instance()->targetEnvCommand(
{ "dd", "bs=512", "count=4", "if=/dev/urandom", QString( "of=%1" ).arg( keyfile ) } );
if ( r.getExitCode() != 0 )
{
cWarning() << "Could not create LUKS keyfile:" << r.getOutput() << "(exit code" << r.getExitCode() << ')';
return false;
}
// Give ample time to check that the file was created correctly
r = CalamaresUtils::System::instance()->targetEnvCommand( { "ls", "-la", "/" } );
cDebug() << "In target system after creating LUKS file" << r.getOutput();
return true;
}
static bool
setupLuks( const LuksDevice& d )
{
auto r = CalamaresUtils::System::instance()->targetEnvCommand(
{ "cryptsetup", "luksAddKey", d.device, keyfile }, QString(), d.passphrase, 15 );
if ( r.getExitCode() != 0 )
{
cWarning() << "Could not configure LUKS keyfile on" << d.device << ':' << r.getOutput() << "(exit code"
<< r.getExitCode() << ')';
return false;
}
return true;
}
Calamares::JobResult
LuksBootKeyFileJob::exec()
{
const auto* gs = Calamares::JobQueue::instance()->globalStorage();
if ( !gs )
{
return Calamares::JobResult::internalError(
"LukeBootKeyFile", "No GlobalStorage defined.", Calamares::JobResult::InvalidConfiguration );
}
if ( !gs->contains( "partitions" ) )
{
cError() << "No GS[partitions] key.";
return Calamares::JobResult::internalError(
"LukeBootKeyFile", tr( "No partitions are defined." ), Calamares::JobResult::InvalidConfiguration );
}
LuksDeviceList s( gs->value( "partitions" ) );
if ( !s.valid )
{
cError() << "GS[partitions] is invalid";
return Calamares::JobResult::internalError(
"LukeBootKeyFile", tr( "No partitions are defined." ), Calamares::JobResult::InvalidConfiguration );
}
cDebug() << "There are" << s.devices.count() << "LUKS partitions";
if ( s.devices.count() < 1 )
{
cDebug() << Logger::SubEntry << "Nothing to do for LUKS.";
return Calamares::JobResult::ok();
}
auto it = std::partition( s.devices.begin(), s.devices.end(), []( const LuksDevice& d ) { return d.isRoot; } );
for ( const auto& d : s.devices )
{
cDebug() << Logger::SubEntry << ( d.isRoot ? "root" : "dev." ) << d.device << "passphrase?"
<< !d.passphrase.isEmpty();
}
if ( it == s.devices.begin() )
{
// Then there was no root partition
cDebug() << Logger::SubEntry << "No root partition.";
return Calamares::JobResult::ok();
}
if ( s.devices.first().passphrase.isEmpty() )
{
cDebug() << Logger::SubEntry << "No root passphrase.";
return Calamares::JobResult::error(
tr( "Encrypted rootfs setup error" ),
tr( "Root partition %1 is LUKS but no passphrase has been set." ).arg( s.devices.first().device ) );
}
if ( !generateTargetKeyfile() )
{
return Calamares::JobResult::error(
tr( "Encrypted rootfs setup error" ),
tr( "Could not create LUKS key file for root partition %1." ).arg( s.devices.first().device ) );
}
for ( const auto& d : s.devices )
{
if ( !setupLuks( d ) )
return Calamares::JobResult::error(
tr( "Encrypted rootfs setup error" ),
tr( "Could configure LUKS key file on partition %1." ).arg( d.device ) );
}
return Calamares::JobResult::ok();
}
CALAMARES_PLUGIN_FACTORY_DEFINITION( LuksBootKeyFileJobFactory, registerPlugin< LuksBootKeyFileJob >(); )

View File

@ -0,0 +1,48 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2019, Adriaan de Groot <groot@kde.org>
*
* Calamares 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.
*
* Calamares 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 Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LUKSBOOTKEYFILEJOB_H
#define LUKSBOOTKEYFILEJOB_H
#include "CppJob.h"
#include "PluginDllMacro.h"
#include "utils/PluginFactory.h"
#include <QObject>
#include <QVariantMap>
/** @brief Creates the LUKS boot key file and adds it to the cryptsetup.
*
* This job has no configuration, because it takes everything
* from the global storage settings set by others.
*/
class PLUGINDLLEXPORT LuksBootKeyFileJob : public Calamares::CppJob
{
Q_OBJECT
public:
explicit LuksBootKeyFileJob( QObject* parent = nullptr );
virtual ~LuksBootKeyFileJob() override;
QString prettyName() const override;
Calamares::JobResult exec() override;
};
CALAMARES_PLUGIN_FACTORY_DECLARATION( LuksBootKeyFileJobFactory )
#endif // LUKSBOOTKEYFILEJOB_H

View File

@ -1,103 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# === This file is part of Calamares - <https://github.com/calamares> ===
#
# Copyright 2016, Teo Mrnjavac <teo@kde.org>
# Copyright 2017, Alf Gaida <agaida@siduction.org>
# Copyright 2017, 2019, Adriaan de Groot <groot@kde.org>
#
# Calamares 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.
#
# Calamares 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 Calamares. If not, see <http://www.gnu.org/licenses/>.
import libcalamares
from libcalamares.utils import check_target_env_call
import gettext
_ = gettext.translation("calamares-python",
localedir=libcalamares.utils.gettext_path(),
languages=libcalamares.utils.gettext_languages(),
fallback=True).gettext
def pretty_name():
return _("Configuring LUKS key file.")
def run():
"""
This module sets up a file crypto_keyfile.bin on the rootfs, assuming the
rootfs is LUKS encrypted and a passphrase is provided. This file is then
included in the initramfs and used for unlocking the rootfs from a
previously unlocked GRUB2 session.
:return:
"""
partitions = libcalamares.globalstorage.value("partitions")
if not partitions:
libcalamares.utils.warning("partitions is empty, {!s}".format(partitions))
return (_("Configuration Error"),
_("No partitions are defined for <pre>{!s}</pre> to use." ).format("luksbootkey"))
luks_root_device = ""
luks_root_passphrase = ""
additional_luks_devices = []
for partition in partitions:
if partition["mountPoint"] == "/" and "luksMapperName" in partition:
luks_root_device = partition["device"]
luks_root_passphrase = partition["luksPassphrase"]
elif "luksMapperName" in partition and\
(partition["mountPoint"] or partition["fs"] == "linuxswap"):
additional_luks_devices.append((partition["device"],
partition["luksPassphrase"]))
if not luks_root_device:
return None
if not luks_root_passphrase:
libcalamares.utils.debug("No LUKS passphrase, root {!s}".format(luks_root_device))
return (
_("Encrypted rootfs setup error"),
_("Rootfs partition {!s} is LUKS but no passphrase found.").format(luks_root_device))
# Generate random keyfile
check_target_env_call(["dd",
"bs=512",
"count=4",
"if=/dev/urandom",
"of=/crypto_keyfile.bin"])
check_target_env_call(["cryptsetup",
"luksAddKey",
luks_root_device,
"/crypto_keyfile.bin"],
luks_root_passphrase,
15) # timeout 15s
for additional_device in additional_luks_devices:
check_target_env_call(["cryptsetup",
"luksAddKey",
additional_device[0],
"/crypto_keyfile.bin"],
additional_device[1],
15) # timeout 15s
check_target_env_call(["chmod",
"g-rwx,o-rwx",
"/crypto_keyfile.bin"])
return None

View File

@ -1,5 +0,0 @@
---
type: "job"
name: "luksbootkeyfile"
interface: "python"
script: "main.py"