LCOV - code coverage report
Current view: top level - src/backend/libpq - be-secure.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 90.5 % 84 76
Test Date: 2026-03-20 12:15:57 Functions: 100.0 % 9 9
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * be-secure.c
       4              :  *    functions related to setting up a secure connection to the frontend.
       5              :  *    Secure connections are expected to provide confidentiality,
       6              :  *    message integrity and endpoint authentication.
       7              :  *
       8              :  *
       9              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
      10              :  * Portions Copyright (c) 1994, Regents of the University of California
      11              :  *
      12              :  *
      13              :  * IDENTIFICATION
      14              :  *    src/backend/libpq/be-secure.c
      15              :  *
      16              :  *-------------------------------------------------------------------------
      17              :  */
      18              : 
      19              : #include "postgres.h"
      20              : 
      21              : #include <signal.h>
      22              : #include <fcntl.h>
      23              : #include <ctype.h>
      24              : #include <sys/socket.h>
      25              : #include <netdb.h>
      26              : #include <netinet/in.h>
      27              : #include <netinet/tcp.h>
      28              : #include <arpa/inet.h>
      29              : 
      30              : #include "libpq/libpq.h"
      31              : #include "miscadmin.h"
      32              : #include "storage/latch.h"
      33              : #include "tcop/tcopprot.h"
      34              : #include "utils/injection_point.h"
      35              : #include "utils/wait_event.h"
      36              : 
      37              : char       *ssl_library;
      38              : char       *ssl_cert_file;
      39              : char       *ssl_key_file;
      40              : char       *ssl_ca_file;
      41              : char       *ssl_crl_file;
      42              : char       *ssl_crl_dir;
      43              : char       *ssl_dh_params_file;
      44              : char       *ssl_passphrase_command;
      45              : bool        ssl_passphrase_command_supports_reload;
      46              : 
      47              : #ifdef USE_SSL
      48              : bool        ssl_loaded_verify_locations = false;
      49              : #endif
      50              : 
      51              : /* GUC variable controlling SSL cipher list */
      52              : char       *SSLCipherSuites = NULL;
      53              : char       *SSLCipherList = NULL;
      54              : 
      55              : /* GUC variable for default ECHD curve. */
      56              : char       *SSLECDHCurve;
      57              : 
      58              : /* GUC variable: if false, prefer client ciphers */
      59              : bool        SSLPreferServerCiphers;
      60              : 
      61              : int         ssl_min_protocol_version = PG_TLS1_2_VERSION;
      62              : int         ssl_max_protocol_version = PG_TLS_ANY;
      63              : 
      64              : /* GUC variable: if false, discards hostname extensions in handshake */
      65              : bool        ssl_sni = false;
      66              : 
      67              : /* ------------------------------------------------------------ */
      68              : /*           Procedures common to all secure sessions           */
      69              : /* ------------------------------------------------------------ */
      70              : 
      71              : /*
      72              :  *  Initialize global context.
      73              :  *
      74              :  * If isServerStart is true, report any errors as FATAL (so we don't return).
      75              :  * Otherwise, log errors at LOG level and return -1 to indicate trouble,
      76              :  * preserving the old SSL state if any.  Returns 0 if OK.
      77              :  */
      78              : int
      79           65 : secure_initialize(bool isServerStart)
      80              : {
      81              : #ifdef USE_SSL
      82           65 :     return be_tls_init(isServerStart);
      83              : #else
      84              :     return 0;
      85              : #endif
      86              : }
      87              : 
      88              : /*
      89              :  *  Destroy global context, if any.
      90              :  */
      91              : void
      92          147 : secure_destroy(void)
      93              : {
      94              : #ifdef USE_SSL
      95          147 :     be_tls_destroy();
      96              : #endif
      97          147 : }
      98              : 
      99              : /*
     100              :  * Indicate if we have loaded the root CA store to verify certificates
     101              :  */
     102              : bool
     103           38 : secure_loaded_verify_locations(void)
     104              : {
     105              : #ifdef USE_SSL
     106           38 :     return ssl_loaded_verify_locations;
     107              : #else
     108              :     return false;
     109              : #endif
     110              : }
     111              : 
     112              : /*
     113              :  *  Attempt to negotiate secure session.
     114              :  */
     115              : int
     116          171 : secure_open_server(Port *port)
     117              : {
     118              : #ifdef USE_SSL
     119          171 :     int         r = 0;
     120              :     ssize_t     len;
     121              : 
     122              :     /* push unencrypted buffered data back through SSL setup */
     123          171 :     len = pq_buffer_remaining_data();
     124          171 :     if (len > 0)
     125              :     {
     126            3 :         char       *buf = palloc(len);
     127              : 
     128            3 :         pq_startmsgread();
     129            3 :         if (pq_getbytes(buf, len) == EOF)
     130            0 :             return STATUS_ERROR;    /* shouldn't be possible */
     131            3 :         pq_endmsgread();
     132            3 :         port->raw_buf = buf;
     133            3 :         port->raw_buf_remaining = len;
     134            3 :         port->raw_buf_consumed = 0;
     135              :     }
     136              :     Assert(pq_buffer_remaining_data() == 0);
     137              : 
     138          171 :     INJECTION_POINT("backend-ssl-startup", NULL);
     139              : 
     140          170 :     r = be_tls_open_server(port);
     141              : 
     142          170 :     if (port->raw_buf_remaining > 0)
     143              :     {
     144              :         /*
     145              :          * This shouldn't be possible -- it would mean the client sent
     146              :          * encrypted data before we established a session key...
     147              :          */
     148            0 :         elog(LOG, "buffered unencrypted data remains after negotiating SSL connection");
     149            0 :         return STATUS_ERROR;
     150              :     }
     151          170 :     if (port->raw_buf != NULL)
     152              :     {
     153            3 :         pfree(port->raw_buf);
     154            3 :         port->raw_buf = NULL;
     155              :     }
     156              : 
     157          170 :     ereport(DEBUG2,
     158              :             (errmsg_internal("SSL connection from DN:\"%s\" CN:\"%s\"",
     159              :                              port->peer_dn ? port->peer_dn : "(anonymous)",
     160              :                              port->peer_cn ? port->peer_cn : "(anonymous)")));
     161          170 :     return r;
     162              : #else
     163              :     return 0;
     164              : #endif
     165              : }
     166              : 
     167              : /*
     168              :  *  Close secure session.
     169              :  */
     170              : void
     171        14489 : secure_close(Port *port)
     172              : {
     173              : #ifdef USE_SSL
     174        14489 :     if (port->ssl_in_use)
     175          170 :         be_tls_close(port);
     176              : #endif
     177        14489 : }
     178              : 
     179              : /*
     180              :  *  Read data from a secure connection.
     181              :  */
     182              : ssize_t
     183      1466236 : secure_read(Port *port, void *ptr, size_t len)
     184              : {
     185              :     ssize_t     n;
     186              :     int         waitfor;
     187              : 
     188              :     /* Deal with any already-pending interrupt condition. */
     189      1466236 :     ProcessClientReadInterrupt(false);
     190              : 
     191      1821852 : retry:
     192              : #ifdef USE_SSL
     193      1821852 :     waitfor = 0;
     194      1821852 :     if (port->ssl_in_use)
     195              :     {
     196          756 :         n = be_tls_read(port, ptr, len, &waitfor);
     197              :     }
     198              :     else
     199              : #endif
     200              : #ifdef ENABLE_GSS
     201              :     if (port->gss && port->gss->enc)
     202              :     {
     203              :         n = be_gssapi_read(port, ptr, len);
     204              :         waitfor = WL_SOCKET_READABLE;
     205              :     }
     206              :     else
     207              : #endif
     208              :     {
     209      1821096 :         n = secure_raw_read(port, ptr, len);
     210      1821096 :         waitfor = WL_SOCKET_READABLE;
     211              :     }
     212              : 
     213              :     /* In blocking mode, wait until the socket is ready */
     214      1821852 :     if (n < 0 && !port->noblock && (errno == EWOULDBLOCK || errno == EAGAIN))
     215              :     {
     216              :         WaitEvent   event;
     217              : 
     218              :         Assert(waitfor);
     219              : 
     220       355638 :         ModifyWaitEvent(FeBeWaitSet, FeBeWaitSetSocketPos, waitfor, NULL);
     221              : 
     222       355638 :         WaitEventSetWait(FeBeWaitSet, -1 /* no timeout */ , &event, 1,
     223              :                          WAIT_EVENT_CLIENT_READ);
     224              : 
     225              :         /*
     226              :          * If the postmaster has died, it's not safe to continue running,
     227              :          * because it is the postmaster's job to kill us if some other backend
     228              :          * exits uncleanly.  Moreover, we won't run very well in this state;
     229              :          * helper processes like walwriter and the bgwriter will exit, so
     230              :          * performance may be poor.  Finally, if we don't exit, pg_ctl will be
     231              :          * unable to restart the postmaster without manual intervention, so no
     232              :          * new connections can be accepted.  Exiting clears the deck for a
     233              :          * postmaster restart.
     234              :          *
     235              :          * (Note that we only make this check when we would otherwise sleep on
     236              :          * our latch.  We might still continue running for a while if the
     237              :          * postmaster is killed in mid-query, or even through multiple queries
     238              :          * if we never have to wait for read.  We don't want to burn too many
     239              :          * cycles checking for this very rare condition, and this should cause
     240              :          * us to exit quickly in most cases.)
     241              :          */
     242       355638 :         if (event.events & WL_POSTMASTER_DEATH)
     243            0 :             ereport(FATAL,
     244              :                     (errcode(ERRCODE_ADMIN_SHUTDOWN),
     245              :                      errmsg("terminating connection due to unexpected postmaster exit")));
     246              : 
     247              :         /* Handle interrupt. */
     248       355638 :         if (event.events & WL_LATCH_SET)
     249              :         {
     250        12869 :             ResetLatch(MyLatch);
     251        12869 :             ProcessClientReadInterrupt(true);
     252              : 
     253              :             /*
     254              :              * We'll retry the read. Most likely it will return immediately
     255              :              * because there's still no data available, and we'll wait for the
     256              :              * socket to become ready again.
     257              :              */
     258              :         }
     259       355619 :         goto retry;
     260              :     }
     261              : 
     262              :     /*
     263              :      * Process interrupts that happened during a successful (or non-blocking,
     264              :      * or hard-failed) read.
     265              :      */
     266      1466214 :     ProcessClientReadInterrupt(false);
     267              : 
     268      1466214 :     return n;
     269              : }
     270              : 
     271              : ssize_t
     272      1824237 : secure_raw_read(Port *port, void *ptr, size_t len)
     273              : {
     274              :     ssize_t     n;
     275              : 
     276              :     /* Read from the "unread" buffered data first. c.f. libpq-be.h */
     277      1824237 :     if (port->raw_buf_remaining > 0)
     278              :     {
     279              :         /* consume up to len bytes from the raw_buf */
     280            6 :         if (len > port->raw_buf_remaining)
     281            0 :             len = port->raw_buf_remaining;
     282              :         Assert(port->raw_buf);
     283            6 :         memcpy(ptr, port->raw_buf + port->raw_buf_consumed, len);
     284            6 :         port->raw_buf_consumed += len;
     285            6 :         port->raw_buf_remaining -= len;
     286            6 :         return len;
     287              :     }
     288              : 
     289              :     /*
     290              :      * Try to read from the socket without blocking. If it succeeds we're
     291              :      * done, otherwise we'll wait for the socket using the latch mechanism.
     292              :      */
     293              : #ifdef WIN32
     294              :     pgwin32_noblock = true;
     295              : #endif
     296      1824231 :     n = recv(port->sock, ptr, len, 0);
     297              : #ifdef WIN32
     298              :     pgwin32_noblock = false;
     299              : #endif
     300              : 
     301      1824231 :     return n;
     302              : }
     303              : 
     304              : 
     305              : /*
     306              :  *  Write data to a secure connection.
     307              :  */
     308              : ssize_t
     309      1242059 : secure_write(Port *port, const void *ptr, size_t len)
     310              : {
     311              :     ssize_t     n;
     312              :     int         waitfor;
     313              : 
     314              :     /* Deal with any already-pending interrupt condition. */
     315      1242059 :     ProcessClientWriteInterrupt(false);
     316              : 
     317      1262791 : retry:
     318      1262791 :     waitfor = 0;
     319              : #ifdef USE_SSL
     320      1262791 :     if (port->ssl_in_use)
     321              :     {
     322          248 :         n = be_tls_write(port, ptr, len, &waitfor);
     323              :     }
     324              :     else
     325              : #endif
     326              : #ifdef ENABLE_GSS
     327              :     if (port->gss && port->gss->enc)
     328              :     {
     329              :         n = be_gssapi_write(port, ptr, len);
     330              :         waitfor = WL_SOCKET_WRITEABLE;
     331              :     }
     332              :     else
     333              : #endif
     334              :     {
     335      1262543 :         n = secure_raw_write(port, ptr, len);
     336      1262543 :         waitfor = WL_SOCKET_WRITEABLE;
     337              :     }
     338              : 
     339      1262791 :     if (n < 0 && !port->noblock && (errno == EWOULDBLOCK || errno == EAGAIN))
     340              :     {
     341              :         WaitEvent   event;
     342              : 
     343              :         Assert(waitfor);
     344              : 
     345        20732 :         ModifyWaitEvent(FeBeWaitSet, FeBeWaitSetSocketPos, waitfor, NULL);
     346              : 
     347        20732 :         WaitEventSetWait(FeBeWaitSet, -1 /* no timeout */ , &event, 1,
     348              :                          WAIT_EVENT_CLIENT_WRITE);
     349              : 
     350              :         /* See comments in secure_read. */
     351        20732 :         if (event.events & WL_POSTMASTER_DEATH)
     352            0 :             ereport(FATAL,
     353              :                     (errcode(ERRCODE_ADMIN_SHUTDOWN),
     354              :                      errmsg("terminating connection due to unexpected postmaster exit")));
     355              : 
     356              :         /* Handle interrupt. */
     357        20732 :         if (event.events & WL_LATCH_SET)
     358              :         {
     359            0 :             ResetLatch(MyLatch);
     360            0 :             ProcessClientWriteInterrupt(true);
     361              : 
     362              :             /*
     363              :              * We'll retry the write. Most likely it will return immediately
     364              :              * because there's still no buffer space available, and we'll wait
     365              :              * for the socket to become ready again.
     366              :              */
     367              :         }
     368        20732 :         goto retry;
     369              :     }
     370              : 
     371              :     /*
     372              :      * Process interrupts that happened during a successful (or non-blocking,
     373              :      * or hard-failed) write.
     374              :      */
     375      1242059 :     ProcessClientWriteInterrupt(false);
     376              : 
     377      1242059 :     return n;
     378              : }
     379              : 
     380              : ssize_t
     381      1263257 : secure_raw_write(Port *port, const void *ptr, size_t len)
     382              : {
     383              :     ssize_t     n;
     384              : 
     385              : #ifdef WIN32
     386              :     pgwin32_noblock = true;
     387              : #endif
     388      1263257 :     n = send(port->sock, ptr, len, 0);
     389              : #ifdef WIN32
     390              :     pgwin32_noblock = false;
     391              : #endif
     392              : 
     393      1263257 :     return n;
     394              : }
        

Generated by: LCOV version 2.0-1