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