LCOV - code coverage report
Current view: top level - src/backend/tcop - backend_startup.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 83.7 % 300 251
Test Date: 2026-07-24 19:15:43 Functions: 81.8 % 11 9
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 60.7 % 267 162

             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);
      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                 :       15259 : BackendMain(const void *startup_data, size_t startup_data_len)
      77                 :             : {
      78                 :       15259 :     const BackendStartupData *bsdata = startup_data;
      79                 :             : 
      80                 :             :     Assert(startup_data_len == sizeof(BackendStartupData));
      81                 :             :     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                 :       15259 :     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                 :       14967 :     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                 :       14964 :     MemoryContextSwitchTo(TopMemoryContext);
     123                 :             : 
     124                 :       14964 :     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                 :       15259 : BackendInitialize(ClientSocket *client_sock, CAC_state cac)
     142                 :             : {
     143                 :             :     int         status;
     144                 :             :     int         ret;
     145                 :             :     Port       *port;
     146                 :             :     char        remote_host[NI_MAXHOST];
     147                 :             :     char        remote_port[NI_MAXSERV];
     148                 :             :     StringInfoData ps_data;
     149                 :             :     MemoryContext oldcontext;
     150                 :             : 
     151                 :             :     /* Tell fd.c about the long-lived FD associated with the client_sock */
     152                 :       15259 :     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         [ -  + ]:       15259 :     if (PreAuthDelay > 0)
     162                 :           0 :         pg_usleep(PreAuthDelay * 1000000L);
     163                 :             : 
     164                 :             :     /* This flag will remain set until InitPostgres finishes authentication */
     165                 :       15259 :     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                 :       15259 :     oldcontext = MemoryContextSwitchTo(TopMemoryContext);
     177                 :       15259 :     port = MyProcPort = pq_init(client_sock);
     178                 :       15259 :     MemoryContextSwitchTo(oldcontext);
     179                 :             : 
     180                 :       15259 :     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                 :       15259 :     port->remote_host = "";
     184                 :       15259 :     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                 :       15259 :     pqsignal(SIGTERM, process_startup_packet_die);
     197                 :             :     /* SIGQUIT handler was already set up by InitPostmasterChild */
     198                 :       15259 :     InitializeTimeouts();       /* establishes SIGALRM handler */
     199                 :       15259 :     sigprocmask(SIG_SETMASK, &StartupBlockSig, NULL);
     200                 :             : 
     201                 :             :     /*
     202                 :             :      * Get the remote host name and port for logging and status display.
     203                 :             :      */
     204                 :       15259 :     remote_host[0] = '\0';
     205                 :       15259 :     remote_port[0] = '\0';
     206   [ +  +  -  + ]:       15259 :     if ((ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
     207                 :             :                                   remote_host, sizeof(remote_host),
     208                 :             :                                   remote_port, sizeof(remote_port),
     209                 :             :                                   (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                 :       15259 :     port->remote_host = MemoryContextStrdup(TopMemoryContext, remote_host);
     219                 :       15259 :     port->remote_port = MemoryContextStrdup(TopMemoryContext, remote_port);
     220                 :             : 
     221                 :             :     /* And now we can log that the connection was received, if enabled */
     222         [ +  + ]:       15259 :     if (log_connections & LOG_CONNECTION_RECEIPT)
     223                 :             :     {
     224         [ +  + ]:         448 :         if (remote_port[0])
     225         [ +  - ]:         192 :             ereport(LOG,
     226                 :             :                     (errmsg("connection received: host=%s port=%s",
     227                 :             :                             remote_host,
     228                 :             :                             remote_port)));
     229                 :             :         else
     230         [ +  - ]:         256 :             ereport(LOG,
     231                 :             :                     (errmsg("connection received: host=%s",
     232                 :             :                             remote_host)));
     233                 :             :     }
     234                 :             : 
     235                 :             :     /* For testing client error handling */
     236                 :             : #ifdef USE_INJECTION_POINTS
     237                 :       15259 :     INJECTION_POINT("backend-initialize", NULL);
     238         [ +  + ]:       15258 :     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                 :           1 :         FrontendProtocol = PG_PROTOCOL(2, 0);
     246         [ +  - ]:           1 :         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   [ +  +  +  - ]:       15257 :     if (log_hostname &&
     262                 :         161 :         ret == 0 &&
     263         [ +  - ]:         161 :         strspn(remote_host, "0123456789.") < strlen(remote_host) &&
     264         [ +  - ]:         161 :         strspn(remote_host, "0123456789ABCDEFabcdef:") < strlen(remote_host))
     265                 :             :     {
     266                 :         161 :         port->remote_hostname = MemoryContextStrdup(TopMemoryContext, remote_host);
     267                 :             :     }
     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                 :       15257 :     RegisterTimeout(STARTUP_PACKET_TIMEOUT, StartupPacketTimeoutHandler);
     285                 :       15257 :     enable_timeout_after(STARTUP_PACKET_TIMEOUT, AuthenticationTimeout * 1000);
     286                 :             : 
     287                 :             :     /* Handle direct SSL handshake */
     288                 :       15257 :     status = ProcessSSLStartup(port);
     289                 :             : 
     290                 :             :     /*
     291                 :             :      * Receive the startup packet (which might turn out to be a cancel request
     292                 :             :      * packet).
     293                 :             :      */
     294         [ +  + ]:       15257 :     if (status == STATUS_OK)
     295                 :       15253 :         status = ProcessStartupPacket(port);
     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         [ +  + ]:       15255 :     if (status == STATUS_OK)
     303                 :             :     {
     304   [ +  +  +  +  :       15188 :         switch (cac)
                +  +  - ]
     305                 :             :         {
     306                 :         165 :             case CAC_STARTUP:
     307         [ +  - ]:         165 :                 ereport(FATAL,
     308                 :             :                         (errcode(ERRCODE_CANNOT_CONNECT_NOW),
     309                 :             :                          errmsg("the database system is starting up")));
     310                 :             :                 break;
     311                 :           6 :             case CAC_NOTHOTSTANDBY:
     312         [ -  + ]:           6 :                 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         [ -  + ]:           6 :                 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         [ +  - ]:           6 :                     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                 :             :                 break;
     330                 :          47 :             case CAC_SHUTDOWN:
     331         [ +  - ]:          47 :                 ereport(FATAL,
     332                 :             :                         (errcode(ERRCODE_CANNOT_CONNECT_NOW),
     333                 :             :                          errmsg("the database system is shutting down")));
     334                 :             :                 break;
     335                 :           2 :             case CAC_RECOVERY:
     336         [ +  - ]:           2 :                 ereport(FATAL,
     337                 :             :                         (errcode(ERRCODE_CANNOT_CONNECT_NOW),
     338                 :             :                          errmsg("the database system is in recovery mode")));
     339                 :             :                 break;
     340                 :           1 :             case CAC_TOOMANY:
     341         [ +  - ]:           1 :                 ereport(FATAL,
     342                 :             :                         (errcode(ERRCODE_TOO_MANY_CONNECTIONS),
     343                 :             :                          errmsg("sorry, too many clients already")));
     344                 :             :                 break;
     345                 :       14967 :             case CAC_OK:
     346                 :       14967 :                 break;
     347                 :             :         }
     348                 :             :     }
     349                 :             : 
     350                 :             :     /*
     351                 :             :      * Disable the timeout, and prevent SIGTERM again.
     352                 :             :      */
     353                 :       15034 :     disable_timeout(STARTUP_PACKET_TIMEOUT, false);
     354                 :       15034 :     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                 :       15034 :     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         [ +  + ]:       15034 :     if (status != STATUS_OK)
     372                 :          67 :         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                 :       14967 :     initStringInfo(&ps_data);
     379         [ +  + ]:       14967 :     if (am_walsender)
     380                 :        1341 :         appendStringInfo(&ps_data, "%s ", GetBackendTypeDesc(B_WAL_SENDER));
     381                 :       14967 :     appendStringInfo(&ps_data, "%s ", port->user_name);
     382         [ +  + ]:       14967 :     if (port->database_name[0] != '\0')
     383                 :       14450 :         appendStringInfo(&ps_data, "%s ", port->database_name);
     384                 :       14967 :     appendStringInfoString(&ps_data, port->remote_host);
     385         [ +  + ]:       14967 :     if (port->remote_port[0] != '\0')
     386                 :         285 :         appendStringInfo(&ps_data, "(%s)", port->remote_port);
     387                 :             : 
     388                 :       14967 :     init_ps_display(ps_data.data);
     389                 :       14967 :     pfree(ps_data.data);
     390                 :             : 
     391                 :       14967 :     set_ps_display("initializing");
     392                 :       14967 : }
     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                 :       15257 : ProcessSSLStartup(Port *port)
     402                 :             : {
     403                 :             :     int         firstbyte;
     404                 :             : 
     405                 :             :     Assert(!port->ssl_in_use);
     406                 :             : 
     407                 :       15257 :     pq_startmsgread();
     408                 :       15257 :     firstbyte = pq_peekbyte();
     409                 :       15257 :     pq_endmsgread();
     410         [ +  + ]:       15257 :     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                 :           2 :         return STATUS_ERROR;
     417                 :             :     }
     418                 :             : 
     419         [ +  + ]:       15255 :     if (firstbyte != 0x16)
     420                 :             :     {
     421                 :             :         /* Not an SSL handshake message */
     422                 :       15250 :         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   [ +  +  -  + ]:           5 :     if (!LoadedSSL || port->laddr.addr.ss_family == AF_UNIX)
     434                 :             :     {
     435                 :             :         /* SSL not supported */
     436                 :           2 :         goto reject;
     437                 :             :     }
     438                 :             : 
     439         [ -  + ]:           3 :     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                 :             :     Assert(port->ssl_in_use);
     448                 :             : 
     449         [ -  + ]:           3 :     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         [ +  - ]:           3 :     if (Trace_connection_negotiation)
     458         [ +  - ]:           3 :         ereport(LOG,
     459                 :             :                 (errmsg("direct SSL connection accepted")));
     460                 :           3 :     return STATUS_OK;
     461                 :             : #else
     462                 :             :     /* SSL not supported by this build */
     463                 :             :     goto reject;
     464                 :             : #endif
     465                 :             : 
     466                 :           2 : reject:
     467         [ +  - ]:           2 :     if (Trace_connection_negotiation)
     468         [ +  - ]:           2 :         ereport(LOG,
     469                 :             :                 (errmsg("direct SSL connection rejected")));
     470                 :           2 :     return STATUS_ERROR;
     471                 :             : }
     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                 :             :  */
     485                 :             : static int
     486                 :       15253 : ProcessStartupPacket(Port *port)
     487                 :             : {
     488                 :             :     int32       len;
     489                 :       15253 :     char       *buf = NULL;
     490                 :             :     ProtocolVersion proto;
     491                 :             :     MemoryContext oldcontext;
     492                 :             :     bool        gss_done;
     493                 :             :     bool        ssl_done;
     494                 :             : 
     495                 :             :     /*
     496                 :             :      * Set ssl_done and/or gss_done when negotiation of an encrypted layer
     497                 :             :      * (currently, TLS or GSSAPI) is completed.  A successful negotiation of
     498                 :             :      * either encryption layer sets both flags, but a rejected negotiation
     499                 :             :      * sets only the flag for that layer, since the client may wish to try the
     500                 :             :      * other one.  We should make no assumption here about the order in which
     501                 :             :      * the client may make requests.
     502                 :             :      */
     503                 :       15253 :     gss_done = false;
     504                 :       15253 :     ssl_done = false;
     505                 :             : 
     506                 :         287 : retry:
     507                 :       15540 :     pq_startmsgread();
     508                 :             : 
     509                 :             :     /*
     510                 :             :      * Grab the first byte of the length word separately, so that we can tell
     511                 :             :      * whether we have no data at all or an incomplete packet.  (This might
     512                 :             :      * sound inefficient, but it's not really, because of buffering in
     513                 :             :      * pqcomm.c.)
     514                 :             :      */
     515         [ +  + ]:       15540 :     if (pq_getbytes(&len, 1) == EOF)
     516                 :             :     {
     517                 :             :         /*
     518                 :             :          * If we get no data at all, don't clutter the log with a complaint;
     519                 :             :          * such cases often occur for legitimate reasons.  An example is that
     520                 :             :          * we might be here after responding to NEGOTIATE_SSL_CODE, and if the
     521                 :             :          * client didn't like our response, it'll probably just drop the
     522                 :             :          * connection.  Service-monitoring software also often just opens and
     523                 :             :          * closes a connection without sending anything.  (So do port
     524                 :             :          * scanners, which may be less benign, but it's not really our job to
     525                 :             :          * notice those.)
     526                 :             :          */
     527                 :          15 :         goto fail;
     528                 :             :     }
     529                 :             : 
     530         [ -  + ]:       15525 :     if (pq_getbytes(((char *) &len) + 1, 3) == EOF)
     531                 :             :     {
     532                 :             :         /* Got a partial length word, so bleat about that */
     533   [ #  #  #  # ]:           0 :         if (!ssl_done && !gss_done)
     534         [ #  # ]:           0 :             ereport(COMMERROR,
     535                 :             :                     (errcode(ERRCODE_PROTOCOL_VIOLATION),
     536                 :             :                      errmsg("incomplete startup packet")));
     537                 :           0 :         goto fail;
     538                 :             :     }
     539                 :             : 
     540                 :       15525 :     len = pg_ntoh32(len);
     541                 :       15525 :     len -= 4;
     542                 :             : 
     543         [ +  - ]:       15525 :     if (len < (int32) sizeof(ProtocolVersion) ||
     544         [ -  + ]:       15525 :         len > MAX_STARTUP_PACKET_LENGTH)
     545                 :             :     {
     546         [ #  # ]:           0 :         ereport(COMMERROR,
     547                 :             :                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     548                 :             :                  errmsg("invalid length of startup packet")));
     549                 :           0 :         goto fail;
     550                 :             :     }
     551                 :             : 
     552                 :             :     /*
     553                 :             :      * Allocate space to hold the startup packet, plus one extra byte that's
     554                 :             :      * initialized to be zero.  This ensures we will have null termination of
     555                 :             :      * all strings inside the packet.
     556                 :             :      */
     557                 :       15525 :     buf = palloc(len + 1);
     558                 :       15525 :     buf[len] = '\0';
     559                 :             : 
     560         [ -  + ]:       15525 :     if (pq_getbytes(buf, len) == EOF)
     561                 :             :     {
     562         [ #  # ]:           0 :         ereport(COMMERROR,
     563                 :             :                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     564                 :             :                  errmsg("incomplete startup packet")));
     565                 :           0 :         goto fail;
     566                 :             :     }
     567                 :       15525 :     pq_endmsgread();
     568                 :             : 
     569                 :             :     /*
     570                 :             :      * The first field is either a protocol version number or a special
     571                 :             :      * request code.
     572                 :             :      */
     573                 :       15525 :     port->proto = proto = pg_ntoh32(*((ProtocolVersion *) buf));
     574                 :             : 
     575         [ +  + ]:       15525 :     if (proto == CANCEL_REQUEST_CODE)
     576                 :             :     {
     577                 :          16 :         ProcessCancelRequestPacket(port, buf, len);
     578                 :             :         /* Not really an error, but we don't want to proceed further */
     579                 :          16 :         goto fail;
     580                 :             :     }
     581                 :             : 
     582   [ +  +  +  + ]:       15509 :     if (proto == NEGOTIATE_SSL_CODE && !ssl_done)
     583                 :             :     {
     584                 :             :         char        SSLok;
     585                 :             : 
     586                 :             : #ifdef USE_SSL
     587                 :             : 
     588                 :             :         /*
     589                 :             :          * No SSL when disabled or on Unix sockets.
     590                 :             :          *
     591                 :             :          * Also no SSL negotiation if we already have a direct SSL connection
     592                 :             :          */
     593   [ +  +  +  -  :         319 :         if (!LoadedSSL || port->laddr.addr.ss_family == AF_UNIX || port->ssl_in_use)
                   -  + ]
     594                 :         151 :             SSLok = 'N';
     595                 :             :         else
     596                 :         168 :             SSLok = 'S';        /* Support for SSL */
     597                 :             : #else
     598                 :             :         SSLok = 'N';            /* No support for SSL */
     599                 :             : #endif
     600                 :             : 
     601         [ +  + ]:         319 :         if (Trace_connection_negotiation)
     602                 :             :         {
     603         [ +  + ]:          13 :             if (SSLok == 'S')
     604         [ +  - ]:           8 :                 ereport(LOG,
     605                 :             :                         (errmsg("SSLRequest accepted")));
     606                 :             :             else
     607         [ +  - ]:           5 :                 ereport(LOG,
     608                 :             :                         (errmsg("SSLRequest rejected")));
     609                 :             :         }
     610                 :             : 
     611         [ -  + ]:         319 :         while (secure_write(port, &SSLok, 1) != 1)
     612                 :             :         {
     613         [ #  # ]:           0 :             if (errno == EINTR)
     614                 :           0 :                 continue;       /* if interrupted, just retry */
     615         [ #  # ]:           0 :             ereport(COMMERROR,
     616                 :             :                     (errcode_for_socket_access(),
     617                 :             :                      errmsg("failed to send SSL negotiation response: %m")));
     618                 :          32 :             goto fail;          /* close the connection */
     619                 :             :         }
     620                 :             : 
     621                 :             : #ifdef USE_SSL
     622   [ +  +  +  + ]:         319 :         if (SSLok == 'S' && secure_open_server(port) == -1)
     623                 :          32 :             goto fail;
     624                 :             : #endif
     625                 :             : 
     626                 :         286 :         pfree(buf);
     627                 :         286 :         buf = NULL;
     628                 :             : 
     629                 :             :         /*
     630                 :             :          * At this point we should have no data already buffered.  If we do,
     631                 :             :          * it was received before we performed the SSL handshake, so it wasn't
     632                 :             :          * encrypted and indeed may have been injected by a man-in-the-middle.
     633                 :             :          * We report this case to the client.
     634                 :             :          */
     635         [ -  + ]:         286 :         if (pq_buffer_remaining_data() > 0)
     636         [ #  # ]:           0 :             ereport(FATAL,
     637                 :             :                     (errcode(ERRCODE_PROTOCOL_VIOLATION),
     638                 :             :                      errmsg("received unencrypted data after SSL request"),
     639                 :             :                      errdetail("This could be either a client-software bug or evidence of an attempted man-in-the-middle attack.")));
     640                 :             : 
     641                 :             :         /*
     642                 :             :          * regular startup packet, cancel, etc packet should follow, but not
     643                 :             :          * another SSL negotiation request, and a GSS request should only
     644                 :             :          * follow if SSL was rejected (client may negotiate in either order)
     645                 :             :          */
     646                 :         286 :         ssl_done = true;
     647         [ +  + ]:         286 :         if (SSLok == 'S')
     648                 :             :         {
     649                 :             :             /*
     650                 :             :              * We are done with SSL and negotiated correctly, so consider the
     651                 :             :              * same for GSS.
     652                 :             :              */
     653                 :         135 :             gss_done = true;
     654                 :             :         }
     655                 :         286 :         goto retry;
     656                 :             :     }
     657   [ +  +  +  - ]:       15190 :     else if (proto == NEGOTIATE_GSS_CODE && !gss_done)
     658                 :             :     {
     659                 :           1 :         char        GSSok = 'N';
     660                 :             : 
     661                 :             : #ifdef ENABLE_GSS
     662                 :             :         /* No GSSAPI encryption when on Unix socket */
     663                 :             :         if (port->laddr.addr.ss_family != AF_UNIX)
     664                 :             :             GSSok = 'G';
     665                 :             : #endif
     666                 :             : 
     667         [ +  - ]:           1 :         if (Trace_connection_negotiation)
     668                 :             :         {
     669         [ -  + ]:           1 :             if (GSSok == 'G')
     670         [ #  # ]:           0 :                 ereport(LOG,
     671                 :             :                         (errmsg("GSSENCRequest accepted")));
     672                 :             :             else
     673         [ +  - ]:           1 :                 ereport(LOG,
     674                 :             :                         (errmsg("GSSENCRequest rejected")));
     675                 :             :         }
     676                 :             : 
     677         [ -  + ]:           1 :         while (secure_write(port, &GSSok, 1) != 1)
     678                 :             :         {
     679         [ #  # ]:           0 :             if (errno == EINTR)
     680                 :           0 :                 continue;
     681         [ #  # ]:           0 :             ereport(COMMERROR,
     682                 :             :                     (errcode_for_socket_access(),
     683                 :             :                      errmsg("failed to send GSSAPI negotiation response: %m")));
     684                 :           0 :             goto fail;          /* close the connection */
     685                 :             :         }
     686                 :             : 
     687                 :             : #ifdef ENABLE_GSS
     688                 :             :         if (GSSok == 'G' && secure_open_gssapi(port) == -1)
     689                 :             :             goto fail;
     690                 :             : #endif
     691                 :             : 
     692                 :           1 :         pfree(buf);
     693                 :           1 :         buf = NULL;
     694                 :             : 
     695                 :             :         /*
     696                 :             :          * At this point we should have no data already buffered.  If we do,
     697                 :             :          * it was received before we performed the GSS handshake, so it wasn't
     698                 :             :          * encrypted and indeed may have been injected by a man-in-the-middle.
     699                 :             :          * We report this case to the client.
     700                 :             :          */
     701         [ -  + ]:           1 :         if (pq_buffer_remaining_data() > 0)
     702         [ #  # ]:           0 :             ereport(FATAL,
     703                 :             :                     (errcode(ERRCODE_PROTOCOL_VIOLATION),
     704                 :             :                      errmsg("received unencrypted data after GSSAPI encryption request"),
     705                 :             :                      errdetail("This could be either a client-software bug or evidence of an attempted man-in-the-middle attack.")));
     706                 :             : 
     707                 :             :         /*
     708                 :             :          * regular startup packet, cancel, etc packet should follow, but not
     709                 :             :          * another GSS negotiation request, and an SSL request should only
     710                 :             :          * follow if GSS was rejected (client may negotiate in either order)
     711                 :             :          */
     712                 :           1 :         gss_done = true;
     713         [ -  + ]:           1 :         if (GSSok == 'G')
     714                 :             :         {
     715                 :             :             /*
     716                 :             :              * We are done with GSS and negotiated correctly, so consider the
     717                 :             :              * same for SSL.
     718                 :             :              */
     719                 :           0 :             ssl_done = true;
     720                 :             :         }
     721                 :           1 :         goto retry;
     722                 :             :     }
     723                 :             : 
     724                 :             :     /* Could add additional special packet types here */
     725                 :             : 
     726                 :             :     /*
     727                 :             :      * Set FrontendProtocol now so that ereport() knows what format to send if
     728                 :             :      * we fail during startup. We use the protocol version requested by the
     729                 :             :      * client unless it's higher than the latest version we support. It's
     730                 :             :      * possible that error message fields might look different in newer
     731                 :             :      * protocol versions, but that's something those new clients should be
     732                 :             :      * able to deal with.
     733                 :             :      */
     734                 :       15189 :     FrontendProtocol = Min(proto, PG_PROTOCOL_LATEST);
     735                 :             : 
     736                 :             :     /* Check that the major protocol version is in range. */
     737         [ +  - ]:       15189 :     if (PG_PROTOCOL_MAJOR(proto) < PG_PROTOCOL_MAJOR(PG_PROTOCOL_EARLIEST) ||
     738         [ +  + ]:       15189 :         PG_PROTOCOL_MAJOR(proto) > PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST))
     739         [ +  - ]:           1 :         ereport(FATAL,
     740                 :             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     741                 :             :                  errmsg("unsupported frontend protocol %u.%u: server supports %u.0 to %u.%u",
     742                 :             :                         PG_PROTOCOL_MAJOR(proto), PG_PROTOCOL_MINOR(proto),
     743                 :             :                         PG_PROTOCOL_MAJOR(PG_PROTOCOL_EARLIEST),
     744                 :             :                         PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST),
     745                 :             :                         PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST))));
     746                 :             : 
     747                 :             :     /*
     748                 :             :      * Now fetch parameters out of startup packet and save them into the Port
     749                 :             :      * structure.
     750                 :             :      */
     751                 :       15188 :     oldcontext = MemoryContextSwitchTo(TopMemoryContext);
     752                 :             : 
     753                 :             :     /* Handle protocol version 3 startup packet */
     754                 :             :     {
     755                 :       15188 :         int32       offset = sizeof(ProtocolVersion);
     756                 :       15188 :         List       *unrecognized_protocol_options = NIL;
     757                 :             : 
     758                 :             :         /*
     759                 :             :          * Scan packet body for name/option pairs.  We can assume any string
     760                 :             :          * beginning within the packet body is null-terminated, thanks to
     761                 :             :          * zeroing extra byte above.
     762                 :             :          */
     763                 :       15188 :         port->guc_options = NIL;
     764                 :             : 
     765         [ +  - ]:       88503 :         while (offset < len)
     766                 :             :         {
     767                 :       88503 :             char       *nameptr = buf + offset;
     768                 :             :             int32       valoffset;
     769                 :             :             char       *valptr;
     770                 :             : 
     771         [ +  + ]:       88503 :             if (*nameptr == '\0')
     772                 :       15188 :                 break;          /* found packet terminator */
     773                 :       73315 :             valoffset = offset + strlen(nameptr) + 1;
     774         [ -  + ]:       73315 :             if (valoffset >= len)
     775                 :           0 :                 break;          /* missing value, will complain below */
     776                 :       73315 :             valptr = buf + valoffset;
     777                 :             : 
     778         [ +  + ]:       73315 :             if (strcmp(nameptr, "database") == 0)
     779                 :       15188 :                 port->database_name = pstrdup(valptr);
     780         [ +  + ]:       58127 :             else if (strcmp(nameptr, "user") == 0)
     781                 :       15188 :                 port->user_name = pstrdup(valptr);
     782         [ +  + ]:       42939 :             else if (strcmp(nameptr, "options") == 0)
     783                 :        4590 :                 port->cmdline_options = pstrdup(valptr);
     784         [ +  + ]:       38349 :             else if (strcmp(nameptr, "replication") == 0)
     785                 :             :             {
     786                 :             :                 /*
     787                 :             :                  * Due to backward compatibility concerns the replication
     788                 :             :                  * parameter is a hybrid beast which allows the value to be
     789                 :             :                  * either boolean or the string 'database'. The latter
     790                 :             :                  * connects to a specific database which is e.g. required for
     791                 :             :                  * logical decoding while.
     792                 :             :                  */
     793         [ +  + ]:        1398 :                 if (strcmp(valptr, "database") == 0)
     794                 :             :                 {
     795                 :         839 :                     am_walsender = true;
     796                 :         839 :                     am_db_walsender = true;
     797                 :             :                 }
     798         [ -  + ]:         559 :                 else if (!parse_bool(valptr, &am_walsender))
     799         [ #  # ]:           0 :                     ereport(FATAL,
     800                 :             :                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     801                 :             :                              errmsg("invalid value for parameter \"%s\": \"%s\"",
     802                 :             :                                     "replication",
     803                 :             :                                     valptr),
     804                 :             :                              errhint("Valid values are: \"false\", 0, \"true\", 1, \"database\".")));
     805                 :             :             }
     806         [ +  + ]:       36951 :             else if (strncmp(nameptr, "_pq_.", 5) == 0)
     807                 :             :             {
     808                 :             :                 /*
     809                 :             :                  * Any option beginning with _pq_. is reserved for use as a
     810                 :             :                  * protocol-level option, but at present no such options are
     811                 :             :                  * defined.
     812                 :             :                  */
     813                 :             :                 unrecognized_protocol_options =
     814                 :       15167 :                     lappend(unrecognized_protocol_options, pstrdup(nameptr));
     815                 :             :             }
     816                 :             :             else
     817                 :             :             {
     818                 :             :                 /* Assume it's a generic GUC option */
     819                 :       21784 :                 port->guc_options = lappend(port->guc_options,
     820                 :       21784 :                                             pstrdup(nameptr));
     821                 :       21784 :                 port->guc_options = lappend(port->guc_options,
     822                 :       21784 :                                             pstrdup(valptr));
     823                 :             : 
     824                 :             :                 /*
     825                 :             :                  * Copy application_name to port if we come across it.  This
     826                 :             :                  * is done so we can log the application_name in the
     827                 :             :                  * connection authorization message.  Note that the GUC would
     828                 :             :                  * be used but we haven't gone through GUC setup yet.
     829                 :             :                  */
     830         [ +  + ]:       21784 :                 if (strcmp(nameptr, "application_name") == 0)
     831                 :             :                 {
     832                 :       15183 :                     port->application_name = pg_clean_ascii(valptr, 0);
     833                 :             :                 }
     834                 :             :             }
     835                 :       73315 :             offset = valoffset + strlen(valptr) + 1;
     836                 :             :         }
     837                 :             : 
     838                 :             :         /*
     839                 :             :          * If we didn't find a packet terminator exactly at the end of the
     840                 :             :          * given packet length, complain.
     841                 :             :          */
     842         [ -  + ]:       15188 :         if (offset != len - 1)
     843         [ #  # ]:           0 :             ereport(FATAL,
     844                 :             :                     (errcode(ERRCODE_PROTOCOL_VIOLATION),
     845                 :             :                      errmsg("invalid startup packet layout: expected terminator as last byte")));
     846                 :             : 
     847                 :             :         /*
     848                 :             :          * If the client requested a newer protocol version or if the client
     849                 :             :          * requested any protocol options we didn't recognize, let them know
     850                 :             :          * the newest minor protocol version we do support and the names of
     851                 :             :          * any unrecognized options.
     852                 :             :          */
     853   [ +  +  -  + ]:       15188 :         if (PG_PROTOCOL_MINOR(proto) > PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST) ||
     854                 :             :             unrecognized_protocol_options != NIL)
     855                 :       15167 :             SendNegotiateProtocolVersion(unrecognized_protocol_options);
     856                 :             : 
     857                 :       15188 :         list_free_deep(unrecognized_protocol_options);
     858                 :             :     }
     859                 :             : 
     860                 :             :     /* Check a user name was given. */
     861   [ +  -  -  + ]:       15188 :     if (port->user_name == NULL || port->user_name[0] == '\0')
     862         [ #  # ]:           0 :         ereport(FATAL,
     863                 :             :                 (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
     864                 :             :                  errmsg("no PostgreSQL user name specified in startup packet")));
     865                 :             : 
     866                 :             :     /* The database defaults to the user name. */
     867   [ +  -  -  + ]:       15188 :     if (port->database_name == NULL || port->database_name[0] == '\0')
     868                 :           0 :         port->database_name = pstrdup(port->user_name);
     869                 :             : 
     870                 :             :     /*
     871                 :             :      * Truncate given database and user names to length of a Postgres name.
     872                 :             :      * This avoids lookup failures when overlength names are given.
     873                 :             :      */
     874         [ -  + ]:       15188 :     if (strlen(port->database_name) >= NAMEDATALEN)
     875                 :           0 :         port->database_name[NAMEDATALEN - 1] = '\0';
     876         [ -  + ]:       15188 :     if (strlen(port->user_name) >= NAMEDATALEN)
     877                 :           0 :         port->user_name[NAMEDATALEN - 1] = '\0';
     878                 :             : 
     879                 :             :     Assert(MyBackendType == B_BACKEND || MyBackendType == B_DEAD_END_BACKEND);
     880         [ +  + ]:       15188 :     if (am_walsender)
     881                 :        1398 :         MyBackendType = B_WAL_SENDER;
     882                 :             : 
     883                 :             :     /*
     884                 :             :      * Normal walsender backends, e.g. for streaming replication, are not
     885                 :             :      * connected to a particular database. But walsenders used for logical
     886                 :             :      * replication need to connect to a specific database. We allow streaming
     887                 :             :      * replication commands to be issued even if connected to a database as it
     888                 :             :      * can make sense to first make a basebackup and then stream changes
     889                 :             :      * starting from that.
     890                 :             :      */
     891   [ +  +  +  + ]:       15188 :     if (am_walsender && !am_db_walsender)
     892                 :         559 :         port->database_name[0] = '\0';
     893                 :             : 
     894                 :             :     /*
     895                 :             :      * Done filling the Port structure
     896                 :             :      */
     897                 :       15188 :     MemoryContextSwitchTo(oldcontext);
     898                 :             : 
     899                 :       15188 :     pfree(buf);
     900                 :             : 
     901                 :       15188 :     return STATUS_OK;
     902                 :             : 
     903                 :          63 : fail:
     904                 :             :     /* be tidy, just to avoid Valgrind complaints */
     905         [ +  + ]:          63 :     if (buf)
     906                 :          48 :         pfree(buf);
     907                 :             : 
     908                 :          63 :     return STATUS_ERROR;
     909                 :             : }
     910                 :             : 
     911                 :             : /*
     912                 :             :  * The client has sent a cancel request packet, not a normal
     913                 :             :  * start-a-new-connection packet.  Perform the necessary processing.  Nothing
     914                 :             :  * is sent back to the client.
     915                 :             :  */
     916                 :             : static void
     917                 :          16 : ProcessCancelRequestPacket(Port *port, void *pkt, int pktlen)
     918                 :             : {
     919                 :             :     CancelRequestPacket *canc;
     920                 :             :     int         len;
     921                 :             : 
     922         [ -  + ]:          16 :     if (pktlen < offsetof(CancelRequestPacket, cancelAuthCode))
     923                 :             :     {
     924         [ #  # ]:           0 :         ereport(COMMERROR,
     925                 :             :                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     926                 :             :                  errmsg("invalid length of cancel request packet")));
     927                 :           0 :         return;
     928                 :             :     }
     929                 :          16 :     len = pktlen - offsetof(CancelRequestPacket, cancelAuthCode);
     930   [ +  -  -  + ]:          16 :     if (len == 0 || len > 256)
     931                 :             :     {
     932         [ #  # ]:           0 :         ereport(COMMERROR,
     933                 :             :                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     934                 :             :                  errmsg("invalid length of cancel key in cancel request packet")));
     935                 :           0 :         return;
     936                 :             :     }
     937                 :             : 
     938                 :          16 :     canc = (CancelRequestPacket *) pkt;
     939                 :          16 :     SendCancelRequest(pg_ntoh32(canc->backendPID), canc->cancelAuthCode, len);
     940                 :             : }
     941                 :             : 
     942                 :             : /*
     943                 :             :  * Send a NegotiateProtocolVersion to the client.  This lets the client know
     944                 :             :  * that they have either requested a newer minor protocol version than we are
     945                 :             :  * able to speak, or at least one protocol option that we don't understand, or
     946                 :             :  * possibly both. FrontendProtocol has already been set to the version
     947                 :             :  * requested by the client or the highest version we know how to speak,
     948                 :             :  * whichever is older. If the highest version that we know how to speak is too
     949                 :             :  * old for the client, it can abandon the connection.
     950                 :             :  *
     951                 :             :  * We also include in the response a list of protocol options we didn't
     952                 :             :  * understand.  This allows clients to include optional parameters that might
     953                 :             :  * be present either in newer protocol versions or third-party protocol
     954                 :             :  * extensions without fear of having to reconnect if those options are not
     955                 :             :  * understood, while at the same time making certain that the client is aware
     956                 :             :  * of which options were actually accepted.
     957                 :             :  */
     958                 :             : static void
     959                 :       15167 : SendNegotiateProtocolVersion(List *unrecognized_protocol_options)
     960                 :             : {
     961                 :             :     StringInfoData buf;
     962                 :             :     ListCell   *lc;
     963                 :             : 
     964                 :       15167 :     pq_beginmessage(&buf, PqMsg_NegotiateProtocolVersion);
     965                 :       15167 :     pq_sendint32(&buf, FrontendProtocol);
     966                 :       15167 :     pq_sendint32(&buf, list_length(unrecognized_protocol_options));
     967   [ +  -  +  +  :       30334 :     foreach(lc, unrecognized_protocol_options)
                   +  + ]
     968                 :       15167 :         pq_sendstring(&buf, lfirst(lc));
     969                 :       15167 :     pq_endmessage(&buf);
     970                 :             : 
     971                 :             :     /* no need to flush, some other message will follow */
     972                 :       15167 : }
     973                 :             : 
     974                 :             : 
     975                 :             : /*
     976                 :             :  * SIGTERM while processing startup packet.
     977                 :             :  *
     978                 :             :  * Running proc_exit() from a signal handler would be quite unsafe.
     979                 :             :  * However, since we have not yet touched shared memory, we can just
     980                 :             :  * pull the plug and exit without running any atexit handlers.
     981                 :             :  *
     982                 :             :  * One might be tempted to try to send a message, or log one, indicating
     983                 :             :  * why we are disconnecting.  However, that would be quite unsafe in itself.
     984                 :             :  * Also, it seems undesirable to provide clues about the database's state
     985                 :             :  * to a client that has not yet completed authentication, or even sent us
     986                 :             :  * a startup packet.
     987                 :             :  */
     988                 :             : static void
     989                 :           0 : process_startup_packet_die(SIGNAL_ARGS)
     990                 :             : {
     991                 :           0 :     _exit(1);
     992                 :             : }
     993                 :             : 
     994                 :             : /*
     995                 :             :  * Timeout while processing startup packet.
     996                 :             :  * As for process_startup_packet_die(), we exit via _exit(1).
     997                 :             :  */
     998                 :             : static void
     999                 :           0 : StartupPacketTimeoutHandler(void)
    1000                 :             : {
    1001                 :           0 :     _exit(1);
    1002                 :             : }
    1003                 :             : 
    1004                 :             : /*
    1005                 :             :  * Helper for the log_connections GUC check hook.
    1006                 :             :  *
    1007                 :             :  * `elemlist` is a listified version of the string input passed to the
    1008                 :             :  * log_connections GUC check hook, check_log_connections().
    1009                 :             :  * check_log_connections() is responsible for cleaning up `elemlist`.
    1010                 :             :  *
    1011                 :             :  * validate_log_connections_options() returns false if an error was
    1012                 :             :  * encountered and the GUC input could not be validated and true otherwise.
    1013                 :             :  *
    1014                 :             :  * `flags` returns the flags that should be stored in the log_connections GUC
    1015                 :             :  * by its assign hook.
    1016                 :             :  */
    1017                 :             : static bool
    1018                 :        1455 : validate_log_connections_options(List *elemlist, uint32 *flags)
    1019                 :             : {
    1020                 :             :     ListCell   *l;
    1021                 :             :     char       *item;
    1022                 :             : 
    1023                 :             :     /*
    1024                 :             :      * For backwards compatibility, we accept these tokens by themselves.
    1025                 :             :      *
    1026                 :             :      * Prior to PostgreSQL 18, log_connections was a boolean GUC that accepted
    1027                 :             :      * any unambiguous substring of 'true', 'false', 'yes', 'no', 'on', and
    1028                 :             :      * 'off'. Since log_connections became a list of strings in 18, we only
    1029                 :             :      * accept complete option strings.
    1030                 :             :      */
    1031                 :             :     static const struct config_enum_entry compat_options[] = {
    1032                 :             :         {"off", 0},
    1033                 :             :         {"false", 0},
    1034                 :             :         {"no", 0},
    1035                 :             :         {"0", 0},
    1036                 :             :         {"on", LOG_CONNECTION_ON},
    1037                 :             :         {"true", LOG_CONNECTION_ON},
    1038                 :             :         {"yes", LOG_CONNECTION_ON},
    1039                 :             :         {"1", LOG_CONNECTION_ON},
    1040                 :             :     };
    1041                 :             : 
    1042                 :        1455 :     *flags = 0;
    1043                 :             : 
    1044                 :             :     /* If an empty string was passed, we're done */
    1045         [ +  + ]:        1455 :     if (list_length(elemlist) == 0)
    1046                 :        1303 :         return true;
    1047                 :             : 
    1048                 :             :     /*
    1049                 :             :      * Now check for the backwards compatibility options. They must always be
    1050                 :             :      * specified on their own, so we error out if the first option is a
    1051                 :             :      * backwards compatibility option and other options are also specified.
    1052                 :             :      */
    1053                 :         152 :     item = linitial(elemlist);
    1054                 :             : 
    1055         [ +  + ]:        1364 :     for (size_t i = 0; i < lengthof(compat_options); i++)
    1056                 :             :     {
    1057                 :        1213 :         struct config_enum_entry option = compat_options[i];
    1058                 :             : 
    1059         [ +  + ]:        1213 :         if (pg_strcasecmp(item, option.name) != 0)
    1060                 :        1212 :             continue;
    1061                 :             : 
    1062         [ -  + ]:           1 :         if (list_length(elemlist) > 1)
    1063                 :             :         {
    1064                 :           0 :             GUC_check_errdetail("Cannot specify log_connections option \"%s\" in a list with other options.",
    1065                 :             :                                 item);
    1066                 :           1 :             return false;
    1067                 :             :         }
    1068                 :             : 
    1069                 :           1 :         *flags = option.val;
    1070                 :           1 :         return true;
    1071                 :             :     }
    1072                 :             : 
    1073                 :             :     /* Now check the aspect options. The empty string was already handled */
    1074   [ +  -  +  +  :         341 :     foreach(l, elemlist)
                   +  + ]
    1075                 :             :     {
    1076                 :             :         static const struct config_enum_entry options[] = {
    1077                 :             :             {"receipt", LOG_CONNECTION_RECEIPT},
    1078                 :             :             {"authentication", LOG_CONNECTION_AUTHENTICATION},
    1079                 :             :             {"authorization", LOG_CONNECTION_AUTHORIZATION},
    1080                 :             :             {"setup_durations", LOG_CONNECTION_SETUP_DURATIONS},
    1081                 :             :             {"all", LOG_CONNECTION_ALL},
    1082                 :             :         };
    1083                 :             : 
    1084                 :         190 :         item = lfirst(l);
    1085         [ +  - ]:         676 :         for (size_t i = 0; i < lengthof(options); i++)
    1086                 :             :         {
    1087                 :         676 :             struct config_enum_entry option = options[i];
    1088                 :             : 
    1089         [ +  + ]:         676 :             if (pg_strcasecmp(item, option.name) == 0)
    1090                 :             :             {
    1091                 :         190 :                 *flags |= option.val;
    1092                 :         190 :                 goto next;
    1093                 :             :             }
    1094                 :             :         }
    1095                 :             : 
    1096                 :           0 :         GUC_check_errdetail("Invalid option \"%s\".", item);
    1097                 :           0 :         return false;
    1098                 :             : 
    1099                 :         190 : next:   ;
    1100                 :             :     }
    1101                 :             : 
    1102                 :         151 :     return true;
    1103                 :             : }
    1104                 :             : 
    1105                 :             : 
    1106                 :             : /*
    1107                 :             :  * GUC check hook for log_connections
    1108                 :             :  */
    1109                 :             : bool
    1110                 :        1455 : check_log_connections(char **newval, void **extra, GucSource source)
    1111                 :             : {
    1112                 :             :     uint32      flags;
    1113                 :             :     char       *rawstring;
    1114                 :             :     List       *elemlist;
    1115                 :             :     bool        success;
    1116                 :             : 
    1117                 :             :     /* Need a modifiable copy of string */
    1118                 :        1455 :     rawstring = pstrdup(*newval);
    1119                 :             : 
    1120         [ -  + ]:        1455 :     if (!SplitIdentifierString(rawstring, ',', &elemlist))
    1121                 :             :     {
    1122                 :           0 :         GUC_check_errdetail("Invalid list syntax in parameter \"%s\".", "log_connections");
    1123                 :           0 :         pfree(rawstring);
    1124                 :           0 :         list_free(elemlist);
    1125                 :           0 :         return false;
    1126                 :             :     }
    1127                 :             : 
    1128                 :             :     /* Validation logic is all in the helper */
    1129                 :        1455 :     success = validate_log_connections_options(elemlist, &flags);
    1130                 :             : 
    1131                 :             :     /* Time for cleanup */
    1132                 :        1455 :     pfree(rawstring);
    1133                 :        1455 :     list_free(elemlist);
    1134                 :             : 
    1135         [ -  + ]:        1455 :     if (!success)
    1136                 :           0 :         return false;
    1137                 :             : 
    1138                 :             :     /*
    1139                 :             :      * We succeeded, so allocate `extra` and save the flags there for use by
    1140                 :             :      * assign_log_connections().
    1141                 :             :      */
    1142                 :        1455 :     *extra = guc_malloc(LOG, sizeof(int));
    1143         [ -  + ]:        1455 :     if (!*extra)
    1144                 :           0 :         return false;
    1145                 :        1455 :     *((int *) *extra) = flags;
    1146                 :             : 
    1147                 :        1455 :     return true;
    1148                 :             : }
    1149                 :             : 
    1150                 :             : /*
    1151                 :             :  * GUC assign hook for log_connections
    1152                 :             :  */
    1153                 :             : void
    1154                 :        1451 : assign_log_connections(const char *newval, void *extra)
    1155                 :             : {
    1156                 :        1451 :     log_connections = *((int *) extra);
    1157                 :        1451 : }
        

Generated by: LCOV version 2.0-1