From 7aec324c254c834008bbcd94b23fc4eba4977512 Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Wed, 10 Jan 2024 09:04:45 +0200
Subject: [PATCH v7 04/12] WIP: refactorings to backend support

---
 src/backend/libpq/be-secure.c       | 38 +++++++++++++++++++++--
 src/backend/libpq/pqcomm.c          |  4 +--
 src/backend/postmaster/postmaster.c | 47 ++++++-----------------------
 3 files changed, 46 insertions(+), 43 deletions(-)

diff --git a/src/backend/libpq/be-secure.c b/src/backend/libpq/be-secure.c
index 0e4786cb2b6..8c770ba5afb 100644
--- a/src/backend/libpq/be-secure.c
+++ b/src/backend/libpq/be-secure.c
@@ -112,18 +112,50 @@ secure_loaded_verify_locations(void)
 int
 secure_open_server(Port *port)
 {
+#ifdef USE_SSL
 	int			r = 0;
+	ssize_t len;
+
+	/* push unencrypted buffered data back through SSL setup */
+	len = pq_buffer_has_data();
+	if (len > 0)
+	{
+		char	   *buf = palloc(len);
+
+		pq_startmsgread();
+		if (pq_getbytes(buf, len) == EOF)
+			return STATUS_ERROR; /* shouldn't be possible */
+		pq_endmsgread();
+		port->raw_buf = buf;
+		port->raw_buf_remaining = len;
+		port->raw_buf_consumed = 0;
+	}
+	Assert(pq_buffer_has_data() == 0);
 
-#ifdef USE_SSL
 	r = be_tls_open_server(port);
 
+	if (port->raw_buf_remaining > 0)
+	{
+		/* This shouldn't be possible -- it would mean the client sent
+		 * encrypted data before we established a session key...
+		 */
+		elog(LOG, "Buffered unencrypted data remains after negotiating native SSL connection");
+		return STATUS_ERROR;
+	}
+	if (port->raw_buf != NULL)
+	{
+		pfree(port->raw_buf);
+		port->raw_buf = NULL;
+	}
+
 	ereport(DEBUG2,
 			(errmsg_internal("SSL connection from DN:\"%s\" CN:\"%s\"",
 							 port->peer_dn ? port->peer_dn : "(anonymous)",
 							 port->peer_cn ? port->peer_cn : "(anonymous)")));
-#endif
-
 	return r;
+#else
+	return 0;
+#endif
 }
 
 /*
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
index ff3a03a2428..caa502b6373 100644
--- a/src/backend/libpq/pqcomm.c
+++ b/src/backend/libpq/pqcomm.c
@@ -1134,9 +1134,7 @@ pq_discardbytes(size_t len)
 }
 
 /* --------------------------------
- *		pq_buffer_has_data		- is any buffered data available to read?
- *
- * Actually returns the number of bytes in the buffer...
+ *		pq_buffer_has_data		- return number of bytes in receive buffer
  *
  * This will *not* attempt to read more data. And reading up to that number of
  * bytes should not cause reading any more data either.
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 085c940aec5..b70e41c9e26 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -1933,13 +1933,10 @@ ServerLoop(void)
  * This happens before startup packets so we are careful not to actual read
  * any bytes from the stream if it's not a direct SSL connection.
  */
-
 static int
 ProcessSSLStartup(Port *port)
 {
-	int		firstbyte;
-
-	pq_startmsgread();
+	int			firstbyte;
 
 	pq_startmsgread();
 	firstbyte = pq_peekbyte();
@@ -1956,7 +1953,9 @@ ProcessSSLStartup(Port *port)
 		 * scanners, which may be less benign, but it's not really our job to
 		 * notice those.)
 		 */
-		return STATUS_ERROR;
+		// XXX: this is OK as far as this function is concerned. Let ProcessStartupPacket
+		// handle it
+		return STATUS_OK;
 	}
 
 	/*
@@ -1967,51 +1966,25 @@ ProcessSSLStartup(Port *port)
 	 */
 	if (firstbyte == 0x16)
 	{
-#ifdef USE_SSL
-		ssize_t len;
-		char *buf = NULL;
 		elog(LOG, "Detected direct SSL handshake");
 
-		/* push unencrypted buffered data back through SSL setup */
-		len = pq_buffer_has_data();
-		if (len > 0)
-		{
-			buf = palloc(len);
-			if (pq_getbytes(buf, len) == EOF)
-				return STATUS_ERROR; /* shouldn't be possible */
-			port->raw_buf = buf;
-			port->raw_buf_remaining = len;
-			port->raw_buf_consumed = 0;
-		}
-
-		Assert(pq_buffer_has_data() == 0);
-		if (secure_open_server(port) == -1)
+#ifdef USE_SSL
+		if (!LoadedSSL || port->laddr.addr.ss_family == AF_UNIX || port->ssl_in_use)
 		{
-			ereport(COMMERROR,
-					(errcode(ERRCODE_PROTOCOL_VIOLATION),
-					 errmsg("SSL Protocol Error during direct SSL connection initiation")));
+			// XXX: Send TLS alert ?
 			return STATUS_ERROR;
 		}
-
-		if (port->raw_buf_remaining > 0)
+		else if (secure_open_server(port) == -1)
 		{
-			/* This shouldn't be possible -- it would mean the client sent
-			 * encrypted data before we established a session key...
-			 */
-			elog(LOG, "Buffered unencrypted data remains after negotiating native SSL connection");
+			/* we assume secure_open_server() sent an appropriate TLS alert already */
 			return STATUS_ERROR;
 		}
-		pfree(port->raw_buf);
 #else
-		ereport(COMMERROR,
-				(errcode(ERRCODE_PROTOCOL_VIOLATION),
-				 errmsg("Received direct SSL connection request with no SSL support")));
+		// XXX: Send TLS alert ?
 		return STATUS_ERROR;
 #endif
 	}
 
-	pq_endmsgread();
-
 	if (port->ssl_in_use)
 		ereport(DEBUG2,
 				(errmsg_internal("Direct SSL connection established")));
-- 
2.39.2

