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 **** ! A record may have one of the five formats local database user authentication-method authentication-option host database user IP-address IP-mask authentication-method authentication-option hostssl database user IP-address IP-mask authentication-method authentication-option host database user IP-address/CIDR-mask authentication-method authentication-option hostssl database user IP-address/CIDR-mask authentication-method authentication-option The meaning of the fields is as follows: --- 83,97 ---- ! A record may have one of the seven formats local database user authentication-method authentication-option host database user IP-address IP-mask authentication-method authentication-option hostssl database user IP-address IP-mask authentication-method authentication-option + hostnossl database user IP-address IP-mask authentication-method authentication-option host database user IP-address/CIDR-mask authentication-method authentication-option hostssl database user IP-address/CIDR-mask authentication-method authentication-option + hostnossl database user IP-address/CIDR-mask authentication-method authentication-option The meaning of the fields is as follows: *************** *** 137,142 **** --- 139,155 ---- + hostnossl + + + This record is similar to hostssl but with the + opposite logic: it matches only regular connection attempts not + using SSL. + + + + + database *************** *** 196,203 **** ! These fields only apply to host and ! hostssl records. --- 209,216 ---- ! These fields only apply to host, ! hostssl, and hostnossl records. *************** *** 224,231 **** ! This field only applies to host and ! hostssl records. --- 237,244 ---- ! This field only applies to host, ! hostssl, and hostnossl records. 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 **** requiressl ! If set to 1, an SSL connection to the server is required. libpq will then refuse to connect if the server does not accept an SSL connection. ! If set to 0 (default), libpq will negotiate the connection type with server. This option is only available if PostgreSQL is compiled with SSL support. --- 207,249 ---- + sslmode + + + This option determines whether or with what priority an SSL + connection will be negotiated with the server. There are four + modes: prevent will attempt only an unencrypted + SSL connection; allow will negotiate, + trying first a non-SSL connection, then if that fails, + then trying an SSL connection; prefer + (the default) will negotiate, trying first an SSL connection, + then if that fails, trying a regular non-SSL connection; + require will try only an SSL connection. + + + Option require is only available if + PostgreSQL is compiled with SSL support. If it is not, + options allow and prefer will + not be able to try to negotiate an SSL connection. + + + + + requiressl ! This option is deprecated in favor of the sslmode ! setting. ! ! ! If set to 1, an SSL connection to the server is required ! (this is equivalent to sslmode require). libpq will then refuse to connect if the server does not accept an SSL connection. ! If set to 0 (default), libpq will negotiate the connection ! type with server (equivalent to sslmode ! prefer). This option is only available if PostgreSQL is compiled with SSL support. *************** *** 3141,3153 **** PGREQUIRESSL PGREQUIRESSL sets whether or not the connection must be made over SSL. If set to 1, libpq will refuse to connect if the server does not accept ! an SSL connection. This option is only available if PostgreSQL is compiled with SSL support. --- 3171,3207 ---- + PGSSLMODE + + PGSSLMODE determines whether and with what priority an + SSL connection will be negotiated with the server. There are + four modes: prevent will attempt only an unencrypted + SSL connection; allow will negotiate, + trying first a non-SSL connection, then if that fails, + then trying an SSL connection; prefer + (the default) will negotiate, trying first an SSL + connection, then if that fails, trying a regular non-SSL + connection; require will try only an SSL + connection. Option require is only available if + PostgreSQL is compiled with SSL support. If it is not, + options allow and prefer + will not be able to try to negotiate an SSL connection. + + + + + + PGREQUIRESSL + This option is deprecated in favor of the sslmode + setting. PGREQUIRESSL sets whether or not the connection must be made over SSL. If set to 1, libpq will refuse to connect if the server does not accept ! an SSL connection (equivalent to sslmode ! prefer). This option is only available if PostgreSQL is compiled with SSL support. 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 */