Index: include/asterisk/module.h =================================================================== --- include/asterisk/module.h (revision 427353) +++ include/asterisk/module.h (working copy) @@ -476,7 +476,7 @@ * \retval 0 success * \retval -1 failure. */ -#define ast_register_application(app, execute, synopsis, description) ast_register_application2(app, execute, synopsis, description, ast_module_info->self) +#define ast_register_application(app, execute, synopsis, description) ast_register_application2(app, execute, synopsis, description, 0, ast_module_info->self) /*! * \brief Register an application using XML documentation. @@ -494,7 +494,19 @@ */ #define ast_register_application_xml(app, execute) ast_register_application(app, execute, NULL, NULL) +/*! + * \brief Register an application which requires escalated privileges. + * + * Examples are System(), TrySystem(), AGI(), EAGI(), DeadAGI(), Monitor() (via MONITOR_EXEC) and + * MixMonitor() which can execute commands as well as Record() and ConfBridge() which can create + * files. + */ +#define ast_register_application_escalating(app, execute, synopsis, description) \ + ast_register_application2(app, execute, synopsis, description, 1, ast_module_info->self); +#define ast_register_application_escalating_xml(app, execute) \ + ast_register_application2(app, execute, NULL, NULL, 1, ast_module_info->self); + /*! * \brief Register an application. * @@ -514,7 +526,7 @@ * \retval -1 failure. */ int ast_register_application2(const char *app, int (*execute)(struct ast_channel *, const char *), - const char *synopsis, const char *description, void *mod); + const char *synopsis, const char *description, int escalates, void *mod); /*! * \brief Unregister an application Index: funcs/func_db.c =================================================================== --- funcs/func_db.c (revision 427353) +++ funcs/func_db.c (working copy) @@ -351,7 +351,7 @@ { int res = 0; - res |= ast_custom_function_register(&db_function); + res |= ast_custom_function_register_escalating(&db_function); res |= ast_custom_function_register(&db_exists_function); res |= ast_custom_function_register_escalating(&db_delete_function, AST_CFE_READ); res |= ast_custom_function_register(&db_keys_function); Index: funcs/func_strings.c =================================================================== --- funcs/func_strings.c (revision 427353) +++ funcs/func_strings.c (working copy) @@ -1988,7 +1988,7 @@ res |= ast_custom_function_register(&len_function); res |= ast_custom_function_register(&strftime_function); res |= ast_custom_function_register(&strptime_function); - res |= ast_custom_function_register(&eval_function); + res |= ast_custom_function_register_escalating(&eval_function, AST_CFE_READ); res |= ast_custom_function_register(&keypadhash_function); res |= ast_custom_function_register(&hashkeys_function); res |= ast_custom_function_register(&hash_function); Index: main/features.c =================================================================== --- main/features.c (revision 427353) +++ main/features.c (working copy) @@ -1178,7 +1178,7 @@ if (res) { return res; } - res |= ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL); + res |= ast_register_application2(app_bridge, bridge_exec, NULL, NULL, 0, NULL); res |= ast_manager_register_xml_core("Bridge", EVENT_FLAG_CALL, action_bridge); if (res) { Index: main/ccss.c =================================================================== --- main/ccss.c (revision 427353) +++ main/ccss.c (working copy) @@ -4674,8 +4674,8 @@ if (ast_sched_start_thread(cc_sched_context)) { return -1; } - res = ast_register_application2(ccreq_app, ccreq_exec, NULL, NULL, NULL); - res |= ast_register_application2(cccancel_app, cccancel_exec, NULL, NULL, NULL); + res = ast_register_application2(ccreq_app, ccreq_exec, NULL, NULL, 0, NULL); + res |= ast_register_application2(cccancel_app, cccancel_exec, NULL, NULL, 0, NULL); res |= ast_cc_monitor_register(&generic_monitor_cbs); res |= ast_cc_agent_register(&generic_agent_callbacks); Index: main/manager.c =================================================================== --- main/manager.c (revision 427353) +++ main/manager.c (working copy) @@ -1854,19 +1854,6 @@ { 0, "none" }, }; -/*! \brief Checks to see if a string which can be used to evaluate functions should be rejected */ -static int function_capable_string_allowed_with_auths(const char *evaluating, int writepermlist) -{ - if (!(writepermlist & EVENT_FLAG_SYSTEM) - && ( - strstr(evaluating, "SHELL") || /* NoOp(${SHELL(rm -rf /)}) */ - strstr(evaluating, "EVAL") /* NoOp(${EVAL(${some_var_containing_SHELL})}) */ - )) { - return 0; - } - return 1; -} - /*! \brief Convert authority code to a list of options for a user. This will only * display those authority codes that have an explicit match on authority */ static const char *user_authority_to_str(int authority, struct ast_str **res) @@ -4251,12 +4238,6 @@ return 0; } - /* We don't want users with insufficient permissions using certain functions. */ - if (!(function_capable_string_allowed_with_auths(varname, s->session->writeperm))) { - astman_send_error(s, m, "GetVar Access Forbidden: Variable"); - return 0; - } - if (!ast_strlen_zero(name)) { if (!(c = ast_channel_get_by_name(name))) { astman_send_error(s, m, "No such channel"); @@ -4428,11 +4409,6 @@ all_variables = ast_true(all_chan_variables); } - if (!(function_capable_string_allowed_with_auths(variables, s->session->writeperm))) { - astman_send_error(s, m, "Status Access Forbidden: Variables"); - return 0; - } - if (all) { if (!(it_chans = ast_channel_iterator_all_new())) { astman_send_error(s, m, "Memory Allocation Failure"); @@ -4921,11 +4897,16 @@ }; if (!ast_strlen_zero(in->app)) { - res = ast_pbx_outgoing_app(in->tech, in->cap, in->data, - in->timeout, in->app, in->appdata, &reason, 1, - S_OR(in->cid_num, NULL), - S_OR(in->cid_name, NULL), - in->vars, in->account, &chan, &assignedids); + if (ast_thread_inhibit_escalations()) { + ast_log(LOG_ERROR, "Failed to inhibit privilege escalations; aborting originate\n"); + res = -1; + } else { + res = ast_pbx_outgoing_app(in->tech, in->cap, in->data, + in->timeout, in->app, in->appdata, &reason, 1, + S_OR(in->cid_num, NULL), + S_OR(in->cid_name, NULL), + in->vars, in->account, &chan, &assignedids); + } } else { res = ast_pbx_outgoing_exten(in->tech, in->cap, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1, @@ -5287,31 +5268,6 @@ ast_format_cap_update_by_allow_disallow(cap, codecs, 1); } - if (!ast_strlen_zero(app) && s->session) { - int bad_appdata = 0; - /* To run the System application (or anything else that goes to - * shell), you must have the additional System privilege */ - if (!(s->session->writeperm & EVENT_FLAG_SYSTEM) - && ( - strcasestr(app, "system") || /* System(rm -rf /) - TrySystem(rm -rf /) */ - strcasestr(app, "exec") || /* Exec(System(rm -rf /)) - TryExec(System(rm -rf /)) */ - strcasestr(app, "agi") || /* AGI(/bin/rm,-rf /) - EAGI(/bin/rm,-rf /) */ - strcasestr(app, "mixmonitor") || /* MixMonitor(blah,,rm -rf) */ - strcasestr(app, "externalivr") || /* ExternalIVR(rm -rf) */ - (strstr(appdata, "SHELL") && (bad_appdata = 1)) || /* NoOp(${SHELL(rm -rf /)}) */ - (strstr(appdata, "EVAL") && (bad_appdata = 1)) /* NoOp(${EVAL(${some_var_containing_SHELL})}) */ - )) { - char error_buf[64]; - snprintf(error_buf, sizeof(error_buf), "Originate Access Forbidden: %s", bad_appdata ? "Data" : "Application"); - astman_send_error(s, m, error_buf); - res = 0; - goto fast_orig_cleanup; - } - } - /* Check early if the extension exists. If not, we need to bail out here. */ if (exten && context && pi) { if (! ast_exists_extension(NULL, context, exten, pi, l)) { Index: main/message.c =================================================================== --- main/message.c (revision 427353) +++ main/message.c (working copy) @@ -1513,7 +1513,7 @@ res |= __ast_custom_function_register(&msg_function, NULL); res |= __ast_custom_function_register(&msg_data_function, NULL); - res |= ast_register_application2(app_msg_send, msg_send_exec, NULL, NULL, NULL); + res |= ast_register_application2(app_msg_send, msg_send_exec, NULL, NULL, 0, NULL); res |= ast_manager_register_xml_core("MessageSend", EVENT_FLAG_MESSAGE, action_messagesend); ast_register_atexit(message_shutdown); Index: main/pbx.c =================================================================== --- main/pbx.c (revision 427353) +++ main/pbx.c (working copy) @@ -885,6 +885,7 @@ * 'dangerous' dialplan functions. */ AST_THREADSTORAGE(thread_inhibit_escalations_tl); +static int thread_inhibits_escalations(void); /*! * \brief Set to true (non-zero) to globally allow all dangerous dialplan @@ -999,6 +1000,7 @@ #endif AST_RWLIST_ENTRY(ast_app) list; /*!< Next app in list */ struct ast_module *module; /*!< Module this app belongs to */ + unsigned int escalates:1; /*!< Application requires escalated privileges */ char name[0]; /*!< Name of the application */ }; @@ -1643,6 +1645,15 @@ const char *saved_c_appl; const char *saved_c_data; + if (app->escalates && thread_inhibits_escalations()) { + if (!live_dangerously) { + ast_log(LOG_ERROR, "Dangerous application %s execute blocked\n", app->name); + return -1; + } + + ast_debug(2, "Executing %s from a dangerous context\n", app->name); + } + /* save channel values */ saved_c_appl= ast_channel_appl(c); saved_c_data= ast_channel_data(c); @@ -7154,7 +7165,7 @@ } /*! \brief Dynamically register a new dial plan application */ -int ast_register_application2(const char *app, int (*execute)(struct ast_channel *, const char *), const char *synopsis, const char *description, void *mod) +int ast_register_application2(const char *app, int (*execute)(struct ast_channel *, const char *), const char *synopsis, const char *description, int escalates, void *mod) { struct ast_app *tmp; struct ast_app *cur; @@ -7186,6 +7197,7 @@ strcpy(tmp->name, app); tmp->execute = execute; + tmp->escalates = escalates; tmp->module = mod; #ifdef AST_XML_DOCS @@ -10190,6 +10202,8 @@ unsigned int dialed:1; /*! \brief Set when execution is completed */ unsigned int executed:1; + /*! \brief Set if thread should inhibit escalations */ + unsigned int inhibit_escalations:1; }; /*! \brief Destructor for outgoing structure */ @@ -10225,6 +10239,11 @@ return NULL; } + if (outgoing->inhibit_escalations && ast_thread_inhibit_escalations()) { + ast_log(LOG_WARNING, "Failed to inhibit privilege escalations; aborting outgoing exec\n"); + return NULL; + } + if (!ast_strlen_zero(outgoing->app)) { struct ast_app *app = pbx_findapp(outgoing->app); @@ -10443,6 +10462,7 @@ } } + outgoing->inhibit_escalations = thread_inhibits_escalations(); ao2_ref(outgoing, +1); if (ast_pthread_create_detached(&thread, NULL, pbx_outgoing_exec, outgoing)) { ast_log(LOG_WARNING, "Unable to spawn dialing thread for '%s/%s'\n", type, addr); @@ -12075,7 +12095,7 @@ /* Register builtin applications */ for (x = 0; x < ARRAY_LEN(builtins); x++) { - if (ast_register_application2(builtins[x].name, builtins[x].execute, NULL, NULL, NULL)) { + if (ast_register_application2(builtins[x].name, builtins[x].execute, NULL, NULL, 0, NULL)) { ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name); return -1; } Index: res/res_monitor.c =================================================================== --- res/res_monitor.c (revision 427353) +++ res/res_monitor.c (working copy) @@ -967,7 +967,7 @@ static int load_module(void) { - ast_register_application_xml("Monitor", start_monitor_exec); + ast_register_application_escalating_xml("Monitor", start_monitor_exec); ast_register_application_xml("StopMonitor", stop_monitor_exec); ast_register_application_xml("ChangeMonitor", change_monitor_exec); ast_register_application_xml("PauseMonitor", pause_monitor_exec); Index: res/res_agi.c =================================================================== --- res/res_agi.c (revision 427353) +++ res/res_agi.c (working copy) @@ -4298,10 +4298,10 @@ err |= ast_cli_register_multiple(cli_agi, ARRAY_LEN(cli_agi)); err |= ast_agi_register_multiple(ast_module_info->self, commands, ARRAY_LEN(commands)); - err |= ast_register_application_xml(deadapp, deadagi_exec); - err |= ast_register_application_xml(eapp, eagi_exec); + err |= ast_register_application_escalating_xml(deadapp, deadagi_exec); + err |= ast_register_application_escalating_xml(eapp, eagi_exec); err |= ast_manager_register_xml("AGI", EVENT_FLAG_AGI, action_add_agi_cmd); - err |= ast_register_application_xml(app, agi_exec); + err |= ast_register_application_escalating_xml(app, agi_exec); AST_TEST_REGISTER(test_agi_null_docs); Index: apps/app_system.c =================================================================== --- apps/app_system.c (revision 427353) +++ apps/app_system.c (working copy) @@ -177,8 +177,8 @@ { int res; - res = ast_register_application_xml(app2, trysystem_exec); - res |= ast_register_application_xml(app, system_exec); + res = ast_register_application_escalating_xml(app2, trysystem_exec); + res |= ast_register_application_escalating_xml(app, system_exec); return res; } Index: apps/app_record.c =================================================================== --- apps/app_record.c (revision 427353) +++ apps/app_record.c (working copy) @@ -478,7 +478,7 @@ static int load_module(void) { - return ast_register_application_xml(app, record_exec); + return ast_register_application_escalating_xml(app, record_exec); } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Trivial Record Application"); Index: apps/app_externalivr.c =================================================================== --- apps/app_externalivr.c (revision 427353) +++ apps/app_externalivr.c (working copy) @@ -912,7 +912,7 @@ static int load_module(void) { - return ast_register_application_xml(app, app_exec); + return ast_register_application_escalating_xml(app, app_exec); } AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "External IVR Interface Application"); Index: apps/app_mixmonitor.c =================================================================== --- apps/app_mixmonitor.c (revision 427353) +++ apps/app_mixmonitor.c (working copy) @@ -1528,7 +1528,7 @@ int res; ast_cli_register_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor)); - res = ast_register_application_xml(app, mixmonitor_exec); + res = ast_register_application_escalating_xml(app, mixmonitor_exec); res |= ast_register_application_xml(stop_app, stop_mixmonitor_exec); res |= ast_manager_register_xml("MixMonitorMute", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, manager_mute_mixmonitor); res |= ast_manager_register_xml("MixMonitor", EVENT_FLAG_SYSTEM, manager_mixmonitor); Index: apps/app_confbridge.c =================================================================== --- apps/app_confbridge.c (revision 427353) +++ apps/app_confbridge.c (working copy) @@ -3410,7 +3410,7 @@ res |= ast_register_application_xml(app, confbridge_exec); - res |= ast_custom_function_register(&confbridge_function); + res |= ast_custom_function_register_escalating(&confbridge_function, AST_CFE_WRITE); res |= ast_custom_function_register(&confbridge_info_function); res |= ast_cli_register_multiple(cli_confbridge, ARRAY_LEN(cli_confbridge));