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