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: 240279 $")
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 struct ast_variable *tmp = realtime_ldap_entry_to_var(table_config, ldap_entry);
00368 tot_count += semicolon_count_var(tmp);
00369 ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
00370 ast_variables_destroy(tmp);
00371 }
00372
00373 if (entries_count_ptr)
00374 *entries_count_ptr = tot_count;
00375
00376
00377
00378
00379
00380 vars = ast_calloc(sizeof(struct ast_variable *), tot_count + 1);
00381
00382 ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
00383
00384 i = 0;
00385
00386
00387 for (entry_index = 0; ldap_entry; ) {
00388 int pos = 0;
00389 delim_value = NULL;
00390 delim_tot_count = 0;
00391 delim_count = 0;
00392
00393 do {
00394
00395
00396 char *ldap_attribute_name = ldap_first_attribute(ldapConn, ldap_entry, &ber);
00397 struct berval *value;
00398 while (ldap_attribute_name) {
00399
00400 const char *attribute_name =
00401 convert_attribute_name_from_ldap(table_config, ldap_attribute_name);
00402 int is_realmed_password_attribute = strcasecmp(attribute_name, "md5secret") == 0;
00403 struct berval **values = NULL;
00404
00405 values = ldap_get_values_len(ldapConn, ldap_entry, ldap_attribute_name);
00406 if (values) {
00407 struct berval **v;
00408 char *valptr;
00409
00410 for (v = values; *v; v++) {
00411 value = *v;
00412 valptr = value->bv_val;
00413 if (is_realmed_password_attribute) {
00414 if (strncasecmp(valptr, "{md5}", 5) == 0) {
00415 valptr += 5;
00416 } else {
00417 valptr = NULL;
00418 }
00419 ast_debug(2, "md5: %s\n", valptr);
00420 }
00421 if (valptr) {
00422 if (delim_value == NULL
00423 && !is_realmed_password_attribute
00424 && (static_table_config != table_config || strcmp(attribute_name, "variable_value") == 0)) {
00425
00426 delim_value = ast_strdup(valptr);
00427
00428 if ((delim_tot_count = semicolon_count_str(delim_value)) > 0) {
00429 ast_debug(4, "LINE(%d) is delimited %d times: %s\n", __LINE__, delim_tot_count, delim_value);
00430 is_delimited = 1;
00431 }
00432 }
00433
00434 if (is_delimited != 0
00435 && !is_realmed_password_attribute
00436 && (static_table_config != table_config || strcmp(attribute_name, "variable_value") == 0) ) {
00437
00438
00439 for (i = pos; !ast_strlen_zero(valptr + i); i++) {
00440 ast_debug(4, "LINE(%d) DELIM pos: %d i: %d\n", __LINE__, pos, i);
00441 if (delim_value[i] == ';') {
00442 delim_value[i] = '\0';
00443
00444 ast_debug(2, "LINE(%d) DELIM - attribute_name: %s value: %s pos: %d\n", __LINE__, attribute_name, &delim_value[pos], pos);
00445
00446 if (prev) {
00447 prev->next = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name);
00448 if (prev->next) {
00449 prev = prev->next;
00450 }
00451 } else {
00452 prev = var = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name);
00453 }
00454 pos = i + 1;
00455
00456 if (static_table_config == table_config) {
00457 break;
00458 }
00459 }
00460 }
00461 if (ast_strlen_zero(valptr + i)) {
00462 ast_debug(4, "LINE(%d) DELIM pos: %d i: %d delim_count: %d\n", __LINE__, pos, i, delim_count);
00463
00464 ast_debug(4, "LINE(%d) DELIM - attribute_name: %s value: %s pos: %d\n", __LINE__, attribute_name, &delim_value[pos], pos);
00465 if (prev) {
00466 prev->next = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name);
00467 if (prev->next) {
00468 prev = prev->next;
00469 }
00470 } else {
00471 prev = var = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name);
00472 }
00473
00474 is_delimited = 0;
00475 pos = 0;
00476 }
00477 free(delim_value);
00478 delim_value = NULL;
00479
00480 ast_debug(4, "LINE(%d) DELIM pos: %d i: %d\n", __LINE__, pos, i);
00481 } else {
00482
00483 if (delim_value) {
00484 free(delim_value);
00485 delim_value = NULL;
00486 }
00487 ast_debug(2, "LINE(%d) attribute_name: %s value: %s\n", __LINE__, attribute_name, valptr);
00488
00489 if (prev) {
00490 prev->next = ast_variable_new(attribute_name, valptr, table_config->table_name);
00491 if (prev->next) {
00492 prev = prev->next;
00493 }
00494 } else {
00495 prev = var = ast_variable_new(attribute_name, valptr, table_config->table_name);
00496 }
00497 }
00498 }
00499 }
00500 ldap_value_free_len(values);
00501 }
00502 ldap_attribute_name = ldap_next_attribute(ldapConn, ldap_entry, ber);
00503 }
00504 ber_free(ber, 0);
00505 if (static_table_config == table_config) {
00506 if (option_debug > 2) {
00507 const struct ast_variable *tmpdebug = variable_named(var, "variable_name");
00508 const struct ast_variable *tmpdebug2 = variable_named(var, "variable_value");
00509 if (tmpdebug && tmpdebug2) {
00510 ast_debug(3, "LINE(%d) Added to vars - %s = %s\n", __LINE__, tmpdebug->value, tmpdebug2->value);
00511 }
00512 }
00513 vars[entry_index++] = var;
00514 prev = NULL;
00515 }
00516
00517 delim_count++;
00518 } while (delim_count <= delim_tot_count && static_table_config == table_config);
00519
00520 if (static_table_config != table_config) {
00521 ast_debug(3, "LINE(%d) Added to vars - non static\n", __LINE__);
00522
00523 vars[entry_index++] = var;
00524 prev = NULL;
00525 }
00526 ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
00527 }
00528
00529 return vars;
00530 }
00531
00532
00533 static int is_ldap_connect_error(int err)
00534 {
00535 return (err == LDAP_SERVER_DOWN
00536 || err == LDAP_TIMEOUT || err == LDAP_CONNECT_ERROR);
00537 }
00538
00539
00540
00541
00542 static struct ast_variable *ldap_loadentry(struct ldap_table_config *table_config,
00543 const char *dn)
00544 {
00545 if (!table_config) {
00546 ast_log(LOG_ERROR, "No table config\n");
00547 return NULL;
00548 } else {
00549 struct ast_variable **vars = NULL;
00550 struct ast_variable *var = NULL;
00551 int result = -1;
00552 LDAPMessage *ldap_result_msg = NULL;
00553 int tries = 0;
00554
00555 ast_debug(2, "ldap_loadentry dn=%s\n", dn);
00556
00557 do {
00558 result = ldap_search_ext_s(ldapConn, dn, LDAP_SCOPE_BASE,
00559 "(objectclass=*)", NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &ldap_result_msg);
00560 if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
00561 ast_log(LOG_WARNING,
00562 "Failed to query database. Try %d/3\n",
00563 tries + 1);
00564 tries++;
00565 if (tries < 3) {
00566 usleep(500000L * tries);
00567 if (ldapConn) {
00568 ldap_unbind_ext_s(ldapConn, NULL, NULL);
00569 ldapConn = NULL;
00570 }
00571 if (!ldap_reconnect())
00572 break;
00573 }
00574 }
00575 } while (result != LDAP_SUCCESS && tries < 3 && is_ldap_connect_error(result));
00576
00577 if (result != LDAP_SUCCESS) {
00578 ast_log(LOG_WARNING,
00579 "Failed to query database. Check debug for more info.\n");
00580 ast_debug(2, "dn=%s\n", dn);
00581 ast_debug(2, "Query Failed because: %s\n",
00582 ldap_err2string(result));
00583 ast_mutex_unlock(&ldap_lock);
00584 return NULL;
00585 } else {
00586 int num_entry = 0;
00587 unsigned int *entries_count_ptr = NULL;
00588 if ((num_entry = ldap_count_entries(ldapConn, ldap_result_msg)) > 0) {
00589 ast_debug(3, "num_entry: %d\n", num_entry);
00590
00591 vars = realtime_ldap_result_to_vars(table_config, ldap_result_msg, entries_count_ptr);
00592 if (num_entry > 1)
00593 ast_log(LOG_NOTICE, "More than one entry for dn=%s. Take only 1st one\n", dn);
00594 } else {
00595 ast_debug(2, "Could not find any entry dn=%s.\n", dn);
00596 }
00597 }
00598 ldap_msgfree(ldap_result_msg);
00599
00600
00601 if (vars != NULL) {
00602 struct ast_variable **p = vars;
00603 p++;
00604 var = *p;
00605 while (var) {
00606 ast_variables_destroy(var);
00607 p++;
00608 }
00609 vars = ast_realloc(vars, sizeof(struct ast_variable *));
00610 }
00611
00612 var = *vars;
00613
00614 return var;
00615 }
00616 }
00617
00618
00619 static char *substituted(struct ast_channel *channel, const char *string)
00620 {
00621 #define MAXRESULT 2048
00622 char *ret_string = NULL;
00623
00624 if (!ast_strlen_zero(string)) {
00625 ret_string = ast_calloc(1, MAXRESULT);
00626 pbx_substitute_variables_helper(channel, string, ret_string, MAXRESULT - 1);
00627 }
00628 ast_debug(2, "substituted: string: '%s' => '%s' \n",
00629 string, ret_string);
00630 return ret_string;
00631 }
00632
00633
00634 static char *cleaned_basedn(struct ast_channel *channel, const char *basedn)
00635 {
00636 char *cbasedn = NULL;
00637 if (basedn) {
00638 char *p = NULL;
00639 cbasedn = substituted(channel, basedn);
00640 if (*cbasedn == '"') {
00641 cbasedn++;
00642 if (!ast_strlen_zero(cbasedn)) {
00643 int len = strlen(cbasedn);
00644 if (cbasedn[len - 1] == '"')
00645 cbasedn[len - 1] = '\0';
00646
00647 }
00648 }
00649 p = cbasedn;
00650 while (*p) {
00651 if (*p == '|')
00652 *p = ',';
00653 p++;
00654 }
00655 }
00656 ast_debug(2, "basedn: '%s' => '%s' \n", basedn, cbasedn);
00657 return cbasedn;
00658 }
00659
00660
00661 static int replace_string_in_string(char *string, const char *search, const char *by)
00662 {
00663 int search_len = strlen(search);
00664 int by_len = strlen(by);
00665 int replaced = 0;
00666 char *p = strstr(string, search);
00667 if (p) {
00668 replaced = 1;
00669 while (p) {
00670 if (by_len == search_len)
00671 memcpy(p, by, by_len);
00672 else {
00673 memmove(p + by_len, p + search_len,
00674 strlen(p + search_len) + 1);
00675 memcpy(p, by, by_len);
00676 }
00677 p = strstr(p + by_len, search);
00678 }
00679 }
00680 return replaced;
00681 }
00682
00683
00684 static void append_var_and_value_to_filter(struct ast_str **filter,
00685 struct ldap_table_config *table_config,
00686 const char *name, const char *value)
00687 {
00688 char *new_name = NULL;
00689 char *new_value = NULL;
00690 char *like_pos = strstr(name, " LIKE");
00691
00692 ast_debug(2, "name='%s' value='%s'\n", name, value);
00693
00694 if (like_pos) {
00695 int len = like_pos - name;
00696 name = new_name = ast_strdupa(name);
00697 new_name[len] = '\0';
00698 value = new_value = ast_strdupa(value);
00699 replace_string_in_string(new_value, "\\_", "_");
00700 replace_string_in_string(new_value, "%", "*");
00701 }
00702
00703 name = convert_attribute_name_to_ldap(table_config, name);
00704
00705 ast_str_append(filter, 0, "(%s=%s)", name, value);
00706 }
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716 static struct ast_variable **realtime_ldap_base_ap(unsigned int *entries_count_ptr,
00717 const char *basedn, const char *table_name, va_list ap)
00718 {
00719 struct ast_variable **vars = NULL;
00720 const char *newparam = NULL;
00721 const char *newval = NULL;
00722 struct ldap_table_config *table_config = NULL;
00723 char *clean_basedn = cleaned_basedn(NULL, basedn);
00724 struct ast_str *filter = NULL;
00725 int tries = 0;
00726 int result = 0;
00727 LDAPMessage *ldap_result_msg = NULL;
00728
00729 if (!table_name) {
00730 ast_log(LOG_WARNING, "No table_name specified.\n");
00731 ast_free(clean_basedn);
00732 return NULL;
00733 }
00734
00735 if (!(filter = ast_str_create(80))) {
00736 ast_free(clean_basedn);
00737 return NULL;
00738 }
00739
00740
00741 newparam = va_arg(ap, const char *);
00742 newval = va_arg(ap, const char *);
00743
00744 if (!newparam || !newval) {
00745 ast_log(LOG_WARNING, "Realtime retrieval requires at least 1 parameter"
00746 " and 1 value to search on.\n");
00747 ast_free(filter);
00748 ast_free(clean_basedn);
00749 return NULL;
00750 }
00751
00752 ast_mutex_lock(&ldap_lock);
00753
00754
00755 if (!ldap_reconnect()) {
00756 ast_mutex_unlock(&ldap_lock);
00757 ast_free(filter);
00758 ast_free(clean_basedn);
00759 return NULL;
00760 }
00761
00762 table_config = table_config_for_table_name(table_name);
00763 if (!table_config) {
00764 ast_log(LOG_WARNING, "No table named '%s'.\n", table_name);
00765 ast_mutex_unlock(&ldap_lock);
00766 ast_free(filter);
00767 ast_free(clean_basedn);
00768 return NULL;
00769 }
00770
00771 ast_str_append(&filter, 0, "(&");
00772
00773 if (table_config && table_config->additional_filter)
00774 ast_str_append(&filter, 0, "%s", table_config->additional_filter);
00775 if (table_config != base_table_config && base_table_config &&
00776 base_table_config->additional_filter) {
00777 ast_str_append(&filter, 0, "%s", base_table_config->additional_filter);
00778 }
00779
00780
00781
00782
00783 append_var_and_value_to_filter(&filter, table_config, newparam, newval);
00784 while ((newparam = va_arg(ap, const char *))) {
00785 newval = va_arg(ap, const char *);
00786 append_var_and_value_to_filter(&filter, table_config, newparam, newval);
00787 }
00788 ast_str_append(&filter, 0, ")");
00789
00790 do {
00791
00792 result = ldap_search_ext_s(ldapConn, clean_basedn,
00793 LDAP_SCOPE_SUBTREE, filter->str, NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
00794 &ldap_result_msg);
00795 if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
00796 ast_log(LOG_DEBUG, "Failed to query database. Try %d/10\n",
00797 tries + 1);
00798 if (++tries < 10) {
00799 usleep(1);
00800 if (ldapConn) {
00801 ldap_unbind_ext_s(ldapConn, NULL, NULL);
00802 ldapConn = NULL;
00803 }
00804 if (!ldap_reconnect())
00805 break;
00806 }
00807 }
00808 } while (result != LDAP_SUCCESS && tries < 10 && is_ldap_connect_error(result));
00809
00810 if (result != LDAP_SUCCESS) {
00811 ast_log(LOG_WARNING, "Failed to query database. Check debug for more info.\n");
00812 ast_log(LOG_WARNING, "Query: %s\n", filter->str);
00813 ast_log(LOG_WARNING, "Query Failed because: %s\n", ldap_err2string(result));
00814 } else {
00815
00816
00817 if (ldap_count_entries(ldapConn, ldap_result_msg) > 0) {
00818
00819 vars = realtime_ldap_result_to_vars(table_config, ldap_result_msg, entries_count_ptr);
00820 } else {
00821 ast_debug(1, "Could not find any entry matching %s in base dn %s.\n",
00822 filter->str, clean_basedn);
00823 }
00824
00825 ldap_msgfree(ldap_result_msg);
00826
00827
00828 if (vars) {
00829 struct ast_variable **p = vars;
00830 while (*p) {
00831 struct ast_variable *append_var = NULL;
00832 struct ast_variable *tmp = *p;
00833 while (tmp) {
00834 if (strcasecmp(tmp->name, "accountBaseDN") == 0) {
00835
00836 struct ast_variable *base_var = ldap_loadentry(table_config, tmp->value);
00837
00838 while (base_var) {
00839 struct ast_variable *next = base_var->next;
00840 struct ast_variable *test_var = *p;
00841 int base_var_found = 0;
00842
00843
00844 while (test_var) {
00845 if (strcasecmp(test_var->name, base_var->name) == 0) {
00846 base_var_found = 1;
00847 break;
00848 } else
00849 test_var = test_var->next;
00850 }
00851 if (base_var_found) {
00852 base_var->next = NULL;
00853 ast_variables_destroy(base_var);
00854 base_var = next;
00855 } else {
00856 if (append_var)
00857 base_var->next = append_var;
00858 else
00859 base_var->next = NULL;
00860 append_var = base_var;
00861 base_var = next;
00862 }
00863 }
00864 }
00865 if (!tmp->next && append_var) {
00866 tmp->next = append_var;
00867 tmp = NULL;
00868 } else
00869 tmp = tmp->next;
00870 }
00871 p++;
00872 }
00873 }
00874 }
00875
00876 ast_free(filter);
00877 ast_free(clean_basedn);
00878 ast_mutex_unlock(&ldap_lock);
00879
00880 return vars;
00881 }
00882
00883
00884 static struct ast_variable **realtime_ldap_base(unsigned int *entries_count_ptr,
00885 const char *basedn, const char *table_name, ...)
00886 {
00887 struct ast_variable **vars = NULL;
00888 va_list ap;
00889
00890 va_start(ap, table_name);
00891 vars = realtime_ldap_base_ap(entries_count_ptr, basedn, table_name, ap);
00892 va_end(ap);
00893
00894 return vars;
00895 }
00896
00897
00898
00899
00900
00901 static struct ast_variable *realtime_ldap(const char *basedn,
00902 const char *table_name, va_list ap)
00903 {
00904 struct ast_variable **vars = realtime_ldap_base_ap(NULL, basedn, table_name, ap);
00905 struct ast_variable *var = NULL;
00906
00907 if (vars) {
00908 struct ast_variable *last_var = NULL;
00909 struct ast_variable **p = vars;
00910 while (*p) {
00911 if (last_var) {
00912 while (last_var->next)
00913 last_var = last_var->next;
00914 last_var->next = *p;
00915 } else {
00916 var = *p;
00917 last_var = var;
00918 }
00919 p++;
00920 }
00921 free(vars);
00922 }
00923 return var;
00924 }
00925
00926
00927
00928
00929
00930
00931
00932
00933 static struct ast_config *realtime_multi_ldap(const char *basedn,
00934 const char *table_name, va_list ap)
00935 {
00936 struct ast_variable **vars =
00937 realtime_ldap_base_ap(NULL, basedn, table_name, ap);
00938 struct ast_config *cfg = NULL;
00939
00940 if (vars) {
00941 cfg = ast_config_new();
00942 if (!cfg) {
00943 ast_log(LOG_ERROR, "Unable to create a config!\n");
00944 } else {
00945 struct ast_variable **p = vars;
00946
00947 while (*p) {
00948 struct ast_category *cat = NULL;
00949 cat = ast_category_new("", table_name, -1);
00950 if (!cat) {
00951 ast_log(LOG_ERROR, "Unable to create a new category!\n");
00952 break;
00953 } else {
00954 struct ast_variable *var = *p;
00955 while (var) {
00956 struct ast_variable *next = var->next;
00957 var->next = NULL;
00958 ast_variable_append(cat, var);
00959 var = next;
00960 }
00961 }
00962 ast_category_append(cfg, cat);
00963 p++;
00964 }
00965 }
00966 free(vars);
00967 }
00968 return cfg;
00969
00970 }
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981 static int compare_categories(const void *a, const void *b)
00982 {
00983 const struct category_and_metric *as = a;
00984 const struct category_and_metric *bs = b;
00985
00986 if (as->metric < bs->metric)
00987 return -1;
00988 else if (as->metric > bs->metric)
00989 return 1;
00990 else if (as->metric == bs->metric && strcmp(as->name, bs->name) != 0)
00991 return strcmp(as->name, bs->name);
00992
00993
00994 if (as->var_metric < bs->var_metric)
00995 return -1;
00996 else if (as->var_metric > bs->var_metric)
00997 return 1;
00998
00999 return 0;
01000 }
01001
01002
01003
01004
01005
01006
01007
01008
01009 static struct ast_config *config_ldap(const char *basedn, const char *table_name,
01010 const char *file, struct ast_config *cfg, struct ast_flags config_flags, const char *sugg_incl, const char *who_asked)
01011 {
01012 unsigned int vars_count = 0;
01013 struct ast_variable **vars;
01014 int i = 0;
01015 struct ast_variable *new_v = NULL;
01016 struct ast_category *cur_cat = NULL;
01017 const char *last_category = NULL;
01018 int last_category_metric = 0;
01019 struct category_and_metric *categories;
01020 struct ast_variable **p;
01021
01022 if (ast_strlen_zero(file) || !strcasecmp(file, RES_CONFIG_LDAP_CONF)) {
01023 ast_log(LOG_ERROR, "Cannot configure myself.\n");
01024 return NULL;
01025 }
01026
01027 vars = realtime_ldap_base(&vars_count, basedn, table_name, "filename",
01028 file, "commented", "FALSE", NULL);
01029
01030 if (!vars) {
01031 ast_log(LOG_WARNING, "Could not find config '%s' in database.\n", file);
01032 return NULL;
01033 }
01034
01035
01036
01037
01038
01039 if (!(categories = ast_calloc(sizeof(*categories), vars_count)))
01040 return NULL;
01041
01042 for (vars_count = 0, p = vars; *p; p++) {
01043 struct ast_variable *category = variable_named(*p, "category");
01044 struct ast_variable *cat_metric = variable_named(*p, "cat_metric");
01045 struct ast_variable *var_name = variable_named(*p, "variable_name");
01046 struct ast_variable *var_val = variable_named(*p, "variable_value");
01047 struct ast_variable *var_metric = variable_named(*p, "var_metric");
01048 struct ast_variable *dn = variable_named(*p, "dn");
01049
01050 ast_debug(1, "category: %s\n", category->value);
01051 ast_debug(1, "var_name: %s\n", var_name->value);
01052 ast_debug(1, "var_val: %s\n", var_val->value);
01053 ast_debug(1, "cat_metric: %s\n", cat_metric->value);
01054
01055 if (!category) {
01056 ast_log(LOG_ERROR,
01057 "No category name in entry '%s' for file '%s'.\n",
01058 (dn ? dn->value : "?"), file);
01059 } else if (!cat_metric) {
01060 ast_log(LOG_ERROR,
01061 "No category metric in entry '%s'(category: %s) for file '%s'.\n",
01062 (dn ? dn->value : "?"), category->value, file);
01063 } else if (!var_metric) {
01064 ast_log(LOG_ERROR,
01065 "No variable metric in entry '%s'(category: %s) for file '%s'.\n",
01066 (dn ? dn->value : "?"), category->value, file);
01067 } else if (!var_name) {
01068 ast_log(LOG_ERROR,
01069 "No variable name in entry '%s' (category: %s metric: %s) for file '%s'.\n",
01070 (dn ? dn->value : "?"), category->value,
01071 cat_metric->value, file);
01072 } else if (!var_val) {
01073 ast_log(LOG_ERROR,
01074 "No variable value in entry '%s' (category: %s metric: %s variable: %s) for file '%s'.\n",
01075 (dn ? dn->value : "?"), category->value,
01076 cat_metric->value, var_name->value, file);
01077 } else {
01078 categories[vars_count].name = category->value;
01079 categories[vars_count].metric = atoi(cat_metric->value);
01080 categories[vars_count].variable_name = var_name->value;
01081 categories[vars_count].variable_value = var_val->value;
01082 categories[vars_count].var_metric = atoi(var_metric->value);
01083 vars_count++;
01084 }
01085 }
01086
01087 qsort(categories, vars_count, sizeof(*categories), compare_categories);
01088
01089 for (i = 0; i < vars_count; i++) {
01090 if (!strcmp(categories[i].variable_name, "#include")) {
01091 struct ast_flags flags = { 0 };
01092 if (!ast_config_internal_load(categories[i].variable_value, cfg, flags, "", who_asked))
01093 break;
01094 continue;
01095 }
01096
01097 if (!last_category || strcmp(last_category, categories[i].name) ||
01098 last_category_metric != categories[i].metric) {
01099 cur_cat = ast_category_new(categories[i].name, table_name, -1);
01100 if (!cur_cat)
01101 break;
01102 last_category = categories[i].name;
01103 last_category_metric = categories[i].metric;
01104 ast_category_append(cfg, cur_cat);
01105 }
01106
01107 if (!(new_v = ast_variable_new(categories[i].variable_name, categories[i].variable_value, table_name)))
01108 break;
01109
01110 ast_variable_append(cur_cat, new_v);
01111 }
01112
01113 free(vars);
01114 free(categories);
01115
01116 return cfg;
01117 }
01118
01119
01120
01121
01122 static int update_ldap(const char *basedn, const char *table_name, const char *attribute,
01123 const char *lookup, va_list ap)
01124 {
01125 int error = 0;
01126 LDAPMessage *ldap_entry = NULL;
01127 LDAPMod **ldap_mods;
01128 const char *newparam = NULL;
01129 const char *newval = NULL;
01130 char *dn;
01131 int num_entries = 0;
01132 int i = 0;
01133 int mods_size = 0;
01134 int mod_exists = 0;
01135 struct ldap_table_config *table_config = NULL;
01136 char *clean_basedn = NULL;
01137 struct ast_str *filter = NULL;
01138 int tries = 0;
01139 int result = 0;
01140 LDAPMessage *ldap_result_msg = NULL;
01141
01142 if (!table_name) {
01143 ast_log(LOG_WARNING, "No table_name specified.\n");
01144 return -1;
01145 }
01146
01147 if (!(filter = ast_str_create(80)))
01148 return -1;
01149
01150 if (!attribute || !lookup) {
01151 ast_log(LOG_WARNING,
01152 "LINE(%d): search parameters are empty.\n", __LINE__);
01153 return -1;
01154 }
01155 ast_mutex_lock(&ldap_lock);
01156
01157
01158 if (!ldap_reconnect()) {
01159 ast_mutex_unlock(&ldap_lock);
01160 return -1;
01161 }
01162
01163 table_config = table_config_for_table_name(table_name);
01164 if (!table_config) {
01165 ast_log(LOG_WARNING, "No table named '%s'.\n", table_name);
01166 ast_mutex_unlock(&ldap_lock);
01167 return -1;
01168 }
01169
01170 clean_basedn = cleaned_basedn(NULL, basedn);
01171
01172
01173 ast_str_append(&filter, 0, "(&");
01174 if (table_config && table_config->additional_filter) {
01175 ast_str_append(&filter, 0, "%s", table_config->additional_filter);
01176 }
01177 if (table_config != base_table_config && base_table_config
01178 && base_table_config->additional_filter) {
01179 ast_str_append(&filter, 0, "%s", base_table_config->additional_filter);
01180 }
01181 append_var_and_value_to_filter(&filter, table_config, attribute, lookup);
01182 ast_str_append(&filter, 0, ")");
01183
01184
01185
01186
01187 newparam = va_arg(ap, const char *);
01188 newparam = convert_attribute_name_to_ldap(table_config, newparam);
01189 newval = va_arg(ap, const char *);
01190 if (!newparam || !newval) {
01191 ast_log(LOG_WARNING,
01192 "LINE(%d): need at least one parameter to modify.\n", __LINE__);
01193 return -1;
01194 }
01195
01196 mods_size = 2;
01197 ldap_mods = ast_calloc(sizeof(LDAPMod *), mods_size);
01198 ldap_mods[0] = ast_calloc(1, sizeof(LDAPMod));
01199
01200 ldap_mods[0]->mod_op = LDAP_MOD_REPLACE;
01201 ldap_mods[0]->mod_type = ast_strdup(newparam);
01202
01203 ldap_mods[0]->mod_values = ast_calloc(sizeof(char *), 2);
01204 ldap_mods[0]->mod_values[0] = ast_strdup(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
01228 ldap_mods[mods_size - 2] = ast_calloc(1, sizeof(LDAPMod));
01229
01230 ldap_mods[mods_size - 2]->mod_type = ast_calloc(sizeof(char), strlen(newparam) + 1);
01231 strcpy(ldap_mods[mods_size - 2]->mod_type, newparam);
01232
01233 if (strlen(newval) == 0) {
01234 ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_DELETE;
01235 } else {
01236 ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_REPLACE;
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
01246 do {
01247
01248 result = ldap_search_ext_s(ldapConn, clean_basedn,
01249 LDAP_SCOPE_SUBTREE, filter->str, NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
01250 &ldap_result_msg);
01251 if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
01252 ast_log(LOG_WARNING, "Failed to query database. Try %d/3\n",
01253 tries + 1);
01254 tries++;
01255 if (tries < 3) {
01256 usleep(500000L * tries);
01257 if (ldapConn) {
01258 ldap_unbind_ext_s(ldapConn, NULL, NULL);
01259 ldapConn = NULL;
01260 }
01261 if (!ldap_reconnect())
01262 break;
01263 }
01264 }
01265 } while (result != LDAP_SUCCESS && tries < 3 && is_ldap_connect_error(result));
01266
01267 if (result != LDAP_SUCCESS) {
01268 ast_log(LOG_WARNING, "Failed to query directory. Check debug for more info.\n");
01269 ast_log(LOG_WARNING, "Query: %s\n", filter->str);
01270 ast_log(LOG_WARNING, "Query Failed because: %s\n",
01271 ldap_err2string(result));
01272
01273 ast_mutex_unlock(&ldap_lock);
01274 free(filter);
01275 free(clean_basedn);
01276 ldap_msgfree(ldap_result_msg);
01277 ldap_mods_free(ldap_mods, 0);
01278 return -1;
01279 }
01280
01281 if ((num_entries = ldap_count_entries(ldapConn, ldap_result_msg)) > 0) {
01282 ast_debug(3, "LINE(%d) Modifying %s=%s hits: %d\n", __LINE__, attribute, lookup, num_entries);
01283 for (i = 0; option_debug > 2 && i < mods_size - 1; i++) {
01284 if (ldap_mods[i]->mod_op != LDAP_MOD_DELETE) {
01285 ast_debug(3, "LINE(%d) %s=%s \n", __LINE__, ldap_mods[i]->mod_type, ldap_mods[i]->mod_values[0]);
01286 } else {
01287 ast_debug(3, "LINE(%d) deleting %s \n", __LINE__, ldap_mods[i]->mod_type);
01288 }
01289 }
01290 ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
01291
01292 for (i = 0; ldap_entry; i++) {
01293 dn = ldap_get_dn(ldapConn, ldap_entry);
01294 if ((error = ldap_modify_ext_s(ldapConn, dn, ldap_mods, NULL, NULL)) != LDAP_SUCCESS)
01295 ast_log(LOG_ERROR, "Couldn't modify dn:%s because %s", dn, ldap_err2string(error));
01296
01297 ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
01298 }
01299 }
01300
01301 ast_mutex_unlock(&ldap_lock);
01302 free(filter);
01303 free(clean_basedn);
01304 ldap_msgfree(ldap_result_msg);
01305 ldap_mods_free(ldap_mods, 0);
01306 return num_entries;
01307 }
01308
01309 static struct ast_config_engine ldap_engine = {
01310 .name = "ldap",
01311 .load_func = config_ldap,
01312 .realtime_func = realtime_ldap,
01313 .realtime_multi_func = realtime_multi_ldap,
01314 .update_func = update_ldap
01315 };
01316
01317 static int load_module(void)
01318 {
01319 if (parse_config() < 0) {
01320 ast_log(LOG_NOTICE, "Cannot load LDAP RealTime driver.\n");
01321 return 0;
01322 }
01323
01324 ast_mutex_lock(&ldap_lock);
01325
01326 if (!ldap_reconnect())
01327 ast_log(LOG_WARNING, "Couldn't establish connection. Check debug.\n");
01328
01329 ast_config_engine_register(&ldap_engine);
01330 ast_verb(1, "LDAP RealTime driver loaded.\n");
01331 ast_cli_register_multiple(ldap_cli, sizeof(ldap_cli) / sizeof(struct ast_cli_entry));
01332
01333 ast_mutex_unlock(&ldap_lock);
01334
01335 return 0;
01336 }
01337
01338 static int unload_module(void)
01339 {
01340
01341 ast_mutex_lock(&ldap_lock);
01342
01343 table_configs_free();
01344
01345 if (ldapConn) {
01346 ldap_unbind_ext_s(ldapConn, NULL, NULL);
01347 ldapConn = NULL;
01348 }
01349 ast_cli_unregister_multiple(ldap_cli, sizeof(ldap_cli) / sizeof(struct ast_cli_entry));
01350 ast_config_engine_deregister(&ldap_engine);
01351 ast_verb(1, "LDAP RealTime unloaded.\n");
01352
01353
01354 ast_mutex_unlock(&ldap_lock);
01355
01356 return 0;
01357 }
01358
01359 static int reload(void)
01360 {
01361
01362 ast_mutex_lock(&ldap_lock);
01363
01364 if (ldapConn) {
01365 ldap_unbind_ext_s(ldapConn, NULL, NULL);
01366 ldapConn = NULL;
01367 }
01368
01369 if (parse_config() < 0) {
01370 ast_log(LOG_NOTICE, "Cannot reload LDAP RealTime driver.\n");
01371 ast_mutex_unlock(&ldap_lock);
01372 return 0;
01373 }
01374
01375 if (!ldap_reconnect())
01376 ast_log(LOG_WARNING, "Couldn't establish connection. Check debug.\n");
01377
01378 ast_verb(2, "LDAP RealTime reloaded.\n");
01379
01380
01381 ast_mutex_unlock(&ldap_lock);
01382
01383 return 0;
01384 }
01385
01386 int parse_config(void)
01387 {
01388 struct ast_config *config;
01389 struct ast_flags config_flags = {0};
01390 const char *s, *host;
01391 int port;
01392 char *category_name = NULL;
01393
01394 config = ast_config_load(RES_CONFIG_LDAP_CONF, config_flags);
01395
01396 if (!config) {
01397 ast_log(LOG_WARNING, "Cannot load configuration %s\n", RES_CONFIG_LDAP_CONF);
01398 return -1;
01399 }
01400
01401 if (!(s = ast_variable_retrieve(config, "_general", "user"))) {
01402 ast_log(LOG_WARNING, "No directory user found, anonymous binding as default.\n");
01403 user[0] = '\0';
01404 } else
01405 ast_copy_string(user, s, sizeof(user));
01406
01407 if (!ast_strlen_zero(user)) {
01408 if (!(s = ast_variable_retrieve(config, "_general", "pass"))) {
01409 ast_log(LOG_WARNING, "No directory password found, using 'asterisk' as default.\n");
01410 ast_copy_string(pass, "asterisk", sizeof(pass));
01411 } else {
01412 ast_copy_string(pass, s, sizeof(pass));
01413 }
01414 }
01415
01416
01417 if ((s = ast_variable_retrieve(config, "_general", "url"))) {
01418 ast_copy_string(url, s, sizeof(url));
01419 } else if ((host = ast_variable_retrieve(config, "_general", "host"))) {
01420 if (!(s = ast_variable_retrieve(config, "_general", "port")) || sscanf(s, "%5d", &port) != 1 || port > 65535) {
01421 ast_log(LOG_NOTICE, "No directory port found, using 389 as default.\n");
01422 port = 389;
01423 }
01424
01425 snprintf(url, sizeof(url), "ldap://%s:%d", host, port);
01426 } else {
01427 ast_log(LOG_ERROR, "No directory URL or host found.\n");
01428 ast_config_destroy(config);
01429 return -1;
01430 }
01431
01432 if (!(s = ast_variable_retrieve(config, "_general", "basedn"))) {
01433 ast_log(LOG_ERROR, "No LDAP base dn found, using '%s' as default.\n", RES_CONFIG_LDAP_DEFAULT_BASEDN);
01434 ast_copy_string(base_distinguished_name, RES_CONFIG_LDAP_DEFAULT_BASEDN, sizeof(base_distinguished_name));
01435 } else
01436 ast_copy_string(base_distinguished_name, s, sizeof(base_distinguished_name));
01437
01438 if (!(s = ast_variable_retrieve(config, "_general", "version")) && !(s = ast_variable_retrieve(config, "_general", "protocol"))) {
01439 ast_log(LOG_NOTICE, "No explicit LDAP version found, using 3 as default.\n");
01440 version = 3;
01441 } else if (sscanf(s, "%30d", &version) != 1 || version < 1 || version > 6) {
01442 ast_log(LOG_WARNING, "Invalid LDAP version '%s', using 3 as default.\n", s);
01443 version = 3;
01444 }
01445
01446 table_configs_free();
01447
01448 while ((category_name = ast_category_browse(config, category_name))) {
01449 int is_general = (strcasecmp(category_name, "_general") == 0);
01450 int is_config = (strcasecmp(category_name, "config") == 0);
01451 struct ast_variable *var = ast_variable_browse(config, category_name);
01452
01453 if (var) {
01454 struct ldap_table_config *table_config =
01455 table_config_for_table_name(category_name);
01456 if (!table_config) {
01457 table_config = table_config_new(category_name);
01458 AST_LIST_INSERT_HEAD(&table_configs, table_config, entry);
01459 if (is_general)
01460 base_table_config = table_config;
01461 if (is_config)
01462 static_table_config = table_config;
01463 }
01464 for (; var; var = var->next) {
01465 if (!strcasecmp(var->name, "additionalFilter")) {
01466 table_config->additional_filter = ast_strdup(var->value);
01467 } else {
01468 ldap_table_config_add_attribute(table_config, var->name, var->value);
01469 }
01470 }
01471 }
01472 }
01473
01474 ast_config_destroy(config);
01475
01476 return 1;
01477 }
01478
01479
01480 static int ldap_reconnect(void)
01481 {
01482 int bind_result = 0;
01483 struct berval cred;
01484
01485 if (ldapConn) {
01486 ast_debug(2, "Everything seems fine.\n");
01487 return 1;
01488 }
01489
01490 if (ast_strlen_zero(url)) {
01491 ast_log(LOG_ERROR, "Not enough parameters to connect to ldap database\n");
01492 return 0;
01493 }
01494
01495 if (LDAP_SUCCESS != ldap_initialize(&ldapConn, url)) {
01496 ast_log(LOG_ERROR, "Failed to init ldap connection to '%s'. Check debug for more info.\n", url);
01497 return 0;
01498 }
01499
01500 if (LDAP_OPT_SUCCESS != ldap_set_option(ldapConn, LDAP_OPT_PROTOCOL_VERSION, &version)) {
01501 ast_log(LOG_WARNING, "Unable to set LDAP protocol version to %d, falling back to default.\n", version);
01502 }
01503
01504 if (!ast_strlen_zero(user)) {
01505 ast_debug(2, "bind to '%s' as user '%s'\n", url, user);
01506 cred.bv_val = (char *) pass;
01507 cred.bv_len = strlen(pass);
01508 bind_result = ldap_sasl_bind_s(ldapConn, user, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
01509 } else {
01510 ast_debug(2, "bind %s anonymously\n", url);
01511 cred.bv_val = NULL;
01512 cred.bv_len = 0;
01513 bind_result = ldap_sasl_bind_s(ldapConn, NULL, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
01514 }
01515 if (bind_result == LDAP_SUCCESS) {
01516 ast_debug(2, "Successfully connected to database.\n");
01517 connect_time = time(NULL);
01518 return 1;
01519 } else {
01520 ast_log(LOG_WARNING, "bind failed: %s\n", ldap_err2string(bind_result));
01521 ldap_unbind_ext_s(ldapConn, NULL, NULL);
01522 ldapConn = NULL;
01523 return 0;
01524 }
01525 }
01526
01527 static char *realtime_ldap_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01528 {
01529 char status[256], credentials[100] = "";
01530 int ctimesec = time(NULL) - connect_time;
01531
01532 switch (cmd) {
01533 case CLI_INIT:
01534 e->command = "realtime ldap status";
01535 e->usage =
01536 "Usage: realtime ldap status\n"
01537 " Shows connection information for the LDAP RealTime driver\n";
01538 return NULL;
01539 case CLI_GENERATE:
01540 return NULL;
01541 }
01542
01543 if (!ldapConn)
01544 return CLI_FAILURE;
01545
01546 if (!ast_strlen_zero(url))
01547 snprintf(status, sizeof(status), "Connected to '%s', baseDN %s", url, base_distinguished_name);
01548
01549 if (!ast_strlen_zero(user))
01550 snprintf(credentials, sizeof(credentials), " with username %s", user);
01551
01552 if (ctimesec > 31536000) {
01553 ast_cli(a->fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n",
01554 status, credentials, ctimesec / 31536000,
01555 (ctimesec % 31536000) / 86400, (ctimesec % 86400) / 3600,
01556 (ctimesec % 3600) / 60, ctimesec % 60);
01557 } else if (ctimesec > 86400) {
01558 ast_cli(a->fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n",
01559 status, credentials, ctimesec / 86400, (ctimesec % 86400) / 3600,
01560 (ctimesec % 3600) / 60, ctimesec % 60);
01561 } else if (ctimesec > 3600) {
01562 ast_cli(a->fd, "%s%s for %d hours, %d minutes, %d seconds.\n",
01563 status, credentials, ctimesec / 3600, (ctimesec % 3600) / 60,
01564 ctimesec % 60);
01565 } else if (ctimesec > 60) {
01566 ast_cli(a->fd, "%s%s for %d minutes, %d seconds.\n", status, credentials,
01567 ctimesec / 60, ctimesec % 60);
01568 } else {
01569 ast_cli(a->fd, "%s%s for %d seconds.\n", status, credentials, ctimesec);
01570 }
01571
01572 return CLI_SUCCESS;
01573 }
01574
01575 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "LDAP realtime interface",
01576 .load = load_module,
01577 .unload = unload_module,
01578 .reload = reload,
01579 );