mirror of
https://github.com/psycopg/psycopg2.git
synced 2024-11-22 08:56:34 +03:00
Obscure the dsn password before storing it into the connection
This avoids the need to juggle with exceptions in order to scrub the password after a connection error, which may also swallow signals (see #898).
This commit is contained in:
parent
491296e0f5
commit
f40ad0f3ae
|
@ -164,7 +164,7 @@ HIDDEN void conn_notice_process(connectionObject *self);
|
||||||
HIDDEN void conn_notice_clean(connectionObject *self);
|
HIDDEN void conn_notice_clean(connectionObject *self);
|
||||||
HIDDEN void conn_notifies_process(connectionObject *self);
|
HIDDEN void conn_notifies_process(connectionObject *self);
|
||||||
RAISES_NEG HIDDEN int conn_setup(connectionObject *self);
|
RAISES_NEG HIDDEN int conn_setup(connectionObject *self);
|
||||||
HIDDEN int conn_connect(connectionObject *self, long int async);
|
HIDDEN int conn_connect(connectionObject *self, const char *dsn, long int async);
|
||||||
HIDDEN void conn_close(connectionObject *self);
|
HIDDEN void conn_close(connectionObject *self);
|
||||||
HIDDEN void conn_close_locked(connectionObject *self);
|
HIDDEN void conn_close_locked(connectionObject *self);
|
||||||
RAISES_NEG HIDDEN int conn_commit(connectionObject *self);
|
RAISES_NEG HIDDEN int conn_commit(connectionObject *self);
|
||||||
|
|
|
@ -705,7 +705,7 @@ exit:
|
||||||
/* conn_connect - execute a connection to the database */
|
/* conn_connect - execute a connection to the database */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_conn_sync_connect(connectionObject *self)
|
_conn_sync_connect(connectionObject *self, const char *dsn)
|
||||||
{
|
{
|
||||||
int green;
|
int green;
|
||||||
|
|
||||||
|
@ -714,26 +714,26 @@ _conn_sync_connect(connectionObject *self)
|
||||||
green = psyco_green();
|
green = psyco_green();
|
||||||
if (!green) {
|
if (!green) {
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
self->pgconn = PQconnectdb(self->dsn);
|
self->pgconn = PQconnectdb(dsn);
|
||||||
Py_END_ALLOW_THREADS;
|
Py_END_ALLOW_THREADS;
|
||||||
Dprintf("conn_connect: new PG connection at %p", self->pgconn);
|
Dprintf("conn_connect: new PG connection at %p", self->pgconn);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
self->pgconn = PQconnectStart(self->dsn);
|
self->pgconn = PQconnectStart(dsn);
|
||||||
Py_END_ALLOW_THREADS;
|
Py_END_ALLOW_THREADS;
|
||||||
Dprintf("conn_connect: new green PG connection at %p", self->pgconn);
|
Dprintf("conn_connect: new green PG connection at %p", self->pgconn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!self->pgconn)
|
if (!self->pgconn)
|
||||||
{
|
{
|
||||||
Dprintf("conn_connect: PQconnectdb(%s) FAILED", self->dsn);
|
Dprintf("conn_connect: PQconnectdb(%s) FAILED", dsn);
|
||||||
PyErr_SetString(OperationalError, "PQconnectdb() failed");
|
PyErr_SetString(OperationalError, "PQconnectdb() failed");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else if (PQstatus(self->pgconn) == CONNECTION_BAD)
|
else if (PQstatus(self->pgconn) == CONNECTION_BAD)
|
||||||
{
|
{
|
||||||
Dprintf("conn_connect: PQconnectdb(%s) returned BAD", self->dsn);
|
Dprintf("conn_connect: PQconnectdb(%s) returned BAD", dsn);
|
||||||
PyErr_SetString(OperationalError, PQerrorMessage(self->pgconn));
|
PyErr_SetString(OperationalError, PQerrorMessage(self->pgconn));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -763,23 +763,23 @@ _conn_sync_connect(connectionObject *self)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_conn_async_connect(connectionObject *self)
|
_conn_async_connect(connectionObject *self, const char *dsn)
|
||||||
{
|
{
|
||||||
PGconn *pgconn;
|
PGconn *pgconn;
|
||||||
|
|
||||||
self->pgconn = pgconn = PQconnectStart(self->dsn);
|
self->pgconn = pgconn = PQconnectStart(dsn);
|
||||||
|
|
||||||
Dprintf("conn_connect: new postgresql connection at %p", pgconn);
|
Dprintf("conn_connect: new postgresql connection at %p", pgconn);
|
||||||
|
|
||||||
if (pgconn == NULL)
|
if (pgconn == NULL)
|
||||||
{
|
{
|
||||||
Dprintf("conn_connect: PQconnectStart(%s) FAILED", self->dsn);
|
Dprintf("conn_connect: PQconnectStart(%s) FAILED", dsn);
|
||||||
PyErr_SetString(OperationalError, "PQconnectStart() failed");
|
PyErr_SetString(OperationalError, "PQconnectStart() failed");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else if (PQstatus(pgconn) == CONNECTION_BAD)
|
else if (PQstatus(pgconn) == CONNECTION_BAD)
|
||||||
{
|
{
|
||||||
Dprintf("conn_connect: PQconnectdb(%s) returned BAD", self->dsn);
|
Dprintf("conn_connect: PQconnectdb(%s) returned BAD", dsn);
|
||||||
PyErr_SetString(OperationalError, PQerrorMessage(pgconn));
|
PyErr_SetString(OperationalError, PQerrorMessage(pgconn));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -800,17 +800,17 @@ _conn_async_connect(connectionObject *self)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
conn_connect(connectionObject *self, long int async)
|
conn_connect(connectionObject *self, const char *dsn, long int async)
|
||||||
{
|
{
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
if (async == 1) {
|
if (async == 1) {
|
||||||
Dprintf("con_connect: connecting in ASYNC mode");
|
Dprintf("con_connect: connecting in ASYNC mode");
|
||||||
rv = _conn_async_connect(self);
|
rv = _conn_async_connect(self, dsn);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Dprintf("con_connect: connecting in SYNC mode");
|
Dprintf("con_connect: connecting in SYNC mode");
|
||||||
rv = _conn_sync_connect(self);
|
rv = _conn_sync_connect(self, dsn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
|
|
|
@ -1297,21 +1297,28 @@ static struct PyGetSetDef connectionObject_getsets[] = {
|
||||||
|
|
||||||
/* initialization and finalization methods */
|
/* initialization and finalization methods */
|
||||||
|
|
||||||
RAISES_NEG static int
|
/* Return a copy of the 'dsn' string with the password scrubbed.
|
||||||
obscure_password(connectionObject *conn)
|
*
|
||||||
|
* The string returned is allocated on the Python heap.
|
||||||
|
*
|
||||||
|
* In case of error return NULL and raise an exception.
|
||||||
|
*/
|
||||||
|
static char *
|
||||||
|
obscure_password(const char *dsn)
|
||||||
{
|
{
|
||||||
PQconninfoOption *options;
|
PQconninfoOption *options = NULL;
|
||||||
PyObject *d = NULL, *v = NULL, *dsn = NULL;
|
PyObject *d = NULL, *v = NULL, *pydsn = NULL;
|
||||||
char *tmp;
|
char *rv = NULL;
|
||||||
int rv = -1;
|
|
||||||
|
|
||||||
if (!conn || !conn->dsn) {
|
if (!dsn) {
|
||||||
return 0;
|
PyErr_SetString(InternalError, "unexpected null string");
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(options = PQconninfoParse(conn->dsn, NULL))) {
|
if (!(options = PQconninfoParse(dsn, NULL))) {
|
||||||
/* unlikely: the dsn was already tested valid */
|
/* unlikely: the dsn was already tested valid */
|
||||||
return 0;
|
PyErr_SetString(InternalError, "the connection string is not valid");
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(d = psyco_dict_from_conninfo_options(
|
if (!(d = psyco_dict_from_conninfo_options(
|
||||||
|
@ -1320,28 +1327,24 @@ obscure_password(connectionObject *conn)
|
||||||
}
|
}
|
||||||
if (NULL == PyDict_GetItemString(d, "password")) {
|
if (NULL == PyDict_GetItemString(d, "password")) {
|
||||||
/* the dsn doesn't have a password */
|
/* the dsn doesn't have a password */
|
||||||
rv = 0;
|
psyco_strdup(&rv, dsn, -1);
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* scrub the password and put back the connection string together */
|
/* scrub the password and put back the connection string together */
|
||||||
if (!(v = Text_FromUTF8("xxx"))) { goto exit; }
|
if (!(v = Text_FromUTF8("xxx"))) { goto exit; }
|
||||||
if (0 > PyDict_SetItemString(d, "password", v)) { goto exit; }
|
if (0 > PyDict_SetItemString(d, "password", v)) { goto exit; }
|
||||||
if (!(dsn = psyco_make_dsn(Py_None, d))) { goto exit; }
|
if (!(pydsn = psyco_make_dsn(Py_None, d))) { goto exit; }
|
||||||
if (!(dsn = psyco_ensure_bytes(dsn))) { goto exit; }
|
if (!(pydsn = psyco_ensure_bytes(pydsn))) { goto exit; }
|
||||||
|
|
||||||
/* Replace the connection string on the connection object */
|
/* Return the connection string with the password replaced */
|
||||||
tmp = conn->dsn;
|
psyco_strdup(&rv, Bytes_AS_STRING(pydsn), -1);
|
||||||
psyco_strdup(&conn->dsn, Bytes_AS_STRING(dsn), -1);
|
|
||||||
PyMem_Free(tmp);
|
|
||||||
|
|
||||||
rv = 0;
|
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
PQconninfoFree(options);
|
PQconninfoFree(options);
|
||||||
Py_XDECREF(v);
|
Py_XDECREF(v);
|
||||||
Py_XDECREF(d);
|
Py_XDECREF(d);
|
||||||
Py_XDECREF(dsn);
|
Py_XDECREF(pydsn);
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -1356,7 +1359,7 @@ connection_setup(connectionObject *self, const char *dsn, long int async)
|
||||||
self, async, Py_REFCNT(self)
|
self, async, Py_REFCNT(self)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (0 > psyco_strdup(&self->dsn, dsn, -1)) { goto exit; }
|
if (!(self->dsn = obscure_password(dsn))) { goto exit; }
|
||||||
if (!(self->notice_list = PyList_New(0))) { goto exit; }
|
if (!(self->notice_list = PyList_New(0))) { goto exit; }
|
||||||
if (!(self->notifies = PyList_New(0))) { goto exit; }
|
if (!(self->notifies = PyList_New(0))) { goto exit; }
|
||||||
self->async = async;
|
self->async = async;
|
||||||
|
@ -1378,7 +1381,7 @@ connection_setup(connectionObject *self, const char *dsn, long int async)
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conn_connect(self, async) != 0) {
|
if (conn_connect(self, dsn, async) != 0) {
|
||||||
Dprintf("connection_init: FAILED");
|
Dprintf("connection_init: FAILED");
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
@ -1390,13 +1393,6 @@ connection_setup(connectionObject *self, const char *dsn, long int async)
|
||||||
self, Py_REFCNT(self));
|
self, Py_REFCNT(self));
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
/* here we obfuscate the password even if there was a connection error */
|
|
||||||
{
|
|
||||||
PyObject *ptype = NULL, *pvalue = NULL, *ptb = NULL;
|
|
||||||
PyErr_Fetch(&ptype, &pvalue, &ptb);
|
|
||||||
obscure_password(self);
|
|
||||||
PyErr_Restore(ptype, pvalue, ptb);
|
|
||||||
}
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user