mirror of
https://github.com/postgres/postgres.git
synced 2025-07-11 10:01:57 +03:00
* make pg_hba authoption be a set of 0 or more name=value pairs
* make LDAP use this instead of the hacky previous method to specify the DN to bind as * make all auth options behave the same when they are not compiled into the server * rename "ident maps" to "user name maps", and support them for all auth methods that provide an external username This makes a backwards incompatible change in the format of pg_hba.conf for the ident, PAM and LDAP authentication methods.
This commit is contained in:
@ -1,4 +1,4 @@
|
|||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/client-auth.sgml,v 1.108 2008/09/15 12:41:54 mha Exp $ -->
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/client-auth.sgml,v 1.109 2008/10/23 13:31:09 mha Exp $ -->
|
||||||
|
|
||||||
<chapter id="client-authentication">
|
<chapter id="client-authentication">
|
||||||
<title>Client Authentication</title>
|
<title>Client Authentication</title>
|
||||||
@ -96,13 +96,13 @@
|
|||||||
<para>
|
<para>
|
||||||
A record can have one of the seven formats
|
A record can have one of the seven formats
|
||||||
<synopsis>
|
<synopsis>
|
||||||
local <replaceable>database</replaceable> <replaceable>user</replaceable> <replaceable>auth-method</replaceable> <optional><replaceable>auth-option</replaceable></optional>
|
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-option</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-option</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-option</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-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-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-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-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-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-options</replaceable></optional>
|
||||||
</synopsis>
|
</synopsis>
|
||||||
The meaning of the fields is as follows:
|
The meaning of the fields is as follows:
|
||||||
|
|
||||||
@ -422,11 +422,13 @@ hostnossl <replaceable>database</replaceable> <replaceable>user</replaceable>
|
|||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><replaceable>auth-option</replaceable></term>
|
<term><replaceable>auth-options</replaceable></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
The meaning of this optional field depends on the chosen
|
This field contains zero or more name-value pairs with
|
||||||
authentication method. Details appear below.
|
extra options passed to this authentication method. Details
|
||||||
|
about which options are available for which authentication
|
||||||
|
method appear below.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@ -534,7 +536,7 @@ host all all 0.0.0.0/0 krb5
|
|||||||
# "omicron" that says "bryanh" is allowed to connect as "guest1".
|
# "omicron" that says "bryanh" is allowed to connect as "guest1".
|
||||||
#
|
#
|
||||||
# TYPE DATABASE USER CIDR-ADDRESS METHOD
|
# TYPE DATABASE USER CIDR-ADDRESS METHOD
|
||||||
host all all 192.168.0.0/16 ident omicron
|
host all all 192.168.0.0/16 ident map=omicron
|
||||||
|
|
||||||
# If these are the only three lines for local connections, they will
|
# If these are the only three lines for local connections, they will
|
||||||
# allow local users to connect only to their own databases (databases
|
# allow local users to connect only to their own databases (databases
|
||||||
@ -557,6 +559,92 @@ local db1,db2,@demodbs all md5
|
|||||||
</example>
|
</example>
|
||||||
</sect1>
|
</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">
|
<sect1 id="auth-methods">
|
||||||
<title>Authentication methods</title>
|
<title>Authentication methods</title>
|
||||||
<para>
|
<para>
|
||||||
@ -686,6 +774,20 @@ local db1,db2,@demodbs all md5
|
|||||||
see <xref linkend="installation"> for more information.
|
see <xref linkend="installation"> for more information.
|
||||||
</para>
|
</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>
|
||||||
|
|
||||||
<sect2 id="sspi-auth">
|
<sect2 id="sspi-auth">
|
||||||
@ -713,6 +815,20 @@ local db1,db2,@demodbs all md5
|
|||||||
for details.
|
for details.
|
||||||
</para>
|
</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>
|
||||||
|
|
||||||
<sect2 id="kerberos-auth">
|
<sect2 id="kerberos-auth">
|
||||||
@ -846,6 +962,21 @@ local db1,db2,@demodbs all md5
|
|||||||
depending on the connection type.
|
depending on the connection type.
|
||||||
</para>
|
</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>
|
<sect3>
|
||||||
<title>Ident Authentication over TCP/IP</title>
|
<title>Ident Authentication over TCP/IP</title>
|
||||||
|
|
||||||
@ -918,83 +1049,6 @@ local db1,db2,@demodbs all md5
|
|||||||
</para>
|
</para>
|
||||||
</sect3>
|
</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>
|
||||||
|
|
||||||
<sect2 id="auth-ldap">
|
<sect2 id="auth-ldap">
|
||||||
@ -1007,49 +1061,84 @@ omicron bryanh guest1
|
|||||||
<para>
|
<para>
|
||||||
This authentication method operates similarly to
|
This authentication method operates similarly to
|
||||||
<literal>password</literal> except that it uses LDAP
|
<literal>password</literal> except that it uses LDAP
|
||||||
as the authentication method. LDAP is used only to validate
|
as the password verification method. LDAP is used only to validate
|
||||||
the user name/password pairs. Therefore the user must already
|
the user name/password pairs. Therefore the user must already
|
||||||
exist in the database before LDAP can be used for
|
exist in the database before LDAP can be used for
|
||||||
authentication. The server and parameters used are specified
|
authentication.
|
||||||
after the <literal>ldap</> key word in the file
|
</para>
|
||||||
<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>
|
<para>
|
||||||
If <literal>ldaps</> is specified instead of <literal>ldap</>,
|
The server will bind to the distinguished name constructed as
|
||||||
TLS encryption will be enabled for the connection. Note that this
|
<replaceable>prefix</> <replaceable>username</> <replaceable>suffix</>.
|
||||||
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
|
before the bind. Typically, the prefix parameter is used to specify
|
||||||
<replaceable>cn=</>, or <replaceable>DOMAIN\</> in an Active
|
<replaceable>cn=</>, or <replaceable>DOMAIN\</> in an Active
|
||||||
Directory environment.
|
Directory environment, and suffix is used to specify the remaining part
|
||||||
|
of the DN in a non-Active Directory environment.
|
||||||
</para>
|
</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>
|
||||||
|
|
||||||
<sect2 id="auth-pam">
|
<sect2 id="auth-pam">
|
||||||
@ -1063,9 +1152,7 @@ ldap[<replaceable>s</>]://<replaceable>servername</>[:<replaceable>port</>]/<rep
|
|||||||
This authentication method operates similarly to
|
This authentication method operates similarly to
|
||||||
<literal>password</literal> except that it uses PAM (Pluggable
|
<literal>password</literal> except that it uses PAM (Pluggable
|
||||||
Authentication Modules) as the authentication mechanism. The
|
Authentication Modules) as the authentication mechanism. The
|
||||||
default PAM service name is <literal>postgresql</literal>. You can
|
default PAM service name is <literal>postgresql</literal>.
|
||||||
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.
|
PAM is used only to validate user name/password pairs.
|
||||||
Therefore the user must already exist in the database before PAM
|
Therefore the user must already exist in the database before PAM
|
||||||
can be used for authentication. For more information about
|
can be used for authentication. For more information about
|
||||||
@ -1075,6 +1162,20 @@ ldap[<replaceable>s</>]://<replaceable>servername</>[:<replaceable>port</>]/<rep
|
|||||||
<systemitem class="osname">Solaris</> PAM Page</ulink>.
|
<systemitem class="osname">Solaris</> PAM Page</ulink>.
|
||||||
</para>
|
</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>
|
<note>
|
||||||
<para>
|
<para>
|
||||||
If PAM is set up to read <filename>/etc/shadow</>, authentication
|
If PAM is set up to read <filename>/etc/shadow</>, authentication
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.168 2008/09/15 12:32:56 mha Exp $
|
* $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.169 2008/10/23 13:31:10 mha Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -126,9 +126,8 @@ char *pg_krb_realm = NULL;
|
|||||||
* MIT Kerberos authentication system - protocol version 5
|
* MIT Kerberos authentication system - protocol version 5
|
||||||
*----------------------------------------------------------------
|
*----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
static int pg_krb5_recvauth(Port *port);
|
|
||||||
|
|
||||||
#ifdef KRB5
|
#ifdef KRB5
|
||||||
|
static int pg_krb5_recvauth(Port *port);
|
||||||
|
|
||||||
#include <krb5.h>
|
#include <krb5.h>
|
||||||
/* Some old versions of Kerberos do not include <com_err.h> in <krb5.h> */
|
/* Some old versions of Kerberos do not include <com_err.h> in <krb5.h> */
|
||||||
@ -150,14 +149,14 @@ static krb5_principal pg_krb5_server;
|
|||||||
* GSSAPI Authentication
|
* GSSAPI Authentication
|
||||||
*----------------------------------------------------------------
|
*----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
static int pg_GSS_recvauth(Port *port);
|
|
||||||
|
|
||||||
#ifdef ENABLE_GSS
|
#ifdef ENABLE_GSS
|
||||||
#if defined(HAVE_GSSAPI_H)
|
#if defined(HAVE_GSSAPI_H)
|
||||||
#include <gssapi.h>
|
#include <gssapi.h>
|
||||||
#else
|
#else
|
||||||
#include <gssapi/gssapi.h>
|
#include <gssapi/gssapi.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static int pg_GSS_recvauth(Port *port);
|
||||||
#endif /* ENABLE_GSS */
|
#endif /* ENABLE_GSS */
|
||||||
|
|
||||||
|
|
||||||
@ -165,12 +164,11 @@ static int pg_GSS_recvauth(Port *port);
|
|||||||
* SSPI Authentication
|
* SSPI Authentication
|
||||||
*----------------------------------------------------------------
|
*----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
static int pg_SSPI_recvauth(Port *port);
|
|
||||||
|
|
||||||
#ifdef ENABLE_SSPI
|
#ifdef ENABLE_SSPI
|
||||||
typedef SECURITY_STATUS
|
typedef SECURITY_STATUS
|
||||||
(WINAPI * QUERY_SECURITY_CONTEXT_TOKEN_FN) (
|
(WINAPI * QUERY_SECURITY_CONTEXT_TOKEN_FN) (
|
||||||
PCtxtHandle, void **);
|
PCtxtHandle, void **);
|
||||||
|
static int pg_SSPI_recvauth(Port *port);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@ -236,16 +234,12 @@ auth_failed(Port *port, int status)
|
|||||||
case uaPassword:
|
case uaPassword:
|
||||||
errstr = gettext_noop("password authentication failed for user \"%s\"");
|
errstr = gettext_noop("password authentication failed for user \"%s\"");
|
||||||
break;
|
break;
|
||||||
#ifdef USE_PAM
|
|
||||||
case uaPAM:
|
case uaPAM:
|
||||||
errstr = gettext_noop("PAM authentication failed for user \"%s\"");
|
errstr = gettext_noop("PAM authentication failed for user \"%s\"");
|
||||||
break;
|
break;
|
||||||
#endif /* USE_PAM */
|
|
||||||
#ifdef USE_LDAP
|
|
||||||
case uaLDAP:
|
case uaLDAP:
|
||||||
errstr = gettext_noop("LDAP authentication failed for user \"%s\"");
|
errstr = gettext_noop("LDAP authentication failed for user \"%s\"");
|
||||||
break;
|
break;
|
||||||
#endif /* USE_LDAP */
|
|
||||||
default:
|
default:
|
||||||
errstr = gettext_noop("authentication failed for user \"%s\": invalid authentication method");
|
errstr = gettext_noop("authentication failed for user \"%s\": invalid authentication method");
|
||||||
break;
|
break;
|
||||||
@ -316,18 +310,30 @@ ClientAuthentication(Port *port)
|
|||||||
}
|
}
|
||||||
|
|
||||||
case uaKrb5:
|
case uaKrb5:
|
||||||
|
#ifdef KRB5
|
||||||
sendAuthRequest(port, AUTH_REQ_KRB5);
|
sendAuthRequest(port, AUTH_REQ_KRB5);
|
||||||
status = pg_krb5_recvauth(port);
|
status = pg_krb5_recvauth(port);
|
||||||
|
#else
|
||||||
|
Assert(false);
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case uaGSS:
|
case uaGSS:
|
||||||
|
#ifdef ENABLE_GSS
|
||||||
sendAuthRequest(port, AUTH_REQ_GSS);
|
sendAuthRequest(port, AUTH_REQ_GSS);
|
||||||
status = pg_GSS_recvauth(port);
|
status = pg_GSS_recvauth(port);
|
||||||
|
#else
|
||||||
|
Assert(false);
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case uaSSPI:
|
case uaSSPI:
|
||||||
|
#ifdef ENABLE_SSPI
|
||||||
sendAuthRequest(port, AUTH_REQ_SSPI);
|
sendAuthRequest(port, AUTH_REQ_SSPI);
|
||||||
status = pg_SSPI_recvauth(port);
|
status = pg_SSPI_recvauth(port);
|
||||||
|
#else
|
||||||
|
Assert(false);
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case uaIdent:
|
case uaIdent:
|
||||||
@ -377,18 +383,22 @@ ClientAuthentication(Port *port)
|
|||||||
status = recv_and_check_password_packet(port);
|
status = recv_and_check_password_packet(port);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef USE_PAM
|
|
||||||
case uaPAM:
|
case uaPAM:
|
||||||
|
#ifdef USE_PAM
|
||||||
pam_port_cludge = port;
|
pam_port_cludge = port;
|
||||||
status = CheckPAMAuth(port, port->user_name, "");
|
status = CheckPAMAuth(port, port->user_name, "");
|
||||||
break;
|
#else
|
||||||
|
Assert(false);
|
||||||
#endif /* USE_PAM */
|
#endif /* USE_PAM */
|
||||||
|
|
||||||
#ifdef USE_LDAP
|
|
||||||
case uaLDAP:
|
|
||||||
status = CheckLDAPAuth(port);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case uaLDAP:
|
||||||
|
#ifdef USE_LDAP
|
||||||
|
status = CheckLDAPAuth(port);
|
||||||
|
#else
|
||||||
|
Assert(false);
|
||||||
#endif
|
#endif
|
||||||
|
break;
|
||||||
|
|
||||||
case uaTrust:
|
case uaTrust:
|
||||||
status = STATUS_OK;
|
status = STATUS_OK;
|
||||||
@ -713,19 +723,8 @@ pg_krb5_recvauth(Port *port)
|
|||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pg_krb_caseins_users)
|
ret = check_usermap(port->hba->usermap, port->user_name, kusername,
|
||||||
ret = pg_strncasecmp(port->user_name, kusername, SM_DATABASE_USER);
|
pg_krb_caseins_users);
|
||||||
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_free_ticket(pg_krb5_context, ticket);
|
||||||
krb5_auth_con_free(pg_krb5_context, auth_context);
|
krb5_auth_con_free(pg_krb5_context, auth_context);
|
||||||
@ -733,16 +732,6 @@ pg_krb5_recvauth(Port *port)
|
|||||||
|
|
||||||
return ret;
|
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 */
|
#endif /* KRB5 */
|
||||||
|
|
||||||
|
|
||||||
@ -1020,38 +1009,13 @@ pg_GSS_recvauth(Port *port)
|
|||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pg_krb_caseins_users)
|
ret = check_usermap(port->hba->usermap, port->user_name, gbuf.value,
|
||||||
ret = pg_strcasecmp(port->user_name, gbuf.value);
|
pg_krb_caseins_users);
|
||||||
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);
|
gss_release_buffer(&lmin_s, &gbuf);
|
||||||
|
|
||||||
return STATUS_OK;
|
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 */
|
#endif /* ENABLE_GSS */
|
||||||
|
|
||||||
|
|
||||||
@ -1328,30 +1292,8 @@ pg_SSPI_recvauth(Port *port)
|
|||||||
* We have the username (without domain/realm) in accountname, compare to
|
* We have the username (without domain/realm) in accountname, compare to
|
||||||
* the supplied value. In SSPI, always compare case insensitive.
|
* the supplied value. In SSPI, always compare case insensitive.
|
||||||
*/
|
*/
|
||||||
if (pg_strcasecmp(port->user_name, accountname))
|
return check_usermap(port->hba->usermap, port->user_name, accountname, true);
|
||||||
{
|
|
||||||
/* 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 */
|
#endif /* ENABLE_SSPI */
|
||||||
|
|
||||||
|
|
||||||
@ -1795,14 +1737,7 @@ authident(hbaPort *port)
|
|||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
ereport(DEBUG2,
|
return check_usermap(port->hba->usermap, port->user_name, ident_user, false);
|
||||||
(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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1913,8 +1848,8 @@ CheckPAMAuth(Port *port, char *user, char *password)
|
|||||||
* not allocated */
|
* not allocated */
|
||||||
|
|
||||||
/* Optionally, one can set the service name in pg_hba.conf */
|
/* Optionally, one can set the service name in pg_hba.conf */
|
||||||
if (port->hba->auth_arg && port->hba->auth_arg[0] != '\0')
|
if (port->hba->pamservice && port->hba->pamservice[0] != '\0')
|
||||||
retval = pam_start(port->hba->auth_arg, "pgsql@",
|
retval = pam_start(port->hba->pamservice, "pgsql@",
|
||||||
&pam_passw_conv, &pamh);
|
&pam_passw_conv, &pamh);
|
||||||
else
|
else
|
||||||
retval = pam_start(PGSQL_PAM_SERVICE, "pgsql@",
|
retval = pam_start(PGSQL_PAM_SERVICE, "pgsql@",
|
||||||
@ -2000,76 +1935,20 @@ static int
|
|||||||
CheckLDAPAuth(Port *port)
|
CheckLDAPAuth(Port *port)
|
||||||
{
|
{
|
||||||
char *passwd;
|
char *passwd;
|
||||||
char server[128];
|
|
||||||
char basedn[128];
|
|
||||||
char prefix[128];
|
|
||||||
char suffix[128];
|
|
||||||
LDAP *ldap;
|
LDAP *ldap;
|
||||||
bool ssl = false;
|
|
||||||
int r;
|
int r;
|
||||||
int ldapversion = LDAP_VERSION3;
|
int ldapversion = LDAP_VERSION3;
|
||||||
int ldapport = LDAP_PORT;
|
|
||||||
char fulluser[NAMEDATALEN + 256 + 1];
|
char fulluser[NAMEDATALEN + 256 + 1];
|
||||||
|
|
||||||
if (!port->hba->auth_arg || port->hba->auth_arg[0] == '\0')
|
if (!port->hba->ldapserver|| port->hba->ldapserver[0] == '\0')
|
||||||
{
|
{
|
||||||
ereport(LOG,
|
ereport(LOG,
|
||||||
(errmsg("LDAP configuration URL not specified")));
|
(errmsg("LDAP server not specified")));
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
if (port->hba->ldapport == 0)
|
||||||
* Crack the LDAP url. We do a very trivial parse:
|
port->hba->ldapport = LDAP_PORT;
|
||||||
*
|
|
||||||
* 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);
|
sendAuthRequest(port, AUTH_REQ_PASSWORD);
|
||||||
|
|
||||||
@ -2077,7 +1956,7 @@ CheckLDAPAuth(Port *port)
|
|||||||
if (passwd == NULL)
|
if (passwd == NULL)
|
||||||
return STATUS_EOF; /* client wouldn't send password */
|
return STATUS_EOF; /* client wouldn't send password */
|
||||||
|
|
||||||
ldap = ldap_init(server, ldapport);
|
ldap = ldap_init(port->hba->ldapserver, port->hba->ldapport);
|
||||||
if (!ldap)
|
if (!ldap)
|
||||||
{
|
{
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
@ -2100,7 +1979,7 @@ CheckLDAPAuth(Port *port)
|
|||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ssl)
|
if (port->hba->ldaptls)
|
||||||
{
|
{
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
if ((r = ldap_start_tls_s(ldap, NULL, NULL)) != LDAP_SUCCESS)
|
if ((r = ldap_start_tls_s(ldap, NULL, NULL)) != LDAP_SUCCESS)
|
||||||
@ -2155,7 +2034,9 @@ CheckLDAPAuth(Port *port)
|
|||||||
}
|
}
|
||||||
|
|
||||||
snprintf(fulluser, sizeof(fulluser), "%s%s%s",
|
snprintf(fulluser, sizeof(fulluser), "%s%s%s",
|
||||||
prefix, port->user_name, suffix);
|
port->hba->ldapprefix ? port->hba->ldapprefix : "",
|
||||||
|
port->user_name,
|
||||||
|
port->hba->ldapsuffix ? port->hba->ldapsuffix : "");
|
||||||
fulluser[sizeof(fulluser) - 1] = '\0';
|
fulluser[sizeof(fulluser) - 1] = '\0';
|
||||||
|
|
||||||
r = ldap_simple_bind_s(ldap, fulluser, passwd);
|
r = ldap_simple_bind_s(ldap, fulluser, passwd);
|
||||||
@ -2165,7 +2046,7 @@ CheckLDAPAuth(Port *port)
|
|||||||
{
|
{
|
||||||
ereport(LOG,
|
ereport(LOG,
|
||||||
(errmsg("LDAP login failed for user \"%s\" on server \"%s\": error code %d",
|
(errmsg("LDAP login failed for user \"%s\" on server \"%s\": error code %d",
|
||||||
fulluser, server, r)));
|
fulluser, port->hba->ldapserver, r)));
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.168 2008/09/15 20:55:04 mha Exp $
|
* $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.169 2008/10/23 13:31:10 mha Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -564,6 +564,44 @@ check_db(const char *dbname, const char *role, char *param_str)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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) do {\
|
||||||
|
if (parsedline->auth_method != methodval) \
|
||||||
|
INVALID_AUTH_OPTION("ldaptls", "ldap"); \
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
#define MANDATORY_AUTH_ARG(argvar, argname, authname) do {\
|
||||||
|
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
|
* Parse one line in the hba config file and store the result in
|
||||||
* a HbaLine structure.
|
* a HbaLine structure.
|
||||||
@ -801,37 +839,101 @@ parse_hba_line(List *line, int line_num, HbaLine *parsedline)
|
|||||||
goto hba_other_error;
|
goto hba_other_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the authentication argument token, if any */
|
/* Parse remaining arguments */
|
||||||
line_item = lnext(line_item);
|
while ((line_item = lnext(line_item)) != NULL)
|
||||||
if (line_item)
|
|
||||||
{
|
{
|
||||||
token = lfirst(line_item);
|
char *c;
|
||||||
parsedline->auth_arg= pstrdup(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
token = lfirst(line_item);
|
||||||
|
|
||||||
|
c = strchr(token, '=');
|
||||||
|
if (c == NULL)
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* Backwards compatible format of ident authentication - support "naked" ident map
|
* Got something that's not a name=value pair.
|
||||||
* name, as well as "sameuser"/"samerole"
|
*
|
||||||
|
* XXX: attempt to do some backwards compatible parsing here?
|
||||||
*/
|
*/
|
||||||
if (parsedline->auth_method == uaIdent)
|
ereport(LOG,
|
||||||
{
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
||||||
if (parsedline->auth_arg && strlen(parsedline->auth_arg))
|
errmsg("authentication option not in name=value format: %s", token),
|
||||||
{
|
errcontext("line %d of configuration file \"%s\"",
|
||||||
if (strcmp(parsedline->auth_arg, "sameuser\n") == 0 ||
|
line_num, HbaFileName)));
|
||||||
strcmp(parsedline->auth_arg, "samerole\n") == 0)
|
goto hba_other_error;
|
||||||
{
|
|
||||||
/* This is now the default */
|
|
||||||
pfree(parsedline->auth_arg);
|
|
||||||
parsedline->auth_arg = NULL;
|
|
||||||
parsedline->usermap = NULL;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Specific ident map specified */
|
*c++ = '\0'; /* token now holds "name", c holds "value" */
|
||||||
parsedline->usermap = parsedline->auth_arg;
|
if (strcmp(token, "map") == 0)
|
||||||
parsedline->auth_arg = NULL;
|
{
|
||||||
|
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;
|
return true;
|
||||||
@ -1018,8 +1120,14 @@ free_hba_record(HbaLine *record)
|
|||||||
pfree(record->database);
|
pfree(record->database);
|
||||||
if (record->role)
|
if (record->role)
|
||||||
pfree(record->role);
|
pfree(record->role);
|
||||||
if (record->auth_arg)
|
if (record->pamservice)
|
||||||
pfree(record->auth_arg);
|
pfree(record->pamservice);
|
||||||
|
if (record->ldapserver)
|
||||||
|
pfree(record->ldapserver);
|
||||||
|
if (record->ldapprefix)
|
||||||
|
pfree(record->ldapprefix);
|
||||||
|
if (record->ldapsuffix)
|
||||||
|
pfree(record->ldapsuffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1150,7 +1258,7 @@ read_pg_database_line(FILE *fp, char *dbname, Oid *dboid,
|
|||||||
static void
|
static void
|
||||||
parse_ident_usermap(List *line, int line_number, const char *usermap_name,
|
parse_ident_usermap(List *line, int line_number, const char *usermap_name,
|
||||||
const char *pg_role, const char *ident_user,
|
const char *pg_role, const char *ident_user,
|
||||||
bool *found_p, bool *error_p)
|
bool case_insensitive, bool *found_p, bool *error_p)
|
||||||
{
|
{
|
||||||
ListCell *line_item;
|
ListCell *line_item;
|
||||||
char *token;
|
char *token;
|
||||||
@ -1183,10 +1291,20 @@ parse_ident_usermap(List *line, int line_number, const char *usermap_name,
|
|||||||
file_pgrole = token;
|
file_pgrole = token;
|
||||||
|
|
||||||
/* Match? */
|
/* 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 &&
|
if (strcmp(file_map, usermap_name) == 0 &&
|
||||||
strcmp(file_pgrole, pg_role) == 0 &&
|
strcmp(file_pgrole, pg_role) == 0 &&
|
||||||
strcmp(file_ident_user, ident_user) == 0)
|
strcmp(file_ident_user, ident_user) == 0)
|
||||||
*found_p = true;
|
*found_p = true;
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -1210,22 +1328,32 @@ ident_syntax:
|
|||||||
* file. That's an implied map where "pgrole" must be identical to
|
* file. That's an implied map where "pgrole" must be identical to
|
||||||
* "ident_user" in order to be authorized.
|
* "ident_user" in order to be authorized.
|
||||||
*
|
*
|
||||||
* Iff authorized, return true.
|
* Iff authorized, return STATUS_OK, otherwise return STATUS_ERROR.
|
||||||
*/
|
*/
|
||||||
bool
|
int
|
||||||
check_ident_usermap(const char *usermap_name,
|
check_usermap(const char *usermap_name,
|
||||||
const char *pg_role,
|
const char *pg_role,
|
||||||
const char *ident_user)
|
const char *auth_user,
|
||||||
|
bool case_insensitive)
|
||||||
{
|
{
|
||||||
bool found_entry = false,
|
bool found_entry = false,
|
||||||
error = false;
|
error = false;
|
||||||
|
|
||||||
if (usermap_name == NULL || usermap_name[0] == '\0')
|
if (usermap_name == NULL || usermap_name[0] == '\0')
|
||||||
{
|
{
|
||||||
if (strcmp(pg_role, ident_user) == 0)
|
if (case_insensitive)
|
||||||
found_entry = true;
|
{
|
||||||
else
|
if (pg_strcasecmp(pg_role, auth_user) == 0)
|
||||||
found_entry = false;
|
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
|
else
|
||||||
{
|
{
|
||||||
@ -1235,13 +1363,20 @@ check_ident_usermap(const char *usermap_name,
|
|||||||
forboth(line_cell, ident_lines, num_cell, ident_line_nums)
|
forboth(line_cell, ident_lines, num_cell, ident_line_nums)
|
||||||
{
|
{
|
||||||
parse_ident_usermap(lfirst(line_cell), lfirst_int(num_cell),
|
parse_ident_usermap(lfirst(line_cell), lfirst_int(num_cell),
|
||||||
usermap_name, pg_role, ident_user,
|
usermap_name, pg_role, auth_user, case_insensitive,
|
||||||
&found_entry, &error);
|
&found_entry, &error);
|
||||||
if (found_entry || error)
|
if (found_entry || error)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return found_entry;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,10 +9,10 @@
|
|||||||
# are authenticated, which PostgreSQL user names they can use, which
|
# are authenticated, which PostgreSQL user names they can use, which
|
||||||
# databases they can access. Records take one of these forms:
|
# databases they can access. Records take one of these forms:
|
||||||
#
|
#
|
||||||
# local DATABASE USER METHOD [OPTION]
|
# local DATABASE USER METHOD [OPTIONS]
|
||||||
# host DATABASE USER CIDR-ADDRESS METHOD [OPTION]
|
# host DATABASE USER CIDR-ADDRESS METHOD [OPTIONS]
|
||||||
# hostssl DATABASE USER CIDR-ADDRESS METHOD [OPTION]
|
# hostssl DATABASE USER CIDR-ADDRESS METHOD [OPTIONS]
|
||||||
# hostnossl DATABASE USER CIDR-ADDRESS METHOD [OPTION]
|
# hostnossl DATABASE USER CIDR-ADDRESS METHOD [OPTIONS]
|
||||||
#
|
#
|
||||||
# (The uppercase items must be replaced by actual values.)
|
# (The uppercase items must be replaced by actual values.)
|
||||||
#
|
#
|
||||||
@ -38,7 +38,10 @@
|
|||||||
# "krb5", "ident", "pam" or "ldap". Note that "password" sends passwords
|
# "krb5", "ident", "pam" or "ldap". Note that "password" sends passwords
|
||||||
# in clear text; "md5" is preferred since it sends encrypted 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.
|
# 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
|
# Database and user names containing spaces, commas, quotes and other special
|
||||||
# characters must be quoted. Quoting one of the keywords "all", "sameuser" or
|
# characters must be quoted. Quoting one of the keywords "all", "sameuser" or
|
||||||
|
@ -5,18 +5,18 @@
|
|||||||
# Authentication" for a complete description. A short synopsis
|
# Authentication" for a complete description. A short synopsis
|
||||||
# follows.
|
# follows.
|
||||||
#
|
#
|
||||||
# This file controls PostgreSQL ident-based authentication. It maps
|
# This file controls PostgreSQL username mapping. It maps
|
||||||
# ident user names (typically Unix user names) to their corresponding
|
# external user names to their corresponding
|
||||||
# PostgreSQL user names. Records are of the form:
|
# PostgreSQL user names. Records are of the form:
|
||||||
#
|
#
|
||||||
# MAPNAME IDENT-USERNAME PG-USERNAME
|
# MAPNAME SYSTEM-USERNAME PG-USERNAME
|
||||||
#
|
#
|
||||||
# (The uppercase quantities must be replaced by actual values.)
|
# (The uppercase quantities must be replaced by actual values.)
|
||||||
#
|
#
|
||||||
# MAPNAME is the (otherwise freely chosen) map name that was used in
|
# MAPNAME is the (otherwise freely chosen) map name that was used in
|
||||||
# pg_hba.conf. IDENT-USERNAME is the detected user name of the
|
# pg_hba.conf. SYSTEM-USERNAME is the detected user name of the
|
||||||
# client. PG-USERNAME is the requested PostgreSQL user name. The
|
# client. PG-USERNAME is the requested PostgreSQL user name. The
|
||||||
# existence of a record specifies that IDENT-USERNAME may connect as
|
# existence of a record specifies that SYSTEM-USERNAME may connect as
|
||||||
# PG-USERNAME. Multiple maps may be specified in this file and used
|
# PG-USERNAME. Multiple maps may be specified in this file and used
|
||||||
# by pg_hba.conf.
|
# by pg_hba.conf.
|
||||||
#
|
#
|
||||||
@ -28,8 +28,8 @@
|
|||||||
# Put your actual configuration here
|
# Put your actual configuration here
|
||||||
# ----------------------------------
|
# ----------------------------------
|
||||||
#
|
#
|
||||||
# No map names are defined in the default configuration. If all ident
|
# 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
|
# user names and PostgreSQL user names are the same, you don't need
|
||||||
# this file.
|
# this file.
|
||||||
|
|
||||||
# MAPNAME IDENT-USERNAME PG-USERNAME
|
# MAPNAME SYSTEM-USERNAME PG-USERNAME
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* Interface to hba.c
|
* Interface to hba.c
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/libpq/hba.h,v 1.49 2008/09/15 12:32:57 mha Exp $
|
* $PostgreSQL: pgsql/src/include/libpq/hba.h,v 1.50 2008/10/23 13:31:10 mha Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -25,13 +25,9 @@ typedef enum UserAuth
|
|||||||
uaCrypt,
|
uaCrypt,
|
||||||
uaMD5,
|
uaMD5,
|
||||||
uaGSS,
|
uaGSS,
|
||||||
uaSSPI
|
uaSSPI,
|
||||||
#ifdef USE_PAM
|
uaPAM,
|
||||||
,uaPAM
|
uaLDAP
|
||||||
#endif /* USE_PAM */
|
|
||||||
#ifdef USE_LDAP
|
|
||||||
,uaLDAP
|
|
||||||
#endif
|
|
||||||
} UserAuth;
|
} UserAuth;
|
||||||
|
|
||||||
typedef enum ConnType
|
typedef enum ConnType
|
||||||
@ -51,8 +47,14 @@ typedef struct
|
|||||||
struct sockaddr_storage addr;
|
struct sockaddr_storage addr;
|
||||||
struct sockaddr_storage mask;
|
struct sockaddr_storage mask;
|
||||||
UserAuth auth_method;
|
UserAuth auth_method;
|
||||||
|
|
||||||
char *usermap;
|
char *usermap;
|
||||||
char *auth_arg;
|
char *pamservice;
|
||||||
|
bool ldaptls;
|
||||||
|
char *ldapserver;
|
||||||
|
int ldapport;
|
||||||
|
char *ldapprefix;
|
||||||
|
char *ldapsuffix;
|
||||||
} HbaLine;
|
} HbaLine;
|
||||||
|
|
||||||
typedef struct Port hbaPort;
|
typedef struct Port hbaPort;
|
||||||
@ -64,8 +66,9 @@ extern void load_role(void);
|
|||||||
extern int hba_getauthmethod(hbaPort *port);
|
extern int hba_getauthmethod(hbaPort *port);
|
||||||
extern bool read_pg_database_line(FILE *fp, char *dbname, Oid *dboid,
|
extern bool read_pg_database_line(FILE *fp, char *dbname, Oid *dboid,
|
||||||
Oid *dbtablespace, TransactionId *dbfrozenxid);
|
Oid *dbtablespace, TransactionId *dbfrozenxid);
|
||||||
extern bool check_ident_usermap(const char *usermap_name,
|
extern int check_usermap(const char *usermap_name,
|
||||||
const char *pg_role, const char *ident_user);
|
const char *pg_role, const char *auth_user,
|
||||||
|
bool case_sensitive);
|
||||||
extern bool pg_isblank(const char c);
|
extern bool pg_isblank(const char c);
|
||||||
|
|
||||||
#endif /* HBA_H */
|
#endif /* HBA_H */
|
||||||
|
Reference in New Issue
Block a user