Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: NixOS/nixpkgs
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 88235d99a484
Choose a base ref
...
head repository: NixOS/nixpkgs
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 2d9e51adc37c
Choose a head ref
  • 4 commits
  • 1 file changed
  • 2 contributors

Commits on Jan 18, 2020

  1. nixos/roundcube: do not write passwords to the store nor run php as root

    If the database is local, use postgres peer authentication.
    Otherwise, use a password file.
    
    Leave database initialisation to postgresql.ensure*.
    Leave /var/lib/roundcube creation to systemd.
    Run php upgrade script as unpriviledged user.
    symphorien committed Jan 18, 2020

    Verified

    This commit was signed with the committer’s verified signature.
    aykevl Ayke
    Copy the full SHA
    52cf727 View commit details
  2. nixos/roundcube: don't use the default and insecure des_key

    The php installer creates a random one, but we bypass it, so we have
    to create one ourselves.
    
    This should be backward compatible as encryption is used for session
    cookies only: users at the time of the upgrade will be logged out but
    nothing more.
    
    https://github.com/roundcube/roundcubemail/blob/259b7fa0650fea9320b38cb17c4e80497acae7a3/config/config.inc.php.sample#L73
    symphorien committed Jan 18, 2020

    Verified

    This commit was signed with the committer’s verified signature.
    aykevl Ayke
    Copy the full SHA
    b6e6bec View commit details
  3. nixos/roundcube: provide path to mime.types file

    fixes this warning:
    WARNING: Mimetype to file extension mapping doesn't work properly!
    symphorien committed Jan 18, 2020

    Verified

    This commit was signed with the committer’s verified signature.
    aykevl Ayke
    Copy the full SHA
    b5d692e View commit details

Commits on Jan 22, 2020

  1. Merge pull request #77532 from symphorien/roundcube

    nixos/roundcube: security improvements
    Ma27 authored Jan 22, 2020

    Verified

    This commit was signed with the committer’s verified signature.
    aykevl Ayke
    Copy the full SHA
    2d9e51a View commit details
Showing with 59 additions and 20 deletions.
  1. +59 −20 nixos/modules/services/mail/roundcube.nix
79 changes: 59 additions & 20 deletions nixos/modules/services/mail/roundcube.nix
Original file line number Diff line number Diff line change
@@ -5,6 +5,8 @@ with lib;
let
cfg = config.services.roundcube;
fpm = config.services.phpfpm.pools.roundcube;
localDB = cfg.database.host == "localhost";
user = cfg.database.username;
in
{
options.services.roundcube = {
@@ -44,7 +46,10 @@ in
username = mkOption {
type = types.str;
default = "roundcube";
description = "Username for the postgresql connection";
description = ''
Username for the postgresql connection.
If <literal>database.host</literal> is set to <literal>localhost</literal>, a unix user and group of the same name will be created as well.
'';
};
host = mkOption {
type = types.str;
@@ -58,7 +63,12 @@ in
};
password = mkOption {
type = types.str;
description = "Password for the postgresql connection";
description = "Password for the postgresql connection. Do not use: the password will be stored world readable in the store; use <literal>passwordFile</literal> instead.";
default = "";
};
passwordFile = mkOption {
type = types.str;
description = "Password file for the postgresql connection. Must be readable by user <literal>nginx</literal>. Ignored if <literal>database.host</literal> is set to <literal>localhost</literal>, as peer authentication will be used.";
};
dbname = mkOption {
type = types.str;
@@ -83,14 +93,22 @@ in
};

config = mkIf cfg.enable {
# backward compatibility: if password is set but not passwordFile, make one.
services.roundcube.database.passwordFile = mkIf (!localDB && cfg.database.password != "") (mkDefault ("${pkgs.writeText "roundcube-password" cfg.database.password}"));
warnings = lib.optional (!localDB && cfg.database.password != "") "services.roundcube.database.password is deprecated and insecure; use services.roundcube.database.passwordFile instead";

environment.etc."roundcube/config.inc.php".text = ''
<?php
${lib.optionalString (!localDB) "$password = file_get_contents('${cfg.database.passwordFile}');"}
$config = array();
$config['db_dsnw'] = 'pgsql://${cfg.database.username}:${cfg.database.password}@${cfg.database.host}/${cfg.database.dbname}';
$config['db_dsnw'] = 'pgsql://${cfg.database.username}${lib.optionalString (!localDB) ":' . $password . '"}@${if localDB then "unix(/run/postgresql)" else cfg.database.host}/${cfg.database.dbname}';
$config['log_driver'] = 'syslog';
$config['max_message_size'] = '25M';
$config['plugins'] = [${concatMapStringsSep "," (p: "'${p}'") cfg.plugins}];
$config['des_key'] = file_get_contents('/var/lib/roundcube/des_key');
$config['mime_types'] = '${pkgs.nginx}/conf/mime.types';
${cfg.extraConfig}
'';

@@ -116,12 +134,26 @@ in
};
};

services.postgresql = mkIf (cfg.database.host == "localhost") {
services.postgresql = mkIf localDB {
enable = true;
ensureDatabases = [ cfg.database.dbname ];
ensureUsers = [ {
name = cfg.database.username;
ensurePermissions = {
"DATABASE ${cfg.database.username}" = "ALL PRIVILEGES";
};
} ];
};

users.users.${user} = mkIf localDB {
group = user;
isSystemUser = true;
createHome = false;
};
users.groups.${user} = mkIf localDB {};

services.phpfpm.pools.roundcube = {
user = "nginx";
user = if localDB then user else "nginx";
phpOptions = ''
error_log = 'stderr'
log_errors = on
@@ -143,32 +175,39 @@ in
};
systemd.services.phpfpm-roundcube.after = [ "roundcube-setup.service" ];

systemd.services.roundcube-setup = let
pgSuperUser = config.services.postgresql.superUser;
in mkMerge [
systemd.services.roundcube-setup = mkMerge [
(mkIf (cfg.database.host == "localhost") {
requires = [ "postgresql.service" ];
after = [ "postgresql.service" ];
path = [ config.services.postgresql.package ];
})
{
wantedBy = [ "multi-user.target" ];
script = ''
mkdir -p /var/lib/roundcube
if [ ! -f /var/lib/roundcube/db-created ]; then
if [ "${cfg.database.host}" = "localhost" ]; then
${pkgs.sudo}/bin/sudo -u ${pgSuperUser} psql postgres -c "create role ${cfg.database.username} with login password '${cfg.database.password}'";
${pkgs.sudo}/bin/sudo -u ${pgSuperUser} psql postgres -c "create database ${cfg.database.dbname} with owner ${cfg.database.username}";
fi
PGPASSWORD="${cfg.database.password}" ${pkgs.postgresql}/bin/psql -U ${cfg.database.username} \
-f ${cfg.package}/SQL/postgres.initial.sql \
-h ${cfg.database.host} ${cfg.database.dbname}
touch /var/lib/roundcube/db-created
script = let
psql = "${lib.optionalString (!localDB) "PGPASSFILE=${cfg.database.passwordFile}"} ${pkgs.postgresql}/bin/psql ${lib.optionalString (!localDB) "-h ${cfg.database.host} -U ${cfg.database.username} "} ${cfg.database.dbname}";
in
''
version="$(${psql} -t <<< "select value from system where name = 'roundcube-version';" || true)"
if ! (grep -E '[a-zA-Z0-9]' <<< "$version"); then
${psql} -f ${cfg.package}/SQL/postgres.initial.sql
fi
if [ ! -f /var/lib/roundcube/des_key ]; then
base64 /dev/urandom | head -c 24 > /var/lib/roundcube/des_key;
# we need to log out everyone in case change the des_key
# from the default when upgrading from nixos 19.09
${psql} <<< 'TRUNCATE TABLE session;'
fi
${pkgs.php}/bin/php ${cfg.package}/bin/update.sh
'';
serviceConfig.Type = "oneshot";
serviceConfig = {
Type = "oneshot";
StateDirectory = "roundcube";
User = if localDB then user else "nginx";
# so that the des_key is not world readable
StateDirectoryMode = "0700";
};
}
];
};