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