[asterisk-commits] branch oej/res_config_ldap r12474 - in /team/oej/res_config_ldap: ./ configs/...

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Wed Mar 8 14:10:26 MST 2006


Author: oej
Date: Wed Mar  8 15:10:21 2006
New Revision: 12474

URL: http://svn.digium.com/view/asterisk?rev=12474&view=rev
Log:
Adding patch from issue #5768 with some formatting changes.

Added:
    team/oej/res_config_ldap/configs/res_ldap.conf.sample   (with props)
    team/oej/res_config_ldap/doc/rt-ldap.txt   (with props)
    team/oej/res_config_ldap/res/res_config_ldap.c   (with props)
Modified:
    team/oej/res_config_ldap/   (props changed)
    team/oej/res_config_ldap/res/Makefile

Propchange: team/oej/res_config_ldap/
------------------------------------------------------------------------------
    svnmerge-integrated = /trunk:1-12471

Added: team/oej/res_config_ldap/configs/res_ldap.conf.sample
URL: http://svn.digium.com/view/asterisk/team/oej/res_config_ldap/configs/res_ldap.conf.sample?rev=12474&view=auto
==============================================================================
--- team/oej/res_config_ldap/configs/res_ldap.conf.sample (added)
+++ team/oej/res_config_ldap/configs/res_ldap.conf.sample Wed Mar  8 15:10:21 2006
@@ -1,0 +1,134 @@
+; Sample Asterisk config file for res_config_ldap
+; in extconfig.conf you can use it like this:
+; sipusers => ldap,"dc=myDomain,dc=myDomainExt",sip
+; sippeers => ldap,"dc=myDomain,dc=myDomainExt",sip
+; extensions => ldap,"dc=myDomain,dc=myDomainExt",extensions
+; sip.conf => ldap,"dc=myDomain,dc=myDomainExt",config
+
+
+[_general]
+dbhost=192.168.1.1,ldap.mydomain.com	; LDAP host(s)
+dbbasedn=MyRootDN	; Base DN
+dbpass=MyPassword	; Bind password
+dbuser=MyDN		; Bind DN
+
+; Configuration Table
+[config]
+; Attributes mapping (asterisk variable name => ldap attribute name)
+attribute = filename => oxyPBXConfigFilename
+attribute = category => oxyPBXConfigCategory
+attribute = variable_name => oxyPBXConfigVariableName
+attribute = variable_value => oxyPBXConfigVariableValue
+attribute = cat_metric => oxyPBXConfigCategoryMetric
+attribute = commented => oxyPBXConfigCommented
+
+; addtional filter
+additionalFilter=(objectClass=oxyPBXConfig)
+
+; Extensions Table
+[extensions]
+attribute = context  =>  oxyPBXExtensionContext
+attribute = exten  =>  oxyPBXExtensionExten
+attribute = priority => oxyPBXExtensionPriority
+attribute = app => oxyPBXExtensionApplication
+attribute = appdata => oxyPBXExtensionApplicationData
+additionalFilter=(objectClass=oxyPBXExtension)
+
+// Sip Users Table
+[sip]
+attribute = name => uid
+attribute = amaflags => oxyPBXAccountAMAFlags
+attribute = callgroup => oxyPBXAccountCallGroup
+attribute = callerid => oxyPBXAccountCallerID
+attribute = canreinvite => oxyPBXAccountCanReinvite
+attribute = context => oxyPBXAccountContext
+attribute = dtmfmode => oxyPBXAccountDTMFMode
+attribute = fromuser => oxyPBXAccountFromUser
+attribute = fromdomain => oxyPBXAccountFromDomain
+attribute = fullcontact => oxyPBXAccountFullContact
+attribute = fullcontact => gecos
+attribute = host => oxyPBXAccountHost
+attribute = insecure => oxyPBXAccountInsecure
+attribute = mailbox => oxyPBXAccountMailbox
+attribute = md5secret => realmedPassword
+attribute = nat => oxyPBXAccountNAT
+attribute = deny => oxyPBXAccountDeny
+attribute = permit => oxyPBXAccountPermit
+attribute = pickupgroup => oxyPBXAccountPickupGroup
+attribute = port => oxyPBXAccountPort
+attribute = qualify => oxyPBXAccountQualify
+attribute = restrictcid => oxyPBXAccountRestrictCID
+attribute = rtptimeout => oxyPBXAccountRTPTimeout
+attribute = rtpholdtimeout => oxyPBXAccountRTPHoldTimeout
+attribute = type => oxyPBXAccountType
+attribute = disallow => oxyPBXAccountDisallowedCodec
+attribute = allow => oxyPBXAccountAllowedCodec
+attribute = MusicOnHold => oxyPBXAccountMusicOnHold
+attribute = regseconds => oxyPBXAccountExpirationTimestamp
+attribute = regcontext => oxyPBXAccountRegistrationContext
+attribute = regexten => oxyPBXAccountRegistrationExten
+attribute = CanCallForward => oxyPBXAccountCanCallForward
+additionalFilter=(objectClass=oxyPBXAccountSIP)
+
+; IAX Users Table
+[iax]
+attribute = amaflags => oxyPBXAccountAMAFlags
+attribute = callerid => oxyPBXAccountCallerID
+attribute = context => oxyPBXAccountContext
+attribute = fullcontact => oxyPBXAccountFullContact
+attribute = fullcontact => gecos
+attribute = host => oxyPBXAccountHost
+attribute = mailbox => oxyPBXAccountMailbox
+attribute = md5secret => realmedPassword
+attribute = deny => oxyPBXAccountDeny
+attribute = permit => oxyPBXAccountPermit
+attribute = port => oxyPBXAccountPort
+attribute = qualify => oxyPBXAccountQualify
+attribute = type => oxyPBXAccountType
+attribute = disallow => oxyPBXAccountDisallowedCodec
+attribute = allow => oxyPBXAccountAllowedCodec
+attribute = regseconds => oxyPBXAccountExpirationTimestamp
+attribute = regcontext => oxyPBXAccountRegistrationContext
+attribute = regexten => oxyPBXAccountRegistrationExten
+attribute = notransfer => oxyPBXAccountNoTransfer
+additionalFilter=(objectClass=oxyPBXAccountIAX)
+
+; A Test Family
+[testfamily]
+attribute = MyUSERID => uid
+additionalFilter=(objectClass=*)
+
+[accounts]
+attribute = amaflags => oxyPBXAccountAMAFlags
+attribute = callgroup => oxyPBXAccountCallGroup
+attribute = callerid => oxyPBXAccountCallerID
+attribute = canreinvite => oxyPBXAccountCanReinvite
+attribute = context => oxyPBXAccountContext
+attribute = dtmfmode => oxyPBXAccountDTMFMode
+attribute = fromuser => oxyPBXAccountFromUser
+attribute = fromdomain => oxyPBXAccountFromDomain
+attribute = fullcontact => oxyPBXAccountFullContact
+attribute = fullcontact => gecos
+attribute = host => oxyPBXAccountHost
+attribute = insecure => oxyPBXAccountInsecure
+attribute = mailbox => oxyPBXAccountMailbox
+attribute = md5secret => realmedPassword
+attribute = nat => oxyPBXAccountNAT
+attribute = deny => oxyPBXAccountDeny
+attribute = permit => oxyPBXAccountPermit
+attribute = pickupgroup => oxyPBXAccountPickupGroup
+attribute = port => oxyPBXAccountPort
+attribute = qualify => oxyPBXAccountQualify
+attribute = restrictcid => oxyPBXAccountRestrictCID
+attribute = rtptimeout => oxyPBXAccountRTPTimeout
+attribute = rtpholdtimeout => oxyPBXAccountRTPHoldTimeout
+attribute = type => oxyPBXAccountType
+attribute = disallow => oxyPBXAccountDisallowedCodec
+attribute = allow => oxyPBXAccountAllowedCodec
+attribute = MusicOnHold => oxyPBXAccountMusicOnHold
+attribute = regseconds => oxyPBXAccountExpirationTimestamp
+attribute = regcontext => oxyPBXAccountRegistrationContext
+attribute = regexten => oxyPBXAccountRegistrationExten
+attribute = CanCallForward => oxyPBXAccountCanCallForward
+additionalFilter=(objectClass=oxyPBXAccount)
+

Propchange: team/oej/res_config_ldap/configs/res_ldap.conf.sample
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/oej/res_config_ldap/configs/res_ldap.conf.sample
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/oej/res_config_ldap/configs/res_ldap.conf.sample
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: team/oej/res_config_ldap/doc/rt-ldap.txt
URL: http://svn.digium.com/view/asterisk/team/oej/res_config_ldap/doc/rt-ldap.txt?rev=12474&view=auto
==============================================================================
--- team/oej/res_config_ldap/doc/rt-ldap.txt (added)
+++ team/oej/res_config_ldap/doc/rt-ldap.txt Wed Mar  8 15:10:21 2006
@@ -1,0 +1,65 @@
+Asterisk Realtim LDAP Driver
+---------------------------
+
+With this driver Asterisk can retrieve information from a LDAP drectory, including 
+sip/iax users, extensions and configuration.
+
+See configs/res_ldap.conf.sample for a configuration file sample
+
+
+Here is a LDAP dif sample:
+
+# Base SIP Phones Entry
+dn: uid=phone-base,dc=myDomain,dc=myDomainExt
+objectClass: top
+objectClass: oxyPBXAccount
+objectClass: oxyPBXAccountSIP
+uid: phone-base
+oxyPBXAccountAccountingCode: baseacccode
+oxyPBXAccountHost: dynamic
+preferredLanguage: FR
+oxyPBXAccountAMAFlags: billing
+oxyPBXAccountContext: ldaptest
+
+
+# A Phone. realmedPassword md5 hash should be the result of 
+#  echo -n "UID:SIPRealm:Password" | md5sum
+dn: uid=phone-test,dc=myDomain,dc=myDomainExt
+objectClass: top
+objectClass: oxyPBXAccount
+objectClass: oxyPBXAccountSIP
+uid: phone-test
+oxyPBXAccountAccountingCode: acc-phone-base
+oxyPBXAccountFullContact: Noone <1234>
+oxyPBXAccountCallerID: 1234
+oxyPBXAccountBaseDN: uid=phone-base,dc=myDomain,dc=myDomainExt
+realmedPassword: {MD5}f67965da780bf9c70d6e337f938cee6f
+
+
+# extensions, 
+dn: ou=extensions,dc=myDomain,dc=myDomainExt
+ou: extensions
+objectClass: top
+objectClass: organizationalUnit
+
+# Extension 100 Priority 1 in context ldaptest
+dn: cn=100-1,ou=extensions,dc=myDomain,dc=myDomainExt
+oxyPBXExtensionApplication: NoOp
+oxyPBXExtensionApplicationData: TEST LDAP
+objectClass: top
+objectClass: oxyPBXExtension
+oxyPBXExtensionExten: 100
+oxyPBXExtensionContext: ldaptest
+cn: 100-1
+oxyPBXExtensionPriority: 1
+
+# Extension 100 Priority 1 in context ldaptest
+dn: cn=100-2,ou=extensions,dc=myDomain,dc=myDomainExt
+objectClass: top
+objectClass: oxyPBXExtension
+oxyPBXExtensionExten: 100
+oxyPBXExtensionContext: ldaptest
+cn: 100-2
+oxyPBXExtensionPriority: 2
+oxyPBXExtensionApplication: hangup
+

Propchange: team/oej/res_config_ldap/doc/rt-ldap.txt
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/oej/res_config_ldap/doc/rt-ldap.txt
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/oej/res_config_ldap/doc/rt-ldap.txt
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: team/oej/res_config_ldap/res/Makefile
URL: http://svn.digium.com/view/asterisk/team/oej/res_config_ldap/res/Makefile?rev=12474&r1=12473&r2=12474&view=diff
==============================================================================
--- team/oej/res_config_ldap/res/Makefile (original)
+++ team/oej/res_config_ldap/res/Makefile Wed Mar  8 15:10:21 2006
@@ -41,6 +41,11 @@
   ifeq ($(findstring BSD,$(OSARCH)),BSD)
     MODS:=$(filter-out res_snmp.so,$(MODS))
   endif
+endif
+
+
+ifeq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/include/ldap.h $(CROSS_COMPILE_TARGET)/usr/local/include/ldap.h),)
+  MODS:=$(filter-out res_config_ldap.so,$(MODS))
 endif
 
 ifeq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/include/net-snmp/net-snmp-config.h),)
@@ -128,6 +133,10 @@
 res_snmp.so: res_snmp.o snmp/agent.o
 	$(CC) $(SOLINK) ${SNMP_LDFLAGS} -o $@ ${CYGSOLINK} res_snmp.o snmp/agent.o ${CYGSOLIB} ${SNMP_LDLIBS}
 
+res_config_ldap.so: res_config_ldap.o
+	$(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} -lldap
+
+
 ifneq ($(wildcard .depend),)
   include .depend
 endif

Added: team/oej/res_config_ldap/res/res_config_ldap.c
URL: http://svn.digium.com/view/asterisk/team/oej/res_config_ldap/res/res_config_ldap.c?rev=12474&view=auto
==============================================================================
--- team/oej/res_config_ldap/res/res_config_ldap.c (added)
+++ team/oej/res_config_ldap/res/res_config_ldap.c Wed Mar  8 15:10:21 2006
@@ -1,0 +1,1308 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * Copyright (C) 2005, Oxymium sarl
+ * 
+ * Manuel Guesdon <mguesdon at oxymium.net> - LDAP RealTime Driver Author/Adaptor
+ *
+ * res_config_ldap.c <LDAP plugin for RealTime configuration engine>
+ *
+ * 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
+ * \par	Version notes
+ * - v0.5   - (11-16-2005) - Initial version based
+ * - v0.7   - (03-08-2006) - Fixes, confg file changes
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <ldap.h>
+#include <stdio.h>
+
+#include "asterisk.h"
+
+STERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#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>
+
+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);
+
+
+STANDARD_LOCAL_USER;
+
+LOCAL_USER_DECL;
+
+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 Log variable */
+static void ast_variable_log(const char *log_prefix, struct ast_variable *var)
+{
+	ast_log(LOG_DEBUG, "LOG Variable: %s\n", log_prefix);
+	while (var) {
+		ast_log(LOG_DEBUG, "%s => %s\n", var->name, var->value);
+		var = var->next;
+	};
+	ast_log(LOG_DEBUG, "END LOG Variable: %s\n", log_prefix);
+}
+
+/*! \brief Log config */
+static void ast_config_log(const char *log_prefix, struct ast_config *config)
+{
+	ast_log(LOG_DEBUG, "LOG Config: %s\n", log_prefix);
+	char *category_name = NULL;
+	while ((category_name = ast_category_browse(config, category_name))) {
+		ast_log(LOG_DEBUG, "========= category: %s ==========\n",
+				category_name);
+		struct ast_variable *var = ast_variable_browse(config, category_name);
+		if (var) {
+			while (var) {
+				ast_log(LOG_DEBUG, "%s=%s\n", var->name, var->value);
+				var = var->next;
+			}
+		}
+	}
+	ast_log(LOG_DEBUG, "END LOG Config: %s\n", log_prefix);
+};
+
+/*! \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 table */
+};
+
+/*! \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 = malloc(sizeof(struct ldap_table_config));
+	memset(p, 0, sizeof(struct ldap_table_config));
+	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 attributes to table config - Should be locked before using it */
+static void ldap_table_config_add_attributes(struct ldap_table_config* table_config,const char* attributes_string)
+{
+	if (attributes_string && *attributes_string) {      
+		char* string=strdup(attributes_string);
+		char* string_end=string+strlen(string);
+		char* start=string;
+		while(start<string_end) {
+			char* conv_sep=NULL;
+    			char* attr_sep=strchr(start,',');
+			if (!attr_sep)
+				attr_sep=string_end;
+			else
+				*attr_sep='\0';
+			conv_sep=strchr(start,'=');
+			if (conv_sep>=attr_sep)
+				conv_sep=NULL;
+			if (!conv_sep) {
+				ast_log(LOG_WARNING, "LDAP RealTime: Missing '=' in attributes conversion list: %s\n",attributes_string);
+			} else {
+				struct ast_variable* var;
+				*conv_sep='\0';
+				var=ast_variable_new(start,conv_sep+1);
+				if (table_config->attributes)
+					var->next=table_config->attributes;
+				table_config->attributes=var;
+			}
+			start=attr_sep+1;
+		};
+		free(string);
+	};
+};
+*/
+
+/*! \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;
+		ast_log(LOG_DEBUG, "LDAP RealTime: Add attribute: start: %s\n",
+				start);
+		char *p = strstr(start, "=>");
+		if (!p) {
+			ast_log(LOG_WARNING,
+					"LDAP RealTime: 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 (*start == '\0') {
+				ast_log(LOG_WARNING,
+						"LDAP RealTime: Empty variable name in attribute: %s in %s\n",
+						attribute_string, table_config->table_name);
+			} else if (*value == '\0') {
+				ast_log(LOG_WARNING,
+						"LDAP RealTime: 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);
+				//ast_log(LOG_DEBUG, "LDAP RealTime: Add attribute: VAR %s => %s\n",var->name,var->value);
+				if (table_config->attributes)
+					var->next = table_config->attributes;
+				table_config->attributes = var;
+				ast_log(LOG_DEBUG,
+						"LDAP RealTime (%d): Added attribute in %s: %s -> %s\n",
+						__LINE__, 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) {
+		} else {
+			char **v = values;
+
+			while (*v) {
+				char *value = *v;
+				ast_log(LOG_DEBUG,
+						"LDAP RealTime (%d): attribute_name: %s value: %s\n",
+						__LINE__, attribute_name, value);
+				if (is_realmed_password_attribute) {
+					if (strncasecmp(value, "{md5}", 5) == 0)
+						value += 5;
+					else
+						value = NULL;
+					ast_log(LOG_DEBUG, "LDAP RealTime (%d): md5: %s\n",
+							__LINE__, 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, "LDAP RealTime: Not table config\n");
+		return NULL;
+	} else {
+		struct ast_variable *var = NULL;
+		int result = -1;
+		LDAPMessage *ldap_result = NULL;
+		int tries = 0;
+
+		ast_log(LOG_DEBUG, "LDAP RealTime (%d): ldap_loadentry dn=%s\n",
+				__LINE__, 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,
+						"LDAP RealTime: 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,
+					"LDAP RealTime: Failed to query database. Check debug for more info.\n");
+			ast_log(LOG_DEBUG, "LDAP RealTime: dn=%s\n", dn);
+			ast_log(LOG_DEBUG, "LDAP RealTime: 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;
+				ast_log(LOG_DEBUG, "LDAP RealTime (%d): num_entry: %d\n",
+						__LINE__, 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,
+							"LDAP RealTime: More than one entry for dn=%s. Take only 1st one\n",
+							dn);
+				}
+			} else {
+				ast_log(LOG_WARNING,
+						"LDAP RealTime: Could not find any entry dn=%s.\n",
+						dn);
+			}
+		}
+		ldap_msgfree(ldap_result);
+
+		ast_variable_log("LDAP RealTime: Found Entry", var);
+		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 = malloc(MAXRESULT);
+		if (!ret_string) {
+			ast_log(LOG_WARNING, "Out of memory\n");
+		} else {
+			memset(ret_string, 0, MAXRESULT);
+			pbx_substitute_variables_helper(channel, string, ret_string, MAXRESULT - 1);
+		}
+	}
+	ast_log(LOG_DEBUG, "LDAP RealTime: 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 (*cbasedn != '\0') {
+				int len = strlen(cbasedn);
+				if (cbasedn[len - 1] == '"')
+					cbasedn[len - 1] = '\0';
+
+			}
+		}
+		p = cbasedn;
+		while (*p) {
+			if (*p == '|')
+				*p = ',';
+			p++;
+		};
+	}
+	ast_log(LOG_DEBUG, "LDAP RealTime (%d): basedn: '%s' => '%s' \n",
+			__LINE__, 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");
+	//ast_log(LOG_DEBUG, "LDAP RealTime: 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)
+{
+	ast_log(LOG_DEBUG,
+			"LDAP RealTime (%d): realtime_ldap_base: basedn: %s table_name: %s\n",
+			__LINE__, basedn, table_name);
+	struct ast_variable **vars = NULL;
+	if (!table_name) {
+		ast_log(LOG_WARNING, "LDAP RealTime: No table_name specified.\n");
+	} else {
+		const char *newparam = NULL;
+		const char *newval = 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,
+					"LDAP RealTime: 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()) {
+			} else {
+				struct ldap_table_config *table_config = NULL;
+
+				table_config = table_config_for_table_name(table_name);
+				if (!table_config) {
+					ast_log(LOG_WARNING,
+							"LDAP RealTime: 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, ")");
+
+					ast_log(LOG_DEBUG, "LDAP RealTime (%d): filter: %s\n",
+							__LINE__, 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,
+									"LDAP RealTime: 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,
+								"LDAP RealTime: Failed to query database. Check debug for more info.\n");
+						ast_log(LOG_WARNING, "LDAP RealTime: Query: %s\n",
+								filter);
+						ast_log(LOG_WARNING,
+								"LDAP RealTime: 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 =
+								malloc(sizeof(struct ast_variable *) *
+									   (num_entry + 1));
+							memset(vars, 0,
+								   sizeof(struct ast_variable *) *
+								   (num_entry + 1));
+							ast_log(LOG_DEBUG,
+									"LDAP RealTime (%d): num_entry: %d\n",
+									__LINE__, 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);
+								ast_variable_log("LDAP RealTime: Found Entry",
+												 vars[entry_index]);
+								ldap_entry =
+									ldap_next_entry(ldapConn, ldap_entry);
+								ast_log(LOG_DEBUG,
+										"LDAP RealTime (%d): next entry: %p\n",
+										__LINE__, ldap_entry);
+							};
+						} else {
+							ast_log(LOG_WARNING,
+									"LDAP RealTime: 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);
+										ast_log(LOG_DEBUG,
+												"LDAP RealTime (%d): Loaded base: %s\n",
+												__LINE__, tmp->value);
+										ast_variable_log("Base Variables",
+														 base_var);
+										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)
+{
+	ast_log(LOG_DEBUG,
+			"LDAP RealTime (%d): realtime_ldap: basedn: %s table_name: %s\n",
+			__LINE__, basedn, table_name);
+	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);
+	}
+	ast_variable_log("LDAP RealTime: ==> Found Entry", var);
+	return var;
+}
+
+/*! \brief See Asterisk doc */
+static struct ast_config *realtime_multi_ldap(const char *basedn,
+					      const char *table_name,
+					      va_list ap)
+{
+	ast_log(LOG_DEBUG,
+			"LDAP RealTime (%d): realtime_multi_ldap: basedn: %s table_name: %s\n",
+			__LINE__, basedn, table_name);
+	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;
+
+}
+struct category_and_metric {
+	char *name;
+	int metric;
+	char *variable_name;
+	char *variable_value;
+};
+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)
+{
+	ast_log(LOG_DEBUG,
+			"LDAP RealTime (%d): config_ldap: basedn: %s table_name: %s\n",
+			__LINE__, basedn, table_name);
+	if (!file || !strcmp(file, RES_CONFIG_LDAP_CONF)) {
+		ast_log(LOG_WARNING, "LDAP RealTime: 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");
+				ast_log(LOG_DEBUG, "LDAP RealTime: category: %s\n",
+						category->value);
+				ast_log(LOG_DEBUG, "LDAP RealTime: var_name: %s\n",
+						var_name->value);
+				ast_log(LOG_DEBUG, "LDAP RealTime: var_val: %s\n",
+						var_val->value);
+				ast_log(LOG_DEBUG, "LDAP RealTime: cat_metric: %s\n",
+						cat_metric->value);
+				if (!category) {
+					struct ast_variable *dn = variable_named(*p, "dn");

[... 369 lines stripped ...]


More information about the asterisk-commits mailing list