1 /*-------------------------------------------------------------------------
2 *
3 * be-secure-gssapi.c
4 * GSSAPI encryption support
5 *
6 * Portions Copyright (c) 2018-2020, 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"
19 #include "libpq/be-gssapi-common.h"
20 #include "libpq/libpq.h"
21 #include "libpq/pqformat.h"
22 #include "miscadmin.h"
23 #include "pgstat.h"
24 #include "utils/memutils.h"
25
26
27 /*
28 * Handle the encryption/decryption of data using GSSAPI.
29 *
30 * In the encrypted data stream on the wire, we break up the data
31 * into packets where each packet starts with a uint32-size length
32 * word (in network byte order), then encrypted data of that length
33 * immediately following. Decryption yields the same data stream
34 * that would appear when not using encryption.
35 *
36 * Encrypted data typically ends up being larger than the same data
37 * unencrypted, so we use fixed-size buffers for handling the
38 * encryption/decryption which are larger than PQComm's buffer will
39 * typically be to minimize the times where we have to make multiple
40 * packets (and therefore multiple recv/send calls for a single
41 * read/write call to us).
42 *
43 * NOTE: The client and server have to agree on the max packet size,
44 * because we have to pass an entire packet to GSSAPI at a time and we
45 * don't want the other side to send arbitrarily huge packets as we
46 * would have to allocate memory for them to then pass them to GSSAPI.
47 *
48 * Therefore, these two #define's are effectively part of the protocol
49 * spec and can't ever be changed.
50 */
51 #define PQ_GSS_SEND_BUFFER_SIZE 16384
52 #define PQ_GSS_RECV_BUFFER_SIZE 16384
53
54 /*
55 * Since we manage at most one GSS-encrypted connection per backend,
56 * we can just keep all this state in static variables. The char *
57 * variables point to buffers that are allocated once and re-used.
58 */
59 static char *PqGSSSendBuffer; /* Encrypted data waiting to be sent */
60 static int PqGSSSendLength; /* End of data available in PqGSSSendBuffer */
61 static int PqGSSSendNext; /* Next index to send a byte from
62 * PqGSSSendBuffer */
63 static int PqGSSSendConsumed; /* Number of *unencrypted* bytes consumed for
64 * current contents of PqGSSSendBuffer */
65
66 static char *PqGSSRecvBuffer; /* Received, encrypted data */
67 static int PqGSSRecvLength; /* End of data available in PqGSSRecvBuffer */
68
69 static char *PqGSSResultBuffer; /* Decryption of data in gss_RecvBuffer */
70 static int PqGSSResultLength; /* End of data available in PqGSSResultBuffer */
71 static int PqGSSResultNext; /* Next index to read a byte from
72 * PqGSSResultBuffer */
73
74 static uint32 PqGSSMaxPktSize; /* Maximum size we can encrypt and fit the
75 * results into our output buffer */
76
77
78 /*
79 * Attempt to write len bytes of data from ptr to a GSSAPI-encrypted connection.
80 *
81 * The connection must be already set up for GSSAPI encryption (i.e., GSSAPI
82 * transport negotiation is complete).
83 *
84 * On success, returns the number of data bytes consumed (possibly less than
85 * len). On failure, returns -1 with errno set appropriately. For retryable
86 * errors, caller should call again (passing the same data) once the socket
87 * is ready.
88 *
89 * Dealing with fatal errors here is a bit tricky: we can't invoke elog(FATAL)
90 * since it would try to write to the client, probably resulting in infinite
91 * recursion. Instead, use elog(COMMERROR) to log extra info about the
92 * failure if necessary, and then return an errno indicating connection loss.
93 */
94 ssize_t
be_gssapi_write(Port * port,void * ptr,size_t len)95 be_gssapi_write(Port *port, void *ptr, size_t len)
96 {
97 OM_uint32 major,
98 minor;
99 gss_buffer_desc input,
100 output;
101 size_t bytes_sent = 0;
102 size_t bytes_to_encrypt;
103 size_t bytes_encrypted;
104 gss_ctx_id_t gctx = port->gss->ctx;
105
106 /*
107 * When we get a failure, we must not tell the caller we have successfully
108 * transmitted everything, else it won't retry. Hence a "success"
109 * (positive) return value must only count source bytes corresponding to
110 * fully-transmitted encrypted packets. The amount of source data
111 * corresponding to the current partly-transmitted packet is remembered in
112 * PqGSSSendConsumed. On a retry, the caller *must* be sending that data
113 * again, so if it offers a len less than that, something is wrong.
114 */
115 if (len < PqGSSSendConsumed)
116 {
117 elog(COMMERROR, "GSSAPI caller failed to retransmit all data needing to be retried");
118 errno = ECONNRESET;
119 return -1;
120 }
121 /* Discount whatever source data we already encrypted. */
122 bytes_to_encrypt = len - PqGSSSendConsumed;
123 bytes_encrypted = PqGSSSendConsumed;
124
125 /*
126 * Loop through encrypting data and sending it out until it's all done or
127 * secure_raw_write() complains (which would likely mean that the socket
128 * is non-blocking and the requested send() would block, or there was some
129 * kind of actual error).
130 */
131 while (bytes_to_encrypt || PqGSSSendLength)
132 {
133 int conf_state = 0;
134 uint32 netlen;
135
136 /*
137 * Check if we have data in the encrypted output buffer that needs to
138 * be sent (possibly left over from a previous call), and if so, try
139 * to send it. If we aren't able to, return that fact back up to the
140 * caller.
141 */
142 if (PqGSSSendLength)
143 {
144 ssize_t ret;
145 ssize_t amount = PqGSSSendLength - PqGSSSendNext;
146
147 ret = secure_raw_write(port, PqGSSSendBuffer + PqGSSSendNext, amount);
148 if (ret <= 0)
149 {
150 /*
151 * Report any previously-sent data; if there was none, reflect
152 * the secure_raw_write result up to our caller. When there
153 * was some, we're effectively assuming that any interesting
154 * failure condition will recur on the next try.
155 */
156 if (bytes_sent)
157 return bytes_sent;
158 return ret;
159 }
160
161 /*
162 * Check if this was a partial write, and if so, move forward that
163 * far in our buffer and try again.
164 */
165 if (ret != amount)
166 {
167 PqGSSSendNext += ret;
168 continue;
169 }
170
171 /* We've successfully sent whatever data was in that packet. */
172 bytes_sent += PqGSSSendConsumed;
173
174 /* All encrypted data was sent, our buffer is empty now. */
175 PqGSSSendLength = PqGSSSendNext = PqGSSSendConsumed = 0;
176 }
177
178 /*
179 * Check if there are any bytes left to encrypt. If not, we're done.
180 */
181 if (!bytes_to_encrypt)
182 break;
183
184 /*
185 * Check how much we are being asked to send, if it's too much, then
186 * we will have to loop and possibly be called multiple times to get
187 * through all the data.
188 */
189 if (bytes_to_encrypt > PqGSSMaxPktSize)
190 input.length = PqGSSMaxPktSize;
191 else
192 input.length = bytes_to_encrypt;
193
194 input.value = (char *) ptr + bytes_encrypted;
195
196 output.value = NULL;
197 output.length = 0;
198
199 /* Create the next encrypted packet */
200 major = gss_wrap(&minor, gctx, 1, GSS_C_QOP_DEFAULT,
201 &input, &conf_state, &output);
202 if (major != GSS_S_COMPLETE)
203 {
204 pg_GSS_error(_("GSSAPI wrap error"), major, minor);
205 errno = ECONNRESET;
206 return -1;
207 }
208 if (conf_state == 0)
209 {
210 ereport(COMMERROR,
211 (errmsg("outgoing GSSAPI message would not use confidentiality")));
212 errno = ECONNRESET;
213 return -1;
214 }
215 if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32))
216 {
217 ereport(COMMERROR,
218 (errmsg("server tried to send oversize GSSAPI packet (%zu > %zu)",
219 (size_t) output.length,
220 PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32))));
221 errno = ECONNRESET;
222 return -1;
223 }
224
225 bytes_encrypted += input.length;
226 bytes_to_encrypt -= input.length;
227 PqGSSSendConsumed += input.length;
228
229 /* 4 network-order bytes of length, then payload */
230 netlen = htonl(output.length);
231 memcpy(PqGSSSendBuffer + PqGSSSendLength, &netlen, sizeof(uint32));
232 PqGSSSendLength += sizeof(uint32);
233
234 memcpy(PqGSSSendBuffer + PqGSSSendLength, output.value, output.length);
235 PqGSSSendLength += output.length;
236
237 /* Release buffer storage allocated by GSSAPI */
238 gss_release_buffer(&minor, &output);
239 }
240
241 /* If we get here, our counters should all match up. */
242 Assert(bytes_sent == len);
243 Assert(bytes_sent == bytes_encrypted);
244
245 return bytes_sent;
246 }
247
248 /*
249 * Read up to len bytes of data into ptr from a GSSAPI-encrypted connection.
250 *
251 * The connection must be already set up for GSSAPI encryption (i.e., GSSAPI
252 * transport negotiation is complete).
253 *
254 * Returns the number of data bytes read, or on failure, returns -1
255 * with errno set appropriately. For retryable errors, caller should call
256 * again once the socket is ready.
257 *
258 * We treat fatal errors the same as in be_gssapi_write(), even though the
259 * argument about infinite recursion doesn't apply here.
260 */
261 ssize_t
be_gssapi_read(Port * port,void * ptr,size_t len)262 be_gssapi_read(Port *port, void *ptr, size_t len)
263 {
264 OM_uint32 major,
265 minor;
266 gss_buffer_desc input,
267 output;
268 ssize_t ret;
269 size_t bytes_returned = 0;
270 gss_ctx_id_t gctx = port->gss->ctx;
271
272 /*
273 * The plan here is to read one incoming encrypted packet into
274 * PqGSSRecvBuffer, decrypt it into PqGSSResultBuffer, and then dole out
275 * data from there to the caller. When we exhaust the current input
276 * packet, read another.
277 */
278 while (bytes_returned < len)
279 {
280 int conf_state = 0;
281
282 /* Check if we have data in our buffer that we can return immediately */
283 if (PqGSSResultNext < PqGSSResultLength)
284 {
285 size_t bytes_in_buffer = PqGSSResultLength - PqGSSResultNext;
286 size_t bytes_to_copy = Min(bytes_in_buffer, len - bytes_returned);
287
288 /*
289 * Copy the data from our result buffer into the caller's buffer,
290 * at the point where we last left off filling their buffer.
291 */
292 memcpy((char *) ptr + bytes_returned, PqGSSResultBuffer + PqGSSResultNext, bytes_to_copy);
293 PqGSSResultNext += bytes_to_copy;
294 bytes_returned += bytes_to_copy;
295
296 /*
297 * At this point, we've either filled the caller's buffer or
298 * emptied our result buffer. Either way, return to caller. In
299 * the second case, we could try to read another encrypted packet,
300 * but the odds are good that there isn't one available. (If this
301 * isn't true, we chose too small a max packet size.) In any
302 * case, there's no harm letting the caller process the data we've
303 * already returned.
304 */
305 break;
306 }
307
308 /* Result buffer is empty, so reset buffer pointers */
309 PqGSSResultLength = PqGSSResultNext = 0;
310
311 /*
312 * Because we chose above to return immediately as soon as we emit
313 * some data, bytes_returned must be zero at this point. Therefore
314 * the failure exits below can just return -1 without worrying about
315 * whether we already emitted some data.
316 */
317 Assert(bytes_returned == 0);
318
319 /*
320 * At this point, our result buffer is empty with more bytes being
321 * requested to be read. We are now ready to load the next packet and
322 * decrypt it (entirely) into our result buffer.
323 */
324
325 /* Collect the length if we haven't already */
326 if (PqGSSRecvLength < sizeof(uint32))
327 {
328 ret = secure_raw_read(port, PqGSSRecvBuffer + PqGSSRecvLength,
329 sizeof(uint32) - PqGSSRecvLength);
330
331 /* If ret <= 0, secure_raw_read already set the correct errno */
332 if (ret <= 0)
333 return ret;
334
335 PqGSSRecvLength += ret;
336
337 /* If we still haven't got the length, return to the caller */
338 if (PqGSSRecvLength < sizeof(uint32))
339 {
340 errno = EWOULDBLOCK;
341 return -1;
342 }
343 }
344
345 /* Decode the packet length and check for overlength packet */
346 input.length = ntohl(*(uint32 *) PqGSSRecvBuffer);
347
348 if (input.length > PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32))
349 {
350 ereport(COMMERROR,
351 (errmsg("oversize GSSAPI packet sent by the client (%zu > %zu)",
352 (size_t) input.length,
353 PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32))));
354 errno = ECONNRESET;
355 return -1;
356 }
357
358 /*
359 * Read as much of the packet as we are able to on this call into
360 * wherever we left off from the last time we were called.
361 */
362 ret = secure_raw_read(port, PqGSSRecvBuffer + PqGSSRecvLength,
363 input.length - (PqGSSRecvLength - sizeof(uint32)));
364 /* If ret <= 0, secure_raw_read already set the correct errno */
365 if (ret <= 0)
366 return ret;
367
368 PqGSSRecvLength += ret;
369
370 /* If we don't yet have the whole packet, return to the caller */
371 if (PqGSSRecvLength - sizeof(uint32) < input.length)
372 {
373 errno = EWOULDBLOCK;
374 return -1;
375 }
376
377 /*
378 * We now have the full packet and we can perform the decryption and
379 * refill our result buffer, then loop back up to pass data back to
380 * the caller.
381 */
382 output.value = NULL;
383 output.length = 0;
384 input.value = PqGSSRecvBuffer + sizeof(uint32);
385
386 major = gss_unwrap(&minor, gctx, &input, &output, &conf_state, NULL);
387 if (major != GSS_S_COMPLETE)
388 {
389 pg_GSS_error(_("GSSAPI unwrap error"), major, minor);
390 errno = ECONNRESET;
391 return -1;
392 }
393 if (conf_state == 0)
394 {
395 ereport(COMMERROR,
396 (errmsg("incoming GSSAPI message did not use confidentiality")));
397 errno = ECONNRESET;
398 return -1;
399 }
400
401 memcpy(PqGSSResultBuffer, output.value, output.length);
402 PqGSSResultLength = output.length;
403
404 /* Our receive buffer is now empty, reset it */
405 PqGSSRecvLength = 0;
406
407 /* Release buffer storage allocated by GSSAPI */
408 gss_release_buffer(&minor, &output);
409 }
410
411 return bytes_returned;
412 }
413
414 /*
415 * Read the specified number of bytes off the wire, waiting using
416 * WaitLatchOrSocket if we would block.
417 *
418 * Results are read into PqGSSRecvBuffer.
419 *
420 * Will always return either -1, to indicate a permanent error, or len.
421 */
422 static ssize_t
read_or_wait(Port * port,ssize_t len)423 read_or_wait(Port *port, ssize_t len)
424 {
425 ssize_t ret;
426
427 /*
428 * Keep going until we either read in everything we were asked to, or we
429 * error out.
430 */
431 while (PqGSSRecvLength < len)
432 {
433 ret = secure_raw_read(port, PqGSSRecvBuffer + PqGSSRecvLength, len - PqGSSRecvLength);
434
435 /*
436 * If we got back an error and it wasn't just
437 * EWOULDBLOCK/EAGAIN/EINTR, then give up.
438 */
439 if (ret < 0 &&
440 !(errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR))
441 return -1;
442
443 /*
444 * Ok, we got back either a positive value, zero, or a negative result
445 * indicating we should retry.
446 *
447 * If it was zero or negative, then we wait on the socket to be
448 * readable again.
449 */
450 if (ret <= 0)
451 {
452 WaitLatchOrSocket(MyLatch,
453 WL_SOCKET_READABLE | WL_EXIT_ON_PM_DEATH,
454 port->sock, 0, WAIT_EVENT_GSS_OPEN_SERVER);
455
456 /*
457 * If we got back zero bytes, and then waited on the socket to be
458 * readable and got back zero bytes on a second read, then this is
459 * EOF and the client hung up on us.
460 *
461 * If we did get data here, then we can just fall through and
462 * handle it just as if we got data the first time.
463 *
464 * Otherwise loop back to the top and try again.
465 */
466 if (ret == 0)
467 {
468 ret = secure_raw_read(port, PqGSSRecvBuffer + PqGSSRecvLength, len - PqGSSRecvLength);
469 if (ret == 0)
470 return -1;
471 }
472 if (ret < 0)
473 continue;
474 }
475
476 PqGSSRecvLength += ret;
477 }
478
479 return len;
480 }
481
482 /*
483 * Start up a GSSAPI-encrypted connection. This performs GSSAPI
484 * authentication; after this function completes, it is safe to call
485 * be_gssapi_read and be_gssapi_write. Returns -1 and logs on failure;
486 * otherwise, returns 0 and marks the connection as ready for GSSAPI
487 * encryption.
488 *
489 * Note that unlike the be_gssapi_read/be_gssapi_write functions, this
490 * function WILL block on the socket to be ready for read/write (using
491 * WaitLatchOrSocket) as appropriate while establishing the GSSAPI
492 * session.
493 */
494 ssize_t
secure_open_gssapi(Port * port)495 secure_open_gssapi(Port *port)
496 {
497 bool complete_next = false;
498 OM_uint32 major,
499 minor;
500
501 /*
502 * Allocate subsidiary Port data for GSSAPI operations.
503 */
504 port->gss = (pg_gssinfo *)
505 MemoryContextAllocZero(TopMemoryContext, sizeof(pg_gssinfo));
506
507 /*
508 * Allocate buffers and initialize state variables. By malloc'ing the
509 * buffers at this point, we avoid wasting static data space in processes
510 * that will never use them, and we ensure that the buffers are
511 * sufficiently aligned for the length-word accesses that we do in some
512 * places in this file.
513 */
514 PqGSSSendBuffer = malloc(PQ_GSS_SEND_BUFFER_SIZE);
515 PqGSSRecvBuffer = malloc(PQ_GSS_RECV_BUFFER_SIZE);
516 PqGSSResultBuffer = malloc(PQ_GSS_RECV_BUFFER_SIZE);
517 if (!PqGSSSendBuffer || !PqGSSRecvBuffer || !PqGSSResultBuffer)
518 ereport(FATAL,
519 (errcode(ERRCODE_OUT_OF_MEMORY),
520 errmsg("out of memory")));
521 PqGSSSendLength = PqGSSSendNext = PqGSSSendConsumed = 0;
522 PqGSSRecvLength = PqGSSResultLength = PqGSSResultNext = 0;
523
524 /*
525 * Use the configured keytab, if there is one. Unfortunately, Heimdal
526 * doesn't support the cred store extensions, so use the env var.
527 */
528 if (pg_krb_server_keyfile != NULL && pg_krb_server_keyfile[0] != '\0')
529 {
530 if (setenv("KRB5_KTNAME", pg_krb_server_keyfile, 1) != 0)
531 {
532 /* The only likely failure cause is OOM, so use that errcode */
533 ereport(FATAL,
534 (errcode(ERRCODE_OUT_OF_MEMORY),
535 errmsg("could not set environment: %m")));
536 }
537 }
538
539 while (true)
540 {
541 ssize_t ret;
542 gss_buffer_desc input,
543 output = GSS_C_EMPTY_BUFFER;
544
545 /*
546 * The client always sends first, so try to go ahead and read the
547 * length and wait on the socket to be readable again if that fails.
548 */
549 ret = read_or_wait(port, sizeof(uint32));
550 if (ret < 0)
551 return ret;
552
553 /*
554 * Get the length for this packet from the length header.
555 */
556 input.length = ntohl(*(uint32 *) PqGSSRecvBuffer);
557
558 /* Done with the length, reset our buffer */
559 PqGSSRecvLength = 0;
560
561 /*
562 * During initialization, packets are always fully consumed and
563 * shouldn't ever be over PQ_GSS_RECV_BUFFER_SIZE in length.
564 *
565 * Verify on our side that the client doesn't do something funny.
566 */
567 if (input.length > PQ_GSS_RECV_BUFFER_SIZE)
568 {
569 ereport(COMMERROR,
570 (errmsg("oversize GSSAPI packet sent by the client (%zu > %d)",
571 (size_t) input.length,
572 PQ_GSS_RECV_BUFFER_SIZE)));
573 return -1;
574 }
575
576 /*
577 * Get the rest of the packet so we can pass it to GSSAPI to accept
578 * the context.
579 */
580 ret = read_or_wait(port, input.length);
581 if (ret < 0)
582 return ret;
583
584 input.value = PqGSSRecvBuffer;
585
586 /* Process incoming data. (The client sends first.) */
587 major = gss_accept_sec_context(&minor, &port->gss->ctx,
588 GSS_C_NO_CREDENTIAL, &input,
589 GSS_C_NO_CHANNEL_BINDINGS,
590 &port->gss->name, NULL, &output, NULL,
591 NULL, NULL);
592 if (GSS_ERROR(major))
593 {
594 pg_GSS_error(_("could not accept GSSAPI security context"),
595 major, minor);
596 gss_release_buffer(&minor, &output);
597 return -1;
598 }
599 else if (!(major & GSS_S_CONTINUE_NEEDED))
600 {
601 /*
602 * rfc2744 technically permits context negotiation to be complete
603 * both with and without a packet to be sent.
604 */
605 complete_next = true;
606 }
607
608 /* Done handling the incoming packet, reset our buffer */
609 PqGSSRecvLength = 0;
610
611 /*
612 * Check if we have data to send and, if we do, make sure to send it
613 * all
614 */
615 if (output.length > 0)
616 {
617 uint32 netlen = htonl(output.length);
618
619 if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32))
620 {
621 ereport(COMMERROR,
622 (errmsg("server tried to send oversize GSSAPI packet (%zu > %zu)",
623 (size_t) output.length,
624 PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32))));
625 gss_release_buffer(&minor, &output);
626 return -1;
627 }
628
629 memcpy(PqGSSSendBuffer, (char *) &netlen, sizeof(uint32));
630 PqGSSSendLength += sizeof(uint32);
631
632 memcpy(PqGSSSendBuffer + PqGSSSendLength, output.value, output.length);
633 PqGSSSendLength += output.length;
634
635 /* we don't bother with PqGSSSendConsumed here */
636
637 while (PqGSSSendNext < PqGSSSendLength)
638 {
639 ret = secure_raw_write(port, PqGSSSendBuffer + PqGSSSendNext,
640 PqGSSSendLength - PqGSSSendNext);
641
642 /*
643 * If we got back an error and it wasn't just
644 * EWOULDBLOCK/EAGAIN/EINTR, then give up.
645 */
646 if (ret < 0 &&
647 !(errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR))
648 {
649 gss_release_buffer(&minor, &output);
650 return -1;
651 }
652
653 /* Wait and retry if we couldn't write yet */
654 if (ret <= 0)
655 {
656 WaitLatchOrSocket(MyLatch,
657 WL_SOCKET_WRITEABLE | WL_EXIT_ON_PM_DEATH,
658 port->sock, 0, WAIT_EVENT_GSS_OPEN_SERVER);
659 continue;
660 }
661
662 PqGSSSendNext += ret;
663 }
664
665 /* Done sending the packet, reset our buffer */
666 PqGSSSendLength = PqGSSSendNext = 0;
667
668 gss_release_buffer(&minor, &output);
669 }
670
671 /*
672 * If we got back that the connection is finished being set up, now
673 * that we've sent the last packet, exit our loop.
674 */
675 if (complete_next)
676 break;
677 }
678
679 /*
680 * Determine the max packet size which will fit in our buffer, after
681 * accounting for the length. be_gssapi_write will need this.
682 */
683 major = gss_wrap_size_limit(&minor, port->gss->ctx, 1, GSS_C_QOP_DEFAULT,
684 PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32),
685 &PqGSSMaxPktSize);
686
687 if (GSS_ERROR(major))
688 {
689 pg_GSS_error(_("GSSAPI size check error"), major, minor);
690 return -1;
691 }
692
693 port->gss->enc = true;
694
695 return 0;
696 }
697
698 /*
699 * Return if GSSAPI authentication was used on this connection.
700 */
701 bool
be_gssapi_get_auth(Port * port)702 be_gssapi_get_auth(Port *port)
703 {
704 if (!port || !port->gss)
705 return false;
706
707 return port->gss->auth;
708 }
709
710 /*
711 * Return if GSSAPI encryption is enabled and being used on this connection.
712 */
713 bool
be_gssapi_get_enc(Port * port)714 be_gssapi_get_enc(Port *port)
715 {
716 if (!port || !port->gss)
717 return false;
718
719 return port->gss->enc;
720 }
721
722 /*
723 * Return the GSSAPI principal used for authentication on this connection
724 * (NULL if we did not perform GSSAPI authentication).
725 */
726 const char *
be_gssapi_get_princ(Port * port)727 be_gssapi_get_princ(Port *port)
728 {
729 if (!port || !port->gss)
730 return NULL;
731
732 return port->gss->princ;
733 }
734