LCOV - differential code coverage report
Current view: top level - src/backend/tcop - backend_startup.c (source / functions) Coverage Total Hit UNC UBC GNC CBC DUB DCB
Current: c70b6db34ffeab48beef1fb4ce61bcad3772b8dd vs 06473f5a344df8c9594ead90a609b86f6724cff8 Lines: 79.5 % 293 233 5 55 12 221 6 3
Current Date: 2025-09-06 07:49:51 +0900 Functions: 72.7 % 11 8 3 1 7
Baseline: lcov-20250906-005545-baseline Branches: 56.4 % 273 154 119 2 152
Baseline Date: 2025-09-05 08:21:35 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(30,360] days: 75.3 % 85 64 5 16 12 52
(360..) days: 81.2 % 208 169 39 169
Function coverage date bins:
(30,360] days: 100.0 % 5 5 5
(360..) days: 50.0 % 6 3 3 1 2
Branch coverage date bins:
(30,360] days: 62.0 % 50 31 19 2 29
(360..) days: 55.2 % 223 123 100 123

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * backend_startup.c
                                  4                 :                :  *    Backend startup code
                                  5                 :                :  *
                                  6                 :                :  * Portions Copyright (c) 1996-2025, 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
  197 peter@eisentraut.org       76                 :CBC       12358 : BackendMain(const void *startup_data, size_t startup_data_len)
                                 77                 :                : {
                                 78                 :          12358 :     const BackendStartupData *bsdata = startup_data;
                                 79                 :                : 
  537 heikki.linnakangas@i       80         [ -  + ]:          12358 :     Assert(startup_data_len == sizeof(BackendStartupData));
                                 81         [ -  + ]:          12358 :     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                 :          12358 :     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                 :          12034 :     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                 :          12031 :     MemoryContextSwitchTo(TopMemoryContext);
                                123                 :                : 
                                124                 :          12031 :     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                 :          12358 : 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                 :          12358 :     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         [ -  + ]:          12358 :     if (PreAuthDelay > 0)
  537 heikki.linnakangas@i      162                 :UBC           0 :         pg_usleep(PreAuthDelay * 1000000L);
                                163                 :                : 
                                164                 :                :     /* This flag will remain set until InitPostgres finishes authentication */
  537 heikki.linnakangas@i      165                 :CBC       12358 :     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                 :          12358 :     oldcontext = MemoryContextSwitchTo(TopMemoryContext);
                                177                 :          12358 :     port = MyProcPort = pq_init(client_sock);
                                178                 :          12358 :     MemoryContextSwitchTo(oldcontext);
                                179                 :                : 
                                180                 :          12358 :     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                 :          12358 :     port->remote_host = "";
                                184                 :          12358 :     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                 :          12358 :     pqsignal(SIGTERM, process_startup_packet_die);
                                197                 :                :     /* SIGQUIT handler was already set up by InitPostmasterChild */
                                198                 :          12358 :     InitializeTimeouts();       /* establishes SIGALRM handler */
                                199                 :          12358 :     sigprocmask(SIG_SETMASK, &StartupBlockSig, NULL);
                                200                 :                : 
                                201                 :                :     /*
                                202                 :                :      * Get the remote host name and port for logging and status display.
                                203                 :                :      */
                                204                 :          12358 :     remote_host[0] = '\0';
                                205                 :          12358 :     remote_port[0] = '\0';
                                206   [ +  +  -  + ]:          12358 :     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)
  537 heikki.linnakangas@i      210         [ #  # ]:UBC           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                 :                :      */
  432 tgl@sss.pgh.pa.us         218                 :CBC       12358 :     port->remote_host = MemoryContextStrdup(TopMemoryContext, remote_host);
                                219                 :          12358 :     port->remote_port = MemoryContextStrdup(TopMemoryContext, remote_port);
                                220                 :                : 
                                221                 :                :     /* And now we can log that the connection was received, if enabled */
  178 melanieplageman@gmai      222         [ +  + ]:          12358 :     if (log_connections & LOG_CONNECTION_RECEIPT)
                                223                 :                :     {
  537 heikki.linnakangas@i      224         [ +  + ]:            655 :         if (remote_port[0])
                                225         [ +  - ]:            340 :             ereport(LOG,
                                226                 :                :                     (errmsg("connection received: host=%s port=%s",
                                227                 :                :                             remote_host,
                                228                 :                :                             remote_port)));
                                229                 :                :         else
                                230         [ +  - ]:            315 :             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                 :                :     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   [ +  +  +  - ]:          12358 :     if (log_hostname &&
                                262                 :            117 :         ret == 0 &&
                                263         [ +  - ]:            117 :         strspn(remote_host, "0123456789.") < strlen(remote_host) &&
                                264         [ +  - ]:            117 :         strspn(remote_host, "0123456789ABCDEFabcdef:") < strlen(remote_host))
                                265                 :                :     {
  432 tgl@sss.pgh.pa.us         266                 :            117 :         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                 :                :      */
  537 heikki.linnakangas@i      284                 :          12358 :     RegisterTimeout(STARTUP_PACKET_TIMEOUT, StartupPacketTimeoutHandler);
                                285                 :          12358 :     enable_timeout_after(STARTUP_PACKET_TIMEOUT, AuthenticationTimeout * 1000);
                                286                 :                : 
                                287                 :                :     /* Handle direct SSL handshake */
  516                           288                 :          12358 :     status = ProcessSSLStartup(port);
                                289                 :                : 
                                290                 :                :     /*
                                291                 :                :      * Receive the startup packet (which might turn out to be a cancel request
                                292                 :                :      * packet).
                                293                 :                :      */
                                294         [ +  + ]:          12358 :     if (status == STATUS_OK)
                                295                 :          12350 :         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                 :                :      */
  537                           302         [ +  + ]:          12358 :     if (status == STATUS_OK)
                                303                 :                :     {
                                304   [ +  +  +  +  :          12295 :         switch (cac)
                                           +  +  - ]
                                305                 :                :         {
                                306                 :            217 :             case CAC_STARTUP:
                                307         [ +  - ]:            217 :                 ereport(FATAL,
                                308                 :                :                         (errcode(ERRCODE_CANNOT_CONNECT_NOW),
                                309                 :                :                          errmsg("the database system is starting up")));
                                310                 :                :                 break;
  157 fujii@postgresql.org      311                 :              5 :             case CAC_NOTHOTSTANDBY:
                                312         [ -  + ]:              5 :                 if (!EnableHotStandby)
  157 fujii@postgresql.org      313         [ #  # ]:UBC           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.")));
  157 fujii@postgresql.org      317         [ -  + ]:CBC           5 :                 else if (reachedConsistency)
  537 heikki.linnakangas@i      318         [ #  # ]:UBC           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
  537 heikki.linnakangas@i      325         [ +  - ]:CBC           5 :                     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                 :             36 :             case CAC_SHUTDOWN:
                                331         [ +  - ]:             36 :                 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                 :          12034 :             case CAC_OK:
                                346                 :          12034 :                 break;
                                347                 :                :         }
                                348                 :                :     }
                                349                 :                : 
                                350                 :                :     /*
                                351                 :                :      * Disable the timeout, and prevent SIGTERM again.
                                352                 :                :      */
                                353                 :          12097 :     disable_timeout(STARTUP_PACKET_TIMEOUT, false);
                                354                 :          12097 :     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                 :          12097 :     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         [ +  + ]:          12097 :     if (status != STATUS_OK)
                                372                 :             63 :         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                 :          12034 :     initStringInfo(&ps_data);
                                379         [ +  + ]:          12034 :     if (am_walsender)
                                380                 :           1101 :         appendStringInfo(&ps_data, "%s ", GetBackendTypeDesc(B_WAL_SENDER));
                                381                 :          12034 :     appendStringInfo(&ps_data, "%s ", port->user_name);
                                382         [ +  + ]:          12034 :     if (port->database_name[0] != '\0')
                                383                 :          11583 :         appendStringInfo(&ps_data, "%s ", port->database_name);
                                384                 :          12034 :     appendStringInfoString(&ps_data, port->remote_host);
                                385         [ +  + ]:          12034 :     if (port->remote_port[0] != '\0')
                                386                 :            295 :         appendStringInfo(&ps_data, "(%s)", port->remote_port);
                                387                 :                : 
                                388                 :          12034 :     init_ps_display(ps_data.data);
                                389                 :          12034 :     pfree(ps_data.data);
                                390                 :                : 
                                391                 :          12034 :     set_ps_display("initializing");
                                392                 :          12034 : }
                                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
  516                           401                 :          12358 : ProcessSSLStartup(Port *port)
                                402                 :                : {
                                403                 :                :     int         firstbyte;
                                404                 :                : 
                                405         [ -  + ]:          12358 :     Assert(!port->ssl_in_use);
                                406                 :                : 
                                407                 :          12358 :     pq_startmsgread();
                                408                 :          12358 :     firstbyte = pq_peekbyte();
                                409                 :          12358 :     pq_endmsgread();
                                410         [ +  + ]:          12358 :     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         [ +  + ]:          12356 :     if (firstbyte != 0x16)
                                420                 :                :     {
                                421                 :                :         /* Not an SSL handshake message */
                                422                 :          12340 :         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   [ +  +  -  + ]:             16 :     if (!LoadedSSL || port->laddr.addr.ss_family == AF_UNIX)
                                434                 :                :     {
                                435                 :                :         /* SSL not supported */
                                436                 :              6 :         goto reject;
                                437                 :                :     }
                                438                 :                : 
                                439         [ -  + ]:             10 :     if (secure_open_server(port) == -1)
                                440                 :                :     {
                                441                 :                :         /*
                                442                 :                :          * we assume secure_open_server() sent an appropriate TLS alert
                                443                 :                :          * already
                                444                 :                :          */
  516 heikki.linnakangas@i      445                 :UBC           0 :         goto reject;
                                446                 :                :     }
  516 heikki.linnakangas@i      447         [ -  + ]:CBC          10 :     Assert(port->ssl_in_use);
                                448                 :                : 
                                449         [ -  + ]:             10 :     if (!port->alpn_used)
                                450                 :                :     {
  516 heikki.linnakangas@i      451         [ #  # ]:UBC           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                 :                : 
  516 heikki.linnakangas@i      457         [ +  - ]:CBC          10 :     if (Trace_connection_negotiation)
                                458         [ +  - ]:             10 :         ereport(LOG,
                                459                 :                :                 (errmsg("direct SSL connection accepted")));
                                460                 :             10 :     return STATUS_OK;
                                461                 :                : #else
                                462                 :                :     /* SSL not supported by this build */
                                463                 :                :     goto reject;
                                464                 :                : #endif
                                465                 :                : 
                                466                 :              6 : reject:
                                467         [ +  - ]:              6 :     if (Trace_connection_negotiation)
                                468         [ +  - ]:              6 :         ereport(LOG,
                                469                 :                :                 (errmsg("direct SSL connection rejected")));
                                470                 :              6 :     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                 :                :  * 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
  537                           492                 :          12619 : ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done)
                                493                 :                : {
                                494                 :                :     int32       len;
   35 tgl@sss.pgh.pa.us         495                 :GNC       12619 :     char       *buf = NULL;
                                496                 :                :     ProtocolVersion proto;
                                497                 :                :     MemoryContext oldcontext;
                                498                 :                : 
  537 heikki.linnakangas@i      499                 :CBC       12619 :     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                 :                :      */
  195 peter@eisentraut.org      507         [ +  + ]:          12619 :     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                 :                :          */
   35 tgl@sss.pgh.pa.us         519                 :GNC          20 :         goto fail;
                                520                 :                :     }
                                521                 :                : 
  537 heikki.linnakangas@i      522         [ -  + ]:CBC       12599 :     if (pq_getbytes(((char *) &len) + 1, 3) == EOF)
                                523                 :                :     {
                                524                 :                :         /* Got a partial length word, so bleat about that */
  537 heikki.linnakangas@i      525   [ #  #  #  # ]:UBC           0 :         if (!ssl_done && !gss_done)
                                526         [ #  # ]:              0 :             ereport(COMMERROR,
                                527                 :                :                     (errcode(ERRCODE_PROTOCOL_VIOLATION),
                                528                 :                :                      errmsg("incomplete startup packet")));
   35 tgl@sss.pgh.pa.us         529                 :UNC           0 :         goto fail;
                                530                 :                :     }
                                531                 :                : 
  537 heikki.linnakangas@i      532                 :CBC       12599 :     len = pg_ntoh32(len);
                                533                 :          12599 :     len -= 4;
                                534                 :                : 
                                535         [ +  - ]:          12599 :     if (len < (int32) sizeof(ProtocolVersion) ||
                                536         [ -  + ]:          12599 :         len > MAX_STARTUP_PACKET_LENGTH)
                                537                 :                :     {
  537 heikki.linnakangas@i      538         [ #  # ]:UBC           0 :         ereport(COMMERROR,
                                539                 :                :                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
                                540                 :                :                  errmsg("invalid length of startup packet")));
   35 tgl@sss.pgh.pa.us         541                 :UNC           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                 :                :      */
  537 heikki.linnakangas@i      549                 :CBC       12599 :     buf = palloc(len + 1);
                                550                 :          12599 :     buf[len] = '\0';
                                551                 :                : 
                                552         [ -  + ]:          12599 :     if (pq_getbytes(buf, len) == EOF)
                                553                 :                :     {
  537 heikki.linnakangas@i      554         [ #  # ]:UBC           0 :         ereport(COMMERROR,
                                555                 :                :                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
                                556                 :                :                  errmsg("incomplete startup packet")));
   35 tgl@sss.pgh.pa.us         557                 :UNC           0 :         goto fail;
                                558                 :                :     }
  537 heikki.linnakangas@i      559                 :CBC       12599 :     pq_endmsgread();
                                560                 :                : 
                                561                 :                :     /*
                                562                 :                :      * The first field is either a protocol version number or a special
                                563                 :                :      * request code.
                                564                 :                :      */
                                565                 :          12599 :     port->proto = proto = pg_ntoh32(*((ProtocolVersion *) buf));
                                566                 :                : 
                                567         [ +  + ]:          12599 :     if (proto == CANCEL_REQUEST_CODE)
                                568                 :                :     {
  157                           569                 :             16 :         ProcessCancelRequestPacket(port, buf, len);
                                570                 :                :         /* Not really an error, but we don't want to proceed further */
   35 tgl@sss.pgh.pa.us         571                 :GNC          16 :         goto fail;
                                572                 :                :     }
                                573                 :                : 
  537 heikki.linnakangas@i      574   [ +  +  +  - ]:CBC       12583 :     if (proto == NEGOTIATE_SSL_CODE && !ssl_done)
                                575                 :                :     {
                                576                 :                :         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                 :                :          */
  516                           585   [ +  +  +  -  :            167 :         if (!LoadedSSL || port->laddr.addr.ss_family == AF_UNIX || port->ssl_in_use)
                                              -  + ]
  537                           586                 :             27 :             SSLok = 'N';
                                587                 :                :         else
                                588                 :            140 :             SSLok = 'S';        /* Support for SSL */
                                589                 :                : #else
                                590                 :                :         SSLok = 'N';            /* No support for SSL */
                                591                 :                : #endif
                                592                 :                : 
  516                           593         [ +  + ]:            167 :         if (Trace_connection_negotiation)
                                594                 :                :         {
                                595         [ +  + ]:             37 :             if (SSLok == 'S')
                                596         [ +  - ]:             24 :                 ereport(LOG,
                                597                 :                :                         (errmsg("SSLRequest accepted")));
                                598                 :                :             else
                                599         [ +  - ]:             13 :                 ereport(LOG,
                                600                 :                :                         (errmsg("SSLRequest rejected")));
                                601                 :                :         }
                                602                 :                : 
                                603         [ -  + ]:            167 :         while (secure_write(port, &SSLok, 1) != 1)
                                604                 :                :         {
  537 heikki.linnakangas@i      605         [ #  # ]:UBC           0 :             if (errno == EINTR)
  516                           606                 :              0 :                 continue;       /* if interrupted, just retry */
  537                           607         [ #  # ]:              0 :             ereport(COMMERROR,
                                608                 :                :                     (errcode_for_socket_access(),
                                609                 :                :                      errmsg("failed to send SSL negotiation response: %m")));
   35 tgl@sss.pgh.pa.us         610                 :GNC          19 :             goto fail;          /* close the connection */
                                611                 :                :         }
                                612                 :                : 
                                613                 :                : #ifdef USE_SSL
  537 heikki.linnakangas@i      614   [ +  +  +  + ]:CBC         167 :         if (SSLok == 'S' && secure_open_server(port) == -1)
   35 tgl@sss.pgh.pa.us         615                 :GNC          19 :             goto fail;
                                616                 :                : #endif
                                617                 :                : 
                                618                 :            148 :         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                 :                :          */
  516 heikki.linnakangas@i      626         [ -  + ]:CBC         148 :         if (pq_buffer_remaining_data() > 0)
  537 heikki.linnakangas@i      627         [ #  # ]:UBC           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                 :                :          */
  537 heikki.linnakangas@i      637                 :CBC         148 :         return ProcessStartupPacket(port, true, SSLok == 'S');
                                638                 :                :     }
                                639   [ +  +  +  - ]:          12416 :     else if (proto == NEGOTIATE_GSS_CODE && !gss_done)
                                640                 :                :     {
                                641                 :            121 :         char        GSSok = 'N';
                                642                 :                : 
                                643                 :                : #ifdef ENABLE_GSS
                                644                 :                :         /* No GSSAPI encryption when on Unix socket */
                                645         [ +  - ]:            121 :         if (port->laddr.addr.ss_family != AF_UNIX)
                                646                 :            121 :             GSSok = 'G';
                                647                 :                : #endif
                                648                 :                : 
  516                           649         [ +  + ]:            121 :         if (Trace_connection_negotiation)
                                650                 :                :         {
                                651         [ +  - ]:             81 :             if (GSSok == 'G')
                                652         [ +  - ]:             81 :                 ereport(LOG,
                                653                 :                :                         (errmsg("GSSENCRequest accepted")));
                                654                 :                :             else
  516 heikki.linnakangas@i      655         [ #  # ]:UBC           0 :                 ereport(LOG,
                                656                 :                :                         (errmsg("GSSENCRequest rejected")));
                                657                 :                :         }
                                658                 :                : 
  516 heikki.linnakangas@i      659         [ -  + ]:CBC         121 :         while (secure_write(port, &GSSok, 1) != 1)
                                660                 :                :         {
  537 heikki.linnakangas@i      661         [ #  # ]:UBC           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")));
   35 tgl@sss.pgh.pa.us         666                 :UNC           0 :             goto fail;          /* close the connection */
                                667                 :                :         }
                                668                 :                : 
                                669                 :                : #ifdef ENABLE_GSS
  537 heikki.linnakangas@i      670   [ +  -  -  + ]:CBC         121 :         if (GSSok == 'G' && secure_open_gssapi(port) == -1)
   35 tgl@sss.pgh.pa.us         671                 :UNC           0 :             goto fail;
                                672                 :                : #endif
                                673                 :                : 
   35 tgl@sss.pgh.pa.us         674                 :GNC         121 :         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                 :                :          */
  516 heikki.linnakangas@i      682         [ -  + ]:CBC         121 :         if (pq_buffer_remaining_data() > 0)
  537 heikki.linnakangas@i      683         [ #  # ]:UBC           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                 :                :          */
  537 heikki.linnakangas@i      693                 :CBC         121 :         return ProcessStartupPacket(port, GSSok == 'G', true);
                                694                 :                :     }
                                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                 :                :      */
  387 rhaas@postgresql.org      706                 :          12295 :     FrontendProtocol = Min(proto, PG_PROTOCOL_LATEST);
                                707                 :                : 
                                708                 :                :     /* Check that the major protocol version is in range. */
  537 heikki.linnakangas@i      709         [ +  - ]:          12295 :     if (PG_PROTOCOL_MAJOR(proto) < PG_PROTOCOL_MAJOR(PG_PROTOCOL_EARLIEST) ||
                                710         [ -  + ]:          12295 :         PG_PROTOCOL_MAJOR(proto) > PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST))
  537 heikki.linnakangas@i      711         [ #  # ]:UBC           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                 :                :      */
  537 heikki.linnakangas@i      723                 :CBC       12295 :     oldcontext = MemoryContextSwitchTo(TopMemoryContext);
                                724                 :                : 
                                725                 :                :     /* Handle protocol version 3 startup packet */
                                726                 :                :     {
                                727                 :          12295 :         int32       offset = sizeof(ProtocolVersion);
                                728                 :          12295 :         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                 :          12295 :         port->guc_options = NIL;
                                736                 :                : 
                                737         [ +  - ]:          59376 :         while (offset < len)
                                738                 :                :         {
                                739                 :          59376 :             char       *nameptr = buf + offset;
                                740                 :                :             int32       valoffset;
                                741                 :                :             char       *valptr;
                                742                 :                : 
                                743         [ +  + ]:          59376 :             if (*nameptr == '\0')
                                744                 :          12295 :                 break;          /* found packet terminator */
                                745                 :          47081 :             valoffset = offset + strlen(nameptr) + 1;
                                746         [ -  + ]:          47081 :             if (valoffset >= len)
  537 heikki.linnakangas@i      747                 :UBC           0 :                 break;          /* missing value, will complain below */
  537 heikki.linnakangas@i      748                 :CBC       47081 :             valptr = buf + valoffset;
                                749                 :                : 
                                750         [ +  + ]:          47081 :             if (strcmp(nameptr, "database") == 0)
                                751                 :          12295 :                 port->database_name = pstrdup(valptr);
                                752         [ +  + ]:          34786 :             else if (strcmp(nameptr, "user") == 0)
                                753                 :          12295 :                 port->user_name = pstrdup(valptr);
                                754         [ +  + ]:          22491 :             else if (strcmp(nameptr, "options") == 0)
                                755                 :           3746 :                 port->cmdline_options = pstrdup(valptr);
                                756         [ +  + ]:          18745 :             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         [ +  + ]:           1148 :                 if (strcmp(valptr, "database") == 0)
                                766                 :                :                 {
                                767                 :            664 :                     am_walsender = true;
                                768                 :            664 :                     am_db_walsender = true;
                                769                 :                :                 }
                                770         [ -  + ]:            484 :                 else if (!parse_bool(valptr, &am_walsender))
  537 heikki.linnakangas@i      771         [ #  # ]:UBC           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                 :                :             }
  537 heikki.linnakangas@i      778         [ -  + ]:CBC       17597 :             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                 :                :                 unrecognized_protocol_options =
  537 heikki.linnakangas@i      786                 :UBC           0 :                     lappend(unrecognized_protocol_options, pstrdup(nameptr));
                                787                 :                :             }
                                788                 :                :             else
                                789                 :                :             {
                                790                 :                :                 /* Assume it's a generic GUC option */
  537 heikki.linnakangas@i      791                 :CBC       17597 :                 port->guc_options = lappend(port->guc_options,
                                792                 :          17597 :                                             pstrdup(nameptr));
                                793                 :          17597 :                 port->guc_options = lappend(port->guc_options,
                                794                 :          17597 :                                             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         [ +  + ]:          17597 :                 if (strcmp(nameptr, "application_name") == 0)
                                803                 :                :                 {
                                804                 :          12286 :                     port->application_name = pg_clean_ascii(valptr, 0);
                                805                 :                :                 }
                                806                 :                :             }
                                807                 :          47081 :             offset = valoffset + strlen(valptr) + 1;
                                808                 :                :         }
                                809                 :                : 
                                810                 :                :         /*
                                811                 :                :          * If we didn't find a packet terminator exactly at the end of the
                                812                 :                :          * given packet length, complain.
                                813                 :                :          */
                                814         [ -  + ]:          12295 :         if (offset != len - 1)
  537 heikki.linnakangas@i      815         [ #  # ]:UBC           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                 :                :          */
  537 heikki.linnakangas@i      825   [ +  -  -  + ]:CBC       12295 :         if (PG_PROTOCOL_MINOR(proto) > PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST) ||
                                826                 :                :             unrecognized_protocol_options != NIL)
  537 heikki.linnakangas@i      827                 :UBC           0 :             SendNegotiateProtocolVersion(unrecognized_protocol_options);
                                828                 :                :     }
                                829                 :                : 
                                830                 :                :     /* Check a user name was given. */
  537 heikki.linnakangas@i      831   [ +  -  -  + ]:CBC       12295 :     if (port->user_name == NULL || port->user_name[0] == '\0')
  537 heikki.linnakangas@i      832         [ #  # ]:UBC           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. */
  537 heikki.linnakangas@i      837   [ +  -  -  + ]:CBC       12295 :     if (port->database_name == NULL || port->database_name[0] == '\0')
  537 heikki.linnakangas@i      838                 :UBC           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                 :                :      */
  268 nathan@postgresql.or      844         [ -  + ]:CBC       12295 :     if (strlen(port->database_name) >= NAMEDATALEN)
  268 nathan@postgresql.or      845                 :UBC           0 :         port->database_name[NAMEDATALEN - 1] = '\0';
  268 nathan@postgresql.or      846         [ -  + ]:CBC       12295 :     if (strlen(port->user_name) >= NAMEDATALEN)
  268 nathan@postgresql.or      847                 :UBC           0 :         port->user_name[NAMEDATALEN - 1] = '\0';
                                848                 :                : 
  537 heikki.linnakangas@i      849         [ +  + ]:CBC       12295 :     if (am_walsender)
                                850                 :           1148 :         MyBackendType = B_WAL_SENDER;
                                851                 :                :     else
                                852                 :          11147 :         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   [ +  +  +  + ]:          12295 :     if (am_walsender && !am_db_walsender)
                                863                 :            484 :         port->database_name[0] = '\0';
                                864                 :                : 
                                865                 :                :     /*
                                866                 :                :      * Done filling the Port structure
                                867                 :                :      */
                                868                 :          12295 :     MemoryContextSwitchTo(oldcontext);
                                869                 :                : 
   35 tgl@sss.pgh.pa.us         870                 :GNC       12295 :     pfree(buf);
                                871                 :                : 
  537 heikki.linnakangas@i      872                 :CBC       12295 :     return STATUS_OK;
                                873                 :                : 
   35 tgl@sss.pgh.pa.us         874                 :GNC          55 : fail:
                                875                 :                :     /* be tidy, just to avoid Valgrind complaints */
                                876         [ +  + ]:             55 :     if (buf)
                                877                 :             35 :         pfree(buf);
                                878                 :                : 
                                879                 :             55 :     return STATUS_ERROR;
                                880                 :                : }
                                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
  157 heikki.linnakangas@i      888                 :CBC          16 : ProcessCancelRequestPacket(Port *port, void *pkt, int pktlen)
                                889                 :                : {
                                890                 :                :     CancelRequestPacket *canc;
                                891                 :                :     int         len;
                                892                 :                : 
                                893         [ -  + ]:             16 :     if (pktlen < offsetof(CancelRequestPacket, cancelAuthCode))
                                894                 :                :     {
  157 heikki.linnakangas@i      895         [ #  # ]:UBC           0 :         ereport(COMMERROR,
                                896                 :                :                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
                                897                 :                :                  errmsg("invalid length of cancel request packet")));
                                898                 :              0 :         return;
                                899                 :                :     }
  157 heikki.linnakangas@i      900                 :CBC          16 :     len = pktlen - offsetof(CancelRequestPacket, cancelAuthCode);
                                901   [ +  -  -  + ]:             16 :     if (len == 0 || len > 256)
                                902                 :                :     {
  157 heikki.linnakangas@i      903         [ #  # ]:UBC           0 :         ereport(COMMERROR,
                                904                 :                :                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
                                905                 :                :                  errmsg("invalid length of cancel key in cancel request packet")));
                                906                 :              0 :         return;
                                907                 :                :     }
                                908                 :                : 
  157 heikki.linnakangas@i      909                 :CBC          16 :     canc = (CancelRequestPacket *) pkt;
                                910                 :             16 :     SendCancelRequest(pg_ntoh32(canc->backendPID), canc->cancelAuthCode, len);
                                911                 :                : }
                                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
  537 heikki.linnakangas@i      930                 :UBC           0 : SendNegotiateProtocolVersion(List *unrecognized_protocol_options)
                                931                 :                : {
                                932                 :                :     StringInfoData buf;
                                933                 :                :     ListCell   *lc;
                                934                 :                : 
                                935                 :              0 :     pq_beginmessage(&buf, PqMsg_NegotiateProtocolVersion);
  387 rhaas@postgresql.org      936                 :              0 :     pq_sendint32(&buf, FrontendProtocol);
  537 heikki.linnakangas@i      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
  178 melanieplageman@gmai      989                 :CBC        1187 : validate_log_connections_options(List *elemlist, uint32 *flags)
                                990                 :                : {
                                991                 :                :     ListCell   *l;
                                992                 :                :     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                 :           1187 :     *flags = 0;
                               1014                 :                : 
                               1015                 :                :     /* If an empty string was passed, we're done */
                               1016         [ +  + ]:           1187 :     if (list_length(elemlist) == 0)
                               1017                 :           1073 :         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                 :            114 :     item = linitial(elemlist);
                               1025                 :                : 
                               1026         [ +  + ]:           1022 :     for (size_t i = 0; i < lengthof(compat_options); i++)
                               1027                 :                :     {
                               1028                 :            909 :         struct config_enum_entry option = compat_options[i];
                               1029                 :                : 
                               1030         [ +  + ]:            909 :         if (pg_strcasecmp(item, option.name) != 0)
                               1031                 :            908 :             continue;
                               1032                 :                : 
                               1033         [ -  + ]:              1 :         if (list_length(elemlist) > 1)
                               1034                 :                :         {
  178 melanieplageman@gmai     1035                 :UBC           0 :             GUC_check_errdetail("Cannot specify log_connections option \"%s\" in a list with other options.",
                               1036                 :                :                                 item);
  178 melanieplageman@gmai     1037                 :CBC           1 :             return false;
                               1038                 :                :         }
                               1039                 :                : 
                               1040                 :              1 :         *flags = option.val;
                               1041                 :              1 :         return true;
                               1042                 :                :     }
                               1043                 :                : 
                               1044                 :                :     /* Now check the aspect options. The empty string was already handled */
                               1045   [ +  -  +  +  :            246 :     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                 :            133 :         item = lfirst(l);
                               1056         [ +  - ]:            479 :         for (size_t i = 0; i < lengthof(options); i++)
                               1057                 :                :         {
                               1058                 :            479 :             struct config_enum_entry option = options[i];
                               1059                 :                : 
                               1060         [ +  + ]:            479 :             if (pg_strcasecmp(item, option.name) == 0)
                               1061                 :                :             {
                               1062                 :            133 :                 *flags |= option.val;
                               1063                 :            133 :                 goto next;
                               1064                 :                :             }
                               1065                 :                :         }
                               1066                 :                : 
  178 melanieplageman@gmai     1067                 :UBC           0 :         GUC_check_errdetail("Invalid option \"%s\".", item);
                               1068                 :              0 :         return false;
                               1069                 :                : 
  178 melanieplageman@gmai     1070                 :CBC         133 : next:   ;
                               1071                 :                :     }
                               1072                 :                : 
                               1073                 :            113 :     return true;
                               1074                 :                : }
                               1075                 :                : 
                               1076                 :                : 
                               1077                 :                : /*
                               1078                 :                :  * GUC check hook for log_connections
                               1079                 :                :  */
                               1080                 :                : bool
                               1081                 :           1187 : check_log_connections(char **newval, void **extra, GucSource source)
                               1082                 :                : {
                               1083                 :                :     uint32      flags;
                               1084                 :                :     char       *rawstring;
                               1085                 :                :     List       *elemlist;
                               1086                 :                :     bool        success;
                               1087                 :                : 
                               1088                 :                :     /* Need a modifiable copy of string */
                               1089                 :           1187 :     rawstring = pstrdup(*newval);
                               1090                 :                : 
                               1091         [ -  + ]:           1187 :     if (!SplitIdentifierString(rawstring, ',', &elemlist))
                               1092                 :                :     {
   70 peter@eisentraut.org     1093                 :UBC           0 :         GUC_check_errdetail("Invalid list syntax in parameter \"%s\".", "log_connections");
  178 melanieplageman@gmai     1094                 :              0 :         pfree(rawstring);
                               1095                 :              0 :         list_free(elemlist);
                               1096                 :              0 :         return false;
                               1097                 :                :     }
                               1098                 :                : 
                               1099                 :                :     /* Validation logic is all in the helper */
  178 melanieplageman@gmai     1100                 :CBC        1187 :     success = validate_log_connections_options(elemlist, &flags);
                               1101                 :                : 
                               1102                 :                :     /* Time for cleanup */
                               1103                 :           1187 :     pfree(rawstring);
                               1104                 :           1187 :     list_free(elemlist);
                               1105                 :                : 
                               1106         [ -  + ]:           1187 :     if (!success)
  178 melanieplageman@gmai     1107                 :UBC           0 :         return false;
                               1108                 :                : 
                               1109                 :                :     /*
                               1110                 :                :      * We succeeded, so allocate `extra` and save the flags there for use by
                               1111                 :                :      * assign_log_connections().
                               1112                 :                :      */
  163 dgustafsson@postgres     1113                 :CBC        1187 :     *extra = guc_malloc(LOG, sizeof(int));
                               1114         [ -  + ]:           1187 :     if (!*extra)
  163 dgustafsson@postgres     1115                 :UBC           0 :         return false;
  178 melanieplageman@gmai     1116                 :CBC        1187 :     *((int *) *extra) = flags;
                               1117                 :                : 
                               1118                 :           1187 :     return true;
                               1119                 :                : }
                               1120                 :                : 
                               1121                 :                : /*
                               1122                 :                :  * GUC assign hook for log_connections
                               1123                 :                :  */
                               1124                 :                : void
                               1125                 :           1183 : assign_log_connections(const char *newval, void *extra)
                               1126                 :                : {
                               1127                 :           1183 :     log_connections = *((int *) extra);
                               1128                 :           1183 : }
        

Generated by: LCOV version 2.4-beta