text: /*-------------------------------------------------------------------------
   *
   * fe-secure-openssl.c
   *	  OpenSSL support
   *
   *
   * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
   * Portions Copyright (c) 1994, Regents of the University of California
   *
   *
   * IDENTIFICATION
   *	  src/interfaces/libpq/fe-secure-openssl.c
   *
   * NOTES
   *
   *	  We don't provide informational callbacks here (like
   *	  info_cb() in be-secure.c), since there's no good mechanism to
   *	  display such information to the user.
   *
   *-------------------------------------------------------------------------
   */
  
  #include "postgres_fe.h"
  
  #include <signal.h>
  #include <fcntl.h>
  #include <ctype.h>
  
  #include "libpq-fe.h"
  #include "fe-auth.h"
  #include "fe-secure-common.h"
  #include "libpq-int.h"
  
  #ifdef WIN32
  #include "win32.h"
  #else
  #include <sys/socket.h>
  #include <unistd.h>
  #include <netdb.h>
  #include <netinet/in.h>
  #ifdef HAVE_NETINET_TCP_H
  #include <netinet/tcp.h>
  #endif
  #include <arpa/inet.h>
  #endif
  
  #include <sys/stat.h>
  
  #ifdef ENABLE_THREAD_SAFETY
  #ifdef WIN32
  #include "pthread-win32.h"
  #else
  #include <pthread.h>
  #endif
  #endif
  
  #include <openssl/ssl.h>
  #include <openssl/conf.h>
  #ifdef USE_SSL_ENGINE
  #include <openssl/engine.h>
  #endif
  #include <openssl/x509v3.h>
  
  static int	verify_cb(int ok, X509_STORE_CTX *ctx);
  static int openssl_verify_peer_name_matches_certificate_name(PGconn *conn,
  												  ASN1_STRING *name,
  												  char **store_name);
  static void destroy_ssl_system(void);
  static int	initialize_SSL(PGconn *conn);
  static PostgresPollingStatusType open_client_SSL(PGconn *);
  static char *SSLerrmessage(unsigned long ecode);
  static void SSLerrfree(char *buf);
  
  static int	my_sock_read(BIO *h, char *buf, int size);
  static int	my_sock_write(BIO *h, const char *buf, int size);
  static BIO_METHOD *my_BIO_s_socket(void);
  static int	my_SSL_set_fd(PGconn *conn, int fd);
  
  
  static bool pq_init_ssl_lib = true;
  static bool pq_init_crypto_lib = true;
  
  static bool ssl_lib_initialized = false;
  
  #ifdef ENABLE_THREAD_SAFETY
  static long ssl_open_connections = 0;
  
  #ifndef WIN32
  static pthread_mutex_t ssl_config_mutex = PTHREAD_MUTEX_INITIALIZER;
  #else
  static pthread_mutex_t ssl_config_mutex = NULL;
  static long win32_ssl_create_mutex = 0;
  #endif
  #endif							/* ENABLE_THREAD_SAFETY */
  
  
  /* ------------------------------------------------------------ */
  /*			 Procedures common to all secure sessions			*/
  /* ------------------------------------------------------------ */
  
  void
  pgtls_init_library(bool do_ssl, int do_crypto)
  {
  #ifdef ENABLE_THREAD_SAFETY
  
  	/*
  	 * Disallow changing the flags while we have open connections, else we'd
  	 * get completely confused.
  	 */
  	if (ssl_open_connections != 0)
  		return;
  #endif
  
  	pq_init_ssl_lib = do_ssl;
  	pq_init_crypto_lib = do_crypto;
  }
  
  PostgresPollingStatusType
  pgtls_open_client(PGconn *conn)
  {
  	/* First time through? */
  	if (conn->ssl == NULL)
  	{
  		/*
  		 * Create a connection-specific SSL object, and load client
  		 * certificate, private key, and trusted CA certs.
  		 */
  		if (initialize_SSL(conn) != 0)
  		{
  			/* initialize_SSL already put a message in conn->errorMessage */
  			pgtls_close(conn);
  			return PGRES_POLLING_FAILED;
  		}
  	}
  
  	/* Begin or continue the actual handshake */
  	return open_client_SSL(conn);
  }
  
  ssize_t
  pgtls_read(PGconn *conn, void *ptr, size_t len)
  {
  	ssize_t		n;
  	int			result_errno = 0;
  	char		sebuf[256];
  	int			err;
  	unsigned long ecode;
  
  rloop:
  
  	/*
  	 * Prepare to call SSL_get_error() by clearing thread's OpenSSL error
  	 * queue.  In general, the current thread's error queue must be empty
  	 * before the TLS/SSL I/O operation is attempted, or SSL_get_error() will
  	 * not work reliably.  Since the possibility exists that other OpenSSL
  	 * clients running in the same thread but not under our control will fail
  	 * to call ERR_get_error() themselves (after their own I/O operations),
  	 * pro-actively clear the per-thread error queue now.
  	 */
  	SOCK_ERRNO_SET(0);
  	ERR_clear_error();
  	n = SSL_read(conn->ssl, ptr, len);
  	err = SSL_get_error(conn->ssl, n);
  
  	/*
  	 * Other clients of OpenSSL may fail to call ERR_get_error(), but we
  	 * always do, so as to not cause problems for OpenSSL clients that don't
  	 * call ERR_clear_error() defensively.  Be sure that this happens by
  	 * calling now.  SSL_get_error() relies on the OpenSSL per-thread error
  	 * queue being intact, so this is the earliest possible point
  	 * ERR_get_error() may be called.
  	 */
  	ecode = (err != SSL_ERROR_NONE || n < 0) ? ERR_get_error() : 0;
  	switch (err)
  	{
  		case SSL_ERROR_NONE:
  			if (n < 0)
  			{
  				/* Not supposed to happen, so we don't translate the msg */
  				printfPQExpBuffer(&conn->errorMessage,
  								  "SSL_read failed but did not provide error information\n");
  				/* assume the connection is broken */
  				result_errno = ECONNRESET;
  			}
  			break;
  		case SSL_ERROR_WANT_READ:
  			n = 0;
  			break;
  		case SSL_ERROR_WANT_WRITE:
  
  			/*
  			 * Returning 0 here would cause caller to wait for read-ready,
  			 * which is not correct since what SSL wants is wait for
  			 * write-ready.  The former could get us stuck in an infinite
  			 * wait, so don't risk it; busy-loop instead.
  			 */
  			goto rloop;
  		case SSL_ERROR_SYSCALL:
  			if (n < 0)
  			{
  				result_errno = SOCK_ERRNO;
  				if (result_errno == EPIPE ||
  					result_errno == ECONNRESET)
  					printfPQExpBuffer(&conn->errorMessage,
  									  libpq_gettext(
  													"server closed the connection unexpectedly\n"
  													"\tThis probably means the server terminated abnormally\n"
  													"\tbefore or while processing the request.\n"));
  				else
  					printfPQExpBuffer(&conn->errorMessage,
  									  libpq_gettext("SSL SYSCALL error: %s\n"),
  									  SOCK_STRERROR(result_errno,
  													sebuf, sizeof(sebuf)));
  			}
  			else
  			{
  				printfPQExpBuffer(&conn->errorMessage,
  								  libpq_gettext("SSL SYSCALL error: EOF detected\n"));
  				/* assume the connection is broken */
  				result_errno = ECONNRESET;
  				n = -1;
  			}
  			break;
  		case SSL_ERROR_SSL:
  			{
  				char	   *errm = SSLerrmessage(ecode);
  
  				printfPQExpBuffer(&conn->errorMessage,
  								  libpq_gettext("SSL error: %s\n"), errm);
  				SSLerrfree(errm);
  				/* assume the connection is broken */
  				result_errno = ECONNRESET;
  				n = -1;
  				break;
  			}
  		case SSL_ERROR_ZERO_RETURN:
  
  			/*
  			 * Per OpenSSL documentation, this error code is only returned for
  			 * a clean connection closure, so we should not report it as a
  			 * server crash.
  			 */
  			printfPQExpBuffer(&conn->errorMessage,
  							  libpq_gettext("SSL connection has been closed unexpectedly\n"));
  			result_errno = ECONNRESET;
  			n = -1;
  			break;
  		default:
  			printfPQExpBuffer(&conn->errorMessage,
  							  libpq_gettext("unrecognized SSL error code: %d\n"),
  							  err);
  			/* assume the connection is broken */
  			result_errno = ECONNRESET;
  			n = -1;
  			break;
  	}
  
  	/* ensure we return the intended errno to caller */
  	SOCK_ERRNO_SET(result_errno);
  
  	return n;
  }
  
  bool
  pgtls_read_pending(PGconn *conn)
  {
  	return SSL_pending(conn->ssl) > 0;
  }
  
  ssize_t
  pgtls_write(PGconn *conn, const void *ptr, size_t len)
  {
  	ssize_t		n;
  	int			result_errno = 0;
  	char		sebuf[256];
  	int			err;
  	unsigned long ecode;
  
  	SOCK_ERRNO_SET(0);
  	ERR_clear_error();
  	n = SSL_write(conn->ssl, ptr, len);
  	err = SSL_get_error(conn->ssl, n);
  	ecode = (err != SSL_ERROR_NONE || n < 0) ? ERR_get_error() : 0;
  	switch (err)
  	{
  		case SSL_ERROR_NONE:
  			if (n < 0)
  			{
  				/* Not supposed to happen, so we don't translate the msg */
  				printfPQExpBuffer(&conn->errorMessage,
  								  "SSL_write failed but did not provide error information\n");
  				/* assume the connection is broken */
  				result_errno = ECONNRESET;
  			}
  			break;
  		case SSL_ERROR_WANT_READ:
  
  			/*
  			 * Returning 0 here causes caller to wait for write-ready, which
  			 * is not really the right thing, but it's the best we can do.
  			 */
  			n = 0;
  			break;
  		case SSL_ERROR_WANT_WRITE:
  			n = 0;
  			break;
  		case SSL_ERROR_SYSCALL:
  			if (n < 0)
  			{
  				result_errno = SOCK_ERRNO;
  				if (result_errno == EPIPE || result_errno == ECONNRESET)
  					printfPQExpBuffer(&conn->errorMessage,
  									  libpq_gettext(
  													"server closed the connection unexpectedly\n"
  													"\tThis probably means the server terminated abnormally\n"
  													"\tbefore or while processing the request.\n"));
  				else
  					printfPQExpBuffer(&conn->errorMessage,
  									  libpq_gettext("SSL SYSCALL error: %s\n"),
  									  SOCK_STRERROR(result_errno,
  													sebuf, sizeof(sebuf)));
  			}
  			else
  			{
  				printfPQExpBuffer(&conn->errorMessage,
  								  libpq_gettext("SSL SYSCALL error: EOF detected\n"));
  				/* assume the connection is broken */
  				result_errno = ECONNRESET;
  				n = -1;
  			}
  			break;
  		case SSL_ERROR_SSL:
  			{
  				char	   *errm = SSLerrmessage(ecode);
  
  				printfPQExpBuffer(&conn->errorMessage,
  								  libpq_gettext("SSL error: %s\n"), errm);
  				SSLerrfree(errm);
  				/* assume the connection is broken */
  				result_errno = ECONNRESET;
  				n = -1;
  				break;
  			}
  		case SSL_ERROR_ZERO_RETURN:
  
  			/*
  			 * Per OpenSSL documentation, this error code is only returned for
  			 * a clean connection closure, so we should not report it as a
  			 * server crash.
  			 */
  			printfPQExpBuffer(&conn->errorMessage,
  							  libpq_gettext("SSL connection has been closed unexpectedly\n"));
  			result_errno = ECONNRESET;
  			n = -1;
  			break;
  		default:
  			printfPQExpBuffer(&conn->errorMessage,
  							  libpq_gettext("unrecognized SSL error code: %d\n"),
  							  err);
  			/* assume the connection is broken */
  			result_errno = ECONNRESET;
  			n = -1;
  			break;
  	}
  
  	/* ensure we return the intended errno to caller */
  	SOCK_ERRNO_SET(result_errno);
  
  	return n;
  }
  
  #ifdef HAVE_X509_GET_SIGNATURE_NID
  char *
  pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len)
  {
  	X509	   *peer_cert;
  	const EVP_MD *algo_type;
  	unsigned char hash[EVP_MAX_MD_SIZE];	/* size for SHA-512 */
  	unsigned int hash_size;
  	int			algo_nid;
  	char	   *cert_hash;
  
  	*len = 0;
  
  	if (!conn->peer)
  		return NULL;
  
  	peer_cert = conn->peer;
  
  	/*
  	 * Get the signature algorithm of the certificate to determine the hash
  	 * algorithm to use for the result.
  	 */
  	if (!OBJ_find_sigid_algs(X509_get_signature_nid(peer_cert),
  							 &algo_nid, NULL))
  	{
  		printfPQExpBuffer(&conn->errorMessage,
  						  libpq_gettext("could not determine server certificate signature algorithm\n"));
  		return NULL;
  	}
  
  	/*
  	 * The TLS server's certificate bytes need to be hashed with SHA-256 if
  	 * its signature algorithm is MD5 or SHA-1 as per RFC 5929
  	 * (https://tools.ietf.org/html/rfc5929#section-4.1).  If something else
  	 * is used, the same hash as the signature algorithm is used.
  	 */
  	switch (algo_nid)
  	{
  		case NID_md5:
  		case NID_sha1:
  			algo_type = EVP_sha256();
  			break;
  		default:
  			algo_type = EVP_get_digestbynid(algo_nid);
  			if (algo_type == NULL)
  			{
  				printfPQExpBuffer(&conn->errorMessage,
  								  libpq_gettext("could not find digest for NID %s\n"),
  								  OBJ_nid2sn(algo_nid));
  				return NULL;
  			}
  			break;
  	}
  
  	if (!X509_digest(peer_cert, algo_type, hash, &hash_size))
  	{
  		printfPQExpBuffer(&conn->errorMessage,
  						  libpq_gettext("could not generate peer certificate hash\n"));
  		return NULL;
  	}
  
  	/* save result */
  	cert_hash = malloc(hash_size);
  	if (cert_hash == NULL)
  	{
  		printfPQExpBuffer(&conn->errorMessage,
  						  libpq_gettext("out of memory\n"));
  		return NULL;
  	}
  	memcpy(cert_hash, hash, hash_size);
  	*len = hash_size;
  
  	return cert_hash;
  }
  #endif /* HAVE_X509_GET_SIGNATURE_NID */
  
  /* ------------------------------------------------------------ */
  /*						OpenSSL specific code					*/
  /* ------------------------------------------------------------ */
  
  /*
   *	Certificate verification callback
   *
   *	This callback allows us to log intermediate problems during
   *	verification, but there doesn't seem to be a clean way to get
   *	our PGconn * structure.  So we can't log anything!
   *
   *	This callback also allows us to override the default acceptance
   *	criteria (e.g., accepting self-signed or expired certs), but
   *	for now we accept the default checks.
   */
  static int
  verify_cb(int ok, X509_STORE_CTX *ctx)
  {
  	return ok;
  }
  
  
  /*
   * OpenSSL-specific wrapper around
   * pq_verify_peer_name_matches_certificate_name(), converting the ASN1_STRING
   * into a plain C string.
   */
  static int
  openssl_verify_peer_name_matches_certificate_name(PGconn *conn, ASN1_STRING *name_entry,
  												  char **store_name)
  {
  	int			len;
  	const unsigned char *namedata;
  
  	/* Should not happen... */
  	if (name_entry == NULL)
  	{
  		printfPQExpBuffer(&conn->errorMessage,
  						  libpq_gettext("SSL certificate's name entry is missing\n"));
  		return -1;
  	}
  
  	/*
  	 * GEN_DNS can be only IA5String, equivalent to US ASCII.
  	 */
  #ifdef HAVE_ASN1_STRING_GET0_DATA
  	namedata = ASN1_STRING_get0_data(name_entry);
  #else
  	namedata = ASN1_STRING_data(name_entry);
  #endif
  	len = ASN1_STRING_length(name_entry);
  
  	/* OK to cast from unsigned to plain char, since it's all ASCII. */
  	return pq_verify_peer_name_matches_certificate_name(conn, (const char *) namedata, len, store_name);
  }
  
  /*
   *	Verify that the server certificate matches the hostname we connected to.
   *
   * The certificate's Common Name and Subject Alternative Names are considered.
   */
  int
  pgtls_verify_peer_name_matches_certificate_guts(PGconn *conn,
  												int *names_examined,
  												char **first_name)
  {
  	STACK_OF(GENERAL_NAME) *peer_san;
  	int			i;
  	int			rc = 0;
  
  	/*
  	 * First, get the Subject Alternative Names (SANs) from the certificate,
  	 * and compare them against the originally given hostname.
  	 */
  	peer_san = (STACK_OF(GENERAL_NAME) *)
  		X509_get_ext_d2i(conn->peer, NID_subject_alt_name, NULL, NULL);
  
  	if (peer_san)
  	{
  		int			san_len = sk_GENERAL_NAME_num(peer_san);
  
  		for (i = 0; i < san_len; i++)
  		{
  			const GENERAL_NAME *name = sk_GENERAL_NAME_value(peer_san, i);
  
  			if (name->type == GEN_DNS)
  			{
  				char	   *alt_name;
  
  				(*names_examined)++;
  				rc = openssl_verify_peer_name_matches_certificate_name(conn,
  																	   name->d.dNSName,
  																	   &alt_name);
  
  				if (alt_name)
  				{
  					if (!*first_name)
  						*first_name = alt_name;
  					else
  						free(alt_name);
  				}
  			}
  			if (rc != 0)
  				break;
  		}
  		sk_GENERAL_NAME_pop_free(peer_san, GENERAL_NAME_free);
  	}
  
  	/*
  	 * If there is no subjectAltName extension of type dNSName, check the
  	 * Common Name.
  	 *
  	 * (Per RFC 2818 and RFC 6125, if the subjectAltName extension of type
  	 * dNSName is present, the CN must be ignored.)
  	 */
  	if (*names_examined == 0)
  	{
  		X509_NAME  *subject_name;
  
  		subject_name = X509_get_subject_name(conn->peer);
  		if (subject_name != NULL)
  		{
  			int			cn_index;
  
  			cn_index = X509_NAME_get_index_by_NID(subject_name,
  												  NID_commonName, -1);
  			if (cn_index >= 0)
  			{
  				(*names_examined)++;
  				rc = openssl_verify_peer_name_matches_certificate_name(
  																	   conn,
  																	   X509_NAME_ENTRY_get_data(
  																								X509_NAME_get_entry(subject_name, cn_index)),
  																	   first_name);
  			}
  		}
  	}
  
  	return rc;
  }
  
  #if defined(ENABLE_THREAD_SAFETY) && defined(HAVE_CRYPTO_LOCK)
  /*
   *	Callback functions for OpenSSL internal locking.  (OpenSSL 1.1.0
   *	does its own locking, and doesn't need these anymore.  The
   *	CRYPTO_lock() function was removed in 1.1.0, when the callbacks
   *	were made obsolete, so we assume that if CRYPTO_lock() exists,
   *	the callbacks are still required.)
   */
  
  static unsigned long
  pq_threadidcallback(void)
  {
  	/*
  	 * This is not standards-compliant.  pthread_self() returns pthread_t, and
  	 * shouldn't be cast to unsigned long, but CRYPTO_set_id_callback requires
  	 * it, so we have to do it.
  	 */
  	return (unsigned long) pthread_self();
  }
  
  static pthread_mutex_t *pq_lockarray;
  
  static void
  pq_lockingcallback(int mode, int n, const char *file, int line)
  {
  	if (mode & CRYPTO_LOCK)
  	{
  		if (pthread_mutex_lock(&pq_lockarray[n]))
  			PGTHREAD_ERROR("failed to lock mutex");
  	}
  	else
  	{
  		if (pthread_mutex_unlock(&pq_lockarray[n]))
  			PGTHREAD_ERROR("failed to unlock mutex");
  	}
  }
  #endif							/* ENABLE_THREAD_SAFETY && HAVE_CRYPTO_LOCK */
  
  /*
   * Initialize SSL library.
   *
   * In threadsafe mode, this includes setting up libcrypto callback functions
   * to do thread locking.
   *
   * If the caller has told us (through PQinitOpenSSL) that he's taking care
   * of libcrypto, we expect that callbacks are already set, and won't try to
   * override it.
   */
  int
  pgtls_init(PGconn *conn)
  {
  #ifdef ENABLE_THREAD_SAFETY
  #ifdef WIN32
  	/* Also see similar code in fe-connect.c, default_threadlock() */
  	if (ssl_config_mutex == NULL)
  	{
  		while (InterlockedExchange(&win32_ssl_create_mutex, 1) == 1)
  			 /* loop, another thread own the lock */ ;
  		if (ssl_config_mutex == NULL)
  		{
  			if (pthread_mutex_init(&ssl_config_mutex, NULL))
  				return -1;
  		}
  		InterlockedExchange(&win32_ssl_create_mutex, 0);
  	}
  #endif
  	if (pthread_mutex_lock(&ssl_config_mutex))
  		return -1;
  
  #ifdef HAVE_CRYPTO_LOCK
  	if (pq_init_crypto_lib)
  	{
  		/*
  		 * If necessary, set up an array to hold locks for libcrypto.
  		 * libcrypto will tell us how big to make this array.
  		 */
  		if (pq_lockarray == NULL)
  		{
  			int			i;
  
  			pq_lockarray = malloc(sizeof(pthread_mutex_t) * CRYPTO_num_locks());
  			if (!pq_lockarray)
  			{
  				pthread_mutex_unlock(&ssl_config_mutex);
  				return -1;
  			}
  			for (i = 0; i < CRYPTO_num_locks(); i++)
  			{
  				if (pthread_mutex_init(&pq_lockarray[i], NULL))
  				{
  					free(pq_lockarray);
  					pq_lockarray = NULL;
  					pthread_mutex_unlock(&ssl_config_mutex);
  					return -1;
  				}
  			}
  		}
  
  		if (ssl_open_connections++ == 0)
  		{
  			/*
  			 * These are only required for threaded libcrypto applications,
  			 * but make sure we don't stomp on them if they're already set.
  			 */
  			if (CRYPTO_get_id_callback() == NULL)
  				CRYPTO_set_id_callback(pq_threadidcallback);
  			if (CRYPTO_get_locking_callback() == NULL)
  				CRYPTO_set_locking_callback(pq_lockingcallback);
  		}
  	}
  #endif							/* HAVE_CRYPTO_LOCK */
  #endif							/* ENABLE_THREAD_SAFETY */
  
  	if (!ssl_lib_initialized)
  	{
  		if (pq_init_ssl_lib)
  		{
  #ifdef HAVE_OPENSSL_INIT_SSL
  			OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL);
  #else
  			OPENSSL_config(NULL);
  			SSL_library_init();
  			SSL_load_error_strings();
  #endif
  		}
  		ssl_lib_initialized = true;
  	}
  
  #ifdef ENABLE_THREAD_SAFETY
  	pthread_mutex_unlock(&ssl_config_mutex);
  #endif
  	return 0;
  }
  
  /*
   *	This function is needed because if the libpq library is unloaded
   *	from the application, the callback functions will no longer exist when
   *	libcrypto is used by other parts of the system.  For this reason,
   *	we unregister the callback functions when the last libpq
   *	connection is closed.  (The same would apply for OpenSSL callbacks
   *	if we had any.)
   *
   *	Callbacks are only set when we're compiled in threadsafe mode, so
   *	we only need to remove them in this case. They are also not needed
   *	with OpenSSL 1.1.0 anymore.
   */
  static void
  destroy_ssl_system(void)
  {
  #if defined(ENABLE_THREAD_SAFETY) && defined(HAVE_CRYPTO_LOCK)
  	/* Mutex is created in initialize_ssl_system() */
  	if (pthread_mutex_lock(&ssl_config_mutex))
  		return;
  
  	if (pq_init_crypto_lib && ssl_open_connections > 0)
  		--ssl_open_connections;
  
  	if (pq_init_crypto_lib && ssl_open_connections == 0)
  	{
  		/*
  		 * No connections left, unregister libcrypto callbacks, if no one
  		 * registered different ones in the meantime.
  		 */
  		if (CRYPTO_get_locking_callback() == pq_lockingcallback)
  			CRYPTO_set_locking_callback(NULL);
  		if (CRYPTO_get_id_callback() == pq_threadidcallback)
  			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 them with the existing mutexes.
  		 *
  		 * This means we leak a little memory on repeated load/unload of the
  		 * library.
  		 */
  	}
  
  	pthread_mutex_unlock(&ssl_config_mutex);
  #endif
  }
  
  /*
   *	Create per-connection SSL object, and load the client certificate,
   *	private key, and trusted CA certs.
   *
   *	Returns 0 if OK, -1 on failure (with a message in conn->errorMessage).
   */
  static int
  initialize_SSL(PGconn *conn)
  {
  	SSL_CTX    *SSL_context;
  	struct stat buf;
  	char		homedir[MAXPGPATH];
  	char		fnbuf[MAXPGPATH];
  	char		sebuf[256];
  	bool		have_homedir;
  	bool		have_cert;
  	bool		have_rootcert;
  	EVP_PKEY   *pkey = NULL;
  
  	/*
  	 * We'll need the home directory if any of the relevant parameters are
  	 * defaulted.  If pqGetHomeDirectory fails, act as though none of the
  	 * files could be found.
  	 */
  	if (!(conn->sslcert && strlen(conn->sslcert) > 0) ||
  		!(conn->sslkey && strlen(conn->sslkey) > 0) ||
  		!(conn->sslrootcert && strlen(conn->sslrootcert) > 0) ||
  		!(conn->sslcrl && strlen(conn->sslcrl) > 0))
  		have_homedir = pqGetHomeDirectory(homedir, sizeof(homedir));
  	else						/* won't need it */
  		have_homedir = false;
  
  	/*
  	 * Create a new SSL_CTX object.
  	 *
  	 * We used to share a single SSL_CTX between all connections, but it was
  	 * complicated if connections used different certificates. So now we
  	 * create a separate context for each connection, and accept the overhead.
  	 */
  	SSL_context = SSL_CTX_new(SSLv23_method());
  	if (!SSL_context)
  	{
  		char	   *err = SSLerrmessage(ERR_get_error());
  
  		printfPQExpBuffer(&conn->errorMessage,
  						  libpq_gettext("could not create SSL context: %s\n"),
  						  err);
  		SSLerrfree(err);
  		return -1;
  	}
  
  	/* Disable old protocol versions */
  	SSL_CTX_set_options(SSL_context, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
  
  	/*
  	 * Disable OpenSSL's moving-write-buffer sanity check, because it causes
  	 * unnecessary failures in nonblocking send cases.
  	 */
  	SSL_CTX_set_mode(SSL_context, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
  
  	/*
  	 * If the root cert file exists, load it so we can perform certificate
  	 * verification. If sslmode is "verify-full" we will also do further
  	 * verification after the connection has been completed.
  	 */
  	if (conn->sslrootcert && strlen(conn->sslrootcert) > 0)
  		strlcpy(fnbuf, conn->sslrootcert, sizeof(fnbuf));
  	else if (have_homedir)
  		snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, ROOT_CERT_FILE);
  	else
  		fnbuf[0] = '\0';
  
  	if (fnbuf[0] != '\0' &&
  		stat(fnbuf, &buf) == 0)
  	{
  		X509_STORE *cvstore;
  
  		if (SSL_CTX_load_verify_locations(SSL_context, fnbuf, NULL) != 1)
  		{
  			char	   *err = SSLerrmessage(ERR_get_error());
  
  			printfPQExpBuffer(&conn->errorMessage,
  							  libpq_gettext("could not read root certificate file \"%s\": %s\n"),
  							  fnbuf, err);
  			SSLerrfree(err);
  			SSL_CTX_free(SSL_context);
  			return -1;
  		}
  
  		if ((cvstore = SSL_CTX_get_cert_store(SSL_context)) != NULL)
  		{
  			if (conn->sslcrl && strlen(conn->sslcrl) > 0)
  				strlcpy(fnbuf, conn->sslcrl, sizeof(fnbuf));
  			else if (have_homedir)
  				snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, ROOT_CRL_FILE);
  			else
  				fnbuf[0] = '\0';
  
  			/* Set the flags to check against the complete CRL chain */
  			if (fnbuf[0] != '\0' &&
  				X509_STORE_load_locations(cvstore, fnbuf, NULL) == 1)
  			{
  				/* OpenSSL 0.96 does not support X509_V_FLAG_CRL_CHECK */
  #ifdef X509_V_FLAG_CRL_CHECK
  				X509_STORE_set_flags(cvstore,
  									 X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
  #else
  				char	   *err = SSLerrmessage(ERR_get_error());
  
  				printfPQExpBuffer(&conn->errorMessage,
  								  libpq_gettext("SSL library does not support CRL certificates (file \"%s\")\n"),
  								  fnbuf);
  				SSLerrfree(err);
  				SSL_CTX_free(SSL_context);
  				return -1;
  #endif
  			}
  			/* if not found, silently ignore;  we do not require CRL */
  			ERR_clear_error();
  		}
  		have_rootcert = true;
  	}
  	else
  	{
  		/*
  		 * stat() failed; assume root file doesn't exist.  If sslmode is
  		 * verify-ca or verify-full, this is an error.  Otherwise, continue
  		 * without performing any server cert verification.
  		 */
  		if (conn->sslmode[0] == 'v')	/* "verify-ca" or "verify-full" */
  		{
  			/*
  			 * The only way to reach here with an empty filename is if
  			 * pqGetHomeDirectory failed.  That's a sufficiently unusual case
  			 * that it seems worth having a specialized error message for it.
  			 */
  			if (fnbuf[0] == '\0')
  				printfPQExpBuffer(&conn->errorMessage,
  								  libpq_gettext("could not get home directory to locate root certificate file\n"
  												"Either provide the file or change sslmode to disable server certificate verification.\n"));
  			else
  				printfPQExpBuffer(&conn->errorMessage,
  								  libpq_gettext("root certificate file \"%s\" does not exist\n"
  												"Either provide the file or change sslmode to disable server certificate verification.\n"), fnbuf);
  			SSL_CTX_free(SSL_context);
  			return -1;
  		}
  		have_rootcert = false;
  	}
  
  	/* Read the client certificate file */
  	if (conn->sslcert && strlen(conn->sslcert) > 0)
  		strlcpy(fnbuf, conn->sslcert, sizeof(fnbuf));
  	else if (have_homedir)
  		snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_CERT_FILE);
  	else
  		fnbuf[0] = '\0';
  
  	if (fnbuf[0] == '\0')
  	{
  		/* no home directory, proceed without a client cert */
  		have_cert = false;
  	}
  	else if (stat(fnbuf, &buf) != 0)
  	{
  		/*
  		 * If file is not present, just go on without a client cert; server
  		 * might or might not accept the connection.  Any other error,
  		 * however, is grounds for complaint.
  		 */
  		if (errno != ENOENT && errno != ENOTDIR)
  		{
  			printfPQExpBuffer(&conn->errorMessage,
  							  libpq_gettext("could not open certificate file \"%s\": %s\n"),
  							  fnbuf, pqStrerror(errno, sebuf, sizeof(sebuf)));
  			SSL_CTX_free(SSL_context);
  			return -1;
  		}
  		have_cert = false;
  	}
  	else
  	{
  		/*
  		 * Cert file exists, so load it. Since OpenSSL doesn't provide the
  		 * equivalent of "SSL_use_certificate_chain_file", we have to load it
  		 * into the SSL context, rather than the SSL object.
  		 */
  		if (SSL_CTX_use_certificate_chain_file(SSL_context, fnbuf) != 1)
  		{
  			char	   *err = SSLerrmessage(ERR_get_error());
  
  			printfPQExpBuffer(&conn->errorMessage,
  							  libpq_gettext("could not read certificate file \"%s\": %s\n"),
  							  fnbuf, err);
  			SSLerrfree(err);
  			SSL_CTX_free(SSL_context);
  			return -1;
  		}
  
  		/* need to load the associated private key, too */
  		have_cert = true;
  	}
  
  	/*
  	 * The SSL context is now loaded with the correct root and client
  	 * certificates. Create a connection-specific SSL object. The private key
  	 * is loaded directly into the SSL object. (We could load the private key
  	 * into the context, too, but we have done it this way historically, and
  	 * it doesn't really matter.)
  	 */
  	if (!(conn->ssl = SSL_new(SSL_context)) ||
  		!SSL_set_app_data(conn->ssl, conn) ||
  		!my_SSL_set_fd(conn, conn->sock))
  	{
  		char	   *err = SSLerrmessage(ERR_get_error());
  
  		printfPQExpBuffer(&conn->errorMessage,
  						  libpq_gettext("could not establish SSL connection: %s\n"),
  						  err);
  		SSLerrfree(err);
  		SSL_CTX_free(SSL_context);
  		return -1;
  	}
  	conn->ssl_in_use = true;
  
  	/*
  	 * SSL contexts are reference counted by OpenSSL. We can free it as soon
  	 * as we have created the SSL object, and it will stick around for as long
  	 * as it's actually needed.
  	 */
  	SSL_CTX_free(SSL_context);
  	SSL_context = NULL;
  
  	/*
  	 * Read the SSL key. If a key is specified, treat it as an engine:key
  	 * combination if there is colon present - we don't support files with
  	 * colon in the name. The exception is if the second character is a colon,
  	 * in which case it can be a Windows filename with drive specification.
  	 */
  	if (have_cert && conn->sslkey && strlen(conn->sslkey) > 0)
  	{
  #ifdef USE_SSL_ENGINE
  		if (strchr(conn->sslkey, ':')
  #ifdef WIN32
  			&& conn->sslkey[1] != ':'
  #endif
  			)
  		{
  			/* Colon, but not in second character, treat as engine:key */
  			char	   *engine_str = strdup(conn->sslkey);
  			char	   *engine_colon;
  
  			if (engine_str == NULL)
  			{
  				printfPQExpBuffer(&conn->errorMessage,
  								  libpq_gettext("out of memory\n"));
  				return -1;
  			}
  
  			/* cannot return NULL because we already checked before strdup */
  			engine_colon = strchr(engine_str, ':');
  
  			*engine_colon = '\0';	/* engine_str now has engine name */
  			engine_colon++;		/* engine_colon now has key name */
  
  			conn->engine = ENGINE_by_id(engine_str);
  			if (conn->engine == NULL)
  			{
  				char	   *err = SSLerrmessage(ERR_get_error());
  
  				printfPQExpBuffer(&conn->errorMessage,
  								  libpq_gettext("could not load SSL engine \"%s\": %s\n"),
  								  engine_str, err);
  				SSLerrfree(err);
  				free(engine_str);
  				return -1;
  			}
  
  			if (ENGINE_init(conn->engine) == 0)
  			{
  				char	   *err = SSLerrmessage(ERR_get_error());
  
  				printfPQExpBuffer(&conn->errorMessage,
  								  libpq_gettext("could not initialize SSL engine \"%s\": %s\n"),
  								  engine_str, err);
  				SSLerrfree(err);
  				ENGINE_free(conn->engine);
  				conn->engine = NULL;
  				free(engine_str);
  				return -1;
  			}
  
  			pkey = ENGINE_load_private_key(conn->engine, engine_colon,
  										   NULL, NULL);
  			if (pkey == NULL)
  			{
  				char	   *err = SSLerrmessage(ERR_get_error());
  
  				printfPQExpBuffer(&conn->errorMessage,
  								  libpq_gettext("could not read private SSL key \"%s\" from engine \"%s\": %s\n"),
  								  engine_colon, engine_str, err);
  				SSLerrfree(err);
  				ENGINE_finish(conn->engine);
  				ENGINE_free(conn->engine);
  				conn->engine = NULL;
  				free(engine_str);
  				return -1;
  			}
  			if (SSL_use_PrivateKey(conn->ssl, pkey) != 1)
  			{
  				char	   *err = SSLerrmessage(ERR_get_error());
  
  				printfPQExpBuffer(&conn->errorMessage,
  								  libpq_gettext("could not load private SSL key \"%s\" from engine \"%s\": %s\n"),
  								  engine_colon, engine_str, err);
  				SSLerrfree(err);
  				ENGINE_finish(conn->engine);
  				ENGINE_free(conn->engine);
  				conn->engine = NULL;
  				free(engine_str);
  				return -1;
  			}
  
  			free(engine_str);
  
  			fnbuf[0] = '\0';	/* indicate we're not going to load from a
  								 * file */
  		}
  		else
  #endif							/* USE_SSL_ENGINE */
  		{
  			/* PGSSLKEY is not an engine, treat it as a filename */
  			strlcpy(fnbuf, conn->sslkey, sizeof(fnbuf));
  		}
  	}
  	else if (have_homedir)
  	{
  		/* No PGSSLKEY specified, load default file */
  		snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_KEY_FILE);
  	}
  	else
  		fnbuf[0] = '\0';
  
  	if (have_cert && fnbuf[0] != '\0')
  	{
  		/* read the client key from file */
  
  		if (stat(fnbuf, &buf) != 0)
  		{
  			printfPQExpBuffer(&conn->errorMessage,
  							  libpq_gettext("certificate present, but not private key file \"%s\"\n"),
  							  fnbuf);
  			return -1;
  		}
  #ifndef WIN32
  		if (!S_ISREG(buf.st_mode) || buf.st_mode & (S_IRWXG | S_IRWXO))
  		{
  			printfPQExpBuffer(&conn->errorMessage,
  							  libpq_gettext("private key file \"%s\" has group or world access; permissions should be u=rw (0600) or less\n"),
  							  fnbuf);
  			return -1;
  		}
  #endif
  
  		if (SSL_use_PrivateKey_file(conn->ssl, fnbuf, SSL_FILETYPE_PEM) != 1)
  		{
  			char	   *err = SSLerrmessage(ERR_get_error());
  
  			printfPQExpBuffer(&conn->errorMessage,
  							  libpq_gettext("could not load private key file \"%s\": %s\n"),
  							  fnbuf, err);
  			SSLerrfree(err);
  			return -1;
  		}
  	}
  
  	/* verify that the cert and key go together */
  	if (have_cert &&
  		SSL_check_private_key(conn->ssl) != 1)
  	{
  		char	   *err = SSLerrmessage(ERR_get_error());
  
  		printfPQExpBuffer(&conn->errorMessage,
  						  libpq_gettext("certificate does not match private key file \"%s\": %s\n"),
  						  fnbuf, err);
  		SSLerrfree(err);
  		return -1;
  	}
  
  	/*
  	 * If a root cert was loaded, also set our certificate verification
  	 * callback.
  	 */
  	if (have_rootcert)
  		SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, verify_cb);
  
  	/*
  	 * Set compression option if the OpenSSL version used supports it (from
  	 * 1.0.0 on).
  	 */
  #ifdef SSL_OP_NO_COMPRESSION
  	if (conn->sslcompression && conn->sslcompression[0] == '0')
  		SSL_set_options(conn->ssl, SSL_OP_NO_COMPRESSION);
  
  	/*
  	 * Mainline OpenSSL introduced SSL_clear_options() before
  	 * SSL_OP_NO_COMPRESSION, so this following #ifdef should not be
  	 * necessary, but some old NetBSD version have a locally modified libssl
  	 * that has SSL_OP_NO_COMPRESSION but not SSL_clear_options().
  	 */
  #ifdef HAVE_SSL_CLEAR_OPTIONS
  	else
  		SSL_clear_options(conn->ssl, SSL_OP_NO_COMPRESSION);
  #endif
  #endif
  
  	return 0;
  }
  
  /*
   *	Attempt to negotiate SSL connection.
   */
  static PostgresPollingStatusType
  open_client_SSL(PGconn *conn)
  {
  	int			r;
  
  	ERR_clear_error();
  	r = SSL_connect(conn->ssl);
  	if (r <= 0)
  	{
  		int			err = SSL_get_error(conn->ssl, r);
  		unsigned long ecode;
  
  		ecode = ERR_get_error();
  		switch (err)
  		{
  			case SSL_ERROR_WANT_READ:
  				return PGRES_POLLING_READING;
  
  			case SSL_ERROR_WANT_WRITE:
  				return PGRES_POLLING_WRITING;
  
  			case SSL_ERROR_SYSCALL:
  				{
  					char		sebuf[256];
  
  					if (r == -1)
  						printfPQExpBuffer(&conn->errorMessage,
  										  libpq_gettext("SSL SYSCALL error: %s\n"),
  										  SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
  					else
  						printfPQExpBuffer(&conn->errorMessage,
  										  libpq_gettext("SSL SYSCALL error: EOF detected\n"));
  					pgtls_close(conn);
  					return PGRES_POLLING_FAILED;
  				}
  			case SSL_ERROR_SSL:
  				{
  					char	   *err = SSLerrmessage(ecode);
  
  					printfPQExpBuffer(&conn->errorMessage,
  									  libpq_gettext("SSL error: %s\n"),
  									  err);
  					SSLerrfree(err);
  					pgtls_close(conn);
  					return PGRES_POLLING_FAILED;
  				}
  
  			default:
  				printfPQExpBuffer(&conn->errorMessage,
  								  libpq_gettext("unrecognized SSL error code: %d\n"),
  								  err);
  				pgtls_close(conn);
  				return PGRES_POLLING_FAILED;
  		}
  	}
  
  	/*
  	 * We already checked the server certificate in initialize_SSL() using
  	 * SSL_CTX_set_verify(), if root.crt exists.
  	 */
  
  	/* get server certificate */
  	conn->peer = SSL_get_peer_certificate(conn->ssl);
  	if (conn->peer == NULL)
  	{
  		char	   *err;
  
  		err = SSLerrmessage(ERR_get_error());
  
  		printfPQExpBuffer(&conn->errorMessage,
  						  libpq_gettext("certificate could not be obtained: %s\n"),
  						  err);
  		SSLerrfree(err);
  		pgtls_close(conn);
  		return PGRES_POLLING_FAILED;
  	}
  
  	if (!pq_verify_peer_name_matches_certificate(conn))
  	{
  		pgtls_close(conn);
  		return PGRES_POLLING_FAILED;
  	}
  
  	/* SSL handshake is complete */
  	return PGRES_POLLING_OK;
  }
  
  void
  pgtls_close(PGconn *conn)
  {
  	bool		destroy_needed = false;
  
  	if (conn->ssl)
  	{
  		/*
  		 * We can't destroy everything SSL-related here due to the possible
  		 * later calls to OpenSSL routines which may need our thread
  		 * callbacks, so set a flag here and check at the end.
  		 */
  		destroy_needed = true;
  
  		SSL_shutdown(conn->ssl);
  		SSL_free(conn->ssl);
  		conn->ssl = NULL;
  		conn->ssl_in_use = false;
  	}
  
  	if (conn->peer)
  	{
  		X509_free(conn->peer);
  		conn->peer = NULL;
  	}
  
  #ifdef USE_SSL_ENGINE
  	if (conn->engine)
  	{
  		ENGINE_finish(conn->engine);
  		ENGINE_free(conn->engine);
  		conn->engine = NULL;
  	}
  #endif
  
  	/*
  	 * This will remove our SSL locking hooks, if this is the last SSL
  	 * connection, which means we must wait to call it until after all SSL
  	 * calls have been made, otherwise we can end up with a race condition and
  	 * possible deadlocks.
  	 *
  	 * See comments above destroy_ssl_system().
  	 */
  	if (destroy_needed)
  		destroy_ssl_system();
  }
  
  
  /*
   * Obtain reason string for passed SSL errcode
   *
   * ERR_get_error() is used by caller to get errcode to pass here.
   *
   * Some caution is needed here since ERR_reason_error_string will
   * return NULL if it doesn't recognize the error code.  We don't
   * want to return NULL ever.
   */
  static char ssl_nomem[] = "out of memory allocating error description";
  
  #define SSL_ERR_LEN 128
  
  static char *
  SSLerrmessage(unsigned long ecode)
  {
  	const char *errreason;
  	char	   *errbuf;
  
  	errbuf = malloc(SSL_ERR_LEN);
  	if (!errbuf)
  		return ssl_nomem;
  	if (ecode == 0)
  	{
  		snprintf(errbuf, SSL_ERR_LEN, libpq_gettext("no SSL error reported"));
  		return errbuf;
  	}
  	errreason = ERR_reason_error_string(ecode);
  	if (errreason != NULL)
  	{
  		strlcpy(errbuf, errreason, SSL_ERR_LEN);
  		return errbuf;
  	}
  	snprintf(errbuf, SSL_ERR_LEN, libpq_gettext("SSL error code %lu"), ecode);
  	return errbuf;
  }
  
  static void
  SSLerrfree(char *buf)
  {
  	if (buf != ssl_nomem)
  		free(buf);
  }
  
  /* ------------------------------------------------------------ */
  /*					SSL information functions					*/
  /* ------------------------------------------------------------ */
  
  /*
   *	Return pointer to OpenSSL object.
   */
  void *
  PQgetssl(PGconn *conn)
  {
  	if (!conn)
  		return NULL;
  	return conn->ssl;
  }
  
  void *
  PQsslStruct(PGconn *conn, const char *struct_name)
  {
  	if (!conn)
  		return NULL;
  	if (strcmp(struct_name, "OpenSSL") == 0)
  		return conn->ssl;
  	return NULL;
  }
  
  const char *const *
  PQsslAttributeNames(PGconn *conn)
  {
  	static const char *const result[] = {
  		"library",
  		"key_bits",
  		"cipher",
  		"compression",
  		"protocol",
  		NULL
  	};
  
  	return result;
  }
  
  const char *
  PQsslAttribute(PGconn *conn, const char *attribute_name)
  {
  	if (!conn)
  		return NULL;
  	if (conn->ssl == NULL)
  		return NULL;
  
  	if (strcmp(attribute_name, "library") == 0)
  		return "OpenSSL";
  
  	if (strcmp(attribute_name, "key_bits") == 0)
  	{
  		static char sslbits_str[12];
  		int			sslbits;
  
  		SSL_get_cipher_bits(conn->ssl, &sslbits);
  		snprintf(sslbits_str, sizeof(sslbits_str), "%d", sslbits);
  		return sslbits_str;
  	}
  
  	if (strcmp(attribute_name, "cipher") == 0)
  		return SSL_get_cipher(conn->ssl);
  
  	if (strcmp(attribute_name, "compression") == 0)
  		return SSL_get_current_compression(conn->ssl) ? "on" : "off";
  
  	if (strcmp(attribute_name, "protocol") == 0)
  		return SSL_get_version(conn->ssl);
  
  	return NULL;				/* unknown attribute */
  }
  
  /*
   * Private substitute BIO: this does the sending and receiving using
   * pqsecure_raw_write() and pqsecure_raw_read() instead, to allow those
   * functions to disable SIGPIPE and give better error messages on I/O errors.
   *
   * These functions are closely modelled on the standard socket BIO in OpenSSL;
   * see sock_read() and sock_write() in OpenSSL's crypto/bio/bss_sock.c.
   * XXX OpenSSL 1.0.1e considers many more errcodes than just EINTR as reasons
   * 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
  
  static BIO_METHOD *my_bio_methods;
  
  static int
  my_sock_read(BIO *h, char *buf, int size)
  {
  	int			res;
  
  	res = pqsecure_raw_read((PGconn *) BIO_get_data(h), buf, size);
  	BIO_clear_retry_flags(h);
  	if (res < 0)
  	{
  		/* If we were interrupted, tell caller to retry */
  		switch (SOCK_ERRNO)
  		{
  #ifdef EAGAIN
  			case EAGAIN:
  #endif
  #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
  			case EWOULDBLOCK:
  #endif
  			case EINTR:
  				BIO_set_retry_read(h);
  				break;
  
  			default:
  				break;
  		}
  	}
  
  	return res;
  }
  
  static int
  my_sock_write(BIO *h, const char *buf, int size)
  {
  	int			res;
  
  	res = pqsecure_raw_write((PGconn *) BIO_get_data(h), buf, size);
  	BIO_clear_retry_flags(h);
  	if (res <= 0)
  	{
  		/* If we were interrupted, tell caller to retry */
  		switch (SOCK_ERRNO)
  		{
  #ifdef EAGAIN
  			case EAGAIN:
  #endif
  #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
  			case EWOULDBLOCK:
  #endif
  			case EINTR:
  				BIO_set_retry_write(h);
  				break;
  
  			default:
  				break;
  		}
  	}
  
  	return res;
  }
  
  static BIO_METHOD *
  my_BIO_s_socket(void)
  {
  	if (!my_bio_methods)
  	{
  		BIO_METHOD *biom = (BIO_METHOD *) BIO_s_socket();
  #ifdef HAVE_BIO_METH_NEW
  		int			my_bio_index;
  
  		my_bio_index = BIO_get_new_index();
  		if (my_bio_index == -1)
  			return NULL;
  		my_bio_methods = BIO_meth_new(my_bio_index, "libpq socket");
  		if (!my_bio_methods)
  			return NULL;
  
  		/*
  		 * 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)))
  		{
  			BIO_meth_free(my_bio_methods);
  			my_bio_methods = NULL;
  			return NULL;
  		}
  #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;
  #endif
  	}
  	return my_bio_methods;
  }
  
  /* This should exactly match OpenSSL's SSL_set_fd except for using my BIO */
  static int
  my_SSL_set_fd(PGconn *conn, int fd)
  {
  	int			ret = 0;
  	BIO		   *bio;
  	BIO_METHOD *bio_method;
  
  	bio_method = my_BIO_s_socket();
  	if (bio_method == NULL)
  	{
  		SSLerr(SSL_F_SSL_SET_FD, ERR_R_BUF_LIB);
  		goto err;
  	}
  	bio = BIO_new(bio_method);
  	if (bio == NULL)
  	{
  		SSLerr(SSL_F_SSL_SET_FD, ERR_R_BUF_LIB);
  		goto err;
  	}
  	BIO_set_data(bio, conn);
  
  	SSL_set_bio(conn->ssl, bio, bio);
  	BIO_set_fd(bio, fd, BIO_NOCLOSE);
  	ret = 1;
  err:
  	return ret;
  }
  