Asterisk - The Open Source Telephony Project GIT-master-5467495
Loading...
Searching...
No Matches
res_config_ldap.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
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 * OpenLDAP http://www.openldap.org
32 */
33
34/*! \li \ref res_config_ldap.c uses the configuration file \ref res_ldap.conf
35 * \addtogroup configuration_file Configuration Files
36 */
37
38/*!
39 * \page res_ldap.conf res_ldap.conf
40 * \verbinclude res_ldap.conf.sample
41 */
42
43/*** MODULEINFO
44 <depend>ldap</depend>
45 <support_level>extended</support_level>
46 ***/
47
48#include "asterisk.h"
49
50#include <stdlib.h>
51#include <string.h>
52#include <ctype.h>
53#include <stdio.h>
54#include <ldap.h>
55
56#include "asterisk/channel.h"
57#include "asterisk/logger.h"
58#include "asterisk/config.h"
59#include "asterisk/module.h"
60#include "asterisk/lock.h"
61#include "asterisk/options.h"
62#include "asterisk/cli.h"
63#include "asterisk/utils.h"
64#include "asterisk/strings.h"
65#include "asterisk/pbx.h"
67
68#define RES_CONFIG_LDAP_CONF "res_ldap.conf"
69#define RES_CONFIG_LDAP_DEFAULT_BASEDN "asterisk"
70
72
73static LDAP *ldapConn;
74static char url[512];
75static char user[512];
76static char pass[512];
77static char base_distinguished_name[512];
78static int version;
79static time_t connect_time;
80
81static int parse_config(void);
82static int ldap_reconnect(void);
83static char *realtime_ldap_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
84
86 const char *name;
87 int metric;
88 const char *variable_name;
89 const char *variable_value;
90 int var_metric; /*!< For organizing variables (particularly includes and switch statements) within a context */
91};
92
93/*! \brief Table configuration
94 */
96 char *table_name; /*!< table name */
97 char *additional_filter; /*!< additional filter */
98 struct ast_variable *attributes; /*!< attribute names conversion */
99 struct ast_variable *delimiters; /*!< the current delimiter is semicolon, so we are not using this variable */
101 /*! \todo: Make proxies work */
102};
103
104/*! \brief Should be locked before using it
105 */
109
110static struct ast_cli_entry ldap_cli[] = {
111 AST_CLI_DEFINE(realtime_ldap_status, "Shows connection information for the LDAP RealTime driver"),
112};
113
114/*! \brief Create a new table_config
115 */
117{
118 struct ldap_table_config *p;
119
120 if (!(p = ast_calloc(1, sizeof(*p))))
121 return NULL;
122
123 if (table_name) {
124 if (!(p->table_name = ast_strdup(table_name))) {
125 ast_free(p);
126 return NULL;
127 }
128 }
129
130 return p;
131}
132
133/*! \brief Find a table_config
134 *
135 * Should be locked before using it
136 *
137 * \note This function assumes ldap_lock to be locked.
138 */
140{
141 struct ldap_table_config *c = NULL;
142
144 if (!strcmp(c->table_name, table_name))
145 break;
146 }
147
148 return c;
149}
150
151/*! \brief Find variable by name
152 */
153static struct ast_variable *variable_named(struct ast_variable *var, const char *name)
154{
155 for (; var; var = var->next) {
156 if (!strcasecmp(name, var->name))
157 break;
158 }
159
160 return var;
161}
162
163/*!
164 * \brief Count semicolons in string
165 * \param somestr - pointer to a string
166 *
167 * \return number of occurances of the delimiter(semicolon)
168 */
169static int semicolon_count_str(const char *somestr)
170{
171 int count = 0;
172
173 for (; *somestr; somestr++) {
174 if (*somestr == ';')
175 count++;
176 }
177
178 return count;
179}
180
181/*!
182 * \brief Count semicolons in variables
183 *
184 * takes a linked list of \a ast_variable variables, finds the one with the name variable_value
185 * and returns the number of semicolons in the value for that \a ast_variable
186 */
188{
189 struct ast_variable *var_value = variable_named(var, "variable_value");
190
191 if (!var_value) {
192 return 0;
193 }
194
195 ast_debug(2, "semicolon_count_var: %s\n", var_value->value);
196
197 return semicolon_count_str(var_value->value);
198}
199
200/*! \brief add attribute to table config
201 *
202 * Should be locked before using it
203 */
204static void ldap_table_config_add_attribute(struct ldap_table_config *table_config,
205 const char *attribute_name, const char *attribute_value)
206{
207 struct ast_variable *var;
208
209 if (ast_strlen_zero(attribute_name) || ast_strlen_zero(attribute_value)) {
210 return;
211 }
212
213 if (!(var = ast_variable_new(attribute_name, attribute_value, table_config->table_name))) {
214 return;
215 }
216
217 if (table_config->attributes) {
218 var->next = table_config->attributes;
219 }
220 table_config->attributes = var;
221}
222
223/*! \brief Free table_config
224 *
225 * \note assumes ldap_lock to be locked
226 */
227static void table_configs_free(void)
228{
229 struct ldap_table_config *c;
230
232 if (c->table_name) {
233 ast_free(c->table_name);
234 }
235 if (c->additional_filter) {
236 ast_free(c->additional_filter);
237 }
238 if (c->attributes) {
239 ast_variables_destroy(c->attributes);
240 }
241 ast_free(c);
242 }
243
246}
247
248/*! \brief Convert variable name to ldap attribute name
249 *
250 * \note Should be locked before using it
251 */
252static const char *convert_attribute_name_to_ldap(struct ldap_table_config *table_config,
253 const char *attribute_name)
254{
255 int i = 0;
256 struct ldap_table_config *configs[] = { table_config, base_table_config };
257
258 for (i = 0; i < ARRAY_LEN(configs); i++) {
259 struct ast_variable *attribute;
260
261 if (!configs[i]) {
262 continue;
263 }
264
265 attribute = configs[i]->attributes;
266 for (; attribute; attribute = attribute->next) {
267 if (!strcasecmp(attribute_name, attribute->name)) {
268 return attribute->value;
269 }
270 }
271 }
272
273 return attribute_name;
274}
275
276/*! \brief Convert ldap attribute name to variable name
277 *
278 * \note Should be locked before using it
279 */
280static const char *convert_attribute_name_from_ldap(struct ldap_table_config *table_config,
281 const char *attribute_name)
282{
283 int i = 0;
284 struct ldap_table_config *configs[] = { table_config, base_table_config };
285
286 for (i = 0; i < ARRAY_LEN(configs); i++) {
287 struct ast_variable *attribute;
288
289 if (!configs[i]) {
290 continue;
291 }
292
293 attribute = configs[i]->attributes;
294 for (; attribute; attribute = attribute->next) {
295 if (strcasecmp(attribute_name, attribute->value) == 0) {
296 return attribute->name;
297 }
298 }
299 }
300
301 return attribute_name;
302}
303
304/*! \brief Get variables from ldap entry attributes
305 * \note Should be locked before using it
306 * \return a linked list of ast_variable variables.
307 */
309 LDAPMessage *ldap_entry)
310{
311 BerElement *ber = NULL;
312 struct ast_variable *var = NULL;
313 struct ast_variable *prev = NULL;
314#if 0
315 int is_delimited = 0;
316 int i = 0;
317#endif
318 char *ldap_attribute_name;
319 struct berval *value;
320 int pos = 0;
321
322 ldap_attribute_name = ldap_first_attribute(ldapConn, ldap_entry, &ber);
323
324 while (ldap_attribute_name) {
325 struct berval **values = NULL;
326 const char *attribute_name = convert_attribute_name_from_ldap(table_config, ldap_attribute_name);
327 int is_realmed_password_attribute = strcasecmp(attribute_name, "md5secret") == 0;
328
329 values = ldap_get_values_len(ldapConn, ldap_entry, ldap_attribute_name); /* these are freed at the end */
330 if (values) {
331 struct berval **v;
332 char *valptr;
333
334 for (v = values; *v; v++) {
335 value = *v;
336 valptr = value->bv_val;
337 ast_debug(2, "attribute_name: %s LDAP value: %s\n", attribute_name, valptr);
338 if (is_realmed_password_attribute) {
339 if (!strncasecmp(valptr, "{md5}", 5)) {
340 valptr += 5;
341 }
342 ast_debug(2, "md5: %s\n", valptr);
343 }
344 if (valptr) {
345#if 0
346 /* ok, so looping through all delimited values except the last one (not, last character is not delimited...) */
347 if (is_delimited) {
348 i = 0;
349 pos = 0;
350 while (!ast_strlen_zero(valptr + i)) {
351 if (valptr[i] == ';') {
352 valptr[i] = '\0';
353 if (prev) {
354 prev->next = ast_variable_new(attribute_name, &valptr[pos], table_config->table_name);
355 if (prev->next) {
356 prev = prev->next;
357 }
358 } else {
359 prev = var = ast_variable_new(attribute_name, &valptr[pos], table_config->table_name);
360 }
361 pos = i + 1;
362 }
363 i++;
364 }
365 }
366#endif
367 /* for the last delimited value or if the value is not delimited: */
368 if (prev) {
369 prev->next = ast_variable_new(attribute_name, &valptr[pos], table_config->table_name);
370 if (prev->next) {
371 prev = prev->next;
372 }
373 } else {
374 prev = var = ast_variable_new(attribute_name, &valptr[pos], table_config->table_name);
375 }
376 }
377 }
378 ldap_value_free_len(values);
379 }
380 ldap_memfree(ldap_attribute_name);
381 ldap_attribute_name = ldap_next_attribute(ldapConn, ldap_entry, ber);
382 }
383 ber_free(ber, 0);
384
385 return var;
386}
387
388/*! \brief Get variables from ldap entry attributes - Should be locked before using it
389 *
390 * The results are freed outside this function so is the \a vars array.
391 *
392 * \return \a vars - an array of ast_variable variables terminated with a null.
393 */
395 LDAPMessage *ldap_result_msg, unsigned int *entries_count_ptr)
396{
397 struct ast_variable **vars;
398 int i = 0;
399 int tot_count = 0;
400 int entry_index = 0;
401 LDAPMessage *ldap_entry = NULL;
402 BerElement *ber = NULL;
403 struct ast_variable *var = NULL;
404 struct ast_variable *prev = NULL;
405 int is_delimited = 0;
406 char *delim_value = NULL;
407 int delim_tot_count = 0;
408 int delim_count = 0;
409
410 /*! \brief First find the total count
411 */
412 ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
413
414 for (tot_count = 0; ldap_entry; tot_count++) {
415 struct ast_variable *tmp = realtime_ldap_entry_to_var(table_config, ldap_entry);
416 tot_count += semicolon_count_var(tmp);
417 ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
419 }
420
421 if (entries_count_ptr) {
422 *entries_count_ptr = tot_count;
423 }
424
425 /*! \note Now that we have the total count we allocate space and create the variables
426 * Remember that each element in vars is a linked list that points to realtime variable.
427 * If the we are dealing with a static realtime variable we create a new element in the \a vars array for each delimited
428 * 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.
429 * This memory must be freed outside of this function.
430 */
431 vars = ast_calloc(tot_count + 1, sizeof(struct ast_variable *));
432
433 ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
434
435 i = 0;
436
437 /*! \brief For each static realtime variable we may create several entries in the \a vars array if it's delimited
438 */
439 for (entry_index = 0; ldap_entry; ) {
440 int pos = 0;
441 delim_value = NULL;
442 delim_tot_count = 0;
443 delim_count = 0;
444
445 do { /* while delim_count */
446
447 /* Starting new static var */
448 char *ldap_attribute_name = ldap_first_attribute(ldapConn, ldap_entry, &ber);
449 struct berval *value;
450 while (ldap_attribute_name) {
451 const char *attribute_name = convert_attribute_name_from_ldap(table_config, ldap_attribute_name);
452 int is_realmed_password_attribute = strcasecmp(attribute_name, "md5secret") == 0;
453 struct berval **values = NULL;
454
455 values = ldap_get_values_len(ldapConn, ldap_entry, ldap_attribute_name);
456 if (values) {
457 struct berval **v;
458 char *valptr;
459
460 for (v = values; *v; v++) {
461 value = *v;
462 valptr = value->bv_val;
463 if (is_realmed_password_attribute) {
464 if (strncasecmp(valptr, "{md5}", 5) == 0) {
465 valptr += 5;
466 }
467 ast_debug(2, "md5: %s\n", valptr);
468 }
469 if (valptr) {
470 if (delim_value == NULL && !is_realmed_password_attribute
471 && (static_table_config != table_config || strcmp(attribute_name, "variable_value") == 0)) {
472
473 delim_value = ast_strdup(valptr);
474
475 if ((delim_tot_count = semicolon_count_str(delim_value)) > 0) {
476 ast_debug(4, "is delimited %d times: %s\n", delim_tot_count, delim_value);
477 is_delimited = 1;
478 }
479 }
480
481 if (is_delimited != 0 && !is_realmed_password_attribute
482 && (static_table_config != table_config || strcmp(attribute_name, "variable_value") == 0) ) {
483 /* for non-Static RealTime, first */
484
485 for (i = pos; !ast_strlen_zero(valptr + i); i++) {
486 ast_debug(4, "DELIM pos: %d i: %d\n", pos, i);
487 if (delim_value[i] == ';') {
488 delim_value[i] = '\0';
489
490 ast_debug(2, "DELIM - attribute_name: %s value: %s pos: %d\n", attribute_name, &delim_value[pos], pos);
491
492 if (prev) {
493 prev->next = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name);
494 if (prev->next) {
495 prev = prev->next;
496 }
497 } else {
498 prev = var = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name);
499 }
500 pos = i + 1;
501
502 if (static_table_config == table_config) {
503 break;
504 }
505 }
506 }
507 if (ast_strlen_zero(valptr + i)) {
508 ast_debug(4, "DELIM pos: %d i: %d delim_count: %d\n", pos, i, delim_count);
509 /* Last delimited value */
510 ast_debug(4, "DELIM - attribute_name: %s value: %s pos: %d\n", attribute_name, &delim_value[pos], pos);
511 if (prev) {
512 prev->next = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name);
513 if (prev->next) {
514 prev = prev->next;
515 }
516 } else {
517 prev = var = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name);
518 }
519 /* Remembering to free memory */
520 is_delimited = 0;
521 pos = 0;
522 }
523 ast_free(delim_value);
524 delim_value = NULL;
525
526 ast_debug(4, "DELIM pos: %d i: %d\n", pos, i);
527 } else {
528 /* not delimited */
529 if (delim_value) {
530 ast_free(delim_value);
531 delim_value = NULL;
532 }
533 ast_debug(2, "attribute_name: %s value: %s\n", attribute_name, valptr);
534
535 if (prev) {
536 prev->next = ast_variable_new(attribute_name, valptr, table_config->table_name);
537 if (prev->next) {
538 prev = prev->next;
539 }
540 } else {
541 prev = var = ast_variable_new(attribute_name, valptr, table_config->table_name);
542 }
543 }
544 }
545 } /*!< for (v = values; *v; v++) */
546 ldap_value_free_len(values);
547 }/*!< if (values) */
548 ldap_memfree(ldap_attribute_name);
549 ldap_attribute_name = ldap_next_attribute(ldapConn, ldap_entry, ber);
550 } /*!< while (ldap_attribute_name) */
551 ber_free(ber, 0);
552 if (static_table_config == table_config) {
553 if (DEBUG_ATLEAST(3)) {
554 const struct ast_variable *tmpdebug = variable_named(var, "variable_name");
555 const struct ast_variable *tmpdebug2 = variable_named(var, "variable_value");
556 if (tmpdebug && tmpdebug2) {
557 ast_log(LOG_DEBUG, "Added to vars - %s = %s\n", tmpdebug->value, tmpdebug2->value);
558 }
559 }
560 vars[entry_index++] = var;
561 prev = NULL;
562 }
563
564 delim_count++;
565 } while (delim_count <= delim_tot_count && static_table_config == table_config);
566
567 if (static_table_config != table_config) {
568 ast_debug(3, "Added to vars - non static\n");
569
570 vars[entry_index++] = var;
571 prev = NULL;
572 }
573 ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
574 } /*!< end for loop over ldap_entry */
575
576 return vars;
577}
578
579
580/*! \brief Check if we have a connection error
581 */
582static int is_ldap_connect_error(int err)
583{
584 return (err == LDAP_SERVER_DOWN || err == LDAP_TIMEOUT || err == LDAP_CONNECT_ERROR);
585}
586
587/*! \brief Get LDAP entry by dn and return attributes as variables
588 *
589 * Should be locked before using it
590 *
591 * This is used for setting the default values of an object
592 * i.e., with accountBaseDN
593*/
594static struct ast_variable *ldap_loadentry(struct ldap_table_config *table_config,
595 const char *dn)
596{
597 if (!table_config) {
598 ast_log(LOG_ERROR, "No table config\n");
599 return NULL;
600 } else {
601 struct ast_variable **vars = NULL;
602 struct ast_variable *var = NULL;
603 int result = -1;
604 LDAPMessage *ldap_result_msg = NULL;
605 int tries = 0;
606
607 ast_debug(2, "ldap_loadentry dn=%s\n", dn);
608
609 do {
610 result = ldap_search_ext_s(ldapConn, dn, LDAP_SCOPE_BASE,
611 "(objectclass=*)", NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &ldap_result_msg);
612 if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
613 ast_log(LOG_WARNING, "Failed to query directory. Try %d/3\n", tries + 1);
614 tries++;
615 if (tries < 3) {
616 usleep(500000L * tries);
617 if (ldapConn) {
618 ldap_unbind_ext_s(ldapConn, NULL, NULL);
619 ldapConn = NULL;
620 }
621 if (!ldap_reconnect()) {
622 break;
623 }
624 }
625 }
626 } while (result != LDAP_SUCCESS && tries < 3 && is_ldap_connect_error(result));
627
628 if (result != LDAP_SUCCESS) {
629 ast_log(LOG_WARNING, "Failed to query directory. Error: %s.\n", ldap_err2string(result));
630 ast_debug(2, "dn=%s\n", dn);
632 return NULL;
633 } else {
634 int num_entry = 0;
635 unsigned int *entries_count_ptr = NULL; /*!< not using this */
636
637 if ((num_entry = ldap_count_entries(ldapConn, ldap_result_msg)) > 0) {
638 ast_debug(3, "num_entry: %d\n", num_entry);
639
640 vars = realtime_ldap_result_to_vars(table_config, ldap_result_msg, entries_count_ptr);
641 if (num_entry > 1) {
642 ast_log(LOG_NOTICE, "More than one entry for dn=%s. Take only 1st one\n", dn);
643 }
644 } else {
645 ast_debug(2, "Could not find any entry dn=%s.\n", dn);
646 }
647 }
648 ldap_msgfree(ldap_result_msg);
649
650 /* Chopping \a vars down to one variable */
651 if (vars != NULL) {
652 struct ast_variable **p = vars;
653
654 /* Only take the first one. */
655 var = *vars;
656
657 /* Destroy the rest. */
658 while (*++p) {
660 }
661 ast_free(vars);
662 }
663
664 return var;
665 }
666}
667
668/*! \note caller should free returned pointer
669 */
670static char *substituted(struct ast_channel *channel, const char *string)
671{
672#define MAXRESULT 2048
673 char *ret_string = NULL;
674
675 if (!ast_strlen_zero(string)) {
676 ret_string = ast_calloc(1, MAXRESULT);
677 pbx_substitute_variables_helper(channel, string, ret_string, MAXRESULT - 1);
678 }
679 ast_debug(2, "substituted: string: '%s' => '%s' \n", string, ret_string);
680 return ret_string;
681}
682
683/*! \note caller should free returned pointer
684 */
685static char *cleaned_basedn(struct ast_channel *channel, const char *basedn)
686{
687 char *cbasedn = NULL;
688 if (basedn) {
689 char *p = NULL;
690 cbasedn = substituted(channel, basedn);
691 if (*cbasedn == '"') {
692 cbasedn++;
693 if (!ast_strlen_zero(cbasedn)) {
694 int len = strlen(cbasedn);
695 if (cbasedn[len - 1] == '"')
696 cbasedn[len - 1] = '\0';
697
698 }
699 }
700 p = cbasedn;
701 while (*p) {
702 if (*p == '|')
703 *p = ',';
704 p++;
705 }
706 }
707 ast_debug(2, "basedn: '%s' => '%s' \n", basedn, cbasedn);
708 return cbasedn;
709}
710
711/*! \brief Replace <search> by <by> in string.
712 * \note No check is done on string allocated size !
713 */
714static int replace_string_in_string(char *string, const char *search, const char *by)
715{
716 int search_len = strlen(search);
717 int by_len = strlen(by);
718 int replaced = 0;
719 char *p = strstr(string, search);
720
721 if (p) {
722 replaced = 1;
723 while (p) {
724 if (by_len == search_len) {
725 memcpy(p, by, by_len);
726 } else {
727 memmove(p + by_len, p + search_len, strlen(p + search_len) + 1);
728 memcpy(p, by, by_len);
729 }
730 p = strstr(p + by_len, search);
731 }
732 }
733 return replaced;
734}
735
736/*!
737 * \internal
738 * \brief Escape a value for safe inclusion in an LDAP filter per RFC 4515.
739 *
740 * Characters that have special meaning in LDAP filters are escaped
741 * to their \\HH hex representation: * ( ) \\ and NUL.
742 *
743 * \param value The raw value to escape
744 * \param escaped Output buffer (caller-allocated ast_str)
745 */
746static void ldap_filter_escape_value(const char *value, struct ast_str **escaped)
747{
748 ast_str_reset(*escaped);
749 for (; *value; value++) {
750 switch (*value) {
751 case '*':
752 ast_str_append(escaped, 0, "\\2a");
753 break;
754 case '(':
755 ast_str_append(escaped, 0, "\\28");
756 break;
757 case ')':
758 ast_str_append(escaped, 0, "\\29");
759 break;
760 case '\\':
761 ast_str_append(escaped, 0, "\\5c");
762 break;
763 default:
764 ast_str_append(escaped, 0, "%c", *value);
765 break;
766 }
767 }
768}
769
770/*! \brief Append a name=value filter string. The filter string can grow.
771 */
773 struct ldap_table_config *table_config,
774 const char *name, const char *value)
775{
776 char *new_name = NULL;
777 char *new_value = NULL;
778 const char *like_pos = strstr(name, " LIKE");
779 struct ast_str *escaped_value;
780
781 ast_debug(2, "name='%s' value='%s'\n", name, value);
782
783 escaped_value = ast_str_create(256);
784 if (!escaped_value) {
785 return;
786 }
787
788 if (like_pos) {
789 int len = like_pos - name;
790
791 name = new_name = ast_strdupa(name);
792 new_name[len] = '\0';
793 value = new_value = ast_strdupa(value);
794 replace_string_in_string(new_value, "\\_", "_");
795 replace_string_in_string(new_value, "%", "*");
797 /* Note: The LIKE path preserves original wildcard behavior.
798 * A more comprehensive escaping of the LIKE path is left
799 * to the maintainers familiar with the query semantics.
800 */
801 ast_str_append(filter, 0, "(%s=%s)", name, value);
802 } else {
804 ldap_filter_escape_value(value, &escaped_value);
805 ast_str_append(filter, 0, "(%s=%s)", name,
806 ast_str_buffer(escaped_value));
807 }
808
809 ast_free(escaped_value);
810}
811
812/*!
813 * \internal
814 * \brief Create an LDAP filter using search fields
815 *
816 * \param config the \c ldap_table_config for this search
817 * \param fields the \c ast_variable criteria to include
818 *
819 * \returns an \c ast_str pointer on success, NULL otherwise.
820 */
821static struct ast_str *create_lookup_filter(struct ldap_table_config *config, const struct ast_variable *fields)
822{
823 struct ast_str *filter;
824 const struct ast_variable *field;
825
827 if (!filter) {
828 return NULL;
829 }
830
831 /*
832 * Create the filter with the table additional filter and the
833 * parameter/value pairs we were given
834 */
835 ast_str_append(&filter, 0, "(&");
836 if (config && config->additional_filter) {
837 ast_str_append(&filter, 0, "%s", config->additional_filter);
838 }
843 }
844 /* Append the lookup fields */
845 for (field = fields; field; field = field->next) {
847 }
848 ast_str_append(&filter, 0, ")");
849
850 return filter;
851}
852
853/*! \brief LDAP base function
854 * \return a null terminated array of ast_variable (one per entry) or NULL if no entry is found or if an error occured
855 * caller should free the returned array and ast_variables
856 * \param entries_count_ptr is a pointer to found entries count (can be NULL)
857 * \param basedn is the base DN
858 * \param table_name is the table_name (used dor attribute convertion and additional filter)
859 * \param fields contains list of pairs name/value
860*/
861static struct ast_variable **realtime_ldap_base_ap(unsigned int *entries_count_ptr,
862 const char *basedn, const char *table_name, const struct ast_variable *fields)
863{
864 struct ast_variable **vars = NULL;
865 const struct ast_variable *field = fields;
866 struct ldap_table_config *table_config = NULL;
867 char *clean_basedn = cleaned_basedn(NULL, basedn);
868 struct ast_str *filter = NULL;
869 int tries = 0;
870 int result = 0;
871 LDAPMessage *ldap_result_msg = NULL;
872
873 if (!table_name) {
874 ast_log(LOG_ERROR, "No table_name specified.\n");
875 ast_free(clean_basedn);
876 return NULL;
877 }
878
879 if (!field) {
880 ast_log(LOG_ERROR, "Realtime retrieval requires at least 1 parameter"
881 " and 1 value to search on.\n");
882 ast_free(clean_basedn);
883 return NULL;
884 }
885
887
888 /* We now have our complete statement; Lets connect to the server and execute it. */
889 if (!ldap_reconnect()) {
891 ast_free(clean_basedn);
892 return NULL;
893 }
894
895 table_config = table_config_for_table_name(table_name);
896 if (!table_config) {
897 ast_log(LOG_WARNING, "No table named '%s'.\n", table_name);
899 ast_free(clean_basedn);
900 return NULL;
901 }
902
903 filter = create_lookup_filter(table_config, fields);
904 if (!filter) {
906 ast_free(clean_basedn);
907 return NULL;
908 }
909
910 do {
911 /* freeing ldap_result further down */
912 result = ldap_search_ext_s(ldapConn, clean_basedn,
913 LDAP_SCOPE_SUBTREE, ast_str_buffer(filter), NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
914 &ldap_result_msg);
915 if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
916 ast_debug(1, "Failed to query directory. Try %d/10\n", tries + 1);
917 if (++tries < 10) {
918 usleep(1);
919 if (ldapConn) {
920 ldap_unbind_ext_s(ldapConn, NULL, NULL);
921 ldapConn = NULL;
922 }
923 if (!ldap_reconnect()) {
924 break;
925 }
926 }
927 }
928 } while (result != LDAP_SUCCESS && tries < 10 && is_ldap_connect_error(result));
929
930 if (result != LDAP_SUCCESS) {
931 ast_log(LOG_WARNING, "Failed to query directory. Error: %s.\n", ldap_err2string(result));
932 ast_log(LOG_WARNING, "Query: %s\n", ast_str_buffer(filter));
933 } else {
934 /* this is where we create the variables from the search result
935 * freeing this \a vars outside this function */
936 if (ldap_count_entries(ldapConn, ldap_result_msg) > 0) {
937 /* is this a static var or some other? they are handled different for delimited values */
938 vars = realtime_ldap_result_to_vars(table_config, ldap_result_msg, entries_count_ptr);
939 } else {
940 ast_debug(1, "Could not find any entry matching %s in base dn %s.\n", ast_str_buffer(filter), clean_basedn);
941 }
942
943 ldap_msgfree(ldap_result_msg);
944
945 /*! \todo get the default variables from the accountBaseDN, not implemented with delimited values
946 */
947 if (vars) {
948 struct ast_variable **p = vars;
949 while (*p) {
950 struct ast_variable *append_var = NULL;
951 struct ast_variable *tmp = *p;
952 while (tmp) {
953 if (strcasecmp(tmp->name, "accountBaseDN") == 0) {
954 /* Get the variable to compare with for the defaults */
955 struct ast_variable *base_var = ldap_loadentry(table_config, tmp->value);
956
957 while (base_var) {
958 struct ast_variable *next = base_var->next;
959 struct ast_variable *test_var = *p;
960 int base_var_found = 0;
961
962 /* run throught the default values and fill it inn if it is missing */
963 while (test_var) {
964 if (strcasecmp(test_var->name, base_var->name) == 0) {
965 base_var_found = 1;
966 break;
967 } else {
968 test_var = test_var->next;
969 }
970 }
971 if (base_var_found) {
972 base_var->next = NULL;
973 ast_variables_destroy(base_var);
974 base_var = next;
975 } else {
976 /*!
977 * \todo XXX The interactions with base_var and append_var may
978 * cause a memory leak of base_var nodes. Also the append_var
979 * list and base_var list may get cross linked.
980 */
981 if (append_var) {
982 base_var->next = append_var;
983 } else {
984 base_var->next = NULL;
985 }
986 append_var = base_var;
987 base_var = next;
988 }
989 }
990 }
991 if (!tmp->next && append_var) {
992 tmp->next = append_var;
993 tmp = NULL;
994 } else {
995 tmp = tmp->next;
996 }
997 }
998 p++;
999 }
1000 }
1001 }
1002
1004 ast_free(clean_basedn);
1005
1007
1008 return vars;
1009}
1010
1012{
1013 struct ast_variable *fields = NULL;
1014 const char *newparam, *newval;
1015
1016 while ((newparam = va_arg(ap, const char *))) {
1017 struct ast_variable *field;
1018
1019 newval = va_arg(ap, const char *);
1020 if (!(field = ast_variable_new(newparam, newval, ""))) {
1021 ast_variables_destroy(fields);
1022 return NULL;
1023 }
1024
1025 field->next = fields;
1026 fields = field;
1027 }
1028
1029 return fields;
1030}
1031
1032/*! \brief same as realtime_ldap_base_ap but take variable arguments count list
1033 */
1034static struct ast_variable **realtime_ldap_base(unsigned int *entries_count_ptr,
1035 const char *basedn, const char *table_name, ...)
1036{
1037 RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
1038 struct ast_variable **vars = NULL;
1039 va_list ap;
1040
1041 va_start(ap, table_name);
1042 fields = realtime_arguments_to_fields(ap);
1043 va_end(ap);
1044
1045 vars = realtime_ldap_base_ap(entries_count_ptr, basedn, table_name, fields);
1046
1047 return vars;
1048}
1049
1050/*! \brief See Asterisk doc
1051 *
1052 * For Realtime Dynamic(i.e., switch, queues, and directory)
1053 */
1054static struct ast_variable *realtime_ldap(const char *basedn,
1055 const char *table_name, const struct ast_variable *fields)
1056{
1057 struct ast_variable **vars = realtime_ldap_base_ap(NULL, basedn, table_name, fields);
1058 struct ast_variable *var = NULL;
1059
1060 if (vars) {
1061 struct ast_variable *last_var = NULL;
1062 struct ast_variable **p = vars;
1063
1064 /* Chain the vars array of lists into one list to return. */
1065 while (*p) {
1066 if (last_var) {
1067 while (last_var->next) {
1068 last_var = last_var->next;
1069 }
1070 last_var->next = *p;
1071 } else {
1072 var = *p;
1073 last_var = var;
1074 }
1075 p++;
1076 }
1077 ast_free(vars);
1078 }
1079 return var;
1080}
1081
1082/*! \brief See Asterisk doc
1083 *
1084 * this function will be called for the switch statement if no match is found with the realtime_ldap function(i.e. it is a failover);
1085 * however, the ast_load_realtime wil match on wildcharacters also depending on what the mode is set to
1086 * this is an area of asterisk that could do with a lot of modification
1087 * I think this function returns Realtime dynamic objects
1088 */
1089static struct ast_config *realtime_multi_ldap(const char *basedn,
1090 const char *table_name, const struct ast_variable *fields)
1091{
1092 char *op;
1093 char *initfield = NULL;
1094 struct ast_variable **vars =
1095 realtime_ldap_base_ap(NULL, basedn, table_name, fields);
1096 struct ast_config *cfg = NULL;
1097
1098 if (!fields) {
1099 ast_log(LOG_WARNING, "realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
1100 return NULL;
1101 }
1102 initfield = ast_strdupa(fields->name);
1103 if ((op = strchr(initfield, ' '))) {
1104 *op = '\0';
1105 }
1106
1107 if (vars) {
1108 cfg = ast_config_new();
1109 if (!cfg) {
1110 ast_log(LOG_ERROR, "Unable to create a config!\n");
1111 } else {
1112 struct ast_variable **p = vars;
1113
1114 while (*p) {
1116 if (!cat) {
1117 break;
1118 } else {
1119 struct ast_variable *var = *p;
1120 while (var) {
1121 struct ast_variable *next = var->next;
1122 if (initfield && !strcmp(initfield, var->name)) {
1123 ast_category_rename(cat, var->value);
1124 }
1125 var->next = NULL;
1127 var = next;
1128 }
1129 }
1130 ast_category_append(cfg, cat);
1131 p++;
1132 }
1133 }
1134 ast_free(vars);
1135 }
1136 return cfg;
1137
1138}
1139
1140/*! \brief Sorting alogrithm for qsort to find the order of the variables \a a and \a b
1141 * \param a pointer to category_and_metric struct
1142 * \param b pointer to category_and_metric struct
1143 *
1144 * \retval -1 for if b is greater
1145 * \retval 0 zero for equal
1146 * \retval 1 if a is greater
1147 */
1148static int compare_categories(const void *a, const void *b)
1149{
1150 const struct category_and_metric *as = a;
1151 const struct category_and_metric *bs = b;
1152
1153 if (as->metric < bs->metric) {
1154 return -1;
1155 } else if (as->metric > bs->metric) {
1156 return 1;
1157 } else if (as->metric == bs->metric && strcmp(as->name, bs->name) != 0) {
1158 return strcmp(as->name, bs->name);
1159 }
1160 /* if the metric and the category name is the same, we check the variable metric */
1161 if (as->var_metric < bs->var_metric) {
1162 return -1;
1163 } else if (as->var_metric > bs->var_metric) {
1164 return 1;
1165 }
1166
1167 return 0;
1168}
1169
1170/*! \brief See Asterisk Realtime Documentation
1171 *
1172 * This is for Static Realtime
1173 *
1174 * load the configuration stuff for the .conf files
1175 * called on a reload
1176 */
1177static struct ast_config *config_ldap(const char *basedn, const char *table_name,
1178 const char *file, struct ast_config *cfg, struct ast_flags config_flags, const char *sugg_incl, const char *who_asked)
1179{
1180 unsigned int vars_count = 0;
1181 struct ast_variable **vars;
1182 int i = 0;
1183 struct ast_variable *new_v = NULL;
1184 struct ast_category *cur_cat = NULL;
1185 const char *last_category = NULL;
1186 int last_category_metric = 0;
1188 struct ast_variable **p;
1189
1190 if (ast_strlen_zero(file) || !strcasecmp(file, RES_CONFIG_LDAP_CONF)) {
1191 ast_log(LOG_ERROR, "Missing configuration file: %s. Can't configure myself.\n", RES_CONFIG_LDAP_CONF);
1192 return NULL;
1193 }
1194
1195 vars = realtime_ldap_base(&vars_count, basedn, table_name, "filename", file, "commented", "FALSE", NULL);
1196
1197 if (!vars) {
1198 ast_log(LOG_WARNING, "Could not find config '%s' in directory.\n", file);
1199 return NULL;
1200 }
1201
1202 /*! \note Since the items come back in random order, they need to be sorted
1203 * first, and since the data could easily exceed stack size, this is
1204 * allocated from the heap.
1205 */
1206 if (!(categories = ast_calloc(vars_count, sizeof(*categories)))) {
1207 return NULL;
1208 }
1209
1210 for (vars_count = 0, p = vars; *p; p++) {
1211 struct ast_variable *category = variable_named(*p, "category");
1212 struct ast_variable *cat_metric = variable_named(*p, "cat_metric");
1213 struct ast_variable *var_name = variable_named(*p, "variable_name");
1214 struct ast_variable *var_val = variable_named(*p, "variable_value");
1215 struct ast_variable *var_metric = variable_named(*p, "var_metric");
1216 struct ast_variable *dn = variable_named(*p, "dn");
1217
1218 if (!category) {
1219 ast_log(LOG_ERROR, "No category name in entry '%s' for file '%s'.\n",
1220 (dn ? dn->value : "?"), file);
1221 } else if (!cat_metric) {
1222 ast_log(LOG_ERROR, "No category metric in entry '%s'(category: %s) for file '%s'.\n",
1223 (dn ? dn->value : "?"), category->value, file);
1224 } else if (!var_metric) {
1225 ast_log(LOG_ERROR, "No variable metric in entry '%s'(category: %s) for file '%s'.\n",
1226 (dn ? dn->value : "?"), category->value, file);
1227 } else if (!var_name) {
1228 ast_log(LOG_ERROR, "No variable name in entry '%s' (category: %s metric: %s) for file '%s'.\n",
1229 (dn ? dn->value : "?"), category->value,
1230 cat_metric->value, file);
1231 } else if (!var_val) {
1232 ast_log(LOG_ERROR, "No variable value in entry '%s' (category: %s metric: %s variable: %s) for file '%s'.\n",
1233 (dn ? dn->value : "?"), category->value,
1234 cat_metric->value, var_name->value, file);
1235 } else {
1236 categories[vars_count].name = category->value;
1237 categories[vars_count].metric = atoi(cat_metric->value);
1238 categories[vars_count].variable_name = var_name->value;
1239 categories[vars_count].variable_value = var_val->value;
1240 categories[vars_count].var_metric = atoi(var_metric->value);
1241 vars_count++;
1242 }
1243
1244 ast_debug(3, "category: %s\n", category->value);
1245 ast_debug(3, "var_name: %s\n", var_name->value);
1246 ast_debug(3, "var_val: %s\n", var_val->value);
1247 ast_debug(3, "cat_metric: %s\n", cat_metric->value);
1248
1249 }
1250
1251 qsort(categories, vars_count, sizeof(*categories), compare_categories);
1252
1253 for (i = 0; i < vars_count; i++) {
1254 if (!strcmp(categories[i].variable_name, "#include")) {
1255 struct ast_flags flags = { 0 };
1256 if (!ast_config_internal_load(categories[i].variable_value, cfg, flags, "", who_asked)) {
1257 break;
1258 }
1259 continue;
1260 }
1261
1262 if (!last_category || strcmp(last_category, categories[i].name) ||
1263 last_category_metric != categories[i].metric) {
1264
1266 if (!cur_cat) {
1267 break;
1268 }
1269 last_category = categories[i].name;
1270 last_category_metric = categories[i].metric;
1271 ast_category_append(cfg, cur_cat);
1272 }
1273
1274 if (!(new_v = ast_variable_new(categories[i].variable_name, categories[i].variable_value, table_name))) {
1275 break;
1276 }
1277
1278 ast_variable_append(cur_cat, new_v);
1279 }
1280
1281 ast_free(vars);
1283
1284 return cfg;
1285}
1286
1287/*!
1288 * \internal
1289 * \brief Create an LDAP modification structure (LDAPMod)
1290 *
1291 * \param attribute the name of the LDAP attribute to modify
1292 * \param new_value the new value of the LDAP attribute
1293 *
1294 * \returns an LDAPMod * if successful, NULL otherwise.
1295 */
1296static LDAPMod *ldap_mod_create(const char *attribute, const char *new_value)
1297{
1298 LDAPMod *mod;
1299 char *type;
1300
1301 mod = ldap_memcalloc(1, sizeof(LDAPMod));
1302 type = ldap_strdup(attribute);
1303
1304 if (!(mod && type)) {
1305 ast_log(LOG_ERROR, "Memory allocation failure creating LDAP modification\n");
1306 ldap_memfree(type);
1307 ldap_memfree(mod);
1308 return NULL;
1309 }
1310
1311 mod->mod_type = type;
1312
1313 if (strlen(new_value)) {
1314 char **values, *value;
1315 values = ldap_memcalloc(2, sizeof(char *));
1316 value = ldap_strdup(new_value);
1317
1318 if (!(values && value)) {
1319 ast_log(LOG_ERROR, "Memory allocation failure creating LDAP modification\n");
1320 ldap_memfree(value);
1321 ldap_memfree(values);
1322 ldap_memfree(type);
1323 ldap_memfree(mod);
1324 return NULL;
1325 }
1326
1327 mod->mod_op = LDAP_MOD_REPLACE;
1328 mod->mod_values = values;
1329 mod->mod_values[0] = value;
1330 } else {
1331 mod->mod_op = LDAP_MOD_DELETE;
1332 }
1333
1334 return mod;
1335}
1336
1337/*!
1338 * \internal
1339 * \brief Append a value to an existing LDAP modification structure
1340 *
1341 * \param src the LDAPMod to update
1342 * \param new_value the new value to append to the LDAPMod
1343 *
1344 * \returns the \c src original passed in if successful, NULL otherwise.
1345 */
1346static LDAPMod *ldap_mod_append(LDAPMod *src, const char *new_value)
1347{
1348 char *new_buffer;
1349
1350 if (src->mod_op != LDAP_MOD_REPLACE) {
1351 return src;
1352 }
1353
1354 new_buffer = ldap_memrealloc(
1355 src->mod_values[0],
1356 strlen(src->mod_values[0]) + strlen(new_value) + sizeof(";"));
1357
1358 if (!new_buffer) {
1359 ast_log(LOG_ERROR, "Memory allocation failure creating LDAP modification\n");
1360 return NULL;
1361 }
1362
1363 strcat(new_buffer, ";");
1364 strcat(new_buffer, new_value);
1365
1366 src->mod_values[0] = new_buffer;
1367
1368 return src;
1369}
1370
1371/*!
1372 * \internal
1373 * \brief Duplicates an LDAP modification structure
1374 *
1375 * \param src the LDAPMod to duplicate
1376 *
1377 * \returns a deep copy of \c src if successful, NULL otherwise.
1378 */
1379static LDAPMod *ldap_mod_duplicate(const LDAPMod *src)
1380{
1381 LDAPMod *mod;
1382 char *type, **values = NULL;
1383
1384 mod = ldap_memcalloc(1, sizeof(LDAPMod));
1385 type = ldap_strdup(src->mod_type);
1386
1387 if (!(mod && type)) {
1388 ast_log(LOG_ERROR, "Memory allocation failure creating LDAP modification\n");
1389 ldap_memfree(type);
1390 ldap_memfree(mod);
1391 return NULL;
1392 }
1393
1394 if (src->mod_op == LDAP_MOD_REPLACE) {
1395 char *value;
1396
1397 values = ldap_memcalloc(2, sizeof(char *));
1398 value = ldap_strdup(src->mod_values[0]);
1399
1400 if (!(values && value)) {
1401 ast_log(LOG_ERROR, "Memory allocation failure creating LDAP modification\n");
1402 ldap_memfree(value);
1403 ldap_memfree(values);
1404 ldap_memfree(type);
1405 ldap_memfree(mod);
1406 return NULL;
1407 }
1408
1409 values[0] = value;
1410 }
1411
1412 mod->mod_op = src->mod_op;
1413 mod->mod_type = type;
1414 mod->mod_values = values;
1415 return mod;
1416}
1417
1418/*!
1419 * \internal
1420 * \brief Search for an existing LDAP modification structure
1421 *
1422 * \param modifications a NULL terminated array of LDAP modification structures
1423 * \param lookup the attribute name to search for
1424 *
1425 * \returns an LDAPMod * if successful, NULL otherwise.
1426 */
1427static LDAPMod *ldap_mod_find(LDAPMod **modifications, const char *lookup)
1428{
1429 size_t i;
1430 for (i = 0; modifications[i]; i++) {
1431 if (modifications[i]->mod_op == LDAP_MOD_REPLACE &&
1432 !strcasecmp(modifications[i]->mod_type, lookup)) {
1433 return modifications[i];
1434 }
1435 }
1436 return NULL;
1437}
1438
1439/*!
1440 * \internal
1441 * \brief Determine if an LDAP entry has the specified attribute
1442 *
1443 * \param entry the LDAP entry to examine
1444 * \param lookup the attribute name to search for
1445 *
1446 * \returns 1 if the attribute was found, 0 otherwise.
1447 */
1448static int ldap_entry_has_attribute(LDAPMessage *entry, const char *lookup)
1449{
1450 BerElement *ber = NULL;
1451 char *attribute;
1452
1453 attribute = ldap_first_attribute(ldapConn, entry, &ber);
1454 while (attribute) {
1455 if (!strcasecmp(attribute, lookup)) {
1456 ldap_memfree(attribute);
1457 ber_free(ber, 0);
1458 return 1;
1459 }
1460 ldap_memfree(attribute);
1461 attribute = ldap_next_attribute(ldapConn, entry, ber);
1462 }
1463 ber_free(ber, 0);
1464 return 0;
1465}
1466
1467/*!
1468 * \internal
1469 * \brief Remove LDAP_MOD_DELETE modifications that will not succeed
1470 *
1471 * \details
1472 * A LDAP_MOD_DELETE operation will fail if the LDAP entry does not already have
1473 * the corresponding attribute. Because we may be updating multiple LDAP entries
1474 * in a single call to update_ldap(), we may need our own copy of the
1475 * modifications array for each one.
1476 *
1477 * \note
1478 * This function dynamically allocates memory. If it returns a non-NULL pointer,
1479 * it is up to the caller to free it with ldap_mods_free()
1480 *
1481 * \returns an LDAPMod * if modifications needed to be removed, NULL otherwise.
1482 */
1483static LDAPMod **massage_mods_for_entry(LDAPMessage *entry, LDAPMod **mods)
1484{
1485 size_t k, i, remove_count;
1486 LDAPMod **copies;
1487
1488 for (i = remove_count = 0; mods[i]; i++) {
1489 if (mods[i]->mod_op == LDAP_MOD_DELETE
1490 && !ldap_entry_has_attribute(entry, mods[i]->mod_type)) {
1491 remove_count++;
1492 }
1493 }
1494
1495 if (!remove_count) {
1496 return NULL;
1497 }
1498
1499 copies = ldap_memcalloc(i - remove_count + 1, sizeof(LDAPMod *));
1500 if (!copies) {
1501 ast_log(LOG_ERROR, "Memory allocation failure massaging LDAP modification\n");
1502 return NULL;
1503 }
1504
1505 for (i = k = 0; mods[i]; i++) {
1506 if (mods[i]->mod_op != LDAP_MOD_DELETE
1507 || ldap_entry_has_attribute(entry, mods[i]->mod_type)) {
1508 copies[k] = ldap_mod_duplicate(mods[i]);
1509 if (!copies[k]) {
1510 ast_log(LOG_ERROR, "Memory allocation failure massaging LDAP modification\n");
1511 ldap_mods_free(copies, 1);
1512 return NULL;
1513 }
1514 k++;
1515 } else {
1516 ast_debug(3, "Skipping %s deletion because it doesn't exist\n",
1517 mods[i]->mod_type);
1518 }
1519 }
1520
1521 return copies;
1522}
1523
1524/*!
1525 * \internal
1526 * \brief Count the number of variables in an ast_variables list
1527 *
1528 * \param vars the list of variables to count
1529 *
1530 * \returns the number of variables in the specified list
1531 */
1532static size_t variables_count(const struct ast_variable *vars)
1533{
1534 const struct ast_variable *var;
1535 size_t count = 0;
1536 for (var = vars; var; var = var->next) {
1537 count++;
1538 }
1539 return count;
1540}
1541
1542static int update2_ldap(const char *basedn, const char *table_name, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
1543{
1544 const struct ast_variable *field;
1545 struct ldap_table_config *table_config = NULL;
1546 char *clean_basedn = NULL;
1547 struct ast_str *filter = NULL;
1548 int search_result = 0;
1549 int res = -1;
1550 int tries = 0;
1551 size_t update_count, update_index, entry_count;
1552
1553 LDAPMessage *ldap_entry = NULL;
1554 LDAPMod **modifications;
1555 LDAPMessage *ldap_result_msg = NULL;
1556
1557 if (!table_name) {
1558 ast_log(LOG_ERROR, "No table_name specified.\n");
1559 return res;
1560 }
1561
1562 update_count = variables_count(update_fields);
1563 if (!update_count) {
1564 ast_log(LOG_WARNING, "Need at least one parameter to modify.\n");
1565 return res;
1566 }
1567
1569
1570 /* We now have our complete statement; Lets connect to the server and execute it. */
1571 if (!ldap_reconnect()) {
1573 return res;
1574 }
1575
1576 table_config = table_config_for_table_name(table_name);
1577 if (!table_config) {
1578 ast_log(LOG_ERROR, "No table named '%s'.\n", table_name);
1580 return res;
1581 }
1582
1583 clean_basedn = cleaned_basedn(NULL, basedn);
1584
1585 filter = create_lookup_filter(table_config, lookup_fields);
1586 if (!filter) {
1588 ast_free(clean_basedn);
1589 return res;
1590 }
1591
1592 /*
1593 * Find LDAP records that match our lookup filter. If there are none, then
1594 * we don't go through the hassle of building our modifications list.
1595 */
1596
1597 do {
1598 search_result = ldap_search_ext_s(
1599 ldapConn,
1600 clean_basedn,
1601 LDAP_SCOPE_SUBTREE,
1603 NULL, 0, NULL, NULL, NULL,
1604 LDAP_NO_LIMIT,
1605 &ldap_result_msg);
1606 if (search_result != LDAP_SUCCESS && is_ldap_connect_error(search_result)) {
1607 ast_log(LOG_WARNING, "Failed to query directory. Try %d/3\n", tries + 1);
1608 tries++;
1609 if (tries < 3) {
1610 usleep(500000L * tries);
1611 if (ldapConn) {
1612 ldap_unbind_ext_s(ldapConn, NULL, NULL);
1613 ldapConn = NULL;
1614 }
1615 if (!ldap_reconnect()) {
1616 break;
1617 }
1618 }
1619 }
1620 } while (search_result != LDAP_SUCCESS && tries < 3 && is_ldap_connect_error(search_result));
1621
1622 if (search_result != LDAP_SUCCESS) {
1623 ast_log(LOG_WARNING, "Failed to query directory. Error: %s.\n", ldap_err2string(search_result));
1624 ast_log(LOG_WARNING, "Query: %s\n", ast_str_buffer(filter));
1625 goto early_bailout;
1626 }
1627
1628 entry_count = ldap_count_entries(ldapConn, ldap_result_msg);
1629 if (!entry_count) {
1630 /* Nothing found, nothing to update */
1631 res = 0;
1632 goto early_bailout;
1633 }
1634
1635 /* We need to NULL terminate, so we allocate one more than we need */
1636 modifications = ldap_memcalloc(update_count + 1, sizeof(LDAPMod *));
1637 if (!modifications) {
1638 ast_log(LOG_ERROR, "Memory allocation failure\n");
1639 goto early_bailout;
1640 }
1641
1642 /*
1643 * Create the modification array with the parameter/value pairs we were given,
1644 * if there are several parameters with the same name, we collect them into
1645 * one parameter/value pair and delimit them with a semicolon
1646 */
1647 for (field = update_fields, update_index = 0; field; field = field->next) {
1648 LDAPMod *mod;
1649
1650 const char *ldap_attribute_name = convert_attribute_name_to_ldap(
1651 table_config,
1652 field->name);
1653
1654 /* See if we already have it */
1655 mod = ldap_mod_find(modifications, ldap_attribute_name);
1656 if (mod) {
1657 mod = ldap_mod_append(mod, field->value);
1658 if (!mod) {
1659 goto late_bailout;
1660 }
1661 } else {
1662 mod = ldap_mod_create(ldap_attribute_name, field->value);
1663 if (!mod) {
1664 goto late_bailout;
1665 }
1666 modifications[update_index++] = mod;
1667 }
1668 }
1669
1670 /* Ready to update */
1671 ast_debug(3, "Modifying %zu matched entries\n", entry_count);
1672 if (DEBUG_ATLEAST(3)) {
1673 size_t i;
1674 for (i = 0; modifications[i]; i++) {
1675 if (modifications[i]->mod_op != LDAP_MOD_DELETE) {
1676 ast_log(LOG_DEBUG, "%s => %s\n", modifications[i]->mod_type,
1677 modifications[i]->mod_values[0]);
1678 } else {
1679 ast_log(LOG_DEBUG, "deleting %s\n", modifications[i]->mod_type);
1680 }
1681 }
1682 }
1683
1684 for (ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
1685 ldap_entry;
1686 ldap_entry = ldap_next_entry(ldapConn, ldap_entry)) {
1687 int error;
1688 LDAPMod **massaged, **working;
1689
1690 char *dn = ldap_get_dn(ldapConn, ldap_entry);
1691 if (!dn) {
1692 ast_log(LOG_ERROR, "Memory allocation failure\n");
1693 goto late_bailout;
1694 }
1695
1696 working = modifications;
1697
1698 massaged = massage_mods_for_entry(ldap_entry, modifications);
1699 if (massaged) {
1700 /* Did we massage everything out of the list? */
1701 if (!massaged[0]) {
1702 ast_debug(3, "Nothing left to modify - skipping\n");
1703 ldap_mods_free(massaged, 1);
1704 ldap_memfree(dn);
1705 continue;
1706 }
1707 working = massaged;
1708 }
1709
1710 if ((error = ldap_modify_ext_s(ldapConn, dn, working, NULL, NULL)) != LDAP_SUCCESS) {
1711 ast_log(LOG_ERROR, "Couldn't modify dn:%s because %s", dn, ldap_err2string(error));
1712 }
1713
1714 if (massaged) {
1715 ldap_mods_free(massaged, 1);
1716 }
1717
1718 ldap_memfree(dn);
1719 }
1720
1721 res = entry_count;
1722
1723late_bailout:
1724 ldap_mods_free(modifications, 1);
1725
1726early_bailout:
1727 ldap_msgfree(ldap_result_msg);
1729 ast_free(clean_basedn);
1731
1732 return res;
1733}
1734
1735static int update_ldap(const char *basedn, const char *table_name, const char *attribute, const char *lookup, const struct ast_variable *fields)
1736{
1737 int res;
1738 struct ast_variable *lookup_fields = ast_variable_new(attribute, lookup, "");
1739 res = update2_ldap(basedn, table_name, lookup_fields, fields);
1740 ast_variables_destroy(lookup_fields);
1741 return res;
1742}
1743
1745 .name = "ldap",
1746 .load_func = config_ldap,
1747 .realtime_func = realtime_ldap,
1748 .realtime_multi_func = realtime_multi_ldap,
1749 .update_func = update_ldap,
1750 .update2_func = update2_ldap,
1751};
1752
1753/*!
1754 * \brief Load the module
1755 *
1756 * Module loading including tests for configuration or dependencies.
1757 * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
1758 * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
1759 * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
1760 * configuration file or other non-critical problem return
1761 * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
1762 *
1763 * \todo Don't error or warn on a default install. If the config is
1764 * default we should not attempt to connect to a server. -lathama
1765 */
1766static int load_module(void)
1767{
1768 if (parse_config() < 0) {
1769 ast_log(LOG_ERROR, "Cannot load LDAP RealTime driver.\n");
1770 return 0;
1771 }
1772
1774
1775 if (!ldap_reconnect()) {
1776 ast_log(LOG_WARNING, "Couldn't establish connection to LDAP directory. Check debug.\n");
1777 }
1778
1780 ast_verb(1, "LDAP RealTime driver loaded.\n");
1782
1784
1785 return 0;
1786}
1787
1788/*! \brief Unload Module
1789 *
1790 */
1791static int unload_module(void)
1792{
1793 /* Aquire control before doing anything to the module itself. */
1795
1797
1798 if (ldapConn) {
1799 ldap_unbind_ext_s(ldapConn, NULL, NULL);
1800 ldapConn = NULL;
1801 }
1804 ast_verb(1, "LDAP RealTime driver unloaded.\n");
1805
1806 /* Unlock so something else can destroy the lock. */
1808
1809 return 0;
1810}
1811
1812/*! \brief Reload Module
1813 */
1814static int reload(void)
1815{
1816 /* Aquire control before doing anything to the module itself. */
1818
1819 if (ldapConn) {
1820 ldap_unbind_ext_s(ldapConn, NULL, NULL);
1821 ldapConn = NULL;
1822 }
1823
1824 if (parse_config() < 0) {
1825 ast_log(LOG_NOTICE, "Cannot reload LDAP RealTime driver.\n");
1827 return 0;
1828 }
1829
1830 if (!ldap_reconnect()) {
1831 ast_log(LOG_WARNING, "Couldn't establish connection to your directory server. Check debug.\n");
1832 }
1833
1834 ast_verb(2, "LDAP RealTime driver reloaded.\n");
1835
1836 /* Done reloading. Release lock so others can now use driver. */
1838
1839 return 0;
1840}
1841
1842static int config_can_be_inherited(const char *key)
1843{
1844 int i;
1845 static const char * const config[] = {
1846 "basedn", "host", "pass", "port", "protocol", "url", "user", "version", NULL
1847 };
1848
1849 for (i = 0; config[i]; i++) {
1850 if (!strcasecmp(key, config[i])) {
1851 return 0;
1852 }
1853 }
1854 return 1;
1855}
1856
1857/*! \brief parse the configuration file
1858 */
1859static int parse_config(void)
1860{
1861 struct ast_config *config;
1862 struct ast_flags config_flags = {0};
1863 const char *s, *host;
1864 int port;
1865 char *category_name = NULL;
1866
1867 /* Make sure that global variables are reset */
1868 url[0] = '\0';
1869 user[0] = '\0';
1870 pass[0] = '\0';
1871 base_distinguished_name[0] = '\0';
1872 version = 3;
1873
1876 ast_log(LOG_ERROR, "Cannot load configuration file: %s\n", RES_CONFIG_LDAP_CONF);
1877 return -1;
1878 }
1879
1880 if (!(s = ast_variable_retrieve(config, "_general", "user"))) {
1881 ast_log(LOG_NOTICE, "No directory user found, anonymous binding as default.\n");
1882 user[0] = '\0';
1883 } else {
1884 ast_copy_string(user, s, sizeof(user));
1885 }
1886
1887 if (!ast_strlen_zero(user)) {
1888 if (!(s = ast_variable_retrieve(config, "_general", "pass"))) {
1889 ast_log(LOG_WARNING, "No directory password found, using 'asterisk' as default.\n");
1890 ast_copy_string(pass, "asterisk", sizeof(pass));
1891 } else {
1892 ast_copy_string(pass, s, sizeof(pass));
1893 }
1894 }
1895
1896 /* URL is preferred, use host and port if not found */
1897 if ((s = ast_variable_retrieve(config, "_general", "url"))) {
1898 ast_copy_string(url, s, sizeof(url));
1899 } else if ((host = ast_variable_retrieve(config, "_general", "host"))) {
1900 if (!(s = ast_variable_retrieve(config, "_general", "port")) || sscanf(s, "%5d", &port) != 1 || port > 65535) {
1901 ast_log(LOG_NOTICE, "No directory port found, using 389 as default.\n");
1902 port = 389;
1903 }
1904
1905 snprintf(url, sizeof(url), "ldap://%s:%d", host, port);
1906 } else {
1907 ast_log(LOG_ERROR, "No directory URL or host found.\n");
1909 return -1;
1910 }
1911
1912 if (!(s = ast_variable_retrieve(config, "_general", "basedn"))) {
1913 ast_log(LOG_ERROR, "No LDAP base dn found, using '%s' as default.\n", RES_CONFIG_LDAP_DEFAULT_BASEDN);
1915 } else
1917
1918 if (!(s = ast_variable_retrieve(config, "_general", "version")) && !(s = ast_variable_retrieve(config, "_general", "protocol"))) {
1919 ast_log(LOG_NOTICE, "No explicit LDAP version found, using 3 as default.\n");
1920 } else if (sscanf(s, "%30d", &version) != 1 || version < 1 || version > 6) {
1921 ast_log(LOG_WARNING, "Invalid LDAP version '%s', using 3 as default.\n", s);
1922 version = 3;
1923 }
1924
1926
1927 while ((category_name = ast_category_browse(config, category_name))) {
1928 int is_general = (strcasecmp(category_name, "_general") == 0);
1929 int is_config = (strcasecmp(category_name, "config") == 0); /*!< using the [config] context for Static RealTime */
1930 struct ast_variable *var = ast_variable_browse(config, category_name);
1931
1932 if (var) {
1933 struct ldap_table_config *table_config =
1934 table_config_for_table_name(category_name);
1935 if (!table_config) {
1936 table_config = table_config_new(category_name);
1937 AST_LIST_INSERT_HEAD(&table_configs, table_config, entry);
1938 if (is_general)
1939 base_table_config = table_config;
1940 if (is_config)
1941 static_table_config = table_config;
1942 }
1943 for (; var; var = var->next) {
1944 if (!strcasecmp(var->name, "additionalFilter")) {
1945 table_config->additional_filter = ast_strdup(var->value);
1946 } else {
1947 if (!is_general || config_can_be_inherited(var->name)) {
1948 ldap_table_config_add_attribute(table_config, var->name, var->value);
1949 }
1950 }
1951 }
1952 }
1953 }
1954
1956
1957 return 1;
1958}
1959
1960/*! \note ldap_lock should have been locked before calling this function. */
1961static int ldap_reconnect(void)
1962{
1963 int bind_result = 0;
1964 struct berval cred;
1965
1966 if (ldapConn) {
1967 ast_debug(2, "Everything seems fine.\n");
1968 return 1;
1969 }
1970
1971 if (ast_strlen_zero(url)) {
1972 ast_log(LOG_ERROR, "Not enough parameters to connect to ldap directory\n");
1973 return 0;
1974 }
1975
1976 if (LDAP_SUCCESS != ldap_initialize(&ldapConn, url)) {
1977 ast_log(LOG_ERROR, "Failed to init ldap connection to '%s'. Check debug for more info.\n", url);
1978 return 0;
1979 }
1980
1981 if (LDAP_OPT_SUCCESS != ldap_set_option(ldapConn, LDAP_OPT_PROTOCOL_VERSION, &version)) {
1982 ast_log(LOG_WARNING, "Unable to set LDAP protocol version to %d, falling back to default.\n", version);
1983 }
1984
1985 if (!ast_strlen_zero(user)) {
1986 ast_debug(2, "bind to '%s' as user '%s'\n", url, user);
1987 cred.bv_val = (char *) pass;
1988 cred.bv_len = strlen(pass);
1989 bind_result = ldap_sasl_bind_s(ldapConn, user, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
1990 } else {
1991 ast_debug(2, "bind %s anonymously\n", url);
1992 cred.bv_val = NULL;
1993 cred.bv_len = 0;
1994 bind_result = ldap_sasl_bind_s(ldapConn, NULL, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
1995 }
1996 if (bind_result == LDAP_SUCCESS) {
1997 ast_debug(2, "Successfully connected to directory.\n");
1998 connect_time = time(NULL);
1999 return 1;
2000 } else {
2001 ast_log(LOG_WARNING, "bind failed: %s\n", ldap_err2string(bind_result));
2002 ldap_unbind_ext_s(ldapConn, NULL, NULL);
2003 ldapConn = NULL;
2004 return 0;
2005 }
2006}
2007
2008/*! \brief Realtime Status
2009 *
2010 */
2011static char *realtime_ldap_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2012{
2013 struct ast_str *buf;
2014 int ctimesec = time(NULL) - connect_time;
2015
2016 switch (cmd) {
2017 case CLI_INIT:
2018 e->command = "realtime show ldap status";
2019 e->usage =
2020 "Usage: realtime show ldap status\n"
2021 " Shows connection information for the LDAP RealTime driver\n";
2022 return NULL;
2023 case CLI_GENERATE:
2024 return NULL;
2025 }
2026
2027 if (!ldapConn)
2028 return CLI_FAILURE;
2029
2030 buf = ast_str_create(512);
2031 if (!ast_strlen_zero(url)) {
2032 ast_str_append(&buf, 0, "Connected to '%s', baseDN %s", url, base_distinguished_name);
2033 }
2034
2035 if (!ast_strlen_zero(user)) {
2036 ast_str_append(&buf, 0, " with username %s", user);
2037 }
2038
2039 ast_str_append(&buf, 0, " for ");
2041 ast_free(buf);
2042
2043 return CLI_SUCCESS;
2044}
2045
2046/*! \brief Module Information
2047 *
2048 */
2049AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "LDAP realtime interface",
2050 .support_level = AST_MODULE_SUPPORT_EXTENDED,
2051 .load = load_module,
2052 .unload = unload_module,
2053 .reload = reload,
2054 .load_pri = AST_MODPRI_REALTIME_DRIVER,
2055 .requires = "extconfig",
void ast_cli_unregister_multiple(void)
Definition ael_main.c:408
#define var
Definition ast_expr2f.c:605
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
#define ast_calloc(num, len)
A wrapper for calloc()
Definition astmm.h:202
#define ast_log
Definition astobj2.c:42
static PGresult * result
Definition cel_pgsql.c:84
static const char type[]
static const char config[]
General Asterisk PBX channel definitions.
Standard Command Line Interface.
void ast_cli_print_timestr_fromseconds(int fd, int seconds, const char *prefix)
Print on cli a duration in seconds in format s year(s), s week(s), s day(s), s hour(s),...
Definition main/cli.c:3140
#define CLI_SUCCESS
Definition cli.h:44
#define AST_CLI_DEFINE(fn, txt,...)
Definition cli.h:197
@ CLI_INIT
Definition cli.h:152
@ CLI_GENERATE
Definition cli.h:153
#define CLI_FAILURE
Definition cli.h:46
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition cli.h:265
char * bs
Definition eagi_proxy.c:73
char buf[BUFSIZE]
Definition eagi_proxy.c:66
static const char name[]
Definition format_mp3.c:68
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
static int filter(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
Configuration File Parser.
#define ast_config_load(filename, flags)
Load a config file.
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition extconf.c:3324
void ast_category_rename(struct ast_category *cat, const char *name)
#define CONFIG_STATUS_FILEMISSING
struct ast_config * ast_config_new(void)
Create a new base configuration structure.
Definition extconf.c:3272
void ast_category_append(struct ast_config *config, struct ast_category *category)
Appends a category to a config.
Definition extconf.c:2831
void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
Definition extconf.c:1175
#define ast_category_new_anonymous()
Create a nameless category that is not backed by a file.
#define ast_variable_new(name, value, filename)
int ast_config_engine_deregister(struct ast_config_engine *del)
Deregister config engine.
#define CONFIG_STATUS_FILEINVALID
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition extconf.c:1287
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
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)
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition extconf.c:1260
#define ast_category_new_dynamic(name)
Create a category that is not backed by a file.
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition extconf.c:1213
int ast_config_engine_register(struct ast_config_engine *newconfig)
Register config engine.
Support for logging to various files, console and syslog Configuration in file logger....
#define DEBUG_ATLEAST(level)
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_DEBUG
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_NOTICE
#define LOG_WARNING
A set of macros to manage forward-linked lists.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_HEAD_NOLOCK_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Asterisk locking-related definitions:
#define ast_mutex_unlock(a)
Definition lock.h:197
#define ast_mutex_lock(a)
Definition lock.h:196
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition lock.h:527
#define realtime_arguments_to_fields(ap, result)
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition module.h:331
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition module.h:557
@ AST_MODPRI_REALTIME_DRIVER
Definition module.h:337
@ AST_MODULE_SUPPORT_EXTENDED
Definition module.h:122
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition module.h:46
Options provided by main asterisk program.
Core PBX routines and definitions.
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition ael_main.c:211
static int config_can_be_inherited(const char *key)
static LDAPMod * ldap_mod_find(LDAPMod **modifications, const char *lookup)
static struct ast_variable * realtime_ldap_entry_to_var(struct ldap_table_config *table_config, LDAPMessage *ldap_entry)
Get variables from ldap entry attributes.
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.
static LDAPMod ** massage_mods_for_entry(LDAPMessage *entry, LDAPMod **mods)
static struct ast_config * realtime_multi_ldap(const char *basedn, const char *table_name, const struct ast_variable *fields)
See Asterisk doc.
#define MAXRESULT
static int replace_string_in_string(char *string, const char *search, const char *by)
Replace <search> by <by> in string.
static struct ldap_table_config * base_table_config
static struct ldap_table_config * static_table_config
static struct ast_variable ** realtime_ldap_base_ap(unsigned int *entries_count_ptr, const char *basedn, const char *table_name, const struct ast_variable *fields)
LDAP base function.
static char pass[512]
static ast_mutex_t ldap_lock
static struct ast_cli_entry ldap_cli[]
static void ldap_filter_escape_value(const char *value, struct ast_str **escaped)
static int compare_categories(const void *a, const void *b)
Sorting alogrithm for qsort to find the order of the variables a and b.
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 size_t variables_count(const struct ast_variable *vars)
static struct ast_config_engine ldap_engine
static int semicolon_count_var(struct ast_variable *var)
Count semicolons in variables.
static char url[512]
static int ldap_reconnect(void)
static LDAP * ldapConn
static int is_ldap_connect_error(int err)
Check if we have a connection error.
static void table_configs_free(void)
Free table_config.
static struct ldap_table_config * table_config_new(const char *table_name)
Create a new table_config.
static int ldap_entry_has_attribute(LDAPMessage *entry, const char *lookup)
static LDAPMod * ldap_mod_duplicate(const LDAPMod *src)
static struct ast_variable * realtime_ldap(const char *basedn, const char *table_name, const struct ast_variable *fields)
See Asterisk doc.
static int version
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 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
static LDAPMod * ldap_mod_append(LDAPMod *src, const char *new_value)
static struct ldap_table_config * table_config_for_table_name(const char *table_name)
Find a table_config.
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.
static int load_module(void)
Load the module.
static time_t connect_time
#define RES_CONFIG_LDAP_DEFAULT_BASEDN
static int semicolon_count_str(const char *somestr)
Count semicolons in string.
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 Realtime Documentation.
static char base_distinguished_name[512]
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
static int unload_module(void)
Unload Module.
static int reload(void)
Reload Module.
static char * cleaned_basedn(struct ast_channel *channel, const char *basedn)
static char * realtime_ldap_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Realtime Status.
static int parse_config(void)
parse the configuration file
static char * substituted(struct ast_channel *channel, const char *string)
static int update_ldap(const char *basedn, const char *table_name, const char *attribute, const char *lookup, const struct ast_variable *fields)
static struct ast_str * create_lookup_filter(struct ldap_table_config *config, const struct ast_variable *fields)
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.
static struct ast_variable * variable_named(struct ast_variable *var, const char *name)
Find variable by name.
static LDAPMod * ldap_mod_create(const char *attribute, const char *new_value)
static int update2_ldap(const char *basedn, const char *table_name, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
#define RES_CONFIG_LDAP_CONF
#define NULL
Definition resample.c:96
String manipulation functions.
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:1139
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Definition strings.h:693
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition strings.h:659
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition strings.h:425
Main Channel structure associated with a channel.
descriptor for a cli entry.
Definition cli.h:171
char * command
Definition cli.h:186
const char * usage
Definition cli.h:177
Configuration engine structure, used to define realtime drivers.
Structure used to handle boolean flags.
Definition utils.h:220
unsigned int flags
Definition utils.h:221
Support for dynamic strings.
Definition strings.h:623
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
const char * variable_value
const char * variable_name
Table configuration.
struct ast_variable * attributes
struct ast_variable * delimiters
struct ldap_table_config::@460 entry
Should be locked before using it.
structure to hold users read from phoneprov_users.conf
int value
Definition syslog.c:37
struct association categories[]
static struct test_val b
static struct test_val a
static struct test_val c
int error(const char *format,...)
Utility functions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition utils.h:981
#define ARRAY_LEN(a)
Definition utils.h:706