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