Commit ab3f008a authored by Robert Haas's avatar Robert Haas

postgres_fdw: Judge password use by run-as user, not session user.

This is a backward incompatibility which should be noted in the
release notes for PostgreSQL 11.

For security reasons, we require that a postgres_fdw foreign table use
password authentication when accessing a remote server, so that an
unprivileged user cannot usurp the server's credentials.  Superusers
are exempt from this requirement, because we assume they are entitled
to usurp the server's credentials or, at least, can find some other
way to do it.

But what should happen when the foreign table is accessed by a view
owned by a user different from the session user?  Is it the view owner
that must be a superuser in order to avoid the requirement of using a
password, or the session user?  Historically it was the latter, but
this requirement makes it the former instead.  This allows superusers
to delegate to other users the right to select from a foreign table
that doesn't use password authentication by creating a view over the
foreign table and handing out rights to the view.  It is also more
consistent with the idea that access to a view should use the view
owner's privileges rather than the session user's privileges.

The upshot of this change is that a superuser selecting from a view
created by a non-superuser may now get an error complaining that no
password was used, while a non-superuser selecting from a view
created by a superuser will no longer receive such an error.

No documentation changes are present in this patch because the
wording of the documentation already suggests that it works this
way.  We should perhaps adjust the documentation in the back-branches,
but that's a task for another patch.

Originally proposed by Jeff Janes, but with different semantics;
adjusted to work like this by me per discussion.

Discussion: http://postgr.es/m/CA+TgmoaY4HsVZJv5SqEjCKLDwtCTSwXzKpRftgj50wmMMBwciA@mail.gmail.com
parent c572599c
...@@ -75,7 +75,7 @@ static bool xact_got_connection = false; ...@@ -75,7 +75,7 @@ static bool xact_got_connection = false;
/* prototypes of private functions */ /* prototypes of private functions */
static PGconn *connect_pg_server(ForeignServer *server, UserMapping *user); static PGconn *connect_pg_server(ForeignServer *server, UserMapping *user);
static void disconnect_pg_server(ConnCacheEntry *entry); static void disconnect_pg_server(ConnCacheEntry *entry);
static void check_conn_params(const char **keywords, const char **values); static void check_conn_params(const char **keywords, const char **values, UserMapping *user);
static void configure_remote_session(PGconn *conn); static void configure_remote_session(PGconn *conn);
static void do_sql_command(PGconn *conn, const char *sql); static void do_sql_command(PGconn *conn, const char *sql);
static void begin_remote_xact(ConnCacheEntry *entry); static void begin_remote_xact(ConnCacheEntry *entry);
...@@ -261,7 +261,7 @@ connect_pg_server(ForeignServer *server, UserMapping *user) ...@@ -261,7 +261,7 @@ connect_pg_server(ForeignServer *server, UserMapping *user)
keywords[n] = values[n] = NULL; keywords[n] = values[n] = NULL;
/* verify connection parameters and make connection */ /* verify connection parameters and make connection */
check_conn_params(keywords, values); check_conn_params(keywords, values, user);
conn = PQconnectdbParams(keywords, values, false); conn = PQconnectdbParams(keywords, values, false);
if (!conn || PQstatus(conn) != CONNECTION_OK) if (!conn || PQstatus(conn) != CONNECTION_OK)
...@@ -276,7 +276,7 @@ connect_pg_server(ForeignServer *server, UserMapping *user) ...@@ -276,7 +276,7 @@ connect_pg_server(ForeignServer *server, UserMapping *user)
* otherwise, he's piggybacking on the postgres server's user * otherwise, he's piggybacking on the postgres server's user
* identity. See also dblink_security_check() in contrib/dblink. * identity. See also dblink_security_check() in contrib/dblink.
*/ */
if (!superuser() && !PQconnectionUsedPassword(conn)) if (!superuser_arg(user->userid) && !PQconnectionUsedPassword(conn))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED), (errcode(ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED),
errmsg("password is required"), errmsg("password is required"),
...@@ -322,12 +322,12 @@ disconnect_pg_server(ConnCacheEntry *entry) ...@@ -322,12 +322,12 @@ disconnect_pg_server(ConnCacheEntry *entry)
* contrib/dblink.) * contrib/dblink.)
*/ */
static void static void
check_conn_params(const char **keywords, const char **values) check_conn_params(const char **keywords, const char **values, UserMapping *user)
{ {
int i; int i;
/* no check required if superuser */ /* no check required if superuser */
if (superuser()) if (superuser_arg(user->userid))
return; return;
/* ok if params contain a non-empty password */ /* ok if params contain a non-empty password */
......
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