Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 7506677

Browse files
committed
Improve error reporting for SSL connection failures. Remove redundant
free operations in client_cert_cb --- openssl will also attempt to free these structures, resulting in core dumps.
1 parent 88969ea commit 7506677

File tree

2 files changed

+69
-50
lines changed

2 files changed

+69
-50
lines changed

src/backend/libpq/be-secure.c

+47-38
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*
1212
*
1313
* IDENTIFICATION
14-
* $PostgreSQL: pgsql/src/backend/libpq/be-secure.c,v 1.53 2004/11/17 04:05:42 neilc Exp $
14+
* $PostgreSQL: pgsql/src/backend/libpq/be-secure.c,v 1.54 2004/11/20 00:18:13 tgl Exp $
1515
*
1616
* Since the server static private key ($DataDir/server.key)
1717
* will normally be stored unencrypted so that the database
@@ -727,37 +727,6 @@ initialize_SSL(void)
727727
return 0;
728728
}
729729

730-
#ifdef WIN32
731-
/*
732-
* Win32 socket code uses nonblocking sockets. We ned to deal with that
733-
* by waiting on the socket if the SSL accept operation didn't complete
734-
* right away.
735-
*/
736-
static int pgwin32_SSL_accept(SSL *ssl)
737-
{
738-
int r;
739-
740-
while (1)
741-
{
742-
int rc;
743-
int waitfor;
744-
745-
r = SSL_accept(ssl);
746-
if (r == 1)
747-
return 1;
748-
749-
rc = SSL_get_error(ssl, r);
750-
if (rc != SSL_ERROR_WANT_READ && rc != SSL_ERROR_WANT_WRITE)
751-
return r;
752-
753-
waitfor = (rc == SSL_ERROR_WANT_READ)?FD_READ|FD_CLOSE|FD_ACCEPT:FD_WRITE|FD_CLOSE;
754-
if (pgwin32_waitforsinglesocket(SSL_get_fd(ssl), waitfor) == 0)
755-
return -1;
756-
}
757-
}
758-
#define SSL_accept(ssl) pgwin32_SSL_accept(ssl)
759-
#endif
760-
761730
/*
762731
* Destroy global SSL context.
763732
*/
@@ -777,7 +746,9 @@ destroy_SSL(void)
777746
static int
778747
open_server_SSL(Port *port)
779748
{
780-
int r;
749+
int r;
750+
int err;
751+
781752
Assert(!port->ssl);
782753
Assert(!port->peer);
783754

@@ -799,12 +770,50 @@ open_server_SSL(Port *port)
799770
close_SSL(port);
800771
return -1;
801772
}
802-
if ((r=SSL_accept(port->ssl)) <= 0)
773+
774+
aloop:
775+
r = SSL_accept(port->ssl);
776+
if (r <= 0)
803777
{
804-
ereport(COMMERROR,
805-
(errcode(ERRCODE_PROTOCOL_VIOLATION),
806-
errmsg("could not accept SSL connection: %i",
807-
SSL_get_error(port->ssl,r))));
778+
err = SSL_get_error(port->ssl, r);
779+
switch (err)
780+
{
781+
case SSL_ERROR_WANT_READ:
782+
case SSL_ERROR_WANT_WRITE:
783+
#ifdef WIN32
784+
pgwin32_waitforsinglesocket(SSL_get_fd(port->ssl),
785+
(err==SSL_ERROR_WANT_READ) ?
786+
FD_READ|FD_CLOSE|FD_ACCEPT : FD_WRITE|FD_CLOSE);
787+
#endif
788+
goto aloop;
789+
case SSL_ERROR_SYSCALL:
790+
if (r < 0)
791+
ereport(COMMERROR,
792+
(errcode_for_socket_access(),
793+
errmsg("could not accept SSL connection: %m")));
794+
else
795+
ereport(COMMERROR,
796+
(errcode(ERRCODE_PROTOCOL_VIOLATION),
797+
errmsg("could not accept SSL connection: EOF detected")));
798+
break;
799+
case SSL_ERROR_SSL:
800+
ereport(COMMERROR,
801+
(errcode(ERRCODE_PROTOCOL_VIOLATION),
802+
errmsg("could not accept SSL connection: %s",
803+
SSLerrmessage())));
804+
break;
805+
case SSL_ERROR_ZERO_RETURN:
806+
ereport(COMMERROR,
807+
(errcode(ERRCODE_PROTOCOL_VIOLATION),
808+
errmsg("could not accept SSL connection: EOF detected")));
809+
break;
810+
default:
811+
ereport(COMMERROR,
812+
(errcode(ERRCODE_PROTOCOL_VIOLATION),
813+
errmsg("unrecognized SSL error code: %d",
814+
err)));
815+
break;
816+
}
808817
close_SSL(port);
809818
return -1;
810819
}

src/interfaces/libpq/fe-secure.c

+22-12
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*
1212
*
1313
* IDENTIFICATION
14-
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.55 2004/10/16 03:26:43 momjian Exp $
14+
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.56 2004/11/20 00:18:18 tgl Exp $
1515
*
1616
* NOTES
1717
* [ Most of these notes are wrong/obsolete, but perhaps not all ]
@@ -267,6 +267,11 @@ pqsecure_open_client(PGconn *conn)
267267
close_SSL(conn);
268268
return PGRES_POLLING_FAILED;
269269
}
270+
/*
271+
* Initialize errorMessage to empty. This allows open_client_SSL()
272+
* to detect whether client_cert_cb() has stored a message.
273+
*/
274+
resetPQExpBuffer(&conn->errorMessage);
270275
}
271276
/* Begin or continue the actual handshake */
272277
return open_client_SSL(conn);
@@ -797,7 +802,6 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
797802
printfPQExpBuffer(&conn->errorMessage,
798803
libpq_gettext("certificate present, but not private key file \"%s\"\n"),
799804
fnbuf);
800-
X509_free(*x509);
801805
return 0;
802806
}
803807
if (!S_ISREG(buf.st_mode) || (buf.st_mode & 0077) ||
@@ -806,23 +810,20 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
806810
printfPQExpBuffer(&conn->errorMessage,
807811
libpq_gettext("private key file \"%s\" has wrong permissions\n"),
808812
fnbuf);
809-
X509_free(*x509);
810813
return 0;
811814
}
812815
if ((fp = fopen(fnbuf, "r")) == NULL)
813816
{
814817
printfPQExpBuffer(&conn->errorMessage,
815818
libpq_gettext("could not open private key file \"%s\": %s\n"),
816819
fnbuf, pqStrerror(errno, sebuf, sizeof(sebuf)));
817-
X509_free(*x509);
818820
return 0;
819821
}
820822
if (fstat(fileno(fp), &buf2) == -1 ||
821823
buf.st_dev != buf2.st_dev || buf.st_ino != buf2.st_ino)
822824
{
823825
printfPQExpBuffer(&conn->errorMessage,
824826
libpq_gettext("private key file \"%s\" changed during execution\n"), fnbuf);
825-
X509_free(*x509);
826827
return 0;
827828
}
828829
if (PEM_read_PrivateKey(fp, pkey, cb, NULL) == NULL)
@@ -833,7 +834,6 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
833834
libpq_gettext("could not read private key file \"%s\": %s\n"),
834835
fnbuf, err);
835836
SSLerrfree(err);
836-
X509_free(*x509);
837837
fclose(fp);
838838
return 0;
839839
}
@@ -848,8 +848,6 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
848848
libpq_gettext("certificate does not match private key file \"%s\": %s\n"),
849849
fnbuf, err);
850850
SSLerrfree(err);
851-
X509_free(*x509);
852-
EVP_PKEY_free(*pkey);
853851
return 0;
854852
}
855853

@@ -1045,11 +1043,23 @@ open_client_SSL(PGconn *conn)
10451043
}
10461044
case SSL_ERROR_SSL:
10471045
{
1048-
char *err = SSLerrmessage();
1046+
/*
1047+
* If there are problems with the local certificate files,
1048+
* these will be detected by client_cert_cb() which is
1049+
* called from SSL_connect(). We want to return that
1050+
* error message and not the rather unhelpful error that
1051+
* OpenSSL itself returns. So check to see if an error
1052+
* message was already stored.
1053+
*/
1054+
if (conn->errorMessage.len == 0)
1055+
{
1056+
char *err = SSLerrmessage();
10491057

1050-
printfPQExpBuffer(&conn->errorMessage,
1051-
libpq_gettext("SSL error: %s\n"), err);
1052-
SSLerrfree(err);
1058+
printfPQExpBuffer(&conn->errorMessage,
1059+
libpq_gettext("SSL error: %s\n"),
1060+
err);
1061+
SSLerrfree(err);
1062+
}
10531063
close_SSL(conn);
10541064
return PGRES_POLLING_FAILED;
10551065
}

0 commit comments

Comments
 (0)