diff --git a/src/include/switch_channel.h b/src/include/switch_channel.h index 94eb9e571d..844013361e 100644 --- a/src/include/switch_channel.h +++ b/src/include/switch_channel.h @@ -591,7 +591,10 @@ SWITCH_DECLARE(void) switch_channel_event_set_extended_data(_In_ switch_channel_ \return the original string if no expansion takes place otherwise a new string that must be freed \note it's necessary to test if the return val is the same as the input and free the string if it is not. */ -SWITCH_DECLARE(char *) switch_channel_expand_variables(_In_ switch_channel_t *channel, _In_ const char *in); +SWITCH_DECLARE(char *) switch_channel_expand_variables_check(switch_channel_t *channel, const char *in, switch_event_t *var_list, switch_event_t *api_list); +#define switch_channel_expand_variables(_channel, _in) switch_channel_expand_variables_check(_channel, _in, NULL, NULL) + + SWITCH_DECLARE(char *) switch_channel_build_param_string(_In_ switch_channel_t *channel, _In_opt_ switch_caller_profile_t *caller_profile, _In_opt_ const char *prefix); SWITCH_DECLARE(switch_status_t) switch_channel_set_timestamps(_In_ switch_channel_t *channel); diff --git a/src/include/switch_event.h b/src/include/switch_event.h index 23cd0825b5..c77e4aebb4 100644 --- a/src/include/switch_event.h +++ b/src/include/switch_event.h @@ -104,7 +104,8 @@ struct switch_event { typedef enum { EF_UNIQ_HEADERS = (1 << 0), - EF_NO_CHAT_EXEC = (1 << 1) + EF_NO_CHAT_EXEC = (1 << 1), + EF_DEFAULT_ALLOW = (1 << 2) } switch_event_flag_t; @@ -329,7 +330,8 @@ SWITCH_DECLARE(switch_status_t) switch_event_add_body(switch_event_t *event, con SWITCH_DECLARE(switch_status_t) switch_event_set_body(switch_event_t *event, const char *body); -SWITCH_DECLARE(char *) switch_event_expand_headers(switch_event_t *event, const char *in); +SWITCH_DECLARE(char *) switch_event_expand_headers_check(switch_event_t *event, const char *in, switch_event_t *var_list, switch_event_t *api_list); +#define switch_event_expand_headers(_event, _in) switch_event_expand_headers_check(_event, _in, NULL, NULL) SWITCH_DECLARE(switch_status_t) switch_event_create_pres_in_detailed(_In_z_ char *file, _In_z_ char *func, _In_ int line, _In_z_ const char *proto, _In_z_ const char *login, @@ -399,7 +401,7 @@ SWITCH_DECLARE(void) switch_event_deliver(switch_event_t **event); #define switch_event_fire_data(event, data) switch_event_fire_detailed(__FILE__, (const char * )__SWITCH_FUNC__, __LINE__, event, data) SWITCH_DECLARE(char *) switch_event_build_param_string(switch_event_t *event, const char *prefix, switch_hash_t *vars_map); - +SWITCH_DECLARE(int) switch_event_check_permission_list(switch_event_t *list, const char *name); ///\} SWITCH_END_EXTERN_C diff --git a/src/mod/applications/mod_httapi/httapi.conf.xml b/src/mod/applications/mod_httapi/httapi.conf.xml index dfd7d692fb..c2fe584a02 100644 --- a/src/mod/applications/mod_httapi/httapi.conf.xml +++ b/src/mod/applications/mod_httapi/httapi.conf.xml @@ -26,7 +26,26 @@ - + + + + + + + + + + @@ -36,7 +55,21 @@ - + + + + + diff --git a/src/mod/applications/mod_httapi/mod_httapi.c b/src/mod/applications/mod_httapi/mod_httapi.c index 4465eb6162..6392167ec5 100644 --- a/src/mod/applications/mod_httapi/mod_httapi.c +++ b/src/mod/applications/mod_httapi/mod_httapi.c @@ -38,6 +38,7 @@ SWITCH_MODULE_DEFINITION(mod_httapi, mod_httapi_load, mod_httapi_shutdown, NULL) typedef struct profile_perms_s { switch_byte_t set_params; switch_byte_t set_vars; + switch_byte_t get_vars; switch_byte_t extended_data; switch_byte_t execute_apps; switch_byte_t expand_vars; @@ -99,6 +100,14 @@ typedef struct client_profile_s { int default_allow; } dial_params; + struct { + switch_event_t *expand_var_list; + switch_event_t *set_var_list; + switch_event_t *get_var_list; + switch_event_t *api_list; + int default_allow; + } var_params; + } client_profile_t; #define HTTAPI_MAX_API_BYTES 1024 * 1024 @@ -259,6 +268,26 @@ static void console_clean_log(const char *level_str, const char *msg) switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, level, "%s", switch_str_nil(msg)); } +static switch_status_t parse_get_var(const char *tag_name, client_t *client, switch_xml_t tag, const char *body) +{ + const char *var = switch_xml_attr(tag, "name"); + const char *perm = switch_xml_attr(tag, "permanent"); + + + if (switch_event_check_permission_list(client->profile->var_params.get_var_list, var)) { + const char *vval = switch_channel_get_variable(client->channel, var); + if (vval) { + switch_event_add_header_string(perm ? client->params : client->one_time_params, SWITCH_STACK_BOTTOM, var, vval); + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "variable %s permission denied!\n", var); + return SWITCH_STATUS_FALSE; + } + + return SWITCH_STATUS_SUCCESS; + +} + static switch_status_t parse_continue(const char *tag_name, client_t *client, switch_xml_t tag, const char *body) { @@ -648,29 +677,11 @@ static switch_status_t parse_sms(const char *tag_name, client_t *client, switch_ static int check_app_perm(client_t *client, const char *app_name) { - const char *v; - int r = 0; - if (!client->profile->perms.execute_apps) { return 0; } - if (!client->profile->dial_params.app_list) { - return 1; - } - - if ((v = switch_event_get_header(client->profile->dial_params.app_list, app_name))) { - if (*v == 'd') { - r = 0; - } else { - r = 1; - } - } else { - r = client->profile->dial_params.default_allow; - } - - - return r; + return switch_event_check_permission_list(client->profile->dial_params.app_list, app_name); } static switch_status_t parse_execute(const char *tag_name, client_t *client, switch_xml_t tag, const char *body) @@ -997,7 +1008,11 @@ static switch_status_t parse_xml(client_t *client) if (zstr(val)) { val = NULL; } - switch_channel_set_variable(client->channel, tag->name, val); + if (switch_event_check_permission_list(client->profile->var_params.set_var_list, tag->name)) { + switch_channel_set_variable(client->channel, tag->name, val); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "variable %s permission denied!\n", tag->name); + } } tag = tag->sibling; } @@ -1019,7 +1034,8 @@ static switch_status_t parse_xml(client_t *client) if (tag->txt && client->profile->perms.expand_vars) { switch_channel_get_variables(client->channel, &templ_data); switch_event_merge(templ_data, client->params); - expanded = switch_event_expand_headers(templ_data, tag->txt); + expanded = switch_event_expand_headers_check(templ_data, tag->txt, + client->profile->var_params.expand_var_list, client->profile->var_params.api_list); switch_event_destroy(&templ_data); } @@ -1639,6 +1655,60 @@ static switch_status_t do_config(void) profile->perms.set_params = switch_true(val); } else if (!strcasecmp(var, "set-vars")) { profile->perms.set_vars = switch_true(val); + + if (profile->perms.set_vars) { + switch_xml_t x_list, x_var; + if ((x_list = switch_xml_child(param, "variable-list"))) { + char *var = (char *) switch_xml_attr_soft(param, "default"); + + profile->var_params.default_allow = (var && !strcasecmp(var, "allow")); + switch_event_create(&profile->var_params.set_var_list, SWITCH_EVENT_CLONE); + profile->var_params.set_var_list->flags |= EF_UNIQ_HEADERS; + if (profile->var_params.default_allow) { + profile->var_params.set_var_list->flags |= EF_DEFAULT_ALLOW; + } + + + for (x_var = switch_xml_child(x_list, "variable"); x_var; x_var = x_var->next) { + const char *name = switch_xml_attr(x_var, "name"); + const char *type = switch_xml_attr(x_var, "type"); + + if (zstr(type)) type = profile->var_params.default_allow ? "deny" : "allow"; + + if (name) { + switch_event_add_header_string(profile->var_params.set_var_list, SWITCH_STACK_BOTTOM, name, type); + } + } + } + } + } else if (!strcasecmp(var, "get-vars")) { + profile->perms.get_vars = switch_true(val); + + if (profile->perms.get_vars) { + switch_xml_t x_list, x_var; + if ((x_list = switch_xml_child(param, "variable-list"))) { + char *var = (char *) switch_xml_attr_soft(param, "default"); + + profile->var_params.default_allow = (var && !strcasecmp(var, "allow")); + switch_event_create(&profile->var_params.get_var_list, SWITCH_EVENT_CLONE); + profile->var_params.get_var_list->flags |= EF_UNIQ_HEADERS; + if (profile->var_params.default_allow) { + profile->var_params.get_var_list->flags |= EF_DEFAULT_ALLOW; + } + + + for (x_var = switch_xml_child(x_list, "variable"); x_var; x_var = x_var->next) { + const char *name = switch_xml_attr(x_var, "name"); + const char *type = switch_xml_attr(x_var, "type"); + + if (zstr(type)) type = profile->var_params.default_allow ? "deny" : "allow"; + + if (name) { + switch_event_add_header_string(profile->var_params.get_var_list, SWITCH_STACK_BOTTOM, name, type); + } + } + } + } } else if (!strcasecmp(var, "extended-data")) { profile->perms.extended_data = switch_true(val); } else if (!strcasecmp(var, "execute-apps")) { @@ -1652,6 +1722,10 @@ static switch_status_t do_config(void) profile->dial_params.default_allow = (var && !strcasecmp(var, "allow")); switch_event_create(&profile->dial_params.app_list, SWITCH_EVENT_CLONE); profile->dial_params.app_list->flags |= EF_UNIQ_HEADERS; + if (profile->dial_params.default_allow) { + profile->dial_params.app_list->flags |= EF_DEFAULT_ALLOW; + } + for (x_app = switch_xml_child(x_list, "application"); x_app; x_app = x_app->next) { const char *name = switch_xml_attr(x_app, "name"); @@ -1668,6 +1742,56 @@ static switch_status_t do_config(void) } else if (!strcasecmp(var, "expand-vars")) { profile->perms.expand_vars = switch_true(val); + + if (profile->perms.expand_vars) { + switch_xml_t x_list, x_var, x_api; + if ((x_list = switch_xml_child(param, "variable-list"))) { + char *var = (char *) switch_xml_attr_soft(param, "default"); + + profile->var_params.default_allow = (var && !strcasecmp(var, "allow")); + switch_event_create(&profile->var_params.expand_var_list, SWITCH_EVENT_CLONE); + profile->var_params.expand_var_list->flags |= EF_UNIQ_HEADERS; + if (profile->var_params.default_allow) { + profile->var_params.expand_var_list->flags |= EF_DEFAULT_ALLOW; + } + + + for (x_var = switch_xml_child(x_list, "variable"); x_var; x_var = x_var->next) { + const char *name = switch_xml_attr(x_var, "name"); + const char *type = switch_xml_attr(x_var, "type"); + + if (zstr(type)) type = profile->var_params.default_allow ? "deny" : "allow"; + + if (name) { + switch_event_add_header_string(profile->var_params.expand_var_list, SWITCH_STACK_BOTTOM, name, type); + } + } + } + + if ((x_list = switch_xml_child(param, "api-list"))) { + char *api = (char *) switch_xml_attr_soft(param, "default"); + + profile->var_params.default_allow = (api && !strcasecmp(api, "allow")); + switch_event_create(&profile->var_params.api_list, SWITCH_EVENT_CLONE); + profile->var_params.api_list->flags |= EF_UNIQ_HEADERS; + if (profile->var_params.default_allow) { + profile->var_params.api_list->flags |= EF_DEFAULT_ALLOW; + } + + + for (x_api = switch_xml_child(x_list, "api"); x_api; x_api = x_api->next) { + const char *name = switch_xml_attr(x_api, "name"); + const char *type = switch_xml_attr(x_api, "type"); + + if (zstr(type)) type = profile->var_params.default_allow ? "deny" : "allow"; + + if (name) { + switch_event_add_header_string(profile->var_params.api_list, SWITCH_STACK_BOTTOM, name, type); + } + } + } + } + } else if (!strcasecmp(var, "dial")) { profile->perms.dial.enabled = switch_true(val); } else if (!strcasecmp(var, "dial-set-context")) { @@ -2465,6 +2589,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_httapi_load) bind_parser("break", parse_break); bind_parser("log", parse_log); bind_parser("continue", parse_continue); + bind_parser("setVar", parse_get_var); if (do_config() != SWITCH_STATUS_SUCCESS) { return SWITCH_STATUS_FALSE; @@ -2498,6 +2623,9 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_httapi_shutdown) switch_hash_this(hi, &vvar, NULL, &val); profile = (client_profile_t *) val; switch_event_destroy(&profile->dial_params.app_list); + switch_event_destroy(&profile->var_params.expand_var_list); + switch_event_destroy(&profile->var_params.set_var_list); + switch_event_destroy(&profile->var_params.get_var_list); } diff --git a/src/mod/applications/mod_httapi/mod_httapi_doc.txt b/src/mod/applications/mod_httapi/mod_httapi_doc.txt index e865209682..c8121379bc 100644 --- a/src/mod/applications/mod_httapi/mod_httapi_doc.txt +++ b/src/mod/applications/mod_httapi/mod_httapi_doc.txt @@ -249,6 +249,15 @@ action : Change url to submit to. temp-action : Change url to submit to. just for the next loop. + + : Get a Channel variable (depends on permissions) + +ATTRS: +action : Change url to submit to. +temp-action : Change url to submit to. just for the next loop. +permanent : Add as a permanent param or just once. + + diff --git a/src/switch_channel.c b/src/switch_channel.c index 5620681027..435c2a3929 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -151,6 +151,9 @@ struct switch_channel { opaque_channel_flag_t opaque_flags; switch_originator_type_t last_profile_type; switch_caller_extension_t *queued_extension; + switch_event_t *app_list; + switch_event_t *api_list; + switch_event_t *var_list; }; @@ -578,6 +581,9 @@ SWITCH_DECLARE(void) switch_channel_uninit(switch_channel_t *channel) } switch_mutex_lock(channel->profile_mutex); switch_event_destroy(&channel->variables); + switch_event_destroy(&channel->api_list); + switch_event_destroy(&channel->var_list); + switch_event_destroy(&channel->app_list); switch_mutex_unlock(channel->profile_mutex); } @@ -3287,7 +3293,7 @@ SWITCH_DECLARE(switch_status_t) switch_channel_perform_answer(switch_channel_t * memset(c, 0, olen - cpos);\ }} \ -SWITCH_DECLARE(char *) switch_channel_expand_variables(switch_channel_t *channel, const char *in) +SWITCH_DECLARE(char *) switch_channel_expand_variables_check(switch_channel_t *channel, const char *in, switch_event_t *var_list, switch_event_t *api_list) { char *p, *c = NULL; char *data, *indup, *endof_indup; @@ -3425,7 +3431,7 @@ SWITCH_DECLARE(char *) switch_channel_expand_variables(switch_channel_t *channel char *ptr; int idx = -1; - if ((expanded = switch_channel_expand_variables(channel, (char *) vname)) == vname) { + if ((expanded = switch_channel_expand_variables_check(channel, (char *) vname, var_list, api_list)) == vname) { expanded = NULL; } else { vname = expanded; @@ -3446,6 +3452,10 @@ SWITCH_DECLARE(char *) switch_channel_expand_variables(switch_channel_t *channel } if ((sub_val = (char *) switch_channel_get_variable_dup(channel, vname, SWITCH_TRUE, idx))) { + if (var_list && !switch_event_check_permission_list(var_list, vname)) { + sub_val = "INVALID"; + } + if (offset || ooffset) { cloned_sub_val = strdup(sub_val); switch_assert(cloned_sub_val); @@ -3478,24 +3488,29 @@ SWITCH_DECLARE(char *) switch_channel_expand_variables(switch_channel_t *channel if (stream.data) { char *expanded_vname = NULL; - - if ((expanded_vname = switch_channel_expand_variables(channel, (char *) vname)) == vname) { + + if ((expanded_vname = switch_channel_expand_variables_check(channel, (char *) vname, var_list, api_list)) == vname) { expanded_vname = NULL; } else { vname = expanded_vname; } - if ((expanded = switch_channel_expand_variables(channel, vval)) == vval) { + if ((expanded = switch_channel_expand_variables_check(channel, vval, var_list, api_list)) == vval) { expanded = NULL; } else { vval = expanded; } - if (switch_api_execute(vname, vval, channel->session, &stream) == SWITCH_STATUS_SUCCESS) { - func_val = stream.data; - sub_val = func_val; + if (api_list && !switch_event_check_permission_list(api_list, vname)) { + func_val = "INVALID"; + sub_val = "INVALID"; } else { - free(stream.data); + if (switch_api_execute(vname, vval, channel->session, &stream) == SWITCH_STATUS_SUCCESS) { + func_val = stream.data; + sub_val = func_val; + } else { + free(stream.data); + } } switch_safe_free(expanded); diff --git a/src/switch_event.c b/src/switch_event.c index fcb913f2a5..f17ec08e5c 100644 --- a/src/switch_event.c +++ b/src/switch_event.c @@ -1981,7 +1981,7 @@ if ((dp = realloc(data, olen))) {\ memset(c, 0, olen - cpos);\ }} \ -SWITCH_DECLARE(char *) switch_event_expand_headers(switch_event_t *event, const char *in) +SWITCH_DECLARE(char *) switch_event_expand_headers_check(switch_event_t *event, const char *in, switch_event_t *var_list, switch_event_t *api_list) { char *p, *c = NULL; char *data, *indup, *endof_indup; @@ -2121,7 +2121,7 @@ SWITCH_DECLARE(char *) switch_event_expand_headers(switch_event_t *event, const char *ptr; int idx = -1; - if ((expanded = switch_event_expand_headers(event, (char *) vname)) == vname) { + if ((expanded = switch_event_expand_headers_check(event, (char *) vname, var_list, api_list)) == vname) { expanded = NULL; } else { vname = expanded; @@ -2145,6 +2145,11 @@ SWITCH_DECLARE(char *) switch_event_expand_headers(switch_event_t *event, const if ((gvar = switch_core_get_variable_dup(vname))) { sub_val = gvar; } + + if (var_list && !switch_event_check_permission_list(var_list, vname)) { + sub_val = "INVALID"; + } + } if (offset || ooffset) { @@ -2175,23 +2180,28 @@ SWITCH_DECLARE(char *) switch_event_expand_headers(switch_event_t *event, const if (stream.data) { char *expanded_vname = NULL; - if ((expanded_vname = switch_event_expand_headers(event, (char *) vname)) == vname) { + if ((expanded_vname = switch_event_expand_headers_check(event, (char *) vname, var_list, api_list)) == vname) { expanded_vname = NULL; } else { vname = expanded_vname; } - if ((expanded = switch_event_expand_headers(event, vval)) == vval) { + if ((expanded = switch_event_expand_headers_check(event, vval, var_list, api_list)) == vval) { expanded = NULL; } else { vval = expanded; } - if (switch_api_execute(vname, vval, NULL, &stream) == SWITCH_STATUS_SUCCESS) { - func_val = stream.data; - sub_val = func_val; + if (api_list && !switch_event_check_permission_list(api_list, vname)) { + func_val = "INVALID"; + sub_val = "INVALID"; } else { - free(stream.data); + if (switch_api_execute(vname, vval, NULL, &stream) == SWITCH_STATUS_SUCCESS) { + func_val = stream.data; + sub_val = func_val; + } else { + free(stream.data); + } } switch_safe_free(expanded); @@ -2330,6 +2340,32 @@ SWITCH_DECLARE(char *) switch_event_build_param_string(switch_event_t *event, co return stream.data; } +SWITCH_DECLARE(int) switch_event_check_permission_list(switch_event_t *list, const char *name) +{ + const char *v; + int r = 0; + int default_allow = switch_test_flag(list, EF_DEFAULT_ALLOW); + + if (!list->headers) { + return default_allow; + } + + if ((v = switch_event_get_header(list, name))) { + if (*v == 'd') { + r = 0; + } else { + r = 1; + } + } else { + r = default_allow; + } + + return r; +} + + + + /* For Emacs: * Local Variables: * mode:c