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

Generated by: LCOV version 2.0-1