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