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: 279597 $")
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[512];
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 char *op;
00942 const char *initfield = NULL;
00943 const char *newparam, *newval;
00944 struct ast_variable **vars =
00945 realtime_ldap_base_ap(NULL, basedn, table_name, ap);
00946 struct ast_config *cfg = NULL;
00947
00948 newparam = va_arg(ap, const char *);
00949 newval = va_arg(ap, const char *);
00950 if (!newparam || !newval) {
00951 ast_log(LOG_WARNING, "realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
00952 return NULL;
00953 }
00954 initfield = ast_strdupa(newparam);
00955 if ((op = strchr(initfield, ' '))) {
00956 *op = '\0';
00957 }
00958
00959 if (vars) {
00960 cfg = ast_config_new();
00961 if (!cfg) {
00962 ast_log(LOG_ERROR, "Unable to create a config!\n");
00963 } else {
00964 struct ast_variable **p = vars;
00965
00966 while (*p) {
00967 struct ast_category *cat = NULL;
00968 cat = ast_category_new("", table_name, -1);
00969 if (!cat) {
00970 ast_log(LOG_ERROR, "Unable to create a new category!\n");
00971 break;
00972 } else {
00973 struct ast_variable *var = *p;
00974 while (var) {
00975 struct ast_variable *next = var->next;
00976 if (initfield && !strcmp(initfield, var->name)) {
00977 ast_category_rename(cat, var->value);
00978 }
00979 var->next = NULL;
00980 ast_variable_append(cat, var);
00981 var = next;
00982 }
00983 }
00984 ast_category_append(cfg, cat);
00985 p++;
00986 }
00987 }
00988 free(vars);
00989 }
00990 return cfg;
00991
00992 }
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003 static int compare_categories(const void *a, const void *b)
01004 {
01005 const struct category_and_metric *as = a;
01006 const struct category_and_metric *bs = b;
01007
01008 if (as->metric < bs->metric)
01009 return -1;
01010 else if (as->metric > bs->metric)
01011 return 1;
01012 else if (as->metric == bs->metric && strcmp(as->name, bs->name) != 0)
01013 return strcmp(as->name, bs->name);
01014
01015
01016 if (as->var_metric < bs->var_metric)
01017 return -1;
01018 else if (as->var_metric > bs->var_metric)
01019 return 1;
01020
01021 return 0;
01022 }
01023
01024
01025
01026
01027
01028
01029
01030
01031 static struct ast_config *config_ldap(const char *basedn, const char *table_name,
01032 const char *file, struct ast_config *cfg, struct ast_flags config_flags, const char *sugg_incl, const char *who_asked)
01033 {
01034 unsigned int vars_count = 0;
01035 struct ast_variable **vars;
01036 int i = 0;
01037 struct ast_variable *new_v = NULL;
01038 struct ast_category *cur_cat = NULL;
01039 const char *last_category = NULL;
01040 int last_category_metric = 0;
01041 struct category_and_metric *categories;
01042 struct ast_variable **p;
01043
01044 if (ast_strlen_zero(file) || !strcasecmp(file, RES_CONFIG_LDAP_CONF)) {
01045 ast_log(LOG_ERROR, "Cannot configure myself.\n");
01046 return NULL;
01047 }
01048
01049 vars = realtime_ldap_base(&vars_count, basedn, table_name, "filename",
01050 file, "commented", "FALSE", NULL);
01051
01052 if (!vars) {
01053 ast_log(LOG_WARNING, "Could not find config '%s' in database.\n", file);
01054 return NULL;
01055 }
01056
01057
01058
01059
01060
01061 if (!(categories = ast_calloc(sizeof(*categories), vars_count)))
01062 return NULL;
01063
01064 for (vars_count = 0, p = vars; *p; p++) {
01065 struct ast_variable *category = variable_named(*p, "category");
01066 struct ast_variable *cat_metric = variable_named(*p, "cat_metric");
01067 struct ast_variable *var_name = variable_named(*p, "variable_name");
01068 struct ast_variable *var_val = variable_named(*p, "variable_value");
01069 struct ast_variable *var_metric = variable_named(*p, "var_metric");
01070 struct ast_variable *dn = variable_named(*p, "dn");
01071
01072 ast_debug(1, "category: %s\n", category->value);
01073 ast_debug(1, "var_name: %s\n", var_name->value);
01074 ast_debug(1, "var_val: %s\n", var_val->value);
01075 ast_debug(1, "cat_metric: %s\n", cat_metric->value);
01076
01077 if (!category) {
01078 ast_log(LOG_ERROR,
01079 "No category name in entry '%s' for file '%s'.\n",
01080 (dn ? dn->value : "?"), file);
01081 } else if (!cat_metric) {
01082 ast_log(LOG_ERROR,
01083 "No category metric in entry '%s'(category: %s) for file '%s'.\n",
01084 (dn ? dn->value : "?"), category->value, file);
01085 } else if (!var_metric) {
01086 ast_log(LOG_ERROR,
01087 "No variable metric in entry '%s'(category: %s) for file '%s'.\n",
01088 (dn ? dn->value : "?"), category->value, file);
01089 } else if (!var_name) {
01090 ast_log(LOG_ERROR,
01091 "No variable name in entry '%s' (category: %s metric: %s) for file '%s'.\n",
01092 (dn ? dn->value : "?"), category->value,
01093 cat_metric->value, file);
01094 } else if (!var_val) {
01095 ast_log(LOG_ERROR,
01096 "No variable value in entry '%s' (category: %s metric: %s variable: %s) for file '%s'.\n",
01097 (dn ? dn->value : "?"), category->value,
01098 cat_metric->value, var_name->value, file);
01099 } else {
01100 categories[vars_count].name = category->value;
01101 categories[vars_count].metric = atoi(cat_metric->value);
01102 categories[vars_count].variable_name = var_name->value;
01103 categories[vars_count].variable_value = var_val->value;
01104 categories[vars_count].var_metric = atoi(var_metric->value);
01105 vars_count++;
01106 }
01107 }
01108
01109 qsort(categories, vars_count, sizeof(*categories), compare_categories);
01110
01111 for (i = 0; i < vars_count; i++) {
01112 if (!strcmp(categories[i].variable_name, "#include")) {
01113 struct ast_flags flags = { 0 };
01114 if (!ast_config_internal_load(categories[i].variable_value, cfg, flags, "", who_asked))
01115 break;
01116 continue;
01117 }
01118
01119 if (!last_category || strcmp(last_category, categories[i].name) ||
01120 last_category_metric != categories[i].metric) {
01121 cur_cat = ast_category_new(categories[i].name, table_name, -1);
01122 if (!cur_cat)
01123 break;
01124 last_category = categories[i].name;
01125 last_category_metric = categories[i].metric;
01126 ast_category_append(cfg, cur_cat);
01127 }
01128
01129 if (!(new_v = ast_variable_new(categories[i].variable_name, categories[i].variable_value, table_name)))
01130 break;
01131
01132 ast_variable_append(cur_cat, new_v);
01133 }
01134
01135 free(vars);
01136 free(categories);
01137
01138 return cfg;
01139 }
01140
01141
01142
01143
01144 static int update_ldap(const char *basedn, const char *table_name, const char *attribute,
01145 const char *lookup, va_list ap)
01146 {
01147 int error = 0;
01148 LDAPMessage *ldap_entry = NULL;
01149 LDAPMod **ldap_mods;
01150 const char *newparam = NULL;
01151 const char *newval = NULL;
01152 char *dn;
01153 int num_entries = 0;
01154 int i = 0;
01155 int mods_size = 0;
01156 int mod_exists = 0;
01157 struct ldap_table_config *table_config = NULL;
01158 char *clean_basedn = NULL;
01159 struct ast_str *filter = NULL;
01160 int tries = 0;
01161 int result = 0;
01162 LDAPMessage *ldap_result_msg = NULL;
01163
01164 if (!table_name) {
01165 ast_log(LOG_WARNING, "No table_name specified.\n");
01166 return -1;
01167 }
01168
01169 if (!(filter = ast_str_create(80)))
01170 return -1;
01171
01172 if (!attribute || !lookup) {
01173 ast_log(LOG_WARNING,
01174 "LINE(%d): search parameters are empty.\n", __LINE__);
01175 return -1;
01176 }
01177 ast_mutex_lock(&ldap_lock);
01178
01179
01180 if (!ldap_reconnect()) {
01181 ast_mutex_unlock(&ldap_lock);
01182 return -1;
01183 }
01184
01185 table_config = table_config_for_table_name(table_name);
01186 if (!table_config) {
01187 ast_log(LOG_WARNING, "No table named '%s'.\n", table_name);
01188 ast_mutex_unlock(&ldap_lock);
01189 return -1;
01190 }
01191
01192 clean_basedn = cleaned_basedn(NULL, basedn);
01193
01194
01195 ast_str_append(&filter, 0, "(&");
01196 if (table_config && table_config->additional_filter) {
01197 ast_str_append(&filter, 0, "%s", table_config->additional_filter);
01198 }
01199 if (table_config != base_table_config && base_table_config
01200 && base_table_config->additional_filter) {
01201 ast_str_append(&filter, 0, "%s", base_table_config->additional_filter);
01202 }
01203 append_var_and_value_to_filter(&filter, table_config, attribute, lookup);
01204 ast_str_append(&filter, 0, ")");
01205
01206
01207
01208
01209 newparam = va_arg(ap, const char *);
01210 newparam = convert_attribute_name_to_ldap(table_config, newparam);
01211 newval = va_arg(ap, const char *);
01212 if (!newparam || !newval) {
01213 ast_log(LOG_WARNING,
01214 "LINE(%d): need at least one parameter to modify.\n", __LINE__);
01215 return -1;
01216 }
01217
01218 mods_size = 2;
01219 ldap_mods = ast_calloc(sizeof(LDAPMod *), mods_size);
01220 ldap_mods[0] = ast_calloc(1, sizeof(LDAPMod));
01221
01222 ldap_mods[0]->mod_op = LDAP_MOD_REPLACE;
01223 ldap_mods[0]->mod_type = ast_strdup(newparam);
01224
01225 ldap_mods[0]->mod_values = ast_calloc(sizeof(char *), 2);
01226 ldap_mods[0]->mod_values[0] = ast_strdup(newval);
01227
01228 while ((newparam = va_arg(ap, const char *))) {
01229 newparam = convert_attribute_name_to_ldap(table_config, newparam);
01230 newval = va_arg(ap, const char *);
01231 mod_exists = 0;
01232
01233 for (i = 0; i < mods_size - 1; i++) {
01234 if (ldap_mods[i]&& !strcmp(ldap_mods[i]->mod_type, newparam)) {
01235
01236 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));
01237 strcat(ldap_mods[i]->mod_values[0], ";");
01238 strcat(ldap_mods[i]->mod_values[0], newval);
01239 mod_exists = 1;
01240 break;
01241 }
01242 }
01243
01244
01245 if (!mod_exists) {
01246 mods_size++;
01247 ldap_mods = ast_realloc(ldap_mods, sizeof(LDAPMod *) * mods_size);
01248 ldap_mods[mods_size - 1] = NULL;
01249
01250 ldap_mods[mods_size - 2] = ast_calloc(1, sizeof(LDAPMod));
01251
01252 ldap_mods[mods_size - 2]->mod_type = ast_calloc(sizeof(char), strlen(newparam) + 1);
01253 strcpy(ldap_mods[mods_size - 2]->mod_type, newparam);
01254
01255 if (strlen(newval) == 0) {
01256 ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_DELETE;
01257 } else {
01258 ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_REPLACE;
01259
01260 ldap_mods[mods_size - 2]->mod_values = ast_calloc(sizeof(char *), 2);
01261 ldap_mods[mods_size - 2]->mod_values[0] = ast_calloc(sizeof(char), strlen(newval) + 1);
01262 strcpy(ldap_mods[mods_size - 2]->mod_values[0], newval);
01263 }
01264 }
01265 }
01266
01267
01268 do {
01269
01270 result = ldap_search_ext_s(ldapConn, clean_basedn,
01271 LDAP_SCOPE_SUBTREE, ast_str_buffer(filter), NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
01272 &ldap_result_msg);
01273 if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
01274 ast_log(LOG_WARNING, "Failed to query database. Try %d/3\n",
01275 tries + 1);
01276 tries++;
01277 if (tries < 3) {
01278 usleep(500000L * tries);
01279 if (ldapConn) {
01280 ldap_unbind_ext_s(ldapConn, NULL, NULL);
01281 ldapConn = NULL;
01282 }
01283 if (!ldap_reconnect())
01284 break;
01285 }
01286 }
01287 } while (result != LDAP_SUCCESS && tries < 3 && is_ldap_connect_error(result));
01288
01289 if (result != LDAP_SUCCESS) {
01290 ast_log(LOG_WARNING, "Failed to query directory. Check debug for more info.\n");
01291 ast_log(LOG_WARNING, "Query: %s\n", ast_str_buffer(filter));
01292 ast_log(LOG_WARNING, "Query Failed because: %s\n",
01293 ldap_err2string(result));
01294
01295 ast_mutex_unlock(&ldap_lock);
01296 free(filter);
01297 free(clean_basedn);
01298 ldap_msgfree(ldap_result_msg);
01299 ldap_mods_free(ldap_mods, 0);
01300 return -1;
01301 }
01302
01303 if ((num_entries = ldap_count_entries(ldapConn, ldap_result_msg)) > 0) {
01304 ast_debug(3, "LINE(%d) Modifying %s=%s hits: %d\n", __LINE__, attribute, lookup, num_entries);
01305 for (i = 0; option_debug > 2 && i < mods_size - 1; i++) {
01306 if (ldap_mods[i]->mod_op != LDAP_MOD_DELETE) {
01307 ast_debug(3, "LINE(%d) %s=%s \n", __LINE__, ldap_mods[i]->mod_type, ldap_mods[i]->mod_values[0]);
01308 } else {
01309 ast_debug(3, "LINE(%d) deleting %s \n", __LINE__, ldap_mods[i]->mod_type);
01310 }
01311 }
01312 ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
01313
01314 for (i = 0; ldap_entry; i++) {
01315 dn = ldap_get_dn(ldapConn, ldap_entry);
01316 if ((error = ldap_modify_ext_s(ldapConn, dn, ldap_mods, NULL, NULL)) != LDAP_SUCCESS)
01317 ast_log(LOG_ERROR, "Couldn't modify dn:%s because %s", dn, ldap_err2string(error));
01318
01319 ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
01320 }
01321 }
01322
01323 ast_mutex_unlock(&ldap_lock);
01324 free(filter);
01325 free(clean_basedn);
01326 ldap_msgfree(ldap_result_msg);
01327 ldap_mods_free(ldap_mods, 0);
01328 return num_entries;
01329 }
01330
01331 static int update2_ldap(const char *basedn, const char *table_name, va_list ap)
01332 {
01333 int error = 0;
01334 LDAPMessage *ldap_entry = NULL;
01335 LDAPMod **ldap_mods;
01336 const char *newparam = NULL;
01337 const char *newval = NULL;
01338 char *dn;
01339 int num_entries = 0;
01340 int i = 0;
01341 int mods_size = 0;
01342 int mod_exists = 0;
01343 struct ldap_table_config *table_config = NULL;
01344 char *clean_basedn = NULL;
01345 struct ast_str *filter = NULL;
01346 int tries = 0;
01347 int result = 0;
01348 LDAPMessage *ldap_result_msg = NULL;
01349
01350 if (!table_name) {
01351 ast_log(LOG_WARNING, "No table_name specified.\n");
01352 return -1;
01353 }
01354
01355 if (!(filter = ast_str_create(80)))
01356 return -1;
01357
01358 ast_mutex_lock(&ldap_lock);
01359
01360
01361 if (!ldap_reconnect()) {
01362 ast_mutex_unlock(&ldap_lock);
01363 ast_free(filter);
01364 return -1;
01365 }
01366
01367 table_config = table_config_for_table_name(table_name);
01368 if (!table_config) {
01369 ast_log(LOG_WARNING, "No table named '%s'.\n", table_name);
01370 ast_mutex_unlock(&ldap_lock);
01371 ast_free(filter);
01372 return -1;
01373 }
01374
01375 clean_basedn = cleaned_basedn(NULL, basedn);
01376
01377
01378 ast_str_append(&filter, 0, "(&");
01379 if (table_config && table_config->additional_filter) {
01380 ast_str_append(&filter, 0, "%s", table_config->additional_filter);
01381 }
01382 if (table_config != base_table_config && base_table_config
01383 && base_table_config->additional_filter) {
01384 ast_str_append(&filter, 0, "%s", base_table_config->additional_filter);
01385 }
01386
01387
01388 while ((newparam = va_arg(ap, const char *))) {
01389 newval = va_arg(ap, const char *);
01390 append_var_and_value_to_filter(&filter, table_config, newparam, newval);
01391 }
01392 ast_str_append(&filter, 0, ")");
01393
01394
01395
01396
01397 newparam = va_arg(ap, const char *);
01398 newparam = convert_attribute_name_to_ldap(table_config, newparam);
01399 newval = va_arg(ap, const char *);
01400 if (!newparam || !newval) {
01401 ast_log(LOG_WARNING,
01402 "LINE(%d): need at least one parameter to modify.\n", __LINE__);
01403 ast_free(filter);
01404 ast_free(clean_basedn);
01405 return -1;
01406 }
01407
01408 mods_size = 2;
01409 ldap_mods = ast_calloc(sizeof(LDAPMod *), mods_size);
01410 ldap_mods[0] = ast_calloc(1, sizeof(LDAPMod));
01411
01412 ldap_mods[0]->mod_op = LDAP_MOD_REPLACE;
01413 ldap_mods[0]->mod_type = ast_calloc(sizeof(char), strlen(newparam) + 1);
01414 strcpy(ldap_mods[0]->mod_type, newparam);
01415
01416 ldap_mods[0]->mod_values = ast_calloc(sizeof(char), 2);
01417 ldap_mods[0]->mod_values[0] = ast_calloc(sizeof(char), strlen(newval) + 1);
01418 strcpy(ldap_mods[0]->mod_values[0], newval);
01419
01420 while ((newparam = va_arg(ap, const char *))) {
01421 newparam = convert_attribute_name_to_ldap(table_config, newparam);
01422 newval = va_arg(ap, const char *);
01423 mod_exists = 0;
01424
01425 for (i = 0; i < mods_size - 1; i++) {
01426 if (ldap_mods[i]&& !strcmp(ldap_mods[i]->mod_type, newparam)) {
01427
01428 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));
01429 strcat(ldap_mods[i]->mod_values[0], ";");
01430 strcat(ldap_mods[i]->mod_values[0], newval);
01431 mod_exists = 1;
01432 break;
01433 }
01434 }
01435
01436
01437 if (!mod_exists) {
01438 mods_size++;
01439 ldap_mods = ast_realloc(ldap_mods, sizeof(LDAPMod *) * mods_size);
01440 ldap_mods[mods_size - 1] = NULL;
01441 ldap_mods[mods_size - 2] = ast_calloc(1, sizeof(LDAPMod));
01442
01443 ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_REPLACE;
01444
01445 ldap_mods[mods_size - 2]->mod_type = ast_calloc(sizeof(char), strlen(newparam) + 1);
01446 strcpy(ldap_mods[mods_size - 2]->mod_type, newparam);
01447
01448 ldap_mods[mods_size - 2]->mod_values = ast_calloc(sizeof(char *), 2);
01449 ldap_mods[mods_size - 2]->mod_values[0] = ast_calloc(sizeof(char), strlen(newval) + 1);
01450 strcpy(ldap_mods[mods_size - 2]->mod_values[0], newval);
01451 }
01452 }
01453
01454
01455 do {
01456
01457 result = ldap_search_ext_s(ldapConn, clean_basedn,
01458 LDAP_SCOPE_SUBTREE, ast_str_buffer(filter), NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
01459 &ldap_result_msg);
01460 if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
01461 ast_log(LOG_WARNING, "Failed to query database. Try %d/3\n",
01462 tries + 1);
01463 tries++;
01464 if (tries < 3) {
01465 usleep(500000L * tries);
01466 if (ldapConn) {
01467 ldap_unbind_ext_s(ldapConn, NULL, NULL);
01468 ldapConn = NULL;
01469 }
01470 if (!ldap_reconnect())
01471 break;
01472 }
01473 }
01474 } while (result != LDAP_SUCCESS && tries < 3 && is_ldap_connect_error(result));
01475
01476 if (result != LDAP_SUCCESS) {
01477 ast_log(LOG_WARNING, "Failed to query directory. Check debug for more info.\n");
01478 ast_log(LOG_WARNING, "Query: %s\n", ast_str_buffer(filter));
01479 ast_log(LOG_WARNING, "Query Failed because: %s\n",
01480 ldap_err2string(result));
01481
01482 ast_mutex_unlock(&ldap_lock);
01483 free(filter);
01484 free(clean_basedn);
01485 ldap_msgfree(ldap_result_msg);
01486 ldap_mods_free(ldap_mods, 0);
01487 return -1;
01488 }
01489
01490 if ((num_entries = ldap_count_entries(ldapConn, ldap_result_msg)) > 0) {
01491 for (i = 0; option_debug > 2 && i < mods_size - 1; i++)
01492 ast_debug(3, "LINE(%d) %s=%s \n", __LINE__, ldap_mods[i]->mod_type, ldap_mods[i]->mod_values[0]);
01493
01494 ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
01495
01496 for (i = 0; ldap_entry; i++) {
01497 dn = ldap_get_dn(ldapConn, ldap_entry);
01498 if ((error = ldap_modify_ext_s(ldapConn, dn, ldap_mods, NULL, NULL)) != LDAP_SUCCESS)
01499 ast_log(LOG_ERROR, "Couldn't modify dn:%s because %s", dn, ldap_err2string(error));
01500
01501 ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
01502 }
01503 }
01504
01505 ast_mutex_unlock(&ldap_lock);
01506 if (filter)
01507 free(filter);
01508 if (clean_basedn)
01509 free(clean_basedn);
01510 ldap_msgfree(ldap_result_msg);
01511 ldap_mods_free(ldap_mods, 0);
01512 return num_entries;
01513 }
01514
01515 static struct ast_config_engine ldap_engine = {
01516 .name = "ldap",
01517 .load_func = config_ldap,
01518 .realtime_func = realtime_ldap,
01519 .realtime_multi_func = realtime_multi_ldap,
01520 .update_func = update_ldap,
01521 .update2_func = update2_ldap,
01522 };
01523
01524 static int load_module(void)
01525 {
01526 if (parse_config() < 0) {
01527 ast_log(LOG_NOTICE, "Cannot load LDAP RealTime driver.\n");
01528 return 0;
01529 }
01530
01531 ast_mutex_lock(&ldap_lock);
01532
01533 if (!ldap_reconnect())
01534 ast_log(LOG_WARNING, "Couldn't establish connection. Check debug.\n");
01535
01536 ast_config_engine_register(&ldap_engine);
01537 ast_verb(1, "LDAP RealTime driver loaded.\n");
01538 ast_cli_register_multiple(ldap_cli, ARRAY_LEN(ldap_cli));
01539
01540 ast_mutex_unlock(&ldap_lock);
01541
01542 return 0;
01543 }
01544
01545 static int unload_module(void)
01546 {
01547
01548 ast_mutex_lock(&ldap_lock);
01549
01550 table_configs_free();
01551
01552 if (ldapConn) {
01553 ldap_unbind_ext_s(ldapConn, NULL, NULL);
01554 ldapConn = NULL;
01555 }
01556 ast_cli_unregister_multiple(ldap_cli, ARRAY_LEN(ldap_cli));
01557 ast_config_engine_deregister(&ldap_engine);
01558 ast_verb(1, "LDAP RealTime unloaded.\n");
01559
01560
01561 ast_mutex_unlock(&ldap_lock);
01562
01563 return 0;
01564 }
01565
01566 static int reload(void)
01567 {
01568
01569 ast_mutex_lock(&ldap_lock);
01570
01571 if (ldapConn) {
01572 ldap_unbind_ext_s(ldapConn, NULL, NULL);
01573 ldapConn = NULL;
01574 }
01575
01576 if (parse_config() < 0) {
01577 ast_log(LOG_NOTICE, "Cannot reload LDAP RealTime driver.\n");
01578 ast_mutex_unlock(&ldap_lock);
01579 return 0;
01580 }
01581
01582 if (!ldap_reconnect())
01583 ast_log(LOG_WARNING, "Couldn't establish connection. Check debug.\n");
01584
01585 ast_verb(2, "LDAP RealTime reloaded.\n");
01586
01587
01588 ast_mutex_unlock(&ldap_lock);
01589
01590 return 0;
01591 }
01592
01593 int parse_config(void)
01594 {
01595 struct ast_config *config;
01596 struct ast_flags config_flags = {0};
01597 const char *s, *host;
01598 int port;
01599 char *category_name = NULL;
01600
01601 config = ast_config_load(RES_CONFIG_LDAP_CONF, config_flags);
01602 if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEINVALID) {
01603 ast_log(LOG_WARNING, "Cannot load configuration %s\n", RES_CONFIG_LDAP_CONF);
01604 return -1;
01605 }
01606
01607 if (!(s = ast_variable_retrieve(config, "_general", "user"))) {
01608 ast_log(LOG_WARNING, "No directory user found, anonymous binding as default.\n");
01609 user[0] = '\0';
01610 } else
01611 ast_copy_string(user, s, sizeof(user));
01612
01613 if (!ast_strlen_zero(user)) {
01614 if (!(s = ast_variable_retrieve(config, "_general", "pass"))) {
01615 ast_log(LOG_WARNING, "No directory password found, using 'asterisk' as default.\n");
01616 ast_copy_string(pass, "asterisk", sizeof(pass));
01617 } else {
01618 ast_copy_string(pass, s, sizeof(pass));
01619 }
01620 }
01621
01622
01623 if ((s = ast_variable_retrieve(config, "_general", "url"))) {
01624 ast_copy_string(url, s, sizeof(url));
01625 } else if ((host = ast_variable_retrieve(config, "_general", "host"))) {
01626 if (!(s = ast_variable_retrieve(config, "_general", "port")) || sscanf(s, "%5d", &port) != 1 || port > 65535) {
01627 ast_log(LOG_NOTICE, "No directory port found, using 389 as default.\n");
01628 port = 389;
01629 }
01630
01631 snprintf(url, sizeof(url), "ldap://%s:%d", host, port);
01632 } else {
01633 ast_log(LOG_ERROR, "No directory URL or host found.\n");
01634 ast_config_destroy(config);
01635 return -1;
01636 }
01637
01638 if (!(s = ast_variable_retrieve(config, "_general", "basedn"))) {
01639 ast_log(LOG_ERROR, "No LDAP base dn found, using '%s' as default.\n", RES_CONFIG_LDAP_DEFAULT_BASEDN);
01640 ast_copy_string(base_distinguished_name, RES_CONFIG_LDAP_DEFAULT_BASEDN, sizeof(base_distinguished_name));
01641 } else
01642 ast_copy_string(base_distinguished_name, s, sizeof(base_distinguished_name));
01643
01644 if (!(s = ast_variable_retrieve(config, "_general", "version")) && !(s = ast_variable_retrieve(config, "_general", "protocol"))) {
01645 ast_log(LOG_NOTICE, "No explicit LDAP version found, using 3 as default.\n");
01646 version = 3;
01647 } else if (sscanf(s, "%30d", &version) != 1 || version < 1 || version > 6) {
01648 ast_log(LOG_WARNING, "Invalid LDAP version '%s', using 3 as default.\n", s);
01649 version = 3;
01650 }
01651
01652 table_configs_free();
01653
01654 while ((category_name = ast_category_browse(config, category_name))) {
01655 int is_general = (strcasecmp(category_name, "_general") == 0);
01656 int is_config = (strcasecmp(category_name, "config") == 0);
01657 struct ast_variable *var = ast_variable_browse(config, category_name);
01658
01659 if (var) {
01660 struct ldap_table_config *table_config =
01661 table_config_for_table_name(category_name);
01662 if (!table_config) {
01663 table_config = table_config_new(category_name);
01664 AST_LIST_INSERT_HEAD(&table_configs, table_config, entry);
01665 if (is_general)
01666 base_table_config = table_config;
01667 if (is_config)
01668 static_table_config = table_config;
01669 }
01670 for (; var; var = var->next) {
01671 if (!strcasecmp(var->name, "additionalFilter")) {
01672 table_config->additional_filter = ast_strdup(var->value);
01673 } else {
01674 ldap_table_config_add_attribute(table_config, var->name, var->value);
01675 }
01676 }
01677 }
01678 }
01679
01680 ast_config_destroy(config);
01681
01682 return 1;
01683 }
01684
01685
01686 static int ldap_reconnect(void)
01687 {
01688 int bind_result = 0;
01689 struct berval cred;
01690
01691 if (ldapConn) {
01692 ast_debug(2, "Everything seems fine.\n");
01693 return 1;
01694 }
01695
01696 if (ast_strlen_zero(url)) {
01697 ast_log(LOG_ERROR, "Not enough parameters to connect to ldap database\n");
01698 return 0;
01699 }
01700
01701 if (LDAP_SUCCESS != ldap_initialize(&ldapConn, url)) {
01702 ast_log(LOG_ERROR, "Failed to init ldap connection to '%s'. Check debug for more info.\n", url);
01703 return 0;
01704 }
01705
01706 if (LDAP_OPT_SUCCESS != ldap_set_option(ldapConn, LDAP_OPT_PROTOCOL_VERSION, &version)) {
01707 ast_log(LOG_WARNING, "Unable to set LDAP protocol version to %d, falling back to default.\n", version);
01708 }
01709
01710 if (!ast_strlen_zero(user)) {
01711 ast_debug(2, "bind to '%s' as user '%s'\n", url, user);
01712 cred.bv_val = (char *) pass;
01713 cred.bv_len = strlen(pass);
01714 bind_result = ldap_sasl_bind_s(ldapConn, user, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
01715 } else {
01716 ast_debug(2, "bind %s anonymously\n", url);
01717 cred.bv_val = NULL;
01718 cred.bv_len = 0;
01719 bind_result = ldap_sasl_bind_s(ldapConn, NULL, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
01720 }
01721 if (bind_result == LDAP_SUCCESS) {
01722 ast_debug(2, "Successfully connected to database.\n");
01723 connect_time = time(NULL);
01724 return 1;
01725 } else {
01726 ast_log(LOG_WARNING, "bind failed: %s\n", ldap_err2string(bind_result));
01727 ldap_unbind_ext_s(ldapConn, NULL, NULL);
01728 ldapConn = NULL;
01729 return 0;
01730 }
01731 }
01732
01733 static char *realtime_ldap_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01734 {
01735 char status[256], credentials[100] = "";
01736 int ctimesec = time(NULL) - connect_time;
01737
01738 switch (cmd) {
01739 case CLI_INIT:
01740 e->command = "realtime show ldap status";
01741 e->usage =
01742 "Usage: realtime show ldap status\n"
01743 " Shows connection information for the LDAP RealTime driver\n";
01744 return NULL;
01745 case CLI_GENERATE:
01746 return NULL;
01747 }
01748
01749 if (!ldapConn)
01750 return CLI_FAILURE;
01751
01752 if (!ast_strlen_zero(url))
01753 snprintf(status, sizeof(status), "Connected to '%s', baseDN %s", url, base_distinguished_name);
01754
01755 if (!ast_strlen_zero(user))
01756 snprintf(credentials, sizeof(credentials), " with username %s", user);
01757
01758 if (ctimesec > 31536000) {
01759 ast_cli(a->fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n",
01760 status, credentials, ctimesec / 31536000,
01761 (ctimesec % 31536000) / 86400, (ctimesec % 86400) / 3600,
01762 (ctimesec % 3600) / 60, ctimesec % 60);
01763 } else if (ctimesec > 86400) {
01764 ast_cli(a->fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n",
01765 status, credentials, ctimesec / 86400, (ctimesec % 86400) / 3600,
01766 (ctimesec % 3600) / 60, ctimesec % 60);
01767 } else if (ctimesec > 3600) {
01768 ast_cli(a->fd, "%s%s for %d hours, %d minutes, %d seconds.\n",
01769 status, credentials, ctimesec / 3600, (ctimesec % 3600) / 60,
01770 ctimesec % 60);
01771 } else if (ctimesec > 60) {
01772 ast_cli(a->fd, "%s%s for %d minutes, %d seconds.\n", status, credentials,
01773 ctimesec / 60, ctimesec % 60);
01774 } else {
01775 ast_cli(a->fd, "%s%s for %d seconds.\n", status, credentials, ctimesec);
01776 }
01777
01778 return CLI_SUCCESS;
01779 }
01780
01781 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "LDAP realtime interface",
01782 .load = load_module,
01783 .unload = unload_module,
01784 .reload = reload,
01785 );