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