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

Generated by: LCOV version 1.14