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