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
00039 #include "asterisk.h"
00040
00041 #include <stdlib.h>
00042 #include <string.h>
00043 #include <ctype.h>
00044 #include <stdio.h>
00045 #include <ldap.h>
00046
00047 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 385199 $")
00048
00049 #include "asterisk/channel.h"
00050 #include "asterisk/logger.h"
00051 #include "asterisk/config.h"
00052 #include "asterisk/module.h"
00053 #include "asterisk/lock.h"
00054 #include "asterisk/options.h"
00055 #include "asterisk/cli.h"
00056 #include "asterisk/utils.h"
00057 #include "asterisk/strings.h"
00058 #include "asterisk/pbx.h"
00059 #include "asterisk/linkedlists.h"
00060
00061 #define RES_CONFIG_LDAP_CONF "res_ldap.conf"
00062 #define RES_CONFIG_LDAP_DEFAULT_BASEDN "asterisk"
00063
00064 AST_MUTEX_DEFINE_STATIC(ldap_lock);
00065
00066 static LDAP *ldapConn;
00067 static char url[512];
00068 static char user[512];
00069 static char pass[512];
00070 static char base_distinguished_name[512];
00071 static int version;
00072 static time_t connect_time;
00073
00074 static int parse_config(void);
00075 static int ldap_reconnect(void);
00076 static char *realtime_ldap_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
00077
00078 struct category_and_metric {
00079 const char *name;
00080 int metric;
00081 const char *variable_name;
00082 const char *variable_value;
00083 int var_metric;
00084 };
00085
00086
00087 struct ldap_table_config {
00088 char *table_name;
00089 char *additional_filter;
00090 struct ast_variable *attributes;
00091 struct ast_variable *delimiters;
00092 AST_LIST_ENTRY(ldap_table_config) entry;
00093
00094 };
00095
00096
00097 static AST_LIST_HEAD_NOLOCK_STATIC(table_configs, ldap_table_config);
00098 static struct ldap_table_config *base_table_config;
00099 static struct ldap_table_config *static_table_config;
00100
00101 static struct ast_cli_entry ldap_cli[] = {
00102 AST_CLI_DEFINE(realtime_ldap_status, "Shows connection information for the LDAP RealTime driver"),
00103 };
00104
00105
00106 static struct ldap_table_config *table_config_new(const char *table_name)
00107 {
00108 struct ldap_table_config *p;
00109
00110 if (!(p = ast_calloc(1, sizeof(*p))))
00111 return NULL;
00112
00113 if (table_name) {
00114 if (!(p->table_name = ast_strdup(table_name))) {
00115 free(p);
00116 return NULL;
00117 }
00118 }
00119
00120 return p;
00121 }
00122
00123
00124
00125 static struct ldap_table_config *table_config_for_table_name(const char *table_name)
00126 {
00127 struct ldap_table_config *c = NULL;
00128
00129 AST_LIST_TRAVERSE(&table_configs, c, entry) {
00130 if (!strcmp(c->table_name, table_name))
00131 break;
00132 }
00133
00134 return c;
00135 }
00136
00137
00138 static struct ast_variable *variable_named(struct ast_variable *var, const char *name)
00139 {
00140 for (; var; var = var->next) {
00141 if (!strcasecmp(name, var->name))
00142 break;
00143 }
00144
00145 return var;
00146 }
00147
00148
00149
00150
00151
00152
00153 static int semicolon_count_str(const char *somestr)
00154 {
00155 int count = 0;
00156
00157 for (; *somestr; somestr++) {
00158 if (*somestr == ';')
00159 count++;
00160 }
00161
00162 return count;
00163 }
00164
00165
00166
00167
00168 static int semicolon_count_var(struct ast_variable *var)
00169 {
00170 struct ast_variable *var_value = variable_named(var, "variable_value");
00171
00172 if (!var_value) {
00173 return 0;
00174 }
00175
00176 ast_debug(2, "LINE(%d) semicolon_count_var: %s\n", __LINE__, var_value->value);
00177
00178 return semicolon_count_str(var_value->value);
00179 }
00180
00181
00182 static void ldap_table_config_add_attribute(struct ldap_table_config *table_config,
00183 const char *attribute_name, const char *attribute_value)
00184 {
00185 struct ast_variable *var;
00186
00187 if (ast_strlen_zero(attribute_name) || ast_strlen_zero(attribute_value)) {
00188 return;
00189 }
00190
00191 if (!(var = ast_variable_new(attribute_name, attribute_value, table_config->table_name))) {
00192 return;
00193 }
00194
00195 if (table_config->attributes) {
00196 var->next = table_config->attributes;
00197 }
00198 table_config->attributes = var;
00199 }
00200
00201
00202
00203 static void table_configs_free(void)
00204 {
00205 struct ldap_table_config *c;
00206
00207 while ((c = AST_LIST_REMOVE_HEAD(&table_configs, entry))) {
00208 if (c->table_name) {
00209 ast_free(c->table_name);
00210 }
00211 if (c->additional_filter) {
00212 ast_free(c->additional_filter);
00213 }
00214 if (c->attributes) {
00215 ast_variables_destroy(c->attributes);
00216 }
00217 free(c);
00218 }
00219
00220 base_table_config = NULL;
00221 static_table_config = NULL;
00222 }
00223
00224
00225 static const char *convert_attribute_name_to_ldap(struct ldap_table_config *table_config,
00226 const char *attribute_name)
00227 {
00228 int i = 0;
00229 struct ldap_table_config *configs[] = { table_config, base_table_config };
00230
00231 for (i = 0; i < ARRAY_LEN(configs); i++) {
00232 struct ast_variable *attribute;
00233
00234 if (!configs[i]) {
00235 continue;
00236 }
00237
00238 attribute = configs[i]->attributes;
00239 for (; attribute; attribute = attribute->next) {
00240 if (!strcasecmp(attribute_name, attribute->name)) {
00241 return attribute->value;
00242 }
00243 }
00244 }
00245
00246 return attribute_name;
00247 }
00248
00249
00250
00251 static const char *convert_attribute_name_from_ldap(struct ldap_table_config *table_config,
00252 const char *attribute_name)
00253 {
00254 int i = 0;
00255 struct ldap_table_config *configs[] = { table_config, base_table_config };
00256
00257 for (i = 0; i < ARRAY_LEN(configs); i++) {
00258 struct ast_variable *attribute;
00259
00260 if (!configs[i]) {
00261 continue;
00262 }
00263
00264 attribute = configs[i]->attributes;
00265 for (; attribute; attribute = attribute->next) {
00266 if (strcasecmp(attribute_name, attribute->value) == 0) {
00267 return attribute->name;
00268 }
00269 }
00270 }
00271
00272 return attribute_name;
00273 }
00274
00275
00276
00277
00278
00279 static struct ast_variable *realtime_ldap_entry_to_var(struct ldap_table_config *table_config,
00280 LDAPMessage *ldap_entry)
00281 {
00282 BerElement *ber = NULL;
00283 struct ast_variable *var = NULL;
00284 struct ast_variable *prev = NULL;
00285 int is_delimited = 0;
00286 int i = 0;
00287 char *ldap_attribute_name;
00288 struct berval *value;
00289 int pos = 0;
00290
00291 ldap_attribute_name = ldap_first_attribute(ldapConn, ldap_entry, &ber);
00292
00293 while (ldap_attribute_name) {
00294 struct berval **values = NULL;
00295 const char *attribute_name = convert_attribute_name_from_ldap(table_config, ldap_attribute_name);
00296 int is_realmed_password_attribute = strcasecmp(attribute_name, "md5secret") == 0;
00297
00298 values = ldap_get_values_len(ldapConn, ldap_entry, ldap_attribute_name);
00299 if (values) {
00300 struct berval **v;
00301 char *valptr;
00302
00303 for (v = values; *v; v++) {
00304 value = *v;
00305 valptr = value->bv_val;
00306 ast_debug(2, "LINE(%d) attribute_name: %s LDAP value: %s\n", __LINE__, attribute_name, valptr);
00307 if (is_realmed_password_attribute) {
00308 if (!strncasecmp(valptr, "{md5}", 5)) {
00309 valptr += 5;
00310 }
00311 ast_debug(2, "md5: %s\n", valptr);
00312 }
00313 if (valptr) {
00314
00315 if (is_delimited) {
00316 i = 0;
00317 pos = 0;
00318 while (!ast_strlen_zero(valptr + i)) {
00319 if (valptr[i] == ';') {
00320 valptr[i] = '\0';
00321 if (prev) {
00322 prev->next = ast_variable_new(attribute_name, &valptr[pos], table_config->table_name);
00323 if (prev->next) {
00324 prev = prev->next;
00325 }
00326 } else {
00327 prev = var = ast_variable_new(attribute_name, &valptr[pos], table_config->table_name);
00328 }
00329 pos = i + 1;
00330 }
00331 i++;
00332 }
00333 }
00334
00335 if (prev) {
00336 prev->next = ast_variable_new(attribute_name, &valptr[pos], table_config->table_name);
00337 if (prev->next) {
00338 prev = prev->next;
00339 }
00340 } else {
00341 prev = var = ast_variable_new(attribute_name, &valptr[pos], table_config->table_name);
00342 }
00343 }
00344 }
00345 ldap_value_free_len(values);
00346 }
00347 ldap_memfree(ldap_attribute_name);
00348 ldap_attribute_name = ldap_next_attribute(ldapConn, ldap_entry, ber);
00349 }
00350 ber_free(ber, 0);
00351
00352 return var;
00353 }
00354
00355
00356
00357
00358
00359
00360
00361 static struct ast_variable **realtime_ldap_result_to_vars(struct ldap_table_config *table_config,
00362 LDAPMessage *ldap_result_msg, unsigned int *entries_count_ptr)
00363 {
00364 struct ast_variable **vars;
00365 int i = 0;
00366 int tot_count = 0;
00367 int entry_index = 0;
00368 LDAPMessage *ldap_entry = NULL;
00369 BerElement *ber = NULL;
00370 struct ast_variable *var = NULL;
00371 struct ast_variable *prev = NULL;
00372 int is_delimited = 0;
00373 char *delim_value = NULL;
00374 int delim_tot_count = 0;
00375 int delim_count = 0;
00376
00377
00378 ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
00379
00380 for (tot_count = 0; ldap_entry; tot_count++) {
00381 struct ast_variable *tmp = realtime_ldap_entry_to_var(table_config, ldap_entry);
00382 tot_count += semicolon_count_var(tmp);
00383 ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
00384 ast_variables_destroy(tmp);
00385 }
00386
00387 if (entries_count_ptr) {
00388 *entries_count_ptr = tot_count;
00389 }
00390
00391
00392
00393
00394
00395
00396 vars = ast_calloc(sizeof(struct ast_variable *), tot_count + 1);
00397
00398 ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
00399
00400 i = 0;
00401
00402
00403 for (entry_index = 0; ldap_entry; ) {
00404 int pos = 0;
00405 delim_value = NULL;
00406 delim_tot_count = 0;
00407 delim_count = 0;
00408
00409 do {
00410
00411
00412 char *ldap_attribute_name = ldap_first_attribute(ldapConn, ldap_entry, &ber);
00413 struct berval *value;
00414 while (ldap_attribute_name) {
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
00613
00614 var = *vars;
00615
00616
00617 while (*++p) {
00618 ast_variables_destroy(*p);
00619 }
00620 ast_free(vars);
00621 }
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_debug(1, "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
00868
00869
00870
00871
00872 if (append_var) {
00873 base_var->next = append_var;
00874 } else {
00875 base_var->next = NULL;
00876 }
00877 append_var = base_var;
00878 base_var = next;
00879 }
00880 }
00881 }
00882 if (!tmp->next && append_var) {
00883 tmp->next = append_var;
00884 tmp = NULL;
00885 } else {
00886 tmp = tmp->next;
00887 }
00888 }
00889 p++;
00890 }
00891 }
00892 }
00893
00894 if (filter) {
00895 ast_free(filter);
00896 }
00897
00898 if (clean_basedn) {
00899 ast_free(clean_basedn);
00900 }
00901
00902 ast_mutex_unlock(&ldap_lock);
00903
00904 return vars;
00905 }
00906
00907
00908 static struct ast_variable **realtime_ldap_base(unsigned int *entries_count_ptr,
00909 const char *basedn, const char *table_name, ...)
00910 {
00911 struct ast_variable **vars = NULL;
00912 va_list ap;
00913
00914 va_start(ap, table_name);
00915 vars = realtime_ldap_base_ap(entries_count_ptr, basedn, table_name, ap);
00916 va_end(ap);
00917
00918 return vars;
00919 }
00920
00921
00922
00923
00924
00925 static struct ast_variable *realtime_ldap(const char *basedn,
00926 const char *table_name, va_list ap)
00927 {
00928 struct ast_variable **vars = realtime_ldap_base_ap(NULL, basedn, table_name, ap);
00929 struct ast_variable *var = NULL;
00930
00931 if (vars) {
00932 struct ast_variable *last_var = NULL;
00933 struct ast_variable **p = vars;
00934
00935
00936 while (*p) {
00937 if (last_var) {
00938 while (last_var->next) {
00939 last_var = last_var->next;
00940 }
00941 last_var->next = *p;
00942 } else {
00943 var = *p;
00944 last_var = var;
00945 }
00946 p++;
00947 }
00948 free(vars);
00949 }
00950 return var;
00951 }
00952
00953
00954
00955
00956
00957
00958
00959
00960 static struct ast_config *realtime_multi_ldap(const char *basedn,
00961 const char *table_name, va_list ap)
00962 {
00963 char *op;
00964 const char *initfield = NULL;
00965 const char *newparam, *newval;
00966 struct ast_variable **vars =
00967 realtime_ldap_base_ap(NULL, basedn, table_name, ap);
00968 struct ast_config *cfg = NULL;
00969
00970 newparam = va_arg(ap, const char *);
00971 newval = va_arg(ap, const char *);
00972 if (!newparam || !newval) {
00973 ast_log(LOG_WARNING, "realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
00974 return NULL;
00975 }
00976 initfield = ast_strdupa(newparam);
00977 if ((op = strchr(initfield, ' '))) {
00978 *op = '\0';
00979 }
00980
00981 if (vars) {
00982 cfg = ast_config_new();
00983 if (!cfg) {
00984 ast_log(LOG_ERROR, "Unable to create a config!\n");
00985 } else {
00986 struct ast_variable **p = vars;
00987
00988 while (*p) {
00989 struct ast_category *cat = NULL;
00990 cat = ast_category_new("", table_name, -1);
00991 if (!cat) {
00992 ast_log(LOG_ERROR, "Unable to create a new category!\n");
00993 break;
00994 } else {
00995 struct ast_variable *var = *p;
00996 while (var) {
00997 struct ast_variable *next = var->next;
00998 if (initfield && !strcmp(initfield, var->name)) {
00999 ast_category_rename(cat, var->value);
01000 }
01001 var->next = NULL;
01002 ast_variable_append(cat, var);
01003 var = next;
01004 }
01005 }
01006 ast_category_append(cfg, cat);
01007 p++;
01008 }
01009 }
01010 free(vars);
01011 }
01012 return cfg;
01013
01014 }
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025 static int compare_categories(const void *a, const void *b)
01026 {
01027 const struct category_and_metric *as = a;
01028 const struct category_and_metric *bs = b;
01029
01030 if (as->metric < bs->metric) {
01031 return -1;
01032 } else if (as->metric > bs->metric) {
01033 return 1;
01034 } else if (as->metric == bs->metric && strcmp(as->name, bs->name) != 0) {
01035 return strcmp(as->name, bs->name);
01036 }
01037
01038 if (as->var_metric < bs->var_metric) {
01039 return -1;
01040 } else if (as->var_metric > bs->var_metric) {
01041 return 1;
01042 }
01043
01044 return 0;
01045 }
01046
01047
01048
01049
01050
01051
01052
01053
01054 static struct ast_config *config_ldap(const char *basedn, const char *table_name,
01055 const char *file, struct ast_config *cfg, struct ast_flags config_flags, const char *sugg_incl, const char *who_asked)
01056 {
01057 unsigned int vars_count = 0;
01058 struct ast_variable **vars;
01059 int i = 0;
01060 struct ast_variable *new_v = NULL;
01061 struct ast_category *cur_cat = NULL;
01062 const char *last_category = NULL;
01063 int last_category_metric = 0;
01064 struct category_and_metric *categories;
01065 struct ast_variable **p;
01066
01067 if (ast_strlen_zero(file) || !strcasecmp(file, RES_CONFIG_LDAP_CONF)) {
01068 ast_log(LOG_ERROR, "Missing configuration file: %s. Can't configure myself.\n", RES_CONFIG_LDAP_CONF);
01069 return NULL;
01070 }
01071
01072 vars = realtime_ldap_base(&vars_count, basedn, table_name, "filename", file, "commented", "FALSE", NULL);
01073
01074 if (!vars) {
01075 ast_log(LOG_WARNING, "Could not find config '%s' in directory.\n", file);
01076 return NULL;
01077 }
01078
01079
01080
01081
01082
01083 if (!(categories = ast_calloc(sizeof(*categories), vars_count))) {
01084 return NULL;
01085 }
01086
01087 for (vars_count = 0, p = vars; *p; p++) {
01088 struct ast_variable *category = variable_named(*p, "category");
01089 struct ast_variable *cat_metric = variable_named(*p, "cat_metric");
01090 struct ast_variable *var_name = variable_named(*p, "variable_name");
01091 struct ast_variable *var_val = variable_named(*p, "variable_value");
01092 struct ast_variable *var_metric = variable_named(*p, "var_metric");
01093 struct ast_variable *dn = variable_named(*p, "dn");
01094
01095 if (!category) {
01096 ast_log(LOG_ERROR, "No category name in entry '%s' for file '%s'.\n",
01097 (dn ? dn->value : "?"), file);
01098 } else if (!cat_metric) {
01099 ast_log(LOG_ERROR, "No category metric in entry '%s'(category: %s) for file '%s'.\n",
01100 (dn ? dn->value : "?"), category->value, file);
01101 } else if (!var_metric) {
01102 ast_log(LOG_ERROR, "No variable metric in entry '%s'(category: %s) for file '%s'.\n",
01103 (dn ? dn->value : "?"), category->value, file);
01104 } else if (!var_name) {
01105 ast_log(LOG_ERROR, "No variable name in entry '%s' (category: %s metric: %s) for file '%s'.\n",
01106 (dn ? dn->value : "?"), category->value,
01107 cat_metric->value, file);
01108 } else if (!var_val) {
01109 ast_log(LOG_ERROR, "No variable value in entry '%s' (category: %s metric: %s variable: %s) for file '%s'.\n",
01110 (dn ? dn->value : "?"), category->value,
01111 cat_metric->value, var_name->value, file);
01112 } else {
01113 categories[vars_count].name = category->value;
01114 categories[vars_count].metric = atoi(cat_metric->value);
01115 categories[vars_count].variable_name = var_name->value;
01116 categories[vars_count].variable_value = var_val->value;
01117 categories[vars_count].var_metric = atoi(var_metric->value);
01118 vars_count++;
01119 }
01120
01121 ast_debug(3, "category: %s\n", category->value);
01122 ast_debug(3, "var_name: %s\n", var_name->value);
01123 ast_debug(3, "var_val: %s\n", var_val->value);
01124 ast_debug(3, "cat_metric: %s\n", cat_metric->value);
01125
01126 }
01127
01128 qsort(categories, vars_count, sizeof(*categories), compare_categories);
01129
01130 for (i = 0; i < vars_count; i++) {
01131 if (!strcmp(categories[i].variable_name, "#include")) {
01132 struct ast_flags flags = { 0 };
01133 if (!ast_config_internal_load(categories[i].variable_value, cfg, flags, "", who_asked)) {
01134 break;
01135 }
01136 continue;
01137 }
01138
01139 if (!last_category || strcmp(last_category, categories[i].name) ||
01140 last_category_metric != categories[i].metric) {
01141
01142 cur_cat = ast_category_new(categories[i].name, table_name, -1);
01143 if (!cur_cat) {
01144 break;
01145 }
01146 last_category = categories[i].name;
01147 last_category_metric = categories[i].metric;
01148 ast_category_append(cfg, cur_cat);
01149 }
01150
01151 if (!(new_v = ast_variable_new(categories[i].variable_name, categories[i].variable_value, table_name))) {
01152 break;
01153 }
01154
01155 ast_variable_append(cur_cat, new_v);
01156 }
01157
01158 ast_free(vars);
01159 ast_free(categories);
01160
01161 return cfg;
01162 }
01163
01164
01165
01166 static int update_ldap(const char *basedn, const char *table_name, const char *attribute,
01167 const char *lookup, va_list ap)
01168 {
01169 int error = 0;
01170 LDAPMessage *ldap_entry = NULL;
01171 LDAPMod **ldap_mods;
01172 const char *newparam = NULL;
01173 const char *newval = NULL;
01174 char *dn;
01175 int num_entries = 0;
01176 int i = 0;
01177 int mods_size = 0;
01178 int mod_exists = 0;
01179 struct ldap_table_config *table_config = NULL;
01180 char *clean_basedn = NULL;
01181 struct ast_str *filter = NULL;
01182 int tries = 0;
01183 int result = 0;
01184 LDAPMessage *ldap_result_msg = NULL;
01185
01186 if (!table_name) {
01187 ast_log(LOG_ERROR, "No table_name specified.\n");
01188 return -1;
01189 }
01190
01191 if (!(filter = ast_str_create(80))) {
01192 return -1;
01193 }
01194
01195 if (!attribute || !lookup) {
01196 ast_log(LOG_WARNING, "LINE(%d): search parameters are empty.\n", __LINE__);
01197 return -1;
01198 }
01199 ast_mutex_lock(&ldap_lock);
01200
01201
01202 if (!ldap_reconnect()) {
01203 ast_mutex_unlock(&ldap_lock);
01204 return -1;
01205 }
01206
01207 table_config = table_config_for_table_name(table_name);
01208 if (!table_config) {
01209 ast_log(LOG_ERROR, "No table named '%s'.\n", table_name);
01210 ast_mutex_unlock(&ldap_lock);
01211 return -1;
01212 }
01213
01214 clean_basedn = cleaned_basedn(NULL, basedn);
01215
01216
01217 ast_str_append(&filter, 0, "(&");
01218 if (table_config && table_config->additional_filter) {
01219 ast_str_append(&filter, 0, "%s", table_config->additional_filter);
01220 }
01221 if (table_config != base_table_config && base_table_config && base_table_config->additional_filter) {
01222 ast_str_append(&filter, 0, "%s", base_table_config->additional_filter);
01223 }
01224 append_var_and_value_to_filter(&filter, table_config, attribute, lookup);
01225 ast_str_append(&filter, 0, ")");
01226
01227
01228
01229
01230 newparam = va_arg(ap, const char *);
01231 newparam = convert_attribute_name_to_ldap(table_config, newparam);
01232 newval = va_arg(ap, const char *);
01233 if (!newparam || !newval) {
01234 ast_log(LOG_WARNING, "LINE(%d): need at least one parameter to modify.\n", __LINE__);
01235 return -1;
01236 }
01237
01238 mods_size = 2;
01239 ldap_mods = ldap_memcalloc(sizeof(LDAPMod *), mods_size);
01240 ldap_mods[0] = ldap_memcalloc(1, sizeof(LDAPMod));
01241
01242 ldap_mods[0]->mod_op = LDAP_MOD_REPLACE;
01243 ldap_mods[0]->mod_type = ldap_strdup(newparam);
01244
01245 ldap_mods[0]->mod_values = ast_calloc(sizeof(char *), 2);
01246 ldap_mods[0]->mod_values[0] = ldap_strdup(newval);
01247
01248 while ((newparam = va_arg(ap, const char *))) {
01249 newparam = convert_attribute_name_to_ldap(table_config, newparam);
01250 newval = va_arg(ap, const char *);
01251 mod_exists = 0;
01252
01253 for (i = 0; i < mods_size - 1; i++) {
01254 if (ldap_mods[i]&& !strcmp(ldap_mods[i]->mod_type, newparam)) {
01255
01256 ldap_mods[i]->mod_values[0] = ldap_memrealloc(ldap_mods[i]->mod_values[0], sizeof(char) * (strlen(ldap_mods[i]->mod_values[0]) + strlen(newval) + 2));
01257 strcat(ldap_mods[i]->mod_values[0], ";");
01258 strcat(ldap_mods[i]->mod_values[0], newval);
01259 mod_exists = 1;
01260 break;
01261 }
01262 }
01263
01264
01265 if (!mod_exists) {
01266 mods_size++;
01267 ldap_mods = ldap_memrealloc(ldap_mods, sizeof(LDAPMod *) * mods_size);
01268 ldap_mods[mods_size - 1] = NULL;
01269
01270 ldap_mods[mods_size - 2] = ldap_memcalloc(1, sizeof(LDAPMod));
01271
01272 ldap_mods[mods_size - 2]->mod_type = ldap_memcalloc(sizeof(char), strlen(newparam) + 1);
01273 strcpy(ldap_mods[mods_size - 2]->mod_type, newparam);
01274
01275 if (strlen(newval) == 0) {
01276 ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_DELETE;
01277 } else {
01278 ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_REPLACE;
01279
01280 ldap_mods[mods_size - 2]->mod_values = ldap_memcalloc(sizeof(char *), 2);
01281 ldap_mods[mods_size - 2]->mod_values[0] = ldap_memcalloc(sizeof(char), strlen(newval) + 1);
01282 strcpy(ldap_mods[mods_size - 2]->mod_values[0], newval);
01283 }
01284 }
01285 }
01286
01287
01288 do {
01289
01290 result = ldap_search_ext_s(ldapConn, clean_basedn,
01291 LDAP_SCOPE_SUBTREE, ast_str_buffer(filter), NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
01292 &ldap_result_msg);
01293 if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
01294 ast_log(LOG_WARNING, "Failed to query directory. Try %d/3\n", tries + 1);
01295 tries++;
01296 if (tries < 3) {
01297 usleep(500000L * tries);
01298 if (ldapConn) {
01299 ldap_unbind_ext_s(ldapConn, NULL, NULL);
01300 ldapConn = NULL;
01301 }
01302 if (!ldap_reconnect())
01303 break;
01304 }
01305 }
01306 } while (result != LDAP_SUCCESS && tries < 3 && is_ldap_connect_error(result));
01307
01308 if (result != LDAP_SUCCESS) {
01309 ast_log(LOG_WARNING, "Failed to query directory. Error: %s.\n", ldap_err2string(result));
01310 ast_log(LOG_WARNING, "Query: %s\n", ast_str_buffer(filter));
01311
01312 ast_mutex_unlock(&ldap_lock);
01313 free(filter);
01314 free(clean_basedn);
01315 ldap_msgfree(ldap_result_msg);
01316 ldap_mods_free(ldap_mods, 0);
01317 return -1;
01318 }
01319
01320 if ((num_entries = ldap_count_entries(ldapConn, ldap_result_msg)) > 0) {
01321 ast_debug(3, "LINE(%d) Modifying %s=%s hits: %d\n", __LINE__, attribute, lookup, num_entries);
01322 for (i = 0; option_debug > 2 && i < mods_size - 1; i++) {
01323 if (ldap_mods[i]->mod_op != LDAP_MOD_DELETE) {
01324 ast_debug(3, "LINE(%d) %s=%s \n", __LINE__, ldap_mods[i]->mod_type, ldap_mods[i]->mod_values[0]);
01325 } else {
01326 ast_debug(3, "LINE(%d) deleting %s \n", __LINE__, ldap_mods[i]->mod_type);
01327 }
01328 }
01329 ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
01330
01331 for (i = 0; ldap_entry; i++) {
01332 dn = ldap_get_dn(ldapConn, ldap_entry);
01333 if ((error = ldap_modify_ext_s(ldapConn, dn, ldap_mods, NULL, NULL)) != LDAP_SUCCESS) {
01334 ast_log(LOG_ERROR, "Couldn't modify '%s'='%s', dn:%s because %s\n",
01335 attribute, lookup, dn, ldap_err2string(error));
01336 }
01337 ldap_memfree(dn);
01338 ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
01339 }
01340 }
01341
01342 ast_mutex_unlock(&ldap_lock);
01343 ast_free(filter);
01344 ast_free(clean_basedn);
01345 ldap_msgfree(ldap_result_msg);
01346 ldap_mods_free(ldap_mods, 0);
01347 return num_entries;
01348 }
01349
01350 static int update2_ldap(const char *basedn, const char *table_name, va_list ap)
01351 {
01352 int error = 0;
01353 LDAPMessage *ldap_entry = NULL;
01354 LDAPMod **ldap_mods;
01355 const char *newparam = NULL;
01356 const char *newval = NULL;
01357 char *dn;
01358 int num_entries = 0;
01359 int i = 0;
01360 int mods_size = 0;
01361 int mod_exists = 0;
01362 struct ldap_table_config *table_config = NULL;
01363 char *clean_basedn = NULL;
01364 struct ast_str *filter = NULL;
01365 int tries = 0;
01366 int result = 0;
01367 LDAPMessage *ldap_result_msg = NULL;
01368
01369 if (!table_name) {
01370 ast_log(LOG_ERROR, "No table_name specified.\n");
01371 return -1;
01372 }
01373
01374 if (!(filter = ast_str_create(80))) {
01375 return -1;
01376 }
01377
01378 ast_mutex_lock(&ldap_lock);
01379
01380
01381 if (!ldap_reconnect()) {
01382 ast_mutex_unlock(&ldap_lock);
01383 ast_free(filter);
01384 return -1;
01385 }
01386
01387 table_config = table_config_for_table_name(table_name);
01388 if (!table_config) {
01389 ast_log(LOG_ERROR, "No table named '%s'.\n", table_name);
01390 ast_mutex_unlock(&ldap_lock);
01391 ast_free(filter);
01392 return -1;
01393 }
01394
01395 clean_basedn = cleaned_basedn(NULL, basedn);
01396
01397
01398 ast_str_append(&filter, 0, "(&");
01399 if (table_config && table_config->additional_filter) {
01400 ast_str_append(&filter, 0, "%s", table_config->additional_filter);
01401 }
01402 if (table_config != base_table_config && base_table_config
01403 && base_table_config->additional_filter) {
01404 ast_str_append(&filter, 0, "%s", base_table_config->additional_filter);
01405 }
01406
01407
01408 while ((newparam = va_arg(ap, const char *))) {
01409 newval = va_arg(ap, const char *);
01410 append_var_and_value_to_filter(&filter, table_config, newparam, newval);
01411 }
01412 ast_str_append(&filter, 0, ")");
01413
01414
01415
01416
01417 newparam = va_arg(ap, const char *);
01418 newparam = convert_attribute_name_to_ldap(table_config, newparam);
01419 newval = va_arg(ap, const char *);
01420 if (!newparam || !newval) {
01421 ast_log(LOG_WARNING, "LINE(%d): need at least one parameter to modify.\n", __LINE__);
01422 ast_free(filter);
01423 ast_free(clean_basedn);
01424 return -1;
01425 }
01426
01427 mods_size = 2;
01428 ldap_mods = ast_calloc(sizeof(LDAPMod *), mods_size);
01429 ldap_mods[0] = ast_calloc(1, sizeof(LDAPMod));
01430
01431 ldap_mods[0]->mod_op = LDAP_MOD_REPLACE;
01432 ldap_mods[0]->mod_type = ast_calloc(sizeof(char), strlen(newparam) + 1);
01433 strcpy(ldap_mods[0]->mod_type, newparam);
01434
01435 ldap_mods[0]->mod_values = ast_calloc(sizeof(char), 2);
01436 ldap_mods[0]->mod_values[0] = ast_calloc(sizeof(char), strlen(newval) + 1);
01437 strcpy(ldap_mods[0]->mod_values[0], newval);
01438
01439 while ((newparam = va_arg(ap, const char *))) {
01440 newparam = convert_attribute_name_to_ldap(table_config, newparam);
01441 newval = va_arg(ap, const char *);
01442 mod_exists = 0;
01443
01444 for (i = 0; i < mods_size - 1; i++) {
01445 if (ldap_mods[i]&& !strcmp(ldap_mods[i]->mod_type, newparam)) {
01446
01447 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));
01448 strcat(ldap_mods[i]->mod_values[0], ";");
01449 strcat(ldap_mods[i]->mod_values[0], newval);
01450 mod_exists = 1;
01451 break;
01452 }
01453 }
01454
01455
01456 if (!mod_exists) {
01457 mods_size++;
01458 ldap_mods = ast_realloc(ldap_mods, sizeof(LDAPMod *) * mods_size);
01459 ldap_mods[mods_size - 1] = NULL;
01460 ldap_mods[mods_size - 2] = ast_calloc(1, sizeof(LDAPMod));
01461
01462 ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_REPLACE;
01463
01464 ldap_mods[mods_size - 2]->mod_type = ast_calloc(sizeof(char), strlen(newparam) + 1);
01465 strcpy(ldap_mods[mods_size - 2]->mod_type, newparam);
01466
01467 ldap_mods[mods_size - 2]->mod_values = ast_calloc(sizeof(char *), 2);
01468 ldap_mods[mods_size - 2]->mod_values[0] = ast_calloc(sizeof(char), strlen(newval) + 1);
01469 strcpy(ldap_mods[mods_size - 2]->mod_values[0], newval);
01470 }
01471 }
01472
01473
01474 do {
01475
01476 result = ldap_search_ext_s(ldapConn, clean_basedn,
01477 LDAP_SCOPE_SUBTREE, ast_str_buffer(filter), NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
01478 &ldap_result_msg);
01479 if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
01480 ast_log(LOG_WARNING, "Failed to query directory. Try %d/3\n", tries + 1);
01481 tries++;
01482 if (tries < 3) {
01483 usleep(500000L * tries);
01484 if (ldapConn) {
01485 ldap_unbind_ext_s(ldapConn, NULL, NULL);
01486 ldapConn = NULL;
01487 }
01488 if (!ldap_reconnect()) {
01489 break;
01490 }
01491 }
01492 }
01493 } while (result != LDAP_SUCCESS && tries < 3 && is_ldap_connect_error(result));
01494
01495 if (result != LDAP_SUCCESS) {
01496 ast_log(LOG_WARNING, "Failed to query directory. Error: %s.\n", ldap_err2string(result));
01497 ast_log(LOG_WARNING, "Query: %s\n", ast_str_buffer(filter));
01498
01499 ast_mutex_unlock(&ldap_lock);
01500 ast_free(filter);
01501 ast_free(clean_basedn);
01502 ldap_msgfree(ldap_result_msg);
01503 ldap_mods_free(ldap_mods, 0);
01504 return -1;
01505 }
01506
01507 if ((num_entries = ldap_count_entries(ldapConn, ldap_result_msg)) > 0) {
01508 for (i = 0; option_debug > 2 && i < mods_size - 1; i++) {
01509 ast_debug(3, "LINE(%d) %s=%s \n", __LINE__, ldap_mods[i]->mod_type, ldap_mods[i]->mod_values[0]);
01510 }
01511
01512 ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
01513
01514 for (i = 0; ldap_entry; i++) {
01515 dn = ldap_get_dn(ldapConn, ldap_entry);
01516 if ((error = ldap_modify_ext_s(ldapConn, dn, ldap_mods, NULL, NULL)) != LDAP_SUCCESS) {
01517 ast_log(LOG_ERROR, "Couldn't modify dn:%s because %s", dn, ldap_err2string(error));
01518 }
01519 ldap_memfree(dn);
01520 ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
01521 }
01522 }
01523
01524 ast_mutex_unlock(&ldap_lock);
01525 if (filter) {
01526 ast_free(filter);
01527 }
01528 if (clean_basedn) {
01529 ast_free(clean_basedn);
01530 }
01531 ldap_msgfree(ldap_result_msg);
01532 ldap_mods_free(ldap_mods, 0);
01533 return num_entries;
01534 }
01535
01536 static struct ast_config_engine ldap_engine = {
01537 .name = "ldap",
01538 .load_func = config_ldap,
01539 .realtime_func = realtime_ldap,
01540 .realtime_multi_func = realtime_multi_ldap,
01541 .update_func = update_ldap,
01542 .update2_func = update2_ldap,
01543 };
01544
01545 static int load_module(void)
01546 {
01547 if (parse_config() < 0) {
01548 ast_log(LOG_ERROR, "Cannot load LDAP RealTime driver.\n");
01549 return 0;
01550 }
01551
01552 ast_mutex_lock(&ldap_lock);
01553
01554 if (!ldap_reconnect()) {
01555 ast_log(LOG_WARNING, "Couldn't establish connection to LDAP directory. Check debug.\n");
01556 }
01557
01558 ast_config_engine_register(&ldap_engine);
01559 ast_verb(1, "LDAP RealTime driver loaded.\n");
01560 ast_cli_register_multiple(ldap_cli, ARRAY_LEN(ldap_cli));
01561
01562 ast_mutex_unlock(&ldap_lock);
01563
01564 return 0;
01565 }
01566
01567 static int unload_module(void)
01568 {
01569
01570 ast_mutex_lock(&ldap_lock);
01571
01572 table_configs_free();
01573
01574 if (ldapConn) {
01575 ldap_unbind_ext_s(ldapConn, NULL, NULL);
01576 ldapConn = NULL;
01577 }
01578 ast_cli_unregister_multiple(ldap_cli, ARRAY_LEN(ldap_cli));
01579 ast_config_engine_deregister(&ldap_engine);
01580 ast_verb(1, "LDAP RealTime driver unloaded.\n");
01581
01582
01583 ast_mutex_unlock(&ldap_lock);
01584
01585 return 0;
01586 }
01587
01588 static int reload(void)
01589 {
01590
01591 ast_mutex_lock(&ldap_lock);
01592
01593 if (ldapConn) {
01594 ldap_unbind_ext_s(ldapConn, NULL, NULL);
01595 ldapConn = NULL;
01596 }
01597
01598 if (parse_config() < 0) {
01599 ast_log(LOG_NOTICE, "Cannot reload LDAP RealTime driver.\n");
01600 ast_mutex_unlock(&ldap_lock);
01601 return 0;
01602 }
01603
01604 if (!ldap_reconnect()) {
01605 ast_log(LOG_WARNING, "Couldn't establish connection to your directory server. Check debug.\n");
01606 }
01607
01608 ast_verb(2, "LDAP RealTime driver reloaded.\n");
01609
01610
01611 ast_mutex_unlock(&ldap_lock);
01612
01613 return 0;
01614 }
01615
01616
01617 static int parse_config(void)
01618 {
01619 struct ast_config *config;
01620 struct ast_flags config_flags = {0};
01621 const char *s, *host;
01622 int port;
01623 char *category_name = NULL;
01624
01625
01626 url[0] = '\0';
01627 user[0] = '\0';
01628 pass[0] = '\0';
01629 base_distinguished_name[0] = '\0';
01630 version = 3;
01631
01632 config = ast_config_load(RES_CONFIG_LDAP_CONF, config_flags);
01633 if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEINVALID) {
01634 ast_log(LOG_ERROR, "Cannot load configuration file: %s\n", RES_CONFIG_LDAP_CONF);
01635 return -1;
01636 }
01637
01638 if (!(s = ast_variable_retrieve(config, "_general", "user"))) {
01639 ast_log(LOG_NOTICE, "No directory user found, anonymous binding as default.\n");
01640 user[0] = '\0';
01641 } else {
01642 ast_copy_string(user, s, sizeof(user));
01643 }
01644
01645 if (!ast_strlen_zero(user)) {
01646 if (!(s = ast_variable_retrieve(config, "_general", "pass"))) {
01647 ast_log(LOG_WARNING, "No directory password found, using 'asterisk' as default.\n");
01648 ast_copy_string(pass, "asterisk", sizeof(pass));
01649 } else {
01650 ast_copy_string(pass, s, sizeof(pass));
01651 }
01652 }
01653
01654
01655 if ((s = ast_variable_retrieve(config, "_general", "url"))) {
01656 ast_copy_string(url, s, sizeof(url));
01657 } else if ((host = ast_variable_retrieve(config, "_general", "host"))) {
01658 if (!(s = ast_variable_retrieve(config, "_general", "port")) || sscanf(s, "%5d", &port) != 1 || port > 65535) {
01659 ast_log(LOG_NOTICE, "No directory port found, using 389 as default.\n");
01660 port = 389;
01661 }
01662
01663 snprintf(url, sizeof(url), "ldap://%s:%d", host, port);
01664 } else {
01665 ast_log(LOG_ERROR, "No directory URL or host found.\n");
01666 ast_config_destroy(config);
01667 return -1;
01668 }
01669
01670 if (!(s = ast_variable_retrieve(config, "_general", "basedn"))) {
01671 ast_log(LOG_ERROR, "No LDAP base dn found, using '%s' as default.\n", RES_CONFIG_LDAP_DEFAULT_BASEDN);
01672 ast_copy_string(base_distinguished_name, RES_CONFIG_LDAP_DEFAULT_BASEDN, sizeof(base_distinguished_name));
01673 } else
01674 ast_copy_string(base_distinguished_name, s, sizeof(base_distinguished_name));
01675
01676 if (!(s = ast_variable_retrieve(config, "_general", "version")) && !(s = ast_variable_retrieve(config, "_general", "protocol"))) {
01677 ast_log(LOG_NOTICE, "No explicit LDAP version found, using 3 as default.\n");
01678 } else if (sscanf(s, "%30d", &version) != 1 || version < 1 || version > 6) {
01679 ast_log(LOG_WARNING, "Invalid LDAP version '%s', using 3 as default.\n", s);
01680 version = 3;
01681 }
01682
01683 table_configs_free();
01684
01685 while ((category_name = ast_category_browse(config, category_name))) {
01686 int is_general = (strcasecmp(category_name, "_general") == 0);
01687 int is_config = (strcasecmp(category_name, "config") == 0);
01688 struct ast_variable *var = ast_variable_browse(config, category_name);
01689
01690 if (var) {
01691 struct ldap_table_config *table_config =
01692 table_config_for_table_name(category_name);
01693 if (!table_config) {
01694 table_config = table_config_new(category_name);
01695 AST_LIST_INSERT_HEAD(&table_configs, table_config, entry);
01696 if (is_general)
01697 base_table_config = table_config;
01698 if (is_config)
01699 static_table_config = table_config;
01700 }
01701 for (; var; var = var->next) {
01702 if (!strcasecmp(var->name, "additionalFilter")) {
01703 table_config->additional_filter = ast_strdup(var->value);
01704 } else {
01705 ldap_table_config_add_attribute(table_config, var->name, var->value);
01706 }
01707 }
01708 }
01709 }
01710
01711 ast_config_destroy(config);
01712
01713 return 1;
01714 }
01715
01716
01717 static int ldap_reconnect(void)
01718 {
01719 int bind_result = 0;
01720 struct berval cred;
01721
01722 if (ldapConn) {
01723 ast_debug(2, "Everything seems fine.\n");
01724 return 1;
01725 }
01726
01727 if (ast_strlen_zero(url)) {
01728 ast_log(LOG_ERROR, "Not enough parameters to connect to ldap directory\n");
01729 return 0;
01730 }
01731
01732 if (LDAP_SUCCESS != ldap_initialize(&ldapConn, url)) {
01733 ast_log(LOG_ERROR, "Failed to init ldap connection to '%s'. Check debug for more info.\n", url);
01734 return 0;
01735 }
01736
01737 if (LDAP_OPT_SUCCESS != ldap_set_option(ldapConn, LDAP_OPT_PROTOCOL_VERSION, &version)) {
01738 ast_log(LOG_WARNING, "Unable to set LDAP protocol version to %d, falling back to default.\n", version);
01739 }
01740
01741 if (!ast_strlen_zero(user)) {
01742 ast_debug(2, "bind to '%s' as user '%s'\n", url, user);
01743 cred.bv_val = (char *) pass;
01744 cred.bv_len = strlen(pass);
01745 bind_result = ldap_sasl_bind_s(ldapConn, user, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
01746 } else {
01747 ast_debug(2, "bind %s anonymously\n", url);
01748 cred.bv_val = NULL;
01749 cred.bv_len = 0;
01750 bind_result = ldap_sasl_bind_s(ldapConn, NULL, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
01751 }
01752 if (bind_result == LDAP_SUCCESS) {
01753 ast_debug(2, "Successfully connected to directory.\n");
01754 connect_time = time(NULL);
01755 return 1;
01756 } else {
01757 ast_log(LOG_WARNING, "bind failed: %s\n", ldap_err2string(bind_result));
01758 ldap_unbind_ext_s(ldapConn, NULL, NULL);
01759 ldapConn = NULL;
01760 return 0;
01761 }
01762 }
01763
01764 static char *realtime_ldap_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01765 {
01766 char status[256], credentials[100] = "";
01767 int ctimesec = time(NULL) - connect_time;
01768
01769 switch (cmd) {
01770 case CLI_INIT:
01771 e->command = "realtime show ldap status";
01772 e->usage =
01773 "Usage: realtime show ldap status\n"
01774 " Shows connection information for the LDAP RealTime driver\n";
01775 return NULL;
01776 case CLI_GENERATE:
01777 return NULL;
01778 }
01779
01780 if (!ldapConn)
01781 return CLI_FAILURE;
01782
01783 if (!ast_strlen_zero(url))
01784 snprintf(status, sizeof(status), "Connected to '%s', baseDN %s", url, base_distinguished_name);
01785
01786 if (!ast_strlen_zero(user))
01787 snprintf(credentials, sizeof(credentials), " with username %s", user);
01788
01789 if (ctimesec > 31536000) {
01790 ast_cli(a->fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n",
01791 status, credentials, ctimesec / 31536000,
01792 (ctimesec % 31536000) / 86400, (ctimesec % 86400) / 3600,
01793 (ctimesec % 3600) / 60, ctimesec % 60);
01794 } else if (ctimesec > 86400) {
01795 ast_cli(a->fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n",
01796 status, credentials, ctimesec / 86400, (ctimesec % 86400) / 3600,
01797 (ctimesec % 3600) / 60, ctimesec % 60);
01798 } else if (ctimesec > 3600) {
01799 ast_cli(a->fd, "%s%s for %d hours, %d minutes, %d seconds.\n",
01800 status, credentials, ctimesec / 3600, (ctimesec % 3600) / 60,
01801 ctimesec % 60);
01802 } else if (ctimesec > 60) {
01803 ast_cli(a->fd, "%s%s for %d minutes, %d seconds.\n", status, credentials,
01804 ctimesec / 60, ctimesec % 60);
01805 } else {
01806 ast_cli(a->fd, "%s%s for %d seconds.\n", status, credentials, ctimesec);
01807 }
01808
01809 return CLI_SUCCESS;
01810 }
01811
01812 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "LDAP realtime interface",
01813 .load = load_module,
01814 .unload = unload_module,
01815 .reload = reload,
01816 .load_pri = AST_MODPRI_REALTIME_DRIVER,
01817 );