diff options
Diffstat (limited to 'src/backend/replication')
-rw-r--r-- | src/backend/replication/libpqwalreceiver/libpqwalreceiver.c | 65 | ||||
-rw-r--r-- | src/backend/replication/logical/tablesync.c | 9 | ||||
-rw-r--r-- | src/backend/replication/logical/worker.c | 6 | ||||
-rw-r--r-- | src/backend/replication/walreceiver.c | 2 |
4 files changed, 72 insertions, 10 deletions
diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c index 560ec974fa7..052505e46f8 100644 --- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c +++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c @@ -49,9 +49,10 @@ struct WalReceiverConn /* Prototypes for interface functions */ static WalReceiverConn *libpqrcv_connect(const char *conninfo, - bool logical, const char *appname, - char **err); -static void libpqrcv_check_conninfo(const char *conninfo); + bool logical, bool must_use_password, + const char *appname, char **err); +static void libpqrcv_check_conninfo(const char *conninfo, + bool must_use_password); static char *libpqrcv_get_conninfo(WalReceiverConn *conn); static void libpqrcv_get_senderinfo(WalReceiverConn *conn, char **sender_host, int *sender_port); @@ -119,11 +120,17 @@ _PG_init(void) /* * Establish the connection to the primary server for XLOG streaming * - * Returns NULL on error and fills the err with palloc'ed error message. + * If an error occurs, this function will normally return NULL and set *err + * to a palloc'ed error message. However, if must_use_password is true and + * the connection fails to use the password, this function will ereport(ERROR). + * We do this because in that case the error includes a detail and a hint for + * consistency with other parts of the system, and it's not worth adding the + * machinery to pass all of those back to the caller just to cover this one + * case. */ static WalReceiverConn * -libpqrcv_connect(const char *conninfo, bool logical, const char *appname, - char **err) +libpqrcv_connect(const char *conninfo, bool logical, bool must_use_password, + const char *appname, char **err) { WalReceiverConn *conn; const char *keys[6]; @@ -180,6 +187,18 @@ libpqrcv_connect(const char *conninfo, bool logical, const char *appname, if (PQstatus(conn->streamConn) != CONNECTION_OK) goto bad_connection_errmsg; + if (must_use_password && !PQconnectionUsedPassword(conn->streamConn)) + { + libpqsrv_disconnect(conn->streamConn); + pfree(conn); + + ereport(ERROR, + (errcode(ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED), + errmsg("password is required"), + errdetail("Non-superuser cannot connect if the server does not request a password."), + errhint("Target server's authentication method must be changed. or set password_required=false in the subscription attributes."))); + } + if (logical) { PGresult *res; @@ -212,12 +231,18 @@ bad_connection: } /* - * Validate connection info string (just try to parse it) + * Validate connection info string, and determine whether it might cause + * local filesystem access to be attempted. + * + * If the connection string can't be parsed, this function will raise + * an error and will not return. If it can, it will return true if this + * connection string specifies a password and false otherwise. */ static void -libpqrcv_check_conninfo(const char *conninfo) +libpqrcv_check_conninfo(const char *conninfo, bool must_use_password) { PQconninfoOption *opts = NULL; + PQconninfoOption *opt; char *err = NULL; opts = PQconninfoParse(conninfo, &err); @@ -232,6 +257,30 @@ libpqrcv_check_conninfo(const char *conninfo) errmsg("invalid connection string syntax: %s", errcopy))); } + if (must_use_password) + { + bool uses_password = false; + + for (opt = opts; opt->keyword != NULL; ++opt) + { + /* Ignore connection options that are not present. */ + if (opt->val == NULL) + continue; + + if (strcmp(opt->keyword, "password") == 0 && opt->val[0] != '\0') + { + uses_password = true; + break; + } + } + + if (!uses_password) + ereport(ERROR, + (errcode(ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED), + errmsg("password is required"), + errdetail("Non-superusers must provide a password in the connection string."))); + } + PQconninfoFree(opts); } diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c index fb6d5474d00..6dce3556332 100644 --- a/src/backend/replication/logical/tablesync.c +++ b/src/backend/replication/logical/tablesync.c @@ -1252,6 +1252,7 @@ LogicalRepSyncTableStart(XLogRecPtr *origin_startpos) WalRcvExecResult *res; char originname[NAMEDATALEN]; RepOriginId originid; + bool must_use_password; /* Check the state of the table synchronization. */ StartTransactionCommand(); @@ -1284,13 +1285,19 @@ LogicalRepSyncTableStart(XLogRecPtr *origin_startpos) slotname, NAMEDATALEN); + /* Is the use of a password mandatory? */ + must_use_password = MySubscription->passwordrequired && + !superuser_arg(MySubscription->owner); + /* * Here we use the slot name instead of the subscription name as the * application_name, so that it is different from the leader apply worker, * so that synchronous replication can distinguish them. */ LogRepWorkerWalRcvConn = - walrcv_connect(MySubscription->conninfo, true, slotname, &err); + walrcv_connect(MySubscription->conninfo, true, + must_use_password, + slotname, &err); if (LogRepWorkerWalRcvConn == NULL) ereport(ERROR, (errcode(ERRCODE_CONNECTION_FAILURE), diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c index 10f97119727..6fd674b5d60 100644 --- a/src/backend/replication/logical/worker.c +++ b/src/backend/replication/logical/worker.c @@ -4521,6 +4521,7 @@ ApplyWorkerMain(Datum main_arg) RepOriginId originid; TimeLineID startpointTLI; char *err; + bool must_use_password; myslotname = MySubscription->slotname; @@ -4546,7 +4547,12 @@ ApplyWorkerMain(Datum main_arg) origin_startpos = replorigin_session_get_progress(false); CommitTransactionCommand(); + /* Is the use of a password mandatory? */ + must_use_password = MySubscription->passwordrequired && + !superuser_arg(MySubscription->owner); + LogRepWorkerWalRcvConn = walrcv_connect(MySubscription->conninfo, true, + must_use_password, MySubscription->name, &err); if (LogRepWorkerWalRcvConn == NULL) ereport(ERROR, diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c index f6446da2d6d..685af51d5d3 100644 --- a/src/backend/replication/walreceiver.c +++ b/src/backend/replication/walreceiver.c @@ -296,7 +296,7 @@ WalReceiverMain(void) sigprocmask(SIG_SETMASK, &UnBlockSig, NULL); /* Establish the connection to the primary for XLOG streaming */ - wrconn = walrcv_connect(conninfo, false, + wrconn = walrcv_connect(conninfo, false, false, cluster_name[0] ? cluster_name : "walreceiver", &err); if (!wrconn) |