Skip to content

Commit

Permalink
Merge pull request #1238 from tdimitrov/sec-agree
Browse files Browse the repository at this point in the history
ims_registrar_pcscf: Add support for sec-agree parameters parsing
  • Loading branch information
ngvoice committed Sep 20, 2017
2 parents be80d95 + 52f9bc1 commit 0c47c62
Show file tree
Hide file tree
Showing 3 changed files with 244 additions and 2 deletions.
23 changes: 21 additions & 2 deletions src/modules/ims_registrar_pcscf/save.c
Expand Up @@ -50,6 +50,7 @@
#include "subscribe.h"

#include "../pua/pua_bind.h"
#include "sec_agree.h"

extern struct tm_binds tmb;
extern usrloc_api_t ul;
Expand Down Expand Up @@ -332,6 +333,15 @@ int save_pending(struct sip_msg* _m, udomain_t* _d) {
if (ci.received_port == 0)
ci.received_port = 5060;

// Parse security parameters
security_t sec_params;
memset(&sec_params, 0, sizeof(security_t));

int ret;
if((ret = cscf_get_security(_m, &sec_params)) != 0) {
LM_ERR("Error parsing sec-agree parameters: %d\n", ret);
}

ul.lock_udomain(_d, &ci.via_host, ci.via_port, ci.via_prot);
if (ul.get_pcontact(_d, &ci, &pcontact) != 0) { //need to insert new contact
LM_DBG("Adding pending pcontact: <%.*s>\n", c->uri.len, c->uri.s);
Expand All @@ -343,10 +353,19 @@ int save_pending(struct sip_msg* _m, udomain_t* _d) {
ul.register_ulcb(pcontact, PCSCF_CONTACT_DELETE | PCSCF_CONTACT_EXPIRE | PCSCF_CONTACT_UPDATE, callback_pcscf_contact_cb, NULL);
}
} else { //contact already exists - update
LM_DBG("Contact already exists - not doing anything for now\n");
LM_DBG("Contact already exists - not doing anything for now\n");
}

// Update security parameters
if(ul.update_temp_security(_d, sec_params.type, &sec_params, pcontact) != 0)
{
LM_ERR("Error updating temp security\n");
}

ul.unlock_udomain(_d, &ci.via_host, ci.via_port, ci.via_prot);

free_security_t(&sec_params);

return 1;

error:
Expand Down Expand Up @@ -422,7 +441,7 @@ int save(struct sip_msg* _m, udomain_t* _d, int _cflags) {
goto error;
}
}else{
//Now some how check if there is a pua record and what the presentity uri is from there - if nothing there
//Now some how check if there is a pua record and what the presentity uri is from there - if nothing there
LM_DBG("No p_associated_uri in 200 OK this must be a de-register - we ignore this - will unsubscribe when the notify is received");
goto done;

Expand Down
207 changes: 207 additions & 0 deletions src/modules/ims_registrar_pcscf/sec_agree.c
@@ -0,0 +1,207 @@
#include "sec_agree.h"

#include "../../core/str.h"
#include "../../core/parser/msg_parser.h"
#include "../../core/mem/mem.h"


static uint32_t parse_digits(str value)
{
uint32_t ret = 0;

int buf_len = value.len+1;
char* buf = (char*)malloc(buf_len);

if(!buf) {
return ret;
}

memset(buf, 0, buf_len);
memcpy(buf, value.s, value.len);

ret = atoll(buf);

free(buf);

return ret;
}

static void process_sec_agree_param(str name, str value, ipsec_t *ret)
{
if(strncasecmp(name.s, "alg", name.len) == 0) {
ret->r_alg = value;
}
else if(strncasecmp(name.s, "prot", name.len) == 0) {
ret->prot = value;
}
else if(strncasecmp(name.s, "mod", name.len) == 0) {
ret->mod = value;
}
else if(strncasecmp(name.s, "ealg", name.len) == 0) {
ret->r_alg = value;
}
else if(strncasecmp(name.s, "spi-c", name.len) == 0) {
ret->spi_uc = parse_digits(value);
}
else if(strncasecmp(name.s, "spi-s", name.len) == 0) {
ret->spi_us = parse_digits(value);
}
else if(strncasecmp(name.s, "port-c", name.len) == 0) {
ret->port_uc = parse_digits(value);
}
else if(strncasecmp(name.s, "port-s", name.len) == 0) {
ret->port_us = parse_digits(value);
}
else {
//unknown parameter
}
}

static int parse_sec_agree(str body, security_t *params)
{
int i = 0;

str name = {0,0};
str value = {0,0};
str mechanism_name = {0,0};

if(!params) {
return 10;
}

// skip leading whitespace
while(body.len && (body.s[0]==' ' || body.s[0]=='\t' || body.s[0]=='<')){
body.s = body.s + 1;
body.len --;
}

// skip trailing whitespace
while(body.len && (body.s[body.len-1]==' ' || body.s[body.len-1]=='\t')){
body.len--;
}

// skip mechanism name - noone seems to need it
for(i = 0; body.s[i] != ';' && i < body.len; i++);

mechanism_name.s = body.s;
mechanism_name.len = i;

if(strncasecmp(mechanism_name.s, "ipsec-3gpp", 10) != 0) {
//unsupported mechanism
LM_ERR("Unsupported mechanism: %.*s\n", STR_FMT(&mechanism_name));
return 11;
}

params->type = SECURITY_IPSEC;

params->data.ipsec = pkg_malloc(sizeof(ipsec_t));
if(!params->data.ipsec) {
LM_ERR("Error allocating memory for ipsec parameters during sec-agree parsing\n");
return 12;
}

memset(params->data.ipsec, 0, sizeof(ipsec_t));

body.s=body.s+i+1;
body.len=body.len-i-1;

// get the rest of the parameters
i = 0;
while(i <= body.len) {
//look for end of buffer or parameter separator
if(i == body.len || body.s[i] == ';' ) {
if(name.len) {
// if(name.len) => a param name is parsed
// and now i points to the end of its value
value.s = body.s;
value.len = i;
}
//else - name is not read but there is a value
//so there is some error - skip ahead
body.s=body.s+i+1;
body.len=body.len-i-1;

i=0;

if(name.len && value.len) {
process_sec_agree_param(name, value, params->data.ipsec);
}
//else - something's wrong. Ignore!

//processing is done - reset
name.len=0;
value.len=0;
}
//look for param=value separator
else if(body.s[i] == '=') {
name.s = body.s;
name.len = i;

//position saved - skip ahead
body.s=body.s+i+1;
body.len=body.len-i-1;

i=0;
}
//nothing interesting - move on
else {
i++;
}
}

return 0;
}

static str s_security_client={"Security-Client",15};
static str s_security_server={"Security-Server",15};
static str s_security_verify={"Security-Verify",15};
/**
* Looks for the Security-Client header
* @param msg - the sip message
* @param hr - ptr to return the found hdr_field
* @param params - ptr to struct sec_agree_params, where parsed values will be saved
* @returns 0 on success, error code on failure
*/
int cscf_get_security(struct sip_msg *msg, security_t *params)
{
struct hdr_field *h = NULL;

if (!msg) return 1;
if (!params) return 2;

if (parse_headers(msg, HDR_EOH_F, 0)<0) {
return 3;
}

h = msg->headers;
while(h)
{
if ((h->name.len == s_security_client.len && strncasecmp(h->name.s, s_security_client.s, s_security_client.len)==0) ||
(h->name.len == s_security_server.len && strncasecmp(h->name.s, s_security_server.s, s_security_server.len)==0) ||
(h->name.len == s_security_verify.len && strncasecmp(h->name.s, s_security_verify.s, s_security_verify.len)==0) )
{
params->sec_header = h->name;
return parse_sec_agree(h->body, params);
}

h = h->next;
}

return 4;
}

void free_security_t(security_t *params)
{
switch (params->type)
{
case SECURITY_IPSEC:
pkg_free(params->data.ipsec);
break;

case SECURITY_TLS:
pkg_free(params->data.ipsec);
break;

//default: Nothing to deallocate
}
}
16 changes: 16 additions & 0 deletions src/modules/ims_registrar_pcscf/sec_agree.h
@@ -0,0 +1,16 @@
#ifndef SEC_AGREE_H
#define SEC_AGREE_H

#include "../ims_usrloc_pcscf/usrloc.h"

/**
* Looks for the Security-Client header
* @param msg - the sip message
* @param params - ptr to struct sec_agree_params, where parsed values will be saved
* @returns 0 on success, error code on failure
*/
int cscf_get_security(struct sip_msg *msg, security_t *params);

void free_security_t(security_t *params);

#endif // SEC_AGREE_H

0 comments on commit 0c47c62

Please sign in to comment.