Coverage Report

Created: 2025-06-15 06:31

/src/postgres/src/backend/libpq/be-secure.c
Line
Count
Source (jump to first uncovered line)
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
75
secure_initialize(bool isServerStart)
76
0
{
77
#ifdef USE_SSL
78
  return be_tls_init(isServerStart);
79
#else
80
0
  return 0;
81
0
#endif
82
0
}
83
84
/*
85
 *  Destroy global context, if any.
86
 */
87
void
88
secure_destroy(void)
89
0
{
90
#ifdef USE_SSL
91
  be_tls_destroy();
92
#endif
93
0
}
94
95
/*
96
 * Indicate if we have loaded the root CA store to verify certificates
97
 */
98
bool
99
secure_loaded_verify_locations(void)
100
0
{
101
#ifdef USE_SSL
102
  return ssl_loaded_verify_locations;
103
#else
104
0
  return false;
105
0
#endif
106
0
}
107
108
/*
109
 *  Attempt to negotiate secure session.
110
 */
111
int
112
secure_open_server(Port *port)
113
0
{
114
#ifdef USE_SSL
115
  int     r = 0;
116
  ssize_t   len;
117
118
  /* push unencrypted buffered data back through SSL setup */
119
  len = pq_buffer_remaining_data();
120
  if (len > 0)
121
  {
122
    char     *buf = palloc(len);
123
124
    pq_startmsgread();
125
    if (pq_getbytes(buf, len) == EOF)
126
      return STATUS_ERROR;  /* shouldn't be possible */
127
    pq_endmsgread();
128
    port->raw_buf = buf;
129
    port->raw_buf_remaining = len;
130
    port->raw_buf_consumed = 0;
131
  }
132
  Assert(pq_buffer_remaining_data() == 0);
133
134
  INJECTION_POINT("backend-ssl-startup", NULL);
135
136
  r = be_tls_open_server(port);
137
138
  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
     */
144
    elog(LOG, "buffered unencrypted data remains after negotiating SSL connection");
145
    return STATUS_ERROR;
146
  }
147
  if (port->raw_buf != NULL)
148
  {
149
    pfree(port->raw_buf);
150
    port->raw_buf = NULL;
151
  }
152
153
  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)")));
157
  return r;
158
#else
159
0
  return 0;
160
0
#endif
161
0
}
162
163
/*
164
 *  Close secure session.
165
 */
166
void
167
secure_close(Port *port)
168
0
{
169
#ifdef USE_SSL
170
  if (port->ssl_in_use)
171
    be_tls_close(port);
172
#endif
173
0
}
174
175
/*
176
 *  Read data from a secure connection.
177
 */
178
ssize_t
179
secure_read(Port *port, void *ptr, size_t len)
180
0
{
181
0
  ssize_t   n;
182
0
  int     waitfor;
183
184
  /* Deal with any already-pending interrupt condition. */
185
0
  ProcessClientReadInterrupt(false);
186
187
0
retry:
188
#ifdef USE_SSL
189
  waitfor = 0;
190
  if (port->ssl_in_use)
191
  {
192
    n = be_tls_read(port, ptr, len, &waitfor);
193
  }
194
  else
195
#endif
196
#ifdef ENABLE_GSS
197
  if (port->gss && port->gss->enc)
198
  {
199
    n = be_gssapi_read(port, ptr, len);
200
    waitfor = WL_SOCKET_READABLE;
201
  }
202
  else
203
#endif
204
0
  {
205
0
    n = secure_raw_read(port, ptr, len);
206
0
    waitfor = WL_SOCKET_READABLE;
207
0
  }
208
209
  /* In blocking mode, wait until the socket is ready */
210
0
  if (n < 0 && !port->noblock && (errno == EWOULDBLOCK || errno == EAGAIN))
211
0
  {
212
0
    WaitEvent event;
213
214
0
    Assert(waitfor);
215
216
0
    ModifyWaitEvent(FeBeWaitSet, FeBeWaitSetSocketPos, waitfor, NULL);
217
218
0
    WaitEventSetWait(FeBeWaitSet, -1 /* no timeout */ , &event, 1,
219
0
             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
     */
238
0
    if (event.events & WL_POSTMASTER_DEATH)
239
0
      ereport(FATAL,
240
0
          (errcode(ERRCODE_ADMIN_SHUTDOWN),
241
0
           errmsg("terminating connection due to unexpected postmaster exit")));
242
243
    /* Handle interrupt. */
244
0
    if (event.events & WL_LATCH_SET)
245
0
    {
246
0
      ResetLatch(MyLatch);
247
0
      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
0
    }
255
0
    goto retry;
256
0
  }
257
258
  /*
259
   * Process interrupts that happened during a successful (or non-blocking,
260
   * or hard-failed) read.
261
   */
262
0
  ProcessClientReadInterrupt(false);
263
264
0
  return n;
265
0
}
266
267
ssize_t
268
secure_raw_read(Port *port, void *ptr, size_t len)
269
0
{
270
0
  ssize_t   n;
271
272
  /* Read from the "unread" buffered data first. c.f. libpq-be.h */
273
0
  if (port->raw_buf_remaining > 0)
274
0
  {
275
    /* consume up to len bytes from the raw_buf */
276
0
    if (len > port->raw_buf_remaining)
277
0
      len = port->raw_buf_remaining;
278
0
    Assert(port->raw_buf);
279
0
    memcpy(ptr, port->raw_buf + port->raw_buf_consumed, len);
280
0
    port->raw_buf_consumed += len;
281
0
    port->raw_buf_remaining -= len;
282
0
    return len;
283
0
  }
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
292
0
  n = recv(port->sock, ptr, len, 0);
293
#ifdef WIN32
294
  pgwin32_noblock = false;
295
#endif
296
297
0
  return n;
298
0
}
299
300
301
/*
302
 *  Write data to a secure connection.
303
 */
304
ssize_t
305
secure_write(Port *port, const void *ptr, size_t len)
306
0
{
307
0
  ssize_t   n;
308
0
  int     waitfor;
309
310
  /* Deal with any already-pending interrupt condition. */
311
0
  ProcessClientWriteInterrupt(false);
312
313
0
retry:
314
0
  waitfor = 0;
315
#ifdef USE_SSL
316
  if (port->ssl_in_use)
317
  {
318
    n = be_tls_write(port, ptr, len, &waitfor);
319
  }
320
  else
321
#endif
322
#ifdef ENABLE_GSS
323
  if (port->gss && port->gss->enc)
324
  {
325
    n = be_gssapi_write(port, ptr, len);
326
    waitfor = WL_SOCKET_WRITEABLE;
327
  }
328
  else
329
#endif
330
0
  {
331
0
    n = secure_raw_write(port, ptr, len);
332
0
    waitfor = WL_SOCKET_WRITEABLE;
333
0
  }
334
335
0
  if (n < 0 && !port->noblock && (errno == EWOULDBLOCK || errno == EAGAIN))
336
0
  {
337
0
    WaitEvent event;
338
339
0
    Assert(waitfor);
340
341
0
    ModifyWaitEvent(FeBeWaitSet, FeBeWaitSetSocketPos, waitfor, NULL);
342
343
0
    WaitEventSetWait(FeBeWaitSet, -1 /* no timeout */ , &event, 1,
344
0
             WAIT_EVENT_CLIENT_WRITE);
345
346
    /* See comments in secure_read. */
347
0
    if (event.events & WL_POSTMASTER_DEATH)
348
0
      ereport(FATAL,
349
0
          (errcode(ERRCODE_ADMIN_SHUTDOWN),
350
0
           errmsg("terminating connection due to unexpected postmaster exit")));
351
352
    /* Handle interrupt. */
353
0
    if (event.events & WL_LATCH_SET)
354
0
    {
355
0
      ResetLatch(MyLatch);
356
0
      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
0
    }
364
0
    goto retry;
365
0
  }
366
367
  /*
368
   * Process interrupts that happened during a successful (or non-blocking,
369
   * or hard-failed) write.
370
   */
371
0
  ProcessClientWriteInterrupt(false);
372
373
0
  return n;
374
0
}
375
376
ssize_t
377
secure_raw_write(Port *port, const void *ptr, size_t len)
378
0
{
379
0
  ssize_t   n;
380
381
#ifdef WIN32
382
  pgwin32_noblock = true;
383
#endif
384
0
  n = send(port->sock, ptr, len, 0);
385
#ifdef WIN32
386
  pgwin32_noblock = false;
387
#endif
388
389
0
  return n;
390
0
}