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

Generated by: LCOV version 1.14