diff -durpN postgresql/doc/src/sgml/libpq.sgml postgresql.1/doc/src/sgml/libpq.sgml --- postgresql/doc/src/sgml/libpq.sgml 2012-08-03 09:39:30.114266570 +0200 +++ postgresql.1/doc/src/sgml/libpq.sgml 2012-11-20 11:57:41.359859195 +0100 @@ -496,6 +496,49 @@ typedef struct + + PQconninfoPQconninfo + + + Returns the connection options used by a live connection. + +/* + * Option flags for PQconninfo + */ +#define PG_CONNINFO_NORMAL 0x01 +#define PG_CONNINFO_PASSWORD 0x02 +#define PG_CONNINFO_REPLICATION 0x04 + +PQconninfoOption *PQconninfo(PGconn *conn, int flags); + + + + + Returns a connection options array. This can be used to determine + all possible PQconnectdb options and their + current values that were used to connect to the server. The return + value points to an array of PQconninfoOption + structures, which ends with an entry having a null keyword + pointer. Every notes above for PQconndefaults also apply. + An application may present a dialog using the previous settings by: + + PQconninfoOption *options = PQconninfo(conn, PG_CONNINFO_NORMAL | PG_CONNINFO_PASSWORD); + + + + + The array returned by the PG_CONNINFO_REPLICATION flag is + a subset of PG_CONNINFO_NORMAL | PG_CONNINFO_PASSWORD. + This subset excludes some options from the array which are used by the + walreceiver module. pg_basebackup uses this + pre-filtered list of options to construct primary_conninfo + in the automatically generated recovery.conf file. + + + + + + PQconninfoParsePQconninfoParse diff -durpN postgresql/src/interfaces/libpq/exports.txt postgresql.1/src/interfaces/libpq/exports.txt --- postgresql/src/interfaces/libpq/exports.txt 2012-10-09 09:58:14.342782974 +0200 +++ postgresql.1/src/interfaces/libpq/exports.txt 2012-11-20 10:55:03.396145749 +0100 @@ -164,3 +164,4 @@ PQsetSingleRowMode 161 lo_lseek64 162 lo_tell64 163 lo_truncate64 164 +PQconninfo 165 diff -durpN postgresql/src/interfaces/libpq/fe-connect.c postgresql.1/src/interfaces/libpq/fe-connect.c --- postgresql/src/interfaces/libpq/fe-connect.c 2012-09-09 08:11:09.470401480 +0200 +++ postgresql.1/src/interfaces/libpq/fe-connect.c 2012-11-20 16:25:11.722295729 +0100 @@ -137,6 +137,9 @@ static int ldapServiceLookup(const char * PQconninfoOptions[] *must* be NULL. In a working copy, non-null "val" * fields point to malloc'd strings that should be freed when the working * array is freed (see PQconninfoFree). + * + * If you add a new connection option to this list, remember to add it to + * PQconninfoMappings[] below. * ---------- */ static const PQconninfoOption PQconninfoOptions[] = { @@ -203,16 +206,6 @@ static const PQconninfoOption PQconninfo {"keepalives_count", NULL, NULL, NULL, "TCP-Keepalives-Count", "", 10}, /* strlen(INT32_MAX) == 10 */ -#ifdef USE_SSL - - /* - * "requiressl" is deprecated, its purpose having been taken over by - * "sslmode". It remains for backwards compatibility. - */ - {"requiressl", "PGREQUIRESSL", "0", NULL, - "Require-SSL", "D", 1}, -#endif - /* * ssl options are allowed even without client SSL support because the * client can still handle SSL modes "disable" and "allow". Other @@ -264,6 +257,83 @@ static const PQconninfoOption PQconninfo NULL, NULL, 0} }; +/* + * We need a mapping between the PQconninfoOptions[] array + * and PGconn members. We have to keep it separate from + * PQconninfoOptions[] to not leak info about PGconn members + * to clients. + */ +typedef struct PQconninfoMapping { + char *keyword; + size_t member_offset; + int flags; +} PQconninfoMapping; +#define PGCONNMEMBERADDR(conn, mapping) ((char **)((char *)conn + mapping->member_offset)) + +static const PQconninfoMapping PQconninfoMappings[] = +{ + /* "authtype" is not used anymore, there is no mapping to PGconn */ + /* there is no mapping of "service" to PGconn */ + { "user", offsetof(struct pg_conn, pguser), + PG_CONNINFO_NORMAL | PG_CONNINFO_REPLICATION }, + { "password", offsetof(struct pg_conn, pgpass), + PG_CONNINFO_PASSWORD | PG_CONNINFO_REPLICATION }, + { "connect_timeout", offsetof(struct pg_conn, connect_timeout), + PG_CONNINFO_NORMAL | PG_CONNINFO_REPLICATION }, + { "dbname", offsetof(struct pg_conn, dbName), + PG_CONNINFO_NORMAL }, + { "host", offsetof(struct pg_conn, pghost), + PG_CONNINFO_NORMAL | PG_CONNINFO_REPLICATION }, + { "hostaddr", offsetof(struct pg_conn, pghostaddr), + PG_CONNINFO_NORMAL | PG_CONNINFO_REPLICATION }, + { "port", offsetof(struct pg_conn, pgport), + PG_CONNINFO_NORMAL | PG_CONNINFO_REPLICATION }, + { "client_encoding", offsetof(struct pg_conn, client_encoding_initial), + PG_CONNINFO_NORMAL }, + { "tty", offsetof(struct pg_conn, pgtty), + PG_CONNINFO_NORMAL }, + { "options", offsetof(struct pg_conn, pgoptions), + PG_CONNINFO_NORMAL | PG_CONNINFO_REPLICATION }, + { "application_name", offsetof(struct pg_conn, appname), + PG_CONNINFO_NORMAL }, + { "fallback_application_name", offsetof(struct pg_conn, fbappname), + PG_CONNINFO_NORMAL }, + { "keepalives", offsetof(struct pg_conn, keepalives), + PG_CONNINFO_NORMAL | PG_CONNINFO_REPLICATION }, + { "keepalives_idle", offsetof(struct pg_conn, keepalives_idle), + PG_CONNINFO_NORMAL | PG_CONNINFO_REPLICATION }, + { "keepalives_interval", offsetof(struct pg_conn, keepalives_interval), + PG_CONNINFO_NORMAL | PG_CONNINFO_REPLICATION }, + { "keepalives_count", offsetof(struct pg_conn, keepalives_count), + PG_CONNINFO_NORMAL | PG_CONNINFO_REPLICATION }, + { "sslmode", offsetof(struct pg_conn, sslmode), + PG_CONNINFO_NORMAL | PG_CONNINFO_REPLICATION }, + { "sslcompression", offsetof(struct pg_conn, sslcompression), + PG_CONNINFO_NORMAL | PG_CONNINFO_REPLICATION }, + { "sslcert", offsetof(struct pg_conn, sslcert), + PG_CONNINFO_NORMAL | PG_CONNINFO_REPLICATION }, + { "sslkey", offsetof(struct pg_conn, sslkey), + PG_CONNINFO_NORMAL | PG_CONNINFO_REPLICATION }, + { "sslrootcert", offsetof(struct pg_conn, sslrootcert), + PG_CONNINFO_NORMAL | PG_CONNINFO_REPLICATION }, + { "sslcrl", offsetof(struct pg_conn, sslcrl), + PG_CONNINFO_NORMAL | PG_CONNINFO_REPLICATION }, + { "requirepeer", offsetof(struct pg_conn, requirepeer), + PG_CONNINFO_NORMAL | PG_CONNINFO_REPLICATION }, +#if defined(KRB5) || defined(ENABLE_GSS) || defined(ENABLE_SSPI) + { "krbsrvname", offsetof(struct pg_conn, krbsrvname), + PG_CONNINFO_NORMAL | PG_CONNINFO_REPLICATION }, +#endif +#if defined(ENABLE_GSS) && defined(ENABLE_SSPI) + { "gsslib", offsetof(struct pg_conn, requirepeer), + PG_CONNINFO_NORMAL | PG_CONNINFO_REPLICATION }, +#endif + { "replication", offsetof(struct pg_conn, replication), + PG_CONNINFO_NORMAL }, + /* Terminating entry --- MUST BE LAST */ + { NULL, 0, 0 } +}; + static const PQEnvironmentOption EnvironmentOptions[] = { /* common user-interface settings */ @@ -295,7 +365,8 @@ static PGconn *makeEmptyPGconn(void); static void fillPGconn(PGconn *conn, PQconninfoOption *connOptions); static void freePGconn(PGconn *conn); static void closePGconn(PGconn *conn); -static PQconninfoOption *conninfo_init(PQExpBuffer errorMessage); +static PQconninfoOption *conninfo_init(PQExpBuffer errorMessage, + int flags); static PQconninfoOption *parse_connection_string(const char *conninfo, PQExpBuffer errorMessage, bool use_defaults); static int uri_prefix_length(const char *connstr); @@ -627,7 +698,7 @@ PQconnectStart(const char *conninfo) static void fillPGconn(PGconn *conn, PQconninfoOption *connOptions) { - const char *tmp; + const PQconninfoMapping *mapping; /* * Move option values into conn structure @@ -637,72 +708,19 @@ fillPGconn(PGconn *conn, PQconninfoOptio * * XXX: probably worth checking strdup() return value here... */ - tmp = conninfo_getval(connOptions, "hostaddr"); - conn->pghostaddr = tmp ? strdup(tmp) : NULL; - tmp = conninfo_getval(connOptions, "host"); - conn->pghost = tmp ? strdup(tmp) : NULL; - tmp = conninfo_getval(connOptions, "port"); - conn->pgport = tmp ? strdup(tmp) : NULL; - tmp = conninfo_getval(connOptions, "tty"); - conn->pgtty = tmp ? strdup(tmp) : NULL; - tmp = conninfo_getval(connOptions, "options"); - conn->pgoptions = tmp ? strdup(tmp) : NULL; - tmp = conninfo_getval(connOptions, "application_name"); - conn->appname = tmp ? strdup(tmp) : NULL; - tmp = conninfo_getval(connOptions, "fallback_application_name"); - conn->fbappname = tmp ? strdup(tmp) : NULL; - tmp = conninfo_getval(connOptions, "dbname"); - conn->dbName = tmp ? strdup(tmp) : NULL; - tmp = conninfo_getval(connOptions, "user"); - conn->pguser = tmp ? strdup(tmp) : NULL; - tmp = conninfo_getval(connOptions, "password"); - conn->pgpass = tmp ? strdup(tmp) : NULL; - tmp = conninfo_getval(connOptions, "connect_timeout"); - conn->connect_timeout = tmp ? strdup(tmp) : NULL; - tmp = conninfo_getval(connOptions, "client_encoding"); - conn->client_encoding_initial = tmp ? strdup(tmp) : NULL; - tmp = conninfo_getval(connOptions, "keepalives"); - conn->keepalives = tmp ? strdup(tmp) : NULL; - tmp = conninfo_getval(connOptions, "keepalives_idle"); - conn->keepalives_idle = tmp ? strdup(tmp) : NULL; - tmp = conninfo_getval(connOptions, "keepalives_interval"); - conn->keepalives_interval = tmp ? strdup(tmp) : NULL; - tmp = conninfo_getval(connOptions, "keepalives_count"); - conn->keepalives_count = tmp ? strdup(tmp) : NULL; - tmp = conninfo_getval(connOptions, "sslmode"); - conn->sslmode = tmp ? strdup(tmp) : NULL; - tmp = conninfo_getval(connOptions, "sslcompression"); - conn->sslcompression = tmp ? strdup(tmp) : NULL; - tmp = conninfo_getval(connOptions, "sslkey"); - conn->sslkey = tmp ? strdup(tmp) : NULL; - tmp = conninfo_getval(connOptions, "sslcert"); - conn->sslcert = tmp ? strdup(tmp) : NULL; - tmp = conninfo_getval(connOptions, "sslrootcert"); - conn->sslrootcert = tmp ? strdup(tmp) : NULL; - tmp = conninfo_getval(connOptions, "sslcrl"); - conn->sslcrl = tmp ? strdup(tmp) : NULL; -#ifdef USE_SSL - tmp = conninfo_getval(connOptions, "requiressl"); - if (tmp && tmp[0] == '1') + for (mapping = PQconninfoMappings; mapping->keyword; mapping++) { - /* here warn that the requiressl option is deprecated? */ - if (conn->sslmode) - free(conn->sslmode); - conn->sslmode = strdup("require"); + const char *tmp = conninfo_getval(connOptions, mapping->keyword); + + if (tmp) + { + char **connmember = PGCONNMEMBERADDR(conn, mapping); + + if (*connmember) + free(*connmember); + *connmember = tmp ? strdup(tmp) : NULL; + } } -#endif - tmp = conninfo_getval(connOptions, "requirepeer"); - conn->requirepeer = tmp ? strdup(tmp) : NULL; -#if defined(KRB5) || defined(ENABLE_GSS) || defined(ENABLE_SSPI) - tmp = conninfo_getval(connOptions, "krbsrvname"); - conn->krbsrvname = tmp ? strdup(tmp) : NULL; -#endif -#if defined(ENABLE_GSS) && defined(ENABLE_SSPI) - tmp = conninfo_getval(connOptions, "gsslib"); - conn->gsslib = tmp ? strdup(tmp) : NULL; -#endif - tmp = conninfo_getval(connOptions, "replication"); - conn->replication = tmp ? strdup(tmp) : NULL; } /* @@ -884,7 +902,7 @@ PQconndefaults(void) if (PQExpBufferDataBroken(errorBuf)) return NULL; /* out of memory already :-( */ - connOptions = conninfo_init(&errorBuf); + connOptions = conninfo_init(&errorBuf, PG_CONNINFO_NORMAL | PG_CONNINFO_PASSWORD); if (connOptions != NULL) { if (!conninfo_add_defaults(connOptions, &errorBuf)) @@ -4008,9 +4026,11 @@ PQconninfoParse(const char *conninfo, ch * Build a working copy of the constant PQconninfoOptions array. */ static PQconninfoOption * -conninfo_init(PQExpBuffer errorMessage) +conninfo_init(PQExpBuffer errorMessage, int flags) { + const PQconninfoMapping *mapping; PQconninfoOption *options; + PQconninfoOption *opt_dest; options = (PQconninfoOption *) malloc(sizeof(PQconninfoOptions)); if (options == NULL) @@ -4019,7 +4039,23 @@ conninfo_init(PQExpBuffer errorMessage) libpq_gettext("out of memory\n")); return NULL; } - memcpy(options, PQconninfoOptions, sizeof(PQconninfoOptions)); + + opt_dest = options; + for (mapping = PQconninfoMappings; mapping->keyword; mapping++) + { + PQconninfoOption *opt_src; + + if (!(mapping->flags & flags)) + continue; + + opt_src = conninfo_find((PQconninfoOption *)PQconninfoOptions, mapping->keyword); + if (opt_src) + { + memcpy(opt_dest, opt_src, sizeof(PQconninfoOption)); + opt_dest++; + } + } + MemSet(opt_dest, 0, sizeof(PQconninfoOption)); return options; } @@ -4095,7 +4131,7 @@ conninfo_parse(const char *conninfo, PQE PQconninfoOption *options; /* Make a working copy of PQconninfoOptions */ - options = conninfo_init(errorMessage); + options = conninfo_init(errorMessage, PG_CONNINFO_NORMAL | PG_CONNINFO_PASSWORD); if (options == NULL) return NULL; @@ -4295,7 +4331,7 @@ conninfo_array_parse(const char *const * } /* Make a working copy of PQconninfoOptions */ - options = conninfo_init(errorMessage); + options = conninfo_init(errorMessage, PG_CONNINFO_NORMAL | PG_CONNINFO_PASSWORD); if (options == NULL) { PQconninfoFree(dbname_options); @@ -4485,7 +4521,7 @@ conninfo_uri_parse(const char *uri, PQEx PQconninfoOption *options; /* Make a working copy of PQconninfoOptions */ - options = conninfo_init(errorMessage); + options = conninfo_init(errorMessage, PG_CONNINFO_NORMAL | PG_CONNINFO_PASSWORD); if (options == NULL) return NULL; @@ -5066,6 +5102,45 @@ conninfo_find(PQconninfoOption *connOpti } +/* + * Return the connection options used for the connections + */ +PQconninfoOption * +PQconninfo(PGconn *conn, int flags) +{ + PQExpBufferData errorBuf; + PQconninfoOption *connOptions; + + if (conn == NULL) + return NULL; + + /* We don't actually report any errors here, but callees want a buffer */ + initPQExpBuffer(&errorBuf); + if (PQExpBufferDataBroken(errorBuf)) + return NULL; /* out of memory already :-( */ + + connOptions = conninfo_init(&errorBuf, flags); + + if (connOptions != NULL) + { + const PQconninfoMapping *mapping; + + for (mapping = PQconninfoMappings; mapping->keyword; mapping++) + { + char **connmember = PGCONNMEMBERADDR(conn, mapping); + + if (*connmember) + conninfo_storeval(connOptions, mapping->keyword, *connmember, + &errorBuf, false, false); + } + } + + termPQExpBuffer(&errorBuf); + + return connOptions; +} + + void PQconninfoFree(PQconninfoOption *connOptions) { diff -durpN postgresql/src/interfaces/libpq/libpq-fe.h postgresql.1/src/interfaces/libpq/libpq-fe.h --- postgresql/src/interfaces/libpq/libpq-fe.h 2012-10-09 09:58:14.343782980 +0200 +++ postgresql.1/src/interfaces/libpq/libpq-fe.h 2012-11-20 11:49:36.747692399 +0100 @@ -36,6 +36,13 @@ extern "C" #define PG_COPYRES_EVENTS 0x04 #define PG_COPYRES_NOTICEHOOKS 0x08 +/* + * Option flags for PQconninfo + */ +#define PG_CONNINFO_NORMAL 0x01 +#define PG_CONNINFO_PASSWORD 0x02 +#define PG_CONNINFO_REPLICATION 0x04 + /* Application-visible enum types */ /* @@ -262,6 +269,9 @@ extern PQconninfoOption *PQconndefaults( /* parse connection options in same way as PQconnectdb */ extern PQconninfoOption *PQconninfoParse(const char *conninfo, char **errmsg); +/* return the connection options used by a live connection */ +extern PQconninfoOption *PQconninfo(PGconn *conn, int flags); + /* free the data structure returned by PQconndefaults() or PQconninfoParse() */ extern void PQconninfoFree(PQconninfoOption *connOptions);