LCOV - code coverage report
Current view: top level - src/interfaces/libpq - fe-auth.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 233 378 61.6 %
Date: 2025-03-14 05:15:48 Functions: 10 14 71.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * fe-auth.c
       4             :  *     The front-end (client) authorization routines
       5             :  *
       6             :  * Portions Copyright (c) 1996-2025, 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             : pg_GSS_continue(PGconn *conn, int payloadlen)
      62             : {
      63             :     OM_uint32   maj_stat,
      64             :                 min_stat,
      65             :                 lmin_s,
      66             :                 gss_flags = GSS_C_MUTUAL_FLAG;
      67             :     gss_buffer_desc ginbuf;
      68             :     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             :     if (conn->gctx != GSS_C_NO_CONTEXT)
      75             :     {
      76             :         ginbuf.length = payloadlen;
      77             :         ginbuf.value = malloc(payloadlen);
      78             :         if (!ginbuf.value)
      79             :         {
      80             :             libpq_append_conn_error(conn, "out of memory allocating GSSAPI buffer (%d)",
      81             :                                     payloadlen);
      82             :             return STATUS_ERROR;
      83             :         }
      84             :         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             :             free(ginbuf.value);
      91             :             return STATUS_ERROR;
      92             :         }
      93             :     }
      94             :     else
      95             :     {
      96             :         ginbuf.length = 0;
      97             :         ginbuf.value = NULL;
      98             :     }
      99             : 
     100             :     /* finished parsing, trace server-to-client message */
     101             :     if (conn->Pfdebug)
     102             :         pqTraceOutputMessage(conn, conn->inBuffer + conn->inStart, false);
     103             : 
     104             :     /* Only try to acquire credentials if GSS delegation isn't disabled. */
     105             :     if (!pg_GSS_have_cred_cache(&conn->gcred))
     106             :         conn->gcred = GSS_C_NO_CREDENTIAL;
     107             : 
     108             :     if (conn->gssdelegation && conn->gssdelegation[0] == '1')
     109             :         gss_flags |= GSS_C_DELEG_FLAG;
     110             : 
     111             :     maj_stat = gss_init_sec_context(&min_stat,
     112             :                                     conn->gcred,
     113             :                                     &conn->gctx,
     114             :                                     conn->gtarg_nam,
     115             :                                     GSS_C_NO_OID,
     116             :                                     gss_flags,
     117             :                                     0,
     118             :                                     GSS_C_NO_CHANNEL_BINDINGS,
     119             :                                     (ginbuf.value == NULL) ? GSS_C_NO_BUFFER : &ginbuf,
     120             :                                     NULL,
     121             :                                     &goutbuf,
     122             :                                     NULL,
     123             :                                     NULL);
     124             : 
     125             :     free(ginbuf.value);
     126             : 
     127             :     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             :         conn->current_auth_response = AUTH_RESPONSE_GSS;
     135             :         if (pqPacketSend(conn, PqMsg_GSSResponse,
     136             :                          goutbuf.value, goutbuf.length) != STATUS_OK)
     137             :         {
     138             :             gss_release_buffer(&lmin_s, &goutbuf);
     139             :             return STATUS_ERROR;
     140             :         }
     141             :     }
     142             :     gss_release_buffer(&lmin_s, &goutbuf);
     143             : 
     144             :     if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
     145             :     {
     146             :         pg_GSS_error(libpq_gettext("GSSAPI continuation error"),
     147             :                      conn,
     148             :                      maj_stat, min_stat);
     149             :         gss_release_name(&lmin_s, &conn->gtarg_nam);
     150             :         if (conn->gctx)
     151             :             gss_delete_sec_context(&lmin_s, &conn->gctx, GSS_C_NO_BUFFER);
     152             :         return STATUS_ERROR;
     153             :     }
     154             : 
     155             :     if (maj_stat == GSS_S_COMPLETE)
     156             :     {
     157             :         conn->client_finished_auth = true;
     158             :         gss_release_name(&lmin_s, &conn->gtarg_nam);
     159             :         conn->gssapi_used = true;
     160             :     }
     161             : 
     162             :     return STATUS_OK;
     163             : }
     164             : 
     165             : /*
     166             :  * Send initial GSS authentication token
     167             :  */
     168             : static int
     169             : pg_GSS_startup(PGconn *conn, int payloadlen)
     170             : {
     171             :     int         ret;
     172             :     char       *host = conn->connhost[conn->whichhost].host;
     173             : 
     174             :     if (!(host && host[0] != '\0'))
     175             :     {
     176             :         libpq_append_conn_error(conn, "host name must be specified");
     177             :         return STATUS_ERROR;
     178             :     }
     179             : 
     180             :     if (conn->gctx)
     181             :     {
     182             :         libpq_append_conn_error(conn, "duplicate GSS authentication request");
     183             :         return STATUS_ERROR;
     184             :     }
     185             : 
     186             :     ret = pg_GSS_load_servicename(conn);
     187             :     if (ret != STATUS_OK)
     188             :         return ret;
     189             : 
     190             :     /*
     191             :      * Initial packet is the same as a continuation packet with no initial
     192             :      * context.
     193             :      */
     194             :     conn->gctx = GSS_C_NO_CONTEXT;
     195             : 
     196             :     return pg_GSS_continue(conn, payloadlen);
     197             : }
     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         108 : pg_SASL_init(PGconn *conn, int payloadlen, bool *async)
     436             : {
     437         108 :     char       *initialresponse = NULL;
     438             :     int         initialresponselen;
     439             :     const char *selected_mechanism;
     440             :     PQExpBufferData mechanism_buf;
     441         108 :     char       *password = NULL;
     442             :     SASLStatus  status;
     443             : 
     444         108 :     initPQExpBuffer(&mechanism_buf);
     445             : 
     446         108 :     if (conn->channel_binding[0] == 'r' &&   /* require */
     447           8 :         !conn->ssl_in_use)
     448             :     {
     449           2 :         libpq_append_conn_error(conn, "channel binding required, but SSL not in use");
     450           2 :         goto error;
     451             :     }
     452             : 
     453         106 :     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         106 :     selected_mechanism = NULL;
     465             :     for (;;)
     466             :     {
     467         226 :         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         226 :         if (PQExpBufferDataBroken(mechanism_buf))
     474           0 :             goto oom_error;
     475             : 
     476             :         /* An empty string indicates end of list */
     477         226 :         if (mechanism_buf.data[0] == '\0')
     478         106 :             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         120 :         if (strcmp(mechanism_buf.data, SCRAM_SHA_256_PLUS_NAME) == 0)
     488             :         {
     489          14 :             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          14 :                 if (conn->channel_binding[0] != 'd') /* disable */
     499             :                 {
     500          10 :                     selected_mechanism = SCRAM_SHA_256_PLUS_NAME;
     501          10 :                     conn->sasl = &pg_scram_mech;
     502          10 :                     conn->password_needed = true;
     503             :                 }
     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             :             }
     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             :         }
     533         106 :         else if (strcmp(mechanism_buf.data, SCRAM_SHA_256_NAME) == 0 &&
     534             :                  !selected_mechanism)
     535             :         {
     536          96 :             selected_mechanism = SCRAM_SHA_256_NAME;
     537          96 :             conn->sasl = &pg_scram_mech;
     538          96 :             conn->password_needed = true;
     539             :         }
     540          10 :         else if (strcmp(mechanism_buf.data, OAUTHBEARER_NAME) == 0 &&
     541             :                  !selected_mechanism)
     542             :         {
     543           0 :             selected_mechanism = OAUTHBEARER_NAME;
     544           0 :             conn->sasl = &pg_oauth_mech;
     545           0 :             conn->password_needed = false;
     546             :         }
     547             :     }
     548             : 
     549         106 :     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         106 :     if (conn->require_auth)
     557             :     {
     558          24 :         bool        allowed = false;
     559             : 
     560          40 :         for (int i = 0; i < lengthof(conn->allowed_sasl_mechs); i++)
     561             :         {
     562          32 :             if (conn->sasl == conn->allowed_sasl_mechs[i])
     563             :             {
     564          16 :                 allowed = true;
     565          16 :                 break;
     566             :             }
     567             :         }
     568             : 
     569          24 :         if (!allowed)
     570             :         {
     571           8 :             libpq_append_conn_error(conn, "authentication method requirement \"%s\" failed: server requested %s authentication",
     572             :                                     conn->require_auth, selected_mechanism);
     573           8 :             goto error;
     574             :         }
     575             :     }
     576             : 
     577          98 :     if (conn->channel_binding[0] == 'r' &&   /* require */
     578           6 :         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          98 :     if (conn->password_needed && !conn->scram_client_key_binary)
     594             :     {
     595          90 :         password = conn->connhost[conn->whichhost].password;
     596          90 :         if (password == NULL)
     597          90 :             password = conn->pgpass;
     598          90 :         if (password == NULL || password[0] == '\0')
     599             :         {
     600           0 :             appendPQExpBufferStr(&conn->errorMessage,
     601             :                                  PQnoPasswordSupplied);
     602           0 :             goto error;
     603             :         }
     604             :     }
     605             : 
     606             :     /* finished parsing, trace server-to-client message */
     607          98 :     if (conn->Pfdebug)
     608           0 :         pqTraceOutputMessage(conn, conn->inBuffer + conn->inStart, false);
     609             : 
     610             :     Assert(conn->sasl);
     611             : 
     612          98 :     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          98 :         conn->sasl_state = conn->sasl->init(conn,
     621             :                                             password,
     622             :                                             selected_mechanism);
     623          98 :         if (!conn->sasl_state)
     624           0 :             goto oom_error;
     625             :     }
     626             :     else
     627             :     {
     628             :         /*
     629             :          * This is only possible if we're returning from an async loop.
     630             :          * Disconnect it now.
     631             :          */
     632             :         Assert(conn->async_auth);
     633           0 :         conn->async_auth = NULL;
     634             :     }
     635             : 
     636             :     /* Get the mechanism-specific Initial Client Response, if any */
     637          98 :     status = conn->sasl->exchange(conn->sasl_state, false,
     638             :                                   NULL, -1,
     639             :                                   &initialresponse, &initialresponselen);
     640             : 
     641          98 :     if (status == SASL_FAILED)
     642           0 :         goto error;
     643             : 
     644          98 :     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             :         Assert(conn->async_auth);
     654             :         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          98 :     if (pqPutMsgStart(PqMsg_SASLInitialResponse, conn))
     664           0 :         goto error;
     665          98 :     if (pqPuts(selected_mechanism, conn))
     666           0 :         goto error;
     667          98 :     if (initialresponse)
     668             :     {
     669          98 :         if (pqPutInt(initialresponselen, 4, conn))
     670           0 :             goto error;
     671          98 :         if (pqPutnchar(initialresponse, initialresponselen, conn))
     672           0 :             goto error;
     673             :     }
     674          98 :     conn->current_auth_response = AUTH_RESPONSE_SASL_INITIAL;
     675          98 :     if (pqPutMsgEnd(conn))
     676           0 :         goto error;
     677             : 
     678          98 :     if (pqFlush(conn))
     679           0 :         goto error;
     680             : 
     681          98 :     termPQExpBuffer(&mechanism_buf);
     682          98 :     free(initialresponse);
     683             : 
     684          98 :     return STATUS_OK;
     685             : 
     686          10 : error:
     687          10 :     termPQExpBuffer(&mechanism_buf);
     688          10 :     free(initialresponse);
     689          10 :     return STATUS_ERROR;
     690             : 
     691           0 : 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             : }
     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         184 : pg_SASL_continue(PGconn *conn, int payloadlen, bool final, bool *async)
     705             : {
     706             :     char       *output;
     707             :     int         outputlen;
     708             :     int         res;
     709             :     char       *challenge;
     710             :     SASLStatus  status;
     711             : 
     712             :     /* Read the SASL challenge from the AuthenticationSASLContinue message. */
     713         184 :     challenge = malloc(payloadlen + 1);
     714         184 :     if (!challenge)
     715             :     {
     716           0 :         libpq_append_conn_error(conn, "out of memory allocating SASL buffer (%d)",
     717             :                                 payloadlen);
     718           0 :         return STATUS_ERROR;
     719             :     }
     720             : 
     721         184 :     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         184 :     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         184 :     challenge[payloadlen] = '\0';
     733             : 
     734         184 :     status = conn->sasl->exchange(conn->sasl_state, final,
     735             :                                   challenge, payloadlen,
     736             :                                   &output, &outputlen);
     737         184 :     free(challenge);            /* don't need the input anymore */
     738             : 
     739         184 :     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             :     }
     752             : 
     753         184 :     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         184 :     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         184 :     if (output)
     777             :     {
     778             :         /*
     779             :          * Send the SASL response to the server.
     780             :          */
     781          98 :         conn->current_auth_response = AUTH_RESPONSE_SASL;
     782          98 :         res = pqPacketSend(conn, PqMsg_SASLResponse, output, outputlen);
     783          98 :         free(output);
     784             : 
     785          98 :         if (res != STATUS_OK)
     786           0 :             return STATUS_ERROR;
     787             :     }
     788             : 
     789         184 :     if (status == SASL_FAILED)
     790           0 :         return STATUS_ERROR;
     791             : 
     792         184 :     return STATUS_OK;
     793             : }
     794             : 
     795             : static int
     796          84 : pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq)
     797             : {
     798             :     int         ret;
     799          84 :     char       *crypt_pwd = NULL;
     800             :     const char *pwd_to_send;
     801             :     char        md5Salt[4];
     802             : 
     803             :     /* Read the salt from the AuthenticationMD5Password message. */
     804          84 :     if (areq == AUTH_REQ_MD5)
     805             :     {
     806           2 :         if (pqGetnchar(md5Salt, 4, conn))
     807           0 :             return STATUS_ERROR;    /* shouldn't happen */
     808             :     }
     809             : 
     810             :     /* finished parsing, trace server-to-client message */
     811          84 :     if (conn->Pfdebug)
     812           0 :         pqTraceOutputMessage(conn, conn->inBuffer + conn->inStart, false);
     813             : 
     814             :     /* Encrypt the password if needed. */
     815             : 
     816          84 :     switch (areq)
     817             :     {
     818           2 :         case AUTH_REQ_MD5:
     819             :             {
     820             :                 char       *crypt_pwd2;
     821           2 :                 const char *errstr = NULL;
     822             : 
     823             :                 /* Allocate enough space for two MD5 hashes */
     824           2 :                 crypt_pwd = malloc(2 * (MD5_PASSWD_LEN + 1));
     825           2 :                 if (!crypt_pwd)
     826             :                 {
     827           0 :                     libpq_append_conn_error(conn, "out of memory");
     828           0 :                     return STATUS_ERROR;
     829             :                 }
     830             : 
     831           2 :                 crypt_pwd2 = crypt_pwd + MD5_PASSWD_LEN + 1;
     832           2 :                 if (!pg_md5_encrypt(password, conn->pguser,
     833           2 :                                     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           2 :                 if (!pg_md5_encrypt(crypt_pwd2 + strlen("md5"), md5Salt,
     841             :                                     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           2 :                 pwd_to_send = crypt_pwd;
     849           2 :                 break;
     850             :             }
     851          82 :         case AUTH_REQ_PASSWORD:
     852          82 :             pwd_to_send = password;
     853          82 :             break;
     854           0 :         default:
     855           0 :             return STATUS_ERROR;
     856             :     }
     857          84 :     conn->current_auth_response = AUTH_RESPONSE_PASSWORD;
     858          84 :     ret = pqPacketSend(conn, PqMsg_PasswordMessage,
     859          84 :                        pwd_to_send, strlen(pwd_to_send) + 1);
     860          84 :     free(crypt_pwd);
     861          84 :     return ret;
     862             : }
     863             : 
     864             : /*
     865             :  * Translate a disallowed AuthRequest code into an error message.
     866             :  */
     867             : static const char *
     868          24 : auth_method_description(AuthRequest areq)
     869             : {
     870          24 :     switch (areq)
     871             :     {
     872          12 :         case AUTH_REQ_PASSWORD:
     873          12 :             return libpq_gettext("server requested a cleartext password");
     874           0 :         case AUTH_REQ_MD5:
     875           0 :             return libpq_gettext("server requested a hashed password");
     876           0 :         case AUTH_REQ_GSS:
     877             :         case AUTH_REQ_GSS_CONT:
     878           0 :             return libpq_gettext("server requested GSSAPI authentication");
     879           0 :         case AUTH_REQ_SSPI:
     880           0 :             return libpq_gettext("server requested SSPI authentication");
     881          12 :         case AUTH_REQ_SASL:
     882             :         case AUTH_REQ_SASL_CONT:
     883             :         case AUTH_REQ_SASL_FIN:
     884          12 :             return libpq_gettext("server requested SASL authentication");
     885             :     }
     886             : 
     887           0 :     return libpq_gettext("server requested an unknown authentication type");
     888             : }
     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       26962 : check_expected_areq(AuthRequest areq, PGconn *conn)
     904             : {
     905       26962 :     bool        result = true;
     906       26962 :     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       26962 :     if (conn->sslcertmode[0] == 'r' /* require */
     912           6 :         && 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           6 :         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           6 :         else if (!conn->ssl_cert_sent)
     924             :         {
     925           2 :             libpq_append_conn_error(conn, "server accepted connection without a valid SSL certificate");
     926           2 :             return false;
     927             :         }
     928             :     }
     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       26960 :     if (conn->require_auth)
     936             :     {
     937         144 :         switch (areq)
     938             :         {
     939          54 :             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          54 :                 if (!conn->auth_required || conn->client_finished_auth)
     956             :                     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             :                 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             :                 }
     976             :                 else
     977             : #endif
     978             :                 {
     979          14 :                     reason = libpq_gettext("server did not complete authentication");
     980          14 :                     result = false;
     981             :                 }
     982             : 
     983          14 :                 break;
     984             : 
     985          90 :             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          90 :                 result = auth_method_allowed(conn, areq);
    1000          90 :                 break;
    1001             : 
    1002           0 :             default:
    1003           0 :                 result = false;
    1004           0 :                 break;
    1005             :         }
    1006       26856 :     }
    1007             : 
    1008       26960 :     if (!result)
    1009             :     {
    1010          38 :         if (!reason)
    1011          24 :             reason = auth_method_description(areq);
    1012             : 
    1013          38 :         libpq_append_conn_error(conn, "authentication method requirement \"%s\" failed: %s",
    1014             :                                 conn->require_auth, reason);
    1015          38 :         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       26922 :     if (conn->channel_binding[0] == 'r' /* require */ )
    1026             :     {
    1027          34 :         switch (areq)
    1028             :         {
    1029          20 :             case AUTH_REQ_SASL:
    1030             :             case AUTH_REQ_SASL_CONT:
    1031             :             case AUTH_REQ_SASL_FIN:
    1032          20 :                 break;
    1033           8 :             case AUTH_REQ_OK:
    1034           8 :                 if (!conn->sasl || !conn->sasl->channel_bound(conn->sasl_state))
    1035             :                 {
    1036           2 :                     libpq_append_conn_error(conn, "channel binding required, but server authenticated client without channel binding");
    1037           2 :                     result = false;
    1038             :                 }
    1039           8 :                 break;
    1040           6 :             default:
    1041           6 :                 libpq_append_conn_error(conn, "channel binding required but not supported by server's authentication request");
    1042           6 :                 result = false;
    1043           6 :                 break;
    1044             :         }
    1045       26888 :     }
    1046             : 
    1047       26922 :     return result;
    1048             : }
    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       26962 : pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn, bool *async)
    1067             : {
    1068             :     int         oldmsglen;
    1069             : 
    1070       26962 :     *async = false;
    1071             : 
    1072       26962 :     if (!check_expected_areq(areq, conn))
    1073          48 :         return STATUS_ERROR;
    1074             : 
    1075       26914 :     switch (areq)
    1076             :     {
    1077       26536 :         case AUTH_REQ_OK:
    1078       26536 :             break;
    1079             : 
    1080           0 :         case AUTH_REQ_KRB4:
    1081           0 :             libpq_append_conn_error(conn, "Kerberos 4 authentication not supported");
    1082           0 :             return STATUS_ERROR;
    1083             : 
    1084           0 :         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             :                 int         r;
    1096             : 
    1097             :                 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             :                 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             :                 if (r != STATUS_OK)
    1118             :                 {
    1119             :                     /* Error message already filled in. */
    1120             :                     pgunlock_thread();
    1121             :                     return STATUS_ERROR;
    1122             :                 }
    1123             :                 pgunlock_thread();
    1124             :             }
    1125             :             break;
    1126             : 
    1127             :         case AUTH_REQ_GSS_CONT:
    1128             :             {
    1129             :                 int         r;
    1130             : 
    1131             :                 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             :                 r = pg_GSS_continue(conn, payloadlen);
    1139             : #elif !defined(ENABLE_GSS) && defined(ENABLE_SSPI)
    1140             :                 r = pg_SSPI_continue(conn, payloadlen);
    1141             : #endif
    1142             :                 if (r != STATUS_OK)
    1143             :                 {
    1144             :                     /* Error message already filled in. */
    1145             :                     pgunlock_thread();
    1146             :                     return STATUS_ERROR;
    1147             :                 }
    1148             :                 pgunlock_thread();
    1149             :             }
    1150             :             break;
    1151             : #else                           /* defined(ENABLE_GSS) || defined(ENABLE_SSPI) */
    1152             :             /* No GSSAPI *or* SSPI support */
    1153           0 :         case AUTH_REQ_GSS:
    1154             :         case AUTH_REQ_GSS_CONT:
    1155           0 :             libpq_append_conn_error(conn, "GSSAPI authentication not supported");
    1156           0 :             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           0 :         case AUTH_REQ_SSPI:
    1186           0 :             libpq_append_conn_error(conn, "SSPI authentication not supported");
    1187           0 :             return STATUS_ERROR;
    1188             : #endif                          /* !define(ENABLE_GSS) */
    1189             : #endif                          /* ENABLE_SSPI */
    1190             : 
    1191             : 
    1192           0 :         case AUTH_REQ_CRYPT:
    1193           0 :             libpq_append_conn_error(conn, "Crypt authentication not supported");
    1194           0 :             return STATUS_ERROR;
    1195             : 
    1196          86 :         case AUTH_REQ_MD5:
    1197             :         case AUTH_REQ_PASSWORD:
    1198             :             {
    1199             :                 char       *password;
    1200             : 
    1201          86 :                 conn->password_needed = true;
    1202          86 :                 password = conn->connhost[conn->whichhost].password;
    1203          86 :                 if (password == NULL)
    1204          76 :                     password = conn->pgpass;
    1205          86 :                 if (password == NULL || password[0] == '\0')
    1206             :                 {
    1207           2 :                     appendPQExpBufferStr(&conn->errorMessage,
    1208             :                                          PQnoPasswordSupplied);
    1209           2 :                     return STATUS_ERROR;
    1210             :                 }
    1211          84 :                 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          84 :                 conn->client_finished_auth = true;
    1220          84 :                 break;
    1221             :             }
    1222             : 
    1223         108 :         case AUTH_REQ_SASL:
    1224             : 
    1225             :             /*
    1226             :              * The request contains the name (as assigned by IANA) of the
    1227             :              * authentication mechanism.
    1228             :              */
    1229         108 :             if (pg_SASL_init(conn, payloadlen, async) != STATUS_OK)
    1230             :             {
    1231             :                 /* pg_SASL_init already set the error message */
    1232          10 :                 return STATUS_ERROR;
    1233             :             }
    1234          98 :             break;
    1235             : 
    1236         184 :         case AUTH_REQ_SASL_CONT:
    1237             :         case AUTH_REQ_SASL_FIN:
    1238             :             {
    1239         184 :                 bool        final = false;
    1240             : 
    1241         184 :                 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         184 :                 oldmsglen = conn->errorMessage.len;
    1248             : 
    1249         184 :                 if (areq == AUTH_REQ_SASL_FIN)
    1250          86 :                     final = true;
    1251             : 
    1252         184 :                 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         184 :                 break;
    1264             :             }
    1265             : 
    1266           0 :         default:
    1267           0 :             libpq_append_conn_error(conn, "authentication method %u not supported", areq);
    1268           0 :             return STATUS_ERROR;
    1269             :     }
    1270             : 
    1271       26902 :     return STATUS_OK;
    1272             : }
    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       25630 : pg_fe_getusername(uid_t user_id, PQExpBuffer errorMessage)
    1287             : {
    1288       25630 :     char       *result = NULL;
    1289       25630 :     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             :     struct passwd pwbuf;
    1297       25630 :     struct passwd *pw = NULL;
    1298             :     char        buf[1024];
    1299             :     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       25630 :     rc = getpwuid_r(user_id, &pwbuf, buf, sizeof buf, &pw);
    1311       25630 :     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             :     }
    1317       25630 :     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             :     }
    1322             :     else
    1323       25630 :         name = pw->pw_name;
    1324             : #endif
    1325             : 
    1326       25630 :     if (name)
    1327             :     {
    1328       25630 :         result = strdup(name);
    1329       25630 :         if (result == NULL && errorMessage)
    1330           0 :             libpq_append_error(errorMessage, "out of memory");
    1331             :     }
    1332             : 
    1333       25630 :     return result;
    1334             : }
    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       25630 : pg_fe_getauthname(PQExpBuffer errorMessage)
    1345             : {
    1346             : #ifdef WIN32
    1347             :     return pg_fe_getusername(0, errorMessage);
    1348             : #else
    1349       25630 :     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             :     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, user, strlen(user), crypt_pwd, &errstr))
    1373             :     {
    1374           0 :         free(crypt_pwd);
    1375           0 :         return NULL;
    1376             :     }
    1377             : 
    1378           0 :     return crypt_pwd;
    1379             : }
    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           2 : PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user,
    1407             :                       const char *algorithm)
    1408             : {
    1409             : #define MAX_ALGORITHM_NAME_LEN 50
    1410             :     char        algobuf[MAX_ALGORITHM_NAME_LEN + 1];
    1411           2 :     char       *crypt_pwd = NULL;
    1412             : 
    1413           2 :     if (!conn)
    1414           0 :         return NULL;
    1415             : 
    1416           2 :     pqClearConnErrorState(conn);
    1417             : 
    1418             :     /* If no algorithm was given, ask the server. */
    1419           2 :     if (algorithm == NULL)
    1420             :     {
    1421             :         PGresult   *res;
    1422             :         char       *val;
    1423             : 
    1424           2 :         res = PQexec(conn, "show password_encryption");
    1425           2 :         if (res == NULL)
    1426             :         {
    1427             :             /* PQexec() should've set conn->errorMessage already */
    1428           0 :             return NULL;
    1429             :         }
    1430           2 :         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           2 :         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           2 :         val = PQgetvalue(res, 0, 0);
    1443             : 
    1444           2 :         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           2 :         strcpy(algobuf, val);
    1451           2 :         PQclear(res);
    1452             : 
    1453           2 :         algorithm = algobuf;
    1454             :     }
    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           2 :     if (strcmp(algorithm, "on") == 0 ||
    1462           2 :         strcmp(algorithm, "off") == 0)
    1463           0 :         algorithm = "md5";
    1464             : 
    1465             :     /*
    1466             :      * Ok, now we know what algorithm to use
    1467             :      */
    1468           2 :     if (strcmp(algorithm, "scram-sha-256") == 0)
    1469             :     {
    1470           2 :         const char *errstr = NULL;
    1471             : 
    1472           2 :         crypt_pwd = pg_fe_scram_build_secret(passwd,
    1473             :                                              conn->scram_sha_256_iterations,
    1474             :                                              &errstr);
    1475           2 :         if (!crypt_pwd)
    1476           0 :             libpq_append_conn_error(conn, "could not encrypt password: %s", errstr);
    1477             :     }
    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, 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             :             }
    1491             :         }
    1492             :         else
    1493           0 :             libpq_append_conn_error(conn, "out of memory");
    1494             :     }
    1495             :     else
    1496             :     {
    1497           0 :         libpq_append_conn_error(conn, "unrecognized password encryption algorithm \"%s\"",
    1498             :                                 algorithm);
    1499           0 :         return NULL;
    1500             :     }
    1501             : 
    1502           2 :     return crypt_pwd;
    1503             : }
    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           2 : PQchangePassword(PGconn *conn, const char *user, const char *passwd)
    1532             : {
    1533           2 :     char       *encrypted_password = PQencryptPasswordConn(conn, passwd,
    1534             :                                                            user, NULL);
    1535             : 
    1536           2 :     if (!encrypted_password)
    1537             :     {
    1538             :         /* PQencryptPasswordConn() already registered the error */
    1539           0 :         return NULL;
    1540             :     }
    1541             :     else
    1542             :     {
    1543           2 :         char       *fmtpw = PQescapeLiteral(conn, encrypted_password,
    1544             :                                             strlen(encrypted_password));
    1545             : 
    1546             :         /* no longer needed, so clean up now */
    1547           2 :         PQfreemem(encrypted_password);
    1548             : 
    1549           2 :         if (!fmtpw)
    1550             :         {
    1551             :             /* PQescapeLiteral() already registered the error */
    1552           0 :             return NULL;
    1553             :         }
    1554             :         else
    1555             :         {
    1556           2 :             char       *fmtuser = PQescapeIdentifier(conn, user, strlen(user));
    1557             : 
    1558           2 :             if (!fmtuser)
    1559             :             {
    1560             :                 /* PQescapeIdentifier() already registered the error */
    1561           0 :                 PQfreemem(fmtpw);
    1562           0 :                 return NULL;
    1563             :             }
    1564             :             else
    1565             :             {
    1566             :                 PQExpBufferData buf;
    1567             :                 PGresult   *res;
    1568             : 
    1569           2 :                 initPQExpBuffer(&buf);
    1570           2 :                 printfPQExpBuffer(&buf, "ALTER USER %s PASSWORD %s",
    1571             :                                   fmtuser, fmtpw);
    1572             : 
    1573           2 :                 res = PQexec(conn, buf.data);
    1574             : 
    1575             :                 /* clean up */
    1576           2 :                 termPQExpBuffer(&buf);
    1577           2 :                 PQfreemem(fmtuser);
    1578           2 :                 PQfreemem(fmtpw);
    1579             : 
    1580           2 :                 return res;
    1581             :             }
    1582             :         }
    1583             :     }
    1584             : }
    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 1.14