summaryrefslogtreecommitdiff
path: root/res
diff options
context:
space:
mode:
Diffstat (limited to 'res')
-rw-r--r--res/res_config_curl.c7
-rw-r--r--res/res_config_ldap.c273
-rw-r--r--res/res_config_odbc.c6
-rw-r--r--res/res_config_pgsql.c59
-rw-r--r--res/res_config_sqlite.c8
-rw-r--r--res/res_config_sqlite3.c45
-rw-r--r--res/res_pjsip.c51
-rw-r--r--res/res_pjsip/pjsip_distributor.c84
-rw-r--r--res/res_pjsip_outbound_publish.c13
-rw-r--r--res/res_pjsip_outbound_registration.c13
10 files changed, 414 insertions, 145 deletions
diff --git a/res/res_config_curl.c b/res/res_config_curl.c
index a51802928..bc1a3fb35 100644
--- a/res/res_config_curl.c
+++ b/res/res_config_curl.c
@@ -184,7 +184,8 @@ static struct ast_config *realtime_multi_curl(const char *url, const char *unuse
continue;
}
- if (!(cat = ast_category_new("", "", 99999))) {
+ cat = ast_category_new_anonymous();
+ if (!cat) {
continue;
}
@@ -571,8 +572,10 @@ static struct ast_config *config_curl(const char *url, const char *unused, const
}
if (!cat || strcmp(category, cur_cat) || last_cat_metric != cat_metric) {
- if (!(cat = ast_category_new(category, "", 99999)))
+ cat = ast_category_new_dynamic(category);
+ if (!cat) {
break;
+ }
cur_cat = category;
last_cat_metric = cat_metric;
ast_category_append(cfg, cat);
diff --git a/res/res_config_ldap.c b/res/res_config_ldap.c
index fd21aab80..2489dfc93 100644
--- a/res/res_config_ldap.c
+++ b/res/res_config_ldap.c
@@ -124,7 +124,7 @@ static struct ldap_table_config *table_config_new(const char *table_name)
if (table_name) {
if (!(p->table_name = ast_strdup(table_name))) {
- free(p);
+ ast_free(p);
return NULL;
}
}
@@ -192,7 +192,7 @@ static int semicolon_count_var(struct ast_variable *var)
return 0;
}
- ast_debug(2, "LINE(%d) semicolon_count_var: %s\n", __LINE__, var_value->value);
+ ast_debug(2, "semicolon_count_var: %s\n", var_value->value);
return semicolon_count_str(var_value->value);
}
@@ -238,7 +238,7 @@ static void table_configs_free(void)
if (c->attributes) {
ast_variables_destroy(c->attributes);
}
- free(c);
+ ast_free(c);
}
base_table_config = NULL;
@@ -332,7 +332,7 @@ static struct ast_variable *realtime_ldap_entry_to_var(struct ldap_table_config
for (v = values; *v; v++) {
value = *v;
valptr = value->bv_val;
- ast_debug(2, "LINE(%d) attribute_name: %s LDAP value: %s\n", __LINE__, attribute_name, valptr);
+ ast_debug(2, "attribute_name: %s LDAP value: %s\n", attribute_name, valptr);
if (is_realmed_password_attribute) {
if (!strncasecmp(valptr, "{md5}", 5)) {
valptr += 5;
@@ -424,7 +424,7 @@ static struct ast_variable **realtime_ldap_result_to_vars(struct ldap_table_conf
* value in \a variable_value; otherwise, we keep \a vars static and increase the length of the linked list of variables in the array element.
* This memory must be freed outside of this function.
*/
- vars = ast_calloc(sizeof(struct ast_variable *), tot_count + 1);
+ vars = ast_calloc(tot_count + 1, sizeof(struct ast_variable *));
ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
@@ -469,7 +469,7 @@ static struct ast_variable **realtime_ldap_result_to_vars(struct ldap_table_conf
delim_value = ast_strdup(valptr);
if ((delim_tot_count = semicolon_count_str(delim_value)) > 0) {
- ast_debug(4, "LINE(%d) is delimited %d times: %s\n", __LINE__, delim_tot_count, delim_value);
+ ast_debug(4, "is delimited %d times: %s\n", delim_tot_count, delim_value);
is_delimited = 1;
}
}
@@ -479,11 +479,11 @@ static struct ast_variable **realtime_ldap_result_to_vars(struct ldap_table_conf
/* for non-Static RealTime, first */
for (i = pos; !ast_strlen_zero(valptr + i); i++) {
- ast_debug(4, "LINE(%d) DELIM pos: %d i: %d\n", __LINE__, pos, i);
+ ast_debug(4, "DELIM pos: %d i: %d\n", pos, i);
if (delim_value[i] == ';') {
delim_value[i] = '\0';
- ast_debug(2, "LINE(%d) DELIM - attribute_name: %s value: %s pos: %d\n", __LINE__, attribute_name, &delim_value[pos], pos);
+ ast_debug(2, "DELIM - attribute_name: %s value: %s pos: %d\n", attribute_name, &delim_value[pos], pos);
if (prev) {
prev->next = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name);
@@ -501,9 +501,9 @@ static struct ast_variable **realtime_ldap_result_to_vars(struct ldap_table_conf
}
}
if (ast_strlen_zero(valptr + i)) {
- ast_debug(4, "LINE(%d) DELIM pos: %d i: %d delim_count: %d\n", __LINE__, pos, i, delim_count);
+ ast_debug(4, "DELIM pos: %d i: %d delim_count: %d\n", pos, i, delim_count);
/* Last delimited value */
- ast_debug(4, "LINE(%d) DELIM - attribute_name: %s value: %s pos: %d\n", __LINE__, attribute_name, &delim_value[pos], pos);
+ ast_debug(4, "DELIM - attribute_name: %s value: %s pos: %d\n", attribute_name, &delim_value[pos], pos);
if (prev) {
prev->next = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name);
if (prev->next) {
@@ -516,17 +516,17 @@ static struct ast_variable **realtime_ldap_result_to_vars(struct ldap_table_conf
is_delimited = 0;
pos = 0;
}
- free(delim_value);
+ ast_free(delim_value);
delim_value = NULL;
- ast_debug(4, "LINE(%d) DELIM pos: %d i: %d\n", __LINE__, pos, i);
+ ast_debug(4, "DELIM pos: %d i: %d\n", pos, i);
} else {
/* not delimited */
if (delim_value) {
- free(delim_value);
+ ast_free(delim_value);
delim_value = NULL;
}
- ast_debug(2, "LINE(%d) attribute_name: %s value: %s\n", __LINE__, attribute_name, valptr);
+ ast_debug(2, "attribute_name: %s value: %s\n", attribute_name, valptr);
if (prev) {
prev->next = ast_variable_new(attribute_name, valptr, table_config->table_name);
@@ -550,7 +550,7 @@ static struct ast_variable **realtime_ldap_result_to_vars(struct ldap_table_conf
const struct ast_variable *tmpdebug = variable_named(var, "variable_name");
const struct ast_variable *tmpdebug2 = variable_named(var, "variable_value");
if (tmpdebug && tmpdebug2) {
- ast_debug(3, "LINE(%d) Added to vars - %s = %s\n", __LINE__, tmpdebug->value, tmpdebug2->value);
+ ast_debug(3, "Added to vars - %s = %s\n", tmpdebug->value, tmpdebug2->value);
}
}
vars[entry_index++] = var;
@@ -561,7 +561,7 @@ static struct ast_variable **realtime_ldap_result_to_vars(struct ldap_table_conf
} while (delim_count <= delim_tot_count && static_table_config == table_config);
if (static_table_config != table_config) {
- ast_debug(3, "LINE(%d) Added to vars - non static\n", __LINE__);
+ ast_debug(3, "Added to vars - non static\n");
vars[entry_index++] = var;
prev = NULL;
@@ -928,13 +928,8 @@ static struct ast_variable **realtime_ldap_base_ap(unsigned int *entries_count_p
}
}
- if (filter) {
- ast_free(filter);
- }
-
- if (clean_basedn) {
- ast_free(clean_basedn);
- }
+ ast_free(filter);
+ ast_free(clean_basedn);
ast_mutex_unlock(&ldap_lock);
@@ -1007,7 +1002,7 @@ static struct ast_variable *realtime_ldap(const char *basedn,
}
p++;
}
- free(vars);
+ ast_free(vars);
}
return var;
}
@@ -1045,10 +1040,8 @@ static struct ast_config *realtime_multi_ldap(const char *basedn,
struct ast_variable **p = vars;
while (*p) {
- struct ast_category *cat = NULL;
- cat = ast_category_new("", table_name, -1);
+ struct ast_category *cat = ast_category_new_anonymous();
if (!cat) {
- ast_log(LOG_ERROR, "Unable to create a new category!\n");
break;
} else {
struct ast_variable *var = *p;
@@ -1066,7 +1059,7 @@ static struct ast_config *realtime_multi_ldap(const char *basedn,
p++;
}
}
- free(vars);
+ ast_free(vars);
}
return cfg;
@@ -1138,7 +1131,7 @@ static struct ast_config *config_ldap(const char *basedn, const char *table_name
* first, and since the data could easily exceed stack size, this is
* allocated from the heap.
*/
- if (!(categories = ast_calloc(sizeof(*categories), vars_count))) {
+ if (!(categories = ast_calloc(vars_count, sizeof(*categories)))) {
return NULL;
}
@@ -1197,7 +1190,7 @@ static struct ast_config *config_ldap(const char *basedn, const char *table_name
if (!last_category || strcmp(last_category, categories[i].name) ||
last_category_metric != categories[i].metric) {
- cur_cat = ast_category_new(categories[i].name, table_name, -1);
+ cur_cat = ast_category_new_dynamic(categories[i].name);
if (!cur_cat) {
break;
}
@@ -1219,6 +1212,90 @@ static struct ast_config *config_ldap(const char *basedn, const char *table_name
return cfg;
}
+/*!
+ * \internal
+ * \brief Remove LDAP_MOD_DELETE modifications that will not succeed
+ *
+ * \details
+ * A LDAP_MOD_DELETE operation will fail if the LDAP entry does not already have
+ * the corresponding attribute. Because we may be updating multiple LDAP entries
+ * in a single call to update_ldap(), we may need our own copy of the
+ * modifications array for each one.
+ *
+ * \note
+ * This function dynamically allocates memory. If it returns a non-NULL pointer,
+ * it is up to the caller to free it with ldap_mods_free()
+ *
+ * \returns an LDAPMod * if modifications needed to be removed, NULL otherwise.
+ */
+static LDAPMod **massage_mods_for_entry(LDAPMessage *entry, LDAPMod **mods, size_t count)
+{
+ size_t i;
+ int remove[count];
+ size_t remove_count = 0;
+
+ for (i = 0; i < count; i++) {
+ BerElement *ber = NULL;
+ char *attribute;
+ int exists = 0;
+
+ if (mods[i]->mod_op != LDAP_MOD_DELETE) {
+ continue;
+ }
+
+ /* If we are deleting something, it has to exist */
+ attribute = ldap_first_attribute(ldapConn, entry, &ber);
+ while (attribute) {
+ if (!strcasecmp(attribute, mods[i]->mod_type)) {
+ /* OK, we have the attribute */
+ exists = 1;
+ ldap_memfree(attribute);
+ break;
+ }
+
+ ldap_memfree(attribute);
+ attribute = ldap_next_attribute(ldapConn, entry, ber);
+ }
+
+ if (!exists) {
+ remove[remove_count++] = i;
+ }
+ }
+
+ if (remove_count) {
+ size_t k, remove_index;
+ LDAPMod **x = ldap_memcalloc(count - remove_count + 1, sizeof(LDAPMod *));
+ for (i = 0, k = 0; i < count; i++) {
+ int skip = 0;
+ /* Is this one we have to remove? */
+ for (remove_index = 0; !skip && remove_index < remove_count; remove_index++) {
+ skip = (remove[remove_index] == i);
+ }
+
+ if (skip) {
+ ast_debug(3, "Skipping %s deletion because it doesn't exist\n",
+ mods[i]->mod_type);
+ continue;
+ }
+
+ x[k] = ldap_memcalloc(1, sizeof(LDAPMod));
+ x[k]->mod_op = mods[i]->mod_op;
+ x[k]->mod_type = ldap_strdup(mods[i]->mod_type);
+ if (mods[i]->mod_values) {
+ x[k]->mod_values = ldap_memcalloc(2, sizeof(char *));
+ x[k]->mod_values[0] = ldap_strdup(mods[i]->mod_values[0]);
+ }
+ k++;
+ }
+ /* NULL terminate */
+ x[k] = NULL;
+ return x;
+ }
+
+ return NULL;
+}
+
+
/* \brief Function to update a set of values in ldap static mode
*/
static int update_ldap(const char *basedn, const char *table_name, const char *attribute,
@@ -1251,7 +1328,7 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a
}
if (!attribute || !lookup) {
- ast_log(LOG_WARNING, "LINE(%d): search parameters are empty.\n", __LINE__);
+ ast_log(LOG_WARNING, "Search parameters are empty.\n");
return -1;
}
ast_mutex_lock(&ldap_lock);
@@ -1287,19 +1364,22 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a
* one parameter/value pair and delimit them with a semicolon */
newparam = convert_attribute_name_to_ldap(table_config, field->name);
if (!newparam) {
- ast_log(LOG_WARNING, "LINE(%d): need at least one parameter to modify.\n", __LINE__);
+ ast_log(LOG_WARNING, "Need at least one parameter to modify.\n");
return -1;
}
mods_size = 2; /* one for the first param/value pair and one for the the terminating NULL */
- ldap_mods = ldap_memcalloc(sizeof(LDAPMod *), mods_size);
+ ldap_mods = ldap_memcalloc(mods_size, sizeof(LDAPMod *));
ldap_mods[0] = ldap_memcalloc(1, sizeof(LDAPMod));
-
- ldap_mods[0]->mod_op = LDAP_MOD_REPLACE;
ldap_mods[0]->mod_type = ldap_strdup(newparam);
- ldap_mods[0]->mod_values = ast_calloc(sizeof(char *), 2);
- ldap_mods[0]->mod_values[0] = ldap_strdup(field->value);
+ if (strlen(field->value) == 0) {
+ ldap_mods[0]->mod_op = LDAP_MOD_DELETE;
+ } else {
+ ldap_mods[0]->mod_op = LDAP_MOD_REPLACE;
+ ldap_mods[0]->mod_values = ldap_memcalloc(2, sizeof(char *));
+ ldap_mods[0]->mod_values[0] = ldap_strdup(field->value);
+ }
while ((field = field->next)) {
newparam = convert_attribute_name_to_ldap(table_config, field->name);
@@ -1311,7 +1391,7 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a
ldap_mods[i]->mod_values[0] = ldap_memrealloc(ldap_mods[i]->mod_values[0], sizeof(char) * (strlen(ldap_mods[i]->mod_values[0]) + strlen(field->value) + 2));
strcat(ldap_mods[i]->mod_values[0], ";");
strcat(ldap_mods[i]->mod_values[0], field->value);
- mod_exists = 1;
+ mod_exists = 1;
break;
}
}
@@ -1320,22 +1400,19 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a
if (!mod_exists) {
mods_size++;
ldap_mods = ldap_memrealloc(ldap_mods, sizeof(LDAPMod *) * mods_size);
- ldap_mods[mods_size - 1] = NULL;
-
ldap_mods[mods_size - 2] = ldap_memcalloc(1, sizeof(LDAPMod));
-
- ldap_mods[mods_size - 2]->mod_type = ldap_memcalloc(sizeof(char), strlen(newparam) + 1);
- strcpy(ldap_mods[mods_size - 2]->mod_type, newparam);
+ ldap_mods[mods_size - 2]->mod_type = ldap_strdup(newparam);
if (strlen(field->value) == 0) {
ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_DELETE;
} else {
ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_REPLACE;
-
- ldap_mods[mods_size - 2]->mod_values = ldap_memcalloc(sizeof(char *), 2);
- ldap_mods[mods_size - 2]->mod_values[0] = ldap_memcalloc(sizeof(char), strlen(field->value) + 1);
- strcpy(ldap_mods[mods_size - 2]->mod_values[0], field->value);
+ ldap_mods[mods_size - 2]->mod_values = ldap_memcalloc(2, sizeof(char *));
+ ldap_mods[mods_size - 2]->mod_values[0] = ldap_strdup(field->value);
}
+
+ /* NULL terminate */
+ ldap_mods[mods_size - 1] = NULL;
}
}
/* freeing ldap_mods further down */
@@ -1365,30 +1442,48 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a
ast_log(LOG_WARNING, "Query: %s\n", ast_str_buffer(filter));
ast_mutex_unlock(&ldap_lock);
- free(filter);
- free(clean_basedn);
+ ast_free(filter);
+ ast_free(clean_basedn);
ldap_msgfree(ldap_result_msg);
- ldap_mods_free(ldap_mods, 0);
+ ldap_mods_free(ldap_mods, 1);
return -1;
}
/* Ready to update */
if ((num_entries = ldap_count_entries(ldapConn, ldap_result_msg)) > 0) {
- ast_debug(3, "LINE(%d) Modifying %s=%s hits: %d\n", __LINE__, attribute, lookup, num_entries);
+ ast_debug(3, "Modifying %s=%s hits: %d\n", attribute, lookup, num_entries);
for (i = 0; option_debug > 2 && i < mods_size - 1; i++) {
if (ldap_mods[i]->mod_op != LDAP_MOD_DELETE) {
- ast_debug(3, "LINE(%d) %s=%s \n", __LINE__, ldap_mods[i]->mod_type, ldap_mods[i]->mod_values[0]);
+ ast_debug(3, "%s=%s\n", ldap_mods[i]->mod_type, ldap_mods[i]->mod_values[0]);
} else {
- ast_debug(3, "LINE(%d) deleting %s \n", __LINE__, ldap_mods[i]->mod_type);
+ ast_debug(3, "deleting %s\n", ldap_mods[i]->mod_type);
}
}
ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
- for (i = 0; ldap_entry; i++) {
+ for (i = 0; ldap_entry; i++) {
+ LDAPMod **working = ldap_mods;
+ LDAPMod **massaged = massage_mods_for_entry(ldap_entry, ldap_mods, mods_size - 1);
+
+ if (massaged) {
+ /* Did we massage everything out of the list? */
+ if (massaged[0] == NULL) {
+ ast_debug(3, "Nothing left to modify - skipping\n");
+ ldap_mods_free(massaged, 1);
+ continue;
+ }
+ working = massaged;
+ }
+
dn = ldap_get_dn(ldapConn, ldap_entry);
- if ((error = ldap_modify_ext_s(ldapConn, dn, ldap_mods, NULL, NULL)) != LDAP_SUCCESS) {
+ if ((error = ldap_modify_ext_s(ldapConn, dn, working, NULL, NULL)) != LDAP_SUCCESS) {
ast_log(LOG_ERROR, "Couldn't modify '%s'='%s', dn:%s because %s\n",
attribute, lookup, dn, ldap_err2string(error));
}
+
+ if (massaged) {
+ ldap_mods_free(massaged, 1);
+ }
+
ldap_memfree(dn);
ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
}
@@ -1398,7 +1493,7 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a
ast_free(filter);
ast_free(clean_basedn);
ldap_msgfree(ldap_result_msg);
- ldap_mods_free(ldap_mods, 0);
+ ldap_mods_free(ldap_mods, 1);
return num_entries;
}
@@ -1471,23 +1566,19 @@ static int update2_ldap(const char *basedn, const char *table_name, const struct
field = update_fields;
newparam = convert_attribute_name_to_ldap(table_config, field->name);
if (!newparam) {
- ast_log(LOG_WARNING, "LINE(%d): need at least one parameter to modify.\n", __LINE__);
+ ast_log(LOG_WARNING, "Need at least one parameter to modify.\n");
ast_free(filter);
ast_free(clean_basedn);
return -1;
}
mods_size = 2; /* one for the first param/value pair and one for the the terminating NULL */
- ldap_mods = ast_calloc(sizeof(LDAPMod *), mods_size);
- ldap_mods[0] = ast_calloc(1, sizeof(LDAPMod));
-
+ ldap_mods = ldap_memcalloc(mods_size, sizeof(LDAPMod *));
+ ldap_mods[0] = ldap_memcalloc(1, sizeof(LDAPMod));
ldap_mods[0]->mod_op = LDAP_MOD_REPLACE;
- ldap_mods[0]->mod_type = ast_calloc(sizeof(char), strlen(newparam) + 1);
- strcpy(ldap_mods[0]->mod_type, newparam);
-
- ldap_mods[0]->mod_values = ast_calloc(sizeof(char), 2);
- ldap_mods[0]->mod_values[0] = ast_calloc(sizeof(char), strlen(field->value) + 1);
- strcpy(ldap_mods[0]->mod_values[0], field->value);
+ ldap_mods[0]->mod_type = ldap_strdup(newparam);
+ ldap_mods[0]->mod_values = ldap_memcalloc(2, sizeof(char *));
+ ldap_mods[0]->mod_values[0] = ldap_strdup(field->value);
while ((field = field->next)) {
newparam = convert_attribute_name_to_ldap(table_config, field->name);
@@ -1507,18 +1598,15 @@ static int update2_ldap(const char *basedn, const char *table_name, const struct
/* create new mod */
if (!mod_exists) {
mods_size++;
- ldap_mods = ast_realloc(ldap_mods, sizeof(LDAPMod *) * mods_size);
- ldap_mods[mods_size - 1] = NULL;
- ldap_mods[mods_size - 2] = ast_calloc(1, sizeof(LDAPMod));
-
+ ldap_mods = ldap_memrealloc(ldap_mods, sizeof(LDAPMod *) * mods_size);
+ ldap_mods[mods_size - 2] = ldap_memcalloc(1, sizeof(LDAPMod));
ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_REPLACE;
+ ldap_mods[mods_size - 2]->mod_type = ldap_strdup(newparam);
+ ldap_mods[mods_size - 2]->mod_values = ldap_memcalloc(2, sizeof(char *));
+ ldap_mods[mods_size - 2]->mod_values[0] = ldap_strdup(field->value);
- ldap_mods[mods_size - 2]->mod_type = ast_calloc(sizeof(char), strlen(newparam) + 1);
- strcpy(ldap_mods[mods_size - 2]->mod_type, newparam);
-
- ldap_mods[mods_size - 2]->mod_values = ast_calloc(sizeof(char *), 2);
- ldap_mods[mods_size - 2]->mod_values[0] = ast_calloc(sizeof(char), strlen(field->value) + 1);
- strcpy(ldap_mods[mods_size - 2]->mod_values[0], field->value);
+ /* NULL terminate */
+ ldap_mods[mods_size - 1] = NULL;
}
}
/* freeing ldap_mods further down */
@@ -1552,13 +1640,13 @@ static int update2_ldap(const char *basedn, const char *table_name, const struct
ast_free(filter);
ast_free(clean_basedn);
ldap_msgfree(ldap_result_msg);
- ldap_mods_free(ldap_mods, 0);
+ ldap_mods_free(ldap_mods, 1);
return -1;
}
/* Ready to update */
if ((num_entries = ldap_count_entries(ldapConn, ldap_result_msg)) > 0) {
for (i = 0; option_debug > 2 && i < mods_size - 1; i++) {
- ast_debug(3, "LINE(%d) %s=%s \n", __LINE__, ldap_mods[i]->mod_type, ldap_mods[i]->mod_values[0]);
+ ast_debug(3, "%s=%s\n", ldap_mods[i]->mod_type, ldap_mods[i]->mod_values[0]);
}
ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
@@ -1574,14 +1662,10 @@ static int update2_ldap(const char *basedn, const char *table_name, const struct
}
ast_mutex_unlock(&ldap_lock);
- if (filter) {
- ast_free(filter);
- }
- if (clean_basedn) {
- ast_free(clean_basedn);
- }
+ ast_free(filter);
+ ast_free(clean_basedn);
ldap_msgfree(ldap_result_msg);
- ldap_mods_free(ldap_mods, 0);
+ ldap_mods_free(ldap_mods, 1);
return num_entries;
}
@@ -1683,6 +1767,21 @@ static int reload(void)
return 0;
}
+static int config_can_be_inherited(const char *key)
+{
+ int i;
+ static const char * const config[] = {
+ "basedn", "host", "pass", "port", "protocol", "url", "user", "version", NULL
+ };
+
+ for (i = 0; config[i]; i++) {
+ if (!strcasecmp(key, config[i])) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
/*! \brief parse the configuration file
*/
static int parse_config(void)
@@ -1773,7 +1872,9 @@ static int parse_config(void)
if (!strcasecmp(var->name, "additionalFilter")) {
table_config->additional_filter = ast_strdup(var->value);
} else {
- ldap_table_config_add_attribute(table_config, var->name, var->value);
+ if (!is_general || config_can_be_inherited(var->name)) {
+ ldap_table_config_add_attribute(table_config, var->name, var->value);
+ }
}
}
}
diff --git a/res/res_config_odbc.c b/res/res_config_odbc.c
index 893b9d897..583a84558 100644
--- a/res/res_config_odbc.c
+++ b/res/res_config_odbc.c
@@ -409,9 +409,8 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char *
ast_log(LOG_WARNING, "SQL Fetch error! [%s]\n", ast_str_buffer(sql));
continue;
}
- cat = ast_category_new("","",99999);
+ cat = ast_category_new_anonymous();
if (!cat) {
- ast_log(LOG_WARNING, "Out of memory!\n");
continue;
}
for (x=0;x<colcount;x++) {
@@ -1018,9 +1017,8 @@ static struct ast_config *config_odbc(const char *database, const char *table, c
continue;
}
if (strcmp(last, q.category) || last_cat_metric != q.cat_metric) {
- cur_cat = ast_category_new(q.category, "", 99999);
+ cur_cat = ast_category_new_dynamic(q.category);
if (!cur_cat) {
- ast_log(LOG_WARNING, "Out of memory!\n");
break;
}
strcpy(last, q.category);
diff --git a/res/res_config_pgsql.c b/res/res_config_pgsql.c
index 52c8ede74..824adbf34 100644
--- a/res/res_config_pgsql.c
+++ b/res/res_config_pgsql.c
@@ -417,6 +417,9 @@ static struct columns *find_column(struct tables *t, const char *colname)
return NULL;
}
+#define IS_SQL_LIKE_CLAUSE(x) ((x) && ast_ends_with(x, " LIKE"))
+static char *ESCAPE_CLAUSE = " ESCAPE '\\'";
+
static struct ast_variable *realtime_pgsql(const char *database, const char *tablename, const struct ast_variable *fields)
{
RAII_VAR(PGresult *, result, NULL, PQclear);
@@ -426,6 +429,7 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
char *stringp;
char *chunk;
char *op;
+ char *escape = "";
const struct ast_variable *field = fields;
struct ast_variable *var = NULL, *prev = NULL;
@@ -453,7 +457,14 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
/* Create the first part of the query using the first parameter/value pairs we just extracted
If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
- op = strchr(field->name, ' ') ? "" : " =";
+ if (!strchr(field->name, ' ')) {
+ op = " =";
+ } else {
+ op = "";
+ if (IS_SQL_LIKE_CLAUSE(field->name)) {
+ escape = ESCAPE_CLAUSE;
+ }
+ }
ESCAPE_STRING(escapebuf, field->value);
if (pgresult) {
@@ -461,12 +472,17 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
return NULL;
}
- ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", tablename, field->name, op, ast_str_buffer(escapebuf));
+ ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'%s", tablename, field->name, op, ast_str_buffer(escapebuf), escape);
while ((field = field->next)) {
- if (!strchr(field->name, ' '))
+ escape = "";
+ if (!strchr(field->name, ' ')) {
op = " =";
- else
+ } else {
op = "";
+ if (IS_SQL_LIKE_CLAUSE(field->name)) {
+ escape = ESCAPE_CLAUSE;
+ }
+ }
ESCAPE_STRING(escapebuf, field->value);
if (pgresult) {
@@ -474,7 +490,7 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
return NULL;
}
- ast_str_append(&sql, 0, " AND %s%s '%s'", field->name, op, ast_str_buffer(escapebuf));
+ ast_str_append(&sql, 0, " AND %s%s '%s'%s", field->name, op, ast_str_buffer(escapebuf), escape);
}
/* We now have our complete statement; Lets connect to the server and execute it. */
@@ -540,6 +556,7 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
char *stringp;
char *chunk;
char *op;
+ char *escape = "";
struct ast_variable *var = NULL;
struct ast_config *cfg = NULL;
struct ast_category *cat = NULL;
@@ -578,10 +595,15 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
/* Create the first part of the query using the first parameter/value pairs we just extracted
If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
- if (!strchr(field->name, ' '))
+ if (!strchr(field->name, ' ')) {
op = " =";
- else
+ escape = "";
+ } else {
op = "";
+ if (IS_SQL_LIKE_CLAUSE(field->name)) {
+ escape = ESCAPE_CLAUSE;
+ }
+ }
ESCAPE_STRING(escapebuf, field->value);
if (pgresult) {
@@ -590,12 +612,18 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
return NULL;
}
- ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, field->name, op, ast_str_buffer(escapebuf));
+ ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'%s", table, field->name, op, ast_str_buffer(escapebuf), escape);
while ((field = field->next)) {
- if (!strchr(field->name, ' '))
+ escape = "";
+ if (!strchr(field->name, ' ')) {
op = " =";
- else
+ escape = "";
+ } else {
op = "";
+ if (IS_SQL_LIKE_CLAUSE(field->name)) {
+ escape = ESCAPE_CLAUSE;
+ }
+ }
ESCAPE_STRING(escapebuf, field->value);
if (pgresult) {
@@ -604,7 +632,7 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
return NULL;
}
- ast_str_append(&sql, 0, " AND %s%s '%s'", field->name, op, ast_str_buffer(escapebuf));
+ ast_str_append(&sql, 0, " AND %s%s '%s'%s", field->name, op, ast_str_buffer(escapebuf), escape);
}
if (initfield) {
@@ -655,8 +683,10 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
for (rowIndex = 0; rowIndex < num_rows; rowIndex++) {
var = NULL;
- if (!(cat = ast_category_new("","",99999)))
+ cat = ast_category_new_anonymous();
+ if (!cat) {
continue;
+ }
for (i = 0; i < numFields; i++) {
stringp = PQgetvalue(result, rowIndex, i);
while (stringp) {
@@ -1136,9 +1166,10 @@ static struct ast_config *config_pgsql(const char *database, const char *table,
}
if (strcmp(last, field_category) || last_cat_metric != atoi(field_cat_metric)) {
- cur_cat = ast_category_new(field_category, "", 99999);
- if (!cur_cat)
+ cur_cat = ast_category_new_dynamic(field_category);
+ if (!cur_cat) {
break;
+ }
ast_copy_string(last, field_category, sizeof(last));
last_cat_metric = atoi(field_cat_metric);
ast_category_append(cfg, cur_cat);
diff --git a/res/res_config_sqlite.c b/res/res_config_sqlite.c
index b97ef7a86..a5a831ea3 100644
--- a/res/res_config_sqlite.c
+++ b/res/res_config_sqlite.c
@@ -875,10 +875,8 @@ static int add_cfg_entry(void *arg, int argc, char **argv, char **columnNames)
}
if (!args->cat_name || strcmp(args->cat_name, argv[RES_CONFIG_SQLITE_CONFIG_CATEGORY])) {
- args->cat = ast_category_new(argv[RES_CONFIG_SQLITE_CONFIG_CATEGORY], "", 99999);
-
+ args->cat = ast_category_new_dynamic(argv[RES_CONFIG_SQLITE_CONFIG_CATEGORY]);
if (!args->cat) {
- ast_log(LOG_WARNING, "Unable to allocate category\n");
return 1;
}
@@ -1087,8 +1085,8 @@ static int add_rt_multi_cfg_entry(void *arg, int argc, char **argv, char **colum
return 1;
}
- if (!(cat = ast_category_new(cat_name, "", 99999))) {
- ast_log(LOG_WARNING, "Unable to allocate category\n");
+ cat = ast_category_new_dynamic(cat_name);
+ if (!cat) {
return 1;
}
diff --git a/res/res_config_sqlite3.c b/res/res_config_sqlite3.c
index d812bfbd3..5362e9ede 100644
--- a/res/res_config_sqlite3.c
+++ b/res/res_config_sqlite3.c
@@ -60,6 +60,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
/*** DOCUMENTATION
***/
+static int has_explicit_like_escaping;
+
static struct ast_config *realtime_sqlite3_load(const char *database, const char *table, const char *configfile, struct ast_config *config, struct ast_flags flags, const char *suggested_include_file, const char *who_asked);
static struct ast_variable *realtime_sqlite3(const char *database, const char *table, const struct ast_variable *fields);
static struct ast_config *realtime_sqlite3_multi(const char *database, const char *table, const struct ast_variable *fields);
@@ -503,7 +505,8 @@ static int append_row_to_cfg(void *arg, int num_columns, char **values, char **c
struct ast_category *cat;
int i;
- if (!(cat = ast_category_new("", "", 99999))) {
+ cat = ast_category_new_anonymous();
+ if (!cat) {
return SQLITE_ABORT;
}
@@ -723,8 +726,8 @@ static int static_realtime_cb(void *arg, int num_columns, char **values, char **
}
if (!args->cat_name || strcmp(args->cat_name, values[COL_CATEGORY])) {
- if (!(args->cat = ast_category_new(values[COL_CATEGORY], "", 99999))) {
- ast_log(LOG_WARNING, "Unable to allocate category\n");
+ args->cat = ast_category_new_dynamic(values[COL_CATEGORY]);
+ if (!args->cat) {
return SQLITE_ABORT;
}
@@ -779,6 +782,8 @@ static struct ast_config *realtime_sqlite3_load(const char *database, const char
return config;
}
+#define IS_SQL_LIKE_CLAUSE(x) ((x) && ast_ends_with(x, " LIKE"))
+
/*! \brief Helper function for single and multi-row realtime load functions */
static int realtime_sqlite3_helper(const char *database, const char *table, const struct ast_variable *fields, int is_multi, void *arg)
{
@@ -804,6 +809,15 @@ static int realtime_sqlite3_helper(const char *database, const char *table, cons
ast_str_append(&sql, 0, " AND %s %s", sqlite3_escape_column_op(field->name),
sqlite3_escape_value(field->value));
}
+
+ if (has_explicit_like_escaping && IS_SQL_LIKE_CLAUSE(field->name)) {
+ /*
+ * The realtime framework is going to pre-escape these
+ * for us with a backslash. We just need to make sure
+ * to tell SQLite about it
+ */
+ ast_str_append(&sql, 0, " ESCAPE '\\'");
+ }
}
if (!is_multi) {
@@ -1309,6 +1323,29 @@ static int unload_module(void)
return 0;
}
+static void discover_sqlite3_caps(void)
+{
+ /*
+ * So we cheat a little bit here. SQLite3 added support for the
+ * 'ESCAPE' keyword in 3.1.0. They added SQLITE_VERSION_NUMBER
+ * in 3.1.2. So if we run into 3.1.0 or 3.1.1 in the wild, we
+ * just treat it like < 3.1.0.
+ *
+ * For reference: 3.1.0, 3.1.1, and 3.1.2 were all released
+ * within 30 days of each other in Jan/Feb 2005, so I don't
+ * imagine we'll be finding something pre-3.1.2 that often in
+ * practice.
+ */
+#if defined(SQLITE_VERSION_NUMBER)
+ has_explicit_like_escaping = 1;
+#else
+ has_explicit_like_escaping = 0;
+#endif
+
+ ast_debug(3, "SQLite3 has 'LIKE ... ESCAPE ...' support? %s\n",
+ has_explicit_like_escaping ? "Yes" : "No");
+}
+
/*!
* \brief Load the module
*
@@ -1321,6 +1358,8 @@ static int unload_module(void)
*/
static int load_module(void)
{
+ discover_sqlite3_caps();
+
if (!((databases = ao2_container_alloc(DB_BUCKETS, db_hash_fn, db_cmp_fn)))) {
return AST_MODULE_LOAD_FAILURE;
}
diff --git a/res/res_pjsip.c b/res/res_pjsip.c
index a167150f6..9970d84f4 100644
--- a/res/res_pjsip.c
+++ b/res/res_pjsip.c
@@ -112,9 +112,15 @@
This is a comma-delimited list of <replaceable>auth</replaceable> sections defined
in <filename>pjsip.conf</filename> to be used to verify inbound connection attempts.
</para><para>
- Endpoints without an <literal>authentication</literal> object
- configured will allow connections without vertification.
- </para></description>
+ Endpoints without an authentication object
+ configured will allow connections without verification.</para>
+ <note><para>
+ Using the same auth section for inbound and outbound
+ authentication is not recommended. There is a difference in
+ meaning for an empty realm setting between inbound and outbound
+ authentication uses. See the auth realm description for details.
+ </para></note>
+ </description>
</configOption>
<configOption name="callerid">
<synopsis>CallerID information for the endpoint</synopsis>
@@ -329,7 +335,18 @@
<synopsis>Default Music On Hold class</synopsis>
</configOption>
<configOption name="outbound_auth">
- <synopsis>Authentication object used for outbound requests</synopsis>
+ <synopsis>Authentication object(s) used for outbound requests</synopsis>
+ <description><para>
+ This is a comma-delimited list of <replaceable>auth</replaceable>
+ sections defined in <filename>pjsip.conf</filename> used to respond
+ to outbound connection authentication challenges.</para>
+ <note><para>
+ Using the same auth section for inbound and outbound
+ authentication is not recommended. There is a difference in
+ meaning for an empty realm setting between inbound and outbound
+ authentication uses. See the auth realm description for details.
+ </para></note>
+ </description>
</configOption>
<configOption name="outbound_proxy">
<synopsis>Proxy through which to send requests, a full SIP URI must be provided</synopsis>
@@ -961,8 +978,30 @@
<synopsis>PlainText password used for authentication.</synopsis>
<description><para>Only used when auth_type is <literal>userpass</literal>.</para></description>
</configOption>
- <configOption name="realm" default="asterisk">
+ <configOption name="realm">
<synopsis>SIP realm for endpoint</synopsis>
+ <description><para>
+ The treatment of this value depends upon how the authentication
+ object is used.
+ </para><para>
+ When used as an inbound authentication object, the realm is sent
+ as part of the challenge so the peer can know which key to use
+ when responding. An empty value will use the
+ <replaceable>global</replaceable> section's
+ <literal>default_realm</literal> value when issuing a challenge.
+ </para><para>
+ When used as an outbound authentication object, the realm is
+ matched with the received challenge realm to determine which
+ authentication object to use when responding to the challenge. An
+ empty value matches any challenging realm when determining
+ which authentication object matches a received challenge.
+ </para>
+ <note><para>
+ Using the same auth section for inbound and outbound
+ authentication is not recommended. There is a difference in
+ meaning for an empty realm setting between inbound and outbound
+ authentication uses.</para></note>
+ </description>
</configOption>
<configOption name="type">
<synopsis>Must be 'auth'</synopsis>
@@ -1506,7 +1545,7 @@
used.</synopsis>
</configOption>
<configOption name="default_realm" default="asterisk">
- <synopsis>When Asterisk generates an challenge, the digest will be
+ <synopsis>When Asterisk generates a challenge, the digest realm will be
set to this value if there is no better option (such as auth/realm) to be
used.</synopsis>
</configOption>
diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c
index e076db3b8..7bea6b735 100644
--- a/res/res_pjsip/pjsip_distributor.c
+++ b/res/res_pjsip/pjsip_distributor.c
@@ -42,7 +42,6 @@ struct ast_sched_context *prune_context;
/* From the auth/realm realtime column size */
#define MAX_REALM_LENGTH 40
-static char default_realm[MAX_REALM_LENGTH + 1];
#define DEFAULT_SUSPECTS_BUCKETS 53
@@ -452,35 +451,54 @@ static pj_bool_t distributor(pjsip_rx_data *rdata)
return PJ_TRUE;
}
-static struct ast_sip_auth *artificial_auth;
+static struct ast_sip_auth *alloc_artificial_auth(char *default_realm)
+{
+ struct ast_sip_auth *fake_auth;
+
+ fake_auth = ast_sorcery_alloc(ast_sip_get_sorcery(), SIP_SORCERY_AUTH_TYPE,
+ "artificial");
+ if (!fake_auth) {
+ return NULL;
+ }
+
+ ast_string_field_set(fake_auth, realm, default_realm);
+ ast_string_field_set(fake_auth, auth_user, "");
+ ast_string_field_set(fake_auth, auth_pass, "");
+ fake_auth->type = AST_SIP_AUTH_TYPE_ARTIFICIAL;
+
+ return fake_auth;
+}
+
+static AO2_GLOBAL_OBJ_STATIC(artificial_auth);
static int create_artificial_auth(void)
{
- if (!(artificial_auth = ast_sorcery_alloc(
- ast_sip_get_sorcery(), SIP_SORCERY_AUTH_TYPE, "artificial"))) {
+ char default_realm[MAX_REALM_LENGTH + 1];
+ struct ast_sip_auth *fake_auth;
+
+ ast_sip_get_default_realm(default_realm, sizeof(default_realm));
+ fake_auth = alloc_artificial_auth(default_realm);
+ if (!fake_auth) {
ast_log(LOG_ERROR, "Unable to create artificial auth\n");
return -1;
}
- ast_string_field_set(artificial_auth, realm, default_realm);
- ast_string_field_set(artificial_auth, auth_user, "");
- ast_string_field_set(artificial_auth, auth_pass, "");
- artificial_auth->type = AST_SIP_AUTH_TYPE_ARTIFICIAL;
+ ao2_global_obj_replace_unref(artificial_auth, fake_auth);
+ ao2_ref(fake_auth, -1);
return 0;
}
struct ast_sip_auth *ast_sip_get_artificial_auth(void)
{
- ao2_ref(artificial_auth, +1);
- return artificial_auth;
+ return ao2_global_obj_ref(artificial_auth);
}
static struct ast_sip_endpoint *artificial_endpoint = NULL;
static int create_artificial_endpoint(void)
{
- if (!(artificial_endpoint = ast_sorcery_alloc(
- ast_sip_get_sorcery(), "endpoint", NULL))) {
+ artificial_endpoint = ast_sorcery_alloc(ast_sip_get_sorcery(), "endpoint", NULL);
+ if (!artificial_endpoint) {
return -1;
}
@@ -958,20 +976,40 @@ static int clean_task(const void *data)
static void global_loaded(const char *object_type)
{
- char *identifier_order = ast_sip_get_endpoint_identifier_order();
- char *io_copy = identifier_order ? ast_strdupa(identifier_order) : NULL;
- char *identify_method;
-
- ast_free(identifier_order);
- using_auth_username = 0;
- while ((identify_method = ast_strip(strsep(&io_copy, ",")))) {
- if (!strcmp(identify_method, "auth_username")) {
- using_auth_username = 1;
- break;
+ char default_realm[MAX_REALM_LENGTH + 1];
+ struct ast_sip_auth *fake_auth;
+ char *identifier_order;
+
+ /* Update using_auth_username */
+ identifier_order = ast_sip_get_endpoint_identifier_order();
+ if (identifier_order) {
+ char *identify_method;
+ char *io_copy = ast_strdupa(identifier_order);
+ int new_using = 0;
+
+ ast_free(identifier_order);
+ while ((identify_method = ast_strip(strsep(&io_copy, ",")))) {
+ if (!strcmp(identify_method, "auth_username")) {
+ new_using = 1;
+ break;
+ }
}
+ using_auth_username = new_using;
}
+ /* Update default_realm of artificial_auth */
ast_sip_get_default_realm(default_realm, sizeof(default_realm));
+ fake_auth = ast_sip_get_artificial_auth();
+ if (!fake_auth || strcmp(fake_auth->realm, default_realm)) {
+ ao2_cleanup(fake_auth);
+
+ fake_auth = alloc_artificial_auth(default_realm);
+ if (fake_auth) {
+ ao2_global_obj_replace_unref(artificial_auth, fake_auth);
+ ao2_ref(fake_auth, -1);
+ }
+ }
+
ast_sip_get_unidentified_request_thresholds(&unidentified_count, &unidentified_period, &unidentified_prune_interval);
/* Clean out the old task, if any */
@@ -1104,7 +1142,7 @@ void ast_sip_destroy_distributor(void)
internal_sip_unregister_service(&endpoint_mod);
internal_sip_unregister_service(&distributor_mod);
- ao2_cleanup(artificial_auth);
+ ao2_global_obj_release(artificial_auth);
ao2_cleanup(artificial_endpoint);
ast_sorcery_observer_remove(ast_sip_get_sorcery(), "global", &global_observer);
diff --git a/res/res_pjsip_outbound_publish.c b/res/res_pjsip_outbound_publish.c
index 7c0b64b4d..37f64481e 100644
--- a/res/res_pjsip_outbound_publish.c
+++ b/res/res_pjsip_outbound_publish.c
@@ -54,7 +54,18 @@
<synopsis>Expiration time for publications in seconds</synopsis>
</configOption>
<configOption name="outbound_auth" default="">
- <synopsis>Authentication object to be used for outbound publishes.</synopsis>
+ <synopsis>Authentication object(s) to be used for outbound publishes.</synopsis>
+ <description><para>
+ This is a comma-delimited list of <replaceable>auth</replaceable>
+ sections defined in <filename>pjsip.conf</filename> used to respond
+ to outbound authentication challenges.</para>
+ <note><para>
+ Using the same auth section for inbound and outbound
+ authentication is not recommended. There is a difference in
+ meaning for an empty realm setting between inbound and outbound
+ authentication uses. See the auth realm description for details.
+ </para></note>
+ </description>
</configOption>
<configOption name="outbound_proxy" default="">
<synopsis>SIP URI of the outbound proxy used to send publishes</synopsis>
diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c
index 6c615f0a4..122d5bb69 100644
--- a/res/res_pjsip_outbound_registration.c
+++ b/res/res_pjsip_outbound_registration.c
@@ -82,7 +82,18 @@
<synopsis>Maximum number of registration attempts.</synopsis>
</configOption>
<configOption name="outbound_auth" default="">
- <synopsis>Authentication object to be used for outbound registrations.</synopsis>
+ <synopsis>Authentication object(s) to be used for outbound registrations.</synopsis>
+ <description><para>
+ This is a comma-delimited list of <replaceable>auth</replaceable>
+ sections defined in <filename>pjsip.conf</filename> used to respond
+ to outbound authentication challenges.</para>
+ <note><para>
+ Using the same auth section for inbound and outbound
+ authentication is not recommended. There is a difference in
+ meaning for an empty realm setting between inbound and outbound
+ authentication uses. See the auth realm description for details.
+ </para></note>
+ </description>
</configOption>
<configOption name="outbound_proxy" default="">
<synopsis>Outbound Proxy used to send registrations</synopsis>