From 46c1b4217cccbfbcd7db421438e875870c55bcd3 Mon Sep 17 00:00:00 2001 From: Luis Azedo <luis@2600hz.com> Date: Fri, 20 Oct 2017 14:59:09 +0100 Subject: [PATCH 1/4] FS-10746 [mod_sofia] allow authoritative proxy to provide token --- src/mod/endpoints/mod_sofia/mod_sofia.h | 1 + src/mod/endpoints/mod_sofia/sofia.c | 78 ++++++++++++++++--------- 2 files changed, 50 insertions(+), 29 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 46d215a2d5..929fc60db6 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -309,6 +309,7 @@ typedef enum { PFLAG_FIRE_BYE_RESPONSE_EVENTS, PFLAG_AUTO_INVITE_100, PFLAG_UPDATE_REFRESHER, + PFLAG_AUTH_REQUIRE_USER, /* No new flags below this line */ PFLAG_MAX diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 617446e983..cccd6bde80 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -4591,6 +4591,7 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) sofia_clear_pflag(profile, PFLAG_MAKE_EVERY_TRANSFER_A_NIGHTMARE); sofia_clear_pflag(profile, PFLAG_FIRE_TRANFER_EVENTS); sofia_clear_pflag(profile, PFLAG_BLIND_AUTH_ENFORCE_RESULT); + sofia_clear_pflag(profile, PFLAG_AUTH_REQUIRE_USER); profile->shutdown_type = "false"; profile->local_network = "localnet.auto"; sofia_set_flag(profile, TFLAG_ENABLE_SOA); @@ -5486,6 +5487,12 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) profile->nonce_ttl = atoi(val); } else if (!strcasecmp(var, "max-auth-validity") && !zstr(val)) { profile->max_auth_validity = atoi(val); + } else if (!strcasecmp(var, "auth-require-user")) { + if (switch_true(val)) { + sofia_set_pflag(profile, PFLAG_AUTH_REQUIRE_USER); + } else { + sofia_clear_pflag(profile, PFLAG_AUTH_REQUIRE_USER); + } } else if (!strcasecmp(var, "accept-blind-reg")) { if (switch_true(val)) { sofia_set_pflag(profile, PFLAG_BLIND_REG); @@ -10232,54 +10239,57 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia * ip header and see if it matches against the inbound acl */ if (network_ip_is_proxy) { + const char * x_auth_ip = sofia_glue_get_unknown_header(sip, "X-AUTH-IP"); + const char * x_auth_token = sofia_glue_get_unknown_header(sip, "X-AUTH-Token"); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "network ip is a proxy\n"); - for (un = sip->sip_unknown; un; un = un->un_next) { - if (!strcasecmp(un->un_name, "X-AUTH-IP")) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "found auth ip [%s] header of [%s]\n", un->un_name, un->un_value); - if (!zstr(un->un_value)) { - for (x = 0; x < profile->acl_count; x++) { - last_acl = profile->acl[x]; - if ((ok = switch_check_network_list_ip_token(un->un_value, last_acl, &token))) { - switch_copy_string(proxied_client_ip, un->un_value, sizeof(proxied_client_ip)); - break; - } - } + if (!zstr(x_auth_token) && !zstr(x_auth_ip)) { + switch_copy_string(proxied_client_ip, x_auth_ip, sizeof(proxied_client_ip)); + token = x_auth_token; + ok = 1; + } else if (!zstr(x_auth_ip)) { + for (x = 0; x < profile->acl_count; x++) { + last_acl = profile->acl[x]; + if ((ok = switch_check_network_list_ip_token(x_auth_ip, last_acl, &token))) { + switch_copy_string(proxied_client_ip, x_auth_ip, sizeof(proxied_client_ip)); + break; } } } - } - if (!ok) { - - if (!sofia_test_pflag(profile, PFLAG_AUTH_CALLS)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "IP %s Rejected by acl \"%s\"\n", network_ip, switch_str_nil(last_acl)); - - if (!acl_context) { + if (!ok) { + if (!sofia_test_pflag(profile, PFLAG_AUTH_CALLS)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "IP %s Rejected by acl \"%s\"\n", x_auth_ip, switch_str_nil(last_acl)); nua_respond(nh, SIP_403_FORBIDDEN, TAG_END()); goto fail; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IP %s Rejected by acl \"%s\". Falling back to Digest auth.\n", + x_auth_ip, switch_str_nil(last_acl)); } } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IP %s Rejected by acl \"%s\". Falling back to Digest auth.\n", - network_ip, switch_str_nil(last_acl)); - } - } else { - if (token) { - switch_set_string(acl_token, token); - } - if (sofia_test_pflag(profile, PFLAG_AUTH_CALLS)) { + if (token) { + switch_set_string(acl_token, token); + } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IP %s Approved by acl \"%s[%s]\". Access Granted.\n", proxied_client_ip, switch_str_nil(last_acl), acl_token); switch_set_string(sip_acl_authed_by, last_acl); switch_set_string(sip_acl_token, acl_token); - is_auth = 1; - + } + } else { + if (!sofia_test_pflag(profile, PFLAG_AUTH_CALLS)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "IP %s Rejected by acl \"%s\"\n", network_ip, switch_str_nil(last_acl)); + nua_respond(nh, SIP_403_FORBIDDEN, TAG_END()); + goto fail; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IP %s Rejected by acl \"%s\". Falling back to Digest auth.\n", + network_ip, switch_str_nil(last_acl)); } } } } + if (!is_auth && sofia_test_pflag(profile, PFLAG_AUTH_CALLS) && sofia_test_pflag(profile, PFLAG_BLIND_AUTH)) { char *user; switch_status_t blind_result = SWITCH_STATUS_FALSE; @@ -10343,10 +10353,20 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia if (*acl_token) { switch_channel_set_variable(channel, "acl_token", acl_token); if (strchr(acl_token, '@')) { - if (switch_ivr_set_user(session, acl_token) == SWITCH_STATUS_SUCCESS) { + switch_event_create(&v_event, SWITCH_EVENT_REQUEST_PARAMS); + for (un = sip->sip_unknown; un; un = un->un_next) { + switch_event_add_header_string(v_event, SWITCH_STACK_BOTTOM, un->un_name, un->un_value); + }; + if (switch_ivr_set_user_extended(session, acl_token, v_event) == SWITCH_STATUS_SUCCESS) { + switch_event_destroy(&v_event); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Authenticating user %s\n", acl_token); } else { + switch_event_destroy(&v_event); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Error Authenticating user %s\n", acl_token); + if(sofia_test_pflag(profile, PFLAG_AUTH_REQUIRE_USER)) { + nua_respond(nh, SIP_480_TEMPORARILY_UNAVAILABLE, TAG_END()); + goto fail; + } } } } From 60956d7f85412d120642c1fded9a975bc7bbe4dd Mon Sep 17 00:00:00 2001 From: Luis Azedo <luis@2600hz.com> Date: Tue, 13 Mar 2018 19:41:45 +0000 Subject: [PATCH 2/4] FS-11025 [core] allow/check ports in network lists --- src/include/switch_core.h | 1 + src/include/switch_utils.h | 16 ++++++ src/switch_core.c | 44 +++++++++++---- src/switch_utils.c | 106 ++++++++++++++++++++++++++++++++----- 4 files changed, 146 insertions(+), 21 deletions(-) diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 526fe26323..7631fc287f 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -2427,6 +2427,7 @@ SWITCH_DECLARE(const char *) switch_lookup_timezone(const char *tz_name); SWITCH_DECLARE(switch_status_t) switch_strftime_tz(const char *tz, const char *format, char *date, size_t len, switch_time_t thetime); SWITCH_DECLARE(switch_status_t) switch_time_exp_tz_name(const char *tz, switch_time_exp_t *tm, switch_time_t thetime); SWITCH_DECLARE(void) switch_load_network_lists(switch_bool_t reload); +SWITCH_DECLARE(switch_bool_t) switch_check_network_list_ip_port_token(const char *ip_str, int port, const char *list_name, const char **token); SWITCH_DECLARE(switch_bool_t) switch_check_network_list_ip_token(const char *ip_str, const char *list_name, const char **token); #define switch_check_network_list_ip(_ip_str, _list_name) switch_check_network_list_ip_token(_ip_str, _list_name, NULL) SWITCH_DECLARE(void) switch_time_set_monotonic(switch_bool_t enable); diff --git a/src/include/switch_utils.h b/src/include/switch_utils.h index 10242525f1..62ec7c8d41 100644 --- a/src/include/switch_utils.h +++ b/src/include/switch_utils.h @@ -46,6 +46,16 @@ SWITCH_BEGIN_EXTERN_C #define SWITCH_URL_UNSAFE "\r\n #%&+:;<=>?@[\\]^`{|}\"" +#define MAX_NETWORK_PORTS 10 + +struct switch_network_port_range { + int port; + int ports[MAX_NETWORK_PORTS]; + int min_port; + int max_port; +}; +typedef struct switch_network_port_range switch_network_port_range_t; +typedef switch_network_port_range_t* switch_network_port_range_p; static inline char *switch_get_hex_bytes(switch_byte_t *buf, switch_size_t datalen, char *new_buf, switch_size_t new_datalen) { @@ -1270,6 +1280,12 @@ SWITCH_DECLARE(switch_status_t) switch_network_list_add_cidr_token(switch_networ SWITCH_DECLARE(char *) switch_network_ipv4_mapped_ipv6_addr(const char* ip_str); SWITCH_DECLARE(switch_status_t) switch_network_list_add_host_mask(switch_network_list_t *list, const char *host, const char *mask_str, switch_bool_t ok); + +SWITCH_DECLARE(switch_status_t) switch_network_list_add_cidr_port_token(switch_network_list_t *list, const char *cidr_str, switch_bool_t ok, const char *token, switch_network_port_range_p port); +SWITCH_DECLARE(switch_status_t) switch_network_list_add_host_port_mask(switch_network_list_t *list, const char *host, const char *mask_str, switch_bool_t ok, switch_network_port_range_p port); + +SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip_port_token(switch_network_list_t *list, uint32_t ip, int port, const char **token); +SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip6_port_token(switch_network_list_t *list, ip_t ip, int port, const char **token); SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip_token(switch_network_list_t *list, uint32_t ip, const char **token); SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip6_token(switch_network_list_t *list, ip_t ip, const char **token); #define switch_network_list_validate_ip(_list, _ip) switch_network_list_validate_ip_token(_list, _ip, NULL); diff --git a/src/switch_core.c b/src/switch_core.c index 596ef2bbe4..0fb040fbbd 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -1370,7 +1370,7 @@ typedef struct { static switch_ip_list_t IP_LIST = { 0 }; -SWITCH_DECLARE(switch_bool_t) switch_check_network_list_ip_token(const char *ip_str, const char *list_name, const char **token) +SWITCH_DECLARE(switch_bool_t) switch_check_network_list_ip_port_token(const char *ip_str, int port, const char *list_name, const char **token) { switch_network_list_t *list; ip_t ip, mask, net; @@ -1398,9 +1398,9 @@ SWITCH_DECLARE(switch_bool_t) switch_check_network_list_ip_token(const char *ip_ if ((list = switch_core_hash_find(IP_LIST.hash, list_name))) { if (ipv6) { - ok = switch_network_list_validate_ip6_token(list, ip, token); + ok = switch_network_list_validate_ip6_port_token(list, ip, port, token); } else { - ok = switch_network_list_validate_ip_token(list, ip.v4, token); + ok = switch_network_list_validate_ip_port_token(list, ip.v4, port, token); } } else if (strchr(list_name, '/')) { if (strchr(list_name, ',')) { @@ -1443,6 +1443,10 @@ SWITCH_DECLARE(switch_bool_t) switch_check_network_list_ip_token(const char *ip_ return ok; } +SWITCH_DECLARE(switch_bool_t) switch_check_network_list_ip_token(const char *ip_str, const char *list_name, const char **token) +{ + return switch_check_network_list_ip_port_token(ip_str, 0, list_name, token); +} SWITCH_DECLARE(void) switch_load_network_lists(switch_bool_t reload) { @@ -1589,9 +1593,12 @@ SWITCH_DECLARE(void) switch_load_network_lists(switch_bool_t reload) for (x_node = switch_xml_child(x_list, "node"); x_node; x_node = x_node->next) { - const char *cidr = NULL, *host = NULL, *mask = NULL, *domain = NULL; + const char *cidr = NULL, *host = NULL, *mask = NULL, *domain = NULL, *port = NULL; switch_bool_t ok = default_type; const char *type = switch_xml_attr(x_node, "type"); + switch_network_port_range_t port_range; + char *argv[MAX_NETWORK_PORTS] = { 0 }; + int argc = 0, i; if (type) { ok = switch_true(type); @@ -1602,6 +1609,25 @@ SWITCH_DECLARE(void) switch_load_network_lists(switch_bool_t reload) mask = switch_xml_attr(x_node, "mask"); domain = switch_xml_attr(x_node, "domain"); + memset(&port_range, 0, sizeof(switch_network_port_range_t)); + + if( (port = switch_xml_attr(x_node, "port")) != NULL) { + port_range.port = atoi(port); + } + + if( (port = switch_xml_attr(x_node, "ports")) != NULL) { + argc = switch_separate_string((char*)port, ',', argv, (sizeof(argv) / sizeof(argv[0]))); + for(i=0; i < argc; i++) { + port_range.ports[i] = atoi(argv[i]); + } + } + if( (port = switch_xml_attr(x_node, "port-min")) != NULL) { + port_range.min_port = atoi(port); + } + if( (port = switch_xml_attr(x_node, "port-max")) != NULL) { + port_range.max_port = atoi(port); + } + if (domain) { switch_event_t *my_params = NULL; switch_xml_t x_domain, xml_root; @@ -1646,7 +1672,7 @@ SWITCH_DECLARE(void) switch_load_network_lists(switch_bool_t reload) if (id && user_cidr) { char *token = switch_mprintf("%s@%s", id, domain); switch_assert(token); - switch_network_list_add_cidr_token(list, user_cidr, ok, token); + switch_network_list_add_cidr_port_token(list, user_cidr, ok, token, &port_range); free(token); } } @@ -1656,13 +1682,13 @@ SWITCH_DECLARE(void) switch_load_network_lists(switch_bool_t reload) switch_xml_free(xml_root); } else if (cidr) { - switch_network_list_add_cidr(list, cidr, ok); + switch_network_list_add_cidr_port_token(list, cidr, ok, NULL, &port_range); } else if (host && mask) { - switch_network_list_add_host_mask(list, host, mask, ok); + switch_network_list_add_host_port_mask(list, host, mask, ok, &port_range); } - - switch_core_hash_insert(IP_LIST.hash, name, list); } + + switch_core_hash_insert(IP_LIST.hash, name, list); } } diff --git a/src/switch_utils.c b/src/switch_utils.c index 52ec8f6327..2ac0a0e415 100644 --- a/src/switch_utils.c +++ b/src/switch_utils.c @@ -54,6 +54,7 @@ struct switch_network_node { switch_bool_t ok; char *token; char *str; + switch_network_port_range_t port_range; struct switch_network_node *next; }; typedef struct switch_network_node switch_network_node_t; @@ -467,7 +468,8 @@ SWITCH_DECLARE(switch_bool_t) switch_testv6_subnet(ip_t _ip, ip_t _net, ip_t _ma else return SWITCH_TRUE; } } -SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip6_token(switch_network_list_t *list, ip_t ip, const char **token) + +SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip6_port_token(switch_network_list_t *list, ip_t ip, int port, const char **token) { switch_network_node_t *node; switch_bool_t ok = list->default_type; @@ -494,7 +496,29 @@ SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip6_token(switch_netw return ok; } -SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip_token(switch_network_list_t *list, uint32_t ip, const char **token) +SWITCH_DECLARE(switch_bool_t) is_port_in_node(int port, switch_network_node_t *node) +{ + if(port == 0) + return SWITCH_TRUE; + if(node->port_range.port != 0 && node->port_range.port != port) + return SWITCH_FALSE; + if(node->port_range.ports[0] != 0) { + int i; + for(i=0; i < MAX_NETWORK_PORTS && node->port_range.ports[i] != 0; i++) { + if(port == node->port_range.ports[i]) + return SWITCH_TRUE; + } + return SWITCH_FALSE; + } + if(node->port_range.min_port != 0 || node->port_range.max_port != 0) { + if(port >= node->port_range.min_port && port <= node->port_range.max_port) + return SWITCH_TRUE; + return SWITCH_FALSE; + } + return SWITCH_TRUE; +} + +SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip_port_token(switch_network_list_t *list, uint32_t ip, int port, const char **token) { switch_network_node_t *node; switch_bool_t ok = list->default_type; @@ -502,7 +526,7 @@ SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip_token(switch_netwo for (node = list->node_head; node; node = node->next) { if (node->family == AF_INET6) continue; /* want AF_INET */ - if (node->bits >= bits && switch_test_subnet(ip, node->ip.v4, node->mask.v4)) { + if (node->bits >= bits && switch_test_subnet(ip, node->ip.v4, node->mask.v4) && is_port_in_node(port, node)) { if (node->ok) { ok = SWITCH_TRUE; } else { @@ -520,6 +544,16 @@ SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip_token(switch_netwo return ok; } +SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip6_token(switch_network_list_t *list, ip_t ip, const char **token) +{ + return switch_network_list_validate_ip6_port_token(list, ip, 0, token); +} + +SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip_token(switch_network_list_t *list, uint32_t ip, const char **token) +{ + return switch_network_list_validate_ip_port_token(list, ip, 0, token); +} + SWITCH_DECLARE(char *) switch_network_ipv4_mapped_ipv6_addr(const char* ip_str) { /* ipv4 mapped ipv6 address */ @@ -531,22 +565,52 @@ SWITCH_DECLARE(char *) switch_network_ipv4_mapped_ipv6_addr(const char* ip_str) return strdup(ip_str + 7); } +SWITCH_DECLARE(char*) switch_network_port_range_to_string(switch_network_port_range_p port) +{ + if (!port) { + return NULL; + } + + if (port->port != 0) { + return switch_mprintf("port: %i ", port->port); + } + + if (port->ports[0] != 0) { + int i, written = 0; + char buf[MAX_NETWORK_PORTS * 6]; + for (i = 0; i < MAX_NETWORK_PORTS && port->ports[i] != 0; i++) { + written += snprintf(buf + written, sizeof(buf) - written, (i != 0 ? ", %u" : "%u"), port->ports[i]); + } + return switch_mprintf("ports: [%s] ", buf); + } + + if (port->min_port != 0 || port->max_port != 0) { + return switch_mprintf("port range: [%i-%i] ", port->min_port, port->max_port); + } + + return NULL; +} + SWITCH_DECLARE(switch_status_t) switch_network_list_perform_add_cidr_token(switch_network_list_t *list, const char *cidr_str, switch_bool_t ok, - const char *token) + const char *token, switch_network_port_range_p port) { ip_t ip, mask; uint32_t bits; switch_network_node_t *node; char *ipv4 = NULL; + char *ports = NULL; if ((ipv4 = switch_network_ipv4_mapped_ipv6_addr(cidr_str))) { cidr_str = ipv4; } + ports = switch_network_port_range_to_string(port); + if (switch_parse_cidr(cidr_str, &ip, &mask, &bits)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Adding %s (%s) [%s] to list %s\n", - cidr_str, ok ? "allow" : "deny", switch_str_nil(token), list->name); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Adding %s %s(%s) [%s] to list %s\n", + cidr_str, ports ? ports : "", ok ? "allow" : "deny", switch_str_nil(token), list->name); switch_safe_free(ipv4); + switch_safe_free(ports); return SWITCH_STATUS_GENERR; } @@ -557,6 +621,10 @@ SWITCH_DECLARE(switch_status_t) switch_network_list_perform_add_cidr_token(switc node->ok = ok; node->bits = bits; node->str = switch_core_strdup(list->pool, cidr_str); + if(port) { + memcpy(&node->port_range, port, sizeof(switch_network_port_range_t)); + } + if (strchr(cidr_str,':')) { node->family = AF_INET6; @@ -571,14 +639,15 @@ SWITCH_DECLARE(switch_status_t) switch_network_list_perform_add_cidr_token(switc node->next = list->node_head; list->node_head = node; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Adding %s (%s) [%s] to list %s\n", - cidr_str, ok ? "allow" : "deny", switch_str_nil(token), list->name); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Adding %s %s(%s) [%s] to list %s\n", + cidr_str, ports ? ports : "", ok ? "allow" : "deny", switch_str_nil(token), list->name); switch_safe_free(ipv4); + switch_safe_free(ports); return SWITCH_STATUS_SUCCESS; } -SWITCH_DECLARE(switch_status_t) switch_network_list_add_cidr_token(switch_network_list_t *list, const char *cidr_str, switch_bool_t ok, const char *token) +SWITCH_DECLARE(switch_status_t) switch_network_list_add_cidr_port_token(switch_network_list_t *list, const char *cidr_str, switch_bool_t ok, const char *token, switch_network_port_range_p port) { char *cidr_str_dup = NULL; switch_status_t status = SWITCH_STATUS_SUCCESS; @@ -592,20 +661,25 @@ SWITCH_DECLARE(switch_status_t) switch_network_list_add_cidr_token(switch_networ if ((argc = switch_separate_string(cidr_str_dup, ',', argv, (sizeof(argv) / sizeof(argv[0]))))) { for (i = 0; i < argc; i++) { switch_status_t this_status; - if ((this_status = switch_network_list_perform_add_cidr_token(list, argv[i], ok, token)) != SWITCH_STATUS_SUCCESS) { + if ((this_status = switch_network_list_perform_add_cidr_token(list, argv[i], ok, token, port)) != SWITCH_STATUS_SUCCESS) { status = this_status; } } } } else { - status = switch_network_list_perform_add_cidr_token(list, cidr_str, ok, token); + status = switch_network_list_perform_add_cidr_token(list, cidr_str, ok, token, port); } switch_safe_free(cidr_str_dup); return status; } -SWITCH_DECLARE(switch_status_t) switch_network_list_add_host_mask(switch_network_list_t *list, const char *host, const char *mask_str, switch_bool_t ok) +SWITCH_DECLARE(switch_status_t) switch_network_list_add_cidr_token(switch_network_list_t *list, const char *cidr_str, switch_bool_t ok, const char *token) +{ + return switch_network_list_add_cidr_port_token(list, cidr_str, ok, token, NULL); +} + +SWITCH_DECLARE(switch_status_t) switch_network_list_add_host_port_mask(switch_network_list_t *list, const char *host, const char *mask_str, switch_bool_t ok, switch_network_port_range_p port) { ip_t ip, mask; switch_network_node_t *node; @@ -618,6 +692,9 @@ SWITCH_DECLARE(switch_status_t) switch_network_list_add_host_mask(switch_network node->ip.v4 = ntohl(ip.v4); node->mask.v4 = ntohl(mask.v4); node->ok = ok; + if(port) { + memcpy(&node->port_range, port, sizeof(switch_network_port_range_t)); + } /* http://graphics.stanford.edu/~seander/bithacks.html */ mask.v4 = mask.v4 - ((mask.v4 >> 1) & 0x55555555); @@ -632,6 +709,11 @@ SWITCH_DECLARE(switch_status_t) switch_network_list_add_host_mask(switch_network return SWITCH_STATUS_SUCCESS; } +SWITCH_DECLARE(switch_status_t) switch_network_list_add_host_mask(switch_network_list_t *list, const char *host, const char *mask_str, switch_bool_t ok) +{ + return switch_network_list_add_host_port_mask(list, host, mask_str, ok, NULL); +} + SWITCH_DECLARE(int) switch_parse_cidr(const char *string, ip_t *ip, ip_t *mask, uint32_t *bitp) { From 254b739b96abaec50a0cfaf9d06955b9e0c26390 Mon Sep 17 00:00:00 2001 From: Luis Azedo <luis@2600hz.com> Date: Tue, 13 Mar 2018 19:59:41 +0000 Subject: [PATCH 3/4] FS-11025 [mod_sofia] use ports for acl check * optionally use port for acl check * optionally lookup acl token from header * optionally processed auth only by acl --- src/mod/endpoints/mod_sofia/mod_sofia.h | 4 + src/mod/endpoints/mod_sofia/sofia.c | 138 ++++++++++++++++-------- 2 files changed, 100 insertions(+), 42 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 929fc60db6..f008335338 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -310,6 +310,8 @@ typedef enum { PFLAG_AUTO_INVITE_100, PFLAG_UPDATE_REFRESHER, PFLAG_AUTH_REQUIRE_USER, + PFLAG_AUTH_CALLS_ACL_ONLY, + PFLAG_USE_PORT_FOR_ACL_CHECK, /* No new flags below this line */ PFLAG_MAX @@ -787,6 +789,8 @@ struct sofia_profile { int bind_attempt_interval; char *proxy_notify_events; char *proxy_info_content_types; + char *acl_inbound_x_token_header; + char *acl_proxy_x_token_header; }; diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index cccd6bde80..48a43ef5b7 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -4592,6 +4592,8 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) sofia_clear_pflag(profile, PFLAG_FIRE_TRANFER_EVENTS); sofia_clear_pflag(profile, PFLAG_BLIND_AUTH_ENFORCE_RESULT); sofia_clear_pflag(profile, PFLAG_AUTH_REQUIRE_USER); + sofia_clear_pflag(profile, PFLAG_AUTH_CALLS_ACL_ONLY); + sofia_clear_pflag(profile, PFLAG_USE_PORT_FOR_ACL_CHECK); profile->shutdown_type = "false"; profile->local_network = "localnet.auto"; sofia_set_flag(profile, TFLAG_ENABLE_SOA); @@ -5908,6 +5910,22 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) } else { sofia_clear_pflag(profile, PFLAG_BLIND_AUTH_ENFORCE_RESULT); } + } else if (!strcasecmp(var, "auth-calls-acl-only")) { + if(switch_true(val)) { + sofia_set_pflag(profile, PFLAG_AUTH_CALLS_ACL_ONLY); + } else { + sofia_clear_pflag(profile, PFLAG_AUTH_CALLS_ACL_ONLY); + } + } else if (!strcasecmp(var, "use-port-for-acl-check")) { + if(switch_true(val)) { + sofia_set_pflag(profile, PFLAG_USE_PORT_FOR_ACL_CHECK); + } else { + sofia_clear_pflag(profile, PFLAG_USE_PORT_FOR_ACL_CHECK); + } + } else if (!strcasecmp(var, "apply-inbound-acl-x-token")) { + profile->acl_inbound_x_token_header = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "apply-proxy-acl-x-token")) { + profile->acl_proxy_x_token_header = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "proxy-hold")) { if(switch_true(val)) { sofia_set_pflag(profile, PFLAG_PROXY_HOLD); @@ -10188,14 +10206,23 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia int ok = 1; char *last_acl = NULL; const char *token = NULL; + int acl_port = sofia_test_pflag(profile, PFLAG_USE_PORT_FOR_ACL_CHECK) ? network_port : 0; for (x = 0; x < profile->acl_count; x++) { last_acl = profile->acl[x]; - if ((ok = switch_check_network_list_ip_token(network_ip, last_acl, &token))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "verifying acl \"%s\" for ip/port %s:%i.\n", + switch_str_nil(last_acl), network_ip, acl_port); + if ((ok = switch_check_network_list_ip_port_token(network_ip, acl_port, last_acl, &token))) { if (profile->acl_pass_context[x]) { acl_context = profile->acl_pass_context[x]; } + if(!token && profile->acl_inbound_x_token_header) { + const char * x_auth_token = sofia_glue_get_unknown_header(sip, profile->acl_inbound_x_token_header); + if (!zstr(x_auth_token)) { + token = x_auth_token; + } + } break; } @@ -10220,76 +10247,103 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia } } else { int network_ip_is_proxy = 0; + const char* x_auth_ip = network_ip; /* Check if network_ip is a proxy allowed to send us calls */ if (profile->proxy_acl_count) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%d acls to check for proxy\n", profile->proxy_acl_count); - } - - for (x = 0; x < profile->proxy_acl_count; x++) { - last_acl = profile->proxy_acl[x]; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "checking %s against acl %s\n", network_ip, last_acl); - if (switch_check_network_list_ip_token(network_ip, last_acl, &token)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s is a proxy according to the %s acl\n", network_ip, last_acl); - network_ip_is_proxy = 1; - break; + for (x = 0; x < profile->proxy_acl_count; x++) { + last_acl = profile->proxy_acl[x]; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "checking %s against acl %s\n", network_ip, last_acl); + if (switch_check_network_list_ip_port_token(network_ip, network_port, last_acl, &token)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s is a proxy according to the %s acl\n", network_ip, last_acl); + network_ip_is_proxy = 1; + break; + } } } + /* * if network_ip is a proxy allowed to send calls, check for auth * ip header and see if it matches against the inbound acl */ if (network_ip_is_proxy) { - const char * x_auth_ip = sofia_glue_get_unknown_header(sip, "X-AUTH-IP"); - const char * x_auth_token = sofia_glue_get_unknown_header(sip, "X-AUTH-Token"); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "network ip is a proxy\n"); + const char * x_auth_port = sofia_glue_get_unknown_header(sip, "X-AUTH-PORT"); + int x_auth_port_i = sofia_test_pflag(profile, PFLAG_USE_PORT_FOR_ACL_CHECK) ? zstr(x_auth_port) ? 0 : atoi(x_auth_port) : 0; - if (!zstr(x_auth_token) && !zstr(x_auth_ip)) { - switch_copy_string(proxied_client_ip, x_auth_ip, sizeof(proxied_client_ip)); - token = x_auth_token; - ok = 1; - } else if (!zstr(x_auth_ip)) { - for (x = 0; x < profile->acl_count; x++) { - last_acl = profile->acl[x]; - if ((ok = switch_check_network_list_ip_token(x_auth_ip, last_acl, &token))) { - switch_copy_string(proxied_client_ip, x_auth_ip, sizeof(proxied_client_ip)); - break; - } + /* + * if network_ip is a proxy allowed to send calls, + * authorize call if proxy provided matched token header + */ + if (profile->acl_proxy_x_token_header) { + const char * x_auth_token = sofia_glue_get_unknown_header(sip, profile->acl_proxy_x_token_header); + if (!zstr(x_auth_token)) { + token = x_auth_token; + switch_copy_string(proxied_client_ip, x_auth_ip, sizeof(proxied_client_ip)); + ok = 1; } } - if (!ok) { - if (!sofia_test_pflag(profile, PFLAG_AUTH_CALLS)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "IP %s Rejected by acl \"%s\"\n", x_auth_ip, switch_str_nil(last_acl)); - nua_respond(nh, SIP_403_FORBIDDEN, TAG_END()); - goto fail; - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IP %s Rejected by acl \"%s\". Falling back to Digest auth.\n", - x_auth_ip, switch_str_nil(last_acl)); + if (!ok && (x_auth_ip = sofia_glue_get_unknown_header(sip, "X-AUTH-IP")) && !zstr(x_auth_ip)) { + for (x = 0; x < profile->acl_count; x++) { + last_acl = profile->acl[x]; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "verifying acl \"%s\" from proxy for ip/port %s:%i.\n", + switch_str_nil(last_acl), x_auth_ip, x_auth_port_i); + if ((ok = switch_check_network_list_ip_port_token(x_auth_ip, x_auth_port_i, last_acl, &token))) { + + switch_copy_string(proxied_client_ip, x_auth_ip, sizeof(proxied_client_ip)); + + if (profile->acl_pass_context[x]) { + acl_context = profile->acl_pass_context[x]; + } + + break; + } + + if (profile->acl_fail_context[x]) { + acl_context = profile->acl_fail_context[x]; + } else { + acl_context = NULL; + } } } else { - if (token) { - switch_set_string(acl_token, token); - } + x_auth_ip = network_ip; + } + } + + if (ok) { + if (token) { + switch_set_string(acl_token, token); + } + if (sofia_test_pflag(profile, PFLAG_AUTH_CALLS)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IP %s Approved by acl \"%s[%s]\". Access Granted.\n", - proxied_client_ip, switch_str_nil(last_acl), acl_token); + x_auth_ip, switch_str_nil(last_acl), acl_token); switch_set_string(sip_acl_authed_by, last_acl); switch_set_string(sip_acl_token, acl_token); is_auth = 1; } } else { if (!sofia_test_pflag(profile, PFLAG_AUTH_CALLS)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "IP %s Rejected by acl \"%s\"\n", network_ip, switch_str_nil(last_acl)); - nua_respond(nh, SIP_403_FORBIDDEN, TAG_END()); - goto fail; - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IP %s Rejected by acl \"%s\". Falling back to Digest auth.\n", - network_ip, switch_str_nil(last_acl)); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "IP %s Rejected by acl \"%s\"\n", x_auth_ip, switch_str_nil(last_acl)); + if (!acl_context) { + nua_respond(nh, SIP_403_FORBIDDEN, TAG_END()); + goto fail; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IP %s Rejected by acl \"%s\". Falling back to Digest auth.\n", + x_auth_ip, switch_str_nil(last_acl)); + } } } } } + if (!is_auth && sofia_test_pflag(profile, PFLAG_AUTH_CALLS) && sofia_test_pflag(profile, PFLAG_AUTH_CALLS_ACL_ONLY)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IP/Port %s %i Rejected by acls and auth-calls-acl-only flag is set, rejecting call\n", + network_ip, network_port); + nua_respond(nh, SIP_403_FORBIDDEN, TAG_END()); + goto fail; + } + if (!is_auth && sofia_test_pflag(profile, PFLAG_AUTH_CALLS) && sofia_test_pflag(profile, PFLAG_BLIND_AUTH)) { char *user; switch_status_t blind_result = SWITCH_STATUS_FALSE; From 6ceb9885d4bd10763b982255af732e3e6a8936ee Mon Sep 17 00:00:00 2001 From: lazedo <luis.azedo@factorlusitano.com> Date: Tue, 5 Mar 2019 12:14:45 +0000 Subject: [PATCH 4/4] FS-9956 [mod_sofia] retain user lookup in blind & acl auth * retains lookup to be used after caller context is created and switch_ivr_set_user_xml is called --- src/mod/endpoints/mod_sofia/sofia.c | 77 ++++++++++++++++++++--------- 1 file changed, 54 insertions(+), 23 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 48a43ef5b7..bf21a353ab 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -10017,6 +10017,46 @@ void sofia_handle_sip_i_reinvite(switch_core_session_t *session, } +switch_status_t sofia_locate_user(char* user, switch_core_session_t *session, sip_t const *sip, switch_xml_t* x_user) +{ + char *username, *domain; + switch_event_t *v_event = NULL; + switch_status_t result = SWITCH_STATUS_FALSE; + + if (!session) { + return SWITCH_STATUS_FALSE; + } + + if (zstr(user)) { + return SWITCH_STATUS_FALSE; + } + + if (!(username = switch_core_session_strdup(session, user))) { + return SWITCH_STATUS_FALSE; + } + + if (!(domain = strchr(username, '@'))) { + return SWITCH_STATUS_FALSE; + } + + *domain++ = '\0'; + + if (switch_event_create(&v_event, SWITCH_EVENT_REQUEST_PARAMS) == SWITCH_STATUS_SUCCESS) { + sip_unknown_t *un; + for (un = sip->sip_unknown; un; un = un->un_next) { + switch_event_add_header_string(v_event, SWITCH_STACK_BOTTOM, un->un_name, un->un_value); + }; + } + + result = switch_xml_locate_user_merged("id", username, domain, NULL, x_user, v_event); + + if (v_event) { + switch_event_destroy(&v_event); + } + + return result; +} + void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, sofia_dispatch_event_t *de, tagi_t tags[]) { char key[128] = ""; @@ -10345,7 +10385,7 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia } if (!is_auth && sofia_test_pflag(profile, PFLAG_AUTH_CALLS) && sofia_test_pflag(profile, PFLAG_BLIND_AUTH)) { - char *user; + char *user = NULL; switch_status_t blind_result = SWITCH_STATUS_FALSE; if (!strcmp(network_ip, profile->sipip) && network_port == profile->sip_port) { @@ -10354,15 +10394,14 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia if (sip && sip->sip_from) { user = switch_core_session_sprintf(session, "%s@%s", sip->sip_from->a_url->url_user, sip->sip_from->a_url->url_host); - switch_event_create(&v_event, SWITCH_EVENT_REQUEST_PARAMS); - for (un = sip->sip_unknown; un; un = un->un_next) { - switch_event_add_header_string(v_event, SWITCH_STACK_BOTTOM, un->un_name, un->un_value); - }; - blind_result = switch_ivr_set_user_extended(session, user, v_event); - switch_event_destroy(&v_event); + blind_result = sofia_locate_user(user, session, sip, &x_user); } - if(!sofia_test_pflag(profile, PFLAG_BLIND_AUTH_ENFORCE_RESULT) || blind_result == SWITCH_STATUS_SUCCESS) { + if (!sofia_test_pflag(profile, PFLAG_BLIND_AUTH_ENFORCE_RESULT) || blind_result == SWITCH_STATUS_SUCCESS) { is_auth++; + } else if (sofia_test_pflag(profile, PFLAG_BLIND_AUTH_ENFORCE_RESULT)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "blind auth enforce result enabled and couldn't find user %s, rejecting call\n", user); + nua_respond(nh, SIP_403_FORBIDDEN, TAG_END()); + goto fail; } } @@ -10406,21 +10445,13 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia if (*acl_token) { switch_channel_set_variable(channel, "acl_token", acl_token); - if (strchr(acl_token, '@')) { - switch_event_create(&v_event, SWITCH_EVENT_REQUEST_PARAMS); - for (un = sip->sip_unknown; un; un = un->un_next) { - switch_event_add_header_string(v_event, SWITCH_STACK_BOTTOM, un->un_name, un->un_value); - }; - if (switch_ivr_set_user_extended(session, acl_token, v_event) == SWITCH_STATUS_SUCCESS) { - switch_event_destroy(&v_event); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Authenticating user %s\n", acl_token); - } else { - switch_event_destroy(&v_event); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Error Authenticating user %s\n", acl_token); - if(sofia_test_pflag(profile, PFLAG_AUTH_REQUIRE_USER)) { - nua_respond(nh, SIP_480_TEMPORARILY_UNAVAILABLE, TAG_END()); - goto fail; - } + if (sofia_locate_user(acl_token, session, sip, &x_user) == SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Authenticating user %s\n", acl_token); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Error Authenticating user %s\n", acl_token); + if (sofia_test_pflag(profile, PFLAG_AUTH_REQUIRE_USER)) { + nua_respond(nh, SIP_480_TEMPORARILY_UNAVAILABLE, TAG_END()); + goto fail; } } }