mirror of https://github.com/sipwise/kamailio.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
320 lines
8.6 KiB
320 lines
8.6 KiB
/*
|
|
* $Id$
|
|
*
|
|
* Copyright (C) 2012 Smile Communications, jason.penton@smilecoms.com
|
|
* Copyright (C) 2012 Smile Communications, richard.good@smilecoms.com
|
|
*
|
|
* The initial version of this code was written by Dragos Vingarzan
|
|
* (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
|
|
* Fruanhofer Institute. It was and still is maintained in a separate
|
|
* branch of the original SER. We are therefore migrating it to
|
|
* Kamailio/SR and look forward to maintaining it from here on out.
|
|
* 2011/2012 Smile Communications, Pty. Ltd.
|
|
* ported/maintained/improved by
|
|
* Jason Penton (jason(dot)penton(at)smilecoms.com and
|
|
* Richard Good (richard(dot)good(at)smilecoms.com) as part of an
|
|
* effort to add full IMS support to Kamailio/SR using a new and
|
|
* improved architecture
|
|
*
|
|
* NB: Alot of this code was originally part of OpenIMSCore,
|
|
* FhG Fokus.
|
|
* Copyright (C) 2004-2006 FhG Fokus
|
|
* Thanks for great work! This is an effort to
|
|
* break apart the various CSCF functions into logically separate
|
|
* components. We hope this will drive wider use. We also feel
|
|
* that in this way the architecture is more complete and thereby easier
|
|
* to manage in the Kamailio/SR environment
|
|
*
|
|
* This file is part of Kamailio, a free SIP server.
|
|
*
|
|
* Kamailio is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version
|
|
*
|
|
* Kamailio is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
*/
|
|
|
|
|
|
#include "utils.h"
|
|
|
|
/*
|
|
* Find credentials with given realm in a SIP message header
|
|
*/
|
|
inline int ims_find_credentials(struct sip_msg* _m, str* _realm,
|
|
hdr_types_t _hftype, struct hdr_field** _h) {
|
|
struct hdr_field** hook, *ptr, *prev;
|
|
hdr_flags_t hdr_flags;
|
|
int res;
|
|
str* r;
|
|
|
|
LM_DBG("Searching credentials in realm [%.*s]\n", _realm->len, _realm->s);
|
|
|
|
/*
|
|
* Determine if we should use WWW-Authorization or
|
|
* Proxy-Authorization header fields, this parameter
|
|
* is set in www_authorize and proxy_authorize
|
|
*/
|
|
switch (_hftype) {
|
|
case HDR_AUTHORIZATION_T:
|
|
hook = &(_m->authorization);
|
|
hdr_flags = HDR_AUTHORIZATION_F;
|
|
break;
|
|
case HDR_PROXYAUTH_T:
|
|
hook = &(_m->proxy_auth);
|
|
hdr_flags = HDR_PROXYAUTH_F;
|
|
break;
|
|
default:
|
|
hook = &(_m->authorization);
|
|
hdr_flags = HDR_T2F(_hftype);
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* If the credentials haven't been parsed yet, do it now
|
|
*/
|
|
if (*hook == 0) {
|
|
/* No credentials parsed yet */
|
|
LM_DBG("*hook == 0, No credentials parsed yet\n");
|
|
if (parse_headers(_m, hdr_flags, 0) == -1) {
|
|
LM_ERR("Error while parsing headers\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
ptr = *hook;
|
|
LM_DBG("*hook = %p\n", ptr);
|
|
/*
|
|
* Iterate through the credentials in the message and
|
|
* find credentials with given realm
|
|
*/
|
|
while (ptr) {
|
|
res = parse_credentials(ptr);
|
|
if (res < 0) {
|
|
LM_ERR("Error while parsing credentials\n");
|
|
return (res == -1) ? -2 : -3;
|
|
} else if (res == 0) {
|
|
LM_DBG("Credential parsed successfully\n");
|
|
if (_realm->len) {
|
|
r = &(((auth_body_t*) (ptr->parsed))->digest.realm);
|
|
LM_DBG("Comparing realm <%.*s> and <%.*s>\n", _realm->len, _realm->s, r->len, r->s);
|
|
if (r->len == _realm->len) {
|
|
if (!strncasecmp(_realm->s, r->s, r->len)) {
|
|
*_h = ptr;
|
|
return 0;
|
|
}
|
|
}
|
|
} else {
|
|
*_h = ptr;
|
|
return 0;
|
|
}
|
|
|
|
}
|
|
|
|
prev = ptr;
|
|
if (parse_headers(_m, hdr_flags, 1) == -1) {
|
|
LM_ERR("Error while parsing headers\n");
|
|
return -4;
|
|
} else {
|
|
if (prev != _m->last_header) {
|
|
if (_m->last_header->type == _hftype)
|
|
ptr = _m->last_header;
|
|
else
|
|
break;
|
|
} else
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Credentials with given realm not found
|
|
*/
|
|
LM_DBG("Credentials with given realm not found\n");
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Looks for the nonce and response parameters in the Authorization header and returns them
|
|
* @param msg - the SIP message
|
|
* @param realm - realm to match the right Authorization header
|
|
* @param nonce - param to fill with the nonce found
|
|
* @param response - param to fill with the response
|
|
* @returns 1 if found, 0 if not
|
|
*/
|
|
int get_nonce_response(struct sip_msg *msg, str *username, str realm,str *nonce,str *response,
|
|
enum qop_type *qop,str *qop_str,str *nc,str *cnonce,str *uri, int is_proxy_auth)
|
|
{
|
|
struct hdr_field* h = 0;
|
|
int ret;
|
|
|
|
|
|
ret = parse_headers(msg, is_proxy_auth ? HDR_PROXYAUTH_F : HDR_AUTHORIZATION_F, 0);
|
|
|
|
if (ret != 0) {
|
|
return 0;
|
|
}
|
|
|
|
if ((!is_proxy_auth && !msg->authorization)
|
|
|| (is_proxy_auth && !msg->proxy_auth)) {
|
|
return 0;
|
|
}
|
|
|
|
LM_DBG("Calling find_credentials with realm [%.*s]\n", realm.len, realm.s);
|
|
ret = ims_find_credentials(msg, &realm, is_proxy_auth ? HDR_PROXYAUTH_T : HDR_AUTHORIZATION_T, &h);
|
|
if (ret < 0) {
|
|
return 0;
|
|
} else if (ret > 0) {
|
|
LM_DBG("ret > 0");
|
|
return 0;
|
|
}
|
|
|
|
if (h && h->parsed) {
|
|
if (nonce)
|
|
*nonce = ((auth_body_t*) h->parsed)->digest.nonce;
|
|
if (response)
|
|
*response = ((auth_body_t*) h->parsed)->digest.response;
|
|
if (qop)
|
|
*qop = ((auth_body_t*) h->parsed)->digest.qop.qop_parsed;
|
|
if (qop_str)
|
|
*qop_str = ((auth_body_t*) h->parsed)->digest.qop.qop_str;
|
|
if (nc)
|
|
*nc = ((auth_body_t*) h->parsed)->digest.nc;
|
|
if (cnonce)
|
|
*cnonce = ((auth_body_t*) h->parsed)->digest.cnonce;
|
|
if (uri)
|
|
*uri = ((auth_body_t*) h->parsed)->digest.uri;
|
|
if (username)
|
|
*username = ((auth_body_t*) h->parsed)->digest.username.whole;
|
|
}
|
|
LM_DBG("Found nonce response\n");
|
|
return 1;
|
|
}
|
|
|
|
str ims_get_body(struct sip_msg * msg)
|
|
{
|
|
str x={0,0};
|
|
|
|
if (parse_headers(msg,HDR_CONTENTLENGTH_F,0)!=0) {
|
|
LM_DBG("Error parsing until header Content-Length: \n");
|
|
return x;
|
|
}
|
|
x.len = (int)(long)msg->content_length->parsed;
|
|
|
|
if (x.len>0)
|
|
x.s = get_body(msg);
|
|
|
|
return x;
|
|
}
|
|
|
|
|
|
/**
|
|
* Looks for the auts parameter in the Authorization header and returns its value.
|
|
* @param msg - the SIP message
|
|
* @param realm - realm to match the right Authorization header
|
|
* @returns the auts value or an empty string if not found
|
|
*/
|
|
str ims_get_auts(struct sip_msg *msg, str realm, int is_proxy_auth)
|
|
{
|
|
str name={"auts=\"",6};
|
|
struct hdr_field* h=0;
|
|
int i,ret;
|
|
str auts={0,0};
|
|
|
|
if (parse_headers(msg, is_proxy_auth ? HDR_PROXYAUTH_F : HDR_AUTHORIZATION_F,0)!=0) {
|
|
LM_ERR("Error parsing until header Authorization: \n");
|
|
return auts;
|
|
}
|
|
|
|
if ((!is_proxy_auth && !msg->authorization)
|
|
|| (is_proxy_auth && !msg->proxy_auth)){
|
|
LM_ERR("Message does not contain Authorization nor Proxy-Authorization header.\n");
|
|
return auts;
|
|
}
|
|
|
|
ret = find_credentials(msg, &realm, is_proxy_auth ? HDR_PROXYAUTH_F : HDR_AUTHORIZATION_F, &h);
|
|
if (ret < 0) {
|
|
LM_ERR("Error while looking for credentials.\n");
|
|
return auts;
|
|
} else
|
|
if (ret > 0) {
|
|
LM_ERR("No credentials for this realm found.\n");
|
|
return auts;
|
|
}
|
|
|
|
if (h) {
|
|
for(i=0;i<h->body.len-name.len;i++)
|
|
if (strncasecmp(h->body.s+i,name.s,name.len)==0){
|
|
auts.s = h->body.s+i+name.len;
|
|
while(i+auts.len<h->body.len && auts.s[auts.len]!='\"')
|
|
auts.len++;
|
|
}
|
|
}
|
|
|
|
return auts;
|
|
}
|
|
|
|
/**
|
|
* Looks for the nonce parameter in the Authorization header and returns its value.
|
|
* @param msg - the SIP message
|
|
* @param realm - realm to match the right Authorization header
|
|
* @returns the nonce or an empty string if none found
|
|
*/
|
|
str ims_get_nonce(struct sip_msg *msg, str realm)
|
|
{
|
|
struct hdr_field* h=0;
|
|
int ret;
|
|
str nonce={0,0};
|
|
|
|
if (parse_headers(msg,HDR_AUTHORIZATION_F,0)!=0) {
|
|
LM_ERR("Error parsing until header Authorization: \n");
|
|
return nonce;
|
|
}
|
|
|
|
if (!msg->authorization){
|
|
LM_ERR("Message does not contain Authorization header.\n");
|
|
return nonce;
|
|
}
|
|
|
|
ret = find_credentials(msg, &realm, HDR_AUTHORIZATION_F, &h);
|
|
if (ret < 0) {
|
|
LM_ERR("Error while looking for credentials.\n");
|
|
return nonce;
|
|
} else
|
|
if (ret > 0) {
|
|
LM_ERR("No credentials for this realm found.\n");
|
|
return nonce;
|
|
}
|
|
|
|
if (h&&h->parsed) {
|
|
nonce = ((auth_body_t*)h->parsed)->digest.nonce;
|
|
}
|
|
|
|
return nonce;
|
|
}
|
|
|
|
/**
|
|
* Adds a header to the reply message
|
|
* @param msg - the request to add a header to its reply
|
|
* @param content - the str containing the new header
|
|
* @returns 1 on succes, 0 on failure
|
|
*/
|
|
int ims_add_header_rpl(struct sip_msg *msg, str *hdr)
|
|
{
|
|
if (add_lump_rpl( msg, hdr->s, hdr->len, LUMP_RPL_HDR)==0) {
|
|
LM_ERR("Can't add header <%.*s>\n",
|
|
hdr->len,hdr->s);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|