Fix timeout in LDAP lookup of libpq connection parameters
authorMagnus Hagander <magnus@hagander.net>
Wed, 16 Apr 2014 15:18:02 +0000 (17:18 +0200)
committerMagnus Hagander <magnus@hagander.net>
Wed, 16 Apr 2014 16:59:48 +0000 (18:59 +0200)
Bind attempts to an LDAP server should time out after two seconds,
allowing additional lines in the service control file to be parsed
(which provide a fall back to a secondary LDAP server or default options).
The existing code failed to enforce that timeout during TCP connect,
resulting in a hang far longer than two seconds if the LDAP server
does not respond.

Laurenz Albe

src/interfaces/libpq/fe-connect.c

index 728e0fd106ac1b1f25e877cbe937bfcda96b77b5..0c32045a78d13a467289a277529de19b2cf198dd 100644 (file)
@@ -2758,12 +2758,37 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options,
    }
 
    /*
-    * Initialize connection to the server.  We do an explicit bind because we
-    * want to return 2 if the bind fails.
+    * Perform an explicit anonymous bind.
+    * LDAP does not require that an anonymous bind is preformed explicitly,
+    * but we want to distinguish between the case where LDAP bind does not
+    * succeed within PGLDAP_TIMEOUT seconds (return 2 to continue parsing
+    * the service control file) and the case where querying the LDAP server
+    * fails (return 1 to end parsing).
+    * Unfortunately there is no way of setting a timeout that works for
+    * both Windows and OpenLDAP.
     */
+#ifdef WIN32
+   /* the nonstandard ldap_connect function performs an anonymous bind */
+   if (ldap_connect(ld, &time) != LDAP_SUCCESS)
+   {
+       /* error or timeout in ldap_connect */
+       free(url);
+       ldap_unbind(ld);
+       return 2;
+   }
+#else /* WIN32 */
+   /* in OpenLDAP, use the LDAP_OPT_NETWORK_TIMEOUT option */
+   if (ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &time) != LDAP_SUCCESS)
+   {
+       free(url);
+       ldap_unbind(ld);
+       return 3;
+   }
+
+   /* anonymous bind */
    if ((msgid = ldap_simple_bind(ld, NULL, NULL)) == -1)
    {
-       /* error in ldap_simple_bind() */
+       /* error or network timeout */
        free(url);
        ldap_unbind(ld);
        return 2;
@@ -2774,18 +2799,25 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options,
    if ((rc = ldap_result(ld, msgid, LDAP_MSG_ALL, &time, &res)) == -1 ||
        res == NULL)
    {
+       /* error or timeout */
        if (res != NULL)
-       {
-           /* timeout */
            ldap_msgfree(res);
-       }
-       /* error in ldap_result() */
        free(url);
        ldap_unbind(ld);
        return 2;
    }
    ldap_msgfree(res);
 
+   /* reset timeout */
+   time.tv_sec = -1;
+   if (ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &time) != LDAP_SUCCESS)
+   {
+       free(url);
+       ldap_unbind(ld);
+       return 3;
+   }
+#endif /* WIN32 */
+
    /* search */
    res = NULL;
    if ((rc = ldap_search_st(ld, dn, scope, filter, attrs, 0, &time, &res))