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