static bool pq_init_ssl_lib = true;
static bool pq_init_crypto_lib = true;
+
+/*
+ * SSL_context is currently shared between threads and therefore we need to be
+ * careful to lock around any usage of it when providing thread safety.
+ * ssl_config_mutex is the mutex that we use to protect it.
+ */
static SSL_CTX *SSL_context = NULL;
#ifdef ENABLE_THREAD_SAFETY
/* We cannot use MSG_NOSIGNAL to block SIGPIPE when using SSL */
conn->sigpipe_flag = false;
+#ifdef ENABLE_THREAD_SAFETY
+ if (pthread_mutex_lock(&ssl_config_mutex))
+ return -1;
+#endif
/* Create a connection-specific SSL object */
if (!(conn->ssl = SSL_new(SSL_context)) ||
!SSL_set_app_data(conn->ssl, conn) ||
err);
SSLerrfree(err);
close_SSL(conn);
+#ifdef ENABLE_THREAD_SAFETY
+ pthread_mutex_unlock(&ssl_config_mutex);
+#endif
return PGRES_POLLING_FAILED;
}
-
+#ifdef ENABLE_THREAD_SAFETY
+ pthread_mutex_unlock(&ssl_config_mutex);
+#endif
/*
* Load client certificate, private key, and trusted CA certs.
*/
CRYPTO_set_id_callback(NULL);
/*
- * We don't free the lock array. If we get another connection in this
- * process, we will just re-use it with the existing mutexes.
+ * We don't free the lock array or the SSL_context. If we get another
+ * connection in this process, we will just re-use them with the
+ * existing mutexes.
*
* This means we leak a little memory on repeated load/unload of the
* library.
* understands which subject cert to present, in case different
* sslcert settings are used for different connections in the same
* process.
+ *
+ * NOTE: This function may also modify our SSL_context and therefore
+ * we have to lock around this call and any places where we use the
+ * SSL_context struct.
*/
+#ifdef ENABLE_THREAD_SAFETY
+ if (pthread_mutex_lock(&ssl_config_mutex))
+ return -1;
+#endif
if (SSL_CTX_use_certificate_chain_file(SSL_context, fnbuf) != 1)
{
char *err = SSLerrmessage();
libpq_gettext("could not read certificate file \"%s\": %s\n"),
fnbuf, err);
SSLerrfree(err);
+
+#ifdef ENABLE_THREAD_SAFETY
+ pthread_mutex_unlock(&ssl_config_mutex);
+#endif
return -1;
}
+
if (SSL_use_certificate_file(conn->ssl, fnbuf, SSL_FILETYPE_PEM) != 1)
{
char *err = SSLerrmessage();
libpq_gettext("could not read certificate file \"%s\": %s\n"),
fnbuf, err);
SSLerrfree(err);
+#ifdef ENABLE_THREAD_SAFETY
+ pthread_mutex_unlock(&ssl_config_mutex);
+#endif
return -1;
}
+
/* need to load the associated private key, too */
have_cert = true;
+
+#ifdef ENABLE_THREAD_SAFETY
+ pthread_mutex_unlock(&ssl_config_mutex);
+#endif
}
/*
{
X509_STORE *cvstore;
+#ifdef ENABLE_THREAD_SAFETY
+ if (pthread_mutex_lock(&ssl_config_mutex))
+ return -1;
+#endif
if (SSL_CTX_load_verify_locations(SSL_context, fnbuf, NULL) != 1)
{
char *err = SSLerrmessage();
libpq_gettext("could not read root certificate file \"%s\": %s\n"),
fnbuf, err);
SSLerrfree(err);
+#ifdef ENABLE_THREAD_SAFETY
+ pthread_mutex_unlock(&ssl_config_mutex);
+#endif
return -1;
}
libpq_gettext("SSL library does not support CRL certificates (file \"%s\")\n"),
fnbuf);
SSLerrfree(err);
+#ifdef ENABLE_THREAD_SAFETY
+ pthread_mutex_unlock(&ssl_config_mutex);
+#endif
return -1;
#endif
}
/* if not found, silently ignore; we do not require CRL */
}
+#ifdef ENABLE_THREAD_SAFETY
+ pthread_mutex_unlock(&ssl_config_mutex);
+#endif
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, verify_cb);
}