aboutsummaryrefslogtreecommitdiff
path: root/src/interfaces/libpq/fe-connect.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/interfaces/libpq/fe-connect.c')
-rw-r--r--src/interfaces/libpq/fe-connect.c108
1 files changed, 75 insertions, 33 deletions
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 430c0fa4442..2a2b10d5a29 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -201,6 +201,10 @@ static const internalPQconninfoOption PQconninfoOptions[] = {
"Database-Service", "", 20,
offsetof(struct pg_conn, pgservice)},
+ {"servicefile", "PGSERVICEFILE", NULL, NULL,
+ "Database-Service-File", "", 64,
+ offsetof(struct pg_conn, pgservicefile)},
+
{"user", "PGUSER", NULL, NULL,
"Database-User", "", 20,
offsetof(struct pg_conn, pguser)},
@@ -2027,13 +2031,11 @@ pqConnectOptions2(PGconn *conn)
if (len < 0)
{
libpq_append_conn_error(conn, "invalid SCRAM client key");
- free(conn->scram_client_key_binary);
return false;
}
if (len != SCRAM_MAX_KEY_LEN)
{
libpq_append_conn_error(conn, "invalid SCRAM client key length: %d", len);
- free(conn->scram_client_key_binary);
return false;
}
conn->scram_client_key_len = len;
@@ -2052,13 +2054,11 @@ pqConnectOptions2(PGconn *conn)
if (len < 0)
{
libpq_append_conn_error(conn, "invalid SCRAM server key");
- free(conn->scram_server_key_binary);
return false;
}
if (len != SCRAM_MAX_KEY_LEN)
{
libpq_append_conn_error(conn, "invalid SCRAM server key length: %d", len);
- free(conn->scram_server_key_binary);
return false;
}
conn->scram_server_key_len = len;
@@ -2145,7 +2145,7 @@ pqConnectOptions2(PGconn *conn)
if (conn->min_pversion > conn->max_pversion)
{
conn->status = CONNECTION_BAD;
- libpq_append_conn_error(conn, "min_protocol_version is greater than max_protocol_version");
+ libpq_append_conn_error(conn, "\"%s\" is greater than \"%s\"", "min_protocol_version", "max_protocol_version");
return false;
}
@@ -5053,21 +5053,20 @@ freePGconn(PGconn *conn)
free(conn->events[i].name);
}
- release_conn_addrinfo(conn);
- pqReleaseConnHosts(conn);
-
- free(conn->client_encoding_initial);
- free(conn->events);
+ /* free everything not freed in pqClosePGconn */
free(conn->pghost);
free(conn->pghostaddr);
free(conn->pgport);
free(conn->connect_timeout);
free(conn->pgtcp_user_timeout);
+ free(conn->client_encoding_initial);
free(conn->pgoptions);
free(conn->appname);
free(conn->fbappname);
free(conn->dbName);
free(conn->replication);
+ free(conn->pgservice);
+ free(conn->pgservicefile);
free(conn->pguser);
if (conn->pgpass)
{
@@ -5082,8 +5081,9 @@ freePGconn(PGconn *conn)
free(conn->keepalives_count);
free(conn->sslmode);
free(conn->sslnegotiation);
- free(conn->sslcert);
+ free(conn->sslcompression);
free(conn->sslkey);
+ free(conn->sslcert);
if (conn->sslpassword)
{
explicit_bzero(conn->sslpassword, strlen(conn->sslpassword));
@@ -5093,32 +5093,40 @@ freePGconn(PGconn *conn)
free(conn->sslrootcert);
free(conn->sslcrl);
free(conn->sslcrldir);
- free(conn->sslcompression);
free(conn->sslsni);
free(conn->requirepeer);
- free(conn->require_auth);
- free(conn->ssl_min_protocol_version);
- free(conn->ssl_max_protocol_version);
free(conn->gssencmode);
free(conn->krbsrvname);
free(conn->gsslib);
free(conn->gssdelegation);
- free(conn->connip);
- /* Note that conn->Pfdebug is not ours to close or free */
- free(conn->write_err_msg);
- free(conn->inBuffer);
- free(conn->outBuffer);
- free(conn->rowBuf);
+ free(conn->min_protocol_version);
+ free(conn->max_protocol_version);
+ free(conn->ssl_min_protocol_version);
+ free(conn->ssl_max_protocol_version);
free(conn->target_session_attrs);
+ free(conn->require_auth);
free(conn->load_balance_hosts);
free(conn->scram_client_key);
free(conn->scram_server_key);
+ free(conn->sslkeylogfile);
free(conn->oauth_issuer);
free(conn->oauth_issuer_id);
free(conn->oauth_discovery_uri);
free(conn->oauth_client_id);
free(conn->oauth_client_secret);
free(conn->oauth_scope);
+ /* Note that conn->Pfdebug is not ours to close or free */
+ free(conn->events);
+ pqReleaseConnHosts(conn);
+ free(conn->connip);
+ release_conn_addrinfo(conn);
+ free(conn->scram_client_key_binary);
+ free(conn->scram_server_key_binary);
+ /* if this is a cancel connection, be_cancel_key may still be allocated */
+ free(conn->be_cancel_key);
+ free(conn->inBuffer);
+ free(conn->outBuffer);
+ free(conn->rowBuf);
termPQExpBuffer(&conn->errorMessage);
termPQExpBuffer(&conn->workBuffer);
@@ -5147,6 +5155,7 @@ pqReleaseConnHosts(PGconn *conn)
}
}
free(conn->connhost);
+ conn->connhost = NULL;
}
}
@@ -5910,6 +5919,7 @@ static int
parseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage)
{
const char *service = conninfo_getval(options, "service");
+ const char *service_fname = conninfo_getval(options, "servicefile");
char serviceFile[MAXPGPATH];
char *env;
bool group_found = false;
@@ -5929,10 +5939,13 @@ parseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage)
return 0;
/*
- * Try PGSERVICEFILE if specified, else try ~/.pg_service.conf (if that
- * exists).
+ * First, try the "servicefile" option in connection string. Then, try
+ * the PGSERVICEFILE environment variable. Finally, check
+ * ~/.pg_service.conf (if that exists).
*/
- if ((env = getenv("PGSERVICEFILE")) != NULL)
+ if (service_fname != NULL)
+ strlcpy(serviceFile, service_fname, sizeof(serviceFile));
+ else if ((env = getenv("PGSERVICEFILE")) != NULL)
strlcpy(serviceFile, env, sizeof(serviceFile));
else
{
@@ -6088,7 +6101,17 @@ parseServiceFile(const char *serviceFile,
if (strcmp(key, "service") == 0)
{
libpq_append_error(errorMessage,
- "nested service specifications not supported in service file \"%s\", line %d",
+ "nested \"service\" specifications not supported in service file \"%s\", line %d",
+ serviceFile,
+ linenr);
+ result = 3;
+ goto exit;
+ }
+
+ if (strcmp(key, "servicefile") == 0)
+ {
+ libpq_append_error(errorMessage,
+ "nested \"servicefile\" specifications not supported in service file \"%s\", line %d",
serviceFile,
linenr);
result = 3;
@@ -6131,6 +6154,33 @@ parseServiceFile(const char *serviceFile,
}
exit:
+
+ /*
+ * If a service has been successfully found, set the "servicefile" option
+ * if not already set. This matters when we use a default service file or
+ * PGSERVICEFILE, where we want to be able track the value.
+ */
+ if (*group_found && result == 0)
+ {
+ for (i = 0; options[i].keyword; i++)
+ {
+ if (strcmp(options[i].keyword, "servicefile") != 0)
+ continue;
+
+ /* If value is already set, nothing to do */
+ if (options[i].val != NULL)
+ break;
+
+ options[i].val = strdup(serviceFile);
+ if (options[i].val == NULL)
+ {
+ libpq_append_error(errorMessage, "out of memory");
+ result = 3;
+ }
+ break;
+ }
+ }
+
fclose(f);
return result;
@@ -7458,14 +7508,6 @@ PQdb(const PGconn *conn)
}
char *
-PQservice(const PGconn *conn)
-{
- if (!conn)
- return NULL;
- return conn->pgservice;
-}
-
-char *
PQuser(const PGconn *conn)
{
if (!conn)