sslmode patch
Folks,
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
------- -----------
prevent 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
Attachments:
sslmode.patchtext/plain; CHARSET=US-ASCII; NAME=sslmode.patchDownload
Index: doc/FAQ
===================================================================
RCS file: /projects/cvsroot/pgsql-server/doc/FAQ,v
retrieving revision 1.221
diff -c -r1.221 FAQ
*** doc/FAQ 6 Jun 2003 22:20:40 -0000 1.221
--- doc/FAQ 1 Jul 2003 02:33:19 -0000
***************
*** 1111,1118 ****
* contrib/pgcrypto contains many encryption functions for use in SQL
queries.
! * The only way to encrypt transmission from the client to the server
! is by using hostssl in pg_hba.conf.
* Database user passwords are automatically encrypted when stored in
version 7.3. In previous versions, you must enable the option
PASSWORD_ENCRYPTION in postgresql.conf.
--- 1111,1122 ----
* contrib/pgcrypto contains many encryption functions for use in SQL
queries.
! * To encrypt transmission from the client to the server, the server
! must have the "ssl" option set to true in postgresql.conf, and an
! applicable host or hostssl record must exist in pg_hba.conf, and the
! client "sslmode" must not be "prevent". (Note that it is also
! possible to use a third-party encrypted transport, such as stunnel
! or ssh, rather than PostgreSQL's native SSL connections.)
* Database user passwords are automatically encrypted when stored in
version 7.3. In previous versions, you must enable the option
PASSWORD_ENCRYPTION in postgresql.conf.
Index: doc/src/sgml/client-auth.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql-server/doc/src/sgml/client-auth.sgml,v
retrieving revision 1.52
diff -c -r1.52 client-auth.sgml
*** doc/src/sgml/client-auth.sgml 25 Jun 2003 01:20:50 -0000 1.52
--- doc/src/sgml/client-auth.sgml 1 Jul 2003 02:33:20 -0000
***************
*** 83,95 ****
</para>
<para>
! A record may have one of the five formats
<synopsis>
local <replaceable>database</replaceable> <replaceable>user</replaceable> <replaceable>authentication-method</replaceable> <optional><replaceable>authentication-option</replaceable></optional>
host <replaceable>database</replaceable> <replaceable>user</replaceable> <replaceable>IP-address</replaceable> <replaceable>IP-mask</replaceable> <replaceable>authentication-method</replaceable> <optional><replaceable>authentication-option</replaceable></optional>
hostssl <replaceable>database</replaceable> <replaceable>user</replaceable> <replaceable>IP-address</replaceable> <replaceable>IP-mask</replaceable> <replaceable>authentication-method</replaceable> <optional><replaceable>authentication-option</replaceable></optional>
host <replaceable>database</replaceable> <replaceable>user</replaceable> <replaceable>IP-address</replaceable>/<replaceable>CIDR-mask</replaceable> <replaceable>authentication-method</replaceable> <optional><replaceable>authentication-option</replaceable></optional>
hostssl <replaceable>database</replaceable> <replaceable>user</replaceable> <replaceable>IP-address</replaceable>/<replaceable>CIDR-mask</replaceable> <replaceable>authentication-method</replaceable> <optional><replaceable>authentication-option</replaceable></optional>
</synopsis>
The meaning of the fields is as follows:
--- 83,97 ----
</para>
<para>
! A record may have one of the seven formats
<synopsis>
local <replaceable>database</replaceable> <replaceable>user</replaceable> <replaceable>authentication-method</replaceable> <optional><replaceable>authentication-option</replaceable></optional>
host <replaceable>database</replaceable> <replaceable>user</replaceable> <replaceable>IP-address</replaceable> <replaceable>IP-mask</replaceable> <replaceable>authentication-method</replaceable> <optional><replaceable>authentication-option</replaceable></optional>
hostssl <replaceable>database</replaceable> <replaceable>user</replaceable> <replaceable>IP-address</replaceable> <replaceable>IP-mask</replaceable> <replaceable>authentication-method</replaceable> <optional><replaceable>authentication-option</replaceable></optional>
+ hostnossl <replaceable>database</replaceable> <replaceable>user</replaceable> <replaceable>IP-address</replaceable> <replaceable>IP-mask</replaceable> <replaceable>authentication-method</replaceable> <optional><replaceable>authentication-option</replaceable></optional>
host <replaceable>database</replaceable> <replaceable>user</replaceable> <replaceable>IP-address</replaceable>/<replaceable>CIDR-mask</replaceable> <replaceable>authentication-method</replaceable> <optional><replaceable>authentication-option</replaceable></optional>
hostssl <replaceable>database</replaceable> <replaceable>user</replaceable> <replaceable>IP-address</replaceable>/<replaceable>CIDR-mask</replaceable> <replaceable>authentication-method</replaceable> <optional><replaceable>authentication-option</replaceable></optional>
+ hostnossl <replaceable>database</replaceable> <replaceable>user</replaceable> <replaceable>IP-address</replaceable>/<replaceable>CIDR-mask</replaceable> <replaceable>authentication-method</replaceable> <optional><replaceable>authentication-option</replaceable></optional>
</synopsis>
The meaning of the fields is as follows:
***************
*** 137,142 ****
--- 139,155 ----
</varlistentry>
<varlistentry>
+ <term><literal>hostnossl</literal></term>
+ <listitem>
+ <para>
+ This record is similar to <literal>hostssl</> but with the
+ opposite logic: it matches only regular connection attempts not
+ using SSL.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><replaceable>database</replaceable></term>
<listitem>
<para>
***************
*** 196,203 ****
</para>
<para>
! These fields only apply to <literal>host</literal> and
! <literal>hostssl</literal> records.
</para>
</listitem>
</varlistentry>
--- 209,216 ----
</para>
<para>
! These fields only apply to <literal>host</literal>,
! <literal>hostssl</literal>, and <literal>hostnossl</> records.
</para>
</listitem>
</varlistentry>
***************
*** 224,231 ****
</para>
<para>
! This field only applies to <literal>host</literal> and
! <literal>hostssl</literal> records.
</para>
</listitem>
</varlistentry>
--- 237,244 ----
</para>
<para>
! This field only applies to <literal>host</literal>,
! <literal>hostssl</literal>, and <literal>hostnossl</> records.
</para>
</listitem>
</varlistentry>
Index: doc/src/sgml/libpq.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql-server/doc/src/sgml/libpq.sgml,v
retrieving revision 1.127
diff -c -r1.127 libpq.sgml
*** doc/src/sgml/libpq.sgml 27 Jun 2003 19:08:37 -0000 1.127
--- doc/src/sgml/libpq.sgml 1 Jul 2003 02:33:21 -0000
***************
*** 207,219 ****
</varlistentry>
<varlistentry>
<term><literal>requiressl</literal></term>
<listitem>
<para>
! If set to 1, an <acronym>SSL</acronym> connection to the server is required.
<application>libpq</> will then refuse to connect if the server does not
accept an <acronym>SSL</acronym> connection.
! If set to 0 (default), <application>libpq</> will negotiate the connection type with server.
This option is only available if
<productname>PostgreSQL</> is compiled with SSL support.
</para>
--- 207,249 ----
</varlistentry>
<varlistentry>
+ <term><literal>sslmode</literal></term>
+ <listitem>
+ <para>
+ This option determines whether or with what priority an <acronym>SSL</>
+ connection will be negotiated with the server. There are four
+ modes: <term><literal>prevent</></> will attempt only an unencrypted
+ <acronym>SSL</> connection; <term><literal>allow</></> will negotiate,
+ trying first a non-<acronym>SSL</> connection, then if that fails,
+ then trying an <acronym>SSL</> connection; <term><literal>prefer</></>
+ (the default) will negotiate, trying first an <acronym>SSL</> connection,
+ then if that fails, trying a regular non-<acronym>SSL</> connection;
+ <term><literal>require</></> will try only an <acronym>SSL</> connection.
+ </para>
+ <para>
+ Option <term><literal>require</></> is only available if
+ <productname>PostgreSQL</> is compiled with SSL support. If it is not,
+ options <term><literal>allow</></> and <term><literal>prefer</></> will
+ not be able to try to negotiate an <acronym>SSL</> connection.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><literal>requiressl</literal></term>
<listitem>
<para>
! This option is deprecated in favor of the <term><literal>sslmode</></>
! setting.
! </para>
! <para>
! If set to 1, an <acronym>SSL</acronym> connection to the server is required
! (this is equivalent to <term><literal>sslmode</></> <term><literal>require</></>).
<application>libpq</> will then refuse to connect if the server does not
accept an <acronym>SSL</acronym> connection.
! If set to 0 (default), <application>libpq</> will negotiate the connection
! type with server (equivalent to <term><literal>sslmode</></>
! <term><literal>prefer</></>).
This option is only available if
<productname>PostgreSQL</> is compiled with SSL support.
</para>
***************
*** 3141,3153 ****
<listitem>
<para>
<indexterm>
<primary><envar>PGREQUIRESSL</envar></primary>
</indexterm>
<envar>PGREQUIRESSL</envar> sets whether or not the connection must be
made over <acronym>SSL</acronym>. If set to
<quote>1</quote>, <application>libpq</>
will refuse to connect if the server does not accept
! an <acronym>SSL</acronym> connection.
This option is only available if
<productname>PostgreSQL</> is compiled with SSL support.
</para>
--- 3171,3207 ----
<listitem>
<para>
<indexterm>
+ <primary><envar>PGSSLMODE</envar></primary>
+ </indexterm>
+ <envar>PGSSLMODE</envar> determines whether and with what priority an
+ <acronym>SSL</> connection will be negotiated with the server. There are
+ four modes: <term><literal>prevent</></> will attempt only an unencrypted
+ <acronym>SSL</> connection; <term><literal>allow</></> will negotiate,
+ trying first a non-<acronym>SSL</> connection, then if that fails,
+ then trying an <acronym>SSL</> connection; <term><literal>prefer</></>
+ (the default) will negotiate, trying first an <acronym>SSL</>
+ connection, then if that fails, trying a regular non-<acronym>SSL</>
+ connection; <term><literal>require</></> will try only an <acronym>SSL</>
+ connection. Option <term><literal>require</></> is only available if
+ <productname>PostgreSQL</> is compiled with SSL support. If it is not,
+ options <term><literal>allow</></> and <term><literal>prefer</></>
+ will not be able to try to negotiate an <acronym>SSL</> connection.
+ </para>
+ </listitem>
+ <listitem>
+ <listitem>
+ <para>
+ <indexterm>
<primary><envar>PGREQUIRESSL</envar></primary>
</indexterm>
+ This option is deprecated in favor of the <term><literal>sslmode</></>
+ setting.
<envar>PGREQUIRESSL</envar> sets whether or not the connection must be
made over <acronym>SSL</acronym>. If set to
<quote>1</quote>, <application>libpq</>
will refuse to connect if the server does not accept
! an <acronym>SSL</acronym> connection (equivalent to <term><literal>sslmode</></>
! <term><literal>prefer</></>).
This option is only available if
<productname>PostgreSQL</> is compiled with SSL support.
</para>
Index: src/backend/libpq/auth.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/libpq/auth.c,v
retrieving revision 1.103
diff -c -r1.103 auth.c
*** src/backend/libpq/auth.c 25 Jun 2003 01:19:47 -0000 1.103
--- src/backend/libpq/auth.c 1 Jul 2003 02:33:22 -0000
***************
*** 424,431 ****
NULL, 0, NI_NUMERICHOST);
elog(FATAL,
! "No pg_hba.conf entry for host %s, user %s, database %s",
! hostinfo, port->user_name, port->database_name);
break;
}
--- 424,432 ----
NULL, 0, NI_NUMERICHOST);
elog(FATAL,
! "No pg_hba.conf entry for host %s, user %s, database %s, SSL %s",
! hostinfo, port->user_name, port->database_name,
! port->ssl ? "on" : "off");
break;
}
Index: src/backend/libpq/be-secure.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/libpq/be-secure.c,v
retrieving revision 1.34
diff -c -r1.34 be-secure.c
*** src/backend/libpq/be-secure.c 11 Jun 2003 15:05:50 -0000 1.34
--- src/backend/libpq/be-secure.c 1 Jul 2003 02:33:22 -0000
***************
*** 643,649 ****
SSL_CTX_set_options(SSL_context, SSL_OP_SINGLE_DH_USE | SSL_OP_NO_SSLv2);
/* setup the allowed cipher list */
! if (SSL_CTX_set_cipher_list(SSL_context, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGH") != 1)
{
postmaster_error("unable to set the cipher list (no valid ciphers available)");
ExitPostmaster(1);
--- 643,649 ----
SSL_CTX_set_options(SSL_context, SSL_OP_SINGLE_DH_USE | SSL_OP_NO_SSLv2);
/* setup the allowed cipher list */
! if (SSL_CTX_set_cipher_list(SSL_context, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH") != 1)
{
postmaster_error("unable to set the cipher list (no valid ciphers available)");
ExitPostmaster(1);
Index: src/backend/libpq/hba.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/libpq/hba.c,v
retrieving revision 1.104
diff -c -r1.104 hba.c
*** src/backend/libpq/hba.c 15 Jun 2003 16:21:39 -0000 1.104
--- src/backend/libpq/hba.c 1 Jul 2003 02:33:22 -0000
***************
*** 590,596 ****
if (port->raddr.addr.ss_family != AF_UNIX)
return;
}
! else if (strcmp(token, "host") == 0 || strcmp(token, "hostssl") == 0)
{
if (strcmp(token, "hostssl") == 0)
--- 590,598 ----
if (port->raddr.addr.ss_family != AF_UNIX)
return;
}
! else if (strcmp(token, "host") == 0
! || strcmp(token, "hostssl") == 0
! || strcmp(token, "hostnossl") == 0)
{
if (strcmp(token, "hostssl") == 0)
***************
*** 608,613 ****
--- 610,621 ----
/* We don't accept this keyword at all if no SSL support */
goto hba_syntax;
#endif
+ }
+ else if (strcmp(token, "hostnossl") == 0)
+ {
+ /* Record does not match if we are on an SSL connection */
+ if (port->ssl)
+ return;
}
/* Get the database. */
Index: src/interfaces/libpq/fe-connect.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/interfaces/libpq/fe-connect.c,v
retrieving revision 1.252
diff -c -r1.252 fe-connect.c
*** src/interfaces/libpq/fe-connect.c 23 Jun 2003 19:20:24 -0000 1.252
--- src/interfaces/libpq/fe-connect.c 1 Jul 2003 02:33:28 -0000
***************
*** 60,65 ****
--- 60,70 ----
#define DefaultOption ""
#define DefaultAuthtype ""
#define DefaultPassword ""
+ #ifdef USE_SSL
+ #define DefaultSSLMode "prefer"
+ #else
+ #define DefaultSSLMode "prevent"
+ #endif
/* ----------
***************
*** 131,140 ****
"Backend-Debug-Options", "D", 40},
#ifdef USE_SSL
{"requiressl", "PGREQUIRESSL", "0", NULL,
! "Require-SSL", "", 1},
#endif
/* Terminating entry --- MUST BE LAST */
{NULL, NULL, NULL, NULL,
NULL, NULL, 0}
--- 136,157 ----
"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", "D", 1},
#endif
+ /*
+ * "sslmode" option is allowed even without client SSL support
+ * because the client can still handle SSL modes "prevent" and
+ * "allow".
+ */
+ {"sslmode", "PGSSLMODE", DefaultSSLMode, NULL,
+ "SSL-Mode", "", 8}, /* sizeof("prevent") == 8 */
+
/* Terminating entry --- MUST BE LAST */
{NULL, NULL, NULL, NULL,
NULL, NULL, 0}
***************
*** 340,349 ****
conn->pgpass = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "connect_timeout");
conn->connect_timeout = tmp ? strdup(tmp) : NULL;
#ifdef USE_SSL
tmp = conninfo_getval(connOptions, "requiressl");
if (tmp && tmp[0] == '1')
! conn->require_ssl = true;
#endif
/*
--- 357,373 ----
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')
! {
! /* here warn that the requiressl option is deprecated? */
! if (conn->sslmode)
! free(conn->sslmode);
! conn->sslmode = "require";
! }
#endif
/*
***************
*** 412,417 ****
--- 436,482 ----
}
#endif
+ /*
+ * validate sslmode option
+ */
+ if (conn->sslmode)
+ {
+ if (strcmp(conn->sslmode, "prevent") != 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;
+ }
+
+ #ifdef USE_SSL
+ if (strcmp(conn->sslmode, "allow") == 0
+ || strcmp(conn->sslmode, "prefer") == 0)
+ {
+ /*
+ * warn user that an SSL connection will never be
+ * negotiated since SSL was not compiled in?
+ */
+ }
+ #else
+ if (strcmp(conn->sslmode, "require") == 0)
+ {
+ 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;
}
***************
*** 865,870 ****
--- 930,941 ----
goto connect_errReturn;
}
+ /* setup values based on SSL mode */
+ if (strcmp(conn->sslmode, "prevent") == 0)
+ conn->allow_ssl_try = false;
+ else if (strcmp(conn->sslmode, "allow") == 0)
+ conn->wait_ssl_try = true;
+
/*
* Set up to try to connect, with protocol 3.0 as the first attempt.
*/
***************
*** 1269,1278 ****
{
/* Don't bother requesting SSL over a Unix socket */
conn->allow_ssl_try = false;
- conn->require_ssl = false;
}
#endif
! if (conn->allow_ssl_try && conn->ssl == NULL)
{
ProtocolVersion pv;
--- 1340,1348 ----
{
/* Don't bother requesting SSL over a Unix socket */
conn->allow_ssl_try = false;
}
#endif
! if (conn->allow_ssl_try && ! conn->wait_ssl_try && conn->ssl == NULL)
{
ProtocolVersion pv;
***************
*** 1376,1388 ****
}
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;
}
/* Otherwise, proceed with normal startup */
conn->allow_ssl_try = false;
conn->status = CONNECTION_MADE;
--- 1446,1470 ----
}
else if (SSLok == 'N')
{
! if (strcmp(conn->sslmode, "require") == 0)
{
/* 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;
}
+ else if (conn->wait_ssl_try)
+ {
+ /*
+ * normal startup already failed, so SSL failure
+ * means the end
+ */
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("server does not support normal or SSL connections\n"));
+ goto error_return;
+ }
+
+
/* Otherwise, proceed with normal startup */
conn->allow_ssl_try = false;
conn->status = CONNECTION_MADE;
***************
*** 1393,1405 ****
/* 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;
}
/* Otherwise, try again without SSL */
conn->allow_ssl_try = false;
/* Assume it ain't gonna handle protocol 3, either */
--- 1475,1497 ----
/* Received error - probably protocol mismatch */
if (conn->Pfdebug)
fprintf(conn->Pfdebug, "Postmaster reports error, attempting fallback to pre-7.0.\n");
! if (strcmp(conn->sslmode, "require") == 0)
{
/* 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;
}
+ else if (conn->wait_ssl_try)
+ {
+ /*
+ * normal startup already failed, so SSL failure
+ * means the end
+ */
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("server does not support normal or SSL connections\n"));
+ goto error_return;
+ }
/* Otherwise, try again without SSL */
conn->allow_ssl_try = false;
/* Assume it ain't gonna handle protocol 3, either */
***************
*** 1586,1591 ****
--- 1678,1722 ----
}
/* 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 not "require" 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
+ && strcmp(conn->sslmode, "require") != 0
+ && strcmp(conn->sslmode, "allow") != 0)
+ {
+ conn->allow_ssl_try = false;
+ /* Must drop the old connection */
+ closesocket(conn->sock);
+ conn->sock = -1;
+ free(conn->ssl);
+ conn->status = CONNECTION_NEEDED;
+ goto keep_going;
+ }
+ #endif
+
goto error_return;
}
***************
*** 1637,1642 ****
--- 1768,1811 ----
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 not "require" 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
+ && strcmp(conn->sslmode, "require") != 0
+ && strcmp(conn->sslmode, "allow") != 0)
+ {
+ conn->allow_ssl_try = false;
+ /* Must drop the old connection */
+ 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;
}
Index: src/interfaces/libpq/libpq-int.h
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/interfaces/libpq/libpq-int.h,v
retrieving revision 1.76
diff -c -r1.76 libpq-int.h
*** src/interfaces/libpq/libpq-int.h 23 Jun 2003 19:20:25 -0000 1.76
--- src/interfaces/libpq/libpq-int.h 1 Jul 2003 02:33:28 -0000
***************
*** 316,324 ****
PGresult *result; /* result being constructed */
PGresAttValue *curTuple; /* tuple currently being read */
#ifdef USE_SSL
bool allow_ssl_try; /* Allowed to try SSL negotiation */
! bool require_ssl; /* Require SSL to make connection */
SSL *ssl; /* SSL status, if have SSL connection */
X509 *peer; /* X509 cert of server */
char peer_dn[256 + 1]; /* peer distinguished name */
--- 316,326 ----
PGresult *result; /* result being constructed */
PGresAttValue *curTuple; /* tuple currently being read */
+ char *sslmode; /* SSL mode option string */
#ifdef USE_SSL
bool allow_ssl_try; /* Allowed to try SSL negotiation */
! bool wait_ssl_try; /* Delay SSL negotiation until after
! attempting normal connection */
SSL *ssl; /* SSL status, if have SSL connection */
X509 *peer; /* X509 cert of server */
char peer_dn[256 + 1]; /* peer distinguished name */
Jon Jensen wrote:
Folks,
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
------- -----------
prevent Unencrypted non-SSL only
I think the word 'never' would be more appropriate than 'prevent'.
allow Negotiate, prefer non-SSL
I like 'allow'. The never liked the 'prefernonssl/preferssl', though I
may have been the one to suggest it.
prefer Negotiate, prefer SSL (default)
require Require SSLThe only change to the server is a new pg_hba.conf line type,
"hostnossl", for specifying connections that are not allowed to use SSL
Should this be 'hostneverssl'? Nossl implies to me that the host
doesn't have SSL, which really isn't the issue.
(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 connectionsThese 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.
Are out defaults right, that we prefer SSL if client and server can do
it? And now have hostnossl(or hostneverssl) to turn it off?
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. :)
I think we can get this into 7.4.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
On Tue, 1 Jul 2003, Bruce Momjian wrote:
To sum up, there's a new client parameter "sslmode" and environment
variable "PGSSLMODE", with these options:sslmode description
------- -----------
prevent Unencrypted non-SSL onlyI think the word 'never' would be more appropriate than 'prevent'.
That sounds fine to me, though it breaks with the pattern of all four
option words being verbs, allowing the user to think "I want to *** SSL
mode for this connect."
The only change to the server is a new pg_hba.conf line type,
"hostnossl", for specifying connections that are not allowed to use SSLShould this be 'hostneverssl'? Nossl implies to me that the host
doesn't have SSL, which really isn't the issue.
Well, perhaps. But by that logic, "hostssl" would imply that the client
only will do SSL, which the server can't know. Since the server doesn't
know anything about the client ahead of time, I don't read anything into
it. I just think:
host = apply this line for any kind of connection,
hostssl = apply this line only to SSL connections, and
hostnossl = apply this line only to non-SSL connections.
It's unfortunate there's not a more distinctive name for a "regular" or
"plain" or "unencrypted" connection than "no SSL", but I don't think it's
too big of a deal.
Are out defaults right, that we prefer SSL if client and server can do
it? And now have hostnossl(or hostneverssl) to turn it off?
Yes, I think the defaults are good. Users who don't bother to read the
docs will end up with secured connections, which is good, and users
seeking to avoid the SSL overhead can then read the docs and learn how,
and consider how secure their network really is. :)
I think we can get this into 7.4.
That would be great. It would be good to hear someone else's take on the
above, and also on the code itself, since I'm not a C expert. I was unable
to build docs from SGML yesterday on my machine, and now that I got it to
work, I find I made some markup errors which I've corrected and can
resubmit whenever you're ready.
Jon
Jon Jensen wrote:
On Tue, 1 Jul 2003, Bruce Momjian wrote:
To sum up, there's a new client parameter "sslmode" and environment
variable "PGSSLMODE", with these options:sslmode description
------- -----------
prevent Unencrypted non-SSL onlyI think the word 'never' would be more appropriate than 'prevent'.
That sounds fine to me, though it breaks with the pattern of all four
option words being verbs, allowing the user to think "I want to *** SSL
mode for this connect."
Good point, how about "disable". My point in objecting to "prevent" is
that you don't really "prevent" a mode, I think.
The only change to the server is a new pg_hba.conf line type,
"hostnossl", for specifying connections that are not allowed to use SSLShould this be 'hostneverssl'? Nossl implies to me that the host
doesn't have SSL, which really isn't the issue.Well, perhaps. But by that logic, "hostssl" would imply that the client
only will do SSL, which the server can't know. Since the server doesn't
know anything about the client ahead of time, I don't read anything into
it. I just think:host = apply this line for any kind of connection,
hostssl = apply this line only to SSL connections, and
hostnossl = apply this line only to non-SSL connections.It's unfortunate there's not a more distinctive name for a "regular" or
"plain" or "unencrypted" connection than "no SSL", but I don't think it's
too big of a deal.
Yes, hostnossl is probably best.
Are out defaults right, that we prefer SSL if client and server can do
it? And now have hostnossl(or hostneverssl) to turn it off?Yes, I think the defaults are good. Users who don't bother to read the
docs will end up with secured connections, which is good, and users
seeking to avoid the SSL overhead can then read the docs and learn how,
and consider how secure their network really is. :)
Good.
I think we can get this into 7.4.
That would be great. It would be good to hear someone else's take on the
above, and also on the code itself, since I'm not a C expert. I was unable
to build docs from SGML yesterday on my machine, and now that I got it to
work, I find I made some markup errors which I've corrected and can
resubmit whenever you're ready.
Tom agrees on the 7.4 target. The docs can be done later, even during
beta, though we discourage waiting that long.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Newest patch applied. Thanks.
---------------------------------------------------------------------------
Jon Jensen wrote:
Folks,
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 SSLThe 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 connectionsThese 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
Content-Description:
[ Attachment, skipping... ]
Content-Description:
[ Attachment, skipping... ]
---------------------------(end of broadcast)---------------------------
TIP 6: Have you searched our list archives?
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
I had a little problem apply this patch because it had an #ifdef for
elog() parameter passing. Because ereport() is now a macro, you can't
do #ifdef inside a macro _call_, so I did it this way:
#ifdef USE_SSL
#define EREPORT_SSL_STATUS (port->ssl ? "on" : "off")
#else
#define EREPORT_SSL_STATUS "off"
#endif
ereport(FATAL,
(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
errmsg("no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\", SSL \"%s\"",
hostinfo, port->user_name, port->database_name, EREPORT_SSL_STATUS)));
break;
Is this the proper way to do it?
---------------------------------------------------------------------------
Bruce Momjian wrote:
Newest patch applied. Thanks.
---------------------------------------------------------------------------
Jon Jensen wrote:
Folks,
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 SSLThe 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 connectionsThese 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
Content-Description:
[ Attachment, skipping... ]
Content-Description:
[ Attachment, skipping... ]
---------------------------(end of broadcast)---------------------------
TIP 6: Have you searched our list archives?-- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 359-1001 + If your life is a hard drive, | 13 Roberts Road + Christ can be your backup. | Newtown Square, Pennsylvania 19073---------------------------(end of broadcast)---------------------------
TIP 1: subscribe and unsubscribe commands go to majordomo@postgresql.org
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Bruce Momjian <pgman@candle.pha.pa.us> writes:
I had a little problem apply this patch because it had an #ifdef for
elog() parameter passing. Because ereport() is now a macro, you can't
do #ifdef inside a macro _call_, so I did it this way:
I don't think a non-SSL-enabled build need be pointing that out in every
error message --- the SSL phrase shouldn't even be there in the message.
Accordingly, I'd be inclined to do this:
#ifdef USE_SSL
ereport(FATAL,
(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
errmsg("no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\", %s",
hostinfo, port->user_name, port->database_name,
(port->ssl ? gettext("SSL on") : gettext("SSL off")))));
#else
ereport(FATAL,
(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
errmsg("no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\"",
hostinfo, port->user_name, port->database_name)));
#endif
This approach is also more localizable.
regards, tom lane
Excellent idea. Patch attached and applied.
---------------------------------------------------------------------------
Tom Lane wrote:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
I had a little problem apply this patch because it had an #ifdef for
elog() parameter passing. Because ereport() is now a macro, you can't
do #ifdef inside a macro _call_, so I did it this way:I don't think a non-SSL-enabled build need be pointing that out in every
error message --- the SSL phrase shouldn't even be there in the message.
Accordingly, I'd be inclined to do this:#ifdef USE_SSL
ereport(FATAL,
(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
errmsg("no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\", %s",
hostinfo, port->user_name, port->database_name,
(port->ssl ? gettext("SSL on") : gettext("SSL off")))));
#else
ereport(FATAL,
(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
errmsg("no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\"",
hostinfo, port->user_name, port->database_name)));
#endifThis approach is also more localizable.
regards, tom lane
---------------------------(end of broadcast)---------------------------
TIP 6: Have you searched our list archives?
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Attachments:
/bjm/difftext/plainDownload
Index: auth.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/libpq/auth.c,v
retrieving revision 1.106
diff -c -c -r1.106 auth.c
*** auth.c 26 Jul 2003 13:50:02 -0000 1.106
--- auth.c 26 Jul 2003 15:21:20 -0000
***************
*** 440,454 ****
NI_NUMERICHOST);
#ifdef USE_SSL
- #define EREPORT_SSL_STATUS (port->ssl ? "on" : "off")
- #else
- #define EREPORT_SSL_STATUS "off"
- #endif
-
ereport(FATAL,
(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
errmsg("no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\", SSL \"%s\"",
! hostinfo, port->user_name, port->database_name, EREPORT_SSL_STATUS)));
break;
}
--- 440,455 ----
NI_NUMERICHOST);
#ifdef USE_SSL
ereport(FATAL,
(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
errmsg("no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\", SSL \"%s\"",
! hostinfo, port->user_name, port->database_name, port->ssl ? "on" : "off")));
! #else
! ereport(FATAL,
! (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
! errmsg("no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\"",
! hostinfo, port->user_name, port->database_name)));
! #endif
break;
}