mirror of
https://github.com/postgres/postgres.git
synced 2025-11-19 13:42:17 +03:00
Commits83dec5a712andff402ae11btaught vacuumdb to reuse passwords instead of prompting repeatedly. However, the docs still warn about repeated prompts, and this improvement was not applied to clusterdb and reindexdb. This commit allows clusterdb and reindexdb to reuse passwords just like vacuumdb does, and it expunges the aforementioned warnings from the docs. Reviewed-by: Gurjeet Singh, Zhang Mingli Discussion: https://postgr.es/m/20230628045741.GA1813397%40nathanxps13
177 lines
4.5 KiB
C
177 lines
4.5 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* Facilities for frontend code to connect to and disconnect from databases.
|
|
*
|
|
* Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
* src/fe_utils/connect_utils.c
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#include "postgres_fe.h"
|
|
|
|
#include "common/connect.h"
|
|
#include "common/logging.h"
|
|
#include "common/string.h"
|
|
#include "fe_utils/connect_utils.h"
|
|
#include "fe_utils/query_utils.h"
|
|
|
|
/*
|
|
* Make a database connection with the given parameters.
|
|
*
|
|
* An interactive password prompt is automatically issued if needed and
|
|
* allowed by cparams->prompt_password.
|
|
*
|
|
* If allow_password_reuse is true, we will try to re-use any password
|
|
* given during previous calls to this routine. (Callers should not pass
|
|
* allow_password_reuse=true unless reconnecting to the same host+port+user
|
|
* as before, else we might create password exposure hazards.)
|
|
*/
|
|
PGconn *
|
|
connectDatabase(const ConnParams *cparams, const char *progname,
|
|
bool echo, bool fail_ok, bool allow_password_reuse)
|
|
{
|
|
PGconn *conn;
|
|
bool new_pass;
|
|
static char *password = NULL;
|
|
|
|
/* Callers must supply at least dbname; other params can be NULL */
|
|
Assert(cparams->dbname);
|
|
|
|
if (!allow_password_reuse && password)
|
|
{
|
|
free(password);
|
|
password = NULL;
|
|
}
|
|
|
|
if (cparams->prompt_password == TRI_YES && password == NULL)
|
|
password = simple_prompt("Password: ", false);
|
|
|
|
/*
|
|
* Start the connection. Loop until we have a password if requested by
|
|
* backend.
|
|
*/
|
|
do
|
|
{
|
|
const char *keywords[8];
|
|
const char *values[8];
|
|
int i = 0;
|
|
|
|
/*
|
|
* If dbname is a connstring, its entries can override the other
|
|
* values obtained from cparams; but in turn, override_dbname can
|
|
* override the dbname component of it.
|
|
*/
|
|
keywords[i] = "host";
|
|
values[i++] = cparams->pghost;
|
|
keywords[i] = "port";
|
|
values[i++] = cparams->pgport;
|
|
keywords[i] = "user";
|
|
values[i++] = cparams->pguser;
|
|
keywords[i] = "password";
|
|
values[i++] = password;
|
|
keywords[i] = "dbname";
|
|
values[i++] = cparams->dbname;
|
|
if (cparams->override_dbname)
|
|
{
|
|
keywords[i] = "dbname";
|
|
values[i++] = cparams->override_dbname;
|
|
}
|
|
keywords[i] = "fallback_application_name";
|
|
values[i++] = progname;
|
|
keywords[i] = NULL;
|
|
values[i++] = NULL;
|
|
Assert(i <= lengthof(keywords));
|
|
|
|
new_pass = false;
|
|
conn = PQconnectdbParams(keywords, values, true);
|
|
|
|
if (!conn)
|
|
pg_fatal("could not connect to database %s: out of memory",
|
|
cparams->dbname);
|
|
|
|
/*
|
|
* No luck? Trying asking (again) for a password.
|
|
*/
|
|
if (PQstatus(conn) == CONNECTION_BAD &&
|
|
PQconnectionNeedsPassword(conn) &&
|
|
cparams->prompt_password != TRI_NO)
|
|
{
|
|
PQfinish(conn);
|
|
free(password);
|
|
password = simple_prompt("Password: ", false);
|
|
new_pass = true;
|
|
}
|
|
} while (new_pass);
|
|
|
|
/* check to see that the backend connection was successfully made */
|
|
if (PQstatus(conn) == CONNECTION_BAD)
|
|
{
|
|
if (fail_ok)
|
|
{
|
|
PQfinish(conn);
|
|
return NULL;
|
|
}
|
|
pg_fatal("%s", PQerrorMessage(conn));
|
|
}
|
|
|
|
/* Start strict; callers may override this. */
|
|
PQclear(executeQuery(conn, ALWAYS_SECURE_SEARCH_PATH_SQL, echo));
|
|
|
|
return conn;
|
|
}
|
|
|
|
/*
|
|
* Try to connect to the appropriate maintenance database.
|
|
*
|
|
* This differs from connectDatabase only in that it has a rule for
|
|
* inserting a default "dbname" if none was given (which is why cparams
|
|
* is not const). Note that cparams->dbname should typically come from
|
|
* a --maintenance-db command line parameter.
|
|
*/
|
|
PGconn *
|
|
connectMaintenanceDatabase(ConnParams *cparams,
|
|
const char *progname, bool echo)
|
|
{
|
|
PGconn *conn;
|
|
|
|
/* If a maintenance database name was specified, just connect to it. */
|
|
if (cparams->dbname)
|
|
return connectDatabase(cparams, progname, echo, false, false);
|
|
|
|
/* Otherwise, try postgres first and then template1. */
|
|
cparams->dbname = "postgres";
|
|
conn = connectDatabase(cparams, progname, echo, true, false);
|
|
if (!conn)
|
|
{
|
|
cparams->dbname = "template1";
|
|
conn = connectDatabase(cparams, progname, echo, false, false);
|
|
}
|
|
return conn;
|
|
}
|
|
|
|
/*
|
|
* Disconnect the given connection, canceling any statement if one is active.
|
|
*/
|
|
void
|
|
disconnectDatabase(PGconn *conn)
|
|
{
|
|
char errbuf[256];
|
|
|
|
Assert(conn != NULL);
|
|
|
|
if (PQtransactionStatus(conn) == PQTRANS_ACTIVE)
|
|
{
|
|
PGcancel *cancel;
|
|
|
|
if ((cancel = PQgetCancel(conn)))
|
|
{
|
|
(void) PQcancel(cancel, errbuf, sizeof(errbuf));
|
|
PQfreeCancel(cancel);
|
|
}
|
|
}
|
|
|
|
PQfinish(conn);
|
|
}
|