LCOV - code coverage report
Current view: top level - src/backend/libpq - be-secure.c (source / functions) Hit Total Coverage
Test: PostgreSQL 16beta1 Lines: 58 60 96.7 %
Date: 2023-05-30 23:12:14 Functions: 9 9 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * be-secure.c
       4             :  *    functions related to setting up a secure connection to the frontend.
       5             :  *    Secure connections are expected to provide confidentiality,
       6             :  *    message integrity and endpoint authentication.
       7             :  *
       8             :  *
       9             :  * Portions Copyright (c) 1996-2023, 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 "pgstat.h"
      33             : #include "storage/ipc.h"
      34             : #include "storage/proc.h"
      35             : #include "tcop/tcopprot.h"
      36             : #include "utils/memutils.h"
      37             : 
      38             : char       *ssl_library;
      39             : char       *ssl_cert_file;
      40             : char       *ssl_key_file;
      41             : char       *ssl_ca_file;
      42             : char       *ssl_crl_file;
      43             : char       *ssl_crl_dir;
      44             : char       *ssl_dh_params_file;
      45             : char       *ssl_passphrase_command;
      46             : bool        ssl_passphrase_command_supports_reload;
      47             : 
      48             : #ifdef USE_SSL
      49             : bool        ssl_loaded_verify_locations = false;
      50             : #endif
      51             : 
      52             : /* GUC variable controlling SSL cipher list */
      53             : char       *SSLCipherSuites = 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             : /* ------------------------------------------------------------ */
      65             : /*           Procedures common to all secure sessions           */
      66             : /* ------------------------------------------------------------ */
      67             : 
      68             : /*
      69             :  *  Initialize global context.
      70             :  *
      71             :  * If isServerStart is true, report any errors as FATAL (so we don't return).
      72             :  * Otherwise, log errors at LOG level and return -1 to indicate trouble,
      73             :  * preserving the old SSL state if any.  Returns 0 if OK.
      74             :  */
      75             : int
      76          52 : secure_initialize(bool isServerStart)
      77             : {
      78             : #ifdef USE_SSL
      79          52 :     return be_tls_init(isServerStart);
      80             : #else
      81             :     return 0;
      82             : #endif
      83             : }
      84             : 
      85             : /*
      86             :  *  Destroy global context, if any.
      87             :  */
      88             : void
      89         206 : secure_destroy(void)
      90             : {
      91             : #ifdef USE_SSL
      92         206 :     be_tls_destroy();
      93             : #endif
      94         206 : }
      95             : 
      96             : /*
      97             :  * Indicate if we have loaded the root CA store to verify certificates
      98             :  */
      99             : bool
     100          60 : secure_loaded_verify_locations(void)
     101             : {
     102             : #ifdef USE_SSL
     103          60 :     return ssl_loaded_verify_locations;
     104             : #else
     105             :     return false;
     106             : #endif
     107             : }
     108             : 
     109             : /*
     110             :  *  Attempt to negotiate secure session.
     111             :  */
     112             : int
     113         228 : secure_open_server(Port *port)
     114             : {
     115         228 :     int         r = 0;
     116             : 
     117             : #ifdef USE_SSL
     118         228 :     r = be_tls_open_server(port);
     119             : 
     120         228 :     ereport(DEBUG2,
     121             :             (errmsg_internal("SSL connection from DN:\"%s\" CN:\"%s\"",
     122             :                              port->peer_dn ? port->peer_dn : "(anonymous)",
     123             :                              port->peer_cn ? port->peer_cn : "(anonymous)")));
     124             : #endif
     125             : 
     126         228 :     return r;
     127             : }
     128             : 
     129             : /*
     130             :  *  Close secure session.
     131             :  */
     132             : void
     133       18270 : secure_close(Port *port)
     134             : {
     135             : #ifdef USE_SSL
     136       18270 :     if (port->ssl_in_use)
     137         228 :         be_tls_close(port);
     138             : #endif
     139       18270 : }
     140             : 
     141             : /*
     142             :  *  Read data from a secure connection.
     143             :  */
     144             : ssize_t
     145     2541078 : secure_read(Port *port, void *ptr, size_t len)
     146             : {
     147             :     ssize_t     n;
     148             :     int         waitfor;
     149             : 
     150             :     /* Deal with any already-pending interrupt condition. */
     151     2541078 :     ProcessClientReadInterrupt(false);
     152             : 
     153     2751260 : retry:
     154             : #ifdef USE_SSL
     155     2751260 :     waitfor = 0;
     156     2751260 :     if (port->ssl_in_use)
     157             :     {
     158         684 :         n = be_tls_read(port, ptr, len, &waitfor);
     159             :     }
     160             :     else
     161             : #endif
     162             : #ifdef ENABLE_GSS
     163             :     if (port->gss && port->gss->enc)
     164             :     {
     165             :         n = be_gssapi_read(port, ptr, len);
     166             :         waitfor = WL_SOCKET_READABLE;
     167             :     }
     168             :     else
     169             : #endif
     170             :     {
     171     2750576 :         n = secure_raw_read(port, ptr, len);
     172     2750576 :         waitfor = WL_SOCKET_READABLE;
     173             :     }
     174             : 
     175             :     /* In blocking mode, wait until the socket is ready */
     176     2751260 :     if (n < 0 && !port->noblock && (errno == EWOULDBLOCK || errno == EAGAIN))
     177             :     {
     178             :         WaitEvent   event;
     179             : 
     180             :         Assert(waitfor);
     181             : 
     182      210240 :         ModifyWaitEvent(FeBeWaitSet, FeBeWaitSetSocketPos, waitfor, NULL);
     183             : 
     184      210240 :         WaitEventSetWait(FeBeWaitSet, -1 /* no timeout */ , &event, 1,
     185             :                          WAIT_EVENT_CLIENT_READ);
     186             : 
     187             :         /*
     188             :          * If the postmaster has died, it's not safe to continue running,
     189             :          * because it is the postmaster's job to kill us if some other backend
     190             :          * exits uncleanly.  Moreover, we won't run very well in this state;
     191             :          * helper processes like walwriter and the bgwriter will exit, so
     192             :          * performance may be poor.  Finally, if we don't exit, pg_ctl will be
     193             :          * unable to restart the postmaster without manual intervention, so no
     194             :          * new connections can be accepted.  Exiting clears the deck for a
     195             :          * postmaster restart.
     196             :          *
     197             :          * (Note that we only make this check when we would otherwise sleep on
     198             :          * our latch.  We might still continue running for a while if the
     199             :          * postmaster is killed in mid-query, or even through multiple queries
     200             :          * if we never have to wait for read.  We don't want to burn too many
     201             :          * cycles checking for this very rare condition, and this should cause
     202             :          * us to exit quickly in most cases.)
     203             :          */
     204      210240 :         if (event.events & WL_POSTMASTER_DEATH)
     205           0 :             ereport(FATAL,
     206             :                     (errcode(ERRCODE_ADMIN_SHUTDOWN),
     207             :                      errmsg("terminating connection due to unexpected postmaster exit")));
     208             : 
     209             :         /* Handle interrupt. */
     210      210240 :         if (event.events & WL_LATCH_SET)
     211             :         {
     212       15702 :             ResetLatch(MyLatch);
     213       15702 :             ProcessClientReadInterrupt(true);
     214             : 
     215             :             /*
     216             :              * We'll retry the read. Most likely it will return immediately
     217             :              * because there's still no data available, and we'll wait for the
     218             :              * socket to become ready again.
     219             :              */
     220             :         }
     221      210222 :         goto retry;
     222             :     }
     223             : 
     224             :     /*
     225             :      * Process interrupts that happened during a successful (or non-blocking,
     226             :      * or hard-failed) read.
     227             :      */
     228     2541020 :     ProcessClientReadInterrupt(false);
     229             : 
     230     2541020 :     return n;
     231             : }
     232             : 
     233             : ssize_t
     234     2754294 : secure_raw_read(Port *port, void *ptr, size_t len)
     235             : {
     236             :     ssize_t     n;
     237             : 
     238             :     /*
     239             :      * Try to read from the socket without blocking. If it succeeds we're
     240             :      * done, otherwise we'll wait for the socket using the latch mechanism.
     241             :      */
     242             : #ifdef WIN32
     243             :     pgwin32_noblock = true;
     244             : #endif
     245     2754294 :     n = recv(port->sock, ptr, len, 0);
     246             : #ifdef WIN32
     247             :     pgwin32_noblock = false;
     248             : #endif
     249             : 
     250     2754294 :     return n;
     251             : }
     252             : 
     253             : 
     254             : /*
     255             :  *  Write data to a secure connection.
     256             :  */
     257             : ssize_t
     258     1753380 : secure_write(Port *port, void *ptr, size_t len)
     259             : {
     260             :     ssize_t     n;
     261             :     int         waitfor;
     262             : 
     263             :     /* Deal with any already-pending interrupt condition. */
     264     1753380 :     ProcessClientWriteInterrupt(false);
     265             : 
     266     1770490 : retry:
     267     1770490 :     waitfor = 0;
     268             : #ifdef USE_SSL
     269     1770490 :     if (port->ssl_in_use)
     270             :     {
     271         338 :         n = be_tls_write(port, ptr, len, &waitfor);
     272             :     }
     273             :     else
     274             : #endif
     275             : #ifdef ENABLE_GSS
     276             :     if (port->gss && port->gss->enc)
     277             :     {
     278             :         n = be_gssapi_write(port, ptr, len);
     279             :         waitfor = WL_SOCKET_WRITEABLE;
     280             :     }
     281             :     else
     282             : #endif
     283             :     {
     284     1770152 :         n = secure_raw_write(port, ptr, len);
     285     1770152 :         waitfor = WL_SOCKET_WRITEABLE;
     286             :     }
     287             : 
     288     1770490 :     if (n < 0 && !port->noblock && (errno == EWOULDBLOCK || errno == EAGAIN))
     289             :     {
     290             :         WaitEvent   event;
     291             : 
     292             :         Assert(waitfor);
     293             : 
     294       17110 :         ModifyWaitEvent(FeBeWaitSet, FeBeWaitSetSocketPos, waitfor, NULL);
     295             : 
     296       17110 :         WaitEventSetWait(FeBeWaitSet, -1 /* no timeout */ , &event, 1,
     297             :                          WAIT_EVENT_CLIENT_WRITE);
     298             : 
     299             :         /* See comments in secure_read. */
     300       17110 :         if (event.events & WL_POSTMASTER_DEATH)
     301           0 :             ereport(FATAL,
     302             :                     (errcode(ERRCODE_ADMIN_SHUTDOWN),
     303             :                      errmsg("terminating connection due to unexpected postmaster exit")));
     304             : 
     305             :         /* Handle interrupt. */
     306       17110 :         if (event.events & WL_LATCH_SET)
     307             :         {
     308          20 :             ResetLatch(MyLatch);
     309          20 :             ProcessClientWriteInterrupt(true);
     310             : 
     311             :             /*
     312             :              * We'll retry the write. Most likely it will return immediately
     313             :              * because there's still no buffer space available, and we'll wait
     314             :              * for the socket to become ready again.
     315             :              */
     316             :         }
     317       17110 :         goto retry;
     318             :     }
     319             : 
     320             :     /*
     321             :      * Process interrupts that happened during a successful (or non-blocking,
     322             :      * or hard-failed) write.
     323             :      */
     324     1753380 :     ProcessClientWriteInterrupt(false);
     325             : 
     326     1753380 :     return n;
     327             : }
     328             : 
     329             : ssize_t
     330     1771504 : secure_raw_write(Port *port, const void *ptr, size_t len)
     331             : {
     332             :     ssize_t     n;
     333             : 
     334             : #ifdef WIN32
     335             :     pgwin32_noblock = true;
     336             : #endif
     337     1771504 :     n = send(port->sock, ptr, len, 0);
     338             : #ifdef WIN32
     339             :     pgwin32_noblock = false;
     340             : #endif
     341             : 
     342     1771504 :     return n;
     343             : }

Generated by: LCOV version 1.14