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

Generated by: LCOV version 1.14