Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * be-secure.c
4 : : * functions related to setting up a secure connection to the frontend.
5 : : * Secure connections are expected to provide confidentiality,
6 : : * message integrity and endpoint authentication.
7 : : *
8 : : *
9 : : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
10 : : * Portions Copyright (c) 1994, Regents of the University of California
11 : : *
12 : : *
13 : : * IDENTIFICATION
14 : : * src/backend/libpq/be-secure.c
15 : : *
16 : : *-------------------------------------------------------------------------
17 : : */
18 : :
19 : : #include "postgres.h"
20 : :
21 : : #include <signal.h>
22 : : #include <fcntl.h>
23 : : #include <ctype.h>
24 : : #include <sys/socket.h>
25 : : #include <netdb.h>
26 : : #include <netinet/in.h>
27 : : #include <netinet/tcp.h>
28 : : #include <arpa/inet.h>
29 : :
30 : : #include "libpq/libpq.h"
31 : : #include "miscadmin.h"
32 : : #include "storage/latch.h"
33 : : #include "tcop/tcopprot.h"
34 : : #include "utils/injection_point.h"
35 : : #include "utils/wait_event.h"
36 : :
37 : : char *ssl_library;
38 : : char *ssl_cert_file;
39 : : char *ssl_key_file;
40 : : char *ssl_ca_file;
41 : : char *ssl_crl_file;
42 : : char *ssl_crl_dir;
43 : : char *ssl_dh_params_file;
44 : : char *ssl_passphrase_command;
45 : : bool ssl_passphrase_command_supports_reload;
46 : :
47 : : #ifdef USE_SSL
48 : : bool ssl_loaded_verify_locations = false;
49 : : #endif
50 : :
51 : : /* GUC variable controlling SSL cipher list */
52 : : char *SSLCipherSuites = NULL;
53 : : char *SSLCipherList = NULL;
54 : :
55 : : /* GUC variable for default ECHD curve. */
56 : : char *SSLECDHCurve;
57 : :
58 : : /* GUC variable: if false, prefer client ciphers */
59 : : bool SSLPreferServerCiphers;
60 : :
61 : : int ssl_min_protocol_version = PG_TLS1_2_VERSION;
62 : : int ssl_max_protocol_version = PG_TLS_ANY;
63 : :
64 : : /* GUC variable: if false, discards hostname extensions in handshake */
65 : : bool ssl_sni = false;
66 : :
67 : : /* ------------------------------------------------------------ */
68 : : /* Procedures common to all secure sessions */
69 : : /* ------------------------------------------------------------ */
70 : :
71 : : /*
72 : : * Initialize global context.
73 : : *
74 : : * If isServerStart is true, report any errors as FATAL (so we don't return).
75 : : * Otherwise, log errors at LOG level and return -1 to indicate trouble,
76 : : * preserving the old SSL state if any. Returns 0 if OK.
77 : : */
78 : : int
3408 tgl@sss.pgh.pa.us 79 :CBC 66 : secure_initialize(bool isServerStart)
80 : : {
81 : : #ifdef USE_SSL
82 : 66 : return be_tls_init(isServerStart);
83 : : #else
84 : : return 0;
85 : : #endif
86 : : }
87 : :
88 : : /*
89 : : * Destroy global context, if any.
90 : : */
91 : : void
3410 92 : 163 : secure_destroy(void)
93 : : {
94 : : #ifdef USE_SSL
95 : 163 : be_tls_destroy();
96 : : #endif
8726 bruce@momjian.us 97 : 163 : }
98 : :
99 : : /*
100 : : * Indicate if we have loaded the root CA store to verify certificates
101 : : */
102 : : bool
6375 magnus@hagander.net 103 : 38 : secure_loaded_verify_locations(void)
104 : : {
105 : : #ifdef USE_SSL
106 : 38 : return ssl_loaded_verify_locations;
107 : : #else
108 : : return false;
109 : : #endif
110 : : }
111 : :
112 : : /*
113 : : * Attempt to negotiate secure session.
114 : : */
115 : : int
8644 bruce@momjian.us 116 : 193 : secure_open_server(Port *port)
117 : : {
118 : : #ifdef USE_SSL
119 : 193 : int r = 0;
120 : : ssize_t len;
121 : :
122 : : /* push unencrypted buffered data back through SSL setup */
757 heikki.linnakangas@i 123 : 193 : len = pq_buffer_remaining_data();
124 [ + + ]: 193 : if (len > 0)
125 : : {
126 : 10 : char *buf = palloc(len);
127 : :
128 : 10 : pq_startmsgread();
129 [ - + ]: 10 : if (pq_getbytes(buf, len) == EOF)
757 heikki.linnakangas@i 130 :UBC 0 : return STATUS_ERROR; /* shouldn't be possible */
757 heikki.linnakangas@i 131 :CBC 10 : pq_endmsgread();
132 : 10 : port->raw_buf = buf;
133 : 10 : port->raw_buf_remaining = len;
134 : 10 : port->raw_buf_consumed = 0;
135 : : }
136 [ - + ]: 193 : Assert(pq_buffer_remaining_data() == 0);
137 : :
360 michael@paquier.xyz 138 : 193 : INJECTION_POINT("backend-ssl-startup", NULL);
139 : :
4285 heikki.linnakangas@i 140 : 192 : r = be_tls_open_server(port);
141 : :
757 142 [ - + ]: 192 : if (port->raw_buf_remaining > 0)
143 : : {
144 : : /*
145 : : * This shouldn't be possible -- it would mean the client sent
146 : : * encrypted data before we established a session key...
147 : : */
757 heikki.linnakangas@i 148 [ # # ]:UBC 0 : elog(LOG, "buffered unencrypted data remains after negotiating SSL connection");
149 : 0 : return STATUS_ERROR;
150 : : }
757 heikki.linnakangas@i 151 [ + + ]:CBC 192 : if (port->raw_buf != NULL)
152 : : {
153 : 10 : pfree(port->raw_buf);
154 : 10 : port->raw_buf = NULL;
155 : : }
156 : :
3028 peter_e@gmx.net 157 [ + + + + : 192 : ereport(DEBUG2,
+ + ]
158 : : (errmsg_internal("SSL connection from DN:\"%s\" CN:\"%s\"",
159 : : port->peer_dn ? port->peer_dn : "(anonymous)",
160 : : port->peer_cn ? port->peer_cn : "(anonymous)")));
8726 bruce@momjian.us 161 : 192 : return r;
162 : : #else
163 : : return 0;
164 : : #endif
165 : : }
166 : :
167 : : /*
168 : : * Close secure session.
169 : : */
170 : : void
8644 171 : 15033 : secure_close(Port *port)
172 : : {
173 : : #ifdef USE_SSL
4285 heikki.linnakangas@i 174 [ + + ]: 15033 : if (port->ssl_in_use)
175 : 192 : be_tls_close(port);
176 : : #endif
8726 bruce@momjian.us 177 : 15033 : }
178 : :
179 : : /*
180 : : * Read data from a secure connection.
181 : : */
182 : : ssize_t
8644 183 : 1687178 : secure_read(Port *port, void *ptr, size_t len)
184 : : {
185 : : ssize_t n;
186 : : int waitfor;
187 : :
188 : : /* Deal with any already-pending interrupt condition. */
2755 tgl@sss.pgh.pa.us 189 : 1687178 : ProcessClientReadInterrupt(false);
190 : :
4109 andres@anarazel.de 191 : 1911546 : retry:
192 : : #ifdef USE_SSL
4099 heikki.linnakangas@i 193 : 1911546 : waitfor = 0;
4285 194 [ + + ]: 1911546 : if (port->ssl_in_use)
195 : : {
4099 196 : 709 : n = be_tls_read(port, ptr, len, &waitfor);
197 : : }
198 : : else
199 : : #endif
200 : : #ifdef ENABLE_GSS
1954 tgl@sss.pgh.pa.us 201 [ + + + + ]: 1910837 : if (port->gss && port->gss->enc)
202 : : {
2589 sfrost@snowman.net 203 : 733 : n = be_gssapi_read(port, ptr, len);
204 : 733 : waitfor = WL_SOCKET_READABLE;
205 : : }
206 : : else
207 : : #endif
208 : : {
4285 heikki.linnakangas@i 209 : 1910104 : n = secure_raw_read(port, ptr, len);
4099 210 : 1910104 : waitfor = WL_SOCKET_READABLE;
211 : : }
212 : :
213 : : /* In blocking mode, wait until the socket is ready */
214 [ + + + + : 1911546 : if (n < 0 && !port->noblock && (errno == EWOULDBLOCK || errno == EAGAIN))
+ + - + ]
215 : : {
216 : : WaitEvent event;
217 : :
218 [ - + ]: 224400 : Assert(waitfor);
219 : :
1891 tmunro@postgresql.or 220 : 224400 : ModifyWaitEvent(FeBeWaitSet, FeBeWaitSetSocketPos, waitfor, NULL);
221 : :
3500 rhaas@postgresql.org 222 : 224400 : WaitEventSetWait(FeBeWaitSet, -1 /* no timeout */ , &event, 1,
223 : : WAIT_EVENT_CLIENT_READ);
224 : :
225 : : /*
226 : : * If the postmaster has died, it's not safe to continue running,
227 : : * because it is the postmaster's job to kill us if some other backend
228 : : * exits uncleanly. Moreover, we won't run very well in this state;
229 : : * helper processes like walwriter and the bgwriter will exit, so
230 : : * performance may be poor. Finally, if we don't exit, pg_ctl will be
231 : : * unable to restart the postmaster without manual intervention, so no
232 : : * new connections can be accepted. Exiting clears the deck for a
233 : : * postmaster restart.
234 : : *
235 : : * (Note that we only make this check when we would otherwise sleep on
236 : : * our latch. We might still continue running for a while if the
237 : : * postmaster is killed in mid-query, or even through multiple queries
238 : : * if we never have to wait for read. We don't want to burn too many
239 : : * cycles checking for this very rare condition, and this should cause
240 : : * us to exit quickly in most cases.)
241 : : */
3697 andres@anarazel.de 242 [ - + ]: 224400 : if (event.events & WL_POSTMASTER_DEATH)
3827 rhaas@postgresql.org 243 [ # # ]:UBC 0 : ereport(FATAL,
244 : : (errcode(ERRCODE_ADMIN_SHUTDOWN),
245 : : errmsg("terminating connection due to unexpected postmaster exit")));
246 : :
247 : : /* Handle interrupt. */
3697 andres@anarazel.de 248 [ + + ]:CBC 224400 : if (event.events & WL_LATCH_SET)
249 : : {
4099 heikki.linnakangas@i 250 : 11699 : ResetLatch(MyLatch);
251 : 11699 : ProcessClientReadInterrupt(true);
252 : :
253 : : /*
254 : : * We'll retry the read. Most likely it will return immediately
255 : : * because there's still no data available, and we'll wait for the
256 : : * socket to become ready again.
257 : : */
258 : : }
4109 andres@anarazel.de 259 : 224380 : goto retry;
260 : : }
261 : :
262 : : /*
263 : : * Process interrupts that happened during a successful (or non-blocking,
264 : : * or hard-failed) read.
265 : : */
266 : 1687146 : ProcessClientReadInterrupt(false);
267 : :
8726 bruce@momjian.us 268 : 1687145 : return n;
269 : : }
270 : :
271 : : ssize_t
4285 heikki.linnakangas@i 272 : 1914773 : secure_raw_read(Port *port, void *ptr, size_t len)
273 : : {
274 : : ssize_t n;
275 : :
276 : : /* Read from the "unread" buffered data first. c.f. libpq-be.h */
757 277 [ + + ]: 1914773 : if (port->raw_buf_remaining > 0)
278 : : {
279 : : /* consume up to len bytes from the raw_buf */
280 [ - + ]: 20 : if (len > port->raw_buf_remaining)
757 heikki.linnakangas@i 281 :UBC 0 : len = port->raw_buf_remaining;
757 heikki.linnakangas@i 282 [ - + ]:CBC 20 : Assert(port->raw_buf);
283 : 20 : memcpy(ptr, port->raw_buf + port->raw_buf_consumed, len);
284 : 20 : port->raw_buf_consumed += len;
285 : 20 : port->raw_buf_remaining -= len;
286 : 20 : return len;
287 : : }
288 : :
289 : : /*
290 : : * Try to read from the socket without blocking. If it succeeds we're
291 : : * done, otherwise we'll wait for the socket using the latch mechanism.
292 : : */
293 : : #ifdef WIN32
294 : : pgwin32_noblock = true;
295 : : #endif
4285 296 : 1914753 : n = recv(port->sock, ptr, len, 0);
297 : : #ifdef WIN32
298 : : pgwin32_noblock = false;
299 : : #endif
300 : :
301 : 1914753 : return n;
302 : : }
303 : :
304 : :
305 : : /*
306 : : * Write data to a secure connection.
307 : : */
308 : : ssize_t
450 peter@eisentraut.org 309 : 1217575 : secure_write(Port *port, const void *ptr, size_t len)
310 : : {
311 : : ssize_t n;
312 : : int waitfor;
313 : :
314 : : /* Deal with any already-pending interrupt condition. */
2755 tgl@sss.pgh.pa.us 315 : 1217575 : ProcessClientWriteInterrupt(false);
316 : :
4109 andres@anarazel.de 317 : 1235949 : retry:
4099 heikki.linnakangas@i 318 : 1235949 : waitfor = 0;
319 : : #ifdef USE_SSL
4285 320 [ + + ]: 1235949 : if (port->ssl_in_use)
321 : : {
4099 322 : 285 : n = be_tls_write(port, ptr, len, &waitfor);
323 : : }
324 : : else
325 : : #endif
326 : : #ifdef ENABLE_GSS
1954 tgl@sss.pgh.pa.us 327 [ + + + + ]: 1235664 : if (port->gss && port->gss->enc)
328 : : {
2589 sfrost@snowman.net 329 : 415 : n = be_gssapi_write(port, ptr, len);
330 : 415 : waitfor = WL_SOCKET_WRITEABLE;
331 : : }
332 : : else
333 : : #endif
334 : : {
4285 heikki.linnakangas@i 335 : 1235249 : n = secure_raw_write(port, ptr, len);
4099 336 : 1235249 : waitfor = WL_SOCKET_WRITEABLE;
337 : : }
338 : :
339 [ + + + + : 1235949 : if (n < 0 && !port->noblock && (errno == EWOULDBLOCK || errno == EAGAIN))
+ + - + ]
340 : : {
341 : : WaitEvent event;
342 : :
343 [ - + ]: 18374 : Assert(waitfor);
344 : :
1891 tmunro@postgresql.or 345 : 18374 : ModifyWaitEvent(FeBeWaitSet, FeBeWaitSetSocketPos, waitfor, NULL);
346 : :
3500 rhaas@postgresql.org 347 : 18374 : WaitEventSetWait(FeBeWaitSet, -1 /* no timeout */ , &event, 1,
348 : : WAIT_EVENT_CLIENT_WRITE);
349 : :
350 : : /* See comments in secure_read. */
3697 andres@anarazel.de 351 [ - + ]: 18374 : if (event.events & WL_POSTMASTER_DEATH)
3827 rhaas@postgresql.org 352 [ # # ]:UBC 0 : ereport(FATAL,
353 : : (errcode(ERRCODE_ADMIN_SHUTDOWN),
354 : : errmsg("terminating connection due to unexpected postmaster exit")));
355 : :
356 : : /* Handle interrupt. */
3697 andres@anarazel.de 357 [ + + ]:CBC 18374 : if (event.events & WL_LATCH_SET)
358 : : {
4099 heikki.linnakangas@i 359 : 5 : ResetLatch(MyLatch);
360 : 5 : ProcessClientWriteInterrupt(true);
361 : :
362 : : /*
363 : : * We'll retry the write. Most likely it will return immediately
364 : : * because there's still no buffer space available, and we'll wait
365 : : * for the socket to become ready again.
366 : : */
367 : : }
4109 andres@anarazel.de 368 : 18374 : goto retry;
369 : : }
370 : :
371 : : /*
372 : : * Process interrupts that happened during a successful (or non-blocking,
373 : : * or hard-failed) write.
374 : : */
4099 heikki.linnakangas@i 375 : 1217575 : ProcessClientWriteInterrupt(false);
376 : :
4285 377 : 1217575 : return n;
378 : : }
379 : :
380 : : ssize_t
381 : 1236578 : secure_raw_write(Port *port, const void *ptr, size_t len)
382 : : {
383 : : ssize_t n;
384 : :
385 : : #ifdef WIN32
386 : : pgwin32_noblock = true;
387 : : #endif
4109 andres@anarazel.de 388 : 1236578 : n = send(port->sock, ptr, len, 0);
389 : : #ifdef WIN32
390 : : pgwin32_noblock = false;
391 : : #endif
392 : :
393 : 1236578 : return n;
394 : : }
|