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-2023, 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 "common/ip.h"
22 : : #include "common/string.h"
23 : : #include "libpq/libpq.h"
24 : : #include "libpq/libpq-be.h"
25 : : #include "libpq/pqformat.h"
26 : : #include "libpq/pqsignal.h"
27 : : #include "miscadmin.h"
28 : : #include "postmaster/postmaster.h"
29 : : #include "replication/walsender.h"
30 : : #include "storage/fd.h"
31 : : #include "storage/ipc.h"
32 : : #include "storage/proc.h"
33 : : #include "tcop/backend_startup.h"
34 : : #include "tcop/tcopprot.h"
35 : : #include "utils/builtins.h"
36 : : #include "utils/memutils.h"
37 : : #include "utils/ps_status.h"
38 : : #include "utils/timeout.h"
39 : :
40 : : /* GUCs */
41 : : bool Trace_connection_negotiation = false;
42 : :
43 : : static void BackendInitialize(ClientSocket *client_sock, CAC_state cac);
44 : : static int ProcessSSLStartup(Port *port);
45 : : static int ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done);
46 : : static void SendNegotiateProtocolVersion(List *unrecognized_protocol_options);
47 : : static void process_startup_packet_die(SIGNAL_ARGS);
48 : : static void StartupPacketTimeoutHandler(void);
49 : :
50 : : /*
51 : : * Entry point for a new backend process.
52 : : *
53 : : * Initialize the connection, read the startup packet, authenticate the
54 : : * client, and start the main processing loop.
55 : : */
56 : : void
27 heikki.linnakangas@i 57 :GNC 11437 : BackendMain(char *startup_data, size_t startup_data_len)
58 : : {
59 : 11437 : BackendStartupData *bsdata = (BackendStartupData *) startup_data;
60 : :
61 [ - + ]: 11437 : Assert(startup_data_len == sizeof(BackendStartupData));
62 [ - + ]: 11437 : Assert(MyClientSocket != NULL);
63 : :
64 : : #ifdef EXEC_BACKEND
65 : :
66 : : /*
67 : : * Need to reinitialize the SSL library in the backend, since the context
68 : : * structures contain function pointers and cannot be passed through the
69 : : * parameter file.
70 : : *
71 : : * If for some reason reload fails (maybe the user installed broken key
72 : : * files), soldier on without SSL; that's better than all connections
73 : : * becoming impossible.
74 : : *
75 : : * XXX should we do this in all child processes? For the moment it's
76 : : * enough to do it in backend children.
77 : : */
78 : : #ifdef USE_SSL
79 : : if (EnableSSL)
80 : : {
81 : : if (secure_initialize(false) == 0)
82 : : LoadedSSL = true;
83 : : else
84 : : ereport(LOG,
85 : : (errmsg("SSL configuration could not be loaded in child process")));
86 : : }
87 : : #endif
88 : : #endif
89 : :
90 : : /* Perform additional initialization and collect startup packet */
91 : 11437 : BackendInitialize(MyClientSocket, bsdata->canAcceptConnections);
92 : :
93 : : /*
94 : : * Create a per-backend PGPROC struct in shared memory. We must do this
95 : : * before we can use LWLocks or access any shared memory.
96 : : */
97 : 11233 : InitProcess();
98 : :
99 : : /*
100 : : * Make sure we aren't in PostmasterContext anymore. (We can't delete it
101 : : * just yet, though, because InitPostgres will need the HBA data.)
102 : : */
103 : 11231 : MemoryContextSwitchTo(TopMemoryContext);
104 : :
105 : 11231 : PostgresMain(MyProcPort->database_name, MyProcPort->user_name);
106 : : }
107 : :
108 : :
109 : : /*
110 : : * BackendInitialize -- initialize an interactive (postmaster-child)
111 : : * backend process, and collect the client's startup packet.
112 : : *
113 : : * returns: nothing. Will not return at all if there's any failure.
114 : : *
115 : : * Note: this code does not depend on having any access to shared memory.
116 : : * Indeed, our approach to SIGTERM/timeout handling *requires* that
117 : : * shared memory not have been touched yet; see comments within.
118 : : * In the EXEC_BACKEND case, we are physically attached to shared memory
119 : : * but have not yet set up most of our local pointers to shmem structures.
120 : : */
121 : : static void
122 : 11437 : BackendInitialize(ClientSocket *client_sock, CAC_state cac)
123 : : {
124 : : int status;
125 : : int ret;
126 : : Port *port;
127 : : char remote_host[NI_MAXHOST];
128 : : char remote_port[NI_MAXSERV];
129 : : StringInfoData ps_data;
130 : : MemoryContext oldcontext;
131 : :
132 : : /* Tell fd.c about the long-lived FD associated with the client_sock */
133 : 11437 : ReserveExternalFD();
134 : :
135 : : /*
136 : : * PreAuthDelay is a debugging aid for investigating problems in the
137 : : * authentication cycle: it can be set in postgresql.conf to allow time to
138 : : * attach to the newly-forked backend with a debugger. (See also
139 : : * PostAuthDelay, which we allow clients to pass through PGOPTIONS, but it
140 : : * is not honored until after authentication.)
141 : : */
142 [ - + ]: 11437 : if (PreAuthDelay > 0)
27 heikki.linnakangas@i 143 :UNC 0 : pg_usleep(PreAuthDelay * 1000000L);
144 : :
145 : : /* This flag will remain set until InitPostgres finishes authentication */
27 heikki.linnakangas@i 146 :GNC 11437 : ClientAuthInProgress = true; /* limit visibility of log messages */
147 : :
148 : : /*
149 : : * Initialize libpq and enable reporting of ereport errors to the client.
150 : : * Must do this now because authentication uses libpq to send messages.
151 : : *
152 : : * The Port structure and all data structures attached to it are allocated
153 : : * in TopMemoryContext, so that they survive into PostgresMain execution.
154 : : * We need not worry about leaking this storage on failure, since we
155 : : * aren't in the postmaster process anymore.
156 : : */
157 : 11437 : oldcontext = MemoryContextSwitchTo(TopMemoryContext);
158 : 11437 : port = MyProcPort = pq_init(client_sock);
159 : 11437 : MemoryContextSwitchTo(oldcontext);
160 : :
161 : 11437 : whereToSendOutput = DestRemote; /* now safe to ereport to client */
162 : :
163 : : /* set these to empty in case they are needed before we set them up */
164 : 11437 : port->remote_host = "";
165 : 11437 : port->remote_port = "";
166 : :
167 : : /*
168 : : * We arrange to do _exit(1) if we receive SIGTERM or timeout while trying
169 : : * to collect the startup packet; while SIGQUIT results in _exit(2).
170 : : * Otherwise the postmaster cannot shutdown the database FAST or IMMED
171 : : * cleanly if a buggy client fails to send the packet promptly.
172 : : *
173 : : * Exiting with _exit(1) is only possible because we have not yet touched
174 : : * shared memory; therefore no outside-the-process state needs to get
175 : : * cleaned up.
176 : : */
177 : 11437 : pqsignal(SIGTERM, process_startup_packet_die);
178 : : /* SIGQUIT handler was already set up by InitPostmasterChild */
179 : 11437 : InitializeTimeouts(); /* establishes SIGALRM handler */
180 : 11437 : sigprocmask(SIG_SETMASK, &StartupBlockSig, NULL);
181 : :
182 : : /*
183 : : * Get the remote host name and port for logging and status display.
184 : : */
185 : 11437 : remote_host[0] = '\0';
186 : 11437 : remote_port[0] = '\0';
187 [ + + - + ]: 11437 : if ((ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
188 : : remote_host, sizeof(remote_host),
189 : : remote_port, sizeof(remote_port),
190 : : (log_hostname ? 0 : NI_NUMERICHOST) | NI_NUMERICSERV)) != 0)
27 heikki.linnakangas@i 191 [ # # ]:UNC 0 : ereport(WARNING,
192 : : (errmsg_internal("pg_getnameinfo_all() failed: %s",
193 : : gai_strerror(ret))));
194 : :
195 : : /*
196 : : * Save remote_host and remote_port in port structure (after this, they
197 : : * will appear in log_line_prefix data for log messages).
198 : : */
27 heikki.linnakangas@i 199 :GNC 11437 : oldcontext = MemoryContextSwitchTo(TopMemoryContext);
200 : 11437 : port->remote_host = pstrdup(remote_host);
201 : 11437 : port->remote_port = pstrdup(remote_port);
202 : :
203 : : /* And now we can issue the Log_connections message, if wanted */
204 [ + + ]: 11437 : if (Log_connections)
205 : : {
206 [ + + ]: 873 : if (remote_port[0])
207 [ + - ]: 595 : ereport(LOG,
208 : : (errmsg("connection received: host=%s port=%s",
209 : : remote_host,
210 : : remote_port)));
211 : : else
212 [ + - ]: 278 : ereport(LOG,
213 : : (errmsg("connection received: host=%s",
214 : : remote_host)));
215 : : }
216 : :
217 : : /*
218 : : * If we did a reverse lookup to name, we might as well save the results
219 : : * rather than possibly repeating the lookup during authentication.
220 : : *
221 : : * Note that we don't want to specify NI_NAMEREQD above, because then we'd
222 : : * get nothing useful for a client without an rDNS entry. Therefore, we
223 : : * must check whether we got a numeric IPv4 or IPv6 address, and not save
224 : : * it into remote_hostname if so. (This test is conservative and might
225 : : * sometimes classify a hostname as numeric, but an error in that
226 : : * direction is safe; it only results in a possible extra lookup.)
227 : : */
228 [ + + + - ]: 11437 : if (log_hostname &&
229 : 114 : ret == 0 &&
230 [ + - ]: 114 : strspn(remote_host, "0123456789.") < strlen(remote_host) &&
231 [ + - ]: 114 : strspn(remote_host, "0123456789ABCDEFabcdef:") < strlen(remote_host))
232 : : {
233 : 114 : port->remote_hostname = pstrdup(remote_host);
234 : : }
235 : 11437 : MemoryContextSwitchTo(oldcontext);
236 : :
237 : : /*
238 : : * Ready to begin client interaction. We will give up and _exit(1) after
239 : : * a time delay, so that a broken client can't hog a connection
240 : : * indefinitely. PreAuthDelay and any DNS interactions above don't count
241 : : * against the time limit.
242 : : *
243 : : * Note: AuthenticationTimeout is applied here while waiting for the
244 : : * startup packet, and then again in InitPostgres for the duration of any
245 : : * authentication operations. So a hostile client could tie up the
246 : : * process for nearly twice AuthenticationTimeout before we kick him off.
247 : : *
248 : : * Note: because PostgresMain will call InitializeTimeouts again, the
249 : : * registration of STARTUP_PACKET_TIMEOUT will be lost. This is okay
250 : : * since we never use it again after this function.
251 : : */
252 : 11437 : RegisterTimeout(STARTUP_PACKET_TIMEOUT, StartupPacketTimeoutHandler);
253 : 11437 : enable_timeout_after(STARTUP_PACKET_TIMEOUT, AuthenticationTimeout * 1000);
254 : :
255 : : /* Handle direct SSL handshake */
6 256 : 11437 : status = ProcessSSLStartup(port);
257 : :
258 : : /*
259 : : * Receive the startup packet (which might turn out to be a cancel request
260 : : * packet).
261 : : */
262 [ + + ]: 11437 : if (status == STATUS_OK)
263 : 11411 : status = ProcessStartupPacket(port, false, false);
264 : :
265 : : /*
266 : : * If we're going to reject the connection due to database state, say so
267 : : * now instead of wasting cycles on an authentication exchange. (This also
268 : : * allows a pg_ping utility to be written.)
269 : : */
27 270 [ + + ]: 11437 : if (status == STATUS_OK)
271 : : {
272 [ + + + + : 11356 : switch (cac)
- + - ]
273 : : {
274 : 104 : case CAC_STARTUP:
275 [ + - ]: 104 : ereport(FATAL,
276 : : (errcode(ERRCODE_CANNOT_CONNECT_NOW),
277 : : errmsg("the database system is starting up")));
278 : : break;
279 : 1 : case CAC_NOTCONSISTENT:
280 [ + - ]: 1 : if (EnableHotStandby)
281 [ + - ]: 1 : ereport(FATAL,
282 : : (errcode(ERRCODE_CANNOT_CONNECT_NOW),
283 : : errmsg("the database system is not yet accepting connections"),
284 : : errdetail("Consistent recovery state has not been yet reached.")));
285 : : else
27 heikki.linnakangas@i 286 [ # # ]:UNC 0 : ereport(FATAL,
287 : : (errcode(ERRCODE_CANNOT_CONNECT_NOW),
288 : : errmsg("the database system is not accepting connections"),
289 : : errdetail("Hot standby mode is disabled.")));
290 : : break;
27 heikki.linnakangas@i 291 :GNC 14 : case CAC_SHUTDOWN:
292 [ + - ]: 14 : ereport(FATAL,
293 : : (errcode(ERRCODE_CANNOT_CONNECT_NOW),
294 : : errmsg("the database system is shutting down")));
295 : : break;
296 : 4 : case CAC_RECOVERY:
297 [ + - ]: 4 : ereport(FATAL,
298 : : (errcode(ERRCODE_CANNOT_CONNECT_NOW),
299 : : errmsg("the database system is in recovery mode")));
300 : : break;
27 heikki.linnakangas@i 301 :UNC 0 : case CAC_TOOMANY:
302 [ # # ]: 0 : ereport(FATAL,
303 : : (errcode(ERRCODE_TOO_MANY_CONNECTIONS),
304 : : errmsg("sorry, too many clients already")));
305 : : break;
27 heikki.linnakangas@i 306 :GNC 11233 : case CAC_OK:
307 : 11233 : break;
308 : : }
309 : : }
310 : :
311 : : /*
312 : : * Disable the timeout, and prevent SIGTERM again.
313 : : */
314 : 11314 : disable_timeout(STARTUP_PACKET_TIMEOUT, false);
315 : 11314 : sigprocmask(SIG_SETMASK, &BlockSig, NULL);
316 : :
317 : : /*
318 : : * As a safety check that nothing in startup has yet performed
319 : : * shared-memory modifications that would need to be undone if we had
320 : : * exited through SIGTERM or timeout above, check that no on_shmem_exit
321 : : * handlers have been registered yet. (This isn't terribly bulletproof,
322 : : * since someone might misuse an on_proc_exit handler for shmem cleanup,
323 : : * but it's a cheap and helpful check. We cannot disallow on_proc_exit
324 : : * handlers unfortunately, since pq_init() already registered one.)
325 : : */
326 : 11314 : check_on_shmem_exit_lists_are_empty();
327 : :
328 : : /*
329 : : * Stop here if it was bad or a cancel packet. ProcessStartupPacket
330 : : * already did any appropriate error reporting.
331 : : */
332 [ + + ]: 11314 : if (status != STATUS_OK)
333 : 81 : proc_exit(0);
334 : :
335 : : /*
336 : : * Now that we have the user and database name, we can set the process
337 : : * title for ps. It's good to do this as early as possible in startup.
338 : : */
339 : 11233 : initStringInfo(&ps_data);
340 [ + + ]: 11233 : if (am_walsender)
341 : 1031 : appendStringInfo(&ps_data, "%s ", GetBackendTypeDesc(B_WAL_SENDER));
342 : 11233 : appendStringInfo(&ps_data, "%s ", port->user_name);
343 [ + + ]: 11233 : if (port->database_name[0] != '\0')
344 : 10788 : appendStringInfo(&ps_data, "%s ", port->database_name);
345 : 11233 : appendStringInfoString(&ps_data, port->remote_host);
346 [ + + ]: 11233 : if (port->remote_port[0] != '\0')
347 : 581 : appendStringInfo(&ps_data, "(%s)", port->remote_port);
348 : :
349 : 11233 : init_ps_display(ps_data.data);
350 : 11233 : pfree(ps_data.data);
351 : :
352 : 11233 : set_ps_display("initializing");
353 : 11233 : }
354 : :
355 : : /*
356 : : * Check for a direct SSL connection.
357 : : *
358 : : * This happens before the startup packet so we are careful not to actually
359 : : * read any bytes from the stream if it's not a direct SSL connection.
360 : : */
361 : : static int
6 362 : 11437 : ProcessSSLStartup(Port *port)
363 : : {
364 : : int firstbyte;
365 : :
366 [ - + ]: 11437 : Assert(!port->ssl_in_use);
367 : :
368 : 11437 : pq_startmsgread();
369 : 11437 : firstbyte = pq_peekbyte();
370 : 11437 : pq_endmsgread();
371 [ - + ]: 11437 : if (firstbyte == EOF)
372 : : {
373 : : /*
374 : : * Like in ProcessStartupPacket, if we get no data at all, don't
375 : : * clutter the log with a complaint.
376 : : */
6 heikki.linnakangas@i 377 :UNC 0 : return STATUS_ERROR;
378 : : }
379 : :
6 heikki.linnakangas@i 380 [ + + ]:GNC 11437 : if (firstbyte != 0x16)
381 : : {
382 : : /* Not an SSL handshake message */
383 : 11363 : return STATUS_OK;
384 : : }
385 : :
386 : : /*
387 : : * First byte indicates standard SSL handshake message
388 : : *
389 : : * (It can't be a Postgres startup length because in network byte order
390 : : * that would be a startup packet hundreds of megabytes long)
391 : : */
392 : :
393 : : #ifdef USE_SSL
394 [ + + - + ]: 74 : if (!LoadedSSL || port->laddr.addr.ss_family == AF_UNIX)
395 : : {
396 : : /* SSL not supported */
397 : 26 : goto reject;
398 : : }
399 : :
400 [ - + ]: 48 : if (secure_open_server(port) == -1)
401 : : {
402 : : /*
403 : : * we assume secure_open_server() sent an appropriate TLS alert
404 : : * already
405 : : */
6 heikki.linnakangas@i 406 :UNC 0 : goto reject;
407 : : }
6 heikki.linnakangas@i 408 [ - + ]:GNC 48 : Assert(port->ssl_in_use);
409 : :
410 [ - + ]: 48 : if (!port->alpn_used)
411 : : {
6 heikki.linnakangas@i 412 [ # # ]:UNC 0 : ereport(COMMERROR,
413 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
414 : : errmsg("received direct SSL connection request without ALPN protocol negotiation extension")));
415 : 0 : goto reject;
416 : : }
417 : :
6 heikki.linnakangas@i 418 [ + - ]:GNC 48 : if (Trace_connection_negotiation)
419 [ + - ]: 48 : ereport(LOG,
420 : : (errmsg("direct SSL connection accepted")));
421 : 48 : return STATUS_OK;
422 : : #else
423 : : /* SSL not supported by this build */
424 : : goto reject;
425 : : #endif
426 : :
427 : 26 : reject:
428 [ + - ]: 26 : if (Trace_connection_negotiation)
429 [ + - ]: 26 : ereport(LOG,
430 : : (errmsg("direct SSL connection rejected")));
431 : 26 : return STATUS_ERROR;
432 : : }
433 : :
434 : : /*
435 : : * Read a client's startup packet and do something according to it.
436 : : *
437 : : * Returns STATUS_OK or STATUS_ERROR, or might call ereport(FATAL) and
438 : : * not return at all.
439 : : *
440 : : * (Note that ereport(FATAL) stuff is sent to the client, so only use it
441 : : * if that's what you want. Return STATUS_ERROR if you don't want to
442 : : * send anything to the client, which would typically be appropriate
443 : : * if we detect a communications failure.)
444 : : *
445 : : * Set ssl_done and/or gss_done when negotiation of an encrypted layer
446 : : * (currently, TLS or GSSAPI) is completed. A successful negotiation of either
447 : : * encryption layer sets both flags, but a rejected negotiation sets only the
448 : : * flag for that layer, since the client may wish to try the other one. We
449 : : * should make no assumption here about the order in which the client may make
450 : : * requests.
451 : : */
452 : : static int
27 453 : 11859 : ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done)
454 : : {
455 : : int32 len;
456 : : char *buf;
457 : : ProtocolVersion proto;
458 : : MemoryContext oldcontext;
459 : :
460 : 11859 : pq_startmsgread();
461 : :
462 : : /*
463 : : * Grab the first byte of the length word separately, so that we can tell
464 : : * whether we have no data at all or an incomplete packet. (This might
465 : : * sound inefficient, but it's not really, because of buffering in
466 : : * pqcomm.c.)
467 : : */
468 [ + + ]: 11859 : if (pq_getbytes((char *) &len, 1) == EOF)
469 : : {
470 : : /*
471 : : * If we get no data at all, don't clutter the log with a complaint;
472 : : * such cases often occur for legitimate reasons. An example is that
473 : : * we might be here after responding to NEGOTIATE_SSL_CODE, and if the
474 : : * client didn't like our response, it'll probably just drop the
475 : : * connection. Service-monitoring software also often just opens and
476 : : * closes a connection without sending anything. (So do port
477 : : * scanners, which may be less benign, but it's not really our job to
478 : : * notice those.)
479 : : */
480 : 27 : return STATUS_ERROR;
481 : : }
482 : :
483 [ - + ]: 11832 : if (pq_getbytes(((char *) &len) + 1, 3) == EOF)
484 : : {
485 : : /* Got a partial length word, so bleat about that */
27 heikki.linnakangas@i 486 [ # # # # ]:UNC 0 : if (!ssl_done && !gss_done)
487 [ # # ]: 0 : ereport(COMMERROR,
488 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
489 : : errmsg("incomplete startup packet")));
490 : 0 : return STATUS_ERROR;
491 : : }
492 : :
27 heikki.linnakangas@i 493 :GNC 11832 : len = pg_ntoh32(len);
494 : 11832 : len -= 4;
495 : :
496 [ + - ]: 11832 : if (len < (int32) sizeof(ProtocolVersion) ||
497 [ - + ]: 11832 : len > MAX_STARTUP_PACKET_LENGTH)
498 : : {
27 heikki.linnakangas@i 499 [ # # ]:UNC 0 : ereport(COMMERROR,
500 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
501 : : errmsg("invalid length of startup packet")));
502 : 0 : return STATUS_ERROR;
503 : : }
504 : :
505 : : /*
506 : : * Allocate space to hold the startup packet, plus one extra byte that's
507 : : * initialized to be zero. This ensures we will have null termination of
508 : : * all strings inside the packet.
509 : : */
27 heikki.linnakangas@i 510 :GNC 11832 : buf = palloc(len + 1);
511 : 11832 : buf[len] = '\0';
512 : :
513 [ - + ]: 11832 : if (pq_getbytes(buf, len) == EOF)
514 : : {
27 heikki.linnakangas@i 515 [ # # ]:UNC 0 : ereport(COMMERROR,
516 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
517 : : errmsg("incomplete startup packet")));
518 : 0 : return STATUS_ERROR;
519 : : }
27 heikki.linnakangas@i 520 :GNC 11832 : pq_endmsgread();
521 : :
522 : : /*
523 : : * The first field is either a protocol version number or a special
524 : : * request code.
525 : : */
526 : 11832 : port->proto = proto = pg_ntoh32(*((ProtocolVersion *) buf));
527 : :
528 [ + + ]: 11832 : if (proto == CANCEL_REQUEST_CODE)
529 : : {
530 : : CancelRequestPacket *canc;
531 : : int backendPID;
532 : : int32 cancelAuthCode;
533 : :
534 [ - + ]: 10 : if (len != sizeof(CancelRequestPacket))
535 : : {
27 heikki.linnakangas@i 536 [ # # ]:UNC 0 : ereport(COMMERROR,
537 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
538 : : errmsg("invalid length of startup packet")));
539 : 0 : return STATUS_ERROR;
540 : : }
27 heikki.linnakangas@i 541 :GNC 10 : canc = (CancelRequestPacket *) buf;
542 : 10 : backendPID = (int) pg_ntoh32(canc->backendPID);
543 : 10 : cancelAuthCode = (int32) pg_ntoh32(canc->cancelAuthCode);
544 : :
545 : 10 : processCancelRequest(backendPID, cancelAuthCode);
546 : : /* Not really an error, but we don't want to proceed further */
547 : 10 : return STATUS_ERROR;
548 : : }
549 : :
550 [ + + + - ]: 11822 : if (proto == NEGOTIATE_SSL_CODE && !ssl_done)
551 : : {
552 : : char SSLok;
553 : :
554 : : #ifdef USE_SSL
555 : :
556 : : /*
557 : : * No SSL when disabled or on Unix sockets.
558 : : *
559 : : * Also no SSL negotiation if we already have a direct SSL connection
560 : : */
6 561 [ + + + - : 233 : if (!LoadedSSL || port->laddr.addr.ss_family == AF_UNIX || port->ssl_in_use)
- + ]
27 562 : 96 : SSLok = 'N';
563 : : else
564 : 137 : SSLok = 'S'; /* Support for SSL */
565 : : #else
566 : : SSLok = 'N'; /* No support for SSL */
567 : : #endif
568 : :
6 569 [ + + ]: 233 : if (Trace_connection_negotiation)
570 : : {
571 [ + + ]: 50 : if (SSLok == 'S')
572 [ + - ]: 24 : ereport(LOG,
573 : : (errmsg("SSLRequest accepted")));
574 : : else
575 [ + - ]: 26 : ereport(LOG,
576 : : (errmsg("SSLRequest rejected")));
577 : : }
578 : :
579 [ - + ]: 233 : while (secure_write(port, &SSLok, 1) != 1)
580 : : {
27 heikki.linnakangas@i 581 [ # # ]:UNC 0 : if (errno == EINTR)
6 582 : 0 : continue; /* if interrupted, just retry */
27 583 [ # # ]: 0 : ereport(COMMERROR,
584 : : (errcode_for_socket_access(),
585 : : errmsg("failed to send SSL negotiation response: %m")));
586 : 0 : return STATUS_ERROR; /* close the connection */
587 : : }
588 : :
589 : : #ifdef USE_SSL
27 heikki.linnakangas@i 590 [ + + + + ]:GNC 233 : if (SSLok == 'S' && secure_open_server(port) == -1)
591 : 18 : return STATUS_ERROR;
592 : : #endif
593 : :
594 : : /*
595 : : * At this point we should have no data already buffered. If we do,
596 : : * it was received before we performed the SSL handshake, so it wasn't
597 : : * encrypted and indeed may have been injected by a man-in-the-middle.
598 : : * We report this case to the client.
599 : : */
6 600 [ - + ]: 215 : if (pq_buffer_remaining_data() > 0)
27 heikki.linnakangas@i 601 [ # # ]:UNC 0 : ereport(FATAL,
602 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
603 : : errmsg("received unencrypted data after SSL request"),
604 : : errdetail("This could be either a client-software bug or evidence of an attempted man-in-the-middle attack.")));
605 : :
606 : : /*
607 : : * regular startup packet, cancel, etc packet should follow, but not
608 : : * another SSL negotiation request, and a GSS request should only
609 : : * follow if SSL was rejected (client may negotiate in either order)
610 : : */
27 heikki.linnakangas@i 611 :GNC 215 : return ProcessStartupPacket(port, true, SSLok == 'S');
612 : : }
613 [ + + + - ]: 11589 : else if (proto == NEGOTIATE_GSS_CODE && !gss_done)
614 : : {
615 : 233 : char GSSok = 'N';
616 : :
617 : : #ifdef ENABLE_GSS
618 : : /* No GSSAPI encryption when on Unix socket */
619 [ + - ]: 233 : if (port->laddr.addr.ss_family != AF_UNIX)
620 : 233 : GSSok = 'G';
621 : : #endif
622 : :
6 623 [ + + ]: 233 : if (Trace_connection_negotiation)
624 : : {
625 [ + - ]: 193 : if (GSSok == 'G')
626 [ + - ]: 193 : ereport(LOG,
627 : : (errmsg("GSSENCRequest accepted")));
628 : : else
6 heikki.linnakangas@i 629 [ # # ]:UNC 0 : ereport(LOG,
630 : : (errmsg("GSSENCRequest rejected")));
631 : : }
632 : :
6 heikki.linnakangas@i 633 [ - + ]:GNC 233 : while (secure_write(port, &GSSok, 1) != 1)
634 : : {
27 heikki.linnakangas@i 635 [ # # ]:UNC 0 : if (errno == EINTR)
636 : 0 : continue;
637 [ # # ]: 0 : ereport(COMMERROR,
638 : : (errcode_for_socket_access(),
639 : : errmsg("failed to send GSSAPI negotiation response: %m")));
640 : 0 : return STATUS_ERROR; /* close the connection */
641 : : }
642 : :
643 : : #ifdef ENABLE_GSS
27 heikki.linnakangas@i 644 [ + - - + ]:GNC 233 : if (GSSok == 'G' && secure_open_gssapi(port) == -1)
27 heikki.linnakangas@i 645 :UNC 0 : return STATUS_ERROR;
646 : : #endif
647 : :
648 : : /*
649 : : * At this point we should have no data already buffered. If we do,
650 : : * it was received before we performed the GSS handshake, so it wasn't
651 : : * encrypted and indeed may have been injected by a man-in-the-middle.
652 : : * We report this case to the client.
653 : : */
6 heikki.linnakangas@i 654 [ - + ]:GNC 233 : if (pq_buffer_remaining_data() > 0)
27 heikki.linnakangas@i 655 [ # # ]:UNC 0 : ereport(FATAL,
656 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
657 : : errmsg("received unencrypted data after GSSAPI encryption request"),
658 : : errdetail("This could be either a client-software bug or evidence of an attempted man-in-the-middle attack.")));
659 : :
660 : : /*
661 : : * regular startup packet, cancel, etc packet should follow, but not
662 : : * another GSS negotiation request, and an SSL request should only
663 : : * follow if GSS was rejected (client may negotiate in either order)
664 : : */
27 heikki.linnakangas@i 665 :GNC 233 : return ProcessStartupPacket(port, GSSok == 'G', true);
666 : : }
667 : :
668 : : /* Could add additional special packet types here */
669 : :
670 : : /*
671 : : * Set FrontendProtocol now so that ereport() knows what format to send if
672 : : * we fail during startup.
673 : : */
674 : 11356 : FrontendProtocol = proto;
675 : :
676 : : /* Check that the major protocol version is in range. */
677 [ + - ]: 11356 : if (PG_PROTOCOL_MAJOR(proto) < PG_PROTOCOL_MAJOR(PG_PROTOCOL_EARLIEST) ||
678 [ - + ]: 11356 : PG_PROTOCOL_MAJOR(proto) > PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST))
27 heikki.linnakangas@i 679 [ # # ]:UNC 0 : ereport(FATAL,
680 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
681 : : errmsg("unsupported frontend protocol %u.%u: server supports %u.0 to %u.%u",
682 : : PG_PROTOCOL_MAJOR(proto), PG_PROTOCOL_MINOR(proto),
683 : : PG_PROTOCOL_MAJOR(PG_PROTOCOL_EARLIEST),
684 : : PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST),
685 : : PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST))));
686 : :
687 : : /*
688 : : * Now fetch parameters out of startup packet and save them into the Port
689 : : * structure.
690 : : */
27 heikki.linnakangas@i 691 :GNC 11356 : oldcontext = MemoryContextSwitchTo(TopMemoryContext);
692 : :
693 : : /* Handle protocol version 3 startup packet */
694 : : {
695 : 11356 : int32 offset = sizeof(ProtocolVersion);
696 : 11356 : List *unrecognized_protocol_options = NIL;
697 : :
698 : : /*
699 : : * Scan packet body for name/option pairs. We can assume any string
700 : : * beginning within the packet body is null-terminated, thanks to
701 : : * zeroing extra byte above.
702 : : */
703 : 11356 : port->guc_options = NIL;
704 : :
705 [ + - ]: 54287 : while (offset < len)
706 : : {
707 : 54287 : char *nameptr = buf + offset;
708 : : int32 valoffset;
709 : : char *valptr;
710 : :
711 [ + + ]: 54287 : if (*nameptr == '\0')
712 : 11356 : break; /* found packet terminator */
713 : 42931 : valoffset = offset + strlen(nameptr) + 1;
714 [ - + ]: 42931 : if (valoffset >= len)
27 heikki.linnakangas@i 715 :UNC 0 : break; /* missing value, will complain below */
27 heikki.linnakangas@i 716 :GNC 42931 : valptr = buf + valoffset;
717 : :
718 [ + + ]: 42931 : if (strcmp(nameptr, "database") == 0)
719 : 11356 : port->database_name = pstrdup(valptr);
720 [ + + ]: 31575 : else if (strcmp(nameptr, "user") == 0)
721 : 11356 : port->user_name = pstrdup(valptr);
722 [ + + ]: 20219 : else if (strcmp(nameptr, "options") == 0)
723 : 3048 : port->cmdline_options = pstrdup(valptr);
724 [ + + ]: 17171 : else if (strcmp(nameptr, "replication") == 0)
725 : : {
726 : : /*
727 : : * Due to backward compatibility concerns the replication
728 : : * parameter is a hybrid beast which allows the value to be
729 : : * either boolean or the string 'database'. The latter
730 : : * connects to a specific database which is e.g. required for
731 : : * logical decoding while.
732 : : */
733 [ + + ]: 1050 : if (strcmp(valptr, "database") == 0)
734 : : {
735 : 599 : am_walsender = true;
736 : 599 : am_db_walsender = true;
737 : : }
738 [ - + ]: 451 : else if (!parse_bool(valptr, &am_walsender))
27 heikki.linnakangas@i 739 [ # # ]:UNC 0 : ereport(FATAL,
740 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
741 : : errmsg("invalid value for parameter \"%s\": \"%s\"",
742 : : "replication",
743 : : valptr),
744 : : errhint("Valid values are: \"false\", 0, \"true\", 1, \"database\".")));
745 : : }
27 heikki.linnakangas@i 746 [ - + ]:GNC 16121 : else if (strncmp(nameptr, "_pq_.", 5) == 0)
747 : : {
748 : : /*
749 : : * Any option beginning with _pq_. is reserved for use as a
750 : : * protocol-level option, but at present no such options are
751 : : * defined.
752 : : */
753 : : unrecognized_protocol_options =
27 heikki.linnakangas@i 754 :UNC 0 : lappend(unrecognized_protocol_options, pstrdup(nameptr));
755 : : }
756 : : else
757 : : {
758 : : /* Assume it's a generic GUC option */
27 heikki.linnakangas@i 759 :GNC 16121 : port->guc_options = lappend(port->guc_options,
760 : 16121 : pstrdup(nameptr));
761 : 16121 : port->guc_options = lappend(port->guc_options,
762 : 16121 : pstrdup(valptr));
763 : :
764 : : /*
765 : : * Copy application_name to port if we come across it. This
766 : : * is done so we can log the application_name in the
767 : : * connection authorization message. Note that the GUC would
768 : : * be used but we haven't gone through GUC setup yet.
769 : : */
770 [ + + ]: 16121 : if (strcmp(nameptr, "application_name") == 0)
771 : : {
772 : 11351 : port->application_name = pg_clean_ascii(valptr, 0);
773 : : }
774 : : }
775 : 42931 : offset = valoffset + strlen(valptr) + 1;
776 : : }
777 : :
778 : : /*
779 : : * If we didn't find a packet terminator exactly at the end of the
780 : : * given packet length, complain.
781 : : */
782 [ - + ]: 11356 : if (offset != len - 1)
27 heikki.linnakangas@i 783 [ # # ]:UNC 0 : ereport(FATAL,
784 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
785 : : errmsg("invalid startup packet layout: expected terminator as last byte")));
786 : :
787 : : /*
788 : : * If the client requested a newer protocol version or if the client
789 : : * requested any protocol options we didn't recognize, let them know
790 : : * the newest minor protocol version we do support and the names of
791 : : * any unrecognized options.
792 : : */
27 heikki.linnakangas@i 793 [ + - - + ]:GNC 11356 : if (PG_PROTOCOL_MINOR(proto) > PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST) ||
794 : : unrecognized_protocol_options != NIL)
27 heikki.linnakangas@i 795 :UNC 0 : SendNegotiateProtocolVersion(unrecognized_protocol_options);
796 : : }
797 : :
798 : : /* Check a user name was given. */
27 heikki.linnakangas@i 799 [ + - - + ]:GNC 11356 : if (port->user_name == NULL || port->user_name[0] == '\0')
27 heikki.linnakangas@i 800 [ # # ]:UNC 0 : ereport(FATAL,
801 : : (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
802 : : errmsg("no PostgreSQL user name specified in startup packet")));
803 : :
804 : : /* The database defaults to the user name. */
27 heikki.linnakangas@i 805 [ + - - + ]:GNC 11356 : if (port->database_name == NULL || port->database_name[0] == '\0')
27 heikki.linnakangas@i 806 :UNC 0 : port->database_name = pstrdup(port->user_name);
807 : :
27 heikki.linnakangas@i 808 [ + + ]:GNC 11356 : if (am_walsender)
809 : 1050 : MyBackendType = B_WAL_SENDER;
810 : : else
811 : 10306 : MyBackendType = B_BACKEND;
812 : :
813 : : /*
814 : : * Normal walsender backends, e.g. for streaming replication, are not
815 : : * connected to a particular database. But walsenders used for logical
816 : : * replication need to connect to a specific database. We allow streaming
817 : : * replication commands to be issued even if connected to a database as it
818 : : * can make sense to first make a basebackup and then stream changes
819 : : * starting from that.
820 : : */
821 [ + + + + ]: 11356 : if (am_walsender && !am_db_walsender)
822 : 451 : port->database_name[0] = '\0';
823 : :
824 : : /*
825 : : * Done filling the Port structure
826 : : */
827 : 11356 : MemoryContextSwitchTo(oldcontext);
828 : :
829 : 11356 : return STATUS_OK;
830 : : }
831 : :
832 : : /*
833 : : * Send a NegotiateProtocolVersion to the client. This lets the client know
834 : : * that they have requested a newer minor protocol version than we are able
835 : : * to speak. We'll speak the highest version we know about; the client can,
836 : : * of course, abandon the connection if that's a problem.
837 : : *
838 : : * We also include in the response a list of protocol options we didn't
839 : : * understand. This allows clients to include optional parameters that might
840 : : * be present either in newer protocol versions or third-party protocol
841 : : * extensions without fear of having to reconnect if those options are not
842 : : * understood, while at the same time making certain that the client is aware
843 : : * of which options were actually accepted.
844 : : */
845 : : static void
27 heikki.linnakangas@i 846 :UNC 0 : SendNegotiateProtocolVersion(List *unrecognized_protocol_options)
847 : : {
848 : : StringInfoData buf;
849 : : ListCell *lc;
850 : :
851 : 0 : pq_beginmessage(&buf, PqMsg_NegotiateProtocolVersion);
852 : 0 : pq_sendint32(&buf, PG_PROTOCOL_LATEST);
853 : 0 : pq_sendint32(&buf, list_length(unrecognized_protocol_options));
854 [ # # # # : 0 : foreach(lc, unrecognized_protocol_options)
# # ]
855 : 0 : pq_sendstring(&buf, lfirst(lc));
856 : 0 : pq_endmessage(&buf);
857 : :
858 : : /* no need to flush, some other message will follow */
859 : 0 : }
860 : :
861 : :
862 : : /*
863 : : * SIGTERM while processing startup packet.
864 : : *
865 : : * Running proc_exit() from a signal handler would be quite unsafe.
866 : : * However, since we have not yet touched shared memory, we can just
867 : : * pull the plug and exit without running any atexit handlers.
868 : : *
869 : : * One might be tempted to try to send a message, or log one, indicating
870 : : * why we are disconnecting. However, that would be quite unsafe in itself.
871 : : * Also, it seems undesirable to provide clues about the database's state
872 : : * to a client that has not yet completed authentication, or even sent us
873 : : * a startup packet.
874 : : */
875 : : static void
876 : 0 : process_startup_packet_die(SIGNAL_ARGS)
877 : : {
0 andres@anarazel.de 878 : 0 : immediate_exit(1);
879 : : }
880 : :
881 : : /*
882 : : * Timeout while processing startup packet.
883 : : * As for process_startup_packet_die(), we exit via immediate_exit(1).
884 : : */
885 : : static void
27 heikki.linnakangas@i 886 : 0 : StartupPacketTimeoutHandler(void)
887 : : {
0 andres@anarazel.de 888 : 0 : immediate_exit(1);
889 : : }
|