1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-27 12:41:57 +03:00

Fix dblink_connect() so that it verifies that a password is supplied in the

conninfo string *before* trying to connect to the remote server, not after.
As pointed out by Marko Kreen, in certain not-very-plausible situations
this could result in sending a password from the postgres user's .pgpass file,
or other places that non-superusers shouldn't have access to, to an
untrustworthy remote server.  The cleanest fix seems to be to expose libpq's
conninfo-string-parsing code so that dblink can check for a password option
without duplicating the parsing logic.

Joe Conway, with a little cleanup by Tom Lane
This commit is contained in:
Tom Lane
2008-09-22 13:55:14 +00:00
parent 579c025e5f
commit cae7ad906a
6 changed files with 226 additions and 50 deletions

View File

@ -8,7 +8,7 @@
* Darko Prenosil <Darko.Prenosil@finteh.hr>
* Shridhar Daithankar <shridhar_daithankar@persistent.co.in>
*
* $PostgreSQL: pgsql/contrib/dblink/dblink.c,v 1.74 2008/07/03 03:56:57 joe Exp $
* $PostgreSQL: pgsql/contrib/dblink/dblink.c,v 1.75 2008/09/22 13:55:13 tgl Exp $
* Copyright (c) 2001-2008, PostgreSQL Global Development Group
* ALL RIGHTS RESERVED;
*
@ -93,6 +93,7 @@ static int16 get_attnum_pk_pos(int2vector *pkattnums, int16 pknumatts, int16 key
static HeapTuple get_tuple_of_interest(Oid relid, int2vector *pkattnums, int16 pknumatts, char **src_pkattvals);
static Oid get_relid_from_relname(text *relname_text);
static char *generate_relation_name(Oid relid);
static void dblink_connstr_check(const char *connstr);
static void dblink_security_check(PGconn *conn, remoteConn *rconn);
static void dblink_res_error(const char *conname, PGresult *res, const char *dblink_context_msg, bool fail);
@ -165,6 +166,7 @@ typedef struct remoteConnHashEnt
else \
{ \
connstr = conname_or_str; \
dblink_connstr_check(connstr); \
conn = PQconnectdb(connstr); \
if (PQstatus(conn) == CONNECTION_BAD) \
{ \
@ -229,6 +231,9 @@ dblink_connect(PG_FUNCTION_ARGS)
if (connname)
rconn = (remoteConn *) palloc(sizeof(remoteConn));
/* check password in connection string if not superuser */
dblink_connstr_check(connstr);
conn = PQconnectdb(connstr);
MemoryContextSwitchTo(oldcontext);
@ -246,7 +251,7 @@ dblink_connect(PG_FUNCTION_ARGS)
errdetail("%s", msg)));
}
/* check password used if not superuser */
/* check password actually used if not superuser */
dblink_security_check(conn, rconn);
if (connname)
@ -2251,6 +2256,46 @@ dblink_security_check(PGconn *conn, remoteConn *rconn)
}
}
/*
* For non-superusers, insist that the connstr specify a password. 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
* to be accessible to non-superusers.
*/
static void
dblink_connstr_check(const char *connstr)
{
if (!superuser())
{
PQconninfoOption *options;
PQconninfoOption *option;
bool connstr_gives_password = false;
options = PQconninfoParse(connstr, NULL);
if (options)
{
for (option = options; option->keyword != NULL; option++)
{
if (strcmp(option->keyword, "password") == 0)
{
if (option->val != NULL && option->val[0] != '\0')
{
connstr_gives_password = true;
break;
}
}
}
PQconninfoFree(options);
}
if (!connstr_gives_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.")));
}
}
static void
dblink_res_error(const char *conname, PGresult *res, const char *dblink_context_msg, bool fail)
{