LCOV - differential code coverage report
Current view: top level - src/backend/libpq - be-secure.c (source / functions) Coverage Total Hit UBC CBC
Current: bed3ffbf9d952be6c7d739d068cdce44c046dfb7 vs 574581b50ac9c63dd9e4abebb731a3b67e5b50f6 Lines: 93.6 % 94 88 6 88
Current Date: 2026-05-05 10:23:31 +0900 Functions: 100.0 % 9 9 9
Baseline: lcov-20260505-025707-baseline Branches: 75.7 % 70 53 17 53
Baseline Date: 2026-05-05 10:27:06 +0900 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(30,360] days: 100.0 % 1 1 1
(360..) days: 93.5 % 93 87 6 87
Function coverage date bins:
(360..) days: 100.0 % 9 9 9
Branch coverage date bins:
(360..) days: 75.7 % 70 53 17 53

 Age         Owner                    Branch data    TLA  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
 3408 tgl@sss.pgh.pa.us          79                 :CBC          66 : secure_initialize(bool isServerStart)
                                 80                 :                : {
                                 81                 :                : #ifdef USE_SSL
                                 82                 :             66 :     return be_tls_init(isServerStart);
                                 83                 :                : #else
                                 84                 :                :     return 0;
                                 85                 :                : #endif
                                 86                 :                : }
                                 87                 :                : 
                                 88                 :                : /*
                                 89                 :                :  *  Destroy global context, if any.
                                 90                 :                :  */
                                 91                 :                : void
 3410                            92                 :            163 : secure_destroy(void)
                                 93                 :                : {
                                 94                 :                : #ifdef USE_SSL
                                 95                 :            163 :     be_tls_destroy();
                                 96                 :                : #endif
 8726 bruce@momjian.us           97                 :            163 : }
                                 98                 :                : 
                                 99                 :                : /*
                                100                 :                :  * Indicate if we have loaded the root CA store to verify certificates
                                101                 :                :  */
                                102                 :                : bool
 6375 magnus@hagander.net       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
 8644 bruce@momjian.us          116                 :            193 : secure_open_server(Port *port)
                                117                 :                : {
                                118                 :                : #ifdef USE_SSL
                                119                 :            193 :     int         r = 0;
                                120                 :                :     ssize_t     len;
                                121                 :                : 
                                122                 :                :     /* push unencrypted buffered data back through SSL setup */
  757 heikki.linnakangas@i      123                 :            193 :     len = pq_buffer_remaining_data();
                                124         [ +  + ]:            193 :     if (len > 0)
                                125                 :                :     {
                                126                 :             10 :         char       *buf = palloc(len);
                                127                 :                : 
                                128                 :             10 :         pq_startmsgread();
                                129         [ -  + ]:             10 :         if (pq_getbytes(buf, len) == EOF)
  757 heikki.linnakangas@i      130                 :UBC           0 :             return STATUS_ERROR;    /* shouldn't be possible */
  757 heikki.linnakangas@i      131                 :CBC          10 :         pq_endmsgread();
                                132                 :             10 :         port->raw_buf = buf;
                                133                 :             10 :         port->raw_buf_remaining = len;
                                134                 :             10 :         port->raw_buf_consumed = 0;
                                135                 :                :     }
                                136         [ -  + ]:            193 :     Assert(pq_buffer_remaining_data() == 0);
                                137                 :                : 
  360 michael@paquier.xyz       138                 :            193 :     INJECTION_POINT("backend-ssl-startup", NULL);
                                139                 :                : 
 4285 heikki.linnakangas@i      140                 :            192 :     r = be_tls_open_server(port);
                                141                 :                : 
  757                           142         [ -  + ]:            192 :     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                 :                :          */
  757 heikki.linnakangas@i      148         [ #  # ]:UBC           0 :         elog(LOG, "buffered unencrypted data remains after negotiating SSL connection");
                                149                 :              0 :         return STATUS_ERROR;
                                150                 :                :     }
  757 heikki.linnakangas@i      151         [ +  + ]:CBC         192 :     if (port->raw_buf != NULL)
                                152                 :                :     {
                                153                 :             10 :         pfree(port->raw_buf);
                                154                 :             10 :         port->raw_buf = NULL;
                                155                 :                :     }
                                156                 :                : 
 3028 peter_e@gmx.net           157   [ +  +  +  +  :            192 :     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)")));
 8726 bruce@momjian.us          161                 :            192 :     return r;
                                162                 :                : #else
                                163                 :                :     return 0;
                                164                 :                : #endif
                                165                 :                : }
                                166                 :                : 
                                167                 :                : /*
                                168                 :                :  *  Close secure session.
                                169                 :                :  */
                                170                 :                : void
 8644                           171                 :          15033 : secure_close(Port *port)
                                172                 :                : {
                                173                 :                : #ifdef USE_SSL
 4285 heikki.linnakangas@i      174         [ +  + ]:          15033 :     if (port->ssl_in_use)
                                175                 :            192 :         be_tls_close(port);
                                176                 :                : #endif
 8726 bruce@momjian.us          177                 :          15033 : }
                                178                 :                : 
                                179                 :                : /*
                                180                 :                :  *  Read data from a secure connection.
                                181                 :                :  */
                                182                 :                : ssize_t
 8644                           183                 :        1687178 : 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. */
 2755 tgl@sss.pgh.pa.us         189                 :        1687178 :     ProcessClientReadInterrupt(false);
                                190                 :                : 
 4109 andres@anarazel.de        191                 :        1911546 : retry:
                                192                 :                : #ifdef USE_SSL
 4099 heikki.linnakangas@i      193                 :        1911546 :     waitfor = 0;
 4285                           194         [ +  + ]:        1911546 :     if (port->ssl_in_use)
                                195                 :                :     {
 4099                           196                 :            709 :         n = be_tls_read(port, ptr, len, &waitfor);
                                197                 :                :     }
                                198                 :                :     else
                                199                 :                : #endif
                                200                 :                : #ifdef ENABLE_GSS
 1954 tgl@sss.pgh.pa.us         201   [ +  +  +  + ]:        1910837 :     if (port->gss && port->gss->enc)
                                202                 :                :     {
 2589 sfrost@snowman.net        203                 :            733 :         n = be_gssapi_read(port, ptr, len);
                                204                 :            733 :         waitfor = WL_SOCKET_READABLE;
                                205                 :                :     }
                                206                 :                :     else
                                207                 :                : #endif
                                208                 :                :     {
 4285 heikki.linnakangas@i      209                 :        1910104 :         n = secure_raw_read(port, ptr, len);
 4099                           210                 :        1910104 :         waitfor = WL_SOCKET_READABLE;
                                211                 :                :     }
                                212                 :                : 
                                213                 :                :     /* In blocking mode, wait until the socket is ready */
                                214   [ +  +  +  +  :        1911546 :     if (n < 0 && !port->noblock && (errno == EWOULDBLOCK || errno == EAGAIN))
                                        +  +  -  + ]
                                215                 :                :     {
                                216                 :                :         WaitEvent   event;
                                217                 :                : 
                                218         [ -  + ]:         224400 :         Assert(waitfor);
                                219                 :                : 
 1891 tmunro@postgresql.or      220                 :         224400 :         ModifyWaitEvent(FeBeWaitSet, FeBeWaitSetSocketPos, waitfor, NULL);
                                221                 :                : 
 3500 rhaas@postgresql.org      222                 :         224400 :         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                 :                :          */
 3697 andres@anarazel.de        242         [ -  + ]:         224400 :         if (event.events & WL_POSTMASTER_DEATH)
 3827 rhaas@postgresql.org      243         [ #  # ]:UBC           0 :             ereport(FATAL,
                                244                 :                :                     (errcode(ERRCODE_ADMIN_SHUTDOWN),
                                245                 :                :                      errmsg("terminating connection due to unexpected postmaster exit")));
                                246                 :                : 
                                247                 :                :         /* Handle interrupt. */
 3697 andres@anarazel.de        248         [ +  + ]:CBC      224400 :         if (event.events & WL_LATCH_SET)
                                249                 :                :         {
 4099 heikki.linnakangas@i      250                 :          11699 :             ResetLatch(MyLatch);
                                251                 :          11699 :             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                 :                :         }
 4109 andres@anarazel.de        259                 :         224380 :         goto retry;
                                260                 :                :     }
                                261                 :                : 
                                262                 :                :     /*
                                263                 :                :      * Process interrupts that happened during a successful (or non-blocking,
                                264                 :                :      * or hard-failed) read.
                                265                 :                :      */
                                266                 :        1687146 :     ProcessClientReadInterrupt(false);
                                267                 :                : 
 8726 bruce@momjian.us          268                 :        1687145 :     return n;
                                269                 :                : }
                                270                 :                : 
                                271                 :                : ssize_t
 4285 heikki.linnakangas@i      272                 :        1914773 : 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 */
  757                           277         [ +  + ]:        1914773 :     if (port->raw_buf_remaining > 0)
                                278                 :                :     {
                                279                 :                :         /* consume up to len bytes from the raw_buf */
                                280         [ -  + ]:             20 :         if (len > port->raw_buf_remaining)
  757 heikki.linnakangas@i      281                 :UBC           0 :             len = port->raw_buf_remaining;
  757 heikki.linnakangas@i      282         [ -  + ]:CBC          20 :         Assert(port->raw_buf);
                                283                 :             20 :         memcpy(ptr, port->raw_buf + port->raw_buf_consumed, len);
                                284                 :             20 :         port->raw_buf_consumed += len;
                                285                 :             20 :         port->raw_buf_remaining -= len;
                                286                 :             20 :         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
 4285                           296                 :        1914753 :     n = recv(port->sock, ptr, len, 0);
                                297                 :                : #ifdef WIN32
                                298                 :                :     pgwin32_noblock = false;
                                299                 :                : #endif
                                300                 :                : 
                                301                 :        1914753 :     return n;
                                302                 :                : }
                                303                 :                : 
                                304                 :                : 
                                305                 :                : /*
                                306                 :                :  *  Write data to a secure connection.
                                307                 :                :  */
                                308                 :                : ssize_t
  450 peter@eisentraut.org      309                 :        1217575 : 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. */
 2755 tgl@sss.pgh.pa.us         315                 :        1217575 :     ProcessClientWriteInterrupt(false);
                                316                 :                : 
 4109 andres@anarazel.de        317                 :        1235949 : retry:
 4099 heikki.linnakangas@i      318                 :        1235949 :     waitfor = 0;
                                319                 :                : #ifdef USE_SSL
 4285                           320         [ +  + ]:        1235949 :     if (port->ssl_in_use)
                                321                 :                :     {
 4099                           322                 :            285 :         n = be_tls_write(port, ptr, len, &waitfor);
                                323                 :                :     }
                                324                 :                :     else
                                325                 :                : #endif
                                326                 :                : #ifdef ENABLE_GSS
 1954 tgl@sss.pgh.pa.us         327   [ +  +  +  + ]:        1235664 :     if (port->gss && port->gss->enc)
                                328                 :                :     {
 2589 sfrost@snowman.net        329                 :            415 :         n = be_gssapi_write(port, ptr, len);
                                330                 :            415 :         waitfor = WL_SOCKET_WRITEABLE;
                                331                 :                :     }
                                332                 :                :     else
                                333                 :                : #endif
                                334                 :                :     {
 4285 heikki.linnakangas@i      335                 :        1235249 :         n = secure_raw_write(port, ptr, len);
 4099                           336                 :        1235249 :         waitfor = WL_SOCKET_WRITEABLE;
                                337                 :                :     }
                                338                 :                : 
                                339   [ +  +  +  +  :        1235949 :     if (n < 0 && !port->noblock && (errno == EWOULDBLOCK || errno == EAGAIN))
                                        +  +  -  + ]
                                340                 :                :     {
                                341                 :                :         WaitEvent   event;
                                342                 :                : 
                                343         [ -  + ]:          18374 :         Assert(waitfor);
                                344                 :                : 
 1891 tmunro@postgresql.or      345                 :          18374 :         ModifyWaitEvent(FeBeWaitSet, FeBeWaitSetSocketPos, waitfor, NULL);
                                346                 :                : 
 3500 rhaas@postgresql.org      347                 :          18374 :         WaitEventSetWait(FeBeWaitSet, -1 /* no timeout */ , &event, 1,
                                348                 :                :                          WAIT_EVENT_CLIENT_WRITE);
                                349                 :                : 
                                350                 :                :         /* See comments in secure_read. */
 3697 andres@anarazel.de        351         [ -  + ]:          18374 :         if (event.events & WL_POSTMASTER_DEATH)
 3827 rhaas@postgresql.org      352         [ #  # ]:UBC           0 :             ereport(FATAL,
                                353                 :                :                     (errcode(ERRCODE_ADMIN_SHUTDOWN),
                                354                 :                :                      errmsg("terminating connection due to unexpected postmaster exit")));
                                355                 :                : 
                                356                 :                :         /* Handle interrupt. */
 3697 andres@anarazel.de        357         [ +  + ]:CBC       18374 :         if (event.events & WL_LATCH_SET)
                                358                 :                :         {
 4099 heikki.linnakangas@i      359                 :              5 :             ResetLatch(MyLatch);
                                360                 :              5 :             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                 :                :         }
 4109 andres@anarazel.de        368                 :          18374 :         goto retry;
                                369                 :                :     }
                                370                 :                : 
                                371                 :                :     /*
                                372                 :                :      * Process interrupts that happened during a successful (or non-blocking,
                                373                 :                :      * or hard-failed) write.
                                374                 :                :      */
 4099 heikki.linnakangas@i      375                 :        1217575 :     ProcessClientWriteInterrupt(false);
                                376                 :                : 
 4285                           377                 :        1217575 :     return n;
                                378                 :                : }
                                379                 :                : 
                                380                 :                : ssize_t
                                381                 :        1236578 : 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
 4109 andres@anarazel.de        388                 :        1236578 :     n = send(port->sock, ptr, len, 0);
                                389                 :                : #ifdef WIN32
                                390                 :                :     pgwin32_noblock = false;
                                391                 :                : #endif
                                392                 :                : 
                                393                 :        1236578 :     return n;
                                394                 :                : }
        

Generated by: LCOV version 2.5.0-beta