#include "postgres_fe.h"
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include "libpq-fe.h"
#include "fe-auth.h"
#include "libpq-int.h"
#include <sys/socket.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/stat.h>
Go to the source code of this file.
Defines | |
#define | SIGPIPE_MASKED(conn) ((conn)->sigpipe_so || (conn)->sigpipe_flag) |
#define | DECLARE_SIGPIPE_INFO(spinfo) pqsigfunc spinfo = NULL |
#define | DISABLE_SIGPIPE(conn, spinfo, failaction) |
#define | REMEMBER_EPIPE(spinfo, cond) |
#define | RESTORE_SIGPIPE(conn, spinfo) |
Functions | |
void | PQinitSSL (int do_init) |
void | PQinitOpenSSL (int do_ssl, int do_crypto) |
int | pqsecure_initialize (PGconn *conn) |
void | pqsecure_destroy (void) |
PostgresPollingStatusType | pqsecure_open_client (PGconn *conn) |
void | pqsecure_close (PGconn *conn) |
ssize_t | pqsecure_read (PGconn *conn, void *ptr, size_t len) |
ssize_t | pqsecure_write (PGconn *conn, const void *ptr, size_t len) |
void * | PQgetssl (PGconn *conn) |
#define DECLARE_SIGPIPE_INFO | ( | spinfo | ) | pqsigfunc spinfo = NULL |
Definition at line 155 of file fe-secure.c.
Referenced by pqsecure_read(), and pqsecure_write().
#define DISABLE_SIGPIPE | ( | conn, | ||
spinfo, | ||||
failaction | ||||
) |
do { \ if (!SIGPIPE_MASKED(conn)) \ spinfo = pqsignal(SIGPIPE, SIG_IGN); \ } while (0)
Definition at line 157 of file fe-secure.c.
Referenced by pqsecure_read(), and pqsecure_write().
#define REMEMBER_EPIPE | ( | spinfo, | ||
cond | ||||
) |
Definition at line 163 of file fe-secure.c.
Referenced by pqsecure_read(), and pqsecure_write().
#define RESTORE_SIGPIPE | ( | conn, | ||
spinfo | ||||
) |
do { \ if (!SIGPIPE_MASKED(conn)) \ pqsignal(SIGPIPE, spinfo); \ } while (0)
Definition at line 165 of file fe-secure.c.
Referenced by pqsecure_read(), and pqsecure_write().
Definition at line 117 of file fe-secure.c.
void* PQgetssl | ( | PGconn * | conn | ) |
void PQinitOpenSSL | ( | int | do_ssl, | |
int | do_crypto | |||
) |
Definition at line 199 of file fe-secure.c.
Referenced by PQinitSSL().
{ #ifdef USE_SSL #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 }
void PQinitSSL | ( | int | do_init | ) |
Definition at line 189 of file fe-secure.c.
References PQinitOpenSSL().
{ PQinitOpenSSL(do_init, do_init); }
void pqsecure_close | ( | PGconn * | conn | ) |
Definition at line 294 of file fe-secure.c.
Referenced by pqDropConnection().
{ #ifdef USE_SSL if (conn->ssl) close_SSL(conn); #endif }
void pqsecure_destroy | ( | void | ) |
Definition at line 236 of file fe-secure.c.
{ #ifdef USE_SSL destroySSL(); #endif }
int pqsecure_initialize | ( | PGconn * | conn | ) |
Definition at line 221 of file fe-secure.c.
Referenced by PQconnectPoll().
{ int r = 0; #ifdef USE_SSL r = init_ssl_system(conn); #endif return r; }
PostgresPollingStatusType pqsecure_open_client | ( | PGconn * | conn | ) |
Definition at line 247 of file fe-secure.c.
References pg_conn::errorMessage, libpq_gettext, NULL, printfPQExpBuffer(), pg_conn::sigpipe_flag, and pg_conn::sock.
Referenced by PQconnectPoll().
{ #ifdef USE_SSL /* First time through? */ if (conn->ssl == NULL) { /* We cannot use MSG_NOSIGNAL to block SIGPIPE when using SSL */ conn->sigpipe_flag = false; /* Create a connection-specific SSL object */ if (!(conn->ssl = SSL_new(SSL_context)) || !SSL_set_app_data(conn->ssl, conn) || !SSL_set_fd(conn->ssl, conn->sock)) { char *err = SSLerrmessage(); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not establish SSL connection: %s\n"), err); SSLerrfree(err); close_SSL(conn); return PGRES_POLLING_FAILED; } /* * Load client certificate, private key, and trusted CA certs. */ if (initialize_SSL(conn) != 0) { /* initialize_SSL already put a message in conn->errorMessage */ close_SSL(conn); return PGRES_POLLING_FAILED; } } /* Begin or continue the actual handshake */ return open_client_SSL(conn); #else /* shouldn't get here */ return PGRES_POLLING_FAILED; #endif }
ssize_t pqsecure_read | ( | PGconn * | conn, | |
void * | ptr, | |||
size_t | len | |||
) |
Definition at line 310 of file fe-secure.c.
References DECLARE_SIGPIPE_INFO, DISABLE_SIGPIPE, EAGAIN, ECONNRESET, EINTR, pg_conn::errorMessage, EWOULDBLOCK, libpq_gettext, printfPQExpBuffer(), recv, REMEMBER_EPIPE, RESTORE_SIGPIPE, pg_conn::sock, SOCK_ERRNO_SET, and SOCK_STRERROR.
Referenced by pqReadData().
{ ssize_t n; int result_errno = 0; char sebuf[256]; #ifdef USE_SSL if (conn->ssl) { int err; DECLARE_SIGPIPE_INFO(spinfo); /* SSL_read can write to the socket, so we need to disable SIGPIPE */ DISABLE_SIGPIPE(conn, spinfo, return -1); rloop: SOCK_ERRNO_SET(0); n = SSL_read(conn->ssl, ptr, len); err = SSL_get_error(conn->ssl, n); 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; REMEMBER_EPIPE(spinfo, result_errno == EPIPE); 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(); 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; } RESTORE_SIGPIPE(conn, spinfo); } else #endif /* USE_SSL */ { n = recv(conn->sock, ptr, len, 0); if (n < 0) { result_errno = SOCK_ERRNO; /* Set error message if appropriate */ switch (result_errno) { #ifdef EAGAIN case EAGAIN: #endif #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) case EWOULDBLOCK: #endif case EINTR: /* no error message, caller is expected to retry */ break; #ifdef ECONNRESET case 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")); break; #endif default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not receive data from server: %s\n"), SOCK_STRERROR(result_errno, sebuf, sizeof(sebuf))); break; } } } /* ensure we return the intended errno to caller */ SOCK_ERRNO_SET(result_errno); return n; }
ssize_t pqsecure_write | ( | PGconn * | conn, | |
const void * | ptr, | |||
size_t | len | |||
) |
Definition at line 473 of file fe-secure.c.
References DECLARE_SIGPIPE_INFO, DISABLE_SIGPIPE, EAGAIN, ECONNRESET, EINTR, pg_conn::errorMessage, EWOULDBLOCK, libpq_gettext, printfPQExpBuffer(), REMEMBER_EPIPE, RESTORE_SIGPIPE, send, pg_conn::sigpipe_flag, pg_conn::sock, SOCK_ERRNO_SET, and SOCK_STRERROR.
Referenced by pqSendSome().
{ ssize_t n; int result_errno = 0; char sebuf[256]; DECLARE_SIGPIPE_INFO(spinfo); #ifdef USE_SSL if (conn->ssl) { int err; DISABLE_SIGPIPE(conn, spinfo, return -1); SOCK_ERRNO_SET(0); n = SSL_write(conn->ssl, ptr, len); err = SSL_get_error(conn->ssl, n); 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; REMEMBER_EPIPE(spinfo, result_errno == EPIPE); 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(); 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; } } else #endif /* USE_SSL */ { 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) { result_errno = SOCK_ERRNO; /* * 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 && result_errno == EINVAL) { conn->sigpipe_flag = false; flags = 0; goto retry_masked; } #endif /* MSG_NOSIGNAL */ /* Set error message if appropriate */ switch (result_errno) { #ifdef EAGAIN case EAGAIN: #endif #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) case EWOULDBLOCK: #endif case EINTR: /* no error message, caller is expected to retry */ break; case EPIPE: /* Set flag for EPIPE */ REMEMBER_EPIPE(spinfo, true); /* FALL THRU */ #ifdef ECONNRESET case ECONNRESET: #endif 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")); break; default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not send data to server: %s\n"), SOCK_STRERROR(result_errno, sebuf, sizeof(sebuf))); break; } } } RESTORE_SIGPIPE(conn, spinfo); /* ensure we return the intended errno to caller */ SOCK_ERRNO_SET(result_errno); return n; }