ARI: Fix crash if integer values used in JSON payload 'variables' object.
[asterisk/asterisk.git] / res / ari / resource_endpoints.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2012 - 2013, Digium, Inc.
5  *
6  * David M. Lee, II <dlee@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief /api-docs/endpoints.{format} implementation- Endpoint resources
22  *
23  * \author David M. Lee, II <dlee@digium.com>
24  */
25
26 #include "asterisk.h"
27
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
29
30 #include "resource_endpoints.h"
31
32 #include "asterisk/astobj2.h"
33 #include "asterisk/stasis.h"
34 #include "asterisk/stasis_app.h"
35 #include "asterisk/stasis_endpoints.h"
36 #include "asterisk/channel.h"
37 #include "asterisk/message.h"
38
39 void ast_ari_endpoints_list(struct ast_variable *headers,
40         struct ast_ari_endpoints_list_args *args,
41         struct ast_ari_response *response)
42 {
43         RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);
44         RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
45         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
46         struct ao2_iterator i;
47         void *obj;
48
49         cache = ast_endpoint_cache();
50         if (!cache) {
51                 ast_ari_response_error(
52                         response, 500, "Internal Server Error",
53                         "Message bus not initialized");
54                 return;
55         }
56         ao2_ref(cache, +1);
57
58         snapshots = stasis_cache_dump(cache, ast_endpoint_snapshot_type());
59         if (!snapshots) {
60                 ast_ari_response_alloc_failed(response);
61                 return;
62         }
63
64         json = ast_json_array_create();
65         if (!json) {
66                 ast_ari_response_alloc_failed(response);
67                 return;
68         }
69
70         i = ao2_iterator_init(snapshots, 0);
71         while ((obj = ao2_iterator_next(&i))) {
72                 RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);
73                 struct ast_endpoint_snapshot *snapshot = stasis_message_data(msg);
74                 struct ast_json *json_endpoint = ast_endpoint_snapshot_to_json(snapshot, stasis_app_get_sanitizer());
75
76                 if (!json_endpoint || ast_json_array_append(json, json_endpoint)) {
77                         ao2_iterator_destroy(&i);
78                         ast_ari_response_alloc_failed(response);
79                         return;
80                 }
81         }
82         ao2_iterator_destroy(&i);
83
84         ast_ari_response_ok(response, ast_json_ref(json));
85 }
86
87 void ast_ari_endpoints_list_by_tech(struct ast_variable *headers,
88         struct ast_ari_endpoints_list_by_tech_args *args,
89         struct ast_ari_response *response)
90 {
91         RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);
92         RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
93         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
94         struct ast_endpoint *tech_endpoint;
95         struct ao2_iterator i;
96         void *obj;
97
98         tech_endpoint = ast_endpoint_find_by_id(args->tech);
99         if (!tech_endpoint) {
100                 ast_ari_response_error(response, 404, "Not Found",
101                                        "No Endpoints found - invalid tech %s", args->tech);
102                 return;
103         }
104         ao2_ref(tech_endpoint, -1);
105
106         cache = ast_endpoint_cache();
107         if (!cache) {
108                 ast_ari_response_error(
109                         response, 500, "Internal Server Error",
110                         "Message bus not initialized");
111                 return;
112         }
113         ao2_ref(cache, +1);
114
115         snapshots = stasis_cache_dump(cache, ast_endpoint_snapshot_type());
116         if (!snapshots) {
117                 ast_ari_response_alloc_failed(response);
118                 return;
119         }
120
121         json = ast_json_array_create();
122         if (!json) {
123                 ast_ari_response_alloc_failed(response);
124                 return;
125         }
126
127         i = ao2_iterator_init(snapshots, 0);
128         while ((obj = ao2_iterator_next(&i))) {
129                 RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);
130                 struct ast_endpoint_snapshot *snapshot = stasis_message_data(msg);
131                 struct ast_json *json_endpoint;
132                 int r;
133
134                 if (strcasecmp(args->tech, snapshot->tech) != 0) {
135                         continue;
136                 }
137
138                 json_endpoint = ast_endpoint_snapshot_to_json(snapshot, stasis_app_get_sanitizer());
139                 if (!json_endpoint) {
140                         continue;
141                 }
142
143                 r = ast_json_array_append(
144                         json, json_endpoint);
145                 if (r != 0) {
146                         ao2_iterator_destroy(&i);
147                         ast_ari_response_alloc_failed(response);
148                         return;
149                 }
150         }
151         ao2_iterator_destroy(&i);
152         ast_ari_response_ok(response, ast_json_ref(json));
153 }
154
155 void ast_ari_endpoints_get(struct ast_variable *headers,
156         struct ast_ari_endpoints_get_args *args,
157         struct ast_ari_response *response)
158 {
159         struct ast_json *json;
160         RAII_VAR(struct ast_endpoint_snapshot *, snapshot, NULL, ao2_cleanup);
161
162         snapshot = ast_endpoint_latest_snapshot(args->tech, args->resource);
163         if (!snapshot) {
164                 ast_ari_response_error(response, 404, "Not Found",
165                         "Endpoint not found");
166                 return;
167         }
168
169         json = ast_endpoint_snapshot_to_json(snapshot, stasis_app_get_sanitizer());
170         if (!json) {
171                 ast_ari_response_alloc_failed(response);
172                 return;
173         }
174
175         ast_ari_response_ok(response, json);
176 }
177
178 static void send_message(const char *to, const char *from, const char *body, struct ast_variable *variables, struct ast_ari_response *response)
179 {
180         struct ast_variable *current;
181         struct ast_msg *msg;
182         int res = 0;
183
184         if (ast_strlen_zero(to)) {
185                 ast_ari_response_error(response, 400, "Bad Request",
186                         "To must be specified");
187                 return;
188         }
189
190         msg = ast_msg_alloc();
191         if (!msg) {
192                 ast_ari_response_alloc_failed(response);
193                 return;
194         }
195
196         res |= ast_msg_set_from(msg, "%s", from);
197         res |= ast_msg_set_to(msg, "%s", to);
198
199         if (!ast_strlen_zero(body)) {
200                 res |= ast_msg_set_body(msg, "%s", body);
201         }
202
203         for (current = variables; current; current = current->next) {
204                 res |= ast_msg_set_var_outbound(msg, current->name, current->value);
205         }
206
207         if (res) {
208                 ast_ari_response_alloc_failed(response);
209                 ast_msg_destroy(msg);
210                 return;
211         }
212
213         if (ast_msg_send(msg, to, from)) {
214                 ast_ari_response_error(response, 404, "Not Found",
215                         "Endpoint not found");
216         }
217
218         response->message = ast_json_null();
219         response->response_code = 202;
220         response->response_text = "Accepted";
221 }
222
223 /*!
224  * \internal
225  * \brief Convert a \c ast_json list of key/value pair tuples into a \c ast_variable list
226  * \since 13.3.0
227  *
228  * \param[out] response HTTP response if error
229  * \param json_variables The JSON blob containing the variable
230  * \param[out] variables An out reference to the variables to populate.
231  *
232  * \retval 0 on success.
233  * \retval -1 on error.
234  */
235 static int json_to_ast_variables(struct ast_ari_response *response, struct ast_json *json_variables, struct ast_variable **variables)
236 {
237         enum ast_json_to_ast_vars_code res;
238
239         res = ast_json_to_ast_variables(json_variables, variables);
240         switch (res) {
241         case AST_JSON_TO_AST_VARS_CODE_SUCCESS:
242                 return 0;
243         case AST_JSON_TO_AST_VARS_CODE_INVALID_TYPE:
244                 ast_ari_response_error(response, 400, "Bad Request",
245                         "Only string values in the 'variables' object allowed");
246                 break;
247         case AST_JSON_TO_AST_VARS_CODE_OOM:
248                 ast_ari_response_alloc_failed(response);
249                 break;
250         }
251         ast_log(AST_LOG_ERROR, "Unable to convert 'variables' in JSON body to Asterisk variables\n");
252
253         return -1;
254 }
255
256 void ast_ari_endpoints_send_message(struct ast_variable *headers,
257         struct ast_ari_endpoints_send_message_args *args,
258         struct ast_ari_response *response)
259 {
260         struct ast_variable *variables = NULL;
261
262         if (args->variables) {
263                 struct ast_json *json_variables;
264
265                 ast_ari_endpoints_send_message_parse_body(args->variables, args);
266                 json_variables = ast_json_object_get(args->variables, "variables");
267                 if (json_variables
268                         && json_to_ast_variables(response, json_variables, &variables)) {
269                         return;
270                 }
271         }
272
273         send_message(args->to, args->from, args->body, variables, response);
274         ast_variables_destroy(variables);
275 }
276
277 void ast_ari_endpoints_send_message_to_endpoint(struct ast_variable *headers,
278         struct ast_ari_endpoints_send_message_to_endpoint_args *args,
279         struct ast_ari_response *response)
280 {
281         struct ast_variable *variables = NULL;
282         struct ast_endpoint_snapshot *snapshot;
283         char msg_to[128];
284         char *tech = ast_strdupa(args->tech);
285
286         /* Really, we just want to know if this thing exists */
287         snapshot = ast_endpoint_latest_snapshot(args->tech, args->resource);
288         if (!snapshot) {
289                 ast_ari_response_error(response, 404, "Not Found",
290                         "Endpoint not found");
291                 return;
292         }
293         ao2_ref(snapshot, -1);
294
295         if (args->variables) {
296                 struct ast_json *json_variables;
297
298                 ast_ari_endpoints_send_message_to_endpoint_parse_body(args->variables, args);
299                 json_variables = ast_json_object_get(args->variables, "variables");
300                 if (json_variables
301                         && json_to_ast_variables(response, json_variables, &variables)) {
302                         return;
303                 }
304         }
305
306         snprintf(msg_to, sizeof(msg_to), "%s:%s", ast_str_to_lower(tech), args->resource);
307
308         send_message(msg_to, args->from, args->body, variables, response);
309         ast_variables_destroy(variables);
310 }