From 7f386e080d9323e249dfa038a594e06b211c8b6e Mon Sep 17 00:00:00 2001
From: Marius Tomaschewski <mt@suse.de>
Date: Wed, 17 Nov 2010 17:32:39 +0000
Subject: [PATCH] Added ldap connect retry loop while initial startup

Implemented optional ldap connect retry loop during the initial
startup of the dhcp server in cases where the ldap server is not
yet started. Set the ldap-init-retry <secs> option in dhcpd.conf
to enable it (bnc#627617).

Signed-off-by: Marius Tomaschewski <mt@suse.de>
---
 README.ldap      |    5 ++++
 includes/dhcpd.h |   21 ++++++++++---------
 server/ldap.c    |   55 +++++++++++++++++++++++++++++++++++++++++++++++------
 server/stables.c |   19 +++++++++--------
 4 files changed, 74 insertions(+), 26 deletions(-)

diff --git a/README.ldap b/README.ldap
index 86ce58b..b2ba438 100644
--- a/README.ldap
+++ b/README.ldap
@@ -82,6 +82,11 @@ options:
    ldap-tls-reqcert, ldap-tls-ca-file, ldap-tls-ca-dir, ldap-tls-cert
    ldap-tls-key, ldap-tls-crlcheck, ldap-tls-ciphers, ldap-tls-randfile
 
+The ldap-init-retry <secs> enables an optional ldap connect retry loop
+for the specified number of seconds during the initial startup of the
+dhcp server. It allows to catch the condition, that the (remote) ldap
+server is not yet started at start time of the dhcp server.
+
 All of these parameters should be self explanatory except for the ldap-method.
 You can set this to static or dynamic. If you set it to static, the 
 configuration is read once on startup, and LDAP isn't used anymore. But, if you
diff --git a/includes/dhcpd.h b/includes/dhcpd.h
index e6794a1..0623ad2 100644
--- a/includes/dhcpd.h
+++ b/includes/dhcpd.h
@@ -601,17 +601,18 @@ struct lease_state {
 # define SV_LDAP_METHOD			58
 # define SV_LDAP_DEBUG_FILE		59
 # define SV_LDAP_DHCP_SERVER_CN		60
-# define SV_LDAP_REFERRALS              61
+# define SV_LDAP_REFERRALS		61
+# define SV_LDAP_INIT_RETRY		62
 #if defined (USE_SSL)
-# define SV_LDAP_SSL			62
-# define SV_LDAP_TLS_REQCERT		63
-# define SV_LDAP_TLS_CA_FILE		64
-# define SV_LDAP_TLS_CA_DIR		65
-# define SV_LDAP_TLS_CERT		66
-# define SV_LDAP_TLS_KEY		67
-# define SV_LDAP_TLS_CRLCHECK		68
-# define SV_LDAP_TLS_CIPHERS		69
-# define SV_LDAP_TLS_RANDFILE		70
+# define SV_LDAP_SSL			63
+# define SV_LDAP_TLS_REQCERT		64
+# define SV_LDAP_TLS_CA_FILE		65
+# define SV_LDAP_TLS_CA_DIR		66
+# define SV_LDAP_TLS_CERT		67
+# define SV_LDAP_TLS_KEY		68
+# define SV_LDAP_TLS_CRLCHECK		69
+# define SV_LDAP_TLS_CIPHERS		70
+# define SV_LDAP_TLS_RANDFILE		71
 #endif
 #endif
 
diff --git a/server/ldap.c b/server/ldap.c
index fd9bbc3..f472a5b 100644
--- a/server/ldap.c
+++ b/server/ldap.c
@@ -60,7 +60,9 @@ static char *ldap_server = NULL,
 static int ldap_port = LDAP_PORT,
            ldap_method = LDAP_METHOD_DYNAMIC,
            ldap_referrals = -1,
-           ldap_debug_fd = -1;
+           ldap_debug_fd = -1,
+           ldap_enable_retry = -1,
+           ldap_init_retry = -1;
 #if defined (USE_SSL)
 static int ldap_use_ssl = -1,        /* try TLS if possible */
            ldap_tls_reqcert = -1,
@@ -958,6 +960,25 @@ ldap_rebind_cb (LDAP *ld, LDAP_CONST char *url, ber_tag_t request, ber_int_t msg
   return ret;
 }
 
+static int
+_do_ldap_retry(int ret, const char *server, int port)
+{
+  static int inform = 1;
+
+  if (ldap_enable_retry > 0 && ret == LDAP_SERVER_DOWN && ldap_init_retry > 0)
+    {
+      if (inform || (ldap_init_retry % 10) == 0)
+        {
+          inform = 0;
+          log_info ("Can't contact LDAP server %s:%d: retrying for %d sec",
+                    server, port, ldap_init_retry);
+        }
+      sleep(1);
+      return ldap_init_retry--;
+    }
+  return 0;
+}
+
 static void
 ldap_start (void)
 {
@@ -986,6 +1007,7 @@ ldap_start (void)
       ldap_debug_file = _do_lookup_dhcp_string_option (options,
                                                        SV_LDAP_DEBUG_FILE);
       ldap_referrals = _do_lookup_dhcp_enum_option (options, SV_LDAP_REFERRALS);
+      ldap_init_retry = _do_lookup_dhcp_int_option (options, SV_LDAP_INIT_RETRY);
 
 #if defined (USE_SSL)
       ldap_use_ssl = _do_lookup_dhcp_enum_option (options, SV_LDAP_SSL);
@@ -1185,7 +1207,12 @@ ldap_start (void)
     }
   else if (ldap_use_ssl != LDAP_SSL_OFF)
     {
-      if ((ret = ldap_start_tls_s (ld, NULL, NULL)) != LDAP_SUCCESS)
+      do
+        {
+          ret = ldap_start_tls_s (ld, NULL, NULL);
+        } while(_do_ldap_retry(ret, ldap_server, ldap_port) > 0);
+
+      if (ret != LDAP_SUCCESS)
         {
           log_error ("Error: Cannot start TLS session to %s:%d: %s",
                      ldap_server, ldap_port, ldap_err2string (ret));
@@ -1202,8 +1229,12 @@ ldap_start (void)
 
   if (ldap_username != NULL && *ldap_username != '\0')
     {
-      if ((ret = ldap_simple_bind_s (ld, ldap_username,
-                                     ldap_password)) != LDAP_SUCCESS)
+      do
+        {
+          ret = ldap_simple_bind_s (ld, ldap_username, ldap_password);
+        } while(_do_ldap_retry(ret, ldap_server, ldap_port) > 0);
+
+      if (ret != LDAP_SUCCESS)
         {
           log_error ("Error: Cannot login into ldap server %s:%d: %s",
                      ldap_server, ldap_port, ldap_err2string (ret));
@@ -1701,8 +1732,10 @@ ldap_read_config (void)
   size_t length;
   int ret, cnt;
 
+  ldap_enable_retry = 1;
   if (ld == NULL)
     ldap_start ();
+  ldap_enable_retry = 0;
   if (ld == NULL)
     return (ldap_server == NULL ? ISC_R_SUCCESS : ISC_R_FAILURE);
  
@@ -1736,9 +1769,17 @@ ldap_read_config (void)
     }
 
   }
-  hostres = NULL;
-  if ((ret = ldap_search_s (ld, ldap_base_dn, LDAP_SCOPE_SUBTREE,
-                            hfilter, NULL, 0, &hostres)) != LDAP_SUCCESS)
+
+  ldap_enable_retry = 1;
+  do
+    {
+      hostres = NULL;
+      ret = ldap_search_s (ld, ldap_base_dn, LDAP_SCOPE_SUBTREE,
+                           hfilter, NULL, 0, &hostres);
+    } while(_do_ldap_retry(ret, ldap_server, ldap_port) > 0);
+  ldap_enable_retry = 0;
+
+  if (ret != LDAP_SUCCESS)
     {
       log_error ("Cannot find host LDAP entry %s %s",
 		 ((ldap_dhcp_server_cn == NULL)?(unme.nodename):(ldap_dhcp_server_cn)), hfilter);
diff --git a/server/stables.c b/server/stables.c
index e3d0092..126bbdf 100644
--- a/server/stables.c
+++ b/server/stables.c
@@ -248,18 +248,19 @@ static struct option server_options[] = {
 	{ "ldap-debug-file", "t",		&server_universe,  59, 1 },
 	{ "ldap-dhcp-server-cn", "t",		&server_universe,  60, 1 },
 	{ "ldap-referrals", "f",		&server_universe,  61, 1 },
+	{ "ldap-init-retry", "d",		&server_universe,  62, 1 },
 #if defined(USE_SSL)
-	{ "ldap-ssl", "Nldap-ssl-usage.",	&server_universe,  62, 1 },
+	{ "ldap-ssl", "Nldap-ssl-usage.",	&server_universe,  63, 1 },
 	{ "ldap-tls-reqcert", "Nldap-tls-reqcert.",
-						&server_universe,  63, 1 },
-	{ "ldap-tls-ca-file", "t",		&server_universe,  64, 1 },
-	{ "ldap-tls-ca-dir", "t",		&server_universe,  65, 1 },
-	{ "ldap-tls-cert", "t",			&server_universe,  66, 1 },
-	{ "ldap-tls-key", "t",			&server_universe,  67, 1 },
+						&server_universe,  64, 1 },
+	{ "ldap-tls-ca-file", "t",		&server_universe,  65, 1 },
+	{ "ldap-tls-ca-dir", "t",		&server_universe,  66, 1 },
+	{ "ldap-tls-cert", "t",			&server_universe,  67, 1 },
+	{ "ldap-tls-key", "t",			&server_universe,  68, 1 },
 	{ "ldap-tls-crlcheck", "Nldap-tls-crlcheck.",
-						&server_universe,  68, 1 },
-	{ "ldap-tls-ciphers", "t",		&server_universe,  69, 1 },
-	{ "ldap-tls-randfile", "t",		&server_universe,  70, 1 },
+						&server_universe,  69, 1 },
+	{ "ldap-tls-ciphers", "t",		&server_universe,  70, 1 },
+	{ "ldap-tls-randfile", "t",		&server_universe,  71, 1 },
 #endif
 #endif
 	{ NULL, NULL, NULL, 0, 0 }
-- 
1.7.3.4

