LCOV - code coverage report
Current view: top level - src/backend/tcop - backend_startup.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 48.7 % 339 165
Test Date: 2026-01-26 10:56:24 Functions: 63.6 % 11 7
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 16.4 % 348 57

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * backend_startup.c
       4                 :             :  *        Backend startup code
       5                 :             :  *
       6                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
       8                 :             :  *
       9                 :             :  *
      10                 :             :  * IDENTIFICATION
      11                 :             :  *        src/backend/tcop/backend_startup.c
      12                 :             :  *
      13                 :             :  *-------------------------------------------------------------------------
      14                 :             :  */
      15                 :             : 
      16                 :             : #include "postgres.h"
      17                 :             : 
      18                 :             : #include <unistd.h>
      19                 :             : 
      20                 :             : #include "access/xlog.h"
      21                 :             : #include "access/xlogrecovery.h"
      22                 :             : #include "common/ip.h"
      23                 :             : #include "common/string.h"
      24                 :             : #include "libpq/libpq.h"
      25                 :             : #include "libpq/libpq-be.h"
      26                 :             : #include "libpq/pqformat.h"
      27                 :             : #include "libpq/pqsignal.h"
      28                 :             : #include "miscadmin.h"
      29                 :             : #include "postmaster/postmaster.h"
      30                 :             : #include "replication/walsender.h"
      31                 :             : #include "storage/fd.h"
      32                 :             : #include "storage/ipc.h"
      33                 :             : #include "storage/procsignal.h"
      34                 :             : #include "storage/proc.h"
      35                 :             : #include "tcop/backend_startup.h"
      36                 :             : #include "tcop/tcopprot.h"
      37                 :             : #include "utils/builtins.h"
      38                 :             : #include "utils/guc_hooks.h"
      39                 :             : #include "utils/injection_point.h"
      40                 :             : #include "utils/memutils.h"
      41                 :             : #include "utils/ps_status.h"
      42                 :             : #include "utils/timeout.h"
      43                 :             : #include "utils/varlena.h"
      44                 :             : 
      45                 :             : /* GUCs */
      46                 :             : bool            Trace_connection_negotiation = false;
      47                 :             : uint32          log_connections = 0;
      48                 :             : char       *log_connections_string = NULL;
      49                 :             : 
      50                 :             : /* Other globals */
      51                 :             : 
      52                 :             : /*
      53                 :             :  * ConnectionTiming stores timestamps of various points in connection
      54                 :             :  * establishment and setup.
      55                 :             :  * ready_for_use is initialized to a special value here so we can check if
      56                 :             :  * we've already set it before doing so in PostgresMain().
      57                 :             :  */
      58                 :             : ConnectionTiming conn_timing = {.ready_for_use = TIMESTAMP_MINUS_INFINITY};
      59                 :             : 
      60                 :             : static void BackendInitialize(ClientSocket *client_sock, CAC_state cac);
      61                 :             : static int      ProcessSSLStartup(Port *port);
      62                 :             : static int      ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done);
      63                 :             : static void ProcessCancelRequestPacket(Port *port, void *pkt, int pktlen);
      64                 :             : static void SendNegotiateProtocolVersion(List *unrecognized_protocol_options);
      65                 :             : static void process_startup_packet_die(SIGNAL_ARGS);
      66                 :             : static void StartupPacketTimeoutHandler(void);
      67                 :             : static bool validate_log_connections_options(List *elemlist, uint32 *flags);
      68                 :             : 
      69                 :             : /*
      70                 :             :  * Entry point for a new backend process.
      71                 :             :  *
      72                 :             :  * Initialize the connection, read the startup packet, authenticate the
      73                 :             :  * client, and start the main processing loop.
      74                 :             :  */
      75                 :             : void
      76                 :         315 : BackendMain(const void *startup_data, size_t startup_data_len)
      77                 :             : {
      78                 :         315 :         const BackendStartupData *bsdata = startup_data;
      79                 :             : 
      80         [ +  - ]:         315 :         Assert(startup_data_len == sizeof(BackendStartupData));
      81         [ +  - ]:         315 :         Assert(MyClientSocket != NULL);
      82                 :             : 
      83                 :             : #ifdef EXEC_BACKEND
      84                 :             : 
      85                 :             :         /*
      86                 :             :          * Need to reinitialize the SSL library in the backend, since the context
      87                 :             :          * structures contain function pointers and cannot be passed through the
      88                 :             :          * parameter file.
      89                 :             :          *
      90                 :             :          * If for some reason reload fails (maybe the user installed broken key
      91                 :             :          * files), soldier on without SSL; that's better than all connections
      92                 :             :          * becoming impossible.
      93                 :             :          *
      94                 :             :          * XXX should we do this in all child processes?  For the moment it's
      95                 :             :          * enough to do it in backend children.
      96                 :             :          */
      97                 :             : #ifdef USE_SSL
      98                 :             :         if (EnableSSL)
      99                 :             :         {
     100                 :             :                 if (secure_initialize(false) == 0)
     101                 :             :                         LoadedSSL = true;
     102                 :             :                 else
     103                 :             :                         ereport(LOG,
     104                 :             :                                         (errmsg("SSL configuration could not be loaded in child process")));
     105                 :             :         }
     106                 :             : #endif
     107                 :             : #endif
     108                 :             : 
     109                 :             :         /* Perform additional initialization and collect startup packet */
     110                 :         315 :         BackendInitialize(MyClientSocket, bsdata->canAcceptConnections);
     111                 :             : 
     112                 :             :         /*
     113                 :             :          * Create a per-backend PGPROC struct in shared memory.  We must do this
     114                 :             :          * before we can use LWLocks or access any shared memory.
     115                 :             :          */
     116                 :         315 :         InitProcess();
     117                 :             : 
     118                 :             :         /*
     119                 :             :          * Make sure we aren't in PostmasterContext anymore.  (We can't delete it
     120                 :             :          * just yet, though, because InitPostgres will need the HBA data.)
     121                 :             :          */
     122                 :         315 :         MemoryContextSwitchTo(TopMemoryContext);
     123                 :             : 
     124                 :         315 :         PostgresMain(MyProcPort->database_name, MyProcPort->user_name);
     125                 :             : }
     126                 :             : 
     127                 :             : 
     128                 :             : /*
     129                 :             :  * BackendInitialize -- initialize an interactive (postmaster-child)
     130                 :             :  *                              backend process, and collect the client's startup packet.
     131                 :             :  *
     132                 :             :  * returns: nothing.  Will not return at all if there's any failure.
     133                 :             :  *
     134                 :             :  * Note: this code does not depend on having any access to shared memory.
     135                 :             :  * Indeed, our approach to SIGTERM/timeout handling *requires* that
     136                 :             :  * shared memory not have been touched yet; see comments within.
     137                 :             :  * In the EXEC_BACKEND case, we are physically attached to shared memory
     138                 :             :  * but have not yet set up most of our local pointers to shmem structures.
     139                 :             :  */
     140                 :             : static void
     141                 :         315 : BackendInitialize(ClientSocket *client_sock, CAC_state cac)
     142                 :             : {
     143                 :         315 :         int                     status;
     144                 :         315 :         int                     ret;
     145                 :         315 :         Port       *port;
     146                 :         315 :         char            remote_host[NI_MAXHOST];
     147                 :         315 :         char            remote_port[NI_MAXSERV];
     148                 :         315 :         StringInfoData ps_data;
     149                 :         315 :         MemoryContext oldcontext;
     150                 :             : 
     151                 :             :         /* Tell fd.c about the long-lived FD associated with the client_sock */
     152                 :         315 :         ReserveExternalFD();
     153                 :             : 
     154                 :             :         /*
     155                 :             :          * PreAuthDelay is a debugging aid for investigating problems in the
     156                 :             :          * authentication cycle: it can be set in postgresql.conf to allow time to
     157                 :             :          * attach to the newly-forked backend with a debugger.  (See also
     158                 :             :          * PostAuthDelay, which we allow clients to pass through PGOPTIONS, but it
     159                 :             :          * is not honored until after authentication.)
     160                 :             :          */
     161         [ +  - ]:         315 :         if (PreAuthDelay > 0)
     162                 :           0 :                 pg_usleep(PreAuthDelay * 1000000L);
     163                 :             : 
     164                 :             :         /* This flag will remain set until InitPostgres finishes authentication */
     165                 :         315 :         ClientAuthInProgress = true;    /* limit visibility of log messages */
     166                 :             : 
     167                 :             :         /*
     168                 :             :          * Initialize libpq and enable reporting of ereport errors to the client.
     169                 :             :          * Must do this now because authentication uses libpq to send messages.
     170                 :             :          *
     171                 :             :          * The Port structure and all data structures attached to it are allocated
     172                 :             :          * in TopMemoryContext, so that they survive into PostgresMain execution.
     173                 :             :          * We need not worry about leaking this storage on failure, since we
     174                 :             :          * aren't in the postmaster process anymore.
     175                 :             :          */
     176                 :         315 :         oldcontext = MemoryContextSwitchTo(TopMemoryContext);
     177                 :         315 :         port = MyProcPort = pq_init(client_sock);
     178                 :         315 :         MemoryContextSwitchTo(oldcontext);
     179                 :             : 
     180                 :         315 :         whereToSendOutput = DestRemote; /* now safe to ereport to client */
     181                 :             : 
     182                 :             :         /* set these to empty in case they are needed before we set them up */
     183                 :         315 :         port->remote_host = "";
     184                 :         315 :         port->remote_port = "";
     185                 :             : 
     186                 :             :         /*
     187                 :             :          * We arrange to do _exit(1) if we receive SIGTERM or timeout while trying
     188                 :             :          * to collect the startup packet; while SIGQUIT results in _exit(2).
     189                 :             :          * Otherwise the postmaster cannot shutdown the database FAST or IMMED
     190                 :             :          * cleanly if a buggy client fails to send the packet promptly.
     191                 :             :          *
     192                 :             :          * Exiting with _exit(1) is only possible because we have not yet touched
     193                 :             :          * shared memory; therefore no outside-the-process state needs to get
     194                 :             :          * cleaned up.
     195                 :             :          */
     196                 :         315 :         pqsignal(SIGTERM, process_startup_packet_die);
     197                 :             :         /* SIGQUIT handler was already set up by InitPostmasterChild */
     198                 :         315 :         InitializeTimeouts();           /* establishes SIGALRM handler */
     199                 :         315 :         sigprocmask(SIG_SETMASK, &StartupBlockSig, NULL);
     200                 :             : 
     201                 :             :         /*
     202                 :             :          * Get the remote host name and port for logging and status display.
     203                 :             :          */
     204                 :         315 :         remote_host[0] = '\0';
     205                 :         315 :         remote_port[0] = '\0';
     206                 :         630 :         if ((ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
     207                 :         315 :                                                                   remote_host, sizeof(remote_host),
     208                 :         315 :                                                                   remote_port, sizeof(remote_port),
     209   [ +  -  +  - ]:         630 :                                                                   (log_hostname ? 0 : NI_NUMERICHOST) | NI_NUMERICSERV)) != 0)
     210   [ #  #  #  # ]:           0 :                 ereport(WARNING,
     211                 :             :                                 (errmsg_internal("pg_getnameinfo_all() failed: %s",
     212                 :             :                                                                  gai_strerror(ret))));
     213                 :             : 
     214                 :             :         /*
     215                 :             :          * Save remote_host and remote_port in port structure (after this, they
     216                 :             :          * will appear in log_line_prefix data for log messages).
     217                 :             :          */
     218                 :         315 :         port->remote_host = MemoryContextStrdup(TopMemoryContext, remote_host);
     219                 :         315 :         port->remote_port = MemoryContextStrdup(TopMemoryContext, remote_port);
     220                 :             : 
     221                 :             :         /* And now we can log that the connection was received, if enabled */
     222         [ +  - ]:         315 :         if (log_connections & LOG_CONNECTION_RECEIPT)
     223                 :             :         {
     224         [ #  # ]:           0 :                 if (remote_port[0])
     225   [ #  #  #  # ]:           0 :                         ereport(LOG,
     226                 :             :                                         (errmsg("connection received: host=%s port=%s",
     227                 :             :                                                         remote_host,
     228                 :             :                                                         remote_port)));
     229                 :             :                 else
     230   [ #  #  #  # ]:           0 :                         ereport(LOG,
     231                 :             :                                         (errmsg("connection received: host=%s",
     232                 :             :                                                         remote_host)));
     233                 :           0 :         }
     234                 :             : 
     235                 :             :         /* For testing client error handling */
     236                 :             : #ifdef USE_INJECTION_POINTS
     237                 :             :         INJECTION_POINT("backend-initialize", NULL);
     238                 :             :         if (IS_INJECTION_POINT_ATTACHED("backend-initialize-v2-error"))
     239                 :             :         {
     240                 :             :                 /*
     241                 :             :                  * This simulates an early error from a pre-v14 server, which used the
     242                 :             :                  * version 2 protocol for any errors that occurred before processing
     243                 :             :                  * the startup packet.
     244                 :             :                  */
     245                 :             :                 FrontendProtocol = PG_PROTOCOL(2, 0);
     246                 :             :                 elog(FATAL, "protocol version 2 error triggered");
     247                 :             :         }
     248                 :             : #endif
     249                 :             : 
     250                 :             :         /*
     251                 :             :          * If we did a reverse lookup to name, we might as well save the results
     252                 :             :          * rather than possibly repeating the lookup during authentication.
     253                 :             :          *
     254                 :             :          * Note that we don't want to specify NI_NAMEREQD above, because then we'd
     255                 :             :          * get nothing useful for a client without an rDNS entry.  Therefore, we
     256                 :             :          * must check whether we got a numeric IPv4 or IPv6 address, and not save
     257                 :             :          * it into remote_hostname if so.  (This test is conservative and might
     258                 :             :          * sometimes classify a hostname as numeric, but an error in that
     259                 :             :          * direction is safe; it only results in a possible extra lookup.)
     260                 :             :          */
     261         [ -  + ]:         315 :         if (log_hostname &&
     262         [ #  # ]:           0 :                 ret == 0 &&
     263   [ #  #  #  # ]:           0 :                 strspn(remote_host, "0123456789.") < strlen(remote_host) &&
     264                 :           0 :                 strspn(remote_host, "0123456789ABCDEFabcdef:") < strlen(remote_host))
     265                 :             :         {
     266                 :           0 :                 port->remote_hostname = MemoryContextStrdup(TopMemoryContext, remote_host);
     267                 :           0 :         }
     268                 :             : 
     269                 :             :         /*
     270                 :             :          * Ready to begin client interaction.  We will give up and _exit(1) after
     271                 :             :          * a time delay, so that a broken client can't hog a connection
     272                 :             :          * indefinitely.  PreAuthDelay and any DNS interactions above don't count
     273                 :             :          * against the time limit.
     274                 :             :          *
     275                 :             :          * Note: AuthenticationTimeout is applied here while waiting for the
     276                 :             :          * startup packet, and then again in InitPostgres for the duration of any
     277                 :             :          * authentication operations.  So a hostile client could tie up the
     278                 :             :          * process for nearly twice AuthenticationTimeout before we kick him off.
     279                 :             :          *
     280                 :             :          * Note: because PostgresMain will call InitializeTimeouts again, the
     281                 :             :          * registration of STARTUP_PACKET_TIMEOUT will be lost.  This is okay
     282                 :             :          * since we never use it again after this function.
     283                 :             :          */
     284                 :         315 :         RegisterTimeout(STARTUP_PACKET_TIMEOUT, StartupPacketTimeoutHandler);
     285                 :         315 :         enable_timeout_after(STARTUP_PACKET_TIMEOUT, AuthenticationTimeout * 1000);
     286                 :             : 
     287                 :             :         /* Handle direct SSL handshake */
     288                 :         315 :         status = ProcessSSLStartup(port);
     289                 :             : 
     290                 :             :         /*
     291                 :             :          * Receive the startup packet (which might turn out to be a cancel request
     292                 :             :          * packet).
     293                 :             :          */
     294         [ -  + ]:         315 :         if (status == STATUS_OK)
     295                 :         315 :                 status = ProcessStartupPacket(port, false, false);
     296                 :             : 
     297                 :             :         /*
     298                 :             :          * If we're going to reject the connection due to database state, say so
     299                 :             :          * now instead of wasting cycles on an authentication exchange. (This also
     300                 :             :          * allows a pg_ping utility to be written.)
     301                 :             :          */
     302         [ -  + ]:         315 :         if (status == STATUS_OK)
     303                 :             :         {
     304   [ +  -  -  -  :         315 :                 switch (cac)
                   -  - ]
     305                 :             :                 {
     306                 :             :                         case CAC_STARTUP:
     307   [ #  #  #  # ]:           0 :                                 ereport(FATAL,
     308                 :             :                                                 (errcode(ERRCODE_CANNOT_CONNECT_NOW),
     309                 :             :                                                  errmsg("the database system is starting up")));
     310                 :           0 :                                 break;
     311                 :             :                         case CAC_NOTHOTSTANDBY:
     312         [ #  # ]:           0 :                                 if (!EnableHotStandby)
     313   [ #  #  #  # ]:           0 :                                         ereport(FATAL,
     314                 :             :                                                         (errcode(ERRCODE_CANNOT_CONNECT_NOW),
     315                 :             :                                                          errmsg("the database system is not accepting connections"),
     316                 :             :                                                          errdetail("Hot standby mode is disabled.")));
     317         [ #  # ]:           0 :                                 else if (reachedConsistency)
     318   [ #  #  #  # ]:           0 :                                         ereport(FATAL,
     319                 :             :                                                         (errcode(ERRCODE_CANNOT_CONNECT_NOW),
     320                 :             :                                                          errmsg("the database system is not yet accepting connections"),
     321                 :             :                                                          errdetail("Recovery snapshot is not yet ready for hot standby."),
     322                 :             :                                                          errhint("To enable hot standby, close write transactions with more than %d subtransactions on the primary server.",
     323                 :             :                                                                          PGPROC_MAX_CACHED_SUBXIDS)));
     324                 :             :                                 else
     325   [ #  #  #  # ]:           0 :                                         ereport(FATAL,
     326                 :             :                                                         (errcode(ERRCODE_CANNOT_CONNECT_NOW),
     327                 :             :                                                          errmsg("the database system is not yet accepting connections"),
     328                 :             :                                                          errdetail("Consistent recovery state has not been yet reached.")));
     329                 :           0 :                                 break;
     330                 :             :                         case CAC_SHUTDOWN:
     331   [ #  #  #  # ]:           0 :                                 ereport(FATAL,
     332                 :             :                                                 (errcode(ERRCODE_CANNOT_CONNECT_NOW),
     333                 :             :                                                  errmsg("the database system is shutting down")));
     334                 :           0 :                                 break;
     335                 :             :                         case CAC_RECOVERY:
     336   [ #  #  #  # ]:           0 :                                 ereport(FATAL,
     337                 :             :                                                 (errcode(ERRCODE_CANNOT_CONNECT_NOW),
     338                 :             :                                                  errmsg("the database system is in recovery mode")));
     339                 :           0 :                                 break;
     340                 :             :                         case CAC_TOOMANY:
     341   [ #  #  #  # ]:           0 :                                 ereport(FATAL,
     342                 :             :                                                 (errcode(ERRCODE_TOO_MANY_CONNECTIONS),
     343                 :             :                                                  errmsg("sorry, too many clients already")));
     344                 :           0 :                                 break;
     345                 :             :                         case CAC_OK:
     346                 :             :                                 break;
     347                 :             :                 }
     348                 :         315 :         }
     349                 :             : 
     350                 :             :         /*
     351                 :             :          * Disable the timeout, and prevent SIGTERM again.
     352                 :             :          */
     353                 :         315 :         disable_timeout(STARTUP_PACKET_TIMEOUT, false);
     354                 :         315 :         sigprocmask(SIG_SETMASK, &BlockSig, NULL);
     355                 :             : 
     356                 :             :         /*
     357                 :             :          * As a safety check that nothing in startup has yet performed
     358                 :             :          * shared-memory modifications that would need to be undone if we had
     359                 :             :          * exited through SIGTERM or timeout above, check that no on_shmem_exit
     360                 :             :          * handlers have been registered yet.  (This isn't terribly bulletproof,
     361                 :             :          * since someone might misuse an on_proc_exit handler for shmem cleanup,
     362                 :             :          * but it's a cheap and helpful check.  We cannot disallow on_proc_exit
     363                 :             :          * handlers unfortunately, since pq_init() already registered one.)
     364                 :             :          */
     365                 :         315 :         check_on_shmem_exit_lists_are_empty();
     366                 :             : 
     367                 :             :         /*
     368                 :             :          * Stop here if it was bad or a cancel packet.  ProcessStartupPacket
     369                 :             :          * already did any appropriate error reporting.
     370                 :             :          */
     371         [ +  - ]:         315 :         if (status != STATUS_OK)
     372                 :           0 :                 proc_exit(0);
     373                 :             : 
     374                 :             :         /*
     375                 :             :          * Now that we have the user and database name, we can set the process
     376                 :             :          * title for ps.  It's good to do this as early as possible in startup.
     377                 :             :          */
     378                 :         315 :         initStringInfo(&ps_data);
     379         [ +  - ]:         315 :         if (am_walsender)
     380                 :           0 :                 appendStringInfo(&ps_data, "%s ", GetBackendTypeDesc(B_WAL_SENDER));
     381                 :         315 :         appendStringInfo(&ps_data, "%s ", port->user_name);
     382         [ -  + ]:         315 :         if (port->database_name[0] != '\0')
     383                 :         315 :                 appendStringInfo(&ps_data, "%s ", port->database_name);
     384                 :         315 :         appendStringInfoString(&ps_data, port->remote_host);
     385         [ +  - ]:         315 :         if (port->remote_port[0] != '\0')
     386                 :           0 :                 appendStringInfo(&ps_data, "(%s)", port->remote_port);
     387                 :             : 
     388                 :         315 :         init_ps_display(ps_data.data);
     389                 :         315 :         pfree(ps_data.data);
     390                 :             : 
     391                 :         315 :         set_ps_display("initializing");
     392                 :         315 : }
     393                 :             : 
     394                 :             : /*
     395                 :             :  * Check for a direct SSL connection.
     396                 :             :  *
     397                 :             :  * This happens before the startup packet so we are careful not to actually
     398                 :             :  * read any bytes from the stream if it's not a direct SSL connection.
     399                 :             :  */
     400                 :             : static int
     401                 :         315 : ProcessSSLStartup(Port *port)
     402                 :             : {
     403                 :         315 :         int                     firstbyte;
     404                 :             : 
     405         [ +  - ]:         315 :         Assert(!port->ssl_in_use);
     406                 :             : 
     407                 :         315 :         pq_startmsgread();
     408                 :         315 :         firstbyte = pq_peekbyte();
     409                 :         315 :         pq_endmsgread();
     410         [ +  - ]:         315 :         if (firstbyte == EOF)
     411                 :             :         {
     412                 :             :                 /*
     413                 :             :                  * Like in ProcessStartupPacket, if we get no data at all, don't
     414                 :             :                  * clutter the log with a complaint.
     415                 :             :                  */
     416                 :           0 :                 return STATUS_ERROR;
     417                 :             :         }
     418                 :             : 
     419         [ +  - ]:         315 :         if (firstbyte != 0x16)
     420                 :             :         {
     421                 :             :                 /* Not an SSL handshake message */
     422                 :         315 :                 return STATUS_OK;
     423                 :             :         }
     424                 :             : 
     425                 :             :         /*
     426                 :             :          * First byte indicates standard SSL handshake message
     427                 :             :          *
     428                 :             :          * (It can't be a Postgres startup length because in network byte order
     429                 :             :          * that would be a startup packet hundreds of megabytes long)
     430                 :             :          */
     431                 :             : 
     432                 :             : #ifdef USE_SSL
     433   [ #  #  #  # ]:           0 :         if (!LoadedSSL || port->laddr.addr.ss_family == AF_UNIX)
     434                 :             :         {
     435                 :             :                 /* SSL not supported */
     436                 :           0 :                 goto reject;
     437                 :             :         }
     438                 :             : 
     439         [ #  # ]:           0 :         if (secure_open_server(port) == -1)
     440                 :             :         {
     441                 :             :                 /*
     442                 :             :                  * we assume secure_open_server() sent an appropriate TLS alert
     443                 :             :                  * already
     444                 :             :                  */
     445                 :           0 :                 goto reject;
     446                 :             :         }
     447         [ #  # ]:           0 :         Assert(port->ssl_in_use);
     448                 :             : 
     449         [ #  # ]:           0 :         if (!port->alpn_used)
     450                 :             :         {
     451   [ #  #  #  # ]:           0 :                 ereport(COMMERROR,
     452                 :             :                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     453                 :             :                                  errmsg("received direct SSL connection request without ALPN protocol negotiation extension")));
     454                 :           0 :                 goto reject;
     455                 :             :         }
     456                 :             : 
     457         [ #  # ]:           0 :         if (Trace_connection_negotiation)
     458   [ #  #  #  # ]:           0 :                 ereport(LOG,
     459                 :             :                                 (errmsg("direct SSL connection accepted")));
     460                 :           0 :         return STATUS_OK;
     461                 :             : #else
     462                 :             :         /* SSL not supported by this build */
     463                 :             :         goto reject;
     464                 :             : #endif
     465                 :             : 
     466                 :             : reject:
     467         [ #  # ]:           0 :         if (Trace_connection_negotiation)
     468   [ #  #  #  # ]:           0 :                 ereport(LOG,
     469                 :             :                                 (errmsg("direct SSL connection rejected")));
     470                 :           0 :         return STATUS_ERROR;
     471                 :         315 : }
     472                 :             : 
     473                 :             : /*
     474                 :             :  * Read a client's startup packet and do something according to it.
     475                 :             :  *
     476                 :             :  * Returns STATUS_OK or STATUS_ERROR, or might call ereport(FATAL) and
     477                 :             :  * not return at all.
     478                 :             :  *
     479                 :             :  * (Note that ereport(FATAL) stuff is sent to the client, so only use it
     480                 :             :  * if that's what you want.  Return STATUS_ERROR if you don't want to
     481                 :             :  * send anything to the client, which would typically be appropriate
     482                 :             :  * if we detect a communications failure.)
     483                 :             :  *
     484                 :             :  * Set ssl_done and/or gss_done when negotiation of an encrypted layer
     485                 :             :  * (currently, TLS or GSSAPI) is completed. A successful negotiation of either
     486                 :             :  * encryption layer sets both flags, but a rejected negotiation sets only the
     487                 :             :  * flag for that layer, since the client may wish to try the other one. We
     488                 :             :  * should make no assumption here about the order in which the client may make
     489                 :             :  * requests.
     490                 :             :  */
     491                 :             : static int
     492                 :         315 : ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done)
     493                 :             : {
     494                 :         315 :         int32           len;
     495                 :         315 :         char       *buf = NULL;
     496                 :         315 :         ProtocolVersion proto;
     497                 :         315 :         MemoryContext oldcontext;
     498                 :             : 
     499                 :         315 :         pq_startmsgread();
     500                 :             : 
     501                 :             :         /*
     502                 :             :          * Grab the first byte of the length word separately, so that we can tell
     503                 :             :          * whether we have no data at all or an incomplete packet.  (This might
     504                 :             :          * sound inefficient, but it's not really, because of buffering in
     505                 :             :          * pqcomm.c.)
     506                 :             :          */
     507         [ +  - ]:         315 :         if (pq_getbytes(&len, 1) == EOF)
     508                 :             :         {
     509                 :             :                 /*
     510                 :             :                  * If we get no data at all, don't clutter the log with a complaint;
     511                 :             :                  * such cases often occur for legitimate reasons.  An example is that
     512                 :             :                  * we might be here after responding to NEGOTIATE_SSL_CODE, and if the
     513                 :             :                  * client didn't like our response, it'll probably just drop the
     514                 :             :                  * connection.  Service-monitoring software also often just opens and
     515                 :             :                  * closes a connection without sending anything.  (So do port
     516                 :             :                  * scanners, which may be less benign, but it's not really our job to
     517                 :             :                  * notice those.)
     518                 :             :                  */
     519                 :           0 :                 goto fail;
     520                 :             :         }
     521                 :             : 
     522         [ +  - ]:         315 :         if (pq_getbytes(((char *) &len) + 1, 3) == EOF)
     523                 :             :         {
     524                 :             :                 /* Got a partial length word, so bleat about that */
     525   [ #  #  #  # ]:           0 :                 if (!ssl_done && !gss_done)
     526   [ #  #  #  # ]:           0 :                         ereport(COMMERROR,
     527                 :             :                                         (errcode(ERRCODE_PROTOCOL_VIOLATION),
     528                 :             :                                          errmsg("incomplete startup packet")));
     529                 :           0 :                 goto fail;
     530                 :             :         }
     531                 :             : 
     532                 :         315 :         len = pg_ntoh32(len);
     533                 :         315 :         len -= 4;
     534                 :             : 
     535   [ +  -  -  + ]:         315 :         if (len < (int32) sizeof(ProtocolVersion) ||
     536                 :         315 :                 len > MAX_STARTUP_PACKET_LENGTH)
     537                 :             :         {
     538   [ #  #  #  # ]:           0 :                 ereport(COMMERROR,
     539                 :             :                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     540                 :             :                                  errmsg("invalid length of startup packet")));
     541                 :           0 :                 goto fail;
     542                 :             :         }
     543                 :             : 
     544                 :             :         /*
     545                 :             :          * Allocate space to hold the startup packet, plus one extra byte that's
     546                 :             :          * initialized to be zero.  This ensures we will have null termination of
     547                 :             :          * all strings inside the packet.
     548                 :             :          */
     549                 :         315 :         buf = palloc(len + 1);
     550                 :         315 :         buf[len] = '\0';
     551                 :             : 
     552         [ +  - ]:         315 :         if (pq_getbytes(buf, len) == EOF)
     553                 :             :         {
     554   [ #  #  #  # ]:           0 :                 ereport(COMMERROR,
     555                 :             :                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     556                 :             :                                  errmsg("incomplete startup packet")));
     557                 :           0 :                 goto fail;
     558                 :             :         }
     559                 :         315 :         pq_endmsgread();
     560                 :             : 
     561                 :             :         /*
     562                 :             :          * The first field is either a protocol version number or a special
     563                 :             :          * request code.
     564                 :             :          */
     565                 :         315 :         port->proto = proto = pg_ntoh32(*((ProtocolVersion *) buf));
     566                 :             : 
     567         [ -  + ]:         315 :         if (proto == CANCEL_REQUEST_CODE)
     568                 :             :         {
     569                 :           0 :                 ProcessCancelRequestPacket(port, buf, len);
     570                 :             :                 /* Not really an error, but we don't want to proceed further */
     571                 :           0 :                 goto fail;
     572                 :             :         }
     573                 :             : 
     574   [ -  +  #  # ]:         315 :         if (proto == NEGOTIATE_SSL_CODE && !ssl_done)
     575                 :             :         {
     576                 :           0 :                 char            SSLok;
     577                 :             : 
     578                 :             : #ifdef USE_SSL
     579                 :             : 
     580                 :             :                 /*
     581                 :             :                  * No SSL when disabled or on Unix sockets.
     582                 :             :                  *
     583                 :             :                  * Also no SSL negotiation if we already have a direct SSL connection
     584                 :             :                  */
     585   [ #  #  #  #  :           0 :                 if (!LoadedSSL || port->laddr.addr.ss_family == AF_UNIX || port->ssl_in_use)
                   #  # ]
     586                 :           0 :                         SSLok = 'N';
     587                 :             :                 else
     588                 :           0 :                         SSLok = 'S';            /* Support for SSL */
     589                 :             : #else
     590                 :             :                 SSLok = 'N';                    /* No support for SSL */
     591                 :             : #endif
     592                 :             : 
     593         [ #  # ]:           0 :                 if (Trace_connection_negotiation)
     594                 :             :                 {
     595         [ #  # ]:           0 :                         if (SSLok == 'S')
     596   [ #  #  #  # ]:           0 :                                 ereport(LOG,
     597                 :             :                                                 (errmsg("SSLRequest accepted")));
     598                 :             :                         else
     599   [ #  #  #  # ]:           0 :                                 ereport(LOG,
     600                 :             :                                                 (errmsg("SSLRequest rejected")));
     601                 :           0 :                 }
     602                 :             : 
     603         [ #  # ]:           0 :                 while (secure_write(port, &SSLok, 1) != 1)
     604                 :             :                 {
     605         [ #  # ]:           0 :                         if (errno == EINTR)
     606                 :           0 :                                 continue;               /* if interrupted, just retry */
     607   [ #  #  #  # ]:           0 :                         ereport(COMMERROR,
     608                 :             :                                         (errcode_for_socket_access(),
     609                 :             :                                          errmsg("failed to send SSL negotiation response: %m")));
     610                 :           0 :                         goto fail;                      /* close the connection */
     611                 :             :                 }
     612                 :             : 
     613                 :             : #ifdef USE_SSL
     614   [ #  #  #  # ]:           0 :                 if (SSLok == 'S' && secure_open_server(port) == -1)
     615                 :           0 :                         goto fail;
     616                 :             : #endif
     617                 :             : 
     618                 :           0 :                 pfree(buf);
     619                 :             : 
     620                 :             :                 /*
     621                 :             :                  * At this point we should have no data already buffered.  If we do,
     622                 :             :                  * it was received before we performed the SSL handshake, so it wasn't
     623                 :             :                  * encrypted and indeed may have been injected by a man-in-the-middle.
     624                 :             :                  * We report this case to the client.
     625                 :             :                  */
     626         [ #  # ]:           0 :                 if (pq_buffer_remaining_data() > 0)
     627   [ #  #  #  # ]:           0 :                         ereport(FATAL,
     628                 :             :                                         (errcode(ERRCODE_PROTOCOL_VIOLATION),
     629                 :             :                                          errmsg("received unencrypted data after SSL request"),
     630                 :             :                                          errdetail("This could be either a client-software bug or evidence of an attempted man-in-the-middle attack.")));
     631                 :             : 
     632                 :             :                 /*
     633                 :             :                  * regular startup packet, cancel, etc packet should follow, but not
     634                 :             :                  * another SSL negotiation request, and a GSS request should only
     635                 :             :                  * follow if SSL was rejected (client may negotiate in either order)
     636                 :             :                  */
     637                 :           0 :                 return ProcessStartupPacket(port, true, SSLok == 'S');
     638         [ #  # ]:           0 :         }
     639   [ -  +  #  # ]:         315 :         else if (proto == NEGOTIATE_GSS_CODE && !gss_done)
     640                 :             :         {
     641                 :           0 :                 char            GSSok = 'N';
     642                 :             : 
     643                 :             : #ifdef ENABLE_GSS
     644                 :             :                 /* No GSSAPI encryption when on Unix socket */
     645         [ #  # ]:           0 :                 if (port->laddr.addr.ss_family != AF_UNIX)
     646                 :           0 :                         GSSok = 'G';
     647                 :             : #endif
     648                 :             : 
     649         [ #  # ]:           0 :                 if (Trace_connection_negotiation)
     650                 :             :                 {
     651         [ #  # ]:           0 :                         if (GSSok == 'G')
     652   [ #  #  #  # ]:           0 :                                 ereport(LOG,
     653                 :             :                                                 (errmsg("GSSENCRequest accepted")));
     654                 :             :                         else
     655   [ #  #  #  # ]:           0 :                                 ereport(LOG,
     656                 :             :                                                 (errmsg("GSSENCRequest rejected")));
     657                 :           0 :                 }
     658                 :             : 
     659         [ #  # ]:           0 :                 while (secure_write(port, &GSSok, 1) != 1)
     660                 :             :                 {
     661         [ #  # ]:           0 :                         if (errno == EINTR)
     662                 :           0 :                                 continue;
     663   [ #  #  #  # ]:           0 :                         ereport(COMMERROR,
     664                 :             :                                         (errcode_for_socket_access(),
     665                 :             :                                          errmsg("failed to send GSSAPI negotiation response: %m")));
     666                 :           0 :                         goto fail;                      /* close the connection */
     667                 :             :                 }
     668                 :             : 
     669                 :             : #ifdef ENABLE_GSS
     670   [ #  #  #  # ]:           0 :                 if (GSSok == 'G' && secure_open_gssapi(port) == -1)
     671                 :           0 :                         goto fail;
     672                 :             : #endif
     673                 :             : 
     674                 :           0 :                 pfree(buf);
     675                 :             : 
     676                 :             :                 /*
     677                 :             :                  * At this point we should have no data already buffered.  If we do,
     678                 :             :                  * it was received before we performed the GSS handshake, so it wasn't
     679                 :             :                  * encrypted and indeed may have been injected by a man-in-the-middle.
     680                 :             :                  * We report this case to the client.
     681                 :             :                  */
     682         [ #  # ]:           0 :                 if (pq_buffer_remaining_data() > 0)
     683   [ #  #  #  # ]:           0 :                         ereport(FATAL,
     684                 :             :                                         (errcode(ERRCODE_PROTOCOL_VIOLATION),
     685                 :             :                                          errmsg("received unencrypted data after GSSAPI encryption request"),
     686                 :             :                                          errdetail("This could be either a client-software bug or evidence of an attempted man-in-the-middle attack.")));
     687                 :             : 
     688                 :             :                 /*
     689                 :             :                  * regular startup packet, cancel, etc packet should follow, but not
     690                 :             :                  * another GSS negotiation request, and an SSL request should only
     691                 :             :                  * follow if GSS was rejected (client may negotiate in either order)
     692                 :             :                  */
     693                 :           0 :                 return ProcessStartupPacket(port, GSSok == 'G', true);
     694                 :           0 :         }
     695                 :             : 
     696                 :             :         /* Could add additional special packet types here */
     697                 :             : 
     698                 :             :         /*
     699                 :             :          * Set FrontendProtocol now so that ereport() knows what format to send if
     700                 :             :          * we fail during startup. We use the protocol version requested by the
     701                 :             :          * client unless it's higher than the latest version we support. It's
     702                 :             :          * possible that error message fields might look different in newer
     703                 :             :          * protocol versions, but that's something those new clients should be
     704                 :             :          * able to deal with.
     705                 :             :          */
     706         [ +  - ]:         315 :         FrontendProtocol = Min(proto, PG_PROTOCOL_LATEST);
     707                 :             : 
     708                 :             :         /* Check that the major protocol version is in range. */
     709         [ +  - ]:         315 :         if (PG_PROTOCOL_MAJOR(proto) < PG_PROTOCOL_MAJOR(PG_PROTOCOL_EARLIEST) ||
     710                 :         315 :                 PG_PROTOCOL_MAJOR(proto) > PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST))
     711   [ #  #  #  # ]:           0 :                 ereport(FATAL,
     712                 :             :                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     713                 :             :                                  errmsg("unsupported frontend protocol %u.%u: server supports %u.0 to %u.%u",
     714                 :             :                                                 PG_PROTOCOL_MAJOR(proto), PG_PROTOCOL_MINOR(proto),
     715                 :             :                                                 PG_PROTOCOL_MAJOR(PG_PROTOCOL_EARLIEST),
     716                 :             :                                                 PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST),
     717                 :             :                                                 PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST))));
     718                 :             : 
     719                 :             :         /*
     720                 :             :          * Now fetch parameters out of startup packet and save them into the Port
     721                 :             :          * structure.
     722                 :             :          */
     723                 :         315 :         oldcontext = MemoryContextSwitchTo(TopMemoryContext);
     724                 :             : 
     725                 :             :         /* Handle protocol version 3 startup packet */
     726                 :             :         {
     727                 :         315 :                 int32           offset = sizeof(ProtocolVersion);
     728                 :         315 :                 List       *unrecognized_protocol_options = NIL;
     729                 :             : 
     730                 :             :                 /*
     731                 :             :                  * Scan packet body for name/option pairs.  We can assume any string
     732                 :             :                  * beginning within the packet body is null-terminated, thanks to
     733                 :             :                  * zeroing extra byte above.
     734                 :             :                  */
     735                 :         315 :                 port->guc_options = NIL;
     736                 :             : 
     737         [ -  + ]:        2139 :                 while (offset < len)
     738                 :             :                 {
     739                 :        2139 :                         char       *nameptr = buf + offset;
     740                 :        2139 :                         int32           valoffset;
     741                 :        2139 :                         char       *valptr;
     742                 :             : 
     743         [ +  + ]:        2139 :                         if (*nameptr == '\0')
     744                 :         315 :                                 break;                  /* found packet terminator */
     745                 :        1824 :                         valoffset = offset + strlen(nameptr) + 1;
     746         [ -  + ]:        1824 :                         if (valoffset >= len)
     747                 :           0 :                                 break;                  /* missing value, will complain below */
     748                 :        1824 :                         valptr = buf + valoffset;
     749                 :             : 
     750         [ +  + ]:        1824 :                         if (strcmp(nameptr, "database") == 0)
     751                 :         315 :                                 port->database_name = pstrdup(valptr);
     752         [ +  + ]:        1509 :                         else if (strcmp(nameptr, "user") == 0)
     753                 :         315 :                                 port->user_name = pstrdup(valptr);
     754         [ +  + ]:        1194 :                         else if (strcmp(nameptr, "options") == 0)
     755                 :         293 :                                 port->cmdline_options = pstrdup(valptr);
     756         [ +  - ]:         901 :                         else if (strcmp(nameptr, "replication") == 0)
     757                 :             :                         {
     758                 :             :                                 /*
     759                 :             :                                  * Due to backward compatibility concerns the replication
     760                 :             :                                  * parameter is a hybrid beast which allows the value to be
     761                 :             :                                  * either boolean or the string 'database'. The latter
     762                 :             :                                  * connects to a specific database which is e.g. required for
     763                 :             :                                  * logical decoding while.
     764                 :             :                                  */
     765         [ #  # ]:           0 :                                 if (strcmp(valptr, "database") == 0)
     766                 :             :                                 {
     767                 :           0 :                                         am_walsender = true;
     768                 :           0 :                                         am_db_walsender = true;
     769                 :           0 :                                 }
     770         [ #  # ]:           0 :                                 else if (!parse_bool(valptr, &am_walsender))
     771   [ #  #  #  # ]:           0 :                                         ereport(FATAL,
     772                 :             :                                                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     773                 :             :                                                          errmsg("invalid value for parameter \"%s\": \"%s\"",
     774                 :             :                                                                         "replication",
     775                 :             :                                                                         valptr),
     776                 :             :                                                          errhint("Valid values are: \"false\", 0, \"true\", 1, \"database\".")));
     777                 :           0 :                         }
     778         [ +  - ]:         901 :                         else if (strncmp(nameptr, "_pq_.", 5) == 0)
     779                 :             :                         {
     780                 :             :                                 /*
     781                 :             :                                  * Any option beginning with _pq_. is reserved for use as a
     782                 :             :                                  * protocol-level option, but at present no such options are
     783                 :             :                                  * defined.
     784                 :             :                                  */
     785                 :           0 :                                 unrecognized_protocol_options =
     786                 :           0 :                                         lappend(unrecognized_protocol_options, pstrdup(nameptr));
     787                 :           0 :                         }
     788                 :             :                         else
     789                 :             :                         {
     790                 :             :                                 /* Assume it's a generic GUC option */
     791                 :        1802 :                                 port->guc_options = lappend(port->guc_options,
     792                 :         901 :                                                                                         pstrdup(nameptr));
     793                 :        1802 :                                 port->guc_options = lappend(port->guc_options,
     794                 :         901 :                                                                                         pstrdup(valptr));
     795                 :             : 
     796                 :             :                                 /*
     797                 :             :                                  * Copy application_name to port if we come across it.  This
     798                 :             :                                  * is done so we can log the application_name in the
     799                 :             :                                  * connection authorization message.  Note that the GUC would
     800                 :             :                                  * be used but we haven't gone through GUC setup yet.
     801                 :             :                                  */
     802         [ +  + ]:         901 :                                 if (strcmp(nameptr, "application_name") == 0)
     803                 :             :                                 {
     804                 :         315 :                                         port->application_name = pg_clean_ascii(valptr, 0);
     805                 :         315 :                                 }
     806                 :             :                         }
     807                 :        1824 :                         offset = valoffset + strlen(valptr) + 1;
     808      [ -  +  + ]:        2139 :                 }
     809                 :             : 
     810                 :             :                 /*
     811                 :             :                  * If we didn't find a packet terminator exactly at the end of the
     812                 :             :                  * given packet length, complain.
     813                 :             :                  */
     814         [ +  - ]:         315 :                 if (offset != len - 1)
     815   [ #  #  #  # ]:           0 :                         ereport(FATAL,
     816                 :             :                                         (errcode(ERRCODE_PROTOCOL_VIOLATION),
     817                 :             :                                          errmsg("invalid startup packet layout: expected terminator as last byte")));
     818                 :             : 
     819                 :             :                 /*
     820                 :             :                  * If the client requested a newer protocol version or if the client
     821                 :             :                  * requested any protocol options we didn't recognize, let them know
     822                 :             :                  * the newest minor protocol version we do support and the names of
     823                 :             :                  * any unrecognized options.
     824                 :             :                  */
     825   [ +  -  -  + ]:         315 :                 if (PG_PROTOCOL_MINOR(proto) > PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST) ||
     826                 :         315 :                         unrecognized_protocol_options != NIL)
     827                 :           0 :                         SendNegotiateProtocolVersion(unrecognized_protocol_options);
     828                 :         315 :         }
     829                 :             : 
     830                 :             :         /* Check a user name was given. */
     831         [ +  - ]:         315 :         if (port->user_name == NULL || port->user_name[0] == '\0')
     832   [ #  #  #  # ]:           0 :                 ereport(FATAL,
     833                 :             :                                 (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
     834                 :             :                                  errmsg("no PostgreSQL user name specified in startup packet")));
     835                 :             : 
     836                 :             :         /* The database defaults to the user name. */
     837   [ +  -  +  - ]:         315 :         if (port->database_name == NULL || port->database_name[0] == '\0')
     838                 :           0 :                 port->database_name = pstrdup(port->user_name);
     839                 :             : 
     840                 :             :         /*
     841                 :             :          * Truncate given database and user names to length of a Postgres name.
     842                 :             :          * This avoids lookup failures when overlength names are given.
     843                 :             :          */
     844         [ +  - ]:         315 :         if (strlen(port->database_name) >= NAMEDATALEN)
     845                 :           0 :                 port->database_name[NAMEDATALEN - 1] = '\0';
     846         [ +  - ]:         315 :         if (strlen(port->user_name) >= NAMEDATALEN)
     847                 :           0 :                 port->user_name[NAMEDATALEN - 1] = '\0';
     848                 :             : 
     849         [ -  + ]:         315 :         if (am_walsender)
     850                 :           0 :                 MyBackendType = B_WAL_SENDER;
     851                 :             :         else
     852                 :         315 :                 MyBackendType = B_BACKEND;
     853                 :             : 
     854                 :             :         /*
     855                 :             :          * Normal walsender backends, e.g. for streaming replication, are not
     856                 :             :          * connected to a particular database. But walsenders used for logical
     857                 :             :          * replication need to connect to a specific database. We allow streaming
     858                 :             :          * replication commands to be issued even if connected to a database as it
     859                 :             :          * can make sense to first make a basebackup and then stream changes
     860                 :             :          * starting from that.
     861                 :             :          */
     862   [ -  +  #  # ]:         315 :         if (am_walsender && !am_db_walsender)
     863                 :           0 :                 port->database_name[0] = '\0';
     864                 :             : 
     865                 :             :         /*
     866                 :             :          * Done filling the Port structure
     867                 :             :          */
     868                 :         315 :         MemoryContextSwitchTo(oldcontext);
     869                 :             : 
     870                 :         315 :         pfree(buf);
     871                 :             : 
     872                 :         315 :         return STATUS_OK;
     873                 :             : 
     874                 :             : fail:
     875                 :             :         /* be tidy, just to avoid Valgrind complaints */
     876         [ #  # ]:           0 :         if (buf)
     877                 :           0 :                 pfree(buf);
     878                 :             : 
     879                 :           0 :         return STATUS_ERROR;
     880                 :         315 : }
     881                 :             : 
     882                 :             : /*
     883                 :             :  * The client has sent a cancel request packet, not a normal
     884                 :             :  * start-a-new-connection packet.  Perform the necessary processing.  Nothing
     885                 :             :  * is sent back to the client.
     886                 :             :  */
     887                 :             : static void
     888                 :           0 : ProcessCancelRequestPacket(Port *port, void *pkt, int pktlen)
     889                 :             : {
     890                 :           0 :         CancelRequestPacket *canc;
     891                 :           0 :         int                     len;
     892                 :             : 
     893         [ #  # ]:           0 :         if (pktlen < offsetof(CancelRequestPacket, cancelAuthCode))
     894                 :             :         {
     895   [ #  #  #  # ]:           0 :                 ereport(COMMERROR,
     896                 :             :                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     897                 :             :                                  errmsg("invalid length of cancel request packet")));
     898                 :           0 :                 return;
     899                 :             :         }
     900                 :           0 :         len = pktlen - offsetof(CancelRequestPacket, cancelAuthCode);
     901   [ #  #  #  # ]:           0 :         if (len == 0 || len > 256)
     902                 :             :         {
     903   [ #  #  #  # ]:           0 :                 ereport(COMMERROR,
     904                 :             :                                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     905                 :             :                                  errmsg("invalid length of cancel key in cancel request packet")));
     906                 :           0 :                 return;
     907                 :             :         }
     908                 :             : 
     909                 :           0 :         canc = (CancelRequestPacket *) pkt;
     910                 :           0 :         SendCancelRequest(pg_ntoh32(canc->backendPID), canc->cancelAuthCode, len);
     911         [ #  # ]:           0 : }
     912                 :             : 
     913                 :             : /*
     914                 :             :  * Send a NegotiateProtocolVersion to the client.  This lets the client know
     915                 :             :  * that they have either requested a newer minor protocol version than we are
     916                 :             :  * able to speak, or at least one protocol option that we don't understand, or
     917                 :             :  * possibly both. FrontendProtocol has already been set to the version
     918                 :             :  * requested by the client or the highest version we know how to speak,
     919                 :             :  * whichever is older. If the highest version that we know how to speak is too
     920                 :             :  * old for the client, it can abandon the connection.
     921                 :             :  *
     922                 :             :  * We also include in the response a list of protocol options we didn't
     923                 :             :  * understand.  This allows clients to include optional parameters that might
     924                 :             :  * be present either in newer protocol versions or third-party protocol
     925                 :             :  * extensions without fear of having to reconnect if those options are not
     926                 :             :  * understood, while at the same time making certain that the client is aware
     927                 :             :  * of which options were actually accepted.
     928                 :             :  */
     929                 :             : static void
     930                 :           0 : SendNegotiateProtocolVersion(List *unrecognized_protocol_options)
     931                 :             : {
     932                 :           0 :         StringInfoData buf;
     933                 :           0 :         ListCell   *lc;
     934                 :             : 
     935                 :           0 :         pq_beginmessage(&buf, PqMsg_NegotiateProtocolVersion);
     936                 :           0 :         pq_sendint32(&buf, FrontendProtocol);
     937                 :           0 :         pq_sendint32(&buf, list_length(unrecognized_protocol_options));
     938   [ #  #  #  #  :           0 :         foreach(lc, unrecognized_protocol_options)
                   #  # ]
     939                 :           0 :                 pq_sendstring(&buf, lfirst(lc));
     940                 :           0 :         pq_endmessage(&buf);
     941                 :             : 
     942                 :             :         /* no need to flush, some other message will follow */
     943                 :           0 : }
     944                 :             : 
     945                 :             : 
     946                 :             : /*
     947                 :             :  * SIGTERM while processing startup packet.
     948                 :             :  *
     949                 :             :  * Running proc_exit() from a signal handler would be quite unsafe.
     950                 :             :  * However, since we have not yet touched shared memory, we can just
     951                 :             :  * pull the plug and exit without running any atexit handlers.
     952                 :             :  *
     953                 :             :  * One might be tempted to try to send a message, or log one, indicating
     954                 :             :  * why we are disconnecting.  However, that would be quite unsafe in itself.
     955                 :             :  * Also, it seems undesirable to provide clues about the database's state
     956                 :             :  * to a client that has not yet completed authentication, or even sent us
     957                 :             :  * a startup packet.
     958                 :             :  */
     959                 :             : static void
     960                 :           0 : process_startup_packet_die(SIGNAL_ARGS)
     961                 :             : {
     962                 :           0 :         _exit(1);
     963                 :             : }
     964                 :             : 
     965                 :             : /*
     966                 :             :  * Timeout while processing startup packet.
     967                 :             :  * As for process_startup_packet_die(), we exit via _exit(1).
     968                 :             :  */
     969                 :             : static void
     970                 :           0 : StartupPacketTimeoutHandler(void)
     971                 :             : {
     972                 :           0 :         _exit(1);
     973                 :             : }
     974                 :             : 
     975                 :             : /*
     976                 :             :  * Helper for the log_connections GUC check hook.
     977                 :             :  *
     978                 :             :  * `elemlist` is a listified version of the string input passed to the
     979                 :             :  * log_connections GUC check hook, check_log_connections().
     980                 :             :  * check_log_connections() is responsible for cleaning up `elemlist`.
     981                 :             :  *
     982                 :             :  * validate_log_connections_options() returns false if an error was
     983                 :             :  * encountered and the GUC input could not be validated and true otherwise.
     984                 :             :  *
     985                 :             :  * `flags` returns the flags that should be stored in the log_connections GUC
     986                 :             :  * by its assign hook.
     987                 :             :  */
     988                 :             : static bool
     989                 :           6 : validate_log_connections_options(List *elemlist, uint32 *flags)
     990                 :             : {
     991                 :           6 :         ListCell   *l;
     992                 :           6 :         char       *item;
     993                 :             : 
     994                 :             :         /*
     995                 :             :          * For backwards compatibility, we accept these tokens by themselves.
     996                 :             :          *
     997                 :             :          * Prior to PostgreSQL 18, log_connections was a boolean GUC that accepted
     998                 :             :          * any unambiguous substring of 'true', 'false', 'yes', 'no', 'on', and
     999                 :             :          * 'off'. Since log_connections became a list of strings in 18, we only
    1000                 :             :          * accept complete option strings.
    1001                 :             :          */
    1002                 :             :         static const struct config_enum_entry compat_options[] = {
    1003                 :             :                 {"off", 0},
    1004                 :             :                 {"false", 0},
    1005                 :             :                 {"no", 0},
    1006                 :             :                 {"0", 0},
    1007                 :             :                 {"on", LOG_CONNECTION_ON},
    1008                 :             :                 {"true", LOG_CONNECTION_ON},
    1009                 :             :                 {"yes", LOG_CONNECTION_ON},
    1010                 :             :                 {"1", LOG_CONNECTION_ON},
    1011                 :             :         };
    1012                 :             : 
    1013                 :           6 :         *flags = 0;
    1014                 :             : 
    1015                 :             :         /* If an empty string was passed, we're done */
    1016         [ -  + ]:           6 :         if (list_length(elemlist) == 0)
    1017                 :           6 :                 return true;
    1018                 :             : 
    1019                 :             :         /*
    1020                 :             :          * Now check for the backwards compatibility options. They must always be
    1021                 :             :          * specified on their own, so we error out if the first option is a
    1022                 :             :          * backwards compatibility option and other options are also specified.
    1023                 :             :          */
    1024                 :           0 :         item = linitial(elemlist);
    1025                 :             : 
    1026   [ #  #  #  # ]:           0 :         for (size_t i = 0; i < lengthof(compat_options); i++)
    1027                 :             :         {
    1028                 :           0 :                 struct config_enum_entry option = compat_options[i];
    1029                 :             : 
    1030         [ #  # ]:           0 :                 if (pg_strcasecmp(item, option.name) != 0)
    1031                 :           0 :                         continue;
    1032                 :             : 
    1033         [ #  # ]:           0 :                 if (list_length(elemlist) > 1)
    1034                 :             :                 {
    1035                 :           0 :                         GUC_check_errdetail("Cannot specify log_connections option \"%s\" in a list with other options.",
    1036                 :           0 :                                                                 item);
    1037                 :           0 :                         return false;
    1038                 :             :                 }
    1039                 :             : 
    1040                 :           0 :                 *flags = option.val;
    1041                 :           0 :                 return true;
    1042         [ #  # ]:           0 :         }
    1043                 :             : 
    1044                 :             :         /* Now check the aspect options. The empty string was already handled */
    1045   [ #  #  #  #  :           0 :         foreach(l, elemlist)
             #  #  #  # ]
    1046                 :             :         {
    1047                 :             :                 static const struct config_enum_entry options[] = {
    1048                 :             :                         {"receipt", LOG_CONNECTION_RECEIPT},
    1049                 :             :                         {"authentication", LOG_CONNECTION_AUTHENTICATION},
    1050                 :             :                         {"authorization", LOG_CONNECTION_AUTHORIZATION},
    1051                 :             :                         {"setup_durations", LOG_CONNECTION_SETUP_DURATIONS},
    1052                 :             :                         {"all", LOG_CONNECTION_ALL},
    1053                 :             :                 };
    1054                 :             : 
    1055                 :           0 :                 item = lfirst(l);
    1056   [ #  #  #  #  :           0 :                 for (size_t i = 0; i < lengthof(options); i++)
                      # ]
    1057                 :             :                 {
    1058                 :           0 :                         struct config_enum_entry option = options[i];
    1059                 :             : 
    1060         [ #  # ]:           0 :                         if (pg_strcasecmp(item, option.name) == 0)
    1061                 :             :                         {
    1062                 :           0 :                                 *flags |= option.val;
    1063                 :           0 :                                 goto next;
    1064                 :             :                         }
    1065         [ #  # ]:           0 :                 }
    1066                 :             : 
    1067                 :           0 :                 GUC_check_errdetail("Invalid option \"%s\".", item);
    1068                 :           0 :                 return false;
    1069                 :             : 
    1070                 :             : next:   ;
    1071                 :           0 :         }
    1072                 :             : 
    1073                 :           0 :         return true;
    1074                 :           6 : }
    1075                 :             : 
    1076                 :             : 
    1077                 :             : /*
    1078                 :             :  * GUC check hook for log_connections
    1079                 :             :  */
    1080                 :             : bool
    1081                 :           6 : check_log_connections(char **newval, void **extra, GucSource source)
    1082                 :             : {
    1083                 :           6 :         uint32          flags;
    1084                 :           6 :         char       *rawstring;
    1085                 :           6 :         List       *elemlist;
    1086                 :           6 :         bool            success;
    1087                 :             : 
    1088                 :             :         /* Need a modifiable copy of string */
    1089                 :           6 :         rawstring = pstrdup(*newval);
    1090                 :             : 
    1091         [ -  + ]:           6 :         if (!SplitIdentifierString(rawstring, ',', &elemlist))
    1092                 :             :         {
    1093                 :           0 :                 GUC_check_errdetail("Invalid list syntax in parameter \"%s\".", "log_connections");
    1094                 :           0 :                 pfree(rawstring);
    1095                 :           0 :                 list_free(elemlist);
    1096                 :           0 :                 return false;
    1097                 :             :         }
    1098                 :             : 
    1099                 :             :         /* Validation logic is all in the helper */
    1100                 :           6 :         success = validate_log_connections_options(elemlist, &flags);
    1101                 :             : 
    1102                 :             :         /* Time for cleanup */
    1103                 :           6 :         pfree(rawstring);
    1104                 :           6 :         list_free(elemlist);
    1105                 :             : 
    1106         [ +  - ]:           6 :         if (!success)
    1107                 :           0 :                 return false;
    1108                 :             : 
    1109                 :             :         /*
    1110                 :             :          * We succeeded, so allocate `extra` and save the flags there for use by
    1111                 :             :          * assign_log_connections().
    1112                 :             :          */
    1113                 :           6 :         *extra = guc_malloc(LOG, sizeof(int));
    1114         [ +  - ]:           6 :         if (!*extra)
    1115                 :           0 :                 return false;
    1116                 :           6 :         *((int *) *extra) = flags;
    1117                 :             : 
    1118                 :           6 :         return true;
    1119                 :           6 : }
    1120                 :             : 
    1121                 :             : /*
    1122                 :             :  * GUC assign hook for log_connections
    1123                 :             :  */
    1124                 :             : void
    1125                 :           6 : assign_log_connections(const char *newval, void *extra)
    1126                 :             : {
    1127                 :           6 :         log_connections = *((int *) extra);
    1128                 :           6 : }
        

Generated by: LCOV version 2.3.2-1