00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include "asterisk.h"
00039
00040 #include <stdlib.h>
00041 #include <string.h>
00042 #include <ctype.h>
00043 #include <stdio.h>
00044 #include <ldap.h>
00045
00046 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 137028 $")
00047
00048 #include "asterisk/channel.h"
00049 #include "asterisk/logger.h"
00050 #include "asterisk/config.h"
00051 #include "asterisk/module.h"
00052 #include "asterisk/lock.h"
00053 #include "asterisk/options.h"
00054 #include "asterisk/cli.h"
00055 #include "asterisk/utils.h"
00056 #include "asterisk/strings.h"
00057 #include "asterisk/pbx.h"
00058 #include "asterisk/linkedlists.h"
00059
00060 #define RES_CONFIG_LDAP_CONF "res_ldap.conf"
00061 #define RES_CONFIG_LDAP_DEFAULT_BASEDN "asterisk"
00062
00063 AST_MUTEX_DEFINE_STATIC(ldap_lock);
00064
00065 static LDAP *ldapConn;
00066 static char url[512];
00067 static char user[512];
00068 static char pass[50];
00069 static char base_distinguished_name[512];
00070 static int version = 3;
00071 static time_t connect_time;
00072
00073 static int parse_config(void);
00074 static int ldap_reconnect(void);
00075 static char *realtime_ldap_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
00076
00077 struct category_and_metric {
00078 const char *name;
00079 int metric;
00080 const char *variable_name;
00081 const char *variable_value;
00082 int var_metric;
00083 };
00084
00085
00086 struct ldap_table_config {
00087 char *table_name;
00088 char *additional_filter;
00089 struct ast_variable *attributes;
00090 struct ast_variable *delimiters;
00091 AST_LIST_ENTRY(ldap_table_config) entry;
00092 };
00093
00094
00095 static AST_LIST_HEAD_NOLOCK_STATIC(table_configs, ldap_table_config);
00096 static struct ldap_table_config *base_table_config;
00097 static struct ldap_table_config *static_table_config;
00098
00099 static struct ast_cli_entry ldap_cli[] = {
00100 AST_CLI_DEFINE(realtime_ldap_status, "Shows connection information for the LDAP RealTime driver"),
00101 };
00102
00103
00104 static struct ldap_table_config *table_config_new(const char *table_name)
00105 {
00106 struct ldap_table_config *p;
00107
00108 if (!(p = ast_calloc(1, sizeof(*p))))
00109 return NULL;
00110
00111 if (table_name) {
00112 if (!(p->table_name = ast_strdup(table_name))) {
00113 free(p);
00114 return NULL;
00115 }
00116 }
00117
00118 return p;
00119 }
00120
00121
00122
00123 static struct ldap_table_config *table_config_for_table_name(const char *table_name)
00124 {
00125 struct ldap_table_config *c = NULL;
00126
00127 AST_LIST_TRAVERSE(&table_configs, c, entry) {
00128 if (!strcmp(c->table_name, table_name))
00129 break;
00130 }
00131
00132 return c;
00133 }
00134
00135
00136 static struct ast_variable *variable_named(struct ast_variable *var, const char *name)
00137 {
00138 for (; var; var = var->next) {
00139 if (!strcasecmp(name, var->name))
00140 break;
00141 }
00142
00143 return var;
00144 }
00145
00146
00147
00148
00149
00150
00151 static int semicolon_count_str(const char *somestr)
00152 {
00153 int count = 0;
00154
00155 for (; *somestr; somestr++) {
00156 if (*somestr == ';')
00157 count++;
00158 }
00159
00160 return count;
00161 }
00162
00163
00164
00165
00166 static int semicolon_count_var(struct ast_variable *var)
00167 {
00168 struct ast_variable *var_value = variable_named(var, "variable_value");
00169
00170 if (!var_value)
00171 return 0;
00172
00173 ast_debug(1, "LINE(%d) semicolon_count_var: %s\n", __LINE__, var_value->value);
00174
00175 return semicolon_count_str(var_value->value);
00176 }
00177
00178
00179 static void ldap_table_config_add_attribute(struct ldap_table_config *table_config,
00180 const char *attribute_name, const char *attribute_value)
00181 {
00182 struct ast_variable *var;
00183
00184 if (ast_strlen_zero(attribute_name) || ast_strlen_zero(attribute_value))
00185 return;
00186
00187 if (!(var = ast_variable_new(attribute_name, attribute_value, table_config->table_name)))
00188 return;
00189
00190 if (table_config->attributes)
00191 var->next = table_config->attributes;
00192 table_config->attributes = var;
00193 }
00194
00195
00196
00197 static void table_configs_free(void)
00198 {
00199 struct ldap_table_config *c;
00200
00201 while ((c = AST_LIST_REMOVE_HEAD(&table_configs, entry))) {
00202 if (c->table_name)
00203 free(c->table_name);
00204 if (c->additional_filter)
00205 free(c->additional_filter);
00206 if (c->attributes)
00207 ast_variables_destroy(c->attributes);
00208 free(c);
00209 }
00210
00211 base_table_config = NULL;
00212 static_table_config = NULL;
00213 }
00214
00215
00216 static const char *convert_attribute_name_to_ldap(struct ldap_table_config *table_config,
00217 const char *attribute_name)
00218 {
00219 int i = 0;
00220 struct ldap_table_config *configs[] = { table_config, base_table_config };
00221
00222 for (i = 0; i < ARRAY_LEN(configs); i++) {
00223 struct ast_variable *attribute;
00224
00225 if (!configs[i])
00226 continue;
00227
00228 attribute = configs[i]->attributes;
00229 for (; attribute; attribute = attribute->next) {
00230 if (!strcasecmp(attribute_name, attribute->name))
00231 return attribute->value;
00232 }
00233 }
00234
00235 return attribute_name;
00236 }
00237
00238
00239 static const char *convert_attribute_name_from_ldap(struct ldap_table_config *table_config,
00240 const char *attribute_name)
00241 {
00242 int i = 0;
00243 struct ldap_table_config *configs[] = { table_config, base_table_config };
00244
00245 for (i = 0; i < ARRAY_LEN(configs); i++) {
00246 struct ast_variable *attribute;
00247
00248 if (!configs[i])
00249 continue;
00250
00251 attribute = configs[i]->attributes;
00252 for (; attribute; attribute = attribute->next) {
00253 if (strcasecmp(attribute_name, attribute->value) == 0)
00254 return attribute->name;
00255 }
00256 }
00257
00258 return attribute_name;
00259 }
00260
00261
00262
00263
00264 static struct ast_variable *realtime_ldap_entry_to_var(struct ldap_table_config *table_config,
00265 LDAPMessage *ldap_entry)
00266 {
00267 BerElement *ber = NULL;
00268 struct ast_variable *var = NULL;
00269 struct ast_variable *prev = NULL;
00270 int is_delimited = 0;
00271 int i = 0;
00272 char *ldap_attribute_name;
00273 struct berval *value;
00274 int pos = 0;
00275
00276 ldap_attribute_name = ldap_first_attribute(ldapConn, ldap_entry, &ber);
00277
00278 while (ldap_attribute_name) {
00279 struct berval **values = NULL;
00280 const char *attribute_name = convert_attribute_name_from_ldap(table_config, ldap_attribute_name);
00281 int is_realmed_password_attribute = strcasecmp(attribute_name, "md5secret") == 0;
00282
00283 values = ldap_get_values_len(ldapConn, ldap_entry, ldap_attribute_name);
00284 if (values) {
00285 struct berval **v;
00286 char *valptr;
00287
00288 for (v = values; *v; v++) {
00289 value = *v;
00290 valptr = value->bv_val;
00291 ast_debug(2, "LINE(%d) attribute_name: %s LDAP value: %s\n", __LINE__, attribute_name, valptr);
00292 if (is_realmed_password_attribute) {
00293 if (!strncasecmp(valptr, "{md5}", 5)) {
00294 valptr += 5;
00295 } else {
00296 valptr = NULL;
00297 }
00298 ast_debug(2, "md5: %s\n", valptr);
00299 }
00300 if (valptr) {
00301
00302 if (is_delimited) {
00303 i = 0;
00304 pos = 0;
00305 while (!ast_strlen_zero(valptr + i)) {
00306 if (valptr[i] == ';'){
00307 valptr[i] = '\0';
00308 if (prev) {
00309 prev->next = ast_variable_new(attribute_name, &valptr[pos], table_config->table_name);
00310 if (prev->next) {
00311 prev = prev->next;
00312 }
00313 } else {
00314 prev = var = ast_variable_new(attribute_name, &valptr[pos], table_config->table_name);
00315 }
00316 pos = i + 1;
00317 }
00318 i++;
00319 }
00320 }
00321
00322 if (prev) {
00323 prev->next = ast_variable_new(attribute_name, &valptr[pos], table_config->table_name);
00324 if (prev->next) {
00325 prev = prev->next;
00326 }
00327 } else {
00328 prev = var = ast_variable_new(attribute_name, &valptr[pos], table_config->table_name);
00329 }
00330 }
00331 }
00332 ldap_value_free_len(values);
00333 }
00334 ldap_attribute_name = ldap_next_attribute(ldapConn, ldap_entry, ber);
00335 }
00336 ber_free(ber, 0);
00337
00338 return var;
00339 }
00340
00341
00342
00343
00344
00345
00346
00347 static struct ast_variable **realtime_ldap_result_to_vars(struct ldap_table_config *table_config,
00348 LDAPMessage *ldap_result_msg, unsigned int *entries_count_ptr)
00349 {
00350 struct ast_variable **vars;
00351 int i = 0;
00352 int tot_count = 0;
00353 int entry_index = 0;
00354 LDAPMessage *ldap_entry = NULL;
00355 BerElement *ber = NULL;
00356 struct ast_variable *var = NULL;
00357 struct ast_variable *prev = NULL;
00358 int is_delimited = 0;
00359 char *delim_value = NULL;
00360 int delim_tot_count = 0;
00361 int delim_count = 0;
00362
00363
00364 ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
00365
00366 for (tot_count = 0; ldap_entry; tot_count++){
00367 tot_count += semicolon_count_var(realtime_ldap_entry_to_var(table_config, ldap_entry));
00368 ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
00369 }
00370
00371 if (entries_count_ptr)
00372 *entries_count_ptr = tot_count;
00373
00374
00375
00376
00377
00378 vars = ast_calloc(sizeof(struct ast_variable *), tot_count + 1);
00379
00380 ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
00381
00382 i = 0;
00383
00384
00385 for (entry_index = 0; ldap_entry; ) {
00386 int pos = 0;
00387 delim_value = NULL;
00388 delim_tot_count = 0;
00389 delim_count = 0;
00390
00391 do {
00392
00393
00394 char *ldap_attribute_name = ldap_first_attribute(ldapConn, ldap_entry, &ber);
00395 struct berval *value;
00396 while (ldap_attribute_name) {
00397
00398 const char *attribute_name =
00399 convert_attribute_name_from_ldap(table_config, ldap_attribute_name);
00400 int is_realmed_password_attribute = strcasecmp(attribute_name, "md5secret") == 0;
00401 struct berval **values = NULL;
00402
00403 values = ldap_get_values_len(ldapConn, ldap_entry, ldap_attribute_name);
00404 if (values) {
00405 struct berval **v;
00406 char *valptr;
00407
00408 for (v = values; *v; v++) {
00409 value = *v;
00410 valptr = value->bv_val;
00411 if (is_realmed_password_attribute) {
00412 if (strncasecmp(valptr, "{md5}", 5) == 0) {
00413 valptr += 5;
00414 } else {
00415 valptr = NULL;
00416 }
00417 ast_debug(2, "md5: %s\n", valptr);
00418 }
00419 if (valptr) {
00420 if (delim_value == NULL
00421 && !is_realmed_password_attribute
00422 && (static_table_config != table_config || strcmp(attribute_name, "variable_value") == 0)) {
00423
00424 delim_value = ast_strdup(valptr);
00425
00426 if ((delim_tot_count = semicolon_count_str(delim_value)) > 0) {
00427 ast_debug(4, "LINE(%d) is delimited %d times: %s\n", __LINE__, delim_tot_count, delim_value);
00428 is_delimited = 1;
00429 }
00430 }
00431
00432 if (is_delimited != 0
00433 && !is_realmed_password_attribute
00434 && (static_table_config != table_config || strcmp(attribute_name, "variable_value") == 0) ) {
00435
00436
00437 for (i = pos; !ast_strlen_zero(valptr + i); i++) {
00438 ast_debug(4, "LINE(%d) DELIM pos: %d i: %d\n", __LINE__, pos, i);
00439 if (delim_value[i] == ';') {
00440 delim_value[i] = '\0';
00441
00442 ast_debug(2, "LINE(%d) DELIM - attribute_name: %s value: %s pos: %d\n", __LINE__, attribute_name, &delim_value[pos], pos);
00443
00444 if (prev) {
00445 prev->next = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name);
00446 if (prev->next) {
00447 prev = prev->next;
00448 }
00449 } else {
00450 prev = var = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name);
00451 }
00452 pos = i + 1;
00453
00454 if (static_table_config == table_config) {
00455 break;
00456 }
00457 }
00458 }
00459 if (ast_strlen_zero(valptr + i)) {
00460 ast_debug(4, "LINE(%d) DELIM pos: %d i: %d delim_count: %d\n", __LINE__, pos, i, delim_count);
00461
00462 ast_debug(4, "LINE(%d) DELIM - attribute_name: %s value: %s pos: %d\n", __LINE__, attribute_name, &delim_value[pos], pos);
00463 if (prev) {
00464 prev->next = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name);
00465 if (prev->next) {
00466 prev = prev->next;
00467 }
00468 } else {
00469 prev = var = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name);
00470 }
00471
00472 is_delimited = 0;
00473 pos = 0;
00474 }
00475 free(delim_value);
00476 delim_value = NULL;
00477
00478 ast_debug(4, "LINE(%d) DELIM pos: %d i: %d\n", __LINE__, pos, i);
00479 } else {
00480
00481 if (delim_value) {
00482 free(delim_value);
00483 delim_value = NULL;
00484 }
00485 ast_debug(2, "LINE(%d) attribute_name: %s value: %s\n", __LINE__, attribute_name, valptr);
00486
00487 if (prev) {
00488 prev->next = ast_variable_new(attribute_name, valptr, table_config->table_name);
00489 if (prev->next) {
00490 prev = prev->next;
00491 }
00492 } else {
00493 prev = var = ast_variable_new(attribute_name, valptr, table_config->table_name);
00494 }
00495 }
00496 }
00497 }
00498 ldap_value_free_len(values);
00499 }
00500 ldap_attribute_name = ldap_next_attribute(ldapConn, ldap_entry, ber);
00501 }
00502 ber_free(ber, 0);
00503 if (static_table_config == table_config) {
00504 if (option_debug > 2) {
00505 const struct ast_variable *tmpdebug = variable_named(var, "variable_name");
00506 const struct ast_variable *tmpdebug2 = variable_named(var, "variable_value");
00507 if (tmpdebug && tmpdebug2) {
00508 ast_debug(3, "LINE(%d) Added to vars - %s = %s\n", __LINE__, tmpdebug->value, tmpdebug2->value);
00509 }
00510 }
00511 vars[entry_index++] = var;
00512 prev = NULL;
00513 }
00514
00515 delim_count++;
00516 } while (delim_count <= delim_tot_count && static_table_config == table_config);
00517
00518 if (static_table_config != table_config) {
00519 ast_debug(3, "LINE(%d) Added to vars - non static\n", __LINE__);
00520
00521 vars[entry_index++] = var;
00522 prev = NULL;
00523 }
00524 ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
00525 }
00526
00527 return vars;
00528 }
00529
00530
00531 static int is_ldap_connect_error(int err)
00532 {
00533 return (err == LDAP_SERVER_DOWN
00534 || err == LDAP_TIMEOUT || err == LDAP_CONNECT_ERROR);
00535 }
00536
00537
00538
00539
00540 static struct ast_variable *ldap_loadentry(struct ldap_table_config *table_config,
00541 const char *dn)
00542 {
00543 if (!table_config) {
00544 ast_log(LOG_ERROR, "No table config\n");
00545 return NULL;
00546 } else {
00547 struct ast_variable **vars = NULL;
00548 struct ast_variable *var = NULL;
00549 int result = -1;
00550 LDAPMessage *ldap_result_msg = NULL;
00551 int tries = 0;
00552
00553 ast_debug(2, "ldap_loadentry dn=%s\n", dn);
00554
00555 do {
00556 result = ldap_search_ext_s(ldapConn, dn, LDAP_SCOPE_BASE,
00557 "(objectclass=*)", NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &ldap_result_msg);
00558 if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
00559 ast_log(LOG_WARNING,
00560 "Failed to query database. Try %d/3\n",
00561 tries + 1);
00562 tries++;
00563 if (tries < 3) {
00564 usleep(500000L * tries);
00565 if (ldapConn) {
00566 ldap_unbind_ext_s(ldapConn, NULL, NULL);
00567 ldapConn = NULL;
00568 }
00569 if (!ldap_reconnect())
00570 break;
00571 }
00572 }
00573 } while (result != LDAP_SUCCESS && tries < 3 && is_ldap_connect_error(result));
00574
00575 if (result != LDAP_SUCCESS) {
00576 ast_log(LOG_WARNING,
00577 "Failed to query database. Check debug for more info.\n");
00578 ast_debug(2, "dn=%s\n", dn);
00579 ast_debug(2, "Query Failed because: %s\n",
00580 ldap_err2string(result));
00581 ast_mutex_unlock(&ldap_lock);
00582 return NULL;
00583 } else {
00584 int num_entry = 0;
00585 unsigned int *entries_count_ptr = NULL;
00586 if ((num_entry = ldap_count_entries(ldapConn, ldap_result_msg)) > 0) {
00587 ast_debug(3, "num_entry: %d\n", num_entry);
00588
00589 vars = realtime_ldap_result_to_vars(table_config, ldap_result_msg, entries_count_ptr);
00590 if (num_entry > 1)
00591 ast_log(LOG_NOTICE, "More than one entry for dn=%s. Take only 1st one\n", dn);
00592 } else {
00593 ast_debug(2, "Could not find any entry dn=%s.\n", dn);
00594 }
00595 }
00596 ldap_msgfree(ldap_result_msg);
00597
00598
00599 if (vars != NULL) {
00600 struct ast_variable **p = vars;
00601 p++;
00602 var = *p;
00603 while (var) {
00604 ast_variables_destroy(var);
00605 p++;
00606 }
00607 vars = ast_realloc(vars, sizeof(struct ast_variable *));
00608 }
00609
00610 var = *vars;
00611
00612 return var;
00613 }
00614 }
00615
00616
00617 static char *substituted(struct ast_channel *channel, const char *string)
00618 {
00619 #define MAXRESULT 2048
00620 char *ret_string = NULL;
00621
00622 if (!ast_strlen_zero(string)) {
00623 ret_string = ast_calloc(1, MAXRESULT);
00624 pbx_substitute_variables_helper(channel, string, ret_string, MAXRESULT - 1);
00625 }
00626 ast_debug(2, "substituted: string: '%s' => '%s' \n",
00627 string, ret_string);
00628 return ret_string;
00629 }
00630
00631
00632 static char *cleaned_basedn(struct ast_channel *channel, const char *basedn)
00633 {
00634 char *cbasedn = NULL;
00635 if (basedn) {
00636 char *p = NULL;
00637 cbasedn = substituted(channel, basedn);
00638 if (*cbasedn == '"') {
00639 cbasedn++;
00640 if (!ast_strlen_zero(cbasedn)) {
00641 int len = strlen(cbasedn);
00642 if (cbasedn[len - 1] == '"')
00643 cbasedn[len - 1] = '\0';
00644
00645 }
00646 }
00647 p = cbasedn;
00648 while (*p) {
00649 if (*p == '|')
00650 *p = ',';
00651 p++;
00652 }
00653 }
00654 ast_debug(2, "basedn: '%s' => '%s' \n", basedn, cbasedn);
00655 return cbasedn;
00656 }
00657
00658
00659 static int replace_string_in_string(char *string, const char *search, const char *by)
00660 {
00661 int search_len = strlen(search);
00662 int by_len = strlen(by);
00663 int replaced = 0;
00664 char *p = strstr(string, search);
00665 if (p) {
00666 replaced = 1;
00667 while (p) {
00668 if (by_len == search_len)
00669 memcpy(p, by, by_len);
00670 else {
00671 memmove(p + by_len, p + search_len,
00672 strlen(p + search_len) + 1);
00673 memcpy(p, by, by_len);
00674 }
00675 p = strstr(p + by_len, search);
00676 }
00677 }
00678 return replaced;
00679 }
00680
00681
00682 static void append_var_and_value_to_filter(struct ast_str **filter,
00683 struct ldap_table_config *table_config,
00684 const char *name, const char *value)
00685 {
00686 char *new_name = NULL;
00687 char *new_value = NULL;
00688 char *like_pos = strstr(name, " LIKE");
00689
00690 ast_debug(2, "name='%s' value='%s'\n", name, value);
00691
00692 if (like_pos) {
00693 int len = like_pos - name;
00694 name = new_name = ast_strdupa(name);
00695 new_name[len] = '\0';
00696 value = new_value = ast_strdupa(value);
00697 replace_string_in_string(new_value, "\\_", "_");
00698 replace_string_in_string(new_value, "%", "*");
00699 }
00700
00701 name = convert_attribute_name_to_ldap(table_config, name);
00702
00703 ast_str_append(filter, 0, "(%s=%s)", name, value);
00704 }
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714 static struct ast_variable **realtime_ldap_base_ap(unsigned int *entries_count_ptr,
00715 const char *basedn, const char *table_name, va_list ap)
00716 {
00717 struct ast_variable **vars = NULL;
00718 const char *newparam = NULL;
00719 const char *newval = NULL;
00720 struct ldap_table_config *table_config = NULL;
00721 char *clean_basedn = cleaned_basedn(NULL, basedn);
00722 struct ast_str *filter = NULL;
00723 int tries = 0;
00724 int result = 0;
00725 LDAPMessage *ldap_result_msg = NULL;
00726
00727 if (!table_name) {
00728 ast_log(LOG_WARNING, "No table_name specified.\n");
00729 ast_free(clean_basedn);
00730 return NULL;
00731 }
00732
00733 if (!(filter = ast_str_create(80))) {
00734 ast_free(clean_basedn);
00735 return NULL;
00736 }
00737
00738
00739 newparam = va_arg(ap, const char *);
00740 newval = va_arg(ap, const char *);
00741
00742 if (!newparam || !newval) {
00743 ast_log(LOG_WARNING, "Realtime retrieval requires at least 1 parameter"
00744 " and 1 value to search on.\n");
00745 ast_free(filter);
00746 ast_free(clean_basedn);
00747 return NULL;
00748 }
00749
00750 ast_mutex_lock(&ldap_lock);
00751
00752
00753 if (!ldap_reconnect()) {
00754 ast_mutex_unlock(&ldap_lock);
00755 ast_free(filter);
00756 ast_free(clean_basedn);
00757 return NULL;
00758 }
00759
00760 table_config = table_config_for_table_name(table_name);
00761 if (!table_config) {
00762 ast_log(LOG_WARNING, "No table named '%s'.\n", table_name);
00763 ast_mutex_unlock(&ldap_lock);
00764 ast_free(filter);
00765 ast_free(clean_basedn);
00766 return NULL;
00767 }
00768
00769 ast_str_append(&filter, 0, "(&");
00770
00771 if (table_config && table_config->additional_filter)
00772 ast_str_append(&filter, 0, "%s", table_config->additional_filter);
00773 if (table_config != base_table_config && base_table_config &&
00774 base_table_config->additional_filter) {
00775 ast_str_append(&filter, 0, "%s", base_table_config->additional_filter);
00776 }
00777
00778
00779
00780
00781 append_var_and_value_to_filter(&filter, table_config, newparam, newval);
00782 while ((newparam = va_arg(ap, const char *))) {
00783 newval = va_arg(ap, const char *);
00784 append_var_and_value_to_filter(&filter, table_config, newparam, newval);
00785 }
00786 ast_str_append(&filter, 0, ")");
00787
00788 do {
00789
00790 result = ldap_search_ext_s(ldapConn, clean_basedn,
00791 LDAP_SCOPE_SUBTREE, filter->str, NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
00792 &ldap_result_msg);
00793 if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
00794 ast_log(LOG_DEBUG, "Failed to query database. Try %d/10\n",
00795 tries + 1);
00796 if (++tries < 10) {
00797 usleep(1);
00798 if (ldapConn) {
00799 ldap_unbind_ext_s(ldapConn, NULL, NULL);
00800 ldapConn = NULL;
00801 }
00802 if (!ldap_reconnect())
00803 break;
00804 }
00805 }
00806 } while (result != LDAP_SUCCESS && tries < 10 && is_ldap_connect_error(result));
00807
00808 if (result != LDAP_SUCCESS) {
00809 ast_log(LOG_WARNING, "Failed to query database. Check debug for more info.\n");
00810 ast_log(LOG_WARNING, "Query: %s\n", filter->str);
00811 ast_log(LOG_WARNING, "Query Failed because: %s\n", ldap_err2string(result));
00812 } else {
00813
00814
00815 if (ldap_count_entries(ldapConn, ldap_result_msg) > 0) {
00816
00817 vars = realtime_ldap_result_to_vars(table_config, ldap_result_msg, entries_count_ptr);
00818 } else {
00819 ast_debug(1, "Could not find any entry matching %s in base dn %s.\n",
00820 filter->str, clean_basedn);
00821 }
00822
00823 ldap_msgfree(ldap_result_msg);
00824
00825
00826 if (vars) {
00827 struct ast_variable **p = vars;
00828 while (*p) {
00829 struct ast_variable *append_var = NULL;
00830 struct ast_variable *tmp = *p;
00831 while (tmp) {
00832 if (strcasecmp(tmp->name, "accountBaseDN") == 0) {
00833
00834 struct ast_variable *base_var = ldap_loadentry(table_config, tmp->value);
00835
00836 while (base_var) {
00837 struct ast_variable *next = base_var->next;
00838 struct ast_variable *test_var = *p;
00839 int base_var_found = 0;
00840
00841
00842 while (test_var) {
00843 if (strcasecmp(test_var->name, base_var->name) == 0) {
00844 base_var_found = 1;
00845 break;
00846 } else
00847 test_var = test_var->next;
00848 }
00849 if (base_var_found) {
00850 base_var->next = NULL;
00851 ast_variables_destroy(base_var);
00852 base_var = next;
00853 } else {
00854 if (append_var)
00855 base_var->next = append_var;
00856 else
00857 base_var->next = NULL;
00858 append_var = base_var;
00859 base_var = next;
00860 }
00861 }
00862 }
00863 if (!tmp->next && append_var) {
00864 tmp->next = append_var;
00865 tmp = NULL;
00866 } else
00867 tmp = tmp->next;
00868 }
00869 p++;
00870 }
00871 }
00872 }
00873
00874 if (filter)
00875 ast_free(filter);
00876
00877 if (clean_basedn)
00878 ast_free(clean_basedn);
00879
00880 ast_mutex_unlock(&ldap_lock);
00881
00882 return vars;
00883 }
00884
00885
00886 static struct ast_variable **realtime_ldap_base(unsigned int *entries_count_ptr,
00887 const char *basedn, const char *table_name, ...)
00888 {
00889 struct ast_variable **vars = NULL;
00890 va_list ap;
00891
00892 va_start(ap, table_name);
00893 vars = realtime_ldap_base_ap(entries_count_ptr, basedn, table_name, ap);
00894 va_end(ap);
00895
00896 return vars;
00897 }
00898
00899
00900
00901
00902
00903 static struct ast_variable *realtime_ldap(const char *basedn,
00904 const char *table_name, va_list ap)
00905 {
00906 struct ast_variable **vars = realtime_ldap_base_ap(NULL, basedn, table_name, ap);
00907 struct ast_variable *var = NULL;
00908
00909 if (vars) {
00910 struct ast_variable *last_var = NULL;
00911 struct ast_variable **p = vars;
00912 while (*p) {
00913 if (last_var) {
00914 while (last_var->next)
00915 last_var = last_var->next;
00916 last_var->next = *p;
00917 } else {
00918 var = *p;
00919 last_var = var;
00920 }
00921 p++;
00922 }
00923 free(vars);
00924 }
00925 return var;
00926 }
00927
00928
00929
00930
00931
00932
00933
00934
00935 static struct ast_config *realtime_multi_ldap(const char *basedn,
00936 const char *table_name, va_list ap)
00937 {
00938 struct ast_variable **vars =
00939 realtime_ldap_base_ap(NULL, basedn, table_name, ap);
00940 struct ast_config *cfg = NULL;
00941
00942 if (vars) {
00943 cfg = ast_config_new();
00944 if (!cfg) {
00945 ast_log(LOG_ERROR, "Unable to create a config!\n");
00946 } else {
00947 struct ast_variable **p = vars;
00948
00949 while (*p) {
00950 struct ast_category *cat = NULL;
00951 cat = ast_category_new("", table_name, -1);
00952 if (!cat) {
00953 ast_log(LOG_ERROR, "Unable to create a new category!\n");
00954 break;
00955 } else {
00956 struct ast_variable *var = *p;
00957 while (var) {
00958 struct ast_variable *next = var->next;
00959 var->next = NULL;
00960 ast_variable_append(cat, var);
00961 var = next;
00962 }
00963 }
00964 ast_category_append(cfg, cat);
00965 p++;
00966 }
00967 }
00968 free(vars);
00969 }
00970 return cfg;
00971
00972 }
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983 static int compare_categories(const void *a, const void *b)
00984 {
00985 const struct category_and_metric *as = a;
00986 const struct category_and_metric *bs = b;
00987
00988 if (as->metric < bs->metric)
00989 return -1;
00990 else if (as->metric > bs->metric)
00991 return 1;
00992 else if (as->metric == bs->metric && strcmp(as->name, bs->name) != 0)
00993 return strcmp(as->name, bs->name);
00994
00995
00996 if (as->var_metric < bs->var_metric)
00997 return -1;
00998 else if (as->var_metric > bs->var_metric)
00999 return 1;
01000
01001 return 0;
01002 }
01003
01004
01005
01006
01007
01008
01009
01010
01011 static struct ast_config *config_ldap(const char *basedn, const char *table_name,
01012 const char *file, struct ast_config *cfg, struct ast_flags config_flags, const char *sugg_incl, const char *who_asked)
01013 {
01014 unsigned int vars_count = 0;
01015 struct ast_variable **vars;
01016 int i = 0;
01017 struct ast_variable *new_v = NULL;
01018 struct ast_category *cur_cat = NULL;
01019 const char *last_category = NULL;
01020 int last_category_metric = 0;
01021 struct category_and_metric *categories;
01022 struct ast_variable **p;
01023
01024 if (ast_strlen_zero(file) || !strcasecmp(file, RES_CONFIG_LDAP_CONF)) {
01025 ast_log(LOG_ERROR, "Cannot configure myself.\n");
01026 return NULL;
01027 }
01028
01029 vars = realtime_ldap_base(&vars_count, basedn, table_name, "filename",
01030 file, "commented", "FALSE", NULL);
01031
01032 if (!vars) {
01033 ast_log(LOG_WARNING, "Could not find config '%s' in database.\n", file);
01034 return NULL;
01035 }
01036
01037
01038
01039
01040
01041 if (!(categories = ast_calloc(sizeof(*categories), vars_count)))
01042 return NULL;
01043
01044 for (vars_count = 0, p = vars; *p; p++) {
01045 struct ast_variable *category = variable_named(*p, "category");
01046 struct ast_variable *cat_metric = variable_named(*p, "cat_metric");
01047 struct ast_variable *var_name = variable_named(*p, "variable_name");
01048 struct ast_variable *var_val = variable_named(*p, "variable_value");
01049 struct ast_variable *var_metric = variable_named(*p, "var_metric");
01050 struct ast_variable *dn = variable_named(*p, "dn");
01051
01052 ast_debug(1, "category: %s\n", category->value);
01053 ast_debug(1, "var_name: %s\n", var_name->value);
01054 ast_debug(1, "var_val: %s\n", var_val->value);
01055 ast_debug(1, "cat_metric: %s\n", cat_metric->value);
01056
01057 if (!category) {
01058 ast_log(LOG_ERROR,
01059 "No category name in entry '%s' for file '%s'.\n",
01060 (dn ? dn->value : "?"), file);
01061 } else if (!cat_metric) {
01062 ast_log(LOG_ERROR,
01063 "No category metric in entry '%s'(category: %s) for file '%s'.\n",
01064 (dn ? dn->value : "?"), category->value, file);
01065 } else if (!var_metric) {
01066 ast_log(LOG_ERROR,
01067 "No variable metric in entry '%s'(category: %s) for file '%s'.\n",
01068 (dn ? dn->value : "?"), category->value, file);
01069 } else if (!var_name) {
01070 ast_log(LOG_ERROR,
01071 "No variable name in entry '%s' (category: %s metric: %s) for file '%s'.\n",
01072 (dn ? dn->value : "?"), category->value,
01073 cat_metric->value, file);
01074 } else if (!var_val) {
01075 ast_log(LOG_ERROR,
01076 "No variable value in entry '%s' (category: %s metric: %s variable: %s) for file '%s'.\n",
01077 (dn ? dn->value : "?"), category->value,
01078 cat_metric->value, var_name->value, file);
01079 } else {
01080 categories[vars_count].name = category->value;
01081 categories[vars_count].metric = atoi(cat_metric->value);
01082 categories[vars_count].variable_name = var_name->value;
01083 categories[vars_count].variable_value = var_val->value;
01084 categories[vars_count].var_metric = atoi(var_metric->value);
01085 vars_count++;
01086 }
01087 }
01088
01089 qsort(categories, vars_count, sizeof(*categories), compare_categories);
01090
01091 for (i = 0; i < vars_count; i++) {
01092 if (!strcmp(categories[i].variable_name, "#include")) {
01093 struct ast_flags flags = { 0 };
01094 if (!ast_config_internal_load(categories[i].variable_value, cfg, flags, "", who_asked))
01095 break;
01096 continue;
01097 }
01098
01099 if (!last_category || strcmp(last_category, categories[i].name) ||
01100 last_category_metric != categories[i].metric) {
01101 cur_cat = ast_category_new(categories[i].name, table_name, -1);
01102 if (!cur_cat)
01103 break;
01104 last_category = categories[i].name;
01105 last_category_metric = categories[i].metric;
01106 ast_category_append(cfg, cur_cat);
01107 }
01108
01109 if (!(new_v = ast_variable_new(categories[i].variable_name, categories[i].variable_value, table_name)))
01110 break;
01111
01112 ast_variable_append(cur_cat, new_v);
01113 }
01114
01115 free(vars);
01116 free(categories);
01117
01118 return cfg;
01119 }
01120
01121
01122
01123
01124 static int update_ldap(const char *basedn, const char *table_name, const char *attribute,
01125 const char *lookup, va_list ap)
01126 {
01127 int error = 0;
01128 LDAPMessage *ldap_entry = NULL;
01129 LDAPMod **ldap_mods;
01130 const char *newparam = NULL;
01131 const char *newval = NULL;
01132 char *dn;
01133 int num_entries = 0;
01134 int i = 0;
01135 int mods_size = 0;
01136 int mod_exists = 0;
01137 struct ldap_table_config *table_config = NULL;
01138 char *clean_basedn = NULL;
01139 struct ast_str *filter = NULL;
01140 int tries = 0;
01141 int result = 0;
01142 LDAPMessage *ldap_result_msg = NULL;
01143
01144 if (!table_name) {
01145 ast_log(LOG_WARNING, "No table_name specified.\n");
01146 return -1;
01147 }
01148
01149 if (!(filter = ast_str_create(80)))
01150 return -1;
01151
01152 if (!attribute || !lookup) {
01153 ast_log(LOG_WARNING,
01154 "LINE(%d): search parameters are empty.\n", __LINE__);
01155 return -1;
01156 }
01157 ast_mutex_lock(&ldap_lock);
01158
01159
01160 if (!ldap_reconnect()) {
01161 ast_mutex_unlock(&ldap_lock);
01162 return -1;
01163 }
01164
01165 table_config = table_config_for_table_name(table_name);
01166 if (!table_config) {
01167 ast_log(LOG_WARNING, "No table named '%s'.\n", table_name);
01168 ast_mutex_unlock(&ldap_lock);
01169 return -1;
01170 }
01171
01172 clean_basedn = cleaned_basedn(NULL, basedn);
01173
01174
01175 ast_str_append(&filter, 0, "(&");
01176 if (table_config && table_config->additional_filter) {
01177 ast_str_append(&filter, 0, "%s", table_config->additional_filter);
01178 }
01179 if (table_config != base_table_config && base_table_config
01180 && base_table_config->additional_filter) {
01181 ast_str_append(&filter, 0, "%s", base_table_config->additional_filter);
01182 }
01183 append_var_and_value_to_filter(&filter, table_config, attribute, lookup);
01184 ast_str_append(&filter, 0, ")");
01185
01186
01187
01188
01189 newparam = va_arg(ap, const char *);
01190 newparam = convert_attribute_name_to_ldap(table_config, newparam);
01191 newval = va_arg(ap, const char *);
01192 if (!newparam || !newval) {
01193 ast_log(LOG_WARNING,
01194 "LINE(%d): need at least one parameter to modify.\n", __LINE__);
01195 return -1;
01196 }
01197
01198 mods_size = 2;
01199 ldap_mods = ast_calloc(sizeof(LDAPMod *), mods_size);
01200 ldap_mods[0] = ast_calloc(1, sizeof(LDAPMod));
01201
01202 ldap_mods[0]->mod_op = LDAP_MOD_REPLACE;
01203 ldap_mods[0]->mod_type = ast_calloc(sizeof(char), strlen(newparam) + 1);
01204 strcpy(ldap_mods[0]->mod_type, newparam);
01205
01206 ldap_mods[0]->mod_values = ast_calloc(sizeof(char), 2);
01207 ldap_mods[0]->mod_values[0] = ast_calloc(sizeof(char), strlen(newval) + 1);
01208 strcpy(ldap_mods[0]->mod_values[0], newval);
01209
01210 while ((newparam = va_arg(ap, const char *))) {
01211 newparam = convert_attribute_name_to_ldap(table_config, newparam);
01212 newval = va_arg(ap, const char *);
01213 mod_exists = 0;
01214
01215 for (i = 0; i < mods_size - 1; i++) {
01216 if (ldap_mods[i]&& !strcmp(ldap_mods[i]->mod_type, newparam)) {
01217
01218 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));
01219 strcat(ldap_mods[i]->mod_values[0], ";");
01220 strcat(ldap_mods[i]->mod_values[0], newval);
01221 mod_exists = 1;
01222 break;
01223 }
01224 }
01225
01226
01227 if (!mod_exists) {
01228 mods_size++;
01229 ldap_mods = ast_realloc(ldap_mods, sizeof(LDAPMod *) * mods_size);
01230 ldap_mods[mods_size - 1] = NULL;
01231 ldap_mods[mods_size - 2] = ast_calloc(1, sizeof(LDAPMod));
01232
01233 ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_REPLACE;
01234
01235 ldap_mods[mods_size - 2]->mod_type = ast_calloc(sizeof(char), strlen(newparam) + 1);
01236 strcpy(ldap_mods[mods_size - 2]->mod_type, newparam);
01237
01238 ldap_mods[mods_size - 2]->mod_values = ast_calloc(sizeof(char *), 2);
01239 ldap_mods[mods_size - 2]->mod_values[0] = ast_calloc(sizeof(char), strlen(newval) + 1);
01240 strcpy(ldap_mods[mods_size - 2]->mod_values[0], newval);
01241 }
01242 }
01243
01244
01245 do {
01246
01247 result = ldap_search_ext_s(ldapConn, clean_basedn,
01248 LDAP_SCOPE_SUBTREE, filter->str, NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
01249 &ldap_result_msg);
01250 if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
01251 ast_log(LOG_WARNING, "Failed to query database. Try %d/3\n",
01252 tries + 1);
01253 tries++;
01254 if (tries < 3) {
01255 usleep(500000L * tries);
01256 if (ldapConn) {
01257 ldap_unbind_ext_s(ldapConn, NULL, NULL);
01258 ldapConn = NULL;
01259 }
01260 if (!ldap_reconnect())
01261 break;
01262 }
01263 }
01264 } while (result != LDAP_SUCCESS && tries < 3 && is_ldap_connect_error(result));
01265
01266 if (result != LDAP_SUCCESS) {
01267 ast_log(LOG_WARNING, "Failed to query directory. Check debug for more info.\n");
01268 ast_log(LOG_WARNING, "Query: %s\n", filter->str);
01269 ast_log(LOG_WARNING, "Query Failed because: %s\n",
01270 ldap_err2string(result));
01271
01272 ast_mutex_unlock(&ldap_lock);
01273 if (filter)
01274 free(filter);
01275 if (clean_basedn)
01276 free(clean_basedn);
01277 ldap_msgfree(ldap_result_msg);
01278 ldap_mods_free(ldap_mods, 0);
01279 return -1;
01280 }
01281
01282 if ((num_entries = ldap_count_entries(ldapConn, ldap_result_msg)) > 0) {
01283 ast_debug(3, "LINE(%d) Modifying %s=%s hits: %d\n", __LINE__, attribute, lookup, num_entries);
01284 for (i = 0; option_debug > 2 && i < mods_size - 1; i++)
01285 ast_debug(3, "LINE(%d) %s=%s \n", __LINE__, ldap_mods[i]->mod_type, ldap_mods[i]->mod_values[0]);
01286
01287 ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
01288
01289 for (i = 0; ldap_entry; i++) {
01290 dn = ldap_get_dn(ldapConn, ldap_entry);
01291 if ((error = ldap_modify_ext_s(ldapConn, dn, ldap_mods, NULL, NULL)) != LDAP_SUCCESS)
01292 ast_log(LOG_ERROR, "Couldn't modify dn:%s because %s", dn, ldap_err2string(error));
01293
01294 ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
01295 }
01296 }
01297
01298 ast_mutex_unlock(&ldap_lock);
01299 if (filter)
01300 free(filter);
01301 if (clean_basedn)
01302 free(clean_basedn);
01303 ldap_msgfree(ldap_result_msg);
01304 ldap_mods_free(ldap_mods, 0);
01305 return num_entries;
01306 }
01307
01308 static struct ast_config_engine ldap_engine = {
01309 .name = "ldap",
01310 .load_func = config_ldap,
01311 .realtime_func = realtime_ldap,
01312 .realtime_multi_func = realtime_multi_ldap,
01313 .update_func = update_ldap
01314 };
01315
01316 static int load_module(void)
01317 {
01318 if (parse_config() < 0) {
01319 ast_log(LOG_NOTICE, "Cannot load LDAP RealTime driver.\n");
01320 return 0;
01321 }
01322
01323 ast_mutex_lock(&ldap_lock);
01324
01325 if (!ldap_reconnect())
01326 ast_log(LOG_WARNING, "Couldn't establish connection. Check debug.\n");
01327
01328 ast_config_engine_register(&ldap_engine);
01329 ast_verb(1, "LDAP RealTime driver loaded.\n");
01330 ast_cli_register_multiple(ldap_cli, sizeof(ldap_cli) / sizeof(struct ast_cli_entry));
01331
01332 ast_mutex_unlock(&ldap_lock);
01333
01334 return 0;
01335 }
01336
01337 static int unload_module(void)
01338 {
01339
01340 ast_mutex_lock(&ldap_lock);
01341
01342 table_configs_free();
01343
01344 if (ldapConn) {
01345 ldap_unbind_ext_s(ldapConn, NULL, NULL);
01346 ldapConn = NULL;
01347 }
01348 ast_cli_unregister_multiple(ldap_cli, sizeof(ldap_cli) / sizeof(struct ast_cli_entry));
01349 ast_config_engine_deregister(&ldap_engine);
01350 ast_verb(1, "LDAP RealTime unloaded.\n");
01351
01352
01353 ast_mutex_unlock(&ldap_lock);
01354
01355 return 0;
01356 }
01357
01358 static int reload(void)
01359 {
01360
01361 ast_mutex_lock(&ldap_lock);
01362
01363 if (ldapConn) {
01364 ldap_unbind_ext_s(ldapConn, NULL, NULL);
01365 ldapConn = NULL;
01366 }
01367
01368 if (parse_config() < 0) {
01369 ast_log(LOG_NOTICE, "Cannot reload LDAP RealTime driver.\n");
01370 ast_mutex_unlock(&ldap_lock);
01371 return 0;
01372 }
01373
01374 if (!ldap_reconnect())
01375 ast_log(LOG_WARNING, "Couldn't establish connection. Check debug.\n");
01376
01377 ast_verb(2, "LDAP RealTime reloaded.\n");
01378
01379
01380 ast_mutex_unlock(&ldap_lock);
01381
01382 return 0;
01383 }
01384
01385 int parse_config(void)
01386 {
01387 struct ast_config *config;
01388 struct ast_flags config_flags = {0};
01389 const char *s, *host;
01390 int port;
01391 char *category_name = NULL;
01392
01393 config = ast_config_load(RES_CONFIG_LDAP_CONF, config_flags);
01394
01395 if (!config) {
01396 ast_log(LOG_WARNING, "Cannot load configuration %s\n", RES_CONFIG_LDAP_CONF);
01397 return -1;
01398 }
01399
01400 if (!(s = ast_variable_retrieve(config, "_general", "user"))) {
01401 ast_log(LOG_WARNING, "No directory user found, anonymous binding as default.\n");
01402 user[0] = '\0';
01403 } else
01404 ast_copy_string(user, s, sizeof(user));
01405
01406 if (!ast_strlen_zero(user)) {
01407 if (!(s = ast_variable_retrieve(config, "_general", "pass"))) {
01408 ast_log(LOG_WARNING, "No directory password found, using 'asterisk' as default.\n");
01409 ast_copy_string(pass, "asterisk", sizeof(pass));
01410 } else {
01411 ast_copy_string(pass, s, sizeof(pass));
01412 }
01413 }
01414
01415
01416 if ((s = ast_variable_retrieve(config, "_general", "url"))) {
01417 ast_copy_string(url, s, sizeof(url));
01418 } else if ((host = ast_variable_retrieve(config, "_general", "host"))) {
01419 if (!(s = ast_variable_retrieve(config, "_general", "port")) || sscanf(s, "%d", &port) != 1) {
01420 ast_log(LOG_NOTICE, "No directory port found, using 389 as default.\n");
01421 port = 389;
01422 }
01423
01424 snprintf(url, sizeof(url), "ldap://%s:%d", host, port);
01425 } else {
01426 ast_log(LOG_ERROR, "No directory URL or host found.\n");
01427 ast_config_destroy(config);
01428 return -1;
01429 }
01430
01431 if (!(s = ast_variable_retrieve(config, "_general", "basedn"))) {
01432 ast_log(LOG_ERROR, "No LDAP base dn found, using '%s' as default.\n", RES_CONFIG_LDAP_DEFAULT_BASEDN);
01433 ast_copy_string(base_distinguished_name, RES_CONFIG_LDAP_DEFAULT_BASEDN, sizeof(base_distinguished_name));
01434 } else
01435 ast_copy_string(base_distinguished_name, s, sizeof(base_distinguished_name));
01436
01437 if (!(s = ast_variable_retrieve(config, "_general", "version")) && !(s = ast_variable_retrieve(config, "_general", "protocol"))) {
01438 ast_log(LOG_NOTICE, "No explicit LDAP version found, using 3 as default.\n");
01439 version = 3;
01440 } else if (sscanf(s, "%d", &version) != 1 || version < 1 || version > 6) {
01441 ast_log(LOG_WARNING, "Invalid LDAP version '%s', using 3 as default.\n", s);
01442 version = 3;
01443 }
01444
01445 table_configs_free();
01446
01447 while ((category_name = ast_category_browse(config, category_name))) {
01448 int is_general = (strcasecmp(category_name, "_general") == 0);
01449 int is_config = (strcasecmp(category_name, "config") == 0);
01450 struct ast_variable *var = ast_variable_browse(config, category_name);
01451
01452 if (var) {
01453 struct ldap_table_config *table_config =
01454 table_config_for_table_name(category_name);
01455 if (!table_config) {
01456 table_config = table_config_new(category_name);
01457 AST_LIST_INSERT_HEAD(&table_configs, table_config, entry);
01458 if (is_general)
01459 base_table_config = table_config;
01460 if (is_config)
01461 static_table_config = table_config;
01462 }
01463 for (; var; var = var->next) {
01464 if (!strcasecmp(var->name, "additionalFilter")) {
01465 table_config->additional_filter = ast_strdup(var->value);
01466 } else {
01467 ldap_table_config_add_attribute(table_config, var->name, var->value);
01468 }
01469 }
01470 }
01471 }
01472
01473 ast_config_destroy(config);
01474
01475 return 1;
01476 }
01477
01478
01479 static int ldap_reconnect(void)
01480 {
01481 int bind_result = 0;
01482 struct berval cred;
01483
01484 if (ldapConn) {
01485 ast_debug(2, "Everything seems fine.\n");
01486 return 1;
01487 }
01488
01489 if (ast_strlen_zero(url)) {
01490 ast_log(LOG_ERROR, "Not enough parameters to connect to ldap database\n");
01491 return 0;
01492 }
01493
01494 if (LDAP_SUCCESS != ldap_initialize(&ldapConn, url)) {
01495 ast_log(LOG_ERROR, "Failed to init ldap connection to '%s'. Check debug for more info.\n", url);
01496 return 0;
01497 }
01498
01499 if (LDAP_OPT_SUCCESS != ldap_set_option(ldapConn, LDAP_OPT_PROTOCOL_VERSION, &version)) {
01500 ast_log(LOG_WARNING, "Unable to set LDAP protocol version to %d, falling back to default.\n", version);
01501 }
01502
01503 if (!ast_strlen_zero(user)) {
01504 ast_debug(2, "bind to '%s' as user '%s'\n", url, user);
01505 cred.bv_val = (char *) pass;
01506 cred.bv_len = strlen(pass);
01507 bind_result = ldap_sasl_bind_s(ldapConn, user, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
01508 } else {
01509 ast_debug(2, "bind %s anonymously\n", url);
01510 cred.bv_val = NULL;
01511 cred.bv_len = 0;
01512 bind_result = ldap_sasl_bind_s(ldapConn, NULL, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
01513 }
01514 if (bind_result == LDAP_SUCCESS) {
01515 ast_debug(2, "Successfully connected to database.\n");
01516 connect_time = time(NULL);
01517 return 1;
01518 } else {
01519 ast_log(LOG_WARNING, "bind failed: %s\n", ldap_err2string(bind_result));
01520 ldap_unbind_ext_s(ldapConn, NULL, NULL);
01521 ldapConn = NULL;
01522 return 0;
01523 }
01524 }
01525
01526 static char *realtime_ldap_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01527 {
01528 char status[256], credentials[100] = "";
01529 int ctimesec = time(NULL) - connect_time;
01530
01531 switch (cmd) {
01532 case CLI_INIT:
01533 e->command = "realtime ldap status";
01534 e->usage =
01535 "Usage: realtime ldap status\n"
01536 " Shows connection information for the LDAP RealTime driver\n";
01537 return NULL;
01538 case CLI_GENERATE:
01539 return NULL;
01540 }
01541
01542 if (!ldapConn)
01543 return CLI_FAILURE;
01544
01545 if (!ast_strlen_zero(url))
01546 snprintf(status, sizeof(status), "Connected to '%s', baseDN %s", url, base_distinguished_name);
01547
01548 if (!ast_strlen_zero(user))
01549 snprintf(credentials, sizeof(credentials), " with username %s", user);
01550
01551 if (ctimesec > 31536000) {
01552 ast_cli(a->fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n",
01553 status, credentials, ctimesec / 31536000,
01554 (ctimesec % 31536000) / 86400, (ctimesec % 86400) / 3600,
01555 (ctimesec % 3600) / 60, ctimesec % 60);
01556 } else if (ctimesec > 86400) {
01557 ast_cli(a->fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n",
01558 status, credentials, ctimesec / 86400, (ctimesec % 86400) / 3600,
01559 (ctimesec % 3600) / 60, ctimesec % 60);
01560 } else if (ctimesec > 3600) {
01561 ast_cli(a->fd, "%s%s for %d hours, %d minutes, %d seconds.\n",
01562 status, credentials, ctimesec / 3600, (ctimesec % 3600) / 60,
01563 ctimesec % 60);
01564 } else if (ctimesec > 60) {
01565 ast_cli(a->fd, "%s%s for %d minutes, %d seconds.\n", status, credentials,
01566 ctimesec / 60, ctimesec % 60);
01567 } else {
01568 ast_cli(a->fd, "%s%s for %d seconds.\n", status, credentials, ctimesec);
01569 }
01570
01571 return CLI_SUCCESS;
01572 }
01573
01574 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "LDAP realtime interface",
01575 .load = load_module,
01576 .unload = unload_module,
01577 .reload = reload,
01578 );