loader: Add dependency fields to module structures.
[asterisk/asterisk.git] / res / res_ari.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 HTTP binding for the Stasis API
22  * \author David M. Lee, II <dlee@digium.com>
23  *
24  * The API itself is documented using <a
25  * href="https://developers.helloreverb.com/swagger/">Swagger</a>, a lightweight
26  * mechanism for documenting RESTful API's using JSON. This allows us to use <a
27  * href="https://github.com/wordnik/swagger-ui">swagger-ui</a> to provide
28  * executable documentation for the API, generate client bindings in different
29  * <a href="https://github.com/asterisk/asterisk_rest_libraries">languages</a>,
30  * and generate a lot of the boilerplate code for implementing the RESTful
31  * bindings. The API docs live in the \c rest-api/ directory.
32  *
33  * The RESTful bindings are generated from the Swagger API docs using a set of
34  * <a href="http://mustache.github.io/mustache.5.html">Mustache</a> templates.
35  * The code generator is written in Python, and uses the Python implementation
36  * <a href="https://github.com/defunkt/pystache">pystache</a>. Pystache has no
37  * dependencies, and be installed easily using \c pip. Code generation code
38  * lives in \c rest-api-templates/.
39  *
40  * The generated code reduces a lot of boilerplate when it comes to handling
41  * HTTP requests. It also helps us have greater consistency in the REST API.
42  *
43  * The structure of the generated code is:
44  *
45  *  - res/ari/resource_{resource}.h
46  *    - For each operation in the resouce, a generated argument structure
47  *      (holding the parsed arguments from the request) and function
48  *      declarations (to implement in res/ari/resource_{resource}.c)
49  *  - res_ari_{resource}.c
50  *    - A set of \ref stasis_rest_callback functions, which glue the two
51  *      together. They parse out path variables and request parameters to
52  *      populate a specific \c *_args which is passed to the specific request
53  *      handler (in res/ari/resource_{resource}.c)
54  *    - A tree of \ref stasis_rest_handlers for routing requests to its
55  *      \ref stasis_rest_callback
56  *
57  * The basic flow of an HTTP request is:
58  *
59  *  - ast_ari_callback()
60  *    1. Initial request validation
61  *    2. Routes as either a doc request (ast_ari_get_docs) or API
62  *       request (ast_ari_invoke)
63  *       - ast_ari_invoke()
64  *         1. Further request validation
65  *         2. Routes the request through the tree of generated
66  *            \ref stasis_rest_handlers.
67  *         3. Dispatch to the generated callback
68  *            - \c ast_ari_*_cb
69  *              1. Populate \c *_args struct with path and get params
70  *              2. Invoke the request handler
71  *    3. Validates and sends response
72  */
73
74 /*** MODULEINFO
75         <depend type="module">res_http_websocket</depend>
76         <depend type="module">res_stasis</depend>
77         <support_level>core</support_level>
78  ***/
79
80 /*** DOCUMENTATION
81         <configInfo name="res_ari" language="en_US">
82                 <synopsis>HTTP binding for the Stasis API</synopsis>
83                 <configFile name="ari.conf">
84                         <configObject name="general">
85                                 <synopsis>General configuration settings</synopsis>
86                                 <configOption name="enabled">
87                                         <synopsis>Enable/disable the ARI module</synopsis>
88                                         <description>
89                                                 <para>This option enables or disables the ARI module.</para>
90                                                 <note>
91                                                         <para>ARI uses Asterisk's HTTP server, which must also be enabled in <filename>http.conf</filename>.</para>
92                                                 </note>
93                                         </description>
94                                         <see-also>
95                                                 <ref type="filename">http.conf</ref>
96                                                 <ref type="link">https://wiki.asterisk.org/wiki/display/AST/Asterisk+Builtin+mini-HTTP+Server</ref>
97                                         </see-also>
98                                 </configOption>
99                                 <configOption name="websocket_write_timeout">
100                                         <synopsis>The timeout (in milliseconds) to set on WebSocket connections.</synopsis>
101                                         <description>
102                                                 <para>If a websocket connection accepts input slowly, the timeout
103                                                 for writes to it can be increased to keep it from being disconnected.
104                                                 Value is in milliseconds; default is 100 ms.</para>
105                                         </description>
106                                 </configOption>
107                                 <configOption name="pretty">
108                                         <synopsis>Responses from ARI are formatted to be human readable</synopsis>
109                                 </configOption>
110                                 <configOption name="auth_realm">
111                                         <synopsis>Realm to use for authentication. Defaults to Asterisk REST Interface.</synopsis>
112                                 </configOption>
113                                 <configOption name="allowed_origins">
114                                         <synopsis>Comma separated list of allowed origins, for Cross-Origin Resource Sharing. May be set to * to allow all origins.</synopsis>
115                                 </configOption>
116                                 <configOption name="channelvars">
117                                         <synopsis>Comma separated list of channel variables to display in channel json.</synopsis>
118                                 </configOption>
119                         </configObject>
120
121                         <configObject name="user">
122                                 <synopsis>Per-user configuration settings</synopsis>
123                                 <configOption name="type">
124                                         <synopsis>Define this configuration section as a user.</synopsis>
125                                         <description>
126                                                 <enumlist>
127                                                         <enum name="user"><para>Configure this section as a <replaceable>user</replaceable></para></enum>
128                                                 </enumlist>
129                                         </description>
130                                 </configOption>
131                                 <configOption name="read_only">
132                                         <synopsis>When set to yes, user is only authorized for read-only requests</synopsis>
133                                 </configOption>
134                                 <configOption name="password">
135                                         <synopsis>Crypted or plaintext password (see password_format)</synopsis>
136                                 </configOption>
137                                 <configOption name="password_format">
138                                         <synopsis>password_format may be set to plain (the default) or crypt. When set to crypt, crypt(3) is used to validate the password. A crypted password can be generated using mkpasswd -m sha-512. When set to plain, the password is in plaintext</synopsis>
139                                 </configOption>
140                         </configObject>
141                 </configFile>
142         </configInfo>
143 ***/
144
145 #include "asterisk.h"
146
147 #include "ari/internal.h"
148 #include "asterisk/ari.h"
149 #include "asterisk/astobj2.h"
150 #include "asterisk/module.h"
151 #include "asterisk/paths.h"
152 #include "asterisk/stasis_app.h"
153
154 #include <string.h>
155 #include <sys/stat.h>
156 #include <unistd.h>
157
158 /*! \brief Helper function to check if module is enabled. */
159 static int is_enabled(void)
160 {
161         RAII_VAR(struct ast_ari_conf *, cfg, ast_ari_config_get(), ao2_cleanup);
162         return cfg && cfg->general && cfg->general->enabled;
163 }
164
165 /*! Lock for \ref root_handler */
166 static ast_mutex_t root_handler_lock;
167
168 /*! Handler for root RESTful resource. */
169 static struct stasis_rest_handlers *root_handler;
170
171 /*! Pre-defined message for allocation failures. */
172 static struct ast_json *oom_json;
173
174 struct ast_json *ast_ari_oom_json(void)
175 {
176         return oom_json;
177 }
178
179 int ast_ari_add_handler(struct stasis_rest_handlers *handler)
180 {
181         RAII_VAR(struct stasis_rest_handlers *, new_handler, NULL, ao2_cleanup);
182         size_t old_size, new_size;
183
184         SCOPED_MUTEX(lock, &root_handler_lock);
185
186         old_size = sizeof(*new_handler) + root_handler->num_children * sizeof(handler);
187         new_size = old_size + sizeof(handler);
188
189         new_handler = ao2_alloc(new_size, NULL);
190         if (!new_handler) {
191                 return -1;
192         }
193         memcpy(new_handler, root_handler, old_size);
194         new_handler->children[new_handler->num_children++] = handler;
195
196         ao2_cleanup(root_handler);
197         ao2_ref(new_handler, +1);
198         root_handler = new_handler;
199         ast_module_ref(ast_module_info->self);
200         return 0;
201 }
202
203 int ast_ari_remove_handler(struct stasis_rest_handlers *handler)
204 {
205         struct stasis_rest_handlers *new_handler;
206         size_t size;
207         size_t i;
208         size_t j;
209
210         ast_assert(root_handler != NULL);
211
212         ast_mutex_lock(&root_handler_lock);
213         size = sizeof(*new_handler) + root_handler->num_children * sizeof(handler);
214
215         new_handler = ao2_alloc(size, NULL);
216         if (!new_handler) {
217                 ast_mutex_unlock(&root_handler_lock);
218                 return -1;
219         }
220
221         /* Create replacement root_handler less the handler to remove. */
222         memcpy(new_handler, root_handler, sizeof(*new_handler));
223         for (i = 0, j = 0; i < root_handler->num_children; ++i) {
224                 if (root_handler->children[i] == handler) {
225                         ast_module_unref(ast_module_info->self);
226                         continue;
227                 }
228                 new_handler->children[j++] = root_handler->children[i];
229         }
230         new_handler->num_children = j;
231
232         /* Replace the old root_handler with the new. */
233         ao2_cleanup(root_handler);
234         root_handler = new_handler;
235
236         ast_mutex_unlock(&root_handler_lock);
237         return 0;
238 }
239
240 static struct stasis_rest_handlers *get_root_handler(void)
241 {
242         SCOPED_MUTEX(lock, &root_handler_lock);
243         ao2_ref(root_handler, +1);
244         return root_handler;
245 }
246
247 static struct stasis_rest_handlers *root_handler_create(void)
248 {
249         RAII_VAR(struct stasis_rest_handlers *, handler, NULL, ao2_cleanup);
250
251         handler = ao2_alloc(sizeof(*handler), NULL);
252         if (!handler) {
253                 return NULL;
254         }
255         handler->path_segment = "ari";
256
257         ao2_ref(handler, +1);
258         return handler;
259 }
260
261 void ast_ari_response_error(struct ast_ari_response *response,
262                                 int response_code,
263                                 const char *response_text,
264                                 const char *message_fmt, ...)
265 {
266         RAII_VAR(struct ast_json *, message, NULL, ast_json_unref);
267         va_list ap;
268
269         va_start(ap, message_fmt);
270         message = ast_json_vstringf(message_fmt, ap);
271         va_end(ap);
272         response->message = ast_json_pack("{s: o}",
273                                           "message", ast_json_ref(message));
274         response->response_code = response_code;
275         response->response_text = response_text;
276 }
277
278 void ast_ari_response_ok(struct ast_ari_response *response,
279                              struct ast_json *message)
280 {
281         response->message = message;
282         response->response_code = 200;
283         response->response_text = "OK";
284 }
285
286 void ast_ari_response_no_content(struct ast_ari_response *response)
287 {
288         response->message = ast_json_null();
289         response->response_code = 204;
290         response->response_text = "No Content";
291 }
292
293 void ast_ari_response_accepted(struct ast_ari_response *response)
294 {
295         response->message = ast_json_null();
296         response->response_code = 202;
297         response->response_text = "Accepted";
298 }
299
300 void ast_ari_response_alloc_failed(struct ast_ari_response *response)
301 {
302         response->message = ast_json_ref(oom_json);
303         response->response_code = 500;
304         response->response_text = "Internal Server Error";
305 }
306
307 void ast_ari_response_created(struct ast_ari_response *response,
308         const char *url, struct ast_json *message)
309 {
310         RAII_VAR(struct stasis_rest_handlers *, root, get_root_handler(), ao2_cleanup);
311         response->message = message;
312         response->response_code = 201;
313         response->response_text = "Created";
314         ast_str_append(&response->headers, 0, "Location: /%s%s\r\n", root->path_segment, url);
315 }
316
317 static void add_allow_header(struct stasis_rest_handlers *handler,
318                              struct ast_ari_response *response)
319 {
320         enum ast_http_method m;
321         ast_str_append(&response->headers, 0,
322                        "Allow: OPTIONS");
323         for (m = 0; m < AST_HTTP_MAX_METHOD; ++m) {
324                 if (handler->callbacks[m] != NULL) {
325                         ast_str_append(&response->headers, 0,
326                                        ",%s", ast_get_http_method(m));
327                 }
328         }
329         ast_str_append(&response->headers, 0, "\r\n");
330 }
331
332 static int origin_allowed(const char *origin)
333 {
334         RAII_VAR(struct ast_ari_conf *, cfg, ast_ari_config_get(), ao2_cleanup);
335
336         char *allowed = ast_strdupa(cfg->general->allowed_origins);
337         char *current;
338
339         while ((current = strsep(&allowed, ","))) {
340                 if (!strcmp(current, "*")) {
341                         return 1;
342                 }
343
344                 if (!strcmp(current, origin)) {
345                         return 1;
346                 }
347         }
348
349         return 0;
350 }
351
352 #define ACR_METHOD "Access-Control-Request-Method"
353 #define ACR_HEADERS "Access-Control-Request-Headers"
354 #define ACA_METHODS "Access-Control-Allow-Methods"
355 #define ACA_HEADERS "Access-Control-Allow-Headers"
356
357 /*!
358  * \brief Handle OPTIONS request, mainly for CORS preflight requests.
359  *
360  * Some browsers will send this prior to non-simple methods (i.e. DELETE).
361  * See http://www.w3.org/TR/cors/ for the spec. Especially section 6.2.
362  */
363 static void handle_options(struct stasis_rest_handlers *handler,
364                            struct ast_variable *headers,
365                            struct ast_ari_response *response)
366 {
367         struct ast_variable *header;
368         char const *acr_method = NULL;
369         char const *acr_headers = NULL;
370         char const *origin = NULL;
371
372         RAII_VAR(struct ast_str *, allow, NULL, ast_free);
373         enum ast_http_method m;
374         int allowed = 0;
375
376         /* Regular OPTIONS response */
377         add_allow_header(handler, response);
378         ast_ari_response_no_content(response);
379
380         /* Parse CORS headers */
381         for (header = headers; header != NULL; header = header->next) {
382                 if (strcmp(ACR_METHOD, header->name) == 0) {
383                         acr_method = header->value;
384                 } else if (strcmp(ACR_HEADERS, header->name) == 0) {
385                         acr_headers = header->value;
386                 } else if (strcmp("Origin", header->name) == 0) {
387                         origin = header->value;
388                 }
389         }
390
391         /* CORS 6.2, #1 - "If the Origin header is not present terminate this
392          * set of steps."
393          */
394         if (origin == NULL) {
395                 return;
396         }
397
398         /* CORS 6.2, #2 - "If the value of the Origin header is not a
399          * case-sensitive match for any of the values in list of origins do not
400          * set any additional headers and terminate this set of steps.
401          *
402          * Always matching is acceptable since the list of origins can be
403          * unbounded.
404          *
405          * The Origin header can only contain a single origin as the user agent
406          * will not follow redirects."
407          */
408         if (!origin_allowed(origin)) {
409                 ast_log(LOG_NOTICE, "Origin header '%s' does not match an allowed origin.\n", origin);
410                 return;
411         }
412
413         /* CORS 6.2, #3 - "If there is no Access-Control-Request-Method header
414          * or if parsing failed, do not set any additional headers and terminate
415          * this set of steps."
416          */
417         if (acr_method == NULL) {
418                 return;
419         }
420
421         /* CORS 6.2, #4 - "If there are no Access-Control-Request-Headers
422          * headers let header field-names be the empty list."
423          */
424         if (acr_headers == NULL) {
425                 acr_headers = "";
426         }
427
428         /* CORS 6.2, #5 - "If method is not a case-sensitive match for any of
429          * the values in list of methods do not set any additional headers and
430          * terminate this set of steps."
431          */
432         allow = ast_str_create(20);
433
434         if (!allow) {
435                 ast_ari_response_alloc_failed(response);
436                 return;
437         }
438
439         /* Go ahead and build the ACA_METHODS header at the same time */
440         for (m = 0; m < AST_HTTP_MAX_METHOD; ++m) {
441                 if (handler->callbacks[m] != NULL) {
442                         char const *m_str = ast_get_http_method(m);
443                         if (strcmp(m_str, acr_method) == 0) {
444                                 allowed = 1;
445                         }
446                         ast_str_append(&allow, 0, ",%s", m_str);
447                 }
448         }
449
450         if (!allowed) {
451                 return;
452         }
453
454         /* CORS 6.2 #6 - "If any of the header field-names is not a ASCII
455          * case-insensitive match for any of the values in list of headers do
456          * not set any additional headers and terminate this set of steps.
457          *
458          * Note: Always matching is acceptable since the list of headers can be
459          * unbounded."
460          */
461
462         /* CORS 6.2 #7 - "If the resource supports credentials add a single
463          * Access-Control-Allow-Origin header, with the value of the Origin
464          * header as value, and add a single Access-Control-Allow-Credentials
465          * header with the case-sensitive string "true" as value."
466          *
467          * Added by process_cors_request() earlier in the request.
468          */
469
470         /* CORS 6.2 #8 - "Optionally add a single Access-Control-Max-Age
471          * header..."
472          */
473
474         /* CORS 6.2 #9 - "Add one or more Access-Control-Allow-Methods headers
475          * consisting of (a subset of) the list of methods."
476          */
477         ast_str_append(&response->headers, 0, "%s: OPTIONS%s\r\n",
478                        ACA_METHODS, ast_str_buffer(allow));
479
480
481         /* CORS 6.2, #10 - "Add one or more Access-Control-Allow-Headers headers
482          * consisting of (a subset of) the list of headers.
483          *
484          * Since the list of headers can be unbounded simply returning headers
485          * can be enough."
486          */
487         if (!ast_strlen_zero(acr_headers)) {
488                 ast_str_append(&response->headers, 0, "%s: %s\r\n",
489                                ACA_HEADERS, acr_headers);
490         }
491 }
492
493 void ast_ari_invoke(struct ast_tcptls_session_instance *ser,
494         const char *uri, enum ast_http_method method,
495         struct ast_variable *get_params, struct ast_variable *headers,
496         struct ast_json *body, struct ast_ari_response *response)
497 {
498         RAII_VAR(struct stasis_rest_handlers *, root, NULL, ao2_cleanup);
499         struct stasis_rest_handlers *handler;
500         RAII_VAR(struct ast_variable *, path_vars, NULL, ast_variables_destroy);
501         char *path = ast_strdupa(uri);
502         char *path_segment;
503         stasis_rest_callback callback;
504
505         root = handler = get_root_handler();
506         ast_assert(root != NULL);
507
508         while ((path_segment = strsep(&path, "/")) && (strlen(path_segment) > 0)) {
509                 struct stasis_rest_handlers *found_handler = NULL;
510                 int i;
511
512                 ast_uri_decode(path_segment, ast_uri_http_legacy);
513                 ast_debug(3, "Finding handler for %s\n", path_segment);
514
515                 for (i = 0; found_handler == NULL && i < handler->num_children; ++i) {
516                         struct stasis_rest_handlers *child = handler->children[i];
517
518                         ast_debug(3, "  Checking %s\n", child->path_segment);
519                         if (child->is_wildcard) {
520                                 /* Record the path variable */
521                                 struct ast_variable *path_var = ast_variable_new(child->path_segment, path_segment, __FILE__);
522                                 path_var->next = path_vars;
523                                 path_vars = path_var;
524                                 found_handler = child;
525                         } else if (strcmp(child->path_segment, path_segment) == 0) {
526                                 found_handler = child;
527                         }
528                 }
529
530                 if (found_handler == NULL) {
531                         /* resource not found */
532                         ast_debug(3, "  Handler not found\n");
533                         ast_ari_response_error(
534                                 response, 404, "Not Found",
535                                 "Resource not found");
536                         return;
537                 } else {
538                         ast_debug(3, "  Got it!\n");
539                         handler = found_handler;
540                 }
541         }
542
543         ast_assert(handler != NULL);
544         if (method == AST_HTTP_OPTIONS) {
545                 handle_options(handler, headers, response);
546                 return;
547         }
548
549         if (method < 0 || method >= AST_HTTP_MAX_METHOD) {
550                 add_allow_header(handler, response);
551                 ast_ari_response_error(
552                         response, 405, "Method Not Allowed",
553                         "Invalid method");
554                 return;
555         }
556
557         if (handler->ws_server && method == AST_HTTP_GET) {
558                 /* WebSocket! */
559                 ari_handle_websocket(handler->ws_server, ser, uri, method,
560                         get_params, headers);
561                 /* Since the WebSocket code handles the connection, we shouldn't
562                  * do anything else; setting no_response */
563                 response->no_response = 1;
564                 return;
565         }
566
567         callback = handler->callbacks[method];
568         if (callback == NULL) {
569                 add_allow_header(handler, response);
570                 ast_ari_response_error(
571                         response, 405, "Method Not Allowed",
572                         "Invalid method");
573                 return;
574         }
575
576         callback(ser, get_params, path_vars, headers, body, response);
577         if (response->message == NULL && response->response_code == 0) {
578                 /* Really should not happen */
579                 ast_log(LOG_ERROR, "ARI %s %s not implemented\n",
580                         ast_get_http_method(method), uri);
581                 ast_ari_response_error(
582                         response, 501, "Not Implemented",
583                         "Method not implemented");
584         }
585 }
586
587 void ast_ari_get_docs(const char *uri, const char *prefix, struct ast_variable *headers,
588                           struct ast_ari_response *response)
589 {
590         RAII_VAR(struct ast_str *, absolute_path_builder, NULL, ast_free);
591         RAII_VAR(char *, absolute_api_dirname, NULL, ast_std_free);
592         RAII_VAR(char *, absolute_filename, NULL, ast_std_free);
593         struct ast_json *obj = NULL;
594         struct ast_variable *host = NULL;
595         struct ast_json_error error = {};
596         struct stat file_stat;
597
598         ast_debug(3, "%s(%s)\n", __func__, uri);
599
600         absolute_path_builder = ast_str_create(80);
601         if (absolute_path_builder == NULL) {
602                 ast_ari_response_alloc_failed(response);
603                 return;
604         }
605
606         /* absolute path to the rest-api directory */
607         ast_str_append(&absolute_path_builder, 0, "%s", ast_config_AST_DATA_DIR);
608         ast_str_append(&absolute_path_builder, 0, "/rest-api/");
609         absolute_api_dirname = realpath(ast_str_buffer(absolute_path_builder), NULL);
610         if (absolute_api_dirname == NULL) {
611                 ast_log(LOG_ERROR, "Error determining real directory for rest-api\n");
612                 ast_ari_response_error(
613                         response, 500, "Internal Server Error",
614                         "Cannot find rest-api directory");
615                 return;
616         }
617
618         /* absolute path to the requested file */
619         ast_str_append(&absolute_path_builder, 0, "%s", uri);
620         absolute_filename = realpath(ast_str_buffer(absolute_path_builder), NULL);
621         if (absolute_filename == NULL) {
622                 switch (errno) {
623                 case ENAMETOOLONG:
624                 case ENOENT:
625                 case ENOTDIR:
626                         ast_ari_response_error(
627                                 response, 404, "Not Found",
628                                 "Resource not found");
629                         break;
630                 case EACCES:
631                         ast_ari_response_error(
632                                 response, 403, "Forbidden",
633                                 "Permission denied");
634                         break;
635                 default:
636                         ast_log(LOG_ERROR,
637                                 "Error determining real path for uri '%s': %s\n",
638                                 uri, strerror(errno));
639                         ast_ari_response_error(
640                                 response, 500, "Internal Server Error",
641                                 "Cannot find file");
642                         break;
643                 }
644                 return;
645         }
646
647         if (!ast_begins_with(absolute_filename, absolute_api_dirname)) {
648                 /* HACKERZ! */
649                 ast_log(LOG_ERROR,
650                         "Invalid attempt to access '%s' (not in %s)\n",
651                         absolute_filename, absolute_api_dirname);
652                 ast_ari_response_error(
653                         response, 404, "Not Found",
654                         "Resource not found");
655                 return;
656         }
657
658         if (stat(absolute_filename, &file_stat) == 0) {
659                 if (!(file_stat.st_mode & S_IFREG)) {
660                         /* Not a file */
661                         ast_ari_response_error(
662                                 response, 403, "Forbidden",
663                                 "Invalid access");
664                         return;
665                 }
666         } else {
667                 /* Does not exist */
668                 ast_ari_response_error(
669                         response, 404, "Not Found",
670                         "Resource not found");
671                 return;
672         }
673
674         /* Load resource object from file */
675         obj = ast_json_load_new_file(absolute_filename, &error);
676         if (obj == NULL) {
677                 ast_log(LOG_ERROR, "Error parsing resource file: %s:%d(%d) %s\n",
678                         error.source, error.line, error.column, error.text);
679                 ast_ari_response_error(
680                         response, 500, "Internal Server Error",
681                         "Yikes! Cannot parse resource");
682                 return;
683         }
684
685         /* Update the basePath properly */
686         if (ast_json_object_get(obj, "basePath") != NULL) {
687                 for (host = headers; host; host = host->next) {
688                         if (strcasecmp(host->name, "Host") == 0) {
689                                 break;
690                         }
691                 }
692                 if (host != NULL) {
693                         if (prefix != NULL && strlen(prefix) > 0) {
694                                 ast_json_object_set(
695                                         obj, "basePath",
696                                         ast_json_stringf("http://%s%s/ari", host->value,prefix));
697                         } else {
698                                 ast_json_object_set(
699                                         obj, "basePath",
700                                         ast_json_stringf("http://%s/ari", host->value));
701                         }
702                 } else {
703                         /* Without the host, we don't have the basePath */
704                         ast_json_object_del(obj, "basePath");
705                 }
706         }
707
708         ast_ari_response_ok(response, obj);
709 }
710
711 static void remove_trailing_slash(const char *uri,
712                                   struct ast_ari_response *response)
713 {
714         char *slashless = ast_strdupa(uri);
715         slashless[strlen(slashless) - 1] = '\0';
716
717         /* While it's tempting to redirect the client to the slashless URL,
718          * that is problematic. A 302 Found is the most appropriate response,
719          * but most clients issue a GET on the location you give them,
720          * regardless of the method of the original request.
721          *
722          * While there are some ways around this, it gets into a lot of client
723          * specific behavior and corner cases in the HTTP standard. There's also
724          * very little practical benefit of redirecting; only GET and HEAD can
725          * be redirected automagically; all other requests "MUST NOT
726          * automatically redirect the request unless it can be confirmed by the
727          * user, since this might change the conditions under which the request
728          * was issued."
729          *
730          * Given all of that, a 404 with a nice message telling them what to do
731          * is probably our best bet.
732          */
733         ast_ari_response_error(response, 404, "Not Found",
734                 "ARI URLs do not end with a slash. Try /ari/%s", slashless);
735 }
736
737 /*!
738  * \brief Handle CORS headers for simple requests.
739  *
740  * See http://www.w3.org/TR/cors/ for the spec. Especially section 6.1.
741  */
742 static void process_cors_request(struct ast_variable *headers,
743                                  struct ast_ari_response *response)
744 {
745         char const *origin = NULL;
746         struct ast_variable *header;
747
748         /* Parse CORS headers */
749         for (header = headers; header != NULL; header = header->next) {
750                 if (strcmp("Origin", header->name) == 0) {
751                         origin = header->value;
752                 }
753         }
754
755         /* CORS 6.1, #1 - "If the Origin header is not present terminate this
756          * set of steps."
757          */
758         if (origin == NULL) {
759                 return;
760         }
761
762         /* CORS 6.1, #2 - "If the value of the Origin header is not a
763          * case-sensitive match for any of the values in list of origins, do not
764          * set any additional headers and terminate this set of steps.
765          *
766          * Note: Always matching is acceptable since the list of origins can be
767          * unbounded."
768          */
769         if (!origin_allowed(origin)) {
770                 ast_log(LOG_NOTICE, "Origin header '%s' does not match an allowed origin.\n", origin);
771                 return;
772         }
773
774         /* CORS 6.1, #3 - "If the resource supports credentials add a single
775          * Access-Control-Allow-Origin header, with the value of the Origin
776          * header as value, and add a single Access-Control-Allow-Credentials
777          * header with the case-sensitive string "true" as value.
778          *
779          * Otherwise, add a single Access-Control-Allow-Origin header, with
780          * either the value of the Origin header or the string "*" as value."
781          */
782         ast_str_append(&response->headers, 0,
783                        "Access-Control-Allow-Origin: %s\r\n", origin);
784         ast_str_append(&response->headers, 0,
785                        "Access-Control-Allow-Credentials: true\r\n");
786
787         /* CORS 6.1, #4 - "If the list of exposed headers is not empty add one
788          * or more Access-Control-Expose-Headers headers, with as values the
789          * header field names given in the list of exposed headers."
790          *
791          * No exposed headers; skipping
792          */
793 }
794
795 enum ast_json_encoding_format ast_ari_json_format(void)
796 {
797         RAII_VAR(struct ast_ari_conf *, cfg, NULL, ao2_cleanup);
798         cfg = ast_ari_config_get();
799         return cfg->general->format;
800 }
801
802 /*!
803  * \brief Authenticate a <code>?api_key=userid:password</code>
804  *
805  * \param api_key API key query parameter
806  * \return User object for the authenticated user.
807  * \return \c NULL if authentication failed.
808  */
809 static struct ast_ari_conf_user *authenticate_api_key(const char *api_key)
810 {
811         RAII_VAR(char *, copy, NULL, ast_free);
812         char *username;
813         char *password;
814
815         password = copy = ast_strdup(api_key);
816         if (!copy) {
817                 return NULL;
818         }
819
820         username = strsep(&password, ":");
821         if (!password) {
822                 ast_log(LOG_WARNING, "Invalid api_key\n");
823                 return NULL;
824         }
825
826         return ast_ari_config_validate_user(username, password);
827 }
828
829 /*!
830  * \brief Authenticate an HTTP request.
831  *
832  * \param get_params GET parameters of the request.
833  * \param header HTTP headers.
834  * \return User object for the authenticated user.
835  * \return \c NULL if authentication failed.
836  */
837 static struct ast_ari_conf_user *authenticate_user(struct ast_variable *get_params,
838         struct ast_variable *headers)
839 {
840         RAII_VAR(struct ast_http_auth *, http_auth, NULL, ao2_cleanup);
841         struct ast_variable *v;
842
843         /* HTTP Basic authentication */
844         http_auth = ast_http_get_auth(headers);
845         if (http_auth) {
846                 return ast_ari_config_validate_user(http_auth->userid,
847                         http_auth->password);
848         }
849
850         /* ?api_key authentication */
851         for (v = get_params; v; v = v->next) {
852                 if (strcasecmp("api_key", v->name) == 0) {
853                         return authenticate_api_key(v->value);
854                 }
855         }
856
857         return NULL;
858 }
859
860 /*!
861  * \internal
862  * \brief ARI HTTP handler.
863  *
864  * This handler takes the HTTP request and turns it into the appropriate
865  * RESTful request (conversion to JSON, routing, etc.)
866  *
867  * \param ser TCP session.
868  * \param urih URI handler.
869  * \param uri URI requested.
870  * \param method HTTP method.
871  * \param get_params HTTP \c GET params.
872  * \param headers HTTP headers.
873  */
874 static int ast_ari_callback(struct ast_tcptls_session_instance *ser,
875                                 const struct ast_http_uri *urih,
876                                 const char *uri,
877                                 enum ast_http_method method,
878                                 struct ast_variable *get_params,
879                                 struct ast_variable *headers)
880 {
881         RAII_VAR(struct ast_ari_conf *, conf, NULL, ao2_cleanup);
882         RAII_VAR(struct ast_str *, response_body, ast_str_create(256), ast_free);
883         RAII_VAR(struct ast_ari_conf_user *, user, NULL, ao2_cleanup);
884         struct ast_ari_response response = { .fd = -1, 0 };
885         RAII_VAR(struct ast_variable *, post_vars, NULL, ast_variables_destroy);
886         struct ast_variable *var;
887         const char *app_name = NULL;
888         RAII_VAR(struct ast_json *, body, ast_json_null(), ast_json_unref);
889         int debug_app = 0;
890
891         if (!response_body) {
892                 ast_http_request_close_on_completion(ser);
893                 ast_http_error(ser, 500, "Server Error", "Out of memory");
894                 return 0;
895         }
896
897         response.headers = ast_str_create(40);
898         if (!response.headers) {
899                 ast_http_request_close_on_completion(ser);
900                 ast_http_error(ser, 500, "Server Error", "Out of memory");
901                 return 0;
902         }
903
904         conf = ast_ari_config_get();
905         if (!conf || !conf->general) {
906                 ast_free(response.headers);
907                 ast_http_request_close_on_completion(ser);
908                 ast_http_error(ser, 500, "Server Error", "URI handler config missing");
909                 return 0;
910         }
911
912         process_cors_request(headers, &response);
913
914         /* Process form data from a POST. It could be mixed with query
915          * parameters, which seems a bit odd. But it's allowed, so that's okay
916          * with us.
917          */
918         post_vars = ast_http_get_post_vars(ser, headers);
919         if (!post_vars) {
920                 switch (errno) {
921                 case EFBIG:
922                         ast_ari_response_error(&response, 413,
923                                 "Request Entity Too Large",
924                                 "Request body too large");
925                         goto request_failed;
926                 case ENOMEM:
927                         ast_http_request_close_on_completion(ser);
928                         ast_ari_response_error(&response, 500,
929                                 "Internal Server Error",
930                                 "Out of memory");
931                         goto request_failed;
932                 case EIO:
933                         ast_ari_response_error(&response, 400,
934                                 "Bad Request", "Error parsing request body");
935                         goto request_failed;
936                 }
937
938                 /* Look for a JSON request entity only if there were no post_vars.
939                  * If there were post_vars, then the request body would already have
940                  * been consumed and can not be read again.
941                  */
942                 body = ast_http_get_json(ser, headers);
943                 if (!body) {
944                         switch (errno) {
945                         case EFBIG:
946                                 ast_ari_response_error(&response, 413, "Request Entity Too Large", "Request body too large");
947                                 goto request_failed;
948                         case ENOMEM:
949                                 ast_ari_response_error(&response, 500, "Internal Server Error", "Error processing request");
950                                 goto request_failed;
951                         case EIO:
952                                 ast_ari_response_error(&response, 400, "Bad Request", "Error parsing request body");
953                                 goto request_failed;
954                         }
955                 }
956         }
957         if (get_params == NULL) {
958                 get_params = post_vars;
959         } else if (get_params && post_vars) {
960                 /* Has both post_vars and get_params */
961                 struct ast_variable *last_var = post_vars;
962                 while (last_var->next) {
963                         last_var = last_var->next;
964                 }
965                 /* The duped get_params will get freed when post_vars gets
966                  * ast_variables_destroyed.
967                  */
968                 last_var->next = ast_variables_dup(get_params);
969                 get_params = post_vars;
970         }
971
972         /* At this point, get_params will contain post_vars (if any) */
973         app_name = ast_variable_find_in_list(get_params, "app");
974         if (!app_name) {
975                 struct ast_json *app = ast_json_object_get(body, "app");
976
977                 app_name = (app ? ast_json_string_get(app) : NULL);
978         }
979
980         /* stasis_app_get_debug_by_name returns an "||" of the app's debug flag
981          * and the global debug flag.
982          */
983         debug_app = stasis_app_get_debug_by_name(app_name);
984         if (debug_app) {
985                 struct ast_str *buf = ast_str_create(512);
986                 char *str = ast_json_dump_string_format(body, ast_ari_json_format());
987
988                 if (!buf || !str) {
989                         ast_http_request_close_on_completion(ser);
990                         ast_http_error(ser, 500, "Server Error", "Out of memory");
991                         ast_json_free(str);
992                         ast_free(buf);
993                         goto request_failed;
994                 }
995
996                 ast_str_append(&buf, 0, "<--- ARI request received from: %s --->\n",
997                         ast_sockaddr_stringify(&ser->remote_address));
998                 for (var = headers; var; var = var->next) {
999                         ast_str_append(&buf, 0, "%s: %s\n", var->name, var->value);
1000                 }
1001                 for (var = get_params; var; var = var->next) {
1002                         ast_str_append(&buf, 0, "%s: %s\n", var->name, var->value);
1003                 }
1004                 ast_verbose("%sbody:\n%s\n\n", ast_str_buffer(buf), str);
1005                 ast_json_free(str);
1006                 ast_free(buf);
1007         }
1008
1009         user = authenticate_user(get_params, headers);
1010         if (response.response_code > 0) {
1011                 /* POST parameter processing error. Do nothing. */
1012         } else if (!user) {
1013                 /* Per RFC 2617, section 1.2: The 401 (Unauthorized) response
1014                  * message is used by an origin server to challenge the
1015                  * authorization of a user agent. This response MUST include a
1016                  * WWW-Authenticate header field containing at least one
1017                  * challenge applicable to the requested resource.
1018                  */
1019                 ast_ari_response_error(&response, 401, "Unauthorized", "Authentication required");
1020
1021                 /* Section 1.2:
1022                  *   realm       = "realm" "=" realm-value
1023                  *   realm-value = quoted-string
1024                  * Section 2:
1025                  *   challenge   = "Basic" realm
1026                  */
1027                 ast_str_append(&response.headers, 0,
1028                         "WWW-Authenticate: Basic realm=\"%s\"\r\n",
1029                         conf->general->auth_realm);
1030         } else if (!ast_fully_booted) {
1031                 ast_http_request_close_on_completion(ser);
1032                 ast_ari_response_error(&response, 503, "Service Unavailable", "Asterisk not booted");
1033         } else if (user->read_only && method != AST_HTTP_GET && method != AST_HTTP_OPTIONS) {
1034                 ast_ari_response_error(&response, 403, "Forbidden", "Write access denied");
1035         } else if (ast_ends_with(uri, "/")) {
1036                 remove_trailing_slash(uri, &response);
1037         } else if (ast_begins_with(uri, "api-docs/")) {
1038                 /* Serving up API docs */
1039                 if (method != AST_HTTP_GET) {
1040                         ast_ari_response_error(&response, 405, "Method Not Allowed", "Unsupported method");
1041                 } else {
1042                         /* Skip the api-docs prefix */
1043                         ast_ari_get_docs(strchr(uri, '/') + 1, urih->prefix, headers, &response);
1044                 }
1045         } else {
1046                 /* Other RESTful resources */
1047                 ast_ari_invoke(ser, uri, method, get_params, headers, body,
1048                         &response);
1049         }
1050
1051         if (response.no_response) {
1052                 /* The handler indicates no further response is necessary.
1053                  * Probably because it already handled it */
1054                 ast_free(response.headers);
1055                 return 0;
1056         }
1057
1058 request_failed:
1059
1060         /* If you explicitly want to have no content, set message to
1061          * ast_json_null().
1062          */
1063         ast_assert(response.message != NULL);
1064         ast_assert(response.response_code > 0);
1065
1066         /* response.message could be NULL, in which case the empty response_body
1067          * is correct
1068          */
1069         if (response.message && !ast_json_is_null(response.message)) {
1070                 ast_str_append(&response.headers, 0,
1071                                "Content-type: application/json\r\n");
1072                 if (ast_json_dump_str_format(response.message, &response_body,
1073                                 conf->general->format) != 0) {
1074                         /* Error encoding response */
1075                         response.response_code = 500;
1076                         response.response_text = "Internal Server Error";
1077                         ast_str_set(&response_body, 0, "%s", "");
1078                         ast_str_set(&response.headers, 0, "%s", "");
1079                 }
1080         }
1081
1082         if (debug_app) {
1083                 ast_verbose("<--- Sending ARI response to %s --->\n%d %s\n%s%s\n\n",
1084                         ast_sockaddr_stringify(&ser->remote_address), response.response_code,
1085                         response.response_text, ast_str_buffer(response.headers),
1086                         ast_str_buffer(response_body));
1087         }
1088
1089         ast_http_send(ser, method, response.response_code,
1090                       response.response_text, response.headers, response_body,
1091                       response.fd != -1 ? response.fd : 0, 0);
1092         /* ast_http_send takes ownership, so we don't have to free them */
1093         response_body = NULL;
1094
1095         ast_json_unref(response.message);
1096         if (response.fd >= 0) {
1097                 close(response.fd);
1098         }
1099         return 0;
1100 }
1101
1102 static struct ast_http_uri http_uri = {
1103         .callback = ast_ari_callback,
1104         .description = "Asterisk RESTful API",
1105         .uri = "ari",
1106         .has_subtree = 1,
1107         .data = NULL,
1108         .key = __FILE__,
1109         .no_decode_uri = 1,
1110 };
1111
1112 static int unload_module(void)
1113 {
1114         ast_ari_cli_unregister();
1115
1116         if (is_enabled()) {
1117                 ast_debug(3, "Disabling ARI\n");
1118                 ast_http_uri_unlink(&http_uri);
1119         }
1120
1121         ast_ari_config_destroy();
1122
1123         ao2_cleanup(root_handler);
1124         root_handler = NULL;
1125         ast_mutex_destroy(&root_handler_lock);
1126
1127         ast_json_unref(oom_json);
1128         oom_json = NULL;
1129
1130         return 0;
1131 }
1132
1133 static int load_module(void)
1134 {
1135         ast_mutex_init(&root_handler_lock);
1136
1137         /* root_handler may have been built during a declined load */
1138         if (!root_handler) {
1139                 root_handler = root_handler_create();
1140         }
1141         if (!root_handler) {
1142                 return AST_MODULE_LOAD_DECLINE;
1143         }
1144
1145         /* oom_json may have been built during a declined load */
1146         if (!oom_json) {
1147                 oom_json = ast_json_pack(
1148                         "{s: s}", "error", "Allocation failed");
1149         }
1150         if (!oom_json) {
1151                 /* Ironic */
1152                 unload_module();
1153                 return AST_MODULE_LOAD_DECLINE;
1154         }
1155
1156         if (ast_ari_config_init() != 0) {
1157                 unload_module();
1158                 return AST_MODULE_LOAD_DECLINE;
1159         }
1160
1161         if (is_enabled()) {
1162                 ast_debug(3, "ARI enabled\n");
1163                 ast_http_uri_link(&http_uri);
1164         } else {
1165                 ast_debug(3, "ARI disabled\n");
1166         }
1167
1168         if (ast_ari_cli_register() != 0) {
1169                 unload_module();
1170                 return AST_MODULE_LOAD_DECLINE;
1171         }
1172
1173         return AST_MODULE_LOAD_SUCCESS;
1174 }
1175
1176 static int reload_module(void)
1177 {
1178         char was_enabled = is_enabled();
1179
1180         if (ast_ari_config_reload() != 0) {
1181                 return AST_MODULE_LOAD_DECLINE;
1182         }
1183
1184         if (was_enabled && !is_enabled()) {
1185                 ast_debug(3, "Disabling ARI\n");
1186                 ast_http_uri_unlink(&http_uri);
1187         } else if (!was_enabled && is_enabled()) {
1188                 ast_debug(3, "Enabling ARI\n");
1189                 ast_http_uri_link(&http_uri);
1190         }
1191
1192         return AST_MODULE_LOAD_SUCCESS;
1193 }
1194
1195 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Asterisk RESTful Interface",
1196         .support_level = AST_MODULE_SUPPORT_CORE,
1197         .load = load_module,
1198         .unload = unload_module,
1199         .reload = reload_module,
1200         .optional_modules = "res_http_websocket",
1201         .requires = "res_stasis",
1202         .load_pri = AST_MODPRI_APP_DEPEND,
1203 );