Merge branch 'permissions'

FIXES #997
This commit is contained in:
Adriaan de Groot 2018-10-01 11:32:45 +02:00
commit d507425128
7 changed files with 225 additions and 31 deletions

View File

@ -10,6 +10,7 @@ This release contains contributions from (alphabetically by first name):
- Caio Carvalho - Caio Carvalho
- Kevin Kofler - Kevin Kofler
- Philip Mueller - Philip Mueller
- Scott Harvey
## Core ## ## Core ##
@ -25,6 +26,8 @@ There are no core changes in this version.
size is close to the required installation size). size is close to the required installation size).
* The *keyboard* module now handles the (bogus) Austrian keymap for * The *keyboard* module now handles the (bogus) Austrian keymap for
the system console properly. the system console properly.
* The *preservefiles* module now has a mechanism for setting the permissions
(and ownership) of preserved files.
* New module *fsresizer* can be used to resize filesystems. It is intended * New module *fsresizer* can be used to resize filesystems. It is intended
for use in OEM installs where an image of fixed size is created, for use in OEM installs where an image of fixed size is created,
and then sized to the actual SD card the user has used. and then sized to the actual SD card the user has used.

View File

@ -4,6 +4,7 @@ calamares_add_plugin( preservefiles
TYPE job TYPE job
EXPORT_MACRO PLUGINDLLEXPORT_PRO EXPORT_MACRO PLUGINDLLEXPORT_PRO
SOURCES SOURCES
permissions.cpp
PreserveFiles.cpp PreserveFiles.cpp
LINK_PRIVATE_LIBRARIES LINK_PRIVATE_LIBRARIES
calamares calamares

View File

@ -18,6 +18,8 @@
#include "PreserveFiles.h" #include "PreserveFiles.h"
#include "permissions.h"
#include "CalamaresVersion.h" #include "CalamaresVersion.h"
#include "JobQueue.h" #include "JobQueue.h"
#include "GlobalStorage.h" #include "GlobalStorage.h"
@ -83,6 +85,38 @@ PreserveFiles::prettyName() const
return tr( "Saving files for later ..." ); return tr( "Saving files for later ..." );
} }
static bool
copy_file( const QString& source, const QString& dest )
{
QFile sourcef( source );
if ( !sourcef.open( QFile::ReadOnly ) )
{
cWarning() << "Could not read" << source;
return false;
}
QFile destf( dest );
if ( !destf.open( QFile::WriteOnly ) )
{
sourcef.close();
cWarning() << "Could not open" << destf.fileName() << "for writing; could not copy" << source;
return false;
}
QByteArray b;
do
{
b = sourcef.read( 1_MiB );
destf.write( b );
}
while ( b.count() > 0 );
sourcef.close();
destf.close();
return true;
}
Calamares::JobResult PreserveFiles::exec() Calamares::JobResult PreserveFiles::exec()
{ {
if ( m_items.isEmpty() ) if ( m_items.isEmpty() )
@ -96,7 +130,8 @@ Calamares::JobResult PreserveFiles::exec()
for ( const auto& it : m_items ) for ( const auto& it : m_items )
{ {
QString source = it.source; QString source = it.source;
QString dest = prefix + atReplacements( it.dest ); QString bare_dest = atReplacements( it.dest );
QString dest = prefix + bare_dest;
if ( it.type == ItemType::Log ) if ( it.type == ItemType::Log )
source = Logger::logFile(); source = Logger::logFile();
@ -111,32 +146,29 @@ Calamares::JobResult PreserveFiles::exec()
cWarning() << "Skipping unnamed source file for" << dest; cWarning() << "Skipping unnamed source file for" << dest;
else else
{ {
QFile sourcef( source ); if ( copy_file( source, dest ) )
if ( !sourcef.open( QFile::ReadOnly ) )
{ {
cWarning() << "Could not read" << source; if ( it.perm.isValid() )
continue; {
auto s_p = CalamaresUtils::System::instance();
int r;
r = s_p->targetEnvCall( QStringList{ "chown", it.perm.username(), bare_dest } );
if ( r )
cWarning() << "Could not chown target" << bare_dest;
r = s_p->targetEnvCall( QStringList{ "chgrp", it.perm.group(), bare_dest } );
if ( r )
cWarning() << "Could not chgrp target" << bare_dest;
r = s_p->targetEnvCall( QStringList{ "chmod", it.perm.octal(), bare_dest } );
if ( r )
cWarning() << "Could not chmod target" << bare_dest;
}
++count;
} }
QFile destf( dest );
if ( !destf.open( QFile::WriteOnly ) )
{
sourcef.close();
cWarning() << "Could not open" << destf.fileName() << "for writing; could not copy" << source;
continue;
}
QByteArray b;
do
{
b = sourcef.read( 1_MiB );
destf.write( b );
}
while ( b.count() > 0 );
sourcef.close();
destf.close();
++count;
} }
} }
@ -160,6 +192,10 @@ void PreserveFiles::setConfigurationMap(const QVariantMap& configurationMap)
return; return;
} }
QString defaultPermissions = configurationMap[ "perm" ].toString();
if ( defaultPermissions.isEmpty() )
defaultPermissions = QStringLiteral( "root:root:0400" );
QVariantList l = files.toList(); QVariantList l = files.toList();
unsigned int c = 0; unsigned int c = 0;
for ( const auto& li : l ) for ( const auto& li : l )
@ -168,7 +204,7 @@ void PreserveFiles::setConfigurationMap(const QVariantMap& configurationMap)
{ {
QString filename = li.toString(); QString filename = li.toString();
if ( !filename.isEmpty() ) if ( !filename.isEmpty() )
m_items.append( Item{ filename, filename, ItemType::Path } ); m_items.append( Item{ filename, filename, Permissions( defaultPermissions ), ItemType::Path } );
else else
cDebug() << "Empty filename for preservefiles, item" << c; cDebug() << "Empty filename for preservefiles, item" << c;
} }
@ -181,6 +217,9 @@ void PreserveFiles::setConfigurationMap(const QVariantMap& configurationMap)
( from == "log" ) ? ItemType::Log : ( from == "log" ) ? ItemType::Log :
( from == "config" ) ? ItemType::Config : ( from == "config" ) ? ItemType::Config :
ItemType::None; ItemType::None;
QString perm = map[ "perm" ].toString();
if ( perm.isEmpty() )
perm = defaultPermissions;
if ( dest.isEmpty() ) if ( dest.isEmpty() )
{ {
@ -192,7 +231,7 @@ void PreserveFiles::setConfigurationMap(const QVariantMap& configurationMap)
} }
else else
{ {
m_items.append( Item{ QString(), dest, t } ); m_items.append( Item{ QString(), dest, Permissions( perm ), t } );
} }
} }
else else

View File

@ -24,11 +24,11 @@
#include <QVariantMap> #include <QVariantMap>
#include "CppJob.h" #include "CppJob.h"
#include "PluginDllMacro.h"
#include "utils/PluginFactory.h" #include "utils/PluginFactory.h"
#include "PluginDllMacro.h" #include "permissions.h"
class PLUGINDLLEXPORT PreserveFiles : public Calamares::CppJob class PLUGINDLLEXPORT PreserveFiles : public Calamares::CppJob
{ {
@ -46,6 +46,7 @@ class PLUGINDLLEXPORT PreserveFiles : public Calamares::CppJob
{ {
QString source; QString source;
QString dest; QString dest;
Permissions perm;
ItemType type; ItemType type;
} ; } ;

View File

@ -0,0 +1,75 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright (C) 2018 Scott Harvey <scott@spharvey.me>
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <QString>
#include <QStringList>
#include "permissions.h"
Permissions::Permissions() :
m_username(),
m_group(),
m_valid(false),
m_value(0)
{
}
Permissions::Permissions(QString p) : Permissions()
{
parsePermissions(p);
}
void Permissions::parsePermissions(const QString& p) {
QStringList segments = p.split(":");
if (segments.length() != 3) {
m_valid = false;
return;
}
if (segments[0].isEmpty() || segments[1].isEmpty()) {
m_valid = false;
return;
}
bool ok;
int octal = segments[2].toInt(&ok, 8);
if (!ok || octal == 0) {
m_valid = false;
return;
} else {
m_value = octal;
}
// We have exactly three segments and the third is valid octal,
// so we can declare the string valid and set the user and group names
m_valid = true;
m_username = segments[0];
m_group = segments[1];
return;
}

View File

@ -0,0 +1,62 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright (C) 2018 Scott Harvey <scott@spharvey.me>
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PERMISSIONS_H
#define PERMISSIONS_H
#include <QString>
/**
* @brief The Permissions class takes a QString @p in the form of
* <user>:<group>:<permissions>, checks it for validity, and makes the three
* components available indivdually.
*/
class Permissions
{
public:
/** @brief Constructor
*
* Splits the string @p at the colon (":") into separate elements for
* <user>, <group>, and <value> (permissions), where <value> is returned as
* an **octal** integer.
*/
Permissions(QString p);
/** @brief Default constructor of an invalid Permissions. */
Permissions();
bool isValid() const { return m_valid; }
QString username() const { return m_username; }
QString group() const { return m_group; }
int value() const { return m_value; }
QString octal() const { return QString::number( m_value, 8 ); }
private:
void parsePermissions(QString const &p);
QString m_username;
QString m_group;
bool m_valid;
int m_value;
};
#endif // PERMISSIONS_H

View File

@ -9,13 +9,18 @@
# as the source). # as the source).
# - a map with a *dest* key. The *dest* value is a path interpreted in the # - a map with a *dest* key. The *dest* value is a path interpreted in the
# target system (if dontChroot is true, in the host system). Relative paths # target system (if dontChroot is true, in the host system). Relative paths
# are not recommended. There are two possible other keys in the map: # are not recommended. There are three possible other keys in the map:
# - *from*, which must have one of the values, below; it is used to # - *from*, which must have one of the values, below; it is used to
# preserve files whose pathname is known to Calamares internally. # preserve files whose pathname is known to Calamares internally.
# - *src*, to refer to a path interpreted in the host system. Relative # - *src*, to refer to a path interpreted in the host system. Relative
# paths are not recommended, and are interpreted relative to where # paths are not recommended, and are interpreted relative to where
# Calamares is being run. # Calamares is being run.
# Only one of the two other keys (either *from* or *src*) may be set. # - *perm*, is a colon-separated tuple of <user>:<group>:<mode>
# where <mode> is in octal (e.g. 4777 for wide-open, 0400 for read-only
# by owner). If set, the file's ownership and permissions are set to
# those values within the target system; if not set, no permissions
# are changed.
# Only one of the two source keys (either *from* or *src*) may be set.
# #
# The target filename is modified as follows: # The target filename is modified as follows:
# - `@@ROOT@@` is replaced by the path to the target root (may be /) # - `@@ROOT@@` is replaced by the path to the target root (may be /)
@ -32,5 +37,13 @@ files:
- /etc/oem-information - /etc/oem-information
- from: log - from: log
dest: /root/install.log dest: /root/install.log
perm: root:wheel:644
- from: config - from: config
dest: /root/install.cfg dest: /root/install.cfg
perm: root:wheel:400
# The *perm* key contains a default value to apply to all files listed
# above that do not have a *perm* key of their own. If not set,
# root:root:0400 (highly restrictive) is used.
#
# perm: "root:root:0400"