mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
At long last I put together a patch to support 4 client SSL negotiation
modes (and replace the requiressl boolean). The four options were first spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email to pgsql-hackers, archived here: http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php My original less-flexible patch and the ensuing thread are archived at: http://dbforums.com/t623845.html Attached is a new patch, including documentation. To sum up, there's a new client parameter "sslmode" and environment variable "PGSSLMODE", with these options: sslmode description ------- ----------- disable Unencrypted non-SSL only allow Negotiate, prefer non-SSL prefer Negotiate, prefer SSL (default) require Require SSL The only change to the server is a new pg_hba.conf line type, "hostnossl", for specifying connections that are not allowed to use SSL (for example, to prevent servers on a local network from accidentally using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are: pg_hba.conf line types ---------------------- host applies to either SSL or regular connections hostssl applies only to SSL connections hostnossl applies only to regular connections These client and server options, the postgresql.conf ssl = false option, and finally the possibility of compiling with no SSL support at all, make quite a range of combinations to test. I threw together a test script to try many of them out. It's in a separate tarball with its config files, a patch to psql so it'll announce SSL connections even in absence of a tty, and the test output. The test is especially informative when run on the same tty the postmaster was started on, so the FATAL: errors during negotiation are interleaved with the psql client output. I saw Tom write that new submissions for 7.4 have to be in before midnight local time, and since I'm on the east coast in the US, this just makes it in before the bell. :) Jon Jensen
This commit is contained in:
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.253 2003/07/23 23:30:41 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.254 2003/07/26 13:50:02 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -60,6 +60,11 @@ long ioctlsocket_ret;
|
||||
#define DefaultOption ""
|
||||
#define DefaultAuthtype ""
|
||||
#define DefaultPassword ""
|
||||
#ifdef USE_SSL
|
||||
#define DefaultSSLMode "prefer"
|
||||
#else
|
||||
#define DefaultSSLMode "disable"
|
||||
#endif
|
||||
|
||||
|
||||
/* ----------
|
||||
@ -131,10 +136,22 @@ static const PQconninfoOption PQconninfoOptions[] = {
|
||||
"Backend-Debug-Options", "D", 40},
|
||||
|
||||
#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", "", 1},
|
||||
"Require-SSL", "D", 1},
|
||||
#endif
|
||||
|
||||
/*
|
||||
* "sslmode" option is allowed even without client SSL support
|
||||
* because the client can still handle SSL modes "disable" and
|
||||
* "allow".
|
||||
*/
|
||||
{"sslmode", "PGSSLMODE", DefaultSSLMode, NULL,
|
||||
"SSL-Mode", "", 8}, /* sizeof("disable") == 8 */
|
||||
|
||||
/* Terminating entry --- MUST BE LAST */
|
||||
{NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, 0}
|
||||
@ -340,10 +357,17 @@ connectOptions1(PGconn *conn, const char *conninfo)
|
||||
conn->pgpass = tmp ? strdup(tmp) : NULL;
|
||||
tmp = conninfo_getval(connOptions, "connect_timeout");
|
||||
conn->connect_timeout = tmp ? strdup(tmp) : NULL;
|
||||
tmp = conninfo_getval(connOptions, "sslmode");
|
||||
conn->sslmode = tmp ? strdup(tmp) : NULL;
|
||||
#ifdef USE_SSL
|
||||
tmp = conninfo_getval(connOptions, "requiressl");
|
||||
if (tmp && tmp[0] == '1')
|
||||
conn->require_ssl = true;
|
||||
{
|
||||
/* here warn that the requiressl option is deprecated? */
|
||||
if (conn->sslmode)
|
||||
free(conn->sslmode);
|
||||
conn->sslmode = "require";
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -412,6 +436,46 @@ connectOptions2(PGconn *conn)
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* validate sslmode option
|
||||
*/
|
||||
if (conn->sslmode)
|
||||
{
|
||||
if (strcmp(conn->sslmode, "disable") != 0
|
||||
&& strcmp(conn->sslmode, "allow") != 0
|
||||
&& strcmp(conn->sslmode, "prefer") != 0
|
||||
&& strcmp(conn->sslmode, "require") != 0)
|
||||
{
|
||||
conn->status = CONNECTION_BAD;
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("unknown sslmode \"%s\" requested\n"),
|
||||
conn->sslmode);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef USE_SSL
|
||||
switch (conn->sslmode[0]) {
|
||||
case 'a': /* "allow" */
|
||||
case 'p': /* "prefer" */
|
||||
/*
|
||||
* warn user that an SSL connection will never be
|
||||
* negotiated since SSL was not compiled in?
|
||||
*/
|
||||
break;
|
||||
|
||||
case 'r': /* "require" */
|
||||
conn->status = CONNECTION_BAD;
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("sslmode \"%s\" invalid when SSL "
|
||||
"support is not compiled in\n"),
|
||||
conn->sslmode);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
conn->sslmode = DefaultSSLMode;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -878,6 +942,14 @@ connectDBStart(PGconn *conn)
|
||||
goto connect_errReturn;
|
||||
}
|
||||
|
||||
#ifdef USE_SSL
|
||||
/* setup values based on SSL mode */
|
||||
if (conn->sslmode[0] == 'd') /* "disable" */
|
||||
conn->allow_ssl_try = false;
|
||||
else if (conn->sslmode[0] == 'a') /* "allow" */
|
||||
conn->wait_ssl_try = true;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set up to try to connect, with protocol 3.0 as the first attempt.
|
||||
*/
|
||||
@ -1278,9 +1350,8 @@ retry_connect:
|
||||
{
|
||||
/* Don't bother requesting SSL over a Unix socket */
|
||||
conn->allow_ssl_try = false;
|
||||
conn->require_ssl = false;
|
||||
}
|
||||
if (conn->allow_ssl_try && conn->ssl == NULL)
|
||||
if (conn->allow_ssl_try && !conn->wait_ssl_try && conn->ssl == NULL)
|
||||
{
|
||||
ProtocolVersion pv;
|
||||
|
||||
@ -1384,13 +1455,22 @@ retry_ssl_read:
|
||||
}
|
||||
else if (SSLok == 'N')
|
||||
{
|
||||
if (conn->require_ssl)
|
||||
{
|
||||
/* Require SSL, but server does not want it */
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("server does not support SSL, but SSL was required\n"));
|
||||
goto error_return;
|
||||
switch (conn->sslmode[0]) {
|
||||
case 'r': /* "require" */
|
||||
/* Require SSL, but server does not want it */
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("server does not support SSL, but SSL was required\n"));
|
||||
goto error_return;
|
||||
case 'a': /* "allow" */
|
||||
/*
|
||||
* normal startup already failed,
|
||||
* so SSL failure means the end
|
||||
*/
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("server does not support SSL, and previous non-SSL attempt failed\n"));
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
/* Otherwise, proceed with normal startup */
|
||||
conn->allow_ssl_try = false;
|
||||
conn->status = CONNECTION_MADE;
|
||||
@ -1401,13 +1481,22 @@ retry_ssl_read:
|
||||
/* Received error - probably protocol mismatch */
|
||||
if (conn->Pfdebug)
|
||||
fprintf(conn->Pfdebug, "Postmaster reports error, attempting fallback to pre-7.0.\n");
|
||||
if (conn->require_ssl)
|
||||
{
|
||||
/* Require SSL, but server is too old */
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("server does not support SSL, but SSL was required\n"));
|
||||
goto error_return;
|
||||
switch (conn->sslmode[0]) {
|
||||
case 'r': /* "require" */
|
||||
/* Require SSL, but server is too old */
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("server does not support SSL, but SSL was required\n"));
|
||||
goto error_return;
|
||||
case 'a': /* "allow" */
|
||||
/*
|
||||
* normal startup already failed,
|
||||
* so SSL failure means the end
|
||||
*/
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("server does not support SSL, and previous non-SSL attempt failed\n"));
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
/* Otherwise, try again without SSL */
|
||||
conn->allow_ssl_try = false;
|
||||
/* Assume it ain't gonna handle protocol 3, either */
|
||||
@ -1594,6 +1683,45 @@ retry_ssl_read:
|
||||
}
|
||||
/* OK, we read the message; mark data consumed */
|
||||
conn->inStart = conn->inCursor;
|
||||
|
||||
#ifdef USE_SSL
|
||||
/*
|
||||
* if sslmode is "allow" and we haven't tried an
|
||||
* SSL connection already, then retry with an SSL connection
|
||||
*/
|
||||
if (conn->wait_ssl_try
|
||||
&& conn->ssl == NULL
|
||||
&& conn->allow_ssl_try)
|
||||
{
|
||||
conn->wait_ssl_try = false;
|
||||
/* Must drop the old connection */
|
||||
closesocket(conn->sock);
|
||||
conn->sock = -1;
|
||||
conn->status = CONNECTION_NEEDED;
|
||||
goto keep_going;
|
||||
}
|
||||
|
||||
/*
|
||||
* if sslmode is "prefer" and we're in an SSL
|
||||
* connection and we haven't already tried a non-SSL
|
||||
* for "allow", then do a non-SSL retry
|
||||
*/
|
||||
if (!conn->wait_ssl_try
|
||||
&& conn->ssl
|
||||
&& conn->allow_ssl_try
|
||||
&& conn->sslmode[0] == 'p') /* "prefer" */
|
||||
{
|
||||
conn->allow_ssl_try = false;
|
||||
/* Must drop the old connection */
|
||||
pqsecure_close(conn);
|
||||
closesocket(conn->sock);
|
||||
conn->sock = -1;
|
||||
free(conn->ssl);
|
||||
conn->status = CONNECTION_NEEDED;
|
||||
goto keep_going;
|
||||
}
|
||||
#endif
|
||||
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
@ -1645,6 +1773,44 @@ retry_ssl_read:
|
||||
if (fe_sendauth(areq, conn, conn->pghost, conn->pgpass,
|
||||
conn->errorMessage.data) != STATUS_OK)
|
||||
{
|
||||
#ifdef USE_SSL
|
||||
/*
|
||||
* if sslmode is "allow" and we haven't tried an
|
||||
* SSL connection already, then retry with an SSL connection
|
||||
*/
|
||||
if (conn->wait_ssl_try
|
||||
&& conn->ssl == NULL
|
||||
&& conn->allow_ssl_try)
|
||||
{
|
||||
conn->wait_ssl_try = false;
|
||||
/* Must drop the old connection */
|
||||
closesocket(conn->sock);
|
||||
conn->sock = -1;
|
||||
conn->status = CONNECTION_NEEDED;
|
||||
goto keep_going;
|
||||
}
|
||||
|
||||
/*
|
||||
* if sslmode is "prefer" and we're in an SSL
|
||||
* connection and we haven't already tried a non-SSL
|
||||
* for "allow", then do a non-SSL retry
|
||||
*/
|
||||
if (!conn->wait_ssl_try
|
||||
&& conn->ssl
|
||||
&& conn->allow_ssl_try
|
||||
&& conn->sslmode[0] == 'p') /* "prefer" */
|
||||
{
|
||||
conn->allow_ssl_try = false;
|
||||
/* Must drop the old connection */
|
||||
pqsecure_close(conn);
|
||||
closesocket(conn->sock);
|
||||
conn->sock = -1;
|
||||
free(conn->ssl);
|
||||
conn->status = CONNECTION_NEEDED;
|
||||
goto keep_going;
|
||||
}
|
||||
#endif
|
||||
|
||||
conn->errorMessage.len = strlen(conn->errorMessage.data);
|
||||
goto error_return;
|
||||
}
|
||||
|
Reference in New Issue
Block a user