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

Generated by: LCOV version 1.13