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