#include <sofia-sip/sip_header.h>
#include <sofia-sip/stun.h>
#include <sofia-sip/stun_tag.h>
+#include <sofia-sip/su_md5.h>
#ifndef SOFIA_SIP_GCC_4_8_PATCH_APLLIED
#warning ********************************************************
int options_interval;
char auth_user[128];
char auth_password[128];
+ char auth_realm[128];
+ char auth_nonce[128];
su_root_t *root;
nua_t *nua;
add_work(&p_s_delete, delete_event, this, 0);
p_s_handle = 0;
p_s_magic = 0;
+ memset(&p_s_auth_nonce, 0, sizeof(p_s_auth_nonce));
memset(&p_s_rtp_fd, 0, sizeof(p_s_rtp_fd));
memset(&p_s_rtcp_fd, 0, sizeof(p_s_rtcp_fd));
memset(&p_s_rtp_sin_local, 0, sizeof(p_s_rtp_sin_local));
return ip;
}
+/* some simple nonce generator */
+static void generate_nonce(char *result)
+{
+ UPRINT(result, "%08x", (unsigned int)random());
+ result += 8;
+ UPRINT(result, "%08x", (unsigned int)random());
+ result += 8;
+ UPRINT(result, "%08x", (unsigned int)random());
+ result += 8;
+ UPRINT(result, "%08x", (unsigned int)random());
+}
+
+/* check authorization */
+static int check_authorization(sip_authorization_t const *authorization, const char *regstr, const char *check_user, const char *check_pass, const char *check_realm, const char *check_nonce, const char **auth_text)
+{
+ int ret = 500;
+ *auth_text = "Internal Server Error";
+
+ char *username = NULL;
+ char *realm = NULL;
+ char *nonce = NULL;
+ char *uri = NULL;
+ char *qop = NULL;
+ char *cnonce = NULL;
+ char *nc = NULL;
+ char *response = NULL;
+
+ int indexnum;
+ const char *cur;
+
+ char temp[256], first_digest[2 * SU_MD5_DIGEST_SIZE + 1], second_digest[2 * SU_MD5_DIGEST_SIZE + 1], third_digest[2 * SU_MD5_DIGEST_SIZE + 1];
+ su_md5_t md5_ctx;
+
+ if (!check_nonce || !check_nonce[0] || !authorization || !authorization->au_params) {
+ if (!strcmp(regstr, "REGISTER")) {
+ *auth_text = "Unauthorized";
+ ret = 401;
+ } else {
+ *auth_text = "Proxy Authentication Required";
+ ret = 407;
+ }
+ goto end;
+ }
+
+ /* parse header (stolen from freeswitch) */
+ for (indexnum = 0; (cur = authorization->au_params[indexnum]); indexnum++) {
+ 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';
+ }
+
+ PDEBUG(DEBUG_SIP, "Found in Auth header: %s = %s\n", var, val);
+ if (!strcasecmp(var, "username")) {
+ username = strdup(val);
+ } else if (!strcasecmp(var, "realm")) {
+ realm = strdup(val);
+ } else 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 (!username || !realm || !nonce || ! uri || !response) {
+ *auth_text = "Authorization header incomplete";
+ ret = 400;
+ goto end;
+ }
+
+ if (!!strcmp(username, check_user)) {
+ *auth_text = "Authorization Username Missmatch";
+ ret = 403;
+ goto end;
+ }
+ if (!!strcmp(realm, check_realm)) {
+ *auth_text = "Authorization Realm Missmatch";
+ ret = 403;
+ goto end;
+ }
+ if (!!strcmp(nonce, check_nonce)) {
+ *auth_text = "Authorization Nonce Missmatch";
+ ret = 403;
+ goto end;
+ }
+
+ /* perform hash */
+ SPRINT(temp, "%s:%s:%s", check_user, realm, check_pass);
+ PDEBUG(DEBUG_SIP, "First hash: %s\n", temp);
+ su_md5_init(&md5_ctx);
+ su_md5_strupdate(&md5_ctx, temp);
+ su_md5_hexdigest(&md5_ctx, first_digest);
+ su_md5_deinit(&md5_ctx);
+
+ SPRINT(temp, "%s:%s", regstr, uri);
+ PDEBUG(DEBUG_SIP, "First hash: %s\n", temp);
+ su_md5_init(&md5_ctx);
+ su_md5_strupdate(&md5_ctx, temp);
+ su_md5_hexdigest(&md5_ctx, second_digest);
+ su_md5_deinit(&md5_ctx);
+
+ if (nc && cnonce && qop)
+ SPRINT(temp, "%s:%s:%s:%s:%s:%s", first_digest, nonce, nc, cnonce, qop, second_digest);
+ else
+ SPRINT(temp, "%s:%s:%s", first_digest, nonce, second_digest);
+ PDEBUG(DEBUG_SIP, "Third hash: %s\n", temp);
+ su_md5_init(&md5_ctx);
+ su_md5_strupdate(&md5_ctx, temp);
+ su_md5_hexdigest(&md5_ctx, third_digest);
+ su_md5_deinit(&md5_ctx);
+
+ if (!!strcmp(response, third_digest)) {
+ *auth_text = "Authorization Failed";
+ ret = 403;
+ goto end;
+ }
+
+ *auth_text = "Authorization Success";
+ ret = 200;
+
+end:
+ free(username);
+ free(realm);
+ free(nonce);
+ free(uri);
+ free(qop);
+ free(cnonce);
+ free(nc);
+ free(response);
+
+ return ret;
+}
+
/*
* endpoint sends messages to the SIP port
*/
contact = sip->sip_contact;
nua_save_event(nua, saved);
nua_event_data_t const *data = nua_event_data(saved);
+ sip_authorization_t const *authorization;
+ char uri[256] = "";
+ const char *auth_text = NULL;
+ char auth_str[256] = "";
+
+ if (contact->m_url->url_host)
+ SCPY(uri, contact->m_url->url_host);
+ if (contact->m_url->url_port && contact->m_url->url_port[0]) {
+ SCAT(uri, ":");
+ SCAT(uri, contact->m_url->url_port);
+ }
if (!inst->allow_register) {
sip_trace_header(NULL, inst->interface_name, "REGISTER", DIRECTION_IN);
return;
}
- if (contact->m_url->url_host)
- SCPY(inst->remote_peer, contact->m_url->url_host);
- if (contact->m_url->url_port && contact->m_url->url_port[0]) {
- SCAT(inst->remote_peer, ":");
- SCAT(inst->remote_peer, contact->m_url->url_port);
- }
-
sip_trace_header(NULL, inst->interface_name, "REGISTER", DIRECTION_IN);
- add_trace("contact", "uri", "%s", inst->remote_peer);
+ add_trace("contact", "uri", "%s", uri);
+ end_trace();
+
+ sip_trace_header(NULL, inst->interface_name, "Authorization", DIRECTION_IN);
+ if (inst->auth_realm[0]) {
+ authorization = sip->sip_authorization;
+ status = check_authorization(authorization, "REGISTER", inst->auth_user, inst->auth_password, inst->auth_realm, inst->auth_nonce, &auth_text);
+ if (status == 401) {
+ generate_nonce(inst->auth_nonce);
+ SPRINT(auth_str, "Digest realm=\"%s\", nonce=\"%s\", algorithm=MD5, qop=\"auth\"", inst->auth_realm, inst->auth_nonce);
+ }
+ } else {
+ status = 200;
+ auth_text = "Authentication not required";
+ }
+ add_trace("result", NULL, "%s", auth_text);
end_trace();
+ if (status == 200) {
+ SCPY(inst->remote_peer, uri);
+ inst->auth_nonce[0] = '\0';
+ }
+
sip_trace_header(NULL, inst->interface_name, "RESPOND", DIRECTION_OUT);
- add_trace("respond", "value", "200 OK");
- add_trace("reason", NULL, "peer registered");
+ add_trace("respond", "value", "%d", status);
+ add_trace("reason", NULL, "peer registers");
end_trace();
- nua_respond(nh, SIP_200_OK, SIPTAG_CONTACT(sip->sip_contact), NUTAG_WITH_THIS_MSG(data->e_msg), TAG_END());
+ nua_respond(nh, status, auth_text, SIPTAG_CONTACT(sip->sip_contact), NUTAG_WITH_THIS_MSG(data->e_msg), TAG_IF(auth_str[0], SIPTAG_WWW_AUTHENTICATE_STR(auth_str)), TAG_END());
nua_handle_destroy(nh);
inst->register_handle = NULL;
}
int payloads = 0;
unsigned char payload_type;
int media_type;
+ sip_authorization_t const *authorization;
+ const char *auth_text = NULL;
+ char auth_str[256] = "";
interface = getinterfacebyname(inst->interface_name);
if (!interface) {
}
PDEBUG(DEBUG_SIP, "invite received (%s->%s)\n", from, to);
+ sip_trace_header(this, inst->interface_name, "Authorization", DIRECTION_IN);
+ if (inst->auth_realm[0]) {
+ authorization = sip->sip_proxy_authorization;
+ status = check_authorization(authorization, "INVITE", inst->auth_user, inst->auth_password, inst->auth_realm, p_s_auth_nonce, &auth_text);
+ if (status == 401) {
+ generate_nonce(p_s_auth_nonce);
+ SPRINT(auth_str, "Digest realm=\"%s\", nonce=\"%s\", algorithm=MD5, qop=\"auth\"", inst->auth_realm, p_s_auth_nonce);
+ }
+ } else {
+ status = 200;
+ auth_text = "Authentication not required";
+ }
+ add_trace("result", NULL, "%s", auth_text);
+ end_trace();
+
+ if (status == 200) {
+ p_s_auth_nonce[0] = '\0';
+ }
+
sip_trace_header(this, inst->interface_name, "Payload received", DIRECTION_NONE);
ret = parse_sdp(sip, &p_s_rtp_ip_remote, &p_s_rtp_port_remote, payload_types, media_types, &payloads, sizeof(payload_types));
if (!ret) {
}
SCPY(inst->auth_user, interface->sip_auth_user);
SCPY(inst->auth_password, interface->sip_auth_password);
+ SCPY(inst->auth_realm, interface->sip_auth_realm);
inst->register_interval = interface->sip_register_interval;
inst->options_interval = interface->sip_options_interval;