LCOV - code coverage report
Current view: top level - src/interfaces/libpq - fe-auth.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 6.9 % 519 36
Test Date: 2026-01-26 10:56:24 Functions: 25.0 % 16 4
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 3.3 % 306 10

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * fe-auth.c
       4                 :             :  *         The front-end (client) authorization routines
       5                 :             :  *
       6                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
       8                 :             :  *
       9                 :             :  * IDENTIFICATION
      10                 :             :  *        src/interfaces/libpq/fe-auth.c
      11                 :             :  *
      12                 :             :  *-------------------------------------------------------------------------
      13                 :             :  */
      14                 :             : 
      15                 :             : /*
      16                 :             :  * INTERFACE ROUTINES
      17                 :             :  *         frontend (client) routines:
      18                 :             :  *              pg_fe_sendauth                  send authentication information
      19                 :             :  *              pg_fe_getauthname               get user's name according to the client side
      20                 :             :  *                                                              of the authentication system
      21                 :             :  */
      22                 :             : 
      23                 :             : #include "postgres_fe.h"
      24                 :             : 
      25                 :             : #ifdef WIN32
      26                 :             : #include "win32.h"
      27                 :             : #else
      28                 :             : #include <unistd.h>
      29                 :             : #include <fcntl.h>
      30                 :             : #include <limits.h>
      31                 :             : #include <pwd.h>
      32                 :             : #include <sys/param.h>                    /* for MAXHOSTNAMELEN on most */
      33                 :             : #include <sys/socket.h>
      34                 :             : #ifdef HAVE_SYS_UCRED_H
      35                 :             : #include <sys/ucred.h>
      36                 :             : #endif
      37                 :             : #ifndef  MAXHOSTNAMELEN
      38                 :             : #include <netdb.h>                                /* for MAXHOSTNAMELEN on some */
      39                 :             : #endif
      40                 :             : #endif
      41                 :             : 
      42                 :             : #include "common/md5.h"
      43                 :             : #include "common/oauth-common.h"
      44                 :             : #include "common/scram-common.h"
      45                 :             : #include "fe-auth.h"
      46                 :             : #include "fe-auth-sasl.h"
      47                 :             : #include "fe-auth-oauth.h"
      48                 :             : #include "libpq-fe.h"
      49                 :             : 
      50                 :             : #ifdef ENABLE_GSS
      51                 :             : /*
      52                 :             :  * GSSAPI authentication system.
      53                 :             :  */
      54                 :             : 
      55                 :             : #include "fe-gssapi-common.h"
      56                 :             : 
      57                 :             : /*
      58                 :             :  * Continue GSS authentication with next token as needed.
      59                 :             :  */
      60                 :             : static int
      61                 :           0 : pg_GSS_continue(PGconn *conn, int payloadlen)
      62                 :             : {
      63                 :           0 :         OM_uint32       maj_stat,
      64                 :             :                                 min_stat,
      65                 :             :                                 lmin_s,
      66                 :           0 :                                 gss_flags = GSS_C_MUTUAL_FLAG;
      67                 :           0 :         gss_buffer_desc ginbuf;
      68                 :           0 :         gss_buffer_desc goutbuf;
      69                 :             : 
      70                 :             :         /*
      71                 :             :          * On first call, there's no input token. On subsequent calls, read the
      72                 :             :          * input token into a GSS buffer.
      73                 :             :          */
      74         [ #  # ]:           0 :         if (conn->gctx != GSS_C_NO_CONTEXT)
      75                 :             :         {
      76                 :           0 :                 ginbuf.length = payloadlen;
      77                 :           0 :                 ginbuf.value = malloc(payloadlen);
      78         [ #  # ]:           0 :                 if (!ginbuf.value)
      79                 :             :                 {
      80                 :           0 :                         libpq_append_conn_error(conn, "out of memory allocating GSSAPI buffer (%d)",
      81                 :           0 :                                                                         payloadlen);
      82                 :           0 :                         return STATUS_ERROR;
      83                 :             :                 }
      84         [ #  # ]:           0 :                 if (pqGetnchar(ginbuf.value, payloadlen, conn))
      85                 :             :                 {
      86                 :             :                         /*
      87                 :             :                          * Shouldn't happen, because the caller should've ensured that the
      88                 :             :                          * whole message is already in the input buffer.
      89                 :             :                          */
      90                 :           0 :                         free(ginbuf.value);
      91                 :           0 :                         return STATUS_ERROR;
      92                 :             :                 }
      93                 :           0 :         }
      94                 :             :         else
      95                 :             :         {
      96                 :           0 :                 ginbuf.length = 0;
      97                 :           0 :                 ginbuf.value = NULL;
      98                 :             :         }
      99                 :             : 
     100                 :             :         /* finished parsing, trace server-to-client message */
     101         [ #  # ]:           0 :         if (conn->Pfdebug)
     102                 :           0 :                 pqTraceOutputMessage(conn, conn->inBuffer + conn->inStart, false);
     103                 :             : 
     104                 :             :         /* Only try to acquire credentials if GSS delegation isn't disabled. */
     105         [ #  # ]:           0 :         if (!pg_GSS_have_cred_cache(&conn->gcred))
     106                 :           0 :                 conn->gcred = GSS_C_NO_CREDENTIAL;
     107                 :             : 
     108   [ #  #  #  # ]:           0 :         if (conn->gssdelegation && conn->gssdelegation[0] == '1')
     109                 :           0 :                 gss_flags |= GSS_C_DELEG_FLAG;
     110                 :             : 
     111                 :           0 :         maj_stat = gss_init_sec_context(&min_stat,
     112                 :           0 :                                                                         conn->gcred,
     113                 :           0 :                                                                         &conn->gctx,
     114                 :           0 :                                                                         conn->gtarg_nam,
     115                 :             :                                                                         GSS_C_NO_OID,
     116                 :           0 :                                                                         gss_flags,
     117                 :             :                                                                         0,
     118                 :             :                                                                         GSS_C_NO_CHANNEL_BINDINGS,
     119         [ #  # ]:           0 :                                                                         (ginbuf.value == NULL) ? GSS_C_NO_BUFFER : &ginbuf,
     120                 :             :                                                                         NULL,
     121                 :             :                                                                         &goutbuf,
     122                 :             :                                                                         NULL,
     123                 :             :                                                                         NULL);
     124                 :             : 
     125                 :           0 :         free(ginbuf.value);
     126                 :             : 
     127         [ #  # ]:           0 :         if (goutbuf.length != 0)
     128                 :             :         {
     129                 :             :                 /*
     130                 :             :                  * GSS generated data to send to the server. We don't care if it's the
     131                 :             :                  * first or subsequent packet, just send the same kind of password
     132                 :             :                  * packet.
     133                 :             :                  */
     134                 :           0 :                 conn->current_auth_response = AUTH_RESPONSE_GSS;
     135                 :           0 :                 if (pqPacketSend(conn, PqMsg_GSSResponse,
     136   [ #  #  #  # ]:           0 :                                                  goutbuf.value, goutbuf.length) != STATUS_OK)
     137                 :             :                 {
     138                 :           0 :                         gss_release_buffer(&lmin_s, &goutbuf);
     139                 :           0 :                         return STATUS_ERROR;
     140                 :             :                 }
     141                 :           0 :         }
     142                 :           0 :         gss_release_buffer(&lmin_s, &goutbuf);
     143                 :             : 
     144   [ #  #  #  # ]:           0 :         if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
     145                 :             :         {
     146                 :           0 :                 pg_GSS_error(libpq_gettext("GSSAPI continuation error"),
     147                 :           0 :                                          conn,
     148                 :           0 :                                          maj_stat, min_stat);
     149                 :           0 :                 gss_release_name(&lmin_s, &conn->gtarg_nam);
     150         [ #  # ]:           0 :                 if (conn->gctx)
     151                 :           0 :                         gss_delete_sec_context(&lmin_s, &conn->gctx, GSS_C_NO_BUFFER);
     152                 :           0 :                 return STATUS_ERROR;
     153                 :             :         }
     154                 :             : 
     155         [ #  # ]:           0 :         if (maj_stat == GSS_S_COMPLETE)
     156                 :             :         {
     157                 :           0 :                 conn->client_finished_auth = true;
     158                 :           0 :                 gss_release_name(&lmin_s, &conn->gtarg_nam);
     159                 :           0 :                 conn->gssapi_used = true;
     160                 :           0 :         }
     161                 :             : 
     162                 :           0 :         return STATUS_OK;
     163                 :           0 : }
     164                 :             : 
     165                 :             : /*
     166                 :             :  * Send initial GSS authentication token
     167                 :             :  */
     168                 :             : static int
     169                 :           0 : pg_GSS_startup(PGconn *conn, int payloadlen)
     170                 :             : {
     171                 :           0 :         int                     ret;
     172                 :           0 :         char       *host = conn->connhost[conn->whichhost].host;
     173                 :             : 
     174   [ #  #  #  # ]:           0 :         if (!(host && host[0] != '\0'))
     175                 :             :         {
     176                 :           0 :                 libpq_append_conn_error(conn, "host name must be specified");
     177                 :           0 :                 return STATUS_ERROR;
     178                 :             :         }
     179                 :             : 
     180         [ #  # ]:           0 :         if (conn->gctx)
     181                 :             :         {
     182                 :           0 :                 libpq_append_conn_error(conn, "duplicate GSS authentication request");
     183                 :           0 :                 return STATUS_ERROR;
     184                 :             :         }
     185                 :             : 
     186                 :           0 :         ret = pg_GSS_load_servicename(conn);
     187         [ #  # ]:           0 :         if (ret != STATUS_OK)
     188                 :           0 :                 return ret;
     189                 :             : 
     190                 :             :         /*
     191                 :             :          * Initial packet is the same as a continuation packet with no initial
     192                 :             :          * context.
     193                 :             :          */
     194                 :           0 :         conn->gctx = GSS_C_NO_CONTEXT;
     195                 :             : 
     196                 :           0 :         return pg_GSS_continue(conn, payloadlen);
     197                 :           0 : }
     198                 :             : #endif                                                  /* ENABLE_GSS */
     199                 :             : 
     200                 :             : 
     201                 :             : #ifdef ENABLE_SSPI
     202                 :             : /*
     203                 :             :  * SSPI authentication system (Windows only)
     204                 :             :  */
     205                 :             : 
     206                 :             : static void
     207                 :             : pg_SSPI_error(PGconn *conn, const char *mprefix, SECURITY_STATUS r)
     208                 :             : {
     209                 :             :         char            sysmsg[256];
     210                 :             : 
     211                 :             :         if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS |
     212                 :             :                                           FORMAT_MESSAGE_FROM_SYSTEM,
     213                 :             :                                           NULL, r, 0,
     214                 :             :                                           sysmsg, sizeof(sysmsg), NULL) == 0)
     215                 :             :                 appendPQExpBuffer(&conn->errorMessage, "%s: SSPI error %x\n",
     216                 :             :                                                   mprefix, (unsigned int) r);
     217                 :             :         else
     218                 :             :                 appendPQExpBuffer(&conn->errorMessage, "%s: %s (%x)\n",
     219                 :             :                                                   mprefix, sysmsg, (unsigned int) r);
     220                 :             : }
     221                 :             : 
     222                 :             : /*
     223                 :             :  * Continue SSPI authentication with next token as needed.
     224                 :             :  */
     225                 :             : static int
     226                 :             : pg_SSPI_continue(PGconn *conn, int payloadlen)
     227                 :             : {
     228                 :             :         SECURITY_STATUS r;
     229                 :             :         CtxtHandle      newContext;
     230                 :             :         ULONG           contextAttr;
     231                 :             :         SecBufferDesc inbuf;
     232                 :             :         SecBufferDesc outbuf;
     233                 :             :         SecBuffer       OutBuffers[1];
     234                 :             :         SecBuffer       InBuffers[1];
     235                 :             :         char       *inputbuf = NULL;
     236                 :             : 
     237                 :             :         if (conn->sspictx != NULL)
     238                 :             :         {
     239                 :             :                 /*
     240                 :             :                  * On runs other than the first we have some data to send. Put this
     241                 :             :                  * data in a SecBuffer type structure.
     242                 :             :                  */
     243                 :             :                 inputbuf = malloc(payloadlen);
     244                 :             :                 if (!inputbuf)
     245                 :             :                 {
     246                 :             :                         libpq_append_conn_error(conn, "out of memory allocating SSPI buffer (%d)",
     247                 :             :                                                                         payloadlen);
     248                 :             :                         return STATUS_ERROR;
     249                 :             :                 }
     250                 :             :                 if (pqGetnchar(inputbuf, payloadlen, conn))
     251                 :             :                 {
     252                 :             :                         /*
     253                 :             :                          * Shouldn't happen, because the caller should've ensured that the
     254                 :             :                          * whole message is already in the input buffer.
     255                 :             :                          */
     256                 :             :                         free(inputbuf);
     257                 :             :                         return STATUS_ERROR;
     258                 :             :                 }
     259                 :             : 
     260                 :             :                 inbuf.ulVersion = SECBUFFER_VERSION;
     261                 :             :                 inbuf.cBuffers = 1;
     262                 :             :                 inbuf.pBuffers = InBuffers;
     263                 :             :                 InBuffers[0].pvBuffer = inputbuf;
     264                 :             :                 InBuffers[0].cbBuffer = payloadlen;
     265                 :             :                 InBuffers[0].BufferType = SECBUFFER_TOKEN;
     266                 :             :         }
     267                 :             : 
     268                 :             :         /* finished parsing, trace server-to-client message */
     269                 :             :         if (conn->Pfdebug)
     270                 :             :                 pqTraceOutputMessage(conn, conn->inBuffer + conn->inStart, false);
     271                 :             : 
     272                 :             :         OutBuffers[0].pvBuffer = NULL;
     273                 :             :         OutBuffers[0].BufferType = SECBUFFER_TOKEN;
     274                 :             :         OutBuffers[0].cbBuffer = 0;
     275                 :             :         outbuf.cBuffers = 1;
     276                 :             :         outbuf.pBuffers = OutBuffers;
     277                 :             :         outbuf.ulVersion = SECBUFFER_VERSION;
     278                 :             : 
     279                 :             :         r = InitializeSecurityContext(conn->sspicred,
     280                 :             :                                                                   conn->sspictx,
     281                 :             :                                                                   conn->sspitarget,
     282                 :             :                                                                   ISC_REQ_ALLOCATE_MEMORY,
     283                 :             :                                                                   0,
     284                 :             :                                                                   SECURITY_NETWORK_DREP,
     285                 :             :                                                                   (conn->sspictx == NULL) ? NULL : &inbuf,
     286                 :             :                                                                   0,
     287                 :             :                                                                   &newContext,
     288                 :             :                                                                   &outbuf,
     289                 :             :                                                                   &contextAttr,
     290                 :             :                                                                   NULL);
     291                 :             : 
     292                 :             :         /* we don't need the input anymore */
     293                 :             :         free(inputbuf);
     294                 :             : 
     295                 :             :         if (r != SEC_E_OK && r != SEC_I_CONTINUE_NEEDED)
     296                 :             :         {
     297                 :             :                 pg_SSPI_error(conn, libpq_gettext("SSPI continuation error"), r);
     298                 :             : 
     299                 :             :                 return STATUS_ERROR;
     300                 :             :         }
     301                 :             : 
     302                 :             :         if (conn->sspictx == NULL)
     303                 :             :         {
     304                 :             :                 /* On first run, transfer retrieved context handle */
     305                 :             :                 conn->sspictx = malloc(sizeof(CtxtHandle));
     306                 :             :                 if (conn->sspictx == NULL)
     307                 :             :                 {
     308                 :             :                         libpq_append_conn_error(conn, "out of memory");
     309                 :             :                         return STATUS_ERROR;
     310                 :             :                 }
     311                 :             :                 memcpy(conn->sspictx, &newContext, sizeof(CtxtHandle));
     312                 :             :         }
     313                 :             : 
     314                 :             :         /*
     315                 :             :          * If SSPI returned any data to be sent to the server (as it normally
     316                 :             :          * would), send this data as a password packet.
     317                 :             :          */
     318                 :             :         if (outbuf.cBuffers > 0)
     319                 :             :         {
     320                 :             :                 if (outbuf.cBuffers != 1)
     321                 :             :                 {
     322                 :             :                         /*
     323                 :             :                          * This should never happen, at least not for Kerberos
     324                 :             :                          * authentication. Keep check in case it shows up with other
     325                 :             :                          * authentication methods later.
     326                 :             :                          */
     327                 :             :                         appendPQExpBufferStr(&conn->errorMessage,
     328                 :             :                                                                  "SSPI returned invalid number of output buffers\n");
     329                 :             :                         return STATUS_ERROR;
     330                 :             :                 }
     331                 :             : 
     332                 :             :                 /*
     333                 :             :                  * If the negotiation is complete, there may be zero bytes to send.
     334                 :             :                  * The server is at this point not expecting any more data, so don't
     335                 :             :                  * send it.
     336                 :             :                  */
     337                 :             :                 if (outbuf.pBuffers[0].cbBuffer > 0)
     338                 :             :                 {
     339                 :             :                         conn->current_auth_response = AUTH_RESPONSE_GSS;
     340                 :             :                         if (pqPacketSend(conn, PqMsg_GSSResponse,
     341                 :             :                                                          outbuf.pBuffers[0].pvBuffer, outbuf.pBuffers[0].cbBuffer))
     342                 :             :                         {
     343                 :             :                                 FreeContextBuffer(outbuf.pBuffers[0].pvBuffer);
     344                 :             :                                 return STATUS_ERROR;
     345                 :             :                         }
     346                 :             :                 }
     347                 :             :                 FreeContextBuffer(outbuf.pBuffers[0].pvBuffer);
     348                 :             :         }
     349                 :             : 
     350                 :             :         if (r == SEC_E_OK)
     351                 :             :                 conn->client_finished_auth = true;
     352                 :             : 
     353                 :             :         /* Cleanup is handled by the code in freePGconn() */
     354                 :             :         return STATUS_OK;
     355                 :             : }
     356                 :             : 
     357                 :             : /*
     358                 :             :  * Send initial SSPI authentication token.
     359                 :             :  * If use_negotiate is 0, use kerberos authentication package which is
     360                 :             :  * compatible with Unix. If use_negotiate is 1, use the negotiate package
     361                 :             :  * which supports both kerberos and NTLM, but is not compatible with Unix.
     362                 :             :  */
     363                 :             : static int
     364                 :             : pg_SSPI_startup(PGconn *conn, int use_negotiate, int payloadlen)
     365                 :             : {
     366                 :             :         SECURITY_STATUS r;
     367                 :             :         TimeStamp       expire;
     368                 :             :         char       *host = conn->connhost[conn->whichhost].host;
     369                 :             : 
     370                 :             :         if (conn->sspictx)
     371                 :             :         {
     372                 :             :                 libpq_append_conn_error(conn, "duplicate SSPI authentication request");
     373                 :             :                 return STATUS_ERROR;
     374                 :             :         }
     375                 :             : 
     376                 :             :         /*
     377                 :             :          * Retrieve credentials handle
     378                 :             :          */
     379                 :             :         conn->sspicred = malloc(sizeof(CredHandle));
     380                 :             :         if (conn->sspicred == NULL)
     381                 :             :         {
     382                 :             :                 libpq_append_conn_error(conn, "out of memory");
     383                 :             :                 return STATUS_ERROR;
     384                 :             :         }
     385                 :             : 
     386                 :             :         r = AcquireCredentialsHandle(NULL,
     387                 :             :                                                                  use_negotiate ? "negotiate" : "kerberos",
     388                 :             :                                                                  SECPKG_CRED_OUTBOUND,
     389                 :             :                                                                  NULL,
     390                 :             :                                                                  NULL,
     391                 :             :                                                                  NULL,
     392                 :             :                                                                  NULL,
     393                 :             :                                                                  conn->sspicred,
     394                 :             :                                                                  &expire);
     395                 :             :         if (r != SEC_E_OK)
     396                 :             :         {
     397                 :             :                 pg_SSPI_error(conn, libpq_gettext("could not acquire SSPI credentials"), r);
     398                 :             :                 free(conn->sspicred);
     399                 :             :                 conn->sspicred = NULL;
     400                 :             :                 return STATUS_ERROR;
     401                 :             :         }
     402                 :             : 
     403                 :             :         /*
     404                 :             :          * Compute target principal name. SSPI has a different format from GSSAPI,
     405                 :             :          * but not more complex. We can skip the @REALM part, because Windows will
     406                 :             :          * fill that in for us automatically.
     407                 :             :          */
     408                 :             :         if (!(host && host[0] != '\0'))
     409                 :             :         {
     410                 :             :                 libpq_append_conn_error(conn, "host name must be specified");
     411                 :             :                 return STATUS_ERROR;
     412                 :             :         }
     413                 :             :         conn->sspitarget = malloc(strlen(conn->krbsrvname) + strlen(host) + 2);
     414                 :             :         if (!conn->sspitarget)
     415                 :             :         {
     416                 :             :                 libpq_append_conn_error(conn, "out of memory");
     417                 :             :                 return STATUS_ERROR;
     418                 :             :         }
     419                 :             :         sprintf(conn->sspitarget, "%s/%s", conn->krbsrvname, host);
     420                 :             : 
     421                 :             :         /*
     422                 :             :          * Indicate that we're in SSPI authentication mode to make sure that
     423                 :             :          * pg_SSPI_continue is called next time in the negotiation.
     424                 :             :          */
     425                 :             :         conn->usesspi = 1;
     426                 :             : 
     427                 :             :         return pg_SSPI_continue(conn, payloadlen);
     428                 :             : }
     429                 :             : #endif                                                  /* ENABLE_SSPI */
     430                 :             : 
     431                 :             : /*
     432                 :             :  * Initialize SASL authentication exchange.
     433                 :             :  */
     434                 :             : static int
     435                 :           0 : pg_SASL_init(PGconn *conn, int payloadlen, bool *async)
     436                 :             : {
     437                 :           0 :         char       *initialresponse = NULL;
     438                 :           0 :         int                     initialresponselen;
     439                 :           0 :         const char *selected_mechanism;
     440                 :           0 :         PQExpBufferData mechanism_buf;
     441                 :           0 :         char       *password = NULL;
     442                 :           0 :         SASLStatus      status;
     443                 :             : 
     444                 :           0 :         initPQExpBuffer(&mechanism_buf);
     445                 :             : 
     446   [ #  #  #  # ]:           0 :         if (conn->channel_binding[0] == 'r' &&       /* require */
     447                 :           0 :                 !conn->ssl_in_use)
     448                 :             :         {
     449                 :           0 :                 libpq_append_conn_error(conn, "channel binding required, but SSL not in use");
     450                 :           0 :                 goto error;
     451                 :             :         }
     452                 :             : 
     453   [ #  #  #  # ]:           0 :         if (conn->sasl_state && !conn->async_auth)
     454                 :             :         {
     455                 :           0 :                 libpq_append_conn_error(conn, "duplicate SASL authentication request");
     456                 :           0 :                 goto error;
     457                 :             :         }
     458                 :             : 
     459                 :             :         /*
     460                 :             :          * Parse the list of SASL authentication mechanisms in the
     461                 :             :          * AuthenticationSASL message, and select the best mechanism that we
     462                 :             :          * support. Mechanisms are listed by order of decreasing importance.
     463                 :             :          */
     464                 :           0 :         selected_mechanism = NULL;
     465                 :           0 :         for (;;)
     466                 :             :         {
     467         [ #  # ]:           0 :                 if (pqGets(&mechanism_buf, conn))
     468                 :             :                 {
     469                 :           0 :                         appendPQExpBufferStr(&conn->errorMessage,
     470                 :             :                                                                  "fe_sendauth: invalid authentication request from server: invalid list of authentication mechanisms\n");
     471                 :           0 :                         goto error;
     472                 :             :                 }
     473         [ #  # ]:           0 :                 if (PQExpBufferDataBroken(mechanism_buf))
     474                 :           0 :                         goto oom_error;
     475                 :             : 
     476                 :             :                 /* An empty string indicates end of list */
     477         [ #  # ]:           0 :                 if (mechanism_buf.data[0] == '\0')
     478                 :           0 :                         break;
     479                 :             : 
     480                 :             :                 /*
     481                 :             :                  * Select the mechanism to use.  Pick SCRAM-SHA-256-PLUS over anything
     482                 :             :                  * else if a channel binding type is set and if the client supports it
     483                 :             :                  * (and did not set channel_binding=disable). Pick SCRAM-SHA-256 if
     484                 :             :                  * nothing else has already been picked.  If we add more mechanisms, a
     485                 :             :                  * more refined priority mechanism might become necessary.
     486                 :             :                  */
     487         [ #  # ]:           0 :                 if (strcmp(mechanism_buf.data, SCRAM_SHA_256_PLUS_NAME) == 0)
     488                 :             :                 {
     489         [ #  # ]:           0 :                         if (conn->ssl_in_use)
     490                 :             :                         {
     491                 :             :                                 /* The server has offered SCRAM-SHA-256-PLUS. */
     492                 :             : 
     493                 :             : #ifdef USE_SSL
     494                 :             :                                 /*
     495                 :             :                                  * The client supports channel binding, which is chosen if
     496                 :             :                                  * channel_binding is not disabled.
     497                 :             :                                  */
     498         [ #  # ]:           0 :                                 if (conn->channel_binding[0] != 'd') /* disable */
     499                 :             :                                 {
     500                 :           0 :                                         selected_mechanism = SCRAM_SHA_256_PLUS_NAME;
     501                 :           0 :                                         conn->sasl = &pg_scram_mech;
     502                 :           0 :                                         conn->password_needed = true;
     503                 :           0 :                                 }
     504                 :             : #else
     505                 :             :                                 /*
     506                 :             :                                  * The client does not support channel binding.  If it is
     507                 :             :                                  * required, complain immediately instead of the error below
     508                 :             :                                  * which would be confusing as the server is publishing
     509                 :             :                                  * SCRAM-SHA-256-PLUS.
     510                 :             :                                  */
     511                 :             :                                 if (conn->channel_binding[0] == 'r') /* require */
     512                 :             :                                 {
     513                 :             :                                         libpq_append_conn_error(conn, "channel binding is required, but client does not support it");
     514                 :             :                                         goto error;
     515                 :             :                                 }
     516                 :             : #endif
     517                 :           0 :                         }
     518                 :             :                         else
     519                 :             :                         {
     520                 :             :                                 /*
     521                 :             :                                  * The server offered SCRAM-SHA-256-PLUS, but the connection
     522                 :             :                                  * is not SSL-encrypted. That's not sane. Perhaps SSL was
     523                 :             :                                  * stripped by a proxy? There's no point in continuing,
     524                 :             :                                  * because the server will reject the connection anyway if we
     525                 :             :                                  * try authenticate without channel binding even though both
     526                 :             :                                  * the client and server supported it. The SCRAM exchange
     527                 :             :                                  * checks for that, to prevent downgrade attacks.
     528                 :             :                                  */
     529                 :           0 :                                 libpq_append_conn_error(conn, "server offered SCRAM-SHA-256-PLUS authentication over a non-SSL connection");
     530                 :           0 :                                 goto error;
     531                 :             :                         }
     532                 :           0 :                 }
     533   [ #  #  #  # ]:           0 :                 else if (strcmp(mechanism_buf.data, SCRAM_SHA_256_NAME) == 0 &&
     534                 :           0 :                                  !selected_mechanism)
     535                 :             :                 {
     536                 :           0 :                         selected_mechanism = SCRAM_SHA_256_NAME;
     537                 :           0 :                         conn->sasl = &pg_scram_mech;
     538                 :           0 :                         conn->password_needed = true;
     539                 :           0 :                 }
     540   [ #  #  #  # ]:           0 :                 else if (strcmp(mechanism_buf.data, OAUTHBEARER_NAME) == 0 &&
     541                 :           0 :                                  !selected_mechanism)
     542                 :             :                 {
     543                 :           0 :                         selected_mechanism = OAUTHBEARER_NAME;
     544                 :           0 :                         conn->sasl = &pg_oauth_mech;
     545                 :           0 :                         conn->password_needed = false;
     546                 :           0 :                 }
     547                 :             :         }
     548                 :             : 
     549         [ #  # ]:           0 :         if (!selected_mechanism)
     550                 :             :         {
     551                 :           0 :                 libpq_append_conn_error(conn, "none of the server's SASL authentication mechanisms are supported");
     552                 :           0 :                 goto error;
     553                 :             :         }
     554                 :             : 
     555                 :             :         /* Make sure require_auth is satisfied. */
     556         [ #  # ]:           0 :         if (conn->require_auth)
     557                 :             :         {
     558                 :           0 :                 bool            allowed = false;
     559                 :             : 
     560         [ #  # ]:           0 :                 for (int i = 0; i < lengthof(conn->allowed_sasl_mechs); i++)
     561                 :             :                 {
     562         [ #  # ]:           0 :                         if (conn->sasl == conn->allowed_sasl_mechs[i])
     563                 :             :                         {
     564                 :           0 :                                 allowed = true;
     565                 :           0 :                                 break;
     566                 :             :                         }
     567                 :           0 :                 }
     568                 :             : 
     569         [ #  # ]:           0 :                 if (!allowed)
     570                 :             :                 {
     571                 :           0 :                         libpq_append_conn_error(conn, "authentication method requirement \"%s\" failed: server requested %s authentication",
     572                 :           0 :                                                                         conn->require_auth, selected_mechanism);
     573                 :           0 :                         goto error;
     574                 :             :                 }
     575      [ #  #  # ]:           0 :         }
     576                 :             : 
     577   [ #  #  #  # ]:           0 :         if (conn->channel_binding[0] == 'r' &&       /* require */
     578                 :           0 :                 strcmp(selected_mechanism, SCRAM_SHA_256_PLUS_NAME) != 0)
     579                 :             :         {
     580                 :           0 :                 libpq_append_conn_error(conn, "channel binding is required, but server did not offer an authentication method that supports channel binding");
     581                 :           0 :                 goto error;
     582                 :             :         }
     583                 :             : 
     584                 :             :         /*
     585                 :             :          * Now that the SASL mechanism has been chosen for the exchange,
     586                 :             :          * initialize its state information.
     587                 :             :          */
     588                 :             : 
     589                 :             :         /*
     590                 :             :          * First, select the password to use for the exchange, complaining if
     591                 :             :          * there isn't one and the selected SASL mechanism needs it.
     592                 :             :          */
     593   [ #  #  #  # ]:           0 :         if (conn->password_needed && !conn->scram_client_key_binary)
     594                 :             :         {
     595                 :           0 :                 password = conn->connhost[conn->whichhost].password;
     596         [ #  # ]:           0 :                 if (password == NULL)
     597                 :           0 :                         password = conn->pgpass;
     598   [ #  #  #  # ]:           0 :                 if (password == NULL || password[0] == '\0')
     599                 :             :                 {
     600                 :           0 :                         appendPQExpBufferStr(&conn->errorMessage,
     601                 :             :                                                                  PQnoPasswordSupplied);
     602                 :           0 :                         goto error;
     603                 :             :                 }
     604                 :           0 :         }
     605                 :             : 
     606                 :             :         /* finished parsing, trace server-to-client message */
     607         [ #  # ]:           0 :         if (conn->Pfdebug)
     608                 :           0 :                 pqTraceOutputMessage(conn, conn->inBuffer + conn->inStart, false);
     609                 :             : 
     610         [ #  # ]:           0 :         Assert(conn->sasl);
     611                 :             : 
     612         [ #  # ]:           0 :         if (!conn->sasl_state)
     613                 :             :         {
     614                 :             :                 /*
     615                 :             :                  * Initialize the SASL state information with all the information
     616                 :             :                  * gathered during the initial exchange.
     617                 :             :                  *
     618                 :             :                  * Note: Only tls-unique is supported for the moment.
     619                 :             :                  */
     620                 :           0 :                 conn->sasl_state = conn->sasl->init(conn,
     621                 :           0 :                                                                                         password,
     622                 :           0 :                                                                                         selected_mechanism);
     623         [ #  # ]:           0 :                 if (!conn->sasl_state)
     624                 :           0 :                         goto oom_error;
     625                 :           0 :         }
     626                 :             :         else
     627                 :             :         {
     628                 :             :                 /*
     629                 :             :                  * This is only possible if we're returning from an async loop.
     630                 :             :                  * Disconnect it now.
     631                 :             :                  */
     632         [ #  # ]:           0 :                 Assert(conn->async_auth);
     633                 :           0 :                 conn->async_auth = NULL;
     634                 :             :         }
     635                 :             : 
     636                 :             :         /* Get the mechanism-specific Initial Client Response, if any */
     637                 :           0 :         status = conn->sasl->exchange(conn->sasl_state, false,
     638                 :             :                                                                   NULL, -1,
     639                 :             :                                                                   &initialresponse, &initialresponselen);
     640                 :             : 
     641         [ #  # ]:           0 :         if (status == SASL_FAILED)
     642                 :           0 :                 goto error;
     643                 :             : 
     644         [ #  # ]:           0 :         if (status == SASL_ASYNC)
     645                 :             :         {
     646                 :             :                 /*
     647                 :             :                  * The mechanism should have set up the necessary callbacks; all we
     648                 :             :                  * need to do is signal the caller.
     649                 :             :                  *
     650                 :             :                  * In non-assertion builds, this postcondition is enforced at time of
     651                 :             :                  * use in PQconnectPoll().
     652                 :             :                  */
     653         [ #  # ]:           0 :                 Assert(conn->async_auth);
     654         [ #  # ]:           0 :                 Assert(conn->cleanup_async_auth);
     655                 :             : 
     656                 :           0 :                 *async = true;
     657                 :           0 :                 return STATUS_OK;
     658                 :             :         }
     659                 :             : 
     660                 :             :         /*
     661                 :             :          * Build a SASLInitialResponse message, and send it.
     662                 :             :          */
     663         [ #  # ]:           0 :         if (pqPutMsgStart(PqMsg_SASLInitialResponse, conn))
     664                 :           0 :                 goto error;
     665         [ #  # ]:           0 :         if (pqPuts(selected_mechanism, conn))
     666                 :           0 :                 goto error;
     667         [ #  # ]:           0 :         if (initialresponse)
     668                 :             :         {
     669         [ #  # ]:           0 :                 if (pqPutInt(initialresponselen, 4, conn))
     670                 :           0 :                         goto error;
     671         [ #  # ]:           0 :                 if (pqPutnchar(initialresponse, initialresponselen, conn))
     672                 :           0 :                         goto error;
     673                 :           0 :         }
     674                 :           0 :         conn->current_auth_response = AUTH_RESPONSE_SASL_INITIAL;
     675         [ #  # ]:           0 :         if (pqPutMsgEnd(conn))
     676                 :           0 :                 goto error;
     677                 :             : 
     678         [ #  # ]:           0 :         if (pqFlush(conn))
     679                 :           0 :                 goto error;
     680                 :             : 
     681                 :           0 :         termPQExpBuffer(&mechanism_buf);
     682                 :           0 :         free(initialresponse);
     683                 :             : 
     684                 :           0 :         return STATUS_OK;
     685                 :             : 
     686                 :             : error:
     687                 :           0 :         termPQExpBuffer(&mechanism_buf);
     688                 :           0 :         free(initialresponse);
     689                 :           0 :         return STATUS_ERROR;
     690                 :             : 
     691                 :             : oom_error:
     692                 :           0 :         termPQExpBuffer(&mechanism_buf);
     693                 :           0 :         free(initialresponse);
     694                 :           0 :         libpq_append_conn_error(conn, "out of memory");
     695                 :           0 :         return STATUS_ERROR;
     696                 :           0 : }
     697                 :             : 
     698                 :             : /*
     699                 :             :  * Exchange a message for SASL communication protocol with the backend.
     700                 :             :  * This should be used after calling pg_SASL_init to set up the status of
     701                 :             :  * the protocol.
     702                 :             :  */
     703                 :             : static int
     704                 :           0 : pg_SASL_continue(PGconn *conn, int payloadlen, bool final, bool *async)
     705                 :             : {
     706                 :           0 :         char       *output;
     707                 :           0 :         int                     outputlen;
     708                 :           0 :         int                     res;
     709                 :           0 :         char       *challenge;
     710                 :           0 :         SASLStatus      status;
     711                 :             : 
     712                 :             :         /* Read the SASL challenge from the AuthenticationSASLContinue message. */
     713                 :           0 :         challenge = malloc(payloadlen + 1);
     714         [ #  # ]:           0 :         if (!challenge)
     715                 :             :         {
     716                 :           0 :                 libpq_append_conn_error(conn, "out of memory allocating SASL buffer (%d)",
     717                 :           0 :                                                                 payloadlen);
     718                 :           0 :                 return STATUS_ERROR;
     719                 :             :         }
     720                 :             : 
     721         [ #  # ]:           0 :         if (pqGetnchar(challenge, payloadlen, conn))
     722                 :             :         {
     723                 :           0 :                 free(challenge);
     724                 :           0 :                 return STATUS_ERROR;
     725                 :             :         }
     726                 :             : 
     727                 :             :         /* finished parsing, trace server-to-client message */
     728         [ #  # ]:           0 :         if (conn->Pfdebug)
     729                 :           0 :                 pqTraceOutputMessage(conn, conn->inBuffer + conn->inStart, false);
     730                 :             : 
     731                 :             :         /* For safety and convenience, ensure the buffer is NULL-terminated. */
     732                 :           0 :         challenge[payloadlen] = '\0';
     733                 :             : 
     734                 :           0 :         status = conn->sasl->exchange(conn->sasl_state, final,
     735                 :           0 :                                                                   challenge, payloadlen,
     736                 :             :                                                                   &output, &outputlen);
     737                 :           0 :         free(challenge);                        /* don't need the input anymore */
     738                 :             : 
     739         [ #  # ]:           0 :         if (status == SASL_ASYNC)
     740                 :             :         {
     741                 :             :                 /*
     742                 :             :                  * The mechanism should have set up the necessary callbacks; all we
     743                 :             :                  * need to do is signal the caller.
     744                 :             :                  */
     745                 :           0 :                 *async = true;
     746                 :             : 
     747                 :             :                 /*
     748                 :             :                  * The mechanism may optionally generate some output to send before
     749                 :             :                  * switching over to async auth, so continue onwards.
     750                 :             :                  */
     751                 :           0 :         }
     752                 :             : 
     753   [ #  #  #  # ]:           0 :         if (final && status == SASL_CONTINUE)
     754                 :             :         {
     755         [ #  # ]:           0 :                 if (outputlen != 0)
     756                 :           0 :                         free(output);
     757                 :             : 
     758                 :           0 :                 libpq_append_conn_error(conn, "AuthenticationSASLFinal received from server, but SASL authentication was not completed");
     759                 :           0 :                 return STATUS_ERROR;
     760                 :             :         }
     761                 :             : 
     762                 :             :         /*
     763                 :             :          * If the exchange is not completed yet, we need to make sure that the
     764                 :             :          * SASL mechanism has generated a message to send back.
     765                 :             :          */
     766   [ #  #  #  # ]:           0 :         if (output == NULL && status == SASL_CONTINUE)
     767                 :             :         {
     768                 :           0 :                 libpq_append_conn_error(conn, "no client response found after SASL exchange success");
     769                 :           0 :                 return STATUS_ERROR;
     770                 :             :         }
     771                 :             : 
     772                 :             :         /*
     773                 :             :          * SASL allows zero-length responses, so this check uses "output" and not
     774                 :             :          * "outputlen" to allow the case of an empty message.
     775                 :             :          */
     776         [ #  # ]:           0 :         if (output)
     777                 :             :         {
     778                 :             :                 /*
     779                 :             :                  * Send the SASL response to the server.
     780                 :             :                  */
     781                 :           0 :                 conn->current_auth_response = AUTH_RESPONSE_SASL;
     782                 :           0 :                 res = pqPacketSend(conn, PqMsg_SASLResponse, output, outputlen);
     783                 :           0 :                 free(output);
     784                 :             : 
     785         [ #  # ]:           0 :                 if (res != STATUS_OK)
     786                 :           0 :                         return STATUS_ERROR;
     787                 :           0 :         }
     788                 :             : 
     789         [ #  # ]:           0 :         if (status == SASL_FAILED)
     790                 :           0 :                 return STATUS_ERROR;
     791                 :             : 
     792                 :           0 :         return STATUS_OK;
     793                 :           0 : }
     794                 :             : 
     795                 :             : static int
     796                 :           0 : pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq)
     797                 :             : {
     798                 :           0 :         int                     ret;
     799                 :           0 :         char       *crypt_pwd = NULL;
     800                 :           0 :         const char *pwd_to_send;
     801                 :           0 :         uint8           md5Salt[4];
     802                 :             : 
     803                 :             :         /* Read the salt from the AuthenticationMD5Password message. */
     804         [ #  # ]:           0 :         if (areq == AUTH_REQ_MD5)
     805                 :             :         {
     806         [ #  # ]:           0 :                 if (pqGetnchar(md5Salt, 4, conn))
     807                 :           0 :                         return STATUS_ERROR;    /* shouldn't happen */
     808                 :           0 :         }
     809                 :             : 
     810                 :             :         /* finished parsing, trace server-to-client message */
     811         [ #  # ]:           0 :         if (conn->Pfdebug)
     812                 :           0 :                 pqTraceOutputMessage(conn, conn->inBuffer + conn->inStart, false);
     813                 :             : 
     814                 :             :         /* Encrypt the password if needed. */
     815                 :             : 
     816      [ #  #  # ]:           0 :         switch (areq)
     817                 :             :         {
     818                 :             :                 case AUTH_REQ_MD5:
     819                 :             :                         {
     820                 :           0 :                                 char       *crypt_pwd2;
     821                 :           0 :                                 const char *errstr = NULL;
     822                 :             : 
     823                 :             :                                 /* Allocate enough space for two MD5 hashes */
     824                 :           0 :                                 crypt_pwd = malloc(2 * (MD5_PASSWD_LEN + 1));
     825         [ #  # ]:           0 :                                 if (!crypt_pwd)
     826                 :             :                                 {
     827                 :           0 :                                         libpq_append_conn_error(conn, "out of memory");
     828                 :           0 :                                         return STATUS_ERROR;
     829                 :             :                                 }
     830                 :             : 
     831                 :           0 :                                 crypt_pwd2 = crypt_pwd + MD5_PASSWD_LEN + 1;
     832   [ #  #  #  # ]:           0 :                                 if (!pg_md5_encrypt(password, (uint8 *) conn->pguser,
     833                 :           0 :                                                                         strlen(conn->pguser), crypt_pwd2,
     834                 :             :                                                                         &errstr))
     835                 :             :                                 {
     836                 :           0 :                                         libpq_append_conn_error(conn, "could not encrypt password: %s", errstr);
     837                 :           0 :                                         free(crypt_pwd);
     838                 :           0 :                                         return STATUS_ERROR;
     839                 :             :                                 }
     840   [ #  #  #  # ]:           0 :                                 if (!pg_md5_encrypt(crypt_pwd2 + strlen("md5"), md5Salt,
     841                 :           0 :                                                                         4, crypt_pwd, &errstr))
     842                 :             :                                 {
     843                 :           0 :                                         libpq_append_conn_error(conn, "could not encrypt password: %s", errstr);
     844                 :           0 :                                         free(crypt_pwd);
     845                 :           0 :                                         return STATUS_ERROR;
     846                 :             :                                 }
     847                 :             : 
     848                 :           0 :                                 pwd_to_send = crypt_pwd;
     849                 :           0 :                                 break;
     850         [ #  # ]:           0 :                         }
     851                 :             :                 case AUTH_REQ_PASSWORD:
     852                 :           0 :                         pwd_to_send = password;
     853                 :           0 :                         break;
     854                 :             :                 default:
     855                 :           0 :                         return STATUS_ERROR;
     856                 :             :         }
     857                 :           0 :         conn->current_auth_response = AUTH_RESPONSE_PASSWORD;
     858                 :           0 :         ret = pqPacketSend(conn, PqMsg_PasswordMessage,
     859                 :           0 :                                            pwd_to_send, strlen(pwd_to_send) + 1);
     860                 :           0 :         free(crypt_pwd);
     861                 :           0 :         return ret;
     862                 :           0 : }
     863                 :             : 
     864                 :             : /*
     865                 :             :  * Translate a disallowed AuthRequest code into an error message.
     866                 :             :  */
     867                 :             : static const char *
     868                 :           0 : auth_method_description(AuthRequest areq)
     869                 :             : {
     870   [ #  #  #  #  :           0 :         switch (areq)
                   #  # ]
     871                 :             :         {
     872                 :             :                 case AUTH_REQ_PASSWORD:
     873                 :           0 :                         return libpq_gettext("server requested a cleartext password");
     874                 :             :                 case AUTH_REQ_MD5:
     875                 :           0 :                         return libpq_gettext("server requested a hashed password");
     876                 :             :                 case AUTH_REQ_GSS:
     877                 :             :                 case AUTH_REQ_GSS_CONT:
     878                 :           0 :                         return libpq_gettext("server requested GSSAPI authentication");
     879                 :             :                 case AUTH_REQ_SSPI:
     880                 :           0 :                         return libpq_gettext("server requested SSPI authentication");
     881                 :             :                 case AUTH_REQ_SASL:
     882                 :             :                 case AUTH_REQ_SASL_CONT:
     883                 :             :                 case AUTH_REQ_SASL_FIN:
     884                 :           0 :                         return libpq_gettext("server requested SASL authentication");
     885                 :             :         }
     886                 :             : 
     887                 :           0 :         return libpq_gettext("server requested an unknown authentication type");
     888                 :           0 : }
     889                 :             : 
     890                 :             : /*
     891                 :             :  * Convenience macro for checking the allowed_auth_methods bitmask.  Caller
     892                 :             :  * must ensure that type is not greater than 31 (high bit of the bitmask).
     893                 :             :  */
     894                 :             : #define auth_method_allowed(conn, type) \
     895                 :             :         (((conn)->allowed_auth_methods & (1 << (type))) != 0)
     896                 :             : 
     897                 :             : /*
     898                 :             :  * Verify that the authentication request is expected, given the connection
     899                 :             :  * parameters. This is especially important when the client wishes to
     900                 :             :  * authenticate the server before any sensitive information is exchanged.
     901                 :             :  */
     902                 :             : static bool
     903                 :         316 : check_expected_areq(AuthRequest areq, PGconn *conn)
     904                 :             : {
     905                 :         316 :         bool            result = true;
     906                 :         316 :         const char *reason = NULL;
     907                 :             : 
     908                 :             :         StaticAssertDecl((sizeof(conn->allowed_auth_methods) * CHAR_BIT) > AUTH_REQ_MAX,
     909                 :             :                                          "AUTH_REQ_MAX overflows the allowed_auth_methods bitmask");
     910                 :             : 
     911                 :         316 :         if (conn->sslcertmode[0] == 'r' /* require */
     912   [ -  +  #  # ]:         316 :                 && areq == AUTH_REQ_OK)
     913                 :             :         {
     914                 :             :                 /*
     915                 :             :                  * Trade off a little bit of complexity to try to get these error
     916                 :             :                  * messages as precise as possible.
     917                 :             :                  */
     918         [ #  # ]:           0 :                 if (!conn->ssl_cert_requested)
     919                 :             :                 {
     920                 :           0 :                         libpq_append_conn_error(conn, "server did not request an SSL certificate");
     921                 :           0 :                         return false;
     922                 :             :                 }
     923         [ #  # ]:           0 :                 else if (!conn->ssl_cert_sent)
     924                 :             :                 {
     925                 :           0 :                         libpq_append_conn_error(conn, "server accepted connection without a valid SSL certificate");
     926                 :           0 :                         return false;
     927                 :             :                 }
     928                 :           0 :         }
     929                 :             : 
     930                 :             :         /*
     931                 :             :          * If the user required a specific auth method, or specified an allowed
     932                 :             :          * set, then reject all others here, and make sure the server actually
     933                 :             :          * completes an authentication exchange.
     934                 :             :          */
     935         [ +  - ]:         316 :         if (conn->require_auth)
     936                 :             :         {
     937      [ #  #  # ]:           0 :                 switch (areq)
     938                 :             :                 {
     939                 :             :                         case AUTH_REQ_OK:
     940                 :             : 
     941                 :             :                                 /*
     942                 :             :                                  * Check to make sure we've actually finished our exchange (or
     943                 :             :                                  * else that the user has allowed an authentication-less
     944                 :             :                                  * connection).
     945                 :             :                                  *
     946                 :             :                                  * If the user has allowed both SCRAM and unauthenticated
     947                 :             :                                  * (trust) connections, then this check will silently accept
     948                 :             :                                  * partial SCRAM exchanges, where a misbehaving server does
     949                 :             :                                  * not provide its verifier before sending an OK.  This is
     950                 :             :                                  * consistent with historical behavior, but it may be a point
     951                 :             :                                  * to revisit in the future, since it could allow a server
     952                 :             :                                  * that doesn't know the user's password to silently harvest
     953                 :             :                                  * material for a brute force attack.
     954                 :             :                                  */
     955   [ #  #  #  # ]:           0 :                                 if (!conn->auth_required || conn->client_finished_auth)
     956                 :           0 :                                         break;
     957                 :             : 
     958                 :             :                                 /*
     959                 :             :                                  * No explicit authentication request was made by the server
     960                 :             :                                  * -- or perhaps it was made and not completed, in the case of
     961                 :             :                                  * SCRAM -- but there is one special case to check.  If the
     962                 :             :                                  * user allowed "gss", then a GSS-encrypted channel also
     963                 :             :                                  * satisfies the check.
     964                 :             :                                  */
     965                 :             : #ifdef ENABLE_GSS
     966   [ #  #  #  # ]:           0 :                                 if (auth_method_allowed(conn, AUTH_REQ_GSS) && conn->gssenc)
     967                 :             :                                 {
     968                 :             :                                         /*
     969                 :             :                                          * If implicit GSS auth has already been performed via GSS
     970                 :             :                                          * encryption, we don't need to have performed an
     971                 :             :                                          * AUTH_REQ_GSS exchange.  This allows require_auth=gss to
     972                 :             :                                          * be combined with gssencmode, since there won't be an
     973                 :             :                                          * explicit authentication request in that case.
     974                 :             :                                          */
     975                 :           0 :                                 }
     976                 :             :                                 else
     977                 :             : #endif
     978                 :             :                                 {
     979                 :           0 :                                         reason = libpq_gettext("server did not complete authentication");
     980                 :           0 :                                         result = false;
     981                 :             :                                 }
     982                 :             : 
     983                 :           0 :                                 break;
     984                 :             : 
     985                 :             :                         case AUTH_REQ_PASSWORD:
     986                 :             :                         case AUTH_REQ_MD5:
     987                 :             :                         case AUTH_REQ_GSS:
     988                 :             :                         case AUTH_REQ_GSS_CONT:
     989                 :             :                         case AUTH_REQ_SSPI:
     990                 :             :                         case AUTH_REQ_SASL:
     991                 :             :                         case AUTH_REQ_SASL_CONT:
     992                 :             :                         case AUTH_REQ_SASL_FIN:
     993                 :             : 
     994                 :             :                                 /*
     995                 :             :                                  * We don't handle these with the default case, to avoid
     996                 :             :                                  * bit-shifting past the end of the allowed_auth_methods mask
     997                 :             :                                  * if the server sends an unexpected AuthRequest.
     998                 :             :                                  */
     999                 :           0 :                                 result = auth_method_allowed(conn, areq);
    1000                 :           0 :                                 break;
    1001                 :             : 
    1002                 :             :                         default:
    1003                 :           0 :                                 result = false;
    1004                 :           0 :                                 break;
    1005                 :             :                 }
    1006                 :           0 :         }
    1007                 :             : 
    1008         [ +  - ]:         316 :         if (!result)
    1009                 :             :         {
    1010         [ #  # ]:           0 :                 if (!reason)
    1011                 :           0 :                         reason = auth_method_description(areq);
    1012                 :             : 
    1013                 :           0 :                 libpq_append_conn_error(conn, "authentication method requirement \"%s\" failed: %s",
    1014                 :           0 :                                                                 conn->require_auth, reason);
    1015                 :           0 :                 return result;
    1016                 :             :         }
    1017                 :             : 
    1018                 :             :         /*
    1019                 :             :          * When channel_binding=require, we must protect against two cases: (1) we
    1020                 :             :          * must not respond to non-SASL authentication requests, which might leak
    1021                 :             :          * information such as the client's password; and (2) even if we receive
    1022                 :             :          * AUTH_REQ_OK, we still must ensure that channel binding has happened in
    1023                 :             :          * order to authenticate the server.
    1024                 :             :          */
    1025         [ +  - ]:         316 :         if (conn->channel_binding[0] == 'r' /* require */ )
    1026                 :             :         {
    1027      [ #  #  # ]:           0 :                 switch (areq)
    1028                 :             :                 {
    1029                 :             :                         case AUTH_REQ_SASL:
    1030                 :             :                         case AUTH_REQ_SASL_CONT:
    1031                 :             :                         case AUTH_REQ_SASL_FIN:
    1032                 :           0 :                                 break;
    1033                 :             :                         case AUTH_REQ_OK:
    1034   [ #  #  #  # ]:           0 :                                 if (!conn->sasl || !conn->sasl->channel_bound(conn->sasl_state))
    1035                 :             :                                 {
    1036                 :           0 :                                         libpq_append_conn_error(conn, "channel binding required, but server authenticated client without channel binding");
    1037                 :           0 :                                         result = false;
    1038                 :           0 :                                 }
    1039                 :           0 :                                 break;
    1040                 :             :                         default:
    1041                 :           0 :                                 libpq_append_conn_error(conn, "channel binding required but not supported by server's authentication request");
    1042                 :           0 :                                 result = false;
    1043                 :           0 :                                 break;
    1044                 :             :                 }
    1045                 :           0 :         }
    1046                 :             : 
    1047                 :         316 :         return result;
    1048                 :         316 : }
    1049                 :             : 
    1050                 :             : /*
    1051                 :             :  * pg_fe_sendauth
    1052                 :             :  *              client demux routine for processing an authentication request
    1053                 :             :  *
    1054                 :             :  * The server has sent us an authentication challenge (or OK). Send an
    1055                 :             :  * appropriate response. The caller has ensured that the whole message is
    1056                 :             :  * now in the input buffer, and has already read the type and length of
    1057                 :             :  * it. We are responsible for reading any remaining extra data, specific
    1058                 :             :  * to the authentication method. 'payloadlen' is the remaining length in
    1059                 :             :  * the message.
    1060                 :             :  *
    1061                 :             :  * If *async is set to true on return, the client doesn't yet have enough
    1062                 :             :  * information to respond, and the caller must temporarily switch to
    1063                 :             :  * conn->async_auth() to continue driving the exchange.
    1064                 :             :  */
    1065                 :             : int
    1066                 :         316 : pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn, bool *async)
    1067                 :             : {
    1068                 :         316 :         int                     oldmsglen;
    1069                 :             : 
    1070                 :         316 :         *async = false;
    1071                 :             : 
    1072         [ +  - ]:         316 :         if (!check_expected_areq(areq, conn))
    1073                 :           0 :                 return STATUS_ERROR;
    1074                 :             : 
    1075   [ -  -  -  +  :         316 :         switch (areq)
          -  -  -  -  -  
                      - ]
    1076                 :             :         {
    1077                 :             :                 case AUTH_REQ_OK:
    1078                 :             :                         break;
    1079                 :             : 
    1080                 :             :                 case AUTH_REQ_KRB4:
    1081                 :           0 :                         libpq_append_conn_error(conn, "Kerberos 4 authentication not supported");
    1082                 :           0 :                         return STATUS_ERROR;
    1083                 :             : 
    1084                 :             :                 case AUTH_REQ_KRB5:
    1085                 :           0 :                         libpq_append_conn_error(conn, "Kerberos 5 authentication not supported");
    1086                 :           0 :                         return STATUS_ERROR;
    1087                 :             : 
    1088                 :             : #if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
    1089                 :             :                 case AUTH_REQ_GSS:
    1090                 :             : #if !defined(ENABLE_SSPI)
    1091                 :             :                         /* no native SSPI, so use GSSAPI library for it */
    1092                 :             :                 case AUTH_REQ_SSPI:
    1093                 :             : #endif
    1094                 :             :                         {
    1095                 :           0 :                                 int                     r;
    1096                 :             : 
    1097                 :           0 :                                 pglock_thread();
    1098                 :             : 
    1099                 :             :                                 /*
    1100                 :             :                                  * If we have both GSS and SSPI support compiled in, use SSPI
    1101                 :             :                                  * support by default. This is overridable by a connection
    1102                 :             :                                  * string parameter. Note that when using SSPI we still leave
    1103                 :             :                                  * the negotiate parameter off, since we want SSPI to use the
    1104                 :             :                                  * GSSAPI kerberos protocol. For actual SSPI negotiate
    1105                 :             :                                  * protocol, we use AUTH_REQ_SSPI.
    1106                 :             :                                  */
    1107                 :             : #if defined(ENABLE_GSS) && defined(ENABLE_SSPI)
    1108                 :             :                                 if (conn->gsslib && (pg_strcasecmp(conn->gsslib, "gssapi") == 0))
    1109                 :             :                                         r = pg_GSS_startup(conn, payloadlen);
    1110                 :             :                                 else
    1111                 :             :                                         r = pg_SSPI_startup(conn, 0, payloadlen);
    1112                 :             : #elif defined(ENABLE_GSS) && !defined(ENABLE_SSPI)
    1113                 :           0 :                                 r = pg_GSS_startup(conn, payloadlen);
    1114                 :             : #elif !defined(ENABLE_GSS) && defined(ENABLE_SSPI)
    1115                 :             :                                 r = pg_SSPI_startup(conn, 0, payloadlen);
    1116                 :             : #endif
    1117         [ #  # ]:           0 :                                 if (r != STATUS_OK)
    1118                 :             :                                 {
    1119                 :             :                                         /* Error message already filled in. */
    1120                 :           0 :                                         pgunlock_thread();
    1121                 :           0 :                                         return STATUS_ERROR;
    1122                 :             :                                 }
    1123                 :           0 :                                 pgunlock_thread();
    1124         [ #  # ]:           0 :                         }
    1125                 :           0 :                         break;
    1126                 :             : 
    1127                 :             :                 case AUTH_REQ_GSS_CONT:
    1128                 :             :                         {
    1129                 :           0 :                                 int                     r;
    1130                 :             : 
    1131                 :           0 :                                 pglock_thread();
    1132                 :             : #if defined(ENABLE_GSS) && defined(ENABLE_SSPI)
    1133                 :             :                                 if (conn->usesspi)
    1134                 :             :                                         r = pg_SSPI_continue(conn, payloadlen);
    1135                 :             :                                 else
    1136                 :             :                                         r = pg_GSS_continue(conn, payloadlen);
    1137                 :             : #elif defined(ENABLE_GSS) && !defined(ENABLE_SSPI)
    1138                 :           0 :                                 r = pg_GSS_continue(conn, payloadlen);
    1139                 :             : #elif !defined(ENABLE_GSS) && defined(ENABLE_SSPI)
    1140                 :             :                                 r = pg_SSPI_continue(conn, payloadlen);
    1141                 :             : #endif
    1142         [ #  # ]:           0 :                                 if (r != STATUS_OK)
    1143                 :             :                                 {
    1144                 :             :                                         /* Error message already filled in. */
    1145                 :           0 :                                         pgunlock_thread();
    1146                 :           0 :                                         return STATUS_ERROR;
    1147                 :             :                                 }
    1148                 :           0 :                                 pgunlock_thread();
    1149         [ #  # ]:           0 :                         }
    1150                 :           0 :                         break;
    1151                 :             : #else                                                   /* defined(ENABLE_GSS) || defined(ENABLE_SSPI) */
    1152                 :             :                         /* No GSSAPI *or* SSPI support */
    1153                 :             :                 case AUTH_REQ_GSS:
    1154                 :             :                 case AUTH_REQ_GSS_CONT:
    1155                 :             :                         libpq_append_conn_error(conn, "GSSAPI authentication not supported");
    1156                 :             :                         return STATUS_ERROR;
    1157                 :             : #endif                                                  /* defined(ENABLE_GSS) || defined(ENABLE_SSPI) */
    1158                 :             : 
    1159                 :             : #ifdef ENABLE_SSPI
    1160                 :             :                 case AUTH_REQ_SSPI:
    1161                 :             : 
    1162                 :             :                         /*
    1163                 :             :                          * SSPI has its own startup message so libpq can decide which
    1164                 :             :                          * method to use. Indicate to pg_SSPI_startup that we want SSPI
    1165                 :             :                          * negotiation instead of Kerberos.
    1166                 :             :                          */
    1167                 :             :                         pglock_thread();
    1168                 :             :                         if (pg_SSPI_startup(conn, 1, payloadlen) != STATUS_OK)
    1169                 :             :                         {
    1170                 :             :                                 /* Error message already filled in. */
    1171                 :             :                                 pgunlock_thread();
    1172                 :             :                                 return STATUS_ERROR;
    1173                 :             :                         }
    1174                 :             :                         pgunlock_thread();
    1175                 :             :                         break;
    1176                 :             : #else
    1177                 :             : 
    1178                 :             :                         /*
    1179                 :             :                          * No SSPI support. However, if we have GSSAPI but not SSPI
    1180                 :             :                          * support, AUTH_REQ_SSPI will have been handled in the codepath
    1181                 :             :                          * for AUTH_REQ_GSS above, so don't duplicate the case label in
    1182                 :             :                          * that case.
    1183                 :             :                          */
    1184                 :             : #if !defined(ENABLE_GSS)
    1185                 :             :                 case AUTH_REQ_SSPI:
    1186                 :             :                         libpq_append_conn_error(conn, "SSPI authentication not supported");
    1187                 :             :                         return STATUS_ERROR;
    1188                 :             : #endif                                                  /* !define(ENABLE_GSS) */
    1189                 :             : #endif                                                  /* ENABLE_SSPI */
    1190                 :             : 
    1191                 :             : 
    1192                 :             :                 case AUTH_REQ_CRYPT:
    1193                 :           0 :                         libpq_append_conn_error(conn, "Crypt authentication not supported");
    1194                 :           0 :                         return STATUS_ERROR;
    1195                 :             : 
    1196                 :             :                 case AUTH_REQ_MD5:
    1197                 :             :                 case AUTH_REQ_PASSWORD:
    1198                 :             :                         {
    1199                 :           0 :                                 char       *password;
    1200                 :             : 
    1201                 :           0 :                                 conn->password_needed = true;
    1202                 :           0 :                                 password = conn->connhost[conn->whichhost].password;
    1203         [ #  # ]:           0 :                                 if (password == NULL)
    1204                 :           0 :                                         password = conn->pgpass;
    1205   [ #  #  #  # ]:           0 :                                 if (password == NULL || password[0] == '\0')
    1206                 :             :                                 {
    1207                 :           0 :                                         appendPQExpBufferStr(&conn->errorMessage,
    1208                 :             :                                                                                  PQnoPasswordSupplied);
    1209                 :           0 :                                         return STATUS_ERROR;
    1210                 :             :                                 }
    1211         [ #  # ]:           0 :                                 if (pg_password_sendauth(conn, password, areq) != STATUS_OK)
    1212                 :             :                                 {
    1213                 :           0 :                                         appendPQExpBufferStr(&conn->errorMessage,
    1214                 :             :                                                                                  "fe_sendauth: error sending password authentication\n");
    1215                 :           0 :                                         return STATUS_ERROR;
    1216                 :             :                                 }
    1217                 :             : 
    1218                 :             :                                 /* We expect no further authentication requests. */
    1219                 :           0 :                                 conn->client_finished_auth = true;
    1220                 :           0 :                                 break;
    1221                 :           0 :                         }
    1222                 :             : 
    1223                 :             :                 case AUTH_REQ_SASL:
    1224                 :             : 
    1225                 :             :                         /*
    1226                 :             :                          * The request contains the name (as assigned by IANA) of the
    1227                 :             :                          * authentication mechanism.
    1228                 :             :                          */
    1229         [ #  # ]:           0 :                         if (pg_SASL_init(conn, payloadlen, async) != STATUS_OK)
    1230                 :             :                         {
    1231                 :             :                                 /* pg_SASL_init already set the error message */
    1232                 :           0 :                                 return STATUS_ERROR;
    1233                 :             :                         }
    1234                 :           0 :                         break;
    1235                 :             : 
    1236                 :             :                 case AUTH_REQ_SASL_CONT:
    1237                 :             :                 case AUTH_REQ_SASL_FIN:
    1238                 :             :                         {
    1239                 :           0 :                                 bool            final = false;
    1240                 :             : 
    1241         [ #  # ]:           0 :                                 if (conn->sasl_state == NULL)
    1242                 :             :                                 {
    1243                 :           0 :                                         appendPQExpBufferStr(&conn->errorMessage,
    1244                 :             :                                                                                  "fe_sendauth: invalid authentication request from server: AUTH_REQ_SASL_CONT without AUTH_REQ_SASL\n");
    1245                 :           0 :                                         return STATUS_ERROR;
    1246                 :             :                                 }
    1247                 :           0 :                                 oldmsglen = conn->errorMessage.len;
    1248                 :             : 
    1249         [ #  # ]:           0 :                                 if (areq == AUTH_REQ_SASL_FIN)
    1250                 :           0 :                                         final = true;
    1251                 :             : 
    1252         [ #  # ]:           0 :                                 if (pg_SASL_continue(conn, payloadlen, final, async) != STATUS_OK)
    1253                 :             :                                 {
    1254                 :             :                                         /*
    1255                 :             :                                          * Append a generic error message unless pg_SASL_continue
    1256                 :             :                                          * did set a more specific one already.
    1257                 :             :                                          */
    1258         [ #  # ]:           0 :                                         if (conn->errorMessage.len == oldmsglen)
    1259                 :           0 :                                                 appendPQExpBufferStr(&conn->errorMessage,
    1260                 :             :                                                                                          "fe_sendauth: error in SASL authentication\n");
    1261                 :           0 :                                         return STATUS_ERROR;
    1262                 :             :                                 }
    1263                 :           0 :                                 break;
    1264         [ #  # ]:           0 :                         }
    1265                 :             : 
    1266                 :             :                 default:
    1267                 :           0 :                         libpq_append_conn_error(conn, "authentication method %u not supported", areq);
    1268                 :           0 :                         return STATUS_ERROR;
    1269                 :             :         }
    1270                 :             : 
    1271                 :         316 :         return STATUS_OK;
    1272                 :         316 : }
    1273                 :             : 
    1274                 :             : 
    1275                 :             : /*
    1276                 :             :  * pg_fe_getusername
    1277                 :             :  *
    1278                 :             :  * Returns a pointer to malloc'd space containing the name of the
    1279                 :             :  * specified user_id.  If there is an error, return NULL, and append
    1280                 :             :  * a suitable error message to *errorMessage if that's not NULL.
    1281                 :             :  *
    1282                 :             :  * Caution: on Windows, the user_id argument is ignored, and we always
    1283                 :             :  * fetch the current user's name.
    1284                 :             :  */
    1285                 :             : char *
    1286                 :         275 : pg_fe_getusername(uid_t user_id, PQExpBuffer errorMessage)
    1287                 :             : {
    1288                 :         275 :         char       *result = NULL;
    1289                 :         275 :         const char *name = NULL;
    1290                 :             : 
    1291                 :             : #ifdef WIN32
    1292                 :             :         /* Microsoft recommends buffer size of UNLEN+1, where UNLEN = 256 */
    1293                 :             :         char            username[256 + 1];
    1294                 :             :         DWORD           namesize = sizeof(username);
    1295                 :             : #else
    1296                 :         275 :         struct passwd pwbuf;
    1297                 :         275 :         struct passwd *pw = NULL;
    1298                 :         275 :         char            buf[1024];
    1299                 :         275 :         int                     rc;
    1300                 :             : #endif
    1301                 :             : 
    1302                 :             : #ifdef WIN32
    1303                 :             :         if (GetUserName(username, &namesize))
    1304                 :             :                 name = username;
    1305                 :             :         else if (errorMessage)
    1306                 :             :                 libpq_append_error(errorMessage,
    1307                 :             :                                                    "user name lookup failure: error code %lu",
    1308                 :             :                                                    GetLastError());
    1309                 :             : #else
    1310                 :         275 :         rc = getpwuid_r(user_id, &pwbuf, buf, sizeof buf, &pw);
    1311         [ -  + ]:         275 :         if (rc != 0)
    1312                 :             :         {
    1313                 :           0 :                 errno = rc;
    1314         [ #  # ]:           0 :                 if (errorMessage)
    1315                 :           0 :                         libpq_append_error(errorMessage, "could not look up local user ID %ld: %m", (long) user_id);
    1316                 :           0 :         }
    1317         [ +  - ]:         275 :         else if (!pw)
    1318                 :             :         {
    1319         [ #  # ]:           0 :                 if (errorMessage)
    1320                 :           0 :                         libpq_append_error(errorMessage, "local user with ID %ld does not exist", (long) user_id);
    1321                 :           0 :         }
    1322                 :             :         else
    1323                 :         275 :                 name = pw->pw_name;
    1324                 :             : #endif
    1325                 :             : 
    1326         [ -  + ]:         275 :         if (name)
    1327                 :             :         {
    1328                 :         275 :                 result = strdup(name);
    1329   [ -  +  #  # ]:         275 :                 if (result == NULL && errorMessage)
    1330                 :           0 :                         libpq_append_error(errorMessage, "out of memory");
    1331                 :         275 :         }
    1332                 :             : 
    1333                 :         550 :         return result;
    1334                 :         275 : }
    1335                 :             : 
    1336                 :             : /*
    1337                 :             :  * pg_fe_getauthname
    1338                 :             :  *
    1339                 :             :  * Returns a pointer to malloc'd space containing whatever name the user
    1340                 :             :  * has authenticated to the system.  If there is an error, return NULL,
    1341                 :             :  * and append a suitable error message to *errorMessage if that's not NULL.
    1342                 :             :  */
    1343                 :             : char *
    1344                 :         275 : pg_fe_getauthname(PQExpBuffer errorMessage)
    1345                 :             : {
    1346                 :             : #ifdef WIN32
    1347                 :             :         return pg_fe_getusername(0, errorMessage);
    1348                 :             : #else
    1349                 :         275 :         return pg_fe_getusername(geteuid(), errorMessage);
    1350                 :             : #endif
    1351                 :             : }
    1352                 :             : 
    1353                 :             : 
    1354                 :             : /*
    1355                 :             :  * PQencryptPassword -- exported routine to encrypt a password with MD5
    1356                 :             :  *
    1357                 :             :  * This function is equivalent to calling PQencryptPasswordConn with
    1358                 :             :  * "md5" as the encryption method, except that this doesn't require
    1359                 :             :  * a connection object.  This function is deprecated, use
    1360                 :             :  * PQencryptPasswordConn instead.
    1361                 :             :  */
    1362                 :             : char *
    1363                 :           0 : PQencryptPassword(const char *passwd, const char *user)
    1364                 :             : {
    1365                 :           0 :         char       *crypt_pwd;
    1366                 :           0 :         const char *errstr = NULL;
    1367                 :             : 
    1368                 :           0 :         crypt_pwd = malloc(MD5_PASSWD_LEN + 1);
    1369         [ #  # ]:           0 :         if (!crypt_pwd)
    1370                 :           0 :                 return NULL;
    1371                 :             : 
    1372         [ #  # ]:           0 :         if (!pg_md5_encrypt(passwd, (uint8 *) user, strlen(user), crypt_pwd, &errstr))
    1373                 :             :         {
    1374                 :           0 :                 free(crypt_pwd);
    1375                 :           0 :                 return NULL;
    1376                 :             :         }
    1377                 :             : 
    1378                 :           0 :         return crypt_pwd;
    1379                 :           0 : }
    1380                 :             : 
    1381                 :             : /*
    1382                 :             :  * PQencryptPasswordConn -- exported routine to encrypt a password
    1383                 :             :  *
    1384                 :             :  * This is intended to be used by client applications that wish to send
    1385                 :             :  * commands like ALTER USER joe PASSWORD 'pwd'.  The password need not
    1386                 :             :  * be sent in cleartext if it is encrypted on the client side.  This is
    1387                 :             :  * good because it ensures the cleartext password won't end up in logs,
    1388                 :             :  * pg_stat displays, etc.  We export the function so that clients won't
    1389                 :             :  * be dependent on low-level details like whether the encryption is MD5
    1390                 :             :  * or something else.
    1391                 :             :  *
    1392                 :             :  * Arguments are a connection object, the cleartext password, the SQL
    1393                 :             :  * name of the user it is for, and a string indicating the algorithm to
    1394                 :             :  * use for encrypting the password.  If algorithm is NULL, this queries
    1395                 :             :  * the server for the current 'password_encryption' value.  If you wish
    1396                 :             :  * to avoid that, e.g. to avoid blocking, you can execute
    1397                 :             :  * 'show password_encryption' yourself before calling this function, and
    1398                 :             :  * pass it as the algorithm.
    1399                 :             :  *
    1400                 :             :  * Return value is a malloc'd string.  The client may assume the string
    1401                 :             :  * doesn't contain any special characters that would require escaping.
    1402                 :             :  * On error, an error message is stored in the connection object, and
    1403                 :             :  * returns NULL.
    1404                 :             :  */
    1405                 :             : char *
    1406                 :           0 : PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user,
    1407                 :             :                                           const char *algorithm)
    1408                 :             : {
    1409                 :             : #define MAX_ALGORITHM_NAME_LEN 50
    1410                 :           0 :         char            algobuf[MAX_ALGORITHM_NAME_LEN + 1];
    1411                 :           0 :         char       *crypt_pwd = NULL;
    1412                 :             : 
    1413         [ #  # ]:           0 :         if (!conn)
    1414                 :           0 :                 return NULL;
    1415                 :             : 
    1416                 :           0 :         pqClearConnErrorState(conn);
    1417                 :             : 
    1418                 :             :         /* If no algorithm was given, ask the server. */
    1419         [ #  # ]:           0 :         if (algorithm == NULL)
    1420                 :             :         {
    1421                 :           0 :                 PGresult   *res;
    1422                 :           0 :                 char       *val;
    1423                 :             : 
    1424                 :           0 :                 res = PQexec(conn, "show password_encryption");
    1425         [ #  # ]:           0 :                 if (res == NULL)
    1426                 :             :                 {
    1427                 :             :                         /* PQexec() should've set conn->errorMessage already */
    1428                 :           0 :                         return NULL;
    1429                 :             :                 }
    1430         [ #  # ]:           0 :                 if (PQresultStatus(res) != PGRES_TUPLES_OK)
    1431                 :             :                 {
    1432                 :             :                         /* PQexec() should've set conn->errorMessage already */
    1433                 :           0 :                         PQclear(res);
    1434                 :           0 :                         return NULL;
    1435                 :             :                 }
    1436   [ #  #  #  # ]:           0 :                 if (PQntuples(res) != 1 || PQnfields(res) != 1)
    1437                 :             :                 {
    1438                 :           0 :                         PQclear(res);
    1439                 :           0 :                         libpq_append_conn_error(conn, "unexpected shape of result set returned for SHOW");
    1440                 :           0 :                         return NULL;
    1441                 :             :                 }
    1442                 :           0 :                 val = PQgetvalue(res, 0, 0);
    1443                 :             : 
    1444         [ #  # ]:           0 :                 if (strlen(val) > MAX_ALGORITHM_NAME_LEN)
    1445                 :             :                 {
    1446                 :           0 :                         PQclear(res);
    1447                 :           0 :                         libpq_append_conn_error(conn, "\"password_encryption\" value too long");
    1448                 :           0 :                         return NULL;
    1449                 :             :                 }
    1450                 :           0 :                 strcpy(algobuf, val);
    1451                 :           0 :                 PQclear(res);
    1452                 :             : 
    1453                 :           0 :                 algorithm = algobuf;
    1454         [ #  # ]:           0 :         }
    1455                 :             : 
    1456                 :             :         /*
    1457                 :             :          * Also accept "on" and "off" as aliases for "md5", because
    1458                 :             :          * password_encryption was a boolean before PostgreSQL 10.  We refuse to
    1459                 :             :          * send the password in plaintext even if it was "off".
    1460                 :             :          */
    1461   [ #  #  #  # ]:           0 :         if (strcmp(algorithm, "on") == 0 ||
    1462                 :           0 :                 strcmp(algorithm, "off") == 0)
    1463                 :           0 :                 algorithm = "md5";
    1464                 :             : 
    1465                 :             :         /*
    1466                 :             :          * Ok, now we know what algorithm to use
    1467                 :             :          */
    1468         [ #  # ]:           0 :         if (strcmp(algorithm, "scram-sha-256") == 0)
    1469                 :             :         {
    1470                 :           0 :                 const char *errstr = NULL;
    1471                 :             : 
    1472                 :           0 :                 crypt_pwd = pg_fe_scram_build_secret(passwd,
    1473                 :           0 :                                                                                          conn->scram_sha_256_iterations,
    1474                 :             :                                                                                          &errstr);
    1475         [ #  # ]:           0 :                 if (!crypt_pwd)
    1476                 :           0 :                         libpq_append_conn_error(conn, "could not encrypt password: %s", errstr);
    1477                 :           0 :         }
    1478         [ #  # ]:           0 :         else if (strcmp(algorithm, "md5") == 0)
    1479                 :             :         {
    1480                 :           0 :                 crypt_pwd = malloc(MD5_PASSWD_LEN + 1);
    1481         [ #  # ]:           0 :                 if (crypt_pwd)
    1482                 :             :                 {
    1483                 :           0 :                         const char *errstr = NULL;
    1484                 :             : 
    1485         [ #  # ]:           0 :                         if (!pg_md5_encrypt(passwd, (uint8 *) user, strlen(user), crypt_pwd, &errstr))
    1486                 :             :                         {
    1487                 :           0 :                                 libpq_append_conn_error(conn, "could not encrypt password: %s", errstr);
    1488                 :           0 :                                 free(crypt_pwd);
    1489                 :           0 :                                 crypt_pwd = NULL;
    1490                 :           0 :                         }
    1491                 :           0 :                 }
    1492                 :             :                 else
    1493                 :           0 :                         libpq_append_conn_error(conn, "out of memory");
    1494                 :           0 :         }
    1495                 :             :         else
    1496                 :             :         {
    1497                 :           0 :                 libpq_append_conn_error(conn, "unrecognized password encryption algorithm \"%s\"",
    1498                 :           0 :                                                                 algorithm);
    1499                 :           0 :                 return NULL;
    1500                 :             :         }
    1501                 :             : 
    1502                 :           0 :         return crypt_pwd;
    1503                 :           0 : }
    1504                 :             : 
    1505                 :             : /*
    1506                 :             :  * PQchangePassword -- exported routine to change a password
    1507                 :             :  *
    1508                 :             :  * This is intended to be used by client applications that wish to
    1509                 :             :  * change the password for a user. The password is not sent in
    1510                 :             :  * cleartext because it is encrypted on the client side. This is
    1511                 :             :  * good because it ensures the cleartext password is never known by
    1512                 :             :  * the server, and therefore won't end up in logs, pg_stat displays,
    1513                 :             :  * etc. The password encryption is performed by PQencryptPasswordConn(),
    1514                 :             :  * which is passed a NULL for the algorithm argument. Hence encryption
    1515                 :             :  * is done according to the server's password_encryption
    1516                 :             :  * setting. We export the function so that clients won't be dependent
    1517                 :             :  * on the implementation specific details with respect to how the
    1518                 :             :  * server changes passwords.
    1519                 :             :  *
    1520                 :             :  * Arguments are a connection object, the SQL name of the target user,
    1521                 :             :  * and the cleartext password.
    1522                 :             :  *
    1523                 :             :  * Return value is the PGresult of the executed ALTER USER statement
    1524                 :             :  * or NULL if we never get there. The caller is responsible to PQclear()
    1525                 :             :  * the returned PGresult.
    1526                 :             :  *
    1527                 :             :  * PQresultStatus() should be called to check the return value for errors,
    1528                 :             :  * and PQerrorMessage() used to get more information about such errors.
    1529                 :             :  */
    1530                 :             : PGresult *
    1531                 :           0 : PQchangePassword(PGconn *conn, const char *user, const char *passwd)
    1532                 :             : {
    1533                 :           0 :         char       *encrypted_password = PQencryptPasswordConn(conn, passwd,
    1534                 :           0 :                                                                                                                    user, NULL);
    1535                 :             : 
    1536         [ #  # ]:           0 :         if (!encrypted_password)
    1537                 :             :         {
    1538                 :             :                 /* PQencryptPasswordConn() already registered the error */
    1539                 :           0 :                 return NULL;
    1540                 :             :         }
    1541                 :             :         else
    1542                 :             :         {
    1543                 :           0 :                 char       *fmtpw = PQescapeLiteral(conn, encrypted_password,
    1544                 :           0 :                                                                                         strlen(encrypted_password));
    1545                 :             : 
    1546                 :             :                 /* no longer needed, so clean up now */
    1547                 :           0 :                 PQfreemem(encrypted_password);
    1548                 :             : 
    1549         [ #  # ]:           0 :                 if (!fmtpw)
    1550                 :             :                 {
    1551                 :             :                         /* PQescapeLiteral() already registered the error */
    1552                 :           0 :                         return NULL;
    1553                 :             :                 }
    1554                 :             :                 else
    1555                 :             :                 {
    1556                 :           0 :                         char       *fmtuser = PQescapeIdentifier(conn, user, strlen(user));
    1557                 :             : 
    1558         [ #  # ]:           0 :                         if (!fmtuser)
    1559                 :             :                         {
    1560                 :             :                                 /* PQescapeIdentifier() already registered the error */
    1561                 :           0 :                                 PQfreemem(fmtpw);
    1562                 :           0 :                                 return NULL;
    1563                 :             :                         }
    1564                 :             :                         else
    1565                 :             :                         {
    1566                 :           0 :                                 PQExpBufferData buf;
    1567                 :           0 :                                 PGresult   *res;
    1568                 :             : 
    1569                 :           0 :                                 initPQExpBuffer(&buf);
    1570                 :           0 :                                 printfPQExpBuffer(&buf, "ALTER USER %s PASSWORD %s",
    1571                 :           0 :                                                                   fmtuser, fmtpw);
    1572                 :             : 
    1573                 :           0 :                                 res = PQexec(conn, buf.data);
    1574                 :             : 
    1575                 :             :                                 /* clean up */
    1576                 :           0 :                                 termPQExpBuffer(&buf);
    1577                 :           0 :                                 PQfreemem(fmtuser);
    1578                 :           0 :                                 PQfreemem(fmtpw);
    1579                 :             : 
    1580                 :           0 :                                 return res;
    1581                 :           0 :                         }
    1582                 :           0 :                 }
    1583                 :           0 :         }
    1584                 :           0 : }
    1585                 :             : 
    1586                 :             : PQauthDataHook_type PQauthDataHook = PQdefaultAuthDataHook;
    1587                 :             : 
    1588                 :             : PQauthDataHook_type
    1589                 :           0 : PQgetAuthDataHook(void)
    1590                 :             : {
    1591                 :           0 :         return PQauthDataHook;
    1592                 :             : }
    1593                 :             : 
    1594                 :             : void
    1595                 :           0 : PQsetAuthDataHook(PQauthDataHook_type hook)
    1596                 :             : {
    1597         [ #  # ]:           0 :         PQauthDataHook = hook ? hook : PQdefaultAuthDataHook;
    1598                 :           0 : }
    1599                 :             : 
    1600                 :             : int
    1601                 :           0 : PQdefaultAuthDataHook(PGauthData type, PGconn *conn, void *data)
    1602                 :             : {
    1603                 :           0 :         return 0;                                       /* handle nothing */
    1604                 :             : }
        

Generated by: LCOV version 2.3.2-1