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

Generated by: LCOV version 1.14