Header And Logo

PostgreSQL
| The world's most advanced open source database.

Defines | Functions

fe-secure.c File Reference

#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>
Include dependency graph for fe-secure.c:

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 Documentation

#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 
)
Value:
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 
)
Value:
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().

#define SIGPIPE_MASKED (   conn  )     ((conn)->sigpipe_so || (conn)->sigpipe_flag)

Definition at line 117 of file fe-secure.c.


Function Documentation

void* PQgetssl ( PGconn conn  ) 

Definition at line 1547 of file fe-secure.c.

Referenced by printSSLInfo().

{
    return NULL;
}

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().

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;
}