From: Anthony Minessale Date: Tue, 5 Jan 2010 19:47:49 +0000 (+0000) Subject: add userauth @: to event_socket to auth against user directory... X-Git-Tag: v1.0.6~861 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=87ca6ed5537a05ef7de666bc15f4046dc22436c8;p=thirdparty%2Ffreeswitch.git add userauth @: to event_socket to auth against user directory uses esl-password esl-allowed-api esl-allowed-events and esl-allowed-log to control resource access git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@16160 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- diff --git a/src/mod/event_handlers/mod_event_socket/mod_event_socket.c b/src/mod/event_handlers/mod_event_socket/mod_event_socket.c index 2480c8cc94..597b5b8f40 100644 --- a/src/mod/event_handlers/mod_event_socket/mod_event_socket.c +++ b/src/mod/event_handlers/mod_event_socket/mod_event_socket.c @@ -54,6 +54,9 @@ typedef enum { LFLAG_HANDLE_DISCO = (1 << 11), LFLAG_CONNECTED = (1 << 12), LFLAG_RESUME = (1 << 13), + LFLAG_AUTH_EVENTS = (1 << 14), + LFLAG_ALL_EVENTS_AUTHED = (1 << 15), + LFLAG_ALLOW_LOG = (1 << 16) } event_flag_t; typedef enum { @@ -73,7 +76,10 @@ struct listener { switch_log_level_t level; char *ebuf; uint8_t event_list[SWITCH_EVENT_ALL + 1]; + uint8_t allowed_event_list[SWITCH_EVENT_ALL + 1]; switch_hash_t *event_hash; + switch_hash_t *allowed_event_hash; + switch_hash_t *allowed_api_hash; switch_thread_rwlock_t *rwlock; switch_core_session_t *session; int lost_events; @@ -211,6 +217,15 @@ static switch_status_t expire_listener(listener_t **listener) flush_listener(*listener, SWITCH_TRUE, SWITCH_TRUE); switch_core_hash_destroy(&l->event_hash); + if (l->allowed_event_hash) { + switch_core_hash_destroy(&l->allowed_event_hash); + } + + if (l->allowed_api_hash) { + switch_core_hash_destroy(&l->allowed_api_hash); + } + + switch_mutex_lock(l->filter_mutex); if (l->filters) { switch_event_destroy(&l->filters); @@ -429,6 +444,7 @@ SWITCH_STANDARD_APP(socket_function) listener->pool = switch_core_session_get_pool(session); listener->format = EVENT_FORMAT_PLAIN; listener->session = session; + switch_set_flag(listener, LFLAG_ALLOW_LOG); switch_mutex_init(&listener->flag_mutex, SWITCH_MUTEX_NESTED, listener->pool); switch_mutex_init(&listener->filter_mutex, SWITCH_MUTEX_NESTED, listener->pool); @@ -753,6 +769,7 @@ SWITCH_STANDARD_API(event_sink_function) switch_core_hash_init(&listener->event_hash, listener->pool); switch_set_flag(listener, LFLAG_AUTHED); switch_set_flag(listener, LFLAG_STATEFUL); + switch_set_flag(listener, LFLAG_ALLOW_LOG); switch_queue_create(&listener->event_queue, SWITCH_CORE_QUEUE_LEN, listener->pool); switch_queue_create(&listener->log_queue, SWITCH_CORE_QUEUE_LEN, listener->pool); @@ -1390,6 +1407,60 @@ static void *SWITCH_THREAD_FUNC api_exec(switch_thread_t *thread, void *obj) return NULL; } + +static switch_bool_t auth_api_command(listener_t *listener, const char *api_cmd, const char *arg) +{ + const char *check_cmd = api_cmd; + char *sneaky_commands[] = { "bgapi", "sched_api", "eval", "expand", NULL }; + int x = 0; + char *dup_arg = NULL; + char *next = NULL; + switch_bool_t ok = SWITCH_TRUE; + + top: + + if (!switch_core_hash_find(listener->allowed_api_hash, check_cmd)) { + ok = SWITCH_FALSE; + goto end; + } + + while(check_cmd) { + for (x = 0; sneaky_commands[x]; x++) { + if (!strcasecmp(sneaky_commands[x], check_cmd)) { + if (check_cmd == api_cmd) { + if (arg) { + dup_arg = strdup(arg); + check_cmd = dup_arg; + if ((next = strchr(check_cmd, ' '))) { + *next++ = '\0'; + } + } else { + break; + } + } else { + if (next) { + check_cmd = next; + } else { + check_cmd = dup_arg; + } + + if ((next = strchr(check_cmd, ' '))) { + *next++ = '\0'; + } + } + goto top; + } + } + break; + } + + end: + + switch_safe_free(dup_arg); + return ok; + +} + static switch_status_t parse_command(listener_t *listener, switch_event_t **event, char *reply, uint32_t reply_len) { switch_status_t status = SWITCH_STATUS_SUCCESS; @@ -1405,7 +1476,7 @@ static switch_status_t parse_command(listener_t *listener, switch_event_t **even cmd = reload_cheat; } - if (!strncasecmp(cmd, "exit", 4)) { + if (!strncasecmp(cmd, "exit", 4) || !strncasecmp(cmd, "...", 3)) { switch_clear_flag_locked(listener, LFLAG_RUNNING); switch_snprintf(reply, reply_len, "+OK bye"); goto done; @@ -1429,6 +1500,196 @@ static switch_status_t parse_command(listener_t *listener, switch_event_t **even goto done; } + if (!strncasecmp(cmd, "userauth ", 9)) { + const char *passwd; + const char *allowed_api; + const char *allowed_events; + switch_event_t *params; + char *user, *domain_name, *pass; + switch_xml_t x_domain = NULL, x_domain_root, x_user = NULL, x_params, x_param, x_group = NULL; + int authed = 0; + char *edup = NULL; + char event_reply[512] = "Allowed-Events: all\n"; + char api_reply[512] = "Allowed-API: all\n"; + char log_reply[512] = ""; + int allowed_log = 1; + + + switch_clear_flag(listener, LFLAG_ALLOW_LOG); + + strip_cr(cmd); + + user = cmd + 9; + + if ((pass = strchr(user, ':'))) { + *pass++ = '\0'; + } + + if ((domain_name = strchr(user, '@'))) { + *domain_name++ = '\0'; + } + + if (zstr(user) || zstr(domain_name)) { + switch_snprintf(reply, reply_len, "-ERR invalid"); + switch_clear_flag_locked(listener, LFLAG_RUNNING); + goto done; + } + + + passwd = NULL; + allowed_events = NULL; + allowed_api = NULL; + + params = NULL; + x_domain_root = NULL; + + + switch_event_create(¶ms, SWITCH_EVENT_REQUEST_PARAMS); + switch_assert(params); + switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "action", "event_socket_auth"); + + if (switch_xml_locate_user("id", user, domain_name, NULL, &x_domain_root, &x_domain, &x_user, &x_group, params) == SWITCH_STATUS_SUCCESS) { + switch_xml_t list[3]; + int x = 0; + + list[0] = x_domain; + list[1] = x_group; + list[2] = x_user; + + for (x = 0 ; x < 3; x++) { + if ((x_params = switch_xml_child(list[x], "params"))) { + 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, "esl-password")) { + passwd = val; + } else if (!strcasecmp(var, "esl-allowed-log")) { + allowed_log = switch_true(val); + } else if (!strcasecmp(var, "esl-allowed-events")) { + allowed_events = val; + } else if (!strcasecmp(var, "esl-allowed-api")) { + allowed_api = val; + } + } + } + } + } else { + authed = 0; + goto bot; + } + + if (!zstr(passwd) && !zstr(pass) && !strcmp(passwd, pass)) { + authed = 1; + + if (allowed_events) { + char delim = ','; + char *cur, *next; + int count = 0, custom = 0, key_count = 0; + + switch_set_flag(listener, LFLAG_AUTH_EVENTS); + + switch_snprintf(event_reply, sizeof(event_reply), "Allowed-Events: %s\n", allowed_events); + + switch_core_hash_init(&listener->allowed_event_hash, listener->pool); + + edup = strdup(allowed_events); + cur = edup; + + if (strchr(edup, ' ')) { + delim = ' '; + } + + for (cur = edup; cur; count++) { + switch_event_types_t type; + + if ((next = strchr(cur, delim))) { + *next++ = '\0'; + } + + if (custom) { + switch_core_hash_insert(listener->allowed_event_hash, cur, MARKER); + } else if (switch_name_event(cur, &type) == SWITCH_STATUS_SUCCESS) { + key_count++; + if (type == SWITCH_EVENT_ALL) { + uint32_t x = 0; + switch_set_flag(listener, LFLAG_ALL_EVENTS_AUTHED); + for (x = 0; x < SWITCH_EVENT_ALL; x++) { + listener->allowed_event_list[x] = 1; + } + } + if (type <= SWITCH_EVENT_ALL) { + listener->allowed_event_list[type] = 1; + } + if (type == SWITCH_EVENT_CUSTOM) { + custom++; + } + } + + cur = next; + } + + switch_safe_free(edup); + } + + switch_snprintf(log_reply, sizeof(log_reply), "Allowed-LOG: %s\n", allowed_log ? "true" : "false"); + + if (allowed_log) { + switch_set_flag(listener, LFLAG_ALLOW_LOG); + } + + if (allowed_api) { + char delim = ','; + char *cur, *next; + int count = 0; + + switch_snprintf(api_reply, sizeof(api_reply), "Allowed-API: %s\n", allowed_api); + + switch_core_hash_init(&listener->allowed_api_hash, listener->pool); + + edup = strdup(allowed_api); + cur = edup; + + if (strchr(edup, ' ')) { + delim = ' '; + } + + for (cur = edup; cur; count++) { + if ((next = strchr(cur, delim))) { + *next++ = '\0'; + } + + switch_core_hash_insert(listener->allowed_api_hash, cur, MARKER); + + cur = next; + } + + switch_safe_free(edup); + } + + } + + + bot: + + if (params) { + switch_event_destroy(¶ms); + } + + if (authed) { + switch_set_flag_locked(listener, LFLAG_AUTHED); + switch_snprintf(reply, reply_len, "~Reply-Text: +OK accepted\n%s%s%s\n", event_reply, api_reply, log_reply); + } else { + switch_snprintf(reply, reply_len, "-ERR invalid"); + switch_clear_flag_locked(listener, LFLAG_RUNNING); + } + + if (x_domain_root) { + switch_xml_free(x_domain_root); + } + + } + goto done; } @@ -1737,6 +1998,15 @@ static switch_status_t parse_command(listener_t *listener, switch_event_t **even *arg++ = '\0'; } + if (listener->allowed_api_hash) { + if (!auth_api_command(listener, api_cmd, arg)) { + switch_snprintf(reply, reply_len, "-ERR permission denied"); + status = SWITCH_STATUS_SUCCESS; + goto done; + } + } + + acs.listener = listener; acs.api_cmd = api_cmd; acs.arg = arg; @@ -1763,6 +2033,14 @@ static switch_status_t parse_command(listener_t *listener, switch_event_t **even *arg++ = '\0'; } + if (listener->allowed_api_hash) { + if (!auth_api_command(listener, api_cmd, arg)) { + switch_snprintf(reply, reply_len, "-ERR permission denied"); + status = SWITCH_STATUS_SUCCESS; + goto done; + } + } + switch_core_new_memory_pool(&pool); acs = switch_core_alloc(pool, sizeof(*acs)); switch_assert(acs); @@ -1804,6 +2082,11 @@ static switch_status_t parse_command(listener_t *listener, switch_event_t **even char *level_s; switch_log_level_t ltype = SWITCH_LOG_DEBUG; + if (!switch_test_flag(listener, LFLAG_ALLOW_LOG)) { + switch_snprintf(reply, reply_len, "-ERR permission denied"); + goto done; + } + //pull off the first newline/carriage return strip_cr(cmd); @@ -1874,10 +2157,22 @@ static switch_status_t parse_command(listener_t *listener, switch_event_t **even goto end; } } - + + if (custom) { - switch_core_hash_insert(listener->event_hash, cur, MARKER); + if (listener->allowed_event_hash && switch_core_hash_find(listener->allowed_event_hash, cur)) { + switch_core_hash_insert(listener->event_hash, cur, MARKER); + } else { + switch_snprintf(reply, reply_len, "-ERR permission denied"); + goto done; + } } else if (switch_name_event(cur, &type) == SWITCH_STATUS_SUCCESS) { + if (switch_test_flag(listener, LFLAG_AUTH_EVENTS) && !listener->allowed_event_list[type] && + !switch_test_flag(listener, LFLAG_ALL_EVENTS_AUTHED)) { + switch_snprintf(reply, reply_len, "-ERR permission denied"); + goto done; + } + key_count++; if (type == SWITCH_EVENT_ALL) { uint32_t x = 0; @@ -2199,6 +2494,14 @@ static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj) switch_core_hash_destroy(&listener->event_hash); + if (listener->allowed_event_hash) { + switch_core_hash_destroy(&listener->allowed_event_hash); + } + + if (listener->allowed_api_hash) { + switch_core_hash_destroy(&listener->allowed_api_hash); + } + if (listener->session) { switch_channel_clear_flag(switch_core_session_get_channel(listener->session), CF_CONTROLLED); switch_clear_flag_locked(listener, LFLAG_SESSION); @@ -2376,6 +2679,8 @@ SWITCH_MODULE_RUNTIME_FUNCTION(mod_event_socket_runtime) listener_pool = NULL; listener->format = EVENT_FORMAT_PLAIN; switch_set_flag(listener, LFLAG_FULL); + switch_set_flag(listener, LFLAG_ALLOW_LOG); + switch_mutex_init(&listener->flag_mutex, SWITCH_MUTEX_NESTED, listener->pool); switch_mutex_init(&listener->filter_mutex, SWITCH_MUTEX_NESTED, listener->pool); 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 5a37e1d9dc..175357faeb 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 @@ -227,18 +227,19 @@ static abyss_bool user_attributes (const char *user, const char *domain_name, } } - if (x_domain_root) { - switch_xml_free(x_domain_root); - } - if (ppasswd) - *ppasswd = passwd; + *ppasswd = strdup(passwd); if (pvm_passwd) - *pvm_passwd = vm_passwd; + *pvm_passwd = strdup(vm_passwd); if (palias) - *palias = alias; + *palias = strdup(alias); if (pallowed_commands) - *pallowed_commands = allowed_commands; + *pallowed_commands = strdup(allowed_commands); + + + if (x_domain_root) { + switch_xml_free(x_domain_root); + } return TRUE; } @@ -293,7 +294,7 @@ static abyss_bool is_authorized (const TSession *r, const char *command) if (!allowed_commands) return FALSE; - dup = strdup (allowed_commands); + dup = allowed_commands; argc = switch_separate_string (dup, ',', argv, (sizeof(argv) / sizeof(argv[0]))); for (i = 0; i < argc; i++) { @@ -319,7 +320,8 @@ static abyss_bool http_directory_auth(TSession *r, char *domain_name) const char *box = NULL; int at = 0; char *dp; - + abyss_bool rval = FALSE; + p = RequestHeaderValue(r, "authorization"); if (p) { @@ -445,18 +447,25 @@ static abyss_bool http_directory_auth(TSession *r, char *domain_name) ResponseAddField(r, "freeswitch-user", (box ? box : user)); ResponseAddField(r, "freeswitch-domain", domain_name); - - return TRUE; + rval = TRUE; + goto done; } } } - fail: + fail: switch_snprintf(z, sizeof(z), "Basic realm=\"%s\"", domain_name ? domain_name : globals.realm); ResponseAddField(r, "WWW-Authenticate", z); ResponseStatus(r, 401); - return FALSE; + + done: + + switch_safe_free(mypass1); + switch_safe_free(mypass2); + switch_safe_free(box); + + return rval; } abyss_bool auth_hook(TSession * r)