Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12-SP1:GA
dhcp.1901
0007-dhcp-4.2.6-ldap-mt01.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 0007-dhcp-4.2.6-ldap-mt01.patch of Package dhcp.1901
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
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor