diff options
author | Daniele Varrazzo <daniele.varrazzo@gmail.com> | 2017-03-16 03:33:19 +0000 |
---|---|---|
committer | Daniele Varrazzo <daniele.varrazzo@gmail.com> | 2017-03-16 03:53:40 +0000 |
commit | 9f160fd8208f5bad8a724881384835b8e692bad0 (patch) | |
tree | 8e416d58dff49457cd139913e27403ebcce61f93 /psycopg | |
parent | 103655d67086a3377668236662363fa3146fbd32 (diff) | |
download | psycopg2-9f160fd8208f5bad8a724881384835b8e692bad0.tar.gz |
Obscure the password on url dsn too
Note that we don't leak anymore the password length.
Fix #528
Diffstat (limited to 'psycopg')
-rw-r--r-- | psycopg/connection_type.c | 54 | ||||
-rw-r--r-- | psycopg/psycopg.h | 2 | ||||
-rw-r--r-- | psycopg/utils.c | 24 |
3 files changed, 72 insertions, 8 deletions
diff --git a/psycopg/connection_type.c b/psycopg/connection_type.c index 53e9e0f..eb4b241 100644 --- a/psycopg/connection_type.c +++ b/psycopg/connection_type.c @@ -1248,20 +1248,53 @@ static struct PyGetSetDef connectionObject_getsets[] = { /* initialization and finalization methods */ -static void +RAISES_NEG static int obscure_password(connectionObject *conn) { - char *pos; + PQconninfoOption *options; + PyObject *d = NULL, *v = NULL, *dsn = NULL; + char *tmp; + int rv = -1; if (!conn || !conn->dsn) { - return; + return 0; } - pos = strstr(conn->dsn, "password"); - if (pos != NULL) { - for (pos = pos+9 ; *pos != '\0' && *pos != ' '; pos++) - *pos = 'x'; + if (!(options = PQconninfoParse(conn->dsn, NULL))) { + /* unlikely: the dsn was already tested valid */ + return 0; } + + if (!(d = psycopg_dict_from_conninfo_options( + options, /* include_password = */ 1))) { + goto exit; + } + if (NULL == PyDict_GetItemString(d, "password")) { + /* the dsn doesn't have a password */ + rv = 0; + goto exit; + } + + /* scrub the password and put back the connection string together */ + if (!(v = Text_FromUTF8("xxx"))) { goto exit; } + if (0 > PyDict_SetItemString(d, "password", v)) { goto exit; } + if (!(dsn = psycopg_make_dsn(Py_None, d))) { goto exit; } + if (!(dsn = psycopg_ensure_bytes(dsn))) { goto exit; } + + /* Replace the connection string on the connection object */ + tmp = conn->dsn; + psycopg_strdup(&conn->dsn, Bytes_AS_STRING(dsn), -1); + PyMem_Free(tmp); + + rv = 0; + +exit: + PQconninfoFree(options); + Py_XDECREF(v); + Py_XDECREF(d); + Py_XDECREF(dsn); + + return rv; } static int @@ -1303,7 +1336,12 @@ connection_setup(connectionObject *self, const char *dsn, long int async) exit: /* here we obfuscate the password even if there was a connection error */ - obscure_password(self); + { + PyObject *ptype = NULL, *pvalue = NULL, *ptb = NULL; + PyErr_Fetch(&ptype, &pvalue, &ptb); + obscure_password(self); + PyErr_Restore(ptype, pvalue, ptb); + } return res; } diff --git a/psycopg/psycopg.h b/psycopg/psycopg.h index 1367354..d54037f 100644 --- a/psycopg/psycopg.h +++ b/psycopg/psycopg.h @@ -142,6 +142,8 @@ STEALS(1) HIDDEN PyObject * psycopg_ensure_text(PyObject *obj); HIDDEN PyObject *psycopg_dict_from_conninfo_options(PQconninfoOption *options, int include_password); +HIDDEN PyObject *psycopg_make_dsn(PyObject *dsn, PyObject *kwargs); + /* Exceptions docstrings */ #define Error_doc \ "Base class for error exceptions." diff --git a/psycopg/utils.c b/psycopg/utils.c index 7f6b6e6..7073504 100644 --- a/psycopg/utils.c +++ b/psycopg/utils.c @@ -280,6 +280,30 @@ exit: } +/* Make a connection string out of a string and a dictionary of arguments. + * + * Helper to call psycopg2.extensions.make_dns() + */ +PyObject * +psycopg_make_dsn(PyObject *dsn, PyObject *kwargs) +{ + PyObject *ext = NULL, *make_dsn = NULL; + PyObject *args = NULL, *rv = NULL; + + if (!(ext = PyImport_ImportModule("psycopg2.extensions"))) { goto exit; } + if (!(make_dsn = PyObject_GetAttrString(ext, "make_dsn"))) { goto exit; } + + if (!(args = PyTuple_Pack(1, dsn))) { goto exit; } + rv = PyObject_Call(make_dsn, args, kwargs); + +exit: + Py_XDECREF(args); + Py_XDECREF(make_dsn); + Py_XDECREF(ext); + + return rv; +} + /* Convert a C string into Python Text using a specified codec. * * The codec is the python function codec.getdecoder(enc). It is only used on |