[asterisk-commits] anthonyl: branch anthonyl/ldap2-build-fix r48275
- /team/anthonyl/ldap2-build...
asterisk-commits at lists.digium.com
asterisk-commits at lists.digium.com
Tue Dec 5 13:02:33 MST 2006
Author: anthonyl
Date: Tue Dec 5 14:02:32 2006
New Revision: 48275
URL: http://svn.digium.com/view/asterisk?view=rev&rev=48275
Log:
just adding the ldaprealtime core to this branch.
Added:
team/anthonyl/ldap2-build-fix/res/res_config_ldap.c (with props)
Added: team/anthonyl/ldap2-build-fix/res/res_config_ldap.c
URL: http://svn.digium.com/view/asterisk/team/anthonyl/ldap2-build-fix/res/res_config_ldap.c?view=auto&rev=48275
==============================================================================
--- team/anthonyl/ldap2-build-fix/res/res_config_ldap.c (added)
+++ team/anthonyl/ldap2-build-fix/res/res_config_ldap.c Tue Dec 5 14:02:32 2006
@@ -1,0 +1,1165 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * Copyright (C) 2005, Oxymium sarl
+ *
+ * Manuel Guesdon <mguesdon at oxymium.net> - LDAP RealTime Driver Author/Adaptor
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ *
+ */
+
+/*! \file
+ *
+ * \brief ldap plugin for portable configuration engine (ARA)
+ *
+ * \author Mark Spencer <markster at digium.com>
+ * \author Manuel Guesdon
+ *
+ * \arg http://www.openldap.org
+ */
+
+/*** MODULEINFO
+ <depend>ldap</depend>
+ ***/
+
+#include "asterisk.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <ldap.h>
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision: 39401 $")
+
+#include "asterisk/channel.h"
+#include "asterisk/logger.h"
+#include "asterisk/config.h"
+#include "asterisk/module.h"
+#include "asterisk/lock.h"
+#include "asterisk/options.h"
+#include "asterisk/cli.h"
+#include "asterisk/utils.h"
+#include "asterisk/strings.h"
+#include "asterisk/pbx.h"
+#include "asterisk/linkedlists.h"
+
+static char *res_config_ldap_desc = "LDAP RealTime Configuration Driver";
+AST_MUTEX_DEFINE_STATIC(ldap_lock);
+#define RES_CONFIG_LDAP_CONF "res_ldap.conf"
+static LDAP *ldapConn = NULL;
+static char dbhost[512] = "";
+static char dbuser[512] = "";
+static char dbpass[50] = "";
+static char dbbasedn[512] = "";
+static int dbport = 389;
+static time_t connect_time = 0;
+
+static int parse_config(void);
+static int ldap_reconnect(void);
+static int realtime_ldap_status(int fd, int argc, char **argv);
+
+LOCAL_USER_DECL;
+
+struct category_and_metric {
+ char *name;
+ int metric;
+ char *variable_name;
+ char *variable_value;
+};
+
+static char cli_realtime_ldap_status_usage[] =
+ "Usage: realtime ldap status\n"
+ " Shows connection information for the LDAP RealTime driver\n";
+
+static struct ast_cli_entry cli_realtime_ldap_status = {
+ { "realtime", "ldap", "status", NULL }, realtime_ldap_status,
+ "Shows connection information for the LDAP RealTime driver",
+ cli_realtime_ldap_status_usage, NULL
+};
+
+/*! \brief Table configuration */
+struct ldap_table_config {
+ char *table_name; /*!< table name */
+ char *additional_filter; /*!< additional filter */
+ struct ast_variable *attributes; /*!< attribute names conversion */
+ struct ldap_table_config *next; /*!< next entry */
+};
+
+/*! \brief Should be locked before using it */
+static struct ldap_table_config *table_configs = NULL;
+static struct ldap_table_config *base_table_config = NULL;
+
+/*! \brief Create a new table_config */
+static struct ldap_table_config *table_config_new(const char *table_name)
+{
+ struct ldap_table_config *p = ast_calloc(1, sizeof(*p));
+ if (table_name)
+ p->table_name = strdup(table_name);
+ return p;
+}
+
+/*! \brief Find a table_config - Should be locked before using it */
+static struct ldap_table_config *table_config_for_table_name(const char *table_name)
+{
+ struct ldap_table_config *c = table_configs;
+ while (c) {
+ if (strcmp(c->table_name, table_name) == 0)
+ return c;
+ else
+ c = c->next;
+ }
+ return NULL;
+}
+
+/*! \brief add attribute to table config - Should be locked before using it */
+static void ldap_table_config_add_attribute(struct ldap_table_config *table_config,
+ const char *attribute_string)
+{
+ if (attribute_string && *attribute_string) {
+ char *string = strdup(attribute_string);
+ char *start = string;
+ char *p = strstr(start, "=>");
+
+ if (option_debug)
+ ast_log(LOG_DEBUG, "Add attribute: start: %s\n", start);
+
+ if (!p) {
+ ast_log(LOG_WARNING,
+ "Missing '=>' in attribute: %s in %s\n",
+ attribute_string, table_config->table_name);
+ } else {
+ char *value = p + 2; //skip =>
+ /* trim ! */
+ while (isspace(*start))
+ start++;
+ p--;
+ while (p >= start && isspace(*p)) {
+ *p = '\0';
+ p--;
+ }
+ while (isspace(*value))
+ value++;
+ p = value + strlen(value) - 1;
+ while (p >= value && isspace(*p)) {
+ *p = '\0';
+ p--;
+ }
+ if (ast_strlen_zero(start)) {
+ ast_log(LOG_WARNING,
+ "Empty variable name in attribute: %s in %s\n",
+ attribute_string, table_config->table_name);
+ } else if (ast_strlen_zero(value)) {
+ ast_log(LOG_WARNING,
+ "Empty ldap attribute name in attribute: %s in %s\n",
+ attribute_string, table_config->table_name);
+ } else {
+ struct ast_variable *var = ast_variable_new(start, value);
+ if (option_debug > 2)
+ ast_log(LOG_DEBUG, "Add attribute: VAR %s => %s\n",var->name,var->value);
+ if (table_config->attributes)
+ var->next = table_config->attributes;
+ table_config->attributes = var;
+ if (option_debug > 2)
+ ast_log(LOG_DEBUG, "Added attribute in %s: %s -> %s\n",
+ table_config->table_name, start, value);
+ }
+ }
+ free(string);
+ }
+}
+
+/*! \brief Free table_config */
+static void table_configs_free(void)
+{
+ struct ldap_table_config *c = table_configs;
+
+ while (c) {
+ struct ldap_table_config *next = c->next;
+ if (c->table_name)
+ free(c->table_name);
+ if (c->additional_filter)
+ free(c->additional_filter);
+ if (c->attributes) {
+ ast_variables_destroy(c->attributes);
+ }
+ free(c);
+ c = next;
+ }
+ table_configs = NULL;
+ base_table_config = NULL;
+}
+
+/*! \brief Convert variable name to ldap attribute name - Should be locked before using it */
+static const char *convert_attribute_name_to_ldap(struct ldap_table_config *table_config,
+ const char *attribute_name)
+{
+ int i = 0;
+ for (i = 0; i < 2; i++) {
+ if (table_config) {
+ struct ast_variable *attribute = table_config->attributes;
+ while (attribute) {
+ if (strcasecmp(attribute_name, attribute->name) == 0)
+ return attribute->value;
+ else
+ attribute = attribute->next;
+ }
+ }
+ if (table_config == base_table_config)
+ break;
+ else
+ table_config = base_table_config;
+ }
+ return attribute_name;
+}
+
+/*! \brief Convert ldap attribute name to variable name - Should be locked before using it */
+static const char *convert_attribute_name_from_ldap(struct ldap_table_config *table_config,
+ const char *attribute_name)
+{
+ int i = 0;
+
+ for (i = 0; i < 2; i++) {
+ if (table_config) {
+ struct ast_variable *attribute = table_config->attributes;
+
+ while (attribute) {
+ if (strcasecmp(attribute_name, attribute->value) == 0)
+ return attribute->name;
+ else
+ attribute = attribute->next;
+ }
+ }
+ if (table_config == base_table_config)
+ break;
+ else
+ table_config = base_table_config;
+ }
+ return attribute_name;
+}
+
+/*! \brief Find variable by name */
+static struct ast_variable *variable_named(struct ast_variable *var,
+ const char *name)
+{
+ while (var) {
+ if (strcasecmp(name, var->name) == 0)
+ return var;
+ else
+ var = var->next;
+ }
+ return NULL;
+}
+
+/*! \brief Get variables from ldap entry attributes - Should be locked before using it */
+static struct ast_variable *realtime_ldap_entry_to_var(struct ldap_table_config *table_config,
+ LDAPMessage *ldap_entry)
+{
+ BerElement *ber = NULL;
+ struct ast_variable *var = NULL;
+ struct ast_variable *prev = NULL;
+
+ char *ldap_attribute_name = ldap_first_attribute(ldapConn, ldap_entry, &ber);
+
+ while (ldap_attribute_name) {
+ const char *attribute_name =
+ convert_attribute_name_from_ldap(table_config,ldap_attribute_name);
+ int is_realmed_password_attribute = strcasecmp(attribute_name, "md5secret") == 0;
+ char **values = NULL;
+
+ values = ldap_get_values(ldapConn, ldap_entry, ldap_attribute_name);
+ if (values) {
+ char **v = values;
+
+ while (*v) {
+ char *value = *v;
+ if (option_debug > 1)
+ ast_log(LOG_DEBUG, "attribute_name: %s value: %s\n", attribute_name, value);
+ if (is_realmed_password_attribute) {
+ if (strncasecmp(value, "{md5}", 5) == 0)
+ value += 5;
+ else
+ value = NULL;
+ if (option_debug > 1)
+ ast_log(LOG_DEBUG, "md5: %s\n", value);
+ }
+ if (value) {
+ if (prev) {
+ prev->next = ast_variable_new(attribute_name, value);
+ if (prev->next)
+ prev = prev->next;
+ } else {
+ prev = var = ast_variable_new(attribute_name, value);
+ }
+ }
+ v++;
+ }
+ ldap_value_free(values);
+ }
+ ldap_attribute_name = ldap_next_attribute(ldapConn, ldap_entry, ber);
+ }
+ ber_free(ber, 0);
+
+ return var;
+}
+
+static int is_ldap_connect_error(int err)
+{
+ return (err == LDAP_SERVER_DOWN
+ || err == LDAP_TIMEOUT || err == LDAP_CONNECT_ERROR);
+}
+
+/*! \brief LGet LDAP entry by dn and return attributes as variables - Should be locked before using it */
+static struct ast_variable *ldap_loadentry(struct ldap_table_config *table_config,
+ const char *dn)
+{
+ if (!table_config) {
+ ast_log(LOG_ERROR, "No table config\n");
+ return NULL;
+ } else {
+ struct ast_variable *var = NULL;
+ int result = -1;
+ LDAPMessage *ldap_result = NULL;
+ int tries = 0;
+
+ if (option_debug > 1)
+ ast_log(LOG_DEBUG, "ldap_loadentry dn=%s\n", dn);
+
+ do {
+ result = ldap_search_s(ldapConn, dn, LDAP_SCOPE_BASE,
+ "(objectclass=*)", NULL, 0, &ldap_result);
+ if (result < 0 && is_ldap_connect_error(result)) {
+ ast_log(LOG_WARNING,
+ "Failed to query database. Try %d/3\n",
+ tries + 1);
+ tries++;
+ if (tries < 3) {
+ usleep(500000L * tries);
+ if (ldapConn) {
+ ldap_unbind_s(ldapConn);
+ ldapConn = NULL;
+ }
+ if (!ldap_reconnect())
+ break;
+ }
+ }
+ } while (result < 0 && tries < 3 && is_ldap_connect_error(result));
+
+ if (result < 0) {
+ ast_log(LOG_WARNING,
+ "Failed to query database. Check debug for more info.\n");
+ if (option_debug > 1) {
+ ast_log(LOG_DEBUG, "dn=%s\n", dn);
+ ast_log(LOG_DEBUG, "Query Failed because: %s\n",
+ ldap_err2string(result));
+ }
+ ast_mutex_unlock(&ldap_lock);
+ return NULL;
+ } else {
+ int num_entry = 0;
+ if ((num_entry = ldap_count_entries(ldapConn, ldap_result)) > 0) {
+ LDAPMessage *ldap_entry = NULL;
+ if (option_debug)
+ ast_log(LOG_DEBUG, "num_entry: %d\n", num_entry);
+
+ ldap_entry = ldap_first_entry(ldapConn, ldap_result);
+ var = realtime_ldap_entry_to_var(table_config, ldap_entry);
+ if (num_entry > 1)
+ ast_log(LOG_WARNING, "More than one entry for dn=%s. Take only 1st one\n", dn);
+ } else {
+ ast_log(LOG_WARNING, "Could not find any entry dn=%s.\n", dn);
+ }
+ }
+ ldap_msgfree(ldap_result);
+
+ return var;
+ }
+}
+
+/*! \brief caller should free returned pointer */
+static char *substituted(struct ast_channel *channel, const char *string)
+{
+#define MAXRESULT 2048
+ char *ret_string = NULL;
+
+ if (!ast_strlen_zero(string)) {
+ ret_string = ast_calloc(1, MAXRESULT);
+ pbx_substitute_variables_helper(channel, string, ret_string, MAXRESULT - 1);
+ }
+ if (option_debug > 1)
+ ast_log(LOG_DEBUG, "substituted: string: '%s' => '%s' \n",
+ string, ret_string);
+ return ret_string;
+}
+
+/*! \brief caller should free returned pointer */
+static char *cleaned_basedn(struct ast_channel *channel, const char *basedn)
+{
+ char *cbasedn = NULL;
+ if (basedn) {
+ char *p = NULL;
+ cbasedn = substituted(channel, basedn);
+ if (*cbasedn == '"') {
+ cbasedn++;
+ if (!ast_strlen_zero(cbasedn)) {
+ int len = strlen(cbasedn);
+ if (cbasedn[len - 1] == '"')
+ cbasedn[len - 1] = '\0';
+
+ }
+ }
+ p = cbasedn;
+ while (*p) {
+ if (*p == '|')
+ *p = ',';
+ p++;
+ }
+ }
+ if (option_debug > 1)
+ ast_log(LOG_DEBUG, "basedn: '%s' => '%s' \n", basedn, cbasedn);
+ return cbasedn;
+}
+
+/*! \brief Append a string to a filter string. The filter string can grow */
+static void append_string_to_filter(char **filter_ptr, int *filter_size_ptr, const char *filter)
+{
+ int current_len = 0;
+ int needed_len = 0;
+ char *r_filter = NULL;
+
+ if (strchr(filter, '$')) {
+ r_filter = substituted(NULL, filter);
+ filter = r_filter;
+ }
+ current_len = (*filter_ptr ? strlen(*filter_ptr) : 0);
+ needed_len = current_len + strlen(filter);
+ if (*filter_size_ptr < (needed_len + 1)) {
+ if (*filter_size_ptr == 0)
+ *filter_size_ptr = (needed_len > 128 ? needed_len : 128);
+ else
+ *filter_size_ptr = (*filter_size_ptr) * 2;
+ *filter_ptr = realloc(*filter_ptr, *filter_size_ptr);
+ }
+ if (*filter_ptr) {
+ strcpy((*filter_ptr) + current_len, filter);
+ }
+ if (r_filter)
+ free(r_filter);
+}
+
+/*! \brief Replace search by by in string. No check is done on string allocated size ! */
+static int replace_string_in_string(char *string, const char *search,const char *by)
+{
+ int search_len = strlen(search);
+ int by_len = strlen(by);
+ int replaced = 0;
+ char *p = strstr(string, search);
+ if (p) {
+ replaced = 1;
+ while (p) {
+ if (by_len == search_len)
+ memcpy(p, by, by_len);
+ else {
+ memmove(p + by_len, p + search_len,
+ strlen(p + search_len) + 1);
+ memcpy(p, by, by_len);
+ }
+ p = strstr(p + by_len, search);
+ }
+ }
+ return replaced;
+}
+
+/*! \brief Append a name=value filter string. The filter string can grow. */
+/*! \brief convert name and value if "LIKE' is used (see http://bugs.digium.com/view.php?id=5765) */
+static void append_var_and_value_to_filter(char **filter_ptr,
+ int *filter_size_ptr,
+ struct ldap_table_config
+ *table_config, const char *name,
+ const char *value)
+{
+ char *new_name = NULL;
+ char *new_value = NULL;
+ char *wsPos = strstr(name, " LIKE");
+ if (option_debug > 1)
+ ast_log(LOG_DEBUG, "name='%s' value='%s'\n", name, value);
+ if (wsPos) {
+ new_name = strndup(name, wsPos - name);
+ name = new_name;
+ new_value = strdup(value);
+ replace_string_in_string(new_value, "\\_", "_");
+ replace_string_in_string(new_value, "%", "*");
+ value = new_value;
+ }
+ name = convert_attribute_name_to_ldap(table_config, name);
+ append_string_to_filter(filter_ptr, filter_size_ptr, "(");
+ append_string_to_filter(filter_ptr, filter_size_ptr, name);
+ append_string_to_filter(filter_ptr, filter_size_ptr, "=");
+ append_string_to_filter(filter_ptr, filter_size_ptr, value);
+ append_string_to_filter(filter_ptr, filter_size_ptr, ")");
+ if (new_name)
+ free(new_name);
+ if (new_value)
+ free(new_value);
+}
+
+/*! \brief LDAP base function
+ return a null terminated array of ast_variable (one per entry) or NULL if no entry is found or if an error occured
+ caller should free the returned array and ast_variables
+ entries_count_ptr is a pointer to found entries count (can be NULL)
+ basedn is the base DN
+ table_name is the table_name (used dor attribute convertion and additional filter)
+ ap contains null terminated list of pairs name/value
+*/
+static struct ast_variable **realtime_ldap_base(unsigned int *entries_count_ptr,
+ const char *basedn, const char *table_name, va_list ap)
+{
+ struct ast_variable **vars = NULL;
+ const char *newparam = NULL;
+ const char *newval = NULL;
+
+ if (option_debug > 1)
+ ast_log(LOG_DEBUG,
+ "realtime_ldap_base: basedn: %s table_name: %s\n", basedn, table_name);
+ if (!table_name) {
+ ast_log(LOG_WARNING, "No table_name specified.\n");
+ return NULL;
+ }
+
+ /* Get the first parameter and first value in our list of passed paramater/value pairs */
+ newparam = va_arg(ap, const char *);
+ newval = va_arg(ap, const char *);
+ if (!newparam || !newval) {
+ ast_log(LOG_WARNING,
+ "Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
+ } else {
+ ast_mutex_lock(&ldap_lock);
+
+ /* We now have our complete statement; Lets connect to the server and execute it. */
+ if (ldap_reconnect()) {
+ struct ldap_table_config *table_config = NULL;
+
+ table_config = table_config_for_table_name(table_name);
+ if (!table_config) {
+ ast_log(LOG_WARNING,
+ "No table named '%s'.\n",
+ table_name);
+ } else {
+ char *clean_basedn = cleaned_basedn(NULL, basedn);
+ char *filter = NULL;
+ int filter_size = 0;
+ int tries = 0;
+
+ int result = 0;
+ LDAPMessage *ldap_result = NULL;
+
+ append_string_to_filter(&filter, &filter_size, "(&");
+
+ if (table_config && table_config->additional_filter) {
+ append_string_to_filter(&filter, &filter_size,
+ table_config->additional_filter);
+ }
+ if (table_config != base_table_config && base_table_config
+ && base_table_config->additional_filter) {
+ append_string_to_filter(&filter, &filter_size,
+ base_table_config->additional_filter);
+ }
+
+ /* Create the first part of the query using the first parameter/value pairs we just extracted */
+ /* If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
+
+ append_var_and_value_to_filter(&filter, &filter_size,
+ table_config, newparam, newval);
+ while ((newparam = va_arg(ap, const char *))) {
+ newval = va_arg(ap, const char *);
+ append_var_and_value_to_filter(&filter, &filter_size,
+ table_config, newparam, newval);
+ }
+ append_string_to_filter(&filter, &filter_size, ")");
+
+ if (option_debug)
+ ast_log(LOG_DEBUG, "filter: %s\n", filter);
+
+
+ do {
+ result = ldap_search_s(ldapConn, clean_basedn,
+ LDAP_SCOPE_SUBTREE, filter, NULL, 0,
+ &ldap_result);
+ if (result < 0 && is_ldap_connect_error(result)) {
+ ast_log(LOG_WARNING, "Failed to query database. Try %d/3\n",
+ tries + 1);
+ tries++;
+ if (tries < 3) {
+ usleep(500000L * tries);
+ if (ldapConn) {
+ ldap_unbind_s(ldapConn);
+ ldapConn = NULL;
+ }
+ if (!ldap_reconnect())
+ break;
+ }
+ }
+ } while (result < 0 && tries < 3 && is_ldap_connect_error(result));
+
+ if (result < 0) {
+ ast_log(LOG_WARNING,
+ "Failed to query database. Check debug for more info.\n");
+ ast_log(LOG_WARNING, "Query: %s\n",
+ filter);
+ ast_log(LOG_WARNING,
+ "Query Failed because: %s\n",
+ ldap_err2string(result));
+ } else {
+ int num_entry = 0;
+ if ((num_entry = ldap_count_entries(ldapConn, ldap_result)) > 0) {
+ LDAPMessage *ldap_entry = NULL;
+ int entry_index = 0;
+ if (entries_count_ptr)
+ *entries_count_ptr = num_entry;
+ vars = ast_calloc(1, sizeof(struct ast_variable *) *(num_entry + 1));
+ if (option_debug)
+ ast_log(LOG_DEBUG, "num_entry: %d\n", num_entry);
+
+ ldap_entry = ldap_first_entry(ldapConn, ldap_result);
+
+ for (entry_index = 0; ldap_entry; entry_index++) {
+ vars[entry_index] = realtime_ldap_entry_to_var(table_config,ldap_entry);
+ ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
+ }
+ } else {
+ ast_log(LOG_WARNING, "Could not find any entry matching %s in base dn %s.\n",
+ filter, clean_basedn);
+ }
+
+ ldap_msgfree(ldap_result);
+
+ if (vars) {
+ struct ast_variable **p = vars;
+ while (*p) {
+ struct ast_variable *append_var = NULL;
+ struct ast_variable *tmp = *p;
+ while (tmp) {
+ if (strcasecmp(tmp->name, "accountBaseDN") == 0) {
+ struct ast_variable *base_var = ldap_loadentry(table_config, tmp->value);
+ while (base_var) {
+ struct ast_variable *next = base_var->next;
+ struct ast_variable *test_var = *p;
+ int base_var_found = 0;
+
+ while (test_var) {
+ if (strcasecmp(test_var->name, base_var->name) == 0) {
+ base_var_found = 1;
+ break;
+ } else
+ test_var = test_var->next;
+ }
+ if (base_var_found) {
+ base_var->next = NULL;
+ ast_variables_destroy (base_var);
+ base_var = next;
+ } else {
+ if (append_var)
+ base_var->next = append_var;
+ else
+ base_var->next = NULL;
+ append_var = base_var;
+ base_var = next;
+ }
+ }
+ }
+ if (!tmp->next && append_var) {
+ tmp->next = append_var;
+ tmp = NULL;
+ } else
+ tmp = tmp->next;
+ }
+ p++;
+ }
+ }
+ }
+ if (filter)
+ free(filter);
+ if (clean_basedn)
+ free(clean_basedn);
+ }
+ }
+ ast_mutex_unlock(&ldap_lock);
+ }
+ return vars;
+}
+
+/*! \brief same as realtime_ldap_base_ but take variable arguments count list */
+static struct ast_variable **realtime_ldap_base_(unsigned int *entries_count_ptr,
+ const char *basedn, const char *table_name, ...)
+{
+ struct ast_variable **vars = NULL;
+ va_list ap;
+
+ va_start(ap, table_name);
+ vars = realtime_ldap_base(entries_count_ptr, basedn, table_name, ap);
+ va_end(ap);
+ return vars;
+}
+
+/*! \brief See Asterisk doc */
+static struct ast_variable *realtime_ldap(const char *basedn,
+ const char *table_name, va_list ap)
+{
+ struct ast_variable **vars = realtime_ldap_base(NULL, basedn, table_name, ap);
+ struct ast_variable *var = NULL;
+
+ if (vars) {
+ struct ast_variable *last_var = NULL;
+ struct ast_variable **p = vars;
+ while (*p) {
+ if (last_var) {
+ while (last_var->next)
+ last_var = last_var->next;
+ last_var->next = *p;
+ } else {
+ var = *p;
+ last_var = var;
+ }
+ p++;
+ }
+ free(vars);
+ }
+ return var;
+}
+
+/*! \brief See Asterisk doc */
+static struct ast_config *realtime_multi_ldap(const char *basedn,
+ const char *table_name, va_list ap)
+{
+ struct ast_variable **vars =
+ realtime_ldap_base(NULL, basedn, table_name, ap);
+ struct ast_config *cfg = NULL;
+
+ if (vars) {
+ cfg = ast_config_new();
+ if (!cfg) {
+ ast_log(LOG_WARNING, "Out of memory!\n");
+ } else {
+ struct ast_variable **p = vars;
+
+ while (*p) {
+ struct ast_category *cat = NULL;
+ cat = ast_category_new("");
+ if (!cat) {
+ ast_log(LOG_WARNING, "Out of memory!\n");
+ break;
+ } else {
+ struct ast_variable *var = *p;
+ while (var) {
+ struct ast_variable *next = var->next;
+ var->next = NULL;
+ ast_variable_append(cat, var);
+ var = next;
+ }
+ }
+ ast_category_append(cfg, cat);
+ p++;
+ }
+ }
+ free(vars);
+ }
+ return cfg;
+
+}
+
+static int compare_categories(const void *a, const void *b)
+{
+ struct category_and_metric *as = (struct category_and_metric *) a;
+ struct category_and_metric *bs = (struct category_and_metric *) b;
+ if (as->metric < bs->metric)
+ return -1;
+ else if (as->metric > bs->metric)
+ return 1;
+ else
+ return strcmp(as->name, bs->name);
+}
+
+/*! \brief See Asterisk doc */
+static struct ast_config *config_ldap(const char *basedn,
+ const char *table_name,
+ const char *file,
+ struct ast_config *cfg,
+ int withcomments)
+{
+ ast_log(LOG_DEBUG, "config_ldap: basedn: %s table_name: %s\n", basedn, table_name);
+ if (!file || !strcmp(file, RES_CONFIG_LDAP_CONF)) {
+ ast_log(LOG_WARNING, "Cannot configure myself.\n");
+ } else {
+ unsigned int vars_count = 0;
+ struct ast_variable **vars =
+ realtime_ldap_base_(&vars_count, basedn, table_name, "filename",
+ file, "commented", "FALSE", NULL);
+
+ if (vars) {
+ int i = 0;
+ struct ast_variable *new_v = NULL;
+ struct ast_category *cur_cat = NULL;
+ char *last_category = NULL;
+ int last_category_metric = 0;
+
+ /* sort on metric and category */
+ struct category_and_metric *categories =
+ malloc(sizeof(struct category_and_metric) * vars_count);
+ struct ast_variable **p = vars;
+ vars_count = 0;
+ while (*p) {
+ struct ast_variable *category =
+ variable_named(*p, "category");
+ struct ast_variable *cat_metric =
+ variable_named(*p, "cat_metric");
+ struct ast_variable *var_name =
+ variable_named(*p, "variable_name");
+ struct ast_variable *var_val =
+ variable_named(*p, "variable_value");
+ if (option_debug) {
+ ast_log(LOG_DEBUG, "category: %s\n",
+ category->value);
+ ast_log(LOG_DEBUG, "var_name: %s\n",
+ var_name->value);
+ ast_log(LOG_DEBUG, "var_val: %s\n",
+ var_val->value);
+ ast_log(LOG_DEBUG, "cat_metric: %s\n",
+ cat_metric->value);
+ }
+ if (!category) {
+ struct ast_variable *dn = variable_named(*p, "dn");
+ ast_log(LOG_ERROR,
+ "No category name in entry '%s' for file '%s'.\n",
+ (dn ? dn->value : "?"), file);
+ } else if (!cat_metric) {
+ struct ast_variable *dn = variable_named(*p, "dn");
+ ast_log(LOG_ERROR,
+ "No category metric in entry '%s'(category: %s) for file '%s'.\n",
+ (dn ? dn->value : "?"), category->value, file);
+ } else if (!var_name) {
+ struct ast_variable *dn = variable_named(*p, "dn");
+ ast_log(LOG_ERROR,
+ "No variable name in entry '%s' (category: %s metric: %s) for file '%s'.\n",
+ (dn ? dn->value : "?"), category->value,
+ cat_metric->value, file);
+ } else if (!var_val) {
+ struct ast_variable *dn = variable_named(*p, "dn");
+ ast_log(LOG_ERROR,
+ "No variable value in entry '%s' (category: %s metric: %s variable: %s) for file '%s'.\n",
+ (dn ? dn->value : "?"), category->value,
+ cat_metric->value, var_name->value, file);
+ } else {
+ categories[vars_count].name = category->value;
+ categories[vars_count].metric = atoi(cat_metric->value);
+ categories[vars_count].variable_name = var_name->value;
+ categories[vars_count].variable_value = var_val->value;
+ vars_count++;
+ }
+ p++;
+ }
+ qsort(categories, vars_count, sizeof(struct category_and_metric),
+ compare_categories);
+
+ for (i = 0; i < vars_count; i++) {
+ if (strcmp(categories[i].variable_name, "#include") == 0) {
+ if (!ast_config_internal_load(categories[i].variable_value, cfg, 0)) {
+ break;
+ return NULL;
+ }
+ } else {
+ if (!last_category || strcmp(last_category, categories[i].name) != 0 ||
+ last_category_metric != categories[i].metric) {
+ cur_cat = ast_category_new(categories[i].name);
+ if (!cur_cat) {
+ ast_log(LOG_WARNING, "Out of memory!\n");
+ break;
+ }
+ last_category = categories[i].name;
+ last_category_metric = categories[i].metric;
+ ast_category_append(cfg, cur_cat);
+ }
+ new_v = ast_variable_new(categories[i].variable_name,
+ categories[i].variable_value);
+ ast_variable_append(cur_cat, new_v);
+ }
+ }
+ free(vars);
+ free(categories);
+ } else {
+ ast_log(LOG_WARNING, "Could not find config '%s' in database.\n", file);
+ }
+ }
+ return cfg;
+
+}
+
+static struct ast_config_engine ldap_engine = {
+ .name = "ldap",
+ .load_func = config_ldap,
+ .realtime_func = realtime_ldap,
+ .realtime_multi_func = realtime_multi_ldap,
+ .update_func = NULL
+};
+
+static int load_module(void *mod)
+{
+
+ if (parse_config() < 0) {
+ ast_log(LOG_NOTICE, "Cannot load LDAP RealTime driver.\n");
+ return 0;
+ }
+
+ ast_mutex_lock(&ldap_lock);
+
+ if (!ldap_reconnect())
+ ast_log(LOG_WARNING, "Couldn't establish connection. Check debug.\n");
+
+ ast_config_engine_register(&ldap_engine);
+ if (option_verbose)
+ ast_verbose("LDAP RealTime driver loaded.\n");
+ ast_cli_register(&cli_realtime_ldap_status);
+
+ ast_mutex_unlock(&ldap_lock);
+
+ return 0;
+}
+
+static int unload_module(void *mod)
+{
+ /* Aquire control before doing anything to the module itself. */
+ ast_mutex_lock(&ldap_lock);
+
+ table_configs_free();
+
+ if (ldapConn) {
+ ldap_unbind_s(ldapConn);
+ ldapConn = NULL;
+ }
+ ast_cli_unregister(&cli_realtime_ldap_status);
+ ast_config_engine_deregister(&ldap_engine);
+ if (option_verbose)
+ ast_verbose("LDAP RealTime unloaded.\n");
+
+ STANDARD_HANGUP_LOCALUSERS;
+
+ /* Unlock so something else can destroy the lock. */
+ ast_mutex_unlock(&ldap_lock);
+
+ return 0;
+}
+
+static int reload(void *mod)
+{
+ /* Aquire control before doing anything to the module itself. */
+ ast_mutex_lock(&ldap_lock);
+
+ if (ldapConn) {
+ ldap_unbind_s(ldapConn);
+ ldapConn = NULL;
+ }
+
+ if (parse_config() < 0) {
+ ast_log(LOG_NOTICE, "Cannot reload LDAP RealTime driver.\n");
+ return 0;
+ }
+
+ if (!ldap_reconnect())
+ ast_log(LOG_WARNING, "Couldn't establish connection. Check debug.\n");
+
+ ast_verbose(VERBOSE_PREFIX_2 "LDAP RealTime reloaded.\n");
+
+ /* Done reloading. Release lock so others can now use driver. */
+ ast_mutex_unlock(&ldap_lock);
+
+ return 0;
+}
+
+int parse_config(void)
+{
+ struct ast_config *config;
+ char *s;
+
+ config = ast_config_load(RES_CONFIG_LDAP_CONF);
+
+ if (!config) {
+ ast_log(LOG_WARNING, "Cannot load configuration %s\n", RES_CONFIG_LDAP_CONF);
+ return -1;
+ }
+
+ if (!(s = ast_variable_retrieve(config, "_general", "dbuser"))) {
+ ast_log(LOG_WARNING, "No database user found, anonymous binding as default.\n");
+ dbuser[0] = '\0';
+ } else
+ ast_copy_string(dbuser, s, sizeof(dbuser));
+
+ if (!(s = ast_variable_retrieve(config, "_general", "dbpass"))) {
+ ast_log(LOG_WARNING, "No database password found, using 'asterisk' as default.\n");
+ ast_copy_string(dbpass, "asterisk", sizeof(dbpass) - 1);
+ } else
+ ast_copy_string(dbpass, s, sizeof(dbpass));
+
+ if (!(s = ast_variable_retrieve(config, "_general", "dbhost"))) {
+ ast_log(LOG_ERROR, "No directory host found.\n");
+ dbhost[0] = '\0';
+ } else
+ ast_copy_string(dbhost, s, sizeof(dbhost));
+
+ if (!(s = ast_variable_retrieve(config, "_general", "dbbasedn"))) {
+ ast_log(LOG_ERROR, "No LDAP base dn found, using 'asterisk' as default.\n");
+ dbbasedn[0] = '\0';
+ } else
+ ast_copy_string(dbbasedn, s, sizeof(dbbasedn));
+
+ if (!(s = ast_variable_retrieve(config, "_general", "dbport"))) {
+ ast_log(LOG_WARNING, "No directory port found, using 389 as default.\n");
+ dbport = 389;
+ } else
+ dbport = atoi(s);
+
+ table_configs_free();
+
+ char *category_name = NULL;
+ while ((category_name = ast_category_browse(config, category_name))) {
+ int is_general = (strcasecmp(category_name, "_general") == 0);
+ struct ast_variable *var = ast_variable_browse(config, category_name);
+
+ if (option_debug)
+ ast_log(LOG_DEBUG, "found: category_name=%s\n", category_name);
+ if (var) {
+ struct ldap_table_config *table_config =
+ table_config_for_table_name(category_name);
+ if (!table_config) {
+ table_config = table_config_new(category_name);
+ if (table_configs)
+ table_config->next = table_configs;
+ table_configs = table_config;
+ if (is_general)
+ base_table_config = table_config;
+ }
+ while (var) {
+ if (option_debug)
+ ast_log(LOG_DEBUG, "found: category_name=%s var->name=%s var->value=%s\n",
+ category_name, var->name, var->value);
+ if (strcasecmp(var->name, "attribute") == 0)
+ ldap_table_config_add_attribute(table_config, var->value);
+ else if (strcasecmp(var->name, "additionalFilter") == 0)
+ table_config->additional_filter = strdup(var->value);
+ var = var->next;
+ }
+ }
+ }
+
+ ast_config_destroy(config);
+ if (option_debug > 3) {
+ ast_log(LOG_DEBUG, "LDAP RealTime Host: %s\n", dbhost);
+ ast_log(LOG_DEBUG, "LDAP RealTime Port: %i\n", dbport);
+ ast_log(LOG_DEBUG, "LDAP RealTime User: %s\n", dbuser);
+ ast_log(LOG_DEBUG, "LDAP RealTime Password: %s\n", dbpass);
+ ast_log(LOG_DEBUG, "LDAP RealTime BaseDN: %s\n", dbbasedn);
+ }
+ return 1;
+}
+
+static const char *description(void)
+{
+ return res_config_ldap_desc;
+}
+
+static const char *key(void)
+{
+ return ASTERISK_GPL_KEY;
+}
+
+static int ldap_reconnect(void)
+{
+ /* mutex lock should have been locked before calling this function. */
+ int bind_result = 0;
+
+ if (ldapConn) {
+ if (option_debug > 1)
+ ast_log(LOG_DEBUG, "Everything seems fine.\n");
+ return 1;
+ }
+
+ if (!dbhost) {
+ ast_log(LOG_ERROR, "Not enough parameters to connect to ldap database\n");
+ return 0;
+ }
+
+ if (!(ldapConn = ldap_init(dbhost, dbport))) {
+ ast_log(LOG_ERROR, "Failed to init ldap connection to %s. Check debug for more info.\n", dbhost);
+ return 0;
+ }
+
+ if (dbuser && *dbuser) {
+ if (option_debug > 1)
+ ast_log(LOG_DEBUG, "bind to %s as %s\n", dbhost, dbuser);
+ bind_result = ldap_simple_bind_s(ldapConn, dbuser, dbpass);
+ } else {
+ if (option_debug > 1)
+ ast_log(LOG_DEBUG, "bind anonymously %s anonymously\n", dbhost);
+ bind_result = ldap_simple_bind_s(ldapConn, NULL, NULL);
+ }
+ if (bind_result == LDAP_SUCCESS) {
+ if (option_debug > 1)
+ ast_log(LOG_DEBUG, "Successfully connected to database.\n");
+ connect_time = time(NULL);
+ return 1;
+ } else {
+ ast_log(LOG_WARNING, "bind failed: %s\n", ldap_err2string(bind_result));
+ ldap_unbind(ldapConn);
+ ldapConn = NULL;
+ return 0;
+ }
+}
+
+static int realtime_ldap_status(int fd, int argc, char **argv)
+{
+ char status[256], status2[100] = "";
+ int ctime = time(NULL) - connect_time;
+
+ if (!ldapConn)
+ return RESULT_FAILURE;
+ if (dbhost)
+ snprintf(status, 255, "Connected to %s, port %d baseDN %s", dbhost, dbport, dbbasedn);
+
+ if (dbuser && *dbuser)
+ snprintf(status2, 99, " with username %s", dbuser);
+
+ if (ctime > 31536000) {
+ ast_cli(fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n",
+ status, status2, ctime / 31536000,
+ (ctime % 31536000) / 86400, (ctime % 86400) / 3600,
+ (ctime % 3600) / 60, ctime % 60);
+ } else if (ctime > 86400) {
+ ast_cli(fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n",
+ status, status2, ctime / 86400, (ctime % 86400) / 3600,
+ (ctime % 3600) / 60, ctime % 60);
+ } else if (ctime > 3600) {
+ ast_cli(fd, "%s%s for %d hours, %d minutes, %d seconds.\n",
+ status, status2, ctime / 3600, (ctime % 3600) / 60,
+ ctime % 60);
+ } else if (ctime > 60) {
+ ast_cli(fd, "%s%s for %d minutes, %d seconds.\n", status, status2,
+ ctime / 60, ctime % 60);
+ } else {
+ ast_cli(fd, "%s%s for %d seconds.\n", status, status2, ctime);
+ }
+
+ return RESULT_SUCCESS;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "LDAP Configuration",
+ .load = load_module,
+ .unload = unload_module,
+ );
+
Propchange: team/anthonyl/ldap2-build-fix/res/res_config_ldap.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/anthonyl/ldap2-build-fix/res/res_config_ldap.c
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: team/anthonyl/ldap2-build-fix/res/res_config_ldap.c
------------------------------------------------------------------------------
svn:mime-type = text/plain
More information about the asterisk-commits
mailing list