Wed Jan 8 2020 09:49:49

Asterisk developer's documentation


res_config_ldap.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Copyright (C) 2005, Oxymium sarl
5  * Manuel Guesdon <mguesdon@oxymium.net> - LDAP RealTime Driver Author/Adaptor
6  *
7  * Copyright (C) 2007, Digium, Inc.
8  * Russell Bryant <russell@digium.com>
9  *
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.
15  *
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.
19  *
20  */
21 
22 /*! \file
23  *
24  * \brief ldap plugin for portable configuration engine (ARA)
25  *
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>
30  *
31  * \extref OpenLDAP http://www.openldap.org
32  */
33 
34 /*** MODULEINFO
35  <depend>ldap</depend>
36  <support_level>extended</support_level>
37  ***/
38 
39 #include "asterisk.h"
40 
41 #include <stdlib.h>
42 #include <string.h>
43 #include <ctype.h>
44 #include <stdio.h>
45 #include <ldap.h>
46 
47 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 385190 $")
48 
49 #include "asterisk/channel.h"
50 #include "asterisk/logger.h"
51 #include "asterisk/config.h"
52 #include "asterisk/module.h"
53 #include "asterisk/lock.h"
54 #include "asterisk/options.h"
55 #include "asterisk/cli.h"
56 #include "asterisk/utils.h"
57 #include "asterisk/strings.h"
58 #include "asterisk/pbx.h"
59 #include "asterisk/linkedlists.h"
60 
61 #define RES_CONFIG_LDAP_CONF "res_ldap.conf"
62 #define RES_CONFIG_LDAP_DEFAULT_BASEDN "asterisk"
63 
65 
66 static LDAP *ldapConn;
67 static char url[512];
68 static char user[512];
69 static char pass[512];
70 static char base_distinguished_name[512];
71 static int version;
72 static time_t connect_time;
73 
74 static int parse_config(void);
75 static int ldap_reconnect(void);
76 static char *realtime_ldap_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
77 
79  const char *name;
80  int metric;
81  const char *variable_name;
82  const char *variable_value;
83  int var_metric; /*!< For organizing variables (particularly includes and switch statments) within a context */
84 };
85 
86 /*! \brief Table configuration */
88  char *table_name; /*!< table name */
89  char *additional_filter; /*!< additional filter */
90  struct ast_variable *attributes; /*!< attribute names conversion */
91  struct ast_variable *delimiters; /*!< the current delimiter is semicolon, so we are not using this variable */
93  /* TODO: Make proxies work */
94 };
95 
96 /*! \brief Should be locked before using it */
98 static struct ldap_table_config *base_table_config;
99 static struct ldap_table_config *static_table_config;
100 
101 static struct ast_cli_entry ldap_cli[] = {
102  AST_CLI_DEFINE(realtime_ldap_status, "Shows connection information for the LDAP RealTime driver"),
103 };
104 
105 /*! \brief Create a new table_config */
106 static struct ldap_table_config *table_config_new(const char *table_name)
107 {
108  struct ldap_table_config *p;
109 
110  if (!(p = ast_calloc(1, sizeof(*p))))
111  return NULL;
112 
113  if (table_name) {
114  if (!(p->table_name = ast_strdup(table_name))) {
115  free(p);
116  return NULL;
117  }
118  }
119 
120  return p;
121 }
122 
123 /*! \brief Find a table_config - Should be locked before using it
124  * \note This function assumes ldap_lock to be locked. */
126 {
127  struct ldap_table_config *c = NULL;
128 
130  if (!strcmp(c->table_name, table_name))
131  break;
132  }
133 
134  return c;
135 }
136 
137 /*! \brief Find variable by name */
138 static struct ast_variable *variable_named(struct ast_variable *var, const char *name)
139 {
140  for (; var; var = var->next) {
141  if (!strcasecmp(name, var->name))
142  break;
143  }
144 
145  return var;
146 }
147 
148 /*! \brief for the semicolon delimiter
149  \param somestr - pointer to a string
150 
151  \return number of occurances of the delimiter(semicolon)
152  */
153 static int semicolon_count_str(const char *somestr)
154 {
155  int count = 0;
156 
157  for (; *somestr; somestr++) {
158  if (*somestr == ';')
159  count++;
160  }
161 
162  return count;
163 }
164 
165 /* takes a linked list of \a ast_variable variables, finds the one with the name variable_value
166  * and returns the number of semicolons in the value for that \a ast_variable
167  */
169 {
170  struct ast_variable *var_value = variable_named(var, "variable_value");
171 
172  if (!var_value) {
173  return 0;
174  }
175 
176  ast_debug(2, "LINE(%d) semicolon_count_var: %s\n", __LINE__, var_value->value);
177 
178  return semicolon_count_str(var_value->value);
179 }
180 
181 /*! \brief add attribute to table config - Should be locked before using it */
182 static void ldap_table_config_add_attribute(struct ldap_table_config *table_config,
183  const char *attribute_name, const char *attribute_value)
184 {
185  struct ast_variable *var;
186 
187  if (ast_strlen_zero(attribute_name) || ast_strlen_zero(attribute_value)) {
188  return;
189  }
190 
191  if (!(var = ast_variable_new(attribute_name, attribute_value, table_config->table_name))) {
192  return;
193  }
194 
195  if (table_config->attributes) {
196  var->next = table_config->attributes;
197  }
198  table_config->attributes = var;
199 }
200 
201 /*! \brief Free table_config
202  * \note assumes ldap_lock to be locked */
203 static void table_configs_free(void)
204 {
205  struct ldap_table_config *c;
206 
207  while ((c = AST_LIST_REMOVE_HEAD(&table_configs, entry))) {
208  if (c->table_name) {
209  ast_free(c->table_name);
210  }
211  if (c->additional_filter) {
213  }
214  if (c->attributes) {
216  }
217  free(c);
218  }
219 
220  base_table_config = NULL;
221  static_table_config = NULL;
222 }
223 
224 /*! \brief Convert variable name to ldap attribute name - Should be locked before using it */
225 static const char *convert_attribute_name_to_ldap(struct ldap_table_config *table_config,
226  const char *attribute_name)
227 {
228  int i = 0;
229  struct ldap_table_config *configs[] = { table_config, base_table_config };
230 
231  for (i = 0; i < ARRAY_LEN(configs); i++) {
232  struct ast_variable *attribute;
233 
234  if (!configs[i]) {
235  continue;
236  }
237 
238  attribute = configs[i]->attributes;
239  for (; attribute; attribute = attribute->next) {
240  if (!strcasecmp(attribute_name, attribute->name)) {
241  return attribute->value;
242  }
243  }
244  }
245 
246  return attribute_name;
247 }
248 
249 /*! \brief Convert ldap attribute name to variable name
250  \note Should be locked before using it */
251 static const char *convert_attribute_name_from_ldap(struct ldap_table_config *table_config,
252  const char *attribute_name)
253 {
254  int i = 0;
255  struct ldap_table_config *configs[] = { table_config, base_table_config };
256 
257  for (i = 0; i < ARRAY_LEN(configs); i++) {
258  struct ast_variable *attribute;
259 
260  if (!configs[i]) {
261  continue;
262  }
263 
264  attribute = configs[i]->attributes;
265  for (; attribute; attribute = attribute->next) {
266  if (strcasecmp(attribute_name, attribute->value) == 0) {
267  return attribute->name;
268  }
269  }
270  }
271 
272  return attribute_name;
273 }
274 
275 /*! \brief Get variables from ldap entry attributes
276  \note Should be locked before using it
277  \return a linked list of ast_variable variables.
278  */
279 static struct ast_variable *realtime_ldap_entry_to_var(struct ldap_table_config *table_config,
280  LDAPMessage *ldap_entry)
281 {
282  BerElement *ber = NULL;
283  struct ast_variable *var = NULL;
284  struct ast_variable *prev = NULL;
285  int is_delimited = 0;
286  int i = 0;
287  char *ldap_attribute_name;
288  struct berval *value;
289  int pos = 0;
290 
291  ldap_attribute_name = ldap_first_attribute(ldapConn, ldap_entry, &ber);
292 
293  while (ldap_attribute_name) {
294  struct berval **values = NULL;
295  const char *attribute_name = convert_attribute_name_from_ldap(table_config, ldap_attribute_name);
296  int is_realmed_password_attribute = strcasecmp(attribute_name, "md5secret") == 0;
297 
298  values = ldap_get_values_len(ldapConn, ldap_entry, ldap_attribute_name); /* these are freed at the end */
299  if (values) {
300  struct berval **v;
301  char *valptr;
302 
303  for (v = values; *v; v++) {
304  value = *v;
305  valptr = value->bv_val;
306  ast_debug(2, "LINE(%d) attribute_name: %s LDAP value: %s\n", __LINE__, attribute_name, valptr);
307  if (is_realmed_password_attribute) {
308  if (!strncasecmp(valptr, "{md5}", 5)) {
309  valptr += 5;
310  }
311  ast_debug(2, "md5: %s\n", valptr);
312  }
313  if (valptr) {
314  /* ok, so looping through all delimited values except the last one (not, last character is not delimited...) */
315  if (is_delimited) {
316  i = 0;
317  pos = 0;
318  while (!ast_strlen_zero(valptr + i)) {
319  if (valptr[i] == ';') {
320  valptr[i] = '\0';
321  if (prev) {
322  prev->next = ast_variable_new(attribute_name, &valptr[pos], table_config->table_name);
323  if (prev->next) {
324  prev = prev->next;
325  }
326  } else {
327  prev = var = ast_variable_new(attribute_name, &valptr[pos], table_config->table_name);
328  }
329  pos = i + 1;
330  }
331  i++;
332  }
333  }
334  /* for the last delimited value or if the value is not delimited: */
335  if (prev) {
336  prev->next = ast_variable_new(attribute_name, &valptr[pos], table_config->table_name);
337  if (prev->next) {
338  prev = prev->next;
339  }
340  } else {
341  prev = var = ast_variable_new(attribute_name, &valptr[pos], table_config->table_name);
342  }
343  }
344  }
345  ldap_value_free_len(values);
346  }
347  ldap_memfree(ldap_attribute_name);
348  ldap_attribute_name = ldap_next_attribute(ldapConn, ldap_entry, ber);
349  }
350  ber_free(ber, 0);
351 
352  return var;
353 }
354 
355 /*! \brief Get variables from ldap entry attributes - Should be locked before using it
356  *
357  * The results are freed outside this function so is the \a vars array.
358  *
359  * \return \a vars - an array of ast_variable variables terminated with a null.
360  **/
361 static struct ast_variable **realtime_ldap_result_to_vars(struct ldap_table_config *table_config,
362  LDAPMessage *ldap_result_msg, unsigned int *entries_count_ptr)
363 {
364  struct ast_variable **vars;
365  int i = 0;
366  int tot_count = 0;
367  int entry_index = 0;
368  LDAPMessage *ldap_entry = NULL;
369  BerElement *ber = NULL;
370  struct ast_variable *var = NULL;
371  struct ast_variable *prev = NULL;
372  int is_delimited = 0;
373  char *delim_value = NULL;
374  int delim_tot_count = 0;
375  int delim_count = 0;
376 
377  /* First find the total count */
378  ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
379 
380  for (tot_count = 0; ldap_entry; tot_count++) {
381  struct ast_variable *tmp = realtime_ldap_entry_to_var(table_config, ldap_entry);
382  tot_count += semicolon_count_var(tmp);
383  ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
385  }
386 
387  if (entries_count_ptr) {
388  *entries_count_ptr = tot_count;
389  }
390 
391  /* Now that we have the total count we allocate space and create the variables
392  * Remember that each element in vars is a linked list that points to realtime variable.
393  * If the we are dealing with a static realtime variable we create a new element in the \a vars array for each delimited
394  * 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.
395  * This memory must be freed outside of this function. */
396  vars = ast_calloc(sizeof(struct ast_variable *), tot_count + 1);
397 
398  ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
399 
400  i = 0;
401 
402  /* For each static realtime variable we may create several entries in the \a vars array if it's delimited */
403  for (entry_index = 0; ldap_entry; ) {
404  int pos = 0;
405  delim_value = NULL;
406  delim_tot_count = 0;
407  delim_count = 0;
408 
409  do { /* while delim_count */
410 
411  /* Starting new static var */
412  char *ldap_attribute_name = ldap_first_attribute(ldapConn, ldap_entry, &ber);
413  struct berval *value;
414  while (ldap_attribute_name) {
415 
416  const char *attribute_name = convert_attribute_name_from_ldap(table_config, ldap_attribute_name);
417  int is_realmed_password_attribute = strcasecmp(attribute_name, "md5secret") == 0;
418  struct berval **values = NULL;
419 
420  values = ldap_get_values_len(ldapConn, ldap_entry, ldap_attribute_name);
421  if (values) {
422  struct berval **v;
423  char *valptr;
424 
425  for (v = values; *v; v++) {
426  value = *v;
427  valptr = value->bv_val;
428  if (is_realmed_password_attribute) {
429  if (strncasecmp(valptr, "{md5}", 5) == 0) {
430  valptr += 5;
431  }
432  ast_debug(2, "md5: %s\n", valptr);
433  }
434  if (valptr) {
435  if (delim_value == NULL && !is_realmed_password_attribute
436  && (static_table_config != table_config || strcmp(attribute_name, "variable_value") == 0)) {
437 
438  delim_value = ast_strdup(valptr);
439 
440  if ((delim_tot_count = semicolon_count_str(delim_value)) > 0) {
441  ast_debug(4, "LINE(%d) is delimited %d times: %s\n", __LINE__, delim_tot_count, delim_value);
442  is_delimited = 1;
443  }
444  }
445 
446  if (is_delimited != 0 && !is_realmed_password_attribute
447  && (static_table_config != table_config || strcmp(attribute_name, "variable_value") == 0) ) {
448  /* for non-Static RealTime, first */
449 
450  for (i = pos; !ast_strlen_zero(valptr + i); i++) {
451  ast_debug(4, "LINE(%d) DELIM pos: %d i: %d\n", __LINE__, pos, i);
452  if (delim_value[i] == ';') {
453  delim_value[i] = '\0';
454 
455  ast_debug(2, "LINE(%d) DELIM - attribute_name: %s value: %s pos: %d\n", __LINE__, attribute_name, &delim_value[pos], pos);
456 
457  if (prev) {
458  prev->next = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name);
459  if (prev->next) {
460  prev = prev->next;
461  }
462  } else {
463  prev = var = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name);
464  }
465  pos = i + 1;
466 
467  if (static_table_config == table_config) {
468  break;
469  }
470  }
471  }
472  if (ast_strlen_zero(valptr + i)) {
473  ast_debug(4, "LINE(%d) DELIM pos: %d i: %d delim_count: %d\n", __LINE__, pos, i, delim_count);
474  /* Last delimited value */
475  ast_debug(4, "LINE(%d) DELIM - attribute_name: %s value: %s pos: %d\n", __LINE__, attribute_name, &delim_value[pos], pos);
476  if (prev) {
477  prev->next = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name);
478  if (prev->next) {
479  prev = prev->next;
480  }
481  } else {
482  prev = var = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name);
483  }
484  /* Remembering to free memory */
485  is_delimited = 0;
486  pos = 0;
487  }
488  free(delim_value);
489  delim_value = NULL;
490 
491  ast_debug(4, "LINE(%d) DELIM pos: %d i: %d\n", __LINE__, pos, i);
492  } else {
493  /* not delimited */
494  if (delim_value) {
495  free(delim_value);
496  delim_value = NULL;
497  }
498  ast_debug(2, "LINE(%d) attribute_name: %s value: %s\n", __LINE__, attribute_name, valptr);
499 
500  if (prev) {
501  prev->next = ast_variable_new(attribute_name, valptr, table_config->table_name);
502  if (prev->next) {
503  prev = prev->next;
504  }
505  } else {
506  prev = var = ast_variable_new(attribute_name, valptr, table_config->table_name);
507  }
508  }
509  }
510  } /*!< for (v = values; *v; v++) */
511  ldap_value_free_len(values);
512  }/*!< if (values) */
513  ldap_memfree(ldap_attribute_name);
514  ldap_attribute_name = ldap_next_attribute(ldapConn, ldap_entry, ber);
515  } /*!< while (ldap_attribute_name) */
516  ber_free(ber, 0);
517  if (static_table_config == table_config) {
518  if (option_debug > 2) {
519  const struct ast_variable *tmpdebug = variable_named(var, "variable_name");
520  const struct ast_variable *tmpdebug2 = variable_named(var, "variable_value");
521  if (tmpdebug && tmpdebug2) {
522  ast_debug(3, "LINE(%d) Added to vars - %s = %s\n", __LINE__, tmpdebug->value, tmpdebug2->value);
523  }
524  }
525  vars[entry_index++] = var;
526  prev = NULL;
527  }
528 
529  delim_count++;
530  } while (delim_count <= delim_tot_count && static_table_config == table_config);
531 
532  if (static_table_config != table_config) {
533  ast_debug(3, "LINE(%d) Added to vars - non static\n", __LINE__);
534 
535  vars[entry_index++] = var;
536  prev = NULL;
537  }
538  ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
539  } /*!< end for loop over ldap_entry */
540 
541  return vars;
542 }
543 
544 
545 /*! \brief Check if we have a connection error */
546 static int is_ldap_connect_error(int err)
547 {
548  return (err == LDAP_SERVER_DOWN || err == LDAP_TIMEOUT || err == LDAP_CONNECT_ERROR);
549 }
550 
551 /*! \brief Get LDAP entry by dn and return attributes as variables - Should be locked before using it
552  This is used for setting the default values of an object(i.e., with accountBaseDN)
553 */
554 static struct ast_variable *ldap_loadentry(struct ldap_table_config *table_config,
555  const char *dn)
556 {
557  if (!table_config) {
558  ast_log(LOG_ERROR, "No table config\n");
559  return NULL;
560  } else {
561  struct ast_variable **vars = NULL;
562  struct ast_variable *var = NULL;
563  int result = -1;
564  LDAPMessage *ldap_result_msg = NULL;
565  int tries = 0;
566 
567  ast_debug(2, "ldap_loadentry dn=%s\n", dn);
568 
569  do {
570  result = ldap_search_ext_s(ldapConn, dn, LDAP_SCOPE_BASE,
571  "(objectclass=*)", NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &ldap_result_msg);
572  if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
573  ast_log(LOG_WARNING, "Failed to query directory. Try %d/3\n", tries + 1);
574  tries++;
575  if (tries < 3) {
576  usleep(500000L * tries);
577  if (ldapConn) {
578  ldap_unbind_ext_s(ldapConn, NULL, NULL);
579  ldapConn = NULL;
580  }
581  if (!ldap_reconnect()) {
582  break;
583  }
584  }
585  }
586  } while (result != LDAP_SUCCESS && tries < 3 && is_ldap_connect_error(result));
587 
588  if (result != LDAP_SUCCESS) {
589  ast_log(LOG_WARNING, "Failed to query directory. Error: %s.\n", ldap_err2string(result));
590  ast_debug(2, "dn=%s\n", dn);
592  return NULL;
593  } else {
594  int num_entry = 0;
595  unsigned int *entries_count_ptr = NULL; /*!< not using this */
596 
597  if ((num_entry = ldap_count_entries(ldapConn, ldap_result_msg)) > 0) {
598  ast_debug(3, "num_entry: %d\n", num_entry);
599 
600  vars = realtime_ldap_result_to_vars(table_config, ldap_result_msg, entries_count_ptr);
601  if (num_entry > 1) {
602  ast_log(LOG_NOTICE, "More than one entry for dn=%s. Take only 1st one\n", dn);
603  }
604  } else {
605  ast_debug(2, "Could not find any entry dn=%s.\n", dn);
606  }
607  }
608  ldap_msgfree(ldap_result_msg);
609 
610  /* Chopping \a vars down to one variable */
611  if (vars != NULL) {
612  struct ast_variable **p = vars;
613  p++;
614  var = *p;
615  while (var) {
617  p++;
618  }
619  vars = ast_realloc(vars, sizeof(struct ast_variable *));
620  }
621 
622  var = *vars;
623 
624  return var;
625  }
626 }
627 
628 /*! \note caller should free returned pointer */
629 static char *substituted(struct ast_channel *channel, const char *string)
630 {
631 #define MAXRESULT 2048
632  char *ret_string = NULL;
633 
634  if (!ast_strlen_zero(string)) {
635  ret_string = ast_calloc(1, MAXRESULT);
636  pbx_substitute_variables_helper(channel, string, ret_string, MAXRESULT - 1);
637  }
638  ast_debug(2, "substituted: string: '%s' => '%s' \n", string, ret_string);
639  return ret_string;
640 }
641 
642 /*! \note caller should free returned pointer */
643 static char *cleaned_basedn(struct ast_channel *channel, const char *basedn)
644 {
645  char *cbasedn = NULL;
646  if (basedn) {
647  char *p = NULL;
648  cbasedn = substituted(channel, basedn);
649  if (*cbasedn == '"') {
650  cbasedn++;
651  if (!ast_strlen_zero(cbasedn)) {
652  int len = strlen(cbasedn);
653  if (cbasedn[len - 1] == '"')
654  cbasedn[len - 1] = '\0';
655 
656  }
657  }
658  p = cbasedn;
659  while (*p) {
660  if (*p == '|')
661  *p = ',';
662  p++;
663  }
664  }
665  ast_debug(2, "basedn: '%s' => '%s' \n", basedn, cbasedn);
666  return cbasedn;
667 }
668 
669 /*! \brief Replace <search> by <by> in string.
670  \note No check is done on string allocated size ! */
671 static int replace_string_in_string(char *string, const char *search, const char *by)
672 {
673  int search_len = strlen(search);
674  int by_len = strlen(by);
675  int replaced = 0;
676  char *p = strstr(string, search);
677 
678  if (p) {
679  replaced = 1;
680  while (p) {
681  if (by_len == search_len) {
682  memcpy(p, by, by_len);
683  } else {
684  memmove(p + by_len, p + search_len, strlen(p + search_len) + 1);
685  memcpy(p, by, by_len);
686  }
687  p = strstr(p + by_len, search);
688  }
689  }
690  return replaced;
691 }
692 
693 /*! \brief Append a name=value filter string. The filter string can grow. */
695  struct ldap_table_config *table_config,
696  const char *name, const char *value)
697 {
698  char *new_name = NULL;
699  char *new_value = NULL;
700  char *like_pos = strstr(name, " LIKE");
701 
702  ast_debug(2, "name='%s' value='%s'\n", name, value);
703 
704  if (like_pos) {
705  int len = like_pos - name;
706 
707  name = new_name = ast_strdupa(name);
708  new_name[len] = '\0';
709  value = new_value = ast_strdupa(value);
710  replace_string_in_string(new_value, "\\_", "_");
711  replace_string_in_string(new_value, "%", "*");
712  }
713 
714  name = convert_attribute_name_to_ldap(table_config, name);
715 
716  ast_str_append(filter, 0, "(%s=%s)", name, value);
717 }
718 
719 /*! \brief LDAP base function
720  * \return a null terminated array of ast_variable (one per entry) or NULL if no entry is found or if an error occured
721  * caller should free the returned array and ast_variables
722  * \param entries_count_ptr is a pointer to found entries count (can be NULL)
723  * \param basedn is the base DN
724  * \param table_name is the table_name (used dor attribute convertion and additional filter)
725  * \param ap contains null terminated list of pairs name/value
726 */
727 static struct ast_variable **realtime_ldap_base_ap(unsigned int *entries_count_ptr,
728  const char *basedn, const char *table_name, va_list ap)
729 {
730  struct ast_variable **vars = NULL;
731  const char *newparam = NULL;
732  const char *newval = NULL;
733  struct ldap_table_config *table_config = NULL;
734  char *clean_basedn = cleaned_basedn(NULL, basedn);
735  struct ast_str *filter = NULL;
736  int tries = 0;
737  int result = 0;
738  LDAPMessage *ldap_result_msg = NULL;
739 
740  if (!table_name) {
741  ast_log(LOG_ERROR, "No table_name specified.\n");
742  ast_free(clean_basedn);
743  return NULL;
744  }
745 
746  if (!(filter = ast_str_create(80))) {
747  ast_log(LOG_ERROR, "Can't initialize data structures.n");
748  ast_free(clean_basedn);
749  return NULL;
750  }
751 
752  /* Get the first parameter and first value in our list of passed paramater/value pairs */
753  newparam = va_arg(ap, const char *);
754  newval = va_arg(ap, const char *);
755 
756  if (!newparam || !newval) {
757  ast_log(LOG_ERROR, "Realtime retrieval requires at least 1 parameter"
758  " and 1 value to search on.\n");
759  ast_free(filter);
760  ast_free(clean_basedn);
761  return NULL;
762  }
763 
765 
766  /* We now have our complete statement; Lets connect to the server and execute it. */
767  if (!ldap_reconnect()) {
769  ast_free(filter);
770  ast_free(clean_basedn);
771  return NULL;
772  }
773 
774  table_config = table_config_for_table_name(table_name);
775  if (!table_config) {
776  ast_log(LOG_WARNING, "No table named '%s'.\n", table_name);
778  ast_free(filter);
779  ast_free(clean_basedn);
780  return NULL;
781  }
782 
783  ast_str_append(&filter, 0, "(&");
784 
785  if (table_config && table_config->additional_filter) {
786  ast_str_append(&filter, 0, "%s", table_config->additional_filter);
787  }
788  if (table_config != base_table_config && base_table_config &&
791  }
792 
793  /* Create the first part of the query using the first parameter/value pairs we just extracted */
794  /* If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
795 
796  append_var_and_value_to_filter(&filter, table_config, newparam, newval);
797  while ((newparam = va_arg(ap, const char *))) {
798  newval = va_arg(ap, const char *);
799  append_var_and_value_to_filter(&filter, table_config, newparam, newval);
800  }
801  ast_str_append(&filter, 0, ")");
802 
803  do {
804  /* freeing ldap_result further down */
805  result = ldap_search_ext_s(ldapConn, clean_basedn,
806  LDAP_SCOPE_SUBTREE, ast_str_buffer(filter), NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
807  &ldap_result_msg);
808  if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
809  ast_log(LOG_DEBUG, "Failed to query directory. Try %d/10\n", tries + 1);
810  if (++tries < 10) {
811  usleep(1);
812  if (ldapConn) {
813  ldap_unbind_ext_s(ldapConn, NULL, NULL);
814  ldapConn = NULL;
815  }
816  if (!ldap_reconnect()) {
817  break;
818  }
819  }
820  }
821  } while (result != LDAP_SUCCESS && tries < 10 && is_ldap_connect_error(result));
822 
823  if (result != LDAP_SUCCESS) {
824  ast_log(LOG_WARNING, "Failed to query directory. Error: %s.\n", ldap_err2string(result));
825  ast_log(LOG_WARNING, "Query: %s\n", ast_str_buffer(filter));
826  } else {
827  /* this is where we create the variables from the search result
828  * freeing this \a vars outside this function */
829  if (ldap_count_entries(ldapConn, ldap_result_msg) > 0) {
830  /* is this a static var or some other? they are handled different for delimited values */
831  vars = realtime_ldap_result_to_vars(table_config, ldap_result_msg, entries_count_ptr);
832  } else {
833  ast_debug(1, "Could not find any entry matching %s in base dn %s.\n", ast_str_buffer(filter), clean_basedn);
834  }
835 
836  ldap_msgfree(ldap_result_msg);
837 
838  /* TODO: get the default variables from the accountBaseDN, not implemented with delimited values */
839  if (vars) {
840  struct ast_variable **p = vars;
841  while (*p) {
842  struct ast_variable *append_var = NULL;
843  struct ast_variable *tmp = *p;
844  while (tmp) {
845  if (strcasecmp(tmp->name, "accountBaseDN") == 0) {
846  /* Get the variable to compare with for the defaults */
847  struct ast_variable *base_var = ldap_loadentry(table_config, tmp->value);
848 
849  while (base_var) {
850  struct ast_variable *next = base_var->next;
851  struct ast_variable *test_var = *p;
852  int base_var_found = 0;
853 
854  /* run throught the default values and fill it inn if it is missing */
855  while (test_var) {
856  if (strcasecmp(test_var->name, base_var->name) == 0) {
857  base_var_found = 1;
858  break;
859  } else {
860  test_var = test_var->next;
861  }
862  }
863  if (base_var_found) {
864  base_var->next = NULL;
865  ast_variables_destroy(base_var);
866  base_var = next;
867  } else {
868  if (append_var) {
869  base_var->next = append_var;
870  } else {
871  base_var->next = NULL;
872  }
873  append_var = base_var;
874  base_var = next;
875  }
876  }
877  }
878  if (!tmp->next && append_var) {
879  tmp->next = append_var;
880  tmp = NULL;
881  } else {
882  tmp = tmp->next;
883  }
884  }
885  p++;
886  }
887  }
888  }
889 
890  if (filter) {
891  ast_free(filter);
892  }
893 
894  if (clean_basedn) {
895  ast_free(clean_basedn);
896  }
897 
899 
900  return vars;
901 }
902 
903 /*! \brief same as realtime_ldap_base_ap but take variable arguments count list */
904 static struct ast_variable **realtime_ldap_base(unsigned int *entries_count_ptr,
905  const char *basedn, const char *table_name, ...)
906 {
907  struct ast_variable **vars = NULL;
908  va_list ap;
909 
910  va_start(ap, table_name);
911  vars = realtime_ldap_base_ap(entries_count_ptr, basedn, table_name, ap);
912  va_end(ap);
913 
914  return vars;
915 }
916 
917 /*! \brief See Asterisk doc
918 *
919 * For Realtime Dynamic(i.e., switch, queues, and directory) -- I think
920 */
921 static struct ast_variable *realtime_ldap(const char *basedn,
922  const char *table_name, va_list ap)
923 {
924  struct ast_variable **vars = realtime_ldap_base_ap(NULL, basedn, table_name, ap);
925  struct ast_variable *var = NULL;
926 
927  if (vars) {
928  struct ast_variable *last_var = NULL;
929  struct ast_variable **p = vars;
930  while (*p) {
931  if (last_var) {
932  while (last_var->next) {
933  last_var = last_var->next;
934  }
935  last_var->next = *p;
936  } else {
937  var = *p;
938  last_var = var;
939  }
940  p++;
941  }
942  free(vars);
943  }
944  return var;
945 }
946 
947 /*! \brief See Asterisk doc
948 *
949 * 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);
950 * however, the ast_load_realtime wil match on wildcharacters also depending on what the mode is set to
951 * this is an area of asterisk that could do with a lot of modification
952 * I think this function returns Realtime dynamic objects
953 */
954 static struct ast_config *realtime_multi_ldap(const char *basedn,
955  const char *table_name, va_list ap)
956 {
957  char *op;
958  const char *initfield = NULL;
959  const char *newparam, *newval;
960  struct ast_variable **vars =
961  realtime_ldap_base_ap(NULL, basedn, table_name, ap);
962  struct ast_config *cfg = NULL;
963 
964  newparam = va_arg(ap, const char *);
965  newval = va_arg(ap, const char *);
966  if (!newparam || !newval) {
967  ast_log(LOG_WARNING, "realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
968  return NULL;
969  }
970  initfield = ast_strdupa(newparam);
971  if ((op = strchr(initfield, ' '))) {
972  *op = '\0';
973  }
974 
975  if (vars) {
976  cfg = ast_config_new();
977  if (!cfg) {
978  ast_log(LOG_ERROR, "Unable to create a config!\n");
979  } else {
980  struct ast_variable **p = vars;
981 
982  while (*p) {
983  struct ast_category *cat = NULL;
984  cat = ast_category_new("", table_name, -1);
985  if (!cat) {
986  ast_log(LOG_ERROR, "Unable to create a new category!\n");
987  break;
988  } else {
989  struct ast_variable *var = *p;
990  while (var) {
991  struct ast_variable *next = var->next;
992  if (initfield && !strcmp(initfield, var->name)) {
993  ast_category_rename(cat, var->value);
994  }
995  var->next = NULL;
996  ast_variable_append(cat, var);
997  var = next;
998  }
999  }
1000  ast_category_append(cfg, cat);
1001  p++;
1002  }
1003  }
1004  free(vars);
1005  }
1006  return cfg;
1007 
1008 }
1009 
1010 /*!
1011  * \brief Sorting alogrithm for qsort to find the order of the variables \a a and \a b
1012  * \param a pointer to category_and_metric struct
1013  * \param b pointer to category_and_metric struct
1014  *
1015  * \retval -1 for if b is greater
1016  * \retval 0 zero for equal
1017  * \retval 1 if a is greater
1018  */
1019 static int compare_categories(const void *a, const void *b)
1020 {
1021  const struct category_and_metric *as = a;
1022  const struct category_and_metric *bs = b;
1023 
1024  if (as->metric < bs->metric) {
1025  return -1;
1026  } else if (as->metric > bs->metric) {
1027  return 1;
1028  } else if (as->metric == bs->metric && strcmp(as->name, bs->name) != 0) {
1029  return strcmp(as->name, bs->name);
1030  }
1031  /* if the metric and the category name is the same, we check the variable metric */
1032  if (as->var_metric < bs->var_metric) {
1033  return -1;
1034  } else if (as->var_metric > bs->var_metric) {
1035  return 1;
1036  }
1037 
1038  return 0;
1039 }
1040 
1041 /*! \brief See Asterisk doc
1042  *
1043 * This is for Static Realtime (again: I think...)
1044 *
1045 * load the configuration stuff for the .conf files
1046 * called on a reload
1047 */
1048 static struct ast_config *config_ldap(const char *basedn, const char *table_name,
1049  const char *file, struct ast_config *cfg, struct ast_flags config_flags, const char *sugg_incl, const char *who_asked)
1050 {
1051  unsigned int vars_count = 0;
1052  struct ast_variable **vars;
1053  int i = 0;
1054  struct ast_variable *new_v = NULL;
1055  struct ast_category *cur_cat = NULL;
1056  const char *last_category = NULL;
1057  int last_category_metric = 0;
1058  struct category_and_metric *categories;
1059  struct ast_variable **p;
1060 
1061  if (ast_strlen_zero(file) || !strcasecmp(file, RES_CONFIG_LDAP_CONF)) {
1062  ast_log(LOG_ERROR, "Missing configuration file: %s. Can't configure myself.\n", RES_CONFIG_LDAP_CONF);
1063  return NULL;
1064  }
1065 
1066  vars = realtime_ldap_base(&vars_count, basedn, table_name, "filename", file, "commented", "FALSE", NULL);
1067 
1068  if (!vars) {
1069  ast_log(LOG_WARNING, "Could not find config '%s' in directory.\n", file);
1070  return NULL;
1071  }
1072 
1073  /*!\note Since the items come back in random order, they need to be sorted
1074  * first, and since the data could easily exceed stack size, this is
1075  * allocated from the heap.
1076  */
1077  if (!(categories = ast_calloc(sizeof(*categories), vars_count))) {
1078  return NULL;
1079  }
1080 
1081  for (vars_count = 0, p = vars; *p; p++) {
1082  struct ast_variable *category = variable_named(*p, "category");
1083  struct ast_variable *cat_metric = variable_named(*p, "cat_metric");
1084  struct ast_variable *var_name = variable_named(*p, "variable_name");
1085  struct ast_variable *var_val = variable_named(*p, "variable_value");
1086  struct ast_variable *var_metric = variable_named(*p, "var_metric");
1087  struct ast_variable *dn = variable_named(*p, "dn");
1088 
1089  ast_debug(3, "category: %s\n", category->value);
1090  ast_debug(3, "var_name: %s\n", var_name->value);
1091  ast_debug(3, "var_val: %s\n", var_val->value);
1092  ast_debug(3, "cat_metric: %s\n", cat_metric->value);
1093 
1094  if (!category) {
1095  ast_log(LOG_ERROR, "No category name in entry '%s' for file '%s'.\n",
1096  (dn ? dn->value : "?"), file);
1097  } else if (!cat_metric) {
1098  ast_log(LOG_ERROR, "No category metric in entry '%s'(category: %s) for file '%s'.\n",
1099  (dn ? dn->value : "?"), category->value, file);
1100  } else if (!var_metric) {
1101  ast_log(LOG_ERROR, "No variable metric in entry '%s'(category: %s) for file '%s'.\n",
1102  (dn ? dn->value : "?"), category->value, file);
1103  } else if (!var_name) {
1104  ast_log(LOG_ERROR, "No variable name in entry '%s' (category: %s metric: %s) for file '%s'.\n",
1105  (dn ? dn->value : "?"), category->value,
1106  cat_metric->value, file);
1107  } else if (!var_val) {
1108  ast_log(LOG_ERROR, "No variable value in entry '%s' (category: %s metric: %s variable: %s) for file '%s'.\n",
1109  (dn ? dn->value : "?"), category->value,
1110  cat_metric->value, var_name->value, file);
1111  } else {
1112  categories[vars_count].name = category->value;
1113  categories[vars_count].metric = atoi(cat_metric->value);
1114  categories[vars_count].variable_name = var_name->value;
1115  categories[vars_count].variable_value = var_val->value;
1116  categories[vars_count].var_metric = atoi(var_metric->value);
1117  vars_count++;
1118  }
1119  }
1120 
1121  qsort(categories, vars_count, sizeof(*categories), compare_categories);
1122 
1123  for (i = 0; i < vars_count; i++) {
1124  if (!strcmp(categories[i].variable_name, "#include")) {
1125  struct ast_flags flags = { 0 };
1126  if (!ast_config_internal_load(categories[i].variable_value, cfg, flags, "", who_asked)) {
1127  break;
1128  }
1129  continue;
1130  }
1131 
1132  if (!last_category || strcmp(last_category, categories[i].name) ||
1133  last_category_metric != categories[i].metric) {
1134 
1135  cur_cat = ast_category_new(categories[i].name, table_name, -1);
1136  if (!cur_cat) {
1137  break;
1138  }
1139  last_category = categories[i].name;
1140  last_category_metric = categories[i].metric;
1141  ast_category_append(cfg, cur_cat);
1142  }
1143 
1144  if (!(new_v = ast_variable_new(categories[i].variable_name, categories[i].variable_value, table_name))) {
1145  break;
1146  }
1147 
1148  ast_variable_append(cur_cat, new_v);
1149  }
1150 
1151  ast_free(vars);
1152  ast_free(categories);
1153 
1154  return cfg;
1155 }
1156 
1157 /* \brief Function to update a set of values in ldap static mode
1158 */
1159 static int update_ldap(const char *basedn, const char *table_name, const char *attribute,
1160  const char *lookup, va_list ap)
1161 {
1162  int error = 0;
1163  LDAPMessage *ldap_entry = NULL;
1164  LDAPMod **ldap_mods;
1165  const char *newparam = NULL;
1166  const char *newval = NULL;
1167  char *dn;
1168  int num_entries = 0;
1169  int i = 0;
1170  int mods_size = 0;
1171  int mod_exists = 0;
1172  struct ldap_table_config *table_config = NULL;
1173  char *clean_basedn = NULL;
1174  struct ast_str *filter = NULL;
1175  int tries = 0;
1176  int result = 0;
1177  LDAPMessage *ldap_result_msg = NULL;
1178 
1179  if (!table_name) {
1180  ast_log(LOG_ERROR, "No table_name specified.\n");
1181  return -1;
1182  }
1183 
1184  if (!(filter = ast_str_create(80))) {
1185  return -1;
1186  }
1187 
1188  if (!attribute || !lookup) {
1189  ast_log(LOG_WARNING, "LINE(%d): search parameters are empty.\n", __LINE__);
1190  return -1;
1191  }
1193 
1194  /* We now have our complete statement; Lets connect to the server and execute it. */
1195  if (!ldap_reconnect()) {
1197  return -1;
1198  }
1199 
1200  table_config = table_config_for_table_name(table_name);
1201  if (!table_config) {
1202  ast_log(LOG_ERROR, "No table named '%s'.\n", table_name);
1204  return -1;
1205  }
1206 
1207  clean_basedn = cleaned_basedn(NULL, basedn);
1208 
1209  /* Create the filter with the table additional filter and the parameter/value pairs we were given */
1210  ast_str_append(&filter, 0, "(&");
1211  if (table_config && table_config->additional_filter) {
1212  ast_str_append(&filter, 0, "%s", table_config->additional_filter);
1213  }
1216  }
1217  append_var_and_value_to_filter(&filter, table_config, attribute, lookup);
1218  ast_str_append(&filter, 0, ")");
1219 
1220  /* Create the modification array with the parameter/value pairs we were given,
1221  * if there are several parameters with the same name, we collect them into
1222  * one parameter/value pair and delimit them with a semicolon */
1223  newparam = va_arg(ap, const char *);
1224  newparam = convert_attribute_name_to_ldap(table_config, newparam);
1225  newval = va_arg(ap, const char *);
1226  if (!newparam || !newval) {
1227  ast_log(LOG_WARNING, "LINE(%d): need at least one parameter to modify.\n", __LINE__);
1228  return -1;
1229  }
1230 
1231  mods_size = 2; /* one for the first param/value pair and one for the the terminating NULL */
1232  ldap_mods = ldap_memcalloc(sizeof(LDAPMod *), mods_size);
1233  ldap_mods[0] = ldap_memcalloc(1, sizeof(LDAPMod));
1234 
1235  ldap_mods[0]->mod_op = LDAP_MOD_REPLACE;
1236  ldap_mods[0]->mod_type = ldap_strdup(newparam);
1237 
1238  ldap_mods[0]->mod_values = ast_calloc(sizeof(char *), 2);
1239  ldap_mods[0]->mod_values[0] = ldap_strdup(newval);
1240 
1241  while ((newparam = va_arg(ap, const char *))) {
1242  newparam = convert_attribute_name_to_ldap(table_config, newparam);
1243  newval = va_arg(ap, const char *);
1244  mod_exists = 0;
1245 
1246  for (i = 0; i < mods_size - 1; i++) {
1247  if (ldap_mods[i]&& !strcmp(ldap_mods[i]->mod_type, newparam)) {
1248  /* We have the parameter allready, adding the value as a semicolon delimited value */
1249  ldap_mods[i]->mod_values[0] = ldap_memrealloc(ldap_mods[i]->mod_values[0], sizeof(char) * (strlen(ldap_mods[i]->mod_values[0]) + strlen(newval) + 2));
1250  strcat(ldap_mods[i]->mod_values[0], ";");
1251  strcat(ldap_mods[i]->mod_values[0], newval);
1252  mod_exists = 1;
1253  break;
1254  }
1255  }
1256 
1257  /* create new mod */
1258  if (!mod_exists) {
1259  mods_size++;
1260  ldap_mods = ldap_memrealloc(ldap_mods, sizeof(LDAPMod *) * mods_size);
1261  ldap_mods[mods_size - 1] = NULL;
1262 
1263  ldap_mods[mods_size - 2] = ldap_memcalloc(1, sizeof(LDAPMod));
1264 
1265  ldap_mods[mods_size - 2]->mod_type = ldap_memcalloc(sizeof(char), strlen(newparam) + 1);
1266  strcpy(ldap_mods[mods_size - 2]->mod_type, newparam);
1267 
1268  if (strlen(newval) == 0) {
1269  ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_DELETE;
1270  } else {
1271  ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_REPLACE;
1272 
1273  ldap_mods[mods_size - 2]->mod_values = ldap_memcalloc(sizeof(char *), 2);
1274  ldap_mods[mods_size - 2]->mod_values[0] = ldap_memcalloc(sizeof(char), strlen(newval) + 1);
1275  strcpy(ldap_mods[mods_size - 2]->mod_values[0], newval);
1276  }
1277  }
1278  }
1279  /* freeing ldap_mods further down */
1280 
1281  do {
1282  /* freeing ldap_result further down */
1283  result = ldap_search_ext_s(ldapConn, clean_basedn,
1284  LDAP_SCOPE_SUBTREE, ast_str_buffer(filter), NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
1285  &ldap_result_msg);
1286  if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
1287  ast_log(LOG_WARNING, "Failed to query directory. Try %d/3\n", tries + 1);
1288  tries++;
1289  if (tries < 3) {
1290  usleep(500000L * tries);
1291  if (ldapConn) {
1292  ldap_unbind_ext_s(ldapConn, NULL, NULL);
1293  ldapConn = NULL;
1294  }
1295  if (!ldap_reconnect())
1296  break;
1297  }
1298  }
1299  } while (result != LDAP_SUCCESS && tries < 3 && is_ldap_connect_error(result));
1300 
1301  if (result != LDAP_SUCCESS) {
1302  ast_log(LOG_WARNING, "Failed to query directory. Error: %s.\n", ldap_err2string(result));
1303  ast_log(LOG_WARNING, "Query: %s\n", ast_str_buffer(filter));
1304 
1306  free(filter);
1307  free(clean_basedn);
1308  ldap_msgfree(ldap_result_msg);
1309  ldap_mods_free(ldap_mods, 0);
1310  return -1;
1311  }
1312  /* Ready to update */
1313  if ((num_entries = ldap_count_entries(ldapConn, ldap_result_msg)) > 0) {
1314  ast_debug(3, "LINE(%d) Modifying %s=%s hits: %d\n", __LINE__, attribute, lookup, num_entries);
1315  for (i = 0; option_debug > 2 && i < mods_size - 1; i++) {
1316  if (ldap_mods[i]->mod_op != LDAP_MOD_DELETE) {
1317  ast_debug(3, "LINE(%d) %s=%s \n", __LINE__, ldap_mods[i]->mod_type, ldap_mods[i]->mod_values[0]);
1318  } else {
1319  ast_debug(3, "LINE(%d) deleting %s \n", __LINE__, ldap_mods[i]->mod_type);
1320  }
1321  }
1322  ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
1323 
1324  for (i = 0; ldap_entry; i++) {
1325  dn = ldap_get_dn(ldapConn, ldap_entry);
1326  if ((error = ldap_modify_ext_s(ldapConn, dn, ldap_mods, NULL, NULL)) != LDAP_SUCCESS) {
1327  ast_log(LOG_ERROR, "Couldn't modify '%s'='%s', dn:%s because %s\n",
1328  attribute, lookup, dn, ldap_err2string(error));
1329  }
1330  ldap_memfree(dn);
1331  ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
1332  }
1333  }
1334 
1336  ast_free(filter);
1337  ast_free(clean_basedn);
1338  ldap_msgfree(ldap_result_msg);
1339  ldap_mods_free(ldap_mods, 0);
1340  return num_entries;
1341 }
1342 
1343 static int update2_ldap(const char *basedn, const char *table_name, va_list ap)
1344 {
1345  int error = 0;
1346  LDAPMessage *ldap_entry = NULL;
1347  LDAPMod **ldap_mods;
1348  const char *newparam = NULL;
1349  const char *newval = NULL;
1350  char *dn;
1351  int num_entries = 0;
1352  int i = 0;
1353  int mods_size = 0;
1354  int mod_exists = 0;
1355  struct ldap_table_config *table_config = NULL;
1356  char *clean_basedn = NULL;
1357  struct ast_str *filter = NULL;
1358  int tries = 0;
1359  int result = 0;
1360  LDAPMessage *ldap_result_msg = NULL;
1361 
1362  if (!table_name) {
1363  ast_log(LOG_ERROR, "No table_name specified.\n");
1364  return -1;
1365  }
1366 
1367  if (!(filter = ast_str_create(80))) {
1368  return -1;
1369  }
1370 
1372 
1373  /* We now have our complete statement; Lets connect to the server and execute it. */
1374  if (!ldap_reconnect()) {
1376  ast_free(filter);
1377  return -1;
1378  }
1379 
1380  table_config = table_config_for_table_name(table_name);
1381  if (!table_config) {
1382  ast_log(LOG_ERROR, "No table named '%s'.\n", table_name);
1384  ast_free(filter);
1385  return -1;
1386  }
1387 
1388  clean_basedn = cleaned_basedn(NULL, basedn);
1389 
1390  /* Create the filter with the table additional filter and the parameter/value pairs we were given */
1391  ast_str_append(&filter, 0, "(&");
1392  if (table_config && table_config->additional_filter) {
1393  ast_str_append(&filter, 0, "%s", table_config->additional_filter);
1394  }
1395  if (table_config != base_table_config && base_table_config
1398  }
1399 
1400  /* Get multiple lookup keyfields and values */
1401  while ((newparam = va_arg(ap, const char *))) {
1402  newval = va_arg(ap, const char *);
1403  append_var_and_value_to_filter(&filter, table_config, newparam, newval);
1404  }
1405  ast_str_append(&filter, 0, ")");
1406 
1407  /* Create the modification array with the parameter/value pairs we were given,
1408  * if there are several parameters with the same name, we collect them into
1409  * one parameter/value pair and delimit them with a semicolon */
1410  newparam = va_arg(ap, const char *);
1411  newparam = convert_attribute_name_to_ldap(table_config, newparam);
1412  newval = va_arg(ap, const char *);
1413  if (!newparam || !newval) {
1414  ast_log(LOG_WARNING, "LINE(%d): need at least one parameter to modify.\n", __LINE__);
1415  ast_free(filter);
1416  ast_free(clean_basedn);
1417  return -1;
1418  }
1419 
1420  mods_size = 2; /* one for the first param/value pair and one for the the terminating NULL */
1421  ldap_mods = ast_calloc(sizeof(LDAPMod *), mods_size);
1422  ldap_mods[0] = ast_calloc(1, sizeof(LDAPMod));
1423 
1424  ldap_mods[0]->mod_op = LDAP_MOD_REPLACE;
1425  ldap_mods[0]->mod_type = ast_calloc(sizeof(char), strlen(newparam) + 1);
1426  strcpy(ldap_mods[0]->mod_type, newparam);
1427 
1428  ldap_mods[0]->mod_values = ast_calloc(sizeof(char), 2);
1429  ldap_mods[0]->mod_values[0] = ast_calloc(sizeof(char), strlen(newval) + 1);
1430  strcpy(ldap_mods[0]->mod_values[0], newval);
1431 
1432  while ((newparam = va_arg(ap, const char *))) {
1433  newparam = convert_attribute_name_to_ldap(table_config, newparam);
1434  newval = va_arg(ap, const char *);
1435  mod_exists = 0;
1436 
1437  for (i = 0; i < mods_size - 1; i++) {
1438  if (ldap_mods[i]&& !strcmp(ldap_mods[i]->mod_type, newparam)) {
1439  /* We have the parameter allready, adding the value as a semicolon delimited value */
1440  ldap_mods[i]->mod_values[0] = ast_realloc(ldap_mods[i]->mod_values[0], sizeof(char) * (strlen(ldap_mods[i]->mod_values[0]) + strlen(newval) + 2));
1441  strcat(ldap_mods[i]->mod_values[0], ";");
1442  strcat(ldap_mods[i]->mod_values[0], newval);
1443  mod_exists = 1;
1444  break;
1445  }
1446  }
1447 
1448  /* create new mod */
1449  if (!mod_exists) {
1450  mods_size++;
1451  ldap_mods = ast_realloc(ldap_mods, sizeof(LDAPMod *) * mods_size);
1452  ldap_mods[mods_size - 1] = NULL;
1453  ldap_mods[mods_size - 2] = ast_calloc(1, sizeof(LDAPMod));
1454 
1455  ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_REPLACE;
1456 
1457  ldap_mods[mods_size - 2]->mod_type = ast_calloc(sizeof(char), strlen(newparam) + 1);
1458  strcpy(ldap_mods[mods_size - 2]->mod_type, newparam);
1459 
1460  ldap_mods[mods_size - 2]->mod_values = ast_calloc(sizeof(char *), 2);
1461  ldap_mods[mods_size - 2]->mod_values[0] = ast_calloc(sizeof(char), strlen(newval) + 1);
1462  strcpy(ldap_mods[mods_size - 2]->mod_values[0], newval);
1463  }
1464  }
1465  /* freeing ldap_mods further down */
1466 
1467  do {
1468  /* freeing ldap_result further down */
1469  result = ldap_search_ext_s(ldapConn, clean_basedn,
1470  LDAP_SCOPE_SUBTREE, ast_str_buffer(filter), NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
1471  &ldap_result_msg);
1472  if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
1473  ast_log(LOG_WARNING, "Failed to query directory. Try %d/3\n", tries + 1);
1474  tries++;
1475  if (tries < 3) {
1476  usleep(500000L * tries);
1477  if (ldapConn) {
1478  ldap_unbind_ext_s(ldapConn, NULL, NULL);
1479  ldapConn = NULL;
1480  }
1481  if (!ldap_reconnect()) {
1482  break;
1483  }
1484  }
1485  }
1486  } while (result != LDAP_SUCCESS && tries < 3 && is_ldap_connect_error(result));
1487 
1488  if (result != LDAP_SUCCESS) {
1489  ast_log(LOG_WARNING, "Failed to query directory. Error: %s.\n", ldap_err2string(result));
1490  ast_log(LOG_WARNING, "Query: %s\n", ast_str_buffer(filter));
1491 
1493  ast_free(filter);
1494  ast_free(clean_basedn);
1495  ldap_msgfree(ldap_result_msg);
1496  ldap_mods_free(ldap_mods, 0);
1497  return -1;
1498  }
1499  /* Ready to update */
1500  if ((num_entries = ldap_count_entries(ldapConn, ldap_result_msg)) > 0) {
1501  for (i = 0; option_debug > 2 && i < mods_size - 1; i++) {
1502  ast_debug(3, "LINE(%d) %s=%s \n", __LINE__, ldap_mods[i]->mod_type, ldap_mods[i]->mod_values[0]);
1503  }
1504 
1505  ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
1506 
1507  for (i = 0; ldap_entry; i++) {
1508  dn = ldap_get_dn(ldapConn, ldap_entry);
1509  if ((error = ldap_modify_ext_s(ldapConn, dn, ldap_mods, NULL, NULL)) != LDAP_SUCCESS) {
1510  ast_log(LOG_ERROR, "Couldn't modify dn:%s because %s", dn, ldap_err2string(error));
1511  }
1512  ldap_memfree(dn);
1513  ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
1514  }
1515  }
1516 
1518  if (filter) {
1519  ast_free(filter);
1520  }
1521  if (clean_basedn) {
1522  ast_free(clean_basedn);
1523  }
1524  ldap_msgfree(ldap_result_msg);
1525  ldap_mods_free(ldap_mods, 0);
1526  return num_entries;
1527 }
1528 
1530  .name = "ldap",
1531  .load_func = config_ldap,
1532  .realtime_func = realtime_ldap,
1533  .realtime_multi_func = realtime_multi_ldap,
1534  .update_func = update_ldap,
1535  .update2_func = update2_ldap,
1536 };
1537 
1538 static int load_module(void)
1539 {
1540  if (parse_config() < 0) {
1541  ast_log(LOG_ERROR, "Cannot load LDAP RealTime driver.\n");
1542  return 0;
1543  }
1544 
1546 
1547  if (!ldap_reconnect()) {
1548  ast_log(LOG_WARNING, "Couldn't establish connection to LDAP directory. Check debug.\n");
1549  }
1550 
1552  ast_verb(1, "LDAP RealTime driver loaded.\n");
1554 
1556 
1557  return 0;
1558 }
1559 
1560 static int unload_module(void)
1561 {
1562  /* Aquire control before doing anything to the module itself. */
1564 
1566 
1567  if (ldapConn) {
1568  ldap_unbind_ext_s(ldapConn, NULL, NULL);
1569  ldapConn = NULL;
1570  }
1573  ast_verb(1, "LDAP RealTime driver unloaded.\n");
1574 
1575  /* Unlock so something else can destroy the lock. */
1577 
1578  return 0;
1579 }
1580 
1581 static int reload(void)
1582 {
1583  /* Aquire control before doing anything to the module itself. */
1585 
1586  if (ldapConn) {
1587  ldap_unbind_ext_s(ldapConn, NULL, NULL);
1588  ldapConn = NULL;
1589  }
1590 
1591  if (parse_config() < 0) {
1592  ast_log(LOG_NOTICE, "Cannot reload LDAP RealTime driver.\n");
1594  return 0;
1595  }
1596 
1597  if (!ldap_reconnect()) {
1598  ast_log(LOG_WARNING, "Couldn't establish connection to your directory server. Check debug.\n");
1599  }
1600 
1601  ast_verb(2, "LDAP RealTime driver reloaded.\n");
1602 
1603  /* Done reloading. Release lock so others can now use driver. */
1605 
1606  return 0;
1607 }
1608 
1609 /*! \brief parse the configuration file */
1610 static int parse_config(void)
1611 {
1612  struct ast_config *config;
1613  struct ast_flags config_flags = {0};
1614  const char *s, *host;
1615  int port;
1616  char *category_name = NULL;
1617 
1618  /* Make sure that global variables are reset */
1619  url[0] = '\0';
1620  user[0] = '\0';
1621  pass[0] = '\0';
1622  base_distinguished_name[0] = '\0';
1623  version = 3;
1624 
1625  config = ast_config_load(RES_CONFIG_LDAP_CONF, config_flags);
1626  if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEINVALID) {
1627  ast_log(LOG_ERROR, "Cannot load configuration file: %s\n", RES_CONFIG_LDAP_CONF);
1628  return -1;
1629  }
1630 
1631  if (!(s = ast_variable_retrieve(config, "_general", "user"))) {
1632  ast_log(LOG_NOTICE, "No directory user found, anonymous binding as default.\n");
1633  user[0] = '\0';
1634  } else {
1635  ast_copy_string(user, s, sizeof(user));
1636  }
1637 
1638  if (!ast_strlen_zero(user)) {
1639  if (!(s = ast_variable_retrieve(config, "_general", "pass"))) {
1640  ast_log(LOG_WARNING, "No directory password found, using 'asterisk' as default.\n");
1641  ast_copy_string(pass, "asterisk", sizeof(pass));
1642  } else {
1643  ast_copy_string(pass, s, sizeof(pass));
1644  }
1645  }
1646 
1647  /* URL is preferred, use host and port if not found */
1648  if ((s = ast_variable_retrieve(config, "_general", "url"))) {
1649  ast_copy_string(url, s, sizeof(url));
1650  } else if ((host = ast_variable_retrieve(config, "_general", "host"))) {
1651  if (!(s = ast_variable_retrieve(config, "_general", "port")) || sscanf(s, "%5d", &port) != 1 || port > 65535) {
1652  ast_log(LOG_NOTICE, "No directory port found, using 389 as default.\n");
1653  port = 389;
1654  }
1655 
1656  snprintf(url, sizeof(url), "ldap://%s:%d", host, port);
1657  } else {
1658  ast_log(LOG_ERROR, "No directory URL or host found.\n");
1659  ast_config_destroy(config);
1660  return -1;
1661  }
1662 
1663  if (!(s = ast_variable_retrieve(config, "_general", "basedn"))) {
1664  ast_log(LOG_ERROR, "No LDAP base dn found, using '%s' as default.\n", RES_CONFIG_LDAP_DEFAULT_BASEDN);
1665  ast_copy_string(base_distinguished_name, RES_CONFIG_LDAP_DEFAULT_BASEDN, sizeof(base_distinguished_name));
1666  } else
1667  ast_copy_string(base_distinguished_name, s, sizeof(base_distinguished_name));
1668 
1669  if (!(s = ast_variable_retrieve(config, "_general", "version")) && !(s = ast_variable_retrieve(config, "_general", "protocol"))) {
1670  ast_log(LOG_NOTICE, "No explicit LDAP version found, using 3 as default.\n");
1671  } else if (sscanf(s, "%30d", &version) != 1 || version < 1 || version > 6) {
1672  ast_log(LOG_WARNING, "Invalid LDAP version '%s', using 3 as default.\n", s);
1673  version = 3;
1674  }
1675 
1677 
1678  while ((category_name = ast_category_browse(config, category_name))) {
1679  int is_general = (strcasecmp(category_name, "_general") == 0);
1680  int is_config = (strcasecmp(category_name, "config") == 0); /*!< using the [config] context for Static RealTime */
1681  struct ast_variable *var = ast_variable_browse(config, category_name);
1682 
1683  if (var) {
1684  struct ldap_table_config *table_config =
1685  table_config_for_table_name(category_name);
1686  if (!table_config) {
1687  table_config = table_config_new(category_name);
1688  AST_LIST_INSERT_HEAD(&table_configs, table_config, entry);
1689  if (is_general)
1690  base_table_config = table_config;
1691  if (is_config)
1692  static_table_config = table_config;
1693  }
1694  for (; var; var = var->next) {
1695  if (!strcasecmp(var->name, "additionalFilter")) {
1696  table_config->additional_filter = ast_strdup(var->value);
1697  } else {
1698  ldap_table_config_add_attribute(table_config, var->name, var->value);
1699  }
1700  }
1701  }
1702  }
1703 
1704  ast_config_destroy(config);
1705 
1706  return 1;
1707 }
1708 
1709 /*! \note ldap_lock should have been locked before calling this function. */
1710 static int ldap_reconnect(void)
1711 {
1712  int bind_result = 0;
1713  struct berval cred;
1714 
1715  if (ldapConn) {
1716  ast_debug(2, "Everything seems fine.\n");
1717  return 1;
1718  }
1719 
1720  if (ast_strlen_zero(url)) {
1721  ast_log(LOG_ERROR, "Not enough parameters to connect to ldap directory\n");
1722  return 0;
1723  }
1724 
1725  if (LDAP_SUCCESS != ldap_initialize(&ldapConn, url)) {
1726  ast_log(LOG_ERROR, "Failed to init ldap connection to '%s'. Check debug for more info.\n", url);
1727  return 0;
1728  }
1729 
1730  if (LDAP_OPT_SUCCESS != ldap_set_option(ldapConn, LDAP_OPT_PROTOCOL_VERSION, &version)) {
1731  ast_log(LOG_WARNING, "Unable to set LDAP protocol version to %d, falling back to default.\n", version);
1732  }
1733 
1734  if (!ast_strlen_zero(user)) {
1735  ast_debug(2, "bind to '%s' as user '%s'\n", url, user);
1736  cred.bv_val = (char *) pass;
1737  cred.bv_len = strlen(pass);
1738  bind_result = ldap_sasl_bind_s(ldapConn, user, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
1739  } else {
1740  ast_debug(2, "bind %s anonymously\n", url);
1741  cred.bv_val = NULL;
1742  cred.bv_len = 0;
1743  bind_result = ldap_sasl_bind_s(ldapConn, NULL, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
1744  }
1745  if (bind_result == LDAP_SUCCESS) {
1746  ast_debug(2, "Successfully connected to directory.\n");
1747  connect_time = time(NULL);
1748  return 1;
1749  } else {
1750  ast_log(LOG_WARNING, "bind failed: %s\n", ldap_err2string(bind_result));
1751  ldap_unbind_ext_s(ldapConn, NULL, NULL);
1752  ldapConn = NULL;
1753  return 0;
1754  }
1755 }
1756 
1757 static char *realtime_ldap_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1758 {
1759  char status[256], credentials[100] = "";
1760  int ctimesec = time(NULL) - connect_time;
1761 
1762  switch (cmd) {
1763  case CLI_INIT:
1764  e->command = "realtime show ldap status";
1765  e->usage =
1766  "Usage: realtime show ldap status\n"
1767  " Shows connection information for the LDAP RealTime driver\n";
1768  return NULL;
1769  case CLI_GENERATE:
1770  return NULL;
1771  }
1772 
1773  if (!ldapConn)
1774  return CLI_FAILURE;
1775 
1776  if (!ast_strlen_zero(url))
1777  snprintf(status, sizeof(status), "Connected to '%s', baseDN %s", url, base_distinguished_name);
1778 
1779  if (!ast_strlen_zero(user))
1780  snprintf(credentials, sizeof(credentials), " with username %s", user);
1781 
1782  if (ctimesec > 31536000) {
1783  ast_cli(a->fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n",
1784  status, credentials, ctimesec / 31536000,
1785  (ctimesec % 31536000) / 86400, (ctimesec % 86400) / 3600,
1786  (ctimesec % 3600) / 60, ctimesec % 60);
1787  } else if (ctimesec > 86400) {
1788  ast_cli(a->fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n",
1789  status, credentials, ctimesec / 86400, (ctimesec % 86400) / 3600,
1790  (ctimesec % 3600) / 60, ctimesec % 60);
1791  } else if (ctimesec > 3600) {
1792  ast_cli(a->fd, "%s%s for %d hours, %d minutes, %d seconds.\n",
1793  status, credentials, ctimesec / 3600, (ctimesec % 3600) / 60,
1794  ctimesec % 60);
1795  } else if (ctimesec > 60) {
1796  ast_cli(a->fd, "%s%s for %d minutes, %d seconds.\n", status, credentials,
1797  ctimesec / 60, ctimesec % 60);
1798  } else {
1799  ast_cli(a->fd, "%s%s for %d seconds.\n", status, credentials, ctimesec);
1800  }
1801 
1802  return CLI_SUCCESS;
1803 }
1804 
1805 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "LDAP realtime interface",
1806  .load = load_module,
1807  .unload = unload_module,
1808  .reload = reload,
1809  .load_pri = AST_MODPRI_REALTIME_DRIVER,
1810 );
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition: pbx.c:4676
static char pass[512]
Main Channel structure associated with a channel.
Definition: channel.h:742
static ast_mutex_t ldap_lock
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:191
uint32_t version
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
const char * ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
Gets a variable.
Definition: config.c:625
static const char config[]
Definition: cdr_csv.c:57
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static void append_var_and_value_to_filter(struct ast_str **filter, struct ldap_table_config *table_config, const char *name, const char *value)
Append a name=value filter string. The filter string can grow.
String manipulation functions.
#define ast_strdup(a)
Definition: astmm.h:109
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: cli.c:2177
int option_debug
Definition: asterisk.c:182
descriptor for a cli entry.
Definition: cli.h:165
#define LOG_WARNING
Definition: logger.h:144
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category)
Goes through variables.
Definition: config.c:597
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
static int semicolon_count_str(const char *somestr)
for the semicolon delimiter
#define RES_CONFIG_LDAP_CONF
Structure for variables, used for configurations and for channel variables.
Definition: config.h:75
#define var
Definition: ast_expr2f.c:606
static struct ast_variable * variable_named(struct ast_variable *var, const char *name)
Find variable by name.
Definition: cli.h:146
Configuration File Parser.
static char * cleaned_basedn(struct ast_channel *channel, const char *basedn)
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:900
struct ast_str * ast_str_create(size_t init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:420
#define ast_mutex_lock(a)
Definition: lock.h:155
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:374
static char * realtime_ldap_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static struct ldap_table_config * table_config_new(const char *table_name)
Create a new table_config.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: config.c:586
int value
Definition: syslog.c:39
void ast_cli(int fd, const char *fmt,...)
Definition: cli.c:105
#define LOG_DEBUG
Definition: logger.h:122
static int is_ldap_connect_error(int err)
Check if we have a connection error.
#define MAXRESULT
static char base_distinguished_name[512]
const char * variable_value
#define ast_verb(level,...)
Definition: logger.h:243
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: config.c:1037
static struct ldap_table_config * base_table_config
static struct ldap_table_config * table_config_for_table_name(const char *table_name)
Find a table_config - Should be locked before using it.
Configuration engine structure, used to define realtime drivers.
Definition: config.h:121
Utility functions.
struct ast_category * ast_category_new(const char *name, const char *in_file, int lineno)
Create a category structure.
Definition: config.c:673
#define CONFIG_STATUS_FILEMISSING
Definition: config.h:50
static int replace_string_in_string(char *string, const char *search, const char *by)
Replace &lt;search&gt; by &lt;by&gt; in string.
static int reload(void)
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
static int compare_categories(const void *a, const void *b)
Sorting alogrithm for qsort to find the order of the variables a and b.
const char * value
Definition: config.h:79
static void table_configs_free(void)
Free table_config.
static struct ast_config_engine ldap_engine
const int fd
Definition: cli.h:153
#define ast_config_load(filename, flags)
Load a config file.
Definition: config.h:170
static const char * convert_attribute_name_to_ldap(struct ldap_table_config *table_config, const char *attribute_name)
Convert variable name to ldap attribute name - Should be locked before using it.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
Table configuration.
char * ast_category_browse(struct ast_config *config, const char *prev)
Goes through categories.
Definition: config.c:810
static struct ast_variable * realtime_ldap(const char *basedn, const char *table_name, va_list ap)
See Asterisk doc.
struct ast_variable * delimiters
static time_t connect_time
A set of macros to manage forward-linked lists.
const char * name
Definition: config.h:77
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:818
static LDAP * ldapConn
Core PBX routines and definitions.
static const char * convert_attribute_name_from_ldap(struct ldap_table_config *table_config, const char *attribute_name)
Convert ldap attribute name to variable name.
static struct ast_variable ** realtime_ldap_base(unsigned int *entries_count_ptr, const char *basedn, const char *table_name,...)
same as realtime_ldap_base_ap but take variable arguments count list
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
#define AST_LIST_HEAD_NOLOCK_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
Definition: linkedlists.h:345
#define LOG_ERROR
Definition: logger.h:155
static struct ast_cli_entry ldap_cli[]
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
#define free(a)
Definition: astmm.h:94
void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
Definition: config.c:483
static struct ast_variable ** realtime_ldap_result_to_vars(struct ldap_table_config *table_config, LDAPMessage *ldap_result_msg, unsigned int *entries_count_ptr)
Get variables from ldap entry attributes - Should be locked before using it.
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
struct ldap_table_config * next
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define LOG_NOTICE
Definition: logger.h:133
int ast_config_engine_register(struct ast_config_engine *newconfig)
Register config engine.
Definition: config.c:2378
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:409
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:696
static struct ast_variable * realtime_ldap_entry_to_var(struct ldap_table_config *table_config, LDAPMessage *ldap_entry)
Get variables from ldap entry attributes.
#define CLI_FAILURE
Definition: cli.h:45
static const char name[]
#define ast_free(a)
Definition: astmm.h:97
char * command
Definition: cli.h:180
struct ast_config * ast_config_new(void)
Create a new base configuration structure.
Definition: config.c:888
static int update_ldap(const char *basedn, const char *table_name, const char *attribute, const char *lookup, va_list ap)
static void ldap_table_config_add_attribute(struct ldap_table_config *table_config, const char *attribute_name, const char *attribute_value)
add attribute to table config - Should be locked before using it
static int semicolon_count_var(struct ast_variable *var)
static int update2_ldap(const char *basedn, const char *table_name, va_list ap)
structure to hold users read from users.conf
Structure used to handle boolean flags.
Definition: utils.h:200
static struct ast_config * realtime_multi_ldap(const char *basedn, const char *table_name, va_list ap)
See Asterisk doc.
Support for logging to various files, console and syslog Configuration in file logger.conf.
static int unload_module(void)
const char * usage
Definition: cli.h:171
const char * variable_name
#define CLI_SUCCESS
Definition: cli.h:43
static int parse_config(void)
parse the configuration file
Standard Command Line Interface.
#define ast_calloc(a, b)
Definition: astmm.h:82
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
struct ast_variable * attributes
#define RES_CONFIG_LDAP_DEFAULT_BASEDN
int ast_cli_register_multiple(struct ast_cli_entry *e, int len)
Register multiple commands.
Definition: cli.c:2167
#define ast_realloc(a, b)
Definition: astmm.h:103
static struct ast_config * config_ldap(const char *basedn, const char *table_name, const char *file, struct ast_config *cfg, struct ast_flags config_flags, const char *sugg_incl, const char *who_asked)
See Asterisk doc.
static struct ast_variable * ldap_loadentry(struct ldap_table_config *table_config, const char *dn)
Get LDAP entry by dn and return attributes as variables - Should be locked before using it This is us...
Options provided by main asterisk program.
struct ldap_table_config::@326 entry
struct ast_variable * next
Definition: config.h:82
static struct ast_variable ** realtime_ldap_base_ap(unsigned int *entries_count_ptr, const char *basedn, const char *table_name, va_list ap)
LDAP base function.
void ast_category_append(struct ast_config *config, struct ast_category *cat)
Definition: config.c:719
#define CONFIG_STATUS_FILEINVALID
Definition: config.h:52
static int filter(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
Definition: func_strings.c:694
static int load_module(void)
struct ast_config * ast_config_internal_load(const char *configfile, struct ast_config *cfg, struct ast_flags flags, const char *suggested_incl_file, const char *who_asked)
Definition: config.c:2459
static char url[512]
void ast_category_rename(struct ast_category *cat, const char *name)
Definition: config.c:867
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:38
Asterisk module definitions.
static char * substituted(struct ast_channel *channel, const char *string)
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:526
struct ast_variable * ast_variable_new(const char *name, const char *value, const char *filename)
Definition: config.c:278
Should be locked before using it.
static int ldap_reconnect(void)
jack_status_t status
Definition: app_jack.c:143
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
int ast_config_engine_deregister(struct ast_config_engine *del)
Deregister config engine.
Definition: config.c:2397
#define ast_mutex_unlock(a)
Definition: lock.h:156
static struct ldap_table_config * static_table_config