Commit 9d2d9e0a authored by Christoph Berg's avatar Christoph Berg

pg_ctlcluster: Refuse operation when config owner does not match data

owner, and config owner is not root.
parent eda24710
......@@ -581,20 +581,24 @@ sub check_pidfile_running {
return undef;
}
# Return a hash with information about a specific cluster.
# Return a hash with information about a specific cluster (which needs to exist).
# Arguments: <version> <cluster name>
# Returns: information hash (keys: pgdata, port, running, logfile [unless it
# has a custom one], configdir, owneruid, ownergid, socketdir,
# statstempdir)
sub cluster_info {
error 'cluster_info must be called with <version> <cluster> arguments' unless $_[0] && $_[1];
my ($v, $c) = @_;
error 'cluster_info must be called with <version> <cluster> arguments' unless ($v and $c);
my %result;
$result{'configdir'} = "$confroot/$_[0]/$_[1]";
my %postgresql_conf = read_cluster_conf_file $_[0], $_[1], 'postgresql.conf';
$result{'pgdata'} = cluster_data_directory $_[0], $_[1], \%postgresql_conf;
$result{'configdir'} = "$confroot/$v/$c";
error 'cluster_info called on non-existing cluster $v $c' unless (-e "$result{configdir}/postgresql.conf");
$result{'configuid'} = (stat "$result{configdir}/postgresql.conf")[4];
my %postgresql_conf = read_cluster_conf_file $v, $c, 'postgresql.conf';
$result{'pgdata'} = cluster_data_directory $v, $c, \%postgresql_conf;
$result{'port'} = $postgresql_conf{'port'} || $defaultport;
$result{'socketdir'} = get_cluster_socketdir $_[0], $_[1];
$result{'socketdir'} = get_cluster_socketdir $v, $c;
$result{'statstempdir'} = $postgresql_conf{'stats_temp_directory'};
# if we can determine the running status with the pid file, prefer that
......@@ -606,7 +610,7 @@ sub cluster_info {
# otherwise fall back to probing the port; this is unreliable if the port
# was changed in the configuration file in the meantime
if (!defined ($result{'running'})) {
$result{'running'} = cluster_port_running ($_[0], $_[1], $result{'port'});
$result{'running'} = cluster_port_running ($v, $c, $result{'port'});
}
if ($result{'pgdata'}) {
......@@ -614,16 +618,16 @@ sub cluster_info {
(stat $result{'pgdata'})[4,5];
$result{'recovery'} = -e "$result{'pgdata'}/recovery.conf";
}
$result{'start'} = get_cluster_start_conf $_[0], $_[1];
$result{'start'} = get_cluster_start_conf $v, $c;
# default log file (only if not expliticly configured in postgresql.conf)
# default log file (only if not explicitly configured in postgresql.conf)
unless (config_bool ($postgresql_conf{logging_collector}) or
($postgresql_conf{'log_destination'} || '') =~ /syslog/) {
my $log_symlink = $result{'configdir'} . "/log";
if (-l $log_symlink) {
($result{'logfile'}) = readlink ($log_symlink) =~ /(.*)/; # untaint
} else {
$result{'logfile'} = "/var/log/postgresql/postgresql-$_[0]-$_[1].log";
$result{'logfile'} = "/var/log/postgresql/postgresql-$v-$c.log";
}
} else {
$result{log_destination} = $postgresql_conf{log_destination};
......@@ -632,8 +636,8 @@ sub cluster_info {
}
# autovacuum defaults to on since 8.3
$result{'avac_enable'} = config_bool $postgresql_conf{'autovacuum'} || ($_[0] >= '8.3');
$result{'avac_enable'} = config_bool $postgresql_conf{'autovacuum'} || ($v >= '8.3');
return %result;
}
......
postgresql-common (161) UNRELEASED; urgency=medium
* pg_ctlcluster: Refuse operation when config owner does not match data
owner, and config owner is not root.
* Stop automatically updating debian/control from debian/control.in in
pgxs_debian_control.mk. Instead, implement "checkcontrol" and
"updatecontrol" actions in pg_buildext. checkcontrol is run from
......
......@@ -372,12 +372,18 @@ unless (-d $info{'pgdata'} && defined $info{'owneruid'}) {
error $info{'pgdata'} . ' is not accessible or does not exist';
}
# check that owner uig/gid is valid
# check that owner uid/gid is valid
unless (getpwuid $info{'owneruid'}) {
error 'The cluster is owned by user id '.$info{'owneruid'}.' which does not exist any more'
error 'The cluster is owned by user id '.$info{'owneruid'}.' which does not exist'
}
unless (getgrgid $info{'ownergid'}) {
error 'The cluster is owned by group id '.$info{'ownergid'}.' which does not exist any more'
error 'The cluster is owned by group id '.$info{'ownergid'}.' which does not exist'
}
# owneruid and configuid need to match, unless configuid is root
if ($info{'configuid'} != 0 and $info{'configuid'} != $info{'owneruid'}) {
my $configowner = (getpwuid $info{'configuid'})[0] || "(unknown)";
my $dataowner = (getpwuid $info{'owneruid'})[0];
error "Config owner ($configowner:$info{configuid}) and data owner ($dataowner:$info{owneruid}) do not match, and config owner is not root";
}
# recreate missing standard log dir
......
......@@ -6,15 +6,23 @@ use strict;
use lib 't';
use TestLib;
use Test::More tests => 49;
use Test::More tests => 52;
my $owner = 'nobody';
my $v = $MAJORS[0];
# create cluster
is ((system "pg_createcluster -u $owner $v main --start >/dev/null"), 0,
is ((system "pg_createcluster -u $owner $v main >/dev/null"), 0,
"pg_createcluster $v main for owner $owner");
# check if start is refused when config and data owner do not match
my $pgconf = "/etc/postgresql/$v/main/postgresql.conf";
my ($origuid, $origgid) = (stat $pgconf)[4,5];
chown 1, 1, $pgconf;
like_program_out 0, "pg_ctlcluster $v main start", 1, qr/do not match/, "start refused when config and data owners mismatch";
chown $origuid, $origgid, $pgconf;
is ((system "pg_ctlcluster $v main start >/dev/null"), 0, "pg_ctlcluster succeeds with owner $owner");
# Check cluster
like_program_out $owner, 'pg_lsclusters -h', 0,
qr/^$v\s+main\s+5432\s+online\s+$owner/,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment