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

Generated by: LCOV version 2.0-1