LCOV - differential code coverage report
Current view: top level - src/interfaces/libpq - fe-secure-gssapi.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 64.0 % 236 151 8 9 47 21 18 72 3 58 39 80 7 4
Current Date: 2023-04-08 15:15:32 Functions: 83.3 % 6 5 1 4 1 1 4
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * fe-secure-gssapi.c
       4                 :  *   The front-end (client) encryption support for GSSAPI
       5                 :  *
       6                 :  * Portions Copyright (c) 2016-2023, PostgreSQL Global Development Group
       7                 :  *
       8                 :  * IDENTIFICATION
       9                 :  *  src/interfaces/libpq/fe-secure-gssapi.c
      10                 :  *
      11                 :  *-------------------------------------------------------------------------
      12                 :  */
      13                 : 
      14                 : #include "postgres_fe.h"
      15                 : 
      16                 : #include "fe-gssapi-common.h"
      17                 : #include "libpq-fe.h"
      18                 : #include "libpq-int.h"
      19                 : #include "port/pg_bswap.h"
      20                 : 
      21                 : 
      22                 : /*
      23                 :  * Require encryption support, as well as mutual authentication and
      24                 :  * tamperproofing measures.
      25                 :  */
      26                 : #define GSS_REQUIRED_FLAGS GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | \
      27                 :     GSS_C_SEQUENCE_FLAG | GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG
      28                 : 
      29                 : /*
      30                 :  * Handle the encryption/decryption of data using GSSAPI.
      31                 :  *
      32                 :  * In the encrypted data stream on the wire, we break up the data
      33                 :  * into packets where each packet starts with a uint32-size length
      34                 :  * word (in network byte order), then encrypted data of that length
      35                 :  * immediately following.  Decryption yields the same data stream
      36                 :  * that would appear when not using encryption.
      37                 :  *
      38                 :  * Encrypted data typically ends up being larger than the same data
      39                 :  * unencrypted, so we use fixed-size buffers for handling the
      40                 :  * encryption/decryption which are larger than PQComm's buffer will
      41                 :  * typically be to minimize the times where we have to make multiple
      42                 :  * packets (and therefore multiple recv/send calls for a single
      43                 :  * read/write call to us).
      44                 :  *
      45                 :  * NOTE: The client and server have to agree on the max packet size,
      46                 :  * because we have to pass an entire packet to GSSAPI at a time and we
      47                 :  * don't want the other side to send arbitrarily huge packets as we
      48                 :  * would have to allocate memory for them to then pass them to GSSAPI.
      49                 :  *
      50                 :  * Therefore, these two #define's are effectively part of the protocol
      51                 :  * spec and can't ever be changed.
      52                 :  */
      53                 : #define PQ_GSS_SEND_BUFFER_SIZE 16384
      54                 : #define PQ_GSS_RECV_BUFFER_SIZE 16384
      55                 : 
      56                 : /*
      57                 :  * We need these state variables per-connection.  To allow the functions
      58                 :  * in this file to look mostly like those in be-secure-gssapi.c, set up
      59                 :  * these macros.
      60                 :  */
      61                 : #define PqGSSSendBuffer (conn->gss_SendBuffer)
      62                 : #define PqGSSSendLength (conn->gss_SendLength)
      63                 : #define PqGSSSendNext (conn->gss_SendNext)
      64                 : #define PqGSSSendConsumed (conn->gss_SendConsumed)
      65                 : #define PqGSSRecvBuffer (conn->gss_RecvBuffer)
      66                 : #define PqGSSRecvLength (conn->gss_RecvLength)
      67                 : #define PqGSSResultBuffer (conn->gss_ResultBuffer)
      68                 : #define PqGSSResultLength (conn->gss_ResultLength)
      69                 : #define PqGSSResultNext (conn->gss_ResultNext)
      70                 : #define PqGSSMaxPktSize (conn->gss_MaxPktSize)
      71                 : 
      72                 : 
      73                 : /*
      74                 :  * Attempt to write len bytes of data from ptr to a GSSAPI-encrypted connection.
      75                 :  *
      76                 :  * The connection must be already set up for GSSAPI encryption (i.e., GSSAPI
      77                 :  * transport negotiation is complete).
      78                 :  *
      79                 :  * On success, returns the number of data bytes consumed (possibly less than
      80                 :  * len).  On failure, returns -1 with errno set appropriately.  If the errno
      81                 :  * indicates a non-retryable error, a message is added to conn->errorMessage.
      82                 :  * For retryable errors, caller should call again (passing the same data)
      83                 :  * once the socket is ready.
      84                 :  */
      85                 : ssize_t
      86 CBC         122 : pg_GSS_write(PGconn *conn, const void *ptr, size_t len)
      87                 : {
      88                 :     OM_uint32   major,
      89                 :                 minor;
      90                 :     gss_buffer_desc input,
      91             122 :                 output = GSS_C_EMPTY_BUFFER;
      92             122 :     ssize_t     ret = -1;
      93             122 :     size_t      bytes_sent = 0;
      94                 :     size_t      bytes_to_encrypt;
      95                 :     size_t      bytes_encrypted;
      96             122 :     gss_ctx_id_t gctx = conn->gctx;
      97                 : 
      98                 :     /*
      99                 :      * When we get a failure, we must not tell the caller we have successfully
     100                 :      * transmitted everything, else it won't retry.  Hence a "success"
     101                 :      * (positive) return value must only count source bytes corresponding to
     102                 :      * fully-transmitted encrypted packets.  The amount of source data
     103                 :      * corresponding to the current partly-transmitted packet is remembered in
     104                 :      * PqGSSSendConsumed.  On a retry, the caller *must* be sending that data
     105                 :      * again, so if it offers a len less than that, something is wrong.
     106                 :      */
     107             122 :     if (len < PqGSSSendConsumed)
     108                 :     {
     109 UBC           0 :         appendPQExpBufferStr(&conn->errorMessage,
     110                 :                              "GSSAPI caller failed to retransmit all data needing to be retried\n");
     111               0 :         errno = EINVAL;
     112               0 :         return -1;
     113                 :     }
     114                 : 
     115                 :     /* Discount whatever source data we already encrypted. */
     116 CBC         122 :     bytes_to_encrypt = len - PqGSSSendConsumed;
     117             122 :     bytes_encrypted = PqGSSSendConsumed;
     118                 : 
     119                 :     /*
     120                 :      * Loop through encrypting data and sending it out until it's all done or
     121                 :      * pqsecure_raw_write() complains (which would likely mean that the socket
     122                 :      * is non-blocking and the requested send() would block, or there was some
     123                 :      * kind of actual error).
     124                 :      */
     125             244 :     while (bytes_to_encrypt || PqGSSSendLength)
     126                 :     {
     127             244 :         int         conf_state = 0;
     128                 :         uint32      netlen;
     129                 : 
     130                 :         /*
     131                 :          * Check if we have data in the encrypted output buffer that needs to
     132                 :          * be sent (possibly left over from a previous call), and if so, try
     133                 :          * to send it.  If we aren't able to, return that fact back up to the
     134                 :          * caller.
     135                 :          */
     136             244 :         if (PqGSSSendLength)
     137                 :         {
     138                 :             ssize_t     retval;
     139             122 :             ssize_t     amount = PqGSSSendLength - PqGSSSendNext;
     140                 : 
     141 GNC         122 :             retval = pqsecure_raw_write(conn, PqGSSSendBuffer + PqGSSSendNext, amount);
     142             122 :             if (retval <= 0)
     143                 :             {
     144                 :                 /*
     145                 :                  * Report any previously-sent data; if there was none, reflect
     146                 :                  * the pqsecure_raw_write result up to our caller.  When there
     147                 :                  * was some, we're effectively assuming that any interesting
     148                 :                  * failure condition will recur on the next try.
     149                 :                  */
     150 UBC           0 :                 if (bytes_sent)
     151               0 :                     return bytes_sent;
     152 UNC           0 :                 return retval;
     153                 :             }
     154                 : 
     155                 :             /*
     156                 :              * Check if this was a partial write, and if so, move forward that
     157                 :              * far in our buffer and try again.
     158                 :              */
     159 GNC         122 :             if (retval != amount)
     160                 :             {
     161 UNC           0 :                 PqGSSSendNext += retval;
     162 UBC           0 :                 continue;
     163                 :             }
     164                 : 
     165                 :             /* We've successfully sent whatever data was in that packet. */
     166 CBC         122 :             bytes_sent += PqGSSSendConsumed;
     167                 : 
     168                 :             /* All encrypted data was sent, our buffer is empty now. */
     169             122 :             PqGSSSendLength = PqGSSSendNext = PqGSSSendConsumed = 0;
     170                 :         }
     171                 : 
     172                 :         /*
     173                 :          * Check if there are any bytes left to encrypt.  If not, we're done.
     174                 :          */
     175             244 :         if (!bytes_to_encrypt)
     176             122 :             break;
     177                 : 
     178                 :         /*
     179                 :          * Check how much we are being asked to send, if it's too much, then
     180                 :          * we will have to loop and possibly be called multiple times to get
     181                 :          * through all the data.
     182                 :          */
     183             122 :         if (bytes_to_encrypt > PqGSSMaxPktSize)
     184 UBC           0 :             input.length = PqGSSMaxPktSize;
     185                 :         else
     186 CBC         122 :             input.length = bytes_to_encrypt;
     187                 : 
     188             122 :         input.value = (char *) ptr + bytes_encrypted;
     189                 : 
     190             122 :         output.value = NULL;
     191             122 :         output.length = 0;
     192                 : 
     193                 :         /*
     194                 :          * Create the next encrypted packet.  Any failure here is considered a
     195                 :          * hard failure, so we return -1 even if bytes_sent > 0.
     196                 :          */
     197             122 :         major = gss_wrap(&minor, gctx, 1, GSS_C_QOP_DEFAULT,
     198                 :                          &input, &conf_state, &output);
     199             122 :         if (major != GSS_S_COMPLETE)
     200                 :         {
     201 UBC           0 :             pg_GSS_error(libpq_gettext("GSSAPI wrap error"), conn, major, minor);
     202               0 :             errno = EIO;        /* for lack of a better idea */
     203               0 :             goto cleanup;
     204                 :         }
     205                 : 
     206 CBC         122 :         if (conf_state == 0)
     207                 :         {
     208 UNC           0 :             libpq_append_conn_error(conn, "outgoing GSSAPI message would not use confidentiality");
     209 UBC           0 :             errno = EIO;        /* for lack of a better idea */
     210 UIC           0 :             goto cleanup;
     211                 :         }
     212 ECB             : 
     213 GIC         122 :         if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32))
     214 EUB             :         {
     215 UNC           0 :             libpq_append_conn_error(conn, "client tried to send oversize GSSAPI packet (%zu > %zu)",
     216 UBC           0 :                               (size_t) output.length,
     217 EUB             :                               PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32));
     218 UIC           0 :             errno = EIO;        /* for lack of a better idea */
     219               0 :             goto cleanup;
     220 ECB             :         }
     221                 : 
     222 CBC         122 :         bytes_encrypted += input.length;
     223 GIC         122 :         bytes_to_encrypt -= input.length;
     224             122 :         PqGSSSendConsumed += input.length;
     225 ECB             : 
     226                 :         /* 4 network-order bytes of length, then payload */
     227 CBC         122 :         netlen = pg_hton32(output.length);
     228 GIC         122 :         memcpy(PqGSSSendBuffer + PqGSSSendLength, &netlen, sizeof(uint32));
     229 CBC         122 :         PqGSSSendLength += sizeof(uint32);
     230 ECB             : 
     231 GIC         122 :         memcpy(PqGSSSendBuffer + PqGSSSendLength, output.value, output.length);
     232             122 :         PqGSSSendLength += output.length;
     233 ECB             : 
     234                 :         /* Release buffer storage allocated by GSSAPI */
     235 GIC         122 :         gss_release_buffer(&minor, &output);
     236                 :     }
     237 ECB             : 
     238                 :     /* If we get here, our counters should all match up. */
     239 GIC         122 :     Assert(bytes_sent == len);
     240 CBC         122 :     Assert(bytes_sent == bytes_encrypted);
     241                 : 
     242             122 :     ret = bytes_sent;
     243                 : 
     244             122 : cleanup:
     245 EUB             :     /* Release GSSAPI buffer storage, if we didn't already */
     246 CBC         122 :     if (output.value != NULL)
     247 UIC           0 :         gss_release_buffer(&minor, &output);
     248 GIC         122 :     return ret;
     249                 : }
     250                 : 
     251                 : /*
     252                 :  * Read up to len bytes of data into ptr from a GSSAPI-encrypted connection.
     253                 :  *
     254                 :  * The connection must be already set up for GSSAPI encryption (i.e., GSSAPI
     255                 :  * transport negotiation is complete).
     256                 :  *
     257                 :  * Returns the number of data bytes read, or on failure, returns -1
     258                 :  * with errno set appropriately.  If the errno indicates a non-retryable
     259                 :  * error, a message is added to conn->errorMessage.  For retryable errors,
     260                 :  * caller should call again once the socket is ready.
     261 ECB             :  */
     262                 : ssize_t
     263 GIC         250 : pg_GSS_read(PGconn *conn, void *ptr, size_t len)
     264                 : {
     265 ECB             :     OM_uint32   major,
     266                 :                 minor;
     267 GIC         250 :     gss_buffer_desc input = GSS_C_EMPTY_BUFFER,
     268 CBC         250 :                 output = GSS_C_EMPTY_BUFFER;
     269 ECB             :     ssize_t     ret;
     270 GIC         250 :     size_t      bytes_returned = 0;
     271             250 :     gss_ctx_id_t gctx = conn->gctx;
     272                 : 
     273                 :     /*
     274                 :      * The plan here is to read one incoming encrypted packet into
     275                 :      * PqGSSRecvBuffer, decrypt it into PqGSSResultBuffer, and then dole out
     276                 :      * data from there to the caller.  When we exhaust the current input
     277 ECB             :      * packet, read another.
     278                 :      */
     279 CBC         481 :     while (bytes_returned < len)
     280                 :     {
     281 GIC         481 :         int         conf_state = 0;
     282 ECB             : 
     283                 :         /* Check if we have data in our buffer that we can return immediately */
     284 CBC         481 :         if (PqGSSResultNext < PqGSSResultLength)
     285 ECB             :         {
     286 GIC         231 :             size_t      bytes_in_buffer = PqGSSResultLength - PqGSSResultNext;
     287             231 :             size_t      bytes_to_copy = Min(bytes_in_buffer, len - bytes_returned);
     288                 : 
     289                 :             /*
     290                 :              * Copy the data from our result buffer into the caller's buffer,
     291 ECB             :              * at the point where we last left off filling their buffer.
     292                 :              */
     293 CBC         231 :             memcpy((char *) ptr + bytes_returned, PqGSSResultBuffer + PqGSSResultNext, bytes_to_copy);
     294 GIC         231 :             PqGSSResultNext += bytes_to_copy;
     295             231 :             bytes_returned += bytes_to_copy;
     296                 : 
     297                 :             /*
     298                 :              * At this point, we've either filled the caller's buffer or
     299                 :              * emptied our result buffer.  Either way, return to caller.  In
     300                 :              * the second case, we could try to read another encrypted packet,
     301                 :              * but the odds are good that there isn't one available.  (If this
     302                 :              * isn't true, we chose too small a max packet size.)  In any
     303                 :              * case, there's no harm letting the caller process the data we've
     304 ECB             :              * already returned.
     305                 :              */
     306 GIC         231 :             break;
     307                 :         }
     308 ECB             : 
     309                 :         /* Result buffer is empty, so reset buffer pointers */
     310 GIC         250 :         PqGSSResultLength = PqGSSResultNext = 0;
     311                 : 
     312                 :         /*
     313                 :          * Because we chose above to return immediately as soon as we emit
     314                 :          * some data, bytes_returned must be zero at this point.  Therefore
     315                 :          * the failure exits below can just return -1 without worrying about
     316 ECB             :          * whether we already emitted some data.
     317                 :          */
     318 GIC         250 :         Assert(bytes_returned == 0);
     319                 : 
     320                 :         /*
     321                 :          * At this point, our result buffer is empty with more bytes being
     322                 :          * requested to be read.  We are now ready to load the next packet and
     323                 :          * decrypt it (entirely) into our result buffer.
     324                 :          */
     325 ECB             : 
     326                 :         /* Collect the length if we haven't already */
     327 CBC         250 :         if (PqGSSRecvLength < sizeof(uint32))
     328 ECB             :         {
     329 GIC         250 :             ret = pqsecure_raw_read(conn, PqGSSRecvBuffer + PqGSSRecvLength,
     330             250 :                                     sizeof(uint32) - PqGSSRecvLength);
     331 ECB             : 
     332                 :             /* If ret <= 0, pqsecure_raw_read already set the correct errno */
     333 GIC         250 :             if (ret <= 0)
     334 CBC          19 :                 return ret;
     335                 : 
     336 GIC         231 :             PqGSSRecvLength += ret;
     337 ECB             : 
     338                 :             /* If we still haven't got the length, return to the caller */
     339 GBC         231 :             if (PqGSSRecvLength < sizeof(uint32))
     340 EUB             :             {
     341 UIC           0 :                 errno = EWOULDBLOCK;
     342               0 :                 return -1;
     343                 :             }
     344                 :         }
     345 ECB             : 
     346                 :         /* Decode the packet length and check for overlength packet */
     347 CBC         231 :         input.length = pg_ntoh32(*(uint32 *) PqGSSRecvBuffer);
     348                 : 
     349 GBC         231 :         if (input.length > PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32))
     350 EUB             :         {
     351 UNC           0 :             libpq_append_conn_error(conn, "oversize GSSAPI packet sent by the server (%zu > %zu)",
     352 UBC           0 :                               (size_t) input.length,
     353                 :                               PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32));
     354 UIC           0 :             errno = EIO;        /* for lack of a better idea */
     355               0 :             return -1;
     356                 :         }
     357                 : 
     358                 :         /*
     359 ECB             :          * 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 CBC         231 :         ret = pqsecure_raw_read(conn, PqGSSRecvBuffer + PqGSSRecvLength,
     363 GBC         231 :                                 input.length - (PqGSSRecvLength - sizeof(uint32)));
     364                 :         /* If ret <= 0, pqsecure_raw_read already set the correct errno */
     365 CBC         231 :         if (ret <= 0)
     366 UIC           0 :             return ret;
     367                 : 
     368 CBC         231 :         PqGSSRecvLength += ret;
     369                 : 
     370 EUB             :         /* If we don't yet have the whole packet, return to the caller */
     371 GBC         231 :         if (PqGSSRecvLength - sizeof(uint32) < input.length)
     372                 :         {
     373 UIC           0 :             errno = EWOULDBLOCK;
     374               0 :             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 ECB             :          * the caller.  Note that error exits below here must take care of
     381                 :          * releasing the gss output buffer.
     382                 :          */
     383 GIC         231 :         output.value = NULL;
     384 CBC         231 :         output.length = 0;
     385             231 :         input.value = PqGSSRecvBuffer + sizeof(uint32);
     386                 : 
     387 GBC         231 :         major = gss_unwrap(&minor, gctx, &input, &output, &conf_state, NULL);
     388 GIC         231 :         if (major != GSS_S_COMPLETE)
     389 EUB             :         {
     390 UBC           0 :             pg_GSS_error(libpq_gettext("GSSAPI unwrap error"), conn,
     391 EUB             :                          major, minor);
     392 UIC           0 :             ret = -1;
     393               0 :             errno = EIO;        /* for lack of a better idea */
     394 LBC           0 :             goto cleanup;
     395                 :         }
     396 EUB             : 
     397 GBC         231 :         if (conf_state == 0)
     398 EUB             :         {
     399 UNC           0 :             libpq_append_conn_error(conn, "incoming GSSAPI message did not use confidentiality");
     400 UIC           0 :             ret = -1;
     401 LBC           0 :             errno = EIO;        /* for lack of a better idea */
     402               0 :             goto cleanup;
     403                 :         }
     404                 : 
     405 CBC         231 :         memcpy(PqGSSResultBuffer, output.value, output.length);
     406 GIC         231 :         PqGSSResultLength = output.length;
     407                 : 
     408 ECB             :         /* Our receive buffer is now empty, reset it */
     409 GIC         231 :         PqGSSRecvLength = 0;
     410                 : 
     411 ECB             :         /* Release buffer storage allocated by GSSAPI */
     412 GIC         231 :         gss_release_buffer(&minor, &output);
     413 ECB             :     }
     414                 : 
     415 CBC         231 :     ret = bytes_returned;
     416 EUB             : 
     417 CBC         231 : cleanup:
     418                 :     /* Release GSSAPI buffer storage, if we didn't already */
     419 GIC         231 :     if (output.value != NULL)
     420 UIC           0 :         gss_release_buffer(&minor, &output);
     421 GIC         231 :     return ret;
     422                 : }
     423                 : 
     424                 : /*
     425                 :  * Simple wrapper for reading from pqsecure_raw_read.
     426                 :  *
     427                 :  * This takes the same arguments as pqsecure_raw_read, plus an output parameter
     428 ECB             :  * to return the number of bytes read.  This handles if blocking would occur and
     429                 :  * if we detect EOF on the connection.
     430                 :  */
     431                 : static PostgresPollingStatusType
     432 GIC          51 : gss_read(PGconn *conn, void *recv_buffer, size_t length, ssize_t *ret)
     433 ECB             : {
     434 CBC          51 :     *ret = pqsecure_raw_read(conn, recv_buffer, length);
     435 GIC          51 :     if (*ret < 0)
     436 EUB             :     {
     437 GIC          15 :         if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
     438              15 :             return PGRES_POLLING_READING;
     439                 :         else
     440 LBC           0 :             return PGRES_POLLING_FAILED;
     441                 :     }
     442 EUB             : 
     443                 :     /* Check for EOF */
     444 GBC          36 :     if (*ret == 0)
     445 EUB             :     {
     446 UIC           0 :         int         result = pqReadReady(conn);
     447 EUB             : 
     448 UBC           0 :         if (result < 0)
     449 UIC           0 :             return PGRES_POLLING_FAILED;
     450 EUB             : 
     451 UBC           0 :         if (!result)
     452 UIC           0 :             return PGRES_POLLING_READING;
     453 EUB             : 
     454 UBC           0 :         *ret = pqsecure_raw_read(conn, recv_buffer, length);
     455 UIC           0 :         if (*ret < 0)
     456 EUB             :         {
     457 UIC           0 :             if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
     458 UBC           0 :                 return PGRES_POLLING_READING;
     459 EUB             :             else
     460 UIC           0 :                 return PGRES_POLLING_FAILED;
     461                 :         }
     462 LBC           0 :         if (*ret == 0)
     463 UIC           0 :             return PGRES_POLLING_FAILED;
     464                 :     }
     465                 : 
     466 GIC          36 :     return PGRES_POLLING_OK;
     467                 : }
     468                 : 
     469                 : /*
     470                 :  * Negotiate GSSAPI transport for a connection.  When complete, returns
     471                 :  * PGRES_POLLING_OK.  Will return PGRES_POLLING_READING or
     472 ECB             :  * PGRES_POLLING_WRITING as appropriate whenever it would block, and
     473                 :  * PGRES_POLLING_FAILED if transport could not be negotiated.
     474                 :  */
     475                 : PostgresPollingStatusType
     476 GIC          51 : pqsecure_open_gss(PGconn *conn)
     477                 : {
     478                 :     ssize_t     ret;
     479 ECB             :     OM_uint32   major,
     480                 :                 minor;
     481                 :     uint32      netlen;
     482                 :     PostgresPollingStatusType result;
     483 GIC          51 :     gss_buffer_desc input = GSS_C_EMPTY_BUFFER,
     484              51 :                 output = GSS_C_EMPTY_BUFFER;
     485                 : 
     486                 :     /*
     487                 :      * If first time through for this connection, allocate buffers and
     488 ECB             :      * initialize state variables.  By malloc'ing the buffers separately, we
     489                 :      * ensure that they are sufficiently aligned for the length-word accesses
     490                 :      * that we do in some places in this file.
     491                 :      */
     492 CBC          51 :     if (PqGSSSendBuffer == NULL)
     493 ECB             :     {
     494 GIC          18 :         PqGSSSendBuffer = malloc(PQ_GSS_SEND_BUFFER_SIZE);
     495 GBC          18 :         PqGSSRecvBuffer = malloc(PQ_GSS_RECV_BUFFER_SIZE);
     496              18 :         PqGSSResultBuffer = malloc(PQ_GSS_RECV_BUFFER_SIZE);
     497 GIC          18 :         if (!PqGSSSendBuffer || !PqGSSRecvBuffer || !PqGSSResultBuffer)
     498 ECB             :         {
     499 UNC           0 :             libpq_append_conn_error(conn, "out of memory");
     500 UIC           0 :             return PGRES_POLLING_FAILED;
     501                 :         }
     502 GIC          18 :         PqGSSSendLength = PqGSSSendNext = PqGSSSendConsumed = 0;
     503              18 :         PqGSSRecvLength = PqGSSResultLength = PqGSSResultNext = 0;
     504 ECB             :     }
     505                 : 
     506                 :     /*
     507                 :      * Check if we have anything to send from a prior call and if so, send it.
     508                 :      */
     509 CBC          51 :     if (PqGSSSendLength)
     510                 :     {
     511 GBC          18 :         ssize_t     amount = PqGSSSendLength - PqGSSSendNext;
     512 EUB             : 
     513 GIC          18 :         ret = pqsecure_raw_write(conn, PqGSSSendBuffer + PqGSSSendNext, amount);
     514 GBC          18 :         if (ret < 0)
     515                 :         {
     516 UIC           0 :             if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
     517 LBC           0 :                 return PGRES_POLLING_WRITING;
     518                 :             else
     519 UBC           0 :                 return PGRES_POLLING_FAILED;
     520 EUB             :         }
     521                 : 
     522 GIC          18 :         if (ret < amount)
     523 ECB             :         {
     524 UIC           0 :             PqGSSSendNext += ret;
     525               0 :             return PGRES_POLLING_WRITING;
     526                 :         }
     527                 : 
     528 GIC          18 :         PqGSSSendLength = PqGSSSendNext = 0;
     529                 :     }
     530                 : 
     531 ECB             :     /*
     532                 :      * Client sends first, and sending creates a context, therefore this will
     533                 :      * be false the first time through, and then when we get called again we
     534                 :      * will check for incoming data.
     535                 :      */
     536 CBC          51 :     if (conn->gctx)
     537                 :     {
     538                 :         /* Process any incoming data we might have */
     539 ECB             : 
     540                 :         /* See if we are still trying to get the length */
     541 CBC          33 :         if (PqGSSRecvLength < sizeof(uint32))
     542                 :         {
     543 ECB             :             /* Attempt to get the length first */
     544 GIC          33 :             result = gss_read(conn, PqGSSRecvBuffer + PqGSSRecvLength, sizeof(uint32) - PqGSSRecvLength, &ret);
     545 CBC          33 :             if (result != PGRES_POLLING_OK)
     546 GBC          15 :                 return result;
     547                 : 
     548 GIC          18 :             PqGSSRecvLength += ret;
     549                 : 
     550              18 :             if (PqGSSRecvLength < sizeof(uint32))
     551 UIC           0 :                 return PGRES_POLLING_READING;
     552                 :         }
     553                 : 
     554                 :         /*
     555                 :          * Check if we got an error packet
     556                 :          *
     557 ECB             :          * This is safe to do because we shouldn't ever get a packet over 8192
     558                 :          * and therefore the actual length bytes, being that they are in
     559                 :          * network byte order, for any real packet will start with two zero
     560                 :          * bytes.
     561                 :          */
     562 GIC          18 :         if (PqGSSRecvBuffer[0] == 'E')
     563                 :         {
     564                 :             /*
     565 EUB             :              * For an error packet during startup, we don't get a length, so
     566                 :              * simply read as much as we can fit into our buffer (as a string,
     567                 :              * so leave a spot at the end for a NULL byte too) and report that
     568                 :              * back to the caller.
     569                 :              */
     570 UIC           0 :             result = gss_read(conn, PqGSSRecvBuffer + PqGSSRecvLength, PQ_GSS_RECV_BUFFER_SIZE - PqGSSRecvLength - 1, &ret);
     571 UBC           0 :             if (result != PGRES_POLLING_OK)
     572               0 :                 return result;
     573 EUB             : 
     574 UIC           0 :             PqGSSRecvLength += ret;
     575 EUB             : 
     576 UIC           0 :             Assert(PqGSSRecvLength < PQ_GSS_RECV_BUFFER_SIZE);
     577               0 :             PqGSSRecvBuffer[PqGSSRecvLength] = '\0';
     578               0 :             appendPQExpBuffer(&conn->errorMessage, "%s\n", PqGSSRecvBuffer + 1);
     579                 : 
     580               0 :             return PGRES_POLLING_FAILED;
     581                 :         }
     582                 : 
     583                 :         /*
     584 ECB             :          * We should have the whole length at this point, so pull it out and
     585                 :          * then read whatever we have left of the packet
     586                 :          */
     587 EUB             : 
     588                 :         /* Get the length and check for over-length packet */
     589 GIC          18 :         input.length = pg_ntoh32(*(uint32 *) PqGSSRecvBuffer);
     590 GBC          18 :         if (input.length > PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32))
     591                 :         {
     592 UNC           0 :             libpq_append_conn_error(conn, "oversize GSSAPI packet sent by the server (%zu > %zu)",
     593 UIC           0 :                               (size_t) input.length,
     594                 :                               PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32));
     595               0 :             return PGRES_POLLING_FAILED;
     596 ECB             :         }
     597                 : 
     598                 :         /*
     599 EUB             :          * Read as much of the packet as we are able to on this call into
     600                 :          * wherever we left off from the last time we were called.
     601 ECB             :          */
     602 GIC          18 :         result = gss_read(conn, PqGSSRecvBuffer + PqGSSRecvLength,
     603              18 :                           input.length - (PqGSSRecvLength - sizeof(uint32)), &ret);
     604              18 :         if (result != PGRES_POLLING_OK)
     605 UIC           0 :             return result;
     606                 : 
     607 CBC          18 :         PqGSSRecvLength += ret;
     608 EUB             : 
     609                 :         /*
     610 ECB             :          * If we got less than the rest of the packet then we need to return
     611                 :          * and be called again.
     612                 :          */
     613 GIC          18 :         if (PqGSSRecvLength - sizeof(uint32) < input.length)
     614 LBC           0 :             return PGRES_POLLING_READING;
     615 ECB             : 
     616 GBC          18 :         input.value = PqGSSRecvBuffer + sizeof(uint32);
     617                 :     }
     618                 : 
     619                 :     /* Load the service name (no-op if already done */
     620 GIC          36 :     ret = pg_GSS_load_servicename(conn);
     621              36 :     if (ret != STATUS_OK)
     622 LBC           0 :         return PGRES_POLLING_FAILED;
     623                 : 
     624                 :     /*
     625                 :      * Call GSS init context, either with an empty input, or with a complete
     626                 :      * packet from the server.
     627                 :      */
     628 CBC          36 :     major = gss_init_sec_context(&minor, conn->gcred, &conn->gctx,
     629                 :                                  conn->gtarg_nam, GSS_C_NO_OID,
     630 ECB             :                                  GSS_REQUIRED_FLAGS, 0, 0, &input, NULL,
     631                 :                                  &output, NULL, NULL);
     632 EUB             : 
     633                 :     /* GSS Init Sec Context uses the whole packet, so clear it */
     634 GBC          36 :     PqGSSRecvLength = 0;
     635                 : 
     636 GIC          36 :     if (GSS_ERROR(major))
     637 ECB             :     {
     638 UIC           0 :         pg_GSS_error(libpq_gettext("could not initiate GSSAPI security context"),
     639                 :                      conn, major, minor);
     640               0 :         return PGRES_POLLING_FAILED;
     641                 :     }
     642                 : 
     643 CBC          36 :     if (output.length == 0)
     644                 :     {
     645                 :         /*
     646 ECB             :          * We're done - hooray!  Set flag to tell the low-level I/O routines
     647                 :          * to do GSS wrapping/unwrapping.
     648                 :          */
     649 GIC          18 :         conn->gssenc = true;
     650                 : 
     651                 :         /* Clean up */
     652              18 :         gss_release_cred(&minor, &conn->gcred);
     653              18 :         conn->gcred = GSS_C_NO_CREDENTIAL;
     654 CBC          18 :         gss_release_buffer(&minor, &output);
     655                 : 
     656 ECB             :         /*
     657                 :          * Determine the max packet size which will fit in our buffer, after
     658                 :          * accounting for the length.  pg_GSS_write will need this.
     659                 :          */
     660 GBC          18 :         major = gss_wrap_size_limit(&minor, conn->gctx, 1, GSS_C_QOP_DEFAULT,
     661                 :                                     PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32),
     662              18 :                                     &PqGSSMaxPktSize);
     663                 : 
     664 GIC          18 :         if (GSS_ERROR(major))
     665 ECB             :         {
     666 UIC           0 :             pg_GSS_error(libpq_gettext("GSSAPI size check error"), conn,
     667                 :                          major, minor);
     668               0 :             return PGRES_POLLING_FAILED;
     669 ECB             :         }
     670                 : 
     671 GBC          18 :         return PGRES_POLLING_OK;
     672                 :     }
     673 EUB             : 
     674                 :     /* Must have output.length > 0 */
     675 GIC          18 :     if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32))
     676                 :     {
     677 UIC           0 :         pg_GSS_error(libpq_gettext("GSSAPI context establishment error"),
     678 ECB             :                      conn, major, minor);
     679 UIC           0 :         gss_release_buffer(&minor, &output);
     680 LBC           0 :         return PGRES_POLLING_FAILED;
     681 ECB             :     }
     682                 : 
     683                 :     /* Queue the token for writing */
     684 CBC          18 :     netlen = pg_hton32(output.length);
     685                 : 
     686 GIC          18 :     memcpy(PqGSSSendBuffer, (char *) &netlen, sizeof(uint32));
     687              18 :     PqGSSSendLength += sizeof(uint32);
     688                 : 
     689 CBC          18 :     memcpy(PqGSSSendBuffer + PqGSSSendLength, output.value, output.length);
     690 GIC          18 :     PqGSSSendLength += output.length;
     691                 : 
     692 ECB             :     /* We don't bother with PqGSSSendConsumed here */
     693                 : 
     694                 :     /* Release buffer storage allocated by GSSAPI */
     695 GIC          18 :     gss_release_buffer(&minor, &output);
     696                 : 
     697                 :     /* Ask to be called again to write data */
     698              18 :     return PGRES_POLLING_WRITING;
     699                 : }
     700                 : 
     701                 : /*
     702                 :  * GSSAPI Information functions.
     703 EUB             :  */
     704                 : 
     705                 : /*
     706                 :  * Return the GSSAPI Context itself.
     707                 :  */
     708                 : void *
     709 UIC           0 : PQgetgssctx(PGconn *conn)
     710                 : {
     711               0 :     if (!conn)
     712               0 :         return NULL;
     713                 : 
     714               0 :     return conn->gctx;
     715 ECB             : }
     716                 : 
     717                 : /*
     718                 :  * Return true if GSSAPI encryption is in use.
     719                 :  */
     720 EUB             : int
     721 GIC           2 : PQgssEncInUse(PGconn *conn)
     722                 : {
     723               2 :     if (!conn || !conn->gctx)
     724               2 :         return 0;
     725                 : 
     726 UIC           0 :     return conn->gssenc;
     727                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a