summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane2008-01-03 21:29:07 +0000
committerTom Lane2008-01-03 21:29:07 +0000
commitd3b3ca9277f8a5b0eb24010f61fe9591711ae33e (patch)
tree4eaa3c11ccba655df39105a7e23a9adf13ae83ce
parenta60e6a0fcec97d7fbec98739d96cfd14dd3fb71b (diff)
The original patch to disallow non-passworded connections to non-superusers
failed to cover all the ways in which a connection can be initiated in dblink. Plug the remaining holes. Also, disallow transient connections in functions for which that feature makes no sense (because they are only sensible as part of a sequence of operations on the same connection). Joe Conway Security: CVE-2007-6601
-rw-r--r--contrib/dblink/dblink.c76
-rw-r--r--contrib/dblink/expected/dblink.out37
-rw-r--r--contrib/dblink/sql/dblink.sql9
3 files changed, 85 insertions, 37 deletions
diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 29734c0fdd..9ee6ae8aab 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -91,6 +91,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_security_check(PGconn *conn, remoteConn *rconn);
/* Global */
static remoteConn *pconn = NULL;
@@ -187,10 +188,21 @@ typedef struct remoteConnHashEnt
errmsg("could not establish connection"), \
errdetail("%s", msg))); \
} \
+ dblink_security_check(conn, rconn); \
freeconn = true; \
} \
} while (0)
+#define DBLINK_GET_NAMED_CONN \
+ do { \
+ char *conname = GET_STR(PG_GETARG_TEXT_P(0)); \
+ rconn = getConnectionByName(conname); \
+ if(rconn) \
+ conn = rconn->conn; \
+ else \
+ DBLINK_CONN_NOT_AVAIL; \
+ } while (0)
+
#define DBLINK_INIT \
do { \
if (!pconn) \
@@ -247,21 +259,8 @@ dblink_connect(PG_FUNCTION_ARGS)
errdetail("%s", msg)));
}
- if (!superuser())
- {
- if (!PQconnectionUsedPassword(conn))
- {
- PQfinish(conn);
- if (rconn)
- pfree(rconn);
-
- 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.")));
- }
- }
+ /* check password used if not superuser */
+ dblink_security_check(conn, rconn);
if (connname)
{
@@ -1047,17 +1046,11 @@ PG_FUNCTION_INFO_V1(dblink_is_busy);
Datum
dblink_is_busy(PG_FUNCTION_ARGS)
{
- char *msg;
PGconn *conn = NULL;
- char *conname = NULL;
- char *connstr = NULL;
remoteConn *rconn = NULL;
- bool freeconn = false;
DBLINK_INIT;
- DBLINK_GET_CONN;
- if (!conn)
- DBLINK_CONN_NOT_AVAIL;
+ DBLINK_GET_NAMED_CONN;
PQconsumeInput(conn);
PG_RETURN_INT32(PQisBusy(conn));
@@ -1078,26 +1071,20 @@ PG_FUNCTION_INFO_V1(dblink_cancel_query);
Datum
dblink_cancel_query(PG_FUNCTION_ARGS)
{
- char *msg;
int res = 0;
PGconn *conn = NULL;
- char *conname = NULL;
- char *connstr = NULL;
remoteConn *rconn = NULL;
- bool freeconn = false;
PGcancel *cancel;
char errbuf[256];
DBLINK_INIT;
- DBLINK_GET_CONN;
- if (!conn)
- DBLINK_CONN_NOT_AVAIL;
+ DBLINK_GET_NAMED_CONN;
cancel = PQgetCancel(conn);
res = PQcancel(cancel, errbuf, 256);
PQfreeCancel(cancel);
- if (res == 0)
+ if (res == 1)
PG_RETURN_TEXT_P(GET_TEXT("OK"));
else
PG_RETURN_TEXT_P(GET_TEXT(errbuf));
@@ -1120,18 +1107,13 @@ dblink_error_message(PG_FUNCTION_ARGS)
{
char *msg;
PGconn *conn = NULL;
- char *conname = NULL;
- char *connstr = NULL;
remoteConn *rconn = NULL;
- bool freeconn = false;
DBLINK_INIT;
- DBLINK_GET_CONN;
- if (!conn)
- DBLINK_CONN_NOT_AVAIL;
+ DBLINK_GET_NAMED_CONN;
msg = PQerrorMessage(conn);
- if (!msg)
+ if (msg == NULL || msg[0] == '\0')
PG_RETURN_TEXT_P(GET_TEXT("OK"));
else
PG_RETURN_TEXT_P(GET_TEXT(msg));
@@ -2299,3 +2281,23 @@ deleteConnection(const char *name)
errmsg("undefined connection name")));
}
+
+static void
+dblink_security_check(PGconn *conn, remoteConn *rconn)
+{
+ if (!superuser())
+ {
+ if (!PQconnectionUsedPassword(conn))
+ {
+ PQfinish(conn);
+ if (rconn)
+ pfree(rconn);
+
+ 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.")));
+ }
+ }
+}
diff --git a/contrib/dblink/expected/dblink.out b/contrib/dblink/expected/dblink.out
index bdd2f9926f..fd35d76af9 100644
--- a/contrib/dblink/expected/dblink.out
+++ b/contrib/dblink/expected/dblink.out
@@ -724,6 +724,12 @@ SELECT dblink_get_connections();
{dtest1,dtest2,dtest3}
(1 row)
+SELECT dblink_is_busy('dtest1');
+ dblink_is_busy
+----------------
+ 0
+(1 row)
+
SELECT dblink_disconnect('dtest1');
dblink_disconnect
-------------------
@@ -758,3 +764,34 @@ SELECT * from result;
10 | k | {a10,b10,c10}
(11 rows)
+SELECT dblink_connect('dtest1', 'dbname=contrib_regression');
+ dblink_connect
+----------------
+ OK
+(1 row)
+
+SELECT * from
+ dblink_send_query('dtest1', 'select * from foo where f1 < 3') as t1;
+ t1
+----
+ 1
+(1 row)
+
+SELECT dblink_cancel_query('dtest1');
+ dblink_cancel_query
+---------------------
+ OK
+(1 row)
+
+SELECT dblink_error_message('dtest1');
+ dblink_error_message
+----------------------
+ OK
+(1 row)
+
+SELECT dblink_disconnect('dtest1');
+ dblink_disconnect
+-------------------
+ OK
+(1 row)
+
diff --git a/contrib/dblink/sql/dblink.sql b/contrib/dblink/sql/dblink.sql
index 277500e6f1..48e1daca54 100644
--- a/contrib/dblink/sql/dblink.sql
+++ b/contrib/dblink/sql/dblink.sql
@@ -344,9 +344,18 @@ UNION
ORDER by f1;
SELECT dblink_get_connections();
+SELECT dblink_is_busy('dtest1');
SELECT dblink_disconnect('dtest1');
SELECT dblink_disconnect('dtest2');
SELECT dblink_disconnect('dtest3');
+
SELECT * from result;
+SELECT dblink_connect('dtest1', 'dbname=contrib_regression');
+SELECT * from
+ dblink_send_query('dtest1', 'select * from foo where f1 < 3') as t1;
+
+SELECT dblink_cancel_query('dtest1');
+SELECT dblink_error_message('dtest1');
+SELECT dblink_disconnect('dtest1');