X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=src%2Finterfaces%2Flibpq%2Ffe-secure.c;h=6f6052b2b05d378cbb0d7f5df1f77a04dd8f5e9a;hb=abf23ee86d871850347cfec80636537e9eb20ea6;hp=2d5eff7dee1f35d7b2394c494d42b73594a9bda2;hpb=cc1d292d786e593e3842db6bb5084d499c5f3383;p=postgresql diff --git a/src/interfaces/libpq/fe-secure.c b/src/interfaces/libpq/fe-secure.c index 2d5eff7dee..6f6052b2b0 100644 --- a/src/interfaces/libpq/fe-secure.c +++ b/src/interfaces/libpq/fe-secure.c @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.118 2009/01/19 17:17:50 tgl Exp $ + * $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.129 2009/12/09 06:37:06 mha Exp $ * * NOTES * @@ -31,6 +31,7 @@ #include "libpq-fe.h" #include "fe-auth.h" #include "pqsignal.h" +#include "libpq-int.h" #ifdef WIN32 #include "win32.h" @@ -62,7 +63,7 @@ #if (SSLEAY_VERSION_NUMBER >= 0x00907000L) #include #endif -#if (SSLEAY_VERSION_NUMBER >= 0x00907000L) && !defined(OPENSSL_NO_ENGINE) +#ifdef USE_SSL_ENGINE #include #endif @@ -98,11 +99,12 @@ static void close_SSL(PGconn *); static char *SSLerrmessage(void); static void SSLerrfree(char *buf); -static bool pq_initssllib = true; +static bool pq_init_ssl_lib = true; +static bool pq_init_crypto_lib = true; static SSL_CTX *SSL_context = NULL; #ifdef ENABLE_THREAD_SAFETY -static int ssl_open_connections = 0; +static long ssl_open_connections = 0; #ifndef WIN32 static pthread_mutex_t ssl_config_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -110,53 +112,80 @@ static pthread_mutex_t ssl_config_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t ssl_config_mutex = NULL; static long win32_ssl_create_mutex = 0; #endif - -#endif /* ENABLE_THREAD_SAFETY */ - -#endif /* SSL */ +#endif /* ENABLE_THREAD_SAFETY */ +#endif /* SSL */ /* * Macros to handle disabling and then restoring the state of SIGPIPE handling. - * Note that DISABLE_SIGPIPE() must appear at the start of a block. + * On Windows, these are all no-ops since there's no SIGPIPEs. */ #ifndef WIN32 + +#define SIGPIPE_MASKED(conn) ((conn)->sigpipe_so || (conn)->sigpipe_flag) + #ifdef ENABLE_THREAD_SAFETY -#define DISABLE_SIGPIPE(failaction) \ - sigset_t osigmask; \ - bool sigpipe_pending; \ - bool got_epipe = false; \ -\ - if (pq_block_sigpipe(&osigmask, &sigpipe_pending) < 0) \ - failaction +struct sigpipe_info +{ + sigset_t oldsigmask; + bool sigpipe_pending; + bool got_epipe; +}; + +#define DECLARE_SIGPIPE_INFO(spinfo) struct sigpipe_info spinfo + +#define DISABLE_SIGPIPE(conn, spinfo, failaction) \ + do { \ + (spinfo).got_epipe = false; \ + if (!SIGPIPE_MASKED(conn)) \ + { \ + if (pq_block_sigpipe(&(spinfo).oldsigmask, \ + &(spinfo).sigpipe_pending) < 0) \ + failaction; \ + } \ + } while (0) -#define REMEMBER_EPIPE(cond) \ +#define REMEMBER_EPIPE(spinfo, cond) \ do { \ if (cond) \ - got_epipe = true; \ + (spinfo).got_epipe = true; \ + } while (0) + +#define RESTORE_SIGPIPE(conn, spinfo) \ + do { \ + if (!SIGPIPE_MASKED(conn)) \ + pq_reset_sigpipe(&(spinfo).oldsigmask, (spinfo).sigpipe_pending, \ + (spinfo).got_epipe); \ } while (0) -#define RESTORE_SIGPIPE() \ - pq_reset_sigpipe(&osigmask, sigpipe_pending, got_epipe) +#else /* !ENABLE_THREAD_SAFETY */ -#else /* !ENABLE_THREAD_SAFETY */ +#define DECLARE_SIGPIPE_INFO(spinfo) pqsigfunc spinfo = NULL -#define DISABLE_SIGPIPE(failaction) \ - pqsigfunc oldsighandler = pqsignal(SIGPIPE, SIG_IGN) +#define DISABLE_SIGPIPE(conn, spinfo, failaction) \ + do { \ + if (!SIGPIPE_MASKED(conn)) \ + spinfo = pqsignal(SIGPIPE, SIG_IGN); \ + } while (0) -#define REMEMBER_EPIPE(cond) +#define REMEMBER_EPIPE(spinfo, cond) -#define RESTORE_SIGPIPE() \ - pqsignal(SIGPIPE, oldsighandler) +#define RESTORE_SIGPIPE(conn, spinfo) \ + do { \ + if (!SIGPIPE_MASKED(conn)) \ + pqsignal(SIGPIPE, spinfo); \ + } while (0) #endif /* ENABLE_THREAD_SAFETY */ + #else /* WIN32 */ -#define DISABLE_SIGPIPE(failaction) -#define REMEMBER_EPIPE(cond) -#define RESTORE_SIGPIPE() +#define DECLARE_SIGPIPE_INFO(spinfo) +#define DISABLE_SIGPIPE(conn, spinfo, failaction) +#define REMEMBER_EPIPE(spinfo, cond) +#define RESTORE_SIGPIPE(conn, spinfo) #endif /* WIN32 */ @@ -171,9 +200,30 @@ static long win32_ssl_create_mutex = 0; */ void PQinitSSL(int do_init) +{ + PQinitOpenSSL(do_init, do_init); +} + +/* + * Exported function to allow application to tell us it's already + * initialized OpenSSL and/or libcrypto. + */ +void +PQinitOpenSSL(int do_ssl, int do_crypto) { #ifdef USE_SSL - pq_initssllib = do_init; +#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; #endif } @@ -213,6 +263,9 @@ pqsecure_open_client(PGconn *conn) /* First time through? */ if (conn->ssl == NULL) { + /* We cannot use MSG_NOSIGNAL to block SIGPIPE when using SSL */ + conn->sigpipe_flag = false; + if (!(conn->ssl = SSL_new(SSL_context)) || !SSL_set_app_data(conn->ssl, conn) || !SSL_set_fd(conn->ssl, conn->sock)) @@ -265,9 +318,10 @@ pqsecure_read(PGconn *conn, void *ptr, size_t len) if (conn->ssl) { int err; + DECLARE_SIGPIPE_INFO(spinfo); /* SSL_read can write to the socket, so we need to disable SIGPIPE */ - DISABLE_SIGPIPE(return -1); + DISABLE_SIGPIPE(conn, spinfo, return -1); rloop: n = SSL_read(conn->ssl, ptr, len); @@ -294,7 +348,7 @@ rloop: if (n == -1) { - REMEMBER_EPIPE(SOCK_ERRNO == EPIPE); + REMEMBER_EPIPE(spinfo, SOCK_ERRNO == EPIPE); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); @@ -330,7 +384,7 @@ rloop: break; } - RESTORE_SIGPIPE(); + RESTORE_SIGPIPE(conn, spinfo); } else #endif @@ -346,14 +400,15 @@ ssize_t pqsecure_write(PGconn *conn, const void *ptr, size_t len) { ssize_t n; - - DISABLE_SIGPIPE(return -1); + DECLARE_SIGPIPE_INFO(spinfo); #ifdef USE_SSL if (conn->ssl) { int err; + DISABLE_SIGPIPE(conn, spinfo, return -1); + n = SSL_write(conn->ssl, ptr, len); err = SSL_get_error(conn->ssl, n); switch (err) @@ -378,7 +433,7 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len) if (n == -1) { - REMEMBER_EPIPE(SOCK_ERRNO == EPIPE); + REMEMBER_EPIPE(spinfo, SOCK_ERRNO == EPIPE); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); @@ -416,11 +471,41 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len) else #endif { - n = send(conn->sock, ptr, len, 0); - REMEMBER_EPIPE(n < 0 && SOCK_ERRNO == EPIPE); + int flags = 0; + +#ifdef MSG_NOSIGNAL + if (conn->sigpipe_flag) + flags |= MSG_NOSIGNAL; + +retry_masked: + +#endif /* MSG_NOSIGNAL */ + + DISABLE_SIGPIPE(conn, spinfo, return -1); + + n = send(conn->sock, ptr, len, flags); + + if (n < 0) + { + /* + * If we see an EINVAL, it may be because MSG_NOSIGNAL isn't + * available on this machine. So, clear sigpipe_flag so we don't + * try the flag again, and retry the send(). + */ +#ifdef MSG_NOSIGNAL + if (flags != 0 && SOCK_ERRNO == EINVAL) + { + conn->sigpipe_flag = false; + flags = 0; + goto retry_masked; + } +#endif /* MSG_NOSIGNAL */ + + REMEMBER_EPIPE(spinfo, SOCK_ERRNO == EPIPE); + } } - RESTORE_SIGPIPE(); + RESTORE_SIGPIPE(conn, spinfo); return n; } @@ -452,11 +537,11 @@ verify_cb(int ok, X509_STORE_CTX *ctx) * Check if a wildcard certificate matches the server hostname. * * The rule for this is: - * 1. We only match the '*' character as wildcard - * 2. We match only wildcards at the start of the string - * 3. The '*' character does *not* match '.', meaning that we match only - * a single pathname component. - * 4. We don't support more than one '*' in a single pattern. + * 1. We only match the '*' character as wildcard + * 2. We match only wildcards at the start of the string + * 3. The '*' character does *not* match '.', meaning that we match only + * a single pathname component. + * 4. We don't support more than one '*' in a single pattern. * * This is roughly in line with RFC2818, but contrary to what most browsers * appear to be implementing (point 3 being the difference) @@ -466,8 +551,8 @@ verify_cb(int ok, X509_STORE_CTX *ctx) static int wildcard_certificate_match(const char *pattern, const char *string) { - int lenpat = strlen(pattern); - int lenstr = strlen(string); + int lenpat = strlen(pattern); + int lenstr = strlen(string); /* If we don't start with a wildcard, it's not a match (rule 1 & 2) */ if (lenpat < 3 || @@ -479,12 +564,20 @@ wildcard_certificate_match(const char *pattern, const char *string) /* If pattern is longer than the string, we can never match */ return 0; - if (pg_strcasecmp(pattern+1, string+lenstr-lenpat+1) != 0) - /* If string does not end in pattern (minus the wildcard), we don't match */ + if (pg_strcasecmp(pattern + 1, string + lenstr - lenpat + 1) != 0) + + /* + * If string does not end in pattern (minus the wildcard), we don't + * match + */ return 0; - if (strchr(string, '.') < string+lenstr-lenpat) - /* If there is a dot left of where the pattern started to match, we don't match (rule 3) */ + if (strchr(string, '.') < string + lenstr - lenpat) + + /* + * If there is a dot left of where the pattern started to match, we + * don't match (rule 3) + */ return 0; /* String ended with pattern, and didn't have a dot before, so we match */ @@ -499,10 +592,10 @@ static bool verify_peer_name_matches_certificate(PGconn *conn) { /* - * If told not to verify the peer name, don't do it. Return - * 0 indicating that the verification was successful. + * If told not to verify the peer name, don't do it. Return 0 indicating + * that the verification was successful. */ - if(strcmp(conn->sslverify, "cn") != 0) + if (strcmp(conn->sslmode, "verify-full") != 0) return true; if (conn->pghostaddr) @@ -629,43 +722,57 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey) BIO_free(bio); /* - * 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. + * 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 (conn->sslkey && strlen(conn->sslkey) > 0) { -#if (SSLEAY_VERSION_NUMBER >= 0x00907000L) && !defined(OPENSSL_NO_ENGINE) +#ifdef USE_SSL_ENGINE if (strchr(conn->sslkey, ':') #ifdef WIN32 && conn->sslkey[1] != ':' #endif - ) + ) { /* Colon, but not in second character, treat as engine:key */ - ENGINE *engine_ptr; char *engine_str = strdup(conn->sslkey); char *engine_colon = strchr(engine_str, ':'); - *engine_colon = '\0'; /* engine_str now has engine name */ - engine_colon++; /* engine_colon now has key name */ + *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(); + + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("could not load SSL engine \"%s\": %s\n"), + engine_str, err); + SSLerrfree(err); + free(engine_str); + ERR_pop_to_mark(); + return 0; + } - engine_ptr = ENGINE_by_id(engine_str); - if (engine_ptr == NULL) + if (ENGINE_init(conn->engine) == 0) { char *err = SSLerrmessage(); printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("could not load SSL engine \"%s\": %s\n"), + 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); ERR_pop_to_mark(); return 0; } - *pkey = ENGINE_load_private_key(engine_ptr, engine_colon, + *pkey = ENGINE_load_private_key(conn->engine, engine_colon, NULL, NULL); if (*pkey == NULL) { @@ -675,16 +782,20 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey) 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); ERR_pop_to_mark(); return 0; } free(engine_str); - fnbuf[0] = '\0'; /* indicate we're not going to load from a file */ + fnbuf[0] = '\0'; /* indicate we're not going to load from a + * file */ } else -#endif /* support for SSL engines */ +#endif /* support for SSL engines */ { /* PGSSLKEY is not an engine, treat it as a filename */ strncpy(fnbuf, conn->sslkey, sizeof(fnbuf)); @@ -712,7 +823,7 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey) 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"), + libpq_gettext("private key file \"%s\" has group or world access; permissions should be u=rw (0600) or less\n"), fnbuf); ERR_pop_to_mark(); return 0; @@ -757,7 +868,7 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey) } /* verify that the cert and key go together */ - if (!X509_check_private_key(*x509, *pkey)) + if (X509_check_private_key(*x509, *pkey) != 1) { char *err = SSLerrmessage(); @@ -810,10 +921,10 @@ pq_lockingcallback(int mode, int n, const char *file, int line) /* * Initialize SSL system. In threadsafe mode, this includes setting - * up OpenSSL callback functions to do thread locking. + * up libcrypto callback functions to do thread locking. * - * If the caller has told us (through PQinitSSL) that he's taking care - * of SSL, we expect that callbacks are already set, and won't try to + * 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. * * The conn parameter is only used to be able to pass back an error @@ -840,15 +951,15 @@ init_ssl_system(PGconn *conn) if (pthread_mutex_lock(&ssl_config_mutex)) return -1; - if (pq_initssllib) + if (pq_init_crypto_lib) { /* - * If necessary, set up an array to hold locks for OpenSSL. OpenSSL will - * tell us how big to make this array. + * 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; + int i; pq_lockarray = malloc(sizeof(pthread_mutex_t) * CRYPTO_num_locks()); if (!pq_lockarray) @@ -870,16 +981,16 @@ init_ssl_system(PGconn *conn) if (ssl_open_connections++ == 0) { - /* These are only required for threaded SSL applications */ + /* These are only required for threaded libcrypto applications */ CRYPTO_set_id_callback(pq_threadidcallback); CRYPTO_set_locking_callback(pq_lockingcallback); } } -#endif /* ENABLE_THREAD_SAFETY */ +#endif /* ENABLE_THREAD_SAFETY */ if (!SSL_context) { - if (pq_initssllib) + if (pq_init_ssl_lib) { #if SSLEAY_VERSION_NUMBER >= 0x00907000L OPENSSL_config(NULL); @@ -912,9 +1023,10 @@ init_ssl_system(PGconn *conn) /* * This function is needed because if the libpq library is unloaded * from the application, the callback functions will no longer exist when - * SSL used by other parts of the system. For this reason, - * we unregister the SSL callback functions when the last libpq - * connection is closed. + * 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. @@ -927,26 +1039,22 @@ destroy_ssl_system(void) if (pthread_mutex_lock(&ssl_config_mutex)) return; - if (pq_initssllib) - { - if (ssl_open_connections > 0) - --ssl_open_connections; + if (pq_init_crypto_lib && ssl_open_connections > 0) + --ssl_open_connections; - if (ssl_open_connections == 0) - { - /* No connections left, unregister all callbacks */ - CRYPTO_set_locking_callback(NULL); - CRYPTO_set_id_callback(NULL); + if (pq_init_crypto_lib && ssl_open_connections == 0) + { + /* No connections left, unregister libcrypto callbacks */ + CRYPTO_set_locking_callback(NULL); + CRYPTO_set_id_callback(NULL); - /* - * We don't free the lock array. If we get another connection - * from the same caller, we will just re-use it with the existing - * mutexes. - * - * This means we leak a little memory on repeated load/unload - * of the library. - */ - } + /* + * 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. + * + * This means we leak a little memory on repeated load/unload of the + * library. + */ } pthread_mutex_unlock(&ssl_config_mutex); @@ -968,19 +1076,20 @@ initialize_SSL(PGconn *conn) return -1; /* - * If sslverify is set to anything other than "none", perform certificate - * verification. If set to "cn" we will also do further verifications after - * the connection has been completed. + * If sslmode is set to one of the verify options, perform certificate + * verification. If set to "verify-full" we will also do further + * verification after the connection has been completed. * - * If we are going to look for either root certificate or CRL in the home directory, - * we need pqGetHomeDirectory() to succeed. In other cases, we don't need to - * get the home directory explicitly. + * If we are going to look for either root certificate or CRL in the home + * directory, we need pqGetHomeDirectory() to succeed. In other cases, we + * don't need to get the home directory explicitly. */ if (!conn->sslrootcert || !conn->sslcrl) { if (!pqGetHomeDirectory(homedir, sizeof(homedir))) { - if (strcmp(conn->sslverify, "none") != 0) + if (conn->sslmode[0] == 'v') /* "verify-ca" or + * "verify-full" */ { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not get home directory to locate root certificate file")); @@ -993,8 +1102,6 @@ initialize_SSL(PGconn *conn) homedir[0] = '\0'; } - - if (conn->sslrootcert) strncpy(fnbuf, conn->sslrootcert, sizeof(fnbuf)); else @@ -1004,7 +1111,7 @@ initialize_SSL(PGconn *conn) { X509_STORE *cvstore; - if (!SSL_CTX_load_verify_locations(SSL_context, fnbuf, NULL)) + if (SSL_CTX_load_verify_locations(SSL_context, fnbuf, NULL) != 1) { char *err = SSLerrmessage(); @@ -1023,11 +1130,11 @@ initialize_SSL(PGconn *conn) snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, ROOT_CRL_FILE); /* setting the flags to check against the complete CRL chain */ - if (X509_STORE_load_locations(cvstore, fnbuf, NULL) != 0) + if (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); + X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); /* if not found, silently ignore; we do not require CRL */ #else { @@ -1047,10 +1154,11 @@ initialize_SSL(PGconn *conn) else { /* stat() failed; assume cert file doesn't exist */ - if (strcmp(conn->sslverify, "none") != 0) + if (conn->sslmode[0] == 'v') /* "verify-ca" or "verify-full" */ { printfPQExpBuffer(&conn->errorMessage, - libpq_gettext("root certificate file \"%s\" does not exist"), fnbuf); + libpq_gettext("root certificate file \"%s\" does not exist\n" + "Either provide the file or change sslmode to disable server certificate verification.\n"), fnbuf); return -1; } } @@ -1135,8 +1243,8 @@ open_client_SSL(PGconn *conn) } /* - * We already checked the server certificate in initialize_SSL() - * using SSL_CTX_set_verify() if root.crt exists. + * We already checked the server certificate in initialize_SSL() using + * SSL_CTX_set_verify() if root.crt exists. */ /* pull out server distinguished and common names */ @@ -1157,9 +1265,28 @@ open_client_SSL(PGconn *conn) conn->peer_dn, sizeof(conn->peer_dn)); conn->peer_dn[sizeof(conn->peer_dn) - 1] = '\0'; - X509_NAME_get_text_by_NID(X509_get_subject_name(conn->peer), + r = X509_NAME_get_text_by_NID(X509_get_subject_name(conn->peer), NID_commonName, conn->peer_cn, SM_USER); - conn->peer_cn[SM_USER] = '\0'; + conn->peer_cn[SM_USER] = '\0'; /* buffer is SM_USER+1 chars! */ + if (r == -1) + { + /* Unable to get the CN, set it to blank so it can't be used */ + conn->peer_cn[0] = '\0'; + } + else + { + /* + * Reject embedded NULLs in certificate common name to prevent attacks like + * CVE-2009-4034. + */ + if (r != strlen(conn->peer_cn)) + { + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("SSL certificate's common name contains embedded null\n")); + close_SSL(conn); + return PGRES_POLLING_FAILED; + } + } if (!verify_peer_name_matches_certificate(conn)) { @@ -1179,14 +1306,16 @@ close_SSL(PGconn *conn) { if (conn->ssl) { - DISABLE_SIGPIPE((void) 0); + DECLARE_SIGPIPE_INFO(spinfo); + + DISABLE_SIGPIPE(conn, spinfo, (void) 0); SSL_shutdown(conn->ssl); SSL_free(conn->ssl); conn->ssl = NULL; pqsecure_destroy(); /* We have to assume we got EPIPE */ - REMEMBER_EPIPE(true); - RESTORE_SIGPIPE(); + REMEMBER_EPIPE(spinfo, true); + RESTORE_SIGPIPE(conn, spinfo); } if (conn->peer) @@ -1194,6 +1323,15 @@ close_SSL(PGconn *conn) 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 } /*