From 7bc654bb16dc08153060c8ddc1e0f3786026a483 Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Wed, 30 Aug 2000 14:54:24 +0000 Subject: [PATCH] SSL patch from Magnus --- src/backend/postmaster/postmaster.c | 52 +++++------ src/bin/psql/startup.c | 34 ++++++- src/interfaces/libpq/fe-connect.c | 137 +++++++++++++++++----------- src/interfaces/libpq/libpq-fe.h | 10 +- src/interfaces/libpq/libpq-int.h | 3 +- 5 files changed, 147 insertions(+), 89 deletions(-) diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 986e0e038c..223b5bbe24 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.163 2000/08/29 16:40:19 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.164 2000/08/30 14:54:22 momjian Exp $ * * NOTES * @@ -195,10 +195,7 @@ static int SendStop = false; bool NetServer = false; /* listen on TCP/IP */ #ifdef USE_SSL -static bool SecureNetServer = false; /* if not zero, postmaster listens - * for only SSL non-local - * connections */ - +static bool DisableSSL = false; /* Completely disable SSL, even if compiled in */ #endif static pid_t StartupPID = 0, @@ -455,7 +452,7 @@ PostmasterMain(int argc, char *argv[]) break; #ifdef USE_SSL case 'l': - SecureNetServer = true; + DisableSSL = true; break; #endif case 'm': @@ -566,13 +563,14 @@ PostmasterMain(int argc, char *argv[]) } #ifdef USE_SSL - if (!NetServer && SecureNetServer) + if (!NetServer && !DisableSSL) { - fprintf(stderr, "%s: For SSL, you must enable TCP/IP connections.\n", + fprintf(stderr, "%s: For SSL, you must enable TCP/IP connections. Use -l to disable SSL\n", progname); exit(1); } - InitSSL(); + if (!DisableSSL) + InitSSL(); #endif if (NetServer) @@ -754,7 +752,7 @@ usage(const char *progname) printf(" -F turn fsync off\n"); printf(" -i listen on TCP/IP sockets\n"); #ifdef USE_SSL - printf(" -l listen only on SSL connections (EXPERIMENTAL)\n"); + printf(" -l disable SSL\n"); #endif printf(" -N maximum number of allowed connections (1..%d, default %d)\n", MAXBACKENDS, DEF_MAXBACKENDS); @@ -1062,7 +1060,11 @@ readStartupPacket(void *arg, PacketLen len, void *pkt) char SSLok; #ifdef USE_SSL - SSLok = 'S'; /* Support for SSL */ + if (DisableSSL || port->laddr.sa.sa_family != AF_INET) + /* No SSL when disabled or on Unix sockets */ + SSLok = 'N'; + else + SSLok = 'S'; /* Support for SSL */ #else SSLok = 'N'; /* No support for SSL */ #endif @@ -1073,13 +1075,15 @@ readStartupPacket(void *arg, PacketLen len, void *pkt) } #ifdef USE_SSL - if (!(port->ssl = SSL_new(SSL_context)) || - !SSL_set_fd(port->ssl, port->sock) || - SSL_accept(port->ssl) <= 0) - { - fprintf(stderr, "Failed to initialize SSL connection: %s, errno: %d (%s)\n", - ERR_reason_error_string(ERR_get_error()), errno, strerror(errno)); - return STATUS_ERROR; + if (SSLok == 'S') { + if (!(port->ssl = SSL_new(SSL_context)) || + !SSL_set_fd(port->ssl, port->sock) || + SSL_accept(port->ssl) <= 0) + { + fprintf(stderr, "Failed to initialize SSL connection: %s, errno: %d (%s)\n", + ERR_reason_error_string(ERR_get_error()), errno, strerror(errno)); + return STATUS_ERROR; + } } #endif /* ready for the normal startup packet */ @@ -1091,18 +1095,6 @@ readStartupPacket(void *arg, PacketLen len, void *pkt) /* Could add additional special packet types here */ -#ifdef USE_SSL - - /* - * Any SSL negotiation must have taken place here, so drop the - * connection ASAP if we require SSL - */ - if (SecureNetServer && !port->ssl) - { - PacketSendError(&port->pktInfo, "Backend requires secure connection."); - return STATUS_OK; - } -#endif /* Check we can handle the protocol the frontend is using. */ diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c index 88ef5865af..0f36e30ef8 100644 --- a/src/bin/psql/startup.c +++ b/src/bin/psql/startup.c @@ -3,7 +3,7 @@ * * Copyright 2000 by PostgreSQL Global Development Group * - * $Header: /cvsroot/pgsql/src/bin/psql/startup.c,v 1.34 2000/07/02 15:21:17 petere Exp $ + * $Header: /cvsroot/pgsql/src/bin/psql/startup.c,v 1.35 2000/08/30 14:54:23 momjian Exp $ */ #include "postgres.h" @@ -81,6 +81,10 @@ static void static void showVersion(void); +#ifdef USE_SSL +static void + printSSLInfo(void); +#endif /* @@ -263,7 +267,9 @@ main(int argc, char *argv[]) " \\g or terminate with semicolon to execute query\n" " \\q to quit\n\n", pset.progname); } - +#ifdef USE_SSL + printSSLInfo(); +#endif SetVariable(pset.vars, "PROMPT1", DEFAULT_PROMPT1); SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2); SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3); @@ -639,3 +645,27 @@ showVersion(void) puts("Read the file COPYRIGHT or use the command \\copyright to see the"); puts("usage and distribution terms."); } + + + +/* + * printSSLInfo + * + * Prints information about the current SSL connection, if SSL is in use + */ +#ifdef USE_SSL +static void +printSSLInfo(void) +{ + int sslbits = -1; + SSL *ssl; + + ssl = PQgetssl(pset.db); + if (!ssl) + return; /* no SSL */ + + SSL_get_cipher_bits(ssl, &sslbits); + printf("SSL enabled connection. Chiper: %s, bits: %i\n\n", + SSL_get_cipher(ssl),sslbits); +} +#endif diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 1db218e12b..7349be6645 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.132 2000/08/20 10:55:35 petere Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.133 2000/08/30 14:54:23 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -63,7 +63,6 @@ inet_aton(const char *cp, struct in_addr * inp) #ifdef USE_SSL static SSL_CTX *SSL_context = NULL; - #endif #define NOTIFYLIST_INITIAL_SIZE 10 @@ -131,6 +130,11 @@ static const PQconninfoOption PQconninfoOptions[] = { {"options", "PGOPTIONS", DefaultOption, NULL, "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} @@ -303,6 +307,10 @@ PQconnectStart(const char *conninfo) conn->pguser = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval(connOptions, "password"); conn->pgpass = tmp ? strdup(tmp) : NULL; +#ifdef USE_SSL + tmp = conninfo_getval(connOptions, "requiressl"); + conn->require_ssl = tmp ? (tmp[0]=='1'?true:false) : false; +#endif /* ---------- * Free the option info - all is in conn now @@ -475,6 +483,14 @@ PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, else conn->dbName = strdup(dbName); + +#ifdef USE_SSL + if ((tmp = getenv("PGREQUIRESSL")) != NULL) + conn->require_ssl = (tmp[0]=='1')?true:false; + else + conn->require_ssl = 0; +#endif + if (error) conn->status = CONNECTION_BAD; else @@ -781,13 +797,55 @@ connectDBStart(PGconn *conn) goto connect_errReturn; #endif -#ifdef USE_SSL - - /* - * This needs to be done before we set into nonblocking, since SSL - * negotiation does not like that mode + /* ---------- + * Start / make connection. We are hopefully in non-blocking mode + * now, but it is possible that: + * 1. Older systems will still block on connect, despite the + * non-blocking flag. (Anyone know if this is true?) + * 2. We are running under Windows, and aren't even trying + * to be non-blocking (see above). + * 3. We are using SSL. + * Thus, we have make arrangements for all eventualities. + * ---------- */ + if (connect(conn->sock, &conn->raddr.sa, conn->raddr_len) < 0) + { +#ifndef WIN32 + if (errno == EINPROGRESS || errno == 0) +#else + if (WSAGetLastError() == WSAEINPROGRESS) +#endif + { + /* + * This is fine - we're in non-blocking mode, and the + * connection is in progress. + */ + conn->status = CONNECTION_STARTED; + } + else + { + /* Something's gone wrong */ + printfPQExpBuffer(&conn->errorMessage, + "connectDBStart() -- connect() failed: %s\n" + "\tIs the postmaster running%s at '%s'\n" + "\tand accepting connections on %s '%s'?\n", + strerror(errno), + (family == AF_INET) ? " (with -i)" : "", + conn->pghost ? conn->pghost : "localhost", + (family == AF_INET) ? + "TCP/IP port" : "Unix socket", + conn->pgport); + goto connect_errReturn; + } + } + else + { + /* We're connected already */ + conn->status = CONNECTION_MADE; + } + +#ifdef USE_SSL /* Attempt to negotiate SSL usage */ if (conn->allow_ssl_try) { @@ -837,7 +895,7 @@ connectDBStart(PGconn *conn) { /* Received error - probably protocol mismatch */ if (conn->Pfdebug) - fprintf(conn->Pfdebug, "Postmaster reports error, attempting fallback to pre-6.6.\n"); + fprintf(conn->Pfdebug, "Postmaster reports error, attempting fallback to pre-7.0.\n"); close(conn->sock); conn->allow_ssl_try = FALSE; return connectDBStart(conn); @@ -849,55 +907,15 @@ connectDBStart(PGconn *conn) goto connect_errReturn; } } + if (conn->require_ssl && !conn->ssl) + { + /* Require SSL, but server does not support/want it */ + printfPQExpBuffer(&conn->errorMessage, + "Server does not support SSL when SSL was required.\n"); + goto connect_errReturn; + } #endif - /* ---------- - * Start / make connection. We are hopefully in non-blocking mode - * now, but it is possible that: - * 1. Older systems will still block on connect, despite the - * non-blocking flag. (Anyone know if this is true?) - * 2. We are running under Windows, and aren't even trying - * to be non-blocking (see above). - * 3. We are using SSL. - * Thus, we have make arrangements for all eventualities. - * ---------- - */ - if (connect(conn->sock, &conn->raddr.sa, conn->raddr_len) < 0) - { -#ifndef WIN32 - if (errno == EINPROGRESS || errno == 0) -#else - if (WSAGetLastError() == WSAEINPROGRESS) -#endif - { - - /* - * This is fine - we're in non-blocking mode, and the - * connection is in progress. - */ - conn->status = CONNECTION_STARTED; - } - else - { - /* Something's gone wrong */ - printfPQExpBuffer(&conn->errorMessage, - "connectDBStart() -- connect() failed: %s\n" - "\tIs the postmaster running%s at '%s'\n" - "\tand accepting connections on %s '%s'?\n", - strerror(errno), - (family == AF_INET) ? " (with -i)" : "", - conn->pghost ? conn->pghost : "localhost", - (family == AF_INET) ? - "TCP/IP port" : "Unix socket", - conn->pgport); - goto connect_errReturn; - } - } - else - { - /* We're connected already */ - conn->status = CONNECTION_MADE; - } /* * This makes the connection non-blocking, for all those cases which @@ -2485,6 +2503,15 @@ PQsetClientEncoding(PGconn *conn, const char *encoding) #endif +#ifdef USE_SSL +SSL *PQgetssl(PGconn *conn) +{ + if (!conn) + return NULL; + return conn->ssl; +} +#endif + void PQtrace(PGconn *conn, FILE *debug_port) { diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h index 3c9a311eaf..cfca198460 100644 --- a/src/interfaces/libpq/libpq-fe.h +++ b/src/interfaces/libpq/libpq-fe.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: libpq-fe.h,v 1.66 2000/04/14 00:24:52 tgl Exp $ + * $Id: libpq-fe.h,v 1.67 2000/08/30 14:54:23 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -25,6 +25,9 @@ extern "C" * such as Oid. */ #include "postgres_ext.h" +#ifdef USE_SSL +#include +#endif /* Application-visible enum types */ @@ -222,6 +225,11 @@ extern "C" extern int PQbackendPID(const PGconn *conn); extern int PQclientEncoding(const PGconn *conn); extern int PQsetClientEncoding(PGconn *conn, const char *encoding); +#ifdef USE_SSL + /* Get the SSL structure associated with a connection */ + extern SSL *PQgetssl(PGconn *conn); +#endif + /* Enable/disable tracing */ extern void PQtrace(PGconn *conn, FILE *debug_port); diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index b7d16d6d39..c640b6df9f 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -12,7 +12,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: libpq-int.h,v 1.26 2000/05/27 04:13:05 momjian Exp $ + * $Id: libpq-int.h,v 1.27 2000/08/30 14:54:24 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -263,6 +263,7 @@ struct pg_conn #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 */ #endif