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

Generated by: LCOV version 1.11