From fc0dc1f9fb6622d0f3770dcefe072cfab0cb355b Mon Sep 17 00:00:00 2001 From: Anthony Minessale <anthony.minessale@gmail.com> Date: Tue, 27 Nov 2007 19:25:16 +0000 Subject: [PATCH] improve http support git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@6413 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- src/include/switch_utils.h | 1 + src/mod/endpoints/mod_alsa/mod_alsa.c | 2 + .../endpoints/mod_portaudio/mod_portaudio.c | 2 + src/mod/xml_int/mod_xml_rpc/mod_xml_rpc.c | 222 ++++++++++++++++-- src/switch_utils.c | 40 ++++ src/switch_xml.cpp | 15 +- 6 files changed, 261 insertions(+), 21 deletions(-) diff --git a/src/include/switch_utils.h b/src/include/switch_utils.h index 3caf62c222..f79fb3eb3d 100644 --- a/src/include/switch_utils.h +++ b/src/include/switch_utils.h @@ -56,6 +56,7 @@ SWITCH_BEGIN_EXTERN_C #endif SWITCH_DECLARE(switch_status_t) switch_b64_encode(unsigned char *in, switch_size_t ilen, unsigned char *out, switch_size_t olen); +SWITCH_DECLARE(switch_status_t) switch_b64_decode(char *in, char *out, switch_size_t olen); static inline switch_bool_t switch_is_digit_string(const char *s) { diff --git a/src/mod/endpoints/mod_alsa/mod_alsa.c b/src/mod/endpoints/mod_alsa/mod_alsa.c index 0d20897d9c..024866e74b 100644 --- a/src/mod/endpoints/mod_alsa/mod_alsa.c +++ b/src/mod/endpoints/mod_alsa/mod_alsa.c @@ -1566,6 +1566,8 @@ SWITCH_STANDARD_API(pa_cmd) stream->write_function(stream, "</pre>"); #endif + stream->write_function(stream, "Content-type: text/html\n\n"); + wcmd = switch_str_nil(switch_event_get_header(stream->event, "wcmd")); action = switch_event_get_header(stream->event, "action"); diff --git a/src/mod/endpoints/mod_portaudio/mod_portaudio.c b/src/mod/endpoints/mod_portaudio/mod_portaudio.c index b46e636609..413ddd0765 100644 --- a/src/mod/endpoints/mod_portaudio/mod_portaudio.c +++ b/src/mod/endpoints/mod_portaudio/mod_portaudio.c @@ -1673,6 +1673,8 @@ SWITCH_STANDARD_API(pa_cmd) if (http) { + stream->write_function(stream, "Content-type: text/html\n\n"); + #if 0 switch_event_header_t *hp; stream->write_function(stream, "<pre>"); diff --git a/src/mod/xml_int/mod_xml_rpc/mod_xml_rpc.c b/src/mod/xml_int/mod_xml_rpc/mod_xml_rpc.c index de29b5ea64..a5104b3211 100644 --- a/src/mod/xml_int/mod_xml_rpc/mod_xml_rpc.c +++ b/src/mod/xml_int/mod_xml_rpc/mod_xml_rpc.c @@ -41,6 +41,7 @@ #include <xmlrpc-c/abyss.h> #include <xmlrpc-c/server.h> #include <xmlrpc-c/server_abyss.h> +#include "../../libs/xmlrpc-c/lib/abyss/src/token.h" SWITCH_MODULE_LOAD_FUNCTION(mod_xml_rpc_load); SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_xml_rpc_shutdown); @@ -137,27 +138,187 @@ static switch_status_t http_stream_write(switch_stream_handle_t *handle, const c } -abyss_bool HandleHook(TSession * r) +static abyss_bool http_directory_auth(TSession *r, char *domain_name) { - char *m = "text/html"; + char *p, *x; + char z[80], t[80]; + char user[512]; + char *pass; + const char *mypass1 = NULL, *mypass2 = NULL; + switch_xml_t x_domain, x_domain_root = NULL, x_user, x_params, x_param; + + p = RequestHeaderValue(r, "authorization"); + + if (p) { + NextToken(&p); + x = GetToken(&p); + if (x) { + if (!strcasecmp(x,"basic")) { + + + NextToken(&p); + switch_b64_decode(p, user, sizeof(user)); + if ((pass = strchr(user, ':'))) { + *pass++ = '\0'; + } + + if (switch_xml_locate_user(user, domain_name, NULL, &x_domain_root, &x_domain, &x_user, NULL) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "can't find user [%s@%s]\n", user, domain_name); + goto fail; + } + + if (!(x_params = switch_xml_child(x_user, "params"))) { + goto authed; + } + + + for (x_param = switch_xml_child(x_params, "param"); x_param; x_param = x_param->next) { + const char *var = switch_xml_attr_soft(x_param, "name"); + const char *val = switch_xml_attr_soft(x_param, "value"); + + if (!strcasecmp(var, "password")) { + mypass1 = val; + } else if (!strcasecmp(var, "vm-password")) { + mypass2 = val; + } else if (!strncasecmp(var, "http-", 5)) { + ResponseAddField(r, (char *)var, (char *)val); + } + } + + sprintf(z, "%s:%s", user, mypass1); + Base64Encode(z, t); + + if (!strcmp(p, t)) { + r->user=strdup(user); + goto authed; + } + + sprintf(z, "%s:%s", user, mypass2); + Base64Encode(z, t); + + if (!strcmp(p, t)) { + r->user=strdup(user); + goto authed; + } + + goto fail; + + + authed: + + if (x_domain_root) { + switch_xml_free(x_domain_root); + } + + return TRUE; + } + } + } + + fail: + + if (x_domain_root) { + switch_xml_free(x_domain_root); + } + + sprintf(z, "Basic realm=\"%s\"", domain_name); + ResponseAddField(r, "WWW-Authenticate", z); + ResponseStatus(r, 401); + return FALSE; +} + +abyss_bool auth_hook(TSession * r) +{ + char *domain_name, *e; + abyss_bool ret = FALSE; + + + + if (!strncmp(r->uri, "/domains/", 9)) { + domain_name = strdup(r->uri + 9); + assert(domain_name); + + if ((e = strchr(domain_name, '/'))) { + *e++ = '\0'; + } + + ret = !http_directory_auth(r, domain_name); + + free(domain_name); + } else { + if (globals.realm) { + if (!RequestAuth(r, globals.realm, globals.user, globals.pass)) { + ret = TRUE; + } + } + } + + return ret; +} + +abyss_bool handler_hook(TSession * r) +{ + //char *mime = "text/html"; + char buf[512] = "HTTP/1.1 200 OK\n"; switch_stream_handle_t stream = { 0 }; char *command; + int i, j = 0; + TTableItem *ti; + char *dup = NULL; stream.data = r; stream.write_function = http_stream_write; - if (globals.realm) { - if (!RequestAuth(r, globals.realm, globals.user, globals.pass)) { - return TRUE; + if ((command = strstr(r->uri, "/api/"))) { + command += 5; + } else { + return FALSE; + } + + for (i=0;i<r->response_headers.size;i++) { + ti=&r->response_headers.item[i]; + if (!strcasecmp(ti->name, "http-allowed-api")) { + int argc, x; + char *argv[256] = { 0 }; + j++; + + if (!strcasecmp(ti->value, "any")) { + goto auth; + } + + if (!strcasecmp(ti->value, "none")) { + goto unauth; + } + + dup = strdup(ti->value); + argc = switch_separate_string(dup, ',', argv, (sizeof(argv) / sizeof(argv[0]))); + + for (x = 0; x < argc; x++) { + if (!strcasecmp(command, argv[x])) { + goto auth; + } + } + + goto unauth; } } - - - if (strncmp(r->uri, "/api/", 5)) { - return FALSE; + if (r->user && !j) { + goto unauth; } + goto auth; + + unauth: + ResponseStatus(r, 403); + ResponseError(r); + switch_safe_free(dup); + + return TRUE; + + auth: + + if (switch_event_create(&stream.event, SWITCH_EVENT_API) == SWITCH_STATUS_SUCCESS) { const char * const content_length = RequestHeaderValue(r, "content-length"); @@ -258,14 +419,40 @@ abyss_bool HandleHook(TSession * r) } } - command = r->uri + 5; - ResponseChunked(r); - ResponseStatus(r, 200); - ResponseContentType(r, m); - ResponseWrite(r); - switch_api_execute(command, r->query, NULL, &stream); - HTTPWriteEnd(r); + + //ResponseChunked(r); + + //ResponseContentType(r, mime); + //ResponseWrite(r); + + HTTPWrite(r, buf, (uint32_t) strlen(buf)); + + /* generation of the date field */ + if (DateToString(&r->date, buf)) { + ResponseAddField(r,"Date", buf); + } + + /* Generation of the server field */ + ResponseAddField(r,"Server", SERVER_HVERSION); + + for (i=0;i<r->response_headers.size;i++) { + ti=&r->response_headers.item[i]; + ConnWrite(r->conn,ti->name,strlen(ti->name)); + ConnWrite(r->conn,": ",2); + ConnWrite(r->conn,ti->value,strlen(ti->value)); + ConnWrite(r->conn,CRLF,2); + } + + + if (switch_api_execute(command, r->query, NULL, &stream) == SWITCH_STATUS_SUCCESS) { + r->done = TRUE; + } else { + ResponseStatus(r, 404); + ResponseError(r); + } + + //HTTPWriteEnd(r); return TRUE; } @@ -387,8 +574,9 @@ SWITCH_MODULE_RUNTIME_FUNCTION(mod_xml_rpc_runtime) return SWITCH_STATUS_TERM; } - ServerAddHandler(&abyssServer, HandleHook); + ServerAddHandler(&abyssServer, handler_hook); + ServerAddHandler(&abyssServer, auth_hook); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Starting HTTP Port %d, DocRoot [%s]\n", globals.port, SWITCH_GLOBAL_dirs.htdocs_dir); while (globals.running) { ServerRunOnce2(&abyssServer, ABYSS_FOREGROUND); diff --git a/src/switch_utils.c b/src/switch_utils.c index 52e7a8876e..9274be47bc 100644 --- a/src/switch_utils.c +++ b/src/switch_utils.c @@ -91,6 +91,46 @@ SWITCH_DECLARE(switch_status_t) switch_b64_encode(unsigned char *in, switch_size } +SWITCH_DECLARE(switch_status_t) switch_b64_decode(char *in, char *out, switch_size_t olen) +{ + + char l64[256]; + int b = 0, c, l = 0, i; + char *ip, *op = out; + size_t ol = 0; + + for (i=0; i<256; i++) { + l64[i] = -1; + } + + for (i=0; i<64; i++) { + l64[(int)switch_b64_table[i]] = i; + } + + for (ip = in; ip && *ip; ip++) { + c = l64[(int)*ip]; + if (c == -1) { + continue; + } + + b = (b << 6) + c; + l += 6; + + while (l >= 8) { + op[ol++] = (b >> (l -= 8)) % 256; + if (ol >= olen -2) { + goto end; + } + } + } + + end: + + op[ol++] = '\0'; + + return SWITCH_STATUS_SUCCESS; +} + static int write_buf(int fd, const char *buf) { diff --git a/src/switch_xml.cpp b/src/switch_xml.cpp index 827e0b6757..6e5cad4f70 100644 --- a/src/switch_xml.cpp +++ b/src/switch_xml.cpp @@ -1316,6 +1316,7 @@ SWITCH_DECLARE(switch_status_t) switch_xml_locate_user(const char *user_name, } else { snprintf(params, sizeof(params), "user=%s&domain=%s&ip=%s", switch_str_nil(user_name), switch_str_nil(domain_name), switch_str_nil(ip)); + xtra_params = ""; } if ((status = switch_xml_locate_domain(domain_name, params, root, domain)) != SWITCH_STATUS_SUCCESS) { return status; @@ -1328,11 +1329,17 @@ SWITCH_DECLARE(switch_status_t) switch_xml_locate_user(const char *user_name, } if (user_name) { - if (!(*user = switch_xml_find_child(*domain, "user", "id", user_name)) && strstr(xtra_params, "mailbox") && - !(*user = switch_xml_find_child(*domain, "user", "mailbox", user_name))) { - return SWITCH_STATUS_FALSE; + + if (strstr(xtra_params, "mailbox")) { + if ((*user = switch_xml_find_child(*domain, "user", "mailbox", user_name))) { + return SWITCH_STATUS_SUCCESS; + } } - return SWITCH_STATUS_SUCCESS; + + if ((*user = switch_xml_find_child(*domain, "user", "id", user_name))) { + return SWITCH_STATUS_SUCCESS; + } + } return SWITCH_STATUS_FALSE;