Header And Logo

PostgreSQL
| The world's most advanced open source database.

auth.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * auth.c
00004  *    Routines to handle network authentication
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/libpq/auth.c
00012  *
00013  *-------------------------------------------------------------------------
00014  */
00015 
00016 #include "postgres.h"
00017 
00018 #include <sys/param.h>
00019 #include <sys/socket.h>
00020 #include <netinet/in.h>
00021 #include <arpa/inet.h>
00022 #include <unistd.h>
00023 
00024 #include "libpq/auth.h"
00025 #include "libpq/crypt.h"
00026 #include "libpq/ip.h"
00027 #include "libpq/libpq.h"
00028 #include "libpq/pqformat.h"
00029 #include "libpq/md5.h"
00030 #include "miscadmin.h"
00031 #include "replication/walsender.h"
00032 #include "storage/ipc.h"
00033 
00034 
00035 /*----------------------------------------------------------------
00036  * Global authentication functions
00037  *----------------------------------------------------------------
00038  */
00039 static void sendAuthRequest(Port *port, AuthRequest areq);
00040 static void auth_failed(Port *port, int status);
00041 static char *recv_password_packet(Port *port);
00042 static int  recv_and_check_password_packet(Port *port);
00043 
00044 
00045 /*----------------------------------------------------------------
00046  * Ident authentication
00047  *----------------------------------------------------------------
00048  */
00049 /* Max size of username ident server can return */
00050 #define IDENT_USERNAME_MAX 512
00051 
00052 /* Standard TCP port number for Ident service.  Assigned by IANA */
00053 #define IDENT_PORT 113
00054 
00055 static int  ident_inet(hbaPort *port);
00056 
00057 #ifdef HAVE_UNIX_SOCKETS
00058 static int  auth_peer(hbaPort *port);
00059 #endif
00060 
00061 
00062 /*----------------------------------------------------------------
00063  * PAM authentication
00064  *----------------------------------------------------------------
00065  */
00066 #ifdef USE_PAM
00067 #ifdef HAVE_PAM_PAM_APPL_H
00068 #include <pam/pam_appl.h>
00069 #endif
00070 #ifdef HAVE_SECURITY_PAM_APPL_H
00071 #include <security/pam_appl.h>
00072 #endif
00073 
00074 #define PGSQL_PAM_SERVICE "postgresql"  /* Service name passed to PAM */
00075 
00076 static int  CheckPAMAuth(Port *port, char *user, char *password);
00077 static int pam_passwd_conv_proc(int num_msg, const struct pam_message ** msg,
00078                      struct pam_response ** resp, void *appdata_ptr);
00079 
00080 static struct pam_conv pam_passw_conv = {
00081     &pam_passwd_conv_proc,
00082     NULL
00083 };
00084 
00085 static char *pam_passwd = NULL; /* Workaround for Solaris 2.6 brokenness */
00086 static Port *pam_port_cludge;   /* Workaround for passing "Port *port" into
00087                                  * pam_passwd_conv_proc */
00088 #endif   /* USE_PAM */
00089 
00090 
00091 /*----------------------------------------------------------------
00092  * LDAP authentication
00093  *----------------------------------------------------------------
00094  */
00095 #ifdef USE_LDAP
00096 #ifndef WIN32
00097 /* We use a deprecated function to keep the codepath the same as win32. */
00098 #define LDAP_DEPRECATED 1
00099 #include <ldap.h>
00100 #else
00101 #include <winldap.h>
00102 
00103 /* Correct header from the Platform SDK */
00104 typedef
00105 ULONG       (*__ldap_start_tls_sA) (
00106                                                 IN PLDAP ExternalHandle,
00107                                                 OUT PULONG ServerReturnValue,
00108                                                 OUT LDAPMessage **result,
00109                                            IN PLDAPControlA * ServerControls,
00110                                             IN PLDAPControlA * ClientControls
00111 );
00112 #endif
00113 
00114 static int  CheckLDAPAuth(Port *port);
00115 #endif   /* USE_LDAP */
00116 
00117 /*----------------------------------------------------------------
00118  * Cert authentication
00119  *----------------------------------------------------------------
00120  */
00121 #ifdef USE_SSL
00122 static int  CheckCertAuth(Port *port);
00123 #endif
00124 
00125 
00126 /*----------------------------------------------------------------
00127  * Kerberos and GSSAPI GUCs
00128  *----------------------------------------------------------------
00129  */
00130 char       *pg_krb_server_keyfile;
00131 char       *pg_krb_srvnam;
00132 bool        pg_krb_caseins_users;
00133 
00134 
00135 /*----------------------------------------------------------------
00136  * MIT Kerberos authentication system - protocol version 5
00137  *----------------------------------------------------------------
00138  */
00139 #ifdef KRB5
00140 static int  pg_krb5_recvauth(Port *port);
00141 
00142 #include <krb5.h>
00143 /* Some old versions of Kerberos do not include <com_err.h> in <krb5.h> */
00144 #if !defined(__COM_ERR_H) && !defined(__COM_ERR_H__)
00145 #include <com_err.h>
00146 #endif
00147 /*
00148  * Various krb5 state which is not connection specific, and a flag to
00149  * indicate whether we have initialised it yet.
00150  */
00151 static int  pg_krb5_initialised;
00152 static krb5_context pg_krb5_context;
00153 static krb5_keytab pg_krb5_keytab;
00154 static krb5_principal pg_krb5_server;
00155 #endif   /* KRB5 */
00156 
00157 
00158 /*----------------------------------------------------------------
00159  * GSSAPI Authentication
00160  *----------------------------------------------------------------
00161  */
00162 #ifdef ENABLE_GSS
00163 #if defined(HAVE_GSSAPI_H)
00164 #include <gssapi.h>
00165 #else
00166 #include <gssapi/gssapi.h>
00167 #endif
00168 
00169 static int  pg_GSS_recvauth(Port *port);
00170 #endif   /* ENABLE_GSS */
00171 
00172 
00173 /*----------------------------------------------------------------
00174  * SSPI Authentication
00175  *----------------------------------------------------------------
00176  */
00177 #ifdef ENABLE_SSPI
00178 typedef SECURITY_STATUS
00179             (WINAPI * QUERY_SECURITY_CONTEXT_TOKEN_FN) (
00180                                                        PCtxtHandle, void **);
00181 static int  pg_SSPI_recvauth(Port *port);
00182 #endif
00183 
00184 /*----------------------------------------------------------------
00185  * RADIUS Authentication
00186  *----------------------------------------------------------------
00187  */
00188 #ifdef USE_SSL
00189 #include <openssl/rand.h>
00190 #endif
00191 static int  CheckRADIUSAuth(Port *port);
00192 
00193 
00194 /*
00195  * Maximum accepted size of GSS and SSPI authentication tokens.
00196  *
00197  * Kerberos tickets are usually quite small, but the TGTs issued by Windows
00198  * domain controllers include an authorization field known as the Privilege
00199  * Attribute Certificate (PAC), which contains the user's Windows permissions
00200  * (group memberships etc.). The PAC is copied into all tickets obtained on
00201  * the basis of this TGT (even those issued by Unix realms which the Windows
00202  * realm trusts), and can be several kB in size. The maximum token size
00203  * accepted by Windows systems is determined by the MaxAuthToken Windows
00204  * registry setting. Microsoft recommends that it is not set higher than
00205  * 65535 bytes, so that seems like a reasonable limit for us as well.
00206  */
00207 #define PG_MAX_AUTH_TOKEN_LENGTH    65535
00208 
00209 
00210 /*----------------------------------------------------------------
00211  * Global authentication functions
00212  *----------------------------------------------------------------
00213  */
00214 
00215 /*
00216  * This hook allows plugins to get control following client authentication,
00217  * but before the user has been informed about the results.  It could be used
00218  * to record login events, insert a delay after failed authentication, etc.
00219  */
00220 ClientAuthentication_hook_type ClientAuthentication_hook = NULL;
00221 
00222 /*
00223  * Tell the user the authentication failed, but not (much about) why.
00224  *
00225  * There is a tradeoff here between security concerns and making life
00226  * unnecessarily difficult for legitimate users.  We would not, for example,
00227  * want to report the password we were expecting to receive...
00228  * But it seems useful to report the username and authorization method
00229  * in use, and these are items that must be presumed known to an attacker
00230  * anyway.
00231  * Note that many sorts of failure report additional information in the
00232  * postmaster log, which we hope is only readable by good guys.
00233  */
00234 static void
00235 auth_failed(Port *port, int status)
00236 {
00237     const char *errstr;
00238     int         errcode_return = ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION;
00239 
00240     /*
00241      * If we failed due to EOF from client, just quit; there's no point in
00242      * trying to send a message to the client, and not much point in logging
00243      * the failure in the postmaster log.  (Logging the failure might be
00244      * desirable, were it not for the fact that libpq closes the connection
00245      * unceremoniously if challenged for a password when it hasn't got one to
00246      * send.  We'll get a useless log entry for every psql connection under
00247      * password auth, even if it's perfectly successful, if we log STATUS_EOF
00248      * events.)
00249      */
00250     if (status == STATUS_EOF)
00251         proc_exit(0);
00252 
00253     switch (port->hba->auth_method)
00254     {
00255         case uaReject:
00256         case uaImplicitReject:
00257             errstr = gettext_noop("authentication failed for user \"%s\": host rejected");
00258             break;
00259         case uaKrb5:
00260             errstr = gettext_noop("Kerberos 5 authentication failed for user \"%s\"");
00261             break;
00262         case uaTrust:
00263             errstr = gettext_noop("\"trust\" authentication failed for user \"%s\"");
00264             break;
00265         case uaIdent:
00266             errstr = gettext_noop("Ident authentication failed for user \"%s\"");
00267             break;
00268         case uaPeer:
00269             errstr = gettext_noop("Peer authentication failed for user \"%s\"");
00270             break;
00271         case uaPassword:
00272         case uaMD5:
00273             errstr = gettext_noop("password authentication failed for user \"%s\"");
00274             /* We use it to indicate if a .pgpass password failed. */
00275             errcode_return = ERRCODE_INVALID_PASSWORD;
00276             break;
00277         case uaGSS:
00278             errstr = gettext_noop("GSSAPI authentication failed for user \"%s\"");
00279             break;
00280         case uaSSPI:
00281             errstr = gettext_noop("SSPI authentication failed for user \"%s\"");
00282             break;
00283         case uaPAM:
00284             errstr = gettext_noop("PAM authentication failed for user \"%s\"");
00285             break;
00286         case uaLDAP:
00287             errstr = gettext_noop("LDAP authentication failed for user \"%s\"");
00288             break;
00289         case uaCert:
00290             errstr = gettext_noop("certificate authentication failed for user \"%s\"");
00291             break;
00292         case uaRADIUS:
00293             errstr = gettext_noop("RADIUS authentication failed for user \"%s\"");
00294             break;
00295         default:
00296             errstr = gettext_noop("authentication failed for user \"%s\": invalid authentication method");
00297             break;
00298     }
00299 
00300     if (port->hba)
00301         ereport(FATAL,
00302                 (errcode(errcode_return),
00303                  errmsg(errstr, port->user_name),
00304                  errdetail_log("Connection matched pg_hba.conf line %d: \"%s\"", port->hba->linenumber, port->hba->rawline)));
00305     else
00306         ereport(FATAL,
00307                 (errcode(errcode_return),
00308                  errmsg(errstr, port->user_name)));
00309 
00310     /* doesn't return */
00311 }
00312 
00313 
00314 /*
00315  * Client authentication starts here.  If there is an error, this
00316  * function does not return and the backend process is terminated.
00317  */
00318 void
00319 ClientAuthentication(Port *port)
00320 {
00321     int         status = STATUS_ERROR;
00322 
00323     /*
00324      * Get the authentication method to use for this frontend/database
00325      * combination.  Note: we do not parse the file at this point; this has
00326      * already been done elsewhere.  hba.c dropped an error message into the
00327      * server logfile if parsing the hba config file failed.
00328      */
00329     hba_getauthmethod(port);
00330 
00331     /*
00332      * Enable immediate response to SIGTERM/SIGINT/timeout interrupts. (We
00333      * don't want this during hba_getauthmethod() because it might have to do
00334      * database access, eg for role membership checks.)
00335      */
00336     ImmediateInterruptOK = true;
00337     /* And don't forget to detect one that already arrived */
00338     CHECK_FOR_INTERRUPTS();
00339 
00340     /*
00341      * This is the first point where we have access to the hba record for the
00342      * current connection, so perform any verifications based on the hba
00343      * options field that should be done *before* the authentication here.
00344      */
00345     if (port->hba->clientcert)
00346     {
00347         /*
00348          * When we parse pg_hba.conf, we have already made sure that we have
00349          * been able to load a certificate store. Thus, if a certificate is
00350          * present on the client, it has been verified against our root
00351          * certificate store, and the connection would have been aborted
00352          * already if it didn't verify ok.
00353          */
00354 #ifdef USE_SSL
00355         if (!port->peer)
00356         {
00357             ereport(FATAL,
00358                     (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
00359                   errmsg("connection requires a valid client certificate")));
00360         }
00361 #else
00362 
00363         /*
00364          * hba.c makes sure hba->clientcert can't be set unless OpenSSL is
00365          * present.
00366          */
00367         Assert(false);
00368 #endif
00369     }
00370 
00371     /*
00372      * Now proceed to do the actual authentication check
00373      */
00374     switch (port->hba->auth_method)
00375     {
00376         case uaReject:
00377 
00378             /*
00379              * An explicit "reject" entry in pg_hba.conf.  This report exposes
00380              * the fact that there's an explicit reject entry, which is
00381              * perhaps not so desirable from a security standpoint; but the
00382              * message for an implicit reject could confuse the DBA a lot when
00383              * the true situation is a match to an explicit reject.  And we
00384              * don't want to change the message for an implicit reject.  As
00385              * noted below, the additional information shown here doesn't
00386              * expose anything not known to an attacker.
00387              */
00388             {
00389                 char        hostinfo[NI_MAXHOST];
00390 
00391                 pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
00392                                    hostinfo, sizeof(hostinfo),
00393                                    NULL, 0,
00394                                    NI_NUMERICHOST);
00395 
00396                 if (am_walsender)
00397                 {
00398 #ifdef USE_SSL
00399                     ereport(FATAL,
00400                        (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
00401                         errmsg("pg_hba.conf rejects replication connection for host \"%s\", user \"%s\", %s",
00402                                hostinfo, port->user_name,
00403                                port->ssl ? _("SSL on") : _("SSL off"))));
00404 #else
00405                     ereport(FATAL,
00406                        (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
00407                         errmsg("pg_hba.conf rejects replication connection for host \"%s\", user \"%s\"",
00408                                hostinfo, port->user_name)));
00409 #endif
00410                 }
00411                 else
00412                 {
00413 #ifdef USE_SSL
00414                     ereport(FATAL,
00415                        (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
00416                         errmsg("pg_hba.conf rejects connection for host \"%s\", user \"%s\", database \"%s\", %s",
00417                                hostinfo, port->user_name,
00418                                port->database_name,
00419                                port->ssl ? _("SSL on") : _("SSL off"))));
00420 #else
00421                     ereport(FATAL,
00422                        (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
00423                         errmsg("pg_hba.conf rejects connection for host \"%s\", user \"%s\", database \"%s\"",
00424                                hostinfo, port->user_name,
00425                                port->database_name)));
00426 #endif
00427                 }
00428                 break;
00429             }
00430 
00431         case uaImplicitReject:
00432 
00433             /*
00434              * No matching entry, so tell the user we fell through.
00435              *
00436              * NOTE: the extra info reported here is not a security breach,
00437              * because all that info is known at the frontend and must be
00438              * assumed known to bad guys.  We're merely helping out the less
00439              * clueful good guys.
00440              */
00441             {
00442                 char        hostinfo[NI_MAXHOST];
00443 
00444                 pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
00445                                    hostinfo, sizeof(hostinfo),
00446                                    NULL, 0,
00447                                    NI_NUMERICHOST);
00448 
00449 #define HOSTNAME_LOOKUP_DETAIL(port) \
00450                 (port->remote_hostname                \
00451                  ? (port->remote_hostname_resolv == +1                  \
00452                     ? errdetail_log("Client IP address resolved to \"%s\", forward lookup matches.", port->remote_hostname) \
00453                     : (port->remote_hostname_resolv == 0                \
00454                        ? errdetail_log("Client IP address resolved to \"%s\", forward lookup not checked.", port->remote_hostname) \
00455                        : (port->remote_hostname_resolv == -1            \
00456                           ? errdetail_log("Client IP address resolved to \"%s\", forward lookup does not match.", port->remote_hostname) \
00457                           : 0)))                                        \
00458                  : 0)
00459 
00460                 if (am_walsender)
00461                 {
00462 #ifdef USE_SSL
00463                     ereport(FATAL,
00464                        (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
00465                         errmsg("no pg_hba.conf entry for replication connection from host \"%s\", user \"%s\", %s",
00466                                hostinfo, port->user_name,
00467                                port->ssl ? _("SSL on") : _("SSL off")),
00468                         HOSTNAME_LOOKUP_DETAIL(port)));
00469 #else
00470                     ereport(FATAL,
00471                        (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
00472                         errmsg("no pg_hba.conf entry for replication connection from host \"%s\", user \"%s\"",
00473                                hostinfo, port->user_name),
00474                         HOSTNAME_LOOKUP_DETAIL(port)));
00475 #endif
00476                 }
00477                 else
00478                 {
00479 #ifdef USE_SSL
00480                     ereport(FATAL,
00481                        (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
00482                         errmsg("no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\", %s",
00483                                hostinfo, port->user_name,
00484                                port->database_name,
00485                                port->ssl ? _("SSL on") : _("SSL off")),
00486                         HOSTNAME_LOOKUP_DETAIL(port)));
00487 #else
00488                     ereport(FATAL,
00489                        (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
00490                         errmsg("no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\"",
00491                                hostinfo, port->user_name,
00492                                port->database_name),
00493                         HOSTNAME_LOOKUP_DETAIL(port)));
00494 #endif
00495                 }
00496                 break;
00497             }
00498 
00499         case uaKrb5:
00500 #ifdef KRB5
00501             sendAuthRequest(port, AUTH_REQ_KRB5);
00502             status = pg_krb5_recvauth(port);
00503 #else
00504             Assert(false);
00505 #endif
00506             break;
00507 
00508         case uaGSS:
00509 #ifdef ENABLE_GSS
00510             sendAuthRequest(port, AUTH_REQ_GSS);
00511             status = pg_GSS_recvauth(port);
00512 #else
00513             Assert(false);
00514 #endif
00515             break;
00516 
00517         case uaSSPI:
00518 #ifdef ENABLE_SSPI
00519             sendAuthRequest(port, AUTH_REQ_SSPI);
00520             status = pg_SSPI_recvauth(port);
00521 #else
00522             Assert(false);
00523 #endif
00524             break;
00525 
00526         case uaPeer:
00527 #ifdef HAVE_UNIX_SOCKETS
00528             status = auth_peer(port);
00529 #else
00530             Assert(false);
00531 #endif
00532             break;
00533 
00534         case uaIdent:
00535             status = ident_inet(port);
00536             break;
00537 
00538         case uaMD5:
00539             if (Db_user_namespace)
00540                 ereport(FATAL,
00541                         (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
00542                          errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled")));
00543             sendAuthRequest(port, AUTH_REQ_MD5);
00544             status = recv_and_check_password_packet(port);
00545             break;
00546 
00547         case uaPassword:
00548             sendAuthRequest(port, AUTH_REQ_PASSWORD);
00549             status = recv_and_check_password_packet(port);
00550             break;
00551 
00552         case uaPAM:
00553 #ifdef USE_PAM
00554             status = CheckPAMAuth(port, port->user_name, "");
00555 #else
00556             Assert(false);
00557 #endif   /* USE_PAM */
00558             break;
00559 
00560         case uaLDAP:
00561 #ifdef USE_LDAP
00562             status = CheckLDAPAuth(port);
00563 #else
00564             Assert(false);
00565 #endif
00566             break;
00567 
00568         case uaCert:
00569 #ifdef USE_SSL
00570             status = CheckCertAuth(port);
00571 #else
00572             Assert(false);
00573 #endif
00574             break;
00575         case uaRADIUS:
00576             status = CheckRADIUSAuth(port);
00577             break;
00578         case uaTrust:
00579             status = STATUS_OK;
00580             break;
00581     }
00582 
00583     if (ClientAuthentication_hook)
00584         (*ClientAuthentication_hook) (port, status);
00585 
00586     if (status == STATUS_OK)
00587         sendAuthRequest(port, AUTH_REQ_OK);
00588     else
00589         auth_failed(port, status);
00590 
00591     /* Done with authentication, so we should turn off immediate interrupts */
00592     ImmediateInterruptOK = false;
00593 }
00594 
00595 
00596 /*
00597  * Send an authentication request packet to the frontend.
00598  */
00599 static void
00600 sendAuthRequest(Port *port, AuthRequest areq)
00601 {
00602     StringInfoData buf;
00603 
00604     pq_beginmessage(&buf, 'R');
00605     pq_sendint(&buf, (int32) areq, sizeof(int32));
00606 
00607     /* Add the salt for encrypted passwords. */
00608     if (areq == AUTH_REQ_MD5)
00609         pq_sendbytes(&buf, port->md5Salt, 4);
00610 
00611 #if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
00612 
00613     /*
00614      * Add the authentication data for the next step of the GSSAPI or SSPI
00615      * negotiation.
00616      */
00617     else if (areq == AUTH_REQ_GSS_CONT)
00618     {
00619         if (port->gss->outbuf.length > 0)
00620         {
00621             elog(DEBUG4, "sending GSS token of length %u",
00622                  (unsigned int) port->gss->outbuf.length);
00623 
00624             pq_sendbytes(&buf, port->gss->outbuf.value, port->gss->outbuf.length);
00625         }
00626     }
00627 #endif
00628 
00629     pq_endmessage(&buf);
00630 
00631     /*
00632      * Flush message so client will see it, except for AUTH_REQ_OK, which need
00633      * not be sent until we are ready for queries.
00634      */
00635     if (areq != AUTH_REQ_OK)
00636         pq_flush();
00637 }
00638 
00639 /*
00640  * Collect password response packet from frontend.
00641  *
00642  * Returns NULL if couldn't get password, else palloc'd string.
00643  */
00644 static char *
00645 recv_password_packet(Port *port)
00646 {
00647     StringInfoData buf;
00648 
00649     if (PG_PROTOCOL_MAJOR(port->proto) >= 3)
00650     {
00651         /* Expect 'p' message type */
00652         int         mtype;
00653 
00654         mtype = pq_getbyte();
00655         if (mtype != 'p')
00656         {
00657             /*
00658              * If the client just disconnects without offering a password,
00659              * don't make a log entry.  This is legal per protocol spec and in
00660              * fact commonly done by psql, so complaining just clutters the
00661              * log.
00662              */
00663             if (mtype != EOF)
00664                 ereport(COMMERROR,
00665                         (errcode(ERRCODE_PROTOCOL_VIOLATION),
00666                     errmsg("expected password response, got message type %d",
00667                            mtype)));
00668             return NULL;        /* EOF or bad message type */
00669         }
00670     }
00671     else
00672     {
00673         /* For pre-3.0 clients, avoid log entry if they just disconnect */
00674         if (pq_peekbyte() == EOF)
00675             return NULL;        /* EOF */
00676     }
00677 
00678     initStringInfo(&buf);
00679     if (pq_getmessage(&buf, 1000))      /* receive password */
00680     {
00681         /* EOF - pq_getmessage already logged a suitable message */
00682         pfree(buf.data);
00683         return NULL;
00684     }
00685 
00686     /*
00687      * Apply sanity check: password packet length should agree with length of
00688      * contained string.  Note it is safe to use strlen here because
00689      * StringInfo is guaranteed to have an appended '\0'.
00690      */
00691     if (strlen(buf.data) + 1 != buf.len)
00692         ereport(COMMERROR,
00693                 (errcode(ERRCODE_PROTOCOL_VIOLATION),
00694                  errmsg("invalid password packet size")));
00695 
00696     /* Do not echo password to logs, for security. */
00697     ereport(DEBUG5,
00698             (errmsg("received password packet")));
00699 
00700     /*
00701      * Return the received string.  Note we do not attempt to do any
00702      * character-set conversion on it; since we don't yet know the client's
00703      * encoding, there wouldn't be much point.
00704      */
00705     return buf.data;
00706 }
00707 
00708 
00709 /*----------------------------------------------------------------
00710  * MD5 authentication
00711  *----------------------------------------------------------------
00712  */
00713 
00714 /*
00715  * Called when we have sent an authorization request for a password.
00716  * Get the response and check it.
00717  */
00718 static int
00719 recv_and_check_password_packet(Port *port)
00720 {
00721     char       *passwd;
00722     int         result;
00723 
00724     passwd = recv_password_packet(port);
00725 
00726     if (passwd == NULL)
00727         return STATUS_EOF;      /* client wouldn't send password */
00728 
00729     result = md5_crypt_verify(port, port->user_name, passwd);
00730 
00731     pfree(passwd);
00732 
00733     return result;
00734 }
00735 
00736 
00737 /*----------------------------------------------------------------
00738  * MIT Kerberos authentication system - protocol version 5
00739  *----------------------------------------------------------------
00740  */
00741 #ifdef KRB5
00742 
00743 static int
00744 pg_krb5_init(Port *port)
00745 {
00746     krb5_error_code retval;
00747     char       *khostname;
00748 
00749     if (pg_krb5_initialised)
00750         return STATUS_OK;
00751 
00752     retval = krb5_init_context(&pg_krb5_context);
00753     if (retval)
00754     {
00755         ereport(LOG,
00756                 (errmsg("Kerberos initialization returned error %d",
00757                         retval)));
00758         com_err("postgres", retval, "while initializing krb5");
00759         return STATUS_ERROR;
00760     }
00761 
00762     retval = krb5_kt_resolve(pg_krb5_context, pg_krb_server_keyfile, &pg_krb5_keytab);
00763     if (retval)
00764     {
00765         ereport(LOG,
00766                 (errmsg("Kerberos keytab resolving returned error %d",
00767                         retval)));
00768         com_err("postgres", retval, "while resolving keytab file \"%s\"",
00769                 pg_krb_server_keyfile);
00770         krb5_free_context(pg_krb5_context);
00771         return STATUS_ERROR;
00772     }
00773 
00774     /*
00775      * If no hostname was specified, pg_krb_server_hostname is already NULL.
00776      * If it's set to blank, force it to NULL.
00777      */
00778     khostname = port->hba->krb_server_hostname;
00779     if (khostname && khostname[0] == '\0')
00780         khostname = NULL;
00781 
00782     retval = krb5_sname_to_principal(pg_krb5_context,
00783                                      khostname,
00784                                      pg_krb_srvnam,
00785                                      KRB5_NT_SRV_HST,
00786                                      &pg_krb5_server);
00787     if (retval)
00788     {
00789         ereport(LOG,
00790                 (errmsg("Kerberos sname_to_principal(\"%s\", \"%s\") returned error %d",
00791          khostname ? khostname : "server hostname", pg_krb_srvnam, retval)));
00792         com_err("postgres", retval,
00793         "while getting server principal for server \"%s\" for service \"%s\"",
00794                 khostname ? khostname : "server hostname", pg_krb_srvnam);
00795         krb5_kt_close(pg_krb5_context, pg_krb5_keytab);
00796         krb5_free_context(pg_krb5_context);
00797         return STATUS_ERROR;
00798     }
00799 
00800     pg_krb5_initialised = 1;
00801     return STATUS_OK;
00802 }
00803 
00804 
00805 /*
00806  * pg_krb5_recvauth -- server routine to receive authentication information
00807  *                     from the client
00808  *
00809  * We still need to compare the username obtained from the client's setup
00810  * packet to the authenticated name.
00811  *
00812  * We have our own keytab file because postgres is unlikely to run as root,
00813  * and so cannot read the default keytab.
00814  */
00815 static int
00816 pg_krb5_recvauth(Port *port)
00817 {
00818     krb5_error_code retval;
00819     int         ret;
00820     krb5_auth_context auth_context = NULL;
00821     krb5_ticket *ticket;
00822     char       *kusername;
00823     char       *cp;
00824 
00825     ret = pg_krb5_init(port);
00826     if (ret != STATUS_OK)
00827         return ret;
00828 
00829     retval = krb5_recvauth(pg_krb5_context, &auth_context,
00830                            (krb5_pointer) &port->sock, pg_krb_srvnam,
00831                            pg_krb5_server, 0, pg_krb5_keytab, &ticket);
00832     if (retval)
00833     {
00834         ereport(LOG,
00835                 (errmsg("Kerberos recvauth returned error %d",
00836                         retval)));
00837         com_err("postgres", retval, "from krb5_recvauth");
00838         return STATUS_ERROR;
00839     }
00840 
00841     /*
00842      * The "client" structure comes out of the ticket and is therefore
00843      * authenticated.  Use it to check the username obtained from the
00844      * postmaster startup packet.
00845      */
00846 #if defined(HAVE_KRB5_TICKET_ENC_PART2)
00847     retval = krb5_unparse_name(pg_krb5_context,
00848                                ticket->enc_part2->client, &kusername);
00849 #elif defined(HAVE_KRB5_TICKET_CLIENT)
00850     retval = krb5_unparse_name(pg_krb5_context,
00851                                ticket->client, &kusername);
00852 #else
00853 #error "bogus configuration"
00854 #endif
00855     if (retval)
00856     {
00857         ereport(LOG,
00858                 (errmsg("Kerberos unparse_name returned error %d",
00859                         retval)));
00860         com_err("postgres", retval, "while unparsing client name");
00861         krb5_free_ticket(pg_krb5_context, ticket);
00862         krb5_auth_con_free(pg_krb5_context, auth_context);
00863         return STATUS_ERROR;
00864     }
00865 
00866     cp = strchr(kusername, '@');
00867     if (cp)
00868     {
00869         /*
00870          * If we are not going to include the realm in the username that is
00871          * passed to the ident map, destructively modify it here to remove the
00872          * realm. Then advance past the separator to check the realm.
00873          */
00874         if (!port->hba->include_realm)
00875             *cp = '\0';
00876         cp++;
00877 
00878         if (port->hba->krb_realm != NULL && strlen(port->hba->krb_realm))
00879         {
00880             /* Match realm against configured */
00881             if (pg_krb_caseins_users)
00882                 ret = pg_strcasecmp(port->hba->krb_realm, cp);
00883             else
00884                 ret = strcmp(port->hba->krb_realm, cp);
00885 
00886             if (ret)
00887             {
00888                 elog(DEBUG2,
00889                      "krb5 realm (%s) and configured realm (%s) don't match",
00890                      cp, port->hba->krb_realm);
00891 
00892                 krb5_free_ticket(pg_krb5_context, ticket);
00893                 krb5_auth_con_free(pg_krb5_context, auth_context);
00894                 return STATUS_ERROR;
00895             }
00896         }
00897     }
00898     else if (port->hba->krb_realm && strlen(port->hba->krb_realm))
00899     {
00900         elog(DEBUG2,
00901              "krb5 did not return realm but realm matching was requested");
00902 
00903         krb5_free_ticket(pg_krb5_context, ticket);
00904         krb5_auth_con_free(pg_krb5_context, auth_context);
00905         return STATUS_ERROR;
00906     }
00907 
00908     ret = check_usermap(port->hba->usermap, port->user_name, kusername,
00909                         pg_krb_caseins_users);
00910 
00911     krb5_free_ticket(pg_krb5_context, ticket);
00912     krb5_auth_con_free(pg_krb5_context, auth_context);
00913     free(kusername);
00914 
00915     return ret;
00916 }
00917 #endif   /* KRB5 */
00918 
00919 
00920 /*----------------------------------------------------------------
00921  * GSSAPI authentication system
00922  *----------------------------------------------------------------
00923  */
00924 #ifdef ENABLE_GSS
00925 
00926 #if defined(WIN32) && !defined(WIN32_ONLY_COMPILER)
00927 /*
00928  * MIT Kerberos GSSAPI DLL doesn't properly export the symbols for MingW
00929  * that contain the OIDs required. Redefine here, values copied
00930  * from src/athena/auth/krb5/src/lib/gssapi/generic/gssapi_generic.c
00931  */
00932 static const gss_OID_desc GSS_C_NT_USER_NAME_desc =
00933 {10, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x02"};
00934 static GSS_DLLIMP gss_OID GSS_C_NT_USER_NAME = &GSS_C_NT_USER_NAME_desc;
00935 #endif
00936 
00937 
00938 static void
00939 pg_GSS_error(int severity, char *errmsg, OM_uint32 maj_stat, OM_uint32 min_stat)
00940 {
00941     gss_buffer_desc gmsg;
00942     OM_uint32   lmin_s,
00943                 msg_ctx;
00944     char        msg_major[128],
00945                 msg_minor[128];
00946 
00947     /* Fetch major status message */
00948     msg_ctx = 0;
00949     gss_display_status(&lmin_s, maj_stat, GSS_C_GSS_CODE,
00950                        GSS_C_NO_OID, &msg_ctx, &gmsg);
00951     strlcpy(msg_major, gmsg.value, sizeof(msg_major));
00952     gss_release_buffer(&lmin_s, &gmsg);
00953 
00954     if (msg_ctx)
00955 
00956         /*
00957          * More than one message available. XXX: Should we loop and read all
00958          * messages? (same below)
00959          */
00960         ereport(WARNING,
00961                 (errmsg_internal("incomplete GSS error report")));
00962 
00963     /* Fetch mechanism minor status message */
00964     msg_ctx = 0;
00965     gss_display_status(&lmin_s, min_stat, GSS_C_MECH_CODE,
00966                        GSS_C_NO_OID, &msg_ctx, &gmsg);
00967     strlcpy(msg_minor, gmsg.value, sizeof(msg_minor));
00968     gss_release_buffer(&lmin_s, &gmsg);
00969 
00970     if (msg_ctx)
00971         ereport(WARNING,
00972                 (errmsg_internal("incomplete GSS minor error report")));
00973 
00974     /*
00975      * errmsg_internal, since translation of the first part must be done
00976      * before calling this function anyway.
00977      */
00978     ereport(severity,
00979             (errmsg_internal("%s", errmsg),
00980              errdetail_internal("%s: %s", msg_major, msg_minor)));
00981 }
00982 
00983 static int
00984 pg_GSS_recvauth(Port *port)
00985 {
00986     OM_uint32   maj_stat,
00987                 min_stat,
00988                 lmin_s,
00989                 gflags;
00990     int         mtype;
00991     int         ret;
00992     StringInfoData buf;
00993     gss_buffer_desc gbuf;
00994 
00995     /*
00996      * GSS auth is not supported for protocol versions before 3, because it
00997      * relies on the overall message length word to determine the GSS payload
00998      * size in AuthenticationGSSContinue and PasswordMessage messages. (This
00999      * is, in fact, a design error in our GSS support, because protocol
01000      * messages are supposed to be parsable without relying on the length
01001      * word; but it's not worth changing it now.)
01002      */
01003     if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
01004         ereport(FATAL,
01005                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01006                  errmsg("GSSAPI is not supported in protocol version 2")));
01007 
01008     if (pg_krb_server_keyfile && strlen(pg_krb_server_keyfile) > 0)
01009     {
01010         /*
01011          * Set default Kerberos keytab file for the Krb5 mechanism.
01012          *
01013          * setenv("KRB5_KTNAME", pg_krb_server_keyfile, 0); except setenv()
01014          * not always available.
01015          */
01016         if (getenv("KRB5_KTNAME") == NULL)
01017         {
01018             size_t      kt_len = strlen(pg_krb_server_keyfile) + 14;
01019             char       *kt_path = malloc(kt_len);
01020 
01021             if (!kt_path)
01022             {
01023                 ereport(LOG,
01024                         (errcode(ERRCODE_OUT_OF_MEMORY),
01025                          errmsg("out of memory")));
01026                 return STATUS_ERROR;
01027             }
01028             snprintf(kt_path, kt_len, "KRB5_KTNAME=%s", pg_krb_server_keyfile);
01029             putenv(kt_path);
01030         }
01031     }
01032 
01033     /*
01034      * We accept any service principal that's present in our keytab. This
01035      * increases interoperability between kerberos implementations that see
01036      * for example case sensitivity differently, while not really opening up
01037      * any vector of attack.
01038      */
01039     port->gss->cred = GSS_C_NO_CREDENTIAL;
01040 
01041     /*
01042      * Initialize sequence with an empty context
01043      */
01044     port->gss->ctx = GSS_C_NO_CONTEXT;
01045 
01046     /*
01047      * Loop through GSSAPI message exchange. This exchange can consist of
01048      * multiple messags sent in both directions. First message is always from
01049      * the client. All messages from client to server are password packets
01050      * (type 'p').
01051      */
01052     do
01053     {
01054         mtype = pq_getbyte();
01055         if (mtype != 'p')
01056         {
01057             /* Only log error if client didn't disconnect. */
01058             if (mtype != EOF)
01059                 ereport(COMMERROR,
01060                         (errcode(ERRCODE_PROTOCOL_VIOLATION),
01061                          errmsg("expected GSS response, got message type %d",
01062                                 mtype)));
01063             return STATUS_ERROR;
01064         }
01065 
01066         /* Get the actual GSS token */
01067         initStringInfo(&buf);
01068         if (pq_getmessage(&buf, PG_MAX_AUTH_TOKEN_LENGTH))
01069         {
01070             /* EOF - pq_getmessage already logged error */
01071             pfree(buf.data);
01072             return STATUS_ERROR;
01073         }
01074 
01075         /* Map to GSSAPI style buffer */
01076         gbuf.length = buf.len;
01077         gbuf.value = buf.data;
01078 
01079         elog(DEBUG4, "Processing received GSS token of length %u",
01080              (unsigned int) gbuf.length);
01081 
01082         maj_stat = gss_accept_sec_context(
01083                                           &min_stat,
01084                                           &port->gss->ctx,
01085                                           port->gss->cred,
01086                                           &gbuf,
01087                                           GSS_C_NO_CHANNEL_BINDINGS,
01088                                           &port->gss->name,
01089                                           NULL,
01090                                           &port->gss->outbuf,
01091                                           &gflags,
01092                                           NULL,
01093                                           NULL);
01094 
01095         /* gbuf no longer used */
01096         pfree(buf.data);
01097 
01098         elog(DEBUG5, "gss_accept_sec_context major: %d, "
01099              "minor: %d, outlen: %u, outflags: %x",
01100              maj_stat, min_stat,
01101              (unsigned int) port->gss->outbuf.length, gflags);
01102 
01103         if (port->gss->outbuf.length != 0)
01104         {
01105             /*
01106              * Negotiation generated data to be sent to the client.
01107              */
01108             elog(DEBUG4, "sending GSS response token of length %u",
01109                  (unsigned int) port->gss->outbuf.length);
01110 
01111             sendAuthRequest(port, AUTH_REQ_GSS_CONT);
01112 
01113             gss_release_buffer(&lmin_s, &port->gss->outbuf);
01114         }
01115 
01116         if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
01117         {
01118             gss_delete_sec_context(&lmin_s, &port->gss->ctx, GSS_C_NO_BUFFER);
01119             pg_GSS_error(ERROR,
01120                        gettext_noop("accepting GSS security context failed"),
01121                          maj_stat, min_stat);
01122         }
01123 
01124         if (maj_stat == GSS_S_CONTINUE_NEEDED)
01125             elog(DEBUG4, "GSS continue needed");
01126 
01127     } while (maj_stat == GSS_S_CONTINUE_NEEDED);
01128 
01129     if (port->gss->cred != GSS_C_NO_CREDENTIAL)
01130     {
01131         /*
01132          * Release service principal credentials
01133          */
01134         gss_release_cred(&min_stat, &port->gss->cred);
01135     }
01136 
01137     /*
01138      * GSS_S_COMPLETE indicates that authentication is now complete.
01139      *
01140      * Get the name of the user that authenticated, and compare it to the pg
01141      * username that was specified for the connection.
01142      */
01143     maj_stat = gss_display_name(&min_stat, port->gss->name, &gbuf, NULL);
01144     if (maj_stat != GSS_S_COMPLETE)
01145         pg_GSS_error(ERROR,
01146                      gettext_noop("retrieving GSS user name failed"),
01147                      maj_stat, min_stat);
01148 
01149     /*
01150      * Split the username at the realm separator
01151      */
01152     if (strchr(gbuf.value, '@'))
01153     {
01154         char       *cp = strchr(gbuf.value, '@');
01155 
01156         /*
01157          * If we are not going to include the realm in the username that is
01158          * passed to the ident map, destructively modify it here to remove the
01159          * realm. Then advance past the separator to check the realm.
01160          */
01161         if (!port->hba->include_realm)
01162             *cp = '\0';
01163         cp++;
01164 
01165         if (port->hba->krb_realm != NULL && strlen(port->hba->krb_realm))
01166         {
01167             /*
01168              * Match the realm part of the name first
01169              */
01170             if (pg_krb_caseins_users)
01171                 ret = pg_strcasecmp(port->hba->krb_realm, cp);
01172             else
01173                 ret = strcmp(port->hba->krb_realm, cp);
01174 
01175             if (ret)
01176             {
01177                 /* GSS realm does not match */
01178                 elog(DEBUG2,
01179                    "GSSAPI realm (%s) and configured realm (%s) don't match",
01180                      cp, port->hba->krb_realm);
01181                 gss_release_buffer(&lmin_s, &gbuf);
01182                 return STATUS_ERROR;
01183             }
01184         }
01185     }
01186     else if (port->hba->krb_realm && strlen(port->hba->krb_realm))
01187     {
01188         elog(DEBUG2,
01189              "GSSAPI did not return realm but realm matching was requested");
01190 
01191         gss_release_buffer(&lmin_s, &gbuf);
01192         return STATUS_ERROR;
01193     }
01194 
01195     ret = check_usermap(port->hba->usermap, port->user_name, gbuf.value,
01196                         pg_krb_caseins_users);
01197 
01198     gss_release_buffer(&lmin_s, &gbuf);
01199 
01200     return ret;
01201 }
01202 #endif   /* ENABLE_GSS */
01203 
01204 
01205 /*----------------------------------------------------------------
01206  * SSPI authentication system
01207  *----------------------------------------------------------------
01208  */
01209 #ifdef ENABLE_SSPI
01210 static void
01211 pg_SSPI_error(int severity, const char *errmsg, SECURITY_STATUS r)
01212 {
01213     char        sysmsg[256];
01214 
01215     if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, r, 0,
01216                       sysmsg, sizeof(sysmsg), NULL) == 0)
01217         ereport(severity,
01218                 (errmsg_internal("%s", errmsg),
01219                  errdetail_internal("SSPI error %x", (unsigned int) r)));
01220     else
01221         ereport(severity,
01222                 (errmsg_internal("%s", errmsg),
01223                  errdetail_internal("%s (%x)", sysmsg, (unsigned int) r)));
01224 }
01225 
01226 static int
01227 pg_SSPI_recvauth(Port *port)
01228 {
01229     int         mtype;
01230     StringInfoData buf;
01231     SECURITY_STATUS r;
01232     CredHandle  sspicred;
01233     CtxtHandle *sspictx = NULL,
01234                 newctx;
01235     TimeStamp   expiry;
01236     ULONG       contextattr;
01237     SecBufferDesc inbuf;
01238     SecBufferDesc outbuf;
01239     SecBuffer   OutBuffers[1];
01240     SecBuffer   InBuffers[1];
01241     HANDLE      token;
01242     TOKEN_USER *tokenuser;
01243     DWORD       retlen;
01244     char        accountname[MAXPGPATH];
01245     char        domainname[MAXPGPATH];
01246     DWORD       accountnamesize = sizeof(accountname);
01247     DWORD       domainnamesize = sizeof(domainname);
01248     SID_NAME_USE accountnameuse;
01249     HMODULE     secur32;
01250     QUERY_SECURITY_CONTEXT_TOKEN_FN _QuerySecurityContextToken;
01251 
01252     /*
01253      * SSPI auth is not supported for protocol versions before 3, because it
01254      * relies on the overall message length word to determine the SSPI payload
01255      * size in AuthenticationGSSContinue and PasswordMessage messages. (This
01256      * is, in fact, a design error in our SSPI support, because protocol
01257      * messages are supposed to be parsable without relying on the length
01258      * word; but it's not worth changing it now.)
01259      */
01260     if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
01261         ereport(FATAL,
01262                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01263                  errmsg("SSPI is not supported in protocol version 2")));
01264 
01265     /*
01266      * Acquire a handle to the server credentials.
01267      */
01268     r = AcquireCredentialsHandle(NULL,
01269                                  "negotiate",
01270                                  SECPKG_CRED_INBOUND,
01271                                  NULL,
01272                                  NULL,
01273                                  NULL,
01274                                  NULL,
01275                                  &sspicred,
01276                                  &expiry);
01277     if (r != SEC_E_OK)
01278         pg_SSPI_error(ERROR, _("could not acquire SSPI credentials"), r);
01279 
01280     /*
01281      * Loop through SSPI message exchange. This exchange can consist of
01282      * multiple messags sent in both directions. First message is always from
01283      * the client. All messages from client to server are password packets
01284      * (type 'p').
01285      */
01286     do
01287     {
01288         mtype = pq_getbyte();
01289         if (mtype != 'p')
01290         {
01291             /* Only log error if client didn't disconnect. */
01292             if (mtype != EOF)
01293                 ereport(COMMERROR,
01294                         (errcode(ERRCODE_PROTOCOL_VIOLATION),
01295                          errmsg("expected SSPI response, got message type %d",
01296                                 mtype)));
01297             return STATUS_ERROR;
01298         }
01299 
01300         /* Get the actual SSPI token */
01301         initStringInfo(&buf);
01302         if (pq_getmessage(&buf, PG_MAX_AUTH_TOKEN_LENGTH))
01303         {
01304             /* EOF - pq_getmessage already logged error */
01305             pfree(buf.data);
01306             return STATUS_ERROR;
01307         }
01308 
01309         /* Map to SSPI style buffer */
01310         inbuf.ulVersion = SECBUFFER_VERSION;
01311         inbuf.cBuffers = 1;
01312         inbuf.pBuffers = InBuffers;
01313         InBuffers[0].pvBuffer = buf.data;
01314         InBuffers[0].cbBuffer = buf.len;
01315         InBuffers[0].BufferType = SECBUFFER_TOKEN;
01316 
01317         /* Prepare output buffer */
01318         OutBuffers[0].pvBuffer = NULL;
01319         OutBuffers[0].BufferType = SECBUFFER_TOKEN;
01320         OutBuffers[0].cbBuffer = 0;
01321         outbuf.cBuffers = 1;
01322         outbuf.pBuffers = OutBuffers;
01323         outbuf.ulVersion = SECBUFFER_VERSION;
01324 
01325 
01326         elog(DEBUG4, "Processing received SSPI token of length %u",
01327              (unsigned int) buf.len);
01328 
01329         r = AcceptSecurityContext(&sspicred,
01330                                   sspictx,
01331                                   &inbuf,
01332                                   ASC_REQ_ALLOCATE_MEMORY,
01333                                   SECURITY_NETWORK_DREP,
01334                                   &newctx,
01335                                   &outbuf,
01336                                   &contextattr,
01337                                   NULL);
01338 
01339         /* input buffer no longer used */
01340         pfree(buf.data);
01341 
01342         if (outbuf.cBuffers > 0 && outbuf.pBuffers[0].cbBuffer > 0)
01343         {
01344             /*
01345              * Negotiation generated data to be sent to the client.
01346              */
01347             elog(DEBUG4, "sending SSPI response token of length %u",
01348                  (unsigned int) outbuf.pBuffers[0].cbBuffer);
01349 
01350             port->gss->outbuf.length = outbuf.pBuffers[0].cbBuffer;
01351             port->gss->outbuf.value = outbuf.pBuffers[0].pvBuffer;
01352 
01353             sendAuthRequest(port, AUTH_REQ_GSS_CONT);
01354 
01355             FreeContextBuffer(outbuf.pBuffers[0].pvBuffer);
01356         }
01357 
01358         if (r != SEC_E_OK && r != SEC_I_CONTINUE_NEEDED)
01359         {
01360             if (sspictx != NULL)
01361             {
01362                 DeleteSecurityContext(sspictx);
01363                 free(sspictx);
01364             }
01365             FreeCredentialsHandle(&sspicred);
01366             pg_SSPI_error(ERROR,
01367                           _("could not accept SSPI security context"), r);
01368         }
01369 
01370         /*
01371          * Overwrite the current context with the one we just received. If
01372          * sspictx is NULL it was the first loop and we need to allocate a
01373          * buffer for it. On subsequent runs, we can just overwrite the buffer
01374          * contents since the size does not change.
01375          */
01376         if (sspictx == NULL)
01377         {
01378             sspictx = malloc(sizeof(CtxtHandle));
01379             if (sspictx == NULL)
01380                 ereport(ERROR,
01381                         (errmsg("out of memory")));
01382         }
01383 
01384         memcpy(sspictx, &newctx, sizeof(CtxtHandle));
01385 
01386         if (r == SEC_I_CONTINUE_NEEDED)
01387             elog(DEBUG4, "SSPI continue needed");
01388 
01389     } while (r == SEC_I_CONTINUE_NEEDED);
01390 
01391 
01392     /*
01393      * Release service principal credentials
01394      */
01395     FreeCredentialsHandle(&sspicred);
01396 
01397 
01398     /*
01399      * SEC_E_OK indicates that authentication is now complete.
01400      *
01401      * Get the name of the user that authenticated, and compare it to the pg
01402      * username that was specified for the connection.
01403      *
01404      * MingW is missing the export for QuerySecurityContextToken in the
01405      * secur32 library, so we have to load it dynamically.
01406      */
01407 
01408     secur32 = LoadLibrary("SECUR32.DLL");
01409     if (secur32 == NULL)
01410         ereport(ERROR,
01411                 (errmsg_internal("could not load secur32.dll: error code %lu",
01412                                  GetLastError())));
01413 
01414     _QuerySecurityContextToken = (QUERY_SECURITY_CONTEXT_TOKEN_FN)
01415         GetProcAddress(secur32, "QuerySecurityContextToken");
01416     if (_QuerySecurityContextToken == NULL)
01417     {
01418         FreeLibrary(secur32);
01419         ereport(ERROR,
01420                 (errmsg_internal("could not locate QuerySecurityContextToken in secur32.dll: error code %lu",
01421                                  GetLastError())));
01422     }
01423 
01424     r = (_QuerySecurityContextToken) (sspictx, &token);
01425     if (r != SEC_E_OK)
01426     {
01427         FreeLibrary(secur32);
01428         pg_SSPI_error(ERROR,
01429                       _("could not get token from SSPI security context"), r);
01430     }
01431 
01432     FreeLibrary(secur32);
01433 
01434     /*
01435      * No longer need the security context, everything from here on uses the
01436      * token instead.
01437      */
01438     DeleteSecurityContext(sspictx);
01439     free(sspictx);
01440 
01441     if (!GetTokenInformation(token, TokenUser, NULL, 0, &retlen) && GetLastError() != 122)
01442         ereport(ERROR,
01443             (errmsg_internal("could not get token user size: error code %lu",
01444                              GetLastError())));
01445 
01446     tokenuser = malloc(retlen);
01447     if (tokenuser == NULL)
01448         ereport(ERROR,
01449                 (errmsg("out of memory")));
01450 
01451     if (!GetTokenInformation(token, TokenUser, tokenuser, retlen, &retlen))
01452         ereport(ERROR,
01453                 (errmsg_internal("could not get user token: error code %lu",
01454                                  GetLastError())));
01455 
01456     if (!LookupAccountSid(NULL, tokenuser->User.Sid, accountname, &accountnamesize,
01457                           domainname, &domainnamesize, &accountnameuse))
01458         ereport(ERROR,
01459             (errmsg_internal("could not look up account SID: error code %lu",
01460                              GetLastError())));
01461 
01462     free(tokenuser);
01463 
01464     /*
01465      * Compare realm/domain if requested. In SSPI, always compare case
01466      * insensitive.
01467      */
01468     if (port->hba->krb_realm && strlen(port->hba->krb_realm))
01469     {
01470         if (pg_strcasecmp(port->hba->krb_realm, domainname) != 0)
01471         {
01472             elog(DEBUG2,
01473                  "SSPI domain (%s) and configured domain (%s) don't match",
01474                  domainname, port->hba->krb_realm);
01475 
01476             return STATUS_ERROR;
01477         }
01478     }
01479 
01480     /*
01481      * We have the username (without domain/realm) in accountname, compare to
01482      * the supplied value. In SSPI, always compare case insensitive.
01483      *
01484      * If set to include realm, append it in <username>@<realm> format.
01485      */
01486     if (port->hba->include_realm)
01487     {
01488         char       *namebuf;
01489         int         retval;
01490 
01491         namebuf = palloc(strlen(accountname) + strlen(domainname) + 2);
01492         sprintf(namebuf, "%s@%s", accountname, domainname);
01493         retval = check_usermap(port->hba->usermap, port->user_name, namebuf, true);
01494         pfree(namebuf);
01495         return retval;
01496     }
01497     else
01498         return check_usermap(port->hba->usermap, port->user_name, accountname, true);
01499 }
01500 #endif   /* ENABLE_SSPI */
01501 
01502 
01503 
01504 /*----------------------------------------------------------------
01505  * Ident authentication system
01506  *----------------------------------------------------------------
01507  */
01508 
01509 /*
01510  *  Parse the string "*ident_response" as a response from a query to an Ident
01511  *  server.  If it's a normal response indicating a user name, return true
01512  *  and store the user name at *ident_user. If it's anything else,
01513  *  return false.
01514  */
01515 static bool
01516 interpret_ident_response(const char *ident_response,
01517                          char *ident_user)
01518 {
01519     const char *cursor = ident_response;        /* Cursor into *ident_response */
01520 
01521     /*
01522      * Ident's response, in the telnet tradition, should end in crlf (\r\n).
01523      */
01524     if (strlen(ident_response) < 2)
01525         return false;
01526     else if (ident_response[strlen(ident_response) - 2] != '\r')
01527         return false;
01528     else
01529     {
01530         while (*cursor != ':' && *cursor != '\r')
01531             cursor++;           /* skip port field */
01532 
01533         if (*cursor != ':')
01534             return false;
01535         else
01536         {
01537             /* We're positioned to colon before response type field */
01538             char        response_type[80];
01539             int         i;      /* Index into *response_type */
01540 
01541             cursor++;           /* Go over colon */
01542             while (pg_isblank(*cursor))
01543                 cursor++;       /* skip blanks */
01544             i = 0;
01545             while (*cursor != ':' && *cursor != '\r' && !pg_isblank(*cursor) &&
01546                    i < (int) (sizeof(response_type) - 1))
01547                 response_type[i++] = *cursor++;
01548             response_type[i] = '\0';
01549             while (pg_isblank(*cursor))
01550                 cursor++;       /* skip blanks */
01551             if (strcmp(response_type, "USERID") != 0)
01552                 return false;
01553             else
01554             {
01555                 /*
01556                  * It's a USERID response.  Good.  "cursor" should be pointing
01557                  * to the colon that precedes the operating system type.
01558                  */
01559                 if (*cursor != ':')
01560                     return false;
01561                 else
01562                 {
01563                     cursor++;   /* Go over colon */
01564                     /* Skip over operating system field. */
01565                     while (*cursor != ':' && *cursor != '\r')
01566                         cursor++;
01567                     if (*cursor != ':')
01568                         return false;
01569                     else
01570                     {
01571                         int         i;  /* Index into *ident_user */
01572 
01573                         cursor++;       /* Go over colon */
01574                         while (pg_isblank(*cursor))
01575                             cursor++;   /* skip blanks */
01576                         /* Rest of line is user name.  Copy it over. */
01577                         i = 0;
01578                         while (*cursor != '\r' && i < IDENT_USERNAME_MAX)
01579                             ident_user[i++] = *cursor++;
01580                         ident_user[i] = '\0';
01581                         return true;
01582                     }
01583                 }
01584             }
01585         }
01586     }
01587 }
01588 
01589 
01590 /*
01591  *  Talk to the ident server on host "remote_ip_addr" and find out who
01592  *  owns the tcp connection from his port "remote_port" to port
01593  *  "local_port_addr" on host "local_ip_addr".  Return the user name the
01594  *  ident server gives as "*ident_user".
01595  *
01596  *  IP addresses and port numbers are in network byte order.
01597  *
01598  *  But iff we're unable to get the information from ident, return false.
01599  */
01600 static int
01601 ident_inet(hbaPort *port)
01602 {
01603     const SockAddr remote_addr = port->raddr;
01604     const SockAddr local_addr = port->laddr;
01605     char        ident_user[IDENT_USERNAME_MAX + 1];
01606     pgsocket    sock_fd;        /* File descriptor for socket on which we talk
01607                                  * to Ident */
01608     int         rc;             /* Return code from a locally called function */
01609     bool        ident_return;
01610     char        remote_addr_s[NI_MAXHOST];
01611     char        remote_port[NI_MAXSERV];
01612     char        local_addr_s[NI_MAXHOST];
01613     char        local_port[NI_MAXSERV];
01614     char        ident_port[NI_MAXSERV];
01615     char        ident_query[80];
01616     char        ident_response[80 + IDENT_USERNAME_MAX];
01617     struct addrinfo *ident_serv = NULL,
01618                *la = NULL,
01619                 hints;
01620 
01621     /*
01622      * Might look a little weird to first convert it to text and then back to
01623      * sockaddr, but it's protocol independent.
01624      */
01625     pg_getnameinfo_all(&remote_addr.addr, remote_addr.salen,
01626                        remote_addr_s, sizeof(remote_addr_s),
01627                        remote_port, sizeof(remote_port),
01628                        NI_NUMERICHOST | NI_NUMERICSERV);
01629     pg_getnameinfo_all(&local_addr.addr, local_addr.salen,
01630                        local_addr_s, sizeof(local_addr_s),
01631                        local_port, sizeof(local_port),
01632                        NI_NUMERICHOST | NI_NUMERICSERV);
01633 
01634     snprintf(ident_port, sizeof(ident_port), "%d", IDENT_PORT);
01635     hints.ai_flags = AI_NUMERICHOST;
01636     hints.ai_family = remote_addr.addr.ss_family;
01637     hints.ai_socktype = SOCK_STREAM;
01638     hints.ai_protocol = 0;
01639     hints.ai_addrlen = 0;
01640     hints.ai_canonname = NULL;
01641     hints.ai_addr = NULL;
01642     hints.ai_next = NULL;
01643     rc = pg_getaddrinfo_all(remote_addr_s, ident_port, &hints, &ident_serv);
01644     if (rc || !ident_serv)
01645     {
01646         if (ident_serv)
01647             pg_freeaddrinfo_all(hints.ai_family, ident_serv);
01648         return STATUS_ERROR;    /* we don't expect this to happen */
01649     }
01650 
01651     hints.ai_flags = AI_NUMERICHOST;
01652     hints.ai_family = local_addr.addr.ss_family;
01653     hints.ai_socktype = SOCK_STREAM;
01654     hints.ai_protocol = 0;
01655     hints.ai_addrlen = 0;
01656     hints.ai_canonname = NULL;
01657     hints.ai_addr = NULL;
01658     hints.ai_next = NULL;
01659     rc = pg_getaddrinfo_all(local_addr_s, NULL, &hints, &la);
01660     if (rc || !la)
01661     {
01662         if (la)
01663             pg_freeaddrinfo_all(hints.ai_family, la);
01664         return STATUS_ERROR;    /* we don't expect this to happen */
01665     }
01666 
01667     sock_fd = socket(ident_serv->ai_family, ident_serv->ai_socktype,
01668                      ident_serv->ai_protocol);
01669     if (sock_fd < 0)
01670     {
01671         ereport(LOG,
01672                 (errcode_for_socket_access(),
01673                  errmsg("could not create socket for Ident connection: %m")));
01674         ident_return = false;
01675         goto ident_inet_done;
01676     }
01677 
01678     /*
01679      * Bind to the address which the client originally contacted, otherwise
01680      * the ident server won't be able to match up the right connection. This
01681      * is necessary if the PostgreSQL server is running on an IP alias.
01682      */
01683     rc = bind(sock_fd, la->ai_addr, la->ai_addrlen);
01684     if (rc != 0)
01685     {
01686         ereport(LOG,
01687                 (errcode_for_socket_access(),
01688                  errmsg("could not bind to local address \"%s\": %m",
01689                         local_addr_s)));
01690         ident_return = false;
01691         goto ident_inet_done;
01692     }
01693 
01694     rc = connect(sock_fd, ident_serv->ai_addr,
01695                  ident_serv->ai_addrlen);
01696     if (rc != 0)
01697     {
01698         ereport(LOG,
01699                 (errcode_for_socket_access(),
01700                  errmsg("could not connect to Ident server at address \"%s\", port %s: %m",
01701                         remote_addr_s, ident_port)));
01702         ident_return = false;
01703         goto ident_inet_done;
01704     }
01705 
01706     /* The query we send to the Ident server */
01707     snprintf(ident_query, sizeof(ident_query), "%s,%s\r\n",
01708              remote_port, local_port);
01709 
01710     /* loop in case send is interrupted */
01711     do
01712     {
01713         rc = send(sock_fd, ident_query, strlen(ident_query), 0);
01714     } while (rc < 0 && errno == EINTR);
01715 
01716     if (rc < 0)
01717     {
01718         ereport(LOG,
01719                 (errcode_for_socket_access(),
01720                  errmsg("could not send query to Ident server at address \"%s\", port %s: %m",
01721                         remote_addr_s, ident_port)));
01722         ident_return = false;
01723         goto ident_inet_done;
01724     }
01725 
01726     do
01727     {
01728         rc = recv(sock_fd, ident_response, sizeof(ident_response) - 1, 0);
01729     } while (rc < 0 && errno == EINTR);
01730 
01731     if (rc < 0)
01732     {
01733         ereport(LOG,
01734                 (errcode_for_socket_access(),
01735                  errmsg("could not receive response from Ident server at address \"%s\", port %s: %m",
01736                         remote_addr_s, ident_port)));
01737         ident_return = false;
01738         goto ident_inet_done;
01739     }
01740 
01741     ident_response[rc] = '\0';
01742     ident_return = interpret_ident_response(ident_response, ident_user);
01743     if (!ident_return)
01744         ereport(LOG,
01745             (errmsg("invalidly formatted response from Ident server: \"%s\"",
01746                     ident_response)));
01747 
01748 ident_inet_done:
01749     if (sock_fd >= 0)
01750         closesocket(sock_fd);
01751     pg_freeaddrinfo_all(remote_addr.addr.ss_family, ident_serv);
01752     pg_freeaddrinfo_all(local_addr.addr.ss_family, la);
01753 
01754     if (ident_return)
01755         /* Success! Check the usermap */
01756         return check_usermap(port->hba->usermap, port->user_name, ident_user, false);
01757     return STATUS_ERROR;
01758 }
01759 
01760 /*
01761  *  Ask kernel about the credentials of the connecting process,
01762  *  determine the symbolic name of the corresponding user, and check
01763  *  if valid per the usermap.
01764  *
01765  *  Iff authorized, return STATUS_OK, otherwise return STATUS_ERROR.
01766  */
01767 #ifdef HAVE_UNIX_SOCKETS
01768 
01769 static int
01770 auth_peer(hbaPort *port)
01771 {
01772     char        ident_user[IDENT_USERNAME_MAX + 1];
01773     uid_t       uid;
01774     gid_t       gid;
01775     struct passwd *pass;
01776 
01777     errno = 0;
01778     if (getpeereid(port->sock, &uid, &gid) != 0)
01779     {
01780         /* Provide special error message if getpeereid is a stub */
01781         if (errno == ENOSYS)
01782             ereport(LOG,
01783                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01784             errmsg("peer authentication is not supported on this platform")));
01785         else
01786             ereport(LOG,
01787                     (errcode_for_socket_access(),
01788                      errmsg("could not get peer credentials: %m")));
01789         return STATUS_ERROR;
01790     }
01791 
01792     pass = getpwuid(uid);
01793 
01794     if (pass == NULL)
01795     {
01796         ereport(LOG,
01797                 (errmsg("local user with ID %d does not exist",
01798                         (int) uid)));
01799         return STATUS_ERROR;
01800     }
01801 
01802     strlcpy(ident_user, pass->pw_name, IDENT_USERNAME_MAX + 1);
01803 
01804     return check_usermap(port->hba->usermap, port->user_name, ident_user, false);
01805 }
01806 #endif   /* HAVE_UNIX_SOCKETS */
01807 
01808 
01809 /*----------------------------------------------------------------
01810  * PAM authentication system
01811  *----------------------------------------------------------------
01812  */
01813 #ifdef USE_PAM
01814 
01815 /*
01816  * PAM conversation function
01817  */
01818 
01819 static int
01820 pam_passwd_conv_proc(int num_msg, const struct pam_message ** msg,
01821                      struct pam_response ** resp, void *appdata_ptr)
01822 {
01823     char       *passwd;
01824     struct pam_response *reply;
01825     int         i;
01826 
01827     if (appdata_ptr)
01828         passwd = (char *) appdata_ptr;
01829     else
01830     {
01831         /*
01832          * Workaround for Solaris 2.6 where the PAM library is broken and does
01833          * not pass appdata_ptr to the conversation routine
01834          */
01835         passwd = pam_passwd;
01836     }
01837 
01838     *resp = NULL;               /* in case of error exit */
01839 
01840     if (num_msg <= 0 || num_msg > PAM_MAX_NUM_MSG)
01841         return PAM_CONV_ERR;
01842 
01843     /*
01844      * Explicitly not using palloc here - PAM will free this memory in
01845      * pam_end()
01846      */
01847     if ((reply = calloc(num_msg, sizeof(struct pam_response))) == NULL)
01848     {
01849         ereport(LOG,
01850                 (errcode(ERRCODE_OUT_OF_MEMORY),
01851                  errmsg("out of memory")));
01852         return PAM_CONV_ERR;
01853     }
01854 
01855     for (i = 0; i < num_msg; i++)
01856     {
01857         switch (msg[i]->msg_style)
01858         {
01859             case PAM_PROMPT_ECHO_OFF:
01860                 if (strlen(passwd) == 0)
01861                 {
01862                     /*
01863                      * Password wasn't passed to PAM the first time around -
01864                      * let's go ask the client to send a password, which we
01865                      * then stuff into PAM.
01866                      */
01867                     sendAuthRequest(pam_port_cludge, AUTH_REQ_PASSWORD);
01868                     passwd = recv_password_packet(pam_port_cludge);
01869                     if (passwd == NULL)
01870                     {
01871                         /*
01872                          * Client didn't want to send password.  We
01873                          * intentionally do not log anything about this.
01874                          */
01875                         goto fail;
01876                     }
01877                     if (strlen(passwd) == 0)
01878                     {
01879                         ereport(LOG,
01880                               (errmsg("empty password returned by client")));
01881                         goto fail;
01882                     }
01883                 }
01884                 if ((reply[i].resp = strdup(passwd)) == NULL)
01885                     goto fail;
01886                 reply[i].resp_retcode = PAM_SUCCESS;
01887                 break;
01888             case PAM_ERROR_MSG:
01889                 ereport(LOG,
01890                         (errmsg("error from underlying PAM layer: %s",
01891                                 msg[i]->msg)));
01892                 /* FALL THROUGH */
01893             case PAM_TEXT_INFO:
01894                 /* we don't bother to log TEXT_INFO messages */
01895                 if ((reply[i].resp = strdup("")) == NULL)
01896                     goto fail;
01897                 reply[i].resp_retcode = PAM_SUCCESS;
01898                 break;
01899             default:
01900                 elog(LOG, "unsupported PAM conversation %d/\"%s\"",
01901                      msg[i]->msg_style,
01902                      msg[i]->msg ? msg[i]->msg : "(none)");
01903                 goto fail;
01904         }
01905     }
01906 
01907     *resp = reply;
01908     return PAM_SUCCESS;
01909 
01910 fail:
01911     /* free up whatever we allocated */
01912     for (i = 0; i < num_msg; i++)
01913     {
01914         if (reply[i].resp != NULL)
01915             free(reply[i].resp);
01916     }
01917     free(reply);
01918 
01919     return PAM_CONV_ERR;
01920 }
01921 
01922 
01923 /*
01924  * Check authentication against PAM.
01925  */
01926 static int
01927 CheckPAMAuth(Port *port, char *user, char *password)
01928 {
01929     int         retval;
01930     pam_handle_t *pamh = NULL;
01931 
01932     /*
01933      * We can't entirely rely on PAM to pass through appdata --- it appears
01934      * not to work on at least Solaris 2.6.  So use these ugly static
01935      * variables instead.
01936      */
01937     pam_passwd = password;
01938     pam_port_cludge = port;
01939 
01940     /*
01941      * Set the application data portion of the conversation struct This is
01942      * later used inside the PAM conversation to pass the password to the
01943      * authentication module.
01944      */
01945     pam_passw_conv.appdata_ptr = (char *) password;     /* from password above,
01946                                                          * not allocated */
01947 
01948     /* Optionally, one can set the service name in pg_hba.conf */
01949     if (port->hba->pamservice && port->hba->pamservice[0] != '\0')
01950         retval = pam_start(port->hba->pamservice, "pgsql@",
01951                            &pam_passw_conv, &pamh);
01952     else
01953         retval = pam_start(PGSQL_PAM_SERVICE, "pgsql@",
01954                            &pam_passw_conv, &pamh);
01955 
01956     if (retval != PAM_SUCCESS)
01957     {
01958         ereport(LOG,
01959                 (errmsg("could not create PAM authenticator: %s",
01960                         pam_strerror(pamh, retval))));
01961         pam_passwd = NULL;      /* Unset pam_passwd */
01962         return STATUS_ERROR;
01963     }
01964 
01965     retval = pam_set_item(pamh, PAM_USER, user);
01966 
01967     if (retval != PAM_SUCCESS)
01968     {
01969         ereport(LOG,
01970                 (errmsg("pam_set_item(PAM_USER) failed: %s",
01971                         pam_strerror(pamh, retval))));
01972         pam_passwd = NULL;      /* Unset pam_passwd */
01973         return STATUS_ERROR;
01974     }
01975 
01976     retval = pam_set_item(pamh, PAM_CONV, &pam_passw_conv);
01977 
01978     if (retval != PAM_SUCCESS)
01979     {
01980         ereport(LOG,
01981                 (errmsg("pam_set_item(PAM_CONV) failed: %s",
01982                         pam_strerror(pamh, retval))));
01983         pam_passwd = NULL;      /* Unset pam_passwd */
01984         return STATUS_ERROR;
01985     }
01986 
01987     retval = pam_authenticate(pamh, 0);
01988 
01989     if (retval != PAM_SUCCESS)
01990     {
01991         ereport(LOG,
01992                 (errmsg("pam_authenticate failed: %s",
01993                         pam_strerror(pamh, retval))));
01994         pam_passwd = NULL;      /* Unset pam_passwd */
01995         return STATUS_ERROR;
01996     }
01997 
01998     retval = pam_acct_mgmt(pamh, 0);
01999 
02000     if (retval != PAM_SUCCESS)
02001     {
02002         ereport(LOG,
02003                 (errmsg("pam_acct_mgmt failed: %s",
02004                         pam_strerror(pamh, retval))));
02005         pam_passwd = NULL;      /* Unset pam_passwd */
02006         return STATUS_ERROR;
02007     }
02008 
02009     retval = pam_end(pamh, retval);
02010 
02011     if (retval != PAM_SUCCESS)
02012     {
02013         ereport(LOG,
02014                 (errmsg("could not release PAM authenticator: %s",
02015                         pam_strerror(pamh, retval))));
02016     }
02017 
02018     pam_passwd = NULL;          /* Unset pam_passwd */
02019 
02020     return (retval == PAM_SUCCESS ? STATUS_OK : STATUS_ERROR);
02021 }
02022 #endif   /* USE_PAM */
02023 
02024 
02025 
02026 /*----------------------------------------------------------------
02027  * LDAP authentication system
02028  *----------------------------------------------------------------
02029  */
02030 #ifdef USE_LDAP
02031 
02032 /*
02033  * Initialize a connection to the LDAP server, including setting up
02034  * TLS if requested.
02035  */
02036 static int
02037 InitializeLDAPConnection(Port *port, LDAP **ldap)
02038 {
02039     int         ldapversion = LDAP_VERSION3;
02040     int         r;
02041 
02042     *ldap = ldap_init(port->hba->ldapserver, port->hba->ldapport);
02043     if (!*ldap)
02044     {
02045 #ifndef WIN32
02046         ereport(LOG,
02047                 (errmsg("could not initialize LDAP: %m")));
02048 #else
02049         ereport(LOG,
02050                 (errmsg("could not initialize LDAP: error code %d",
02051                         (int) LdapGetLastError())));
02052 #endif
02053         return STATUS_ERROR;
02054     }
02055 
02056     if ((r = ldap_set_option(*ldap, LDAP_OPT_PROTOCOL_VERSION, &ldapversion)) != LDAP_SUCCESS)
02057     {
02058         ldap_unbind(*ldap);
02059         ereport(LOG,
02060           (errmsg("could not set LDAP protocol version: %s", ldap_err2string(r))));
02061         return STATUS_ERROR;
02062     }
02063 
02064     if (port->hba->ldaptls)
02065     {
02066 #ifndef WIN32
02067         if ((r = ldap_start_tls_s(*ldap, NULL, NULL)) != LDAP_SUCCESS)
02068 #else
02069         static __ldap_start_tls_sA _ldap_start_tls_sA = NULL;
02070 
02071         if (_ldap_start_tls_sA == NULL)
02072         {
02073             /*
02074              * Need to load this function dynamically because it does not
02075              * exist on Windows 2000, and causes a load error for the whole
02076              * exe if referenced.
02077              */
02078             HANDLE      ldaphandle;
02079 
02080             ldaphandle = LoadLibrary("WLDAP32.DLL");
02081             if (ldaphandle == NULL)
02082             {
02083                 /*
02084                  * should never happen since we import other files from
02085                  * wldap32, but check anyway
02086                  */
02087                 ldap_unbind(*ldap);
02088                 ereport(LOG,
02089                         (errmsg("could not load wldap32.dll")));
02090                 return STATUS_ERROR;
02091             }
02092             _ldap_start_tls_sA = (__ldap_start_tls_sA) GetProcAddress(ldaphandle, "ldap_start_tls_sA");
02093             if (_ldap_start_tls_sA == NULL)
02094             {
02095                 ldap_unbind(*ldap);
02096                 ereport(LOG,
02097                         (errmsg("could not load function _ldap_start_tls_sA in wldap32.dll"),
02098                          errdetail("LDAP over SSL is not supported on this platform.")));
02099                 return STATUS_ERROR;
02100             }
02101 
02102             /*
02103              * Leak LDAP handle on purpose, because we need the library to
02104              * stay open. This is ok because it will only ever be leaked once
02105              * per process and is automatically cleaned up on process exit.
02106              */
02107         }
02108         if ((r = _ldap_start_tls_sA(*ldap, NULL, NULL, NULL, NULL)) != LDAP_SUCCESS)
02109 #endif
02110         {
02111             ldap_unbind(*ldap);
02112             ereport(LOG,
02113              (errmsg("could not start LDAP TLS session: %s", ldap_err2string(r))));
02114             return STATUS_ERROR;
02115         }
02116     }
02117 
02118     return STATUS_OK;
02119 }
02120 
02121 /*
02122  * Perform LDAP authentication
02123  */
02124 static int
02125 CheckLDAPAuth(Port *port)
02126 {
02127     char       *passwd;
02128     LDAP       *ldap;
02129     int         r;
02130     char       *fulluser;
02131 
02132     if (!port->hba->ldapserver || port->hba->ldapserver[0] == '\0')
02133     {
02134         ereport(LOG,
02135                 (errmsg("LDAP server not specified")));
02136         return STATUS_ERROR;
02137     }
02138 
02139     if (port->hba->ldapport == 0)
02140         port->hba->ldapport = LDAP_PORT;
02141 
02142     sendAuthRequest(port, AUTH_REQ_PASSWORD);
02143 
02144     passwd = recv_password_packet(port);
02145     if (passwd == NULL)
02146         return STATUS_EOF;      /* client wouldn't send password */
02147 
02148     if (strlen(passwd) == 0)
02149     {
02150         ereport(LOG,
02151                 (errmsg("empty password returned by client")));
02152         return STATUS_ERROR;
02153     }
02154 
02155     if (InitializeLDAPConnection(port, &ldap) == STATUS_ERROR)
02156         /* Error message already sent */
02157         return STATUS_ERROR;
02158 
02159     if (port->hba->ldapbasedn)
02160     {
02161         /*
02162          * First perform an LDAP search to find the DN for the user we are
02163          * trying to log in as.
02164          */
02165         char       *filter;
02166         LDAPMessage *search_message;
02167         LDAPMessage *entry;
02168         char       *attributes[2];
02169         char       *dn;
02170         char       *c;
02171         int         count;
02172 
02173         /*
02174          * Disallow any characters that we would otherwise need to escape,
02175          * since they aren't really reasonable in a username anyway. Allowing
02176          * them would make it possible to inject any kind of custom filters in
02177          * the LDAP filter.
02178          */
02179         for (c = port->user_name; *c; c++)
02180         {
02181             if (*c == '*' ||
02182                 *c == '(' ||
02183                 *c == ')' ||
02184                 *c == '\\' ||
02185                 *c == '/')
02186             {
02187                 ereport(LOG,
02188                         (errmsg("invalid character in user name for LDAP authentication")));
02189                 return STATUS_ERROR;
02190             }
02191         }
02192 
02193         /*
02194          * Bind with a pre-defined username/password (if available) for
02195          * searching. If none is specified, this turns into an anonymous bind.
02196          */
02197         r = ldap_simple_bind_s(ldap,
02198                           port->hba->ldapbinddn ? port->hba->ldapbinddn : "",
02199                  port->hba->ldapbindpasswd ? port->hba->ldapbindpasswd : "");
02200         if (r != LDAP_SUCCESS)
02201         {
02202             ereport(LOG,
02203                     (errmsg("could not perform initial LDAP bind for ldapbinddn \"%s\" on server \"%s\": %s",
02204                           port->hba->ldapbinddn, port->hba->ldapserver, ldap_err2string(r))));
02205             return STATUS_ERROR;
02206         }
02207 
02208         /* Fetch just one attribute, else *all* attributes are returned */
02209         attributes[0] = port->hba->ldapsearchattribute ? port->hba->ldapsearchattribute : "uid";
02210         attributes[1] = NULL;
02211 
02212         filter = palloc(strlen(attributes[0]) + strlen(port->user_name) + 4);
02213         sprintf(filter, "(%s=%s)",
02214                 attributes[0],
02215                 port->user_name);
02216 
02217         r = ldap_search_s(ldap,
02218                           port->hba->ldapbasedn,
02219                           port->hba->ldapscope,
02220                           filter,
02221                           attributes,
02222                           0,
02223                           &search_message);
02224 
02225         if (r != LDAP_SUCCESS)
02226         {
02227             ereport(LOG,
02228                     (errmsg("could not search LDAP for filter \"%s\" on server \"%s\": %s",
02229                             filter, port->hba->ldapserver, ldap_err2string(r))));
02230             pfree(filter);
02231             return STATUS_ERROR;
02232         }
02233 
02234         count = ldap_count_entries(ldap, search_message);
02235         if (count != 1)
02236         {
02237             if (count == 0)
02238                 ereport(LOG,
02239                         (errmsg("LDAP user \"%s\" does not exist", port->user_name),
02240                          errdetail("LDAP search for filter \"%s\" on server \"%s\" returned no entries.",
02241                                    filter, port->hba->ldapserver)));
02242             else
02243                 ereport(LOG,
02244                         (errmsg("LDAP user \"%s\" is not unique", port->user_name),
02245                          errdetail_plural("LDAP search for filter \"%s\" on server \"%s\" returned %d entry.",
02246                                           "LDAP search for filter \"%s\" on server \"%s\" returned %d entries.",
02247                                           count,
02248                                           filter, port->hba->ldapserver, count)));
02249 
02250             pfree(filter);
02251             ldap_msgfree(search_message);
02252             return STATUS_ERROR;
02253         }
02254 
02255         entry = ldap_first_entry(ldap, search_message);
02256         dn = ldap_get_dn(ldap, entry);
02257         if (dn == NULL)
02258         {
02259             int         error;
02260 
02261             (void) ldap_get_option(ldap, LDAP_OPT_ERROR_NUMBER, &error);
02262             ereport(LOG,
02263                     (errmsg("could not get dn for the first entry matching \"%s\" on server \"%s\": %s",
02264                     filter, port->hba->ldapserver, ldap_err2string(error))));
02265             pfree(filter);
02266             ldap_msgfree(search_message);
02267             return STATUS_ERROR;
02268         }
02269         fulluser = pstrdup(dn);
02270 
02271         pfree(filter);
02272         ldap_memfree(dn);
02273         ldap_msgfree(search_message);
02274 
02275         /* Unbind and disconnect from the LDAP server */
02276         r = ldap_unbind_s(ldap);
02277         if (r != LDAP_SUCCESS)
02278         {
02279             int         error;
02280 
02281             (void) ldap_get_option(ldap, LDAP_OPT_ERROR_NUMBER, &error);
02282             ereport(LOG,
02283                     (errmsg("could not unbind after searching for user \"%s\" on server \"%s\": %s",
02284                   fulluser, port->hba->ldapserver, ldap_err2string(error))));
02285             pfree(fulluser);
02286             return STATUS_ERROR;
02287         }
02288 
02289         /*
02290          * Need to re-initialize the LDAP connection, so that we can bind to
02291          * it with a different username.
02292          */
02293         if (InitializeLDAPConnection(port, &ldap) == STATUS_ERROR)
02294         {
02295             pfree(fulluser);
02296 
02297             /* Error message already sent */
02298             return STATUS_ERROR;
02299         }
02300     }
02301     else
02302     {
02303         fulluser = palloc((port->hba->ldapprefix ? strlen(port->hba->ldapprefix) : 0) +
02304                           strlen(port->user_name) +
02305                 (port->hba->ldapsuffix ? strlen(port->hba->ldapsuffix) : 0) +
02306                           1);
02307 
02308         sprintf(fulluser, "%s%s%s",
02309                 port->hba->ldapprefix ? port->hba->ldapprefix : "",
02310                 port->user_name,
02311                 port->hba->ldapsuffix ? port->hba->ldapsuffix : "");
02312     }
02313 
02314     r = ldap_simple_bind_s(ldap, fulluser, passwd);
02315     ldap_unbind(ldap);
02316 
02317     if (r != LDAP_SUCCESS)
02318     {
02319         ereport(LOG,
02320                 (errmsg("LDAP login failed for user \"%s\" on server \"%s\": %s",
02321                         fulluser, port->hba->ldapserver, ldap_err2string(r))));
02322         pfree(fulluser);
02323         return STATUS_ERROR;
02324     }
02325 
02326     pfree(fulluser);
02327 
02328     return STATUS_OK;
02329 }
02330 #endif   /* USE_LDAP */
02331 
02332 
02333 /*----------------------------------------------------------------
02334  * SSL client certificate authentication
02335  *----------------------------------------------------------------
02336  */
02337 #ifdef USE_SSL
02338 static int
02339 CheckCertAuth(Port *port)
02340 {
02341     Assert(port->ssl);
02342 
02343     /* Make sure we have received a username in the certificate */
02344     if (port->peer_cn == NULL ||
02345         strlen(port->peer_cn) <= 0)
02346     {
02347         ereport(LOG,
02348                 (errmsg("certificate authentication failed for user \"%s\": client certificate contains no user name",
02349                         port->user_name)));
02350         return STATUS_ERROR;
02351     }
02352 
02353     /* Just pass the certificate CN to the usermap check */
02354     return check_usermap(port->hba->usermap, port->user_name, port->peer_cn, false);
02355 }
02356 #endif
02357 
02358 
02359 /*----------------------------------------------------------------
02360  * RADIUS authentication
02361  *----------------------------------------------------------------
02362  */
02363 
02364 /*
02365  * RADIUS authentication is described in RFC2865 (and several
02366  * others).
02367  */
02368 
02369 #define RADIUS_VECTOR_LENGTH 16
02370 #define RADIUS_HEADER_LENGTH 20
02371 
02372 typedef struct
02373 {
02374     uint8       attribute;
02375     uint8       length;
02376     uint8       data[1];
02377 } radius_attribute;
02378 
02379 typedef struct
02380 {
02381     uint8       code;
02382     uint8       id;
02383     uint16      length;
02384     uint8       vector[RADIUS_VECTOR_LENGTH];
02385 } radius_packet;
02386 
02387 /* RADIUS packet types */
02388 #define RADIUS_ACCESS_REQUEST   1
02389 #define RADIUS_ACCESS_ACCEPT    2
02390 #define RADIUS_ACCESS_REJECT    3
02391 
02392 /* RAIDUS attributes */
02393 #define RADIUS_USER_NAME        1
02394 #define RADIUS_PASSWORD         2
02395 #define RADIUS_SERVICE_TYPE     6
02396 #define RADIUS_NAS_IDENTIFIER   32
02397 
02398 /* RADIUS service types */
02399 #define RADIUS_AUTHENTICATE_ONLY    8
02400 
02401 /* Maximum size of a RADIUS packet we will create or accept */
02402 #define RADIUS_BUFFER_SIZE 1024
02403 
02404 /* Seconds to wait - XXX: should be in a config variable! */
02405 #define RADIUS_TIMEOUT 3
02406 
02407 static void
02408 radius_add_attribute(radius_packet *packet, uint8 type, const unsigned char *data, int len)
02409 {
02410     radius_attribute *attr;
02411 
02412     if (packet->length + len > RADIUS_BUFFER_SIZE)
02413     {
02414         /*
02415          * With remotely realistic data, this can never happen. But catch it
02416          * just to make sure we don't overrun a buffer. We'll just skip adding
02417          * the broken attribute, which will in the end cause authentication to
02418          * fail.
02419          */
02420         elog(WARNING,
02421              "Adding attribute code %d with length %d to radius packet would create oversize packet, ignoring",
02422              type, len);
02423         return;
02424 
02425     }
02426 
02427     attr = (radius_attribute *) ((unsigned char *) packet + packet->length);
02428     attr->attribute = type;
02429     attr->length = len + 2;     /* total size includes type and length */
02430     memcpy(attr->data, data, len);
02431     packet->length += attr->length;
02432 }
02433 
02434 static int
02435 CheckRADIUSAuth(Port *port)
02436 {
02437     char       *passwd;
02438     char       *identifier = "postgresql";
02439     char        radius_buffer[RADIUS_BUFFER_SIZE];
02440     char        receive_buffer[RADIUS_BUFFER_SIZE];
02441     radius_packet *packet = (radius_packet *) radius_buffer;
02442     radius_packet *receivepacket = (radius_packet *) receive_buffer;
02443     int32       service = htonl(RADIUS_AUTHENTICATE_ONLY);
02444     uint8      *cryptvector;
02445     uint8       encryptedpassword[RADIUS_VECTOR_LENGTH];
02446     int         packetlength;
02447     pgsocket    sock;
02448 
02449 #ifdef HAVE_IPV6
02450     struct sockaddr_in6 localaddr;
02451     struct sockaddr_in6 remoteaddr;
02452 #else
02453     struct sockaddr_in localaddr;
02454     struct sockaddr_in remoteaddr;
02455 #endif
02456     struct addrinfo hint;
02457     struct addrinfo *serveraddrs;
02458     char        portstr[128];
02459     ACCEPT_TYPE_ARG3 addrsize;
02460     fd_set      fdset;
02461     struct timeval endtime;
02462     int         i,
02463                 r;
02464 
02465     /* Make sure struct alignment is correct */
02466     Assert(offsetof(radius_packet, vector) == 4);
02467 
02468     /* Verify parameters */
02469     if (!port->hba->radiusserver || port->hba->radiusserver[0] == '\0')
02470     {
02471         ereport(LOG,
02472                 (errmsg("RADIUS server not specified")));
02473         return STATUS_ERROR;
02474     }
02475 
02476     if (!port->hba->radiussecret || port->hba->radiussecret[0] == '\0')
02477     {
02478         ereport(LOG,
02479                 (errmsg("RADIUS secret not specified")));
02480         return STATUS_ERROR;
02481     }
02482 
02483     if (port->hba->radiusport == 0)
02484         port->hba->radiusport = 1812;
02485 
02486     MemSet(&hint, 0, sizeof(hint));
02487     hint.ai_socktype = SOCK_DGRAM;
02488     hint.ai_family = AF_UNSPEC;
02489     snprintf(portstr, sizeof(portstr), "%d", port->hba->radiusport);
02490 
02491     r = pg_getaddrinfo_all(port->hba->radiusserver, portstr, &hint, &serveraddrs);
02492     if (r || !serveraddrs)
02493     {
02494         ereport(LOG,
02495                 (errmsg("could not translate RADIUS server name \"%s\" to address: %s",
02496                         port->hba->radiusserver, gai_strerror(r))));
02497         if (serveraddrs)
02498             pg_freeaddrinfo_all(hint.ai_family, serveraddrs);
02499         return STATUS_ERROR;
02500     }
02501     /* XXX: add support for multiple returned addresses? */
02502 
02503     if (port->hba->radiusidentifier && port->hba->radiusidentifier[0])
02504         identifier = port->hba->radiusidentifier;
02505 
02506     /* Send regular password request to client, and get the response */
02507     sendAuthRequest(port, AUTH_REQ_PASSWORD);
02508 
02509     passwd = recv_password_packet(port);
02510     if (passwd == NULL)
02511         return STATUS_EOF;      /* client wouldn't send password */
02512 
02513     if (strlen(passwd) == 0)
02514     {
02515         ereport(LOG,
02516                 (errmsg("empty password returned by client")));
02517         return STATUS_ERROR;
02518     }
02519 
02520     if (strlen(passwd) > RADIUS_VECTOR_LENGTH)
02521     {
02522         ereport(LOG,
02523                 (errmsg("RADIUS authentication does not support passwords longer than 16 characters")));
02524         return STATUS_ERROR;
02525     }
02526 
02527     /* Construct RADIUS packet */
02528     packet->code = RADIUS_ACCESS_REQUEST;
02529     packet->length = RADIUS_HEADER_LENGTH;
02530 #ifdef USE_SSL
02531     if (RAND_bytes(packet->vector, RADIUS_VECTOR_LENGTH) != 1)
02532     {
02533         ereport(LOG,
02534                 (errmsg("could not generate random encryption vector")));
02535         return STATUS_ERROR;
02536     }
02537 #else
02538     for (i = 0; i < RADIUS_VECTOR_LENGTH; i++)
02539         /* Use a lower strengh random number of OpenSSL is not available */
02540         packet->vector[i] = random() % 255;
02541 #endif
02542     packet->id = packet->vector[0];
02543     radius_add_attribute(packet, RADIUS_SERVICE_TYPE, (unsigned char *) &service, sizeof(service));
02544     radius_add_attribute(packet, RADIUS_USER_NAME, (unsigned char *) port->user_name, strlen(port->user_name));
02545     radius_add_attribute(packet, RADIUS_NAS_IDENTIFIER, (unsigned char *) identifier, strlen(identifier));
02546 
02547     /*
02548      * RADIUS password attributes are calculated as: e[0] = p[0] XOR
02549      * MD5(secret + vector)
02550      */
02551     cryptvector = palloc(RADIUS_VECTOR_LENGTH + strlen(port->hba->radiussecret));
02552     memcpy(cryptvector, port->hba->radiussecret, strlen(port->hba->radiussecret));
02553     memcpy(cryptvector + strlen(port->hba->radiussecret), packet->vector, RADIUS_VECTOR_LENGTH);
02554     if (!pg_md5_binary(cryptvector, RADIUS_VECTOR_LENGTH + strlen(port->hba->radiussecret), encryptedpassword))
02555     {
02556         ereport(LOG,
02557                 (errmsg("could not perform MD5 encryption of password")));
02558         pfree(cryptvector);
02559         return STATUS_ERROR;
02560     }
02561     pfree(cryptvector);
02562     for (i = 0; i < RADIUS_VECTOR_LENGTH; i++)
02563     {
02564         if (i < strlen(passwd))
02565             encryptedpassword[i] = passwd[i] ^ encryptedpassword[i];
02566         else
02567             encryptedpassword[i] = '\0' ^ encryptedpassword[i];
02568     }
02569     radius_add_attribute(packet, RADIUS_PASSWORD, encryptedpassword, RADIUS_VECTOR_LENGTH);
02570 
02571     /* Length need to be in network order on the wire */
02572     packetlength = packet->length;
02573     packet->length = htons(packet->length);
02574 
02575     sock = socket(serveraddrs[0].ai_family, SOCK_DGRAM, 0);
02576     if (sock < 0)
02577     {
02578         ereport(LOG,
02579                 (errmsg("could not create RADIUS socket: %m")));
02580         pg_freeaddrinfo_all(hint.ai_family, serveraddrs);
02581         return STATUS_ERROR;
02582     }
02583 
02584     memset(&localaddr, 0, sizeof(localaddr));
02585 #ifdef HAVE_IPV6
02586     localaddr.sin6_family = serveraddrs[0].ai_family;
02587     localaddr.sin6_addr = in6addr_any;
02588     if (localaddr.sin6_family == AF_INET6)
02589         addrsize = sizeof(struct sockaddr_in6);
02590     else
02591         addrsize = sizeof(struct sockaddr_in);
02592 #else
02593     localaddr.sin_family = serveraddrs[0].ai_family;
02594     localaddr.sin_addr.s_addr = INADDR_ANY;
02595     addrsize = sizeof(struct sockaddr_in);
02596 #endif
02597     if (bind(sock, (struct sockaddr *) & localaddr, addrsize))
02598     {
02599         ereport(LOG,
02600                 (errmsg("could not bind local RADIUS socket: %m")));
02601         closesocket(sock);
02602         pg_freeaddrinfo_all(hint.ai_family, serveraddrs);
02603         return STATUS_ERROR;
02604     }
02605 
02606     if (sendto(sock, radius_buffer, packetlength, 0,
02607                serveraddrs[0].ai_addr, serveraddrs[0].ai_addrlen) < 0)
02608     {
02609         ereport(LOG,
02610                 (errmsg("could not send RADIUS packet: %m")));
02611         closesocket(sock);
02612         pg_freeaddrinfo_all(hint.ai_family, serveraddrs);
02613         return STATUS_ERROR;
02614     }
02615 
02616     /* Don't need the server address anymore */
02617     pg_freeaddrinfo_all(hint.ai_family, serveraddrs);
02618 
02619     /*
02620      * Figure out at what time we should time out. We can't just use a single
02621      * call to select() with a timeout, since somebody can be sending invalid
02622      * packets to our port thus causing us to retry in a loop and never time
02623      * out.
02624      */
02625     gettimeofday(&endtime, NULL);
02626     endtime.tv_sec += RADIUS_TIMEOUT;
02627 
02628     while (true)
02629     {
02630         struct timeval timeout;
02631         struct timeval now;
02632         int64       timeoutval;
02633 
02634         gettimeofday(&now, NULL);
02635         timeoutval = (endtime.tv_sec * 1000000 + endtime.tv_usec) - (now.tv_sec * 1000000 + now.tv_usec);
02636         if (timeoutval <= 0)
02637         {
02638             ereport(LOG,
02639                     (errmsg("timeout waiting for RADIUS response")));
02640             closesocket(sock);
02641             return STATUS_ERROR;
02642         }
02643         timeout.tv_sec = timeoutval / 1000000;
02644         timeout.tv_usec = timeoutval % 1000000;
02645 
02646         FD_ZERO(&fdset);
02647         FD_SET(sock, &fdset);
02648 
02649         r = select(sock + 1, &fdset, NULL, NULL, &timeout);
02650         if (r < 0)
02651         {
02652             if (errno == EINTR)
02653                 continue;
02654 
02655             /* Anything else is an actual error */
02656             ereport(LOG,
02657                     (errmsg("could not check status on RADIUS socket: %m")));
02658             closesocket(sock);
02659             return STATUS_ERROR;
02660         }
02661         if (r == 0)
02662         {
02663             ereport(LOG,
02664                     (errmsg("timeout waiting for RADIUS response")));
02665             closesocket(sock);
02666             return STATUS_ERROR;
02667         }
02668 
02669         /*
02670          * Attempt to read the response packet, and verify the contents.
02671          *
02672          * Any packet that's not actually a RADIUS packet, or otherwise does
02673          * not validate as an explicit reject, is just ignored and we retry
02674          * for another packet (until we reach the timeout). This is to avoid
02675          * the possibility to denial-of-service the login by flooding the
02676          * server with invalid packets on the port that we're expecting the
02677          * RADIUS response on.
02678          */
02679 
02680         addrsize = sizeof(remoteaddr);
02681         packetlength = recvfrom(sock, receive_buffer, RADIUS_BUFFER_SIZE, 0,
02682                                 (struct sockaddr *) & remoteaddr, &addrsize);
02683         if (packetlength < 0)
02684         {
02685             ereport(LOG,
02686                     (errmsg("could not read RADIUS response: %m")));
02687             return STATUS_ERROR;
02688         }
02689 
02690 #ifdef HAVE_IPV6
02691         if (remoteaddr.sin6_port != htons(port->hba->radiusport))
02692 #else
02693         if (remoteaddr.sin_port != htons(port->hba->radiusport))
02694 #endif
02695         {
02696 #ifdef HAVE_IPV6
02697             ereport(LOG,
02698                   (errmsg("RADIUS response was sent from incorrect port: %d",
02699                           ntohs(remoteaddr.sin6_port))));
02700 #else
02701             ereport(LOG,
02702                   (errmsg("RADIUS response was sent from incorrect port: %d",
02703                           ntohs(remoteaddr.sin_port))));
02704 #endif
02705             continue;
02706         }
02707 
02708         if (packetlength < RADIUS_HEADER_LENGTH)
02709         {
02710             ereport(LOG,
02711                     (errmsg("RADIUS response too short: %d", packetlength)));
02712             continue;
02713         }
02714 
02715         if (packetlength != ntohs(receivepacket->length))
02716         {
02717             ereport(LOG,
02718                     (errmsg("RADIUS response has corrupt length: %d (actual length %d)",
02719                             ntohs(receivepacket->length), packetlength)));
02720             continue;
02721         }
02722 
02723         if (packet->id != receivepacket->id)
02724         {
02725             ereport(LOG,
02726                     (errmsg("RADIUS response is to a different request: %d (should be %d)",
02727                             receivepacket->id, packet->id)));
02728             continue;
02729         }
02730 
02731         /*
02732          * Verify the response authenticator, which is calculated as
02733          * MD5(Code+ID+Length+RequestAuthenticator+Attributes+Secret)
02734          */
02735         cryptvector = palloc(packetlength + strlen(port->hba->radiussecret));
02736 
02737         memcpy(cryptvector, receivepacket, 4);  /* code+id+length */
02738         memcpy(cryptvector + 4, packet->vector, RADIUS_VECTOR_LENGTH);  /* request
02739                                                                          * authenticator, from
02740                                                                          * original packet */
02741         if (packetlength > RADIUS_HEADER_LENGTH)        /* there may be no
02742                                                          * attributes at all */
02743             memcpy(cryptvector + RADIUS_HEADER_LENGTH, receive_buffer + RADIUS_HEADER_LENGTH, packetlength - RADIUS_HEADER_LENGTH);
02744         memcpy(cryptvector + packetlength, port->hba->radiussecret, strlen(port->hba->radiussecret));
02745 
02746         if (!pg_md5_binary(cryptvector,
02747                            packetlength + strlen(port->hba->radiussecret),
02748                            encryptedpassword))
02749         {
02750             ereport(LOG,
02751             (errmsg("could not perform MD5 encryption of received packet")));
02752             pfree(cryptvector);
02753             continue;
02754         }
02755         pfree(cryptvector);
02756 
02757         if (memcmp(receivepacket->vector, encryptedpassword, RADIUS_VECTOR_LENGTH) != 0)
02758         {
02759             ereport(LOG,
02760                     (errmsg("RADIUS response has incorrect MD5 signature")));
02761             continue;
02762         }
02763 
02764         if (receivepacket->code == RADIUS_ACCESS_ACCEPT)
02765         {
02766             closesocket(sock);
02767             return STATUS_OK;
02768         }
02769         else if (receivepacket->code == RADIUS_ACCESS_REJECT)
02770         {
02771             closesocket(sock);
02772             return STATUS_ERROR;
02773         }
02774         else
02775         {
02776             ereport(LOG,
02777              (errmsg("RADIUS response has invalid code (%d) for user \"%s\"",
02778                      receivepacket->code, port->user_name)));
02779             continue;
02780         }
02781     }                           /* while (true) */
02782 }