2017-12-20 14:39:09 +01:00
|
|
|
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
2014-07-31 14:53:46 +02:00
|
|
|
*
|
2020-06-22 12:47:45 +02:00
|
|
|
* SPDX-FileCopyrightText: 2014-2016 Teo Mrnjavac <teo@kde.org>
|
|
|
|
* SPDX-FileCopyrightText: 2018 Adriaan de Groot <groot@kde.org>
|
|
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
* License-Filename: LICENSE
|
2014-07-31 14:53:46 +02:00
|
|
|
*/
|
|
|
|
|
2020-03-10 02:45:40 +01:00
|
|
|
#include "CreateUserJob.h"
|
2014-07-31 14:53:46 +02:00
|
|
|
|
|
|
|
#include "GlobalStorage.h"
|
2019-10-21 17:21:33 +02:00
|
|
|
#include "JobQueue.h"
|
2014-07-31 14:53:46 +02:00
|
|
|
#include "utils/CalamaresUtilsSystem.h"
|
2019-10-21 17:21:33 +02:00
|
|
|
#include "utils/Logger.h"
|
2014-07-31 14:53:46 +02:00
|
|
|
|
2016-07-15 17:48:29 +02:00
|
|
|
#include <QDateTime>
|
2014-07-31 14:53:46 +02:00
|
|
|
#include <QDir>
|
|
|
|
#include <QFile>
|
|
|
|
#include <QFileInfo>
|
|
|
|
#include <QProcess>
|
|
|
|
#include <QTextStream>
|
|
|
|
|
|
|
|
|
2014-10-08 15:05:23 +02:00
|
|
|
CreateUserJob::CreateUserJob( const QString& userName,
|
|
|
|
const QString& fullName,
|
|
|
|
bool autologin,
|
|
|
|
const QStringList& defaultGroups )
|
2014-07-31 14:53:46 +02:00
|
|
|
: Calamares::Job()
|
|
|
|
, m_userName( userName )
|
|
|
|
, m_fullName( fullName )
|
|
|
|
, m_autologin( autologin )
|
2014-10-08 15:05:23 +02:00
|
|
|
, m_defaultGroups( defaultGroups )
|
2014-07-31 14:53:46 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QString
|
|
|
|
CreateUserJob::prettyName() const
|
|
|
|
{
|
|
|
|
return tr( "Create user %1" ).arg( m_userName );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-06-13 02:22:03 +02:00
|
|
|
QString
|
|
|
|
CreateUserJob::prettyDescription() const
|
|
|
|
{
|
|
|
|
return tr( "Create user <strong>%1</strong>." ).arg( m_userName );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QString
|
|
|
|
CreateUserJob::prettyStatusMessage() const
|
|
|
|
{
|
|
|
|
return tr( "Creating user %1." ).arg( m_userName );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-07-31 14:53:46 +02:00
|
|
|
Calamares::JobResult
|
|
|
|
CreateUserJob::exec()
|
|
|
|
{
|
|
|
|
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
|
|
|
|
QDir destDir( gs->value( "rootMountPoint" ).toString() );
|
|
|
|
|
2019-10-21 17:21:33 +02:00
|
|
|
if ( gs->contains( "sudoersGroup" ) && !gs->value( "sudoersGroup" ).toString().isEmpty() )
|
2014-10-08 15:35:27 +02:00
|
|
|
{
|
2019-11-08 11:38:39 +01:00
|
|
|
cDebug() << "[CREATEUSER]: preparing sudoers";
|
|
|
|
|
2014-10-08 15:35:27 +02:00
|
|
|
QFileInfo sudoersFi( destDir.absoluteFilePath( "etc/sudoers.d/10-installer" ) );
|
2014-07-31 14:53:46 +02:00
|
|
|
|
2014-10-08 15:35:27 +02:00
|
|
|
if ( !sudoersFi.absoluteDir().exists() )
|
2019-10-21 17:21:33 +02:00
|
|
|
{
|
2014-10-08 15:35:27 +02:00
|
|
|
return Calamares::JobResult::error( tr( "Sudoers dir is not writable." ) );
|
2019-10-21 17:21:33 +02:00
|
|
|
}
|
2014-07-31 14:53:46 +02:00
|
|
|
|
2014-10-08 15:35:27 +02:00
|
|
|
QFile sudoersFile( sudoersFi.absoluteFilePath() );
|
2019-10-21 17:21:33 +02:00
|
|
|
if ( !sudoersFile.open( QIODevice::WriteOnly | QIODevice::Text ) )
|
|
|
|
{
|
2014-10-08 15:35:27 +02:00
|
|
|
return Calamares::JobResult::error( tr( "Cannot create sudoers file for writing." ) );
|
2019-10-21 17:21:33 +02:00
|
|
|
}
|
2014-07-31 14:53:46 +02:00
|
|
|
|
2014-10-08 15:35:27 +02:00
|
|
|
QString sudoersGroup = gs->value( "sudoersGroup" ).toString();
|
|
|
|
|
|
|
|
QTextStream sudoersOut( &sudoersFile );
|
|
|
|
sudoersOut << QString( "%%1 ALL=(ALL) ALL\n" ).arg( sudoersGroup );
|
|
|
|
|
|
|
|
if ( QProcess::execute( "chmod", { "440", sudoersFi.absoluteFilePath() } ) )
|
|
|
|
return Calamares::JobResult::error( tr( "Cannot chmod sudoers file." ) );
|
|
|
|
}
|
2014-07-31 14:53:46 +02:00
|
|
|
|
2019-11-08 11:38:39 +01:00
|
|
|
cDebug() << "[CREATEUSER]: preparing groups";
|
|
|
|
|
2014-10-08 15:05:23 +02:00
|
|
|
QFileInfo groupsFi( destDir.absoluteFilePath( "etc/group" ) );
|
|
|
|
QFile groupsFile( groupsFi.absoluteFilePath() );
|
|
|
|
if ( !groupsFile.open( QIODevice::ReadOnly | QIODevice::Text ) )
|
2019-10-21 17:21:33 +02:00
|
|
|
{
|
2014-10-08 15:05:23 +02:00
|
|
|
return Calamares::JobResult::error( tr( "Cannot open groups file for reading." ) );
|
2019-10-21 17:21:33 +02:00
|
|
|
}
|
2014-10-08 15:05:23 +02:00
|
|
|
QString groupsData = QString::fromLocal8Bit( groupsFile.readAll() );
|
|
|
|
QStringList groupsLines = groupsData.split( '\n' );
|
2019-10-21 17:21:33 +02:00
|
|
|
for ( QStringList::iterator it = groupsLines.begin(); it != groupsLines.end(); ++it )
|
2014-10-08 15:05:23 +02:00
|
|
|
{
|
|
|
|
int indexOfFirstToDrop = it->indexOf( ':' );
|
|
|
|
it->truncate( indexOfFirstToDrop );
|
|
|
|
}
|
|
|
|
|
2020-06-22 12:47:45 +02:00
|
|
|
for ( const QString& group : m_defaultGroups )
|
|
|
|
{
|
2014-10-08 15:05:23 +02:00
|
|
|
if ( !groupsLines.contains( group ) )
|
2020-06-22 12:47:45 +02:00
|
|
|
{
|
2019-10-21 17:21:33 +02:00
|
|
|
CalamaresUtils::System::instance()->targetEnvCall( { "groupadd", group } );
|
2020-06-22 12:47:45 +02:00
|
|
|
}
|
|
|
|
}
|
2014-07-31 14:53:46 +02:00
|
|
|
|
2014-10-08 15:05:23 +02:00
|
|
|
QString defaultGroups = m_defaultGroups.join( ',' );
|
2014-07-31 14:53:46 +02:00
|
|
|
if ( m_autologin )
|
|
|
|
{
|
2014-10-08 15:05:23 +02:00
|
|
|
QString autologinGroup;
|
2019-10-21 17:21:33 +02:00
|
|
|
if ( gs->contains( "autologinGroup" ) && !gs->value( "autologinGroup" ).toString().isEmpty() )
|
2017-09-13 21:44:15 +02:00
|
|
|
{
|
2014-10-08 15:05:23 +02:00
|
|
|
autologinGroup = gs->value( "autologinGroup" ).toString();
|
2017-09-13 21:44:15 +02:00
|
|
|
CalamaresUtils::System::instance()->targetEnvCall( { "groupadd", autologinGroup } );
|
|
|
|
defaultGroups.append( QString( ",%1" ).arg( autologinGroup ) );
|
|
|
|
}
|
2014-07-31 14:53:46 +02:00
|
|
|
}
|
|
|
|
|
2016-07-15 17:48:29 +02:00
|
|
|
// If we're looking to reuse the contents of an existing /home
|
|
|
|
if ( gs->value( "reuseHome" ).toBool() )
|
|
|
|
{
|
|
|
|
QString shellFriendlyHome = "/home/" + m_userName;
|
|
|
|
QDir existingHome( destDir.absolutePath() + shellFriendlyHome );
|
|
|
|
if ( existingHome.exists() )
|
|
|
|
{
|
2019-10-21 17:21:33 +02:00
|
|
|
QString backupDirName = "dotfiles_backup_" + QDateTime::currentDateTime().toString( "yyyy-MM-dd_HH-mm-ss" );
|
2016-07-15 17:48:29 +02:00
|
|
|
existingHome.mkdir( backupDirName );
|
|
|
|
|
2019-10-21 17:21:33 +02:00
|
|
|
CalamaresUtils::System::instance()->targetEnvCall(
|
|
|
|
{ "sh", "-c", "mv -f " + shellFriendlyHome + "/.* " + shellFriendlyHome + "/" + backupDirName } );
|
2016-07-15 17:48:29 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-08 11:38:39 +01:00
|
|
|
cDebug() << "[CREATEUSER]: creating user";
|
|
|
|
|
2019-10-21 17:21:33 +02:00
|
|
|
QStringList useradd { "useradd", "-m", "-U" };
|
2018-05-23 11:23:46 +02:00
|
|
|
QString shell = gs->value( "userShell" ).toString();
|
|
|
|
if ( !shell.isEmpty() )
|
2019-10-21 17:21:33 +02:00
|
|
|
{
|
2018-05-23 11:23:46 +02:00
|
|
|
useradd << "-s" << shell;
|
2019-10-21 17:21:33 +02:00
|
|
|
}
|
2018-05-22 17:45:39 +02:00
|
|
|
useradd << "-c" << m_fullName;
|
|
|
|
useradd << m_userName;
|
|
|
|
|
2019-02-21 12:40:49 +01:00
|
|
|
auto commandResult = CalamaresUtils::System::instance()->targetEnvCommand( useradd );
|
|
|
|
if ( commandResult.getExitCode() )
|
2018-05-23 13:03:59 +02:00
|
|
|
{
|
2019-02-21 12:40:49 +01:00
|
|
|
cError() << "useradd failed" << commandResult.getExitCode();
|
2019-08-01 22:59:06 +02:00
|
|
|
return commandResult.explainProcess( useradd, std::chrono::seconds( 10 ) /* bogus timeout */ );
|
2018-05-23 13:03:59 +02:00
|
|
|
}
|
2014-07-31 14:53:46 +02:00
|
|
|
|
2019-10-21 17:21:33 +02:00
|
|
|
commandResult
|
|
|
|
= CalamaresUtils::System::instance()->targetEnvCommand( { "usermod", "-aG", defaultGroups, m_userName } );
|
2019-02-21 12:40:49 +01:00
|
|
|
if ( commandResult.getExitCode() )
|
2018-05-23 14:11:49 +02:00
|
|
|
{
|
2019-02-21 12:40:49 +01:00
|
|
|
cError() << "usermod failed" << commandResult.getExitCode();
|
2019-08-01 22:59:06 +02:00
|
|
|
return commandResult.explainProcess( "usermod", std::chrono::seconds( 10 ) /* bogus timeout */ );
|
2018-05-23 14:11:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QString userGroup = QString( "%1:%2" ).arg( m_userName ).arg( m_userName );
|
|
|
|
QString homeDir = QString( "/home/%1" ).arg( m_userName );
|
2019-10-21 17:21:33 +02:00
|
|
|
commandResult = CalamaresUtils::System::instance()->targetEnvCommand( { "chown", "-R", userGroup, homeDir } );
|
2019-02-21 12:40:49 +01:00
|
|
|
if ( commandResult.getExitCode() )
|
2018-05-23 14:11:49 +02:00
|
|
|
{
|
2019-02-21 12:40:49 +01:00
|
|
|
cError() << "chown failed" << commandResult.getExitCode();
|
2019-08-01 22:59:06 +02:00
|
|
|
return commandResult.explainProcess( "chown", std::chrono::seconds( 10 ) /* bogus timeout */ );
|
2018-05-23 14:11:49 +02:00
|
|
|
}
|
2014-07-31 14:53:46 +02:00
|
|
|
|
|
|
|
return Calamares::JobResult::ok();
|
|
|
|
}
|