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