2020-10-21 14:43:45 +02:00
|
|
|
/* === This file is part of Calamares - <https://calamares.io> ===
|
|
|
|
*
|
|
|
|
* SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac <teo@kde.org>
|
|
|
|
* SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org>
|
|
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
*
|
|
|
|
* Calamares is Free Software: see the License-Identifier above.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "MiscJobs.h"
|
|
|
|
|
|
|
|
#include "Config.h"
|
|
|
|
|
2020-10-22 13:49:45 +02:00
|
|
|
#include "GlobalStorage.h"
|
|
|
|
#include "JobQueue.h"
|
2020-10-21 14:43:45 +02:00
|
|
|
#include "utils/CalamaresUtilsSystem.h"
|
|
|
|
#include "utils/Logger.h"
|
|
|
|
#include "utils/Permissions.h"
|
|
|
|
|
2020-10-22 13:49:45 +02:00
|
|
|
#include <QDir>
|
|
|
|
#include <QFile>
|
|
|
|
#include <QFileInfo>
|
|
|
|
|
2022-02-21 15:49:10 +01:00
|
|
|
SetupSudoJob::SetupSudoJob( const QString& group, Config::SudoStyle style )
|
2020-10-21 14:43:45 +02:00
|
|
|
: m_sudoGroup( group )
|
2022-02-21 15:49:10 +01:00
|
|
|
, m_sudoStyle( style )
|
2020-10-21 14:43:45 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
QString
|
|
|
|
SetupSudoJob::prettyName() const
|
|
|
|
{
|
|
|
|
return tr( "Configure <pre>sudo</pre> users." );
|
|
|
|
}
|
|
|
|
|
2022-02-21 15:49:10 +01:00
|
|
|
static QString
|
|
|
|
designatorForStyle( Config::SudoStyle style )
|
|
|
|
{
|
|
|
|
switch ( style )
|
|
|
|
{
|
|
|
|
case Config::SudoStyle::UserOnly:
|
|
|
|
return QStringLiteral( "(ALL)" );
|
|
|
|
case Config::SudoStyle::UserAndGroup:
|
|
|
|
return QStringLiteral( "(ALL:ALL)" );
|
|
|
|
}
|
|
|
|
__builtin_unreachable();
|
|
|
|
}
|
|
|
|
|
2020-10-21 14:43:45 +02:00
|
|
|
Calamares::JobResult
|
|
|
|
SetupSudoJob::exec()
|
|
|
|
{
|
|
|
|
if ( m_sudoGroup.isEmpty() )
|
|
|
|
{
|
2020-11-06 14:38:12 +01:00
|
|
|
cDebug() << "Skipping sudo 10-installer because the sudoGroup is empty.";
|
2020-10-21 14:43:45 +02:00
|
|
|
return Calamares::JobResult::ok();
|
|
|
|
}
|
|
|
|
|
2022-02-21 15:49:10 +01:00
|
|
|
// One % for the sudo format, keep it outside of the string to avoid accidental replacement
|
|
|
|
QString sudoersLine
|
|
|
|
= QChar( '%' ) + QString( "%1 ALL=%2 ALL\n" ).arg( m_sudoGroup, designatorForStyle( m_sudoStyle ) );
|
2020-10-21 14:43:45 +02:00
|
|
|
auto fileResult
|
|
|
|
= CalamaresUtils::System::instance()->createTargetFile( QStringLiteral( "/etc/sudoers.d/10-installer" ),
|
|
|
|
sudoersLine.toUtf8().constData(),
|
|
|
|
CalamaresUtils::System::WriteMode::Overwrite );
|
|
|
|
|
|
|
|
if ( fileResult )
|
|
|
|
{
|
|
|
|
if ( !CalamaresUtils::Permissions::apply( fileResult.path(), 0440 ) )
|
|
|
|
{
|
|
|
|
return Calamares::JobResult::error( tr( "Cannot chmod sudoers file." ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return Calamares::JobResult::error( tr( "Cannot create sudoers file for writing." ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
return Calamares::JobResult::ok();
|
|
|
|
}
|
2020-10-22 13:49:45 +02:00
|
|
|
|
|
|
|
STATICTEST QStringList
|
|
|
|
groupsInTargetSystem()
|
|
|
|
{
|
|
|
|
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
|
2020-10-23 12:19:28 +02:00
|
|
|
if ( !gs )
|
|
|
|
{
|
|
|
|
return QStringList();
|
|
|
|
}
|
2020-10-22 13:49:45 +02:00
|
|
|
QDir targetRoot( gs->value( "rootMountPoint" ).toString() );
|
|
|
|
|
|
|
|
QFileInfo groupsFi( targetRoot.absoluteFilePath( "etc/group" ) );
|
|
|
|
QFile groupsFile( groupsFi.absoluteFilePath() );
|
|
|
|
if ( !groupsFile.open( QIODevice::ReadOnly | QIODevice::Text ) )
|
|
|
|
{
|
|
|
|
return QStringList();
|
|
|
|
}
|
|
|
|
QString groupsData = QString::fromLocal8Bit( groupsFile.readAll() );
|
|
|
|
QStringList groupsLines = groupsData.split( '\n' );
|
|
|
|
QStringList::iterator it = groupsLines.begin();
|
|
|
|
while ( it != groupsLines.end() )
|
|
|
|
{
|
|
|
|
if ( it->startsWith( '#' ) )
|
|
|
|
{
|
|
|
|
it = groupsLines.erase( it );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
int indexOfFirstToDrop = it->indexOf( ':' );
|
|
|
|
if ( indexOfFirstToDrop < 1 )
|
|
|
|
{
|
|
|
|
it = groupsLines.erase( it );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
it->truncate( indexOfFirstToDrop );
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
return groupsLines;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @brief Create groups in target system as needed
|
|
|
|
*
|
|
|
|
* Given a list of groups that already exist, @p availableGroups,
|
|
|
|
* go through the @p wantedGroups and create each of them. Groups that
|
|
|
|
* fail, or which should have already been there, are added to
|
|
|
|
* @p missingGroups by name.
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
ensureGroupsExistInTarget( const QList< GroupDescription >& wantedGroups,
|
|
|
|
const QStringList& availableGroups,
|
|
|
|
QStringList& missingGroups )
|
|
|
|
{
|
|
|
|
int failureCount = 0;
|
|
|
|
|
|
|
|
for ( const auto& group : wantedGroups )
|
|
|
|
{
|
|
|
|
if ( group.isValid() && !availableGroups.contains( group.name() ) )
|
|
|
|
{
|
|
|
|
if ( group.mustAlreadyExist() )
|
|
|
|
{
|
|
|
|
// Should have been there already: don't create it
|
|
|
|
missingGroups.append( group.name() );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-10-22 14:07:40 +02:00
|
|
|
QStringList cmd;
|
2020-10-22 13:49:45 +02:00
|
|
|
#ifdef __FreeBSD__
|
2020-10-22 14:07:40 +02:00
|
|
|
if ( group.isSystemGroup() )
|
|
|
|
{
|
|
|
|
cWarning() << "Ignoring must-be-a-system group for" << group.name() << "on FreeBSD";
|
|
|
|
}
|
|
|
|
cmd = QStringList { "pw", "groupadd", "-n", group.name() };
|
2020-10-22 13:49:45 +02:00
|
|
|
#else
|
2020-10-22 14:07:40 +02:00
|
|
|
cmd << QStringLiteral( "groupadd" );
|
|
|
|
if ( group.isSystemGroup() )
|
|
|
|
{
|
|
|
|
cmd << "--system";
|
|
|
|
}
|
|
|
|
cmd << group.name();
|
2020-10-22 13:49:45 +02:00
|
|
|
#endif
|
2020-10-22 14:07:40 +02:00
|
|
|
if ( CalamaresUtils::System::instance()->targetEnvCall( cmd ) )
|
2020-10-22 13:49:45 +02:00
|
|
|
{
|
|
|
|
failureCount++;
|
|
|
|
missingGroups.append( group.name() + QChar( '*' ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( !missingGroups.isEmpty() )
|
|
|
|
{
|
|
|
|
cWarning() << "Missing groups in target system (* for groupadd failure):" << Logger::DebugList( missingGroups );
|
|
|
|
}
|
|
|
|
return failureCount == 0;
|
|
|
|
}
|
|
|
|
|
2020-10-22 14:11:01 +02:00
|
|
|
SetupGroupsJob::SetupGroupsJob( const Config* config )
|
|
|
|
: m_config( config )
|
2020-10-22 13:49:45 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
QString
|
|
|
|
SetupGroupsJob::prettyName() const
|
|
|
|
{
|
|
|
|
return tr( "Preparing groups." );
|
|
|
|
}
|
|
|
|
|
|
|
|
Calamares::JobResult
|
|
|
|
SetupGroupsJob::exec()
|
|
|
|
{
|
|
|
|
const auto& defaultGroups = m_config->defaultGroups();
|
|
|
|
QStringList availableGroups = groupsInTargetSystem();
|
|
|
|
QStringList missingGroups;
|
|
|
|
|
|
|
|
if ( !ensureGroupsExistInTarget( defaultGroups, availableGroups, missingGroups ) )
|
|
|
|
{
|
|
|
|
return Calamares::JobResult::error( tr( "Could not create groups in target system" ) );
|
|
|
|
}
|
|
|
|
if ( !missingGroups.isEmpty() )
|
|
|
|
{
|
|
|
|
return Calamares::JobResult::error(
|
|
|
|
tr( "Could not create groups in target system" ),
|
|
|
|
tr( "These groups are missing in the target system: %1" ).arg( missingGroups.join( ',' ) ) );
|
|
|
|
}
|
|
|
|
|
2021-03-15 00:21:26 +01:00
|
|
|
if ( m_config->doAutoLogin() && !m_config->autoLoginGroup().isEmpty() )
|
2020-10-22 13:49:45 +02:00
|
|
|
{
|
2021-03-15 00:21:26 +01:00
|
|
|
const QString autoLoginGroup = m_config->autoLoginGroup();
|
2020-10-22 13:49:45 +02:00
|
|
|
(void)ensureGroupsExistInTarget(
|
2021-03-15 00:21:26 +01:00
|
|
|
QList< GroupDescription >() << GroupDescription( autoLoginGroup ), availableGroups, missingGroups );
|
2020-10-22 13:49:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return Calamares::JobResult::ok();
|
|
|
|
}
|