Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Fix handling of HBA ldapserver with multiple hostnames.
authorThomas Munro <tmunro@postgresql.org>
Tue, 13 Nov 2018 04:39:36 +0000 (17:39 +1300)
committerThomas Munro <tmunro@postgresql.org>
Tue, 13 Nov 2018 04:46:28 +0000 (17:46 +1300)
Commit 35c0754f failed to handle space-separated lists of alternative
hostnames in ldapserver, when building a URI for ldap_initialize()
(OpenLDAP).  Such lists need to be expanded to space-separated URIs.

Repair.  Back-patch to 11, to fix bug report #15495.

Author: Thomas Munro
Reported-by: Renaud Navarro
Discussion: https://postgr.es/m/15495-2c39fc196c95cd72%40postgresql.org

src/backend/libpq/auth.c
src/test/ldap/t/001_auth.pl

index 85175655359829a2cf50dd883066bbb3d45e2286..bbf102ed7de9b29a9c0438be3c2c6f9822b29de8 100644 (file)
@@ -2352,12 +2352,44 @@ InitializeLDAPConnection(Port *port, LDAP **ldap)
 #else
 #ifdef HAVE_LDAP_INITIALIZE
    {
-       char       *uri;
+       const char *hostnames = port->hba->ldapserver;
+       char       *uris = NULL;
 
-       uri = psprintf("%s://%s:%d", scheme, port->hba->ldapserver,
-                      port->hba->ldapport);
-       r = ldap_initialize(ldap, uri);
-       pfree(uri);
+       /*
+        * We have a space-separated list of hostnames.  Convert it
+        * to a space-separated list of URIs.
+        */
+       do
+       {
+           const char *hostname;
+           size_t      hostname_size;
+           char       *new_uris;
+
+           /* Find the leading hostname. */
+           hostname_size = strcspn(hostnames, " ");
+           hostname = pnstrdup(hostnames, hostname_size);
+
+           /* Append a URI for this hostname. */
+           new_uris = psprintf("%s%s%s://%s:%d",
+                               uris ? uris : "",
+                               uris ? " " : "",
+                               scheme,
+                               hostname,
+                               port->hba->ldapport);
+
+           pfree(hostname);
+           if (uris)
+               pfree(uris);
+           uris = new_uris;
+
+           /* Step over this hostname and any spaces. */
+           hostnames += hostname_size;
+           while (*hostnames == ' ')
+               ++hostnames;
+       } while (*hostnames);
+
+       r = ldap_initialize(ldap, uris);
+       pfree(uris);
        if (r != LDAP_SUCCESS)
        {
            ereport(LOG,
index 67b406c981b360439882788fc7346078441f433e..431ad6442c3e152a09666baf4fa7b009c7282706 100644 (file)
@@ -6,7 +6,7 @@ use Test::More;
 
 if ($ENV{with_ldap} eq 'yes')
 {
-   plan tests => 19;
+   plan tests => 22;
 }
 else
 {
@@ -179,6 +179,22 @@ test_access($node, 'test1', 2,
 $ENV{"PGPASSWORD"} = 'secret1';
 test_access($node, 'test1', 0, 'search+bind authentication succeeds');
 
+note "multiple servers";
+
+unlink($node->data_dir . '/pg_hba.conf');
+$node->append_conf('pg_hba.conf',
+   qq{local all all ldap ldapserver="$ldap_server $ldap_server" ldapport=$ldap_port ldapbasedn="$ldap_basedn"}
+);
+$node->restart;
+
+$ENV{"PGPASSWORD"} = 'wrong';
+test_access($node, 'test0', 2,
+   'search+bind authentication fails if user not found in LDAP');
+test_access($node, 'test1', 2,
+   'search+bind authentication fails with wrong password');
+$ENV{"PGPASSWORD"} = 'secret1';
+test_access($node, 'test1', 0, 'search+bind authentication succeeds');
+
 note "LDAP URLs";
 
 unlink($node->data_dir . '/pg_hba.conf');