diff options
Diffstat (limited to 'server/ldap.c')
-rw-r--r-- | server/ldap.c | 1679 |
1 files changed, 1409 insertions, 270 deletions
diff --git a/server/ldap.c b/server/ldap.c index 2994106a..b5f0bc0d 100644 --- a/server/ldap.c +++ b/server/ldap.c @@ -40,6 +40,11 @@ #include "dhcpd.h" #include <signal.h> #include <errno.h> +#include <ctype.h> +#include <netdb.h> +#include <net/if.h> +#include <ifaddrs.h> +#include <string.h> #if defined(LDAP_CONFIGURATION) @@ -47,6 +52,11 @@ #include "ldap_casa.h" #endif +#if defined(LDAP_USE_GSSAPI) +#include <sasl/sasl.h> +#include "ldap_krb_helper.h" +#endif + static LDAP * ld = NULL; static char *ldap_server = NULL, *ldap_username = NULL, @@ -57,7 +67,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, @@ -69,6 +81,25 @@ static char *ldap_tls_ca_file = NULL, *ldap_tls_ciphers = NULL, *ldap_tls_randfile = NULL; #endif + +#if defined (LDAP_USE_GSSAPI) +static char *ldap_gssapi_keytab = NULL, + *ldap_gssapi_principal = NULL; + +struct ldap_sasl_instance { + char *sasl_mech; + char *sasl_realm; + char *sasl_authz_id; + char *sasl_authc_id; + char *sasl_password; +}; + +static struct ldap_sasl_instance *ldap_sasl_inst = NULL; + +static int +_ldap_sasl_interact(LDAP *ld, unsigned flags, void *defaults, void *sin) ; +#endif + static struct ldap_config_stack *ldap_stack = NULL; typedef struct ldap_dn_node { @@ -80,12 +111,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 +390,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 +457,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 +496,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 +530,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 +585,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,16 +601,63 @@ 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; } +static void +ldap_parse_subnet6 (struct ldap_config_stack *item, struct parse *cfile) +{ + struct berval **tempbv; + int i; + + if ((tempbv = ldap_get_values_len (ld, item->ldent, "cn")) == NULL || + tempbv[0] == NULL) + { + if (tempbv != NULL) + ldap_value_free_len (tempbv); + + return; + } + + x_parser_strcat (cfile, "subnet6 "); + 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, "dhcpRange")) != NULL) + { + for (i=0; tempbv[i] != NULL; i++) + { + x_parser_strcat (cfile, "range6"); + x_parser_strcat (cfile, " "); + x_parser_strcat (cfile, tempbv[i]->bv_val); + x_parser_strcat (cfile, ";\n"); + } + ldap_value_free_len (tempbv); + } + + if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpPermitList")) != NULL) + { + for (i=0; tempbv[i] != NULL; i++) + { + x_parser_strcat (cfile, tempbv[i]->bv_val); + x_parser_strcat (cfile, ";\n"); + } + ldap_value_free_len (tempbv); + } + + item->close_brace = 1; +} static void ldap_parse_pool (struct ldap_config_stack *item, struct parse *cfile) @@ -282,17 +665,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 +683,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); } @@ -309,11 +692,43 @@ ldap_parse_pool (struct ldap_config_stack *item, struct parse *cfile) item->close_brace = 1; } +static void +ldap_parse_pool6 (struct ldap_config_stack *item, struct parse *cfile) +{ + struct berval **tempbv; + int i; + + x_parser_strcat (cfile, "pool {\n"); + + if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpRange")) != NULL) + { + x_parser_strcat (cfile, "range6"); + for (i=0; tempbv[i] != NULL; i++) + { + x_parser_strcat (cfile, " "); + x_parser_strcat (cfile, tempbv[i]->bv_val); + } + x_parser_strcat (cfile, ";\n"); + ldap_value_free_len (tempbv); + } + + if ((tempbv = ldap_get_values_len (ld, item->ldent, "dhcpPermitList")) != NULL) + { + for (i=0; tempbv[i] != NULL; i++) + { + x_parser_strcat(cfile, tempbv[i]->bv_val); + x_parser_strcat (cfile, ";\n"); + } + ldap_value_free_len (tempbv); + } + + item->close_brace = 1; +} 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 +740,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 +776,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 +815,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 +830,227 @@ 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; + + 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 +1064,6 @@ add_to_config_stack (LDAPMessage * res, LDAPMessage * ent) ldap_stack = ns; } - static void ldap_stop() { @@ -570,6 +1205,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 +1221,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 @@ -595,21 +1232,80 @@ ldap_rebind_cb (LDAP *ld, LDAP_CONST char *url, ber_tag_t request, ber_int_t msg } #endif +#if defined(LDAP_USE_GSSAPI) + if (ldap_gssapi_principal != NULL) { + krb5_get_tgt(ldap_gssapi_principal, ldap_gssapi_keytab); + if ((ret = ldap_sasl_interactive_bind_s(ld, NULL, ldap_sasl_inst->sasl_mech, + NULL, NULL, LDAP_SASL_AUTOMATIC, + _ldap_sasl_interact, ldap_sasl_inst) + ) != LDAP_SUCCESS) + { + log_error ("Error: Cannot SASL bind to ldap server %s:%d: %s", + ldap_server, ldap_port, ldap_err2string (ret)); + char *msg=NULL; + ldap_get_option( ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, (void*)&msg); + log_error ("\tAdditional info: %s", msg); + ldap_memfree(msg); + ldap_stop(); + } - if (ldap_username != NULL || *ldap_username != '\0') + ldap_free_urldesc(ldapurl); + return ret; + } +#endif + + if (ldap_username != NULL && *ldap_username != '\0' && ldap_password != NULL) { who = ldap_username; creds.bv_val = strdup(ldap_password); + if (creds.bv_val == NULL) + log_fatal ("Error: Unable to allocate memory to duplicate ldap_password"); + creds.bv_len = strlen(ldap_password); - } - if ((ret = ldap_sasl_bind_s (ld, who, LDAP_SASL_SIMPLE, &creds, - NULL, NULL, NULL)) != LDAP_SUCCESS) + if ((ret = ldap_sasl_bind_s (ld, who, LDAP_SASL_SIMPLE, &creds, + NULL, NULL, NULL)) != LDAP_SUCCESS) + { + log_error ("Error: Cannot login into ldap server %s:%d: %s", + ldapurl->lud_host, ldapurl->lud_port, ldap_err2string (ret)); + } + + if (creds.bv_val) + free(creds.bv_val); + } + + 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) { - log_error ("Error: Cannot login into ldap server %s:%d: %s", - ldapurl->lud_host, ldapurl->lud_port, ldap_err2string (ret)); + 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 ret; + 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 @@ -619,6 +1315,12 @@ ldap_start (void) int ret, version; char *uri = NULL; struct berval creds; +#if defined(LDAP_USE_GSSAPI) + char *gssapi_realm = NULL; + char *gssapi_user = NULL; + char *running = NULL; + const char *gssapi_delim = "@"; +#endif if (ld != NULL) return; @@ -641,6 +1343,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); @@ -657,6 +1360,56 @@ ldap_start (void) } #endif +#if defined (LDAP_USE_GSSAPI) + ldap_gssapi_principal = _do_lookup_dhcp_string_option (options, + SV_LDAP_GSSAPI_PRINCIPAL); + + if (ldap_gssapi_principal == NULL) { + log_error("ldap_gssapi_principal is not set," + "GSSAPI Authentication for LDAP will not be used"); + } else { + ldap_gssapi_keytab = _do_lookup_dhcp_string_option (options, + SV_LDAP_GSSAPI_KEYTAB); + if (ldap_gssapi_keytab == NULL) { + log_fatal("ldap_gssapi_keytab must be specified"); + } + + running = strdup(ldap_gssapi_principal); + if (running == NULL) + log_fatal("Could not allocate memory to duplicate gssapi principal"); + + gssapi_user = strtok(running, gssapi_delim); + if (!gssapi_user || strlen(gssapi_user) == 0) { + log_fatal ("GSSAPI principal must specify user: user@realm"); + } + + gssapi_realm = strtok(NULL, gssapi_delim); + if (!gssapi_realm || strlen(gssapi_realm) == 0) { + log_fatal ("GSSAPI principal must specify realm: user@realm"); + } + + ldap_sasl_inst = malloc(sizeof(struct ldap_sasl_instance)); + if (ldap_sasl_inst == NULL) + log_fatal("Could not allocate memory for sasl instance! Can not run!"); + + ldap_sasl_inst->sasl_mech = ber_strdup("GSSAPI"); + if (ldap_sasl_inst->sasl_mech == NULL) + log_fatal("Could not allocate memory to duplicate gssapi mechanism"); + + ldap_sasl_inst->sasl_realm = ber_strdup(gssapi_realm); + if (ldap_sasl_inst->sasl_realm == NULL) + log_fatal("Could not allocate memory to duplicate gssapi realm"); + + ldap_sasl_inst->sasl_authz_id = ber_strdup(gssapi_user); + if (ldap_sasl_inst->sasl_authz_id == NULL) + log_fatal("Could not allocate memory to duplicate gssapi user"); + + ldap_sasl_inst->sasl_authc_id = NULL; + ldap_sasl_inst->sasl_password = NULL; //"" before + free(running); + } +#endif + #if defined (LDAP_CASA_AUTH) if (!load_uname_pwd_from_miCASA(&ldap_username,&ldap_password)) { @@ -853,7 +1606,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)); @@ -868,13 +1627,43 @@ ldap_start (void) } #endif - if (ldap_username != NULL && *ldap_username != '\0') +#if defined(LDAP_USE_GSSAPI) + if (ldap_gssapi_principal != NULL) { + krb5_get_tgt(ldap_gssapi_principal, ldap_gssapi_keytab); + if ((ret = ldap_sasl_interactive_bind_s(ld, NULL, ldap_sasl_inst->sasl_mech, + NULL, NULL, LDAP_SASL_AUTOMATIC, + _ldap_sasl_interact, ldap_sasl_inst) + ) != LDAP_SUCCESS) + { + log_error ("Error: Cannot SASL bind to ldap server %s:%d: %s", + ldap_server, ldap_port, ldap_err2string (ret)); + char *msg=NULL; + ldap_get_option( ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, (void*)&msg); + log_error ("\tAdditional info: %s", msg); + ldap_memfree(msg); + ldap_stop(); + return; + } + } else +#endif + + if (ldap_username != NULL && *ldap_username != '\0' && ldap_password != NULL) { creds.bv_val = strdup(ldap_password); + if (creds.bv_val == NULL) + log_fatal ("Error: Unable to allocate memory to duplicate 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); + free(creds.bv_val); + + if (ret != LDAP_SUCCESS) { log_error ("Error: Cannot login into ldap server %s:%d: %s", ldap_server, ldap_port, ldap_err2string (ret)); @@ -894,7 +1683,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; @@ -934,7 +1731,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; @@ -989,17 +1786,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; } @@ -1010,7 +1807,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; } } @@ -1066,13 +1863,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) @@ -1086,16 +1883,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; } } @@ -1106,15 +1903,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; } } @@ -1131,9 +1928,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 (); @@ -1144,7 +1942,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++) @@ -1155,14 +1954,20 @@ ldap_generate_config_string (struct parse *cfile) ldap_parse_class (entry, cfile); else if (strcasecmp (objectClass[i]->bv_val, "dhcpSubnet") == 0) ldap_parse_subnet (entry, cfile); + else if (strcasecmp (objectClass[i]->bv_val, "dhcpSubnet6") == 0) + ldap_parse_subnet6 (entry, cfile); else if (strcasecmp (objectClass[i]->bv_val, "dhcpPool") == 0) ldap_parse_pool (entry, cfile); + else if (strcasecmp (objectClass[i]->bv_val, "dhcpPool6") == 0) + ldap_parse_pool6 (entry, cfile); else if (strcasecmp (objectClass[i]->bv_val, "dhcpGroup") == 0) ldap_parse_group (entry, cfile); else if (strcasecmp (objectClass[i]->bv_val, "dhcpTSigKey") == 0) 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) @@ -1186,7 +1991,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; @@ -1201,23 +2006,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; @@ -1225,17 +2043,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); } @@ -1268,25 +2102,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++]); } @@ -1321,38 +2160,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; @@ -1360,52 +2173,97 @@ ldap_read_config (void) size_t length; int ret, cnt; struct berval **tempbv = NULL; + struct berval bv_o[2]; + + 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); + } + + *fqdn ='\0'; + 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); + } + } + + // If we have fqdn and it isn't the same as nodename, use it in filter + // otherwise just use nodename + if ((*fqdn) && (strcmp(unme.nodename, fqdn))) { + 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); } @@ -1414,6 +2272,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); } @@ -1427,7 +2286,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); @@ -1436,6 +2297,7 @@ ldap_read_config (void) ldap_memfree (hostdn); ldap_msgfree (hostres); ldap_stop(); + x_parser_free(&cfile); return (ISC_R_FAILURE); } @@ -1443,37 +2305,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, @@ -1489,7 +2365,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); @@ -1533,7 +2409,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); @@ -1544,7 +2420,7 @@ ldap_read_config (void) } } - end_parse (&cfile); + x_parser_free(&cfile); ldap_close_debug_fd(); ldap_memfree (hostdn); @@ -1592,17 +2468,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]; @@ -1624,16 +2501,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); @@ -1641,13 +2531,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; } } @@ -1658,24 +2546,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 @@ -1686,7 +2568,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); } @@ -1702,7 +2584,13 @@ 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]; + + *hp = NULL; + if (ldap_method == LDAP_METHOD_STATIC) return (0); @@ -1732,9 +2620,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; @@ -1765,18 +2672,61 @@ find_haddr_in_ldap (struct host_decl **hp, int htype, unsigned hlen, if (ret == LDAP_SUCCESS) { - if( (ent = ldap_first_entry (ld, res)) != NULL) - break; /* search OK and have entry */ - + ent = ldap_first_entry (ld, res); #if defined (DEBUG_LDAP) - log_info ("No host entry for %s in LDAP tree %s", - buf, curr->dn); + if (ent == NULL) { + log_info ("No host entry for %s in LDAP tree %s", + buf, curr->dn); + } +#endif + while (ent != NULL) { +#if defined (DEBUG_LDAP) + char *dn = ldap_get_dn (ld, ent); + if (dn != NULL) + { + log_info ("Found dhcpHWAddress LDAP entry %s", dn); + ldap_memfree(dn); + } #endif + + host = (struct host_decl *)0; + status = host_allocate (&host, MDL); + if (status != ISC_R_SUCCESS) + { + log_fatal ("can't allocate host decl struct: %s", + isc_result_totext (status)); + ldap_msgfree (res); + return (0); + } + + host->name = ldap_get_host_name (ent); + if (host->name == NULL) + { + host_dereference (&host, MDL); + ldap_msgfree (res); + return (0); + } + + if (!clone_group (&host->group, root_group, MDL)) + { + log_fatal ("can't clone group for host %s", host->name); + host_dereference (&host, MDL); + ldap_msgfree (res); + return (0); + } + + ldap_parse_options (ent, host->group, HOST_DECL, host, NULL); + + host->n_ipaddr = *hp; + *hp = host; + ent = ldap_next_entry (ld, ent); + } if(res) { ldap_msgfree (res); res = NULL; } + return (*hp != NULL); } else { @@ -1803,52 +2753,6 @@ find_haddr_in_ldap (struct host_decl **hp, int htype, unsigned hlen, } } - if (res && ent) - { -#if defined (DEBUG_LDAP) - char *dn = ldap_get_dn (ld, ent); - if (dn != NULL) - { - log_info ("Found dhcpHWAddress LDAP entry %s", dn); - ldap_memfree(dn); - } -#endif - - host = (struct host_decl *)0; - status = host_allocate (&host, MDL); - if (status != ISC_R_SUCCESS) - { - log_fatal ("can't allocate host decl struct: %s", - isc_result_totext (status)); - ldap_msgfree (res); - return (0); - } - - host->name = ldap_get_host_name (ent); - if (host->name == NULL) - { - host_dereference (&host, MDL); - ldap_msgfree (res); - return (0); - } - - if (!clone_group (&host->group, root_group, MDL)) - { - log_fatal ("can't clone group for host %s", host->name); - host_dereference (&host, MDL); - ldap_msgfree (res); - return (0); - } - - ldap_parse_options (ent, host->group, HOST_DECL, host, NULL); - - *hp = host; - ldap_msgfree (res); - return (1); - } - - - if(res) ldap_msgfree (res); return (0); } @@ -1861,7 +2765,10 @@ 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 (ldap_method == LDAP_METHOD_STATIC) return (0); @@ -1871,10 +2778,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((const char*)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 @@ -2000,4 +2930,213 @@ find_subclass_in_ldap (struct class *class, struct class **newclass, return (0); } +int find_client_in_ldap (struct host_decl **hp, struct packet *packet, + struct option_state *state, const char *file, int line) +{ + LDAPMessage * res, * ent; + ldap_dn_node *curr; + struct host_decl * host; + isc_result_t status; + struct data_string client_id; + char buf[1024], buf1[1024]; + int ret; + + if (ldap_method == LDAP_METHOD_STATIC) + return (0); + + if (ld == NULL) + ldap_start (); + if (ld == NULL) + return (0); + + memset(&client_id, 0, sizeof(client_id)); + if (get_client_id(packet, &client_id) != ISC_R_SUCCESS) + return (0); + snprintf(buf, sizeof(buf), + "(&(objectClass=dhcpHost)(dhcpClientId=%s))", + print_hw_addr(0, client_id.len, client_id.data)); + + /* log_info ("Searching LDAP for %s (%s)", buf, packet->interface->shared_network->name); */ + + res = ent = NULL; + for (curr = ldap_service_dn_head; + curr != NULL && *curr->dn != '\0'; + curr = curr->next) + { + snprintf(buf1, sizeof(buf1), "cn=%s,%s", packet->interface->shared_network->name, curr->dn); +#if defined (DEBUG_LDAP) + log_info ("Searching for %s in LDAP tree %s", buf, buf1); +#endif + ret = ldap_search_ext_s (ld, buf1, LDAP_SCOPE_SUBTREE, buf, NULL, 0, + NULL, NULL, NULL, 0, &res); + + if(ret == LDAP_SERVER_DOWN) + { + log_info ("LDAP server was down, trying to reconnect..."); + + ldap_stop(); + ldap_start(); + + if(ld == NULL) + { + log_info ("LDAP reconnect failed - try again later..."); + return (0); + } + + ret = ldap_search_ext_s (ld, buf1, LDAP_SCOPE_SUBTREE, buf, + NULL, 0, NULL, NULL, NULL, 0, &res); + } + + if (ret == LDAP_SUCCESS) + { + if( (ent = ldap_first_entry (ld, res)) != NULL) { + log_info ("found entry in search %s", buf1); + break; /* search OK and have entry */ + } + +#if defined (DEBUG_LDAP) + log_info ("No subclass entry for %s in LDAP tree %s", buf, curr->dn); +#endif + if(res) + { + ldap_msgfree (res); + res = NULL; + } + } + else + { + if(res) + { + ldap_msgfree (res); + res = NULL; + } + + if (ret != LDAP_NO_SUCH_OBJECT && ret != LDAP_SUCCESS) + { + log_error ("Cannot search for %s in LDAP tree %s: %s", buf, + curr->dn, ldap_err2string (ret)); + ldap_stop(); + return (0); + } + else + { + log_info ("did not find: %s", buf); + } + } + } + + if (res && ent) + { +#if defined (DEBUG_LDAP) + log_info ("ldap_get_dn %s", curr->dn); + char *dn = ldap_get_dn (ld, ent); + if (dn != NULL) + { + log_info ("Found subclass LDAP entry %s", dn); + ldap_memfree(dn); + } else { + log_info ("DN is null %s", dn); + } +#endif + + host = (struct host_decl *)0; + status = host_allocate (&host, MDL); + if (status != ISC_R_SUCCESS) + { + log_fatal ("can't allocate host decl struct: %s", + isc_result_totext (status)); + ldap_msgfree (res); + return (0); + } + + host->name = ldap_get_host_name (ent); + if (host->name == NULL) + { + host_dereference (&host, MDL); + ldap_msgfree (res); + return (0); + } + /* log_info ("Host name %s", host->name); */ + + if (!clone_group (&host->group, root_group, MDL)) + { + log_fatal ("can't clone group for host %s", host->name); + host_dereference (&host, MDL); + ldap_msgfree (res); + return (0); + } + + ldap_parse_options (ent, host->group, HOST_DECL, host, NULL); + + *hp = host; + ldap_msgfree (res); + return (1); + } + else + { + log_info ("did not find clientid: %s", buf); + } + + if(res) ldap_msgfree (res); + return (0); + +} + +#if defined(LDAP_USE_GSSAPI) +static int +_ldap_sasl_interact(LDAP *ld, unsigned flags, void *defaults, void *sin) +{ + sasl_interact_t *in; + struct ldap_sasl_instance *ldap_inst = defaults; + int ret = LDAP_OTHER; + size_t size; + + if (ld == NULL || sin == NULL) + return LDAP_PARAM_ERROR; + + log_info("doing interactive bind"); + for (in = sin; in != NULL && in->id != SASL_CB_LIST_END; in++) { + switch (in->id) { + case SASL_CB_USER: + log_info("got request for SASL_CB_USER %s", ldap_inst->sasl_authz_id); + size = strlen(ldap_inst->sasl_authz_id); + in->result = ldap_inst->sasl_authz_id; + in->len = size; + ret = LDAP_SUCCESS; + break; + case SASL_CB_GETREALM: + log_info("got request for SASL_CB_GETREALM %s", ldap_inst->sasl_realm); + size = strlen(ldap_inst->sasl_realm); + in->result = ldap_inst->sasl_realm; + in->len = size; + ret = LDAP_SUCCESS; + break; + case SASL_CB_AUTHNAME: + log_info("got request for SASL_CB_AUTHNAME %s", ldap_inst->sasl_authc_id); + size = strlen(ldap_inst->sasl_authc_id); + in->result = ldap_inst->sasl_authc_id; + in->len = size; + ret = LDAP_SUCCESS; + break; + case SASL_CB_PASS: + log_info("got request for SASL_CB_PASS %s", ldap_inst->sasl_password); + size = strlen(ldap_inst->sasl_password); + in->result = ldap_inst->sasl_password; + in->len = size; + ret = LDAP_SUCCESS; + break; + default: + goto cleanup; + } + } + return ret; + +cleanup: + in->result = NULL; + in->len = 0; + return LDAP_OTHER; +} +#endif /* LDAP_USE_GSSAPI */ + + #endif |