PostgreSQL Source Code git master
Loading...
Searching...
No Matches
be-secure-gssapi.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * be-secure-gssapi.c
4 * GSSAPI encryption support
5 *
6 * Portions Copyright (c) 2018-2026, PostgreSQL Global Development Group
7 *
8 * IDENTIFICATION
9 * src/backend/libpq/be-secure-gssapi.c
10 *
11 *-------------------------------------------------------------------------
12 */
13
14#include "postgres.h"
15
16#include <unistd.h>
17
18#include "libpq/auth.h"
20#include "libpq/libpq.h"
21#include "miscadmin.h"
22#include "pgstat.h"
23#include "port/pg_bswap.h"
24#include "storage/latch.h"
26#include "utils/memutils.h"
27#include "utils/wait_event.h"
28
29
30/*
31 * Handle the encryption/decryption of data using GSSAPI.
32 *
33 * In the encrypted data stream on the wire, we break up the data
34 * into packets where each packet starts with a uint32-size length
35 * word (in network byte order), then encrypted data of that length
36 * immediately following. Decryption yields the same data stream
37 * that would appear when not using encryption.
38 *
39 * Encrypted data typically ends up being larger than the same data
40 * unencrypted, so we use fixed-size buffers for handling the
41 * encryption/decryption which are larger than PQComm's buffer will
42 * typically be to minimize the times where we have to make multiple
43 * packets (and therefore multiple recv/send calls for a single
44 * read/write call to us).
45 *
46 * NOTE: The client and server have to agree on the max packet size,
47 * because we have to pass an entire packet to GSSAPI at a time and we
48 * don't want the other side to send arbitrarily huge packets as we
49 * would have to allocate memory for them to then pass them to GSSAPI.
50 *
51 * Therefore, this #define is effectively part of the protocol
52 * spec and can't ever be changed.
53 */
54#define PQ_GSS_MAX_PACKET_SIZE 16384 /* includes uint32 header word */
55
56/*
57 * However, during the authentication exchange we must cope with whatever
58 * message size the GSSAPI library wants to send (because our protocol
59 * doesn't support splitting those messages). Depending on configuration
60 * those messages might be as much as 64kB.
61 */
62#define PQ_GSS_AUTH_BUFFER_SIZE 65536 /* includes uint32 header word */
63
64/*
65 * Since we manage at most one GSS-encrypted connection per backend,
66 * we can just keep all this state in static variables. The char *
67 * variables point to buffers that are allocated once and re-used.
68 */
69static char *PqGSSSendBuffer; /* Encrypted data waiting to be sent */
70static int PqGSSSendLength; /* End of data available in PqGSSSendBuffer */
71static int PqGSSSendNext; /* Next index to send a byte from
72 * PqGSSSendBuffer */
73static int PqGSSSendConsumed; /* Number of source bytes encrypted but not
74 * yet reported as sent */
75
76static char *PqGSSRecvBuffer; /* Received, encrypted data */
77static int PqGSSRecvLength; /* End of data available in PqGSSRecvBuffer */
78
79static char *PqGSSResultBuffer; /* Decryption of data in gss_RecvBuffer */
80static int PqGSSResultLength; /* End of data available in PqGSSResultBuffer */
81static int PqGSSResultNext; /* Next index to read a byte from
82 * PqGSSResultBuffer */
83
84static uint32 PqGSSMaxPktSize; /* Maximum size we can encrypt and fit the
85 * results into our output buffer */
86
87
88/*
89 * Attempt to write len bytes of data from ptr to a GSSAPI-encrypted connection.
90 *
91 * The connection must be already set up for GSSAPI encryption (i.e., GSSAPI
92 * transport negotiation is complete).
93 *
94 * On success, returns the number of data bytes consumed (possibly less than
95 * len). On failure, returns -1 with errno set appropriately. For retryable
96 * errors, caller should call again (passing the same or more data) once the
97 * socket is ready.
98 *
99 * Dealing with fatal errors here is a bit tricky: we can't invoke elog(FATAL)
100 * since it would try to write to the client, probably resulting in infinite
101 * recursion. Instead, use elog(COMMERROR) to log extra info about the
102 * failure if necessary, and then return an errno indicating connection loss.
103 */
105be_gssapi_write(Port *port, const void *ptr, size_t len)
106{
108 minor;
110 output;
111 size_t bytes_to_encrypt;
112 size_t bytes_encrypted;
113 gss_ctx_id_t gctx = port->gss->ctx;
114
115 /*
116 * When we get a retryable failure, we must not tell the caller we have
117 * successfully transmitted everything, else it won't retry. For
118 * simplicity, we claim we haven't transmitted anything until we have
119 * successfully transmitted all "len" bytes. Between calls, the amount of
120 * the current input data that's already been encrypted and placed into
121 * PqGSSSendBuffer (and perhaps transmitted) is remembered in
122 * PqGSSSendConsumed. On a retry, the caller *must* be sending that data
123 * again, so if it offers a len less than that, something is wrong.
124 *
125 * Note: it may seem attractive to report partial write completion once
126 * we've successfully sent any encrypted packets. However, doing that
127 * expands the state space of this processing and has been responsible for
128 * bugs in the past (cf. commit d053a879b). We won't save much,
129 * typically, by letting callers discard data early, so don't risk it.
130 */
132 {
133 elog(COMMERROR, "GSSAPI caller failed to retransmit all data needing to be retried");
135 return -1;
136 }
137
138 /* Discount whatever source data we already encrypted. */
141
142 /*
143 * Loop through encrypting data and sending it out until it's all done or
144 * secure_raw_write() complains (which would likely mean that the socket
145 * is non-blocking and the requested send() would block, or there was some
146 * kind of actual error).
147 */
149 {
150 int conf_state = 0;
152
153 /*
154 * Check if we have data in the encrypted output buffer that needs to
155 * be sent (possibly left over from a previous call), and if so, try
156 * to send it. If we aren't able to, return that fact back up to the
157 * caller.
158 */
159 if (PqGSSSendLength)
160 {
161 ssize_t ret;
163
165 if (ret <= 0)
166 return ret;
167
168 /*
169 * Check if this was a partial write, and if so, move forward that
170 * far in our buffer and try again.
171 */
172 if (ret < amount)
173 {
174 PqGSSSendNext += ret;
175 continue;
176 }
177
178 /* We've successfully sent whatever data was in the buffer. */
180 }
181
182 /*
183 * Check if there are any bytes left to encrypt. If not, we're done.
184 */
185 if (!bytes_to_encrypt)
186 break;
187
188 /*
189 * Check how much we are being asked to send, if it's too much, then
190 * we will have to loop and possibly be called multiple times to get
191 * through all the data.
192 */
194 input.length = PqGSSMaxPktSize;
195 else
196 input.length = bytes_to_encrypt;
197
198 input.value = (char *) ptr + bytes_encrypted;
199
200 output.value = NULL;
201 output.length = 0;
202
203 /*
204 * Create the next encrypted packet. Any failure here is considered a
205 * hard failure, so we return -1 even if some data has been sent.
206 */
208 &input, &conf_state, &output);
209 if (major != GSS_S_COMPLETE)
210 {
211 pg_GSS_error(_("GSSAPI wrap error"), major, minor);
213 return -1;
214 }
215 if (conf_state == 0)
216 {
218 (errmsg("outgoing GSSAPI message would not use confidentiality")));
220 return -1;
221 }
222 if (output.length > PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32))
223 {
225 (errmsg("server tried to send oversize GSSAPI packet (%zu > %zu)",
226 (size_t) output.length,
227 PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32))));
229 return -1;
230 }
231
232 bytes_encrypted += input.length;
233 bytes_to_encrypt -= input.length;
234 PqGSSSendConsumed += input.length;
235
236 /* 4 network-order bytes of length, then payload */
237 netlen = pg_hton32(output.length);
239 PqGSSSendLength += sizeof(uint32);
240
242 PqGSSSendLength += output.length;
243
244 /* Release buffer storage allocated by GSSAPI */
246 }
247
248 /* If we get here, our counters should all match up. */
251
252 /* We're reporting all the data as sent, so reset PqGSSSendConsumed. */
254
255 return bytes_encrypted;
256}
257
258/*
259 * Read up to len bytes of data into ptr from a GSSAPI-encrypted connection.
260 *
261 * The connection must be already set up for GSSAPI encryption (i.e., GSSAPI
262 * transport negotiation is complete).
263 *
264 * Returns the number of data bytes read, or on failure, returns -1
265 * with errno set appropriately. For retryable errors, caller should call
266 * again once the socket is ready.
267 *
268 * We treat fatal errors the same as in be_gssapi_write(), even though the
269 * argument about infinite recursion doesn't apply here.
270 */
272be_gssapi_read(Port *port, void *ptr, size_t len)
273{
275 minor;
277 output;
278 ssize_t ret;
279 size_t bytes_returned = 0;
280 gss_ctx_id_t gctx = port->gss->ctx;
281
282 /*
283 * The plan here is to read one incoming encrypted packet into
284 * PqGSSRecvBuffer, decrypt it into PqGSSResultBuffer, and then dole out
285 * data from there to the caller. When we exhaust the current input
286 * packet, read another.
287 */
288 while (bytes_returned < len)
289 {
290 int conf_state = 0;
291
292 /* Check if we have data in our buffer that we can return immediately */
294 {
297
298 /*
299 * Copy the data from our result buffer into the caller's buffer,
300 * at the point where we last left off filling their buffer.
301 */
305
306 /*
307 * At this point, we've either filled the caller's buffer or
308 * emptied our result buffer. Either way, return to caller. In
309 * the second case, we could try to read another encrypted packet,
310 * but the odds are good that there isn't one available. (If this
311 * isn't true, we chose too small a max packet size.) In any
312 * case, there's no harm letting the caller process the data we've
313 * already returned.
314 */
315 break;
316 }
317
318 /* Result buffer is empty, so reset buffer pointers */
320
321 /*
322 * Because we chose above to return immediately as soon as we emit
323 * some data, bytes_returned must be zero at this point. Therefore
324 * the failure exits below can just return -1 without worrying about
325 * whether we already emitted some data.
326 */
328
329 /*
330 * At this point, our result buffer is empty with more bytes being
331 * requested to be read. We are now ready to load the next packet and
332 * decrypt it (entirely) into our result buffer.
333 */
334
335 /* Collect the length if we haven't already */
336 if (PqGSSRecvLength < sizeof(uint32))
337 {
339 sizeof(uint32) - PqGSSRecvLength);
340
341 /* If ret <= 0, secure_raw_read already set the correct errno */
342 if (ret <= 0)
343 return ret;
344
345 PqGSSRecvLength += ret;
346
347 /* If we still haven't got the length, return to the caller */
348 if (PqGSSRecvLength < sizeof(uint32))
349 {
351 return -1;
352 }
353 }
354
355 /* Decode the packet length and check for overlength packet */
356 input.length = pg_ntoh32(*(uint32 *) PqGSSRecvBuffer);
357
358 if (input.length > PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32))
359 {
361 (errmsg("oversize GSSAPI packet sent by the client (%zu > %zu)",
362 (size_t) input.length,
363 PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32))));
365 return -1;
366 }
367
368 /*
369 * Read as much of the packet as we are able to on this call into
370 * wherever we left off from the last time we were called.
371 */
373 input.length - (PqGSSRecvLength - sizeof(uint32)));
374 /* If ret <= 0, secure_raw_read already set the correct errno */
375 if (ret <= 0)
376 return ret;
377
378 PqGSSRecvLength += ret;
379
380 /* If we don't yet have the whole packet, return to the caller */
381 if (PqGSSRecvLength - sizeof(uint32) < input.length)
382 {
384 return -1;
385 }
386
387 /*
388 * We now have the full packet and we can perform the decryption and
389 * refill our result buffer, then loop back up to pass data back to
390 * the caller.
391 */
392 output.value = NULL;
393 output.length = 0;
394 input.value = PqGSSRecvBuffer + sizeof(uint32);
395
397 if (major != GSS_S_COMPLETE)
398 {
399 pg_GSS_error(_("GSSAPI unwrap error"), major, minor);
401 return -1;
402 }
403 if (conf_state == 0)
404 {
406 (errmsg("incoming GSSAPI message did not use confidentiality")));
408 return -1;
409 }
410
411 memcpy(PqGSSResultBuffer, output.value, output.length);
412 PqGSSResultLength = output.length;
413
414 /* Our receive buffer is now empty, reset it */
415 PqGSSRecvLength = 0;
416
417 /* Release buffer storage allocated by GSSAPI */
419 }
420
421 return bytes_returned;
422}
423
424/*
425 * Read the specified number of bytes off the wire, waiting using
426 * WaitLatchOrSocket if we would block.
427 *
428 * Results are read into PqGSSRecvBuffer.
429 *
430 * Will always return either -1, to indicate a permanent error, or len.
431 */
432static ssize_t
434{
435 ssize_t ret;
436
437 /*
438 * Keep going until we either read in everything we were asked to, or we
439 * error out.
440 */
441 while (PqGSSRecvLength < len)
442 {
444
445 /*
446 * If we got back an error and it wasn't just
447 * EWOULDBLOCK/EAGAIN/EINTR, then give up.
448 */
449 if (ret < 0 &&
450 !(errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR))
451 return -1;
452
453 /*
454 * Ok, we got back either a positive value, zero, or a negative result
455 * indicating we should retry.
456 *
457 * If it was zero or negative, then we wait on the socket to be
458 * readable again.
459 */
460 if (ret <= 0)
461 {
465
466 /*
467 * If we got back zero bytes, and then waited on the socket to be
468 * readable and got back zero bytes on a second read, then this is
469 * EOF and the client hung up on us.
470 *
471 * If we did get data here, then we can just fall through and
472 * handle it just as if we got data the first time.
473 *
474 * Otherwise loop back to the top and try again.
475 */
476 if (ret == 0)
477 {
479 if (ret == 0)
480 return -1;
481 }
482 if (ret < 0)
483 continue;
484 }
485
486 PqGSSRecvLength += ret;
487 }
488
489 return len;
490}
491
492/*
493 * Start up a GSSAPI-encrypted connection. This performs GSSAPI
494 * authentication; after this function completes, it is safe to call
495 * be_gssapi_read and be_gssapi_write. Returns -1 and logs on failure;
496 * otherwise, returns 0 and marks the connection as ready for GSSAPI
497 * encryption.
498 *
499 * Note that unlike the be_gssapi_read/be_gssapi_write functions, this
500 * function WILL block on the socket to be ready for read/write (using
501 * WaitLatchOrSocket) as appropriate while establishing the GSSAPI
502 * session.
503 */
506{
507 bool complete_next = false;
509 minor;
511
512 INJECTION_POINT("backend-gssapi-startup", NULL);
513
514 /*
515 * Allocate subsidiary Port data for GSSAPI operations.
516 */
517 port->gss = (pg_gssinfo *)
519
521 port->gss->delegated_creds = false;
522
523 /*
524 * Allocate buffers and initialize state variables. By malloc'ing the
525 * buffers at this point, we avoid wasting static data space in processes
526 * that will never use them, and we ensure that the buffers are
527 * sufficiently aligned for the length-word accesses that we do in some
528 * places in this file.
529 *
530 * We'll use PQ_GSS_AUTH_BUFFER_SIZE-sized buffers until transport
531 * negotiation is complete, then switch to PQ_GSS_MAX_PACKET_SIZE.
532 */
539 errmsg("out of memory")));
542
543 /*
544 * Use the configured keytab, if there is one. As we now require MIT
545 * Kerberos, we might consider using the credential store extensions in
546 * the future instead of the environment variable.
547 */
549 {
550 if (setenv("KRB5_KTNAME", pg_krb_server_keyfile, 1) != 0)
551 {
552 /* The only likely failure cause is OOM, so use that errcode */
555 errmsg("could not set environment: %m")));
556 }
557 }
558
559 while (true)
560 {
561 ssize_t ret;
564
565 /*
566 * The client always sends first, so try to go ahead and read the
567 * length and wait on the socket to be readable again if that fails.
568 */
569 ret = read_or_wait(port, sizeof(uint32));
570 if (ret < 0)
571 return ret;
572
573 /*
574 * Get the length for this packet from the length header.
575 */
576 input.length = pg_ntoh32(*(uint32 *) PqGSSRecvBuffer);
577
578 /* Done with the length, reset our buffer */
579 PqGSSRecvLength = 0;
580
581 /*
582 * During initialization, packets are always fully consumed and
583 * shouldn't ever be over PQ_GSS_AUTH_BUFFER_SIZE in total length.
584 *
585 * Verify on our side that the client doesn't do something funny.
586 */
587 if (input.length > PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32))
588 {
590 (errmsg("oversize GSSAPI packet sent by the client (%zu > %zu)",
591 (size_t) input.length,
592 PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32))));
593 return -1;
594 }
595
596 /*
597 * Get the rest of the packet so we can pass it to GSSAPI to accept
598 * the context.
599 */
600 ret = read_or_wait(port, input.length);
601 if (ret < 0)
602 return ret;
603
604 input.value = PqGSSRecvBuffer;
605
606 /* Process incoming data. (The client sends first.) */
607 major = gss_accept_sec_context(&minor, &port->gss->ctx,
610 &port->gss->name, NULL, &output, NULL,
612
613 if (GSS_ERROR(major))
614 {
615 pg_GSS_error(_("could not accept GSSAPI security context"),
616 major, minor);
618 return -1;
619 }
620 else if (!(major & GSS_S_CONTINUE_NEEDED))
621 {
622 /*
623 * rfc2744 technically permits context negotiation to be complete
624 * both with and without a packet to be sent.
625 */
626 complete_next = true;
627 }
628
630 {
632 port->gss->delegated_creds = true;
633 }
634
635 /* Done handling the incoming packet, reset our buffer */
636 PqGSSRecvLength = 0;
637
638 /*
639 * Check if we have data to send and, if we do, make sure to send it
640 * all
641 */
642 if (output.length > 0)
643 {
644 uint32 netlen = pg_hton32(output.length);
645
646 if (output.length > PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32))
647 {
649 (errmsg("server tried to send oversize GSSAPI packet (%zu > %zu)",
650 (size_t) output.length,
651 PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32))));
653 return -1;
654 }
655
657 PqGSSSendLength += sizeof(uint32);
658
660 PqGSSSendLength += output.length;
661
662 /* we don't bother with PqGSSSendConsumed here */
663
665 {
668
669 /*
670 * If we got back an error and it wasn't just
671 * EWOULDBLOCK/EAGAIN/EINTR, then give up.
672 */
673 if (ret < 0 &&
674 !(errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR))
675 {
677 return -1;
678 }
679
680 /* Wait and retry if we couldn't write yet */
681 if (ret <= 0)
682 {
686 continue;
687 }
688
689 PqGSSSendNext += ret;
690 }
691
692 /* Done sending the packet, reset our buffer */
694
696 }
697
698 /*
699 * If we got back that the connection is finished being set up, now
700 * that we've sent the last packet, exit our loop.
701 */
702 if (complete_next)
703 break;
704 }
705
706 /*
707 * Release the large authentication buffers and allocate the ones we want
708 * for normal operation.
709 */
719 errmsg("out of memory")));
722
723 /*
724 * Determine the max packet size which will fit in our buffer, after
725 * accounting for the length. be_gssapi_write will need this.
726 */
730
731 if (GSS_ERROR(major))
732 {
733 pg_GSS_error(_("GSSAPI size check error"), major, minor);
734 return -1;
735 }
736
737 port->gss->enc = true;
738
739 return 0;
740}
741
742/*
743 * Return if GSSAPI authentication was used on this connection.
744 */
745bool
747{
748 if (!port || !port->gss)
749 return false;
750
751 return port->gss->auth;
752}
753
754/*
755 * Return if GSSAPI encryption is enabled and being used on this connection.
756 */
757bool
759{
760 if (!port || !port->gss)
761 return false;
762
763 return port->gss->enc;
764}
765
766/*
767 * Return the GSSAPI principal used for authentication on this connection
768 * (NULL if we did not perform GSSAPI authentication).
769 */
770const char *
772{
773 if (!port || !port->gss)
774 return NULL;
775
776 return port->gss->princ;
777}
778
779/*
780 * Return if GSSAPI delegated credentials were included on this
781 * connection.
782 */
783bool
785{
786 if (!port || !port->gss)
787 return false;
788
789 return port->gss->delegated_creds;
790}
char * pg_krb_server_keyfile
Definition auth.c:173
bool pg_gss_accept_delegation
Definition auth.c:175
void pg_store_delegated_credential(gss_cred_id_t cred)
void pg_GSS_error(const char *errmsg, OM_uint32 maj_stat, OM_uint32 min_stat)
static int PqGSSRecvLength
static int PqGSSResultLength
#define PQ_GSS_AUTH_BUFFER_SIZE
static char * PqGSSSendBuffer
ssize_t be_gssapi_write(Port *port, const void *ptr, size_t len)
bool be_gssapi_get_auth(Port *port)
static int PqGSSSendConsumed
ssize_t be_gssapi_read(Port *port, void *ptr, size_t len)
static ssize_t read_or_wait(Port *port, ssize_t len)
ssize_t secure_open_gssapi(Port *port)
static char * PqGSSRecvBuffer
static int PqGSSResultNext
static uint32 PqGSSMaxPktSize
bool be_gssapi_get_enc(Port *port)
static int PqGSSSendLength
static int PqGSSSendNext
static char * PqGSSResultBuffer
#define PQ_GSS_MAX_PACKET_SIZE
const char * be_gssapi_get_princ(Port *port)
bool be_gssapi_get_delegation(Port *port)
ssize_t secure_raw_read(Port *port, void *ptr, size_t len)
Definition be-secure.c:272
ssize_t secure_raw_write(Port *port, const void *ptr, size_t len)
Definition be-secure.c:381
#define Min(x, y)
Definition c.h:1093
#define Assert(condition)
Definition c.h:945
uint32_t uint32
Definition c.h:618
int errcode(int sqlerrcode)
Definition elog.c:874
#define _(x)
Definition elog.c:95
#define COMMERROR
Definition elog.h:33
#define FATAL
Definition elog.h:41
#define elog(elevel,...)
Definition elog.h:226
#define ereport(elevel,...)
Definition elog.h:150
FILE * input
FILE * output
#define INJECTION_POINT(name, arg)
int WaitLatchOrSocket(Latch *latch, int wakeEvents, pgsocket sock, long timeout, uint32 wait_event_info)
Definition latch.c:223
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition mcxt.c:1266
MemoryContext TopMemoryContext
Definition mcxt.c:166
static char * errmsg
#define pg_ntoh32(x)
Definition pg_bswap.h:125
#define pg_hton32(x)
Definition pg_bswap.h:121
const void size_t len
static int port
Definition pg_regress.c:115
static int fb(int x)
#define free(a)
#define malloc(a)
#define WL_SOCKET_READABLE
#define WL_EXIT_ON_PM_DEATH
#define WL_SOCKET_WRITEABLE
#define EINTR
Definition win32_port.h:361
#define EWOULDBLOCK
Definition win32_port.h:367
#define setenv(x, y, z)
Definition win32_port.h:542
#define ECONNRESET
Definition win32_port.h:371
#define EAGAIN
Definition win32_port.h:359