Patch - SSL back to working

Started by Magnus Haganderover 25 years ago8 messages
#1Magnus Hagander
mha@sollentuna.net
1 attachment(s)

Here is a patch to bring SSL support back working. Sorry for the long delay
:-(

I also added the function sslinfo() to get information about the SSL
connection.
(I'm not 100% sure I got that one right, though. Is it enough to put an
entry in pg_proc.h, or do I need it anywhere else?
Also, I picked "lowest oid in highest free block" - correct?)

Example of the function for non-SSL connection:
template1=# select sslinfo();
sslinfo
-------------------------------
SSL not active on connection.
(1 row)

Example of the function for SSL connection:
template1=# select sslinfo();
sslinfo
-------------------------------------
SSL cipher: DES-CBC3-SHA, bits: 168
(1 row)

//Magnus

Attachments:

ssl_patchapplication/octet-stream; name=ssl_patchDownload
*** ./backend/postmaster/postmaster.c.orig	Sat Aug 19 14:39:05 2000
--- ./backend/postmaster/postmaster.c	Sat Aug 19 16:17:37 2000
***************
*** 1065,1071 ****
  		char		SSLok;
  
  #ifdef USE_SSL
! 		SSLok = 'S';			/* Support for SSL */
  #else
  		SSLok = 'N';			/* No support for SSL */
  #endif
--- 1065,1074 ----
  		char		SSLok;
  
  #ifdef USE_SSL
! 		if (port->laddr.sa.sa_family == AF_UNIX)
! 		  SSLok = 'N';                  /* No SSL on Unix sockets */
! 		else
! 		  SSLok = 'S';			/* Support for SSL */
  #else
  		SSLok = 'N';			/* No support for SSL */
  #endif
***************
*** 1076,1088 ****
  		}
  
  #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;
  		}
  #endif
  		/* ready for the normal startup packet */
--- 1079,1094 ----
  		}
  
  #ifdef USE_SSL
! 		if (port->laddr.sa.sa_family != AF_UNIX) {
! 		  /* Don't do SSL over Unix sockets */
! 		  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 */
***************
*** 1100,1106 ****
  	 * 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;
--- 1106,1112 ----
  	 * Any SSL negotiation must have taken place here, so drop the
  	 * connection ASAP if we require SSL
  	 */
! 	if (SecureNetServer && port->laddr.sa.sa_family == AF_INET && !port->ssl)
  	{
  		PacketSendError(&port->pktInfo, "Backend requires secure connection.");
  		return STATUS_OK;
***************
*** 2078,2090 ****
  		fprintf(stderr, "Failed to create SSL context: %s\n", ERR_reason_error_string(ERR_get_error()));
  		exit(1);
  	}
! 	snprintf(fnbuf, sizeof(fnbuf), "%s/server.crt", DataDir);
  	if (!SSL_CTX_use_certificate_file(SSL_context, fnbuf, SSL_FILETYPE_PEM))
  	{
  		fprintf(stderr, "Failed to load server certificate (%s): %s\n", fnbuf, ERR_reason_error_string(ERR_get_error()));
  		exit(1);
  	}
! 	snprintf(fnbuf, sizeof(fnbuf), "%s/server.key", DataDir);
  	if (!SSL_CTX_use_PrivateKey_file(SSL_context, fnbuf, SSL_FILETYPE_PEM))
  	{
  		fprintf(stderr, "Failed to load private key file (%s): %s\n", fnbuf, ERR_reason_error_string(ERR_get_error()));
--- 2084,2096 ----
  		fprintf(stderr, "Failed to create SSL context: %s\n", ERR_reason_error_string(ERR_get_error()));
  		exit(1);
  	}
! 	snprintf(fnbuf, sizeof(fnbuf), "%s/global/server.crt", DataDir);
  	if (!SSL_CTX_use_certificate_file(SSL_context, fnbuf, SSL_FILETYPE_PEM))
  	{
  		fprintf(stderr, "Failed to load server certificate (%s): %s\n", fnbuf, ERR_reason_error_string(ERR_get_error()));
  		exit(1);
  	}
! 	snprintf(fnbuf, sizeof(fnbuf), "%s/global/server.key", DataDir);
  	if (!SSL_CTX_use_PrivateKey_file(SSL_context, fnbuf, SSL_FILETYPE_PEM))
  	{
  		fprintf(stderr, "Failed to load private key file (%s): %s\n", fnbuf, ERR_reason_error_string(ERR_get_error()));
*** ./backend/utils/adt/Makefile.orig	Sat Aug 19 15:12:16 2000
--- ./backend/utils/adt/Makefile	Sat Aug 19 15:12:27 2000
***************
*** 24,30 ****
  	tid.o timestamp.o varbit.o varchar.o varlena.o version.o \
  	network.o mac.o inet_net_ntop.o inet_net_pton.o \
  	ri_triggers.o pg_lzcompress.o pg_locale.o formatting.o \
! 	ascii.o
  
  all: SUBSYS.o
  
--- 24,30 ----
  	tid.o timestamp.o varbit.o varchar.o varlena.o version.o \
  	network.o mac.o inet_net_ntop.o inet_net_pton.o \
  	ri_triggers.o pg_lzcompress.o pg_locale.o formatting.o \
! 	ascii.o ssl.o
  
  all: SUBSYS.o
  
*** ./backend/utils/adt/ssl.c.orig	Sat Aug 19 15:08:47 2000
--- ./backend/utils/adt/ssl.c	Sat Aug 19 16:50:53 2000
***************
*** 0 ****
--- 1,46 ----
+ /*-------------------------------------------------------------------------
+  *
+  * ssl.c
+  *	 Returns information about SSL on the active connection
+  *
+  * IDENTIFICATION
+  *
+  * $Header$
+  *
+  *-------------------------------------------------------------------------
+  */
+ 
+ #include "postgres.h"
+ 
+ #include "utils/builtins.h"
+ #include "libpq/libpq-be.h"
+ #include "miscadmin.h"
+ 
+ Datum pgsql_sslinfo(PG_FUNCTION_ARGS)
+ {
+   char retstr[256];
+   int n;
+   text *ret;
+ 
+ #ifdef USE_SSL
+   if (!MyProcPort->ssl) {
+     strcpy(retstr, "SSL not active on connection.");
+   }
+   else {
+     int sslbits;
+     SSL_get_cipher_bits(MyProcPort->ssl, &sslbits);
+     snprintf(retstr, sizeof(retstr)-1, "SSL cipher: %s, bits: %i", SSL_get_cipher(MyProcPort->ssl), sslbits);
+   }
+ #else
+   strcpy(retstr, "SSL not supported by this server.");
+ #endif
+ 
+   n = strlen(retstr);
+   ret = (text *) palloc(n + VARHDRSZ);
+ 
+   VARATT_SIZEP(ret) = n + VARHDRSZ;
+   memcpy(VARDATA(ret), retstr, n);
+ 
+   PG_RETURN_TEXT_P(ret);
+ }
+ 
*** ./include/catalog/pg_proc.h.orig	Sat Aug 19 15:35:20 2000
--- ./include/catalog/pg_proc.h	Sat Aug 19 16:25:32 2000
***************
*** 209,214 ****
--- 209,215 ----
  DESCR("not equal");
  DATA(insert OID =  89 (  version		   PGUID 12 f t f t 0 f 25 "" 100 0 0 100 pgsql_version - ));
  DESCR("PostgreSQL version string");
+ DATA(insert OID = 1874 (  sslinfo                  PGUID 12 f t f t 0 f 25 "" 100 0 0 100 pgsql_sslinfo - ));
  
  DATA(insert OID = 1265 (  rtcostestimate   PGUID 12 f t f t 7 f 0 "0 0 0 0 0 0 0" 100 0 0 100  rtcostestimate - ));
  DESCR("r-tree cost estimator");
*** ./include/utils/builtins.h.orig	Sat Aug 19 15:34:36 2000
--- ./include/utils/builtins.h	Sat Aug 19 15:35:02 2000
***************
*** 428,433 ****
--- 428,436 ----
  /* version.c */
  extern Datum pgsql_version(PG_FUNCTION_ARGS);
  
+ /* ssl.c */
+ extern Datum pgsql_sslinfo(PG_FUNCTION_ARGS);
+ 
  /* like.c */
  extern Datum namelike(PG_FUNCTION_ARGS);
  extern Datum namenlike(PG_FUNCTION_ARGS);
*** ./interfaces/libpq/fe-connect.c.orig	Sat Aug 19 14:55:23 2000
--- ./interfaces/libpq/fe-connect.c	Sat Aug 19 15:04:46 2000
***************
*** 781,793 ****
  		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
  	 */
  
  	/* Attempt to negotiate SSL usage */
  	if (conn->allow_ssl_try)
  	{
--- 781,836 ----
  		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;
+ 	}
  
+ #ifdef USE_SSL
  	/* Attempt to negotiate SSL usage */
  	if (conn->allow_ssl_try)
  	{
***************
*** 850,903 ****
  		}
  	}
  #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
--- 893,898 ----
#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Magnus Hagander (#1)
Re: Patch - SSL back to working

Magnus Hagander <mha@sollentuna.net> writes:

Here is a patch to bring SSL support back working. Sorry for the long delay
:-(

This is good ;-)

I also added the function sslinfo() to get information about the SSL
connection.

That strikes me as a very bizarre way of doing things. Why not add an
inquiry function to the libpq API, instead?

regards, tom lane

#3The Hermit Hacker
scrappy@hub.org
In reply to: Tom Lane (#2)
Re: Patch - SSL back to working

On Sat, 19 Aug 2000, Tom Lane wrote:

Magnus Hagander <mha@sollentuna.net> writes:

Here is a patch to bring SSL support back working. Sorry for the long delay
:-(

This is good ;-)

I also added the function sslinfo() to get information about the SSL
connection.

That strikes me as a very bizarre way of doing things. Why not add an
inquiry function to the libpq API, instead?

what's the difference between 'select sslinfo()' and 'select version()',
or is 'select version()' part of the libpq API also?

#4Tom Lane
tgl@sss.pgh.pa.us
In reply to: The Hermit Hacker (#3)
Re: Patch - SSL back to working

The Hermit Hacker <scrappy@hub.org> writes:

I also added the function sslinfo() to get information about the SSL
connection.

That strikes me as a very bizarre way of doing things. Why not add an
inquiry function to the libpq API, instead?

what's the difference between 'select sslinfo()' and 'select version()',

Well, (1) backend version is not known directly to libpq; the backend
*must* be queried in some fashion for that info. I suppose the SSL
connection info is known equally well at both ends of the connection,
so it seems bizarre to inquire of the backend information that would
be available without any round-trip query.

(2) Transport-level info should be available without having to deal with
concerns like whether you have a half-issued query already, or are in
abort transaction state and can't get the backend to execute a SELECT,
etc. This is a confusion of protocol-stack levels; it's like asking
the backend what the client's IP address is.

(3) version() is a constant, more or less, but sslinfo() will vary
depending on how you have connected. That bothers me, although I can't
quite put my finger on the reason why.

regards, tom lane

#5The Hermit Hacker
scrappy@hub.org
In reply to: Tom Lane (#4)
Re: Patch - SSL back to working

all good points, thanks :)

On Sat, 19 Aug 2000, Tom Lane wrote:

The Hermit Hacker <scrappy@hub.org> writes:

I also added the function sslinfo() to get information about the SSL
connection.

That strikes me as a very bizarre way of doing things. Why not add an
inquiry function to the libpq API, instead?

what's the difference between 'select sslinfo()' and 'select version()',

Well, (1) backend version is not known directly to libpq; the backend
*must* be queried in some fashion for that info. I suppose the SSL
connection info is known equally well at both ends of the connection,
so it seems bizarre to inquire of the backend information that would
be available without any round-trip query.

(2) Transport-level info should be available without having to deal with
concerns like whether you have a half-issued query already, or are in
abort transaction state and can't get the backend to execute a SELECT,
etc. This is a confusion of protocol-stack levels; it's like asking
the backend what the client's IP address is.

(3) version() is a constant, more or less, but sslinfo() will vary
depending on how you have connected. That bothers me, although I can't
quite put my finger on the reason why.

regards, tom lane

Marc G. Fournier ICQ#7615664 IRC Nick: Scrappy
Systems Administrator @ hub.org
primary: scrappy@hub.org secondary: scrappy@{freebsd|postgresql}.org

#6Peter Eisentraut
peter_e@gmx.net
In reply to: Magnus Hagander (#1)
Re: [PATCHES] Patch - SSL back to working

Magnus Hagander writes:

Here is a patch to bring SSL support back working. Sorry for the long delay
:-(

Any chance we can get a `diff -cr' patch?

Btw., a while ago I was wondering about the postmaster `-l' option: I
think it should be removed and the job should be done in pg_hba.conf
alone. Instead I would like an option (possibly -l) that turns off SSL
completely. Currently you can't even start the postmaster without the
certificate files etc. (Some docs on how to do that would be nice as
well.)

Btw.2: Where do you get the documenation? I have been looking for SSL API
docs all over.

--
Peter Eisentraut Sernanders v�g 10:115
peter_e@gmx.net 75262 Uppsala
http://yi.org/peter-e/ Sweden

(note to self: change signature, you don't live there anymore...)

#7Magnus Hagander
mha@sollentuna.net
In reply to: Peter Eisentraut (#6)
RE: [PATCHES] Patch - SSL back to working

I also added the function sslinfo() to get information about the SSL
connection.

That strikes me as a very bizarre way of doing things. Why not add an
inquiry function to the libpq API, instead?

Well. I did it mostly so I wouldn't have to change the API :-)
But your points are very good :-) I'll add something to the frontend
library, remove the function, and send a new patch.

Peter wrote:

Any chance we can get a `diff -cr' patch?

Sure, I'll do that next time. I just used the 'difforig' script that is
included in the backend. If this is not the preferred format of the patch,
maybe it shuold be updated?

Btw., a while ago I was wondering about the postmaster `-l' option: I
think it should be removed and the job should be done in pg_hba.conf
alone. Instead I would like an option (possibly -l) that turns off SSL
completely. Currently you can't even start the postmaster without the
certificate files etc. (Some docs on how to do that would be nice as
well.)

Hm. Yeah. It's actually handled at both stages right now. You can use the
"-l" option to reject *all* non-SSL INET connections at an early stage,
before even looknig at pg_hba.conf. But everything can be handled in
pg_hba.conf already.
I'll look at fixing that up as well :-)

Btw.2: Where do you get the documenation? I have been looking for SSL API
docs all over.

Actually, nowhere... I got it looking through other programs source when
developnig a "poor mans VPN" solution for work. Then I just took what I had
there and applied to postgresql. There is a serious lack of documentation of
that API...

//Magnus

#8Peter Eisentraut
peter_e@gmx.net
In reply to: Magnus Hagander (#7)
RE: [PATCHES] Patch - SSL back to working

Magnus Hagander writes:

Well. I did it mostly so I wouldn't have to change the API :-)
But your points are very good :-) I'll add something to the frontend
library, remove the function, and send a new patch.

I think something like what PQhost(), PQport(), etc. are doing would be
okay.

--
Peter Eisentraut Sernanders v�g 10:115
peter_e@gmx.net 75262 Uppsala
http://yi.org/peter-e/ Sweden