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: 366650 $")
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 }
00249
00250
00251 if ((len = strlen(uri) + strlen(ast_config_AST_DATA_DIR) + strlen("/static-http/") + 5) > 1024) {
00252 goto out403;
00253 }
00254
00255 path = alloca(len);
00256 sprintf(path, "%s/static-http/%s", ast_config_AST_DATA_DIR, uri);
00257 if (stat(path, &st)) {
00258 goto out404;
00259 }
00260
00261 if (S_ISDIR(st.st_mode)) {
00262 goto out404;
00263 }
00264
00265 fd = open(path, O_RDONLY);
00266 if (fd < 0) {
00267 goto out403;
00268 }
00269
00270 if (strstr(path, "/private/") && !astman_is_authed(ast_http_manid_from_vars(headers))) {
00271 goto out403;
00272 }
00273
00274
00275 snprintf(etag, sizeof(etag), "\"%ld\"", (long)st.st_mtime);
00276
00277
00278 tv.tv_sec = st.st_mtime;
00279 tv.tv_usec = 0;
00280 ast_strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", ast_localtime(&tv, &tm, "GMT"));
00281
00282
00283 for (v = headers; v; v = v->next) {
00284 if (!strcasecmp(v->name, "If-None-Match")) {
00285 if (!strcasecmp(v->value, etag)) {
00286 not_modified = 1;
00287 }
00288 break;
00289 }
00290 }
00291
00292 if ( (http_header = ast_str_create(255)) == NULL) {
00293 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
00616
00617
00618
00619 struct ast_variable *ast_http_get_post_vars(
00620 struct ast_tcptls_session_instance *ser, struct ast_variable *headers)
00621 {
00622 int content_length = 0;
00623 struct ast_variable *v, *post_vars=NULL, *prev = NULL;
00624 char *buf, *var, *val;
00625
00626 for (v = headers; v; v = v->next) {
00627 if (!strcasecmp(v->name, "Content-Type")) {
00628 if (strcasecmp(v->value, "application/x-www-form-urlencoded")) {
00629 return NULL;
00630 }
00631 break;
00632 }
00633 }
00634
00635 for (v = headers; v; v = v->next) {
00636 if (!strcasecmp(v->name, "Content-Length")) {
00637 content_length = atoi(v->value) + 1;
00638 break;
00639 }
00640 }
00641
00642 if (!content_length) {
00643 return NULL;
00644 }
00645
00646 if (!(buf = alloca(content_length))) {
00647 return NULL;
00648 }
00649 if (!fgets(buf, content_length, ser->f)) {
00650 return NULL;
00651 }
00652
00653 while ((val = strsep(&buf, "&"))) {
00654 var = strsep(&val, "=");
00655 if (val) {
00656 http_decode(val);
00657 } else {
00658 val = "";
00659 }
00660 http_decode(var);
00661 if ((v = ast_variable_new(var, val, ""))) {
00662 if (post_vars) {
00663 prev->next = v;
00664 } else {
00665 post_vars = v;
00666 }
00667 prev = v;
00668 }
00669 }
00670 return post_vars;
00671 }
00672
00673 static int handle_uri(struct ast_tcptls_session_instance *ser, char *uri,
00674 enum ast_http_method method, struct ast_variable *headers)
00675 {
00676 char *c;
00677 int res = -1;
00678 char *params = uri;
00679 struct ast_http_uri *urih = NULL;
00680 int l;
00681 struct ast_variable *get_vars = NULL, *v, *prev = NULL;
00682 struct http_uri_redirect *redirect;
00683
00684 ast_debug(2, "HTTP Request URI is %s \n", uri);
00685
00686 strsep(¶ms, "?");
00687
00688 if (params) {
00689 char *var, *val;
00690
00691 while ((val = strsep(¶ms, "&"))) {
00692 var = strsep(&val, "=");
00693 if (val) {
00694 http_decode(val);
00695 } else {
00696 val = "";
00697 }
00698 http_decode(var);
00699 if ((v = ast_variable_new(var, val, ""))) {
00700 if (get_vars) {
00701 prev->next = v;
00702 } else {
00703 get_vars = v;
00704 }
00705 prev = v;
00706 }
00707 }
00708 }
00709 http_decode(uri);
00710
00711 AST_RWLIST_RDLOCK(&uri_redirects);
00712 AST_RWLIST_TRAVERSE(&uri_redirects, redirect, entry) {
00713 if (!strcasecmp(uri, redirect->target)) {
00714 struct ast_str *http_header = ast_str_create(128);
00715 ast_str_set(&http_header, 0, "Location: %s\r\n", redirect->dest);
00716 ast_http_send(ser, method, 302, "Moved Temporarily", http_header, NULL, 0, 0);
00717
00718 break;
00719 }
00720 }
00721 AST_RWLIST_UNLOCK(&uri_redirects);
00722 if (redirect) {
00723 goto cleanup;
00724 }
00725
00726
00727 l = strlen(prefix);
00728 if (!strncasecmp(uri, prefix, l) && uri[l] == '/') {
00729 uri += l + 1;
00730
00731 AST_RWLIST_RDLOCK(&uris);
00732 AST_RWLIST_TRAVERSE(&uris, urih, entry) {
00733 ast_debug(2, "match request [%s] with handler [%s] len %d\n", uri, urih->uri, l);
00734 l = strlen(urih->uri);
00735 c = uri + l;
00736 if (strncasecmp(urih->uri, uri, l)
00737 || (*c && *c != '/')) {
00738 continue;
00739 }
00740 if (*c == '/') {
00741 c++;
00742 }
00743 if (!*c || urih->has_subtree) {
00744 uri = c;
00745 break;
00746 }
00747 }
00748 AST_RWLIST_UNLOCK(&uris);
00749 }
00750 if (urih) {
00751 res = urih->callback(ser, urih, uri, method, get_vars, headers);
00752 } else {
00753 ast_http_error(ser, 404, "Not Found", "The requested URL was not found on this server.");
00754 }
00755
00756 cleanup:
00757 ast_variables_destroy(get_vars);
00758 return res;
00759 }
00760
00761 #ifdef DO_SSL
00762 #if defined(HAVE_FUNOPEN)
00763 #define HOOK_T int
00764 #define LEN_T int
00765 #else
00766 #define HOOK_T ssize_t
00767 #define LEN_T size_t
00768 #endif
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804 #endif
00805
00806 static struct ast_variable *parse_cookies(char *cookies)
00807 {
00808 char *cur;
00809 struct ast_variable *vars = NULL, *var;
00810
00811 while ((cur = strsep(&cookies, ";"))) {
00812 char *name, *val;
00813
00814 name = val = cur;
00815 strsep(&val, "=");
00816
00817 if (ast_strlen_zero(name) || ast_strlen_zero(val)) {
00818 continue;
00819 }
00820
00821 name = ast_strip(name);
00822 val = ast_strip_quoted(val, "\"", "\"");
00823
00824 if (ast_strlen_zero(name) || ast_strlen_zero(val)) {
00825 continue;
00826 }
00827
00828 ast_debug(1, "HTTP Cookie, Name: '%s' Value: '%s'\n", name, val);
00829
00830 var = ast_variable_new(name, val, __FILE__);
00831 var->next = vars;
00832 vars = var;
00833 }
00834
00835 return vars;
00836 }
00837
00838
00839 struct ast_variable *ast_http_get_cookies(struct ast_variable *headers)
00840 {
00841 struct ast_variable *v, *cookies=NULL;
00842
00843 for (v = headers; v; v = v->next) {
00844 if (!strncasecmp(v->name, "Cookie", 6)) {
00845 char *tmp = ast_strdupa(v->value);
00846 if (cookies) {
00847 ast_variables_destroy(cookies);
00848 }
00849
00850 cookies = parse_cookies(tmp);
00851 }
00852 }
00853 return cookies;
00854 }
00855
00856
00857 static void *httpd_helper_thread(void *data)
00858 {
00859 char buf[4096];
00860 char header_line[4096];
00861 struct ast_tcptls_session_instance *ser = data;
00862 struct ast_variable *headers = NULL;
00863 struct ast_variable *tail = headers;
00864 char *uri, *method;
00865 enum ast_http_method http_method = AST_HTTP_UNKNOWN;
00866
00867 if (ast_atomic_fetchadd_int(&session_count, +1) >= session_limit) {
00868 goto done;
00869 }
00870
00871 if (!fgets(buf, sizeof(buf), ser->f)) {
00872 goto done;
00873 }
00874
00875
00876 method = ast_skip_blanks(buf);
00877 uri = ast_skip_nonblanks(method);
00878 if (*uri) {
00879 *uri++ = '\0';
00880 }
00881
00882 if (!strcasecmp(method,"GET")) {
00883 http_method = AST_HTTP_GET;
00884 } else if (!strcasecmp(method,"POST")) {
00885 http_method = AST_HTTP_POST;
00886 } else if (!strcasecmp(method,"HEAD")) {
00887 http_method = AST_HTTP_HEAD;
00888 } else if (!strcasecmp(method,"PUT")) {
00889 http_method = AST_HTTP_PUT;
00890 }
00891
00892 uri = ast_skip_blanks(uri);
00893
00894 if (*uri) {
00895 char *c = ast_skip_nonblanks(uri);
00896
00897 if (*c) {
00898 *c = '\0';
00899 }
00900 }
00901
00902
00903 while (fgets(header_line, sizeof(header_line), ser->f)) {
00904 char *name, *value;
00905
00906
00907 ast_trim_blanks(header_line);
00908 if (ast_strlen_zero(header_line)) {
00909 break;
00910 }
00911
00912 value = header_line;
00913 name = strsep(&value, ":");
00914 if (!value) {
00915 continue;
00916 }
00917
00918 value = ast_skip_blanks(value);
00919 if (ast_strlen_zero(value) || ast_strlen_zero(name)) {
00920 continue;
00921 }
00922
00923 ast_trim_blanks(name);
00924
00925 if (!headers) {
00926 headers = ast_variable_new(name, value, __FILE__);
00927 tail = headers;
00928 } else {
00929 tail->next = ast_variable_new(name, value, __FILE__);
00930 tail = tail->next;
00931 }
00932 }
00933
00934 if (!*uri) {
00935 ast_http_error(ser, 400, "Bad Request", "Invalid Request");
00936 goto done;
00937 }
00938
00939 handle_uri(ser, uri, http_method, headers);
00940
00941 done:
00942 ast_atomic_fetchadd_int(&session_count, -1);
00943
00944
00945 if (headers) {
00946 ast_variables_destroy(headers);
00947 }
00948
00949 if (ser->f) {
00950 fclose(ser->f);
00951 }
00952 ao2_ref(ser, -1);
00953 ser = NULL;
00954 return NULL;
00955 }
00956
00957
00958
00959
00960
00961
00962 static void add_redirect(const char *value)
00963 {
00964 char *target, *dest;
00965 struct http_uri_redirect *redirect, *cur;
00966 unsigned int target_len;
00967 unsigned int total_len;
00968
00969 dest = ast_strdupa(value);
00970 dest = ast_skip_blanks(dest);
00971 target = strsep(&dest, " ");
00972 target = ast_skip_blanks(target);
00973 target = strsep(&target, " ");
00974
00975 if (!dest) {
00976 ast_log(LOG_WARNING, "Invalid redirect '%s'\n", value);
00977 return;
00978 }
00979
00980 target_len = strlen(target) + 1;
00981 total_len = sizeof(*redirect) + target_len + strlen(dest) + 1;
00982
00983 if (!(redirect = ast_calloc(1, total_len))) {
00984 return;
00985 }
00986 redirect->dest = redirect->target + target_len;
00987 strcpy(redirect->target, target);
00988 strcpy(redirect->dest, dest);
00989
00990 AST_RWLIST_WRLOCK(&uri_redirects);
00991
00992 target_len--;
00993 if (AST_RWLIST_EMPTY(&uri_redirects)
00994 || strlen(AST_RWLIST_FIRST(&uri_redirects)->target) <= target_len ) {
00995 AST_RWLIST_INSERT_HEAD(&uri_redirects, redirect, entry);
00996 AST_RWLIST_UNLOCK(&uri_redirects);
00997
00998 return;
00999 }
01000
01001 AST_RWLIST_TRAVERSE(&uri_redirects, cur, entry) {
01002 if (AST_RWLIST_NEXT(cur, entry)
01003 && strlen(AST_RWLIST_NEXT(cur, entry)->target) <= target_len ) {
01004 AST_RWLIST_INSERT_AFTER(&uri_redirects, cur, redirect, entry);
01005 AST_RWLIST_UNLOCK(&uri_redirects);
01006 return;
01007 }
01008 }
01009
01010 AST_RWLIST_INSERT_TAIL(&uri_redirects, redirect, entry);
01011
01012 AST_RWLIST_UNLOCK(&uri_redirects);
01013 }
01014
01015 static int __ast_http_load(int reload)
01016 {
01017 struct ast_config *cfg;
01018 struct ast_variable *v;
01019 int enabled=0;
01020 int newenablestatic=0;
01021 struct hostent *hp;
01022 struct ast_hostent ahp;
01023 char newprefix[MAX_PREFIX] = "";
01024 struct http_uri_redirect *redirect;
01025 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
01026 struct sockaddr_in tmp = {0,};
01027 struct sockaddr_in tmp2 = {0,};
01028 int http_tls_was_enabled = 0;
01029
01030 cfg = ast_config_load2("http.conf", "http", config_flags);
01031 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
01032 return 0;
01033 }
01034
01035 http_tls_was_enabled = (reload && http_tls_cfg.enabled);
01036
01037 tmp.sin_family = AF_INET;
01038 tmp.sin_port = htons(DEFAULT_HTTP_PORT);
01039 ast_sockaddr_from_sin(&http_desc.local_address, &tmp);
01040
01041 http_tls_cfg.enabled = 0;
01042 if (http_tls_cfg.certfile) {
01043 ast_free(http_tls_cfg.certfile);
01044 }
01045 http_tls_cfg.certfile = ast_strdup(AST_CERTFILE);
01046
01047 if (http_tls_cfg.pvtfile) {
01048 ast_free(http_tls_cfg.pvtfile);
01049 }
01050 http_tls_cfg.pvtfile = ast_strdup("");
01051
01052 if (http_tls_cfg.cipher) {
01053 ast_free(http_tls_cfg.cipher);
01054 }
01055 http_tls_cfg.cipher = ast_strdup("");
01056
01057 AST_RWLIST_WRLOCK(&uri_redirects);
01058 while ((redirect = AST_RWLIST_REMOVE_HEAD(&uri_redirects, entry))) {
01059 ast_free(redirect);
01060 }
01061 AST_RWLIST_UNLOCK(&uri_redirects);
01062
01063 ast_sockaddr_setnull(&https_desc.local_address);
01064
01065 if (cfg) {
01066 v = ast_variable_browse(cfg, "general");
01067 for (; v; v = v->next) {
01068
01069
01070 if (!ast_tls_read_conf(&http_tls_cfg, &https_desc, v->name, v->value)) {
01071 continue;
01072 }
01073
01074 if (!strcasecmp(v->name, "enabled")) {
01075 enabled = ast_true(v->value);
01076 } else if (!strcasecmp(v->name, "enablestatic")) {
01077 newenablestatic = ast_true(v->value);
01078 } else if (!strcasecmp(v->name, "bindport")) {
01079 ast_sockaddr_set_port(&http_desc.local_address,
01080 atoi(v->value));
01081 } else if (!strcasecmp(v->name, "bindaddr")) {
01082 if ((hp = ast_gethostbyname(v->value, &ahp))) {
01083 ast_sockaddr_to_sin(&http_desc.local_address,
01084 &tmp);
01085 memcpy(&tmp.sin_addr, hp->h_addr, sizeof(tmp.sin_addr));
01086 ast_sockaddr_from_sin(&http_desc.local_address,
01087 &tmp);
01088 } else {
01089 ast_log(LOG_WARNING, "Invalid bind address '%s'\n", v->value);
01090 }
01091 } else if (!strcasecmp(v->name, "prefix")) {
01092 if (!ast_strlen_zero(v->value)) {
01093 newprefix[0] = '/';
01094 ast_copy_string(newprefix + 1, v->value, sizeof(newprefix) - 1);
01095 } else {
01096 newprefix[0] = '\0';
01097 }
01098 } else if (!strcasecmp(v->name, "redirect")) {
01099 add_redirect(v->value);
01100 } else if (!strcasecmp(v->name, "sessionlimit")) {
01101 if (ast_parse_arg(v->value, PARSE_INT32|PARSE_DEFAULT|PARSE_IN_RANGE,
01102 &session_limit, DEFAULT_SESSION_LIMIT, 1, INT_MAX)) {
01103 ast_log(LOG_WARNING, "Invalid %s '%s' at line %d of http.conf\n",
01104 v->name, v->value, v->lineno);
01105 }
01106 } else {
01107 ast_log(LOG_WARNING, "Ignoring unknown option '%s' in http.conf\n", v->name);
01108 }
01109 }
01110
01111 ast_config_destroy(cfg);
01112 }
01113
01114 ast_sockaddr_to_sin(&http_desc.local_address, &tmp);
01115 ast_sockaddr_to_sin(&https_desc.local_address, &tmp2);
01116 if (!tmp2.sin_addr.s_addr) {
01117 tmp2.sin_addr = tmp.sin_addr;
01118 }
01119 if (!tmp2.sin_port) {
01120 tmp2.sin_port = htons(DEFAULT_HTTPS_PORT);
01121 }
01122 ast_sockaddr_from_sin(&https_desc.local_address, &tmp2);
01123 if (!enabled) {
01124 ast_sockaddr_setnull(&http_desc.local_address);
01125 ast_sockaddr_setnull(&https_desc.local_address);
01126 }
01127 if (strcmp(prefix, newprefix)) {
01128 ast_copy_string(prefix, newprefix, sizeof(prefix));
01129 }
01130 enablestatic = newenablestatic;
01131 ast_tcptls_server_start(&http_desc);
01132
01133 if (http_tls_was_enabled && !http_tls_cfg.enabled) {
01134 ast_tcptls_server_stop(&https_desc);
01135 } else if (ast_ssl_setup(https_desc.tls_cfg)) {
01136 ast_tcptls_server_start(&https_desc);
01137 }
01138
01139 return 0;
01140 }
01141
01142 static char *handle_show_http(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01143 {
01144 struct ast_http_uri *urih;
01145 struct http_uri_redirect *redirect;
01146 struct sockaddr_in tmp;
01147
01148 switch (cmd) {
01149 case CLI_INIT:
01150 e->command = "http show status";
01151 e->usage =
01152 "Usage: http show status\n"
01153 " Lists status of internal HTTP engine\n";
01154 return NULL;
01155 case CLI_GENERATE:
01156 return NULL;
01157 }
01158
01159 if (a->argc != 3) {
01160 return CLI_SHOWUSAGE;
01161 }
01162 ast_cli(a->fd, "HTTP Server Status:\n");
01163 ast_cli(a->fd, "Prefix: %s\n", prefix);
01164 ast_sockaddr_to_sin(&http_desc.old_address, &tmp);
01165 if (!tmp.sin_family) {
01166 ast_cli(a->fd, "Server Disabled\n\n");
01167 } else {
01168 ast_cli(a->fd, "Server Enabled and Bound to %s:%d\n\n",
01169 ast_inet_ntoa(tmp.sin_addr), ntohs(tmp.sin_port));
01170 if (http_tls_cfg.enabled) {
01171 ast_sockaddr_to_sin(&https_desc.old_address, &tmp);
01172 ast_cli(a->fd, "HTTPS Server Enabled and Bound to %s:%d\n\n",
01173 ast_inet_ntoa(tmp.sin_addr),
01174 ntohs(tmp.sin_port));
01175 }
01176 }
01177
01178 ast_cli(a->fd, "Enabled URI's:\n");
01179 AST_RWLIST_RDLOCK(&uris);
01180 if (AST_RWLIST_EMPTY(&uris)) {
01181 ast_cli(a->fd, "None.\n");
01182 } else {
01183 AST_RWLIST_TRAVERSE(&uris, urih, entry)
01184 ast_cli(a->fd, "%s/%s%s => %s\n", prefix, urih->uri, (urih->has_subtree ? "/..." : "" ), urih->description);
01185 }
01186 AST_RWLIST_UNLOCK(&uris);
01187
01188 ast_cli(a->fd, "\nEnabled Redirects:\n");
01189 AST_RWLIST_RDLOCK(&uri_redirects);
01190 AST_RWLIST_TRAVERSE(&uri_redirects, redirect, entry)
01191 ast_cli(a->fd, " %s => %s\n", redirect->target, redirect->dest);
01192 if (AST_RWLIST_EMPTY(&uri_redirects)) {
01193 ast_cli(a->fd, " None.\n");
01194 }
01195 AST_RWLIST_UNLOCK(&uri_redirects);
01196
01197 return CLI_SUCCESS;
01198 }
01199
01200 int ast_http_reload(void)
01201 {
01202 return __ast_http_load(1);
01203 }
01204
01205 static struct ast_cli_entry cli_http[] = {
01206 AST_CLI_DEFINE(handle_show_http, "Display HTTP server status"),
01207 };
01208
01209 int ast_http_init(void)
01210 {
01211 ast_http_uri_link(&statusuri);
01212 ast_http_uri_link(&staticuri);
01213 ast_cli_register_multiple(cli_http, ARRAY_LEN(cli_http));
01214
01215 return __ast_http_load(0);
01216 }