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