00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include "asterisk.h"
00038
00039 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 416067 $")
00040
00041 #include <time.h>
00042 #include <sys/time.h>
00043 #include <sys/stat.h>
00044 #include <sys/signal.h>
00045 #include <fcntl.h>
00046
00047 #include "asterisk/paths.h"
00048 #include "asterisk/cli.h"
00049 #include "asterisk/tcptls.h"
00050 #include "asterisk/http.h"
00051 #include "asterisk/utils.h"
00052 #include "asterisk/strings.h"
00053 #include "asterisk/config.h"
00054 #include "asterisk/stringfields.h"
00055 #include "asterisk/ast_version.h"
00056 #include "asterisk/manager.h"
00057 #include "asterisk/_private.h"
00058 #include "asterisk/astobj2.h"
00059 #include "asterisk/netsock2.h"
00060
00061 #define MAX_PREFIX 80
00062 #define DEFAULT_PORT 8088
00063 #define DEFAULT_TLS_PORT 8089
00064 #define DEFAULT_SESSION_LIMIT 100
00065 #define DEFAULT_SESSION_INACTIVITY 30000
00066
00067
00068 #if defined(HAVE_OPENSSL) && (defined(HAVE_FUNOPEN) || defined(HAVE_FOPENCOOKIE))
00069 #define DO_SSL
00070 #endif
00071
00072 static int session_limit = DEFAULT_SESSION_LIMIT;
00073 static int session_inactivity = DEFAULT_SESSION_INACTIVITY;
00074 static int session_count = 0;
00075
00076 static struct ast_tls_config http_tls_cfg;
00077
00078 static void *httpd_helper_thread(void *arg);
00079
00080
00081
00082
00083 static struct ast_tcptls_session_args http_desc = {
00084 .accept_fd = -1,
00085 .master = AST_PTHREADT_NULL,
00086 .tls_cfg = NULL,
00087 .poll_timeout = -1,
00088 .name = "http server",
00089 .accept_fn = ast_tcptls_server_root,
00090 .worker_fn = httpd_helper_thread,
00091 };
00092
00093 static struct ast_tcptls_session_args https_desc = {
00094 .accept_fd = -1,
00095 .master = AST_PTHREADT_NULL,
00096 .tls_cfg = &http_tls_cfg,
00097 .poll_timeout = -1,
00098 .name = "https server",
00099 .accept_fn = ast_tcptls_server_root,
00100 .worker_fn = httpd_helper_thread,
00101 };
00102
00103 static AST_RWLIST_HEAD_STATIC(uris, ast_http_uri);
00104
00105
00106 static char prefix[MAX_PREFIX];
00107 static int enablestatic;
00108
00109
00110 static struct {
00111 const char *ext;
00112 const char *mtype;
00113 } mimetypes[] = {
00114 { "png", "image/png" },
00115 { "xml", "text/xml" },
00116 { "jpg", "image/jpeg" },
00117 { "js", "application/x-javascript" },
00118 { "wav", "audio/x-wav" },
00119 { "mp3", "audio/mpeg" },
00120 { "svg", "image/svg+xml" },
00121 { "svgz", "image/svg+xml" },
00122 { "gif", "image/gif" },
00123 { "html", "text/html" },
00124 { "htm", "text/html" },
00125 { "css", "text/css" },
00126 { "cnf", "text/plain" },
00127 { "cfg", "text/plain" },
00128 { "bin", "application/octet-stream" },
00129 { "sbn", "application/octet-stream" },
00130 { "ld", "application/octet-stream" },
00131 };
00132
00133 struct http_uri_redirect {
00134 AST_LIST_ENTRY(http_uri_redirect) entry;
00135 char *dest;
00136 char target[0];
00137 };
00138
00139 static AST_RWLIST_HEAD_STATIC(uri_redirects, http_uri_redirect);
00140
00141 static const struct ast_cfhttp_methods_text {
00142 enum ast_http_method method;
00143 const char *text;
00144 } ast_http_methods_text[] = {
00145 { AST_HTTP_UNKNOWN, "UNKNOWN" },
00146 { AST_HTTP_GET, "GET" },
00147 { AST_HTTP_POST, "POST" },
00148 { AST_HTTP_HEAD, "HEAD" },
00149 { AST_HTTP_PUT, "PUT" },
00150 };
00151
00152 const char *ast_get_http_method(enum ast_http_method method)
00153 {
00154 int x;
00155
00156 for (x = 0; x < ARRAY_LEN(ast_http_methods_text); x++) {
00157 if (ast_http_methods_text[x].method == method) {
00158 return ast_http_methods_text[x].text;
00159 }
00160 }
00161
00162 return NULL;
00163 }
00164
00165 const char *ast_http_ftype2mtype(const char *ftype)
00166 {
00167 int x;
00168
00169 if (ftype) {
00170 for (x = 0; x < ARRAY_LEN(mimetypes); x++) {
00171 if (!strcasecmp(ftype, mimetypes[x].ext)) {
00172 return mimetypes[x].mtype;
00173 }
00174 }
00175 }
00176 return NULL;
00177 }
00178
00179 uint32_t ast_http_manid_from_vars(struct ast_variable *headers)
00180 {
00181 uint32_t mngid = 0;
00182 struct ast_variable *v, *cookies;
00183
00184 cookies = ast_http_get_cookies(headers);
00185 for (v = cookies; v; v = v->next) {
00186 if (!strcasecmp(v->name, "mansession_id")) {
00187 sscanf(v->value, "%30x", &mngid);
00188 break;
00189 }
00190 }
00191 ast_variables_destroy(cookies);
00192 return mngid;
00193 }
00194
00195 void ast_http_prefix(char *buf, int len)
00196 {
00197 if (buf) {
00198 ast_copy_string(buf, prefix, len);
00199 }
00200 }
00201
00202 static int static_callback(struct ast_tcptls_session_instance *ser,
00203 const struct ast_http_uri *urih, const char *uri,
00204 enum ast_http_method method, struct ast_variable *get_vars,
00205 struct ast_variable *headers)
00206 {
00207 char *path;
00208 const char *ftype;
00209 const char *mtype;
00210 char wkspace[80];
00211 struct stat st;
00212 int len;
00213 int fd;
00214 struct ast_str *http_header;
00215 struct timeval tv;
00216 struct ast_tm tm;
00217 char timebuf[80], etag[23];
00218 struct ast_variable *v;
00219 int not_modified = 0;
00220
00221 if (method != AST_HTTP_GET && method != AST_HTTP_HEAD) {
00222 ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
00223 return -1;
00224 }
00225
00226
00227
00228 if (!enablestatic || ast_strlen_zero(uri)) {
00229 goto out403;
00230 }
00231
00232
00233 if ((uri[0] < 33) || strchr("./|~@#$%^&*() \t", uri[0])) {
00234 goto out403;
00235 }
00236
00237 if (strstr(uri, "/..")) {
00238 goto out403;
00239 }
00240
00241 if ((ftype = strrchr(uri, '.'))) {
00242 ftype++;
00243 }
00244
00245 if (!(mtype = ast_http_ftype2mtype(ftype))) {
00246 snprintf(wkspace, sizeof(wkspace), "text/%s", S_OR(ftype, "plain"));
00247 mtype = wkspace;
00248 }
00249
00250
00251 if ((len = strlen(uri) + strlen(ast_config_AST_DATA_DIR) + strlen("/static-http/") + 5) > 1024) {
00252 goto out403;
00253 }
00254
00255 path = ast_alloca(len);
00256 sprintf(path, "%s/static-http/%s", ast_config_AST_DATA_DIR, uri);
00257 if (stat(path, &st)) {
00258 goto out404;
00259 }
00260
00261 if (S_ISDIR(st.st_mode)) {
00262 goto out404;
00263 }
00264
00265 if (strstr(path, "/private/") && !astman_is_authed(ast_http_manid_from_vars(headers))) {
00266 goto out403;
00267 }
00268
00269 fd = open(path, O_RDONLY);
00270 if (fd < 0) {
00271 goto out403;
00272 }
00273
00274
00275 snprintf(etag, sizeof(etag), "\"%ld\"", (long)st.st_mtime);
00276
00277
00278 tv.tv_sec = st.st_mtime;
00279 tv.tv_usec = 0;
00280 ast_strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", ast_localtime(&tv, &tm, "GMT"));
00281
00282
00283 for (v = headers; v; v = v->next) {
00284 if (!strcasecmp(v->name, "If-None-Match")) {
00285 if (!strcasecmp(v->value, etag)) {
00286 not_modified = 1;
00287 }
00288 break;
00289 }
00290 }
00291
00292 if ( (http_header = ast_str_create(255)) == NULL) {
00293 close(fd);
00294 return -1;
00295 }
00296
00297 ast_str_set(&http_header, 0, "Content-type: %s\r\n"
00298 "ETag: %s\r\n"
00299 "Last-Modified: %s\r\n",
00300 mtype,
00301 etag,
00302 timebuf);
00303
00304
00305 if (not_modified) {
00306 ast_http_send(ser, method, 304, "Not Modified", http_header, NULL, 0, 1);
00307 } else {
00308 ast_http_send(ser, method, 200, NULL, http_header, NULL, fd, 1);
00309 }
00310 close(fd);
00311 return 0;
00312
00313 out404:
00314 ast_http_error(ser, 404, "Not Found", "The requested URL was not found on this server.");
00315 return -1;
00316
00317 out403:
00318 ast_http_error(ser, 403, "Access Denied", "You do not have permission to access the requested URL.");
00319 return -1;
00320 }
00321
00322 static int httpstatus_callback(struct ast_tcptls_session_instance *ser,
00323 const struct ast_http_uri *urih, const char *uri,
00324 enum ast_http_method method, struct ast_variable *get_vars,
00325 struct ast_variable *headers)
00326 {
00327 struct ast_str *out;
00328 struct ast_variable *v, *cookies = NULL;
00329
00330 if (method != AST_HTTP_GET && method != AST_HTTP_HEAD) {
00331 ast_http_error(ser, 501, "Not Implemented", "Attempt to use unimplemented / unsupported method");
00332 return -1;
00333 }
00334
00335 if ( (out = ast_str_create(512)) == NULL) {
00336 return -1;
00337 }
00338
00339 ast_str_append(&out, 0,
00340 "<title>Asterisk HTTP Status</title>\r\n"
00341 "<body bgcolor=\"#ffffff\">\r\n"
00342 "<table bgcolor=\"#f1f1f1\" align=\"center\"><tr><td bgcolor=\"#e0e0ff\" colspan=\"2\" width=\"500\">\r\n"
00343 "<h2> Asterisk™ HTTP Status</h2></td></tr>\r\n");
00344
00345 ast_str_append(&out, 0, "<tr><td><i>Prefix</i></td><td><b>%s</b></td></tr>\r\n", prefix);
00346 ast_str_append(&out, 0, "<tr><td><i>Bind Address</i></td><td><b>%s</b></td></tr>\r\n",
00347 ast_sockaddr_stringify_addr(&http_desc.old_address));
00348 ast_str_append(&out, 0, "<tr><td><i>Bind Port</i></td><td><b>%s</b></td></tr>\r\n",
00349 ast_sockaddr_stringify_port(&http_desc.old_address));
00350 if (http_tls_cfg.enabled) {
00351 ast_str_append(&out, 0, "<tr><td><i>SSL Bind Port</i></td><td><b>%s</b></td></tr>\r\n",
00352 ast_sockaddr_stringify_port(&https_desc.old_address));
00353 }
00354 ast_str_append(&out, 0, "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
00355 for (v = get_vars; v; v = v->next) {
00356 ast_str_append(&out, 0, "<tr><td><i>Submitted GET Variable '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value);
00357 }
00358 ast_str_append(&out, 0, "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
00359
00360 cookies = ast_http_get_cookies(headers);
00361 for (v = cookies; v; v = v->next) {
00362 ast_str_append(&out, 0, "<tr><td><i>Cookie '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value);
00363 }
00364 ast_variables_destroy(cookies);
00365
00366 ast_str_append(&out, 0, "</table><center><font size=\"-1\"><i>Asterisk and Digium are registered trademarks of Digium, Inc.</i></font></center></body>\r\n");
00367 ast_http_send(ser, method, 200, NULL, NULL, out, 0, 0);
00368 return 0;
00369 }
00370
00371 static struct ast_http_uri statusuri = {
00372 .callback = httpstatus_callback,
00373 .description = "Asterisk HTTP General Status",
00374 .uri = "httpstatus",
00375 .has_subtree = 0,
00376 .data = NULL,
00377 .key = __FILE__,
00378 };
00379
00380 static struct ast_http_uri staticuri = {
00381 .callback = static_callback,
00382 .description = "Asterisk HTTP Static Delivery",
00383 .uri = "static",
00384 .has_subtree = 1,
00385 .data = NULL,
00386 .key= __FILE__,
00387 };
00388
00389
00390
00391
00392 void ast_http_send(struct ast_tcptls_session_instance *ser,
00393 enum ast_http_method method, int status_code, const char *status_title,
00394 struct ast_str *http_header, struct ast_str *out, const int fd,
00395 unsigned int static_content)
00396 {
00397 struct timeval now = ast_tvnow();
00398 struct ast_tm tm;
00399 char timebuf[80];
00400 int content_length = 0;
00401
00402 if (!ser || 0 == ser->f) {
00403 return;
00404 }
00405
00406 ast_strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", ast_localtime(&now, &tm, "GMT"));
00407
00408
00409 if (out) {
00410 content_length += ast_str_strlen(out);
00411 }
00412
00413 if (fd) {
00414 content_length += lseek(fd, 0, SEEK_END);
00415 lseek(fd, 0, SEEK_SET);
00416 }
00417
00418
00419 fprintf(ser->f, "HTTP/1.1 %d %s\r\n"
00420 "Server: Asterisk/%s\r\n"
00421 "Date: %s\r\n"
00422 "Connection: close\r\n"
00423 "%s"
00424 "Content-Length: %d\r\n"
00425 "%s"
00426 "\r\n",
00427 status_code, status_title ? status_title : "OK",
00428 ast_get_version(),
00429 timebuf,
00430 static_content ? "" : "Cache-Control: no-cache, no-store\r\n",
00431 content_length,
00432 http_header ? ast_str_buffer(http_header) : ""
00433 );
00434
00435
00436 if (method != AST_HTTP_HEAD || status_code >= 400) {
00437 if (out && ast_str_strlen(out)) {
00438 if (fwrite(ast_str_buffer(out), ast_str_strlen(out), 1, ser->f) != 1) {
00439 ast_log(LOG_ERROR, "fwrite() failed: %s\n", strerror(errno));
00440 }
00441 }
00442
00443 if (fd) {
00444 char buf[256];
00445 int len;
00446 while ((len = read(fd, buf, sizeof(buf))) > 0) {
00447 if (fwrite(buf, len, 1, ser->f) != 1) {
00448 ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
00449 break;
00450 }
00451 }
00452 }
00453 }
00454
00455 if (http_header) {
00456 ast_free(http_header);
00457 }
00458 if (out) {
00459 ast_free(out);
00460 }
00461
00462 ast_tcptls_close_session_file(ser);
00463 return;
00464 }
00465
00466
00467 void ast_http_auth(struct ast_tcptls_session_instance *ser, const char *realm,
00468 const unsigned long nonce, const unsigned long opaque, int stale,
00469 const char *text)
00470 {
00471 struct ast_str *http_headers = ast_str_create(128);
00472 struct ast_str *out = ast_str_create(512);
00473
00474 if (!http_headers || !out) {
00475 ast_free(http_headers);
00476 ast_free(out);
00477 return;
00478 }
00479
00480 ast_str_set(&http_headers, 0,
00481 "WWW-authenticate: Digest algorithm=MD5, realm=\"%s\", nonce=\"%08lx\", qop=\"auth\", opaque=\"%08lx\"%s\r\n"
00482 "Content-type: text/html\r\n",
00483 realm ? realm : "Asterisk",
00484 nonce,
00485 opaque,
00486 stale ? ", stale=true" : "");
00487
00488 ast_str_set(&out, 0,
00489 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
00490 "<html><head>\r\n"
00491 "<title>401 Unauthorized</title>\r\n"
00492 "</head><body>\r\n"
00493 "<h1>401 Unauthorized</h1>\r\n"
00494 "<p>%s</p>\r\n"
00495 "<hr />\r\n"
00496 "<address>Asterisk Server</address>\r\n"
00497 "</body></html>\r\n",
00498 text ? text : "");
00499
00500 ast_http_send(ser, AST_HTTP_UNKNOWN, 401, "Unauthorized", http_headers, out, 0, 0);
00501 return;
00502 }
00503
00504
00505 void ast_http_error(struct ast_tcptls_session_instance *ser, int status_code, const char *status_title, const char *text)
00506 {
00507 struct ast_str *http_headers = ast_str_create(40);
00508 struct ast_str *out = ast_str_create(256);
00509
00510 if (!http_headers || !out) {
00511 ast_free(http_headers);
00512 ast_free(out);
00513 return;
00514 }
00515
00516 ast_str_set(&http_headers, 0, "Content-type: text/html\r\n");
00517
00518 ast_str_set(&out, 0,
00519 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
00520 "<html><head>\r\n"
00521 "<title>%d %s</title>\r\n"
00522 "</head><body>\r\n"
00523 "<h1>%s</h1>\r\n"
00524 "<p>%s</p>\r\n"
00525 "<hr />\r\n"
00526 "<address>Asterisk Server</address>\r\n"
00527 "</body></html>\r\n",
00528 status_code, status_title, status_title, text);
00529
00530 ast_http_send(ser, AST_HTTP_UNKNOWN, status_code, status_title, http_headers, out, 0, 0);
00531 return;
00532 }
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543 int ast_http_uri_link(struct ast_http_uri *urih)
00544 {
00545 struct ast_http_uri *uri;
00546 int len = strlen(urih->uri);
00547
00548 AST_RWLIST_WRLOCK(&uris);
00549
00550 if ( AST_RWLIST_EMPTY(&uris) || strlen(AST_RWLIST_FIRST(&uris)->uri) <= len ) {
00551 AST_RWLIST_INSERT_HEAD(&uris, urih, entry);
00552 AST_RWLIST_UNLOCK(&uris);
00553 return 0;
00554 }
00555
00556 AST_RWLIST_TRAVERSE(&uris, uri, entry) {
00557 if (AST_RWLIST_NEXT(uri, entry) &&
00558 strlen(AST_RWLIST_NEXT(uri, entry)->uri) <= len) {
00559 AST_RWLIST_INSERT_AFTER(&uris, uri, urih, entry);
00560 AST_RWLIST_UNLOCK(&uris);
00561
00562 return 0;
00563 }
00564 }
00565
00566 AST_RWLIST_INSERT_TAIL(&uris, urih, entry);
00567
00568 AST_RWLIST_UNLOCK(&uris);
00569
00570 return 0;
00571 }
00572
00573 void ast_http_uri_unlink(struct ast_http_uri *urih)
00574 {
00575 AST_RWLIST_WRLOCK(&uris);
00576 AST_RWLIST_REMOVE(&uris, urih, entry);
00577 AST_RWLIST_UNLOCK(&uris);
00578 }
00579
00580 void ast_http_uri_unlink_all_with_key(const char *key)
00581 {
00582 struct ast_http_uri *urih;
00583 AST_RWLIST_WRLOCK(&uris);
00584 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&uris, urih, entry) {
00585 if (!strcmp(urih->key, key)) {
00586 AST_RWLIST_REMOVE_CURRENT(entry);
00587 if (urih->dmallocd) {
00588 ast_free(urih->data);
00589 }
00590 if (urih->mallocd) {
00591 ast_free(urih);
00592 }
00593 }
00594 }
00595 AST_RWLIST_TRAVERSE_SAFE_END;
00596 AST_RWLIST_UNLOCK(&uris);
00597 }
00598
00599 #define MAX_POST_CONTENT 1025
00600
00601
00602
00603
00604
00605 struct ast_variable *ast_http_get_post_vars(
00606 struct ast_tcptls_session_instance *ser, struct ast_variable *headers)
00607 {
00608 int content_length = 0;
00609 struct ast_variable *v, *post_vars=NULL, *prev = NULL;
00610 char *buf, *var, *val;
00611 int res;
00612
00613 for (v = headers; v; v = v->next) {
00614 if (!strcasecmp(v->name, "Content-Type")) {
00615 if (strcasecmp(v->value, "application/x-www-form-urlencoded")) {
00616 return NULL;
00617 }
00618 break;
00619 }
00620 }
00621
00622 for (v = headers; v; v = v->next) {
00623 if (!strcasecmp(v->name, "Content-Length")) {
00624 content_length = atoi(v->value);
00625 break;
00626 }
00627 }
00628
00629 if (content_length <= 0) {
00630 return NULL;
00631 }
00632
00633 if (content_length > MAX_POST_CONTENT - 1) {
00634 ast_log(LOG_WARNING, "Excessively long HTTP content. %d is greater than our max of %d\n",
00635 content_length, MAX_POST_CONTENT);
00636 ast_http_send(ser, AST_HTTP_POST, 413, "Request Entity Too Large", NULL, NULL, 0, 0);
00637 return NULL;
00638 }
00639
00640 buf = ast_malloc(content_length + 1);
00641 if (!buf) {
00642 return NULL;
00643 }
00644
00645 res = fread(buf, 1, content_length, ser->f);
00646 if (res < content_length) {
00647
00648
00649 goto done;
00650 }
00651 buf[content_length] = '\0';
00652
00653 while ((val = strsep(&buf, "&"))) {
00654 var = strsep(&val, "=");
00655 if (val) {
00656 ast_uri_decode(val, ast_uri_http_legacy);
00657 } else {
00658 val = "";
00659 }
00660 ast_uri_decode(var, ast_uri_http_legacy);
00661 if ((v = ast_variable_new(var, val, ""))) {
00662 if (post_vars) {
00663 prev->next = v;
00664 } else {
00665 post_vars = v;
00666 }
00667 prev = v;
00668 }
00669 }
00670
00671 done:
00672 ast_free(buf);
00673 return post_vars;
00674 }
00675
00676 static int handle_uri(struct ast_tcptls_session_instance *ser, char *uri,
00677 enum ast_http_method method, struct ast_variable *headers)
00678 {
00679 char *c;
00680 int res = -1;
00681 char *params = uri;
00682 struct ast_http_uri *urih = NULL;
00683 int l;
00684 struct ast_variable *get_vars = NULL, *v, *prev = NULL;
00685 struct http_uri_redirect *redirect;
00686
00687 ast_debug(2, "HTTP Request URI is %s \n", uri);
00688
00689 strsep(¶ms, "?");
00690
00691 if (params) {
00692 char *var, *val;
00693
00694 while ((val = strsep(¶ms, "&"))) {
00695 var = strsep(&val, "=");
00696 if (val) {
00697 ast_uri_decode(val, ast_uri_http_legacy);
00698 } else {
00699 val = "";
00700 }
00701 ast_uri_decode(var, ast_uri_http_legacy);
00702 if ((v = ast_variable_new(var, val, ""))) {
00703 if (get_vars) {
00704 prev->next = v;
00705 } else {
00706 get_vars = v;
00707 }
00708 prev = v;
00709 }
00710 }
00711 }
00712 ast_uri_decode(uri, ast_uri_http_legacy);
00713
00714 AST_RWLIST_RDLOCK(&uri_redirects);
00715 AST_RWLIST_TRAVERSE(&uri_redirects, redirect, entry) {
00716 if (!strcasecmp(uri, redirect->target)) {
00717 struct ast_str *http_header = ast_str_create(128);
00718 ast_str_set(&http_header, 0, "Location: %s\r\n", redirect->dest);
00719 ast_http_send(ser, method, 302, "Moved Temporarily", http_header, NULL, 0, 0);
00720
00721 break;
00722 }
00723 }
00724 AST_RWLIST_UNLOCK(&uri_redirects);
00725 if (redirect) {
00726 goto cleanup;
00727 }
00728
00729
00730 l = strlen(prefix);
00731 if (!strncasecmp(uri, prefix, l) && uri[l] == '/') {
00732 uri += l + 1;
00733
00734 AST_RWLIST_RDLOCK(&uris);
00735 AST_RWLIST_TRAVERSE(&uris, urih, entry) {
00736 ast_debug(2, "match request [%s] with handler [%s] len %d\n", uri, urih->uri, l);
00737 l = strlen(urih->uri);
00738 c = uri + l;
00739 if (strncasecmp(urih->uri, uri, l)
00740 || (*c && *c != '/')) {
00741 continue;
00742 }
00743 if (*c == '/') {
00744 c++;
00745 }
00746 if (!*c || urih->has_subtree) {
00747 uri = c;
00748 break;
00749 }
00750 }
00751 AST_RWLIST_UNLOCK(&uris);
00752 }
00753 if (urih) {
00754 res = urih->callback(ser, urih, uri, method, get_vars, headers);
00755 } else {
00756 ast_http_error(ser, 404, "Not Found", "The requested URL was not found on this server.");
00757 }
00758
00759 cleanup:
00760 ast_variables_destroy(get_vars);
00761 return res;
00762 }
00763
00764 #ifdef DO_SSL
00765 #if defined(HAVE_FUNOPEN)
00766 #define HOOK_T int
00767 #define LEN_T int
00768 #else
00769 #define HOOK_T ssize_t
00770 #define LEN_T size_t
00771 #endif
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807 #endif
00808
00809 static struct ast_variable *parse_cookies(const char *cookies)
00810 {
00811 char *parse = ast_strdupa(cookies);
00812 char *cur;
00813 struct ast_variable *vars = NULL, *var;
00814
00815 while ((cur = strsep(&parse, ";"))) {
00816 char *name, *val;
00817
00818 name = val = cur;
00819 strsep(&val, "=");
00820
00821 if (ast_strlen_zero(name) || ast_strlen_zero(val)) {
00822 continue;
00823 }
00824
00825 name = ast_strip(name);
00826 val = ast_strip_quoted(val, "\"", "\"");
00827
00828 if (ast_strlen_zero(name) || ast_strlen_zero(val)) {
00829 continue;
00830 }
00831
00832 ast_debug(1, "HTTP Cookie, Name: '%s' Value: '%s'\n", name, val);
00833
00834 var = ast_variable_new(name, val, __FILE__);
00835 var->next = vars;
00836 vars = var;
00837 }
00838
00839 return vars;
00840 }
00841
00842
00843 struct ast_variable *ast_http_get_cookies(struct ast_variable *headers)
00844 {
00845 struct ast_variable *v, *cookies = NULL;
00846
00847 for (v = headers; v; v = v->next) {
00848 if (!strcasecmp(v->name, "Cookie")) {
00849 ast_variables_destroy(cookies);
00850 cookies = parse_cookies(v->value);
00851 }
00852 }
00853 return cookies;
00854 }
00855
00856
00857 #define MAX_HTTP_REQUEST_HEADERS 100
00858
00859 static void *httpd_helper_thread(void *data)
00860 {
00861 char buf[4096];
00862 char header_line[4096];
00863 struct ast_tcptls_session_instance *ser = data;
00864 struct ast_variable *headers = NULL;
00865 struct ast_variable *tail = headers;
00866 char *uri, *method;
00867 enum ast_http_method http_method = AST_HTTP_UNKNOWN;
00868 int remaining_headers;
00869 int flags;
00870 struct protoent *p;
00871
00872 if (ast_atomic_fetchadd_int(&session_count, +1) >= session_limit) {
00873 goto done;
00874 }
00875
00876
00877
00878
00879 p = getprotobyname("tcp");
00880 if (p) {
00881 int arg = 1;
00882 if( setsockopt(ser->fd, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
00883 ast_log(LOG_WARNING, "Failed to set TCP_NODELAY on HTTP connection: %s\n", strerror(errno));
00884 ast_log(LOG_WARNING, "Some HTTP requests may be slow to respond.\n");
00885 }
00886 } else {
00887 ast_log(LOG_WARNING, "Failed to set TCP_NODELAY on HTTP connection, getprotobyname(\"tcp\") failed\n");
00888 ast_log(LOG_WARNING, "Some HTTP requests may be slow to respond.\n");
00889 }
00890
00891
00892 flags = fcntl(ser->fd, F_GETFL);
00893 flags |= O_NONBLOCK;
00894 fcntl(ser->fd, F_SETFL, flags);
00895
00896
00897 ast_tcptls_stream_set_exclusive_input(ser->stream_cookie, 1);
00898
00899 ast_tcptls_stream_set_timeout_inactivity(ser->stream_cookie, session_inactivity);
00900
00901 if (!fgets(buf, sizeof(buf), ser->f) || feof(ser->f)) {
00902 goto done;
00903 }
00904
00905
00906 method = ast_skip_blanks(buf);
00907 uri = ast_skip_nonblanks(method);
00908 if (*uri) {
00909 *uri++ = '\0';
00910 }
00911
00912 if (!strcasecmp(method,"GET")) {
00913 http_method = AST_HTTP_GET;
00914 } else if (!strcasecmp(method,"POST")) {
00915 http_method = AST_HTTP_POST;
00916 } else if (!strcasecmp(method,"HEAD")) {
00917 http_method = AST_HTTP_HEAD;
00918 } else if (!strcasecmp(method,"PUT")) {
00919 http_method = AST_HTTP_PUT;
00920 }
00921
00922 uri = ast_skip_blanks(uri);
00923
00924 if (*uri) {
00925 char *c = ast_skip_nonblanks(uri);
00926
00927 if (*c) {
00928 *c = '\0';
00929 }
00930 } else {
00931 ast_http_error(ser, 400, "Bad Request", "Invalid Request");
00932 goto done;
00933 }
00934
00935
00936 remaining_headers = MAX_HTTP_REQUEST_HEADERS;
00937 for (;;) {
00938 char *name;
00939 char *value;
00940
00941 if (!fgets(header_line, sizeof(header_line), ser->f) || feof(ser->f)) {
00942 ast_http_error(ser, 400, "Bad Request", "Timeout");
00943 goto done;
00944 }
00945
00946
00947 ast_trim_blanks(header_line);
00948 if (ast_strlen_zero(header_line)) {
00949
00950 break;
00951 }
00952
00953 value = header_line;
00954 name = strsep(&value, ":");
00955 if (!value) {
00956 continue;
00957 }
00958
00959 value = ast_skip_blanks(value);
00960 if (ast_strlen_zero(value) || ast_strlen_zero(name)) {
00961 continue;
00962 }
00963
00964 ast_trim_blanks(name);
00965
00966 if (!remaining_headers--) {
00967
00968 ast_http_error(ser, 413, "Request Entity Too Large", "Too many headers");
00969 goto done;
00970 }
00971 if (!headers) {
00972 headers = ast_variable_new(name, value, __FILE__);
00973 tail = headers;
00974 } else {
00975 tail->next = ast_variable_new(name, value, __FILE__);
00976 tail = tail->next;
00977 }
00978 if (!tail) {
00979
00980
00981
00982
00983 ast_variables_destroy(headers);
00984 headers = NULL;
00985
00986 ast_http_error(ser, 500, "Server Error", "Out of memory");
00987 goto done;
00988 }
00989 }
00990
00991 handle_uri(ser, uri, http_method, headers);
00992
00993 done:
00994 ast_atomic_fetchadd_int(&session_count, -1);
00995
00996
00997 ast_variables_destroy(headers);
00998
00999 if (ser->f) {
01000 ast_tcptls_close_session_file(ser);
01001 }
01002 ao2_ref(ser, -1);
01003 ser = NULL;
01004 return NULL;
01005 }
01006
01007
01008
01009
01010
01011
01012 static void add_redirect(const char *value)
01013 {
01014 char *target, *dest;
01015 struct http_uri_redirect *redirect, *cur;
01016 unsigned int target_len;
01017 unsigned int total_len;
01018
01019 dest = ast_strdupa(value);
01020 dest = ast_skip_blanks(dest);
01021 target = strsep(&dest, " ");
01022 target = ast_skip_blanks(target);
01023 target = strsep(&target, " ");
01024
01025 if (!dest) {
01026 ast_log(LOG_WARNING, "Invalid redirect '%s'\n", value);
01027 return;
01028 }
01029
01030 target_len = strlen(target) + 1;
01031 total_len = sizeof(*redirect) + target_len + strlen(dest) + 1;
01032
01033 if (!(redirect = ast_calloc(1, total_len))) {
01034 return;
01035 }
01036 redirect->dest = redirect->target + target_len;
01037 strcpy(redirect->target, target);
01038 strcpy(redirect->dest, dest);
01039
01040 AST_RWLIST_WRLOCK(&uri_redirects);
01041
01042 target_len--;
01043 if (AST_RWLIST_EMPTY(&uri_redirects)
01044 || strlen(AST_RWLIST_FIRST(&uri_redirects)->target) <= target_len ) {
01045 AST_RWLIST_INSERT_HEAD(&uri_redirects, redirect, entry);
01046 AST_RWLIST_UNLOCK(&uri_redirects);
01047
01048 return;
01049 }
01050
01051 AST_RWLIST_TRAVERSE(&uri_redirects, cur, entry) {
01052 if (AST_RWLIST_NEXT(cur, entry)
01053 && strlen(AST_RWLIST_NEXT(cur, entry)->target) <= target_len ) {
01054 AST_RWLIST_INSERT_AFTER(&uri_redirects, cur, redirect, entry);
01055 AST_RWLIST_UNLOCK(&uri_redirects);
01056 return;
01057 }
01058 }
01059
01060 AST_RWLIST_INSERT_TAIL(&uri_redirects, redirect, entry);
01061
01062 AST_RWLIST_UNLOCK(&uri_redirects);
01063 }
01064
01065 static int __ast_http_load(int reload)
01066 {
01067 struct ast_config *cfg;
01068 struct ast_variable *v;
01069 int enabled=0;
01070 int newenablestatic=0;
01071 char newprefix[MAX_PREFIX] = "";
01072 struct http_uri_redirect *redirect;
01073 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
01074 uint32_t bindport = DEFAULT_PORT;
01075 RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free);
01076 int num_addrs = 0;
01077 int http_tls_was_enabled = 0;
01078
01079 cfg = ast_config_load2("http.conf", "http", config_flags);
01080 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
01081 return 0;
01082 }
01083
01084 http_tls_was_enabled = (reload && http_tls_cfg.enabled);
01085
01086 http_tls_cfg.enabled = 0;
01087 if (http_tls_cfg.certfile) {
01088 ast_free(http_tls_cfg.certfile);
01089 }
01090 http_tls_cfg.certfile = ast_strdup(AST_CERTFILE);
01091
01092 if (http_tls_cfg.pvtfile) {
01093 ast_free(http_tls_cfg.pvtfile);
01094 }
01095 http_tls_cfg.pvtfile = ast_strdup("");
01096
01097 if (http_tls_cfg.cipher) {
01098 ast_free(http_tls_cfg.cipher);
01099 }
01100 http_tls_cfg.cipher = ast_strdup("");
01101
01102 AST_RWLIST_WRLOCK(&uri_redirects);
01103 while ((redirect = AST_RWLIST_REMOVE_HEAD(&uri_redirects, entry))) {
01104 ast_free(redirect);
01105 }
01106 AST_RWLIST_UNLOCK(&uri_redirects);
01107
01108 ast_sockaddr_setnull(&https_desc.local_address);
01109
01110 session_limit = DEFAULT_SESSION_LIMIT;
01111 session_inactivity = DEFAULT_SESSION_INACTIVITY;
01112
01113 if (cfg) {
01114 v = ast_variable_browse(cfg, "general");
01115 for (; v; v = v->next) {
01116
01117
01118 if (strcasecmp(v->name, "tlscafile")
01119 && strcasecmp(v->name, "tlscapath")
01120 && strcasecmp(v->name, "tlscadir")
01121 && strcasecmp(v->name, "tlsverifyclient")
01122 && strcasecmp(v->name, "tlsdontverifyserver")
01123 && strcasecmp(v->name, "tlsclientmethod")
01124 && strcasecmp(v->name, "sslclientmethod")
01125 && strcasecmp(v->name, "tlscipher")
01126 && strcasecmp(v->name, "sslcipher")
01127 && !ast_tls_read_conf(&http_tls_cfg, &https_desc, v->name, v->value)) {
01128 continue;
01129 }
01130
01131 if (!strcasecmp(v->name, "enabled")) {
01132 enabled = ast_true(v->value);
01133 } else if (!strcasecmp(v->name, "enablestatic")) {
01134 newenablestatic = ast_true(v->value);
01135 } else if (!strcasecmp(v->name, "bindport")) {
01136 if (ast_parse_arg(v->value, PARSE_UINT32 | PARSE_IN_RANGE | PARSE_DEFAULT, &bindport, DEFAULT_PORT, 0, 65535)) {
01137 ast_log(LOG_WARNING, "Invalid port %s specified. Using default port %"PRId32, v->value, DEFAULT_PORT);
01138 }
01139 } else if (!strcasecmp(v->name, "bindaddr")) {
01140 if (!(num_addrs = ast_sockaddr_resolve(&addrs, v->value, 0, AST_AF_UNSPEC))) {
01141 ast_log(LOG_WARNING, "Invalid bind address %s\n", v->value);
01142 }
01143 } else if (!strcasecmp(v->name, "prefix")) {
01144 if (!ast_strlen_zero(v->value)) {
01145 newprefix[0] = '/';
01146 ast_copy_string(newprefix + 1, v->value, sizeof(newprefix) - 1);
01147 } else {
01148 newprefix[0] = '\0';
01149 }
01150 } else if (!strcasecmp(v->name, "redirect")) {
01151 add_redirect(v->value);
01152 } else if (!strcasecmp(v->name, "sessionlimit")) {
01153 if (ast_parse_arg(v->value, PARSE_INT32|PARSE_DEFAULT|PARSE_IN_RANGE,
01154 &session_limit, DEFAULT_SESSION_LIMIT, 1, INT_MAX)) {
01155 ast_log(LOG_WARNING, "Invalid %s '%s' at line %d of http.conf\n",
01156 v->name, v->value, v->lineno);
01157 }
01158 } else if (!strcasecmp(v->name, "session_inactivity")) {
01159 if (ast_parse_arg(v->value, PARSE_INT32 |PARSE_DEFAULT | PARSE_IN_RANGE,
01160 &session_inactivity, DEFAULT_SESSION_INACTIVITY, 1, INT_MAX)) {
01161 ast_log(LOG_WARNING, "Invalid %s '%s' at line %d of http.conf\n",
01162 v->name, v->value, v->lineno);
01163 }
01164 } else {
01165 ast_log(LOG_WARNING, "Ignoring unknown option '%s' in http.conf\n", v->name);
01166 }
01167 }
01168
01169 ast_config_destroy(cfg);
01170 }
01171
01172 if (strcmp(prefix, newprefix)) {
01173 ast_copy_string(prefix, newprefix, sizeof(prefix));
01174 }
01175 enablestatic = newenablestatic;
01176
01177 if (num_addrs && enabled) {
01178 int i;
01179 for (i = 0; i < num_addrs; ++i) {
01180 ast_sockaddr_copy(&http_desc.local_address, &addrs[i]);
01181 if (!ast_sockaddr_port(&http_desc.local_address)) {
01182 ast_sockaddr_set_port(&http_desc.local_address, bindport);
01183 }
01184 ast_tcptls_server_start(&http_desc);
01185 if (http_desc.accept_fd == -1) {
01186 ast_log(LOG_WARNING, "Failed to start HTTP server for address %s\n", ast_sockaddr_stringify(&addrs[i]));
01187 ast_sockaddr_setnull(&http_desc.local_address);
01188 } else {
01189 ast_verb(1, "Bound HTTP server to address %s\n", ast_sockaddr_stringify(&addrs[i]));
01190 break;
01191 }
01192 }
01193
01194
01195
01196 if (ast_sockaddr_isnull(&https_desc.local_address) && http_desc.accept_fd != -1) {
01197 ast_sockaddr_copy(&https_desc.local_address, &https_desc.local_address);
01198
01199
01200
01201
01202 ast_sockaddr_set_port(&https_desc.local_address, DEFAULT_TLS_PORT);
01203 }
01204 }
01205 if (http_tls_was_enabled && !http_tls_cfg.enabled) {
01206 ast_tcptls_server_stop(&https_desc);
01207 } else if (http_tls_cfg.enabled && !ast_sockaddr_isnull(&https_desc.local_address)) {
01208
01209
01210
01211
01212
01213 if (!ast_sockaddr_port(&https_desc.local_address)) {
01214 ast_sockaddr_set_port(&https_desc.local_address, DEFAULT_TLS_PORT);
01215 }
01216 if (ast_ssl_setup(https_desc.tls_cfg)) {
01217 ast_tcptls_server_start(&https_desc);
01218 }
01219 }
01220
01221 return 0;
01222 }
01223
01224 static char *handle_show_http(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01225 {
01226 struct ast_http_uri *urih;
01227 struct http_uri_redirect *redirect;
01228
01229 switch (cmd) {
01230 case CLI_INIT:
01231 e->command = "http show status";
01232 e->usage =
01233 "Usage: http show status\n"
01234 " Lists status of internal HTTP engine\n";
01235 return NULL;
01236 case CLI_GENERATE:
01237 return NULL;
01238 }
01239
01240 if (a->argc != 3) {
01241 return CLI_SHOWUSAGE;
01242 }
01243 ast_cli(a->fd, "HTTP Server Status:\n");
01244 ast_cli(a->fd, "Prefix: %s\n", prefix);
01245 if (ast_sockaddr_isnull(&http_desc.old_address)) {
01246 ast_cli(a->fd, "Server Disabled\n\n");
01247 } else {
01248 ast_cli(a->fd, "Server Enabled and Bound to %s\n\n",
01249 ast_sockaddr_stringify(&http_desc.old_address));
01250 if (http_tls_cfg.enabled) {
01251 ast_cli(a->fd, "HTTPS Server Enabled and Bound to %s\n\n",
01252 ast_sockaddr_stringify(&https_desc.old_address));
01253 }
01254 }
01255
01256 ast_cli(a->fd, "Enabled URI's:\n");
01257 AST_RWLIST_RDLOCK(&uris);
01258 if (AST_RWLIST_EMPTY(&uris)) {
01259 ast_cli(a->fd, "None.\n");
01260 } else {
01261 AST_RWLIST_TRAVERSE(&uris, urih, entry)
01262 ast_cli(a->fd, "%s/%s%s => %s\n", prefix, urih->uri, (urih->has_subtree ? "/..." : "" ), urih->description);
01263 }
01264 AST_RWLIST_UNLOCK(&uris);
01265
01266 ast_cli(a->fd, "\nEnabled Redirects:\n");
01267 AST_RWLIST_RDLOCK(&uri_redirects);
01268 AST_RWLIST_TRAVERSE(&uri_redirects, redirect, entry)
01269 ast_cli(a->fd, " %s => %s\n", redirect->target, redirect->dest);
01270 if (AST_RWLIST_EMPTY(&uri_redirects)) {
01271 ast_cli(a->fd, " None.\n");
01272 }
01273 AST_RWLIST_UNLOCK(&uri_redirects);
01274
01275 return CLI_SUCCESS;
01276 }
01277
01278 int ast_http_reload(void)
01279 {
01280 return __ast_http_load(1);
01281 }
01282
01283 static struct ast_cli_entry cli_http[] = {
01284 AST_CLI_DEFINE(handle_show_http, "Display HTTP server status"),
01285 };
01286
01287 static void http_shutdown(void)
01288 {
01289 struct http_uri_redirect *redirect;
01290 ast_cli_unregister_multiple(cli_http, ARRAY_LEN(cli_http));
01291
01292 ast_tcptls_server_stop(&http_desc);
01293 if (http_tls_cfg.enabled) {
01294 ast_tcptls_server_stop(&https_desc);
01295 }
01296 ast_free(http_tls_cfg.certfile);
01297 ast_free(http_tls_cfg.pvtfile);
01298 ast_free(http_tls_cfg.cipher);
01299
01300 ast_http_uri_unlink(&statusuri);
01301 ast_http_uri_unlink(&staticuri);
01302
01303 AST_RWLIST_WRLOCK(&uri_redirects);
01304 while ((redirect = AST_RWLIST_REMOVE_HEAD(&uri_redirects, entry))) {
01305 ast_free(redirect);
01306 }
01307 AST_RWLIST_UNLOCK(&uri_redirects);
01308 }
01309
01310 int ast_http_init(void)
01311 {
01312 ast_http_uri_link(&statusuri);
01313 ast_http_uri_link(&staticuri);
01314 ast_cli_register_multiple(cli_http, ARRAY_LEN(cli_http));
01315 ast_register_atexit(http_shutdown);
01316
01317 return __ast_http_load(0);
01318 }