2 * Asterisk -- A telephony toolkit for Linux.
4 * Copyright (C) 2005, Oxymium sarl
5 * Manuel Guesdon <mguesdon@oxymium.net> - LDAP RealTime Driver Author/Adaptor
7 * Copyright (C) 2007, Digium, Inc.
8 * Russell Bryant <russell@digium.com>
10 * See http://www.asterisk.org for more information about
11 * the Asterisk project. Please do not directly contact
12 * any of the maintainers of this project for assistance;
13 * the project provides a web site, mailing lists and IRC
14 * channels for your use.
16 * This program is free software, distributed under the terms of
17 * the GNU General Public License Version 2. See the LICENSE file
18 * at the top of the source tree.
24 * \brief ldap plugin for portable configuration engine (ARA)
26 * \author Mark Spencer <markster@digium.com>
27 * \author Manuel Guesdon
28 * \author Carl-Einar Thorner <cthorner@voicerd.com>
29 * \author Russell Bryant <russell@digium.com>
31 * \arg http://www.openldap.org
46 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
48 #include "asterisk/channel.h"
49 #include "asterisk/logger.h"
50 #include "asterisk/config.h"
51 #include "asterisk/module.h"
52 #include "asterisk/lock.h"
53 #include "asterisk/options.h"
54 #include "asterisk/cli.h"
55 #include "asterisk/utils.h"
56 #include "asterisk/strings.h"
57 #include "asterisk/pbx.h"
58 #include "asterisk/linkedlists.h"
60 #define RES_CONFIG_LDAP_CONF "res_ldap.conf"
62 AST_MUTEX_DEFINE_STATIC(ldap_lock);
64 static LDAP *ldapConn;
65 static char host[512];
66 static char user[512];
68 static char basedn[512];
69 static int port = 389;
70 static time_t connect_time;
72 static int parse_config(void);
73 static int ldap_reconnect(void);
74 static char *realtime_ldap_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
76 struct category_and_metric {
79 const char *variable_name;
80 const char *variable_value;
81 int var_metric; /*!< For organizing variables (particularly includes and switch statments) within a context */
84 /*! \brief Table configuration */
85 struct ldap_table_config {
86 char *table_name; /*!< table name */
87 char *additional_filter; /*!< additional filter */
88 struct ast_variable *attributes; /*!< attribute names conversion */
89 struct ast_variable *delimiters; /*!< the current delimiter is semicolon, so we are not using this variable */
90 AST_LIST_ENTRY(ldap_table_config) entry;
93 /*! \brief Should be locked before using it */
94 static AST_LIST_HEAD_NOLOCK_STATIC(table_configs, ldap_table_config);
95 static struct ldap_table_config *base_table_config;
96 static struct ldap_table_config *static_table_config;
98 static struct ast_cli_entry ldap_cli[] = {
99 AST_CLI_DEFINE(realtime_ldap_status, "Shows connection information for the LDAP RealTime driver"),
102 /*! \brief Create a new table_config */
103 static struct ldap_table_config *table_config_new(const char *table_name)
105 struct ldap_table_config *p;
107 if (!(p = ast_calloc(1, sizeof(*p))))
111 if (!(p->table_name = ast_strdup(table_name))) {
120 /*! \brief Find a table_config - Should be locked before using it
121 * \note This function assumes ldap_lock to be locked. */
122 static struct ldap_table_config *table_config_for_table_name(const char *table_name)
124 struct ldap_table_config *c = NULL;
126 AST_LIST_TRAVERSE(&table_configs, c, entry) {
127 if (!strcmp(c->table_name, table_name))
134 /*! \brief Find variable by name */
135 static struct ast_variable *variable_named(struct ast_variable *var, const char *name)
137 for (; var; var = var->next) {
138 if (!strcasecmp(name, var->name))
145 /*! \brief for the semicolon delimiter
146 \param somestr - pointer to a string
148 \return number of occurances of the delimiter(semicolon)
150 static int semicolon_count_str(const char *somestr)
154 for (; *somestr; somestr++) {
162 /* takes a linked list of \a ast_variable variables, finds the one with the name variable_value
163 * and returns the number of semicolons in the value for that \a ast_variable
165 static int semicolon_count_var(struct ast_variable *var)
167 struct ast_variable *var_value = variable_named(var, "variable_value");
172 ast_debug(1, "LINE(%d) semicolon_count_var: %s\n", __LINE__, var_value->value);
174 return semicolon_count_str(var_value->value);
177 /*! \brief add attribute to table config - Should be locked before using it */
178 static void ldap_table_config_add_attribute(struct ldap_table_config *table_config,
179 const char *attribute_name, const char *attribute_value)
181 struct ast_variable *var;
183 if (ast_strlen_zero(attribute_name) || ast_strlen_zero(attribute_value))
186 if (!(var = ast_variable_new(attribute_name, attribute_value, table_config->table_name)))
189 if (table_config->attributes)
190 var->next = table_config->attributes;
191 table_config->attributes = var;
194 /*! \brief Free table_config
195 * \note assumes ldap_lock to be locked */
196 static void table_configs_free(void)
198 struct ldap_table_config *c;
200 while ((c = AST_LIST_REMOVE_HEAD(&table_configs, entry))) {
203 if (c->additional_filter)
204 free(c->additional_filter);
206 ast_variables_destroy(c->attributes);
210 base_table_config = NULL;
211 static_table_config = NULL;
214 /*! \brief Convert variable name to ldap attribute name - Should be locked before using it */
215 static const char *convert_attribute_name_to_ldap(struct ldap_table_config *table_config,
216 const char *attribute_name)
219 struct ldap_table_config *configs[] = { table_config, base_table_config };
221 for (i = 0; i < ARRAY_LEN(configs); i++) {
222 struct ast_variable *attribute;
227 attribute = configs[i]->attributes;
228 for (; attribute; attribute = attribute->next) {
229 if (!strcasecmp(attribute_name, attribute->name))
230 return attribute->value;
234 return attribute_name;
237 /*! \brief Convert ldap attribute name to variable name - Should be locked before using it */
238 static const char *convert_attribute_name_from_ldap(struct ldap_table_config *table_config,
239 const char *attribute_name)
242 struct ldap_table_config *configs[] = { table_config, base_table_config };
244 for (i = 0; i < ARRAY_LEN(configs); i++) {
245 struct ast_variable *attribute;
250 attribute = configs[i]->attributes;
251 for (; attribute; attribute = attribute->next) {
252 if (strcasecmp(attribute_name, attribute->value) == 0)
253 return attribute->name;
257 return attribute_name;
260 /*! \brief Get variables from ldap entry attributes - Should be locked before using it
261 * \return a linked list of ast_variable variables.
263 static struct ast_variable *realtime_ldap_entry_to_var(struct ldap_table_config *table_config,
264 LDAPMessage *ldap_entry)
266 BerElement *ber = NULL;
267 struct ast_variable *var = NULL;
268 struct ast_variable *prev = NULL;
269 int is_delimited = 0;
271 char *ldap_attribute_name;
272 struct berval *value;
275 ldap_attribute_name = ldap_first_attribute(ldapConn, ldap_entry, &ber);
277 while (ldap_attribute_name) {
278 struct berval **values = NULL;
279 const char *attribute_name = convert_attribute_name_from_ldap(table_config,ldap_attribute_name);
280 int is_realmed_password_attribute = strcasecmp(attribute_name, "md5secret") == 0;
282 values = ldap_get_values_len(ldapConn, ldap_entry, ldap_attribute_name);/*these are freed at the end*/
284 struct berval **v = values;
288 ast_debug(2, "LINE(%d) attribute_name: %s LDAP value: %s\n", __LINE__, attribute_name, value->bv_val);
289 if (is_realmed_password_attribute) {
290 if (!strncasecmp(value->bv_val, "{md5}", 5))
293 value->bv_val = NULL;
294 ast_debug(2, "md5: %s\n", value->bv_val);
297 /* ok, so looping through all delimited values except the last one (not, last character is not delimited...) */
301 while (!ast_strlen_zero(value->bv_val + i)) {
302 if (value->bv_val[i] == ';'){
303 value->bv_val[i] = '\0';
305 prev->next = ast_variable_new(attribute_name, &value->bv_val[pos], table_config->table_name);
310 prev = var = ast_variable_new(attribute_name, &value->bv_val[pos], table_config->table_name);
317 /* for the last delimited value or if the value is not delimited: */
319 prev->next = ast_variable_new(attribute_name, &value->bv_val[pos], table_config->table_name);
324 prev = var = ast_variable_new(attribute_name, &value->bv_val[pos], table_config->table_name);
329 ber_bvecfree(values);
331 ldap_attribute_name = ldap_next_attribute(ldapConn, ldap_entry, ber);
338 /*! \brief Get variables from ldap entry attributes - Should be locked before using it
340 * The results are freed outside this function so is the \a vars array.
342 * \return \a vars - an array of ast_variable variables terminated with a null.
344 static struct ast_variable **realtime_ldap_result_to_vars(struct ldap_table_config *table_config,
345 LDAPMessage * ldap_result, unsigned int *entries_count_ptr)
347 struct ast_variable ** vars;
351 LDAPMessage *ldap_entry = NULL;
352 BerElement *ber = NULL;
353 struct ast_variable *var = NULL;
354 struct ast_variable *prev = NULL;
356 char * delim_value = NULL;
357 int delim_tot_count = 0;
360 /* First find the total count */
361 ldap_entry = ldap_first_entry(ldapConn, ldap_result);
363 for (tot_count = 0; ldap_entry; tot_count++){
364 tot_count += semicolon_count_var( realtime_ldap_entry_to_var(table_config,ldap_entry) );
365 ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
368 if (entries_count_ptr)
369 *entries_count_ptr = tot_count;
370 /* Now that we have the total count we allocate space and create the variables
371 * Remember that each element in vars is a linked list that points to realtime variable.
372 * If the we are dealing with a static realtime variable we create a new element in the \a vars array for each delimited
373 * 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.
374 * This memory must be freed outside of this function. */
375 vars = ast_calloc(1, sizeof(struct ast_variable *) *(tot_count + 1));
377 ldap_entry = ldap_first_entry(ldapConn, ldap_result);
382 /*For each static realtime variable we may create several entries in the \a vars array if it's delimited*/
383 for (entry_index = 0; ldap_entry; ){
389 do {/* while delim_count */
391 /*Starting new static var*/
392 char *ldap_attribute_name = ldap_first_attribute(ldapConn, ldap_entry, &ber);
394 struct berval *value;
395 while (ldap_attribute_name) {
397 const char *attribute_name =
398 convert_attribute_name_from_ldap(table_config,ldap_attribute_name);
399 int is_realmed_password_attribute = strcasecmp(attribute_name, "md5secret") == 0;
400 struct berval **values = NULL;
402 values = ldap_get_values_len(ldapConn, ldap_entry, ldap_attribute_name);
404 struct berval **v = values;
408 if (is_realmed_password_attribute) {
409 if (strncasecmp(value->bv_val, "{md5}", 5) == 0)
412 value->bv_val = NULL;
413 ast_debug(2, "md5: %s\n", value->bv_val);
417 if( delim_value == NULL
418 && !is_realmed_password_attribute
419 && (static_table_config != table_config || strcmp(attribute_name,"variable_value") == 0) ){
421 delim_value = ast_calloc(1,sizeof(char)*(strlen(value->bv_val)+1));
422 ast_copy_string(delim_value,value->bv_val,strlen(value->bv_val)+1);
424 if( (delim_tot_count = semicolon_count_str(delim_value)) > 0){
425 ast_debug(4, "LINE(%d) is delimited %d times: %s\n", __LINE__, delim_tot_count, delim_value);
430 if( is_delimited != 0
431 && !is_realmed_password_attribute
432 && (static_table_config != table_config || strcmp(attribute_name,"variable_value") == 0)){
433 /* for non-Static RealTime, first */
437 while ( !ast_strlen_zero(value->bv_val + i) ){
438 ast_debug(4, "LINE(%d) DELIM pos: %d i: %d\n", __LINE__, pos, i);
439 if (delim_value[i] == ';'){
440 delim_value[i] = '\0';
442 ast_debug(2, "LINE(%d) DELIM - attribute_name: %s value: %s pos: %d\n", __LINE__, attribute_name, &delim_value[pos], pos);
445 prev->next = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name);
450 prev = var = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name);
454 if(static_table_config == table_config){
460 if (ast_strlen_zero(value->bv_val + i)) {
461 ast_debug(4, "LINE(%d) DELIM pos: %d i: %d delim_count: %d\n", __LINE__, pos, i,delim_count);
462 /* Last delimited value */
463 ast_debug(4, "LINE(%d) DELIM - attribute_name: %s value: %s pos: %d\n", __LINE__, attribute_name, &delim_value[pos], pos);
465 prev->next = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name);
470 prev = var = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name);
472 /* Remembering to free memory */
479 ast_debug(4, "LINE(%d) DELIM pos: %d i: %d\n", __LINE__, pos, i);
486 ast_debug(2, "LINE(%d) attribute_name: %s value: %s\n", __LINE__, attribute_name, value->bv_val);
489 prev->next = ast_variable_new(attribute_name, value->bv_val, table_config->table_name);
494 prev = var = ast_variable_new(attribute_name, value->bv_val, table_config->table_name);
500 //ldap_value_free(values);
501 ber_bvecfree(values);
503 ldap_attribute_name = ldap_next_attribute(ldapConn, ldap_entry, ber);
504 } /*!< while (ldap_attribute_name) */
506 if(static_table_config == table_config){
507 if (option_debug > 2) {
508 const struct ast_variable *tmpdebug = variable_named(var, "variable_name");
509 const struct ast_variable *tmpdebug2 = variable_named(var, "variable_value");
510 if (tmpdebug && tmpdebug2) {
511 ast_debug(3, "LINE(%d) Added to vars - %s = %s\n", __LINE__, tmpdebug->value, tmpdebug2->value);
514 vars[entry_index++] = var;
519 } while(delim_count <= delim_tot_count && static_table_config == table_config );
520 if(static_table_config != table_config){
521 ast_debug(3, "LINE(%d) Added to vars - non static\n", __LINE__ );
523 vars[entry_index++] = var;
526 ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
527 } /*!< end for loop over ldap_entry */
533 static int is_ldap_connect_error(int err)
535 return (err == LDAP_SERVER_DOWN
536 || err == LDAP_TIMEOUT || err == LDAP_CONNECT_ERROR);
539 /*! \brief Get LDAP entry by dn and return attributes as variables - Should be locked before using it
540 This is used for setting the default values of an object(i.e., with accountBaseDN)
542 static struct ast_variable *ldap_loadentry(struct ldap_table_config *table_config,
546 ast_log(LOG_ERROR, "No table config\n");
549 struct ast_variable **vars = NULL;
550 struct ast_variable *var = NULL;
552 LDAPMessage *ldap_result = NULL;
555 ast_debug(2, "ldap_loadentry dn=%s\n", dn);
558 result = ldap_search_ext_s(ldapConn, dn, LDAP_SCOPE_BASE,
559 "(objectclass=*)", NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &ldap_result);
560 if (result < 0 && is_ldap_connect_error(result)) {
562 "Failed to query database. Try %d/3\n",
566 usleep(500000L * tries);
568 ldap_unbind_ext_s(ldapConn,NULL,NULL);
571 if (!ldap_reconnect())
575 } while (result < 0 && tries < 3 && is_ldap_connect_error(result));
579 "Failed to query database. Check debug for more info.\n");
580 ast_debug(2, "dn=%s\n", dn);
581 ast_debug(2, "Query Failed because: %s\n",
582 ldap_err2string(result));
583 ast_mutex_unlock(&ldap_lock);
587 unsigned int *entries_count_ptr=NULL; /*!< not using this*/
588 if ((num_entry = ldap_count_entries(ldapConn, ldap_result)) > 0) {
589 ast_debug(3, "num_entry: %d\n", num_entry);
591 vars = realtime_ldap_result_to_vars(table_config,ldap_result,entries_count_ptr);
593 ast_log(LOG_WARNING, "More than one entry for dn=%s. Take only 1st one\n", dn);
595 ast_log(LOG_WARNING, "Could not find any entry dn=%s.\n", dn);
598 ldap_msgfree(ldap_result);
600 /* Chopping \a vars down to one variable */
602 struct ast_variable **p = vars;
606 ast_variables_destroy(var);
609 vars = realloc(vars, sizeof(struct ast_variable *));
618 /*! \brief caller should free returned pointer */
619 static char *substituted(struct ast_channel *channel, const char *string)
621 #define MAXRESULT 2048
622 char *ret_string = NULL;
624 if (!ast_strlen_zero(string)) {
625 ret_string = ast_calloc(1, MAXRESULT);
626 pbx_substitute_variables_helper(channel, string, ret_string, MAXRESULT - 1);
628 ast_debug(2, "substituted: string: '%s' => '%s' \n",
633 /*! \brief caller should free returned pointer */
634 static char *cleaned_basedn(struct ast_channel *channel, const char *basedn)
636 char *cbasedn = NULL;
639 cbasedn = substituted(channel, basedn);
640 if (*cbasedn == '"') {
642 if (!ast_strlen_zero(cbasedn)) {
643 int len = strlen(cbasedn);
644 if (cbasedn[len - 1] == '"')
645 cbasedn[len - 1] = '\0';
656 ast_debug(2, "basedn: '%s' => '%s' \n", basedn, cbasedn);
660 /*! \brief Replace search by by in string. No check is done on string allocated size ! */
661 static int replace_string_in_string(char *string, const char *search,const char *by)
663 int search_len = strlen(search);
664 int by_len = strlen(by);
666 char *p = strstr(string, search);
670 if (by_len == search_len)
671 memcpy(p, by, by_len);
673 memmove(p + by_len, p + search_len,
674 strlen(p + search_len) + 1);
675 memcpy(p, by, by_len);
677 p = strstr(p + by_len, search);
683 /*! \brief Append a name=value filter string. The filter string can grow. */
684 /*! \brief convert name and value if "LIKE' is used (see http://bugs.digium.com/view.php?id=5765) */
685 static void append_var_and_value_to_filter(struct ast_str **filter,
686 struct ldap_table_config *table_config,
687 const char *name, const char *value)
689 char *new_name = NULL;
690 char *new_value = NULL;
691 char *like_pos = strstr(name, " LIKE");
693 ast_debug(2, "name='%s' value='%s'\n", name, value);
696 name = new_name = ast_strdupa(like_pos + strlen(" LIKE"));
697 value = new_value = ast_strdupa(value);
698 replace_string_in_string(new_value, "\\_", "_");
699 replace_string_in_string(new_value, "%", "*");
702 name = convert_attribute_name_to_ldap(table_config, name);
704 ast_str_append(filter, 0, "(%s=%s)", name, value);
707 /*! \brief LDAP base function
708 return a null terminated array of ast_variable (one per entry) or NULL if no entry is found or if an error occured
709 caller should free the returned array and ast_variables
710 entries_count_ptr is a pointer to found entries count (can be NULL)
711 basedn is the base DN
712 table_name is the table_name (used dor attribute convertion and additional filter)
713 ap contains null terminated list of pairs name/value
715 static struct ast_variable **realtime_ldap_base(unsigned int *entries_count_ptr,
716 const char *basedn, const char *table_name, va_list ap)
718 struct ast_variable **vars = NULL;
719 const char *newparam = NULL;
720 const char *newval = NULL;
721 struct ldap_table_config *table_config = NULL;
722 char *clean_basedn = cleaned_basedn(NULL, basedn);
723 struct ast_str *filter = NULL;
726 LDAPMessage *ldap_result = NULL;
729 ast_log(LOG_WARNING, "No table_name specified.\n");
733 if (!(filter = ast_str_create(80)))
736 /* Get the first parameter and first value in our list of passed paramater/value pairs */
737 newparam = va_arg(ap, const char *);
738 newval = va_arg(ap, const char *);
740 if (!newparam || !newval) {
741 ast_log(LOG_WARNING, "Realtime retrieval requires at least 1 parameter"
742 " and 1 value to search on.\n");
746 ast_mutex_lock(&ldap_lock);
748 /* We now have our complete statement; Lets connect to the server and execute it. */
749 if (!ldap_reconnect()) {
750 ast_mutex_unlock(&ldap_lock);
754 table_config = table_config_for_table_name(table_name);
756 ast_log(LOG_WARNING, "No table named '%s'.\n", table_name);
757 ast_mutex_unlock(&ldap_lock);
761 ast_str_append(&filter, 0, "(&");
763 if (table_config && table_config->additional_filter)
764 ast_str_append(&filter, 0, table_config->additional_filter);
765 if (table_config != base_table_config && base_table_config &&
766 base_table_config->additional_filter) {
767 ast_str_append(&filter, 0, base_table_config->additional_filter);
770 /* Create the first part of the query using the first parameter/value pairs we just extracted */
771 /* If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
773 append_var_and_value_to_filter(&filter, table_config, newparam, newval);
774 while ((newparam = va_arg(ap, const char *))) {
775 newval = va_arg(ap, const char *);
776 append_var_and_value_to_filter(&filter, table_config, newparam, newval);
778 ast_str_append(&filter, 0, ")");
781 /* freeing ldap_result further down */
782 result = ldap_search_ext_s(ldapConn, clean_basedn,
783 LDAP_SCOPE_SUBTREE, filter->str, NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
785 if (result < 0 && is_ldap_connect_error(result)) {
786 ast_log(LOG_WARNING, "Failed to query database. Try %d/3\n",
790 usleep(500000L * tries);
792 ldap_unbind_ext_s(ldapConn,NULL,NULL);
795 if (!ldap_reconnect())
799 } while (result < 0 && tries < 3 && is_ldap_connect_error(result));
802 ast_log(LOG_WARNING, "Failed to query database. Check debug for more info.\n");
803 ast_log(LOG_WARNING, "Query: %s\n", filter->str);
804 ast_log(LOG_WARNING, "Query Failed because: %s\n", ldap_err2string(result));
806 /* this is where we create the variables from the search result
807 * freeing this \a vars outside this function */
808 if (ldap_count_entries(ldapConn, ldap_result) > 0) {
809 //is this a static var or some other? they are handled different for delimited values
810 vars = realtime_ldap_result_to_vars(table_config,ldap_result,entries_count_ptr);
812 ast_log(LOG_WARNING, "Could not find any entry matching %s in base dn %s.\n",
813 filter->str, clean_basedn);
816 ldap_msgfree(ldap_result);
818 /* TODO: get the default variables from the accountBaseDN, not implemented with delimited values */
820 struct ast_variable **p = vars;
822 struct ast_variable *append_var = NULL;
823 struct ast_variable *tmp = *p;
825 if (strcasecmp(tmp->name, "accountBaseDN") == 0) {
826 /* Get the variable to compare with for the defaults */
827 struct ast_variable *base_var = ldap_loadentry(table_config, tmp->value);
830 struct ast_variable *next = base_var->next;
831 struct ast_variable *test_var = *p;
832 int base_var_found = 0;
834 /* run throught the default values and fill it inn if it is missing */
836 if (strcasecmp(test_var->name, base_var->name) == 0) {
840 test_var = test_var->next;
842 if (base_var_found) {
843 base_var->next = NULL;
844 ast_variables_destroy (base_var);
848 base_var->next = append_var;
850 base_var->next = NULL;
851 append_var = base_var;
856 if (!tmp->next && append_var) {
857 tmp->next = append_var;
873 ast_mutex_unlock(&ldap_lock);
878 /*! \brief same as realtime_ldap_base_ but take variable arguments count list */
879 static struct ast_variable **realtime_ldap_base_(unsigned int *entries_count_ptr,
880 const char *basedn, const char *table_name, ...)
882 struct ast_variable **vars = NULL;
885 va_start(ap, table_name);
886 vars = realtime_ldap_base(entries_count_ptr, basedn, table_name, ap);
892 /*! \brief See Asterisk doc
894 * For Realtime Dynamic(i.e., switch, queues, and directory) -- I think
896 static struct ast_variable *realtime_ldap(const char *basedn,
897 const char *table_name, va_list ap)
899 struct ast_variable **vars = realtime_ldap_base(NULL, basedn, table_name, ap);
900 struct ast_variable *var = NULL;
903 struct ast_variable *last_var = NULL;
904 struct ast_variable **p = vars;
907 while (last_var->next)
908 last_var = last_var->next;
921 /*! \brief See Asterisk doc
923 * this function will be called for the switch statment if no match is found with the realtime_ldap function(i.e. it is a failover);
924 * however, the ast_load_realtime wil match on wildcharacters also depending on what the mode is set to
925 * this is an area of asterisk that could do with a lot of modification
926 * I think this function returns Realtime dynamic objects
928 static struct ast_config *realtime_multi_ldap(const char *basedn,
929 const char *table_name, va_list ap)
931 struct ast_variable **vars =
932 realtime_ldap_base(NULL, basedn, table_name, ap);
933 struct ast_config *cfg = NULL;
936 cfg = ast_config_new();
938 ast_log(LOG_WARNING, "Out of memory!\n");
940 struct ast_variable **p = vars;
943 struct ast_category *cat = NULL;
944 cat = ast_category_new("", table_name, -1);
946 ast_log(LOG_WARNING, "Out of memory!\n");
949 struct ast_variable *var = *p;
951 struct ast_variable *next = var->next;
953 ast_variable_append(cat, var);
957 ast_category_append(cfg, cat);
968 * \brief Sorting alogrithm for qsort to find the order of the variables \a a and \a b
969 * \param \a a pointer to category_and_metric struct
970 * \param \a b pointer to category_and_metric struct
972 * \return the -1,0,1 (zero for equal, -1 for if b is greater, and 1 if a is greater)
974 static int compare_categories(const void *a, const void *b)
976 struct category_and_metric *as = (struct category_and_metric *) a;
977 struct category_and_metric *bs = (struct category_and_metric *) b;
979 if (as->metric < bs->metric)
981 else if (as->metric > bs->metric)
983 else if (as->metric == bs->metric && strcmp(as->name, bs->name) < 0)
984 return strcmp(as->name, bs->name);
985 else if (as->metric == bs->metric && strcmp(as->name, bs->name) > 0)
986 return strcmp(as->name, bs->name);
988 /* if the metric and the category name is the same, we check the variable metric */
989 if (as->var_metric < bs->var_metric)
991 else if(as->var_metric > bs->var_metric)
997 /*! \brief See Asterisk doc
999 * This is for Static Realtime (again: I think...)
1001 * load the configuration stuff for the .conf files
1002 * called on a reload
1004 static struct ast_config *config_ldap(const char *basedn, const char *table_name,
1005 const char *file, struct ast_config *cfg, struct ast_flags config_flags, const char *sugg_incl)
1007 unsigned int vars_count = 0;
1008 struct ast_variable **vars;
1010 struct ast_variable *new_v = NULL;
1011 struct ast_category *cur_cat = NULL;
1012 const char *last_category = NULL;
1013 int last_category_metric = 0;
1014 struct category_and_metric *categories;
1015 struct ast_variable **p;
1017 if (!file || !strcasecmp(file, RES_CONFIG_LDAP_CONF)) {
1018 ast_log(LOG_WARNING, "Cannot configure myself.\n");
1022 vars = realtime_ldap_base_(&vars_count, basedn, table_name, "filename",
1023 file, "commented", "FALSE", NULL);
1026 ast_log(LOG_WARNING, "Could not find config '%s' in database.\n", file);
1030 if (!(categories = ast_calloc(1, sizeof(*categories) * vars_count)))
1033 for (vars_count = 0, p = vars; *p; p++) {
1034 struct ast_variable *category = variable_named(*p, "category");
1035 struct ast_variable *cat_metric = variable_named(*p, "cat_metric");
1036 struct ast_variable *var_name = variable_named(*p, "variable_name");
1037 struct ast_variable *var_val = variable_named(*p, "variable_value");
1038 struct ast_variable *var_metric = variable_named(*p, "var_metric");
1039 struct ast_variable *dn = variable_named(*p, "dn");
1041 ast_debug(1, "category: %s\n", category->value);
1042 ast_debug(1, "var_name: %s\n", var_name->value);
1043 ast_debug(1, "var_val: %s\n", var_val->value);
1044 ast_debug(1, "cat_metric: %s\n", cat_metric->value);
1048 "No category name in entry '%s' for file '%s'.\n",
1049 (dn ? dn->value : "?"), file);
1050 } else if (!cat_metric) {
1052 "No category metric in entry '%s'(category: %s) for file '%s'.\n",
1053 (dn ? dn->value : "?"), category->value, file);
1054 } else if (!var_metric) {
1056 "No variable metric in entry '%s'(category: %s) for file '%s'.\n",
1057 (dn ? dn->value : "?"), category->value, file);
1058 } else if (!var_name) {
1060 "No variable name in entry '%s' (category: %s metric: %s) for file '%s'.\n",
1061 (dn ? dn->value : "?"), category->value,
1062 cat_metric->value, file);
1063 } else if (!var_val) {
1065 "No variable value in entry '%s' (category: %s metric: %s variable: %s) for file '%s'.\n",
1066 (dn ? dn->value : "?"), category->value,
1067 cat_metric->value, var_name->value, file);
1069 categories[vars_count].name = category->value;
1070 categories[vars_count].metric = atoi(cat_metric->value);
1071 categories[vars_count].variable_name = var_name->value;
1072 categories[vars_count].variable_value = var_val->value;
1073 categories[vars_count].var_metric = atoi(var_metric->value);
1078 qsort(categories, vars_count, sizeof(*categories), compare_categories);
1080 for (i = 0; i < vars_count; i++) {
1081 if (!strcmp(categories[i].variable_name, "#include")) {
1082 struct ast_flags config_flags = { 0 };
1083 if (!ast_config_internal_load(categories[i].variable_value, cfg, config_flags, ""))
1088 if (!last_category || strcmp(last_category, categories[i].name) ||
1089 last_category_metric != categories[i].metric) {
1090 cur_cat = ast_category_new(categories[i].name, table_name, -1);
1093 last_category = categories[i].name;
1094 last_category_metric = categories[i].metric;
1095 ast_category_append(cfg, cur_cat);
1098 if (!(new_v = ast_variable_new(categories[i].variable_name, categories[i].variable_value, table_name)))
1101 ast_variable_append(cur_cat, new_v);
1110 /* \brief Function to update a set of values in ldap
1113 static int update_ldap(const char *basedn, const char *table_name, const char *attribute,
1114 const char *lookup, va_list ap)
1117 LDAPMessage *ldap_entry = NULL;
1118 LDAPMod **ldap_mods;
1119 const char *newparam = NULL;
1120 const char *newval = NULL;
1122 int num_entries = 0;
1126 struct ldap_table_config *table_config = NULL;
1127 char *clean_basedn = NULL;
1128 struct ast_str *filter = NULL;
1131 LDAPMessage *ldap_result = NULL;
1134 ast_log(LOG_WARNING, "No table_name specified.\n");
1138 if (!(filter = ast_str_create(80)))
1141 if (!attribute || !lookup) {
1142 ast_log(LOG_WARNING,
1143 "LINE(%d): search parameters are empty.\n", __LINE__);
1146 ast_mutex_lock(&ldap_lock);
1148 /* We now have our complete statement; Lets connect to the server and execute it. */
1149 if (!ldap_reconnect()) {
1150 ast_mutex_unlock(&ldap_lock);
1154 table_config = table_config_for_table_name(table_name);
1155 if (!table_config) {
1156 ast_log(LOG_WARNING, "No table named '%s'.\n", table_name);
1157 ast_mutex_unlock(&ldap_lock);
1161 clean_basedn = cleaned_basedn(NULL, basedn);
1163 /* Create the filter with the table additional filter and the parameter/value pairs we were given */
1164 ast_str_append(&filter, 0, "(&");
1165 if (table_config && table_config->additional_filter) {
1166 ast_str_append(&filter, 0, table_config->additional_filter);
1168 if (table_config != base_table_config && base_table_config
1169 && base_table_config->additional_filter) {
1170 ast_str_append(&filter, 0, base_table_config->additional_filter);
1172 append_var_and_value_to_filter(&filter, table_config, attribute, lookup);
1173 ast_str_append(&filter, 0, ")");
1175 /* Create the modification array with the parameter/value pairs we were given,
1176 * if there are several parameters with the same name, we collect them into
1177 * one parameter/value pair and delimit them with a semicolon */
1178 newparam = va_arg(ap, const char *);
1179 newparam = convert_attribute_name_to_ldap(table_config, newparam);
1180 newval = va_arg(ap, const char *);
1181 if (!newparam || !newval) {
1182 ast_log(LOG_WARNING,
1183 "LINE(%d): need at least one paramter to modify.\n",__LINE__);
1187 mods_size = 2; /* one for the first param/value pair and one for the the terminating NULL */
1188 ldap_mods = ast_calloc(1,sizeof(LDAPMod *)*mods_size);
1189 ldap_mods[0] = ast_calloc(1,sizeof(LDAPMod));
1191 ldap_mods[0]->mod_op = LDAP_MOD_REPLACE;
1192 ldap_mods[0]->mod_type = ast_calloc(1,sizeof(char)*(strlen(newparam)+1));
1193 strcpy(ldap_mods[0]->mod_type, newparam);
1195 ldap_mods[0]->mod_values = ast_calloc(1,sizeof(char *)*2);
1196 ldap_mods[0]->mod_values[0] = ast_calloc(1,sizeof(char)*(strlen(newval)+1));
1197 strcpy(ldap_mods[0]->mod_values[0],newval);
1199 while ((newparam = va_arg(ap, const char *))) {
1200 newparam = convert_attribute_name_to_ldap(table_config, newparam);
1202 newval = va_arg(ap, const char *);
1205 for (i = 0; i < mods_size - 1; i++){
1206 if (ldap_mods[i]&& !strcmp(ldap_mods[i]->mod_type, newparam)) {
1207 /* We have the parameter allready, adding the value as a semicolon delimited value */
1208 ldap_mods[i]->mod_values[0] = realloc(ldap_mods[i]->mod_values[0], sizeof(char)*( strlen(ldap_mods[i]->mod_values[0]) + strlen(newval) + 2 ));
1209 strcat(ldap_mods[i]->mod_values[0],";");
1210 strcat(ldap_mods[i]->mod_values[0],newval);
1216 /* create new mod */
1219 ldap_mods = realloc(ldap_mods, sizeof(LDAPMod *)*mods_size);
1220 ldap_mods[mods_size - 1] = NULL;
1221 ldap_mods[mods_size - 2] = ast_calloc(1,sizeof(LDAPMod));
1223 ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_REPLACE;
1225 ldap_mods[mods_size - 2]->mod_type = ast_calloc(1,sizeof(char)*(strlen(newparam)+1));
1226 strcpy(ldap_mods[mods_size - 2]->mod_type,newparam);
1228 ldap_mods[mods_size - 2]->mod_values = ast_calloc(1,sizeof(char *)*2);
1229 ldap_mods[mods_size - 2]->mod_values[0] = ast_calloc(1,sizeof(char)*(strlen(newval)+1));
1230 strcpy(ldap_mods[mods_size - 2]->mod_values[0],newval);
1233 /* freeing ldap_mods further down */
1236 /* freeing ldap_result further down */
1237 result = ldap_search_ext_s(ldapConn, clean_basedn,
1238 LDAP_SCOPE_SUBTREE, filter->str, NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
1240 if (result < 0 && is_ldap_connect_error(result)) {
1241 ast_log(LOG_WARNING, "Failed to query database. Try %d/3\n",
1245 usleep(500000L * tries);
1247 ldap_unbind_ext_s(ldapConn,NULL,NULL);
1250 if (!ldap_reconnect())
1254 } while (result < 0 && tries < 3 && is_ldap_connect_error(result));
1257 ast_log(LOG_WARNING, "Failed to query directory. Check debug for more info.\n");
1258 ast_log(LOG_WARNING, "Query: %s\n", filter->str);
1259 ast_log(LOG_WARNING, "Query Failed because: %s\n",
1260 ldap_err2string(result));
1262 ast_mutex_unlock(&ldap_lock);
1267 ldap_msgfree(ldap_result);
1268 ldap_mods_free(ldap_mods,0);
1271 /* Ready to update */
1272 if ((num_entries = ldap_count_entries(ldapConn, ldap_result)) > 0) {
1273 ast_debug(3, "LINE(%d) Modifying %s=%s hits: %d\n", __LINE__,attribute,lookup,num_entries);
1274 for (i = 0; option_debug > 2 && i < mods_size - 1; i++)
1275 ast_debug(3, "LINE(%d) %s=%s \n", __LINE__,ldap_mods[i]->mod_type,ldap_mods[i]->mod_values[0]);
1277 ldap_entry = ldap_first_entry(ldapConn, ldap_result);
1279 for (i = 0; ldap_entry; i++){
1280 dn = ldap_get_dn(ldapConn,ldap_entry);
1281 if (!(error = ldap_modify_ext_s(ldapConn,dn,ldap_mods,NULL,NULL)))
1282 ast_log(LOG_ERROR,"Couldn't modify dn:%s because %s",dn,ldap_err2string(error) );
1284 ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
1288 ast_mutex_unlock(&ldap_lock);
1293 ldap_msgfree(ldap_result);
1294 ldap_mods_free(ldap_mods,0);
1298 static struct ast_config_engine ldap_engine = {
1300 .load_func = config_ldap,
1301 .realtime_func = realtime_ldap,
1302 .realtime_multi_func = realtime_multi_ldap,
1303 .update_func = update_ldap
1306 static int load_module(void) {
1308 if (parse_config() < 0) {
1309 ast_log(LOG_NOTICE, "Cannot load LDAP RealTime driver.\n");
1313 ast_mutex_lock(&ldap_lock);
1315 if (!ldap_reconnect())
1316 ast_log(LOG_WARNING, "Couldn't establish connection. Check debug.\n");
1318 ast_config_engine_register(&ldap_engine);
1319 ast_verb(1, "LDAP RealTime driver loaded.\n");
1320 ast_cli_register_multiple(ldap_cli, sizeof(ldap_cli) / sizeof(struct ast_cli_entry));
1322 ast_mutex_unlock(&ldap_lock);
1327 static int unload_module(void)
1329 /* Aquire control before doing anything to the module itself. */
1330 ast_mutex_lock(&ldap_lock);
1332 table_configs_free();
1335 ldap_unbind_ext_s(ldapConn,NULL,NULL);
1338 ast_cli_unregister_multiple(ldap_cli, sizeof(ldap_cli) / sizeof(struct ast_cli_entry));
1339 ast_config_engine_deregister(&ldap_engine);
1340 ast_verb(1, "LDAP RealTime unloaded.\n");
1342 /* Unlock so something else can destroy the lock. */
1343 ast_mutex_unlock(&ldap_lock);
1348 static int reload(void)
1350 /* Aquire control before doing anything to the module itself. */
1351 ast_mutex_lock(&ldap_lock);
1354 ldap_unbind_ext_s(ldapConn,NULL,NULL);
1358 if (parse_config() < 0) {
1359 ast_log(LOG_NOTICE, "Cannot reload LDAP RealTime driver.\n");
1363 if (!ldap_reconnect())
1364 ast_log(LOG_WARNING, "Couldn't establish connection. Check debug.\n");
1366 ast_verb(2, "LDAP RealTime reloaded.\n");
1368 /* Done reloading. Release lock so others can now use driver. */
1369 ast_mutex_unlock(&ldap_lock);
1374 int parse_config(void)
1376 struct ast_config *config;
1377 struct ast_flags config_flags = {0};
1379 char *category_name = NULL;
1381 config = ast_config_load(RES_CONFIG_LDAP_CONF, config_flags);
1384 ast_log(LOG_WARNING, "Cannot load configuration %s\n", RES_CONFIG_LDAP_CONF);
1388 if (!(s = ast_variable_retrieve(config, "_general", "user"))) {
1389 ast_log(LOG_WARNING, "No directory user found, anonymous binding as default.\n");
1392 ast_copy_string(user, s, sizeof(user));
1394 if (!(s = ast_variable_retrieve(config, "_general", "pass"))) {
1395 ast_log(LOG_WARNING, "No directory password found, using 'asterisk' as default.\n");
1396 ast_copy_string(pass, "asterisk", sizeof(pass) - 1);
1398 ast_copy_string(pass, s, sizeof(pass));
1400 if (!(s = ast_variable_retrieve(config, "_general", "host"))) {
1401 ast_log(LOG_ERROR, "No directory host found.\n");
1404 ast_copy_string(host, "ldap://", 8 );
1405 ast_copy_string(host + 7, s, sizeof(host));
1408 if (!(s = ast_variable_retrieve(config, "_general", "basedn"))) {
1409 ast_log(LOG_ERROR, "No LDAP base dn found, using 'asterisk' as default.\n");
1412 ast_copy_string(basedn, s, sizeof(basedn));
1414 if (!(s = ast_variable_retrieve(config, "_general", "port"))) {
1415 ast_log(LOG_WARNING, "No directory port found, using 389 as default.\n");
1417 ast_copy_string(host + strlen(host), ":389", sizeof(host));
1419 ast_copy_string(host + 1, ":", sizeof(s));
1420 ast_copy_string(host + strlen(host), s, sizeof(s));
1424 table_configs_free();
1426 while ((category_name = ast_category_browse(config, category_name))) {
1427 int is_general = (strcasecmp(category_name, "_general") == 0);
1428 int is_config = (strcasecmp(category_name, "config") == 0); /*!< using the [config] context for Static RealTime */
1429 struct ast_variable *var = ast_variable_browse(config, category_name);
1432 struct ldap_table_config *table_config =
1433 table_config_for_table_name(category_name);
1434 if (!table_config) {
1435 table_config = table_config_new(category_name);
1436 AST_LIST_INSERT_HEAD(&table_configs, table_config, entry);
1438 base_table_config = table_config;
1440 static_table_config = table_config;
1442 for (; var; var = var->next) {
1443 if (!strcasecmp(var->name, "additionalFilter"))
1444 table_config->additional_filter = strdup(var->value);
1446 ldap_table_config_add_attribute(table_config, var->name, var->value);
1451 ast_config_destroy(config);
1456 /*! \note ldap_lock should have been locked before calling this function. */
1457 static int ldap_reconnect(void)
1459 int bind_result = 0;
1463 ast_debug(2, "Everything seems fine.\n");
1467 if (ast_strlen_zero(host)) {
1468 ast_log(LOG_ERROR, "Not enough parameters to connect to ldap database\n");
1472 if (LDAP_SUCCESS != ldap_initialize(&ldapConn, host)) {
1473 ast_log(LOG_ERROR, "Failed to init ldap connection to %s. Check debug for more info.\n", host);
1477 if (!ast_strlen_zero(user)) {
1478 ast_debug(2, "bind to %s as %s\n", host, user);
1479 cred.bv_val = (char *) pass;
1480 cred.bv_len = strlen(pass);
1481 bind_result = ldap_sasl_bind_s(ldapConn, user, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
1483 ast_debug(2, "bind anonymously %s anonymously\n", host);
1484 bind_result = ldap_sasl_bind_s(ldapConn, NULL, LDAP_SASL_SIMPLE, NULL, NULL, NULL, NULL);
1486 if (bind_result == LDAP_SUCCESS) {
1487 ast_debug(2, "Successfully connected to database.\n");
1488 connect_time = time(NULL);
1491 ast_log(LOG_WARNING, "bind failed: %s\n", ldap_err2string(bind_result));
1492 ldap_unbind_ext_s(ldapConn, NULL, NULL);
1498 static char *realtime_ldap_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1500 char status[256], status2[100] = "";
1501 int ctime = time(NULL) - connect_time;
1505 e->command = "realtime ldap status";
1507 "Usage: realtime ldap status\n"
1508 " Shows connection information for the LDAP RealTime driver\n";
1517 if (!ast_strlen_zero(host))
1518 snprintf(status, sizeof(status), "Connected to %s, port %d baseDN %s", host, port, basedn);
1520 if (!ast_strlen_zero(user))
1521 snprintf(status2, sizeof(status2), " with username %s", user);
1523 if (ctime > 31536000) {
1524 ast_cli(a->fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n",
1525 status, status2, ctime / 31536000,
1526 (ctime % 31536000) / 86400, (ctime % 86400) / 3600,
1527 (ctime % 3600) / 60, ctime % 60);
1528 } else if (ctime > 86400) {
1529 ast_cli(a->fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n",
1530 status, status2, ctime / 86400, (ctime % 86400) / 3600,
1531 (ctime % 3600) / 60, ctime % 60);
1532 } else if (ctime > 3600) {
1533 ast_cli(a->fd, "%s%s for %d hours, %d minutes, %d seconds.\n",
1534 status, status2, ctime / 3600, (ctime % 3600) / 60,
1536 } else if (ctime > 60) {
1537 ast_cli(a->fd, "%s%s for %d minutes, %d seconds.\n", status, status2,
1538 ctime / 60, ctime % 60);
1540 ast_cli(a->fd, "%s%s for %d seconds.\n", status, status2, ctime);
1546 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "LDAP realtime interface",
1547 .load = load_module,
1548 .unload = unload_module,