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: 201682 $")
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 basedn[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, 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);
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);
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 = 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);
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)) > 0) {
00587 ast_debug(3, "num_entry: %d\n", num_entry);
00588
00589 vars = realtime_ldap_result_to_vars(table_config, ldap_result, 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);
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 = 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);
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) > 0) {
00816
00817 vars = realtime_ldap_result_to_vars(table_config, ldap_result, 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);
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 ast_free(filter);
00875 ast_free(clean_basedn);
00876 ast_mutex_unlock(&ldap_lock);
00877
00878 return vars;
00879 }
00880
00881
00882 static struct ast_variable **realtime_ldap_base(unsigned int *entries_count_ptr,
00883 const char *basedn, const char *table_name, ...)
00884 {
00885 struct ast_variable **vars = NULL;
00886 va_list ap;
00887
00888 va_start(ap, table_name);
00889 vars = realtime_ldap_base_ap(entries_count_ptr, basedn, table_name, ap);
00890 va_end(ap);
00891
00892 return vars;
00893 }
00894
00895
00896
00897
00898
00899 static struct ast_variable *realtime_ldap(const char *basedn,
00900 const char *table_name, va_list ap)
00901 {
00902 struct ast_variable **vars = realtime_ldap_base_ap(NULL, basedn, table_name, ap);
00903 struct ast_variable *var = NULL;
00904
00905 if (vars) {
00906 struct ast_variable *last_var = NULL;
00907 struct ast_variable **p = vars;
00908 while (*p) {
00909 if (last_var) {
00910 while (last_var->next)
00911 last_var = last_var->next;
00912 last_var->next = *p;
00913 } else {
00914 var = *p;
00915 last_var = var;
00916 }
00917 p++;
00918 }
00919 free(vars);
00920 }
00921 return var;
00922 }
00923
00924
00925
00926
00927
00928
00929
00930
00931 static struct ast_config *realtime_multi_ldap(const char *basedn,
00932 const char *table_name, va_list ap)
00933 {
00934 struct ast_variable **vars =
00935 realtime_ldap_base_ap(NULL, basedn, table_name, ap);
00936 struct ast_config *cfg = NULL;
00937
00938 if (vars) {
00939 cfg = ast_config_new();
00940 if (!cfg) {
00941 ast_log(LOG_ERROR, "Unable to create a config!\n");
00942 } else {
00943 struct ast_variable **p = vars;
00944
00945 while (*p) {
00946 struct ast_category *cat = NULL;
00947 cat = ast_category_new("", table_name, -1);
00948 if (!cat) {
00949 ast_log(LOG_ERROR, "Unable to create a new category!\n");
00950 break;
00951 } else {
00952 struct ast_variable *var = *p;
00953 while (var) {
00954 struct ast_variable *next = var->next;
00955 var->next = NULL;
00956 ast_variable_append(cat, var);
00957 var = next;
00958 }
00959 }
00960 ast_category_append(cfg, cat);
00961 p++;
00962 }
00963 }
00964 free(vars);
00965 }
00966 return cfg;
00967
00968 }
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979 static int compare_categories(const void *a, const void *b)
00980 {
00981 const struct category_and_metric *as = a;
00982 const struct category_and_metric *bs = b;
00983
00984 if (as->metric < bs->metric)
00985 return -1;
00986 else if (as->metric > bs->metric)
00987 return 1;
00988 else if (as->metric == bs->metric && strcmp(as->name, bs->name) != 0)
00989 return strcmp(as->name, bs->name);
00990
00991
00992 if (as->var_metric < bs->var_metric)
00993 return -1;
00994 else if (as->var_metric > bs->var_metric)
00995 return 1;
00996
00997 return 0;
00998 }
00999
01000
01001
01002
01003
01004
01005
01006
01007 static struct ast_config *config_ldap(const char *basedn, const char *table_name,
01008 const char *file, struct ast_config *cfg, struct ast_flags config_flags, const char *sugg_incl, const char *who_asked)
01009 {
01010 unsigned int vars_count = 0;
01011 struct ast_variable **vars;
01012 int i = 0;
01013 struct ast_variable *new_v = NULL;
01014 struct ast_category *cur_cat = NULL;
01015 const char *last_category = NULL;
01016 int last_category_metric = 0;
01017 struct category_and_metric *categories;
01018 struct ast_variable **p;
01019
01020 if (ast_strlen_zero(file) || !strcasecmp(file, RES_CONFIG_LDAP_CONF)) {
01021 ast_log(LOG_ERROR, "Cannot configure myself.\n");
01022 return NULL;
01023 }
01024
01025 vars = realtime_ldap_base(&vars_count, basedn, table_name, "filename",
01026 file, "commented", "FALSE", NULL);
01027
01028 if (!vars) {
01029 ast_log(LOG_WARNING, "Could not find config '%s' in database.\n", file);
01030 return NULL;
01031 }
01032
01033
01034
01035
01036
01037 if (!(categories = ast_calloc(sizeof(*categories), vars_count)))
01038 return NULL;
01039
01040 for (vars_count = 0, p = vars; *p; p++) {
01041 struct ast_variable *category = variable_named(*p, "category");
01042 struct ast_variable *cat_metric = variable_named(*p, "cat_metric");
01043 struct ast_variable *var_name = variable_named(*p, "variable_name");
01044 struct ast_variable *var_val = variable_named(*p, "variable_value");
01045 struct ast_variable *var_metric = variable_named(*p, "var_metric");
01046 struct ast_variable *dn = variable_named(*p, "dn");
01047
01048 ast_debug(1, "category: %s\n", category->value);
01049 ast_debug(1, "var_name: %s\n", var_name->value);
01050 ast_debug(1, "var_val: %s\n", var_val->value);
01051 ast_debug(1, "cat_metric: %s\n", cat_metric->value);
01052
01053 if (!category) {
01054 ast_log(LOG_ERROR,
01055 "No category name in entry '%s' for file '%s'.\n",
01056 (dn ? dn->value : "?"), file);
01057 } else if (!cat_metric) {
01058 ast_log(LOG_ERROR,
01059 "No category metric in entry '%s'(category: %s) for file '%s'.\n",
01060 (dn ? dn->value : "?"), category->value, file);
01061 } else if (!var_metric) {
01062 ast_log(LOG_ERROR,
01063 "No variable metric in entry '%s'(category: %s) for file '%s'.\n",
01064 (dn ? dn->value : "?"), category->value, file);
01065 } else if (!var_name) {
01066 ast_log(LOG_ERROR,
01067 "No variable name in entry '%s' (category: %s metric: %s) for file '%s'.\n",
01068 (dn ? dn->value : "?"), category->value,
01069 cat_metric->value, file);
01070 } else if (!var_val) {
01071 ast_log(LOG_ERROR,
01072 "No variable value in entry '%s' (category: %s metric: %s variable: %s) for file '%s'.\n",
01073 (dn ? dn->value : "?"), category->value,
01074 cat_metric->value, var_name->value, file);
01075 } else {
01076 categories[vars_count].name = category->value;
01077 categories[vars_count].metric = atoi(cat_metric->value);
01078 categories[vars_count].variable_name = var_name->value;
01079 categories[vars_count].variable_value = var_val->value;
01080 categories[vars_count].var_metric = atoi(var_metric->value);
01081 vars_count++;
01082 }
01083 }
01084
01085 qsort(categories, vars_count, sizeof(*categories), compare_categories);
01086
01087 for (i = 0; i < vars_count; i++) {
01088 if (!strcmp(categories[i].variable_name, "#include")) {
01089 struct ast_flags config_flags = { 0 };
01090 if (!ast_config_internal_load(categories[i].variable_value, cfg, config_flags, "", who_asked))
01091 break;
01092 continue;
01093 }
01094
01095 if (!last_category || strcmp(last_category, categories[i].name) ||
01096 last_category_metric != categories[i].metric) {
01097 cur_cat = ast_category_new(categories[i].name, table_name, -1);
01098 if (!cur_cat)
01099 break;
01100 last_category = categories[i].name;
01101 last_category_metric = categories[i].metric;
01102 ast_category_append(cfg, cur_cat);
01103 }
01104
01105 if (!(new_v = ast_variable_new(categories[i].variable_name, categories[i].variable_value, table_name)))
01106 break;
01107
01108 ast_variable_append(cur_cat, new_v);
01109 }
01110
01111 free(vars);
01112 free(categories);
01113
01114 return cfg;
01115 }
01116
01117
01118
01119
01120 static int update_ldap(const char *basedn, const char *table_name, const char *attribute,
01121 const char *lookup, va_list ap)
01122 {
01123 int error = 0;
01124 LDAPMessage *ldap_entry = NULL;
01125 LDAPMod **ldap_mods;
01126 const char *newparam = NULL;
01127 const char *newval = NULL;
01128 char *dn;
01129 int num_entries = 0;
01130 int i = 0;
01131 int mods_size = 0;
01132 int mod_exists = 0;
01133 struct ldap_table_config *table_config = NULL;
01134 char *clean_basedn = NULL;
01135 struct ast_str *filter = NULL;
01136 int tries = 0;
01137 int result = 0;
01138 LDAPMessage *ldap_result = NULL;
01139
01140 if (!table_name) {
01141 ast_log(LOG_WARNING, "No table_name specified.\n");
01142 return -1;
01143 }
01144
01145 if (!(filter = ast_str_create(80)))
01146 return -1;
01147
01148 if (!attribute || !lookup) {
01149 ast_log(LOG_WARNING,
01150 "LINE(%d): search parameters are empty.\n", __LINE__);
01151 return -1;
01152 }
01153 ast_mutex_lock(&ldap_lock);
01154
01155
01156 if (!ldap_reconnect()) {
01157 ast_mutex_unlock(&ldap_lock);
01158 return -1;
01159 }
01160
01161 table_config = table_config_for_table_name(table_name);
01162 if (!table_config) {
01163 ast_log(LOG_WARNING, "No table named '%s'.\n", table_name);
01164 ast_mutex_unlock(&ldap_lock);
01165 return -1;
01166 }
01167
01168 clean_basedn = cleaned_basedn(NULL, basedn);
01169
01170
01171 ast_str_append(&filter, 0, "(&");
01172 if (table_config && table_config->additional_filter) {
01173 ast_str_append(&filter, 0, "%s", table_config->additional_filter);
01174 }
01175 if (table_config != base_table_config && base_table_config
01176 && base_table_config->additional_filter) {
01177 ast_str_append(&filter, 0, "%s", base_table_config->additional_filter);
01178 }
01179 append_var_and_value_to_filter(&filter, table_config, attribute, lookup);
01180 ast_str_append(&filter, 0, ")");
01181
01182
01183
01184
01185 newparam = va_arg(ap, const char *);
01186 newparam = convert_attribute_name_to_ldap(table_config, newparam);
01187 newval = va_arg(ap, const char *);
01188 if (!newparam || !newval) {
01189 ast_log(LOG_WARNING,
01190 "LINE(%d): need at least one parameter to modify.\n", __LINE__);
01191 return -1;
01192 }
01193
01194 mods_size = 2;
01195 ldap_mods = ast_calloc(sizeof(LDAPMod *), mods_size);
01196 ldap_mods[0] = ast_calloc(1, sizeof(LDAPMod));
01197
01198 ldap_mods[0]->mod_op = LDAP_MOD_REPLACE;
01199 ldap_mods[0]->mod_type = ast_calloc(sizeof(char), strlen(newparam) + 1);
01200 strcpy(ldap_mods[0]->mod_type, newparam);
01201
01202 ldap_mods[0]->mod_values = ast_calloc(sizeof(char), 2);
01203 ldap_mods[0]->mod_values[0] = ast_calloc(sizeof(char), strlen(newval) + 1);
01204 strcpy(ldap_mods[0]->mod_values[0], newval);
01205
01206 while ((newparam = va_arg(ap, const char *))) {
01207 newparam = convert_attribute_name_to_ldap(table_config, newparam);
01208 newval = va_arg(ap, const char *);
01209 mod_exists = 0;
01210
01211 for (i = 0; i < mods_size - 1; i++) {
01212 if (ldap_mods[i]&& !strcmp(ldap_mods[i]->mod_type, newparam)) {
01213
01214 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));
01215 strcat(ldap_mods[i]->mod_values[0], ";");
01216 strcat(ldap_mods[i]->mod_values[0], newval);
01217 mod_exists = 1;
01218 break;
01219 }
01220 }
01221
01222
01223 if (!mod_exists) {
01224 mods_size++;
01225 ldap_mods = ast_realloc(ldap_mods, sizeof(LDAPMod *) * mods_size);
01226 ldap_mods[mods_size - 1] = NULL;
01227 ldap_mods[mods_size - 2] = ast_calloc(1, sizeof(LDAPMod));
01228
01229 ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_REPLACE;
01230
01231 ldap_mods[mods_size - 2]->mod_type = ast_calloc(sizeof(char), strlen(newparam) + 1);
01232 strcpy(ldap_mods[mods_size - 2]->mod_type, newparam);
01233
01234 ldap_mods[mods_size - 2]->mod_values = ast_calloc(sizeof(char *), 2);
01235 ldap_mods[mods_size - 2]->mod_values[0] = ast_calloc(sizeof(char), strlen(newval) + 1);
01236 strcpy(ldap_mods[mods_size - 2]->mod_values[0], newval);
01237 }
01238 }
01239
01240
01241 do {
01242
01243 result = ldap_search_ext_s(ldapConn, clean_basedn,
01244 LDAP_SCOPE_SUBTREE, filter->str, NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
01245 &ldap_result);
01246 if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
01247 ast_log(LOG_WARNING, "Failed to query database. Try %d/3\n",
01248 tries + 1);
01249 tries++;
01250 if (tries < 3) {
01251 usleep(500000L * tries);
01252 if (ldapConn) {
01253 ldap_unbind_ext_s(ldapConn, NULL, NULL);
01254 ldapConn = NULL;
01255 }
01256 if (!ldap_reconnect())
01257 break;
01258 }
01259 }
01260 } while (result != LDAP_SUCCESS && tries < 3 && is_ldap_connect_error(result));
01261
01262 if (result != LDAP_SUCCESS) {
01263 ast_log(LOG_WARNING, "Failed to query directory. Check debug for more info.\n");
01264 ast_log(LOG_WARNING, "Query: %s\n", filter->str);
01265 ast_log(LOG_WARNING, "Query Failed because: %s\n",
01266 ldap_err2string(result));
01267
01268 ast_mutex_unlock(&ldap_lock);
01269 free(filter);
01270 free(clean_basedn);
01271 ldap_msgfree(ldap_result);
01272 ldap_mods_free(ldap_mods, 0);
01273 return -1;
01274 }
01275
01276 if ((num_entries = ldap_count_entries(ldapConn, ldap_result)) > 0) {
01277 ast_debug(3, "LINE(%d) Modifying %s=%s hits: %d\n", __LINE__, attribute, lookup, num_entries);
01278 for (i = 0; option_debug > 2 && i < mods_size - 1; i++)
01279 ast_debug(3, "LINE(%d) %s=%s \n", __LINE__, ldap_mods[i]->mod_type, ldap_mods[i]->mod_values[0]);
01280
01281 ldap_entry = ldap_first_entry(ldapConn, ldap_result);
01282
01283 for (i = 0; ldap_entry; i++) {
01284 dn = ldap_get_dn(ldapConn, ldap_entry);
01285 if ((error = ldap_modify_ext_s(ldapConn, dn, ldap_mods, NULL, NULL)) != LDAP_SUCCESS)
01286 ast_log(LOG_ERROR, "Couldn't modify dn:%s because %s", dn, ldap_err2string(error));
01287
01288 ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
01289 }
01290 }
01291
01292 ast_mutex_unlock(&ldap_lock);
01293 free(filter);
01294 free(clean_basedn);
01295 ldap_msgfree(ldap_result);
01296 ldap_mods_free(ldap_mods, 0);
01297 return num_entries;
01298 }
01299
01300 static struct ast_config_engine ldap_engine = {
01301 .name = "ldap",
01302 .load_func = config_ldap,
01303 .realtime_func = realtime_ldap,
01304 .realtime_multi_func = realtime_multi_ldap,
01305 .update_func = update_ldap
01306 };
01307
01308 static int load_module(void)
01309 {
01310 if (parse_config() < 0) {
01311 ast_log(LOG_NOTICE, "Cannot load LDAP RealTime driver.\n");
01312 return 0;
01313 }
01314
01315 ast_mutex_lock(&ldap_lock);
01316
01317 if (!ldap_reconnect())
01318 ast_log(LOG_WARNING, "Couldn't establish connection. Check debug.\n");
01319
01320 ast_config_engine_register(&ldap_engine);
01321 ast_verb(1, "LDAP RealTime driver loaded.\n");
01322 ast_cli_register_multiple(ldap_cli, sizeof(ldap_cli) / sizeof(struct ast_cli_entry));
01323
01324 ast_mutex_unlock(&ldap_lock);
01325
01326 return 0;
01327 }
01328
01329 static int unload_module(void)
01330 {
01331
01332 ast_mutex_lock(&ldap_lock);
01333
01334 table_configs_free();
01335
01336 if (ldapConn) {
01337 ldap_unbind_ext_s(ldapConn, NULL, NULL);
01338 ldapConn = NULL;
01339 }
01340 ast_cli_unregister_multiple(ldap_cli, sizeof(ldap_cli) / sizeof(struct ast_cli_entry));
01341 ast_config_engine_deregister(&ldap_engine);
01342 ast_verb(1, "LDAP RealTime unloaded.\n");
01343
01344
01345 ast_mutex_unlock(&ldap_lock);
01346
01347 return 0;
01348 }
01349
01350 static int reload(void)
01351 {
01352
01353 ast_mutex_lock(&ldap_lock);
01354
01355 if (ldapConn) {
01356 ldap_unbind_ext_s(ldapConn, NULL, NULL);
01357 ldapConn = NULL;
01358 }
01359
01360 if (parse_config() < 0) {
01361 ast_log(LOG_NOTICE, "Cannot reload LDAP RealTime driver.\n");
01362 ast_mutex_unlock(&ldap_lock);
01363 return 0;
01364 }
01365
01366 if (!ldap_reconnect())
01367 ast_log(LOG_WARNING, "Couldn't establish connection. Check debug.\n");
01368
01369 ast_verb(2, "LDAP RealTime reloaded.\n");
01370
01371
01372 ast_mutex_unlock(&ldap_lock);
01373
01374 return 0;
01375 }
01376
01377 int parse_config(void)
01378 {
01379 struct ast_config *config;
01380 struct ast_flags config_flags = {0};
01381 const char *s, *host;
01382 int port;
01383 char *category_name = NULL;
01384
01385 config = ast_config_load(RES_CONFIG_LDAP_CONF, config_flags);
01386
01387 if (!config) {
01388 ast_log(LOG_WARNING, "Cannot load configuration %s\n", RES_CONFIG_LDAP_CONF);
01389 return -1;
01390 }
01391
01392 if (!(s = ast_variable_retrieve(config, "_general", "user"))) {
01393 ast_log(LOG_WARNING, "No directory user found, anonymous binding as default.\n");
01394 user[0] = '\0';
01395 } else
01396 ast_copy_string(user, s, sizeof(user));
01397
01398 if (!ast_strlen_zero(user)) {
01399 if (!(s = ast_variable_retrieve(config, "_general", "pass"))) {
01400 ast_log(LOG_WARNING, "No directory password found, using 'asterisk' as default.\n");
01401 ast_copy_string(pass, "asterisk", sizeof(pass));
01402 } else {
01403 ast_copy_string(pass, s, sizeof(pass));
01404 }
01405 }
01406
01407
01408 if ((s = ast_variable_retrieve(config, "_general", "url"))) {
01409 ast_copy_string(url, s, sizeof(url));
01410 } else if ((host = ast_variable_retrieve(config, "_general", "host"))) {
01411 if (!(s = ast_variable_retrieve(config, "_general", "port")) || sscanf(s, "%d", &port) != 1) {
01412 ast_log(LOG_NOTICE, "No directory port found, using 389 as default.\n");
01413 port = 389;
01414 }
01415
01416 snprintf(url, sizeof(url), "ldap://%s:%d", host, port);
01417 } else {
01418 ast_log(LOG_ERROR, "No directory URL or host found.\n");
01419 ast_config_destroy(config);
01420 return -1;
01421 }
01422
01423 if (!(s = ast_variable_retrieve(config, "_general", "basedn"))) {
01424 ast_log(LOG_ERROR, "No LDAP base dn found, using '%s' as default.\n", RES_CONFIG_LDAP_DEFAULT_BASEDN);
01425 ast_copy_string(basedn, RES_CONFIG_LDAP_DEFAULT_BASEDN, sizeof(basedn));
01426 } else
01427 ast_copy_string(basedn, s, sizeof(basedn));
01428
01429 if (!(s = ast_variable_retrieve(config, "_general", "version")) && !(s = ast_variable_retrieve(config, "_general", "protocol"))) {
01430 ast_log(LOG_NOTICE, "No explicit LDAP version found, using 3 as default.\n");
01431 version = 3;
01432 } else if (sscanf(s, "%d", &version) != 1 || version < 1 || version > 6) {
01433 ast_log(LOG_WARNING, "Invalid LDAP version '%s', using 3 as default.\n", s);
01434 version = 3;
01435 }
01436
01437 table_configs_free();
01438
01439 while ((category_name = ast_category_browse(config, category_name))) {
01440 int is_general = (strcasecmp(category_name, "_general") == 0);
01441 int is_config = (strcasecmp(category_name, "config") == 0);
01442 struct ast_variable *var = ast_variable_browse(config, category_name);
01443
01444 if (var) {
01445 struct ldap_table_config *table_config =
01446 table_config_for_table_name(category_name);
01447 if (!table_config) {
01448 table_config = table_config_new(category_name);
01449 AST_LIST_INSERT_HEAD(&table_configs, table_config, entry);
01450 if (is_general)
01451 base_table_config = table_config;
01452 if (is_config)
01453 static_table_config = table_config;
01454 }
01455 for (; var; var = var->next) {
01456 if (!strcasecmp(var->name, "additionalFilter")) {
01457 table_config->additional_filter = ast_strdup(var->value);
01458 } else {
01459 ldap_table_config_add_attribute(table_config, var->name, var->value);
01460 }
01461 }
01462 }
01463 }
01464
01465 ast_config_destroy(config);
01466
01467 return 1;
01468 }
01469
01470
01471 static int ldap_reconnect(void)
01472 {
01473 int bind_result = 0;
01474 struct berval cred;
01475
01476 if (ldapConn) {
01477 ast_debug(2, "Everything seems fine.\n");
01478 return 1;
01479 }
01480
01481 if (ast_strlen_zero(url)) {
01482 ast_log(LOG_ERROR, "Not enough parameters to connect to ldap database\n");
01483 return 0;
01484 }
01485
01486 if (LDAP_SUCCESS != ldap_initialize(&ldapConn, url)) {
01487 ast_log(LOG_ERROR, "Failed to init ldap connection to '%s'. Check debug for more info.\n", url);
01488 return 0;
01489 }
01490
01491 if (LDAP_OPT_SUCCESS != ldap_set_option(ldapConn, LDAP_OPT_PROTOCOL_VERSION, &version)) {
01492 ast_log(LOG_WARNING, "Unable to set LDAP protocol version to %d, falling back to default.\n", version);
01493 }
01494
01495 if (!ast_strlen_zero(user)) {
01496 ast_debug(2, "bind to '%s' as user '%s'\n", url, user);
01497 cred.bv_val = (char *) pass;
01498 cred.bv_len = strlen(pass);
01499 bind_result = ldap_sasl_bind_s(ldapConn, user, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
01500 } else {
01501 ast_debug(2, "bind %s anonymously\n", url);
01502 cred.bv_val = NULL;
01503 cred.bv_len = 0;
01504 bind_result = ldap_sasl_bind_s(ldapConn, NULL, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
01505 }
01506 if (bind_result == LDAP_SUCCESS) {
01507 ast_debug(2, "Successfully connected to database.\n");
01508 connect_time = time(NULL);
01509 return 1;
01510 } else {
01511 ast_log(LOG_WARNING, "bind failed: %s\n", ldap_err2string(bind_result));
01512 ldap_unbind_ext_s(ldapConn, NULL, NULL);
01513 ldapConn = NULL;
01514 return 0;
01515 }
01516 }
01517
01518 static char *realtime_ldap_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01519 {
01520 char status[256], credentials[100] = "";
01521 int ctime = time(NULL) - connect_time;
01522
01523 switch (cmd) {
01524 case CLI_INIT:
01525 e->command = "realtime ldap status";
01526 e->usage =
01527 "Usage: realtime ldap status\n"
01528 " Shows connection information for the LDAP RealTime driver\n";
01529 return NULL;
01530 case CLI_GENERATE:
01531 return NULL;
01532 }
01533
01534 if (!ldapConn)
01535 return CLI_FAILURE;
01536
01537 if (!ast_strlen_zero(url))
01538 snprintf(status, sizeof(status), "Connected to '%s', baseDN %s", url, basedn);
01539
01540 if (!ast_strlen_zero(user))
01541 snprintf(credentials, sizeof(credentials), " with username %s", user);
01542
01543 if (ctime > 31536000) {
01544 ast_cli(a->fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n",
01545 status, credentials, ctime / 31536000,
01546 (ctime % 31536000) / 86400, (ctime % 86400) / 3600,
01547 (ctime % 3600) / 60, ctime % 60);
01548 } else if (ctime > 86400) {
01549 ast_cli(a->fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n",
01550 status, credentials, ctime / 86400, (ctime % 86400) / 3600,
01551 (ctime % 3600) / 60, ctime % 60);
01552 } else if (ctime > 3600) {
01553 ast_cli(a->fd, "%s%s for %d hours, %d minutes, %d seconds.\n",
01554 status, credentials, ctime / 3600, (ctime % 3600) / 60,
01555 ctime % 60);
01556 } else if (ctime > 60) {
01557 ast_cli(a->fd, "%s%s for %d minutes, %d seconds.\n", status, credentials,
01558 ctime / 60, ctime % 60);
01559 } else {
01560 ast_cli(a->fd, "%s%s for %d seconds.\n", status, credentials, ctime);
01561 }
01562
01563 return CLI_SUCCESS;
01564 }
01565
01566 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "LDAP realtime interface",
01567 .load = load_module,
01568 .unload = unload_module,
01569 .reload = reload,
01570 );