1 /* === This file is part of Calamares - <https://calamares.io> ===
2  *
3  *   SPDX-FileCopyrightText: 2014 Kevin Kofler <kevin.kofler@chello.at>
4  *   SPDX-FileCopyrightText: 2016 Philip Müller <philm@manjaro.org>
5  *   SPDX-FileCopyrightText: 2017 Alf Gaida <agaida@siduction.org>
6  *   SPDX-FileCopyrightText: 2019-2020 Adriaan de Groot <groot@kde.org>
7  *   SPDX-License-Identifier: GPL-3.0-or-later
8  *
9  *   Calamares is Free Software: see the License-Identifier above.
10  *
11  */
12 
13 #include "Workers.h"
14 
15 #include "utils/CalamaresUtilsSystem.h"
16 #include "utils/Entropy.h"
17 #include "utils/Logger.h"
18 
19 #include <QFile>
20 
21 /// @brief Returns a recommended size for the entropy pool (in bytes)
22 STATICTEST int
getUrandomPoolSize()23 getUrandomPoolSize()
24 {
25     QFile f( "/proc/sys/kernel/random/poolsize" );
26     constexpr const int minimumPoolSize = 512;
27     int poolSize = minimumPoolSize;
28 
29     if ( f.exists() && f.open( QIODevice::ReadOnly | QIODevice::Text ) )
30     {
31         QByteArray v = f.read( 16 );
32         if ( v.length() > 2 )
33         {
34             if ( v.endsWith( '\n' ) )
35             {
36                 v.chop( 1 );
37             }
38             bool ok = false;
39             poolSize = v.toInt( &ok );
40             if ( !ok )
41             {
42                 poolSize = minimumPoolSize;
43             }
44         }
45     }
46     return ( poolSize >= minimumPoolSize ) ? poolSize : minimumPoolSize;
47 }
48 
49 namespace MachineId
50 {
51 
52 static inline bool
isAbsolutePath(const QString & fileName)53 isAbsolutePath( const QString& fileName )
54 {
55     return fileName.startsWith( '/' );
56 }
57 
58 Calamares::JobResult
copyFile(const QString & rootMountPoint,const QString & fileName)59 copyFile( const QString& rootMountPoint, const QString& fileName )
60 {
61     if ( !isAbsolutePath( fileName ) )
62     {
63         return Calamares::JobResult::internalError(
64             QObject::tr( "File not found" ),
65             QObject::tr( "Path <pre>%1</pre> must be an absolute path." ).arg( fileName ),
66             0 );
67     }
68 
69     QFile f( fileName );
70     if ( !f.exists() )
71     {
72         return Calamares::JobResult::error( QObject::tr( "File not found" ), fileName );
73     }
74     if ( !f.copy( rootMountPoint + fileName ) )
75     {
76         return Calamares::JobResult::error( QObject::tr( "File not found" ), rootMountPoint + fileName );
77     }
78     return Calamares::JobResult::ok();
79 }
80 
81 Calamares::JobResult
createNewEntropy(int poolSize,const QString & rootMountPoint,const QString & fileName)82 createNewEntropy( int poolSize, const QString& rootMountPoint, const QString& fileName )
83 {
84     QFile entropyFile( rootMountPoint + fileName );
85     if ( entropyFile.exists() )
86     {
87         cWarning() << "Entropy file" << ( rootMountPoint + fileName ) << "already exists.";
88         return Calamares::JobResult::ok();  // .. anyway
89     }
90     if ( !entropyFile.open( QIODevice::WriteOnly ) )
91     {
92         return Calamares::JobResult::error(
93             QObject::tr( "File not found" ),
94             QObject::tr( "Could not create new random file <pre>%1</pre>." ).arg( fileName ) );
95     }
96 
97     QByteArray data;
98     CalamaresUtils::EntropySource source = CalamaresUtils::getEntropy( poolSize, data );
99     entropyFile.write( data );
100     entropyFile.close();
101     if ( entropyFile.size() < data.length() )
102     {
103         cWarning() << "Entropy file is" << entropyFile.size() << "bytes, random data was" << data.length();
104     }
105     if ( data.length() < poolSize )
106     {
107         cWarning() << "Entropy data is" << data.length() << "bytes, rather than poolSize" << poolSize;
108     }
109     if ( source != CalamaresUtils::EntropySource::URandom )
110     {
111         cWarning() << "Entropy data for pool is low-quality.";
112     }
113     return Calamares::JobResult::ok();
114 }
115 
116 
117 Calamares::JobResult
createEntropy(const EntropyGeneration kind,const QString & rootMountPoint,const QString & fileName)118 createEntropy( const EntropyGeneration kind, const QString& rootMountPoint, const QString& fileName )
119 {
120     if ( kind == EntropyGeneration::CopyFromHost )
121     {
122         if ( QFile::exists( fileName ) )
123         {
124             auto r = copyFile( rootMountPoint, fileName );
125             if ( r )
126             {
127                 return r;
128             }
129             else
130             {
131                 cWarning() << "Could not copy" << fileName << "for entropy, generating new.";
132             }
133         }
134         else
135         {
136             cWarning() << "Host system entropy does not exist at" << fileName;
137         }
138     }
139 
140     int poolSize = getUrandomPoolSize();
141     return createNewEntropy( poolSize, rootMountPoint, fileName );
142 }
143 
144 static Calamares::JobResult
runCmd(const QStringList & cmd)145 runCmd( const QStringList& cmd )
146 {
147     auto r = CalamaresUtils::System::instance()->targetEnvCommand( cmd );
148     if ( r.getExitCode() )
149     {
150         return r.explainProcess( cmd, std::chrono::seconds( 0 ) );
151     }
152 
153     return Calamares::JobResult::ok();
154 }
155 
156 Calamares::JobResult
createSystemdMachineId(const QString & rootMountPoint,const QString & fileName)157 createSystemdMachineId( const QString& rootMountPoint, const QString& fileName )
158 {
159     Q_UNUSED( rootMountPoint )
160     Q_UNUSED( fileName )
161     return runCmd( QStringList { QStringLiteral( "systemd-machine-id-setup" ) } );
162 }
163 
164 Calamares::JobResult
createDBusMachineId(const QString & rootMountPoint,const QString & fileName)165 createDBusMachineId( const QString& rootMountPoint, const QString& fileName )
166 {
167     Q_UNUSED( rootMountPoint )
168     Q_UNUSED( fileName )
169     return runCmd( QStringList { QStringLiteral( "dbus-uuidgen" ), QStringLiteral( "--ensure" ) } );
170 }
171 
172 Calamares::JobResult
createDBusLink(const QString & rootMountPoint,const QString & fileName,const QString & systemdFileName)173 createDBusLink( const QString& rootMountPoint, const QString& fileName, const QString& systemdFileName )
174 {
175     Q_UNUSED( rootMountPoint )
176     return runCmd( QStringList { QStringLiteral( "ln" ), QStringLiteral( "-sf" ), systemdFileName, fileName } );
177 }
178 
179 }  // namespace MachineId
180