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

Generated by: LCOV version 2.0-1