summaryrefslogtreecommitdiff
path: root/raveos-calamares-module/raveusers/RaveUsersJobs.cpp
diff options
context:
space:
mode:
authorNippy <nippy@Nippy-Mac-mini.local>2026-09-19 18:04:27 +0200
committerNippy <nippy@Nippy-Mac-mini.local>2026-09-19 18:04:27 +0200
commit3eb87a14e133b266ab8d8c634dda3af312474f1f (patch)
tree098ea50e2f159b654f3729c69facc6805556813e /raveos-calamares-module/raveusers/RaveUsersJobs.cpp
parentf176110ce0e65756967db40ba2a3fc7d1daa2825 (diff)
downloadRaveOS-PKGBUILD-3eb87a14e133b266ab8d8c634dda3af312474f1f.tar.gz
RaveOS-PKGBUILD-3eb87a14e133b266ab8d8c634dda3af312474f1f.zip
new user settings
Diffstat (limited to 'raveos-calamares-module/raveusers/RaveUsersJobs.cpp')
-rw-r--r--raveos-calamares-module/raveusers/RaveUsersJobs.cpp294
1 files changed, 294 insertions, 0 deletions
diff --git a/raveos-calamares-module/raveusers/RaveUsersJobs.cpp b/raveos-calamares-module/raveusers/RaveUsersJobs.cpp
new file mode 100644
index 0000000..1923c38
--- /dev/null
+++ b/raveos-calamares-module/raveusers/RaveUsersJobs.cpp
@@ -0,0 +1,294 @@
+#include "RaveUsersJobs.h"
+
+#include "RaveUsersBackend.h"
+
+#include "GlobalStorage.h"
+#include "JobQueue.h"
+#include "utils/Logger.h"
+#include "utils/Permissions.h"
+#include "utils/System.h"
+
+#include <QDir>
+#include <QFile>
+#include <QRandomGenerator>
+#include <QSet>
+
+#include <crypt.h>
+
+using WriteMode = Calamares::System::WriteMode;
+
+static QDir
+targetRootDir()
+{
+ Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
+ return QDir( gs->value( "rootMountPoint" ).toString() );
+}
+
+RaveUsersCreateUserJob::RaveUsersCreateUserJob( const RaveUsersBackend* backend )
+ : m_backend( backend )
+{
+}
+
+QString
+RaveUsersCreateUserJob::prettyName() const
+{
+ return tr( "Create user %1" ).arg( m_backend->username() );
+}
+
+QString
+RaveUsersCreateUserJob::prettyStatusMessage() const
+{
+ return tr( "Creating user %1…", "@status" ).arg( m_backend->username() );
+}
+
+Calamares::JobResult
+RaveUsersCreateUserJob::exec()
+{
+ const QString login = m_backend->username();
+
+ QStringList useraddCommand { "useradd", "-m", "-U" };
+ const QString shell = m_backend->userShell();
+ if ( !shell.isEmpty() )
+ {
+ useraddCommand << "-s" << shell;
+ }
+
+ useraddCommand << "-c" << login;
+ if ( m_backend->homeUMask() >= 0 )
+ {
+ useraddCommand << "-K" << QStringLiteral( "UMASK=%1" ).arg( m_backend->homeUMask(), 3, 8, QChar( '0' ) );
+ }
+ useraddCommand << login;
+
+ auto result = Calamares::System::instance()->targetEnvCommand( useraddCommand );
+ if ( result.getExitCode() )
+ {
+ cError() << "useradd failed" << result.getExitCode();
+ return result.explainProcess( useraddCommand, std::chrono::seconds( 10 ) );
+ }
+
+ const QStringList groups = m_backend->groupsForThisUser();
+ if ( !groups.isEmpty() )
+ {
+ QStringList usermodCommand { "usermod", "-aG", groups.join( ',' ), login };
+ result = Calamares::System::instance()->targetEnvCommand( usermodCommand );
+ if ( result.getExitCode() )
+ {
+ cError() << "usermod failed" << result.getExitCode();
+ return result.explainProcess( usermodCommand, std::chrono::seconds( 10 ) );
+ }
+ }
+
+ const QString userGroup = QStringLiteral( "%1:%2" ).arg( login, login );
+ const QString homeDir = QStringLiteral( "/home/%1" ).arg( login );
+ result = Calamares::System::instance()->targetEnvCommand( { "chown", "-R", userGroup, homeDir } );
+ if ( result.getExitCode() )
+ {
+ cError() << "chown failed" << result.getExitCode();
+ return result.explainProcess( "chown", std::chrono::seconds( 10 ) );
+ }
+
+ return Calamares::JobResult::ok();
+}
+
+RaveUsersSetPasswordJob::RaveUsersSetPasswordJob( const QString& userName, const QString& password )
+ : m_userName( userName )
+ , m_password( password )
+{
+}
+
+QString
+RaveUsersSetPasswordJob::prettyName() const
+{
+ return tr( "Set password for user %1" ).arg( m_userName );
+}
+
+QString
+RaveUsersSetPasswordJob::prettyStatusMessage() const
+{
+ return tr( "Setting password for user %1…", "@status" ).arg( m_userName );
+}
+
+static QString
+makeSha512Salt( int length = 16 )
+{
+ static const QString chars = QStringLiteral( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./" );
+ QString salt;
+ salt.reserve( length );
+ for ( int i = 0; i < length; ++i )
+ {
+ salt += chars.at( QRandomGenerator::global()->bounded( chars.size() ) );
+ }
+ return QStringLiteral( "$6$" ) + salt + QLatin1Char( '$' );
+}
+
+Calamares::JobResult
+RaveUsersSetPasswordJob::exec()
+{
+ QDir destDir = targetRootDir();
+ if ( !destDir.exists() )
+ {
+ return Calamares::JobResult::error( tr( "Bad destination system path." ),
+ tr( "rootMountPoint is %1" ).arg( destDir.absolutePath() ) );
+ }
+
+ if ( m_userName == QLatin1String( "root" ) && m_password.isEmpty() )
+ {
+ int ec = Calamares::System::instance()->targetEnvCall( { "usermod", "-p", "!", m_userName } );
+ if ( ec )
+ {
+ return Calamares::JobResult::error( tr( "Cannot disable root account." ),
+ tr( "usermod terminated with error code %1." ).arg( ec ) );
+ }
+ return Calamares::JobResult::ok();
+ }
+
+ const QString salt = makeSha512Salt();
+ const QByteArray hash = crypt( m_password.toUtf8().constData(), salt.toUtf8().constData() );
+ if ( hash.isEmpty() )
+ {
+ return Calamares::JobResult::error( tr( "Cannot hash password." ) );
+ }
+
+ int ec = Calamares::System::instance()->targetEnvCall(
+ { "usermod", "-p", QString::fromLatin1( hash ), m_userName } );
+ if ( ec )
+ {
+ return Calamares::JobResult::error( tr( "Cannot set password for user %1." ).arg( m_userName ),
+ tr( "usermod terminated with error code %1." ).arg( ec ) );
+ }
+
+ return Calamares::JobResult::ok();
+}
+
+RaveUsersSetHostnameJob::RaveUsersSetHostnameJob( const QString& hostname )
+ : m_hostname( hostname )
+{
+}
+
+QString
+RaveUsersSetHostnameJob::prettyName() const
+{
+ return tr( "Set hostname %1" ).arg( m_hostname );
+}
+
+Calamares::JobResult
+RaveUsersSetHostnameJob::exec()
+{
+ if ( !Calamares::System::instance()->createTargetFile( QStringLiteral( "/etc/hostname" ),
+ ( m_hostname + '\n' ).toUtf8(),
+ WriteMode::Overwrite ) )
+ {
+ return Calamares::JobResult::error( tr( "Cannot write hostname to target system" ) );
+ }
+
+ const QString hosts = QStringLiteral( R"(# Standard host addresses
+127.0.0.1 localhost
+::1 localhost ip6-localhost ip6-loopback
+ff02::1 ip6-allnodes
+ff02::2 ip6-allrouters
+# This host address
+127.0.1.1 %1
+)" )
+ .arg( m_hostname );
+
+ if ( !Calamares::System::instance()->createTargetFile(
+ QStringLiteral( "/etc/hosts" ), hosts.toUtf8(), WriteMode::Overwrite ) )
+ {
+ return Calamares::JobResult::error( tr( "Cannot write hosts file to target system" ) );
+ }
+
+ return Calamares::JobResult::ok();
+}
+
+RaveUsersSetupSudoJob::RaveUsersSetupSudoJob( const QString& group, bool configureWithGroup )
+ : m_group( group )
+ , m_configureWithGroup( configureWithGroup )
+{
+}
+
+QString
+RaveUsersSetupSudoJob::prettyName() const
+{
+ return tr( "Configuring sudo users…", "@status" );
+}
+
+Calamares::JobResult
+RaveUsersSetupSudoJob::exec()
+{
+ if ( m_group.isEmpty() )
+ {
+ return Calamares::JobResult::ok();
+ }
+
+ const QString designator = m_configureWithGroup ? QStringLiteral( "(ALL:ALL)" ) : QStringLiteral( "(ALL)" );
+ const QString line = QChar( '%' ) + QStringLiteral( "%1 ALL=%2 ALL\n" ).arg( m_group, designator );
+
+ auto fileResult = Calamares::System::instance()->createTargetFile(
+ QStringLiteral( "/etc/sudoers.d/10-installer" ), line.toUtf8().constData(), WriteMode::Overwrite );
+
+ if ( fileResult )
+ {
+ if ( !Calamares::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();
+}
+
+RaveUsersSetupGroupsJob::RaveUsersSetupGroupsJob( const QStringList& groups )
+ : m_groups( groups )
+{
+}
+
+QString
+RaveUsersSetupGroupsJob::prettyName() const
+{
+ return tr( "Preparing groups…", "@status" );
+}
+
+Calamares::JobResult
+RaveUsersSetupGroupsJob::exec()
+{
+ QDir targetRoot = targetRootDir();
+
+ QSet< QString > existing;
+ QFile groupFile( targetRoot.absoluteFilePath( "etc/group" ) );
+ if ( groupFile.open( QIODevice::ReadOnly | QIODevice::Text ) )
+ {
+ while ( !groupFile.atEnd() )
+ {
+ const QString line = QString::fromLocal8Bit( groupFile.readLine() );
+ if ( line.startsWith( '#' ) )
+ {
+ continue;
+ }
+ const int idx = line.indexOf( ':' );
+ if ( idx > 0 )
+ {
+ existing.insert( line.left( idx ) );
+ }
+ }
+ }
+
+ for ( const QString& group : m_groups )
+ {
+ if ( group.isEmpty() || existing.contains( group ) )
+ {
+ continue;
+ }
+ QStringList cmd { "groupadd", "--system", group };
+ if ( Calamares::System::instance()->targetEnvCall( cmd ) )
+ {
+ cWarning() << "groupadd failed for" << group;
+ }
+ }
+
+ return Calamares::JobResult::ok();
+}