Magnus Hagander wrote:
> This patch changes the options field of pg_hba.conf to take name/value
> pairs instead of a fixed string. This makes it a lot nicer to deal with
> auth methods that need more than one parameter, such as LDAP.
>
> While at it, it also adds map support to kerberos, gssapi and sspi and
> not just ident - basically all methods where the username comes from an
> outside source (lmk if I missed one).
>
> Also in passing, changes the methods in auth.c to deal with "unsupported
> auth method on this platform" errors the same way for all authentication
> methods.
>
> I intend to build on this patch to support setting some
> Kerberos/GSSAPI/SSPI parameters on a per-connection base, but wanted to
> get the basics in first.
>
> Obviously, documentation still pending. I'm working on that in parallel.
>
>
> So, comments? Both in general, and specifically on if we need to do
> backwards compatible parsing of LDAP options (doing it of all the other
> options would be trivial, but LDAP would be harder)
Updated version of this patch, now with doc changes.
//Magnus
*** a/doc/src/sgml/client-auth.sgml
--- b/doc/src/sgml/client-auth.sgml
***************
*** 96,108 ****
<para>
A record can have one of the seven formats
<synopsis>
! local <replaceable>database</replaceable> <replaceable>user</replaceable>
<replaceable>auth-method</replaceable> <optional><replaceable>auth-option</replaceable></optional>
! host <replaceable>database</replaceable> <replaceable>user</replaceable>
<replaceable>CIDR-address</replaceable> <replaceable>auth-method</replaceable>
<optional><replaceable>auth-option</replaceable></optional>
! hostssl <replaceable>database</replaceable> <replaceable>user</replaceable>
<replaceable>CIDR-address</replaceable> <replaceable>auth-method</replaceable>
<optional><replaceable>auth-option</replaceable></optional>
! hostnossl <replaceable>database</replaceable> <replaceable>user</replaceable>
<replaceable>CIDR-address</replaceable> <replaceable>auth-method</replaceable>
<optional><replaceable>auth-option</replaceable></optional>
! host <replaceable>database</replaceable> <replaceable>user</replaceable>
<replaceable>IP-address</replaceable> <replaceable>IP-mask</replaceable> <replaceable>auth-method</replaceable>
<optional><replaceable>auth-option</replaceable></optional>
! hostssl <replaceable>database</replaceable> <replaceable>user</replaceable>
<replaceable>IP-address</replaceable> <replaceable>IP-mask</replaceable> <replaceable>auth-method</replaceable>
<optional><replaceable>auth-option</replaceable></optional>
! hostnossl <replaceable>database</replaceable> <replaceable>user</replaceable>
<replaceable>IP-address</replaceable> <replaceable>IP-mask</replaceable> <replaceable>auth-method</replaceable>
<optional><replaceable>auth-option</replaceable></optional>
</synopsis>
The meaning of the fields is as follows:
--- 96,108 ----
<para>
A record can have one of the seven formats
<synopsis>
! local <replaceable>database</replaceable> <replaceable>user</replaceable>
<replaceable>auth-method</replaceable> <optional><replaceable>auth-options</replaceable></optional>
! host <replaceable>database</replaceable> <replaceable>user</replaceable>
<replaceable>CIDR-address</replaceable> <replaceable>auth-method</replaceable>
<optional><replaceable>auth-options</replaceable></optional>
! hostssl <replaceable>database</replaceable> <replaceable>user</replaceable>
<replaceable>CIDR-address</replaceable> <replaceable>auth-method</replaceable>
<optional><replaceable>auth-options</replaceable></optional>
! hostnossl <replaceable>database</replaceable> <replaceable>user</replaceable>
<replaceable>CIDR-address</replaceable> <replaceable>auth-method</replaceable>
<optional><replaceable>auth-options</replaceable></optional>
! host <replaceable>database</replaceable> <replaceable>user</replaceable>
<replaceable>IP-address</replaceable> <replaceable>IP-mask</replaceable> <replaceable>auth-method</replaceable>
<optional><replaceable>auth-options</replaceable></optional>
! hostssl <replaceable>database</replaceable> <replaceable>user</replaceable>
<replaceable>IP-address</replaceable> <replaceable>IP-mask</replaceable> <replaceable>auth-method</replaceable>
<optional><replaceable>auth-options</replaceable></optional>
! hostnossl <replaceable>database</replaceable> <replaceable>user</replaceable>
<replaceable>IP-address</replaceable> <replaceable>IP-mask</replaceable> <replaceable>auth-method</replaceable>
<optional><replaceable>auth-options</replaceable></optional>
</synopsis>
The meaning of the fields is as follows:
***************
*** 422,432 **** hostnossl <replaceable>database</replaceable> <replaceable>user</replaceable>
</varlistentry>
<varlistentry>
! <term><replaceable>auth-option</replaceable></term>
<listitem>
<para>
! The meaning of this optional field depends on the chosen
! authentication method. Details appear below.
</para>
</listitem>
</varlistentry>
--- 422,434 ----
</varlistentry>
<varlistentry>
! <term><replaceable>auth-options</replaceable></term>
<listitem>
<para>
! This field contains zero or more name-value pairs with
! extra options passed to this authentication method. Details
! about which options are available for which authentication
! method appear below.
</para>
</listitem>
</varlistentry>
***************
*** 534,540 **** host all all 0.0.0.0/0 krb5
# "omicron" that says "bryanh" is allowed to connect as "guest1".
#
# TYPE DATABASE USER CIDR-ADDRESS METHOD
! host all all 192.168.0.0/16 ident omicron
# If these are the only three lines for local connections, they will
# allow local users to connect only to their own databases (databases
--- 536,542 ----
# "omicron" that says "bryanh" is allowed to connect as "guest1".
#
# TYPE DATABASE USER CIDR-ADDRESS METHOD
! host all all 192.168.0.0/16 ident map=omicron
# If these are the only three lines for local connections, they will
# allow local users to connect only to their own databases (databases
***************
*** 557,562 **** local db1,db2,@demodbs all md5
--- 559,650 ----
</example>
</sect1>
+ <sect1 id="auth-username-maps">
+ <title>Username maps</title>
+
+ <indexterm zone="auth-username-maps">
+ <primary>Username maps</primary>
+ </indexterm>
+
+ <para>
+ When using an external authentication system like Ident or GSSAPI,
+ the name of the operating system user that initiated the connection may
+ not be the same as the database user he is requesting to connect as.
+ In this case, a user name map can be applied to map the operating system
+ username to a database user, using the <filename>pg_ident.conf</filename>
+ file. In order to use username mapping, specify
+ <literal>map</literal>=<replaceable>map-name</replaceable>
+ in the options field in <filename>pg_hba.conf</filename>. This option is
+ supported for all authentication methods that receive external usernames.
+ Since the <filename>pg_ident.conf</filename> file can contain multiple maps,
+ the name of the map to be used is specified in the
+ <replaceable>map-name</replaceable> parameter in <filename>pg_hba.conf</filename>
+ to indicate which map to use for each individual connection.
+ </para>
+
+ <para>
+ Ident maps are defined in the ident map file, which by default is named
+ <filename>pg_ident.conf</><indexterm><primary>pg_ident.conf</primary></indexterm>
+ and is stored in the
+ cluster's data directory. (It is possible to place the map file
+ elsewhere, however; see the <xref linkend="guc-ident-file">
+ configuration parameter.)
+ The ident map file contains lines of the general form:
+ <synopsis>
+ <replaceable>map-name</> <replaceable>system-username</> <replaceable>database-username</>
+ </synopsis>
+ Comments and whitespace are handled in the same way as in
+ <filename>pg_hba.conf</>. The
+ <replaceable>map-name</> is an arbitrary name that will be used to
+ refer to this mapping in <filename>pg_hba.conf</filename>. The other
+ two fields specify which operating system user is allowed to connect
+ as which database user. The same <replaceable>map-name</> can be
+ used repeatedly to specify more user-mappings within a single map.
+ There is no restriction regarding how many database users a given
+ operating system user can correspond to, nor vice versa.
+ </para>
+
+ <para>
+ The <filename>pg_ident.conf</filename> file is read on start-up and
+ when the main server process receives a
+ <systemitem>SIGHUP</systemitem><indexterm><primary>SIGHUP</primary></indexterm>
+ signal. If you edit the file on an
+ active system, you will need to signal the server
+ (using <literal>pg_ctl reload</> or <literal>kill -HUP</>) to make it
+ re-read the file.
+ </para>
+
+ <para>
+ A <filename>pg_ident.conf</filename> file that could be used in
+ conjunction with the <filename>pg_hba.conf</> file in <xref
+ linkend="example-pg-hba.conf"> is shown in <xref
+ linkend="example-pg-ident.conf">. In this example setup, anyone
+ logged in to a machine on the 192.168 network that does not have the
+ Unix user name <literal>bryanh</>, <literal>ann</>, or
+ <literal>robert</> would not be granted access. Unix user
+ <literal>robert</> would only be allowed access when he tries to
+ connect as <productname>PostgreSQL</> user <literal>bob</>, not
+ as <literal>robert</> or anyone else. <literal>ann</> would
+ only be allowed to connect as <literal>ann</>. User
+ <literal>bryanh</> would be allowed to connect as either
+ <literal>bryanh</> himself or as <literal>guest1</>.
+ </para>
+
+ <example id="example-pg-ident.conf">
+ <title>An example <filename>pg_ident.conf</> file</title>
+ <programlisting>
+ # MAPNAME IDENT-USERNAME PG-USERNAME
+
+ omicron bryanh bryanh
+ omicron ann ann
+ # bob has user name robert on these machines
+ omicron robert bob
+ # bryanh can also connect as guest1
+ omicron bryanh guest1
+ </programlisting>
+ </example>
+ </sect1>
+
<sect1 id="auth-methods">
<title>Authentication methods</title>
<para>
***************
*** 685,691 **** local db1,db2,@demodbs all md5
GSSAPI support has to be enabled when <productname>PostgreSQL</> is built;
see <xref linkend="installation"> for more information.
</para>
!
</sect2>
<sect2 id="sspi-auth">
--- 773,793 ----
GSSAPI support has to be enabled when <productname>PostgreSQL</> is built;
see <xref linkend="installation"> for more information.
</para>
!
! <para>
! The following configuration options are supported for <productname>GSSAPI</productname>:
! <variablelist>
! <varlistentry>
! <term>map</term>
! <listitem>
! <para>
! Allows for mapping between system and database usernames. See
! <xref linkend="auth-username-maps"> for details.
! </para>
! </listitem>
! </varlistentry>
! </variablelist>
! </para>
</sect2>
<sect2 id="sspi-auth">
***************
*** 713,718 **** local db1,db2,@demodbs all md5
--- 815,834 ----
for details.
</para>
+ <para>
+ The following configuration options are supported for <productname>SSPI</productname>:
+ <variablelist>
+ <varlistentry>
+ <term>map</term>
+ <listitem>
+ <para>
+ Allows for mapping between system and database usernames. See
+ <xref linkend="auth-username-maps"> for details.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
</sect2>
<sect2 id="kerberos-auth">
***************
*** 846,851 **** local db1,db2,@demodbs all md5
--- 962,982 ----
depending on the connection type.
</para>
+ <para>
+ The following configuration options are supported for <productname>GSSAPI</productname>:
+ <variablelist>
+ <varlistentry>
+ <term>map</term>
+ <listitem>
+ <para>
+ Allows for mapping between system and database usernames. See
+ <xref linkend="auth-username-maps"> for details.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+
<sect3>
<title>Ident Authentication over TCP/IP</title>
***************
*** 918,1000 **** local db1,db2,@demodbs all md5
</para>
</sect3>
- <sect3 id="auth-ident-maps">
- <title>Ident Maps</title>
-
- <para>
- When using ident-based authentication, after having determined the
- name of the operating system user that initiated the connection,
- <productname>PostgreSQL</productname> checks whether that user is
- allowed to connect as the database user he is requesting to connect
- as. This is controlled by the ident map argument that follows the
- <literal>ident</> key word in the <filename>pg_hba.conf</filename>
- file. If an ident map is not specified, the database user will be
- checked with the same name as the operating system user. Other maps
- must be created manually.
- </para>
-
- <para>
- Ident maps are defined in the ident map file, which by default is named
- <filename>pg_ident.conf</><indexterm><primary>pg_ident.conf</primary></indexterm>
- and is stored in the
- cluster's data directory. (It is possible to place the map file
- elsewhere, however; see the <xref linkend="guc-ident-file">
- configuration parameter.)
- The ident map file contains lines of the general form:
- <synopsis>
- <replaceable>map-name</> <replaceable>ident-username</> <replaceable>database-username</>
- </synopsis>
- Comments and whitespace are handled in the same way as in
- <filename>pg_hba.conf</>. The
- <replaceable>map-name</> is an arbitrary name that will be used to
- refer to this mapping in <filename>pg_hba.conf</filename>. The other
- two fields specify which operating system user is allowed to connect
- as which database user. The same <replaceable>map-name</> can be
- used repeatedly to specify more user-mappings within a single map.
- There is no restriction regarding how many database users a given
- operating system user can correspond to, nor vice versa.
- </para>
-
- <para>
- The <filename>pg_ident.conf</filename> file is read on start-up and
- when the main server process receives a
- <systemitem>SIGHUP</systemitem><indexterm><primary>SIGHUP</primary></indexterm>
- signal. If you edit the file on an
- active system, you will need to signal the server
- (using <literal>pg_ctl reload</> or <literal>kill -HUP</>) to make it
- re-read the file.
- </para>
-
- <para>
- A <filename>pg_ident.conf</filename> file that could be used in
- conjunction with the <filename>pg_hba.conf</> file in <xref
- linkend="example-pg-hba.conf"> is shown in <xref
- linkend="example-pg-ident.conf">. In this example setup, anyone
- logged in to a machine on the 192.168 network that does not have the
- Unix user name <literal>bryanh</>, <literal>ann</>, or
- <literal>robert</> would not be granted access. Unix user
- <literal>robert</> would only be allowed access when he tries to
- connect as <productname>PostgreSQL</> user <literal>bob</>, not
- as <literal>robert</> or anyone else. <literal>ann</> would
- only be allowed to connect as <literal>ann</>. User
- <literal>bryanh</> would be allowed to connect as either
- <literal>bryanh</> himself or as <literal>guest1</>.
- </para>
-
- <example id="example-pg-ident.conf">
- <title>An example <filename>pg_ident.conf</> file</title>
- <programlisting>
- # MAPNAME IDENT-USERNAME PG-USERNAME
-
- omicron bryanh bryanh
- omicron ann ann
- # bob has user name robert on these machines
- omicron robert bob
- # bryanh can also connect as guest1
- omicron bryanh guest1
- </programlisting>
- </example>
- </sect3>
</sect2>
<sect2 id="auth-ldap">
--- 1049,1054 ----
***************
*** 1007,1055 **** omicron bryanh guest1
<para>
This authentication method operates similarly to
<literal>password</literal> except that it uses LDAP
! as the authentication method. LDAP is used only to validate
the user name/password pairs. Therefore the user must already
exist in the database before LDAP can be used for
! authentication. The server and parameters used are specified
! after the <literal>ldap</> key word in the file
! <filename>pg_hba.conf</filename>. The format of this parameter is:
! <synopsis>
! ldap[<replaceable>s</>]://<replaceable>servername</>[:<replaceable>port</>]/<replaceable>base
dn</replaceable>[;<replaceable>prefix</>[;<replaceable>suffix</>]]
! </synopsis>
! Commas are used to specify multiple items in an <literal>ldap</>
! component. However, because unquoted commas are treated as item
! separators in <filename>pg_hba.conf</filename>, it is wise to
! double-quote the <literal>ldap</> URL to preserve any commas present,
! e.g.:
! <synopsis>
! "ldap://ldap.example.net/dc=example,dc=net;EXAMPLE\"
! </synopsis>
!
! </para>
! <para>
! If <literal>ldaps</> is specified instead of <literal>ldap</>,
! TLS encryption will be enabled for the connection. Note that this
! will encrypt only the connection between the PostgreSQL server
! and the LDAP server. The connection between the client and the
! PostgreSQL server is not affected by this setting. To make use of
! TLS encryption, you might need to configure the LDAP library prior
! to configuring PostgreSQL. Note that encrypted LDAP is available only
! if the platform's LDAP library supports it.
! </para>
! <para>
! If no port is specified, the default port as configured in the
! LDAP library will be used.
</para>
<para>
! The server will bind to the distinguished name specified as
! <replaceable>base dn</> using the user name supplied by the client.
! If <replaceable>prefix</> and <replaceable>suffix</> is
! specified, it will be prepended and appended to the user name
before the bind. Typically, the prefix parameter is used to specify
<replaceable>cn=</>, or <replaceable>DOMAIN\</> in an Active
! Directory environment.
</para>
!
</sect2>
<sect2 id="auth-pam">
--- 1061,1144 ----
<para>
This authentication method operates similarly to
<literal>password</literal> except that it uses LDAP
! as the password verification method. LDAP is used only to validate
the user name/password pairs. Therefore the user must already
exist in the database before LDAP can be used for
! authentication.
</para>
+
<para>
! The server will bind to the distinguished name constructed as
! <replaceable>prefix</> <replaceable>username</> <replaceable>suffix</>.
before the bind. Typically, the prefix parameter is used to specify
<replaceable>cn=</>, or <replaceable>DOMAIN\</> in an Active
! Directory environment, and suffix is used to specify the remaining part
! of the DN in a non-Active Directory environment.
</para>
!
! <para>
! The following configuration options are supported for LDAP:
! <variablelist>
! <varlistentry>
! <term>ldapserver</term>
! <listitem>
! <para>
! Name or IP of LDAP server to connect to.
! </para>
! </listitem>
! </varlistentry>
! <varlistentry>
! <term>ldapprefix</term>
! <listitem>
! <para>
! String to prepend to the username when building the base DN to
! bind as.
! </para>
! </listitem>
! </varlistentry>
! <varlistentry>
! <term>ldapsuffix</term>
! <listitem>
! <para>
! String to append to the username when building the base DN to
! bind as.
! </para>
! </listitem>
! </varlistentry>
! <varlistentry>
! <term>ldapport</term>
! <listitem>
! <para>
! Port number on LDAP server to connect to. If no port is specified,
! the default port in the LDAP library will be used.
! </para>
! </listitem>
! </varlistentry>
! <varlistentry>
! <term>ldaptls</term>
! <listitem>
! <para>
! Set to 1 to make the connection between PostgreSQL and the
! LDAP server use TLS encryption. Note that this only encrypts
! the traffic to the LDAP server - the connection to the client
! may still be unencrypted unless TLS is used there as well.
! </para>
! </listitem>
! </varlistentry>
! </variablelist>
! </para>
!
! <note>
! <para>
! Since LDAP often uses commas and spaces to separate the different
! parts of a DN, it is advised to always use double-quoted parameter
! values when configuring LDAP options, such as:
! </para>
! </note>
! <synopsis>
! ldapserver=ldap.example.net prefix="cn=" suffix="dc=example, dc=net"
! </synopsis>
!
</sect2>
<sect2 id="auth-pam">
***************
*** 1063,1071 **** ldap[<replaceable>s</>]://<replaceable>servername</>[:<replaceable>port</>]/<rep
This authentication method operates similarly to
<literal>password</literal> except that it uses PAM (Pluggable
Authentication Modules) as the authentication mechanism. The
! default PAM service name is <literal>postgresql</literal>. You can
! optionally supply your own service name after the <literal>pam</>
! key word in the file <filename>pg_hba.conf</filename>.
PAM is used only to validate user name/password pairs.
Therefore the user must already exist in the database before PAM
can be used for authentication. For more information about
--- 1152,1158 ----
This authentication method operates similarly to
<literal>password</literal> except that it uses PAM (Pluggable
Authentication Modules) as the authentication mechanism. The
! default PAM service name is <literal>postgresql</literal>.
PAM is used only to validate user name/password pairs.
Therefore the user must already exist in the database before PAM
can be used for authentication. For more information about
***************
*** 1075,1080 **** ldap[<replaceable>s</>]://<replaceable>servername</>[:<replaceable>port</>]/<rep
--- 1162,1181 ----
<systemitem class="osname">Solaris</> PAM Page</ulink>.
</para>
+ <para>
+ The following configuration options are supported for PAM:
+ <variablelist>
+ <varlistentry>
+ <term>pamservice</term>
+ <listitem>
+ <para>
+ PAM service name.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+
<note>
<para>
If PAM is set up to read <filename>/etc/shadow</>, authentication
*** a/src/backend/libpq/auth.c
--- b/src/backend/libpq/auth.c
***************
*** 126,134 **** char *pg_krb_realm = NULL;
* MIT Kerberos authentication system - protocol version 5
*----------------------------------------------------------------
*/
- static int pg_krb5_recvauth(Port *port);
-
#ifdef KRB5
#include <krb5.h>
/* Some old versions of Kerberos do not include <com_err.h> in <krb5.h> */
--- 126,133 ----
* MIT Kerberos authentication system - protocol version 5
*----------------------------------------------------------------
*/
#ifdef KRB5
+ static int pg_krb5_recvauth(Port *port);
#include <krb5.h>
/* Some old versions of Kerberos do not include <com_err.h> in <krb5.h> */
***************
*** 150,163 **** static krb5_principal pg_krb5_server;
* GSSAPI Authentication
*----------------------------------------------------------------
*/
- static int pg_GSS_recvauth(Port *port);
-
#ifdef ENABLE_GSS
#if defined(HAVE_GSSAPI_H)
#include <gssapi.h>
#else
#include <gssapi/gssapi.h>
#endif
#endif /* ENABLE_GSS */
--- 149,162 ----
* GSSAPI Authentication
*----------------------------------------------------------------
*/
#ifdef ENABLE_GSS
#if defined(HAVE_GSSAPI_H)
#include <gssapi.h>
#else
#include <gssapi/gssapi.h>
#endif
+
+ static int pg_GSS_recvauth(Port *port);
#endif /* ENABLE_GSS */
***************
*** 165,176 **** static int pg_GSS_recvauth(Port *port);
* SSPI Authentication
*----------------------------------------------------------------
*/
- static int pg_SSPI_recvauth(Port *port);
-
#ifdef ENABLE_SSPI
typedef SECURITY_STATUS
(WINAPI * QUERY_SECURITY_CONTEXT_TOKEN_FN) (
PCtxtHandle, void **);
#endif
--- 164,174 ----
* SSPI Authentication
*----------------------------------------------------------------
*/
#ifdef ENABLE_SSPI
typedef SECURITY_STATUS
(WINAPI * QUERY_SECURITY_CONTEXT_TOKEN_FN) (
PCtxtHandle, void **);
+ static int pg_SSPI_recvauth(Port *port);
#endif
***************
*** 236,251 **** auth_failed(Port *port, int status)
case uaPassword:
errstr = gettext_noop("password authentication failed for user \"%s\"");
break;
- #ifdef USE_PAM
case uaPAM:
errstr = gettext_noop("PAM authentication failed for user \"%s\"");
break;
- #endif /* USE_PAM */
- #ifdef USE_LDAP
case uaLDAP:
errstr = gettext_noop("LDAP authentication failed for user \"%s\"");
break;
- #endif /* USE_LDAP */
default:
errstr = gettext_noop("authentication failed for user \"%s\": invalid authentication method");
break;
--- 234,245 ----
***************
*** 316,333 **** ClientAuthentication(Port *port)
--- 310,339 ----
}
case uaKrb5:
+ #ifdef KRB5
sendAuthRequest(port, AUTH_REQ_KRB5);
status = pg_krb5_recvauth(port);
+ #else
+ Assert(false);
+ #endif
break;
case uaGSS:
+ #ifdef ENABLE_GSS
sendAuthRequest(port, AUTH_REQ_GSS);
status = pg_GSS_recvauth(port);
+ #else
+ Assert(false);
+ #endif
break;
case uaSSPI:
+ #ifdef ENABLE_SSPI
sendAuthRequest(port, AUTH_REQ_SSPI);
status = pg_SSPI_recvauth(port);
+ #else
+ Assert(false);
+ #endif
break;
case uaIdent:
***************
*** 377,394 **** ClientAuthentication(Port *port)
status = recv_and_check_password_packet(port);
break;
- #ifdef USE_PAM
case uaPAM:
pam_port_cludge = port;
status = CheckPAMAuth(port, port->user_name, "");
! break;
#endif /* USE_PAM */
- #ifdef USE_LDAP
case uaLDAP:
status = CheckLDAPAuth(port);
! break;
#endif
case uaTrust:
status = STATUS_OK;
--- 383,404 ----
status = recv_and_check_password_packet(port);
break;
case uaPAM:
+ #ifdef USE_PAM
pam_port_cludge = port;
status = CheckPAMAuth(port, port->user_name, "");
! #else
! Assert(false);
#endif /* USE_PAM */
+ break;
case uaLDAP:
+ #ifdef USE_LDAP
status = CheckLDAPAuth(port);
! #else
! Assert(false);
#endif
+ break;
case uaTrust:
status = STATUS_OK;
***************
*** 713,731 **** pg_krb5_recvauth(Port *port)
return STATUS_ERROR;
}
! if (pg_krb_caseins_users)
! ret = pg_strncasecmp(port->user_name, kusername, SM_DATABASE_USER);
! else
! ret = strncmp(port->user_name, kusername, SM_DATABASE_USER);
! if (ret)
! {
! ereport(LOG,
! (errmsg("unexpected Kerberos user name received from client (received \"%s\", expected \"%s\")",
! port->user_name, kusername)));
! ret = STATUS_ERROR;
! }
! else
! ret = STATUS_OK;
krb5_free_ticket(pg_krb5_context, ticket);
krb5_auth_con_free(pg_krb5_context, auth_context);
--- 723,730 ----
return STATUS_ERROR;
}
! ret = check_usermap(port->hba->usermap, port->user_name, kusername,
! pg_krb_caseins_users);
krb5_free_ticket(pg_krb5_context, ticket);
krb5_auth_con_free(pg_krb5_context, auth_context);
***************
*** 733,748 **** pg_krb5_recvauth(Port *port)
return ret;
}
- #else
-
- static int
- pg_krb5_recvauth(Port *port)
- {
- ereport(LOG,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("Kerberos 5 not implemented on this server")));
- return STATUS_ERROR;
- }
#endif /* KRB5 */
--- 732,737 ----
***************
*** 1020,1057 **** pg_GSS_recvauth(Port *port)
return STATUS_ERROR;
}
! if (pg_krb_caseins_users)
! ret = pg_strcasecmp(port->user_name, gbuf.value);
! else
! ret = strcmp(port->user_name, gbuf.value);
!
! if (ret)
! {
! /* GSS name and PGUSER are not equivalent */
! elog(DEBUG2,
! "provided username (%s) and GSSAPI username (%s) don't match",
! port->user_name, (char *) gbuf.value);
!
! gss_release_buffer(&lmin_s, &gbuf);
! return STATUS_ERROR;
! }
gss_release_buffer(&lmin_s, &gbuf);
return STATUS_OK;
}
-
- #else /* no ENABLE_GSS */
-
- static int
- pg_GSS_recvauth(Port *port)
- {
- ereport(LOG,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("GSSAPI not implemented on this server")));
- return STATUS_ERROR;
- }
-
#endif /* ENABLE_GSS */
--- 1009,1021 ----
return STATUS_ERROR;
}
! ret = check_usermap(port->hba->usermap, port->user_name, gbuf.value,
! pg_krb_caseins_users);
gss_release_buffer(&lmin_s, &gbuf);
return STATUS_OK;
}
#endif /* ENABLE_GSS */
***************
*** 1328,1357 **** pg_SSPI_recvauth(Port *port)
* We have the username (without domain/realm) in accountname, compare to
* the supplied value. In SSPI, always compare case insensitive.
*/
! if (pg_strcasecmp(port->user_name, accountname))
! {
! /* GSS name and PGUSER are not equivalent */
! elog(DEBUG2,
! "provided username (%s) and SSPI username (%s) don't match",
! port->user_name, accountname);
!
! return STATUS_ERROR;
! }
!
! return STATUS_OK;
}
-
- #else /* no ENABLE_SSPI */
-
- static int
- pg_SSPI_recvauth(Port *port)
- {
- ereport(LOG,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("SSPI not implemented on this server")));
- return STATUS_ERROR;
- }
-
#endif /* ENABLE_SSPI */
--- 1292,1299 ----
* We have the username (without domain/realm) in accountname, compare to
* the supplied value. In SSPI, always compare case insensitive.
*/
! return check_usermap(port->hba->usermap, port->user_name, accountname, true);
}
#endif /* ENABLE_SSPI */
***************
*** 1795,1808 **** authident(hbaPort *port)
return STATUS_ERROR;
}
! ereport(DEBUG2,
! (errmsg("Ident protocol identifies remote user as \"%s\"",
! ident_user)));
!
! if (check_ident_usermap(port->hba->usermap, port->user_name, ident_user))
! return STATUS_OK;
! else
! return STATUS_ERROR;
}
--- 1737,1743 ----
return STATUS_ERROR;
}
! return check_usermap(port->hba->usermap, port->user_name, ident_user, false);
}
***************
*** 1913,1920 **** CheckPAMAuth(Port *port, char *user, char *password)
* not allocated */
/* Optionally, one can set the service name in pg_hba.conf */
! if (port->hba->auth_arg && port->hba->auth_arg[0] != '\0')
! retval = pam_start(port->hba->auth_arg, "pgsql@",
&pam_passw_conv, &pamh);
else
retval = pam_start(PGSQL_PAM_SERVICE, "pgsql@",
--- 1848,1855 ----
* not allocated */
/* Optionally, one can set the service name in pg_hba.conf */
! if (port->hba->pamservice && port->hba->pamservice[0] != '\0')
! retval = pam_start(port->hba->pamservice, "pgsql@",
&pam_passw_conv, &pamh);
else
retval = pam_start(PGSQL_PAM_SERVICE, "pgsql@",
***************
*** 2000,2075 **** static int
CheckLDAPAuth(Port *port)
{
char *passwd;
- char server[128];
- char basedn[128];
- char prefix[128];
- char suffix[128];
LDAP *ldap;
- bool ssl = false;
int r;
int ldapversion = LDAP_VERSION3;
- int ldapport = LDAP_PORT;
char fulluser[NAMEDATALEN + 256 + 1];
! if (!port->hba->auth_arg || port->hba->auth_arg[0] == '\0')
{
ereport(LOG,
! (errmsg("LDAP configuration URL not specified")));
return STATUS_ERROR;
}
! /*
! * Crack the LDAP url. We do a very trivial parse:
! *
! * ldap[s]://<server>[:<port>]/<basedn>[;prefix[;suffix]]
! *
! * This code originally used "%127s" for the suffix, but that doesn't
! * work for embedded whitespace. We know that tokens formed by
! * hba.c won't include newlines, so we can use a "not newline" scanset
! * instead.
! */
!
! server[0] = '\0';
! basedn[0] = '\0';
! prefix[0] = '\0';
! suffix[0] = '\0';
!
! /* ldap, including port number */
! r = sscanf(port->hba->auth_arg,
! "ldap://%127[^:]:%d/%127[^;];%127[^;];%127[^\n]",
! server, &ldapport, basedn, prefix, suffix);
! if (r < 3)
! {
! /* ldaps, including port number */
! r = sscanf(port->hba->auth_arg,
! "ldaps://%127[^:]:%d/%127[^;];%127[^;];%127[^\n]",
! server, &ldapport, basedn, prefix, suffix);
! if (r >= 3)
! ssl = true;
! }
! if (r < 3)
! {
! /* ldap, no port number */
! r = sscanf(port->hba->auth_arg,
! "ldap://%127[^/]/%127[^;];%127[^;];%127[^\n]",
! server, basedn, prefix, suffix);
! }
! if (r < 2)
! {
! /* ldaps, no port number */
! r = sscanf(port->hba->auth_arg,
! "ldaps://%127[^/]/%127[^;];%127[^;];%127[^\n]",
! server, basedn, prefix, suffix);
! if (r >= 2)
! ssl = true;
! }
! if (r < 2)
! {
! ereport(LOG,
! (errmsg("invalid LDAP URL: \"%s\"",
! port->hba->auth_arg)));
! return STATUS_ERROR;
! }
sendAuthRequest(port, AUTH_REQ_PASSWORD);
--- 1935,1954 ----
CheckLDAPAuth(Port *port)
{
char *passwd;
LDAP *ldap;
int r;
int ldapversion = LDAP_VERSION3;
char fulluser[NAMEDATALEN + 256 + 1];
! if (!port->hba->ldapserver|| port->hba->ldapserver[0] == '\0')
{
ereport(LOG,
! (errmsg("LDAP server not specified")));
return STATUS_ERROR;
}
! if (port->hba->ldapport == 0)
! port->hba->ldapport = LDAP_PORT;
sendAuthRequest(port, AUTH_REQ_PASSWORD);
***************
*** 2077,2083 **** CheckLDAPAuth(Port *port)
if (passwd == NULL)
return STATUS_EOF; /* client wouldn't send password */
! ldap = ldap_init(server, ldapport);
if (!ldap)
{
#ifndef WIN32
--- 1956,1962 ----
if (passwd == NULL)
return STATUS_EOF; /* client wouldn't send password */
! ldap = ldap_init(port->hba->ldapserver, port->hba->ldapport);
if (!ldap)
{
#ifndef WIN32
***************
*** 2100,2106 **** CheckLDAPAuth(Port *port)
return STATUS_ERROR;
}
! if (ssl)
{
#ifndef WIN32
if ((r = ldap_start_tls_s(ldap, NULL, NULL)) != LDAP_SUCCESS)
--- 1979,1985 ----
return STATUS_ERROR;
}
! if (port->hba->ldaptls)
{
#ifndef WIN32
if ((r = ldap_start_tls_s(ldap, NULL, NULL)) != LDAP_SUCCESS)
***************
*** 2155,2161 **** CheckLDAPAuth(Port *port)
}
snprintf(fulluser, sizeof(fulluser), "%s%s%s",
! prefix, port->user_name, suffix);
fulluser[sizeof(fulluser) - 1] = '\0';
r = ldap_simple_bind_s(ldap, fulluser, passwd);
--- 2034,2042 ----
}
snprintf(fulluser, sizeof(fulluser), "%s%s%s",
! port->hba->ldapprefix?port->hba->ldapprefix:"",
! port->user_name,
! port->hba->ldapsuffix?port->hba->ldapsuffix:"");
fulluser[sizeof(fulluser) - 1] = '\0';
r = ldap_simple_bind_s(ldap, fulluser, passwd);
***************
*** 2165,2171 **** CheckLDAPAuth(Port *port)
{
ereport(LOG,
(errmsg("LDAP login failed for user \"%s\" on server \"%s\": error code %d",
! fulluser, server, r)));
return STATUS_ERROR;
}
--- 2046,2052 ----
{
ereport(LOG,
(errmsg("LDAP login failed for user \"%s\" on server \"%s\": error code %d",
! fulluser, port->hba->ldapserver, r)));
return STATUS_ERROR;
}
*** a/src/backend/libpq/hba.c
--- b/src/backend/libpq/hba.c
***************
*** 565,570 **** check_db(const char *dbname, const char *role, char *param_str)
--- 565,606 ----
/*
+ * Macros used to check and report on invalid configuration options.
+ * INVALID_AUTH_OPTION = reports when an option is specified for a method where it's
+ * not supported.
+ * REQUIRE_AUTH_OPTION = same as INVALID_AUTH_OPTION, except it also checks if the
+ * method is actually the one specified. Used as a shortcut when
+ * the option is only valid for one authentication method.
+ * MANDATORY_AUTH_ARG = check if a required option is set for an authentication method,
+ * reporting error if it's not.
+ */
+ #define INVALID_AUTH_OPTION(optname, validmethods) do {\
+ ereport(LOG, \
+ (errcode(ERRCODE_CONFIG_FILE_ERROR), \
+ errmsg("authentication option '%s' is only valid for authentication methods '%s'", \
+ optname, validmethods), \
+ errcontext("line %d of configuration file \"%s\"", \
+ line_num, HbaFileName))); \
+ goto hba_other_error; \
+ } while (0)
+
+ #define REQUIRE_AUTH_OPTION(methodval, optname, validmethods) \
+ if (parsedline->auth_method != methodval) \
+ INVALID_AUTH_OPTION("ldaptls", "ldap")
+
+ #define MANDATORY_AUTH_ARG(argvar, argname, authname) \
+ if (argvar == NULL) {\
+ ereport(LOG, \
+ (errcode(ERRCODE_CONFIG_FILE_ERROR), \
+ errmsg("authentication method '%s' requires argument '%s' to be set", \
+ authname, argname), \
+ errcontext("line %d of configuration file \"%s\"", \
+ line_num, HbaFileName))); \
+ goto hba_other_error; \
+ } while (0);
+
+
+ /*
* Parse one line in the hba config file and store the result in
* a HbaLine structure.
*/
***************
*** 801,838 **** parse_hba_line(List *line, int line_num, HbaLine *parsedline)
goto hba_other_error;
}
! /* Get the authentication argument token, if any */
! line_item = lnext(line_item);
! if (line_item)
{
token = lfirst(line_item);
- parsedline->auth_arg= pstrdup(token);
- }
! /*
! * Backwards compatible format of ident authentication - support "naked" ident map
! * name, as well as "sameuser"/"samerole"
! */
! if (parsedline->auth_method == uaIdent)
! {
! if (parsedline->auth_arg && strlen(parsedline->auth_arg))
{
! if (strcmp(parsedline->auth_arg, "sameuser\n") == 0 ||
! strcmp(parsedline->auth_arg, "samerole\n") == 0)
{
! /* This is now the default */
! pfree(parsedline->auth_arg);
! parsedline->auth_arg = NULL;
! parsedline->usermap = NULL;
}
else
{
! /* Specific ident map specified */
! parsedline->usermap = parsedline->auth_arg;
! parsedline->auth_arg = NULL;
}
}
}
return true;
--- 837,938 ----
goto hba_other_error;
}
! /* Parse remaining arguments */
! while ((line_item = lnext(line_item)) != NULL)
{
+ char *c;
+
token = lfirst(line_item);
! c = strchr(token, '=');
! if (c == NULL)
{
! /*
! * Got something that's not a name=value pair.
! *
! * XXX: attempt to do some backwards compatible parsing here?
! */
! ereport(LOG,
! (errcode(ERRCODE_CONFIG_FILE_ERROR),
! errmsg("authentication option not in name=value format: %s", token),
! errcontext("line %d of configuration file \"%s\"",
! line_num, HbaFileName)));
! goto hba_other_error;
! }
! else
! {
! *c++ = '\0'; /* token now holds "name", c holds "value" */
! if (strcmp(token, "map") == 0)
! {
! if (parsedline->auth_method != uaIdent &&
! parsedline->auth_method != uaKrb5 &&
! parsedline->auth_method != uaGSS &&
! parsedline->auth_method != uaSSPI)
! INVALID_AUTH_OPTION("map", "ident, krb5, gssapi and sspi");
! parsedline->usermap = pstrdup(c);
! }
! else if (strcmp(token, "pamservice") == 0)
! {
! REQUIRE_AUTH_OPTION(uaPAM, "pamservice", "pam");
! parsedline->pamservice = pstrdup(c);
! }
! else if (strcmp(token, "ldaptls") == 0)
! {
! REQUIRE_AUTH_OPTION(uaLDAP, "ldaptls", "ldap");
! if (strcmp(c, "1") == 0)
! parsedline->ldaptls = true;
! else
! parsedline->ldaptls = false;
! }
! else if (strcmp(token, "ldapserver") == 0)
! {
! REQUIRE_AUTH_OPTION(uaLDAP, "ldapserver", "ldap");
! parsedline->ldapserver = pstrdup(c);
! }
! else if (strcmp(token, "ldapport") == 0)
! {
! REQUIRE_AUTH_OPTION(uaLDAP, "ldapport", "ldap");
! parsedline->ldapport = atoi(c);
! if (parsedline->ldapport == 0)
! {
! ereport(LOG,
! (errcode(ERRCODE_CONFIG_FILE_ERROR),
! errmsg("invalid ldap port '%s'", c),
! errcontext("line %d of configuration file \"%s\"",
! line_num, HbaFileName)));
! goto hba_other_error;
! }
! }
! else if (strcmp(token, "ldapprefix") == 0)
{
! REQUIRE_AUTH_OPTION(uaLDAP, "ldapprefix", "ldap");
! parsedline->ldapprefix = pstrdup(c);
! }
! else if (strcmp(token, "ldapsuffix") == 0)
! {
! REQUIRE_AUTH_OPTION(uaLDAP, "ldapsuffix", "ldap");
! parsedline->ldapsuffix = pstrdup(c);
}
else
{
! ereport(LOG,
! (errcode(ERRCODE_CONFIG_FILE_ERROR),
! errmsg("unknown authentication option name '%s'", token),
! errcontext("line %d of configuration file \"%s\"",
! line_num, HbaFileName)));
! goto hba_other_error;
}
}
}
+
+ /*
+ * Check if the selected authentication method has any mandatory arguments that
+ * are not set.
+ */
+ if (parsedline->auth_method == uaLDAP)
+ {
+ MANDATORY_AUTH_ARG(parsedline->ldapserver, "ldapserver", "ldap");
+ }
return true;
***************
*** 1018,1025 **** free_hba_record(HbaLine *record)
pfree(record->database);
if (record->role)
pfree(record->role);
! if (record->auth_arg)
! pfree(record->auth_arg);
}
/*
--- 1118,1131 ----
pfree(record->database);
if (record->role)
pfree(record->role);
! if (record->pamservice)
! pfree(record->pamservice);
! if (record->ldapserver)
! pfree(record->ldapserver);
! if (record->ldapprefix)
! pfree(record->ldapprefix);
! if (record->ldapsuffix)
! pfree(record->ldapsuffix);
}
/*
***************
*** 1150,1156 **** read_pg_database_line(FILE *fp, char *dbname, Oid *dboid,
static void
parse_ident_usermap(List *line, int line_number, const char *usermap_name,
const char *pg_role, const char *ident_user,
! bool *found_p, bool *error_p)
{
ListCell *line_item;
char *token;
--- 1256,1262 ----
static void
parse_ident_usermap(List *line, int line_number, const char *usermap_name,
const char *pg_role, const char *ident_user,
! bool case_insensitive, bool *found_p, bool *error_p)
{
ListCell *line_item;
char *token;
***************
*** 1183,1192 **** parse_ident_usermap(List *line, int line_number, const char *usermap_name,
file_pgrole = token;
/* Match? */
! if (strcmp(file_map, usermap_name) == 0 &&
! strcmp(file_pgrole, pg_role) == 0 &&
! strcmp(file_ident_user, ident_user) == 0)
! *found_p = true;
return;
--- 1289,1308 ----
file_pgrole = token;
/* Match? */
! if (case_insensitive)
! {
! if (strcmp(file_map, usermap_name) == 0 &&
! pg_strcasecmp(file_pgrole, pg_role) == 0 &&
! pg_strcasecmp(file_ident_user, ident_user) == 0)
! *found_p = true;
! }
! else
! {
! if (strcmp(file_map, usermap_name) == 0 &&
! strcmp(file_pgrole, pg_role) == 0 &&
! strcmp(file_ident_user, ident_user) == 0)
! *found_p = true;
! }
return;
***************
*** 1210,1231 **** ident_syntax:
* file. That's an implied map where "pgrole" must be identical to
* "ident_user" in order to be authorized.
*
! * Iff authorized, return true.
*/
! bool
! check_ident_usermap(const char *usermap_name,
const char *pg_role,
! const char *ident_user)
{
bool found_entry = false,
error = false;
if (usermap_name == NULL || usermap_name[0] == '\0')
{
! if (strcmp(pg_role, ident_user) == 0)
! found_entry = true;
! else
! found_entry = false;
}
else
{
--- 1326,1357 ----
* file. That's an implied map where "pgrole" must be identical to
* "ident_user" in order to be authorized.
*
! * Iff authorized, return STATUS_OK, otherwise return STATUS_ERROR.
*/
! int
! check_usermap(const char *usermap_name,
const char *pg_role,
! const char *auth_user,
! bool case_insensitive)
{
bool found_entry = false,
error = false;
if (usermap_name == NULL || usermap_name[0] == '\0')
{
! if (case_insensitive)
! {
! if (pg_strcasecmp(pg_role, auth_user) == 0)
! return STATUS_OK;
! }
! else {
! if (strcmp(pg_role, auth_user) == 0)
! return STATUS_OK;
! }
! ereport(LOG,
! (errmsg("provided username (%s) and authenticated username (%s) don't match",
! auth_user, pg_role)));
! return STATUS_ERROR;
}
else
{
***************
*** 1235,1247 **** check_ident_usermap(const char *usermap_name,
forboth(line_cell, ident_lines, num_cell, ident_line_nums)
{
parse_ident_usermap(lfirst(line_cell), lfirst_int(num_cell),
! usermap_name, pg_role, ident_user,
&found_entry, &error);
if (found_entry || error)
break;
}
}
! return found_entry;
}
--- 1361,1380 ----
forboth(line_cell, ident_lines, num_cell, ident_line_nums)
{
parse_ident_usermap(lfirst(line_cell), lfirst_int(num_cell),
! usermap_name, pg_role, auth_user, case_insensitive,
&found_entry, &error);
if (found_entry || error)
break;
}
}
! if (!found_entry && !error)
! {
! ereport(LOG,
! (errmsg("no match in usermap for user '%s' authenticated as '%s'",
! pg_role, auth_user),
! errcontext("usermap '%s'", usermap_name)));
! }
! return found_entry?STATUS_OK:STATUS_ERROR;
}
*** a/src/backend/libpq/pg_hba.conf.sample
--- b/src/backend/libpq/pg_hba.conf.sample
***************
*** 9,18 ****
# are authenticated, which PostgreSQL user names they can use, which
# databases they can access. Records take one of these forms:
#
! # local DATABASE USER METHOD [OPTION]
! # host DATABASE USER CIDR-ADDRESS METHOD [OPTION]
! # hostssl DATABASE USER CIDR-ADDRESS METHOD [OPTION]
! # hostnossl DATABASE USER CIDR-ADDRESS METHOD [OPTION]
#
# (The uppercase items must be replaced by actual values.)
#
--- 9,18 ----
# are authenticated, which PostgreSQL user names they can use, which
# databases they can access. Records take one of these forms:
#
! # local DATABASE USER METHOD [OPTIONS]
! # host DATABASE USER CIDR-ADDRESS METHOD [OPTIONS]
! # hostssl DATABASE USER CIDR-ADDRESS METHOD [OPTIONS]
! # hostnossl DATABASE USER CIDR-ADDRESS METHOD [OPTIONS]
#
# (The uppercase items must be replaced by actual values.)
#
***************
*** 38,44 ****
# "krb5", "ident", "pam" or "ldap". Note that "password" sends passwords
# in clear text; "md5" is preferred since it sends encrypted passwords.
#
! # OPTION is the ident map or the name of the PAM service, depending on METHOD.
#
# Database and user names containing spaces, commas, quotes and other special
# characters must be quoted. Quoting one of the keywords "all", "sameuser" or
--- 38,47 ----
# "krb5", "ident", "pam" or "ldap". Note that "password" sends passwords
# in clear text; "md5" is preferred since it sends encrypted passwords.
#
! # OPTIONS are a set of options for the authentication in the format
! # NAME=VALUE. The available options depend on the different authentication
! # methods - refer to the "Client Authentication" section in the documentation
! # for a list of which options are available for which authentication methods.
#
# Database and user names containing spaces, commas, quotes and other special
# characters must be quoted. Quoting one of the keywords "all", "sameuser" or
*** a/src/backend/libpq/pg_ident.conf.sample
--- b/src/backend/libpq/pg_ident.conf.sample
***************
*** 5,22 ****
# Authentication" for a complete description. A short synopsis
# follows.
#
! # This file controls PostgreSQL ident-based authentication. It maps
! # ident user names (typically Unix user names) to their corresponding
# PostgreSQL user names. Records are of the form:
#
! # MAPNAME IDENT-USERNAME PG-USERNAME
#
# (The uppercase quantities must be replaced by actual values.)
#
# MAPNAME is the (otherwise freely chosen) map name that was used in
! # pg_hba.conf. IDENT-USERNAME is the detected user name of the
# client. PG-USERNAME is the requested PostgreSQL user name. The
! # existence of a record specifies that IDENT-USERNAME may connect as
# PG-USERNAME. Multiple maps may be specified in this file and used
# by pg_hba.conf.
#
--- 5,22 ----
# Authentication" for a complete description. A short synopsis
# follows.
#
! # This file controls PostgreSQL username mapping. It maps
! # external user names to their corresponding
# PostgreSQL user names. Records are of the form:
#
! # MAPNAME SYSTEM-USERNAME PG-USERNAME
#
# (The uppercase quantities must be replaced by actual values.)
#
# MAPNAME is the (otherwise freely chosen) map name that was used in
! # pg_hba.conf. SYSTEM-USERNAME is the detected user name of the
# client. PG-USERNAME is the requested PostgreSQL user name. The
! # existence of a record specifies that SYSTEM-USERNAME may connect as
# PG-USERNAME. Multiple maps may be specified in this file and used
# by pg_hba.conf.
#
***************
*** 28,35 ****
# Put your actual configuration here
# ----------------------------------
#
! # No map names are defined in the default configuration. If all ident
# user names and PostgreSQL user names are the same, you don't need
# this file.
! # MAPNAME IDENT-USERNAME PG-USERNAME
--- 28,35 ----
# Put your actual configuration here
# ----------------------------------
#
! # No map names are defined in the default configuration. If all system
# user names and PostgreSQL user names are the same, you don't need
# this file.
! # MAPNAME SYSTEM-USERNAME PG-USERNAME
*** a/src/include/libpq/hba.h
--- b/src/include/libpq/hba.h
***************
*** 25,37 **** typedef enum UserAuth
uaCrypt,
uaMD5,
uaGSS,
! uaSSPI
! #ifdef USE_PAM
! ,uaPAM
! #endif /* USE_PAM */
! #ifdef USE_LDAP
! ,uaLDAP
! #endif
} UserAuth;
typedef enum ConnType
--- 25,33 ----
uaCrypt,
uaMD5,
uaGSS,
! uaSSPI,
! uaPAM,
! uaLDAP
} UserAuth;
typedef enum ConnType
***************
*** 51,58 **** typedef struct
struct sockaddr_storage addr;
struct sockaddr_storage mask;
UserAuth auth_method;
char *usermap;
! char *auth_arg;
} HbaLine;
typedef struct Port hbaPort;
--- 47,60 ----
struct sockaddr_storage addr;
struct sockaddr_storage mask;
UserAuth auth_method;
+
char *usermap;
! char *pamservice;
! bool ldaptls;
! char *ldapserver;
! int ldapport;
! char *ldapprefix;
! char *ldapsuffix;
} HbaLine;
typedef struct Port hbaPort;
***************
*** 64,71 **** extern void load_role(void);
extern int hba_getauthmethod(hbaPort *port);
extern bool read_pg_database_line(FILE *fp, char *dbname, Oid *dboid,
Oid *dbtablespace, TransactionId *dbfrozenxid);
! extern bool check_ident_usermap(const char *usermap_name,
! const char *pg_role, const char *ident_user);
extern bool pg_isblank(const char c);
#endif /* HBA_H */
--- 66,74 ----
extern int hba_getauthmethod(hbaPort *port);
extern bool read_pg_database_line(FILE *fp, char *dbname, Oid *dboid,
Oid *dbtablespace, TransactionId *dbfrozenxid);
! extern int check_usermap(const char *usermap_name,
! const char *pg_role, const char *auth_user,
! bool case_sensitive);
extern bool pg_isblank(const char c);
#endif /* HBA_H */