diff options
Diffstat (limited to 'src/interfaces/libpq/fe-connect.c')
-rw-r--r-- | src/interfaces/libpq/fe-connect.c | 80 |
1 files changed, 79 insertions, 1 deletions
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 4e86a8db91e..bb61cdfd5bd 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.102 1999/08/31 01:37:36 tgl Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.103 1999/09/27 03:13:16 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -40,6 +40,10 @@ #include "mb/pg_wchar.h" #endif +#ifdef USE_SSL +static SSL_CTX *SSL_context = NULL; +#endif + static ConnStatusType connectDB(PGconn *conn); static PGconn *makeEmptyPGconn(void); static void freePGconn(PGconn *conn); @@ -508,6 +512,12 @@ connectDB(PGconn *conn) family; char beresp; int on = 1; +#ifdef USE_SSL + StartupPacket np; /* Used to negotiate SSL connection */ + char SSLok; + static int allow_ssl_try = 1; /* Allowed to do SSL negotiation */ + int tried_ssl = 0; /* Set if SSL negotiation was tried */ +#endif /* * parse dbName to get all additional info in it, if any @@ -591,6 +601,70 @@ connectDB(PGconn *conn) goto connect_errReturn; } + /* This needs to be done before we set into nonblocking, since SSL negotiation + * does not like that mode */ + +#ifdef USE_SSL + /* Attempt to negotiate SSL usage */ + if (allow_ssl_try) { + tried_ssl = 1; + memset((char *)&np, 0, sizeof(np)); + np.protoVersion = htonl(NEGOTIATE_SSL_CODE); + if (pqPacketSend(conn, (char *) &np, sizeof(StartupPacket)) != STATUS_OK) + { + sprintf(conn->errorMessage, + "connectDB() -- couldn't send SSL negotiation packet: errno=%d\n%s\n", + errno, strerror(errno)); + goto connect_errReturn; + } + /* Now receive the backends response */ + if (recv(conn->sock, &SSLok, 1, 0) != 1) { + sprintf(conn->errorMessage, "PQconnectDB() -- couldn't read backend response: errno=%d\n%s\n", + errno, strerror(errno)); + goto connect_errReturn; + } + if (SSLok == 'S') { + if (!SSL_context) + { + SSL_load_error_strings(); + SSL_library_init(); + SSL_context = SSL_CTX_new(SSLv23_method()); + if (!SSL_context) { + sprintf(conn->errorMessage, + "connectDB() -- couldn't create SSL context: %s\n", + ERR_reason_error_string(ERR_get_error())); + goto connect_errReturn; + } + } + if (!(conn->ssl = SSL_new(SSL_context)) || + !SSL_set_fd(conn->ssl, conn->sock) || + SSL_connect(conn->ssl) <= 0) + { + sprintf(conn->errorMessage, + "connectDB() -- couldn't establish SSL connection: %s\n", + ERR_reason_error_string(ERR_get_error())); + goto connect_errReturn; + } + /* SSL connection finished. Continue to send startup packet */ + } + else if (SSLok == 'E') { + /* Received error - probably protocol mismatch */ + if (conn->Pfdebug) + fprintf(conn->Pfdebug, "Backend reports error, attempting fallback to pre-6.6.\n"); + close(conn->sock); + allow_ssl_try = 0; + return connectDB(conn); + } + else if (SSLok != 'N') { + strcpy(conn->errorMessage, + "Received invalid negotiation response.\n"); + goto connect_errReturn; + } + } + else + allow_ssl_try = 1; /* We'll allow an attempt to use SSL next time */ +#endif + /* * Set the right options. We need nonblocking I/O, and we don't want * delay of outgoing data. @@ -896,6 +970,10 @@ freePGconn(PGconn *conn) if (!conn) return; pqClearAsyncResult(conn); /* deallocate result and curTuple */ +#ifdef USE_SSL + if (conn->ssl) + SSL_free(conn->ssl); +#endif if (conn->sock >= 0) #ifdef WIN32 closesocket(conn->sock); |