LCOV - code coverage report
Current view: top level - src/backend/libpq - auth.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 278 811 34.3 %
Date: 2020-05-29 00:07:09 Functions: 13 21 61.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * auth.c
       4             :  *    Routines to handle network authentication
       5             :  *
       6             :  * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/libpq/auth.c
      12             :  *
      13             :  *-------------------------------------------------------------------------
      14             :  */
      15             : 
      16             : #include "postgres.h"
      17             : 
      18             : #include <sys/param.h>
      19             : #include <sys/socket.h>
      20             : #include <netinet/in.h>
      21             : #include <unistd.h>
      22             : #ifdef HAVE_SYS_SELECT_H
      23             : #include <sys/select.h>
      24             : #endif
      25             : 
      26             : #include "commands/user.h"
      27             : #include "common/ip.h"
      28             : #include "common/md5.h"
      29             : #include "common/scram-common.h"
      30             : #include "libpq/auth.h"
      31             : #include "libpq/crypt.h"
      32             : #include "libpq/libpq.h"
      33             : #include "libpq/pqformat.h"
      34             : #include "libpq/scram.h"
      35             : #include "miscadmin.h"
      36             : #include "port/pg_bswap.h"
      37             : #include "replication/walsender.h"
      38             : #include "storage/ipc.h"
      39             : #include "utils/memutils.h"
      40             : #include "utils/timestamp.h"
      41             : 
      42             : /*----------------------------------------------------------------
      43             :  * Global authentication functions
      44             :  *----------------------------------------------------------------
      45             :  */
      46             : static void sendAuthRequest(Port *port, AuthRequest areq, const char *extradata,
      47             :                             int extralen);
      48             : static void auth_failed(Port *port, int status, char *logdetail);
      49             : static char *recv_password_packet(Port *port);
      50             : 
      51             : 
      52             : /*----------------------------------------------------------------
      53             :  * Password-based authentication methods (password, md5, and scram-sha-256)
      54             :  *----------------------------------------------------------------
      55             :  */
      56             : static int  CheckPasswordAuth(Port *port, char **logdetail);
      57             : static int  CheckPWChallengeAuth(Port *port, char **logdetail);
      58             : 
      59             : static int  CheckMD5Auth(Port *port, char *shadow_pass, char **logdetail);
      60             : static int  CheckSCRAMAuth(Port *port, char *shadow_pass, char **logdetail);
      61             : 
      62             : 
      63             : /*----------------------------------------------------------------
      64             :  * Ident authentication
      65             :  *----------------------------------------------------------------
      66             :  */
      67             : /* Max size of username ident server can return (per RFC 1413) */
      68             : #define IDENT_USERNAME_MAX 512
      69             : 
      70             : /* Standard TCP port number for Ident service.  Assigned by IANA */
      71             : #define IDENT_PORT 113
      72             : 
      73             : static int  ident_inet(hbaPort *port);
      74             : 
      75             : 
      76             : /*----------------------------------------------------------------
      77             :  * Peer authentication
      78             :  *----------------------------------------------------------------
      79             :  */
      80             : static int  auth_peer(hbaPort *port);
      81             : 
      82             : 
      83             : /*----------------------------------------------------------------
      84             :  * PAM authentication
      85             :  *----------------------------------------------------------------
      86             :  */
      87             : #ifdef USE_PAM
      88             : #ifdef HAVE_PAM_PAM_APPL_H
      89             : #include <pam/pam_appl.h>
      90             : #endif
      91             : #ifdef HAVE_SECURITY_PAM_APPL_H
      92             : #include <security/pam_appl.h>
      93             : #endif
      94             : 
      95             : #define PGSQL_PAM_SERVICE "postgresql"    /* Service name passed to PAM */
      96             : 
      97             : static int  CheckPAMAuth(Port *port, const char *user, const char *password);
      98             : static int  pam_passwd_conv_proc(int num_msg, const struct pam_message **msg,
      99             :                                  struct pam_response **resp, void *appdata_ptr);
     100             : 
     101             : static struct pam_conv pam_passw_conv = {
     102             :     &pam_passwd_conv_proc,
     103             :     NULL
     104             : };
     105             : 
     106             : static const char *pam_passwd = NULL;   /* Workaround for Solaris 2.6
     107             :                                          * brokenness */
     108             : static Port *pam_port_cludge;   /* Workaround for passing "Port *port" into
     109             :                                  * pam_passwd_conv_proc */
     110             : static bool pam_no_password;    /* For detecting no-password-given */
     111             : #endif                          /* USE_PAM */
     112             : 
     113             : 
     114             : /*----------------------------------------------------------------
     115             :  * BSD authentication
     116             :  *----------------------------------------------------------------
     117             :  */
     118             : #ifdef USE_BSD_AUTH
     119             : #include <bsd_auth.h>
     120             : 
     121             : static int  CheckBSDAuth(Port *port, char *user);
     122             : #endif                          /* USE_BSD_AUTH */
     123             : 
     124             : 
     125             : /*----------------------------------------------------------------
     126             :  * LDAP authentication
     127             :  *----------------------------------------------------------------
     128             :  */
     129             : #ifdef USE_LDAP
     130             : #ifndef WIN32
     131             : /* We use a deprecated function to keep the codepath the same as win32. */
     132             : #define LDAP_DEPRECATED 1
     133             : #include <ldap.h>
     134             : #else
     135             : #include <winldap.h>
     136             : 
     137             : /* Correct header from the Platform SDK */
     138             : typedef
     139             : ULONG       (*__ldap_start_tls_sA) (IN PLDAP ExternalHandle,
     140             :                                     OUT PULONG ServerReturnValue,
     141             :                                     OUT LDAPMessage **result,
     142             :                                     IN PLDAPControlA * ServerControls,
     143             :                                     IN PLDAPControlA * ClientControls
     144             : );
     145             : #endif
     146             : 
     147             : static int  CheckLDAPAuth(Port *port);
     148             : 
     149             : /* LDAP_OPT_DIAGNOSTIC_MESSAGE is the newer spelling */
     150             : #ifndef LDAP_OPT_DIAGNOSTIC_MESSAGE
     151             : #define LDAP_OPT_DIAGNOSTIC_MESSAGE LDAP_OPT_ERROR_STRING
     152             : #endif
     153             : 
     154             : #endif                          /* USE_LDAP */
     155             : 
     156             : /*----------------------------------------------------------------
     157             :  * Cert authentication
     158             :  *----------------------------------------------------------------
     159             :  */
     160             : #ifdef USE_SSL
     161             : static int  CheckCertAuth(Port *port);
     162             : #endif
     163             : 
     164             : 
     165             : /*----------------------------------------------------------------
     166             :  * Kerberos and GSSAPI GUCs
     167             :  *----------------------------------------------------------------
     168             :  */
     169             : char       *pg_krb_server_keyfile;
     170             : bool        pg_krb_caseins_users;
     171             : 
     172             : 
     173             : /*----------------------------------------------------------------
     174             :  * GSSAPI Authentication
     175             :  *----------------------------------------------------------------
     176             :  */
     177             : #ifdef ENABLE_GSS
     178             : #include "libpq/be-gssapi-common.h"
     179             : 
     180             : static int  pg_GSS_checkauth(Port *port);
     181             : static int  pg_GSS_recvauth(Port *port);
     182             : #endif                          /* ENABLE_GSS */
     183             : 
     184             : 
     185             : /*----------------------------------------------------------------
     186             :  * SSPI Authentication
     187             :  *----------------------------------------------------------------
     188             :  */
     189             : #ifdef ENABLE_SSPI
     190             : typedef SECURITY_STATUS
     191             :             (WINAPI * QUERY_SECURITY_CONTEXT_TOKEN_FN) (PCtxtHandle, void **);
     192             : static int  pg_SSPI_recvauth(Port *port);
     193             : static int  pg_SSPI_make_upn(char *accountname,
     194             :                              size_t accountnamesize,
     195             :                              char *domainname,
     196             :                              size_t domainnamesize,
     197             :                              bool update_accountname);
     198             : #endif
     199             : 
     200             : /*----------------------------------------------------------------
     201             :  * RADIUS Authentication
     202             :  *----------------------------------------------------------------
     203             :  */
     204             : static int  CheckRADIUSAuth(Port *port);
     205             : static int  PerformRadiusTransaction(const char *server, const char *secret, const char *portstr, const char *identifier, const char *user_name, const char *passwd);
     206             : 
     207             : 
     208             : /*
     209             :  * Maximum accepted size of GSS and SSPI authentication tokens.
     210             :  *
     211             :  * Kerberos tickets are usually quite small, but the TGTs issued by Windows
     212             :  * domain controllers include an authorization field known as the Privilege
     213             :  * Attribute Certificate (PAC), which contains the user's Windows permissions
     214             :  * (group memberships etc.). The PAC is copied into all tickets obtained on
     215             :  * the basis of this TGT (even those issued by Unix realms which the Windows
     216             :  * realm trusts), and can be several kB in size. The maximum token size
     217             :  * accepted by Windows systems is determined by the MaxAuthToken Windows
     218             :  * registry setting. Microsoft recommends that it is not set higher than
     219             :  * 65535 bytes, so that seems like a reasonable limit for us as well.
     220             :  */
     221             : #define PG_MAX_AUTH_TOKEN_LENGTH    65535
     222             : 
     223             : /*
     224             :  * Maximum accepted size of SASL messages.
     225             :  *
     226             :  * The messages that the server or libpq generate are much smaller than this,
     227             :  * but have some headroom.
     228             :  */
     229             : #define PG_MAX_SASL_MESSAGE_LENGTH  1024
     230             : 
     231             : /*----------------------------------------------------------------
     232             :  * Global authentication functions
     233             :  *----------------------------------------------------------------
     234             :  */
     235             : 
     236             : /*
     237             :  * This hook allows plugins to get control following client authentication,
     238             :  * but before the user has been informed about the results.  It could be used
     239             :  * to record login events, insert a delay after failed authentication, etc.
     240             :  */
     241             : ClientAuthentication_hook_type ClientAuthentication_hook = NULL;
     242             : 
     243             : /*
     244             :  * Tell the user the authentication failed, but not (much about) why.
     245             :  *
     246             :  * There is a tradeoff here between security concerns and making life
     247             :  * unnecessarily difficult for legitimate users.  We would not, for example,
     248             :  * want to report the password we were expecting to receive...
     249             :  * But it seems useful to report the username and authorization method
     250             :  * in use, and these are items that must be presumed known to an attacker
     251             :  * anyway.
     252             :  * Note that many sorts of failure report additional information in the
     253             :  * postmaster log, which we hope is only readable by good guys.  In
     254             :  * particular, if logdetail isn't NULL, we send that string to the log.
     255             :  */
     256             : static void
     257          40 : auth_failed(Port *port, int status, char *logdetail)
     258             : {
     259             :     const char *errstr;
     260             :     char       *cdetail;
     261          40 :     int         errcode_return = ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION;
     262             : 
     263             :     /*
     264             :      * If we failed due to EOF from client, just quit; there's no point in
     265             :      * trying to send a message to the client, and not much point in logging
     266             :      * the failure in the postmaster log.  (Logging the failure might be
     267             :      * desirable, were it not for the fact that libpq closes the connection
     268             :      * unceremoniously if challenged for a password when it hasn't got one to
     269             :      * send.  We'll get a useless log entry for every psql connection under
     270             :      * password auth, even if it's perfectly successful, if we log STATUS_EOF
     271             :      * events.)
     272             :      */
     273          40 :     if (status == STATUS_EOF)
     274           6 :         proc_exit(0);
     275             : 
     276          34 :     switch (port->hba->auth_method)
     277             :     {
     278           0 :         case uaReject:
     279             :         case uaImplicitReject:
     280           0 :             errstr = gettext_noop("authentication failed for user \"%s\": host rejected");
     281           0 :             break;
     282           2 :         case uaTrust:
     283           2 :             errstr = gettext_noop("\"trust\" authentication failed for user \"%s\"");
     284           2 :             break;
     285           0 :         case uaIdent:
     286           0 :             errstr = gettext_noop("Ident authentication failed for user \"%s\"");
     287           0 :             break;
     288           0 :         case uaPeer:
     289           0 :             errstr = gettext_noop("Peer authentication failed for user \"%s\"");
     290           0 :             break;
     291          10 :         case uaPassword:
     292             :         case uaMD5:
     293             :         case uaSCRAM:
     294          10 :             errstr = gettext_noop("password authentication failed for user \"%s\"");
     295             :             /* We use it to indicate if a .pgpass password failed. */
     296          10 :             errcode_return = ERRCODE_INVALID_PASSWORD;
     297          10 :             break;
     298           0 :         case uaGSS:
     299           0 :             errstr = gettext_noop("GSSAPI authentication failed for user \"%s\"");
     300           0 :             break;
     301           0 :         case uaSSPI:
     302           0 :             errstr = gettext_noop("SSPI authentication failed for user \"%s\"");
     303           0 :             break;
     304           0 :         case uaPAM:
     305           0 :             errstr = gettext_noop("PAM authentication failed for user \"%s\"");
     306           0 :             break;
     307           0 :         case uaBSD:
     308           0 :             errstr = gettext_noop("BSD authentication failed for user \"%s\"");
     309           0 :             break;
     310          20 :         case uaLDAP:
     311          20 :             errstr = gettext_noop("LDAP authentication failed for user \"%s\"");
     312          20 :             break;
     313           2 :         case uaCert:
     314           2 :             errstr = gettext_noop("certificate authentication failed for user \"%s\"");
     315           2 :             break;
     316           0 :         case uaRADIUS:
     317           0 :             errstr = gettext_noop("RADIUS authentication failed for user \"%s\"");
     318           0 :             break;
     319           0 :         default:
     320           0 :             errstr = gettext_noop("authentication failed for user \"%s\": invalid authentication method");
     321           0 :             break;
     322             :     }
     323             : 
     324          68 :     cdetail = psprintf(_("Connection matched pg_hba.conf line %d: \"%s\""),
     325          34 :                        port->hba->linenumber, port->hba->rawline);
     326          34 :     if (logdetail)
     327           2 :         logdetail = psprintf("%s\n%s", logdetail, cdetail);
     328             :     else
     329          32 :         logdetail = cdetail;
     330             : 
     331          34 :     ereport(FATAL,
     332             :             (errcode(errcode_return),
     333             :              errmsg(errstr, port->user_name),
     334             :              logdetail ? errdetail_log("%s", logdetail) : 0));
     335             : 
     336             :     /* doesn't return */
     337             : }
     338             : 
     339             : 
     340             : /*
     341             :  * Client authentication starts here.  If there is an error, this
     342             :  * function does not return and the backend process is terminated.
     343             :  */
     344             : void
     345        7824 : ClientAuthentication(Port *port)
     346             : {
     347        7824 :     int         status = STATUS_ERROR;
     348        7824 :     char       *logdetail = NULL;
     349             : 
     350             :     /*
     351             :      * Get the authentication method to use for this frontend/database
     352             :      * combination.  Note: we do not parse the file at this point; this has
     353             :      * already been done elsewhere.  hba.c dropped an error message into the
     354             :      * server logfile if parsing the hba config file failed.
     355             :      */
     356        7824 :     hba_getauthmethod(port);
     357             : 
     358        7824 :     CHECK_FOR_INTERRUPTS();
     359             : 
     360             :     /*
     361             :      * This is the first point where we have access to the hba record for the
     362             :      * current connection, so perform any verifications based on the hba
     363             :      * options field that should be done *before* the authentication here.
     364             :      */
     365        7824 :     if (port->hba->clientcert != clientCertOff)
     366             :     {
     367             :         /* If we haven't loaded a root certificate store, fail */
     368          22 :         if (!secure_loaded_verify_locations())
     369           0 :             ereport(FATAL,
     370             :                     (errcode(ERRCODE_CONFIG_FILE_ERROR),
     371             :                      errmsg("client certificates can only be checked if a root certificate store is available")));
     372             : 
     373             :         /*
     374             :          * If we loaded a root certificate store, and if a certificate is
     375             :          * present on the client, then it has been verified against our root
     376             :          * certificate store, and the connection would have been aborted
     377             :          * already if it didn't verify ok.
     378             :          */
     379          22 :         if (!port->peer_cert_valid)
     380           2 :             ereport(FATAL,
     381             :                     (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
     382             :                      errmsg("connection requires a valid client certificate")));
     383             :     }
     384             : 
     385             : #ifdef ENABLE_GSS
     386             :     if (port->gss->enc && port->hba->auth_method != uaReject &&
     387             :         port->hba->auth_method != uaImplicitReject &&
     388             :         port->hba->auth_method != uaTrust &&
     389             :         port->hba->auth_method != uaGSS)
     390             :     {
     391             :         ereport(FATAL, (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
     392             :                         errmsg("GSSAPI encryption can only be used with gss, trust, or reject authentication methods")));
     393             :     }
     394             : #endif
     395             : 
     396             :     /*
     397             :      * Now proceed to do the actual authentication check
     398             :      */
     399        7822 :     switch (port->hba->auth_method)
     400             :     {
     401           0 :         case uaReject:
     402             : 
     403             :             /*
     404             :              * An explicit "reject" entry in pg_hba.conf.  This report exposes
     405             :              * the fact that there's an explicit reject entry, which is
     406             :              * perhaps not so desirable from a security standpoint; but the
     407             :              * message for an implicit reject could confuse the DBA a lot when
     408             :              * the true situation is a match to an explicit reject.  And we
     409             :              * don't want to change the message for an implicit reject.  As
     410             :              * noted below, the additional information shown here doesn't
     411             :              * expose anything not known to an attacker.
     412             :              */
     413             :             {
     414             :                 char        hostinfo[NI_MAXHOST];
     415             : 
     416           0 :                 pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
     417             :                                    hostinfo, sizeof(hostinfo),
     418             :                                    NULL, 0,
     419             :                                    NI_NUMERICHOST);
     420             : 
     421           0 :                 if (am_walsender)
     422             :                 {
     423             : #ifdef USE_SSL
     424           0 :                     ereport(FATAL,
     425             :                             (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
     426             :                              errmsg("pg_hba.conf rejects replication connection for host \"%s\", user \"%s\", %s",
     427             :                                     hostinfo, port->user_name,
     428             :                                     port->ssl_in_use ? _("SSL on") : _("SSL off"))));
     429             : #else
     430             :                     ereport(FATAL,
     431             :                             (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
     432             :                              errmsg("pg_hba.conf rejects replication connection for host \"%s\", user \"%s\"",
     433             :                                     hostinfo, port->user_name)));
     434             : #endif
     435             :                 }
     436             :                 else
     437             :                 {
     438             : #ifdef USE_SSL
     439           0 :                     ereport(FATAL,
     440             :                             (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
     441             :                              errmsg("pg_hba.conf rejects connection for host \"%s\", user \"%s\", database \"%s\", %s",
     442             :                                     hostinfo, port->user_name,
     443             :                                     port->database_name,
     444             :                                     port->ssl_in_use ? _("SSL on") : _("SSL off"))));
     445             : #else
     446             :                     ereport(FATAL,
     447             :                             (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
     448             :                              errmsg("pg_hba.conf rejects connection for host \"%s\", user \"%s\", database \"%s\"",
     449             :                                     hostinfo, port->user_name,
     450             :                                     port->database_name)));
     451             : #endif
     452             :                 }
     453             :                 break;
     454             :             }
     455             : 
     456           2 :         case uaImplicitReject:
     457             : 
     458             :             /*
     459             :              * No matching entry, so tell the user we fell through.
     460             :              *
     461             :              * NOTE: the extra info reported here is not a security breach,
     462             :              * because all that info is known at the frontend and must be
     463             :              * assumed known to bad guys.  We're merely helping out the less
     464             :              * clueful good guys.
     465             :              */
     466             :             {
     467             :                 char        hostinfo[NI_MAXHOST];
     468             : 
     469           2 :                 pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
     470             :                                    hostinfo, sizeof(hostinfo),
     471             :                                    NULL, 0,
     472             :                                    NI_NUMERICHOST);
     473             : 
     474             : #define HOSTNAME_LOOKUP_DETAIL(port) \
     475             :                 (port->remote_hostname ? \
     476             :                  (port->remote_hostname_resolv == +1 ? \
     477             :                   errdetail_log("Client IP address resolved to \"%s\", forward lookup matches.", \
     478             :                                 port->remote_hostname) : \
     479             :                   port->remote_hostname_resolv == 0 ? \
     480             :                   errdetail_log("Client IP address resolved to \"%s\", forward lookup not checked.", \
     481             :                                 port->remote_hostname) : \
     482             :                   port->remote_hostname_resolv == -1 ? \
     483             :                   errdetail_log("Client IP address resolved to \"%s\", forward lookup does not match.", \
     484             :                                 port->remote_hostname) : \
     485             :                   port->remote_hostname_resolv == -2 ? \
     486             :                   errdetail_log("Could not translate client host name \"%s\" to IP address: %s.", \
     487             :                                 port->remote_hostname, \
     488             :                                 gai_strerror(port->remote_hostname_errcode)) : \
     489             :                   0) \
     490             :                  : (port->remote_hostname_resolv == -2 ? \
     491             :                     errdetail_log("Could not resolve client IP address to a host name: %s.", \
     492             :                                   gai_strerror(port->remote_hostname_errcode)) : \
     493             :                     0))
     494             : 
     495           2 :                 if (am_walsender)
     496             :                 {
     497             : #ifdef USE_SSL
     498           0 :                     ereport(FATAL,
     499             :                             (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
     500             :                              errmsg("no pg_hba.conf entry for replication connection from host \"%s\", user \"%s\", %s",
     501             :                                     hostinfo, port->user_name,
     502             :                                     port->ssl_in_use ? _("SSL on") : _("SSL off")),
     503             :                              HOSTNAME_LOOKUP_DETAIL(port)));
     504             : #else
     505             :                     ereport(FATAL,
     506             :                             (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
     507             :                              errmsg("no pg_hba.conf entry for replication connection from host \"%s\", user \"%s\"",
     508             :                                     hostinfo, port->user_name),
     509             :                              HOSTNAME_LOOKUP_DETAIL(port)));
     510             : #endif
     511             :                 }
     512             :                 else
     513             :                 {
     514             : #ifdef USE_SSL
     515           2 :                     ereport(FATAL,
     516             :                             (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
     517             :                              errmsg("no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\", %s",
     518             :                                     hostinfo, port->user_name,
     519             :                                     port->database_name,
     520             :                                     port->ssl_in_use ? _("SSL on") : _("SSL off")),
     521             :                              HOSTNAME_LOOKUP_DETAIL(port)));
     522             : #else
     523             :                     ereport(FATAL,
     524             :                             (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
     525             :                              errmsg("no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\"",
     526             :                                     hostinfo, port->user_name,
     527             :                                     port->database_name),
     528             :                              HOSTNAME_LOOKUP_DETAIL(port)));
     529             : #endif
     530             :                 }
     531             :                 break;
     532             :             }
     533             : 
     534           0 :         case uaGSS:
     535             : #ifdef ENABLE_GSS
     536             :             port->gss->auth = true;
     537             :             if (port->gss->enc)
     538             :                 status = pg_GSS_checkauth(port);
     539             :             else
     540             :             {
     541             :                 sendAuthRequest(port, AUTH_REQ_GSS, NULL, 0);
     542             :                 status = pg_GSS_recvauth(port);
     543             :             }
     544             : #else
     545             :             Assert(false);
     546             : #endif
     547           0 :             break;
     548             : 
     549           0 :         case uaSSPI:
     550             : #ifdef ENABLE_SSPI
     551             :             sendAuthRequest(port, AUTH_REQ_SSPI, NULL, 0);
     552             :             status = pg_SSPI_recvauth(port);
     553             : #else
     554             :             Assert(false);
     555             : #endif
     556           0 :             break;
     557             : 
     558           0 :         case uaPeer:
     559           0 :             status = auth_peer(port);
     560           0 :             break;
     561             : 
     562           0 :         case uaIdent:
     563           0 :             status = ident_inet(port);
     564           0 :             break;
     565             : 
     566          42 :         case uaMD5:
     567             :         case uaSCRAM:
     568          42 :             status = CheckPWChallengeAuth(port, &logdetail);
     569          42 :             break;
     570             : 
     571           6 :         case uaPassword:
     572           6 :             status = CheckPasswordAuth(port, &logdetail);
     573           6 :             break;
     574             : 
     575           0 :         case uaPAM:
     576             : #ifdef USE_PAM
     577           0 :             status = CheckPAMAuth(port, port->user_name, "");
     578             : #else
     579             :             Assert(false);
     580             : #endif                          /* USE_PAM */
     581           0 :             break;
     582             : 
     583           0 :         case uaBSD:
     584             : #ifdef USE_BSD_AUTH
     585             :             status = CheckBSDAuth(port, port->user_name);
     586             : #else
     587             :             Assert(false);
     588             : #endif                          /* USE_BSD_AUTH */
     589           0 :             break;
     590             : 
     591          44 :         case uaLDAP:
     592             : #ifdef USE_LDAP
     593          44 :             status = CheckLDAPAuth(port);
     594             : #else
     595             :             Assert(false);
     596             : #endif
     597          44 :             break;
     598           0 :         case uaRADIUS:
     599           0 :             status = CheckRADIUSAuth(port);
     600           0 :             break;
     601        7728 :         case uaCert:
     602             :             /* uaCert will be treated as if clientcert=verify-full (uaTrust) */
     603             :         case uaTrust:
     604        7728 :             status = STATUS_OK;
     605        7728 :             break;
     606             :     }
     607             : 
     608        7820 :     if ((status == STATUS_OK && port->hba->clientcert == clientCertFull)
     609        7816 :         || port->hba->auth_method == uaCert)
     610             :     {
     611             :         /*
     612             :          * Make sure we only check the certificate if we use the cert method
     613             :          * or verify-full option.
     614             :          */
     615             : #ifdef USE_SSL
     616          18 :         status = CheckCertAuth(port);
     617             : #else
     618             :         Assert(false);
     619             : #endif
     620             :     }
     621             : 
     622        7820 :     if (ClientAuthentication_hook)
     623           0 :         (*ClientAuthentication_hook) (port, status);
     624             : 
     625        7820 :     if (status == STATUS_OK)
     626        7780 :         sendAuthRequest(port, AUTH_REQ_OK, NULL, 0);
     627             :     else
     628          40 :         auth_failed(port, status, logdetail);
     629        7780 : }
     630             : 
     631             : 
     632             : /*
     633             :  * Send an authentication request packet to the frontend.
     634             :  */
     635             : static void
     636        7934 : sendAuthRequest(Port *port, AuthRequest areq, const char *extradata, int extralen)
     637             : {
     638             :     StringInfoData buf;
     639             : 
     640        7934 :     CHECK_FOR_INTERRUPTS();
     641             : 
     642        7934 :     pq_beginmessage(&buf, 'R');
     643        7934 :     pq_sendint32(&buf, (int32) areq);
     644        7934 :     if (extralen > 0)
     645         104 :         pq_sendbytes(&buf, extradata, extralen);
     646             : 
     647        7934 :     pq_endmessage(&buf);
     648             : 
     649             :     /*
     650             :      * Flush message so client will see it, except for AUTH_REQ_OK and
     651             :      * AUTH_REQ_SASL_FIN, which need not be sent until we are ready for
     652             :      * queries.
     653             :      */
     654        7934 :     if (areq != AUTH_REQ_OK && areq != AUTH_REQ_SASL_FIN)
     655         128 :         pq_flush();
     656             : 
     657        7934 :     CHECK_FOR_INTERRUPTS();
     658        7934 : }
     659             : 
     660             : /*
     661             :  * Collect password response packet from frontend.
     662             :  *
     663             :  * Returns NULL if couldn't get password, else palloc'd string.
     664             :  */
     665             : static char *
     666          54 : recv_password_packet(Port *port)
     667             : {
     668             :     StringInfoData buf;
     669             : 
     670          54 :     pq_startmsgread();
     671          54 :     if (PG_PROTOCOL_MAJOR(port->proto) >= 3)
     672             :     {
     673             :         /* Expect 'p' message type */
     674             :         int         mtype;
     675             : 
     676          54 :         mtype = pq_getbyte();
     677          54 :         if (mtype != 'p')
     678             :         {
     679             :             /*
     680             :              * If the client just disconnects without offering a password,
     681             :              * don't make a log entry.  This is legal per protocol spec and in
     682             :              * fact commonly done by psql, so complaining just clutters the
     683             :              * log.
     684             :              */
     685           4 :             if (mtype != EOF)
     686           0 :                 ereport(ERROR,
     687             :                         (errcode(ERRCODE_PROTOCOL_VIOLATION),
     688             :                          errmsg("expected password response, got message type %d",
     689             :                                 mtype)));
     690           4 :             return NULL;        /* EOF or bad message type */
     691             :         }
     692             :     }
     693             :     else
     694             :     {
     695             :         /* For pre-3.0 clients, avoid log entry if they just disconnect */
     696           0 :         if (pq_peekbyte() == EOF)
     697           0 :             return NULL;        /* EOF */
     698             :     }
     699             : 
     700          50 :     initStringInfo(&buf);
     701          50 :     if (pq_getmessage(&buf, 1000))  /* receive password */
     702             :     {
     703             :         /* EOF - pq_getmessage already logged a suitable message */
     704           0 :         pfree(buf.data);
     705           0 :         return NULL;
     706             :     }
     707             : 
     708             :     /*
     709             :      * Apply sanity check: password packet length should agree with length of
     710             :      * contained string.  Note it is safe to use strlen here because
     711             :      * StringInfo is guaranteed to have an appended '\0'.
     712             :      */
     713          50 :     if (strlen(buf.data) + 1 != buf.len)
     714           0 :         ereport(ERROR,
     715             :                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
     716             :                  errmsg("invalid password packet size")));
     717             : 
     718             :     /*
     719             :      * Don't allow an empty password. Libpq treats an empty password the same
     720             :      * as no password at all, and won't even try to authenticate. But other
     721             :      * clients might, so allowing it would be confusing.
     722             :      *
     723             :      * Note that this only catches an empty password sent by the client in
     724             :      * plaintext. There's also a check in CREATE/ALTER USER that prevents an
     725             :      * empty string from being stored as a user's password in the first place.
     726             :      * We rely on that for MD5 and SCRAM authentication, but we still need
     727             :      * this check here, to prevent an empty password from being used with
     728             :      * authentication methods that check the password against an external
     729             :      * system, like PAM, LDAP and RADIUS.
     730             :      */
     731          50 :     if (buf.len == 1)
     732           0 :         ereport(ERROR,
     733             :                 (errcode(ERRCODE_INVALID_PASSWORD),
     734             :                  errmsg("empty password returned by client")));
     735             : 
     736             :     /* Do not echo password to logs, for security. */
     737          50 :     elog(DEBUG5, "received password packet");
     738             : 
     739             :     /*
     740             :      * Return the received string.  Note we do not attempt to do any
     741             :      * character-set conversion on it; since we don't yet know the client's
     742             :      * encoding, there wouldn't be much point.
     743             :      */
     744          50 :     return buf.data;
     745             : }
     746             : 
     747             : 
     748             : /*----------------------------------------------------------------
     749             :  * Password-based authentication mechanisms
     750             :  *----------------------------------------------------------------
     751             :  */
     752             : 
     753             : /*
     754             :  * Plaintext password authentication.
     755             :  */
     756             : static int
     757           6 : CheckPasswordAuth(Port *port, char **logdetail)
     758             : {
     759             :     char       *passwd;
     760             :     int         result;
     761             :     char       *shadow_pass;
     762             : 
     763           6 :     sendAuthRequest(port, AUTH_REQ_PASSWORD, NULL, 0);
     764             : 
     765           6 :     passwd = recv_password_packet(port);
     766           6 :     if (passwd == NULL)
     767           2 :         return STATUS_EOF;      /* client wouldn't send password */
     768             : 
     769           4 :     shadow_pass = get_role_password(port->user_name, logdetail);
     770           4 :     if (shadow_pass)
     771             :     {
     772           4 :         result = plain_crypt_verify(port->user_name, shadow_pass, passwd,
     773             :                                     logdetail);
     774             :     }
     775             :     else
     776           0 :         result = STATUS_ERROR;
     777             : 
     778           4 :     if (shadow_pass)
     779           4 :         pfree(shadow_pass);
     780           4 :     pfree(passwd);
     781             : 
     782           4 :     return result;
     783             : }
     784             : 
     785             : /*
     786             :  * MD5 and SCRAM authentication.
     787             :  */
     788             : static int
     789          42 : CheckPWChallengeAuth(Port *port, char **logdetail)
     790             : {
     791             :     int         auth_result;
     792             :     char       *shadow_pass;
     793             :     PasswordType pwtype;
     794             : 
     795             :     Assert(port->hba->auth_method == uaSCRAM ||
     796             :            port->hba->auth_method == uaMD5);
     797             : 
     798             :     /* First look up the user's password. */
     799          42 :     shadow_pass = get_role_password(port->user_name, logdetail);
     800             : 
     801             :     /*
     802             :      * If the user does not exist, or has no password or it's expired, we
     803             :      * still go through the motions of authentication, to avoid revealing to
     804             :      * the client that the user didn't exist.  If 'md5' is allowed, we choose
     805             :      * whether to use 'md5' or 'scram-sha-256' authentication based on current
     806             :      * password_encryption setting.  The idea is that most genuine users
     807             :      * probably have a password of that type, and if we pretend that this user
     808             :      * had a password of that type, too, it "blends in" best.
     809             :      */
     810          42 :     if (!shadow_pass)
     811           0 :         pwtype = Password_encryption;
     812             :     else
     813          42 :         pwtype = get_password_type(shadow_pass);
     814             : 
     815             :     /*
     816             :      * If 'md5' authentication is allowed, decide whether to perform 'md5' or
     817             :      * 'scram-sha-256' authentication based on the type of password the user
     818             :      * has.  If it's an MD5 hash, we must do MD5 authentication, and if it's a
     819             :      * SCRAM secret, we must do SCRAM authentication.
     820             :      *
     821             :      * If MD5 authentication is not allowed, always use SCRAM.  If the user
     822             :      * had an MD5 password, CheckSCRAMAuth() will fail.
     823             :      */
     824          42 :     if (port->hba->auth_method == uaMD5 && pwtype == PASSWORD_TYPE_MD5)
     825           4 :         auth_result = CheckMD5Auth(port, shadow_pass, logdetail);
     826             :     else
     827          38 :         auth_result = CheckSCRAMAuth(port, shadow_pass, logdetail);
     828             : 
     829          42 :     if (shadow_pass)
     830          42 :         pfree(shadow_pass);
     831             : 
     832             :     /*
     833             :      * If get_role_password() returned error, return error, even if the
     834             :      * authentication succeeded.
     835             :      */
     836          42 :     if (!shadow_pass)
     837             :     {
     838             :         Assert(auth_result != STATUS_OK);
     839           0 :         return STATUS_ERROR;
     840             :     }
     841          42 :     return auth_result;
     842             : }
     843             : 
     844             : static int
     845           4 : CheckMD5Auth(Port *port, char *shadow_pass, char **logdetail)
     846             : {
     847             :     char        md5Salt[4];     /* Password salt */
     848             :     char       *passwd;
     849             :     int         result;
     850             : 
     851           4 :     if (Db_user_namespace)
     852           0 :         ereport(FATAL,
     853             :                 (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
     854             :                  errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled")));
     855             : 
     856             :     /* include the salt to use for computing the response */
     857           4 :     if (!pg_strong_random(md5Salt, 4))
     858             :     {
     859           0 :         ereport(LOG,
     860             :                 (errmsg("could not generate random MD5 salt")));
     861           0 :         return STATUS_ERROR;
     862             :     }
     863             : 
     864           4 :     sendAuthRequest(port, AUTH_REQ_MD5, md5Salt, 4);
     865             : 
     866           4 :     passwd = recv_password_packet(port);
     867           4 :     if (passwd == NULL)
     868           2 :         return STATUS_EOF;      /* client wouldn't send password */
     869             : 
     870           2 :     if (shadow_pass)
     871           2 :         result = md5_crypt_verify(port->user_name, shadow_pass, passwd,
     872             :                                   md5Salt, 4, logdetail);
     873             :     else
     874           0 :         result = STATUS_ERROR;
     875             : 
     876           2 :     pfree(passwd);
     877             : 
     878           2 :     return result;
     879             : }
     880             : 
     881             : static int
     882          38 : CheckSCRAMAuth(Port *port, char *shadow_pass, char **logdetail)
     883             : {
     884             :     StringInfoData sasl_mechs;
     885             :     int         mtype;
     886             :     StringInfoData buf;
     887          38 :     void       *scram_opaq = NULL;
     888          38 :     char       *output = NULL;
     889          38 :     int         outputlen = 0;
     890             :     const char *input;
     891             :     int         inputlen;
     892             :     int         result;
     893             :     bool        initial;
     894             : 
     895             :     /*
     896             :      * SASL auth is not supported for protocol versions before 3, because it
     897             :      * relies on the overall message length word to determine the SASL payload
     898             :      * size in AuthenticationSASLContinue and PasswordMessage messages.  (We
     899             :      * used to have a hard rule that protocol messages must be parsable
     900             :      * without relying on the length word, but we hardly care about older
     901             :      * protocol version anymore.)
     902             :      */
     903          38 :     if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
     904           0 :         ereport(FATAL,
     905             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     906             :                  errmsg("SASL authentication is not supported in protocol version 2")));
     907             : 
     908             :     /*
     909             :      * Send the SASL authentication request to user.  It includes the list of
     910             :      * authentication mechanisms that are supported.
     911             :      */
     912          38 :     initStringInfo(&sasl_mechs);
     913             : 
     914          38 :     pg_be_scram_get_mechanisms(port, &sasl_mechs);
     915             :     /* Put another '\0' to mark that list is finished. */
     916          38 :     appendStringInfoChar(&sasl_mechs, '\0');
     917             : 
     918          38 :     sendAuthRequest(port, AUTH_REQ_SASL, sasl_mechs.data, sasl_mechs.len);
     919          38 :     pfree(sasl_mechs.data);
     920             : 
     921             :     /*
     922             :      * Loop through SASL message exchange.  This exchange can consist of
     923             :      * multiple messages sent in both directions.  First message is always
     924             :      * from the client.  All messages from client to server are password
     925             :      * packets (type 'p').
     926             :      */
     927          38 :     initial = true;
     928             :     do
     929             :     {
     930          74 :         pq_startmsgread();
     931          74 :         mtype = pq_getbyte();
     932          74 :         if (mtype != 'p')
     933             :         {
     934             :             /* Only log error if client didn't disconnect. */
     935           2 :             if (mtype != EOF)
     936             :             {
     937           0 :                 ereport(ERROR,
     938             :                         (errcode(ERRCODE_PROTOCOL_VIOLATION),
     939             :                          errmsg("expected SASL response, got message type %d",
     940             :                                 mtype)));
     941             :             }
     942             :             else
     943           2 :                 return STATUS_EOF;
     944             :         }
     945             : 
     946             :         /* Get the actual SASL message */
     947          72 :         initStringInfo(&buf);
     948          72 :         if (pq_getmessage(&buf, PG_MAX_SASL_MESSAGE_LENGTH))
     949             :         {
     950             :             /* EOF - pq_getmessage already logged error */
     951           0 :             pfree(buf.data);
     952           0 :             return STATUS_ERROR;
     953             :         }
     954             : 
     955          72 :         elog(DEBUG4, "processing received SASL response of length %d", buf.len);
     956             : 
     957             :         /*
     958             :          * The first SASLInitialResponse message is different from the others.
     959             :          * It indicates which SASL mechanism the client selected, and contains
     960             :          * an optional Initial Client Response payload.  The subsequent
     961             :          * SASLResponse messages contain just the SASL payload.
     962             :          */
     963          72 :         if (initial)
     964             :         {
     965             :             const char *selected_mech;
     966             : 
     967          36 :             selected_mech = pq_getmsgrawstring(&buf);
     968             : 
     969             :             /*
     970             :              * Initialize the status tracker for message exchanges.
     971             :              *
     972             :              * If the user doesn't exist, or doesn't have a valid password, or
     973             :              * it's expired, we still go through the motions of SASL
     974             :              * authentication, but tell the authentication method that the
     975             :              * authentication is "doomed". That is, it's going to fail, no
     976             :              * matter what.
     977             :              *
     978             :              * This is because we don't want to reveal to an attacker what
     979             :              * usernames are valid, nor which users have a valid password.
     980             :              */
     981          36 :             scram_opaq = pg_be_scram_init(port, selected_mech, shadow_pass);
     982             : 
     983          36 :             inputlen = pq_getmsgint(&buf, 4);
     984          36 :             if (inputlen == -1)
     985           0 :                 input = NULL;
     986             :             else
     987          36 :                 input = pq_getmsgbytes(&buf, inputlen);
     988             : 
     989          36 :             initial = false;
     990             :         }
     991             :         else
     992             :         {
     993          36 :             inputlen = buf.len;
     994          36 :             input = pq_getmsgbytes(&buf, buf.len);
     995             :         }
     996          72 :         pq_getmsgend(&buf);
     997             : 
     998             :         /*
     999             :          * The StringInfo guarantees that there's a \0 byte after the
    1000             :          * response.
    1001             :          */
    1002             :         Assert(input == NULL || input[inputlen] == '\0');
    1003             : 
    1004             :         /*
    1005             :          * we pass 'logdetail' as NULL when doing a mock authentication,
    1006             :          * because we should already have a better error message in that case
    1007             :          */
    1008          72 :         result = pg_be_scram_exchange(scram_opaq, input, inputlen,
    1009             :                                       &output, &outputlen,
    1010             :                                       logdetail);
    1011             : 
    1012             :         /* input buffer no longer used */
    1013          72 :         pfree(buf.data);
    1014             : 
    1015          72 :         if (output)
    1016             :         {
    1017             :             /*
    1018             :              * Negotiation generated data to be sent to the client.
    1019             :              */
    1020          62 :             elog(DEBUG4, "sending SASL challenge of length %u", outputlen);
    1021             : 
    1022          62 :             if (result == SASL_EXCHANGE_SUCCESS)
    1023          26 :                 sendAuthRequest(port, AUTH_REQ_SASL_FIN, output, outputlen);
    1024             :             else
    1025          36 :                 sendAuthRequest(port, AUTH_REQ_SASL_CONT, output, outputlen);
    1026             : 
    1027          62 :             pfree(output);
    1028             :         }
    1029          72 :     } while (result == SASL_EXCHANGE_CONTINUE);
    1030             : 
    1031             :     /* Oops, Something bad happened */
    1032          36 :     if (result != SASL_EXCHANGE_SUCCESS)
    1033             :     {
    1034          10 :         return STATUS_ERROR;
    1035             :     }
    1036             : 
    1037          26 :     return STATUS_OK;
    1038             : }
    1039             : 
    1040             : 
    1041             : /*----------------------------------------------------------------
    1042             :  * GSSAPI authentication system
    1043             :  *----------------------------------------------------------------
    1044             :  */
    1045             : #ifdef ENABLE_GSS
    1046             : static int
    1047             : pg_GSS_recvauth(Port *port)
    1048             : {
    1049             :     OM_uint32   maj_stat,
    1050             :                 min_stat,
    1051             :                 lmin_s,
    1052             :                 gflags;
    1053             :     int         mtype;
    1054             :     StringInfoData buf;
    1055             :     gss_buffer_desc gbuf;
    1056             : 
    1057             :     /*
    1058             :      * GSS auth is not supported for protocol versions before 3, because it
    1059             :      * relies on the overall message length word to determine the GSS payload
    1060             :      * size in AuthenticationGSSContinue and PasswordMessage messages. (This
    1061             :      * is, in fact, a design error in our GSS support, because protocol
    1062             :      * messages are supposed to be parsable without relying on the length
    1063             :      * word; but it's not worth changing it now.)
    1064             :      */
    1065             :     if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
    1066             :         ereport(FATAL,
    1067             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1068             :                  errmsg("GSSAPI is not supported in protocol version 2")));
    1069             : 
    1070             :     if (pg_krb_server_keyfile && strlen(pg_krb_server_keyfile) > 0)
    1071             :     {
    1072             :         /*
    1073             :          * Set default Kerberos keytab file for the Krb5 mechanism.
    1074             :          *
    1075             :          * setenv("KRB5_KTNAME", pg_krb_server_keyfile, 0); except setenv()
    1076             :          * not always available.
    1077             :          */
    1078             :         if (getenv("KRB5_KTNAME") == NULL)
    1079             :         {
    1080             :             size_t      kt_len = strlen(pg_krb_server_keyfile) + 14;
    1081             :             char       *kt_path = malloc(kt_len);
    1082             : 
    1083             :             if (!kt_path ||
    1084             :                 snprintf(kt_path, kt_len, "KRB5_KTNAME=%s",
    1085             :                          pg_krb_server_keyfile) != kt_len - 2 ||
    1086             :                 putenv(kt_path) != 0)
    1087             :             {
    1088             :                 ereport(LOG,
    1089             :                         (errcode(ERRCODE_OUT_OF_MEMORY),
    1090             :                          errmsg("out of memory")));
    1091             :                 return STATUS_ERROR;
    1092             :             }
    1093             :         }
    1094             :     }
    1095             : 
    1096             :     /*
    1097             :      * We accept any service principal that's present in our keytab. This
    1098             :      * increases interoperability between kerberos implementations that see
    1099             :      * for example case sensitivity differently, while not really opening up
    1100             :      * any vector of attack.
    1101             :      */
    1102             :     port->gss->cred = GSS_C_NO_CREDENTIAL;
    1103             : 
    1104             :     /*
    1105             :      * Initialize sequence with an empty context
    1106             :      */
    1107             :     port->gss->ctx = GSS_C_NO_CONTEXT;
    1108             : 
    1109             :     /*
    1110             :      * Loop through GSSAPI message exchange. This exchange can consist of
    1111             :      * multiple messages sent in both directions. First message is always from
    1112             :      * the client. All messages from client to server are password packets
    1113             :      * (type 'p').
    1114             :      */
    1115             :     do
    1116             :     {
    1117             :         pq_startmsgread();
    1118             : 
    1119             :         CHECK_FOR_INTERRUPTS();
    1120             : 
    1121             :         mtype = pq_getbyte();
    1122             :         if (mtype != 'p')
    1123             :         {
    1124             :             /* Only log error if client didn't disconnect. */
    1125             :             if (mtype != EOF)
    1126             :                 ereport(ERROR,
    1127             :                         (errcode(ERRCODE_PROTOCOL_VIOLATION),
    1128             :                          errmsg("expected GSS response, got message type %d",
    1129             :                                 mtype)));
    1130             :             return STATUS_ERROR;
    1131             :         }
    1132             : 
    1133             :         /* Get the actual GSS token */
    1134             :         initStringInfo(&buf);
    1135             :         if (pq_getmessage(&buf, PG_MAX_AUTH_TOKEN_LENGTH))
    1136             :         {
    1137             :             /* EOF - pq_getmessage already logged error */
    1138             :             pfree(buf.data);
    1139             :             return STATUS_ERROR;
    1140             :         }
    1141             : 
    1142             :         /* Map to GSSAPI style buffer */
    1143             :         gbuf.length = buf.len;
    1144             :         gbuf.value = buf.data;
    1145             : 
    1146             :         elog(DEBUG4, "processing received GSS token of length %u",
    1147             :              (unsigned int) gbuf.length);
    1148             : 
    1149             :         maj_stat = gss_accept_sec_context(&min_stat,
    1150             :                                           &port->gss->ctx,
    1151             :                                           port->gss->cred,
    1152             :                                           &gbuf,
    1153             :                                           GSS_C_NO_CHANNEL_BINDINGS,
    1154             :                                           &port->gss->name,
    1155             :                                           NULL,
    1156             :                                           &port->gss->outbuf,
    1157             :                                           &gflags,
    1158             :                                           NULL,
    1159             :                                           NULL);
    1160             : 
    1161             :         /* gbuf no longer used */
    1162             :         pfree(buf.data);
    1163             : 
    1164             :         elog(DEBUG5, "gss_accept_sec_context major: %d, "
    1165             :              "minor: %d, outlen: %u, outflags: %x",
    1166             :              maj_stat, min_stat,
    1167             :              (unsigned int) port->gss->outbuf.length, gflags);
    1168             : 
    1169             :         CHECK_FOR_INTERRUPTS();
    1170             : 
    1171             :         if (port->gss->outbuf.length != 0)
    1172             :         {
    1173             :             /*
    1174             :              * Negotiation generated data to be sent to the client.
    1175             :              */
    1176             :             elog(DEBUG4, "sending GSS response token of length %u",
    1177             :                  (unsigned int) port->gss->outbuf.length);
    1178             : 
    1179             :             sendAuthRequest(port, AUTH_REQ_GSS_CONT,
    1180             :                             port->gss->outbuf.value, port->gss->outbuf.length);
    1181             : 
    1182             :             gss_release_buffer(&lmin_s, &port->gss->outbuf);
    1183             :         }
    1184             : 
    1185             :         if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
    1186             :         {
    1187             :             gss_delete_sec_context(&lmin_s, &port->gss->ctx, GSS_C_NO_BUFFER);
    1188             :             pg_GSS_error(ERROR,
    1189             :                          _("accepting GSS security context failed"),
    1190             :                          maj_stat, min_stat);
    1191             :         }
    1192             : 
    1193             :         if (maj_stat == GSS_S_CONTINUE_NEEDED)
    1194             :             elog(DEBUG4, "GSS continue needed");
    1195             : 
    1196             :     } while (maj_stat == GSS_S_CONTINUE_NEEDED);
    1197             : 
    1198             :     if (port->gss->cred != GSS_C_NO_CREDENTIAL)
    1199             :     {
    1200             :         /*
    1201             :          * Release service principal credentials
    1202             :          */
    1203             :         gss_release_cred(&min_stat, &port->gss->cred);
    1204             :     }
    1205             :     return pg_GSS_checkauth(port);
    1206             : }
    1207             : 
    1208             : /*
    1209             :  * Check whether the GSSAPI-authenticated user is allowed to connect as the
    1210             :  * claimed username.
    1211             :  */
    1212             : static int
    1213             : pg_GSS_checkauth(Port *port)
    1214             : {
    1215             :     int         ret;
    1216             :     OM_uint32   maj_stat,
    1217             :                 min_stat,
    1218             :                 lmin_s;
    1219             :     gss_buffer_desc gbuf;
    1220             : 
    1221             :     /*
    1222             :      * Get the name of the user that authenticated, and compare it to the pg
    1223             :      * username that was specified for the connection.
    1224             :      */
    1225             :     maj_stat = gss_display_name(&min_stat, port->gss->name, &gbuf, NULL);
    1226             :     if (maj_stat != GSS_S_COMPLETE)
    1227             :         pg_GSS_error(ERROR,
    1228             :                      _("retrieving GSS user name failed"),
    1229             :                      maj_stat, min_stat);
    1230             : 
    1231             :     /*
    1232             :      * Copy the original name of the authenticated principal into our backend
    1233             :      * memory for display later.
    1234             :      */
    1235             :     port->gss->princ = MemoryContextStrdup(TopMemoryContext, gbuf.value);
    1236             : 
    1237             :     /*
    1238             :      * Split the username at the realm separator
    1239             :      */
    1240             :     if (strchr(gbuf.value, '@'))
    1241             :     {
    1242             :         char       *cp = strchr(gbuf.value, '@');
    1243             : 
    1244             :         /*
    1245             :          * If we are not going to include the realm in the username that is
    1246             :          * passed to the ident map, destructively modify it here to remove the
    1247             :          * realm. Then advance past the separator to check the realm.
    1248             :          */
    1249             :         if (!port->hba->include_realm)
    1250             :             *cp = '\0';
    1251             :         cp++;
    1252             : 
    1253             :         if (port->hba->krb_realm != NULL && strlen(port->hba->krb_realm))
    1254             :         {
    1255             :             /*
    1256             :              * Match the realm part of the name first
    1257             :              */
    1258             :             if (pg_krb_caseins_users)
    1259             :                 ret = pg_strcasecmp(port->hba->krb_realm, cp);
    1260             :             else
    1261             :                 ret = strcmp(port->hba->krb_realm, cp);
    1262             : 
    1263             :             if (ret)
    1264             :             {
    1265             :                 /* GSS realm does not match */
    1266             :                 elog(DEBUG2,
    1267             :                      "GSSAPI realm (%s) and configured realm (%s) don't match",
    1268             :                      cp, port->hba->krb_realm);
    1269             :                 gss_release_buffer(&lmin_s, &gbuf);
    1270             :                 return STATUS_ERROR;
    1271             :             }
    1272             :         }
    1273             :     }
    1274             :     else if (port->hba->krb_realm && strlen(port->hba->krb_realm))
    1275             :     {
    1276             :         elog(DEBUG2,
    1277             :              "GSSAPI did not return realm but realm matching was requested");
    1278             : 
    1279             :         gss_release_buffer(&lmin_s, &gbuf);
    1280             :         return STATUS_ERROR;
    1281             :     }
    1282             : 
    1283             :     ret = check_usermap(port->hba->usermap, port->user_name, gbuf.value,
    1284             :                         pg_krb_caseins_users);
    1285             : 
    1286             :     gss_release_buffer(&lmin_s, &gbuf);
    1287             : 
    1288             :     return ret;
    1289             : }
    1290             : #endif                          /* ENABLE_GSS */
    1291             : 
    1292             : 
    1293             : /*----------------------------------------------------------------
    1294             :  * SSPI authentication system
    1295             :  *----------------------------------------------------------------
    1296             :  */
    1297             : #ifdef ENABLE_SSPI
    1298             : 
    1299             : /*
    1300             :  * Generate an error for SSPI authentication.  The caller should apply
    1301             :  * _() to errmsg to make it translatable.
    1302             :  */
    1303             : static void
    1304             : pg_SSPI_error(int severity, const char *errmsg, SECURITY_STATUS r)
    1305             : {
    1306             :     char        sysmsg[256];
    1307             : 
    1308             :     if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS |
    1309             :                       FORMAT_MESSAGE_FROM_SYSTEM,
    1310             :                       NULL, r, 0,
    1311             :                       sysmsg, sizeof(sysmsg), NULL) == 0)
    1312             :         ereport(severity,
    1313             :                 (errmsg_internal("%s", errmsg),
    1314             :                  errdetail_internal("SSPI error %x", (unsigned int) r)));
    1315             :     else
    1316             :         ereport(severity,
    1317             :                 (errmsg_internal("%s", errmsg),
    1318             :                  errdetail_internal("%s (%x)", sysmsg, (unsigned int) r)));
    1319             : }
    1320             : 
    1321             : static int
    1322             : pg_SSPI_recvauth(Port *port)
    1323             : {
    1324             :     int         mtype;
    1325             :     StringInfoData buf;
    1326             :     SECURITY_STATUS r;
    1327             :     CredHandle  sspicred;
    1328             :     CtxtHandle *sspictx = NULL,
    1329             :                 newctx;
    1330             :     TimeStamp   expiry;
    1331             :     ULONG       contextattr;
    1332             :     SecBufferDesc inbuf;
    1333             :     SecBufferDesc outbuf;
    1334             :     SecBuffer   OutBuffers[1];
    1335             :     SecBuffer   InBuffers[1];
    1336             :     HANDLE      token;
    1337             :     TOKEN_USER *tokenuser;
    1338             :     DWORD       retlen;
    1339             :     char        accountname[MAXPGPATH];
    1340             :     char        domainname[MAXPGPATH];
    1341             :     DWORD       accountnamesize = sizeof(accountname);
    1342             :     DWORD       domainnamesize = sizeof(domainname);
    1343             :     SID_NAME_USE accountnameuse;
    1344             :     HMODULE     secur32;
    1345             : 
    1346             :     QUERY_SECURITY_CONTEXT_TOKEN_FN _QuerySecurityContextToken;
    1347             : 
    1348             :     /*
    1349             :      * SSPI auth is not supported for protocol versions before 3, because it
    1350             :      * relies on the overall message length word to determine the SSPI payload
    1351             :      * size in AuthenticationGSSContinue and PasswordMessage messages. (This
    1352             :      * is, in fact, a design error in our SSPI support, because protocol
    1353             :      * messages are supposed to be parsable without relying on the length
    1354             :      * word; but it's not worth changing it now.)
    1355             :      */
    1356             :     if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
    1357             :         ereport(FATAL,
    1358             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1359             :                  errmsg("SSPI is not supported in protocol version 2")));
    1360             : 
    1361             :     /*
    1362             :      * Acquire a handle to the server credentials.
    1363             :      */
    1364             :     r = AcquireCredentialsHandle(NULL,
    1365             :                                  "negotiate",
    1366             :                                  SECPKG_CRED_INBOUND,
    1367             :                                  NULL,
    1368             :                                  NULL,
    1369             :                                  NULL,
    1370             :                                  NULL,
    1371             :                                  &sspicred,
    1372             :                                  &expiry);
    1373             :     if (r != SEC_E_OK)
    1374             :         pg_SSPI_error(ERROR, _("could not acquire SSPI credentials"), r);
    1375             : 
    1376             :     /*
    1377             :      * Loop through SSPI message exchange. This exchange can consist of
    1378             :      * multiple messages sent in both directions. First message is always from
    1379             :      * the client. All messages from client to server are password packets
    1380             :      * (type 'p').
    1381             :      */
    1382             :     do
    1383             :     {
    1384             :         pq_startmsgread();
    1385             :         mtype = pq_getbyte();
    1386             :         if (mtype != 'p')
    1387             :         {
    1388             :             if (sspictx != NULL)
    1389             :             {
    1390             :                 DeleteSecurityContext(sspictx);
    1391             :                 free(sspictx);
    1392             :             }
    1393             :             FreeCredentialsHandle(&sspicred);
    1394             : 
    1395             :             /* Only log error if client didn't disconnect. */
    1396             :             if (mtype != EOF)
    1397             :                 ereport(ERROR,
    1398             :                         (errcode(ERRCODE_PROTOCOL_VIOLATION),
    1399             :                          errmsg("expected SSPI response, got message type %d",
    1400             :                                 mtype)));
    1401             :             return STATUS_ERROR;
    1402             :         }
    1403             : 
    1404             :         /* Get the actual SSPI token */
    1405             :         initStringInfo(&buf);
    1406             :         if (pq_getmessage(&buf, PG_MAX_AUTH_TOKEN_LENGTH))
    1407             :         {
    1408             :             /* EOF - pq_getmessage already logged error */
    1409             :             pfree(buf.data);
    1410             :             if (sspictx != NULL)
    1411             :             {
    1412             :                 DeleteSecurityContext(sspictx);
    1413             :                 free(sspictx);
    1414             :             }
    1415             :             FreeCredentialsHandle(&sspicred);
    1416             :             return STATUS_ERROR;
    1417             :         }
    1418             : 
    1419             :         /* Map to SSPI style buffer */
    1420             :         inbuf.ulVersion = SECBUFFER_VERSION;
    1421             :         inbuf.cBuffers = 1;
    1422             :         inbuf.pBuffers = InBuffers;
    1423             :         InBuffers[0].pvBuffer = buf.data;
    1424             :         InBuffers[0].cbBuffer = buf.len;
    1425             :         InBuffers[0].BufferType = SECBUFFER_TOKEN;
    1426             : 
    1427             :         /* Prepare output buffer */
    1428             :         OutBuffers[0].pvBuffer = NULL;
    1429             :         OutBuffers[0].BufferType = SECBUFFER_TOKEN;
    1430             :         OutBuffers[0].cbBuffer = 0;
    1431             :         outbuf.cBuffers = 1;
    1432             :         outbuf.pBuffers = OutBuffers;
    1433             :         outbuf.ulVersion = SECBUFFER_VERSION;
    1434             : 
    1435             :         elog(DEBUG4, "processing received SSPI token of length %u",
    1436             :              (unsigned int) buf.len);
    1437             : 
    1438             :         r = AcceptSecurityContext(&sspicred,
    1439             :                                   sspictx,
    1440             :                                   &inbuf,
    1441             :                                   ASC_REQ_ALLOCATE_MEMORY,
    1442             :                                   SECURITY_NETWORK_DREP,
    1443             :                                   &newctx,
    1444             :                                   &outbuf,
    1445             :                                   &contextattr,
    1446             :                                   NULL);
    1447             : 
    1448             :         /* input buffer no longer used */
    1449             :         pfree(buf.data);
    1450             : 
    1451             :         if (outbuf.cBuffers > 0 && outbuf.pBuffers[0].cbBuffer > 0)
    1452             :         {
    1453             :             /*
    1454             :              * Negotiation generated data to be sent to the client.
    1455             :              */
    1456             :             elog(DEBUG4, "sending SSPI response token of length %u",
    1457             :                  (unsigned int) outbuf.pBuffers[0].cbBuffer);
    1458             : 
    1459             :             port->gss->outbuf.length = outbuf.pBuffers[0].cbBuffer;
    1460             :             port->gss->outbuf.value = outbuf.pBuffers[0].pvBuffer;
    1461             : 
    1462             :             sendAuthRequest(port, AUTH_REQ_GSS_CONT,
    1463             :                             port->gss->outbuf.value, port->gss->outbuf.length);
    1464             : 
    1465             :             FreeContextBuffer(outbuf.pBuffers[0].pvBuffer);
    1466             :         }
    1467             : 
    1468             :         if (r != SEC_E_OK && r != SEC_I_CONTINUE_NEEDED)
    1469             :         {
    1470             :             if (sspictx != NULL)
    1471             :             {
    1472             :                 DeleteSecurityContext(sspictx);
    1473             :                 free(sspictx);
    1474             :             }
    1475             :             FreeCredentialsHandle(&sspicred);
    1476             :             pg_SSPI_error(ERROR,
    1477             :                           _("could not accept SSPI security context"), r);
    1478             :         }
    1479             : 
    1480             :         /*
    1481             :          * Overwrite the current context with the one we just received. If
    1482             :          * sspictx is NULL it was the first loop and we need to allocate a
    1483             :          * buffer for it. On subsequent runs, we can just overwrite the buffer
    1484             :          * contents since the size does not change.
    1485             :          */
    1486             :         if (sspictx == NULL)
    1487             :         {
    1488             :             sspictx = malloc(sizeof(CtxtHandle));
    1489             :             if (sspictx == NULL)
    1490             :                 ereport(ERROR,
    1491             :                         (errmsg("out of memory")));
    1492             :         }
    1493             : 
    1494             :         memcpy(sspictx, &newctx, sizeof(CtxtHandle));
    1495             : 
    1496             :         if (r == SEC_I_CONTINUE_NEEDED)
    1497             :             elog(DEBUG4, "SSPI continue needed");
    1498             : 
    1499             :     } while (r == SEC_I_CONTINUE_NEEDED);
    1500             : 
    1501             : 
    1502             :     /*
    1503             :      * Release service principal credentials
    1504             :      */
    1505             :     FreeCredentialsHandle(&sspicred);
    1506             : 
    1507             : 
    1508             :     /*
    1509             :      * SEC_E_OK indicates that authentication is now complete.
    1510             :      *
    1511             :      * Get the name of the user that authenticated, and compare it to the pg
    1512             :      * username that was specified for the connection.
    1513             :      *
    1514             :      * MingW is missing the export for QuerySecurityContextToken in the
    1515             :      * secur32 library, so we have to load it dynamically.
    1516             :      */
    1517             : 
    1518             :     secur32 = LoadLibrary("SECUR32.DLL");
    1519             :     if (secur32 == NULL)
    1520             :         ereport(ERROR,
    1521             :                 (errmsg("could not load library \"%s\": error code %lu",
    1522             :                         "SECUR32.DLL", GetLastError())));
    1523             : 
    1524             :     _QuerySecurityContextToken = (QUERY_SECURITY_CONTEXT_TOKEN_FN)
    1525             :         GetProcAddress(secur32, "QuerySecurityContextToken");
    1526             :     if (_QuerySecurityContextToken == NULL)
    1527             :     {
    1528             :         FreeLibrary(secur32);
    1529             :         ereport(ERROR,
    1530             :                 (errmsg_internal("could not locate QuerySecurityContextToken in secur32.dll: error code %lu",
    1531             :                                  GetLastError())));
    1532             :     }
    1533             : 
    1534             :     r = (_QuerySecurityContextToken) (sspictx, &token);
    1535             :     if (r != SEC_E_OK)
    1536             :     {
    1537             :         FreeLibrary(secur32);
    1538             :         pg_SSPI_error(ERROR,
    1539             :                       _("could not get token from SSPI security context"), r);
    1540             :     }
    1541             : 
    1542             :     FreeLibrary(secur32);
    1543             : 
    1544             :     /*
    1545             :      * No longer need the security context, everything from here on uses the
    1546             :      * token instead.
    1547             :      */
    1548             :     DeleteSecurityContext(sspictx);
    1549             :     free(sspictx);
    1550             : 
    1551             :     if (!GetTokenInformation(token, TokenUser, NULL, 0, &retlen) && GetLastError() != 122)
    1552             :         ereport(ERROR,
    1553             :                 (errmsg_internal("could not get token information buffer size: error code %lu",
    1554             :                                  GetLastError())));
    1555             : 
    1556             :     tokenuser = malloc(retlen);
    1557             :     if (tokenuser == NULL)
    1558             :         ereport(ERROR,
    1559             :                 (errmsg("out of memory")));
    1560             : 
    1561             :     if (!GetTokenInformation(token, TokenUser, tokenuser, retlen, &retlen))
    1562             :         ereport(ERROR,
    1563             :                 (errmsg_internal("could not get token information: error code %lu",
    1564             :                                  GetLastError())));
    1565             : 
    1566             :     CloseHandle(token);
    1567             : 
    1568             :     if (!LookupAccountSid(NULL, tokenuser->User.Sid, accountname, &accountnamesize,
    1569             :                           domainname, &domainnamesize, &accountnameuse))
    1570             :         ereport(ERROR,
    1571             :                 (errmsg_internal("could not look up account SID: error code %lu",
    1572             :                                  GetLastError())));
    1573             : 
    1574             :     free(tokenuser);
    1575             : 
    1576             :     if (!port->hba->compat_realm)
    1577             :     {
    1578             :         int         status = pg_SSPI_make_upn(accountname, sizeof(accountname),
    1579             :                                               domainname, sizeof(domainname),
    1580             :                                               port->hba->upn_username);
    1581             : 
    1582             :         if (status != STATUS_OK)
    1583             :             /* Error already reported from pg_SSPI_make_upn */
    1584             :             return status;
    1585             :     }
    1586             : 
    1587             :     /*
    1588             :      * Compare realm/domain if requested. In SSPI, always compare case
    1589             :      * insensitive.
    1590             :      */
    1591             :     if (port->hba->krb_realm && strlen(port->hba->krb_realm))
    1592             :     {
    1593             :         if (pg_strcasecmp(port->hba->krb_realm, domainname) != 0)
    1594             :         {
    1595             :             elog(DEBUG2,
    1596             :                  "SSPI domain (%s) and configured domain (%s) don't match",
    1597             :                  domainname, port->hba->krb_realm);
    1598             : 
    1599             :             return STATUS_ERROR;
    1600             :         }
    1601             :     }
    1602             : 
    1603             :     /*
    1604             :      * We have the username (without domain/realm) in accountname, compare to
    1605             :      * the supplied value. In SSPI, always compare case insensitive.
    1606             :      *
    1607             :      * If set to include realm, append it in <username>@<realm> format.
    1608             :      */
    1609             :     if (port->hba->include_realm)
    1610             :     {
    1611             :         char       *namebuf;
    1612             :         int         retval;
    1613             : 
    1614             :         namebuf = psprintf("%s@%s", accountname, domainname);
    1615             :         retval = check_usermap(port->hba->usermap, port->user_name, namebuf, true);
    1616             :         pfree(namebuf);
    1617             :         return retval;
    1618             :     }
    1619             :     else
    1620             :         return check_usermap(port->hba->usermap, port->user_name, accountname, true);
    1621             : }
    1622             : 
    1623             : /*
    1624             :  * Replaces the domainname with the Kerberos realm name,
    1625             :  * and optionally the accountname with the Kerberos user name.
    1626             :  */
    1627             : static int
    1628             : pg_SSPI_make_upn(char *accountname,
    1629             :                  size_t accountnamesize,
    1630             :                  char *domainname,
    1631             :                  size_t domainnamesize,
    1632             :                  bool update_accountname)
    1633             : {
    1634             :     char       *samname;
    1635             :     char       *upname = NULL;
    1636             :     char       *p = NULL;
    1637             :     ULONG       upnamesize = 0;
    1638             :     size_t      upnamerealmsize;
    1639             :     BOOLEAN     res;
    1640             : 
    1641             :     /*
    1642             :      * Build SAM name (DOMAIN\user), then translate to UPN
    1643             :      * (user@kerberos.realm). The realm name is returned in lower case, but
    1644             :      * that is fine because in SSPI auth, string comparisons are always
    1645             :      * case-insensitive.
    1646             :      */
    1647             : 
    1648             :     samname = psprintf("%s\\%s", domainname, accountname);
    1649             :     res = TranslateName(samname, NameSamCompatible, NameUserPrincipal,
    1650             :                         NULL, &upnamesize);
    1651             : 
    1652             :     if ((!res && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
    1653             :         || upnamesize == 0)
    1654             :     {
    1655             :         pfree(samname);
    1656             :         ereport(LOG,
    1657             :                 (errcode(ERRCODE_INVALID_ROLE_SPECIFICATION),
    1658             :                  errmsg("could not translate name")));
    1659             :         return STATUS_ERROR;
    1660             :     }
    1661             : 
    1662             :     /* upnamesize includes the terminating NUL. */
    1663             :     upname = palloc(upnamesize);
    1664             : 
    1665             :     res = TranslateName(samname, NameSamCompatible, NameUserPrincipal,
    1666             :                         upname, &upnamesize);
    1667             : 
    1668             :     pfree(samname);
    1669             :     if (res)
    1670             :         p = strchr(upname, '@');
    1671             : 
    1672             :     if (!res || p == NULL)
    1673             :     {
    1674             :         pfree(upname);
    1675             :         ereport(LOG,
    1676             :                 (errcode(ERRCODE_INVALID_ROLE_SPECIFICATION),
    1677             :                  errmsg("could not translate name")));
    1678             :         return STATUS_ERROR;
    1679             :     }
    1680             : 
    1681             :     /* Length of realm name after the '@', including the NUL. */
    1682             :     upnamerealmsize = upnamesize - (p - upname + 1);
    1683             : 
    1684             :     /* Replace domainname with realm name. */
    1685             :     if (upnamerealmsize > domainnamesize)
    1686             :     {
    1687             :         pfree(upname);
    1688             :         ereport(LOG,
    1689             :                 (errcode(ERRCODE_INVALID_ROLE_SPECIFICATION),
    1690             :                  errmsg("realm name too long")));
    1691             :         return STATUS_ERROR;
    1692             :     }
    1693             : 
    1694             :     /* Length is now safe. */
    1695             :     strcpy(domainname, p + 1);
    1696             : 
    1697             :     /* Replace account name as well (in case UPN != SAM)? */
    1698             :     if (update_accountname)
    1699             :     {
    1700             :         if ((p - upname + 1) > accountnamesize)
    1701             :         {
    1702             :             pfree(upname);
    1703             :             ereport(LOG,
    1704             :                     (errcode(ERRCODE_INVALID_ROLE_SPECIFICATION),
    1705             :                      errmsg("translated account name too long")));
    1706             :             return STATUS_ERROR;
    1707             :         }
    1708             : 
    1709             :         *p = 0;
    1710             :         strcpy(accountname, upname);
    1711             :     }
    1712             : 
    1713             :     pfree(upname);
    1714             :     return STATUS_OK;
    1715             : }
    1716             : #endif                          /* ENABLE_SSPI */
    1717             : 
    1718             : 
    1719             : 
    1720             : /*----------------------------------------------------------------
    1721             :  * Ident authentication system
    1722             :  *----------------------------------------------------------------
    1723             :  */
    1724             : 
    1725             : /*
    1726             :  *  Parse the string "*ident_response" as a response from a query to an Ident
    1727             :  *  server.  If it's a normal response indicating a user name, return true
    1728             :  *  and store the user name at *ident_user. If it's anything else,
    1729             :  *  return false.
    1730             :  */
    1731             : static bool
    1732           0 : interpret_ident_response(const char *ident_response,
    1733             :                          char *ident_user)
    1734             : {
    1735           0 :     const char *cursor = ident_response;    /* Cursor into *ident_response */
    1736             : 
    1737             :     /*
    1738             :      * Ident's response, in the telnet tradition, should end in crlf (\r\n).
    1739             :      */
    1740           0 :     if (strlen(ident_response) < 2)
    1741           0 :         return false;
    1742           0 :     else if (ident_response[strlen(ident_response) - 2] != '\r')
    1743           0 :         return false;
    1744             :     else
    1745             :     {
    1746           0 :         while (*cursor != ':' && *cursor != '\r')
    1747           0 :             cursor++;           /* skip port field */
    1748             : 
    1749           0 :         if (*cursor != ':')
    1750           0 :             return false;
    1751             :         else
    1752             :         {
    1753             :             /* We're positioned to colon before response type field */
    1754             :             char        response_type[80];
    1755             :             int         i;      /* Index into *response_type */
    1756             : 
    1757           0 :             cursor++;           /* Go over colon */
    1758           0 :             while (pg_isblank(*cursor))
    1759           0 :                 cursor++;       /* skip blanks */
    1760           0 :             i = 0;
    1761           0 :             while (*cursor != ':' && *cursor != '\r' && !pg_isblank(*cursor) &&
    1762             :                    i < (int) (sizeof(response_type) - 1))
    1763           0 :                 response_type[i++] = *cursor++;
    1764           0 :             response_type[i] = '\0';
    1765           0 :             while (pg_isblank(*cursor))
    1766           0 :                 cursor++;       /* skip blanks */
    1767           0 :             if (strcmp(response_type, "USERID") != 0)
    1768           0 :                 return false;
    1769             :             else
    1770             :             {
    1771             :                 /*
    1772             :                  * It's a USERID response.  Good.  "cursor" should be pointing
    1773             :                  * to the colon that precedes the operating system type.
    1774             :                  */
    1775           0 :                 if (*cursor != ':')
    1776           0 :                     return false;
    1777             :                 else
    1778             :                 {
    1779           0 :                     cursor++;   /* Go over colon */
    1780             :                     /* Skip over operating system field. */
    1781           0 :                     while (*cursor != ':' && *cursor != '\r')
    1782           0 :                         cursor++;
    1783           0 :                     if (*cursor != ':')
    1784           0 :                         return false;
    1785             :                     else
    1786             :                     {
    1787             :                         int         i;  /* Index into *ident_user */
    1788             : 
    1789           0 :                         cursor++;   /* Go over colon */
    1790           0 :                         while (pg_isblank(*cursor))
    1791           0 :                             cursor++;   /* skip blanks */
    1792             :                         /* Rest of line is user name.  Copy it over. */
    1793           0 :                         i = 0;
    1794           0 :                         while (*cursor != '\r' && i < IDENT_USERNAME_MAX)
    1795           0 :                             ident_user[i++] = *cursor++;
    1796           0 :                         ident_user[i] = '\0';
    1797           0 :                         return true;
    1798             :                     }
    1799             :                 }
    1800             :             }
    1801             :         }
    1802             :     }
    1803             : }
    1804             : 
    1805             : 
    1806             : /*
    1807             :  *  Talk to the ident server on "remote_addr" and find out who
    1808             :  *  owns the tcp connection to "local_addr"
    1809             :  *  If the username is successfully retrieved, check the usermap.
    1810             :  *
    1811             :  *  XXX: Using WaitLatchOrSocket() and doing a CHECK_FOR_INTERRUPTS() if the
    1812             :  *  latch was set would improve the responsiveness to timeouts/cancellations.
    1813             :  */
    1814             : static int
    1815           0 : ident_inet(hbaPort *port)
    1816             : {
    1817           0 :     const SockAddr remote_addr = port->raddr;
    1818           0 :     const SockAddr local_addr = port->laddr;
    1819             :     char        ident_user[IDENT_USERNAME_MAX + 1];
    1820           0 :     pgsocket    sock_fd = PGINVALID_SOCKET; /* for talking to Ident server */
    1821             :     int         rc;             /* Return code from a locally called function */
    1822             :     bool        ident_return;
    1823             :     char        remote_addr_s[NI_MAXHOST];
    1824             :     char        remote_port[NI_MAXSERV];
    1825             :     char        local_addr_s[NI_MAXHOST];
    1826             :     char        local_port[NI_MAXSERV];
    1827             :     char        ident_port[NI_MAXSERV];
    1828             :     char        ident_query[80];
    1829             :     char        ident_response[80 + IDENT_USERNAME_MAX];
    1830           0 :     struct addrinfo *ident_serv = NULL,
    1831           0 :                *la = NULL,
    1832             :                 hints;
    1833             : 
    1834             :     /*
    1835             :      * Might look a little weird to first convert it to text and then back to
    1836             :      * sockaddr, but it's protocol independent.
    1837             :      */
    1838           0 :     pg_getnameinfo_all(&remote_addr.addr, remote_addr.salen,
    1839             :                        remote_addr_s, sizeof(remote_addr_s),
    1840             :                        remote_port, sizeof(remote_port),
    1841             :                        NI_NUMERICHOST | NI_NUMERICSERV);
    1842           0 :     pg_getnameinfo_all(&local_addr.addr, local_addr.salen,
    1843             :                        local_addr_s, sizeof(local_addr_s),
    1844             :                        local_port, sizeof(local_port),
    1845             :                        NI_NUMERICHOST | NI_NUMERICSERV);
    1846             : 
    1847           0 :     snprintf(ident_port, sizeof(ident_port), "%d", IDENT_PORT);
    1848           0 :     hints.ai_flags = AI_NUMERICHOST;
    1849           0 :     hints.ai_family = remote_addr.addr.ss_family;
    1850           0 :     hints.ai_socktype = SOCK_STREAM;
    1851           0 :     hints.ai_protocol = 0;
    1852           0 :     hints.ai_addrlen = 0;
    1853           0 :     hints.ai_canonname = NULL;
    1854           0 :     hints.ai_addr = NULL;
    1855           0 :     hints.ai_next = NULL;
    1856           0 :     rc = pg_getaddrinfo_all(remote_addr_s, ident_port, &hints, &ident_serv);
    1857           0 :     if (rc || !ident_serv)
    1858             :     {
    1859             :         /* we don't expect this to happen */
    1860           0 :         ident_return = false;
    1861           0 :         goto ident_inet_done;
    1862             :     }
    1863             : 
    1864           0 :     hints.ai_flags = AI_NUMERICHOST;
    1865           0 :     hints.ai_family = local_addr.addr.ss_family;
    1866           0 :     hints.ai_socktype = SOCK_STREAM;
    1867           0 :     hints.ai_protocol = 0;
    1868           0 :     hints.ai_addrlen = 0;
    1869           0 :     hints.ai_canonname = NULL;
    1870           0 :     hints.ai_addr = NULL;
    1871           0 :     hints.ai_next = NULL;
    1872           0 :     rc = pg_getaddrinfo_all(local_addr_s, NULL, &hints, &la);
    1873           0 :     if (rc || !la)
    1874             :     {
    1875             :         /* we don't expect this to happen */
    1876           0 :         ident_return = false;
    1877           0 :         goto ident_inet_done;
    1878             :     }
    1879             : 
    1880           0 :     sock_fd = socket(ident_serv->ai_family, ident_serv->ai_socktype,
    1881           0 :                      ident_serv->ai_protocol);
    1882           0 :     if (sock_fd == PGINVALID_SOCKET)
    1883             :     {
    1884           0 :         ereport(LOG,
    1885             :                 (errcode_for_socket_access(),
    1886             :                  errmsg("could not create socket for Ident connection: %m")));
    1887           0 :         ident_return = false;
    1888           0 :         goto ident_inet_done;
    1889             :     }
    1890             : 
    1891             :     /*
    1892             :      * Bind to the address which the client originally contacted, otherwise
    1893             :      * the ident server won't be able to match up the right connection. This
    1894             :      * is necessary if the PostgreSQL server is running on an IP alias.
    1895             :      */
    1896           0 :     rc = bind(sock_fd, la->ai_addr, la->ai_addrlen);
    1897           0 :     if (rc != 0)
    1898             :     {
    1899           0 :         ereport(LOG,
    1900             :                 (errcode_for_socket_access(),
    1901             :                  errmsg("could not bind to local address \"%s\": %m",
    1902             :                         local_addr_s)));
    1903           0 :         ident_return = false;
    1904           0 :         goto ident_inet_done;
    1905             :     }
    1906             : 
    1907           0 :     rc = connect(sock_fd, ident_serv->ai_addr,
    1908           0 :                  ident_serv->ai_addrlen);
    1909           0 :     if (rc != 0)
    1910             :     {
    1911           0 :         ereport(LOG,
    1912             :                 (errcode_for_socket_access(),
    1913             :                  errmsg("could not connect to Ident server at address \"%s\", port %s: %m",
    1914             :                         remote_addr_s, ident_port)));
    1915           0 :         ident_return = false;
    1916           0 :         goto ident_inet_done;
    1917             :     }
    1918             : 
    1919             :     /* The query we send to the Ident server */
    1920           0 :     snprintf(ident_query, sizeof(ident_query), "%s,%s\r\n",
    1921             :              remote_port, local_port);
    1922             : 
    1923             :     /* loop in case send is interrupted */
    1924             :     do
    1925             :     {
    1926           0 :         CHECK_FOR_INTERRUPTS();
    1927             : 
    1928           0 :         rc = send(sock_fd, ident_query, strlen(ident_query), 0);
    1929           0 :     } while (rc < 0 && errno == EINTR);
    1930             : 
    1931           0 :     if (rc < 0)
    1932             :     {
    1933           0 :         ereport(LOG,
    1934             :                 (errcode_for_socket_access(),
    1935             :                  errmsg("could not send query to Ident server at address \"%s\", port %s: %m",
    1936             :                         remote_addr_s, ident_port)));
    1937           0 :         ident_return = false;
    1938           0 :         goto ident_inet_done;
    1939             :     }
    1940             : 
    1941             :     do
    1942             :     {
    1943           0 :         CHECK_FOR_INTERRUPTS();
    1944             : 
    1945           0 :         rc = recv(sock_fd, ident_response, sizeof(ident_response) - 1, 0);
    1946           0 :     } while (rc < 0 && errno == EINTR);
    1947             : 
    1948           0 :     if (rc < 0)
    1949             :     {
    1950           0 :         ereport(LOG,
    1951             :                 (errcode_for_socket_access(),
    1952             :                  errmsg("could not receive response from Ident server at address \"%s\", port %s: %m",
    1953             :                         remote_addr_s, ident_port)));
    1954           0 :         ident_return = false;
    1955           0 :         goto ident_inet_done;
    1956             :     }
    1957             : 
    1958           0 :     ident_response[rc] = '\0';
    1959           0 :     ident_return = interpret_ident_response(ident_response, ident_user);
    1960           0 :     if (!ident_return)
    1961           0 :         ereport(LOG,
    1962             :                 (errmsg("invalidly formatted response from Ident server: \"%s\"",
    1963             :                         ident_response)));
    1964             : 
    1965           0 : ident_inet_done:
    1966           0 :     if (sock_fd != PGINVALID_SOCKET)
    1967           0 :         closesocket(sock_fd);
    1968           0 :     if (ident_serv)
    1969           0 :         pg_freeaddrinfo_all(remote_addr.addr.ss_family, ident_serv);
    1970           0 :     if (la)
    1971           0 :         pg_freeaddrinfo_all(local_addr.addr.ss_family, la);
    1972             : 
    1973           0 :     if (ident_return)
    1974             :         /* Success! Check the usermap */
    1975           0 :         return check_usermap(port->hba->usermap, port->user_name, ident_user, false);
    1976           0 :     return STATUS_ERROR;
    1977             : }
    1978             : 
    1979             : 
    1980             : /*----------------------------------------------------------------
    1981             :  * Peer authentication system
    1982             :  *----------------------------------------------------------------
    1983             :  */
    1984             : 
    1985             : /*
    1986             :  *  Ask kernel about the credentials of the connecting process,
    1987             :  *  determine the symbolic name of the corresponding user, and check
    1988             :  *  if valid per the usermap.
    1989             :  *
    1990             :  *  Iff authorized, return STATUS_OK, otherwise return STATUS_ERROR.
    1991             :  */
    1992             : static int
    1993           0 : auth_peer(hbaPort *port)
    1994             : {
    1995             :     uid_t       uid;
    1996             :     gid_t       gid;
    1997             : #ifndef WIN32
    1998             :     struct passwd *pw;
    1999             :     char       *peer_user;
    2000             :     int         ret;
    2001             : #endif
    2002             : 
    2003           0 :     if (getpeereid(port->sock, &uid, &gid) != 0)
    2004             :     {
    2005             :         /* Provide special error message if getpeereid is a stub */
    2006           0 :         if (errno == ENOSYS)
    2007           0 :             ereport(LOG,
    2008             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2009             :                      errmsg("peer authentication is not supported on this platform")));
    2010             :         else
    2011           0 :             ereport(LOG,
    2012             :                     (errcode_for_socket_access(),
    2013             :                      errmsg("could not get peer credentials: %m")));
    2014           0 :         return STATUS_ERROR;
    2015             :     }
    2016             : 
    2017             : #ifndef WIN32
    2018           0 :     errno = 0;                  /* clear errno before call */
    2019           0 :     pw = getpwuid(uid);
    2020           0 :     if (!pw)
    2021             :     {
    2022           0 :         int         save_errno = errno;
    2023             : 
    2024           0 :         ereport(LOG,
    2025             :                 (errmsg("could not look up local user ID %ld: %s",
    2026             :                         (long) uid,
    2027             :                         save_errno ? strerror(save_errno) : _("user does not exist"))));
    2028           0 :         return STATUS_ERROR;
    2029             :     }
    2030             : 
    2031             :     /* Make a copy of static getpw*() result area. */
    2032           0 :     peer_user = pstrdup(pw->pw_name);
    2033             : 
    2034           0 :     ret = check_usermap(port->hba->usermap, port->user_name, peer_user, false);
    2035             : 
    2036           0 :     pfree(peer_user);
    2037             : 
    2038           0 :     return ret;
    2039             : #else
    2040             :     /* should have failed with ENOSYS above */
    2041             :     Assert(false);
    2042             :     return STATUS_ERROR;
    2043             : #endif
    2044             : }
    2045             : 
    2046             : 
    2047             : /*----------------------------------------------------------------
    2048             :  * PAM authentication system
    2049             :  *----------------------------------------------------------------
    2050             :  */
    2051             : #ifdef USE_PAM
    2052             : 
    2053             : /*
    2054             :  * PAM conversation function
    2055             :  */
    2056             : 
    2057             : static int
    2058           0 : pam_passwd_conv_proc(int num_msg, const struct pam_message **msg,
    2059             :                      struct pam_response **resp, void *appdata_ptr)
    2060             : {
    2061             :     const char *passwd;
    2062             :     struct pam_response *reply;
    2063             :     int         i;
    2064             : 
    2065           0 :     if (appdata_ptr)
    2066           0 :         passwd = (char *) appdata_ptr;
    2067             :     else
    2068             :     {
    2069             :         /*
    2070             :          * Workaround for Solaris 2.6 where the PAM library is broken and does
    2071             :          * not pass appdata_ptr to the conversation routine
    2072             :          */
    2073           0 :         passwd = pam_passwd;
    2074             :     }
    2075             : 
    2076           0 :     *resp = NULL;               /* in case of error exit */
    2077             : 
    2078           0 :     if (num_msg <= 0 || num_msg > PAM_MAX_NUM_MSG)
    2079           0 :         return PAM_CONV_ERR;
    2080             : 
    2081             :     /*
    2082             :      * Explicitly not using palloc here - PAM will free this memory in
    2083             :      * pam_end()
    2084             :      */
    2085           0 :     if ((reply = calloc(num_msg, sizeof(struct pam_response))) == NULL)
    2086             :     {
    2087           0 :         ereport(LOG,
    2088             :                 (errcode(ERRCODE_OUT_OF_MEMORY),
    2089             :                  errmsg("out of memory")));
    2090           0 :         return PAM_CONV_ERR;
    2091             :     }
    2092             : 
    2093           0 :     for (i = 0; i < num_msg; i++)
    2094             :     {
    2095           0 :         switch (msg[i]->msg_style)
    2096             :         {
    2097           0 :             case PAM_PROMPT_ECHO_OFF:
    2098           0 :                 if (strlen(passwd) == 0)
    2099             :                 {
    2100             :                     /*
    2101             :                      * Password wasn't passed to PAM the first time around -
    2102             :                      * let's go ask the client to send a password, which we
    2103             :                      * then stuff into PAM.
    2104             :                      */
    2105           0 :                     sendAuthRequest(pam_port_cludge, AUTH_REQ_PASSWORD, NULL, 0);
    2106           0 :                     passwd = recv_password_packet(pam_port_cludge);
    2107           0 :                     if (passwd == NULL)
    2108             :                     {
    2109             :                         /*
    2110             :                          * Client didn't want to send password.  We
    2111             :                          * intentionally do not log anything about this,
    2112             :                          * either here or at higher levels.
    2113             :                          */
    2114           0 :                         pam_no_password = true;
    2115           0 :                         goto fail;
    2116             :                     }
    2117             :                 }
    2118           0 :                 if ((reply[i].resp = strdup(passwd)) == NULL)
    2119           0 :                     goto fail;
    2120           0 :                 reply[i].resp_retcode = PAM_SUCCESS;
    2121           0 :                 break;
    2122           0 :             case PAM_ERROR_MSG:
    2123           0 :                 ereport(LOG,
    2124             :                         (errmsg("error from underlying PAM layer: %s",
    2125             :                                 msg[i]->msg)));
    2126             :                 /* FALL THROUGH */
    2127             :             case PAM_TEXT_INFO:
    2128             :                 /* we don't bother to log TEXT_INFO messages */
    2129           0 :                 if ((reply[i].resp = strdup("")) == NULL)
    2130           0 :                     goto fail;
    2131           0 :                 reply[i].resp_retcode = PAM_SUCCESS;
    2132           0 :                 break;
    2133           0 :             default:
    2134           0 :                 elog(LOG, "unsupported PAM conversation %d/\"%s\"",
    2135             :                      msg[i]->msg_style,
    2136             :                      msg[i]->msg ? msg[i]->msg : "(none)");
    2137           0 :                 goto fail;
    2138             :         }
    2139             :     }
    2140             : 
    2141           0 :     *resp = reply;
    2142           0 :     return PAM_SUCCESS;
    2143             : 
    2144           0 : fail:
    2145             :     /* free up whatever we allocated */
    2146           0 :     for (i = 0; i < num_msg; i++)
    2147             :     {
    2148           0 :         if (reply[i].resp != NULL)
    2149           0 :             free(reply[i].resp);
    2150             :     }
    2151           0 :     free(reply);
    2152             : 
    2153           0 :     return PAM_CONV_ERR;
    2154             : }
    2155             : 
    2156             : 
    2157             : /*
    2158             :  * Check authentication against PAM.
    2159             :  */
    2160             : static int
    2161           0 : CheckPAMAuth(Port *port, const char *user, const char *password)
    2162             : {
    2163             :     int         retval;
    2164           0 :     pam_handle_t *pamh = NULL;
    2165             : 
    2166             :     /*
    2167             :      * We can't entirely rely on PAM to pass through appdata --- it appears
    2168             :      * not to work on at least Solaris 2.6.  So use these ugly static
    2169             :      * variables instead.
    2170             :      */
    2171           0 :     pam_passwd = password;
    2172           0 :     pam_port_cludge = port;
    2173           0 :     pam_no_password = false;
    2174             : 
    2175             :     /*
    2176             :      * Set the application data portion of the conversation struct.  This is
    2177             :      * later used inside the PAM conversation to pass the password to the
    2178             :      * authentication module.
    2179             :      */
    2180           0 :     pam_passw_conv.appdata_ptr = unconstify(char *, password);  /* from password above,
    2181             :                                                                  * not allocated */
    2182             : 
    2183             :     /* Optionally, one can set the service name in pg_hba.conf */
    2184           0 :     if (port->hba->pamservice && port->hba->pamservice[0] != '\0')
    2185           0 :         retval = pam_start(port->hba->pamservice, "pgsql@",
    2186             :                            &pam_passw_conv, &pamh);
    2187             :     else
    2188           0 :         retval = pam_start(PGSQL_PAM_SERVICE, "pgsql@",
    2189             :                            &pam_passw_conv, &pamh);
    2190             : 
    2191           0 :     if (retval != PAM_SUCCESS)
    2192             :     {
    2193           0 :         ereport(LOG,
    2194             :                 (errmsg("could not create PAM authenticator: %s",
    2195             :                         pam_strerror(pamh, retval))));
    2196           0 :         pam_passwd = NULL;      /* Unset pam_passwd */
    2197           0 :         return STATUS_ERROR;
    2198             :     }
    2199             : 
    2200           0 :     retval = pam_set_item(pamh, PAM_USER, user);
    2201             : 
    2202           0 :     if (retval != PAM_SUCCESS)
    2203             :     {
    2204           0 :         ereport(LOG,
    2205             :                 (errmsg("pam_set_item(PAM_USER) failed: %s",
    2206             :                         pam_strerror(pamh, retval))));
    2207           0 :         pam_passwd = NULL;      /* Unset pam_passwd */
    2208           0 :         return STATUS_ERROR;
    2209             :     }
    2210             : 
    2211           0 :     if (port->hba->conntype != ctLocal)
    2212             :     {
    2213             :         char        hostinfo[NI_MAXHOST];
    2214             :         int         flags;
    2215             : 
    2216           0 :         if (port->hba->pam_use_hostname)
    2217           0 :             flags = 0;
    2218             :         else
    2219           0 :             flags = NI_NUMERICHOST | NI_NUMERICSERV;
    2220             : 
    2221           0 :         retval = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
    2222             :                                     hostinfo, sizeof(hostinfo), NULL, 0,
    2223             :                                     flags);
    2224           0 :         if (retval != 0)
    2225             :         {
    2226           0 :             ereport(WARNING,
    2227             :                     (errmsg_internal("pg_getnameinfo_all() failed: %s",
    2228             :                                      gai_strerror(retval))));
    2229           0 :             return STATUS_ERROR;
    2230             :         }
    2231             : 
    2232           0 :         retval = pam_set_item(pamh, PAM_RHOST, hostinfo);
    2233             : 
    2234           0 :         if (retval != PAM_SUCCESS)
    2235             :         {
    2236           0 :             ereport(LOG,
    2237             :                     (errmsg("pam_set_item(PAM_RHOST) failed: %s",
    2238             :                             pam_strerror(pamh, retval))));
    2239           0 :             pam_passwd = NULL;
    2240           0 :             return STATUS_ERROR;
    2241             :         }
    2242             :     }
    2243             : 
    2244           0 :     retval = pam_set_item(pamh, PAM_CONV, &pam_passw_conv);
    2245             : 
    2246           0 :     if (retval != PAM_SUCCESS)
    2247             :     {
    2248           0 :         ereport(LOG,
    2249             :                 (errmsg("pam_set_item(PAM_CONV) failed: %s",
    2250             :                         pam_strerror(pamh, retval))));
    2251           0 :         pam_passwd = NULL;      /* Unset pam_passwd */
    2252           0 :         return STATUS_ERROR;
    2253             :     }
    2254             : 
    2255           0 :     retval = pam_authenticate(pamh, 0);
    2256             : 
    2257           0 :     if (retval != PAM_SUCCESS)
    2258             :     {
    2259             :         /* If pam_passwd_conv_proc saw EOF, don't log anything */
    2260           0 :         if (!pam_no_password)
    2261           0 :             ereport(LOG,
    2262             :                     (errmsg("pam_authenticate failed: %s",
    2263             :                             pam_strerror(pamh, retval))));
    2264           0 :         pam_passwd = NULL;      /* Unset pam_passwd */
    2265           0 :         return pam_no_password ? STATUS_EOF : STATUS_ERROR;
    2266             :     }
    2267             : 
    2268           0 :     retval = pam_acct_mgmt(pamh, 0);
    2269             : 
    2270           0 :     if (retval != PAM_SUCCESS)
    2271             :     {
    2272             :         /* If pam_passwd_conv_proc saw EOF, don't log anything */
    2273           0 :         if (!pam_no_password)
    2274           0 :             ereport(LOG,
    2275             :                     (errmsg("pam_acct_mgmt failed: %s",
    2276             :                             pam_strerror(pamh, retval))));
    2277           0 :         pam_passwd = NULL;      /* Unset pam_passwd */
    2278           0 :         return pam_no_password ? STATUS_EOF : STATUS_ERROR;
    2279             :     }
    2280             : 
    2281           0 :     retval = pam_end(pamh, retval);
    2282             : 
    2283           0 :     if (retval != PAM_SUCCESS)
    2284             :     {
    2285           0 :         ereport(LOG,
    2286             :                 (errmsg("could not release PAM authenticator: %s",
    2287             :                         pam_strerror(pamh, retval))));
    2288             :     }
    2289             : 
    2290           0 :     pam_passwd = NULL;          /* Unset pam_passwd */
    2291             : 
    2292           0 :     return (retval == PAM_SUCCESS ? STATUS_OK : STATUS_ERROR);
    2293             : }
    2294             : #endif                          /* USE_PAM */
    2295             : 
    2296             : 
    2297             : /*----------------------------------------------------------------
    2298             :  * BSD authentication system
    2299             :  *----------------------------------------------------------------
    2300             :  */
    2301             : #ifdef USE_BSD_AUTH
    2302             : static int
    2303             : CheckBSDAuth(Port *port, char *user)
    2304             : {
    2305             :     char       *passwd;
    2306             :     int         retval;
    2307             : 
    2308             :     /* Send regular password request to client, and get the response */
    2309             :     sendAuthRequest(port, AUTH_REQ_PASSWORD, NULL, 0);
    2310             : 
    2311             :     passwd = recv_password_packet(port);
    2312             :     if (passwd == NULL)
    2313             :         return STATUS_EOF;
    2314             : 
    2315             :     /*
    2316             :      * Ask the BSD auth system to verify password.  Note that auth_userokay
    2317             :      * will overwrite the password string with zeroes, but it's just a
    2318             :      * temporary string so we don't care.
    2319             :      */
    2320             :     retval = auth_userokay(user, NULL, "auth-postgresql", passwd);
    2321             : 
    2322             :     pfree(passwd);
    2323             : 
    2324             :     if (!retval)
    2325             :         return STATUS_ERROR;
    2326             : 
    2327             :     return STATUS_OK;
    2328             : }
    2329             : #endif                          /* USE_BSD_AUTH */
    2330             : 
    2331             : 
    2332             : /*----------------------------------------------------------------
    2333             :  * LDAP authentication system
    2334             :  *----------------------------------------------------------------
    2335             :  */
    2336             : #ifdef USE_LDAP
    2337             : 
    2338             : static int  errdetail_for_ldap(LDAP *ldap);
    2339             : 
    2340             : /*
    2341             :  * Initialize a connection to the LDAP server, including setting up
    2342             :  * TLS if requested.
    2343             :  */
    2344             : static int
    2345          72 : InitializeLDAPConnection(Port *port, LDAP **ldap)
    2346             : {
    2347             :     const char *scheme;
    2348          72 :     int         ldapversion = LDAP_VERSION3;
    2349             :     int         r;
    2350             : 
    2351          72 :     scheme = port->hba->ldapscheme;
    2352          72 :     if (scheme == NULL)
    2353          40 :         scheme = "ldap";
    2354             : #ifdef WIN32
    2355             :     if (strcmp(scheme, "ldaps") == 0)
    2356             :         *ldap = ldap_sslinit(port->hba->ldapserver, port->hba->ldapport, 1);
    2357             :     else
    2358             :         *ldap = ldap_init(port->hba->ldapserver, port->hba->ldapport);
    2359             :     if (!*ldap)
    2360             :     {
    2361             :         ereport(LOG,
    2362             :                 (errmsg("could not initialize LDAP: error code %d",
    2363             :                         (int) LdapGetLastError())));
    2364             : 
    2365             :         return STATUS_ERROR;
    2366             :     }
    2367             : #else
    2368             : #ifdef HAVE_LDAP_INITIALIZE
    2369             : 
    2370             :     /*
    2371             :      * OpenLDAP provides a non-standard extension ldap_initialize() that takes
    2372             :      * a list of URIs, allowing us to request "ldaps" instead of "ldap".  It
    2373             :      * also provides ldap_domain2hostlist() to find LDAP servers automatically
    2374             :      * using DNS SRV.  They were introduced in the same version, so for now we
    2375             :      * don't have an extra configure check for the latter.
    2376             :      */
    2377             :     {
    2378             :         StringInfoData uris;
    2379          72 :         char       *hostlist = NULL;
    2380             :         char       *p;
    2381             :         bool        append_port;
    2382             : 
    2383             :         /* We'll build a space-separated scheme://hostname:port list here */
    2384          72 :         initStringInfo(&uris);
    2385             : 
    2386             :         /*
    2387             :          * If pg_hba.conf provided no hostnames, we can ask OpenLDAP to try to
    2388             :          * find some by extracting a domain name from the base DN and looking
    2389             :          * up DSN SRV records for _ldap._tcp.<domain>.
    2390             :          */
    2391          72 :         if (!port->hba->ldapserver || port->hba->ldapserver[0] == '\0')
    2392           0 :         {
    2393             :             char       *domain;
    2394             : 
    2395             :             /* ou=blah,dc=foo,dc=bar -> foo.bar */
    2396           0 :             if (ldap_dn2domain(port->hba->ldapbasedn, &domain))
    2397             :             {
    2398           0 :                 ereport(LOG,
    2399             :                         (errmsg("could not extract domain name from ldapbasedn")));
    2400           0 :                 return STATUS_ERROR;
    2401             :             }
    2402             : 
    2403             :             /* Look up a list of LDAP server hosts and port numbers */
    2404           0 :             if (ldap_domain2hostlist(domain, &hostlist))
    2405             :             {
    2406           0 :                 ereport(LOG,
    2407             :                         (errmsg("LDAP authentication could not find DNS SRV records for \"%s\"",
    2408             :                                 domain),
    2409             :                          (errhint("Set an LDAP server name explicitly."))));
    2410           0 :                 ldap_memfree(domain);
    2411           0 :                 return STATUS_ERROR;
    2412             :             }
    2413           0 :             ldap_memfree(domain);
    2414             : 
    2415             :             /* We have a space-separated list of host:port entries */
    2416           0 :             p = hostlist;
    2417           0 :             append_port = false;
    2418             :         }
    2419             :         else
    2420             :         {
    2421             :             /* We have a space-separated list of hosts from pg_hba.conf */
    2422          72 :             p = port->hba->ldapserver;
    2423          72 :             append_port = true;
    2424             :         }
    2425             : 
    2426             :         /* Convert the list of host[:port] entries to full URIs */
    2427             :         do
    2428             :         {
    2429             :             size_t      size;
    2430             : 
    2431             :             /* Find the span of the next entry */
    2432          82 :             size = strcspn(p, " ");
    2433             : 
    2434             :             /* Append a space separator if this isn't the first URI */
    2435          82 :             if (uris.len > 0)
    2436          10 :                 appendStringInfoChar(&uris, ' ');
    2437             : 
    2438             :             /* Append scheme://host:port */
    2439          82 :             appendStringInfoString(&uris, scheme);
    2440          82 :             appendStringInfoString(&uris, "://");
    2441          82 :             appendBinaryStringInfo(&uris, p, size);
    2442          82 :             if (append_port)
    2443          82 :                 appendStringInfo(&uris, ":%d", port->hba->ldapport);
    2444             : 
    2445             :             /* Step over this entry and any number of trailing spaces */
    2446          82 :             p += size;
    2447          92 :             while (*p == ' ')
    2448          10 :                 ++p;
    2449          82 :         } while (*p);
    2450             : 
    2451             :         /* Free memory from OpenLDAP if we looked up SRV records */
    2452          72 :         if (hostlist)
    2453           0 :             ldap_memfree(hostlist);
    2454             : 
    2455             :         /* Finally, try to connect using the URI list */
    2456          72 :         r = ldap_initialize(ldap, uris.data);
    2457          72 :         pfree(uris.data);
    2458          72 :         if (r != LDAP_SUCCESS)
    2459             :         {
    2460           0 :             ereport(LOG,
    2461             :                     (errmsg("could not initialize LDAP: %s",
    2462             :                             ldap_err2string(r))));
    2463             : 
    2464           0 :             return STATUS_ERROR;
    2465             :         }
    2466             :     }
    2467             : #else
    2468             :     if (strcmp(scheme, "ldaps") == 0)
    2469             :     {
    2470             :         ereport(LOG,
    2471             :                 (errmsg("ldaps not supported with this LDAP library")));
    2472             : 
    2473             :         return STATUS_ERROR;
    2474             :     }
    2475             :     *ldap = ldap_init(port->hba->ldapserver, port->hba->ldapport);
    2476             :     if (!*ldap)
    2477             :     {
    2478             :         ereport(LOG,
    2479             :                 (errmsg("could not initialize LDAP: %m")));
    2480             : 
    2481             :         return STATUS_ERROR;
    2482             :     }
    2483             : #endif
    2484             : #endif
    2485             : 
    2486          72 :     if ((r = ldap_set_option(*ldap, LDAP_OPT_PROTOCOL_VERSION, &ldapversion)) != LDAP_SUCCESS)
    2487             :     {
    2488           0 :         ereport(LOG,
    2489             :                 (errmsg("could not set LDAP protocol version: %s",
    2490             :                         ldap_err2string(r)),
    2491             :                  errdetail_for_ldap(*ldap)));
    2492           0 :         ldap_unbind(*ldap);
    2493           0 :         return STATUS_ERROR;
    2494             :     }
    2495             : 
    2496          72 :     if (port->hba->ldaptls)
    2497             :     {
    2498             : #ifndef WIN32
    2499           6 :         if ((r = ldap_start_tls_s(*ldap, NULL, NULL)) != LDAP_SUCCESS)
    2500             : #else
    2501             :         static __ldap_start_tls_sA _ldap_start_tls_sA = NULL;
    2502             : 
    2503             :         if (_ldap_start_tls_sA == NULL)
    2504             :         {
    2505             :             /*
    2506             :              * Need to load this function dynamically because it may not exist
    2507             :              * on Windows, and causes a load error for the whole exe if
    2508             :              * referenced.
    2509             :              */
    2510             :             HANDLE      ldaphandle;
    2511             : 
    2512             :             ldaphandle = LoadLibrary("WLDAP32.DLL");
    2513             :             if (ldaphandle == NULL)
    2514             :             {
    2515             :                 /*
    2516             :                  * should never happen since we import other files from
    2517             :                  * wldap32, but check anyway
    2518             :                  */
    2519             :                 ereport(LOG,
    2520             :                         (errmsg("could not load library \"%s\": error code %lu",
    2521             :                                 "WLDAP32.DLL", GetLastError())));
    2522             :                 ldap_unbind(*ldap);
    2523             :                 return STATUS_ERROR;
    2524             :             }
    2525             :             _ldap_start_tls_sA = (__ldap_start_tls_sA) GetProcAddress(ldaphandle, "ldap_start_tls_sA");
    2526             :             if (_ldap_start_tls_sA == NULL)
    2527             :             {
    2528             :                 ereport(LOG,
    2529             :                         (errmsg("could not load function _ldap_start_tls_sA in wldap32.dll"),
    2530             :                          errdetail("LDAP over SSL is not supported on this platform.")));
    2531             :                 ldap_unbind(*ldap);
    2532             :                 FreeLibrary(ldaphandle);
    2533             :                 return STATUS_ERROR;
    2534             :             }
    2535             : 
    2536             :             /*
    2537             :              * Leak LDAP handle on purpose, because we need the library to
    2538             :              * stay open. This is ok because it will only ever be leaked once
    2539             :              * per process and is automatically cleaned up on process exit.
    2540             :              */
    2541             :         }
    2542             :         if ((r = _ldap_start_tls_sA(*ldap, NULL, NULL, NULL, NULL)) != LDAP_SUCCESS)
    2543             : #endif
    2544             :         {
    2545           2 :             ereport(LOG,
    2546             :                     (errmsg("could not start LDAP TLS session: %s",
    2547             :                             ldap_err2string(r)),
    2548             :                      errdetail_for_ldap(*ldap)));
    2549           2 :             ldap_unbind(*ldap);
    2550           2 :             return STATUS_ERROR;
    2551             :         }
    2552             :     }
    2553             : 
    2554          70 :     return STATUS_OK;
    2555             : }
    2556             : 
    2557             : /* Placeholders recognized by FormatSearchFilter.  For now just one. */
    2558             : #define LPH_USERNAME "$username"
    2559             : #define LPH_USERNAME_LEN (sizeof(LPH_USERNAME) - 1)
    2560             : 
    2561             : /* Not all LDAP implementations define this. */
    2562             : #ifndef LDAP_NO_ATTRS
    2563             : #define LDAP_NO_ATTRS "1.1"
    2564             : #endif
    2565             : 
    2566             : /* Not all LDAP implementations define this. */
    2567             : #ifndef LDAPS_PORT
    2568             : #define LDAPS_PORT 636
    2569             : #endif
    2570             : 
    2571             : /*
    2572             :  * Return a newly allocated C string copied from "pattern" with all
    2573             :  * occurrences of the placeholder "$username" replaced with "user_name".
    2574             :  */
    2575             : static char *
    2576          16 : FormatSearchFilter(const char *pattern, const char *user_name)
    2577             : {
    2578             :     StringInfoData output;
    2579             : 
    2580          16 :     initStringInfo(&output);
    2581         238 :     while (*pattern != '\0')
    2582             :     {
    2583         222 :         if (strncmp(pattern, LPH_USERNAME, LPH_USERNAME_LEN) == 0)
    2584             :         {
    2585          26 :             appendStringInfoString(&output, user_name);
    2586          26 :             pattern += LPH_USERNAME_LEN;
    2587             :         }
    2588             :         else
    2589         196 :             appendStringInfoChar(&output, *pattern++);
    2590             :     }
    2591             : 
    2592          16 :     return output.data;
    2593             : }
    2594             : 
    2595             : /*
    2596             :  * Perform LDAP authentication
    2597             :  */
    2598             : static int
    2599          44 : CheckLDAPAuth(Port *port)
    2600             : {
    2601             :     char       *passwd;
    2602             :     LDAP       *ldap;
    2603             :     int         r;
    2604             :     char       *fulluser;
    2605             :     const char *server_name;
    2606             : 
    2607             : #ifdef HAVE_LDAP_INITIALIZE
    2608             : 
    2609             :     /*
    2610             :      * For OpenLDAP, allow empty hostname if we have a basedn.  We'll look for
    2611             :      * servers with DNS SRV records via OpenLDAP library facilities.
    2612             :      */
    2613          44 :     if ((!port->hba->ldapserver || port->hba->ldapserver[0] == '\0') &&
    2614           0 :         (!port->hba->ldapbasedn || port->hba->ldapbasedn[0] == '\0'))
    2615             :     {
    2616           0 :         ereport(LOG,
    2617             :                 (errmsg("LDAP server not specified, and no ldapbasedn")));
    2618           0 :         return STATUS_ERROR;
    2619             :     }
    2620             : #else
    2621             :     if (!port->hba->ldapserver || port->hba->ldapserver[0] == '\0')
    2622             :     {
    2623             :         ereport(LOG,
    2624             :                 (errmsg("LDAP server not specified")));
    2625             :         return STATUS_ERROR;
    2626             :     }
    2627             : #endif
    2628             : 
    2629             :     /*
    2630             :      * If we're using SRV records, we don't have a server name so we'll just
    2631             :      * show an empty string in error messages.
    2632             :      */
    2633          44 :     server_name = port->hba->ldapserver ? port->hba->ldapserver : "";
    2634             : 
    2635          44 :     if (port->hba->ldapport == 0)
    2636             :     {
    2637           0 :         if (port->hba->ldapscheme != NULL &&
    2638           0 :             strcmp(port->hba->ldapscheme, "ldaps") == 0)
    2639           0 :             port->hba->ldapport = LDAPS_PORT;
    2640             :         else
    2641           0 :             port->hba->ldapport = LDAP_PORT;
    2642             :     }
    2643             : 
    2644          44 :     sendAuthRequest(port, AUTH_REQ_PASSWORD, NULL, 0);
    2645             : 
    2646          44 :     passwd = recv_password_packet(port);
    2647          44 :     if (passwd == NULL)
    2648           0 :         return STATUS_EOF;      /* client wouldn't send password */
    2649             : 
    2650          44 :     if (InitializeLDAPConnection(port, &ldap) == STATUS_ERROR)
    2651             :     {
    2652             :         /* Error message already sent */
    2653           2 :         pfree(passwd);
    2654           2 :         return STATUS_ERROR;
    2655             :     }
    2656             : 
    2657          42 :     if (port->hba->ldapbasedn)
    2658             :     {
    2659             :         /*
    2660             :          * First perform an LDAP search to find the DN for the user we are
    2661             :          * trying to log in as.
    2662             :          */
    2663             :         char       *filter;
    2664             :         LDAPMessage *search_message;
    2665             :         LDAPMessage *entry;
    2666          34 :         char       *attributes[] = {LDAP_NO_ATTRS, NULL};
    2667             :         char       *dn;
    2668             :         char       *c;
    2669             :         int         count;
    2670             : 
    2671             :         /*
    2672             :          * Disallow any characters that we would otherwise need to escape,
    2673             :          * since they aren't really reasonable in a username anyway. Allowing
    2674             :          * them would make it possible to inject any kind of custom filters in
    2675             :          * the LDAP filter.
    2676             :          */
    2677         252 :         for (c = port->user_name; *c; c++)
    2678             :         {
    2679         218 :             if (*c == '*' ||
    2680         218 :                 *c == '(' ||
    2681         218 :                 *c == ')' ||
    2682         218 :                 *c == '\\' ||
    2683         218 :                 *c == '/')
    2684             :             {
    2685           0 :                 ereport(LOG,
    2686             :                         (errmsg("invalid character in user name for LDAP authentication")));
    2687           0 :                 ldap_unbind(ldap);
    2688           0 :                 pfree(passwd);
    2689           6 :                 return STATUS_ERROR;
    2690             :             }
    2691             :         }
    2692             : 
    2693             :         /*
    2694             :          * Bind with a pre-defined username/password (if available) for
    2695             :          * searching. If none is specified, this turns into an anonymous bind.
    2696             :          */
    2697          68 :         r = ldap_simple_bind_s(ldap,
    2698          34 :                                port->hba->ldapbinddn ? port->hba->ldapbinddn : "",
    2699          34 :                                port->hba->ldapbindpasswd ? port->hba->ldapbindpasswd : "");
    2700          34 :         if (r != LDAP_SUCCESS)
    2701             :         {
    2702           0 :             ereport(LOG,
    2703             :                     (errmsg("could not perform initial LDAP bind for ldapbinddn \"%s\" on server \"%s\": %s",
    2704             :                             port->hba->ldapbinddn ? port->hba->ldapbinddn : "",
    2705             :                             server_name,
    2706             :                             ldap_err2string(r)),
    2707             :                      errdetail_for_ldap(ldap)));
    2708           0 :             ldap_unbind(ldap);
    2709           0 :             pfree(passwd);
    2710           0 :             return STATUS_ERROR;
    2711             :         }
    2712             : 
    2713             :         /* Build a custom filter or a single attribute filter? */
    2714          34 :         if (port->hba->ldapsearchfilter)
    2715          16 :             filter = FormatSearchFilter(port->hba->ldapsearchfilter, port->user_name);
    2716          18 :         else if (port->hba->ldapsearchattribute)
    2717           6 :             filter = psprintf("(%s=%s)", port->hba->ldapsearchattribute, port->user_name);
    2718             :         else
    2719          12 :             filter = psprintf("(uid=%s)", port->user_name);
    2720             : 
    2721          68 :         r = ldap_search_s(ldap,
    2722          34 :                           port->hba->ldapbasedn,
    2723          34 :                           port->hba->ldapscope,
    2724             :                           filter,
    2725             :                           attributes,
    2726             :                           0,
    2727             :                           &search_message);
    2728             : 
    2729          34 :         if (r != LDAP_SUCCESS)
    2730             :         {
    2731           0 :             ereport(LOG,
    2732             :                     (errmsg("could not search LDAP for filter \"%s\" on server \"%s\": %s",
    2733             :                             filter, server_name, ldap_err2string(r)),
    2734             :                      errdetail_for_ldap(ldap)));
    2735           0 :             ldap_unbind(ldap);
    2736           0 :             pfree(passwd);
    2737           0 :             pfree(filter);
    2738           0 :             return STATUS_ERROR;
    2739             :         }
    2740             : 
    2741          34 :         count = ldap_count_entries(ldap, search_message);
    2742          34 :         if (count != 1)
    2743             :         {
    2744           6 :             if (count == 0)
    2745           6 :                 ereport(LOG,
    2746             :                         (errmsg("LDAP user \"%s\" does not exist", port->user_name),
    2747             :                          errdetail("LDAP search for filter \"%s\" on server \"%s\" returned no entries.",
    2748             :                                    filter, server_name)));
    2749             :             else
    2750           0 :                 ereport(LOG,
    2751             :                         (errmsg("LDAP user \"%s\" is not unique", port->user_name),
    2752             :                          errdetail_plural("LDAP search for filter \"%s\" on server \"%s\" returned %d entry.",
    2753             :                                           "LDAP search for filter \"%s\" on server \"%s\" returned %d entries.",
    2754             :                                           count,
    2755             :                                           filter, server_name, count)));
    2756             : 
    2757           6 :             ldap_unbind(ldap);
    2758           6 :             pfree(passwd);
    2759           6 :             pfree(filter);
    2760           6 :             ldap_msgfree(search_message);
    2761           6 :             return STATUS_ERROR;
    2762             :         }
    2763             : 
    2764          28 :         entry = ldap_first_entry(ldap, search_message);
    2765          28 :         dn = ldap_get_dn(ldap, entry);
    2766          28 :         if (dn == NULL)
    2767             :         {
    2768             :             int         error;
    2769             : 
    2770           0 :             (void) ldap_get_option(ldap, LDAP_OPT_ERROR_NUMBER, &error);
    2771           0 :             ereport(LOG,
    2772             :                     (errmsg("could not get dn for the first entry matching \"%s\" on server \"%s\": %s",
    2773             :                             filter, server_name,
    2774             :                             ldap_err2string(error)),
    2775             :                      errdetail_for_ldap(ldap)));
    2776           0 :             ldap_unbind(ldap);
    2777           0 :             pfree(passwd);
    2778           0 :             pfree(filter);
    2779           0 :             ldap_msgfree(search_message);
    2780           0 :             return STATUS_ERROR;
    2781             :         }
    2782          28 :         fulluser = pstrdup(dn);
    2783             : 
    2784          28 :         pfree(filter);
    2785          28 :         ldap_memfree(dn);
    2786          28 :         ldap_msgfree(search_message);
    2787             : 
    2788             :         /* Unbind and disconnect from the LDAP server */
    2789          28 :         r = ldap_unbind_s(ldap);
    2790          28 :         if (r != LDAP_SUCCESS)
    2791             :         {
    2792           0 :             ereport(LOG,
    2793             :                     (errmsg("could not unbind after searching for user \"%s\" on server \"%s\"",
    2794             :                             fulluser, server_name)));
    2795           0 :             pfree(passwd);
    2796           0 :             pfree(fulluser);
    2797           0 :             return STATUS_ERROR;
    2798             :         }
    2799             : 
    2800             :         /*
    2801             :          * Need to re-initialize the LDAP connection, so that we can bind to
    2802             :          * it with a different username.
    2803             :          */
    2804          28 :         if (InitializeLDAPConnection(port, &ldap) == STATUS_ERROR)
    2805             :         {
    2806           0 :             pfree(passwd);
    2807           0 :             pfree(fulluser);
    2808             : 
    2809             :             /* Error message already sent */
    2810           0 :             return STATUS_ERROR;
    2811             :         }
    2812             :     }
    2813             :     else
    2814           8 :         fulluser = psprintf("%s%s%s",
    2815           8 :                             port->hba->ldapprefix ? port->hba->ldapprefix : "",
    2816             :                             port->user_name,
    2817           8 :                             port->hba->ldapsuffix ? port->hba->ldapsuffix : "");
    2818             : 
    2819          36 :     r = ldap_simple_bind_s(ldap, fulluser, passwd);
    2820             : 
    2821          36 :     if (r != LDAP_SUCCESS)
    2822             :     {
    2823          12 :         ereport(LOG,
    2824             :                 (errmsg("LDAP login failed for user \"%s\" on server \"%s\": %s",
    2825             :                         fulluser, server_name, ldap_err2string(r)),
    2826             :                  errdetail_for_ldap(ldap)));
    2827          12 :         ldap_unbind(ldap);
    2828          12 :         pfree(passwd);
    2829          12 :         pfree(fulluser);
    2830          12 :         return STATUS_ERROR;
    2831             :     }
    2832             : 
    2833          24 :     ldap_unbind(ldap);
    2834          24 :     pfree(passwd);
    2835          24 :     pfree(fulluser);
    2836             : 
    2837          24 :     return STATUS_OK;
    2838             : }
    2839             : 
    2840             : /*
    2841             :  * Add a detail error message text to the current error if one can be
    2842             :  * constructed from the LDAP 'diagnostic message'.
    2843             :  */
    2844             : static int
    2845          14 : errdetail_for_ldap(LDAP *ldap)
    2846             : {
    2847             :     char       *message;
    2848             :     int         rc;
    2849             : 
    2850          14 :     rc = ldap_get_option(ldap, LDAP_OPT_DIAGNOSTIC_MESSAGE, &message);
    2851          14 :     if (rc == LDAP_SUCCESS && message != NULL)
    2852             :     {
    2853           4 :         errdetail("LDAP diagnostics: %s", message);
    2854           4 :         ldap_memfree(message);
    2855             :     }
    2856             : 
    2857          14 :     return 0;
    2858             : }
    2859             : 
    2860             : #endif                          /* USE_LDAP */
    2861             : 
    2862             : 
    2863             : /*----------------------------------------------------------------
    2864             :  * SSL client certificate authentication
    2865             :  *----------------------------------------------------------------
    2866             :  */
    2867             : #ifdef USE_SSL
    2868             : static int
    2869          18 : CheckCertAuth(Port *port)
    2870             : {
    2871          18 :     int         status_check_usermap = STATUS_ERROR;
    2872             : 
    2873             :     Assert(port->ssl);
    2874             : 
    2875             :     /* Make sure we have received a username in the certificate */
    2876          18 :     if (port->peer_cn == NULL ||
    2877          18 :         strlen(port->peer_cn) <= 0)
    2878             :     {
    2879           0 :         ereport(LOG,
    2880             :                 (errmsg("certificate authentication failed for user \"%s\": client certificate contains no user name",
    2881             :                         port->user_name)));
    2882           0 :         return STATUS_ERROR;
    2883             :     }
    2884             : 
    2885             :     /* Just pass the certificate cn to the usermap check */
    2886          18 :     status_check_usermap = check_usermap(port->hba->usermap, port->user_name, port->peer_cn, false);
    2887          18 :     if (status_check_usermap != STATUS_OK)
    2888             :     {
    2889             :         /*
    2890             :          * If clientcert=verify-full was specified and the authentication
    2891             :          * method is other than uaCert, log the reason for rejecting the
    2892             :          * authentication.
    2893             :          */
    2894           4 :         if (port->hba->clientcert == clientCertFull && port->hba->auth_method != uaCert)
    2895             :         {
    2896           2 :             ereport(LOG,
    2897             :                     (errmsg("certificate validation (clientcert=verify-full) failed for user \"%s\": CN mismatch",
    2898             :                             port->user_name)));
    2899             :         }
    2900             :     }
    2901          18 :     return status_check_usermap;
    2902             : }
    2903             : #endif
    2904             : 
    2905             : 
    2906             : /*----------------------------------------------------------------
    2907             :  * RADIUS authentication
    2908             :  *----------------------------------------------------------------
    2909             :  */
    2910             : 
    2911             : /*
    2912             :  * RADIUS authentication is described in RFC2865 (and several others).
    2913             :  */
    2914             : 
    2915             : #define RADIUS_VECTOR_LENGTH 16
    2916             : #define RADIUS_HEADER_LENGTH 20
    2917             : #define RADIUS_MAX_PASSWORD_LENGTH 128
    2918             : 
    2919             : /* Maximum size of a RADIUS packet we will create or accept */
    2920             : #define RADIUS_BUFFER_SIZE 1024
    2921             : 
    2922             : typedef struct
    2923             : {
    2924             :     uint8       attribute;
    2925             :     uint8       length;
    2926             :     uint8       data[FLEXIBLE_ARRAY_MEMBER];
    2927             : } radius_attribute;
    2928             : 
    2929             : typedef struct
    2930             : {
    2931             :     uint8       code;
    2932             :     uint8       id;
    2933             :     uint16      length;
    2934             :     uint8       vector[RADIUS_VECTOR_LENGTH];
    2935             :     /* this is a bit longer than strictly necessary: */
    2936             :     char        pad[RADIUS_BUFFER_SIZE - RADIUS_VECTOR_LENGTH];
    2937             : } radius_packet;
    2938             : 
    2939             : /* RADIUS packet types */
    2940             : #define RADIUS_ACCESS_REQUEST   1
    2941             : #define RADIUS_ACCESS_ACCEPT    2
    2942             : #define RADIUS_ACCESS_REJECT    3
    2943             : 
    2944             : /* RADIUS attributes */
    2945             : #define RADIUS_USER_NAME        1
    2946             : #define RADIUS_PASSWORD         2
    2947             : #define RADIUS_SERVICE_TYPE     6
    2948             : #define RADIUS_NAS_IDENTIFIER   32
    2949             : 
    2950             : /* RADIUS service types */
    2951             : #define RADIUS_AUTHENTICATE_ONLY    8
    2952             : 
    2953             : /* Seconds to wait - XXX: should be in a config variable! */
    2954             : #define RADIUS_TIMEOUT 3
    2955             : 
    2956             : static void
    2957           0 : radius_add_attribute(radius_packet *packet, uint8 type, const unsigned char *data, int len)
    2958             : {
    2959             :     radius_attribute *attr;
    2960             : 
    2961           0 :     if (packet->length + len > RADIUS_BUFFER_SIZE)
    2962             :     {
    2963             :         /*
    2964             :          * With remotely realistic data, this can never happen. But catch it
    2965             :          * just to make sure we don't overrun a buffer. We'll just skip adding
    2966             :          * the broken attribute, which will in the end cause authentication to
    2967             :          * fail.
    2968             :          */
    2969           0 :         elog(WARNING,
    2970             :              "adding attribute code %d with length %d to radius packet would create oversize packet, ignoring",
    2971             :              type, len);
    2972           0 :         return;
    2973             :     }
    2974             : 
    2975           0 :     attr = (radius_attribute *) ((unsigned char *) packet + packet->length);
    2976           0 :     attr->attribute = type;
    2977           0 :     attr->length = len + 2;      /* total size includes type and length */
    2978           0 :     memcpy(attr->data, data, len);
    2979           0 :     packet->length += attr->length;
    2980             : }
    2981             : 
    2982             : static int
    2983           0 : CheckRADIUSAuth(Port *port)
    2984             : {
    2985             :     char       *passwd;
    2986             :     ListCell   *server,
    2987             :                *secrets,
    2988             :                *radiusports,
    2989             :                *identifiers;
    2990             : 
    2991             :     /* Make sure struct alignment is correct */
    2992             :     Assert(offsetof(radius_packet, vector) == 4);
    2993             : 
    2994             :     /* Verify parameters */
    2995           0 :     if (list_length(port->hba->radiusservers) < 1)
    2996             :     {
    2997           0 :         ereport(LOG,
    2998             :                 (errmsg("RADIUS server not specified")));
    2999           0 :         return STATUS_ERROR;
    3000             :     }
    3001             : 
    3002           0 :     if (list_length(port->hba->radiussecrets) < 1)
    3003             :     {
    3004           0 :         ereport(LOG,
    3005             :                 (errmsg("RADIUS secret not specified")));
    3006           0 :         return STATUS_ERROR;
    3007             :     }
    3008             : 
    3009             :     /* Send regular password request to client, and get the response */
    3010           0 :     sendAuthRequest(port, AUTH_REQ_PASSWORD, NULL, 0);
    3011             : 
    3012           0 :     passwd = recv_password_packet(port);
    3013           0 :     if (passwd == NULL)
    3014           0 :         return STATUS_EOF;      /* client wouldn't send password */
    3015             : 
    3016           0 :     if (strlen(passwd) > RADIUS_MAX_PASSWORD_LENGTH)
    3017             :     {
    3018           0 :         ereport(LOG,
    3019             :                 (errmsg("RADIUS authentication does not support passwords longer than %d characters", RADIUS_MAX_PASSWORD_LENGTH)));
    3020           0 :         pfree(passwd);
    3021           0 :         return STATUS_ERROR;
    3022             :     }
    3023             : 
    3024             :     /*
    3025             :      * Loop over and try each server in order.
    3026             :      */
    3027           0 :     secrets = list_head(port->hba->radiussecrets);
    3028           0 :     radiusports = list_head(port->hba->radiusports);
    3029           0 :     identifiers = list_head(port->hba->radiusidentifiers);
    3030           0 :     foreach(server, port->hba->radiusservers)
    3031             :     {
    3032           0 :         int         ret = PerformRadiusTransaction(lfirst(server),
    3033           0 :                                                    lfirst(secrets),
    3034             :                                                    radiusports ? lfirst(radiusports) : NULL,
    3035             :                                                    identifiers ? lfirst(identifiers) : NULL,
    3036           0 :                                                    port->user_name,
    3037             :                                                    passwd);
    3038             : 
    3039             :         /*------
    3040             :          * STATUS_OK = Login OK
    3041             :          * STATUS_ERROR = Login not OK, but try next server
    3042             :          * STATUS_EOF = Login not OK, and don't try next server
    3043             :          *------
    3044             :          */
    3045           0 :         if (ret == STATUS_OK)
    3046             :         {
    3047           0 :             pfree(passwd);
    3048           0 :             return STATUS_OK;
    3049             :         }
    3050           0 :         else if (ret == STATUS_EOF)
    3051             :         {
    3052           0 :             pfree(passwd);
    3053           0 :             return STATUS_ERROR;
    3054             :         }
    3055             : 
    3056             :         /*
    3057             :          * secret, port and identifiers either have length 0 (use default),
    3058             :          * length 1 (use the same everywhere) or the same length as servers.
    3059             :          * So if the length is >1, we advance one step. In other cases, we
    3060             :          * don't and will then reuse the correct value.
    3061             :          */
    3062           0 :         if (list_length(port->hba->radiussecrets) > 1)
    3063           0 :             secrets = lnext(port->hba->radiussecrets, secrets);
    3064           0 :         if (list_length(port->hba->radiusports) > 1)
    3065           0 :             radiusports = lnext(port->hba->radiusports, radiusports);
    3066           0 :         if (list_length(port->hba->radiusidentifiers) > 1)
    3067           0 :             identifiers = lnext(port->hba->radiusidentifiers, identifiers);
    3068             :     }
    3069             : 
    3070             :     /* No servers left to try, so give up */
    3071           0 :     pfree(passwd);
    3072           0 :     return STATUS_ERROR;
    3073             : }
    3074             : 
    3075             : static int
    3076           0 : PerformRadiusTransaction(const char *server, const char *secret, const char *portstr, const char *identifier, const char *user_name, const char *passwd)
    3077             : {
    3078             :     radius_packet radius_send_pack;
    3079             :     radius_packet radius_recv_pack;
    3080           0 :     radius_packet *packet = &radius_send_pack;
    3081           0 :     radius_packet *receivepacket = &radius_recv_pack;
    3082           0 :     char       *radius_buffer = (char *) &radius_send_pack;
    3083           0 :     char       *receive_buffer = (char *) &radius_recv_pack;
    3084           0 :     int32       service = pg_hton32(RADIUS_AUTHENTICATE_ONLY);
    3085             :     uint8      *cryptvector;
    3086             :     int         encryptedpasswordlen;
    3087             :     uint8       encryptedpassword[RADIUS_MAX_PASSWORD_LENGTH];
    3088             :     uint8      *md5trailer;
    3089             :     int         packetlength;
    3090             :     pgsocket    sock;
    3091             : 
    3092             : #ifdef HAVE_IPV6
    3093             :     struct sockaddr_in6 localaddr;
    3094             :     struct sockaddr_in6 remoteaddr;
    3095             : #else
    3096             :     struct sockaddr_in localaddr;
    3097             :     struct sockaddr_in remoteaddr;
    3098             : #endif
    3099             :     struct addrinfo hint;
    3100             :     struct addrinfo *serveraddrs;
    3101             :     int         port;
    3102             :     ACCEPT_TYPE_ARG3 addrsize;
    3103             :     fd_set      fdset;
    3104             :     struct timeval endtime;
    3105             :     int         i,
    3106             :                 j,
    3107             :                 r;
    3108             : 
    3109             :     /* Assign default values */
    3110           0 :     if (portstr == NULL)
    3111           0 :         portstr = "1812";
    3112           0 :     if (identifier == NULL)
    3113           0 :         identifier = "postgresql";
    3114             : 
    3115           0 :     MemSet(&hint, 0, sizeof(hint));
    3116           0 :     hint.ai_socktype = SOCK_DGRAM;
    3117           0 :     hint.ai_family = AF_UNSPEC;
    3118           0 :     port = atoi(portstr);
    3119             : 
    3120           0 :     r = pg_getaddrinfo_all(server, portstr, &hint, &serveraddrs);
    3121           0 :     if (r || !serveraddrs)
    3122             :     {
    3123           0 :         ereport(LOG,
    3124             :                 (errmsg("could not translate RADIUS server name \"%s\" to address: %s",
    3125             :                         server, gai_strerror(r))));
    3126           0 :         if (serveraddrs)
    3127           0 :             pg_freeaddrinfo_all(hint.ai_family, serveraddrs);
    3128           0 :         return STATUS_ERROR;
    3129             :     }
    3130             :     /* XXX: add support for multiple returned addresses? */
    3131             : 
    3132             :     /* Construct RADIUS packet */
    3133           0 :     packet->code = RADIUS_ACCESS_REQUEST;
    3134           0 :     packet->length = RADIUS_HEADER_LENGTH;
    3135           0 :     if (!pg_strong_random(packet->vector, RADIUS_VECTOR_LENGTH))
    3136             :     {
    3137           0 :         ereport(LOG,
    3138             :                 (errmsg("could not generate random encryption vector")));
    3139           0 :         pg_freeaddrinfo_all(hint.ai_family, serveraddrs);
    3140           0 :         return STATUS_ERROR;
    3141             :     }
    3142           0 :     packet->id = packet->vector[0];
    3143           0 :     radius_add_attribute(packet, RADIUS_SERVICE_TYPE, (const unsigned char *) &service, sizeof(service));
    3144           0 :     radius_add_attribute(packet, RADIUS_USER_NAME, (const unsigned char *) user_name, strlen(user_name));
    3145           0 :     radius_add_attribute(packet, RADIUS_NAS_IDENTIFIER, (const unsigned char *) identifier, strlen(identifier));
    3146             : 
    3147             :     /*
    3148             :      * RADIUS password attributes are calculated as: e[0] = p[0] XOR
    3149             :      * MD5(secret + Request Authenticator) for the first group of 16 octets,
    3150             :      * and then: e[i] = p[i] XOR MD5(secret + e[i-1]) for the following ones
    3151             :      * (if necessary)
    3152             :      */
    3153           0 :     encryptedpasswordlen = ((strlen(passwd) + RADIUS_VECTOR_LENGTH - 1) / RADIUS_VECTOR_LENGTH) * RADIUS_VECTOR_LENGTH;
    3154           0 :     cryptvector = palloc(strlen(secret) + RADIUS_VECTOR_LENGTH);
    3155           0 :     memcpy(cryptvector, secret, strlen(secret));
    3156             : 
    3157             :     /* for the first iteration, we use the Request Authenticator vector */
    3158           0 :     md5trailer = packet->vector;
    3159           0 :     for (i = 0; i < encryptedpasswordlen; i += RADIUS_VECTOR_LENGTH)
    3160             :     {
    3161           0 :         memcpy(cryptvector + strlen(secret), md5trailer, RADIUS_VECTOR_LENGTH);
    3162             : 
    3163             :         /*
    3164             :          * .. and for subsequent iterations the result of the previous XOR
    3165             :          * (calculated below)
    3166             :          */
    3167           0 :         md5trailer = encryptedpassword + i;
    3168             : 
    3169           0 :         if (!pg_md5_binary(cryptvector, strlen(secret) + RADIUS_VECTOR_LENGTH, encryptedpassword + i))
    3170             :         {
    3171           0 :             ereport(LOG,
    3172             :                     (errmsg("could not perform MD5 encryption of password")));
    3173           0 :             pfree(cryptvector);
    3174           0 :             pg_freeaddrinfo_all(hint.ai_family, serveraddrs);
    3175           0 :             return STATUS_ERROR;
    3176             :         }
    3177             : 
    3178           0 :         for (j = i; j < i + RADIUS_VECTOR_LENGTH; j++)
    3179             :         {
    3180           0 :             if (j < strlen(passwd))
    3181           0 :                 encryptedpassword[j] = passwd[j] ^ encryptedpassword[j];
    3182             :             else
    3183           0 :                 encryptedpassword[j] = '\0' ^ encryptedpassword[j];
    3184             :         }
    3185             :     }
    3186           0 :     pfree(cryptvector);
    3187             : 
    3188           0 :     radius_add_attribute(packet, RADIUS_PASSWORD, encryptedpassword, encryptedpasswordlen);
    3189             : 
    3190             :     /* Length needs to be in network order on the wire */
    3191           0 :     packetlength = packet->length;
    3192           0 :     packet->length = pg_hton16(packet->length);
    3193             : 
    3194           0 :     sock = socket(serveraddrs[0].ai_family, SOCK_DGRAM, 0);
    3195           0 :     if (sock == PGINVALID_SOCKET)
    3196             :     {
    3197           0 :         ereport(LOG,
    3198             :                 (errmsg("could not create RADIUS socket: %m")));
    3199           0 :         pg_freeaddrinfo_all(hint.ai_family, serveraddrs);
    3200           0 :         return STATUS_ERROR;
    3201             :     }
    3202             : 
    3203           0 :     memset(&localaddr, 0, sizeof(localaddr));
    3204             : #ifdef HAVE_IPV6
    3205           0 :     localaddr.sin6_family = serveraddrs[0].ai_family;
    3206           0 :     localaddr.sin6_addr = in6addr_any;
    3207           0 :     if (localaddr.sin6_family == AF_INET6)
    3208           0 :         addrsize = sizeof(struct sockaddr_in6);
    3209             :     else
    3210           0 :         addrsize = sizeof(struct sockaddr_in);
    3211             : #else
    3212             :     localaddr.sin_family = serveraddrs[0].ai_family;
    3213             :     localaddr.sin_addr.s_addr = INADDR_ANY;
    3214             :     addrsize = sizeof(struct sockaddr_in);
    3215             : #endif
    3216             : 
    3217           0 :     if (bind(sock, (struct sockaddr *) &localaddr, addrsize))
    3218             :     {
    3219           0 :         ereport(LOG,
    3220             :                 (errmsg("could not bind local RADIUS socket: %m")));
    3221           0 :         closesocket(sock);
    3222           0 :         pg_freeaddrinfo_all(hint.ai_family, serveraddrs);
    3223           0 :         return STATUS_ERROR;
    3224             :     }
    3225             : 
    3226           0 :     if (sendto(sock, radius_buffer, packetlength, 0,
    3227           0 :                serveraddrs[0].ai_addr, serveraddrs[0].ai_addrlen) < 0)
    3228             :     {
    3229           0 :         ereport(LOG,
    3230             :                 (errmsg("could not send RADIUS packet: %m")));
    3231           0 :         closesocket(sock);
    3232           0 :         pg_freeaddrinfo_all(hint.ai_family, serveraddrs);
    3233           0 :         return STATUS_ERROR;
    3234             :     }
    3235             : 
    3236             :     /* Don't need the server address anymore */
    3237           0 :     pg_freeaddrinfo_all(hint.ai_family, serveraddrs);
    3238             : 
    3239             :     /*
    3240             :      * Figure out at what time we should time out. We can't just use a single
    3241             :      * call to select() with a timeout, since somebody can be sending invalid
    3242             :      * packets to our port thus causing us to retry in a loop and never time
    3243             :      * out.
    3244             :      *
    3245             :      * XXX: Using WaitLatchOrSocket() and doing a CHECK_FOR_INTERRUPTS() if
    3246             :      * the latch was set would improve the responsiveness to
    3247             :      * timeouts/cancellations.
    3248             :      */
    3249           0 :     gettimeofday(&endtime, NULL);
    3250           0 :     endtime.tv_sec += RADIUS_TIMEOUT;
    3251             : 
    3252             :     while (true)
    3253           0 :     {
    3254             :         struct timeval timeout;
    3255             :         struct timeval now;
    3256             :         int64       timeoutval;
    3257             : 
    3258           0 :         gettimeofday(&now, NULL);
    3259           0 :         timeoutval = (endtime.tv_sec * 1000000 + endtime.tv_usec) - (now.tv_sec * 1000000 + now.tv_usec);
    3260           0 :         if (timeoutval <= 0)
    3261             :         {
    3262           0 :             ereport(LOG,
    3263             :                     (errmsg("timeout waiting for RADIUS response from %s",
    3264             :                             server)));
    3265           0 :             closesocket(sock);
    3266           0 :             return STATUS_ERROR;
    3267             :         }
    3268           0 :         timeout.tv_sec = timeoutval / 1000000;
    3269           0 :         timeout.tv_usec = timeoutval % 1000000;
    3270             : 
    3271           0 :         FD_ZERO(&fdset);
    3272           0 :         FD_SET(sock, &fdset);
    3273             : 
    3274           0 :         r = select(sock + 1, &fdset, NULL, NULL, &timeout);
    3275           0 :         if (r < 0)
    3276             :         {
    3277           0 :             if (errno == EINTR)
    3278           0 :                 continue;
    3279             : 
    3280             :             /* Anything else is an actual error */
    3281           0 :             ereport(LOG,
    3282             :                     (errmsg("could not check status on RADIUS socket: %m")));
    3283           0 :             closesocket(sock);
    3284           0 :             return STATUS_ERROR;
    3285             :         }
    3286           0 :         if (r == 0)
    3287             :         {
    3288           0 :             ereport(LOG,
    3289             :                     (errmsg("timeout waiting for RADIUS response from %s",
    3290             :                             server)));
    3291           0 :             closesocket(sock);
    3292           0 :             return STATUS_ERROR;
    3293             :         }
    3294             : 
    3295             :         /*
    3296             :          * Attempt to read the response packet, and verify the contents.
    3297             :          *
    3298             :          * Any packet that's not actually a RADIUS packet, or otherwise does
    3299             :          * not validate as an explicit reject, is just ignored and we retry
    3300             :          * for another packet (until we reach the timeout). This is to avoid
    3301             :          * the possibility to denial-of-service the login by flooding the
    3302             :          * server with invalid packets on the port that we're expecting the
    3303             :          * RADIUS response on.
    3304             :          */
    3305             : 
    3306           0 :         addrsize = sizeof(remoteaddr);
    3307           0 :         packetlength = recvfrom(sock, receive_buffer, RADIUS_BUFFER_SIZE, 0,
    3308             :                                 (struct sockaddr *) &remoteaddr, &addrsize);
    3309           0 :         if (packetlength < 0)
    3310             :         {
    3311           0 :             ereport(LOG,
    3312             :                     (errmsg("could not read RADIUS response: %m")));
    3313           0 :             closesocket(sock);
    3314           0 :             return STATUS_ERROR;
    3315             :         }
    3316             : 
    3317             : #ifdef HAVE_IPV6
    3318           0 :         if (remoteaddr.sin6_port != pg_hton16(port))
    3319             : #else
    3320             :         if (remoteaddr.sin_port != pg_hton16(port))
    3321             : #endif
    3322             :         {
    3323             : #ifdef HAVE_IPV6
    3324           0 :             ereport(LOG,
    3325             :                     (errmsg("RADIUS response from %s was sent from incorrect port: %d",
    3326             :                             server, pg_ntoh16(remoteaddr.sin6_port))));
    3327             : #else
    3328             :             ereport(LOG,
    3329             :                     (errmsg("RADIUS response from %s was sent from incorrect port: %d",
    3330             :                             server, pg_ntoh16(remoteaddr.sin_port))));
    3331             : #endif
    3332           0 :             continue;
    3333             :         }
    3334             : 
    3335           0 :         if (packetlength < RADIUS_HEADER_LENGTH)
    3336             :         {
    3337           0 :             ereport(LOG,
    3338             :                     (errmsg("RADIUS response from %s too short: %d", server, packetlength)));
    3339           0 :             continue;
    3340             :         }
    3341             : 
    3342           0 :         if (packetlength != pg_ntoh16(receivepacket->length))
    3343             :         {
    3344           0 :             ereport(LOG,
    3345             :                     (errmsg("RADIUS response from %s has corrupt length: %d (actual length %d)",
    3346             :                             server, pg_ntoh16(receivepacket->length), packetlength)));
    3347           0 :             continue;
    3348             :         }
    3349             : 
    3350           0 :         if (packet->id != receivepacket->id)
    3351             :         {
    3352           0 :             ereport(LOG,
    3353             :                     (errmsg("RADIUS response from %s is to a different request: %d (should be %d)",
    3354             :                             server, receivepacket->id, packet->id)));
    3355           0 :             continue;
    3356             :         }
    3357             : 
    3358             :         /*
    3359             :          * Verify the response authenticator, which is calculated as
    3360             :          * MD5(Code+ID+Length+RequestAuthenticator+Attributes+Secret)
    3361             :          */
    3362           0 :         cryptvector = palloc(packetlength + strlen(secret));
    3363             : 
    3364           0 :         memcpy(cryptvector, receivepacket, 4);  /* code+id+length */
    3365           0 :         memcpy(cryptvector + 4, packet->vector, RADIUS_VECTOR_LENGTH);   /* request
    3366             :                                                                          * authenticator, from
    3367             :                                                                          * original packet */
    3368           0 :         if (packetlength > RADIUS_HEADER_LENGTH) /* there may be no
    3369             :                                                      * attributes at all */
    3370           0 :             memcpy(cryptvector + RADIUS_HEADER_LENGTH, receive_buffer + RADIUS_HEADER_LENGTH, packetlength - RADIUS_HEADER_LENGTH);
    3371           0 :         memcpy(cryptvector + packetlength, secret, strlen(secret));
    3372             : 
    3373           0 :         if (!pg_md5_binary(cryptvector,
    3374           0 :                            packetlength + strlen(secret),
    3375             :                            encryptedpassword))
    3376             :         {
    3377           0 :             ereport(LOG,
    3378             :                     (errmsg("could not perform MD5 encryption of received packet")));
    3379           0 :             pfree(cryptvector);
    3380           0 :             continue;
    3381             :         }
    3382           0 :         pfree(cryptvector);
    3383             : 
    3384           0 :         if (memcmp(receivepacket->vector, encryptedpassword, RADIUS_VECTOR_LENGTH) != 0)
    3385             :         {
    3386           0 :             ereport(LOG,
    3387             :                     (errmsg("RADIUS response from %s has incorrect MD5 signature",
    3388             :                             server)));
    3389           0 :             continue;
    3390             :         }
    3391             : 
    3392           0 :         if (receivepacket->code == RADIUS_ACCESS_ACCEPT)
    3393             :         {
    3394           0 :             closesocket(sock);
    3395           0 :             return STATUS_OK;
    3396             :         }
    3397           0 :         else if (receivepacket->code == RADIUS_ACCESS_REJECT)
    3398             :         {
    3399           0 :             closesocket(sock);
    3400           0 :             return STATUS_EOF;
    3401             :         }
    3402             :         else
    3403             :         {
    3404           0 :             ereport(LOG,
    3405             :                     (errmsg("RADIUS response from %s has invalid code (%d) for user \"%s\"",
    3406             :                             server, receivepacket->code, user_name)));
    3407           0 :             continue;
    3408             :         }
    3409             :     }                           /* while (true) */
    3410             : }

Generated by: LCOV version 1.13