LCOV - code coverage report
Current view: top level - src/backend/libpq - be-secure.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 53.1 % 113 60
Test Date: 2026-01-26 10:56:24 Functions: 55.6 % 9 5
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 27.5 % 80 22

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

Generated by: LCOV version 2.3.2-1