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: 411462 $")
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 if (fwrite(ast_str_buffer(out), content_length, 1, ser->f) != 1) {
00438 ast_log(LOG_ERROR, "fwrite() failed: %s\n", strerror(errno));
00439 }
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 ast_tcptls_close_session_file(ser);
00462 return;
00463 }
00464
00465
00466 void ast_http_auth(struct ast_tcptls_session_instance *ser, const char *realm,
00467 const unsigned long nonce, const unsigned long opaque, int stale,
00468 const char *text)
00469 {
00470 struct ast_str *http_headers = ast_str_create(128);
00471 struct ast_str *out = ast_str_create(512);
00472
00473 if (!http_headers || !out) {
00474 ast_free(http_headers);
00475 ast_free(out);
00476 return;
00477 }
00478
00479 ast_str_set(&http_headers, 0,
00480 "WWW-authenticate: Digest algorithm=MD5, realm=\"%s\", nonce=\"%08lx\", qop=\"auth\", opaque=\"%08lx\"%s\r\n"
00481 "Content-type: text/html\r\n",
00482 realm ? realm : "Asterisk",
00483 nonce,
00484 opaque,
00485 stale ? ", stale=true" : "");
00486
00487 ast_str_set(&out, 0,
00488 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
00489 "<html><head>\r\n"
00490 "<title>401 Unauthorized</title>\r\n"
00491 "</head><body>\r\n"
00492 "<h1>401 Unauthorized</h1>\r\n"
00493 "<p>%s</p>\r\n"
00494 "<hr />\r\n"
00495 "<address>Asterisk Server</address>\r\n"
00496 "</body></html>\r\n",
00497 text ? text : "");
00498
00499 ast_http_send(ser, AST_HTTP_UNKNOWN, 401, "Unauthorized", http_headers, out, 0, 0);
00500 return;
00501 }
00502
00503
00504 void ast_http_error(struct ast_tcptls_session_instance *ser, int status_code, const char *status_title, const char *text)
00505 {
00506 struct ast_str *http_headers = ast_str_create(40);
00507 struct ast_str *out = ast_str_create(256);
00508
00509 if (!http_headers || !out) {
00510 ast_free(http_headers);
00511 ast_free(out);
00512 return;
00513 }
00514
00515 ast_str_set(&http_headers, 0, "Content-type: text/html\r\n");
00516
00517 ast_str_set(&out, 0,
00518 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
00519 "<html><head>\r\n"
00520 "<title>%d %s</title>\r\n"
00521 "</head><body>\r\n"
00522 "<h1>%s</h1>\r\n"
00523 "<p>%s</p>\r\n"
00524 "<hr />\r\n"
00525 "<address>Asterisk Server</address>\r\n"
00526 "</body></html>\r\n",
00527 status_code, status_title, status_title, text);
00528
00529 ast_http_send(ser, AST_HTTP_UNKNOWN, status_code, status_title, http_headers, out, 0, 0);
00530 return;
00531 }
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542 int ast_http_uri_link(struct ast_http_uri *urih)
00543 {
00544 struct ast_http_uri *uri;
00545 int len = strlen(urih->uri);
00546
00547 AST_RWLIST_WRLOCK(&uris);
00548
00549 if ( AST_RWLIST_EMPTY(&uris) || strlen(AST_RWLIST_FIRST(&uris)->uri) <= len ) {
00550 AST_RWLIST_INSERT_HEAD(&uris, urih, entry);
00551 AST_RWLIST_UNLOCK(&uris);
00552 return 0;
00553 }
00554
00555 AST_RWLIST_TRAVERSE(&uris, uri, entry) {
00556 if (AST_RWLIST_NEXT(uri, entry) &&
00557 strlen(AST_RWLIST_NEXT(uri, entry)->uri) <= len) {
00558 AST_RWLIST_INSERT_AFTER(&uris, uri, urih, entry);
00559 AST_RWLIST_UNLOCK(&uris);
00560
00561 return 0;
00562 }
00563 }
00564
00565 AST_RWLIST_INSERT_TAIL(&uris, urih, entry);
00566
00567 AST_RWLIST_UNLOCK(&uris);
00568
00569 return 0;
00570 }
00571
00572 void ast_http_uri_unlink(struct ast_http_uri *urih)
00573 {
00574 AST_RWLIST_WRLOCK(&uris);
00575 AST_RWLIST_REMOVE(&uris, urih, entry);
00576 AST_RWLIST_UNLOCK(&uris);
00577 }
00578
00579 void ast_http_uri_unlink_all_with_key(const char *key)
00580 {
00581 struct ast_http_uri *urih;
00582 AST_RWLIST_WRLOCK(&uris);
00583 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&uris, urih, entry) {
00584 if (!strcmp(urih->key, key)) {
00585 AST_RWLIST_REMOVE_CURRENT(entry);
00586 if (urih->dmallocd) {
00587 ast_free(urih->data);
00588 }
00589 if (urih->mallocd) {
00590 ast_free(urih);
00591 }
00592 }
00593 }
00594 AST_RWLIST_TRAVERSE_SAFE_END;
00595 AST_RWLIST_UNLOCK(&uris);
00596 }
00597
00598
00599
00600
00601
00602
00603 static void http_decode(char *s)
00604 {
00605 char *t;
00606
00607 for (t = s; *t; t++) {
00608 if (*t == '+') {
00609 *t = ' ';
00610 }
00611 }
00612
00613 ast_uri_decode(s);
00614 }
00615
00616 #define MAX_POST_CONTENT 1025
00617
00618
00619
00620
00621
00622 struct ast_variable *ast_http_get_post_vars(
00623 struct ast_tcptls_session_instance *ser, struct ast_variable *headers)
00624 {
00625 int content_length = 0;
00626 struct ast_variable *v, *post_vars=NULL, *prev = NULL;
00627 char *buf, *var, *val;
00628 int res;
00629
00630 for (v = headers; v; v = v->next) {
00631 if (!strcasecmp(v->name, "Content-Type")) {
00632 if (strcasecmp(v->value, "application/x-www-form-urlencoded")) {
00633 return NULL;
00634 }
00635 break;
00636 }
00637 }
00638
00639 for (v = headers; v; v = v->next) {
00640 if (!strcasecmp(v->name, "Content-Length")) {
00641 content_length = atoi(v->value);
00642 break;
00643 }
00644 }
00645
00646 if (content_length <= 0) {
00647 return NULL;
00648 }
00649
00650 if (content_length > MAX_POST_CONTENT - 1) {
00651 ast_log(LOG_WARNING, "Excessively long HTTP content. %d is greater than our max of %d\n",
00652 content_length, MAX_POST_CONTENT);
00653 ast_http_send(ser, AST_HTTP_POST, 413, "Request Entity Too Large", NULL, NULL, 0, 0);
00654 return NULL;
00655 }
00656
00657 buf = ast_malloc(content_length + 1);
00658 if (!buf) {
00659 return NULL;
00660 }
00661
00662 res = fread(buf, 1, content_length, ser->f);
00663 if (res < content_length) {
00664
00665
00666 goto done;
00667 }
00668 buf[content_length] = '\0';
00669
00670 while ((val = strsep(&buf, "&"))) {
00671 var = strsep(&val, "=");
00672 if (val) {
00673 http_decode(val);
00674 } else {
00675 val = "";
00676 }
00677 http_decode(var);
00678 if ((v = ast_variable_new(var, val, ""))) {
00679 if (post_vars) {
00680 prev->next = v;
00681 } else {
00682 post_vars = v;
00683 }
00684 prev = v;
00685 }
00686 }
00687
00688 done:
00689 ast_free(buf);
00690 return post_vars;
00691 }
00692
00693 static int handle_uri(struct ast_tcptls_session_instance *ser, char *uri,
00694 enum ast_http_method method, struct ast_variable *headers)
00695 {
00696 char *c;
00697 int res = -1;
00698 char *params = uri;
00699 struct ast_http_uri *urih = NULL;
00700 int l;
00701 struct ast_variable *get_vars = NULL, *v, *prev = NULL;
00702 struct http_uri_redirect *redirect;
00703
00704 ast_debug(2, "HTTP Request URI is %s \n", uri);
00705
00706 strsep(¶ms, "?");
00707
00708 if (params) {
00709 char *var, *val;
00710
00711 while ((val = strsep(¶ms, "&"))) {
00712 var = strsep(&val, "=");
00713 if (val) {
00714 http_decode(val);
00715 } else {
00716 val = "";
00717 }
00718 http_decode(var);
00719 if ((v = ast_variable_new(var, val, ""))) {
00720 if (get_vars) {
00721 prev->next = v;
00722 } else {
00723 get_vars = v;
00724 }
00725 prev = v;
00726 }
00727 }
00728 }
00729 http_decode(uri);
00730
00731 AST_RWLIST_RDLOCK(&uri_redirects);
00732 AST_RWLIST_TRAVERSE(&uri_redirects, redirect, entry) {
00733 if (!strcasecmp(uri, redirect->target)) {
00734 struct ast_str *http_header = ast_str_create(128);
00735 ast_str_set(&http_header, 0, "Location: %s\r\n", redirect->dest);
00736 ast_http_send(ser, method, 302, "Moved Temporarily", http_header, NULL, 0, 0);
00737
00738 break;
00739 }
00740 }
00741 AST_RWLIST_UNLOCK(&uri_redirects);
00742 if (redirect) {
00743 goto cleanup;
00744 }
00745
00746
00747 l = strlen(prefix);
00748 if (!strncasecmp(uri, prefix, l) && uri[l] == '/') {
00749 uri += l + 1;
00750
00751 AST_RWLIST_RDLOCK(&uris);
00752 AST_RWLIST_TRAVERSE(&uris, urih, entry) {
00753 ast_debug(2, "match request [%s] with handler [%s] len %d\n", uri, urih->uri, l);
00754 l = strlen(urih->uri);
00755 c = uri + l;
00756 if (strncasecmp(urih->uri, uri, l)
00757 || (*c && *c != '/')) {
00758 continue;
00759 }
00760 if (*c == '/') {
00761 c++;
00762 }
00763 if (!*c || urih->has_subtree) {
00764 uri = c;
00765 break;
00766 }
00767 }
00768 AST_RWLIST_UNLOCK(&uris);
00769 }
00770 if (urih) {
00771 res = urih->callback(ser, urih, uri, method, get_vars, headers);
00772 } else {
00773 ast_http_error(ser, 404, "Not Found", "The requested URL was not found on this server.");
00774 }
00775
00776 cleanup:
00777 ast_variables_destroy(get_vars);
00778 return res;
00779 }
00780
00781 #ifdef DO_SSL
00782 #if defined(HAVE_FUNOPEN)
00783 #define HOOK_T int
00784 #define LEN_T int
00785 #else
00786 #define HOOK_T ssize_t
00787 #define LEN_T size_t
00788 #endif
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
00824 #endif
00825
00826 static struct ast_variable *parse_cookies(const char *cookies)
00827 {
00828 char *parse = ast_strdupa(cookies);
00829 char *cur;
00830 struct ast_variable *vars = NULL, *var;
00831
00832 while ((cur = strsep(&parse, ";"))) {
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 (!strcasecmp(v->name, "Cookie")) {
00866 ast_variables_destroy(cookies);
00867 cookies = parse_cookies(v->value);
00868 }
00869 }
00870 return cookies;
00871 }
00872
00873
00874 #define MAX_HTTP_REQUEST_HEADERS 100
00875
00876 static void *httpd_helper_thread(void *data)
00877 {
00878 char buf[4096];
00879 char header_line[4096];
00880 struct ast_tcptls_session_instance *ser = data;
00881 struct ast_variable *headers = NULL;
00882 struct ast_variable *tail = headers;
00883 char *uri, *method;
00884 enum ast_http_method http_method = AST_HTTP_UNKNOWN;
00885 int remaining_headers;
00886
00887 if (ast_atomic_fetchadd_int(&session_count, +1) >= session_limit) {
00888 goto done;
00889 }
00890
00891 if (!fgets(buf, sizeof(buf), ser->f)) {
00892 goto done;
00893 }
00894
00895
00896 method = ast_skip_blanks(buf);
00897 uri = ast_skip_nonblanks(method);
00898 if (*uri) {
00899 *uri++ = '\0';
00900 }
00901
00902 if (!strcasecmp(method,"GET")) {
00903 http_method = AST_HTTP_GET;
00904 } else if (!strcasecmp(method,"POST")) {
00905 http_method = AST_HTTP_POST;
00906 } else if (!strcasecmp(method,"HEAD")) {
00907 http_method = AST_HTTP_HEAD;
00908 } else if (!strcasecmp(method,"PUT")) {
00909 http_method = AST_HTTP_PUT;
00910 }
00911
00912 uri = ast_skip_blanks(uri);
00913
00914 if (*uri) {
00915 char *c = ast_skip_nonblanks(uri);
00916
00917 if (*c) {
00918 *c = '\0';
00919 }
00920 } else {
00921 ast_http_error(ser, 400, "Bad Request", "Invalid Request");
00922 goto done;
00923 }
00924
00925
00926 remaining_headers = MAX_HTTP_REQUEST_HEADERS;
00927 while (fgets(header_line, sizeof(header_line), ser->f)) {
00928 char *name, *value;
00929
00930
00931 ast_trim_blanks(header_line);
00932 if (ast_strlen_zero(header_line)) {
00933 break;
00934 }
00935
00936 value = header_line;
00937 name = strsep(&value, ":");
00938 if (!value) {
00939 continue;
00940 }
00941
00942 value = ast_skip_blanks(value);
00943 if (ast_strlen_zero(value) || ast_strlen_zero(name)) {
00944 continue;
00945 }
00946
00947 ast_trim_blanks(name);
00948
00949 if (!remaining_headers--) {
00950
00951 ast_http_error(ser, 413, "Request Entity Too Large", "Too many headers");
00952 goto done;
00953 }
00954 if (!headers) {
00955 headers = ast_variable_new(name, value, __FILE__);
00956 tail = headers;
00957 } else {
00958 tail->next = ast_variable_new(name, value, __FILE__);
00959 tail = tail->next;
00960 }
00961 if (!tail) {
00962
00963
00964
00965
00966 ast_variables_destroy(headers);
00967 headers = NULL;
00968
00969 ast_http_error(ser, 500, "Server Error", "Out of memory");
00970 goto done;
00971 }
00972 }
00973
00974 handle_uri(ser, uri, http_method, headers);
00975
00976 done:
00977 ast_atomic_fetchadd_int(&session_count, -1);
00978
00979
00980 ast_variables_destroy(headers);
00981
00982 if (ser->f) {
00983 fclose(ser->f);
00984 }
00985 ao2_ref(ser, -1);
00986 ser = NULL;
00987 return NULL;
00988 }
00989
00990
00991
00992
00993
00994
00995 static void add_redirect(const char *value)
00996 {
00997 char *target, *dest;
00998 struct http_uri_redirect *redirect, *cur;
00999 unsigned int target_len;
01000 unsigned int total_len;
01001
01002 dest = ast_strdupa(value);
01003 dest = ast_skip_blanks(dest);
01004 target = strsep(&dest, " ");
01005 target = ast_skip_blanks(target);
01006 target = strsep(&target, " ");
01007
01008 if (!dest) {
01009 ast_log(LOG_WARNING, "Invalid redirect '%s'\n", value);
01010 return;
01011 }
01012
01013 target_len = strlen(target) + 1;
01014 total_len = sizeof(*redirect) + target_len + strlen(dest) + 1;
01015
01016 if (!(redirect = ast_calloc(1, total_len))) {
01017 return;
01018 }
01019 redirect->dest = redirect->target + target_len;
01020 strcpy(redirect->target, target);
01021 strcpy(redirect->dest, dest);
01022
01023 AST_RWLIST_WRLOCK(&uri_redirects);
01024
01025 target_len--;
01026 if (AST_RWLIST_EMPTY(&uri_redirects)
01027 || strlen(AST_RWLIST_FIRST(&uri_redirects)->target) <= target_len ) {
01028 AST_RWLIST_INSERT_HEAD(&uri_redirects, redirect, entry);
01029 AST_RWLIST_UNLOCK(&uri_redirects);
01030
01031 return;
01032 }
01033
01034 AST_RWLIST_TRAVERSE(&uri_redirects, cur, entry) {
01035 if (AST_RWLIST_NEXT(cur, entry)
01036 && strlen(AST_RWLIST_NEXT(cur, entry)->target) <= target_len ) {
01037 AST_RWLIST_INSERT_AFTER(&uri_redirects, cur, redirect, entry);
01038 AST_RWLIST_UNLOCK(&uri_redirects);
01039 return;
01040 }
01041 }
01042
01043 AST_RWLIST_INSERT_TAIL(&uri_redirects, redirect, entry);
01044
01045 AST_RWLIST_UNLOCK(&uri_redirects);
01046 }
01047
01048 static int __ast_http_load(int reload)
01049 {
01050 struct ast_config *cfg;
01051 struct ast_variable *v;
01052 int enabled=0;
01053 int newenablestatic=0;
01054 struct hostent *hp;
01055 struct ast_hostent ahp;
01056 char newprefix[MAX_PREFIX] = "";
01057 struct http_uri_redirect *redirect;
01058 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
01059 struct sockaddr_in tmp = {0,};
01060 struct sockaddr_in tmp2 = {0,};
01061 int http_tls_was_enabled = 0;
01062
01063 cfg = ast_config_load2("http.conf", "http", config_flags);
01064 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
01065 return 0;
01066 }
01067
01068 http_tls_was_enabled = (reload && http_tls_cfg.enabled);
01069
01070 tmp.sin_family = AF_INET;
01071 tmp.sin_port = htons(DEFAULT_HTTP_PORT);
01072 ast_sockaddr_from_sin(&http_desc.local_address, &tmp);
01073
01074 http_tls_cfg.enabled = 0;
01075 if (http_tls_cfg.certfile) {
01076 ast_free(http_tls_cfg.certfile);
01077 }
01078 http_tls_cfg.certfile = ast_strdup(AST_CERTFILE);
01079
01080 if (http_tls_cfg.pvtfile) {
01081 ast_free(http_tls_cfg.pvtfile);
01082 }
01083 http_tls_cfg.pvtfile = ast_strdup("");
01084
01085 if (http_tls_cfg.cipher) {
01086 ast_free(http_tls_cfg.cipher);
01087 }
01088 http_tls_cfg.cipher = ast_strdup("");
01089
01090 AST_RWLIST_WRLOCK(&uri_redirects);
01091 while ((redirect = AST_RWLIST_REMOVE_HEAD(&uri_redirects, entry))) {
01092 ast_free(redirect);
01093 }
01094 AST_RWLIST_UNLOCK(&uri_redirects);
01095
01096 ast_sockaddr_setnull(&https_desc.local_address);
01097
01098 if (cfg) {
01099 v = ast_variable_browse(cfg, "general");
01100 for (; v; v = v->next) {
01101
01102
01103 if (strcasecmp(v->name, "tlscafile")
01104 && strcasecmp(v->name, "tlscapath")
01105 && strcasecmp(v->name, "tlscadir")
01106 && strcasecmp(v->name, "tlsverifyclient")
01107 && strcasecmp(v->name, "tlsdontverifyserver")
01108 && strcasecmp(v->name, "tlsclientmethod")
01109 && strcasecmp(v->name, "sslclientmethod")
01110 && strcasecmp(v->name, "tlscipher")
01111 && strcasecmp(v->name, "sslcipher")
01112 && !ast_tls_read_conf(&http_tls_cfg, &https_desc, v->name, v->value)) {
01113 continue;
01114 }
01115
01116 if (!strcasecmp(v->name, "enabled")) {
01117 enabled = ast_true(v->value);
01118 } else if (!strcasecmp(v->name, "enablestatic")) {
01119 newenablestatic = ast_true(v->value);
01120 } else if (!strcasecmp(v->name, "bindport")) {
01121 ast_sockaddr_set_port(&http_desc.local_address,
01122 atoi(v->value));
01123 } else if (!strcasecmp(v->name, "bindaddr")) {
01124 if ((hp = ast_gethostbyname(v->value, &ahp))) {
01125 ast_sockaddr_to_sin(&http_desc.local_address,
01126 &tmp);
01127 memcpy(&tmp.sin_addr, hp->h_addr, sizeof(tmp.sin_addr));
01128 ast_sockaddr_from_sin(&http_desc.local_address,
01129 &tmp);
01130 } else {
01131 ast_log(LOG_WARNING, "Invalid bind address '%s'\n", v->value);
01132 }
01133 } else if (!strcasecmp(v->name, "prefix")) {
01134 if (!ast_strlen_zero(v->value)) {
01135 newprefix[0] = '/';
01136 ast_copy_string(newprefix + 1, v->value, sizeof(newprefix) - 1);
01137 } else {
01138 newprefix[0] = '\0';
01139 }
01140 } else if (!strcasecmp(v->name, "redirect")) {
01141 add_redirect(v->value);
01142 } else if (!strcasecmp(v->name, "sessionlimit")) {
01143 if (ast_parse_arg(v->value, PARSE_INT32|PARSE_DEFAULT|PARSE_IN_RANGE,
01144 &session_limit, DEFAULT_SESSION_LIMIT, 1, INT_MAX)) {
01145 ast_log(LOG_WARNING, "Invalid %s '%s' at line %d of http.conf\n",
01146 v->name, v->value, v->lineno);
01147 }
01148 } else {
01149 ast_log(LOG_WARNING, "Ignoring unknown option '%s' in http.conf\n", v->name);
01150 }
01151 }
01152
01153 ast_config_destroy(cfg);
01154 }
01155
01156 ast_sockaddr_to_sin(&http_desc.local_address, &tmp);
01157 ast_sockaddr_to_sin(&https_desc.local_address, &tmp2);
01158 if (!tmp2.sin_addr.s_addr) {
01159 tmp2.sin_addr = tmp.sin_addr;
01160 }
01161 if (!tmp2.sin_port) {
01162 tmp2.sin_port = htons(DEFAULT_HTTPS_PORT);
01163 }
01164 ast_sockaddr_from_sin(&https_desc.local_address, &tmp2);
01165 if (!enabled) {
01166 ast_sockaddr_setnull(&http_desc.local_address);
01167 ast_sockaddr_setnull(&https_desc.local_address);
01168 }
01169 if (strcmp(prefix, newprefix)) {
01170 ast_copy_string(prefix, newprefix, sizeof(prefix));
01171 }
01172 enablestatic = newenablestatic;
01173 ast_tcptls_server_start(&http_desc);
01174
01175 if (http_tls_was_enabled && !http_tls_cfg.enabled) {
01176 ast_tcptls_server_stop(&https_desc);
01177 } else if (ast_ssl_setup(https_desc.tls_cfg)) {
01178 ast_tcptls_server_start(&https_desc);
01179 }
01180
01181 return 0;
01182 }
01183
01184 static char *handle_show_http(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01185 {
01186 struct ast_http_uri *urih;
01187 struct http_uri_redirect *redirect;
01188 struct sockaddr_in tmp;
01189
01190 switch (cmd) {
01191 case CLI_INIT:
01192 e->command = "http show status";
01193 e->usage =
01194 "Usage: http show status\n"
01195 " Lists status of internal HTTP engine\n";
01196 return NULL;
01197 case CLI_GENERATE:
01198 return NULL;
01199 }
01200
01201 if (a->argc != 3) {
01202 return CLI_SHOWUSAGE;
01203 }
01204 ast_cli(a->fd, "HTTP Server Status:\n");
01205 ast_cli(a->fd, "Prefix: %s\n", prefix);
01206 ast_sockaddr_to_sin(&http_desc.old_address, &tmp);
01207 if (!tmp.sin_family) {
01208 ast_cli(a->fd, "Server Disabled\n\n");
01209 } else {
01210 ast_cli(a->fd, "Server Enabled and Bound to %s:%d\n\n",
01211 ast_inet_ntoa(tmp.sin_addr), ntohs(tmp.sin_port));
01212 if (http_tls_cfg.enabled) {
01213 ast_sockaddr_to_sin(&https_desc.old_address, &tmp);
01214 ast_cli(a->fd, "HTTPS Server Enabled and Bound to %s:%d\n\n",
01215 ast_inet_ntoa(tmp.sin_addr),
01216 ntohs(tmp.sin_port));
01217 }
01218 }
01219
01220 ast_cli(a->fd, "Enabled URI's:\n");
01221 AST_RWLIST_RDLOCK(&uris);
01222 if (AST_RWLIST_EMPTY(&uris)) {
01223 ast_cli(a->fd, "None.\n");
01224 } else {
01225 AST_RWLIST_TRAVERSE(&uris, urih, entry)
01226 ast_cli(a->fd, "%s/%s%s => %s\n", prefix, urih->uri, (urih->has_subtree ? "/..." : "" ), urih->description);
01227 }
01228 AST_RWLIST_UNLOCK(&uris);
01229
01230 ast_cli(a->fd, "\nEnabled Redirects:\n");
01231 AST_RWLIST_RDLOCK(&uri_redirects);
01232 AST_RWLIST_TRAVERSE(&uri_redirects, redirect, entry)
01233 ast_cli(a->fd, " %s => %s\n", redirect->target, redirect->dest);
01234 if (AST_RWLIST_EMPTY(&uri_redirects)) {
01235 ast_cli(a->fd, " None.\n");
01236 }
01237 AST_RWLIST_UNLOCK(&uri_redirects);
01238
01239 return CLI_SUCCESS;
01240 }
01241
01242 int ast_http_reload(void)
01243 {
01244 return __ast_http_load(1);
01245 }
01246
01247 static struct ast_cli_entry cli_http[] = {
01248 AST_CLI_DEFINE(handle_show_http, "Display HTTP server status"),
01249 };
01250
01251 static void http_shutdown(void)
01252 {
01253 struct http_uri_redirect *redirect;
01254 ast_cli_unregister_multiple(cli_http, ARRAY_LEN(cli_http));
01255
01256 ast_tcptls_server_stop(&http_desc);
01257 if (http_tls_cfg.enabled) {
01258 ast_tcptls_server_stop(&https_desc);
01259 }
01260 ast_free(http_tls_cfg.certfile);
01261 ast_free(http_tls_cfg.pvtfile);
01262 ast_free(http_tls_cfg.cipher);
01263
01264 ast_http_uri_unlink(&statusuri);
01265 ast_http_uri_unlink(&staticuri);
01266
01267 AST_RWLIST_WRLOCK(&uri_redirects);
01268 while ((redirect = AST_RWLIST_REMOVE_HEAD(&uri_redirects, entry))) {
01269 ast_free(redirect);
01270 }
01271 AST_RWLIST_UNLOCK(&uri_redirects);
01272 }
01273
01274 int ast_http_init(void)
01275 {
01276 ast_http_uri_link(&statusuri);
01277 ast_http_uri_link(&staticuri);
01278 ast_cli_register_multiple(cli_http, ARRAY_LEN(cli_http));
01279 ast_register_atexit(http_shutdown);
01280
01281 return __ast_http_load(0);
01282 }