LCOV - code coverage report
Current view: top level - src/interfaces/libpq - fe-auth.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 61.4 % 376 231
Test Date: 2026-03-10 15:14:48 Functions: 71.4 % 14 10
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-2026, PostgreSQL Global Development Group
       7              :  * Portions Copyright (c) 1994, Regents of the University of California
       8              :  *
       9              :  * IDENTIFICATION
      10              :  *    src/interfaces/libpq/fe-auth.c
      11              :  *
      12              :  *-------------------------------------------------------------------------
      13              :  */
      14              : 
      15              : /*
      16              :  * INTERFACE ROUTINES
      17              :  *     frontend (client) routines:
      18              :  *      pg_fe_sendauth          send authentication information
      19              :  *      pg_fe_getauthname       get user's name according to the client side
      20              :  *                              of the authentication system
      21              :  */
      22              : 
      23              : #include "postgres_fe.h"
      24              : 
      25              : #ifdef WIN32
      26              : #include "win32.h"
      27              : #else
      28              : #include <unistd.h>
      29              : #include <fcntl.h>
      30              : #include <limits.h>
      31              : #include <pwd.h>
      32              : #include <sys/param.h>            /* for MAXHOSTNAMELEN on most */
      33              : #include <sys/socket.h>
      34              : #ifdef HAVE_SYS_UCRED_H
      35              : #include <sys/ucred.h>
      36              : #endif
      37              : #ifndef  MAXHOSTNAMELEN
      38              : #include <netdb.h>                /* for MAXHOSTNAMELEN on some */
      39              : #endif
      40              : #endif
      41              : 
      42              : #include "common/md5.h"
      43              : #include "common/oauth-common.h"
      44              : #include "common/scram-common.h"
      45              : #include "fe-auth.h"
      46              : #include "fe-auth-sasl.h"
      47              : #include "fe-auth-oauth.h"
      48              : #include "libpq-fe.h"
      49              : 
      50              : #ifdef ENABLE_GSS
      51              : /*
      52              :  * GSSAPI authentication system.
      53              :  */
      54              : 
      55              : #include "fe-gssapi-common.h"
      56              : 
      57              : /*
      58              :  * Continue GSS authentication with next token as needed.
      59              :  */
      60              : static int
      61              : 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           69 : pg_SASL_init(PGconn *conn, int payloadlen, bool *async)
     436              : {
     437           69 :     char       *initialresponse = NULL;
     438              :     int         initialresponselen;
     439              :     const char *selected_mechanism;
     440              :     PQExpBufferData mechanism_buf;
     441           69 :     char       *password = NULL;
     442              :     SASLStatus  status;
     443              : 
     444           69 :     initPQExpBuffer(&mechanism_buf);
     445              : 
     446           69 :     if (conn->channel_binding[0] == 'r' &&   /* require */
     447            4 :         !conn->ssl_in_use)
     448              :     {
     449            1 :         libpq_append_conn_error(conn, "channel binding required, but SSL not in use");
     450            1 :         goto error;
     451              :     }
     452              : 
     453           68 :     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           68 :     selected_mechanism = NULL;
     465              :     for (;;)
     466              :     {
     467          143 :         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          143 :         if (PQExpBufferDataBroken(mechanism_buf))
     474            0 :             goto oom_error;
     475              : 
     476              :         /* An empty string indicates end of list */
     477          143 :         if (mechanism_buf.data[0] == '\0')
     478           68 :             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           75 :         if (strcmp(mechanism_buf.data, SCRAM_SHA_256_PLUS_NAME) == 0)
     488              :         {
     489            7 :             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            7 :                 if (conn->channel_binding[0] != 'd') /* disable */
     499              :                 {
     500            5 :                     selected_mechanism = SCRAM_SHA_256_PLUS_NAME;
     501            5 :                     conn->sasl = &pg_scram_mech;
     502            5 :                     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           68 :         else if (strcmp(mechanism_buf.data, SCRAM_SHA_256_NAME) == 0 &&
     534              :                  !selected_mechanism)
     535              :         {
     536           63 :             selected_mechanism = SCRAM_SHA_256_NAME;
     537           63 :             conn->sasl = &pg_scram_mech;
     538           63 :             conn->password_needed = true;
     539              :         }
     540            5 :         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           68 :     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           68 :     if (conn->require_auth)
     557              :     {
     558           18 :         bool        allowed = false;
     559              : 
     560           26 :         for (int i = 0; i < lengthof(conn->allowed_sasl_mechs); i++)
     561              :         {
     562           22 :             if (conn->sasl == conn->allowed_sasl_mechs[i])
     563              :             {
     564           14 :                 allowed = true;
     565           14 :                 break;
     566              :             }
     567              :         }
     568              : 
     569           18 :         if (!allowed)
     570              :         {
     571            4 :             libpq_append_conn_error(conn, "authentication method requirement \"%s\" failed: server requested %s authentication",
     572              :                                     conn->require_auth, selected_mechanism);
     573            4 :             goto error;
     574              :         }
     575              :     }
     576              : 
     577           64 :     if (conn->channel_binding[0] == 'r' &&   /* require */
     578            3 :         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           64 :     if (conn->password_needed && !conn->scram_client_key_binary)
     594              :     {
     595           58 :         password = conn->connhost[conn->whichhost].password;
     596           58 :         if (password == NULL)
     597           58 :             password = conn->pgpass;
     598           58 :         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           64 :     if (conn->Pfdebug)
     608            0 :         pqTraceOutputMessage(conn, conn->inBuffer + conn->inStart, false);
     609              : 
     610              :     Assert(conn->sasl);
     611              : 
     612           64 :     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           64 :         conn->sasl_state = conn->sasl->init(conn,
     621              :                                             password,
     622              :                                             selected_mechanism);
     623           64 :         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           64 :     status = conn->sasl->exchange(conn->sasl_state, false,
     638              :                                   NULL, -1,
     639              :                                   &initialresponse, &initialresponselen);
     640              : 
     641           64 :     if (status == SASL_FAILED)
     642            0 :         goto error;
     643              : 
     644           64 :     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           64 :     if (pqPutMsgStart(PqMsg_SASLInitialResponse, conn))
     664            0 :         goto error;
     665           64 :     if (pqPuts(selected_mechanism, conn))
     666            0 :         goto error;
     667           64 :     if (initialresponse)
     668              :     {
     669           64 :         if (pqPutInt(initialresponselen, 4, conn))
     670            0 :             goto error;
     671           64 :         if (pqPutnchar(initialresponse, initialresponselen, conn))
     672            0 :             goto error;
     673              :     }
     674           64 :     conn->current_auth_response = AUTH_RESPONSE_SASL_INITIAL;
     675           64 :     if (pqPutMsgEnd(conn))
     676            0 :         goto error;
     677              : 
     678           64 :     if (pqFlush(conn))
     679            0 :         goto error;
     680              : 
     681           64 :     termPQExpBuffer(&mechanism_buf);
     682           64 :     free(initialresponse);
     683              : 
     684           64 :     return STATUS_OK;
     685              : 
     686            5 : error:
     687            5 :     termPQExpBuffer(&mechanism_buf);
     688            5 :     free(initialresponse);
     689            5 :     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          121 : 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          121 :     challenge = malloc(payloadlen + 1);
     714          121 :     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          121 :     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          121 :     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          121 :     challenge[payloadlen] = '\0';
     733              : 
     734          121 :     status = conn->sasl->exchange(conn->sasl_state, final,
     735              :                                   challenge, payloadlen,
     736              :                                   &output, &outputlen);
     737          121 :     free(challenge);            /* don't need the input anymore */
     738              : 
     739          121 :     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          121 :     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          121 :     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          121 :     if (output)
     777              :     {
     778              :         /*
     779              :          * Send the SASL response to the server.
     780              :          */
     781           64 :         conn->current_auth_response = AUTH_RESPONSE_SASL;
     782           64 :         res = pqPacketSend(conn, PqMsg_SASLResponse, output, outputlen);
     783           64 :         free(output);
     784              : 
     785           64 :         if (res != STATUS_OK)
     786            0 :             return STATUS_ERROR;
     787              :     }
     788              : 
     789          121 :     if (status == SASL_FAILED)
     790            0 :         return STATUS_ERROR;
     791              : 
     792          121 :     return STATUS_OK;
     793              : }
     794              : 
     795              : static int
     796           42 : pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq)
     797              : {
     798              :     int         ret;
     799           42 :     char       *crypt_pwd = NULL;
     800              :     const char *pwd_to_send;
     801              :     uint8       md5Salt[4];
     802              : 
     803              :     /* Read the salt from the AuthenticationMD5Password message. */
     804           42 :     if (areq == AUTH_REQ_MD5)
     805              :     {
     806            1 :         if (pqGetnchar(md5Salt, 4, conn))
     807            0 :             return STATUS_ERROR;    /* shouldn't happen */
     808              :     }
     809              : 
     810              :     /* finished parsing, trace server-to-client message */
     811           42 :     if (conn->Pfdebug)
     812            0 :         pqTraceOutputMessage(conn, conn->inBuffer + conn->inStart, false);
     813              : 
     814              :     /* Encrypt the password if needed. */
     815              : 
     816           42 :     switch (areq)
     817              :     {
     818            1 :         case AUTH_REQ_MD5:
     819              :             {
     820              :                 char       *crypt_pwd2;
     821            1 :                 const char *errstr = NULL;
     822              : 
     823              :                 /* Allocate enough space for two MD5 hashes */
     824            1 :                 crypt_pwd = malloc(2 * (MD5_PASSWD_LEN + 1));
     825            1 :                 if (!crypt_pwd)
     826              :                 {
     827            0 :                     libpq_append_conn_error(conn, "out of memory");
     828            0 :                     return STATUS_ERROR;
     829              :                 }
     830              : 
     831            1 :                 crypt_pwd2 = crypt_pwd + MD5_PASSWD_LEN + 1;
     832            1 :                 if (!pg_md5_encrypt(password, (uint8 *) conn->pguser,
     833            1 :                                     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            1 :                 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            1 :                 pwd_to_send = crypt_pwd;
     849            1 :                 break;
     850              :             }
     851           41 :         case AUTH_REQ_PASSWORD:
     852           41 :             pwd_to_send = password;
     853           41 :             break;
     854            0 :         default:
     855            0 :             return STATUS_ERROR;
     856              :     }
     857           42 :     conn->current_auth_response = AUTH_RESPONSE_PASSWORD;
     858           42 :     ret = pqPacketSend(conn, PqMsg_PasswordMessage,
     859           42 :                        pwd_to_send, strlen(pwd_to_send) + 1);
     860           42 :     free(crypt_pwd);
     861           42 :     return ret;
     862              : }
     863              : 
     864              : /*
     865              :  * Translate a disallowed AuthRequest code into an error message.
     866              :  */
     867              : static const char *
     868           12 : auth_method_description(AuthRequest areq)
     869              : {
     870           12 :     switch (areq)
     871              :     {
     872            6 :         case AUTH_REQ_PASSWORD:
     873            6 :             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            6 :         case AUTH_REQ_SASL:
     882              :         case AUTH_REQ_SASL_CONT:
     883              :         case AUTH_REQ_SASL_FIN:
     884            6 :             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        14589 : check_expected_areq(AuthRequest areq, PGconn *conn)
     904              : {
     905        14589 :     bool        result = true;
     906        14589 :     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        14589 :     if (conn->sslcertmode[0] == 'r' /* require */
     912            3 :         && 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            3 :         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            3 :         else if (!conn->ssl_cert_sent)
     924              :         {
     925            1 :             libpq_append_conn_error(conn, "server accepted connection without a valid SSL certificate");
     926            1 :             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        14588 :     if (conn->require_auth)
     936              :     {
     937           98 :         switch (areq)
     938              :         {
     939           35 :             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           35 :                 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            9 :                     reason = libpq_gettext("server did not complete authentication");
     980            9 :                     result = false;
     981              :                 }
     982              : 
     983            9 :                 break;
     984              : 
     985           63 :             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           63 :                 result = auth_method_allowed(conn, areq);
    1000           63 :                 break;
    1001              : 
    1002            0 :             default:
    1003            0 :                 result = false;
    1004            0 :                 break;
    1005              :         }
    1006              :     }
    1007              : 
    1008        14588 :     if (!result)
    1009              :     {
    1010           21 :         if (!reason)
    1011           12 :             reason = auth_method_description(areq);
    1012              : 
    1013           21 :         libpq_append_conn_error(conn, "authentication method requirement \"%s\" failed: %s",
    1014              :                                 conn->require_auth, reason);
    1015           21 :         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        14567 :     if (conn->channel_binding[0] == 'r' /* require */ )
    1026              :     {
    1027           17 :         switch (areq)
    1028              :         {
    1029           10 :             case AUTH_REQ_SASL:
    1030              :             case AUTH_REQ_SASL_CONT:
    1031              :             case AUTH_REQ_SASL_FIN:
    1032           10 :                 break;
    1033            4 :             case AUTH_REQ_OK:
    1034            4 :                 if (!conn->sasl || !conn->sasl->channel_bound(conn->sasl_state))
    1035              :                 {
    1036            1 :                     libpq_append_conn_error(conn, "channel binding required, but server authenticated client without channel binding");
    1037            1 :                     result = false;
    1038              :                 }
    1039            4 :                 break;
    1040            3 :             default:
    1041            3 :                 libpq_append_conn_error(conn, "channel binding required but not supported by server's authentication request");
    1042            3 :                 result = false;
    1043            3 :                 break;
    1044              :         }
    1045              :     }
    1046              : 
    1047        14567 :     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        14589 : pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn, bool *async)
    1067              : {
    1068              :     int         oldmsglen;
    1069              : 
    1070        14589 :     *async = false;
    1071              : 
    1072        14589 :     if (!check_expected_areq(areq, conn))
    1073           26 :         return STATUS_ERROR;
    1074              : 
    1075        14563 :     switch (areq)
    1076              :     {
    1077        14330 :         case AUTH_REQ_OK:
    1078        14330 :             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           43 :         case AUTH_REQ_MD5:
    1197              :         case AUTH_REQ_PASSWORD:
    1198              :             {
    1199              :                 char       *password;
    1200              : 
    1201           43 :                 conn->password_needed = true;
    1202           43 :                 password = conn->connhost[conn->whichhost].password;
    1203           43 :                 if (password == NULL)
    1204           38 :                     password = conn->pgpass;
    1205           43 :                 if (password == NULL || password[0] == '\0')
    1206              :                 {
    1207            1 :                     appendPQExpBufferStr(&conn->errorMessage,
    1208              :                                          PQnoPasswordSupplied);
    1209            1 :                     return STATUS_ERROR;
    1210              :                 }
    1211           42 :                 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           42 :                 conn->client_finished_auth = true;
    1220           42 :                 break;
    1221              :             }
    1222              : 
    1223           69 :         case AUTH_REQ_SASL:
    1224              : 
    1225              :             /*
    1226              :              * The request contains the name (as assigned by IANA) of the
    1227              :              * authentication mechanism.
    1228              :              */
    1229           69 :             if (pg_SASL_init(conn, payloadlen, async) != STATUS_OK)
    1230              :             {
    1231              :                 /* pg_SASL_init already set the error message */
    1232            5 :                 return STATUS_ERROR;
    1233              :             }
    1234           64 :             break;
    1235              : 
    1236          121 :         case AUTH_REQ_SASL_CONT:
    1237              :         case AUTH_REQ_SASL_FIN:
    1238              :             {
    1239          121 :                 bool        final = false;
    1240              : 
    1241          121 :                 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          121 :                 oldmsglen = conn->errorMessage.len;
    1248              : 
    1249          121 :                 if (areq == AUTH_REQ_SASL_FIN)
    1250           57 :                     final = true;
    1251              : 
    1252          121 :                 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          121 :                 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        14557 :     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        13594 : pg_fe_getusername(uid_t user_id, PQExpBuffer errorMessage)
    1287              : {
    1288        13594 :     char       *result = NULL;
    1289        13594 :     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        13594 :     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        13594 :     rc = getpwuid_r(user_id, &pwbuf, buf, sizeof buf, &pw);
    1311        13594 :     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        13594 :     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        13594 :         name = pw->pw_name;
    1324              : #endif
    1325              : 
    1326        13594 :     if (name)
    1327              :     {
    1328        13594 :         result = strdup(name);
    1329        13594 :         if (result == NULL && errorMessage)
    1330            0 :             libpq_append_error(errorMessage, "out of memory");
    1331              :     }
    1332              : 
    1333        13594 :     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        13594 : pg_fe_getauthname(PQExpBuffer errorMessage)
    1345              : {
    1346              : #ifdef WIN32
    1347              :     return pg_fe_getusername(0, errorMessage);
    1348              : #else
    1349        13594 :     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, (const uint8 *) user, strlen(user), crypt_pwd, &errstr))
    1373              :     {
    1374            0 :         free(crypt_pwd);
    1375            0 :         return NULL;
    1376              :     }
    1377              : 
    1378            0 :     return crypt_pwd;
    1379              : }
    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            1 : 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            1 :     char       *crypt_pwd = NULL;
    1412              : 
    1413            1 :     if (!conn)
    1414            0 :         return NULL;
    1415              : 
    1416            1 :     pqClearConnErrorState(conn);
    1417              : 
    1418              :     /* If no algorithm was given, ask the server. */
    1419            1 :     if (algorithm == NULL)
    1420              :     {
    1421              :         PGresult   *res;
    1422              :         char       *val;
    1423              : 
    1424            1 :         res = PQexec(conn, "show password_encryption");
    1425            1 :         if (res == NULL)
    1426              :         {
    1427              :             /* PQexec() should've set conn->errorMessage already */
    1428            0 :             return NULL;
    1429              :         }
    1430            1 :         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            1 :         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            1 :         val = PQgetvalue(res, 0, 0);
    1443              : 
    1444            1 :         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            1 :         strcpy(algobuf, val);
    1451            1 :         PQclear(res);
    1452              : 
    1453            1 :         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            1 :     if (strcmp(algorithm, "on") == 0 ||
    1462            1 :         strcmp(algorithm, "off") == 0)
    1463            0 :         algorithm = "md5";
    1464              : 
    1465              :     /*
    1466              :      * Ok, now we know what algorithm to use
    1467              :      */
    1468            1 :     if (strcmp(algorithm, "scram-sha-256") == 0)
    1469              :     {
    1470            1 :         const char *errstr = NULL;
    1471              : 
    1472            1 :         crypt_pwd = pg_fe_scram_build_secret(passwd,
    1473              :                                              conn->scram_sha_256_iterations,
    1474              :                                              &errstr);
    1475            1 :         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, (const uint8 *) user, strlen(user), crypt_pwd, &errstr))
    1486              :             {
    1487            0 :                 libpq_append_conn_error(conn, "could not encrypt password: %s", errstr);
    1488            0 :                 free(crypt_pwd);
    1489            0 :                 crypt_pwd = NULL;
    1490              :             }
    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            1 :     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            1 : PQchangePassword(PGconn *conn, const char *user, const char *passwd)
    1532              : {
    1533            1 :     char       *encrypted_password = PQencryptPasswordConn(conn, passwd,
    1534              :                                                            user, NULL);
    1535              : 
    1536            1 :     if (!encrypted_password)
    1537              :     {
    1538              :         /* PQencryptPasswordConn() already registered the error */
    1539            0 :         return NULL;
    1540              :     }
    1541              :     else
    1542              :     {
    1543            1 :         char       *fmtpw = PQescapeLiteral(conn, encrypted_password,
    1544              :                                             strlen(encrypted_password));
    1545              : 
    1546              :         /* no longer needed, so clean up now */
    1547            1 :         PQfreemem(encrypted_password);
    1548              : 
    1549            1 :         if (!fmtpw)
    1550              :         {
    1551              :             /* PQescapeLiteral() already registered the error */
    1552            0 :             return NULL;
    1553              :         }
    1554              :         else
    1555              :         {
    1556            1 :             char       *fmtuser = PQescapeIdentifier(conn, user, strlen(user));
    1557              : 
    1558            1 :             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            1 :                 initPQExpBuffer(&buf);
    1570            1 :                 printfPQExpBuffer(&buf, "ALTER USER %s PASSWORD %s",
    1571              :                                   fmtuser, fmtpw);
    1572              : 
    1573            1 :                 res = PQexec(conn, buf.data);
    1574              : 
    1575              :                 /* clean up */
    1576            1 :                 termPQExpBuffer(&buf);
    1577            1 :                 PQfreemem(fmtuser);
    1578            1 :                 PQfreemem(fmtpw);
    1579              : 
    1580            1 :                 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 2.0-1