diff --git a/main/manager.c b/main/manager.c index a59889f22d..68e4e87725 100644 --- a/main/manager.c +++ b/main/manager.c @@ -4942,6 +4942,9 @@ static int app_match(const char *app, const char *data, const char *search) */ static int appdata_match(const char *app, const char *data, const char *search) { + if (ast_strlen_zero(data)) { + return 0; + } return !!(strstr(data, search)); } @@ -4972,7 +4975,7 @@ static int queue_match(const char *app, const char *data, const char *search) AST_APP_ARG(position); ); - if (!strcasestr(app, "queue")) { + if (!strcasestr(app, "queue") || ast_strlen_zero(data)) { return 0; } @@ -5044,6 +5047,98 @@ static int is_originate_app_permitted(const char *app, const char *data, return 1; } +#ifdef TEST_FRAMEWORK +#define ALL_PERMISSIONS (INT_MAX) +#define NO_PERMISSIONS (0) +AST_TEST_DEFINE(originate_permissions_test) +{ + enum ast_test_result_state res = AST_TEST_PASS; + + switch (cmd) { + case TEST_INIT: + info->name = "originate_permissions_test"; + info->category = "/main/manager/"; + info->summary = "Test permissions for originate action"; + info->description = + "Make sure that dialplan apps/functions that need special " + "permissions are prohibited if the user doesn't have the permission."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + /* + * Check application matching. We don't need to check every one. + * The code is the same. + */ + + ast_test_validate(test, is_originate_app_permitted("exec", + NULL, EVENT_FLAG_SYSTEM), "exec permission check failed"); + ast_test_validate(test, is_originate_app_permitted("exec", + NULL, EVENT_FLAG_SYSTEM | EVENT_FLAG_AGI), "exec check permission failed"); + ast_test_validate(test, is_originate_app_permitted("exec", + NULL, ALL_PERMISSIONS), "exec check permission failed"); + ast_test_validate(test, !is_originate_app_permitted("exec", + NULL, EVENT_FLAG_AGI), "exec permission check failed"); + ast_test_validate(test, !is_originate_app_permitted("exec", + NULL, EVENT_FLAG_VERBOSE), "exec permission check failed"); + ast_test_validate(test, !is_originate_app_permitted("exec", + NULL, NO_PERMISSIONS), "exec permission check failed"); + + /* + * If queue is used with the AGI parameter but without the SYSTEM or AGI + * permission, it should be denied. Queue param order: + * queuename,options,url,announceoverride,queuetimeoutstr,AGI,gosub,rule,position + * The values of the options aren't checked. They just have to be present. + */ + + /* AGI not specified should always be allowed */ + ast_test_validate(test, is_originate_app_permitted("queue", + NULL, NO_PERMISSIONS), "Queue permission check failed"); + ast_test_validate(test, is_originate_app_permitted("queue", + "somequeue,CcdHh,someURL,tt-monkeys,100,,gosub,rule,666", + EVENT_FLAG_ORIGINATE | EVENT_FLAG_HOOKRESPONSE ), "Queue permission check failed"); + + /* AGI specified with SYSTEM or AGI permission should be allowed */ + ast_test_validate(test, is_originate_app_permitted("queue", + "somequeue,CcdHh,someURL,tt-monkeys,100,SomeAGIScript,gosub,rule,666", + EVENT_FLAG_SYSTEM | EVENT_FLAG_HOOKRESPONSE ), "Queue permission check failed"); + ast_test_validate(test, is_originate_app_permitted("queue", + "somequeue,CcdHh,someURL,tt-monkeys,100,SomeAGIScript,gosub,rule,666", + EVENT_FLAG_AGI | EVENT_FLAG_HOOKRESPONSE ), "Queue permission check failed"); + ast_test_validate(test, is_originate_app_permitted("queue", + "somequeue,CcdHh,someURL,tt-monkeys,100,SomeAGIScript,gosub,rule,666", + ALL_PERMISSIONS), "Queue permission check failed"); + + /* AGI specified without SYSTEM or AGI permission should be denied */ + ast_test_validate(test, !is_originate_app_permitted("queue", + "somequeue,CcdHh,someURL,tt-monkeys,100,SomeAGIScript,gosub,rule,666", + NO_PERMISSIONS), "Queue permission check failed"); + ast_test_validate(test, !is_originate_app_permitted("queue", + "somequeue,CcdHh,someURL,tt-monkeys,100,SomeAGIScript,gosub,rule,666", + EVENT_FLAG_ORIGINATE | EVENT_FLAG_HOOKRESPONSE ), "Queue permission check failed"); + + /* + * Check appdata. The function name can appear anywhere in appdata. + */ + ast_test_validate(test, is_originate_app_permitted("someapp", + "aaaDBbbb", EVENT_FLAG_SYSTEM), "exec permission check failed"); + ast_test_validate(test, is_originate_app_permitted("someapp", + "aaa DB bbb", ALL_PERMISSIONS), "exec permission check failed"); + ast_test_validate(test, !is_originate_app_permitted("someapp", + "aaaDBbbb", NO_PERMISSIONS), "exec permission check failed"); + ast_test_validate(test, !is_originate_app_permitted("someapp", + "aaa DB bbb", NO_PERMISSIONS), "exec permission check failed"); + /* The check is case-sensitive so although DB is a match, db isn't. */ + ast_test_validate(test, is_originate_app_permitted("someapp", + "aaa db bbb", NO_PERMISSIONS), "exec permission check failed"); + + return res; +} +#undef ALL_PERMISSIONS +#undef NO_PERMISSIONS +#endif + static int action_originate(struct mansession *s, const struct message *m) { const char *name = astman_get_header(m, "Channel"); @@ -9246,6 +9341,7 @@ static void manager_shutdown(void) #ifdef TEST_FRAMEWORK AST_TEST_UNREGISTER(eventfilter_test_creation); AST_TEST_UNREGISTER(eventfilter_test_matching); + AST_TEST_UNREGISTER(originate_permissions_test); #endif /* This event is not actually transmitted, but causes all TCP sessions to be closed */ @@ -9956,6 +10052,7 @@ static int load_module(void) #ifdef TEST_FRAMEWORK AST_TEST_REGISTER(eventfilter_test_creation); AST_TEST_REGISTER(eventfilter_test_matching); + AST_TEST_REGISTER(originate_permissions_test); #endif return rc; }