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