diff --git a/conf/freeswitch.xml b/conf/freeswitch.xml
index 59658299a8..cb52a04975 100644
--- a/conf/freeswitch.xml
+++ b/conf/freeswitch.xml
@@ -123,7 +123,15 @@
+
+
+
+
+
+
+
+
diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c
index 6ff0efc846..197212083e 100644
--- a/src/mod/endpoints/mod_sofia/mod_sofia.c
+++ b/src/mod/endpoints/mod_sofia/mod_sofia.c
@@ -102,6 +102,8 @@ typedef struct sip_alias_node sip_alias_node_t;
typedef enum {
PFLAG_AUTH_CALLS = (1 << 0),
+ PFLAG_BLIND_REG = (1 << 1),
+ PFLAG_AUTH_ALL = (1 << 2),
} PFLAGS;
typedef enum {
@@ -200,6 +202,7 @@ struct private_object {
char *remote_sdp_str;
char *local_sdp_str;
char *dest;
+ char *key;
unsigned long rm_rate;
switch_payload_t pt;
switch_mutex_t *flag_mutex;
@@ -253,6 +256,8 @@ static void do_invite(switch_core_session_t *session);
static uint8_t negotiate_sdp(switch_core_session_t *session, sdp_session_t *sdp);
+static char *get_auth_data(char *dbname, char *nonce, char *npassword, uint32_t len, switch_mutex_t *mutex);
+
static void sip_i_state(int status,
char const *phrase,
nua_t *nua,
@@ -297,6 +302,108 @@ static switch_status_t config_sofia(int reload);
/* BODY OF THE MODULE */
/*************************************************************************************************************************************************************/
+typedef enum {
+ AUTH_OK,
+ AUTH_FORBIDDEN,
+ AUTH_STALE,
+} auth_res_t;
+
+static auth_res_t parse_auth(sofia_profile_t *profile, sip_authorization_t const *authorization, char *regstr, char *np, uint32_t nplen)
+{
+ int index;
+ char *cur;
+ su_md5_t ctx;
+ char uridigest[2 * SU_MD5_DIGEST_SIZE + 1];
+ char bigdigest[2 * SU_MD5_DIGEST_SIZE + 1];
+ char *nonce, *uri, *qop, *cnonce, *nc, *response, *input = NULL, *input2 = NULL;
+ auth_res_t ret = AUTH_OK;
+ char *npassword = NULL;
+ nonce = uri = qop = cnonce = nc = response = NULL;
+
+
+
+ for(index = 0; (cur=(char*)authorization->au_params[index]); index++) {
+ char *var, *val, *p, *work;
+ var = val = work = NULL;
+ if ((work = strdup(cur))) {
+ var = work;
+ if ((val = strchr(var, '='))) {
+ *val++ = '\0';
+ while(*val == '"') {
+ *val++ = '\0';
+ }
+ if ((p = strchr(val, '"'))) {
+ *p = '\0';
+ }
+
+ if (!strcasecmp(var, "nonce")) {
+ nonce = strdup(val);
+ } else if (!strcasecmp(var, "uri")) {
+ uri = strdup(val);
+ } else if (!strcasecmp(var, "qop")) {
+ qop = strdup(val);
+ } else if (!strcasecmp(var, "cnonce")) {
+ cnonce = strdup(val);
+ } else if (!strcasecmp(var, "response")) {
+ response = strdup(val);
+ } else if (!strcasecmp(var, "nc")) {
+ nc = strdup(val);
+ }
+ }
+
+ free(work);
+ }
+ }
+
+ if (switch_strlen_zero(np)) {
+ if (!get_auth_data(profile->dbname, nonce, np, nplen, profile->reg_mutex)) {
+ ret = AUTH_STALE;
+ goto end;
+ }
+ }
+
+ npassword = np;
+
+ if ((input = switch_core_db_mprintf("%s:%q", regstr, uri))) {
+ su_md5_init(&ctx);
+ su_md5_strupdate(&ctx, input);
+ su_md5_hexdigest(&ctx, uridigest);
+ su_md5_deinit(&ctx);
+ }
+
+ if ((input2 = switch_core_db_mprintf("%q:%q:%q:%q:%q:%q", npassword, nonce, nc, cnonce, qop, uridigest))) {
+ memset(&ctx, 0, sizeof(ctx));
+ su_md5_init(&ctx);
+ su_md5_strupdate(&ctx, input2);
+ su_md5_hexdigest(&ctx, bigdigest);
+ su_md5_deinit(&ctx);
+
+ if (!strcasecmp(bigdigest, response)) {
+ ret = AUTH_OK;
+ } else {
+ ret = AUTH_FORBIDDEN;
+ }
+ }
+
+ end:
+ if (input) {
+ switch_core_db_free(input);
+ }
+ if (input2) {
+ switch_core_db_free(input2);
+ }
+ switch_safe_free(nonce);
+ switch_safe_free(uri);
+ switch_safe_free(qop);
+ switch_safe_free(cnonce);
+ switch_safe_free(nc);
+ switch_safe_free(response);
+
+ return ret;
+
+}
+
+
static void execute_sql(char *dbname, char *sql, switch_mutex_t *mutex)
{
switch_core_db_t *db;
@@ -1391,7 +1498,7 @@ static uint8_t negotiate_sdp(switch_core_session_t *session, sdp_session_t *sdp)
for (map = m->m_rtpmaps; map; map = map->rm_next) {
int32_t i;
- if (!strcmp(map->rm_encoding, "telephone-event")) {
+ if (!strcasecmp(map->rm_encoding, "telephone-event")) {
tech_pvt->te = (switch_payload_t)map->rm_pt;
}
@@ -1737,7 +1844,9 @@ static uint8_t handle_register(nua_t *nua,
nua_handle_t *nh,
switch_core_session_t *session,
sip_t const *sip,
- sofia_regtype_t regtype)
+ sofia_regtype_t regtype,
+ char *key,
+ uint32_t keylen)
{
sip_from_t const *from = sip->sip_from;
sip_expires_t const *expires = sip->sip_expires;
@@ -1754,101 +1863,39 @@ static uint8_t handle_register(nua_t *nua,
char *contact_host = (char *) contact->m_url->url_host;
char buf[512];
char *passwd = NULL;
- uint8_t ok = 0, stale = 0, ret = 0;
- long exptime = expires ? expires->ex_delta : 60;
+ uint8_t stale = 0, ret = 0, forbidden = 0;
+ auth_res_t auth_res;
+
+ long exptime = 60;
+
+ if (expires) {
+ exptime = expires->ex_delta;
+ } else if (contact->m_expires) {
+ exptime = atol(contact->m_expires);
+ }
if (regtype == REG_REGISTER) {
authorization = sip->sip_authorization;
} else if (regtype == REG_INVITE) {
authorization = sip->sip_proxy_authorization;
}
-
+
+ if ((profile->pflags & PFLAG_BLIND_REG)) {
+ goto reg;
+ }
+
if (authorization) {
- int index;
- char *cur;
- char npassword[512] = "";
- char *nonce, *uri, *qop, *cnonce, *nc, *input, *response;
- nonce = uri = qop = cnonce = nc = response = NULL;
- for(index = 0; (cur=(char*)authorization->au_params[index]); index++) {
- char *var, *val, *p, *work;
- var = val = work = NULL;
- if ((work = strdup(cur))) {
- var = work;
- if ((val = strchr(var, '='))) {
- *val++ = '\0';
- while(*val == '"') {
- *val++ = '\0';
- }
- if ((p = strchr(val, '"'))) {
- *p = '\0';
- }
+ auth_res = parse_auth(profile, authorization, (char *)sip->sip_request->rq_method_name, key, keylen);
- if (!strcasecmp(var, "nonce")) {
- nonce = strdup(val);
- } else if (!strcasecmp(var, "uri")) {
- uri = strdup(val);
- } else if (!strcasecmp(var, "qop")) {
- qop = strdup(val);
- } else if (!strcasecmp(var, "cnonce")) {
- cnonce = strdup(val);
- } else if (!strcasecmp(var, "response")) {
- response = strdup(val);
- } else if (!strcasecmp(var, "nc")) {
- nc = strdup(val);
- }
- }
-
- free(work);
- }
- }
-
- if (get_auth_data(profile->dbname, nonce, npassword, sizeof(npassword), profile->reg_mutex)) {
- su_md5_t ctx;
- char uridigest[2 * SU_MD5_DIGEST_SIZE + 1];
- char bigdigest[2 * SU_MD5_DIGEST_SIZE + 1];
- char *regstr;
-
- if (regtype == REG_REGISTER) {
- regstr = "REGISTER";
- } else if (regtype == REG_INVITE) {
- regstr = "INVITE";
+ if (auth_res != AUTH_OK && auth_res != AUTH_STALE) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "send %s for [%s@%s]\n",
+ forbidden ? "forbidden" : "challange",
+ from_user, from_host);
+ if (auth_res == AUTH_FORBIDDEN) {
+ nua_respond(nh, SIP_403_FORBIDDEN, TAG_END());
} else {
- regstr = "WTF";
+ nua_respond(nh, SIP_401_UNAUTHORIZED, TAG_END());
}
-
- input = switch_core_db_mprintf("%s:%q", regstr, uri);
- su_md5_init(&ctx);
- su_md5_strupdate(&ctx, input);
- su_md5_hexdigest(&ctx, uridigest);
- su_md5_deinit(&ctx);
- switch_core_db_free(input);
-
- input = switch_core_db_mprintf("%q:%q:%q:%q:%q:%q", npassword, nonce, nc, cnonce, qop, uridigest);
-
- memset(&ctx, 0, sizeof(ctx));
- su_md5_init(&ctx);
- su_md5_strupdate(&ctx, input);
- su_md5_hexdigest(&ctx, bigdigest);
- su_md5_deinit(&ctx);
-
- if (!strcasecmp(bigdigest, response)) {
- ok = 1;
- }
-
- switch_core_db_free(input);
- } else {
- stale = 1;
- }
-
- switch_safe_free(nonce);
- switch_safe_free(uri);
- switch_safe_free(qop);
- switch_safe_free(cnonce);
- switch_safe_free(nc);
- switch_safe_free(response);
-
- if (!ok && !stale) {
- nua_respond(nh, SIP_401_UNAUTHORIZED, TAG_END());
return 1;
}
}
@@ -1905,6 +1952,7 @@ static uint8_t handle_register(nua_t *nua,
switch_uuid_get(&uuid);
switch_uuid_format(uuid_str, &uuid);
+
sql = switch_core_db_mprintf("delete from sip_authentication where user='%q'and host='%q';\n"
"insert into sip_authentication values('%q','%q','%q','%q', %ld)",
from_user,
@@ -1915,11 +1963,12 @@ static uint8_t handle_register(nua_t *nua,
uuid_str,
time(NULL) + 60);
- auth_str = switch_core_db_mprintf("Digest realm=\"%q\", nonce=\"%q\",%s algorithm=MD5, qop=\"auth-int\"", from_host, uuid_str,
+ auth_str = switch_core_db_mprintf("Digest realm=\"%q\", nonce=\"%q\",%s algorithm=MD5, qop=\"auth\"", from_host, uuid_str,
stale ? " stale=\"true\"," : "");
if (regtype == REG_REGISTER) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "invalid for [%s@%s]\n", from_user, from_host);
nua_respond(nh, SIP_401_UNAUTHORIZED,
SIPTAG_WWW_AUTHENTICATE_STR(auth_str),
TAG_END());
@@ -1944,6 +1993,7 @@ static uint8_t handle_register(nua_t *nua,
return ret;
}
}
+ reg:
if (!find_reg_url(profile, from_user, from_host, buf, sizeof(buf))) {
sql = switch_core_db_mprintf("insert into sip_registrations values ('%q','%q','sip:%q@%q',%ld)",
@@ -2006,16 +2056,16 @@ static void sip_i_invite(nua_t *nua,
tagi_t tags[])
{
+ char key[128] = "";
if (!session) {
if ((profile->pflags & PFLAG_AUTH_CALLS)) {
- if (handle_register(nua, profile, nh, session, sip, REG_INVITE)) {
+ if (handle_register(nua, profile, nh, session, sip, REG_INVITE, key, sizeof(key))) {
return;
}
}
-
if ((session = switch_core_session_request(&sofia_endpoint_interface, NULL))) {
private_object_t *tech_pvt = NULL;
switch_channel_t *channel = NULL;
@@ -2031,6 +2081,10 @@ static void sip_i_invite(nua_t *nua,
return;
}
+ if (!switch_strlen_zero(key)) {
+ tech_pvt->key = switch_core_session_strdup(session, key);
+ }
+
displayname = switch_core_session_strdup(session, (char *) from->a_display);
if (*displayname == '"') {
char *p;
@@ -2077,7 +2131,7 @@ static void sip_i_register(nua_t *nua,
sip_t const *sip,
tagi_t tags[])
{
- handle_register(nua, profile, nh, session, sip, REG_REGISTER);
+ handle_register(nua, profile, nh, session, sip, REG_REGISTER, NULL, 0);
}
static void event_callback(nua_event_t event,
@@ -2090,14 +2144,43 @@ static void event_callback(nua_event_t event,
sip_t const *sip,
tagi_t tags[])
{
+ struct private_object *tech_pvt = NULL;
+ auth_res_t auth_res = AUTH_FORBIDDEN;
+
if (session) {
if (switch_core_session_read_lock(session) != SWITCH_STATUS_SUCCESS) {
/* too late */
return;
}
+ tech_pvt = switch_core_session_get_private(session);
+ }
+
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "event [%s] status [%d][%s] %s\n",
+ nua_event_name (event), status, phrase,
+ session ? switch_channel_get_name(switch_core_session_get_channel(session)) : "no session"
+ );
+
+ if ((profile->pflags & PFLAG_AUTH_ALL) && tech_pvt && tech_pvt->key && sip) {
+ sip_authorization_t const *authorization = NULL;
+
+ if (sip->sip_authorization) {
+ authorization = sip->sip_authorization;
+ } else if (sip->sip_proxy_authorization) {
+ authorization = sip->sip_proxy_authorization;
+ }
+
+ if (authorization) {
+ auth_res = parse_auth(profile, authorization, (char *)sip->sip_request->rq_method_name, tech_pvt->key, strlen(tech_pvt->key));
+ }
+
+ if (auth_res != AUTH_OK) {
+ switch_channel_t *channel = switch_core_session_get_channel(tech_pvt->session);
+ switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+ nua_respond(nh, SIP_401_UNAUTHORIZED, TAG_END());
+ return;
+ }
}
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "channel [%s] event [%s] status [%d] [%s]\n",
- session ? switch_channel_get_name(switch_core_session_get_channel(session)) : "null",nua_event_name (event), status, phrase);
switch (event) {
case nua_r_shutdown:
@@ -2371,15 +2454,15 @@ static switch_status_t config_sofia(int reload)
char *var = (char *) switch_xml_attr_soft(param, "name");
char *val = (char *) switch_xml_attr_soft(param, "value");
- if (!strcmp(var, "debug")) {
+ if (!strcasecmp(var, "debug")) {
profile->debug = atoi(val);
- } else if (!strcmp(var, "use-rtp-timer") && switch_true(val)) {
+ } else if (!strcasecmp(var, "use-rtp-timer") && switch_true(val)) {
switch_set_flag(profile, TFLAG_TIMER);
- } else if (!strcmp(var, "rfc2833-pt")) {
+ } else if (!strcasecmp(var, "rfc2833-pt")) {
profile->te = (switch_payload_t) atoi(val);
- } else if (!strcmp(var, "sip-port")) {
+ } else if (!strcasecmp(var, "sip-port")) {
profile->sip_port = atoi(val);
- } else if (!strcmp(var, "vad")) {
+ } else if (!strcasecmp(var, "vad")) {
if (!strcasecmp(val, "in")) {
switch_set_flag(profile, TFLAG_VAD_IN);
} else if (!strcasecmp(val, "out")) {
@@ -2390,31 +2473,39 @@ static switch_status_t config_sofia(int reload)
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invald option %s for VAD\n", val);
}
- } else if (!strcmp(var, "ext-rtp-ip")) {
+ } else if (!strcasecmp(var, "ext-rtp-ip")) {
profile->extrtpip = switch_core_strdup(profile->pool, val);
- } else if (!strcmp(var, "rtp-ip")) {
+ } else if (!strcasecmp(var, "rtp-ip")) {
profile->rtpip = switch_core_strdup(profile->pool, val);
- } else if (!strcmp(var, "sip-ip")) {
+ } else if (!strcasecmp(var, "sip-ip")) {
profile->sipip = switch_core_strdup(profile->pool, val);
- } else if (!strcmp(var, "sip-domain")) {
+ } else if (!strcasecmp(var, "sip-domain")) {
profile->sipdomain = switch_core_strdup(profile->pool, val);
- } else if (!strcmp(var, "rtp-timer-name")) {
+ } else if (!strcasecmp(var, "rtp-timer-name")) {
profile->timer_name = switch_core_strdup(profile->pool, val);
- } else if (!strcmp(var, "auth-calls")) {
+ } else if (!strcasecmp(var, "auth-calls")) {
if (switch_true(val)) {
profile->pflags |= PFLAG_AUTH_CALLS;
}
- } else if (!strcmp(var, "ext-sip-ip")) {
+ } else if (!strcasecmp(var, "accept-blind-reg")) {
+ if (switch_true(val)) {
+ profile->pflags |= PFLAG_BLIND_REG;
+ }
+ } else if (!strcasecmp(var, "auth-all-packets")) {
+ if (switch_true(val)) {
+ profile->pflags |= PFLAG_AUTH_ALL;
+ }
+ } else if (!strcasecmp(var, "ext-sip-ip")) {
profile->extsipip = switch_core_strdup(profile->pool, val);
- } else if (!strcmp(var, "bitpacking")) {
+ } else if (!strcasecmp(var, "bitpacking")) {
if (!strcasecmp(val, "aal2")) {
profile->codec_flags = SWITCH_CODEC_FLAG_AAL2;
}
- } else if (!strcmp(var, "username")) {
+ } else if (!strcasecmp(var, "username")) {
profile->username = switch_core_strdup(profile->pool, val);
- } else if (!strcmp(var, "context")) {
+ } else if (!strcasecmp(var, "context")) {
profile->context = switch_core_strdup(profile->pool, val);
- } else if (!strcmp(var, "alias")) {
+ } else if (!strcasecmp(var, "alias")) {
sip_alias_node_t *node;
if ((node = switch_core_alloc(profile->pool, sizeof(*node)))) {
if ((node->url = switch_core_strdup(profile->pool, val))) {
@@ -2422,16 +2513,16 @@ static switch_status_t config_sofia(int reload)
profile->aliases = node;
}
}
- } else if (!strcmp(var, "dialplan")) {
+ } else if (!strcasecmp(var, "dialplan")) {
profile->dialplan = switch_core_strdup(profile->pool, val);
- } else if (!strcmp(var, "max-calls")) {
+ } else if (!strcasecmp(var, "max-calls")) {
profile->max_calls = atoi(val);
- } else if (!strcmp(var, "codec-prefs")) {
+ } else if (!strcasecmp(var, "codec-prefs")) {
profile->codec_string = switch_core_strdup(profile->pool, val);
profile->codec_order_last = switch_separate_string(profile->codec_string, ',', profile->codec_order, SWITCH_MAX_CODECS);
- } else if (!strcmp(var, "codec-ms")) {
+ } else if (!strcasecmp(var, "codec-ms")) {
profile->codec_ms = atoi(val);
- } else if (!strcmp(var, "dtmf-duration")) {
+ } else if (!strcasecmp(var, "dtmf-duration")) {
int dur = atoi(val);
if (dur > 10 && dur < 8000) {
profile->dtmf_duration = dur;
@@ -2486,7 +2577,7 @@ static void event_handler(switch_event_t *event)
{
char *subclass, *sql;
- if ((subclass = switch_event_get_header(event, "orig-event-subclass")) && !strcmp(subclass, MY_EVENT_REGISTER)) {
+ if ((subclass = switch_event_get_header(event, "orig-event-subclass")) && !strcasecmp(subclass, MY_EVENT_REGISTER)) {
char *from_user = switch_event_get_header(event, "orig-from-user");
char *from_host = switch_event_get_header(event, "orig-from-host");
char *contact_user = switch_event_get_header(event, "orig-contact-user");