From d92d3e7d3778506b58b2bc99bdb81423439d651f Mon Sep 17 00:00:00 2001 From: David Steele Date: Mon, 5 Mar 2018 14:38:18 -0500 Subject: [PATCH 3/3] Allow group access on PGDATA. This includes backend changes, utility changes (initdb, pg_ctl, pg_upgrade, etc.) and tests for each utility. --- doc/src/sgml/backup.sgml | 6 ++++- doc/src/sgml/ref/initdb.sgml | 19 +++++++++++++++ doc/src/sgml/runtime.sgml | 14 ++++++++++- src/backend/postmaster/postmaster.c | 29 +++++++++++++--------- src/bin/initdb/initdb.c | 7 +++++- src/bin/initdb/t/001_initdb.pl | 13 +++++++++- src/bin/pg_ctl/pg_ctl.c | 4 ++++ src/bin/pg_ctl/t/001_start_stop.pl | 24 ++++++++++++++++++- src/bin/pg_resetwal/pg_resetwal.c | 4 ++-- src/bin/pg_resetwal/t/001_basic.pl | 9 +++++-- src/bin/pg_rewind/RewindTest.pm | 9 ++++--- src/bin/pg_rewind/pg_rewind.c | 4 ++-- src/bin/pg_rewind/t/001_basic.pl | 2 +- src/bin/pg_upgrade/pg_upgrade.c | 5 +++- src/bin/pg_upgrade/test.sh | 14 +++++------ src/common/Makefile | 2 +- src/common/file_perm.c | 48 +++++++++++++++++++++++++++++++++++++ src/include/common/file_perm.h | 31 ++++++++++++++++++++---- src/test/perl/PostgresNode.pm | 26 +++++++++++++++++++- src/test/perl/TestLib.pm | 35 +++++++++++++++++++++++---- src/tools/msvc/Mkvcbuild.pm | 2 +- 21 files changed, 260 insertions(+), 47 deletions(-) create mode 100644 src/common/file_perm.c diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml index 9d8e69056f..a9912eb418 100644 --- a/doc/src/sgml/backup.sgml +++ b/doc/src/sgml/backup.sgml @@ -1095,7 +1095,11 @@ SELECT pg_stop_backup(); and postmaster.opts, which record information about the running postmaster, not about the postmaster which will eventually use this backup. - (These files can confuse pg_ctl.) + (These files can confuse pg_ctl.) If group read + access is enabled on the data directory and an unprivileged user in the + PostgreSQL group is performing the backup, then + postmaster.pid will not be readable and must be + excluded. diff --git a/doc/src/sgml/ref/initdb.sgml b/doc/src/sgml/ref/initdb.sgml index 585665f161..5f57b933b9 100644 --- a/doc/src/sgml/ref/initdb.sgml +++ b/doc/src/sgml/ref/initdb.sgml @@ -76,6 +76,14 @@ PostgreSQL documentation to do so.) + + For security reasons the new cluster created by initdb + will only be accessible by the cluster owner by default. The + option allows any user in the same + group as the cluster owner to read files in the cluster. This is useful + for performing backups as a non-privileged user. + + initdb initializes the database cluster's default locale and character set encoding. The character set encoding, @@ -301,6 +309,17 @@ PostgreSQL documentation + + + + + + Allows users in the same group as the cluster owner to read all cluster + files created by initdb. + + + + diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml index 71f02300c2..8d8a48aad4 100644 --- a/doc/src/sgml/runtime.sgml +++ b/doc/src/sgml/runtime.sgml @@ -137,7 +137,10 @@ postgres$ initdb -D /usr/local/pgsql/data database, it is essential that it be secured from unauthorized access. initdb therefore revokes access permissions from everyone but the - PostgreSQL user. + PostgreSQL user, and optionally, group. + Group access, when enabled, is read-only. This allows an unprivileged + user in the PostgreSQL group to take a backup of + the cluster data or perform other operations that only require read access. @@ -2220,6 +2223,15 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433 member of the group that has access to those certificate and key files. + + If the data directory allows group read access then certificate files may + need to be located outside of the data directory in order to conform to the + security requirements outlined above. Generally, group access is enabled + to allow an unprivileged user to backup the database, and in that case the + backup software will not be able to read the certificate files and will + likely error. + + If the private key is protected with a passphrase, the server will prompt for the passphrase and will not start until it has diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index e13a2ae8c4..65f528147a 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -97,6 +97,7 @@ #include "access/xlog.h" #include "bootstrap/bootstrap.h" #include "catalog/pg_control.h" +#include "common/file_perm.h" #include "common/ip.h" #include "lib/ilist.h" #include "libpq/auth.h" @@ -587,7 +588,8 @@ PostmasterMain(int argc, char *argv[]) IsPostmasterEnvironment = true; /* - * for security, no dir or file created can be group or other accessible + * By default, no dir or file created can be group or other accessible. This + * may be modified later depending in the permissions of the data directory. */ umask(S_IRWXG | S_IRWXO); @@ -1524,25 +1526,30 @@ checkDataDir(void) #endif /* - * Check if the directory has group or world access. If so, reject. - * - * It would be possible to allow weaker constraints (for example, allow - * group access) but we cannot make a general assumption that that is - * okay; for example there are platforms where nearly all users - * customarily belong to the same group. Perhaps this test should be - * configurable. + * Check if the directory has correct permissions. If not, reject. * * XXX temporarily suppress check when on Windows, because there may not * be proper support for Unix-y file permissions. Need to think of a * reasonable check to apply on Windows. */ #if !defined(WIN32) && !defined(__CYGWIN__) - if (stat_buf.st_mode & (S_IRWXG | S_IRWXO)) + if (stat_buf.st_mode & PG_MODE_MASK_ALLOW_GROUP) ereport(FATAL, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("data directory \"%s\" has group or world access", + errmsg("data directory \"%s\" has invalid permissions", DataDir), - errdetail("Permissions should be u=rwx (0700)."))); + errdetail("Permissions should be u=rwx (0700) or u=rwx,g=rx (0750)."))); +#endif + + /* + * Reset the file mode creation mask based on the mode of the data + * directory. + * + * Suppress when on Windows, because there may not be proper support + * for Unix-y file permissions. + */ +#if !defined(WIN32) && !defined(__CYGWIN__) + umask(PG_MODE_MASK_DEFAULT & ~stat_buf.st_mode); #endif /* Look for PG_VERSION before looking for pg_control */ diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c index 4ef06c2349..56356d75c5 100644 --- a/src/bin/initdb/initdb.c +++ b/src/bin/initdb/initdb.c @@ -2289,6 +2289,7 @@ usage(const char *progname) printf(_(" --auth-local=METHOD default authentication method for local-socket connections\n")); printf(_(" [-D, --pgdata=]DATADIR location for this database cluster\n")); printf(_(" -E, --encoding=ENCODING set default encoding for new databases\n")); + printf(_(" -g, --allow-group-access allow group read/execute on data directory\n")); printf(_(" --locale=LOCALE set default locale for new databases\n")); printf(_(" --lc-collate=, --lc-ctype=, --lc-messages=LOCALE\n" " --lc-monetary=, --lc-numeric=, --lc-time=LOCALE\n" @@ -2992,6 +2993,7 @@ main(int argc, char *argv[]) {"waldir", required_argument, NULL, 'X'}, {"wal-segsize", required_argument, NULL, 12}, {"data-checksums", no_argument, NULL, 'k'}, + {"allow-group-access", no_argument, NULL, 'g'}, {NULL, 0, NULL, 0} }; @@ -3033,7 +3035,7 @@ main(int argc, char *argv[]) /* process command-line options */ - while ((c = getopt_long(argc, argv, "dD:E:kL:nNU:WA:sST:X:", long_options, &option_index)) != -1) + while ((c = getopt_long(argc, argv, "dD:E:kL:nNU:WA:sST:X:g", long_options, &option_index)) != -1) { switch (c) { @@ -3127,6 +3129,9 @@ main(int argc, char *argv[]) case 12: str_wal_segment_size_mb = pg_strdup(optarg); break; + case 'g': + file_mode_mask = PG_MODE_MASK_ALLOW_GROUP; + break; default: /* getopt_long already emitted a complaint */ fprintf(stderr, _("Try \"%s --help\" for more information.\n"), diff --git a/src/bin/initdb/t/001_initdb.pl b/src/bin/initdb/t/001_initdb.pl index 561608f1d8..f767f07ed5 100644 --- a/src/bin/initdb/t/001_initdb.pl +++ b/src/bin/initdb/t/001_initdb.pl @@ -4,9 +4,11 @@ use strict; use warnings; +use Fcntl ':mode'; +use File::stat qw{lstat}; use PostgresNode; use TestLib; -use Test::More tests => 16; +use Test::More tests => 18; my $tempdir = TestLib::tempdir; my $xlogdir = "$tempdir/pgxlog"; @@ -50,3 +52,12 @@ mkdir $datadir; } command_ok([ 'initdb', '-S', $datadir ], 'sync only'); command_fails([ 'initdb', $datadir ], 'existing data directory'); + +# Init a new db with group access +my $datadir_group = "$tempdir/data_group"; + +command_ok( + [ 'initdb', '-g', $datadir_group ], + 'successful creation with group access'); + +ok(check_pg_data_perm($datadir_group, 1)); diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c index 1eef7179cc..bb70e625fd 100644 --- a/src/bin/pg_ctl/pg_ctl.c +++ b/src/bin/pg_ctl/pg_ctl.c @@ -2171,6 +2171,7 @@ main(int argc, char **argv) */ argv0 = argv[0]; + /* Set restrictive mode mask until PGDATA permissions are checked */ umask(PG_MODE_MASK_DEFAULT); /* support --help and --version even if invoked as root */ @@ -2406,6 +2407,9 @@ main(int argc, char **argv) snprintf(version_file, MAXPGPATH, "%s/PG_VERSION", pg_data); snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data); snprintf(backup_file, MAXPGPATH, "%s/backup_label", pg_data); + + /* Set mask based on PGDATA permissions */ + umask(DataDirectoryMask(pg_data)); } switch (ctl_command) diff --git a/src/bin/pg_ctl/t/001_start_stop.pl b/src/bin/pg_ctl/t/001_start_stop.pl index 909bf4d465..f8facc3f00 100644 --- a/src/bin/pg_ctl/t/001_start_stop.pl +++ b/src/bin/pg_ctl/t/001_start_stop.pl @@ -2,9 +2,11 @@ use strict; use warnings; use Config; +use Fcntl ':mode'; +use File::stat qw{lstat}; use PostgresNode; use TestLib; -use Test::More tests => 20; +use Test::More tests => 24; my $tempdir = TestLib::tempdir; my $tempdir_short = TestLib::tempdir_short; @@ -68,4 +70,24 @@ command_ok( ok(-f $logFileName); ok(check_pg_data_perm("$tempdir/data", 0)); +# Log file for second perm test +$logFileName = "$tempdir/data/perm-test-640.log"; + +# Change the data dir mode so log file will be created with group read +# privileges on the next start +system_or_bail 'pg_ctl', 'stop', '-D', "$tempdir/data"; + +add_pg_data_group_perm("$tempdir/data"); + +command_ok( + [ 'pg_ctl', 'start', '-D', "$tempdir/data", '-l', $logFileName ], + 'start server to check group permissions'); + +ok(-f $logFileName); +ok(check_pg_data_perm("$tempdir/data", 1)); + +command_ok( + [ 'pg_ctl', 'restart', '-D', "$tempdir/data", '-l', $logFileName ], + 'pg_ctl restart with server running'); + system_or_bail 'pg_ctl', 'stop', '-D', "$tempdir/data"; diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c index 47abd41fc3..6a4dc502c4 100644 --- a/src/bin/pg_resetwal/pg_resetwal.c +++ b/src/bin/pg_resetwal/pg_resetwal.c @@ -328,8 +328,8 @@ main(int argc, char *argv[]) exit(1); } - /* Set dir/file mode mask */ - umask(PG_MODE_MASK_DEFAULT); + /* Set mask based on PGDATA permissions */ + umask(DataDirectoryMask(DataDir)); /* Check that data directory matches our server version */ CheckDataVersion(); diff --git a/src/bin/pg_resetwal/t/001_basic.pl b/src/bin/pg_resetwal/t/001_basic.pl index db0c2a630a..4a53358f58 100644 --- a/src/bin/pg_resetwal/t/001_basic.pl +++ b/src/bin/pg_resetwal/t/001_basic.pl @@ -4,7 +4,7 @@ use warnings; use Config; use PostgresNode; use TestLib; -use Test::More tests => 14; +use Test::More tests => 15; my $tempdir = TestLib::tempdir; my $tempdir_short = TestLib::tempdir_short; @@ -40,9 +40,12 @@ ok(check_pg_data_perm($pgdata, 0), 'check PGDATA permissions'); $node->start; -# Reset to specific WAL segment +# Reset to specific WAL segment. Also enable group access to make sure files +# and directories are created with group permissions. $node->stop; +add_pg_data_group_perm($pgdata); + $node->command_ok( ['pg_resetwal', '-l', '000000070000000700000007', '-D', $pgdata], 'set to specific WAL'); @@ -52,4 +55,6 @@ is_deeply( [sort(qw(. .. archive_status 000000070000000700000007))], 'WAL recreated'); +ok(check_pg_data_perm($pgdata, 1), 'check PGDATA permissions'); + $node->start; diff --git a/src/bin/pg_rewind/RewindTest.pm b/src/bin/pg_rewind/RewindTest.pm index b18a7f954c..10d44fd259 100644 --- a/src/bin/pg_rewind/RewindTest.pm +++ b/src/bin/pg_rewind/RewindTest.pm @@ -116,10 +116,12 @@ sub check_query sub setup_cluster { my $extra_name = shift; + my $group_access = shift; # Initialize master, data checksums are mandatory $node_master = get_new_node('master' . ($extra_name ? "_${extra_name}" : '')); - $node_master->init(allows_streaming => 1); + $node_master->init(allows_streaming => 1, + has_group_access => defined($group_access) ? $group_access : 0); # Set wal_keep_segments to prevent WAL segment recycling after enforced # checkpoints in the tests. $node_master->append_conf('postgresql.conf', qq( @@ -237,7 +239,7 @@ sub run_pg_rewind "$tmp_folder/master-postgresql.conf.tmp", "$master_pgdata/postgresql.conf"); - chmod(0600, "$master_pgdata/postgresql.conf") + chmod($node_master->group_access() ? 0640 : 0600, "$master_pgdata/postgresql.conf") or die("unable to set permissions for $master_pgdata/postgresql.conf"); # Plug-in rewound node to the now-promoted standby node @@ -258,7 +260,8 @@ recovery_target_timeline='latest' # Clean up after the test. Stop both servers, if they're still running. sub clean_rewind_test { - ok (check_pg_data_perm($node_master->data_dir(), 0)); + ok (check_pg_data_perm( + $node_master->data_dir(), $node_master->group_access())); $node_master->teardown_node if defined $node_master; $node_standby->teardown_node if defined $node_standby; diff --git a/src/bin/pg_rewind/pg_rewind.c b/src/bin/pg_rewind/pg_rewind.c index 3d179e2c7d..11153e5f2f 100644 --- a/src/bin/pg_rewind/pg_rewind.c +++ b/src/bin/pg_rewind/pg_rewind.c @@ -186,8 +186,8 @@ main(int argc, char **argv) exit(1); } - /* Set dir/file mode mask */ - umask(PG_MODE_MASK_DEFAULT); + /* Set mask based on PGDATA permissions */ + umask(DataDirectoryMask(datadir_target)); /* * Don't allow pg_rewind to be run as root, to avoid overwriting the diff --git a/src/bin/pg_rewind/t/001_basic.pl b/src/bin/pg_rewind/t/001_basic.pl index e7fc200fc0..205bdd77ef 100644 --- a/src/bin/pg_rewind/t/001_basic.pl +++ b/src/bin/pg_rewind/t/001_basic.pl @@ -9,7 +9,7 @@ sub run_test { my $test_mode = shift; - RewindTest::setup_cluster($test_mode); + RewindTest::setup_cluster($test_mode, 1); RewindTest::start_master(); # Create a test table and insert a row in master. diff --git a/src/bin/pg_upgrade/pg_upgrade.c b/src/bin/pg_upgrade/pg_upgrade.c index 59df6fd88f..54f54fb0a4 100644 --- a/src/bin/pg_upgrade/pg_upgrade.c +++ b/src/bin/pg_upgrade/pg_upgrade.c @@ -79,7 +79,7 @@ main(int argc, char **argv) set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_upgrade")); - /* Ensure that all files created by pg_upgrade are non-world-readable */ + /* Set default restrictive mask until new cluster permissions are read */ umask(PG_MODE_MASK_DEFAULT); parseCommandLine(argc, argv); @@ -100,6 +100,9 @@ main(int argc, char **argv) check_cluster_compatibility(live_check); + /* Set mask based on new PGDATA permissions */ + umask(DataDirectoryMask(new_cluster.pgdata)); + check_and_dump_old_cluster(live_check); diff --git a/src/bin/pg_upgrade/test.sh b/src/bin/pg_upgrade/test.sh index 4e8db4aaf4..24631a91c6 100644 --- a/src/bin/pg_upgrade/test.sh +++ b/src/bin/pg_upgrade/test.sh @@ -20,9 +20,9 @@ unset MAKELEVEL # Run a given "initdb" binary and overlay the regression testing # authentication configuration. standard_initdb() { - # To increase coverage of non-standard segment size without - # increase test runtime, run these tests with a lower setting. - "$1" -N --wal-segsize 1 + # To increase coverage of non-standard segment size and group access + # without increasing test runtime, run these tests with a custom setting. + "$1" -N --wal-segsize 1 -g if [ -n "$TEMP_CONFIG" -a -r "$TEMP_CONFIG" ] then cat "$TEMP_CONFIG" >> "$PGDATA/postgresql.conf" @@ -231,13 +231,13 @@ standard_initdb 'initdb' pg_upgrade $PG_UPGRADE_OPTS -d "${PGDATA}.old" -D "${PGDATA}" -b "$oldbindir" -B "$bindir" -p "$PGPORT" -P "$PGPORT" # make sure all directories and files have group permissions -if [ $(find ${PGDATA} -type f ! -perm 600 | wc -l) -ne 0 ]; then - echo "files in PGDATA with permission != 600"; +if [ $(find ${PGDATA} -type f ! -perm 640 | wc -l) -ne 0 ]; then + echo "files in PGDATA with permission != 640"; exit 1; fi -if [ $(find ${PGDATA} -type d ! -perm 700 | wc -l) -ne 0 ]; then - echo "directories in PGDATA with permission != 700"; +if [ $(find ${PGDATA} -type d ! -perm 750 | wc -l) -ne 0 ]; then + echo "directories in PGDATA with permission != 750"; exit 1; fi diff --git a/src/common/Makefile b/src/common/Makefile index 80e78d72fe..504375bef4 100644 --- a/src/common/Makefile +++ b/src/common/Makefile @@ -51,7 +51,7 @@ else OBJS_COMMON += sha2.o endif -OBJS_FRONTEND = $(OBJS_COMMON) fe_memutils.o file_utils.o restricted_token.o +OBJS_FRONTEND = $(OBJS_COMMON) fe_memutils.o file_perm.o file_utils.o restricted_token.o OBJS_SRV = $(OBJS_COMMON:%.o=%_srv.o) diff --git a/src/common/file_perm.c b/src/common/file_perm.c new file mode 100644 index 0000000000..f01d43725e --- /dev/null +++ b/src/common/file_perm.c @@ -0,0 +1,48 @@ +/*------------------------------------------------------------------------- + * + * File and directory permission routines + * + * Group read/execute may optional be enabled on PGDATA so any frontend tools + * That write into PGDATA must know what mask to set and the permissions to + * use for creating files and directories. + * + * + * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/file_perm.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#error "This file is not expected to be compiled for backend code" +#endif + +#include + +#include "common/file_perm.h" + +/* + * Determine the mask to use when writing to PGDATA. + * + * Errors are not handled here and should be checked by the frontend + * application. + */ +mode_t +DataDirectoryMask(const char *dataDir) +{ + struct stat statBuf; + + /* + * If an error occurs getting the mode then return the more restrictive mask. + * It is the reponsibility of the frontend application to generate an error. + */ + if (stat(dataDir, &statBuf) != 0) + return PG_MODE_MASK_DEFAULT; + + /* + * Construct the mask that the caller should pass to umask(). + */ + return PG_MODE_MASK_DEFAULT & ~statBuf.st_mode; +} diff --git a/src/include/common/file_perm.h b/src/include/common/file_perm.h index 3c6da0e000..35dcbe6108 100644 --- a/src/include/common/file_perm.h +++ b/src/include/common/file_perm.h @@ -1,6 +1,10 @@ /*------------------------------------------------------------------------- * - * File and directory permission constants + * File and directory permission constants and routines + * + * Group read/execute may optional be enabled on PGDATA so any frontend tools + * That write into PGDATA must know what mask to set and the permissions to + * use for creating files and directories. * * * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group @@ -20,13 +24,30 @@ #define PG_MODE_MASK_DEFAULT (S_IRWXG | S_IRWXO) /* - * Default mode for created files. + * Optional mode mask for data directory permissions that allows group + * read/execute. + */ +#define PG_MODE_MASK_ALLOW_GROUP (S_IWGRP | S_IRWXO) + +/* + * Default mode for created files, unless something else is specified using + * the *Perm() function variants. + */ +#define PG_FILE_MODE_DEFAULT (S_IRUSR | S_IWUSR | S_IRGRP) + +/* + * Default mode for directories created with MakeDirectoryDefaultPerm(). */ -#define PG_FILE_MODE_DEFAULT (S_IRUSR | S_IWUSR) +#define PG_DIR_MODE_DEFAULT (S_IRWXU | S_IRGRP | S_IXGRP) + +#ifdef FRONTEND /* - * Default mode for directories. + * Determine the mask to use when writing to PGDATA */ -#define PG_DIR_MODE_DEFAULT S_IRWXU +mode_t DataDirectoryMask(const char *dataDir); + +#endif /* FRONTEND */ + #endif /* FILE_PERM_H */ diff --git a/src/test/perl/PostgresNode.pm b/src/test/perl/PostgresNode.pm index 76e571b98c..8e9c6c11f0 100644 --- a/src/test/perl/PostgresNode.pm +++ b/src/test/perl/PostgresNode.pm @@ -269,6 +269,20 @@ sub connstr =pod +=item $node->group_access() + +Does the data dir allow group access? + +=cut + +sub group_access +{ + my ($self) = @_; + return $self->{_group_access}; +} + +=pod + =item $node->data_dir() Returns the path to the data directory. postgresql.conf and pg_hba.conf are @@ -406,10 +420,16 @@ sub init $params{allows_streaming} = 0 unless defined $params{allows_streaming}; $params{has_archiving} = 0 unless defined $params{has_archiving}; + $params{has_group_access} = 0 unless defined $params{has_group_access}; mkdir $self->backup_dir; mkdir $self->archive_dir; + if ($params{has_group_access}) + { + push(@{$params{extra}}, '-g'); + } + TestLib::system_or_bail('initdb', '-D', $pgdata, '-A', 'trust', '-N', @{ $params{extra} }); TestLib::system_or_bail($ENV{PG_REGRESS}, '--config-auth', $pgdata); @@ -460,8 +480,12 @@ sub init } close $conf; + chmod($params{has_group_access} ? 0640 : 0600, "$pgdata/postgresql.conf") + or die("unable to set permissions for $pgdata/postgresql.conf"); + $self->set_replication_conf if $params{allows_streaming}; $self->enable_archiving if $params{has_archiving}; + $self->{_group_access} = 1 if $params{has_group_access}; } =pod @@ -485,7 +509,7 @@ sub append_conf TestLib::append_to_file($conffile, $str . "\n"); - chmod(0600, $conffile) + chmod($self->group_access() ? 0640 : 0600, $conffile) or die("unable to set permissions for $conffile"); } diff --git a/src/test/perl/TestLib.pm b/src/test/perl/TestLib.pm index 21f4a9c55e..3d404eefac 100644 --- a/src/test/perl/TestLib.pm +++ b/src/test/perl/TestLib.pm @@ -30,6 +30,7 @@ our @EXPORT = qw( slurp_file append_to_file check_pg_data_perm + add_pg_data_group_perm check_pg_config system_or_bail system_log @@ -226,18 +227,19 @@ sub append_to_file close $fh; } -# Ensure all permissions in the pg_data directory are correct. Permissions -# should be dir = 0700, file = 0600. +# Ensure all permissions in the pg_data directory are correct. When allow_group +# is true then permissions should be dir = 0750, file = 0640. When allow_group +# is false then permissions should be dir = 0700, file = 0600. sub check_pg_data_perm { - my ($pgdata) = @_; + my ($pgdata, $allow_group) = @_; # Result defaults to true my $result = 1; # Expected permission - my $expected_file_perm = 0600; - my $expected_dir_perm = 0700; + my $expected_file_perm = $allow_group ? 0640 : 0600; + my $expected_dir_perm = $allow_group ? 0750 : 0700; find ( @@ -302,6 +304,29 @@ sub check_pg_data_perm return $result; } +# Add group permissions to a PGDATA directory +sub add_pg_data_group_perm +{ + my ($pgdata) = @_; + + find + ( + sub + { + my $file_stat = stat($File::Find::name); + + defined($file_stat) + or die("unable to stat $file_stat"); + + chmod(S_IMODE($file_stat->mode) | + (S_ISDIR($file_stat->mode) ? 0050 : 0040), + $File::Find::name) + or die "unable to chmod $File::Find::name"; + }, + $pgdata + ); +} + # Check presence of a given regexp within pg_config.h for the installation # where tests are running, returning a match status result depending on # that. diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm index 72976f44d8..78d4934ec6 100644 --- a/src/tools/msvc/Mkvcbuild.pm +++ b/src/tools/msvc/Mkvcbuild.pm @@ -125,7 +125,7 @@ sub mkvcbuild } our @pgcommonfrontendfiles = ( - @pgcommonallfiles, qw(fe_memutils.c file_utils.c + @pgcommonallfiles, qw(fe_memutils.c file_perm.c file_utils.c restricted_token.c)); our @pgcommonbkndfiles = @pgcommonallfiles; -- 2.14.3 (Apple Git-98)