LCOV - code coverage report
Current view: top level - src/backend/libpq - be-secure.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 92.9 % 84 78
Test Date: 2026-07-22 02:15:37 Functions: 100.0 % 9 9
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 72.2 % 54 39

             Branch data     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 ECDH 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                 :         153 : secure_destroy(void)
      93                 :             : {
      94                 :             : #ifdef USE_SSL
      95                 :         153 :     be_tls_destroy();
      96                 :             : #endif
      97                 :         153 : }
      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                 :       15184 : secure_close(Port *port)
     172                 :             : {
     173                 :             : #ifdef USE_SSL
     174         [ +  + ]:       15184 :     if (port->ssl_in_use)
     175                 :         170 :         be_tls_close(port);
     176                 :             : #endif
     177                 :       15184 : }
     178                 :             : 
     179                 :             : /*
     180                 :             :  *  Read data from a secure connection.
     181                 :             :  */
     182                 :             : ssize_t
     183                 :     1428309 : 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                 :     1428309 :     ProcessClientReadInterrupt(false);
     190                 :             : 
     191                 :     1782250 : retry:
     192                 :             : #ifdef USE_SSL
     193                 :     1782250 :     waitfor = 0;
     194         [ +  + ]:     1782250 :     if (port->ssl_in_use)
     195                 :             :     {
     196                 :         750 :         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                 :     1781500 :         n = secure_raw_read(port, ptr, len);
     210                 :     1781500 :         waitfor = WL_SOCKET_READABLE;
     211                 :             :     }
     212                 :             : 
     213                 :             :     /* In blocking mode, wait until the socket is ready */
     214   [ +  +  +  +  :     1782250 :     if (n < 0 && !port->noblock && (errno == EWOULDBLOCK || errno == EAGAIN))
             -  +  -  - ]
     215                 :             :     {
     216                 :             :         WaitEvent   event;
     217                 :             : 
     218                 :             :         Assert(waitfor);
     219                 :             : 
     220                 :      353970 :         ModifyWaitEvent(FeBeWaitSet, FeBeWaitSetSocketPos, waitfor, NULL);
     221                 :             : 
     222                 :      353970 :         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         [ -  + ]:      353970 :         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         [ +  + ]:      353970 :         if (event.events & WL_LATCH_SET)
     249                 :             :         {
     250                 :       13405 :             ResetLatch(MyLatch);
     251                 :       13405 :             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                 :      353948 :         goto retry;
     260                 :             :     }
     261                 :             : 
     262                 :             :     /*
     263                 :             :      * Process interrupts that happened during a successful (or non-blocking,
     264                 :             :      * or hard-failed) read.
     265                 :             :      */
     266                 :     1428280 :     ProcessClientReadInterrupt(false);
     267                 :             : 
     268                 :     1428280 :     return n;
     269                 :             : }
     270                 :             : 
     271                 :             : ssize_t
     272                 :     1784644 : 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         [ +  + ]:     1784644 :     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                 :     1784638 :     n = recv(port->sock, ptr, len, 0);
     297                 :             : #ifdef WIN32
     298                 :             :     pgwin32_noblock = false;
     299                 :             : #endif
     300                 :             : 
     301                 :     1784638 :     return n;
     302                 :             : }
     303                 :             : 
     304                 :             : 
     305                 :             : /*
     306                 :             :  *  Write data to a secure connection.
     307                 :             :  */
     308                 :             : ssize_t
     309                 :     1405240 : 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                 :     1405240 :     ProcessClientWriteInterrupt(false);
     316                 :             : 
     317                 :     1427008 : retry:
     318                 :     1427008 :     waitfor = 0;
     319                 :             : #ifdef USE_SSL
     320         [ +  + ]:     1427008 :     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                 :     1426760 :         n = secure_raw_write(port, ptr, len);
     336                 :     1426760 :         waitfor = WL_SOCKET_WRITEABLE;
     337                 :             :     }
     338                 :             : 
     339   [ +  +  +  +  :     1427008 :     if (n < 0 && !port->noblock && (errno == EWOULDBLOCK || errno == EAGAIN))
             +  +  -  + ]
     340                 :             :     {
     341                 :             :         WaitEvent   event;
     342                 :             : 
     343                 :             :         Assert(waitfor);
     344                 :             : 
     345                 :       21768 :         ModifyWaitEvent(FeBeWaitSet, FeBeWaitSetSocketPos, waitfor, NULL);
     346                 :             : 
     347                 :       21768 :         WaitEventSetWait(FeBeWaitSet, -1 /* no timeout */ , &event, 1,
     348                 :             :                          WAIT_EVENT_CLIENT_WRITE);
     349                 :             : 
     350                 :             :         /* See comments in secure_read. */
     351         [ -  + ]:       21768 :         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         [ +  + ]:       21768 :         if (event.events & WL_LATCH_SET)
     358                 :             :         {
     359                 :           1 :             ResetLatch(MyLatch);
     360                 :           1 :             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                 :       21768 :         goto retry;
     369                 :             :     }
     370                 :             : 
     371                 :             :     /*
     372                 :             :      * Process interrupts that happened during a successful (or non-blocking,
     373                 :             :      * or hard-failed) write.
     374                 :             :      */
     375                 :     1405240 :     ProcessClientWriteInterrupt(false);
     376                 :             : 
     377                 :     1405240 :     return n;
     378                 :             : }
     379                 :             : 
     380                 :             : ssize_t
     381                 :     1427474 : 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                 :     1427474 :     n = send(port->sock, ptr, len, 0);
     389                 :             : #ifdef WIN32
     390                 :             :     pgwin32_noblock = false;
     391                 :             : #endif
     392                 :             : 
     393                 :     1427474 :     return n;
     394                 :             : }
        

Generated by: LCOV version 2.0-1