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 : : /* ------------------------------------------------------------ */
65 : : /* Procedures common to all secure sessions */
66 : : /* ------------------------------------------------------------ */
67 : :
68 : : /*
69 : : * Initialize global context.
70 : : *
71 : : * If isServerStart is true, report any errors as FATAL (so we don't return).
72 : : * Otherwise, log errors at LOG level and return -1 to indicate trouble,
73 : : * preserving the old SSL state if any. Returns 0 if OK.
74 : : */
75 : : int
3357 tgl@sss.pgh.pa.us 76 :CBC 36 : secure_initialize(bool isServerStart)
77 : : {
78 : : #ifdef USE_SSL
79 : 36 : return be_tls_init(isServerStart);
80 : : #else
81 : : return 0;
82 : : #endif
83 : : }
84 : :
85 : : /*
86 : : * Destroy global context, if any.
87 : : */
88 : : void
3359 89 : 155 : secure_destroy(void)
90 : : {
91 : : #ifdef USE_SSL
92 : 155 : be_tls_destroy();
93 : : #endif
8675 bruce@momjian.us 94 : 155 : }
95 : :
96 : : /*
97 : : * Indicate if we have loaded the root CA store to verify certificates
98 : : */
99 : : bool
6324 magnus@hagander.net 100 : 30 : secure_loaded_verify_locations(void)
101 : : {
102 : : #ifdef USE_SSL
103 : 30 : return ssl_loaded_verify_locations;
104 : : #else
105 : : return false;
106 : : #endif
107 : : }
108 : :
109 : : /*
110 : : * Attempt to negotiate secure session.
111 : : */
112 : : int
8593 bruce@momjian.us 113 : 153 : secure_open_server(Port *port)
114 : : {
115 : : #ifdef USE_SSL
116 : 153 : int r = 0;
117 : : ssize_t len;
118 : :
119 : : /* push unencrypted buffered data back through SSL setup */
706 heikki.linnakangas@i 120 : 153 : len = pq_buffer_remaining_data();
121 [ + + ]: 153 : if (len > 0)
122 : : {
123 : 10 : char *buf = palloc(len);
124 : :
125 : 10 : pq_startmsgread();
126 [ - + ]: 10 : if (pq_getbytes(buf, len) == EOF)
706 heikki.linnakangas@i 127 :UBC 0 : return STATUS_ERROR; /* shouldn't be possible */
706 heikki.linnakangas@i 128 :CBC 10 : pq_endmsgread();
129 : 10 : port->raw_buf = buf;
130 : 10 : port->raw_buf_remaining = len;
131 : 10 : port->raw_buf_consumed = 0;
132 : : }
133 [ - + ]: 153 : Assert(pq_buffer_remaining_data() == 0);
134 : :
309 michael@paquier.xyz 135 : 153 : INJECTION_POINT("backend-ssl-startup", NULL);
136 : :
4234 heikki.linnakangas@i 137 : 153 : r = be_tls_open_server(port);
138 : :
706 139 [ - + ]: 153 : if (port->raw_buf_remaining > 0)
140 : : {
141 : : /*
142 : : * This shouldn't be possible -- it would mean the client sent
143 : : * encrypted data before we established a session key...
144 : : */
706 heikki.linnakangas@i 145 [ # # ]:UBC 0 : elog(LOG, "buffered unencrypted data remains after negotiating SSL connection");
146 : 0 : return STATUS_ERROR;
147 : : }
706 heikki.linnakangas@i 148 [ + + ]:CBC 153 : if (port->raw_buf != NULL)
149 : : {
150 : 10 : pfree(port->raw_buf);
151 : 10 : port->raw_buf = NULL;
152 : : }
153 : :
2977 peter_e@gmx.net 154 [ + + + + : 153 : ereport(DEBUG2,
+ + ]
155 : : (errmsg_internal("SSL connection from DN:\"%s\" CN:\"%s\"",
156 : : port->peer_dn ? port->peer_dn : "(anonymous)",
157 : : port->peer_cn ? port->peer_cn : "(anonymous)")));
8675 bruce@momjian.us 158 : 153 : return r;
159 : : #else
160 : : return 0;
161 : : #endif
162 : : }
163 : :
164 : : /*
165 : : * Close secure session.
166 : : */
167 : : void
8593 168 : 14141 : secure_close(Port *port)
169 : : {
170 : : #ifdef USE_SSL
4234 heikki.linnakangas@i 171 [ + + ]: 14141 : if (port->ssl_in_use)
172 : 153 : be_tls_close(port);
173 : : #endif
8675 bruce@momjian.us 174 : 14141 : }
175 : :
176 : : /*
177 : : * Read data from a secure connection.
178 : : */
179 : : ssize_t
8593 180 : 1299829 : secure_read(Port *port, void *ptr, size_t len)
181 : : {
182 : : ssize_t n;
183 : : int waitfor;
184 : :
185 : : /* Deal with any already-pending interrupt condition. */
2704 tgl@sss.pgh.pa.us 186 : 1299829 : ProcessClientReadInterrupt(false);
187 : :
4058 andres@anarazel.de 188 : 1479047 : retry:
189 : : #ifdef USE_SSL
4048 heikki.linnakangas@i 190 : 1479047 : waitfor = 0;
4234 191 [ + + ]: 1479047 : if (port->ssl_in_use)
192 : : {
4048 193 : 605 : n = be_tls_read(port, ptr, len, &waitfor);
194 : : }
195 : : else
196 : : #endif
197 : : #ifdef ENABLE_GSS
1903 tgl@sss.pgh.pa.us 198 [ + + + + ]: 1478442 : if (port->gss && port->gss->enc)
199 : : {
2538 sfrost@snowman.net 200 : 750 : n = be_gssapi_read(port, ptr, len);
201 : 750 : waitfor = WL_SOCKET_READABLE;
202 : : }
203 : : else
204 : : #endif
205 : : {
4234 heikki.linnakangas@i 206 : 1477692 : n = secure_raw_read(port, ptr, len);
4048 207 : 1477692 : waitfor = WL_SOCKET_READABLE;
208 : : }
209 : :
210 : : /* In blocking mode, wait until the socket is ready */
211 [ + + + + : 1479047 : if (n < 0 && !port->noblock && (errno == EWOULDBLOCK || errno == EAGAIN))
+ + - + ]
212 : : {
213 : : WaitEvent event;
214 : :
215 [ - + ]: 179247 : Assert(waitfor);
216 : :
1840 tmunro@postgresql.or 217 : 179247 : ModifyWaitEvent(FeBeWaitSet, FeBeWaitSetSocketPos, waitfor, NULL);
218 : :
3449 rhaas@postgresql.org 219 : 179247 : WaitEventSetWait(FeBeWaitSet, -1 /* no timeout */ , &event, 1,
220 : : WAIT_EVENT_CLIENT_READ);
221 : :
222 : : /*
223 : : * If the postmaster has died, it's not safe to continue running,
224 : : * because it is the postmaster's job to kill us if some other backend
225 : : * exits uncleanly. Moreover, we won't run very well in this state;
226 : : * helper processes like walwriter and the bgwriter will exit, so
227 : : * performance may be poor. Finally, if we don't exit, pg_ctl will be
228 : : * unable to restart the postmaster without manual intervention, so no
229 : : * new connections can be accepted. Exiting clears the deck for a
230 : : * postmaster restart.
231 : : *
232 : : * (Note that we only make this check when we would otherwise sleep on
233 : : * our latch. We might still continue running for a while if the
234 : : * postmaster is killed in mid-query, or even through multiple queries
235 : : * if we never have to wait for read. We don't want to burn too many
236 : : * cycles checking for this very rare condition, and this should cause
237 : : * us to exit quickly in most cases.)
238 : : */
3646 andres@anarazel.de 239 [ - + ]: 179247 : if (event.events & WL_POSTMASTER_DEATH)
3776 rhaas@postgresql.org 240 [ # # ]:UBC 0 : ereport(FATAL,
241 : : (errcode(ERRCODE_ADMIN_SHUTDOWN),
242 : : errmsg("terminating connection due to unexpected postmaster exit")));
243 : :
244 : : /* Handle interrupt. */
3646 andres@anarazel.de 245 [ + + ]:CBC 179247 : if (event.events & WL_LATCH_SET)
246 : : {
4048 heikki.linnakangas@i 247 : 10920 : ResetLatch(MyLatch);
248 : 10920 : ProcessClientReadInterrupt(true);
249 : :
250 : : /*
251 : : * We'll retry the read. Most likely it will return immediately
252 : : * because there's still no data available, and we'll wait for the
253 : : * socket to become ready again.
254 : : */
255 : : }
4058 andres@anarazel.de 256 : 179228 : goto retry;
257 : : }
258 : :
259 : : /*
260 : : * Process interrupts that happened during a successful (or non-blocking,
261 : : * or hard-failed) read.
262 : : */
263 : 1299800 : ProcessClientReadInterrupt(false);
264 : :
8675 bruce@momjian.us 265 : 1299800 : return n;
266 : : }
267 : :
268 : : ssize_t
4234 heikki.linnakangas@i 269 : 1481813 : secure_raw_read(Port *port, void *ptr, size_t len)
270 : : {
271 : : ssize_t n;
272 : :
273 : : /* Read from the "unread" buffered data first. c.f. libpq-be.h */
706 274 [ + + ]: 1481813 : if (port->raw_buf_remaining > 0)
275 : : {
276 : : /* consume up to len bytes from the raw_buf */
277 [ - + ]: 20 : if (len > port->raw_buf_remaining)
706 heikki.linnakangas@i 278 :UBC 0 : len = port->raw_buf_remaining;
706 heikki.linnakangas@i 279 [ - + ]:CBC 20 : Assert(port->raw_buf);
280 : 20 : memcpy(ptr, port->raw_buf + port->raw_buf_consumed, len);
281 : 20 : port->raw_buf_consumed += len;
282 : 20 : port->raw_buf_remaining -= len;
283 : 20 : return len;
284 : : }
285 : :
286 : : /*
287 : : * Try to read from the socket without blocking. If it succeeds we're
288 : : * done, otherwise we'll wait for the socket using the latch mechanism.
289 : : */
290 : : #ifdef WIN32
291 : : pgwin32_noblock = true;
292 : : #endif
4234 293 : 1481793 : n = recv(port->sock, ptr, len, 0);
294 : : #ifdef WIN32
295 : : pgwin32_noblock = false;
296 : : #endif
297 : :
298 : 1481793 : return n;
299 : : }
300 : :
301 : :
302 : : /*
303 : : * Write data to a secure connection.
304 : : */
305 : : ssize_t
399 peter@eisentraut.org 306 : 1094525 : secure_write(Port *port, const void *ptr, size_t len)
307 : : {
308 : : ssize_t n;
309 : : int waitfor;
310 : :
311 : : /* Deal with any already-pending interrupt condition. */
2704 tgl@sss.pgh.pa.us 312 : 1094525 : ProcessClientWriteInterrupt(false);
313 : :
4058 andres@anarazel.de 314 : 1112517 : retry:
4048 heikki.linnakangas@i 315 : 1112517 : waitfor = 0;
316 : : #ifdef USE_SSL
4234 317 [ + + ]: 1112517 : if (port->ssl_in_use)
318 : : {
4048 319 : 237 : n = be_tls_write(port, ptr, len, &waitfor);
320 : : }
321 : : else
322 : : #endif
323 : : #ifdef ENABLE_GSS
1903 tgl@sss.pgh.pa.us 324 [ + + + + ]: 1112280 : if (port->gss && port->gss->enc)
325 : : {
2538 sfrost@snowman.net 326 : 415 : n = be_gssapi_write(port, ptr, len);
327 : 415 : waitfor = WL_SOCKET_WRITEABLE;
328 : : }
329 : : else
330 : : #endif
331 : : {
4234 heikki.linnakangas@i 332 : 1111865 : n = secure_raw_write(port, ptr, len);
4048 333 : 1111865 : waitfor = WL_SOCKET_WRITEABLE;
334 : : }
335 : :
336 [ + + + + : 1112517 : if (n < 0 && !port->noblock && (errno == EWOULDBLOCK || errno == EAGAIN))
+ + - + ]
337 : : {
338 : : WaitEvent event;
339 : :
340 [ - + ]: 17992 : Assert(waitfor);
341 : :
1840 tmunro@postgresql.or 342 : 17992 : ModifyWaitEvent(FeBeWaitSet, FeBeWaitSetSocketPos, waitfor, NULL);
343 : :
3449 rhaas@postgresql.org 344 : 17992 : WaitEventSetWait(FeBeWaitSet, -1 /* no timeout */ , &event, 1,
345 : : WAIT_EVENT_CLIENT_WRITE);
346 : :
347 : : /* See comments in secure_read. */
3646 andres@anarazel.de 348 [ - + ]: 17992 : if (event.events & WL_POSTMASTER_DEATH)
3776 rhaas@postgresql.org 349 [ # # ]:UBC 0 : ereport(FATAL,
350 : : (errcode(ERRCODE_ADMIN_SHUTDOWN),
351 : : errmsg("terminating connection due to unexpected postmaster exit")));
352 : :
353 : : /* Handle interrupt. */
3646 andres@anarazel.de 354 [ + + ]:CBC 17992 : if (event.events & WL_LATCH_SET)
355 : : {
4048 heikki.linnakangas@i 356 : 3 : ResetLatch(MyLatch);
357 : 3 : ProcessClientWriteInterrupt(true);
358 : :
359 : : /*
360 : : * We'll retry the write. Most likely it will return immediately
361 : : * because there's still no buffer space available, and we'll wait
362 : : * for the socket to become ready again.
363 : : */
364 : : }
4058 andres@anarazel.de 365 : 17992 : goto retry;
366 : : }
367 : :
368 : : /*
369 : : * Process interrupts that happened during a successful (or non-blocking,
370 : : * or hard-failed) write.
371 : : */
4048 heikki.linnakangas@i 372 : 1094525 : ProcessClientWriteInterrupt(false);
373 : :
4234 374 : 1094525 : return n;
375 : : }
376 : :
377 : : ssize_t
378 : 1113046 : secure_raw_write(Port *port, const void *ptr, size_t len)
379 : : {
380 : : ssize_t n;
381 : :
382 : : #ifdef WIN32
383 : : pgwin32_noblock = true;
384 : : #endif
4058 andres@anarazel.de 385 : 1113046 : n = send(port->sock, ptr, len, 0);
386 : : #ifdef WIN32
387 : : pgwin32_noblock = false;
388 : : #endif
389 : :
390 : 1113046 : return n;
391 : : }
|