standby switchover: check replication configuration file ownership

Within a PostgreSQL data directory, all files should have the same
ownership as the data directory itself. PostgreSQL itself expects
this, and ownership of files by another user is likely to cause
problems.

In PostgreSQL 11 or earlier, if "recovery.conf" cannot be moved
by PostgreSQL (because e.g. it is owned by root), it will not be
possible to promote the standby to primary.

In PostgreSQL 12 and later, if "postgresql.auto.conf" on the demotion
candidate (current primary) has incorrect ownership (e.g. owned by
root), repmgr will very likely not be able to modify this file and
write the replication configuration required for the node to rejoin
the cluster as a standby.

Checks added to catch both cases before a switchover is executed.
This commit is contained in:
Ian Barwick
2020-03-04 11:35:52 +09:00
parent 194b6d0948
commit 8f6058c676
5 changed files with 287 additions and 3 deletions

View File

@@ -533,6 +533,10 @@ main(int argc, char **argv)
runtime_options.data_directory_config = true;
break;
case OPT_REPLICATION_CONFIG_OWNER:
runtime_options.replication_config_owner = true;
break;
/*--------------------
* "node rejoin" options
*--------------------
@@ -4205,6 +4209,91 @@ check_node_can_attach(TimeLineID local_tli, XLogRecPtr local_xlogpos, PGconn *fo
}
/*
* Check that the replication configuration file is owned by the user who
* owns the data directory.
*/
extern bool
check_replication_config_owner(int pg_version, const char *data_directory, PQExpBufferData *error_msg, PQExpBufferData *detail_msg)
{
PQExpBufferData replication_config_file;
struct stat dirstat;
struct stat confstat;
if (stat(data_directory, &dirstat))
{
if (error_msg != NULL)
{
appendPQExpBuffer(error_msg,
"unable to check ownership of data directory \"%s\"",
data_directory);
appendPQExpBufferStr(detail_msg,
strerror(errno));
}
return false;
}
initPQExpBuffer(&replication_config_file);
appendPQExpBuffer(&replication_config_file,
"%s/%s",
config_file_options.data_directory,
pg_version >= 120000 ? PG_AUTOCONF_FILENAME : RECOVERY_COMMAND_FILE);
stat(replication_config_file.data, &confstat);
if (confstat.st_uid == dirstat.st_uid)
{
termPQExpBuffer(&replication_config_file);
return true;
}
if (error_msg != NULL)
{
char conf_owner[MAXLEN];
char dir_owner[MAXLEN];
struct passwd *pw;
pw = getpwuid(confstat.st_uid);
if (!pw)
{
maxlen_snprintf(conf_owner,
"(unknown user %i)",
confstat.st_uid);
}
else
{
strncpy(conf_owner, pw->pw_name, MAXLEN);
}
pw = getpwuid(dirstat.st_uid);
if (!pw)
{
maxlen_snprintf(conf_owner,
"(unknown user %i)",
dirstat.st_uid);
}
else
{
strncpy(dir_owner, pw->pw_name, MAXLEN);
}
appendPQExpBuffer(error_msg,
"ownership error for file \"%s\"",
replication_config_file.data);
appendPQExpBuffer(detail_msg,
"file owner is \"%s\", data directory owner is \"%s\"",
conf_owner,
dir_owner);
}
termPQExpBuffer(&replication_config_file);
return false;
}
/*
* Simple check to see if "shared_preload_libraries" includes "repmgr".
* Parsing "shared_preload_libraries" is non-trivial, as it's potentially