summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Mudgett <rmudgett@digium.com>2015-02-27 18:31:31 +0000
committerRichard Mudgett <rmudgett@digium.com>2015-02-27 18:31:31 +0000
commit9e841e4fb62f072f26f076bd4dd2a8eebe7a9e75 (patch)
treee0040f22d288c44f53089f95868540264a5689fe
parentd79670b2694c22ab078e029a6a3b7e066d6ae531 (diff)
ARI: Fix crash if integer values used in JSON payload 'variables' object.
Sending the following ARI commands caused Asterisk to crash if the JSON body 'variables' object passes values of types other than strings. POST /ari/channels POST /ari/channels/{channelid} PUT /ari/endpoints/sendMessage PUT /ari/endpoints/{tech}/{resource}/sendMessage * Eliminated RAII_VAR usage in ast_ari_channels_originate_with_id(), ast_ari_channels_originate(), ast_ari_endpoints_send_message(), and ast_ari_endpoints_send_message_to_endpoint(). ASTERISK-24751 #close Reported by: jeffrey putnam Review: https://reviewboard.asterisk.org/r/4447/ ........ Merged revisions 432404 from http://svn.asterisk.org/svn/asterisk/branches/13 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@432405 65c4cc65-6c06-0410-ace0-fbb531ad65f3
-rw-r--r--include/asterisk/json.h18
-rw-r--r--main/json.c29
-rw-r--r--res/ari/resource_channels.c57
-rw-r--r--res/ari/resource_endpoints.c61
-rw-r--r--res/res_ari_endpoints.c1
-rw-r--r--rest-api/api-docs/endpoints.json4
6 files changed, 129 insertions, 41 deletions
diff --git a/include/asterisk/json.h b/include/asterisk/json.h
index 8cb74a459..28ebfbd51 100644
--- a/include/asterisk/json.h
+++ b/include/asterisk/json.h
@@ -1010,13 +1010,24 @@ struct ast_party_id;
*/
struct ast_json *ast_json_party_id(struct ast_party_id *party);
+enum ast_json_to_ast_vars_code {
+ /*! \brief Conversion successful */
+ AST_JSON_TO_AST_VARS_CODE_SUCCESS,
+ /*!
+ * \brief Conversion failed because invalid value type supplied.
+ * \note Only string values allowed.
+ */
+ AST_JSON_TO_AST_VARS_CODE_INVALID_TYPE,
+ /*! \brief Conversion failed because of allocation failure. (Out Of Memory) */
+ AST_JSON_TO_AST_VARS_CODE_OOM,
+};
+
/*!
* \brief Convert a \c ast_json list of key/value pair tuples into a \c ast_variable list
* \since 12.5.0
*
* \param json_variables The JSON blob containing the variable
* \param variables An out reference to the variables to populate.
- * The pointer to the variables should be NULL when calling this.
*
* \code
* struct ast_json *json_variables = ast_json_pack("[ { s: s } ]", "foo", "bar");
@@ -1026,10 +1037,9 @@ struct ast_json *ast_json_party_id(struct ast_party_id *party);
* res = ast_json_to_ast_variables(json_variables, &variables);
* \endcode
*
- * \retval 0 success
- * \retval -1 error
+ * \return Conversion enum ast_json_to_ast_vars_code status
*/
-int ast_json_to_ast_variables(struct ast_json *json_variables, struct ast_variable **variables);
+enum ast_json_to_ast_vars_code ast_json_to_ast_variables(struct ast_json *json_variables, struct ast_variable **variables);
/*!@}*/
diff --git a/main/json.c b/main/json.c
index 88e807772..35e6f16ce 100644
--- a/main/json.c
+++ b/main/json.c
@@ -882,32 +882,47 @@ struct ast_json *ast_json_party_id(struct ast_party_id *party)
return ast_json_ref(json_party_id);
}
-int ast_json_to_ast_variables(struct ast_json *json_variables, struct ast_variable **variables)
+enum ast_json_to_ast_vars_code ast_json_to_ast_variables(struct ast_json *json_variables, struct ast_variable **variables)
{
struct ast_json_iter *it_json_var;
*variables = NULL;
for (it_json_var = ast_json_object_iter(json_variables); it_json_var;
- it_json_var = ast_json_object_iter_next(json_variables, it_json_var)) {
+ it_json_var = ast_json_object_iter_next(json_variables, it_json_var)) {
struct ast_variable *new_var;
const char *key = ast_json_object_iter_key(it_json_var);
+ const char *value;
+ struct ast_json *json_value;
if (ast_strlen_zero(key)) {
continue;
}
- new_var = ast_variable_new(key,
- ast_json_string_get(ast_json_object_iter_value(it_json_var)),
- "");
+ json_value = ast_json_object_iter_value(it_json_var);
+ if (ast_json_typeof(json_value) != AST_JSON_STRING) {
+ /* Error: Only strings allowed */
+ ast_variables_destroy(*variables);
+ *variables = NULL;
+ return AST_JSON_TO_AST_VARS_CODE_INVALID_TYPE;
+ }
+ value = ast_json_string_get(json_value);
+ /* Should never be NULL. Otherwise, how could it be a string type? */
+ ast_assert(value != NULL);
+ if (!value) {
+ /* To be safe. */
+ continue;
+ }
+ new_var = ast_variable_new(key, value, "");
if (!new_var) {
+ /* Error: OOM */
ast_variables_destroy(*variables);
*variables = NULL;
- return -1;
+ return AST_JSON_TO_AST_VARS_CODE_OOM;
}
ast_variable_list_append(variables, new_var);
}
- return 0;
+ return AST_JSON_TO_AST_VARS_CODE_SUCCESS;
}
diff --git a/res/ari/resource_channels.c b/res/ari/resource_channels.c
index 693835129..fb1aa039c 100644
--- a/res/ari/resource_channels.c
+++ b/res/ari/resource_channels.c
@@ -1147,11 +1147,44 @@ static void ari_channels_handle_originate_with_id(const char *args_endpoint,
return;
}
+/*!
+ * \internal
+ * \brief Convert a \c ast_json list of key/value pair tuples into a \c ast_variable list
+ * \since 13.3.0
+ *
+ * \param[out] response HTTP response if error
+ * \param json_variables The JSON blob containing the variable
+ * \param[out] variables An out reference to the variables to populate.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int json_to_ast_variables(struct ast_ari_response *response, struct ast_json *json_variables, struct ast_variable **variables)
+{
+ enum ast_json_to_ast_vars_code res;
+
+ res = ast_json_to_ast_variables(json_variables, variables);
+ switch (res) {
+ case AST_JSON_TO_AST_VARS_CODE_SUCCESS:
+ return 0;
+ case AST_JSON_TO_AST_VARS_CODE_INVALID_TYPE:
+ ast_ari_response_error(response, 400, "Bad Request",
+ "Only string values in the 'variables' object allowed");
+ break;
+ case AST_JSON_TO_AST_VARS_CODE_OOM:
+ ast_ari_response_alloc_failed(response);
+ break;
+ }
+ ast_log(AST_LOG_ERROR, "Unable to convert 'variables' in JSON body to channel variables\n");
+
+ return -1;
+}
+
void ast_ari_channels_originate_with_id(struct ast_variable *headers,
struct ast_ari_channels_originate_with_id_args *args,
struct ast_ari_response *response)
{
- RAII_VAR(struct ast_variable *, variables, NULL, ast_variables_destroy);
+ struct ast_variable *variables = NULL;
/* Parse any query parameters out of the body parameter */
if (args->variables) {
@@ -1159,12 +1192,9 @@ void ast_ari_channels_originate_with_id(struct ast_variable *headers,
ast_ari_channels_originate_with_id_parse_body(args->variables, args);
json_variables = ast_json_object_get(args->variables, "variables");
- if (json_variables) {
- if (ast_json_to_ast_variables(json_variables, &variables)) {
- ast_log(AST_LOG_ERROR, "Unable to convert 'variables' in JSON body to channel variables\n");
- ast_ari_response_alloc_failed(response);
- return;
- }
+ if (json_variables
+ && json_to_ast_variables(response, json_variables, &variables)) {
+ return;
}
}
@@ -1183,13 +1213,14 @@ void ast_ari_channels_originate_with_id(struct ast_variable *headers,
args->other_channel_id,
args->originator,
response);
+ ast_variables_destroy(variables);
}
void ast_ari_channels_originate(struct ast_variable *headers,
struct ast_ari_channels_originate_args *args,
struct ast_ari_response *response)
{
- RAII_VAR(struct ast_variable *, variables, NULL, ast_variables_destroy);
+ struct ast_variable *variables = NULL;
/* Parse any query parameters out of the body parameter */
if (args->variables) {
@@ -1197,12 +1228,9 @@ void ast_ari_channels_originate(struct ast_variable *headers,
ast_ari_channels_originate_parse_body(args->variables, args);
json_variables = ast_json_object_get(args->variables, "variables");
- if (json_variables) {
- if (ast_json_to_ast_variables(json_variables, &variables)) {
- ast_log(AST_LOG_ERROR, "Unable to convert 'variables' in JSON body to channel variables\n");
- ast_ari_response_alloc_failed(response);
- return;
- }
+ if (json_variables
+ && json_to_ast_variables(response, json_variables, &variables)) {
+ return;
}
}
@@ -1221,6 +1249,7 @@ void ast_ari_channels_originate(struct ast_variable *headers,
args->other_channel_id,
args->originator,
response);
+ ast_variables_destroy(variables);
}
void ast_ari_channels_get_channel_var(struct ast_variable *headers,
diff --git a/res/ari/resource_endpoints.c b/res/ari/resource_endpoints.c
index 4f91e781d..f794969f2 100644
--- a/res/ari/resource_endpoints.c
+++ b/res/ari/resource_endpoints.c
@@ -220,35 +220,66 @@ static void send_message(const char *to, const char *from, const char *body, str
response->response_text = "Accepted";
}
+/*!
+ * \internal
+ * \brief Convert a \c ast_json list of key/value pair tuples into a \c ast_variable list
+ * \since 13.3.0
+ *
+ * \param[out] response HTTP response if error
+ * \param json_variables The JSON blob containing the variable
+ * \param[out] variables An out reference to the variables to populate.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int json_to_ast_variables(struct ast_ari_response *response, struct ast_json *json_variables, struct ast_variable **variables)
+{
+ enum ast_json_to_ast_vars_code res;
+
+ res = ast_json_to_ast_variables(json_variables, variables);
+ switch (res) {
+ case AST_JSON_TO_AST_VARS_CODE_SUCCESS:
+ return 0;
+ case AST_JSON_TO_AST_VARS_CODE_INVALID_TYPE:
+ ast_ari_response_error(response, 400, "Bad Request",
+ "Only string values in the 'variables' object allowed");
+ break;
+ case AST_JSON_TO_AST_VARS_CODE_OOM:
+ ast_ari_response_alloc_failed(response);
+ break;
+ }
+ ast_log(AST_LOG_ERROR, "Unable to convert 'variables' in JSON body to Asterisk variables\n");
+
+ return -1;
+}
+
void ast_ari_endpoints_send_message(struct ast_variable *headers,
struct ast_ari_endpoints_send_message_args *args,
struct ast_ari_response *response)
{
- RAII_VAR(struct ast_variable *, variables, NULL, ast_variables_destroy);
+ struct ast_variable *variables = NULL;
if (args->variables) {
struct ast_json *json_variables;
ast_ari_endpoints_send_message_parse_body(args->variables, args);
json_variables = ast_json_object_get(args->variables, "variables");
- if (json_variables) {
- if (ast_json_to_ast_variables(json_variables, &variables)) {
- ast_log(AST_LOG_ERROR, "Unable to convert 'variables' in JSON body to Asterisk variables\n");
- ast_ari_response_alloc_failed(response);
- return;
- }
+ if (json_variables
+ && json_to_ast_variables(response, json_variables, &variables)) {
+ return;
}
}
send_message(args->to, args->from, args->body, variables, response);
+ ast_variables_destroy(variables);
}
void ast_ari_endpoints_send_message_to_endpoint(struct ast_variable *headers,
struct ast_ari_endpoints_send_message_to_endpoint_args *args,
struct ast_ari_response *response)
{
- RAII_VAR(struct ast_variable *, variables, NULL, ast_variables_destroy);
- RAII_VAR(struct ast_endpoint_snapshot *, snapshot, NULL, ao2_cleanup);
+ struct ast_variable *variables = NULL;
+ struct ast_endpoint_snapshot *snapshot;
char msg_to[128];
char *tech = ast_strdupa(args->tech);
@@ -259,23 +290,21 @@ void ast_ari_endpoints_send_message_to_endpoint(struct ast_variable *headers,
"Endpoint not found");
return;
}
+ ao2_ref(snapshot, -1);
if (args->variables) {
struct ast_json *json_variables;
ast_ari_endpoints_send_message_to_endpoint_parse_body(args->variables, args);
json_variables = ast_json_object_get(args->variables, "variables");
-
- if (json_variables) {
- if (ast_json_to_ast_variables(json_variables, &variables)) {
- ast_log(AST_LOG_ERROR, "Unable to convert 'variables' in JSON body to Asterisk variables\n");
- ast_ari_response_alloc_failed(response);
- return;
- }
+ if (json_variables
+ && json_to_ast_variables(response, json_variables, &variables)) {
+ return;
}
}
snprintf(msg_to, sizeof(msg_to), "%s:%s", ast_str_to_lower(tech), args->resource);
send_message(msg_to, args->from, args->body, variables, response);
+ ast_variables_destroy(variables);
}
diff --git a/res/res_ari_endpoints.c b/res/res_ari_endpoints.c
index 3ebe66858..8d8ed716c 100644
--- a/res/res_ari_endpoints.c
+++ b/res/res_ari_endpoints.c
@@ -181,6 +181,7 @@ static void ast_ari_endpoints_send_message_cb(
break;
case 500: /* Internal Server Error */
case 501: /* Not Implemented */
+ case 400: /* Invalid parameters for sending a message. */
case 404: /* Endpoint not found */
is_valid = 1;
break;
diff --git a/rest-api/api-docs/endpoints.json b/rest-api/api-docs/endpoints.json
index e7b4ba73a..17b884784 100644
--- a/rest-api/api-docs/endpoints.json
+++ b/rest-api/api-docs/endpoints.json
@@ -64,6 +64,10 @@
],
"errorResponses": [
{
+ "code": 400,
+ "reason": "Invalid parameters for sending a message."
+ },
+ {
"code": 404,
"reason": "Endpoint not found"
}