PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
backend_startup.c File Reference
#include "postgres.h"
#include <unistd.h>
#include "access/xlog.h"
#include "common/ip.h"
#include "common/string.h"
#include "libpq/libpq.h"
#include "libpq/libpq-be.h"
#include "libpq/pqformat.h"
#include "libpq/pqsignal.h"
#include "miscadmin.h"
#include "postmaster/postmaster.h"
#include "replication/walsender.h"
#include "storage/fd.h"
#include "storage/ipc.h"
#include "storage/procsignal.h"
#include "storage/proc.h"
#include "tcop/backend_startup.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
#include "utils/injection_point.h"
#include "utils/memutils.h"
#include "utils/ps_status.h"
#include "utils/timeout.h"
Include dependency graph for backend_startup.c:

Go to the source code of this file.

Functions

static void BackendInitialize (ClientSocket *client_sock, CAC_state cac)
 
static int ProcessSSLStartup (Port *port)
 
static int ProcessStartupPacket (Port *port, bool ssl_done, bool gss_done)
 
static void SendNegotiateProtocolVersion (List *unrecognized_protocol_options)
 
static void process_startup_packet_die (SIGNAL_ARGS)
 
static void StartupPacketTimeoutHandler (void)
 
void BackendMain (char *startup_data, size_t startup_data_len)
 

Variables

bool Trace_connection_negotiation = false
 

Function Documentation

◆ BackendInitialize()

static void BackendInitialize ( ClientSocket client_sock,
CAC_state  cac 
)
static

Definition at line 124 of file backend_startup.c.

125{
126 int status;
127 int ret;
128 Port *port;
129 char remote_host[NI_MAXHOST];
130 char remote_port[NI_MAXSERV];
131 StringInfoData ps_data;
132 MemoryContext oldcontext;
133
134 /* Tell fd.c about the long-lived FD associated with the client_sock */
136
137 /*
138 * PreAuthDelay is a debugging aid for investigating problems in the
139 * authentication cycle: it can be set in postgresql.conf to allow time to
140 * attach to the newly-forked backend with a debugger. (See also
141 * PostAuthDelay, which we allow clients to pass through PGOPTIONS, but it
142 * is not honored until after authentication.)
143 */
144 if (PreAuthDelay > 0)
145 pg_usleep(PreAuthDelay * 1000000L);
146
147 /* This flag will remain set until InitPostgres finishes authentication */
148 ClientAuthInProgress = true; /* limit visibility of log messages */
149
150 /*
151 * Initialize libpq and enable reporting of ereport errors to the client.
152 * Must do this now because authentication uses libpq to send messages.
153 *
154 * The Port structure and all data structures attached to it are allocated
155 * in TopMemoryContext, so that they survive into PostgresMain execution.
156 * We need not worry about leaking this storage on failure, since we
157 * aren't in the postmaster process anymore.
158 */
160 port = MyProcPort = pq_init(client_sock);
161 MemoryContextSwitchTo(oldcontext);
162
163 whereToSendOutput = DestRemote; /* now safe to ereport to client */
164
165 /* set these to empty in case they are needed before we set them up */
166 port->remote_host = "";
167 port->remote_port = "";
168
169 /*
170 * We arrange to do _exit(1) if we receive SIGTERM or timeout while trying
171 * to collect the startup packet; while SIGQUIT results in _exit(2).
172 * Otherwise the postmaster cannot shutdown the database FAST or IMMED
173 * cleanly if a buggy client fails to send the packet promptly.
174 *
175 * Exiting with _exit(1) is only possible because we have not yet touched
176 * shared memory; therefore no outside-the-process state needs to get
177 * cleaned up.
178 */
180 /* SIGQUIT handler was already set up by InitPostmasterChild */
181 InitializeTimeouts(); /* establishes SIGALRM handler */
182 sigprocmask(SIG_SETMASK, &StartupBlockSig, NULL);
183
184 /*
185 * Get the remote host name and port for logging and status display.
186 */
187 remote_host[0] = '\0';
188 remote_port[0] = '\0';
189 if ((ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
190 remote_host, sizeof(remote_host),
191 remote_port, sizeof(remote_port),
192 (log_hostname ? 0 : NI_NUMERICHOST) | NI_NUMERICSERV)) != 0)
194 (errmsg_internal("pg_getnameinfo_all() failed: %s",
195 gai_strerror(ret))));
196
197 /*
198 * Save remote_host and remote_port in port structure (after this, they
199 * will appear in log_line_prefix data for log messages).
200 */
201 port->remote_host = MemoryContextStrdup(TopMemoryContext, remote_host);
202 port->remote_port = MemoryContextStrdup(TopMemoryContext, remote_port);
203
204 /* And now we can issue the Log_connections message, if wanted */
205 if (Log_connections)
206 {
207 if (remote_port[0])
208 ereport(LOG,
209 (errmsg("connection received: host=%s port=%s",
210 remote_host,
211 remote_port)));
212 else
213 ereport(LOG,
214 (errmsg("connection received: host=%s",
215 remote_host)));
216 }
217
218 /* For testing client error handling */
219#ifdef USE_INJECTION_POINTS
220 INJECTION_POINT("backend-initialize");
221 if (IS_INJECTION_POINT_ATTACHED("backend-initialize-v2-error"))
222 {
223 /*
224 * This simulates an early error from a pre-v14 server, which used the
225 * version 2 protocol for any errors that occurred before processing
226 * the startup packet.
227 */
229 elog(FATAL, "protocol version 2 error triggered");
230 }
231#endif
232
233 /*
234 * If we did a reverse lookup to name, we might as well save the results
235 * rather than possibly repeating the lookup during authentication.
236 *
237 * Note that we don't want to specify NI_NAMEREQD above, because then we'd
238 * get nothing useful for a client without an rDNS entry. Therefore, we
239 * must check whether we got a numeric IPv4 or IPv6 address, and not save
240 * it into remote_hostname if so. (This test is conservative and might
241 * sometimes classify a hostname as numeric, but an error in that
242 * direction is safe; it only results in a possible extra lookup.)
243 */
244 if (log_hostname &&
245 ret == 0 &&
246 strspn(remote_host, "0123456789.") < strlen(remote_host) &&
247 strspn(remote_host, "0123456789ABCDEFabcdef:") < strlen(remote_host))
248 {
249 port->remote_hostname = MemoryContextStrdup(TopMemoryContext, remote_host);
250 }
251
252 /*
253 * Ready to begin client interaction. We will give up and _exit(1) after
254 * a time delay, so that a broken client can't hog a connection
255 * indefinitely. PreAuthDelay and any DNS interactions above don't count
256 * against the time limit.
257 *
258 * Note: AuthenticationTimeout is applied here while waiting for the
259 * startup packet, and then again in InitPostgres for the duration of any
260 * authentication operations. So a hostile client could tie up the
261 * process for nearly twice AuthenticationTimeout before we kick him off.
262 *
263 * Note: because PostgresMain will call InitializeTimeouts again, the
264 * registration of STARTUP_PACKET_TIMEOUT will be lost. This is okay
265 * since we never use it again after this function.
266 */
269
270 /* Handle direct SSL handshake */
271 status = ProcessSSLStartup(port);
272
273 /*
274 * Receive the startup packet (which might turn out to be a cancel request
275 * packet).
276 */
277 if (status == STATUS_OK)
278 status = ProcessStartupPacket(port, false, false);
279
280 /*
281 * If we're going to reject the connection due to database state, say so
282 * now instead of wasting cycles on an authentication exchange. (This also
283 * allows a pg_ping utility to be written.)
284 */
285 if (status == STATUS_OK)
286 {
287 switch (cac)
288 {
289 case CAC_STARTUP:
292 errmsg("the database system is starting up")));
293 break;
298 errmsg("the database system is not yet accepting connections"),
299 errdetail("Consistent recovery state has not been yet reached.")));
300 else
303 errmsg("the database system is not accepting connections"),
304 errdetail("Hot standby mode is disabled.")));
305 break;
306 case CAC_SHUTDOWN:
309 errmsg("the database system is shutting down")));
310 break;
311 case CAC_RECOVERY:
314 errmsg("the database system is in recovery mode")));
315 break;
316 case CAC_TOOMANY:
318 (errcode(ERRCODE_TOO_MANY_CONNECTIONS),
319 errmsg("sorry, too many clients already")));
320 break;
321 case CAC_OK:
322 break;
323 }
324 }
325
326 /*
327 * Disable the timeout, and prevent SIGTERM again.
328 */
330 sigprocmask(SIG_SETMASK, &BlockSig, NULL);
331
332 /*
333 * As a safety check that nothing in startup has yet performed
334 * shared-memory modifications that would need to be undone if we had
335 * exited through SIGTERM or timeout above, check that no on_shmem_exit
336 * handlers have been registered yet. (This isn't terribly bulletproof,
337 * since someone might misuse an on_proc_exit handler for shmem cleanup,
338 * but it's a cheap and helpful check. We cannot disallow on_proc_exit
339 * handlers unfortunately, since pq_init() already registered one.)
340 */
342
343 /*
344 * Stop here if it was bad or a cancel packet. ProcessStartupPacket
345 * already did any appropriate error reporting.
346 */
347 if (status != STATUS_OK)
348 proc_exit(0);
349
350 /*
351 * Now that we have the user and database name, we can set the process
352 * title for ps. It's good to do this as early as possible in startup.
353 */
354 initStringInfo(&ps_data);
355 if (am_walsender)
357 appendStringInfo(&ps_data, "%s ", port->user_name);
358 if (port->database_name[0] != '\0')
359 appendStringInfo(&ps_data, "%s ", port->database_name);
360 appendStringInfoString(&ps_data, port->remote_host);
361 if (port->remote_port[0] != '\0')
362 appendStringInfo(&ps_data, "(%s)", port->remote_port);
363
364 init_ps_display(ps_data.data);
365 pfree(ps_data.data);
366
367 set_ps_display("initializing");
368}
sigset_t StartupBlockSig
Definition: pqsignal.c:24
sigset_t BlockSig
Definition: pqsignal.c:23
static void process_startup_packet_die(SIGNAL_ARGS)
static void StartupPacketTimeoutHandler(void)
static int ProcessSSLStartup(Port *port)
static int ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done)
@ CAC_TOOMANY
@ CAC_OK
@ CAC_RECOVERY
@ CAC_NOTCONSISTENT
@ CAC_STARTUP
@ CAC_SHUTDOWN
#define STATUS_OK
Definition: c.h:1123
@ DestRemote
Definition: dest.h:89
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1157
int errdetail(const char *fmt,...)
Definition: elog.c:1203
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define LOG
Definition: elog.h:31
#define FATAL
Definition: elog.h:41
#define WARNING
Definition: elog.h:36
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
void ReserveExternalFD(void)
Definition: fd.c:1220
#define ERRCODE_CANNOT_CONNECT_NOW
Definition: fe-connect.c:92
ProtocolVersion FrontendProtocol
Definition: globals.c:29
struct Port * MyProcPort
Definition: globals.c:50
#define INJECTION_POINT(name)
#define IS_INJECTION_POINT_ATTACHED(name)
int pg_getnameinfo_all(const struct sockaddr_storage *addr, int salen, char *node, int nodelen, char *service, int servicelen, int flags)
Definition: ip.c:114
void check_on_shmem_exit_lists_are_empty(void)
Definition: ipc.c:432
void proc_exit(int code)
Definition: ipc.c:104
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1683
void pfree(void *pointer)
Definition: mcxt.c:1521
MemoryContext TopMemoryContext
Definition: mcxt.c:149
@ B_WAL_SENDER
Definition: miscadmin.h:346
const char * GetBackendTypeDesc(BackendType backendType)
Definition: miscinit.c:263
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
static int port
Definition: pg_regress.c:115
pqsigfunc pqsignal(int signo, pqsigfunc func)
CommandDest whereToSendOutput
Definition: postgres.c:90
int PreAuthDelay
Definition: postmaster.c:232
bool log_hostname
Definition: postmaster.c:235
bool Log_connections
Definition: postmaster.c:236
bool ClientAuthInProgress
Definition: postmaster.c:355
int AuthenticationTimeout
Definition: postmaster.c:233
Port * pq_init(ClientSocket *client_sock)
Definition: pqcomm.c:174
#define PG_PROTOCOL(m, n)
Definition: pqcomm.h:90
void init_ps_display(const char *fixed_part)
Definition: ps_status.c:269
static void set_ps_display(const char *activity)
Definition: ps_status.h:40
void pg_usleep(long microsec)
Definition: signal.c:53
const char * gai_strerror(int ecode)
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:94
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:179
void initStringInfo(StringInfo str)
Definition: stringinfo.c:56
Definition: libpq-be.h:133
void enable_timeout_after(TimeoutId id, int delay_ms)
Definition: timeout.c:560
void InitializeTimeouts(void)
Definition: timeout.c:470
void disable_timeout(TimeoutId id, bool keep_indicator)
Definition: timeout.c:685
TimeoutId RegisterTimeout(TimeoutId id, timeout_handler_proc handler)
Definition: timeout.c:505
@ STARTUP_PACKET_TIMEOUT
Definition: timeout.h:26
bool am_walsender
Definition: walsender.c:115
bool EnableHotStandby
Definition: xlog.c:121

References am_walsender, appendStringInfo(), appendStringInfoString(), AuthenticationTimeout, B_WAL_SENDER, BlockSig, CAC_NOTCONSISTENT, CAC_OK, CAC_RECOVERY, CAC_SHUTDOWN, CAC_STARTUP, CAC_TOOMANY, check_on_shmem_exit_lists_are_empty(), ClientAuthInProgress, StringInfoData::data, DestRemote, disable_timeout(), elog, enable_timeout_after(), EnableHotStandby, ereport, errcode(), ERRCODE_CANNOT_CONNECT_NOW, errdetail(), errmsg(), errmsg_internal(), FATAL, FrontendProtocol, gai_strerror(), GetBackendTypeDesc(), init_ps_display(), InitializeTimeouts(), initStringInfo(), INJECTION_POINT, IS_INJECTION_POINT_ATTACHED, LOG, Log_connections, log_hostname, MemoryContextStrdup(), MemoryContextSwitchTo(), MyProcPort, pfree(), pg_getnameinfo_all(), PG_PROTOCOL, pg_usleep(), port, pq_init(), pqsignal(), PreAuthDelay, proc_exit(), process_startup_packet_die(), ProcessSSLStartup(), ProcessStartupPacket(), RegisterTimeout(), ReserveExternalFD(), set_ps_display(), STARTUP_PACKET_TIMEOUT, StartupBlockSig, StartupPacketTimeoutHandler(), STATUS_OK, TopMemoryContext, WARNING, and whereToSendOutput.

Referenced by BackendMain().

◆ BackendMain()

void BackendMain ( char *  startup_data,
size_t  startup_data_len 
)

Definition at line 59 of file backend_startup.c.

60{
61 BackendStartupData *bsdata = (BackendStartupData *) startup_data;
62
63 Assert(startup_data_len == sizeof(BackendStartupData));
64 Assert(MyClientSocket != NULL);
65
66#ifdef EXEC_BACKEND
67
68 /*
69 * Need to reinitialize the SSL library in the backend, since the context
70 * structures contain function pointers and cannot be passed through the
71 * parameter file.
72 *
73 * If for some reason reload fails (maybe the user installed broken key
74 * files), soldier on without SSL; that's better than all connections
75 * becoming impossible.
76 *
77 * XXX should we do this in all child processes? For the moment it's
78 * enough to do it in backend children.
79 */
80#ifdef USE_SSL
81 if (EnableSSL)
82 {
83 if (secure_initialize(false) == 0)
84 LoadedSSL = true;
85 else
87 (errmsg("SSL configuration could not be loaded in child process")));
88 }
89#endif
90#endif
91
92 /* Perform additional initialization and collect startup packet */
94
95 /*
96 * Create a per-backend PGPROC struct in shared memory. We must do this
97 * before we can use LWLocks or access any shared memory.
98 */
100
101 /*
102 * Make sure we aren't in PostmasterContext anymore. (We can't delete it
103 * just yet, though, because InitPostgres will need the HBA data.)
104 */
106
108}
static void BackendInitialize(ClientSocket *client_sock, CAC_state cac)
int secure_initialize(bool isServerStart)
Definition: be-secure.c:75
#define Assert(condition)
Definition: c.h:812
struct ClientSocket * MyClientSocket
Definition: globals.c:49
void PostgresMain(const char *dbname, const char *username)
Definition: postgres.c:4146
bool EnableSSL
Definition: postmaster.c:230
PGDLLIMPORT bool LoadedSSL
void InitProcess(void)
Definition: proc.c:341
CAC_state canAcceptConnections
char * user_name
Definition: libpq-be.h:152
char * database_name
Definition: libpq-be.h:151

References Assert, BackendInitialize(), BackendStartupData::canAcceptConnections, Port::database_name, EnableSSL, ereport, errmsg(), InitProcess(), LoadedSSL, LOG, MemoryContextSwitchTo(), MyClientSocket, MyProcPort, PostgresMain(), secure_initialize(), TopMemoryContext, and Port::user_name.

◆ process_startup_packet_die()

static void process_startup_packet_die ( SIGNAL_ARGS  )
static

Definition at line 913 of file backend_startup.c.

914{
915 _exit(1);
916}

Referenced by BackendInitialize().

◆ ProcessSSLStartup()

static int ProcessSSLStartup ( Port port)
static

Definition at line 377 of file backend_startup.c.

378{
379 int firstbyte;
380
381 Assert(!port->ssl_in_use);
382
384 firstbyte = pq_peekbyte();
386 if (firstbyte == EOF)
387 {
388 /*
389 * Like in ProcessStartupPacket, if we get no data at all, don't
390 * clutter the log with a complaint.
391 */
392 return STATUS_ERROR;
393 }
394
395 if (firstbyte != 0x16)
396 {
397 /* Not an SSL handshake message */
398 return STATUS_OK;
399 }
400
401 /*
402 * First byte indicates standard SSL handshake message
403 *
404 * (It can't be a Postgres startup length because in network byte order
405 * that would be a startup packet hundreds of megabytes long)
406 */
407
408#ifdef USE_SSL
409 if (!LoadedSSL || port->laddr.addr.ss_family == AF_UNIX)
410 {
411 /* SSL not supported */
412 goto reject;
413 }
414
415 if (secure_open_server(port) == -1)
416 {
417 /*
418 * we assume secure_open_server() sent an appropriate TLS alert
419 * already
420 */
421 goto reject;
422 }
423 Assert(port->ssl_in_use);
424
425 if (!port->alpn_used)
426 {
428 (errcode(ERRCODE_PROTOCOL_VIOLATION),
429 errmsg("received direct SSL connection request without ALPN protocol negotiation extension")));
430 goto reject;
431 }
432
434 ereport(LOG,
435 (errmsg("direct SSL connection accepted")));
436 return STATUS_OK;
437#else
438 /* SSL not supported by this build */
439 goto reject;
440#endif
441
442reject:
444 ereport(LOG,
445 (errmsg("direct SSL connection rejected")));
446 return STATUS_ERROR;
447}
bool Trace_connection_negotiation
int secure_open_server(Port *port)
Definition: be-secure.c:112
#define STATUS_ERROR
Definition: c.h:1124
#define COMMERROR
Definition: elog.h:33
int pq_peekbyte(void)
Definition: pqcomm.c:983
void pq_endmsgread(void)
Definition: pqcomm.c:1165
void pq_startmsgread(void)
Definition: pqcomm.c:1141

References Assert, COMMERROR, ereport, errcode(), errmsg(), LoadedSSL, LOG, port, pq_endmsgread(), pq_peekbyte(), pq_startmsgread(), secure_open_server(), STATUS_ERROR, STATUS_OK, and Trace_connection_negotiation.

Referenced by BackendInitialize().

◆ ProcessStartupPacket()

static int ProcessStartupPacket ( Port port,
bool  ssl_done,
bool  gss_done 
)
static

Definition at line 468 of file backend_startup.c.

469{
470 int32 len;
471 char *buf;
472 ProtocolVersion proto;
473 MemoryContext oldcontext;
474
476
477 /*
478 * Grab the first byte of the length word separately, so that we can tell
479 * whether we have no data at all or an incomplete packet. (This might
480 * sound inefficient, but it's not really, because of buffering in
481 * pqcomm.c.)
482 */
483 if (pq_getbytes((char *) &len, 1) == EOF)
484 {
485 /*
486 * If we get no data at all, don't clutter the log with a complaint;
487 * such cases often occur for legitimate reasons. An example is that
488 * we might be here after responding to NEGOTIATE_SSL_CODE, and if the
489 * client didn't like our response, it'll probably just drop the
490 * connection. Service-monitoring software also often just opens and
491 * closes a connection without sending anything. (So do port
492 * scanners, which may be less benign, but it's not really our job to
493 * notice those.)
494 */
495 return STATUS_ERROR;
496 }
497
498 if (pq_getbytes(((char *) &len) + 1, 3) == EOF)
499 {
500 /* Got a partial length word, so bleat about that */
501 if (!ssl_done && !gss_done)
503 (errcode(ERRCODE_PROTOCOL_VIOLATION),
504 errmsg("incomplete startup packet")));
505 return STATUS_ERROR;
506 }
507
508 len = pg_ntoh32(len);
509 len -= 4;
510
511 if (len < (int32) sizeof(ProtocolVersion) ||
513 {
515 (errcode(ERRCODE_PROTOCOL_VIOLATION),
516 errmsg("invalid length of startup packet")));
517 return STATUS_ERROR;
518 }
519
520 /*
521 * Allocate space to hold the startup packet, plus one extra byte that's
522 * initialized to be zero. This ensures we will have null termination of
523 * all strings inside the packet.
524 */
525 buf = palloc(len + 1);
526 buf[len] = '\0';
527
528 if (pq_getbytes(buf, len) == EOF)
529 {
531 (errcode(ERRCODE_PROTOCOL_VIOLATION),
532 errmsg("incomplete startup packet")));
533 return STATUS_ERROR;
534 }
536
537 /*
538 * The first field is either a protocol version number or a special
539 * request code.
540 */
541 port->proto = proto = pg_ntoh32(*((ProtocolVersion *) buf));
542
543 if (proto == CANCEL_REQUEST_CODE)
544 {
545 /*
546 * The client has sent a cancel request packet, not a normal
547 * start-a-new-connection packet. Perform the necessary processing.
548 * Nothing is sent back to the client.
549 */
551 int backendPID;
552 int32 cancelAuthCode;
553
554 if (len != sizeof(CancelRequestPacket))
555 {
557 (errcode(ERRCODE_PROTOCOL_VIOLATION),
558 errmsg("invalid length of startup packet")));
559 return STATUS_ERROR;
560 }
561 canc = (CancelRequestPacket *) buf;
562 backendPID = (int) pg_ntoh32(canc->backendPID);
563 cancelAuthCode = (int32) pg_ntoh32(canc->cancelAuthCode);
564
565 if (backendPID != 0)
566 SendCancelRequest(backendPID, cancelAuthCode);
567 /* Not really an error, but we don't want to proceed further */
568 return STATUS_ERROR;
569 }
570
571 if (proto == NEGOTIATE_SSL_CODE && !ssl_done)
572 {
573 char SSLok;
574
575#ifdef USE_SSL
576
577 /*
578 * No SSL when disabled or on Unix sockets.
579 *
580 * Also no SSL negotiation if we already have a direct SSL connection
581 */
582 if (!LoadedSSL || port->laddr.addr.ss_family == AF_UNIX || port->ssl_in_use)
583 SSLok = 'N';
584 else
585 SSLok = 'S'; /* Support for SSL */
586#else
587 SSLok = 'N'; /* No support for SSL */
588#endif
589
591 {
592 if (SSLok == 'S')
593 ereport(LOG,
594 (errmsg("SSLRequest accepted")));
595 else
596 ereport(LOG,
597 (errmsg("SSLRequest rejected")));
598 }
599
600 while (secure_write(port, &SSLok, 1) != 1)
601 {
602 if (errno == EINTR)
603 continue; /* if interrupted, just retry */
606 errmsg("failed to send SSL negotiation response: %m")));
607 return STATUS_ERROR; /* close the connection */
608 }
609
610#ifdef USE_SSL
611 if (SSLok == 'S' && secure_open_server(port) == -1)
612 return STATUS_ERROR;
613#endif
614
615 /*
616 * At this point we should have no data already buffered. If we do,
617 * it was received before we performed the SSL handshake, so it wasn't
618 * encrypted and indeed may have been injected by a man-in-the-middle.
619 * We report this case to the client.
620 */
621 if (pq_buffer_remaining_data() > 0)
623 (errcode(ERRCODE_PROTOCOL_VIOLATION),
624 errmsg("received unencrypted data after SSL request"),
625 errdetail("This could be either a client-software bug or evidence of an attempted man-in-the-middle attack.")));
626
627 /*
628 * regular startup packet, cancel, etc packet should follow, but not
629 * another SSL negotiation request, and a GSS request should only
630 * follow if SSL was rejected (client may negotiate in either order)
631 */
632 return ProcessStartupPacket(port, true, SSLok == 'S');
633 }
634 else if (proto == NEGOTIATE_GSS_CODE && !gss_done)
635 {
636 char GSSok = 'N';
637
638#ifdef ENABLE_GSS
639 /* No GSSAPI encryption when on Unix socket */
640 if (port->laddr.addr.ss_family != AF_UNIX)
641 GSSok = 'G';
642#endif
643
645 {
646 if (GSSok == 'G')
647 ereport(LOG,
648 (errmsg("GSSENCRequest accepted")));
649 else
650 ereport(LOG,
651 (errmsg("GSSENCRequest rejected")));
652 }
653
654 while (secure_write(port, &GSSok, 1) != 1)
655 {
656 if (errno == EINTR)
657 continue;
660 errmsg("failed to send GSSAPI negotiation response: %m")));
661 return STATUS_ERROR; /* close the connection */
662 }
663
664#ifdef ENABLE_GSS
665 if (GSSok == 'G' && secure_open_gssapi(port) == -1)
666 return STATUS_ERROR;
667#endif
668
669 /*
670 * At this point we should have no data already buffered. If we do,
671 * it was received before we performed the GSS handshake, so it wasn't
672 * encrypted and indeed may have been injected by a man-in-the-middle.
673 * We report this case to the client.
674 */
675 if (pq_buffer_remaining_data() > 0)
677 (errcode(ERRCODE_PROTOCOL_VIOLATION),
678 errmsg("received unencrypted data after GSSAPI encryption request"),
679 errdetail("This could be either a client-software bug or evidence of an attempted man-in-the-middle attack.")));
680
681 /*
682 * regular startup packet, cancel, etc packet should follow, but not
683 * another GSS negotiation request, and an SSL request should only
684 * follow if GSS was rejected (client may negotiate in either order)
685 */
686 return ProcessStartupPacket(port, GSSok == 'G', true);
687 }
688
689 /* Could add additional special packet types here */
690
691 /*
692 * Set FrontendProtocol now so that ereport() knows what format to send if
693 * we fail during startup. We use the protocol version requested by the
694 * client unless it's higher than the latest version we support. It's
695 * possible that error message fields might look different in newer
696 * protocol versions, but that's something those new clients should be
697 * able to deal with.
698 */
700
701 /* Check that the major protocol version is in range. */
705 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
706 errmsg("unsupported frontend protocol %u.%u: server supports %u.0 to %u.%u",
711
712 /*
713 * Now fetch parameters out of startup packet and save them into the Port
714 * structure.
715 */
717
718 /* Handle protocol version 3 startup packet */
719 {
720 int32 offset = sizeof(ProtocolVersion);
721 List *unrecognized_protocol_options = NIL;
722
723 /*
724 * Scan packet body for name/option pairs. We can assume any string
725 * beginning within the packet body is null-terminated, thanks to
726 * zeroing extra byte above.
727 */
728 port->guc_options = NIL;
729
730 while (offset < len)
731 {
732 char *nameptr = buf + offset;
733 int32 valoffset;
734 char *valptr;
735
736 if (*nameptr == '\0')
737 break; /* found packet terminator */
738 valoffset = offset + strlen(nameptr) + 1;
739 if (valoffset >= len)
740 break; /* missing value, will complain below */
741 valptr = buf + valoffset;
742
743 if (strcmp(nameptr, "database") == 0)
744 port->database_name = pstrdup(valptr);
745 else if (strcmp(nameptr, "user") == 0)
746 port->user_name = pstrdup(valptr);
747 else if (strcmp(nameptr, "options") == 0)
748 port->cmdline_options = pstrdup(valptr);
749 else if (strcmp(nameptr, "replication") == 0)
750 {
751 /*
752 * Due to backward compatibility concerns the replication
753 * parameter is a hybrid beast which allows the value to be
754 * either boolean or the string 'database'. The latter
755 * connects to a specific database which is e.g. required for
756 * logical decoding while.
757 */
758 if (strcmp(valptr, "database") == 0)
759 {
760 am_walsender = true;
761 am_db_walsender = true;
762 }
763 else if (!parse_bool(valptr, &am_walsender))
765 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
766 errmsg("invalid value for parameter \"%s\": \"%s\"",
767 "replication",
768 valptr),
769 errhint("Valid values are: \"false\", 0, \"true\", 1, \"database\".")));
770 }
771 else if (strncmp(nameptr, "_pq_.", 5) == 0)
772 {
773 /*
774 * Any option beginning with _pq_. is reserved for use as a
775 * protocol-level option, but at present no such options are
776 * defined.
777 */
778 unrecognized_protocol_options =
779 lappend(unrecognized_protocol_options, pstrdup(nameptr));
780 }
781 else
782 {
783 /* Assume it's a generic GUC option */
784 port->guc_options = lappend(port->guc_options,
785 pstrdup(nameptr));
786 port->guc_options = lappend(port->guc_options,
787 pstrdup(valptr));
788
789 /*
790 * Copy application_name to port if we come across it. This
791 * is done so we can log the application_name in the
792 * connection authorization message. Note that the GUC would
793 * be used but we haven't gone through GUC setup yet.
794 */
795 if (strcmp(nameptr, "application_name") == 0)
796 {
797 port->application_name = pg_clean_ascii(valptr, 0);
798 }
799 }
800 offset = valoffset + strlen(valptr) + 1;
801 }
802
803 /*
804 * If we didn't find a packet terminator exactly at the end of the
805 * given packet length, complain.
806 */
807 if (offset != len - 1)
809 (errcode(ERRCODE_PROTOCOL_VIOLATION),
810 errmsg("invalid startup packet layout: expected terminator as last byte")));
811
812 /*
813 * If the client requested a newer protocol version or if the client
814 * requested any protocol options we didn't recognize, let them know
815 * the newest minor protocol version we do support and the names of
816 * any unrecognized options.
817 */
819 unrecognized_protocol_options != NIL)
820 SendNegotiateProtocolVersion(unrecognized_protocol_options);
821 }
822
823 /* Check a user name was given. */
824 if (port->user_name == NULL || port->user_name[0] == '\0')
826 (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
827 errmsg("no PostgreSQL user name specified in startup packet")));
828
829 /* The database defaults to the user name. */
830 if (port->database_name == NULL || port->database_name[0] == '\0')
831 port->database_name = pstrdup(port->user_name);
832
833 /*
834 * Truncate given database and user names to length of a Postgres name.
835 * This avoids lookup failures when overlength names are given.
836 */
837 if (strlen(port->database_name) >= NAMEDATALEN)
838 port->database_name[NAMEDATALEN - 1] = '\0';
839 if (strlen(port->user_name) >= NAMEDATALEN)
840 port->user_name[NAMEDATALEN - 1] = '\0';
841
842 if (am_walsender)
844 else
846
847 /*
848 * Normal walsender backends, e.g. for streaming replication, are not
849 * connected to a particular database. But walsenders used for logical
850 * replication need to connect to a specific database. We allow streaming
851 * replication commands to be issued even if connected to a database as it
852 * can make sense to first make a basebackup and then stream changes
853 * starting from that.
854 */
856 port->database_name[0] = '\0';
857
858 /*
859 * Done filling the Port structure
860 */
861 MemoryContextSwitchTo(oldcontext);
862
863 return STATUS_OK;
864}
static void SendNegotiateProtocolVersion(List *unrecognized_protocol_options)
ssize_t secure_open_gssapi(Port *port)
ssize_t secure_write(Port *port, void *ptr, size_t len)
Definition: be-secure.c:305
bool parse_bool(const char *value, bool *result)
Definition: bool.c:31
#define Min(x, y)
Definition: c.h:958
int32_t int32
Definition: c.h:481
int errcode_for_socket_access(void)
Definition: elog.c:953
int errhint(const char *fmt,...)
Definition: elog.c:1317
List * lappend(List *list, void *datum)
Definition: list.c:339
char * pstrdup(const char *in)
Definition: mcxt.c:1696
void * palloc(Size size)
Definition: mcxt.c:1317
@ B_BACKEND
Definition: miscadmin.h:341
BackendType MyBackendType
Definition: miscinit.c:64
#define pg_ntoh32(x)
Definition: pg_bswap.h:125
#define NAMEDATALEN
const void size_t len
#define NIL
Definition: pg_list.h:68
static char * buf
Definition: pg_test_fsync.c:72
int pq_getbytes(char *s, size_t len)
Definition: pqcomm.c:1063
ssize_t pq_buffer_remaining_data(void)
Definition: pqcomm.c:1127
#define PG_PROTOCOL_MAJOR(v)
Definition: pqcomm.h:87
#define PG_PROTOCOL_EARLIEST
Definition: pqcomm.h:97
#define CANCEL_REQUEST_CODE
Definition: pqcomm.h:133
#define MAX_STARTUP_PACKET_LENGTH
Definition: pqcomm.h:119
#define PG_PROTOCOL_LATEST
Definition: pqcomm.h:98
#define NEGOTIATE_GSS_CODE
Definition: pqcomm.h:168
#define NEGOTIATE_SSL_CODE
Definition: pqcomm.h:167
uint32 ProtocolVersion
Definition: pqcomm.h:100
#define PG_PROTOCOL_MINOR(v)
Definition: pqcomm.h:88
void SendCancelRequest(int backendPID, int32 cancelAuthCode)
Definition: procsignal.c:726
char * pg_clean_ascii(const char *str, int alloc_flags)
Definition: string.c:85
uint32 backendPID
Definition: pqcomm.h:139
uint32 cancelAuthCode
Definition: pqcomm.h:140
Definition: pg_list.h:54
bool am_db_walsender
Definition: walsender.c:118
#define EINTR
Definition: win32_port.h:374

References am_db_walsender, am_walsender, B_BACKEND, B_WAL_SENDER, CancelRequestPacket::backendPID, buf, CANCEL_REQUEST_CODE, CancelRequestPacket::cancelAuthCode, COMMERROR, EINTR, ereport, errcode(), errcode_for_socket_access(), errdetail(), errhint(), errmsg(), FATAL, FrontendProtocol, lappend(), len, LoadedSSL, LOG, MAX_STARTUP_PACKET_LENGTH, MemoryContextSwitchTo(), Min, MyBackendType, NAMEDATALEN, NEGOTIATE_GSS_CODE, NEGOTIATE_SSL_CODE, NIL, palloc(), parse_bool(), pg_clean_ascii(), pg_ntoh32, PG_PROTOCOL_EARLIEST, PG_PROTOCOL_LATEST, PG_PROTOCOL_MAJOR, PG_PROTOCOL_MINOR, port, pq_buffer_remaining_data(), pq_endmsgread(), pq_getbytes(), pq_startmsgread(), ProcessStartupPacket(), pstrdup(), secure_open_gssapi(), secure_open_server(), secure_write(), SendCancelRequest(), SendNegotiateProtocolVersion(), STATUS_ERROR, STATUS_OK, TopMemoryContext, and Trace_connection_negotiation.

Referenced by BackendInitialize(), and ProcessStartupPacket().

◆ SendNegotiateProtocolVersion()

static void SendNegotiateProtocolVersion ( List unrecognized_protocol_options)
static

Definition at line 883 of file backend_startup.c.

884{
886 ListCell *lc;
887
890 pq_sendint32(&buf, list_length(unrecognized_protocol_options));
891 foreach(lc, unrecognized_protocol_options)
892 pq_sendstring(&buf, lfirst(lc));
894
895 /* no need to flush, some other message will follow */
896}
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
void pq_sendstring(StringInfo buf, const char *str)
Definition: pqformat.c:195
void pq_endmessage(StringInfo buf)
Definition: pqformat.c:296
void pq_beginmessage(StringInfo buf, char msgtype)
Definition: pqformat.c:88
static void pq_sendint32(StringInfo buf, uint32 i)
Definition: pqformat.h:144
#define PqMsg_NegotiateProtocolVersion
Definition: protocol.h:59

References buf, FrontendProtocol, lfirst, list_length(), pq_beginmessage(), pq_endmessage(), pq_sendint32(), pq_sendstring(), and PqMsg_NegotiateProtocolVersion.

Referenced by ProcessStartupPacket().

◆ StartupPacketTimeoutHandler()

static void StartupPacketTimeoutHandler ( void  )
static

Definition at line 923 of file backend_startup.c.

924{
925 _exit(1);
926}

Referenced by BackendInitialize().

Variable Documentation

◆ Trace_connection_negotiation

bool Trace_connection_negotiation = false

Definition at line 43 of file backend_startup.c.

Referenced by ProcessSSLStartup(), and ProcessStartupPacket().