diff options
-rw-r--r-- | addons/res_config_mysql.c | 61 | ||||
-rw-r--r-- | apps/app_voicemail.c | 12 | ||||
-rw-r--r-- | configs/samples/pjsip.conf.sample | 20 | ||||
-rw-r--r-- | include/asterisk/config.h | 12 | ||||
-rw-r--r-- | main/Makefile | 8 | ||||
-rw-r--r-- | main/tcptls.c | 20 | ||||
-rw-r--r-- | res/res_config_curl.c | 7 | ||||
-rw-r--r-- | res/res_config_ldap.c | 273 | ||||
-rw-r--r-- | res/res_config_odbc.c | 6 | ||||
-rw-r--r-- | res/res_config_pgsql.c | 59 | ||||
-rw-r--r-- | res/res_config_sqlite.c | 8 | ||||
-rw-r--r-- | res/res_config_sqlite3.c | 45 | ||||
-rw-r--r-- | res/res_pjsip.c | 51 | ||||
-rw-r--r-- | res/res_pjsip/pjsip_distributor.c | 84 | ||||
-rw-r--r-- | res/res_pjsip_outbound_publish.c | 13 | ||||
-rw-r--r-- | res/res_pjsip_outbound_registration.c | 13 |
16 files changed, 511 insertions, 181 deletions
diff --git a/addons/res_config_mysql.c b/addons/res_config_mysql.c index 1041c1120..cdc641bd1 100644 --- a/addons/res_config_mysql.c +++ b/addons/res_config_mysql.c @@ -305,6 +305,11 @@ static char *decode_chunk(char *chunk) return orig; } +#define IS_SQL_LIKE_CLAUSE(x) ((x) && ast_ends_with(x, " LIKE")) + +/* MySQL requires us to escape the escape... yo dawg */ +static char *ESCAPE_CLAUSE = " ESCAPE '\\\\'"; + static struct ast_variable *realtime_mysql(const char *database, const char *table, const struct ast_variable *rt_fields) { struct mysql_conn *dbh; @@ -317,6 +322,7 @@ static struct ast_variable *realtime_mysql(const char *database, const char *tab char *stringp; char *chunk; char *op; + char *escape = ""; const struct ast_variable *field = rt_fields; struct ast_variable *var=NULL, *prev=NULL; @@ -347,20 +353,29 @@ static struct ast_variable *realtime_mysql(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 */ - if (!strchr(field->name, ' ')) - op = " ="; - else + if (!strchr(field->name, ' ')) { + op = " ="; + } else { op = ""; + if (IS_SQL_LIKE_CLAUSE(field->name)) { + escape = ESCAPE_CLAUSE; + } + } ESCAPE_STRING(buf, field->value); - ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, field->name, op, ast_str_buffer(buf)); + ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'%s", table, field->name, op, ast_str_buffer(buf), escape); while ((field = field->next)) { - if (!strchr(field->name, ' ')) - op = " ="; - else + escape = ""; + if (!strchr(field->name, ' ')) { + op = " ="; + } else { op = ""; + if (IS_SQL_LIKE_CLAUSE(field->name)) { + escape = ESCAPE_CLAUSE; + } + } ESCAPE_STRING(buf, field->value); - ast_str_append(&sql, 0, " AND %s%s '%s'", field->name, op, ast_str_buffer(buf)); + ast_str_append(&sql, 0, " AND %s%s '%s'%s", field->name, op, ast_str_buffer(buf), escape); } ast_debug(1, "MySQL RealTime: Retrieve SQL: %s\n", ast_str_buffer(sql)); @@ -418,6 +433,7 @@ static struct ast_config *realtime_multi_mysql(const char *database, const char char *stringp; char *chunk; char *op; + char *escape = ""; const struct ast_variable *field = rt_fields; struct ast_variable *var = NULL; struct ast_config *cfg = NULL; @@ -464,17 +480,29 @@ static struct ast_config *realtime_multi_mysql(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 + } else { op = ""; + if (IS_SQL_LIKE_CLAUSE(field->name)) { + escape = ESCAPE_CLAUSE; + } + } ESCAPE_STRING(buf, field->value); - ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, field->name, op, ast_str_buffer(buf)); + ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'%s", table, field->name, op, ast_str_buffer(buf), escape); while ((field = field->next)) { - if (!strchr(field->name, ' ')) op = " ="; else op = ""; + escape = ""; + if (!strchr(field->name, ' ')) { + op = " ="; + } else { + op = ""; + if (IS_SQL_LIKE_CLAUSE(field->name)) { + escape = ESCAPE_CLAUSE; + } + } ESCAPE_STRING(buf, field->value); - ast_str_append(&sql, 0, " AND %s%s '%s'", field->name, op, ast_str_buffer(buf)); + ast_str_append(&sql, 0, " AND %s%s '%s'%s", field->name, op, ast_str_buffer(buf), escape); } if (initfield) { @@ -497,9 +525,8 @@ static struct ast_config *realtime_multi_mysql(const char *database, const char while ((row = mysql_fetch_row(result))) { var = NULL; - cat = ast_category_new("", "", -1); + cat = ast_category_new_anonymous(); if (!cat) { - ast_log(LOG_WARNING, "Out of memory!\n"); continue; } for (i = 0; i < numFields; i++) { @@ -908,8 +935,8 @@ static struct ast_config *config_mysql(const char *database, const char *table, } if (strcmp(last, row[0]) || last_cat_metric != atoi(row[3])) { - if (!(cur_cat = ast_category_new(row[0], "", -1))) { - ast_log(LOG_WARNING, "Out of memory!\n"); + cur_cat = ast_category_new_dynamic(row[0]); + if (!cur_cat) { break; } strcpy(last, row[0]); diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index ef210c2ef..608977952 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -11113,7 +11113,7 @@ static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_ return -1; } if (vmu && !skipuser) { - memcpy(res_vmu, vmu, sizeof(struct ast_vm_user)); + *res_vmu = *vmu; } return 0; } @@ -11275,8 +11275,8 @@ static int vm_execmain(struct ast_channel *chan, const char *data) int box; int useadsi = 0; int skipuser = 0; - struct vm_state vms; - struct ast_vm_user *vmu = NULL, vmus; + struct vm_state vms = {{0}}; + struct ast_vm_user *vmu = NULL, vmus = {{0}}; char *context = NULL; int silentexit = 0; struct ast_flags flags = { 0 }; @@ -11289,12 +11289,8 @@ static int vm_execmain(struct ast_channel *chan, const char *data) #endif /* Add the vm_state to the active list and keep it active */ - memset(&vms, 0, sizeof(vms)); - vms.lastmsg = -1; - memset(&vmus, 0, sizeof(vmus)); - ast_test_suite_event_notify("START", "Message: vm_execmain started"); if (ast_channel_state(chan) != AST_STATE_UP) { ast_debug(1, "Before ast_answer\n"); @@ -12587,7 +12583,7 @@ static struct ast_custom_function vm_info_acf = { static int vmauthenticate(struct ast_channel *chan, const char *data) { char *s, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = ""; - struct ast_vm_user vmus; + struct ast_vm_user vmus = {{0}}; char *options = NULL; int silent = 0, skipuser = 0; int res = -1; diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index 2ef893384..bb2ad94f8 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -12,6 +12,12 @@ ; If you want to see more detail please check the documentation sources ; mentioned at the top of this file. +; ============================================================================ +; NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE +; +; This file does not maintain the complete option documentation. +; ============================================================================ + ; Documentation ; ; The official documentation is at http://wiki.asterisk.org @@ -759,6 +765,14 @@ ;==========================AUTH SECTION OPTIONS========================= ;[auth] ; SYNOPSIS: Authentication type +; +; Note: 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. Look to the CLI config help +; "config show help res_pjsip auth realm" or on the wiki for the +; difference. +; ;auth_type=userpass ; Authentication type (default: "userpass") ;nonce_lifetime=32 ; Lifetime of a nonce associated with this ; authentication config (default: "32") @@ -947,9 +961,9 @@ ; From header username will be set to this value if ; there is no better option (such as CallerID or ; endpoint/from_user) to be used -;default_realm=asterisk ; When Asterisk generates a challenge, the realm will be - ; set to this value if there is no better option (such as - ; auth/realm) to be used +;default_realm=asterisk ; 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. ; Asterisk Task Processor Queue Size ; On heavy loaded system with DB storage you may need to increase diff --git a/include/asterisk/config.h b/include/asterisk/config.h index 0b59f63b6..4dc473cd7 100644 --- a/include/asterisk/config.h +++ b/include/asterisk/config.h @@ -834,6 +834,18 @@ const char *ast_config_option(struct ast_config *cfg, const char *cat, const cha struct ast_category *ast_category_new(const char *name, const char *in_file, int lineno); /*! + * \brief Create a category that is not backed by a file + * + * \param name name of new category + */ +#define ast_category_new_dynamic(name) ast_category_new(name, "", -1) + +/*! + * \brief Create a nameless category that is not backed by a file + */ +#define ast_category_new_anonymous() ast_category_new_dynamic("") + +/*! * \brief Create a category making it a template * * \param name name of new template diff --git a/main/Makefile b/main/Makefile index a51b48bb1..b3e84e16c 100644 --- a/main/Makefile +++ b/main/Makefile @@ -355,7 +355,11 @@ else # Darwin endif endif ifneq ($(LDCONFIG),) +ifneq ($(DESTDIR),) $(LDCONFIG) $(LDCONFIG_FLAGS) "$(DESTDIR)$(ASTLIBDIR)/" +else + $(LDCONFIG) +endif endif $(LN) -sf asterisk "$(DESTDIR)$(ASTSBINDIR)/rasterisk" @@ -373,7 +377,11 @@ ifneq ($(ASTPJ_LIB).$(ASTPJ_SO_VERSION),.) rm -f "$(DESTDIR)$(ASTLIBDIR)/$(ASTPJ_LIB)" endif ifneq ($(LDCONFIG),) +ifneq ($(DESTDIR),) $(LDCONFIG) $(LDCONFIG_FLAGS) "$(DESTDIR)$(ASTLIBDIR)/" +else + $(LDCONFIG) +endif endif clean:: diff --git a/main/tcptls.c b/main/tcptls.c index 4d110cda9..c46b8df43 100644 --- a/main/tcptls.c +++ b/main/tcptls.c @@ -773,14 +773,16 @@ void *ast_tcptls_server_root(void *data) } tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor); if (!tcptls_session) { - ast_log(LOG_WARNING, "No memory for new session: %s\n", strerror(errno)); - if (close(fd)) { - ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno)); - } + close(fd); continue; } tcptls_session->overflow_buf = ast_str_create(128); + if (!tcptls_session->overflow_buf) { + ao2_ref(tcptls_session, -1); + close(fd); + continue; + } flags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); tcptls_session->fd = fd; @@ -1059,11 +1061,15 @@ struct ast_tcptls_session_instance *ast_tcptls_client_create(struct ast_tcptls_s } } - if (!(tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor))) { + tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor); + if (!tcptls_session) { goto error; } tcptls_session->overflow_buf = ast_str_create(128); + if (!tcptls_session->overflow_buf) { + goto error; + } tcptls_session->client = 1; tcptls_session->fd = desc->accept_fd; tcptls_session->parent = desc; @@ -1078,9 +1084,7 @@ struct ast_tcptls_session_instance *ast_tcptls_client_create(struct ast_tcptls_s error: close(desc->accept_fd); desc->accept_fd = -1; - if (tcptls_session) { - ao2_ref(tcptls_session, -1); - } + ao2_cleanup(tcptls_session); return NULL; } 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> |