File 0007-dhcp-4.2.6-ldap-mt01.patch of Package dhcp

From b61fe9752fa8fe76a9c9dd04c9808e510a8dc3fe Mon Sep 17 00:00:00 2001
From: Marius Tomaschewski <mt@suse.de>
Date: Mon, 10 Feb 2014 13:59:27 +0100
Subject: [PATCH] dhcp-4.2.6-ldap-mt01

A squashed commit of the following changes:

commit f3961ac1dea087b365ae7d5b3085a4d5cfb918ac
Author: Marius Tomaschewski <mt@suse.de>
Date:   Mon Dec 10 09:56:00 2012 +0100

    Fixed memory leaks in ldap read config error handling

    Fixed to free ldap results before bailing out when the
    dhcpServer object or it's dhcpService references can't
    be parsed / resolved.

commit f0ab39c5a6fcca07d305f45536050ba5af91c599
Author: Marius Tomaschewski <mt@suse.de>
Date:   Fri Nov 30 13:00:32 2012 +0100

    Fixed subclass class-name and data quoting/escaping

commit 94869d5c2087d44057954425a588712da2c012cf
Author: Marius Tomaschewski <mt@suse.de>
Date:   Thu Nov 29 19:02:25 2012 +0100

    Resize ldap buffer to not truncate bigger objects

    Fixed parse buffer handling code to not avoid truncation
    of config > ~8k from bigger ldap objects. Fixed to free
    the ldap config buffer passed to the config parser and
    append new config, while the parser is in saved state.

commit 65bced9870ff1a63599321c021519ce6649af57c
Author: Marius Tomaschewski <mt@suse.de>
Date:   Thu Nov 15 14:42:21 2012 +0100

    dhcp-ldap: reset bufix in ldap_read_function

    Fixed ldap_read_function to reset bufix variable to 0 and
    to set buflen to the complete length (do not discard last
    character, usually \n).
    This caused a parsing error at further run of the function,
    e.g. while processing the second dhcpService container that
    the dhcpServer object may refer to.

commit 9b306cdbce9666f1a87a8da9526b5b3cd45da334
Author: Marius Tomaschewski <mt@suse.de>
Date:   Thu Nov 15 12:07:42 2012 +0100

    dhcp-ldap: memleak fix in subnet range processing

commit ac85a9311e5f466cae4de4f1c717421b14b8b679
Author: Marius Tomaschewski <mt@suse.de>
Date:   Tue Jun 12 09:44:16 2012 +0200

    Removed SV_LDAP constant redefinition

commit c4423481cc65360d1d892fd08eebbdd3887af793
Author: Marius Tomaschewski <mt@suse.de>
Date:   Tue Jan 31 17:38:25 2012 +0100

    Fixed to escape values used in ldap filters

    Use ldap_bv2escaped_filter_value to escape all values used in
    constructed ldap filters, e.g. "o=*Test" in DN (bnc#721829).

commit d6cdf45ef8b80fc245bd0b8e5aa2962680619a91
Author: Marius Tomaschewski <mt@suse.de>
Date:   Wed Apr 27 16:37:00 2011 +0200

    ldap connect retry loop while initial startup

    Implemented optional ldap connect retry loop during the initial startup
    of the dhcp server for cases where the ldap server is not yet started.
    Set the ldap-init-retry <num> option in dhcpd.conf to retry to connect
    <num> times with one second between each try (bnc#627617).
    (cherry picked from commit c09a950a0f706f86a07dd575752d44d1691eb400)

commit cc266c5e2c54da8f38d00af99ce37ac7f3701931
Author: Marius Tomaschewski <mt@suse.de>
Date:   Fri Nov 26 15:16:55 2010 +0100

    Do not link dhclient against libldap

commit fd61b1d7b14d714ba9066f9331d02cf13b87431e
Author: Marius Tomaschewski <mt@suse.de>
Date:   Fri Nov 26 09:32:00 2010 +0100

    Added --with-ldapcasa configure switch and checks

commit 551e8f9ffc28ac1671205b33dc5c22caf377e5c5
Author: Marius Tomaschewski <mt@suse.de>
Date:   Thu Oct 1 15:29:16 2009 +0200

    Added configure check for inet_pton and inet_ntop.

commit 46f3cc4b58872a15d519f657eb95cd5a0e3f1e00
Author: Marius Tomaschewski <mt@suse.de>
Date:   Fri Nov 26 09:16:52 2010 +0100

    Changed inclusion order in ldap_casa.c

    Include dhcpd.h first, so config.h is included first and pktinfo
    type is known (_GNU_SOURCE required for socket extensions).

commit d02fdfbc9c43b124323098d322eb157895c98350
Author: Marius Tomaschewski <mt@suse.de>
Date:   Fri Nov 26 08:43:19 2010 +0100

    Moved includes from ldap_casa.h to ldap_casa.c

commit 2bf6db555f3accb81b42847181bd3e16ac7b627b
Author: Marius Tomaschewski <mt@suse.de>
Date:   Thu Nov 25 09:11:28 2010 +0100

    Added missed includes/ldap_casa.h file

commit 856003a7eef4bade55bdadeadeb822a4059da5fe
Author: Marius Tomaschewski <mt@suse.de>
Date:   Thu Oct 28 17:17:18 2010 +0200

    Allow all local addresses for dhcpd failover

    Fixed to allow all local addresses for dhcpd failover peering by name
    or address and show the name of affected failover peering in log/error
    messages (bnc#597825).

commit 915ce91842a2316e0b382e8b3771f6bcce9b5b7c
Author: Marius Tomaschewski <mt@suse.de>
Date:   Fri Nov 26 13:07:33 2010 +0100

    Disabled ldap support for DHCPv6 (not implemented yet).

commit bc287137134aa5b759aa501ebb3c37021b29d55d
Author: Marius Tomaschewski <mt@suse.de>
Date:   Tue Sep 29 09:25:09 2009 +0200

    Free ldap url in ldap rebind function

    Fixes an ldap url memory leak in the dhcp ldap rebind function.

commit 25f051c769ed435020215fb99d1ea54ba7b2786d
Author: Marius Tomaschewski <mt@suse.de>
Date:   Tue Sep 29 09:23:37 2009 +0200

    Disable external dhcpZoneDN and dhcpFailOverPeerDN

    Applied S Kalyanasundaram's patch disabling incorrect parsing
    of external dhcpZoneDN and dhcpFailOverPeerDN references.

commit c34f12ab1b06f0fcd12c30601e4e83d38ff17e69
Author: Marius Tomaschewski <mt@suse.de>
Date:   Thu Oct 28 16:43:21 2010 +0200

    Meaningful error message on missed dhcpServiceDN

    Fix to provide more meaningful error message in case of missed
    dhcpServiceDN attribute in a dhcpServer object (bnc#392354).

commit 14e0ba1c80eced74ef84b72e7b840d95f53e2022
Author: Marius Tomaschewski <mt@suse.de>
Date:   Mon Sep 28 23:04:08 2009 +0200

    Support for dhcpFailOverPeer objects

    Ported support for dhcpFailOverPeer objects (failover peering
    definition) by S Kalyanasundaram and Marius Tomaschewski
    (fate#303198).

commit 071b5b5fbbd0064c4c396064cd4460baf77af83e
Author: Marius Tomaschewski <mt@suse.de>
Date:   Thu Oct 28 15:56:11 2010 +0200

    Case insensitive hardware address search

    Added dhcp-server compatibility workaround to search for lower- and
    upper-case MAC addresses in the dhcpHWAddress LDAP attribute, for
    the case, the ldap server is still using an old schema with case
    sensitive match definition (bnc#343069).

commit 683798b58a15456c0bb03b691d9db4ac706b3519
Author: Marius Tomaschewski <mt@suse.de>
Date:   Mon Sep 28 23:02:31 2009 +0200

    Missed host brace opening

    Generate proper "host ... {" block begin brace even if no harware
    address is specified for the host (bnc#265337).

commit f65005a662a47cd8126776023633f9b1c0906107
Author: Marius Tomaschewski <mt@suse.de>
Date:   Mon Sep 28 23:01:21 2009 +0200

    Fix to support dhcpServerDN reference

    Fixes to support new dhcpServerDN reference in dhcpService object
    search filter (bnc#258493).

commit e702ee4a39d401d277bb56e3162c8be6be3ad80a
Author: Marius Tomaschewski <mt@suse.de>
Date:   Thu Oct 28 15:45:15 2010 +0200

    Fix for object-order related parse errors

    Fixed object order related parse errors, that occured in case a dhcp-ldap
    object referencing a dhcp-tsigkey, class or failoverpeer object, was parsed
    before the declaration of the referenced objects, because of the "random"
    object order in ldap results (bnc#250153).

commit 815559287fec09ae1edd49caad8e110f5ab2bbff
Author: Marius Tomaschewski <mt@suse.de>
Date:   Wed Nov 24 16:41:37 2010 +0100

    Typos in access of the tempbv value in ldap debug log

    Fixed typos in access of the tempbv value in ldap debug log
    messages guarded by DEBUG_LDAP.

commit c5c400475a6d1317cc075cbfc10c420e6231f07e
Author: Marius Tomaschewski <mt@suse.de>
Date:   Wed Nov 24 16:23:23 2010 +0100

    Use LDAP_CFLAGS for common/libdhcp to avoid a SEGV

    Use LDAP_CFLAGS for common/libdhcp.a compilation to avoid a segfault
    when dhcp server ldap code is enabled. The parse struct allocated by
    new_parse, does not contain/allocate any read_function pointer, when
    LDAP_CONFIGURATION is not defined.
---
 common/Makefile.am       |    1 +
 common/conflex.c         |   18 +-
 configure.ac             |   18 +
 contrib/ldap/README.ldap |    6 +
 includes/dhcpd.h         |   24 +-
 includes/ldap_casa.h     |  101 ++++
 server/Makefile.am       |    2 +-
 server/ldap.c            | 1143 +++++++++++++++++++++++++++++++++++++---------
 server/ldap_casa.c       |    4 +-
 server/stables.c         |    1 +
 10 files changed, 1078 insertions(+), 240 deletions(-)
 create mode 100644 includes/ldap_casa.h

diff --git a/common/Makefile.am b/common/Makefile.am
index eddef05..631025c 100644
--- a/common/Makefile.am
+++ b/common/Makefile.am
@@ -7,6 +7,7 @@ libdhcp_a_SOURCES = alloc.c bpf.c comapi.c conflex.c ctrace.c discover.c \
 		    icmp.c inet.c lpf.c memory.c nit.c ns_name.c options.c \
 		    packet.c parse.c print.c raw.c resolv.c socket.c \
 		    tables.c tr.c tree.c upf.c
+libdhcp_a_CFLAGS = $(LDAP_CFLAGS)
 man_MANS = dhcp-eval.5 dhcp-options.5
 EXTRA_DIST = $(man_MANS)
 
diff --git a/common/conflex.c b/common/conflex.c
index c39e91d..8badcf9 100644
--- a/common/conflex.c
+++ b/common/conflex.c
@@ -147,13 +147,19 @@ save_parse_state(struct parse *cfile) {
 /*
  * Return the parser to the previous saved state.
  *
- * You must call save_parse_state() before calling 
- * restore_parse_state(), but you can call restore_parse_state() any
- * number of times after that.
+ * You must call save_parse_state() every time before calling
+ * restore_parse_state().
+ *
+ * Note: When the read function callback is in use in ldap mode,
+ * a call to get_char() may reallocate the buffer and will append
+ * config data to the buffer until a state restore.
+ * Do not restore to the (freed) pointer and size, but use new one.
  */
 isc_result_t
 restore_parse_state(struct parse *cfile) {
 	struct parse *saved_state;
+	char *inbuf = cfile->inbuf;
+	size_t size = cfile->bufsiz;
 
 	if (cfile->saved_state == NULL) {
 		return DHCP_R_NOTYET;
@@ -161,7 +167,11 @@ restore_parse_state(struct parse *cfile) {
 
 	saved_state = cfile->saved_state;
 	memcpy(cfile, saved_state, sizeof(*cfile));
-	cfile->saved_state = saved_state;
+	dfree(cfile->saved_state, MDL);
+	cfile->saved_state = NULL;
+
+	cfile->inbuf = inbuf;
+	cfile->bufsiz = size;
 	return ISC_R_SUCCESS;
 }
 
diff --git a/configure.ac b/configure.ac
index c810de8..e8d8fd1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -618,20 +618,38 @@ AC_ARG_WITH(ldapcrypto,
     [ldapcrypto=$withval],
     [ldapcrypto=no])
 
+# LDAP CASA auth support.
+AC_ARG_WITH(ldapcasa,
+    AC_HELP_STRING([--with-ldapcasa],
+                   [enable LDAP CASA auth support in dhcpd (default is no)]),
+    [ldapcasa=$withval],
+    [ldapcasa=no])
+
 # OpenLDAP support is disabled by default, if enabled then SSL support is an
 # extra optional that is also disabled by default.  Enabling LDAP SSL support
 # implies enabling LDAP support.
 if test x$ldap = xyes || test x$ldapcrypto = xyes ; then
+    saved_LIBS="$LIBS"
+    LIBS=""
     AC_SEARCH_LIBS(ldap_initialize, [ldap], ,
 		   AC_MSG_FAILURE([*** Cannot find ldap_initialize with -lldap - do you need to install an OpenLDAP2 Devel package?]))
     AC_SEARCH_LIBS(ber_pvt_opt_on, [lber], ,
 		   AC_MSG_FAILURE([*** Cannot find ber_pvt_opt_on with -llber - do you need to install an OpenLDAP2 Devel package?]))
+    AC_SUBST(LDAP_LIBS, ["$LIBS"])
+    LIBS="$saved_LIBS"
+
+    AC_CHECK_FUNCS([inet_pton inet_ntop])
 
     if test x$ldapcrypto = xyes ; then
 	AC_SUBST(LDAP_CFLAGS, ["-DLDAP_CONFIGURATION -DLDAP_USE_SSL"])
     else
 	AC_SUBST(LDAP_CFLAGS, ["-DLDAP_CONFIGURATION"])
     fi
+    if test x$ldapcasa = xyes ; then
+	AC_CHECK_HEADERS([micasa_mgmd.h],[
+	    	LDAP_CFLAGS="$LDAP_CFLAGS -DLDAP_CASA_AUTH"
+	], AC_MSG_FAILURE([*** Cannot find micasa_mgmd.h for ldap casa auth support]))
+    fi
 fi
 
 # Append selected warning levels to CFLAGS before substitution (but after
diff --git a/contrib/ldap/README.ldap b/contrib/ldap/README.ldap
index c413790..63b839c 100644
--- a/contrib/ldap/README.ldap
+++ b/contrib/ldap/README.ldap
@@ -83,6 +83,12 @@ 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 <num> enables an optional ldap connect retry loop with
+the specified number of retries with a one second sleep between each try
+during the initial startup of the dhcp server.
+It allows to catch the condition, that the (remote) ldap server is not yet
+started at the 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
diff --git a/includes/dhcpd.h b/includes/dhcpd.h
index 5830bdb..63d58e5 100644
--- a/includes/dhcpd.h
+++ b/includes/dhcpd.h
@@ -712,6 +712,7 @@ struct lease_state {
 # define SV_LDAP_TLS_CIPHERS            76
 # define SV_LDAP_TLS_RANDFILE           77
 #endif
+# define SV_LDAP_INIT_RETRY		78
 #endif
 
 #if !defined (DEFAULT_PING_TIMEOUT)
@@ -734,29 +735,6 @@ struct lease_state {
 # define DEFAULT_MIN_ACK_DELAY_USECS 10000 /* 1/100 second */
 #endif
 
-#if defined(LDAP_CONFIGURATION)
-# define SV_LDAP_SERVER			60
-# define SV_LDAP_PORT			61
-# define SV_LDAP_USERNAME		62
-# define SV_LDAP_PASSWORD		63
-# define SV_LDAP_BASE_DN		64
-# define SV_LDAP_METHOD			65
-# define SV_LDAP_DEBUG_FILE		66
-# define SV_LDAP_DHCP_SERVER_CN		67
-# define SV_LDAP_REFERRALS		68
-#if defined (LDAP_USE_SSL)
-# define SV_LDAP_SSL			69
-# define SV_LDAP_TLS_REQCERT		70
-# define SV_LDAP_TLS_CA_FILE		71
-# define SV_LDAP_TLS_CA_DIR		72
-# define SV_LDAP_TLS_CERT		73
-# define SV_LDAP_TLS_KEY		74
-# define SV_LDAP_TLS_CRLCHECK		75
-# define SV_LDAP_TLS_CIPHERS		76
-# define SV_LDAP_TLS_RANDFILE		77
-#endif
-#endif
-
 #if !defined (DEFAULT_DEFAULT_LEASE_TIME)
 # define DEFAULT_DEFAULT_LEASE_TIME 43200
 #endif
diff --git a/includes/ldap_casa.h b/includes/ldap_casa.h
new file mode 100644
index 0000000..b1dad7f
--- /dev/null
+++ b/includes/ldap_casa.h
@@ -0,0 +1,101 @@
+/* ldap_casa.h
+   
+   Definition for CASA modules... */
+
+/* Copyright (c) 2006 Novell, Inc.
+
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met: 
+ * 1.Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer. 
+ * 2.Redistributions in binary form must reproduce the above copyright notice, 
+ *   this list of conditions and the following disclaimer in the documentation 
+ *   and/or other materials provided with the distribution. 
+ * 3.Neither the name of ISC, ISC DHCP, nor the names of its contributors 
+ *   may be used to endorse or promote products derived from this software 
+ *   without specific prior written permission. 
+
+ * THIS SOFTWARE IS PROVIDED BY INTERNET SYSTEMS CONSORTIUM AND CONTRIBUTORS 
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ISC OR CONTRIBUTORS BE LIABLE 
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+
+ * This file was written by S Kalyanasundaram <skalyanasundaram@novell.com>
+ */
+/*
+ * Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1995-2003 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *   Internet Systems Consortium, Inc.
+ *   950 Charter Street
+ *   Redwood City, CA 94063
+ *   <info@isc.org>
+ *   https://www.isc.org/
+ */
+
+#if defined(LDAP_CASA_AUTH)
+#ifndef __LDAP_CASA_H__
+#define __LDAP_CASA_H__
+
+#include <micasa_mgmd.h>
+
+#define MICASA_LIB     "libmicasa.so.1"
+
+SSCS_TYPEDEF_LIBCALL(int, CASA_GetCredential_T)
+(
+       uint32_t            ssFlags,
+       SSCS_SECRET_ID_T   *appSecretID,
+       SSCS_SECRET_ID_T   *sharedSecretID,
+       uint32_t           *credentialType,
+       void               *credential,
+       SSCS_EXT_T         *ext 
+);
+SSCS_TYPEDEF_LIBCALL(int, CASA_SetCredential_T)
+(
+       uint32_t            ssFlags,
+       SSCS_SECRET_ID_T   *appSecretID,
+       SSCS_SECRET_ID_T   *sharedSecretID,
+       uint32_t            credentialType,
+       void               *credential,
+       SSCS_EXT_T         *ext
+);
+
+SSCS_TYPEDEF_LIBCALL(int, CASA_RemoveCredential_T)
+(
+       uint32_t            ssFlags,
+       SSCS_SECRET_ID_T   *appSecretID,
+       SSCS_SECRET_ID_T   *sharedSecretID,
+       SSCS_EXT_T         *ext
+);
+static CASA_GetCredential_T            p_miCASAGetCredential = NULL;
+static CASA_SetCredential_T            p_miCASASetCredential = NULL;
+static CASA_RemoveCredential_T         p_miCASARemoveCredential = NULL;
+static void                            *casaIDK = NULL;
+
+int load_casa(void);
+static void release_casa(void);
+int load_uname_pwd_from_miCASA(char **, char **);
+
+#endif /* __LDAP_CASA_H__ */
+#endif /* LDAP_CASA_AUTH */
+
diff --git a/server/Makefile.am b/server/Makefile.am
index dc5d4f3..c4c2417 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -15,7 +15,7 @@ dhcpd_SOURCES = dhcpd.c dhcp.c bootp.c confpars.c db.c class.c failover.c \
 dhcpd_CFLAGS = $(LDAP_CFLAGS)
 dhcpd_LDADD = ../common/libdhcp.a ../omapip/libomapi.a \
 	      ../dhcpctl/libdhcpctl.a ../bind/lib/libdns.a \
-	      ../bind/lib/libisc.a
+	      ../bind/lib/libisc.a $(LDAP_LIBS)
 
 man_MANS = dhcpd.8 dhcpd.conf.5 dhcpd.leases.5
 EXTRA_DIST = $(man_MANS)
diff --git a/server/ldap.c b/server/ldap.c
index 8a7d695..6e7f508 100644
--- a/server/ldap.c
+++ b/server/ldap.c
@@ -40,6 +40,10 @@
 #include "dhcpd.h"
 #include <signal.h>
 #include <errno.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <net/if.h>
+#include <ifaddrs.h>
 
 #if defined(LDAP_CONFIGURATION)
 
@@ -57,7 +61,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 (LDAP_USE_SSL)
 static int ldap_use_ssl = -1,        /* try TLS if possible */
            ldap_tls_reqcert = -1,
@@ -80,12 +86,269 @@ typedef struct ldap_dn_node {
 static ldap_dn_node *ldap_service_dn_head = NULL;
 static ldap_dn_node *ldap_service_dn_tail = NULL;
 
+static int ldap_read_function (struct parse *cfile);
+
+static struct parse *
+x_parser_init(const char *name)
+{
+  struct parse *cfile;
+  isc_result_t res;
+  char *inbuf;
+
+  inbuf = dmalloc (LDAP_BUFFER_SIZE, MDL);
+  if (inbuf == NULL)
+    return NULL;
+
+  cfile = (struct parse *) NULL;
+  res = new_parse (&cfile, -1, inbuf, LDAP_BUFFER_SIZE, name, 0);
+  if (res != ISC_R_SUCCESS)
+    {
+      dfree(inbuf, MDL);
+      return NULL;
+    }
+  /* the buffer is still empty */
+  cfile->bufsiz = LDAP_BUFFER_SIZE;
+  cfile->buflen = cfile->bufix = 0;
+  /* attach ldap read function */
+  cfile->read_function = ldap_read_function;
+  return cfile;
+}
+
+static isc_result_t
+x_parser_free(struct parse **cfile)
+{
+  if (cfile && *cfile)
+    {
+      if ((*cfile)->inbuf)
+          dfree((*cfile)->inbuf, MDL);
+      (*cfile)->inbuf = NULL;
+      (*cfile)->bufsiz = 0;
+      return end_parse(cfile);
+    }
+  return ISC_R_SUCCESS;
+}
+
+static int
+x_parser_resize(struct parse *cfile, size_t len)
+{
+  size_t size;
+  char * temp;
+
+  /* grow by len rounded up at LDAP_BUFFER_SIZE */
+  size = cfile->bufsiz + (len | (LDAP_BUFFER_SIZE-1)) + 1;
+
+  /* realloc would be better, but there isn't any */
+  if ((temp = dmalloc (size, MDL)) != NULL)
+    {
+#if defined (DEBUG_LDAP)
+      log_info ("Reallocated %s buffer from %zu to %zu",
+                cfile->tlname, cfile->bufsiz, size);
+#endif
+      memcpy(temp, cfile->inbuf, cfile->bufsiz);
+      dfree(cfile->inbuf, MDL);
+      cfile->inbuf  = temp;
+      cfile->bufsiz = size;
+      return 1;
+    }
+
+  /*
+   * Hmm... what is worser, consider it as fatal error and
+   * bail out completely or discard config data in hope it
+   * is "only" an option in dynamic host lookup?
+   */
+  log_error("Unable to reallocated %s buffer from %zu to %zu",
+            cfile->tlname, cfile->bufsiz, size);
+  return 0;
+}
 
 static char *
-x_strncat(char *dst, const char *src, size_t dst_size)
+x_parser_strcat(struct parse *cfile, const char *str)
+{
+  size_t cur = strlen(cfile->inbuf);
+  size_t len = strlen(str);
+  size_t cnt;
+
+  if (cur + len >= cfile->bufsiz && !x_parser_resize(cfile, len))
+    return NULL;
+
+  cnt = cfile->bufsiz > cur ? cfile->bufsiz - cur - 1 : 0;
+  return strncat(cfile->inbuf, str, cnt);
+}
+
+static inline void
+x_parser_reset(struct parse *cfile)
+{
+  cfile->inbuf[0] = '\0';
+  cfile->bufix = cfile->buflen = 0;
+}
+
+static inline size_t
+x_parser_length(struct parse *cfile)
+{
+  cfile->buflen = strlen(cfile->inbuf);
+  return cfile->buflen;
+}
+
+static char *
+x_strxform(char *dst, const char *src, size_t dst_size,
+           int (*xform)(int))
+{
+  if(dst && src && dst_size)
+    {
+      size_t len, pos;
+
+      len = strlen(src);
+      for(pos=0; pos < len && pos + 1 < dst_size; pos++)
+        dst[pos] = xform((int)src[pos]);
+      dst[pos] = '\0';
+
+      return dst;
+    }
+  return NULL;
+}
+
+static int
+get_host_entry(char *fqdnname, size_t fqdnname_size,
+               char *hostaddr, size_t hostaddr_size)
+{
+#if defined(MAXHOSTNAMELEN)
+  char   hname[MAXHOSTNAMELEN+1];
+#else
+  char   hname[65];
+#endif
+  struct hostent *hp;
+
+  if (NULL == fqdnname || 1 >= fqdnname_size)
+    return -1;
+
+  memset(hname, 0, sizeof(hname));
+  if (gethostname(hname, sizeof(hname)-1))
+    return -1;
+
+  if (NULL == (hp = gethostbyname(hname)))
+    return -1;
+
+  strncpy(fqdnname, hp->h_name, fqdnname_size-1);
+  fqdnname[fqdnname_size-1] = '\0';
+
+  if (hostaddr != NULL)
+    {
+      if (hp->h_addr != NULL)
+        {
+          struct in_addr *aptr = (struct in_addr *)hp->h_addr;
+#if defined(HAVE_INET_NTOP)
+          if (hostaddr_size >= INET_ADDRSTRLEN &&
+              inet_ntop(AF_INET, aptr, hostaddr, hostaddr_size) != NULL)
+            {
+              return 0;
+            }
+#else
+          char  *astr = inet_ntoa(*aptr);
+          size_t alen = strlen(astr);
+          if (astr && alen > 0 && hostaddr_size > alen)
+            {
+              strncpy(hostaddr, astr, hostaddr_size-1);
+              hostaddr[hostaddr_size-1] = '\0';
+              return 0;
+            }
+#endif
+        }
+      return -1;
+    }
+  return 0;
+}
+
+static int
+is_iface_address(struct ifaddrs *addrs, struct in_addr *addr)
 {
-  size_t len = strlen(dst);
-  return strncat(dst, src, dst_size > len ? dst_size - len - 1: 0);
+  struct ifaddrs     *ia;
+  struct sockaddr_in *sa;
+  int                 num = 0;
+
+  if(addrs == NULL || addr == NULL)
+    return -1;
+
+  for (ia = addrs; ia != NULL; ia = ia->ifa_next)
+    {
+      ++num;
+      if (ia->ifa_addr && (ia->ifa_flags & IFF_UP) &&
+          ia->ifa_addr->sa_family == AF_INET)
+      {
+        sa = (struct sockaddr_in *)(ia->ifa_addr);
+        if (addr->s_addr == sa->sin_addr.s_addr)
+          return num;
+      }
+    }
+  return 0;
+}
+
+static int
+get_host_address(const char *hostname, char *hostaddr, size_t hostaddr_size, struct ifaddrs *addrs)
+{
+  if (hostname && *hostname && hostaddr && hostaddr_size)
+    {
+      struct in_addr addr;
+
+#if defined(HAVE_INET_PTON)
+      if (inet_pton(AF_INET, hostname, &addr) == 1)
+#else
+      if (inet_aton(hostname, &addr) != 0)
+#endif
+        {
+          /* it is already IP address string */
+          if(strlen(hostname) < hostaddr_size)
+            {
+              strncpy(hostaddr, hostname, hostaddr_size-1);
+              hostaddr[hostaddr_size-1] = '\0';
+
+              if (addrs != NULL && is_iface_address (addrs, &addr) > 0)
+                return 1;
+              else
+                return 0;
+            }
+        }
+      else
+        {
+          struct hostent *hp;
+          if ((hp = gethostbyname(hostname)) != NULL && hp->h_addr != NULL)
+            {
+              struct in_addr *aptr  = (struct in_addr *)hp->h_addr;
+              int             mret = 0;
+
+              if (addrs != NULL)
+                {
+                  char **h;
+                  for (h=hp->h_addr_list; *h; h++)
+                    {
+                      struct in_addr *haddr = (struct in_addr *)*h;
+                      if (is_iface_address (addrs, haddr) > 0)
+                        {
+                          aptr = haddr;
+                          mret = 1;
+                        }
+                    }
+                }
+
+#if defined(HAVE_INET_NTOP)
+              if (hostaddr_size >= INET_ADDRSTRLEN &&
+                  inet_ntop(AF_INET, aptr, hostaddr, hostaddr_size) != NULL)
+                {
+                  return mret;
+                }
+#else
+              char  *astr = inet_ntoa(*aptr);
+              size_t alen = strlen(astr);
+              if (astr && alen > 0 && alen < hostaddr_size)
+                {
+                  strncpy(hostaddr, astr, hostaddr_size-1);
+                  hostaddr[hostaddr_size-1] = '\0';
+                  return mret;
+                }
+#endif
+            }
+        }
+    }
+  return -1;
 }
 
 static void
@@ -102,19 +365,52 @@ ldap_parse_class (struct ldap_config_stack *item, struct parse *cfile)
       return;
     }
 
-  x_strncat (cfile->inbuf, "class \"", LDAP_BUFFER_SIZE);
-  x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE);
-  x_strncat (cfile->inbuf, "\" {\n", LDAP_BUFFER_SIZE);
+  x_parser_strcat (cfile, "class \"");
+  x_parser_strcat (cfile, tempbv[0]->bv_val);
+  x_parser_strcat (cfile, "\" {\n");
 
   item->close_brace = 1;
   ldap_value_free_len (tempbv);
 }
 
+static int
+is_hex_string(const char *str)
+{
+  int colon = 1;
+  int xdigit = 0;
+  size_t i;
+
+  if (!str)
+    return 0;
+
+  if (*str == '-')
+    str++;
+
+  for (i=0; str[i]; ++i)
+    {
+      if (str[i] == ':')
+        {
+          xdigit = 0;
+          if(++colon > 1)
+            return 0;
+        }
+      else if(isxdigit((unsigned char)str[i]))
+        {
+          colon = 0;
+          if (++xdigit > 2)
+            return 0;
+        }
+      else
+        return 0;
+    }
+  return i > 0 && !colon;
+}
 
 static void
 ldap_parse_subclass (struct ldap_config_stack *item, struct parse *cfile)
 {
   struct berval **tempbv, **classdata;
+  char *tmp;
 
   if ((tempbv = ldap_get_values_len (ld, item->ldent, "cn")) == NULL ||
       tempbv[0] == NULL)
@@ -136,11 +432,22 @@ ldap_parse_subclass (struct ldap_config_stack *item, struct parse *cfile)
       return;
     }
 
-  x_strncat (cfile->inbuf, "subclass ", LDAP_BUFFER_SIZE);
-  x_strncat (cfile->inbuf, classdata[0]->bv_val, LDAP_BUFFER_SIZE);
-  x_strncat (cfile->inbuf, " ", LDAP_BUFFER_SIZE);
-  x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE);
-  x_strncat (cfile->inbuf, " {\n", LDAP_BUFFER_SIZE);
+  x_parser_strcat (cfile, "subclass \"");
+  x_parser_strcat (cfile, classdata[0]->bv_val);
+  if (is_hex_string(tempbv[0]->bv_val))
+    {
+      x_parser_strcat (cfile, "\" ");
+      x_parser_strcat (cfile, tempbv[0]->bv_val);
+      x_parser_strcat (cfile, " {\n");
+    }
+  else
+    {
+      tmp = quotify_string(tempbv[0]->bv_val, MDL);
+      x_parser_strcat (cfile, "\" \"");
+      x_parser_strcat (cfile, tmp);
+      x_parser_strcat (cfile, "\" {\n");
+      dfree(tmp, MDL);
+    }
 
   item->close_brace = 1;
   ldap_value_free_len (tempbv);
@@ -164,14 +471,18 @@ ldap_parse_host (struct ldap_config_stack *item, struct parse *cfile)
 
   hwaddr = ldap_get_values_len (ld, item->ldent, "dhcpHWAddress");
 
-  x_strncat (cfile->inbuf, "host ", LDAP_BUFFER_SIZE);
-  x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE);
+  x_parser_strcat (cfile, "host ");
+  x_parser_strcat (cfile, tempbv[0]->bv_val);
+  x_parser_strcat (cfile, " {\n");
 
-  if (hwaddr != NULL && hwaddr[0] != NULL)
+  if (hwaddr != NULL)
     {
-      x_strncat (cfile->inbuf, " {\nhardware ", LDAP_BUFFER_SIZE);
-      x_strncat (cfile->inbuf, hwaddr[0]->bv_val, LDAP_BUFFER_SIZE);
-      x_strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE);
+      if (hwaddr[0] != NULL)
+        {
+          x_parser_strcat (cfile, "hardware ");
+          x_parser_strcat (cfile, hwaddr[0]->bv_val);
+          x_parser_strcat (cfile, ";\n");
+        }
       ldap_value_free_len (hwaddr);
     }
 
@@ -194,9 +505,9 @@ ldap_parse_shared_network (struct ldap_config_stack *item, struct parse *cfile)
       return;
     }
 
-  x_strncat (cfile->inbuf, "shared-network \"", LDAP_BUFFER_SIZE);
-  x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE);
-  x_strncat (cfile->inbuf, "\" {\n", LDAP_BUFFER_SIZE);
+  x_parser_strcat (cfile, "shared-network \"");
+  x_parser_strcat (cfile, tempbv[0]->bv_val);
+  x_parser_strcat (cfile, "\" {\n");
 
   item->close_brace = 1;
   ldap_value_free_len (tempbv);
@@ -249,14 +560,14 @@ ldap_parse_subnet (struct ldap_config_stack *item, struct parse *cfile)
       return;
     }
 
-  x_strncat (cfile->inbuf, "subnet ", LDAP_BUFFER_SIZE);
-  x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE);
+  x_parser_strcat (cfile, "subnet ");
+  x_parser_strcat (cfile, tempbv[0]->bv_val);
 
-  x_strncat (cfile->inbuf, " netmask ", LDAP_BUFFER_SIZE);
+  x_parser_strcat (cfile, " netmask ");
   parse_netmask (strtol (netmaskstr[0]->bv_val, NULL, 10), netmaskbuf);
-  x_strncat (cfile->inbuf, netmaskbuf, LDAP_BUFFER_SIZE);
+  x_parser_strcat (cfile, netmaskbuf);
 
-  x_strncat (cfile->inbuf, " {\n", LDAP_BUFFER_SIZE);
+  x_parser_strcat (cfile, " {\n");
 
   ldap_value_free_len (tempbv);
   ldap_value_free_len (netmaskstr);
@@ -265,11 +576,12 @@ ldap_parse_subnet (struct ldap_config_stack *item, struct parse *cfile)
     {
       for (i=0; tempbv[i] != NULL; i++)
         {
-          x_strncat (cfile->inbuf, "range", LDAP_BUFFER_SIZE);
-          x_strncat (cfile->inbuf, " ", LDAP_BUFFER_SIZE);
-          x_strncat (cfile->inbuf, tempbv[i]->bv_val, LDAP_BUFFER_SIZE);
-          x_strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE);
+          x_parser_strcat (cfile, "range");
+          x_parser_strcat (cfile, " ");
+          x_parser_strcat (cfile, tempbv[i]->bv_val);
+          x_parser_strcat (cfile, ";\n");
         }
+      ldap_value_free_len (tempbv);
     }
 
   item->close_brace = 1;
@@ -282,17 +594,17 @@ ldap_parse_pool (struct ldap_config_stack *item, struct parse *cfile)
   struct berval **tempbv;
   int i;
 
-  x_strncat (cfile->inbuf, "pool {\n", LDAP_BUFFER_SIZE);
+  x_parser_strcat (cfile, "pool {\n");
 
   if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpRange")) != NULL)
     {
-      x_strncat (cfile->inbuf, "range", LDAP_BUFFER_SIZE);
+      x_parser_strcat (cfile, "range");
       for (i=0; tempbv[i] != NULL; i++)
         {
-          x_strncat (cfile->inbuf, " ", LDAP_BUFFER_SIZE);
-          x_strncat (cfile->inbuf, tempbv[i]->bv_val, LDAP_BUFFER_SIZE);
+          x_parser_strcat (cfile, " ");
+          x_parser_strcat (cfile, tempbv[i]->bv_val);
         }
-      x_strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE);
+      x_parser_strcat (cfile, ";\n");
       ldap_value_free_len (tempbv);
     }
 
@@ -300,8 +612,8 @@ ldap_parse_pool (struct ldap_config_stack *item, struct parse *cfile)
     {
       for (i=0; tempbv[i] != NULL; i++)
         {
-          x_strncat (cfile->inbuf, tempbv[i]->bv_val, LDAP_BUFFER_SIZE);
-          x_strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE);
+          x_parser_strcat (cfile, tempbv[i]->bv_val);
+          x_parser_strcat (cfile, ";\n");
         }
       ldap_value_free_len (tempbv);
     }
@@ -313,7 +625,7 @@ ldap_parse_pool (struct ldap_config_stack *item, struct parse *cfile)
 static void
 ldap_parse_group (struct ldap_config_stack *item, struct parse *cfile)
 {
-  x_strncat (cfile->inbuf, "group {\n", LDAP_BUFFER_SIZE);
+  x_parser_strcat (cfile, "group {\n");
   item->close_brace = 1;
 }
 
@@ -325,25 +637,25 @@ ldap_parse_key (struct ldap_config_stack *item, struct parse *cfile)
 
   if ((tempbv = ldap_get_values_len (ld, item->ldent, "cn")) != NULL)
     {
-      x_strncat (cfile->inbuf, "key ", LDAP_BUFFER_SIZE);
-      x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE);
-      x_strncat (cfile->inbuf, " {\n", LDAP_BUFFER_SIZE);
+      x_parser_strcat (cfile, "key ");
+      x_parser_strcat (cfile, tempbv[0]->bv_val);
+      x_parser_strcat (cfile, " {\n");
       ldap_value_free_len (tempbv);
     }
 
   if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpKeyAlgorithm")) != NULL)
     {
-      x_strncat (cfile->inbuf, "algorithm ", LDAP_BUFFER_SIZE);
-      x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE);
-      x_strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE);
+      x_parser_strcat (cfile, "algorithm ");
+      x_parser_strcat (cfile, tempbv[0]->bv_val);
+      x_parser_strcat (cfile, ";\n");
       ldap_value_free_len (tempbv);
     }
 
   if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpKeySecret")) != NULL)
     {
-      x_strncat (cfile->inbuf, "secret ", LDAP_BUFFER_SIZE);
-      x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE);
-      x_strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE);
+      x_parser_strcat (cfile, "secret ");
+      x_parser_strcat (cfile, tempbv[0]->bv_val);
+      x_parser_strcat (cfile, ";\n");
       ldap_value_free_len (tempbv);
     }
 
@@ -361,18 +673,18 @@ ldap_parse_zone (struct ldap_config_stack *item, struct parse *cfile)
 
   if ((tempbv = ldap_get_values_len (ld, item->ldent, "cn")) != NULL)
     {
-      x_strncat (cfile->inbuf, "zone ", LDAP_BUFFER_SIZE);
-      x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE);
-      x_strncat (cfile->inbuf, " {\n", LDAP_BUFFER_SIZE);
+      x_parser_strcat (cfile, "zone ");
+      x_parser_strcat (cfile, tempbv[0]->bv_val);
+      x_parser_strcat (cfile, " {\n");
       ldap_value_free_len (tempbv);
     }
 
   if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpDnsZoneServer")) != NULL)
     {
-      x_strncat (cfile->inbuf, "primary ", LDAP_BUFFER_SIZE);
-      x_strncat (cfile->inbuf, tempbv[0]->bv_val, LDAP_BUFFER_SIZE);
+      x_parser_strcat (cfile, "primary ");
+      x_parser_strcat (cfile, tempbv[0]->bv_val);
 
-      x_strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE);
+      x_parser_strcat (cfile, ";\n");
       ldap_value_free_len (tempbv);
     }
 
@@ -400,9 +712,9 @@ ldap_parse_zone (struct ldap_config_stack *item, struct parse *cfile)
           strncpy (keyCn, cnFindStart, len);
           keyCn[len] = '\0';
 
-          x_strncat (cfile->inbuf, "key ", LDAP_BUFFER_SIZE);
-          x_strncat (cfile->inbuf, keyCn, LDAP_BUFFER_SIZE);
-          x_strncat (cfile->inbuf, ";\n", LDAP_BUFFER_SIZE);
+          x_parser_strcat (cfile, "key ");
+          x_parser_strcat (cfile, keyCn);
+          x_parser_strcat (cfile, ";\n");
 
           dfree (keyCn, MDL);
         }
@@ -415,6 +727,228 @@ ldap_parse_zone (struct ldap_config_stack *item, struct parse *cfile)
 
 
 static void
+ldap_parse_failover (struct ldap_config_stack *item, struct parse *cfile)
+{
+  struct berval **tempbv, **peername;
+  struct ifaddrs *addrs = NULL;
+  char srvaddr[2][64] = {"\0", "\0"};
+  int primary, split = 0, match;
+  struct utsname unme;
+
+  if ((peername = ldap_get_values_len (ld, item->ldent, "cn")) == NULL ||
+      peername[0] == NULL)
+    {
+      if (peername != NULL)
+        ldap_value_free_len (peername);
+
+      // ldap with disabled schema checks? fail to avoid syntax error.
+      log_error("Unable to find mandatory failover peering name attribute");
+      return;
+    }
+
+  /* Get all interface addresses */
+  getifaddrs(&addrs);
+
+  /*
+  ** when dhcpFailOverPrimaryServer or dhcpFailOverSecondaryServer
+  ** matches one of our IP address, the following valiables are set:
+  ** - primary is 1 when we are primary or 0 when we are secondary
+  ** - srvaddr[0] contains ip address of the primary
+  ** - srvaddr[1] contains ip address of the secondary
+  */
+  primary = -1;
+  if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpFailOverPrimaryServer")) != NULL &&
+      tempbv[0] != NULL)
+    {
+      match = get_host_address (tempbv[0]->bv_val, srvaddr[0], sizeof(srvaddr[0]), addrs);
+      if (match >= 0)
+        {
+          /* we are the primary */
+          if (match > 0)
+            primary = 1;
+        }
+      else
+        {
+          log_info("Can't resolve address of the primary failover '%s' server %s",
+                   peername[0]->bv_val, tempbv[0]->bv_val);
+          ldap_value_free_len (tempbv);
+          ldap_value_free_len (peername);
+          if (addrs)
+            freeifaddrs(addrs);
+          return;
+        }
+    }
+  if (tempbv != NULL)
+    ldap_value_free_len (tempbv);
+
+  if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpFailOverSecondaryServer")) != NULL &&
+      tempbv[0] != NULL)
+    {
+      match = get_host_address (tempbv[0]->bv_val, srvaddr[1], sizeof(srvaddr[1]), addrs);
+      if (match >= 0)
+        {
+          if (match > 0)
+            {
+              if (primary == 1)
+                {
+                  log_info("Both, primary and secondary failover '%s' server"
+                           " attributes match our local address", peername[0]->bv_val);
+                  ldap_value_free_len (tempbv);
+                  ldap_value_free_len (peername);
+                  if (addrs)
+                    freeifaddrs(addrs);
+                  return;
+                }
+
+              /* we are the secondary */
+              primary = 0;
+            }
+        }
+      else
+        {
+          log_info("Can't resolve address of the secondary failover '%s' server %s",
+                   peername[0]->bv_val, tempbv[0]->bv_val);
+          ldap_value_free_len (tempbv);
+          ldap_value_free_len (peername);
+          if (addrs)
+            freeifaddrs(addrs);
+          return;
+        }
+    }
+  if (tempbv != NULL)
+    ldap_value_free_len (tempbv);
+
+
+  if (primary == -1 || srvaddr[0] == '\0' || srvaddr[1] == '\0')
+    {
+      log_error("Could not decide if the server type is primary"
+                " or secondary for failover peering '%s'.", peername[0]->bv_val);
+      ldap_value_free_len (peername);
+      if (addrs)
+        freeifaddrs(addrs);
+      return;
+    }
+
+  x_parser_strcat (cfile, "failover peer \"");
+  x_parser_strcat (cfile, peername[0]->bv_val);
+  x_parser_strcat (cfile, "\" {\n");
+
+  if (primary)
+    x_parser_strcat (cfile, "primary;\n");
+  else
+    x_parser_strcat (cfile, "secondary;\n");
+
+  x_parser_strcat (cfile, "address ");
+  if (primary)
+    x_parser_strcat (cfile, srvaddr[0]);
+  else
+    x_parser_strcat (cfile, srvaddr[1]);
+  x_parser_strcat (cfile, ";\n");
+
+  x_parser_strcat (cfile, "peer address ");
+  if (primary)
+    x_parser_strcat (cfile, srvaddr[1]);
+  else
+    x_parser_strcat (cfile, srvaddr[0]);
+  x_parser_strcat (cfile, ";\n");
+
+  if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpFailOverPrimaryPort")) != NULL &&
+      tempbv[0] != NULL)
+    {
+      if (primary)
+        x_parser_strcat (cfile, "port ");
+      else
+        x_parser_strcat (cfile, "peer port ");
+      x_parser_strcat (cfile, tempbv[0]->bv_val);
+      x_parser_strcat (cfile, ";\n");
+    }
+  if (tempbv != NULL)
+    ldap_value_free_len (tempbv);
+
+  if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpFailOverSecondaryPort")) != NULL &&
+      tempbv[0] != NULL)
+    {
+      if (primary)
+        x_parser_strcat (cfile, "peer port ");
+      else
+        x_parser_strcat (cfile, "port ");
+      x_parser_strcat (cfile, tempbv[0]->bv_val);
+      x_parser_strcat (cfile, ";\n");
+    }
+  if (tempbv != NULL)
+    ldap_value_free_len (tempbv);
+
+  if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpFailOverResponseDelay")) != NULL &&
+      tempbv[0] != NULL)
+    {
+      x_parser_strcat (cfile, "max-response-delay ");
+      x_parser_strcat (cfile, tempbv[0]->bv_val);
+      x_parser_strcat (cfile, ";\n");
+    }
+  if (tempbv != NULL)
+    ldap_value_free_len (tempbv);
+
+  if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpFailOverUnackedUpdates")) != NULL &&
+      tempbv[0] != NULL)
+    {
+      x_parser_strcat (cfile, "max-unacked-updates ");
+      x_parser_strcat (cfile, tempbv[0]->bv_val);
+      x_parser_strcat (cfile, ";\n");
+    }
+  if (tempbv != NULL)
+    ldap_value_free_len (tempbv);
+
+  if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpFailOverLoadBalanceTime")) != NULL &&
+      tempbv[0] != NULL)
+    {
+      x_parser_strcat (cfile, "load balance max seconds ");
+      x_parser_strcat (cfile, tempbv[0]->bv_val);
+      x_parser_strcat (cfile, ";\n");
+    }
+  if (tempbv != NULL)
+    ldap_value_free_len (tempbv);
+
+  tempbv = NULL;
+  if (primary &&
+      (tempbv = ldap_get_values_len (ld, item->ldent, "dhcpMaxClientLeadTime")) != NULL &&
+      tempbv[0] != NULL)
+    {
+      x_parser_strcat (cfile, "mclt ");
+      x_parser_strcat (cfile, tempbv[0]->bv_val);
+      x_parser_strcat (cfile, ";\n");
+    }
+  if (tempbv != NULL)
+    ldap_value_free_len (tempbv);
+
+  tempbv = NULL;
+  if (primary &&
+      (tempbv = ldap_get_values_len (ld, item->ldent, "dhcpFailOverSplit")) != NULL &&
+      tempbv[0] != NULL)
+    {
+      x_parser_strcat (cfile, "split ");
+      x_parser_strcat (cfile, tempbv[0]->bv_val);
+      x_parser_strcat (cfile, ";\n");
+      split = 1;
+    }
+  if (tempbv != NULL)
+    ldap_value_free_len (tempbv);
+
+  tempbv = NULL;
+  if (primary && !split &&
+      (tempbv = ldap_get_values_len (ld, item->ldent, "dhcpFailOverHashBucketAssignment")) != NULL &&
+      tempbv[0] != NULL)
+    {
+      x_parser_strcat (cfile, "hba ");
+      x_parser_strcat (cfile, tempbv[0]->bv_val);
+      x_parser_strcat (cfile, ";\n");
+    }
+  if (tempbv != NULL)
+    ldap_value_free_len (tempbv);
+
+  item->close_brace = 1;
+}
+
+static void
 add_to_config_stack (LDAPMessage * res, LDAPMessage * ent)
 {
   struct ldap_config_stack *ns;
@@ -428,7 +962,6 @@ add_to_config_stack (LDAPMessage * res, LDAPMessage * ent)
   ldap_stack = ns;
 }
 
-
 static void
 ldap_stop()
 {
@@ -570,6 +1103,7 @@ ldap_rebind_cb (LDAP *ld, LDAP_CONST char *url, ber_tag_t request, ber_int_t msg
         {
           log_error ("Error: Cannot init LDAPS session to %s:%d: %s",
                     ldapurl->lud_host, ldapurl->lud_port, ldap_err2string (ret));
+          ldap_free_urldesc(ldapurl);
           return ret;
         }
       else
@@ -585,6 +1119,7 @@ ldap_rebind_cb (LDAP *ld, LDAP_CONST char *url, ber_tag_t request, ber_int_t msg
         {
           log_error ("Error: Cannot start TLS session to %s:%d: %s",
                      ldapurl->lud_host, ldapurl->lud_port, ldap_err2string (ret));
+          ldap_free_urldesc(ldapurl);
           return ret;
         }
       else
@@ -609,9 +1144,40 @@ ldap_rebind_cb (LDAP *ld, LDAP_CONST char *url, ber_tag_t request, ber_int_t msg
       log_error ("Error: Cannot login into ldap server %s:%d: %s",
                  ldapurl->lud_host, ldapurl->lud_port, ldap_err2string (ret));
     }
+  ldap_free_urldesc(ldapurl);
   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 struct berval *
+_do_ldap_str2esc_filter_bv(const char *str, ber_len_t len, struct berval *bv_o)
+{
+  struct berval bv_i;
+
+  if (!str || !bv_o || (ber_str2bv(str, len, 0, &bv_i) == NULL) ||
+     (ldap_bv2escaped_filter_value(&bv_i, bv_o) != 0))
+    return NULL;
+  return bv_o;
+}
+
 static void
 ldap_start (void)
 {
@@ -642,6 +1208,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 (LDAP_USE_SSL)
       ldap_use_ssl = _do_lookup_dhcp_enum_option (options, SV_LDAP_SSL);
@@ -854,7 +1421,13 @@ 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));
@@ -874,8 +1447,14 @@ ldap_start (void)
       creds.bv_val = strdup(ldap_password);
       creds.bv_len = strlen(ldap_password);
 
-      if ((ret = ldap_sasl_bind_s (ld, ldap_username, LDAP_SASL_SIMPLE,
-                                   &creds, NULL, NULL, NULL)) != LDAP_SUCCESS)
+      do
+        {
+          ret = ldap_sasl_bind_s (ld, ldap_username, LDAP_SASL_SIMPLE,
+                                  &creds, NULL, NULL, NULL);
+        }
+      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));
@@ -895,7 +1474,15 @@ parse_external_dns (LDAPMessage * ent)
 {
   char *search[] = {"dhcpOptionsDN", "dhcpSharedNetworkDN", "dhcpSubnetDN",
                     "dhcpGroupDN", "dhcpHostDN", "dhcpClassesDN",
-                    "dhcpPoolDN", NULL};
+                    "dhcpPoolDN", "dhcpZoneDN", "dhcpFailOverPeerDN", NULL};
+
+  /* TODO: dhcpKeyDN can't be added. It is referenced in dhcpDnsZone to
+     retrive the key name (cn). Adding keyDN will reflect adding a key
+     declaration inside the zone configuration.
+
+     dhcpSubClassesDN cant be added. It is also similar to the above.
+     Needs schema change.
+   */
   LDAPMessage * newres, * newent;
   struct berval **tempbv;
   int i, j, ret;
@@ -935,7 +1522,7 @@ parse_external_dns (LDAPMessage * ent)
             }
     
 #if defined (DEBUG_LDAP)
-          log_info ("Adding contents of subtree '%s' to config stack from '%s' reference", tempbv[j], search[i]);
+          log_info ("Adding contents of subtree '%s' to config stack from '%s' reference", tempbv[j]->bv_val, search[i]);
 #endif
           for (newent = ldap_first_entry (ld, newres);
                newent != NULL;
@@ -990,17 +1577,17 @@ next_ldap_entry (struct parse *cfile)
 
   if (ldap_stack != NULL && ldap_stack->close_brace)
     {
-      x_strncat (cfile->inbuf, "}\n", LDAP_BUFFER_SIZE);
+      x_parser_strcat (cfile, "}\n");
       ldap_stack->close_brace = 0;
     }
 
   while (ldap_stack != NULL && 
-         (ldap_stack->ldent == NULL ||
-          (ldap_stack->ldent = ldap_next_entry (ld, ldap_stack->ldent)) == NULL))
+         (ldap_stack->ldent == NULL || ( ldap_stack->processed &&
+          (ldap_stack->ldent = ldap_next_entry (ld, ldap_stack->ldent)) == NULL)))
     {
       if (ldap_stack->close_brace)
         {
-          x_strncat (cfile->inbuf, "}\n", LDAP_BUFFER_SIZE);
+          x_parser_strcat (cfile, "}\n");
           ldap_stack->close_brace = 0;
         }
 
@@ -1011,7 +1598,7 @@ next_ldap_entry (struct parse *cfile)
 
   if (ldap_stack != NULL && ldap_stack->close_brace)
     {
-      x_strncat (cfile->inbuf, "}\n", LDAP_BUFFER_SIZE);
+      x_parser_strcat (cfile, "}\n");
       ldap_stack->close_brace = 0;
     }
 }
@@ -1067,13 +1654,13 @@ check_statement_end (const char *statement)
 
 
 static isc_result_t
-ldap_parse_entry_options (LDAPMessage *ent, char *buffer, size_t size,
+ldap_parse_entry_options (LDAPMessage *ent, struct parse *cfile,
                           int *lease_limit)
 {
   struct berval **tempbv;
   int i;
 
-  if (ent == NULL || buffer == NULL || size == 0)
+  if (ent == NULL || cfile == NULL)
     return (ISC_R_FAILURE);
 
   if ((tempbv = ldap_get_values_len (ld, ent, "dhcpStatements")) != NULL)
@@ -1087,16 +1674,16 @@ ldap_parse_entry_options (LDAPMessage *ent, char *buffer, size_t size,
               continue;
             }
 
-          x_strncat (buffer, tempbv[i]->bv_val, size);
+          x_parser_strcat (cfile, tempbv[i]->bv_val);
 
           switch((int) check_statement_end (tempbv[i]->bv_val))
             {
               case '}':
               case ';':
-                x_strncat (buffer, "\n", size);
+                x_parser_strcat (cfile, "\n");
                 break;
               default:
-                x_strncat (buffer, ";\n", size);
+                x_parser_strcat (cfile, ";\n");
                 break;
             }
         }
@@ -1107,15 +1694,15 @@ ldap_parse_entry_options (LDAPMessage *ent, char *buffer, size_t size,
     {
       for (i=0; tempbv[i] != NULL; i++)
         {
-          x_strncat (buffer, "option ", size);
-          x_strncat (buffer, tempbv[i]->bv_val, size);
+          x_parser_strcat (cfile, "option ");
+          x_parser_strcat (cfile, tempbv[i]->bv_val);
           switch ((int) check_statement_end (tempbv[i]->bv_val))
             {
               case ';':
-                x_strncat (buffer, "\n", size);
+                x_parser_strcat (cfile, "\n");
                 break;
               default:
-                x_strncat (buffer, ";\n", size);
+                x_parser_strcat (cfile, ";\n");
                 break;
             }
         }
@@ -1132,9 +1719,10 @@ ldap_generate_config_string (struct parse *cfile)
   struct berval **objectClass;
   char *dn;
   struct ldap_config_stack *entry;
-  LDAPMessage * ent, * res;
+  LDAPMessage * ent, * res, *entfirst, *resfirst;
   int i, ignore, found;
-  int ret;
+  int ret, parsedn = 1;
+  size_t len = cfile->buflen;
 
   if (ld == NULL)
     ldap_start ();
@@ -1145,7 +1733,8 @@ ldap_generate_config_string (struct parse *cfile)
   if ((objectClass = ldap_get_values_len (ld, entry->ldent, 
                                       "objectClass")) == NULL)
     return;
-    
+
+  entry->processed = 1;
   ignore = 0;
   found = 1;
   for (i=0; objectClass[i] != NULL; i++)
@@ -1164,6 +1753,8 @@ ldap_generate_config_string (struct parse *cfile)
         ldap_parse_key (entry, cfile);
       else if (strcasecmp (objectClass[i]->bv_val, "dhcpDnsZone") == 0)
         ldap_parse_zone (entry, cfile);
+      else if (strcasecmp (objectClass[i]->bv_val, "dhcpFailOverPeer") == 0)
+        ldap_parse_failover (entry, cfile);
       else if (strcasecmp (objectClass[i]->bv_val, "dhcpHost") == 0)
         {
           if (ldap_method == LDAP_METHOD_STATIC)
@@ -1187,7 +1778,7 @@ ldap_generate_config_string (struct parse *cfile)
       else
         found = 0;
 
-      if (found && cfile->inbuf[0] == '\0')
+      if (found && x_parser_length(cfile) <= len)
         {
           ignore = 1;
           break;
@@ -1202,23 +1793,36 @@ ldap_generate_config_string (struct parse *cfile)
       return;
     }
 
-  ldap_parse_entry_options(entry->ldent, cfile->inbuf,
-                           LDAP_BUFFER_SIZE-1, NULL);
+  ldap_parse_entry_options(entry->ldent, cfile, NULL);
 
   dn = ldap_get_dn (ld, entry->ldent);
-
+  if (dn == NULL)
+    {
+      ldap_stop();
+      return;
+    }
 #if defined(DEBUG_LDAP)
-  if (dn != NULL)
-    log_info ("Found LDAP entry '%s'", dn);
+  log_info ("Found LDAP entry '%s'", dn);
 #endif
 
-  if (dn == NULL ||
-      (ret = ldap_search_ext_s (ld, dn, LDAP_SCOPE_ONELEVEL,
-                                "objectClass=*", NULL, 0, NULL, NULL,
+  if ((ret = ldap_search_ext_s (ld, dn, LDAP_SCOPE_ONELEVEL,
+                                "(!(|(|(objectClass=dhcpTSigKey)(objectClass=dhcpClass)) (objectClass=dhcpFailOverPeer)))",
+                                NULL, 0, NULL, NULL,
                                 NULL, 0, &res)) != LDAP_SUCCESS)
     {
-      if (dn)
-        ldap_memfree (dn);
+      ldap_memfree (dn);
+
+      ldap_stop();
+      return;
+    }
+
+  if ((ret = ldap_search_ext_s (ld, dn, LDAP_SCOPE_ONELEVEL,
+                                "(|(|(objectClass=dhcpTSigKey)(objectClass=dhcpClass)) (objectClass=dhcpFailOverPeer))",
+                                NULL, 0, NULL, NULL,
+                                NULL, 0, &resfirst)) != LDAP_SUCCESS)
+    {
+      ldap_memfree (dn);
+      ldap_msgfree (res);
 
       ldap_stop();
       return;
@@ -1226,17 +1830,33 @@ ldap_generate_config_string (struct parse *cfile)
 
   ldap_memfree (dn);
 
-  if ((ent = ldap_first_entry (ld, res)) != NULL)
+  ent = ldap_first_entry(ld, res);
+  entfirst = ldap_first_entry(ld, resfirst);
+
+  if (ent == NULL && entfirst == NULL)
+    {
+      parse_external_dns (entry->ldent);
+      next_ldap_entry (cfile);
+    }
+
+  if (ent != NULL)
     {
       add_to_config_stack (res, ent);
       parse_external_dns (entry->ldent);
+      parsedn = 0;
     }
   else
+    ldap_msgfree (res);
+
+  if (entfirst != NULL)
     {
-      ldap_msgfree (res);
-      parse_external_dns (entry->ldent);
-      next_ldap_entry (cfile);
+      add_to_config_stack (resfirst, entfirst);
+      if(parsedn)
+        parse_external_dns (entry->ldent);
+
     }
+  else
+    ldap_msgfree (resfirst);
 }
 
 
@@ -1269,25 +1889,30 @@ ldap_write_debug (const void *buff, size_t size)
 static int
 ldap_read_function (struct parse *cfile)
 {
-  cfile->inbuf[0] = '\0';
-  cfile->buflen = 0;
- 
-  while (ldap_stack != NULL && *cfile->inbuf == '\0')
+  size_t len;
+
+  /* append when in saved state */
+  if (cfile->saved_state == NULL)
+    {
+      cfile->inbuf[0] = '\0';
+      cfile->bufix = 0;
+      cfile->buflen = 0;
+    }
+  len = cfile->buflen;
+
+  while (ldap_stack != NULL && x_parser_length(cfile) <= len)
     ldap_generate_config_string (cfile);
 
-  if (ldap_stack == NULL && *cfile->inbuf == '\0')
+  if (x_parser_length(cfile) <= len && ldap_stack == NULL)
     return (EOF);
 
-  cfile->bufix = 1;
-  cfile->buflen = strlen (cfile->inbuf) - 1;
-  if (cfile->buflen > 0)
-    ldap_write_debug (cfile->inbuf, cfile->buflen);
-
+  if (cfile->buflen > len)
+    ldap_write_debug (cfile->inbuf + len, cfile->buflen - len);
 #if defined (DEBUG_LDAP)
-  log_info ("Sending config line '%s'", cfile->inbuf);
+  log_info ("Sending config portion '%s'", cfile->inbuf + len);
 #endif
 
-  return (cfile->inbuf[0]);
+  return (cfile->inbuf[cfile->bufix++]);
 }
 
 
@@ -1322,38 +1947,12 @@ ldap_get_host_name (LDAPMessage * ent)
 }
 
 
-static int
-getfqhostname(char *fqhost, size_t size)
-{
-#if defined(MAXHOSTNAMELEN)
-  char   hname[MAXHOSTNAMELEN];
-#else
-  char   hname[65];
-#endif
-  struct hostent *hp;
-
-  if(NULL == fqhost || 1 >= size)
-    return -1;
-
-  memset(hname, 0, sizeof(hname));
-  if( gethostname(hname, sizeof(hname)-1))
-    return -1;
-
-  if(NULL == (hp = gethostbyname(hname)))
-    return -1;
-
-  strncpy(fqhost, hp->h_name, size-1);
-  fqhost[size-1] = '\0';
-  return 0;
-}
-
-
 isc_result_t
 ldap_read_config (void)
 {
   LDAPMessage * ldres, * hostres, * ent, * hostent;
   char hfilter[1024], sfilter[1024], fqdn[257];
-  char *buffer, *hostdn;
+  char *hostdn;
   ldap_dn_node *curr = NULL;
   struct parse *cfile;
   struct utsname unme;
@@ -1361,52 +1960,95 @@ ldap_read_config (void)
   size_t length;
   int ret, cnt;
   struct berval **tempbv = NULL;
+  struct berval bv_o[2];
 
+  if (local_family != AF_INET)
+    return (ISC_R_SUCCESS);
+
+  cfile = x_parser_init("LDAP");
+  if (cfile == NULL)
+    return (ISC_R_NOMEMORY);
+
+  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);
- 
-  buffer = dmalloc (LDAP_BUFFER_SIZE+1, MDL);
-  if (buffer == NULL)
-    return (ISC_R_FAILURE);
+    {
+      x_parser_free(&cfile);
+      return (ldap_server == NULL ? ISC_R_SUCCESS : ISC_R_FAILURE);
+    }
 
-  cfile = (struct parse *) NULL;
-  res = new_parse (&cfile, -1, buffer, LDAP_BUFFER_SIZE, "LDAP", 0);
-  if (res != ISC_R_SUCCESS)
-    return (res);
- 
   uname (&unme);
   if (ldap_dhcp_server_cn != NULL)
     {
+      if (_do_ldap_str2esc_filter_bv(ldap_dhcp_server_cn, 0, &bv_o[0]) == NULL)
+        {
+          log_error ("Cannot escape ldap filter value %s: %m", ldap_dhcp_server_cn);
+          x_parser_free(&cfile);
+          return (ISC_R_FAILURE);
+        }
+
      snprintf (hfilter, sizeof (hfilter),
-                "(&(objectClass=dhcpServer)(cn=%s))", ldap_dhcp_server_cn);
+                "(&(objectClass=dhcpServer)(cn=%s))", bv_o[0].bv_val);
+
+     ber_memfree(bv_o[0].bv_val);
     }
   else
-  {
-  if(0 == getfqhostname(fqdn, sizeof(fqdn)))
     {
-      snprintf (hfilter, sizeof (hfilter),
-                "(&(objectClass=dhcpServer)(|(cn=%s)(cn=%s)))", 
-                unme.nodename, fqdn);
+      if (_do_ldap_str2esc_filter_bv(unme.nodename, 0, &bv_o[0]) == NULL)
+        {
+          log_error ("Cannot escape ldap filter value %s: %m", unme.nodename);
+          x_parser_free(&cfile);
+          return (ISC_R_FAILURE);
+        }
+
+      if(0 == get_host_entry(fqdn, sizeof(fqdn), NULL, 0))
+        {
+          if (_do_ldap_str2esc_filter_bv(fqdn, 0, &bv_o[1]) == NULL)
+            {
+              log_error ("Cannot escape ldap filter value %s: %m", fqdn);
+              ber_memfree(bv_o[0].bv_val);
+              x_parser_free(&cfile);
+              return (ISC_R_FAILURE);
+            }
+
+          snprintf (hfilter, sizeof (hfilter),
+                    "(&(objectClass=dhcpServer)(|(cn=%s)(cn=%s)))", 
+                    bv_o[0].bv_val, bv_o[1].bv_val);
+
+          ber_memfree(bv_o[1].bv_val);
+        }
+      else
+        {
+          snprintf (hfilter, sizeof (hfilter),
+                    "(&(objectClass=dhcpServer)(cn=%s))",
+                    bv_o[0].bv_val);
+        }
+
+      ber_memfree(bv_o[0].bv_val);
     }
-  else
+
+  ldap_enable_retry = 1;
+  do
     {
-      snprintf (hfilter, sizeof (hfilter),
-                "(&(objectClass=dhcpServer)(cn=%s))", unme.nodename);
+      hostres = NULL;
+      ret = ldap_search_ext_s (ld, ldap_base_dn, LDAP_SCOPE_SUBTREE,
+                                hfilter, NULL, 0, NULL, NULL, NULL, 0,
+                                &hostres);
     }
+  while(_do_ldap_retry(ret, ldap_server, ldap_port) > 0);
+  ldap_enable_retry = 0;
 
-  }
-  hostres = NULL;
-  if ((ret = ldap_search_ext_s (ld, ldap_base_dn, LDAP_SCOPE_SUBTREE,
-                                hfilter, NULL, 0, NULL, NULL, NULL, 0,
-                                &hostres)) != LDAP_SUCCESS)
+  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);
+                 ((ldap_dhcp_server_cn == NULL)?(unme.nodename):(ldap_dhcp_server_cn)), hfilter);
       if(NULL != hostres)
         ldap_msgfree (hostres);
       ldap_stop();
+      x_parser_free(&cfile);
       return (ISC_R_FAILURE);
     }
 
@@ -1415,6 +2057,7 @@ ldap_read_config (void)
       log_error ("Error: Cannot find LDAP entry matching %s", hfilter);
       ldap_msgfree (hostres);
       ldap_stop();
+      x_parser_free(&cfile);
       return (ISC_R_FAILURE);
     }
 
@@ -1428,7 +2071,9 @@ ldap_read_config (void)
       (tempbv = ldap_get_values_len (ld, hostent, "dhcpServiceDN")) == NULL ||
       tempbv[0] == NULL)
     {
-      log_error ("Error: Cannot find LDAP entry matching %s", hfilter);
+      log_error ("Error: No dhcp service is associated with the server %s %s",
+                 (hostdn ? "dn" : "name"), (hostdn ? hostdn :
+                 (ldap_dhcp_server_cn ? ldap_dhcp_server_cn : unme.nodename)));
 
       if (tempbv != NULL)
         ldap_value_free_len (tempbv);
@@ -1437,6 +2082,7 @@ ldap_read_config (void)
         ldap_memfree (hostdn);
       ldap_msgfree (hostres);
       ldap_stop();
+      x_parser_free(&cfile);
       return (ISC_R_FAILURE);
     }
 
@@ -1444,37 +2090,51 @@ ldap_read_config (void)
   log_info ("LDAP: Parsing dhcpServer options '%s' ...", hostdn);
 #endif
 
-  cfile->inbuf[0] = '\0';
-  ldap_parse_entry_options(hostent, cfile->inbuf, LDAP_BUFFER_SIZE, NULL);
-  cfile->buflen = strlen (cfile->inbuf);
-  if(cfile->buflen > 0)
+  res = ldap_parse_entry_options(hostent, cfile, NULL);
+  if (res != ISC_R_SUCCESS)
     {
-      ldap_write_debug (cfile->inbuf, cfile->buflen);
+      ldap_value_free_len (tempbv);
+      ldap_msgfree (hostres);
+      ldap_memfree (hostdn);
+      ldap_stop();
+      x_parser_free(&cfile);
+      return res;
+    }
 
+  if (x_parser_length(cfile) > 0)
+    {
       res = conf_file_subparse (cfile, root_group, ROOT_GROUP);
       if (res != ISC_R_SUCCESS)
         {
           log_error ("LDAP: cannot parse dhcpServer entry '%s'", hostdn);
+          ldap_value_free_len (tempbv);
+          ldap_msgfree (hostres);
           ldap_memfree (hostdn);
           ldap_stop();
+          x_parser_free(&cfile);
           return res;
         }
-      cfile->inbuf[0] = '\0';
+      x_parser_reset(cfile);
     }
   ldap_msgfree (hostres);
 
-  /*
-  ** attach ldap (tree) read function now
-  */
-  cfile->bufix = cfile->buflen = 0;
-  cfile->read_function = ldap_read_function;
-
   res = ISC_R_SUCCESS;
   for (cnt=0; tempbv[cnt] != NULL; cnt++)
     {
+
+      if (_do_ldap_str2esc_filter_bv(hostdn, 0, &bv_o[0]) == NULL)
+        {
+          log_error ("Cannot escape ldap filter value %s: %m", hostdn);
+          res = ISC_R_FAILURE;
+          break;
+        }
+
       snprintf(sfilter, sizeof(sfilter), "(&(objectClass=dhcpService)"
-                        "(|(dhcpPrimaryDN=%s)(dhcpSecondaryDN=%s)))",
-                        hostdn, hostdn);
+                        "(|(|(dhcpPrimaryDN=%s)(dhcpSecondaryDN=%s))(dhcpServerDN=%s)))",
+                        bv_o[0].bv_val, bv_o[0].bv_val, bv_o[0].bv_val);
+
+      ber_memfree(bv_o[0].bv_val);
+
       ldres = NULL;
       if ((ret = ldap_search_ext_s (ld, tempbv[cnt]->bv_val, LDAP_SCOPE_BASE,
                                     sfilter, NULL, 0, NULL, NULL, NULL,
@@ -1490,7 +2150,7 @@ ldap_read_config (void)
 
       if ((ent = ldap_first_entry (ld, ldres)) == NULL)
         {
-          log_error ("Error: Cannot find dhcpService DN '%s' with primary or secondary server reference. Please update the LDAP server entry '%s'",
+          log_error ("Error: Cannot find dhcpService DN '%s' with server reference. Please update the LDAP server entry '%s'",
                      tempbv[cnt]->bv_val, hostdn);
 
           ldap_msgfree(ldres);
@@ -1534,7 +2194,7 @@ ldap_read_config (void)
         log_fatal ("no memory to remember ldap service dn");
 
 #if defined (DEBUG_LDAP)
-      log_info ("LDAP: Parsing dhcpService DN '%s' ...", tempbv[cnt]);
+      log_info ("LDAP: Parsing dhcpService DN '%s' ...", tempbv[cnt]->bv_val);
 #endif
       add_to_config_stack (ldres, ent);
       res = conf_file_subparse (cfile, root_group, ROOT_GROUP);
@@ -1545,7 +2205,7 @@ ldap_read_config (void)
         }
     }
 
-  end_parse (&cfile);
+  x_parser_free(&cfile);
   ldap_close_debug_fd();
 
   ldap_memfree (hostdn);
@@ -1593,17 +2253,18 @@ ldap_parse_options (LDAPMessage * ent, struct group *group,
                          struct class **class)
 {
   int declaration, lease_limit;
-  char option_buffer[8192];
   enum dhcp_token token;
   struct parse *cfile;
   isc_result_t res;
   const char *val;
 
   lease_limit = 0;
-  *option_buffer = '\0';
- 
- /* This block of code will try to find the parent of the host, and
-    if it is a group object, fetch the options and apply to the host. */
+  cfile = x_parser_init(type == HOST_DECL ? "LDAP-HOST" : "LDAP-SUBCLASS");
+  if (cfile == NULL)
+    return (lease_limit);
+
+  /* This block of code will try to find the parent of the host, and
+     if it is a group object, fetch the options and apply to the host. */
   if (type == HOST_DECL) 
     {
       char *hostdn, *basedn, *temp1, *temp2, filter[1024];
@@ -1625,16 +2286,29 @@ ldap_parse_options (LDAPMessage * ent, struct group *group,
 
           if (temp2 != NULL)
             {
-              snprintf (filter, sizeof(filter),
-                        "(&(cn=%.*s)(objectClass=dhcpGroup))",
-                        (int)(temp2 - temp1), temp1);
+              struct berval bv_o;
+
+              if (_do_ldap_str2esc_filter_bv(temp1, (temp2 - temp1), &bv_o) == NULL)
+                {
+                  log_error ("Cannot escape ldap filter value %.*s: %m",
+                              (int)(temp2 - temp1), temp1);
+                  filter[0] = '\0';
+                }
+              else
+                {
+                  snprintf (filter, sizeof(filter),
+                            "(&(cn=%s)(objectClass=dhcpGroup))",
+                            bv_o.bv_val);
+
+                  ber_memfree(bv_o.bv_val); 
+                }
 
               basedn = strchr (temp1, ',');
               if (basedn != NULL)
                 ++basedn;
             }
 
-          if (basedn != NULL && *basedn != '\0')
+          if (basedn != NULL && *basedn != '\0' && filter[0] != '\0')
             {
               ret = ldap_search_ext_s (ld, basedn, LDAP_SCOPE_SUBTREE, filter,
                                        NULL, 0, NULL, NULL, NULL, 0, &groupdn);
@@ -1642,13 +2316,11 @@ ldap_parse_options (LDAPMessage * ent, struct group *group,
                 {
                   if ((entry = ldap_first_entry (ld, groupdn)) != NULL)
                     {
-                      res = ldap_parse_entry_options (entry, option_buffer,
-                                                      sizeof(option_buffer) - 1,
-                                                      &lease_limit);
+                      res = ldap_parse_entry_options (entry, cfile, &lease_limit);
                       if (res != ISC_R_SUCCESS)
                         {
                           /* reset option buffer discarding any results */
-                          *option_buffer = '\0';
+                          x_parser_reset(cfile);
                           lease_limit = 0;
                         }
                     }
@@ -1659,24 +2331,18 @@ ldap_parse_options (LDAPMessage * ent, struct group *group,
         }
     }
 
-  res = ldap_parse_entry_options (ent, option_buffer, sizeof(option_buffer) - 1,
-                                  &lease_limit);
-  if (res != ISC_R_SUCCESS)
-    return (lease_limit);
-
-  option_buffer[sizeof(option_buffer) - 1] = '\0';
-  if (*option_buffer == '\0')
-    return (lease_limit);
-
-  cfile = (struct parse *) NULL;
-  res = new_parse (&cfile, -1, option_buffer, strlen (option_buffer), 
-                   type == HOST_DECL ? "LDAP-HOST" : "LDAP-SUBCLASS", 0);
+  res = ldap_parse_entry_options (ent, cfile, &lease_limit);
   if (res != ISC_R_SUCCESS)
-    return (lease_limit);
+    {
+      x_parser_free(&cfile);
+      return (lease_limit);
+    }
 
-#if defined (DEBUG_LDAP)
-  log_info ("Sending the following options: '%s'", option_buffer);
-#endif
+  if (x_parser_length(cfile) == 0)
+    {
+      x_parser_free(&cfile);
+      return (lease_limit);
+    }
 
   declaration = 0;
   do
@@ -1687,7 +2353,7 @@ ldap_parse_options (LDAPMessage * ent, struct group *group,
        declaration = parse_statement (cfile, group, type, host, declaration);
     } while (1);
 
-  end_parse (&cfile);
+  x_parser_free(&cfile);
 
   return (lease_limit);
 }
@@ -1703,7 +2369,14 @@ find_haddr_in_ldap (struct host_decl **hp, int htype, unsigned hlen,
   struct host_decl * host;
   isc_result_t status;
   ldap_dn_node *curr;
+  char up_hwaddr[20];
+  char lo_hwaddr[20];
   int ret;
+  struct berval bv_o[2];
+
+
+  if (local_family != AF_INET)
+    return (0);
 
   if (ldap_method == LDAP_METHOD_STATIC)
     return (0);
@@ -1733,9 +2406,28 @@ find_haddr_in_ldap (struct host_decl **hp, int htype, unsigned hlen,
   ** FIXME: It is not guaranteed, that the dhcpHWAddress attribute
   **        contains _exactly_ "type addr" with one space between!
   */
+  snprintf(lo_hwaddr, sizeof(lo_hwaddr), "%s",
+           print_hw_addr (htype, hlen, haddr));
+  x_strxform(up_hwaddr, lo_hwaddr, sizeof(up_hwaddr), toupper);
+
+  if (_do_ldap_str2esc_filter_bv(lo_hwaddr, 0, &bv_o[0]) == NULL)
+    {
+      log_error ("Cannot escape ldap filter value %s: %m", lo_hwaddr);
+      return (0);
+    }
+  if (_do_ldap_str2esc_filter_bv(up_hwaddr, 0, &bv_o[1]) == NULL)
+    {
+      log_error ("Cannot escape ldap filter value %s: %m", up_hwaddr);
+      ber_memfree(bv_o[0].bv_val);
+      return (0);
+    }
+
   snprintf (buf, sizeof (buf),
-            "(&(objectClass=dhcpHost)(dhcpHWAddress=%s %s))",
-           type_str, print_hw_addr (htype, hlen, haddr));
+            "(&(objectClass=dhcpHost)(|(dhcpHWAddress=%s %s)(dhcpHWAddress=%s %s)))",
+            type_str, bv_o[0].bv_val, type_str, bv_o[1].bv_val);
+
+  ber_memfree(bv_o[0].bv_val);
+  ber_memfree(bv_o[1].bv_val);
 
   res = ent = NULL;
   for (curr = ldap_service_dn_head;
@@ -1862,7 +2554,13 @@ find_subclass_in_ldap (struct class *class, struct class **newclass,
   int ret, lease_limit;
   isc_result_t status;
   ldap_dn_node *curr;
-  char buf[1024];
+  char buf[2048];
+  struct berval bv_class;
+  struct berval bv_cdata;
+  char *hex_1;
+
+  if (local_family != AF_INET)
+    return (0);
 
   if (ldap_method == LDAP_METHOD_STATIC)
     return (0);
@@ -1872,10 +2570,33 @@ find_subclass_in_ldap (struct class *class, struct class **newclass,
   if (ld == NULL)
     return (0);
 
+  hex_1 = print_hex_1 (data->len, data->data, 1024);
+  if (*hex_1 == '"')
+    {
+      /* result is a quotted not hex string: ldap escape the original string */
+      if (_do_ldap_str2esc_filter_bv(data->data, data->len, &bv_cdata) == NULL)
+        {
+          log_error ("Cannot escape ldap filter value %s: %m", hex_1);
+          return (0);
+        }
+        hex_1 = NULL;
+    }
+  if (_do_ldap_str2esc_filter_bv(class->name, strlen (class->name), &bv_class) == NULL)
+    {
+      log_error ("Cannot escape ldap filter value %s: %m", class->name);
+      if (hex_1 == NULL)
+        ber_memfree(bv_cdata.bv_val);
+      return (0);
+    }
+
   snprintf (buf, sizeof (buf),
             "(&(objectClass=dhcpSubClass)(cn=%s)(dhcpClassData=%s))",
-            print_hex_1 (data->len, data->data, 60),
-            print_hex_2 (strlen (class->name), (u_int8_t *) class->name, 60));
+            (hex_1 == NULL ? bv_cdata.bv_val : hex_1), bv_class.bv_val);
+
+  if (hex_1 == NULL)
+    ber_memfree(bv_cdata.bv_val);
+  ber_memfree(bv_class.bv_val);
+
 #if defined (DEBUG_LDAP)
   log_info ("Searching LDAP for %s", buf);
 #endif
diff --git a/server/ldap_casa.c b/server/ldap_casa.c
index 952d9b9..cd10157 100644
--- a/server/ldap_casa.c
+++ b/server/ldap_casa.c
@@ -55,8 +55,10 @@
  */
 
 #if defined(LDAP_CASA_AUTH)
-#include "ldap_casa.h"
 #include "dhcpd.h"
+#include "ldap_casa.h"
+#include <dlfcn.h>
+#include <string.h>
 
 int
 load_casa (void)
diff --git a/server/stables.c b/server/stables.c
index da25764..cf85334 100644
--- a/server/stables.c
+++ b/server/stables.c
@@ -259,6 +259,7 @@ static struct option server_options[] = {
 	{ "ldap-tls-ciphers", "t",		&server_universe,  76, 1 },
 	{ "ldap-tls-randfile", "t",		&server_universe,  77, 1 },
 #endif /* LDAP_USE_SSL */
+	{ "ldap-init-retry", "d",		&server_universe,  78, 1 },
 #endif /* LDAP_CONFIGURATION */
 	{ NULL, NULL, NULL, 0, 0 }
 };
-- 
1.8.4