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