From bea0f8ef6393650e210adfc7812d3ca27e475632 Mon Sep 17 00:00:00 2001 From: Grigory Smolkin Date: Mon, 19 Mar 2018 20:51:01 +0300 Subject: [PATCH] Github Issue 24: check PQresultStatus for pg_stop_backup() --- src/backup.c | 29 ++++++++++---- tests/auth_test.py | 95 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+), 8 deletions(-) diff --git a/src/backup.c b/src/backup.c index 06552aeb..cd3a5139 100644 --- a/src/backup.c +++ b/src/backup.c @@ -1544,6 +1544,7 @@ pg_stop_backup(pgBackup *backup) pgFile *file; size_t len; char *val = NULL; + char *stop_backup_query; /* * We will use this values if there are no transactions between start_lsn @@ -1600,26 +1601,25 @@ pg_stop_backup(pgBackup *backup) * pg_stop_backup(false) copy of the backup label and tablespace map * so they can be written to disk by the caller. */ - sent = pgut_send(conn, - "SELECT" + stop_backup_query = "SELECT" " pg_catalog.txid_snapshot_xmax(pg_catalog.txid_current_snapshot())," " current_timestamp(0)::timestamptz," " lsn," " labelfile," " spcmapfile" - " FROM pg_catalog.pg_stop_backup(false)", - 0, NULL, WARNING); + " FROM pg_catalog.pg_stop_backup(false)"; + } else { - sent = pgut_send(conn, - "SELECT" + stop_backup_query = "SELECT" " pg_catalog.txid_snapshot_xmax(pg_catalog.txid_current_snapshot())," " current_timestamp(0)::timestamptz," - " pg_catalog.pg_stop_backup() as lsn", - 0, NULL, WARNING); + " pg_catalog.pg_stop_backup() as lsn"; } + + sent = pgut_send(conn, stop_backup_query, 0, NULL, WARNING); pg_stop_backup_is_sent = true; if (!sent) elog(ERROR, "Failed to send pg_stop_backup query"); @@ -1664,10 +1664,23 @@ pg_stop_backup(pgBackup *backup) break; } } + + /* Check successfull execution of pg_stop_backup() */ if (!res) elog(ERROR, "pg_stop backup() failed"); else + { + switch (PQresultStatus(res)) + { + case PGRES_TUPLES_OK: + case PGRES_COMMAND_OK: + break; + default: + elog(ERROR, "query failed: %s query was: %s", + PQerrorMessage(conn), stop_backup_query); + } elog(INFO, "pg_stop backup() successfully executed"); + } backup_in_progress = false; diff --git a/tests/auth_test.py b/tests/auth_test.py index a268254f..65f9ed31 100644 --- a/tests/auth_test.py +++ b/tests/auth_test.py @@ -6,6 +6,7 @@ The Test suite check behavior of pg_probackup utility, if password is required f import os import unittest import signal +import time from .helpers.ptrack_helpers import ProbackupTest, ProbackupException from testgres import StartNodeException @@ -20,6 +21,100 @@ except ImportError: skip_test = True +class SimpleAuthTest(ProbackupTest, unittest.TestCase): + + # @unittest.skip("skip") + def test_backup_via_unpriviledged_user(self): + """ + Make node, create unpriviledged user, try to + run a backups without EXECUTE rights on + certain functions + """ + fname = self.id().split('.')[3] + node = self.make_simple_node( + base_dir="{0}/{1}/node".format(module_name, fname), + set_replication=True, + initdb_params=['--data-checksums'], + pg_options={'wal_level': 'replica', 'max_wal_senders': '2'} + ) + backup_dir = os.path.join(self.tmp_path, module_name, fname, 'backup') + self.init_pb(backup_dir) + self.add_instance(backup_dir, 'node', node) + self.set_archiving(backup_dir, 'node', node) + node.start() + + node.safe_psql("postgres", "CREATE ROLE backup with LOGIN") + + try: + self.backup_node( + backup_dir, 'node', node, options=['-U', 'backup']) + self.assertEqual( + 1, 0, + "Expecting Error due to missing grant on EXECUTE.") + except ProbackupException as e: + self.assertIn( + "ERROR: query failed: ERROR: permission denied " + "for function pg_start_backup", e.message, + '\n Unexpected Error Message: {0}\n CMD: {1}'.format( + repr(e.message), self.cmd)) + + node.safe_psql( + "postgres", + "GRANT EXECUTE ON FUNCTION" + " pg_start_backup(text, boolean, boolean) TO backup;") + + time.sleep(1) + try: + self.backup_node( + backup_dir, 'node', node, options=['-U', 'backup']) + self.assertEqual( + 1, 0, + "Expecting Error due to missing grant on EXECUTE.") + except ProbackupException as e: + self.assertIn( + "ERROR: query failed: ERROR: permission denied for function " + "pg_create_restore_point\nquery was: " + "SELECT pg_catalog.pg_create_restore_point($1)", e.message, + '\n Unexpected Error Message: {0}\n CMD: {1}'.format( + repr(e.message), self.cmd)) + + node.safe_psql( + "postgres", + "GRANT EXECUTE ON FUNCTION" + " pg_create_restore_point(text) TO backup;") + + time.sleep(1) + + try: + self.backup_node( + backup_dir, 'node', node, options=['-U', 'backup']) + self.assertEqual( + 1, 0, + "Expecting Error due to missing grant on EXECUTE.") + except ProbackupException as e: + self.assertIn( + "ERROR: query failed: ERROR: permission denied " + "for function pg_stop_backup", e.message, + '\n Unexpected Error Message: {0}\n CMD: {1}'.format( + repr(e.message), self.cmd)) + + if self.get_version(node) < self.version_to_num('10.0'): + node.safe_psql( + "postgres", + "GRANT EXECUTE ON FUNCTION pg_stop_backup(boolean) TO backup") + else: + node.safe_psql( + "postgres", + "GRANT EXECUTE ON FUNCTION " + "pg_stop_backup(boolean, boolean) TO backup") + + self.backup_node( + backup_dir, 'node', node, options=['-U', 'backup']) + + # Clean after yourself + self.del_test_dir(module_name, fname) + + class AuthTest(unittest.TestCase): pb = None node = None