diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2008-09-22 13:55:14 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2008-09-22 13:55:14 +0000 |
commit | cae7ad906a0337120afe856b0a76b03b8ffc7440 (patch) | |
tree | ed5c181dfee6f69d46ecff8eaeaef77035c0466b /src | |
parent | 579c025e5fc8d3cc42fc65e1b23da20c9c9f4866 (diff) | |
download | postgresql-cae7ad906a0337120afe856b0a76b03b8ffc7440.tar.gz postgresql-cae7ad906a0337120afe856b0a76b03b8ffc7440.zip |
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
Diffstat (limited to 'src')
-rw-r--r-- | src/interfaces/libpq/exports.txt | 3 | ||||
-rw-r--r-- | src/interfaces/libpq/fe-connect.c | 62 | ||||
-rw-r--r-- | src/interfaces/libpq/libpq-fe.h | 10 |
3 files changed, 65 insertions, 10 deletions
diff --git a/src/interfaces/libpq/exports.txt b/src/interfaces/libpq/exports.txt index eeabe40671e..655968e5f32 100644 --- a/src/interfaces/libpq/exports.txt +++ b/src/interfaces/libpq/exports.txt @@ -1,4 +1,4 @@ -# $PostgreSQL: pgsql/src/interfaces/libpq/exports.txt,v 1.21 2008/09/19 20:06:13 tgl Exp $ +# $PostgreSQL: pgsql/src/interfaces/libpq/exports.txt,v 1.22 2008/09/22 13:55:14 tgl Exp $ # Functions to be exported by libpq DLLs PQconnectdb 1 PQsetdbLogin 2 @@ -151,3 +151,4 @@ PQsetInstanceData 148 PQresultInstanceData 149 PQresultSetInstanceData 150 PQfireResultCreateEvents 151 +PQconninfoParse 152 diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 7e77c9a5c7a..bd70679aa2d 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.360 2008/09/17 04:31:08 tgl Exp $ + * $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.361 2008/09/22 13:55:14 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -232,7 +232,8 @@ static PGconn *makeEmptyPGconn(void); static void freePGconn(PGconn *conn); static void closePGconn(PGconn *conn); static PQconninfoOption *conninfo_parse(const char *conninfo, - PQExpBuffer errorMessage, bool *password_from_string); + PQExpBuffer errorMessage, bool use_defaults, + bool *password_from_string); static char *conninfo_getval(PQconninfoOption *connOptions, const char *keyword); static void defaultNoticeReceiver(void *arg, const PGresult *res); @@ -376,7 +377,7 @@ connectOptions1(PGconn *conn, const char *conninfo) /* * Parse the conninfo string */ - connOptions = conninfo_parse(conninfo, &conn->errorMessage, + connOptions = conninfo_parse(conninfo, &conn->errorMessage, true, &conn->pgpass_from_client); if (connOptions == NULL) { @@ -542,7 +543,9 @@ connectOptions2(PGconn *conn) * PQconndefaults * * Parse an empty string like PQconnectdb() would do and return the - * working connection options array. + * resulting connection options array, ie, all the default values that are + * available from the environment etc. On error (eg out of memory), + * NULL is returned. * * Using this function, an application may determine all possible options * and their current default values. @@ -561,7 +564,10 @@ PQconndefaults(void) PQconninfoOption *connOptions; initPQExpBuffer(&errorBuf); - connOptions = conninfo_parse("", &errorBuf, &password_from_string); + if (errorBuf.data == NULL) + return NULL; /* out of memory already :-( */ + connOptions = conninfo_parse("", &errorBuf, true, + &password_from_string); termPQExpBuffer(&errorBuf); return connOptions; } @@ -3103,17 +3109,55 @@ parseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage) /* + * PQconninfoParse + * + * Parse a string like PQconnectdb() would do and return the + * resulting connection options array. NULL is returned on failure. + * The result contains only options specified directly in the string, + * not any possible default values. + * + * If errmsg isn't NULL, *errmsg is set to NULL on success, or a malloc'd + * string on failure (use PQfreemem to free it). In out-of-memory conditions + * both *errmsg and the result could be NULL. + * + * NOTE: the returned array is dynamically allocated and should + * be freed when no longer needed via PQconninfoFree(). + */ +PQconninfoOption * +PQconninfoParse(const char *conninfo, char **errmsg) +{ + PQExpBufferData errorBuf; + bool password_from_string; + PQconninfoOption *connOptions; + + if (errmsg) + *errmsg = NULL; /* default */ + initPQExpBuffer(&errorBuf); + if (errorBuf.data == NULL) + return NULL; /* out of memory already :-( */ + connOptions = conninfo_parse(conninfo, &errorBuf, false, + &password_from_string); + if (connOptions == NULL && errmsg) + *errmsg = errorBuf.data; + else + termPQExpBuffer(&errorBuf); + return connOptions; +} + +/* * Conninfo parser routine * * If successful, a malloc'd PQconninfoOption array is returned. * If not successful, NULL is returned and an error message is * left in errorMessage. + * Defaults are supplied (from a service file, environment variables, etc) + * for unspecified options, but only if use_defaults is TRUE. * *password_from_string is set TRUE if we got a password from the * conninfo string, otherwise FALSE. */ static PQconninfoOption * conninfo_parse(const char *conninfo, PQExpBuffer errorMessage, - bool *password_from_string) + bool use_defaults, bool *password_from_string) { char *pname; char *pval; @@ -3294,6 +3338,12 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage, free(buf); /* + * Stop here if caller doesn't want defaults filled in. + */ + if (!use_defaults) + return options; + + /* * If there's a service spec, use it to obtain any not-explicitly-given * parameters. */ diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h index f923b968408..85552d5e34b 100644 --- a/src/interfaces/libpq/libpq-fe.h +++ b/src/interfaces/libpq/libpq-fe.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-fe.h,v 1.143 2008/09/17 04:31:08 tgl Exp $ + * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-fe.h,v 1.144 2008/09/22 13:55:14 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -164,6 +164,7 @@ typedef struct _PQprintOpt /* ---------------- * Structure for the conninfo parameter definitions returned by PQconndefaults + * or PQconninfoParse. * * All fields except "val" point at static strings which must not be altered. * "val" is either NULL or a malloc'd current-value string. PQconninfoFree() @@ -177,7 +178,7 @@ typedef struct _PQconninfoOption char *compiled; /* Fallback compiled in default value */ char *val; /* Option's current value, or NULL */ char *label; /* Label for field in connect dialog */ - char *dispchar; /* Character to display for this field in a + char *dispchar; /* Indicates how to display this field in a * connect dialog. Values are: "" Display * entered value as is "*" Password field - * hide value "D" Debug option - don't show @@ -243,7 +244,10 @@ extern void PQfinish(PGconn *conn); /* get info about connection options known to PQconnectdb */ extern PQconninfoOption *PQconndefaults(void); -/* free the data structure returned by PQconndefaults() */ +/* parse connection options in same way as PQconnectdb */ +extern PQconninfoOption *PQconninfoParse(const char *conninfo, char **errmsg); + +/* free the data structure returned by PQconndefaults() or PQconninfoParse() */ extern void PQconninfoFree(PQconninfoOption *connOptions); /* |