aboutsummaryrefslogtreecommitdiff
path: root/contrib/postgres_fdw/connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/postgres_fdw/connection.c')
-rw-r--r--contrib/postgres_fdw/connection.c72
1 files changed, 56 insertions, 16 deletions
diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c
index 2969351e9a9..75d93d6eadf 100644
--- a/contrib/postgres_fdw/connection.c
+++ b/contrib/postgres_fdw/connection.c
@@ -17,6 +17,7 @@
#include "catalog/pg_user_mapping.h"
#include "commands/defrem.h"
#include "funcapi.h"
+#include "libpq/libpq-be.h"
#include "libpq/libpq-be-fe-helpers.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
@@ -149,6 +150,8 @@ static void pgfdw_finish_pre_subcommit_cleanup(List *pending_entries,
static void pgfdw_finish_abort_cleanup(List *pending_entries,
List *cancel_requested,
bool toplevel);
+static void pgfdw_security_check(const char **keywords, const char **values,
+ UserMapping *user, PGconn *conn);
static bool UserMappingPasswordRequired(UserMapping *user);
static bool disconnect_cached_connections(Oid serverid);
@@ -385,6 +388,47 @@ make_new_connection(ConnCacheEntry *entry, UserMapping *user)
}
/*
+ * Check that non-superuser has used password or delegated credentials
+ * to establish connection; otherwise, he's piggybacking on the
+ * postgres server's user identity. See also dblink_security_check()
+ * in contrib/dblink and check_conn_params.
+ */
+static void
+pgfdw_security_check(const char **keywords, const char **values, UserMapping *user, PGconn *conn)
+{
+ /* Superusers bypass the check */
+ if (superuser_arg(user->userid))
+ return;
+
+#ifdef ENABLE_GSS
+ /* Connected via GSSAPI with delegated credentials- all good. */
+ if (PQconnectionUsedGSSAPI(conn) && be_gssapi_get_deleg(MyProcPort))
+ return;
+#endif
+
+ /* Ok if superuser set PW required false. */
+ if (!UserMappingPasswordRequired(user))
+ return;
+
+ /* Connected via PW, with PW required true, and provided non-empty PW. */
+ if (PQconnectionUsedPassword(conn))
+ {
+ /* ok if params contain a non-empty password */
+ for (int i = 0; keywords[i] != NULL; i++)
+ {
+ if (strcmp(keywords[i], "password") == 0 && values[i][0] != '\0')
+ return;
+ }
+ }
+
+ ereport(ERROR,
+ (errcode(ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED),
+ errmsg("password or GSSAPI delegated credentials required"),
+ errdetail("Non-superuser cannot connect if the server does not request a password or use GSSAPI with delegated credentials."),
+ errhint("Target server's authentication method must be changed or password_required=false set in the user mapping attributes.")));
+}
+
+/*
* Connect to remote server using specified server and user mapping properties.
*/
static PGconn *
@@ -495,19 +539,8 @@ connect_pg_server(ForeignServer *server, UserMapping *user)
server->servername),
errdetail_internal("%s", pchomp(PQerrorMessage(conn)))));
- /*
- * Check that non-superuser has used password to establish connection;
- * otherwise, he's piggybacking on the postgres server's user
- * identity. See also dblink_security_check() in contrib/dblink and
- * check_conn_params.
- */
- if (!superuser_arg(user->userid) && UserMappingPasswordRequired(user) &&
- !PQconnectionUsedPassword(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 password_required=false set in the user mapping attributes.")));
+ /* Perform post-connection security checks */
+ pgfdw_security_check(keywords, values, user, conn);
/* Prepare new session for use */
configure_remote_session(conn);
@@ -561,7 +594,8 @@ UserMappingPasswordRequired(UserMapping *user)
}
/*
- * For non-superusers, insist that the connstr specify a password. This
+ * For non-superusers, insist that the connstr specify a password or that the
+ * user provided their own GSSAPI delegated credentials. This
* prevents a password from being picked up from .pgpass, a service file, the
* environment, etc. We don't want the postgres user's passwords,
* certificates, etc to be accessible to non-superusers. (See also
@@ -576,6 +610,12 @@ check_conn_params(const char **keywords, const char **values, UserMapping *user)
if (superuser_arg(user->userid))
return;
+#ifdef ENABLE_GSS
+ /* ok if the user provided their own delegated credentials */
+ if (be_gssapi_get_deleg(MyProcPort))
+ return;
+#endif
+
/* ok if params contain a non-empty password */
for (i = 0; keywords[i] != NULL; i++)
{
@@ -589,8 +629,8 @@ check_conn_params(const char **keywords, const char **values, UserMapping *user)
ereport(ERROR,
(errcode(ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED),
- errmsg("password is required"),
- errdetail("Non-superusers must provide a password in the user mapping.")));
+ errmsg("password or GSSAPI delegated credentials required"),
+ errdetail("Non-superusers must delegate GSSAPI credentials or provide a password in the user mapping.")));
}
/*