|
@@ -207,7 +207,7 @@ rloop:
|
|
|
*/
|
|
|
goto rloop;
|
|
|
case SSL_ERROR_SYSCALL:
|
|
|
- if (n < 0)
|
|
|
+ if (n < 0 && SOCK_ERRNO != 0)
|
|
|
{
|
|
|
result_errno = SOCK_ERRNO;
|
|
|
if (result_errno == EPIPE ||
|
|
@@ -308,7 +308,13 @@ pgtls_write(PGconn *conn, const void *ptr, size_t len)
|
|
|
n = 0;
|
|
|
break;
|
|
|
case SSL_ERROR_SYSCALL:
|
|
|
- if (n < 0)
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If errno is still zero then assume it's a read EOF situation,
|
|
|
+ * and report EOF. (This seems possible because SSL_write can
|
|
|
+ * also do reads.)
|
|
|
+ */
|
|
|
+ if (n < 0 && SOCK_ERRNO != 0)
|
|
|
{
|
|
|
result_errno = SOCK_ERRNO;
|
|
|
if (result_errno == EPIPE || result_errno == ECONNRESET)
|
|
@@ -1523,11 +1529,12 @@ open_client_SSL(PGconn *conn)
|
|
|
* was using the system CA pool. For other errors, log
|
|
|
* them using the normal SYSCALL logging.
|
|
|
*/
|
|
|
- if (!save_errno && vcode == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY &&
|
|
|
+ if (save_errno == 0 &&
|
|
|
+ vcode == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY &&
|
|
|
strcmp(conn->sslrootcert, "system") == 0)
|
|
|
libpq_append_conn_error(conn, "SSL error: certificate verify failed: %s",
|
|
|
X509_verify_cert_error_string(vcode));
|
|
|
- else if (r == -1)
|
|
|
+ else if (r == -1 && save_errno != 0)
|
|
|
libpq_append_conn_error(conn, "SSL SYSCALL error: %s",
|
|
|
SOCK_STRERROR(save_errno, sebuf, sizeof(sebuf)));
|
|
|
else
|
|
@@ -1834,11 +1841,7 @@ PQsslAttribute(PGconn *conn, const char *attribute_name)
|
|
|
* to retry; do we need to adopt their logic for that?
|
|
|
*/
|
|
|
|
|
|
-#ifndef HAVE_BIO_GET_DATA
|
|
|
-#define BIO_get_data(bio) (bio->ptr)
|
|
|
-#define BIO_set_data(bio, data) (bio->ptr = data)
|
|
|
-#endif
|
|
|
-
|
|
|
+/* protected by ssl_config_mutex */
|
|
|
static BIO_METHOD *my_bio_methods;
|
|
|
|
|
|
static int
|
|
@@ -1846,7 +1849,7 @@ my_sock_read(BIO *h, char *buf, int size)
|
|
|
{
|
|
|
int res;
|
|
|
|
|
|
- res = pqsecure_raw_read((PGconn *) BIO_get_data(h), buf, size);
|
|
|
+ res = pqsecure_raw_read((PGconn *) BIO_get_app_data(h), buf, size);
|
|
|
BIO_clear_retry_flags(h);
|
|
|
if (res < 0)
|
|
|
{
|
|
@@ -1876,7 +1879,7 @@ my_sock_write(BIO *h, const char *buf, int size)
|
|
|
{
|
|
|
int res;
|
|
|
|
|
|
- res = pqsecure_raw_write((PGconn *) BIO_get_data(h), buf, size);
|
|
|
+ res = pqsecure_raw_write((PGconn *) BIO_get_app_data(h), buf, size);
|
|
|
BIO_clear_retry_flags(h);
|
|
|
if (res < 0)
|
|
|
{
|
|
@@ -1904,6 +1907,15 @@ my_sock_write(BIO *h, const char *buf, int size)
|
|
|
static BIO_METHOD *
|
|
|
my_BIO_s_socket(void)
|
|
|
{
|
|
|
+ BIO_METHOD *res;
|
|
|
+
|
|
|
+#ifdef ENABLE_THREAD_SAFETY
|
|
|
+ if (pthread_mutex_lock(&ssl_config_mutex))
|
|
|
+ return NULL;
|
|
|
+#endif
|
|
|
+
|
|
|
+ res = my_bio_methods;
|
|
|
+
|
|
|
if (!my_bio_methods)
|
|
|
{
|
|
|
BIO_METHOD *biom = (BIO_METHOD *) BIO_s_socket();
|
|
@@ -1912,39 +1924,58 @@ my_BIO_s_socket(void)
|
|
|
|
|
|
my_bio_index = BIO_get_new_index();
|
|
|
if (my_bio_index == -1)
|
|
|
- return NULL;
|
|
|
+ goto err;
|
|
|
my_bio_index |= (BIO_TYPE_DESCRIPTOR | BIO_TYPE_SOURCE_SINK);
|
|
|
- my_bio_methods = BIO_meth_new(my_bio_index, "libpq socket");
|
|
|
- if (!my_bio_methods)
|
|
|
- return NULL;
|
|
|
+ res = BIO_meth_new(my_bio_index, "libpq socket");
|
|
|
+ if (!res)
|
|
|
+ goto err;
|
|
|
|
|
|
/*
|
|
|
* As of this writing, these functions never fail. But check anyway,
|
|
|
* like OpenSSL's own examples do.
|
|
|
*/
|
|
|
- if (!BIO_meth_set_write(my_bio_methods, my_sock_write) ||
|
|
|
- !BIO_meth_set_read(my_bio_methods, my_sock_read) ||
|
|
|
- !BIO_meth_set_gets(my_bio_methods, BIO_meth_get_gets(biom)) ||
|
|
|
- !BIO_meth_set_puts(my_bio_methods, BIO_meth_get_puts(biom)) ||
|
|
|
- !BIO_meth_set_ctrl(my_bio_methods, BIO_meth_get_ctrl(biom)) ||
|
|
|
- !BIO_meth_set_create(my_bio_methods, BIO_meth_get_create(biom)) ||
|
|
|
- !BIO_meth_set_destroy(my_bio_methods, BIO_meth_get_destroy(biom)) ||
|
|
|
- !BIO_meth_set_callback_ctrl(my_bio_methods, BIO_meth_get_callback_ctrl(biom)))
|
|
|
+ if (!BIO_meth_set_write(res, my_sock_write) ||
|
|
|
+ !BIO_meth_set_read(res, my_sock_read) ||
|
|
|
+ !BIO_meth_set_gets(res, BIO_meth_get_gets(biom)) ||
|
|
|
+ !BIO_meth_set_puts(res, BIO_meth_get_puts(biom)) ||
|
|
|
+ !BIO_meth_set_ctrl(res, BIO_meth_get_ctrl(biom)) ||
|
|
|
+ !BIO_meth_set_create(res, BIO_meth_get_create(biom)) ||
|
|
|
+ !BIO_meth_set_destroy(res, BIO_meth_get_destroy(biom)) ||
|
|
|
+ !BIO_meth_set_callback_ctrl(res, BIO_meth_get_callback_ctrl(biom)))
|
|
|
{
|
|
|
- BIO_meth_free(my_bio_methods);
|
|
|
- my_bio_methods = NULL;
|
|
|
- return NULL;
|
|
|
+ goto err;
|
|
|
}
|
|
|
#else
|
|
|
- my_bio_methods = malloc(sizeof(BIO_METHOD));
|
|
|
- if (!my_bio_methods)
|
|
|
- return NULL;
|
|
|
- memcpy(my_bio_methods, biom, sizeof(BIO_METHOD));
|
|
|
- my_bio_methods->bread = my_sock_read;
|
|
|
- my_bio_methods->bwrite = my_sock_write;
|
|
|
+ res = malloc(sizeof(BIO_METHOD));
|
|
|
+ if (!res)
|
|
|
+ goto err;
|
|
|
+ memcpy(res, biom, sizeof(BIO_METHOD));
|
|
|
+ res->bread = my_sock_read;
|
|
|
+ res->bwrite = my_sock_write;
|
|
|
#endif
|
|
|
}
|
|
|
- return my_bio_methods;
|
|
|
+
|
|
|
+ my_bio_methods = res;
|
|
|
+
|
|
|
+#ifdef ENABLE_THREAD_SAFETY
|
|
|
+ pthread_mutex_unlock(&ssl_config_mutex);
|
|
|
+#endif
|
|
|
+
|
|
|
+ return res;
|
|
|
+
|
|
|
+err:
|
|
|
+#ifdef HAVE_BIO_METH_NEW
|
|
|
+ if (res)
|
|
|
+ BIO_meth_free(res);
|
|
|
+#else
|
|
|
+ if (res)
|
|
|
+ free(res);
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef ENABLE_THREAD_SAFETY
|
|
|
+ pthread_mutex_unlock(&ssl_config_mutex);
|
|
|
+#endif
|
|
|
+ return NULL;
|
|
|
}
|
|
|
|
|
|
/* This should exactly match OpenSSL's SSL_set_fd except for using my BIO */
|
|
@@ -1967,7 +1998,7 @@ my_SSL_set_fd(PGconn *conn, int fd)
|
|
|
SSLerr(SSL_F_SSL_SET_FD, ERR_R_BUF_LIB);
|
|
|
goto err;
|
|
|
}
|
|
|
- BIO_set_data(bio, conn);
|
|
|
+ BIO_set_app_data(bio, conn);
|
|
|
|
|
|
SSL_set_bio(conn->ssl, bio, bio);
|
|
|
BIO_set_fd(bio, fd, BIO_NOCLOSE);
|