Newer
Older
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2005, Oxymium sarl
* Manuel Guesdon <mguesdon@oxymium.net> - LDAP RealTime Driver Author/Adaptor
*
* Copyright (C) 2007, Digium, Inc.
* Russell Bryant <russell@digium.com>
*
* 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@digium.com>
* \author Manuel Guesdon
* \author Carl-Einar Thorner <cthorner@voicerd.com>
* \author Russell Bryant <russell@digium.com>
*
/*! \li \ref res_config_ldap.c uses the configuration file \ref res_ldap.conf
* \addtogroup configuration_file Configuration Files
*/
* \page res_ldap.conf res_ldap.conf
* \verbinclude res_ldap.conf.sample
*/
/*** MODULEINFO
<depend>ldap</depend>
<support_level>extended</support_level>
***/
#include "asterisk.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <ldap.h>
#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"
#define RES_CONFIG_LDAP_CONF "res_ldap.conf"
#define RES_CONFIG_LDAP_DEFAULT_BASEDN "asterisk"
AST_MUTEX_DEFINE_STATIC(ldap_lock);
static LDAP *ldapConn;
Tilghman Lesher
committed
static char url[512];
static char base_distinguished_name[512];
static time_t connect_time;
static int parse_config(void);
static int ldap_reconnect(void);
static char *realtime_ldap_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
struct category_and_metric {
const char *name;
int metric;
const char *variable_name;
const char *variable_value;
int var_metric; /*!< For organizing variables (particularly includes and switch statements) within a context */
/*! \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 ast_variable *delimiters; /*!< the current delimiter is semicolon, so we are not using this variable */
AST_LIST_ENTRY(ldap_table_config) entry;
/*! \brief Should be locked before using it
static AST_LIST_HEAD_NOLOCK_STATIC(table_configs, ldap_table_config);
static struct ldap_table_config *base_table_config;
static struct ldap_table_config *static_table_config;
static struct ast_cli_entry ldap_cli[] = {
AST_CLI_DEFINE(realtime_ldap_status, "Shows connection information for the LDAP RealTime driver"),
};
static struct ldap_table_config *table_config_new(const char *table_name)
{
struct ldap_table_config *p;
if (!(p = ast_calloc(1, sizeof(*p))))
return NULL;
if (table_name) {
if (!(p->table_name = ast_strdup(table_name))) {
ast_free(p);
return NULL;
}
}
return p;
}
* Should be locked before using it
* \note This function assumes ldap_lock to be locked.
*/
static struct ldap_table_config *table_config_for_table_name(const char *table_name)
{
struct ldap_table_config *c = NULL;
AST_LIST_TRAVERSE(&table_configs, c, entry) {
if (!strcmp(c->table_name, table_name))
break;
}
return c;
}
static struct ast_variable *variable_named(struct ast_variable *var, const char *name)
{
for (; var; var = var->next) {
if (!strcasecmp(name, var->name))
break;
}
return var;
}
* \param somestr - pointer to a string
*
* \return number of occurances of the delimiter(semicolon)
*/
static int semicolon_count_str(const char *somestr)
{
int count = 0;
for (; *somestr; somestr++) {
if (*somestr == ';')
count++;
}
return count;
* takes a linked list of \a ast_variable variables, finds the one with the name variable_value
* and returns the number of semicolons in the value for that \a ast_variable
*/
static int semicolon_count_var(struct ast_variable *var)
{
struct ast_variable *var_value = variable_named(var, "variable_value");
Olle Johansson
committed
if (!var_value) {
Olle Johansson
committed
}
ast_debug(2, "semicolon_count_var: %s\n", var_value->value);
return semicolon_count_str(var_value->value);
}
/*! \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_name, const char *attribute_value)
{
struct ast_variable *var;
Olle Johansson
committed
if (ast_strlen_zero(attribute_name) || ast_strlen_zero(attribute_value)) {
Olle Johansson
committed
}
Olle Johansson
committed
if (!(var = ast_variable_new(attribute_name, attribute_value, table_config->table_name))) {
Olle Johansson
committed
}
Olle Johansson
committed
if (table_config->attributes) {
var->next = table_config->attributes;
Olle Johansson
committed
}
table_config->attributes = var;
}
static void table_configs_free(void)
{
struct ldap_table_config *c;
while ((c = AST_LIST_REMOVE_HEAD(&table_configs, entry))) {
Olle Johansson
committed
if (c->table_name) {
ast_free(c->table_name);
}
if (c->additional_filter) {
ast_free(c->additional_filter);
}
if (c->attributes) {
ast_variables_destroy(c->attributes);
Olle Johansson
committed
}
ast_free(c);
}
base_table_config = NULL;
static_table_config = NULL;
}
/*! \brief Convert variable name to ldap attribute name
*
static const char *convert_attribute_name_to_ldap(struct ldap_table_config *table_config,
const char *attribute_name)
{
int i = 0;
struct ldap_table_config *configs[] = { table_config, base_table_config };
for (i = 0; i < ARRAY_LEN(configs); i++) {
struct ast_variable *attribute;
Olle Johansson
committed
if (!configs[i]) {
Olle Johansson
committed
}
attribute = configs[i]->attributes;
for (; attribute; attribute = attribute->next) {
Olle Johansson
committed
if (!strcasecmp(attribute_name, attribute->name)) {
return attribute->value;
Olle Johansson
committed
}
}
}
return attribute_name;
}
/*! \brief Convert ldap attribute name to variable name
static const char *convert_attribute_name_from_ldap(struct ldap_table_config *table_config,
const char *attribute_name)
{
int i = 0;
struct ldap_table_config *configs[] = { table_config, base_table_config };
for (i = 0; i < ARRAY_LEN(configs); i++) {
struct ast_variable *attribute;
Olle Johansson
committed
if (!configs[i]) {
Olle Johansson
committed
}
attribute = configs[i]->attributes;
for (; attribute; attribute = attribute->next) {
Olle Johansson
committed
if (strcasecmp(attribute_name, attribute->value) == 0) {
Olle Johansson
committed
}
}
}
return attribute_name;
}
/*! \brief Get variables from ldap entry attributes
* \note Should be locked before using it
* \return a linked list of ast_variable variables.
Olle Johansson
committed
*/
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;
int is_delimited = 0;
int i = 0;
char *ldap_attribute_name;
struct berval *value;
int pos = 0;
ldap_attribute_name = ldap_first_attribute(ldapConn, ldap_entry, &ber);
while (ldap_attribute_name) {
struct berval **values = NULL;
const char *attribute_name = convert_attribute_name_from_ldap(table_config, ldap_attribute_name);
int is_realmed_password_attribute = strcasecmp(attribute_name, "md5secret") == 0;
values = ldap_get_values_len(ldapConn, ldap_entry, ldap_attribute_name); /* these are freed at the end */
struct berval **v;
char *valptr;
for (v = values; *v; v++) {
valptr = value->bv_val;
ast_debug(2, "attribute_name: %s LDAP value: %s\n", attribute_name, valptr);
if (is_realmed_password_attribute) {
if (!strncasecmp(valptr, "{md5}", 5)) {
valptr += 5;
}
ast_debug(2, "md5: %s\n", valptr);
if (valptr) {
/* ok, so looping through all delimited values except the last one (not, last character is not delimited...) */
if (is_delimited) {
i = 0;
pos = 0;
while (!ast_strlen_zero(valptr + i)) {
Olle Johansson
committed
if (valptr[i] == ';') {
valptr[i] = '\0';
prev->next = ast_variable_new(attribute_name, &valptr[pos], table_config->table_name);
if (prev->next) {
prev = prev->next;
}
} else {
prev = var = ast_variable_new(attribute_name, &valptr[pos], table_config->table_name);
}
pos = i + 1;
}
i++;
}
}
/* for the last delimited value or if the value is not delimited: */
if (prev) {
prev->next = ast_variable_new(attribute_name, &valptr[pos], table_config->table_name);
if (prev->next) {
prev = prev->next;
}
} else {
prev = var = ast_variable_new(attribute_name, &valptr[pos], table_config->table_name);
ldap_value_free_len(values);
ldap_memfree(ldap_attribute_name);
ldap_attribute_name = ldap_next_attribute(ldapConn, ldap_entry, ber);
}
ber_free(ber, 0);
return var;
}
/*! \brief Get variables from ldap entry attributes - Should be locked before using it
*
* The results are freed outside this function so is the \a vars array.
* \return \a vars - an array of ast_variable variables terminated with a null.
static struct ast_variable **realtime_ldap_result_to_vars(struct ldap_table_config *table_config,
LDAPMessage *ldap_result_msg, unsigned int *entries_count_ptr)
struct ast_variable **vars;
int i = 0;
int tot_count = 0;
int entry_index = 0;
LDAPMessage *ldap_entry = NULL;
BerElement *ber = NULL;
struct ast_variable *var = NULL;
struct ast_variable *prev = NULL;
int is_delimited = 0;
char *delim_value = NULL;
int delim_tot_count = 0;
int delim_count = 0;
ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
for (tot_count = 0; ldap_entry; tot_count++) {
struct ast_variable *tmp = realtime_ldap_entry_to_var(table_config, ldap_entry);
tot_count += semicolon_count_var(tmp);
ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
Olle Johansson
committed
if (entries_count_ptr) {
*entries_count_ptr = tot_count;
Olle Johansson
committed
}
/*! \note Now that we have the total count we allocate space and create the variables
* Remember that each element in vars is a linked list that points to realtime variable.
* If the we are dealing with a static realtime variable we create a new element in the \a vars array for each delimited
* value in \a variable_value; otherwise, we keep \a vars static and increase the length of the linked list of variables in the array element.
* This memory must be freed outside of this function.
*/
vars = ast_calloc(tot_count + 1, sizeof(struct ast_variable *));
ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
/*! \brief For each static realtime variable we may create several entries in the \a vars array if it's delimited
for (entry_index = 0; ldap_entry; ) {
int pos = 0;
delim_value = NULL;
delim_tot_count = 0;
delim_count = 0;
char *ldap_attribute_name = ldap_first_attribute(ldapConn, ldap_entry, &ber);
struct berval *value;
while (ldap_attribute_name) {
Olle Johansson
committed
const char *attribute_name = convert_attribute_name_from_ldap(table_config, ldap_attribute_name);
int is_realmed_password_attribute = strcasecmp(attribute_name, "md5secret") == 0;
struct berval **values = NULL;
values = ldap_get_values_len(ldapConn, ldap_entry, ldap_attribute_name);
if (values) {
struct berval **v;
char *valptr;
for (v = values; *v; v++) {
valptr = value->bv_val;
if (is_realmed_password_attribute) {
if (strncasecmp(valptr, "{md5}", 5) == 0) {
valptr += 5;
}
ast_debug(2, "md5: %s\n", valptr);
if (valptr) {
if (delim_value == NULL && !is_realmed_password_attribute
&& (static_table_config != table_config || strcmp(attribute_name, "variable_value") == 0)) {
delim_value = ast_strdup(valptr);
if ((delim_tot_count = semicolon_count_str(delim_value)) > 0) {
ast_debug(4, "is delimited %d times: %s\n", delim_tot_count, delim_value);
is_delimited = 1;
}
}
if (is_delimited != 0 && !is_realmed_password_attribute
&& (static_table_config != table_config || strcmp(attribute_name, "variable_value") == 0) ) {
/* for non-Static RealTime, first */
for (i = pos; !ast_strlen_zero(valptr + i); i++) {
ast_debug(4, "DELIM pos: %d i: %d\n", pos, i);
delim_value[i] = '\0';
ast_debug(2, "DELIM - attribute_name: %s value: %s pos: %d\n", attribute_name, &delim_value[pos], pos);
if (prev) {
prev->next = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name);
if (prev->next) {
prev = prev->next;
}
} else {
prev = var = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name);
}
pos = i + 1;
break;
}
}
}
if (ast_strlen_zero(valptr + i)) {
ast_debug(4, "DELIM pos: %d i: %d delim_count: %d\n", pos, i, delim_count);
/* Last delimited value */
ast_debug(4, "DELIM - attribute_name: %s value: %s pos: %d\n", attribute_name, &delim_value[pos], pos);
if (prev) {
prev->next = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name);
if (prev->next) {
prev = prev->next;
}
} else {
prev = var = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name);
}
/* Remembering to free memory */
is_delimited = 0;
ast_free(delim_value);
delim_value = NULL;
ast_debug(4, "DELIM pos: %d i: %d\n", pos, i);
} else {
/* not delimited */
if (delim_value) {
ast_free(delim_value);
delim_value = NULL;
}
ast_debug(2, "attribute_name: %s value: %s\n", attribute_name, valptr);
prev->next = ast_variable_new(attribute_name, valptr, table_config->table_name);
if (prev->next) {
prev = prev->next;
}
} else {
prev = var = ast_variable_new(attribute_name, valptr, table_config->table_name);
} /*!< for (v = values; *v; v++) */
ldap_value_free_len(values);
ldap_memfree(ldap_attribute_name);
ldap_attribute_name = ldap_next_attribute(ldapConn, ldap_entry, ber);
} /*!< while (ldap_attribute_name) */
ber_free(ber, 0);
if (DEBUG_ATLEAST(3)) {
const struct ast_variable *tmpdebug = variable_named(var, "variable_name");
const struct ast_variable *tmpdebug2 = variable_named(var, "variable_value");
if (tmpdebug && tmpdebug2) {
ast_log(LOG_DEBUG, "Added to vars - %s = %s\n", tmpdebug->value, tmpdebug2->value);
}
}
vars[entry_index++] = var;
prev = NULL;
}
delim_count++;
} while (delim_count <= delim_tot_count && static_table_config == table_config);
if (static_table_config != table_config) {
ast_debug(3, "Added to vars - non static\n");
vars[entry_index++] = var;
prev = NULL;
}
ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
} /*!< end for loop over ldap_entry */
return vars;
}
static int is_ldap_connect_error(int err)
{
Olle Johansson
committed
return (err == LDAP_SERVER_DOWN || err == LDAP_TIMEOUT || err == LDAP_CONNECT_ERROR);
/*! \brief Get LDAP entry by dn and return attributes as variables
*
* Should be locked before using it
*
* This is used for setting the default values of an object
* i.e., with accountBaseDN
*/
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 **vars = NULL;
struct ast_variable *var = NULL;
int result = -1;
LDAPMessage *ldap_result_msg = NULL;
int tries = 0;
ast_debug(2, "ldap_loadentry dn=%s\n", dn);
do {
result = ldap_search_ext_s(ldapConn, dn, LDAP_SCOPE_BASE,
"(objectclass=*)", NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &ldap_result_msg);
if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
ast_log(LOG_WARNING, "Failed to query directory. Try %d/3\n", tries + 1);
tries++;
if (tries < 3) {
usleep(500000L * tries);
if (ldapConn) {
Olle Johansson
committed
if (!ldap_reconnect()) {
Olle Johansson
committed
}
} while (result != LDAP_SUCCESS && tries < 3 && is_ldap_connect_error(result));
ast_log(LOG_WARNING, "Failed to query directory. Error: %s.\n", ldap_err2string(result));
ast_debug(2, "dn=%s\n", dn);
ast_mutex_unlock(&ldap_lock);
return NULL;
} else {
int num_entry = 0;
unsigned int *entries_count_ptr = NULL; /*!< not using this */
Olle Johansson
committed
if ((num_entry = ldap_count_entries(ldapConn, ldap_result_msg)) > 0) {
ast_debug(3, "num_entry: %d\n", num_entry);
vars = realtime_ldap_result_to_vars(table_config, ldap_result_msg, entries_count_ptr);
Olle Johansson
committed
if (num_entry > 1) {
Tilghman Lesher
committed
ast_log(LOG_NOTICE, "More than one entry for dn=%s. Take only 1st one\n", dn);
Olle Johansson
committed
}
Tilghman Lesher
committed
ast_debug(2, "Could not find any entry dn=%s.\n", dn);
ldap_msgfree(ldap_result_msg);
/* Chopping \a vars down to one variable */
struct ast_variable **p = vars;
/* Only take the first one. */
var = *vars;
/* Destroy the rest. */
while (*++p) {
ast_variables_destroy(*p);
ast_free(vars);
return var;
}
}
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);
}
Olle Johansson
committed
ast_debug(2, "substituted: string: '%s' => '%s' \n", string, ret_string);
return ret_string;
}
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
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++;
}
}
ast_debug(2, "basedn: '%s' => '%s' \n", basedn, cbasedn);
return cbasedn;
}
/*! \brief Replace \<search\> by \<by\> in string.
* \note 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);
Olle Johansson
committed
if (p) {
replaced = 1;
while (p) {
Olle Johansson
committed
if (by_len == search_len) {
Olle Johansson
committed
} 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.
static void append_var_and_value_to_filter(struct ast_str **filter,
struct ldap_table_config *table_config,
const char *name, const char *value)
{
char *new_name = NULL;
char *new_value = NULL;
char *like_pos = strstr(name, " LIKE");
ast_debug(2, "name='%s' value='%s'\n", name, value);
if (like_pos) {
Olle Johansson
committed
name = new_name = ast_strdupa(name);
new_name[len] = '\0';
value = new_value = ast_strdupa(value);
replace_string_in_string(new_value, "\\_", "_");
replace_string_in_string(new_value, "%", "*");
}
name = convert_attribute_name_to_ldap(table_config, name);
ast_str_append(filter, 0, "(%s=%s)", name, value);
}
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
/*!
* \internal
* \brief Create an LDAP filter using search fields
*
* \param config the \c ldap_table_config for this search
* \param fields the \c ast_variable criteria to include
*
* \returns an \c ast_str pointer on success, NULL otherwise.
*/
static struct ast_str *create_lookup_filter(struct ldap_table_config *config, const struct ast_variable *fields)
{
struct ast_str *filter;
const struct ast_variable *field;
filter = ast_str_create(80);
if (!filter) {
return NULL;
}
/*
* Create the filter with the table additional filter and the
* parameter/value pairs we were given
*/
ast_str_append(&filter, 0, "(&");
if (config && config->additional_filter) {
ast_str_append(&filter, 0, "%s", config->additional_filter);
}
if (config != base_table_config
&& base_table_config
&& base_table_config->additional_filter) {
ast_str_append(&filter, 0, "%s", base_table_config->additional_filter);
}
/* Append the lookup fields */
for (field = fields; field; field = field->next) {
append_var_and_value_to_filter(&filter, config, field->name, field->value);
}
ast_str_append(&filter, 0, ")");
return filter;
}
/*! \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
* \param entries_count_ptr is a pointer to found entries count (can be NULL)
* \param basedn is the base DN
* \param table_name is the table_name (used dor attribute convertion and additional filter)
* \param fields contains list of pairs name/value
static struct ast_variable **realtime_ldap_base_ap(unsigned int *entries_count_ptr,
const char *basedn, const char *table_name, const struct ast_variable *fields)
{
struct ast_variable **vars = NULL;
const struct ast_variable *field = fields;
struct ldap_table_config *table_config = NULL;
char *clean_basedn = cleaned_basedn(NULL, basedn);
struct ast_str *filter = NULL;
int tries = 0;
int result = 0;
LDAPMessage *ldap_result_msg = NULL;
Olle Johansson
committed
ast_log(LOG_ERROR, "No table_name specified.\n");
Olle Johansson
committed
ast_log(LOG_ERROR, "Realtime retrieval requires at least 1 parameter"
" and 1 value to search on.\n");
return NULL;
}
ast_mutex_lock(&ldap_lock);
/* We now have our complete statement; Lets connect to the server and execute it. */
if (!ldap_reconnect()) {
ast_mutex_unlock(&ldap_lock);
table_config = table_config_for_table_name(table_name);
if (!table_config) {
ast_log(LOG_WARNING, "No table named '%s'.\n", table_name);
ast_mutex_unlock(&ldap_lock);
filter = create_lookup_filter(table_config, fields);
if (!filter) {
ast_mutex_unlock(&ldap_lock);
ast_free(clean_basedn);
return NULL;
}
do {
/* freeing ldap_result further down */
result = ldap_search_ext_s(ldapConn, clean_basedn,
LDAP_SCOPE_SUBTREE, ast_str_buffer(filter), NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
&ldap_result_msg);
if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
ast_debug(1, "Failed to query directory. Try %d/10\n", tries + 1);
Olle Johansson
committed
if (!ldap_reconnect()) {
Olle Johansson
committed
}
} while (result != LDAP_SUCCESS && tries < 10 && is_ldap_connect_error(result));
ast_log(LOG_WARNING, "Failed to query directory. Error: %s.\n", ldap_err2string(result));
ast_log(LOG_WARNING, "Query: %s\n", ast_str_buffer(filter));
/* this is where we create the variables from the search result
* freeing this \a vars outside this function */
if (ldap_count_entries(ldapConn, ldap_result_msg) > 0) {
/* is this a static var or some other? they are handled different for delimited values */
vars = realtime_ldap_result_to_vars(table_config, ldap_result_msg, entries_count_ptr);
Olle Johansson
committed
ast_debug(1, "Could not find any entry matching %s in base dn %s.\n", ast_str_buffer(filter), clean_basedn);
ldap_msgfree(ldap_result_msg);
/*! \todo get the default variables from the accountBaseDN, not implemented with delimited values
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) {
/* Get the variable to compare with for the defaults */
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;
/* run throught the default values and fill it inn if it is missing */
while (test_var) {
if (strcasecmp(test_var->name, base_var->name) == 0) {
base_var_found = 1;
break;
Olle Johansson
committed
} else {
test_var = test_var->next;
Olle Johansson
committed
}
}
if (base_var_found) {
base_var->next = NULL;
base_var = next;
} else {
/*!
* \todo XXX The interactions with base_var and append_var may
* cause a memory leak of base_var nodes. Also the append_var
* list and base_var list may get cross linked.
*/
Olle Johansson
committed
if (append_var) {
base_var->next = append_var;
Olle Johansson
committed
} else {
Olle Johansson
committed
}
append_var = base_var;
base_var = next;
}
}
}
if (!tmp->next && append_var) {
tmp->next = append_var;
tmp = NULL;
Olle Johansson
committed
} else {
Olle Johansson
committed
}
}
p++;
}
}
}
ast_free(filter);
ast_free(clean_basedn);
ast_mutex_unlock(&ldap_lock);
return vars;
}
static struct ast_variable *realtime_arguments_to_fields(va_list ap)
{
struct ast_variable *fields = NULL;
const char *newparam, *newval;
while ((newparam = va_arg(ap, const char *))) {
struct ast_variable *field;
newval = va_arg(ap, const char *);
if (!(field = ast_variable_new(newparam, newval, ""))) {
ast_variables_destroy(fields);
return NULL;
}
field->next = fields;
fields = field;
}
return fields;
}
/*! \brief same as realtime_ldap_base_ap 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, ...)
{
RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
struct ast_variable **vars = NULL;
va_list ap;
va_start(ap, table_name);
fields = realtime_arguments_to_fields(ap);
vars = realtime_ldap_base_ap(entries_count_ptr, basedn, table_name, fields);