forked from Mirrors/freeswitch
b7c6c0e483
Thu Nov 15 08:40:38 EST 2007 Pekka.Pessi@nokia.com * htable2.h: fixed usize_t/size_t confusion Fri Nov 16 06:38:51 EST 2007 Youness Alaoui <youness.alaoui@collabora.co.uk> * Added #include <stdio.h> Fri Nov 16 10:27:58 EST 2007 Pekka.Pessi@nokia.com * auth_client.c: allow multiple challenges in auc_credentials() or auc_all_credentials() Fri Nov 16 10:29:00 EST 2007 Pekka.Pessi@nokia.com * nua/test_proxy.[hc], nua/test_register.c: test support of multiple realms. Fri Nov 16 11:17:09 EST 2007 Pekka.Pessi@nokia.com * sofia-sip/su_alloc.h, su_alloc.c: added su_home_lock(), su_home_trylock(), su_home_unlock() Added test in torture_su_alloc.c. Using in su_pthread_port.c. Fri Nov 16 12:29:55 EST 2007 Pekka.Pessi@nokia.com * test_register.c, test_proxy.c: use realm "test-proxy" during normal tests Fri Nov 16 12:34:00 EST 2007 Pekka.Pessi@nokia.com * nua_register.c: sf.net bug #1816647: Outbound contact does not make it to dialogs Now use Contact from first registration instead of Contact generated from transport. Mon Nov 19 12:00:06 EST 2007 Pekka Pessi <Pekka.Pessi@nokia.com> * su_alloc.c: silenced warnings on Sun CC git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@6338 d0543943-73ff-0310-b7d9-9358b9ac24b2
843 lines
27 KiB
C
843 lines
27 KiB
C
/*
|
|
* This file is part of the Sofia-SIP package
|
|
*
|
|
* Copyright (C) 2005 Nokia Corporation.
|
|
*
|
|
* Contact: Pekka Pessi <pekka.pessi@nokia.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public License
|
|
* as published by the Free Software Foundation; either version 2.1 of
|
|
* the License, or (at your option) any later version.
|
|
*
|
|
* This library 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
* 02110-1301 USA
|
|
*
|
|
*/
|
|
|
|
/**@CFILE sip_security.c
|
|
*
|
|
* Security-related SIP header handling.
|
|
*
|
|
* This file contains implementation of headers related to HTTP authentication
|
|
* (@RFC2617):
|
|
* @ref sip_authorization "Authorization",
|
|
* @ref sip_authentication_info "Authentication-Info",
|
|
* @ref sip_proxy_authenticate "Proxy-Authenticate",
|
|
* @ref sip_proxy_authentication_info "Proxy-Authentication-Info",
|
|
* @ref sip_proxy_authorization "Proxy-Authorization", and
|
|
* @ref sip_www_authenticate "WWW-Authenticate".
|
|
*
|
|
* There is also implementation of headers related to security agreement
|
|
* (@RFC3329):
|
|
* @ref sip_security_client "Security-Client",
|
|
* @ref sip_security_server "Security-Server", and
|
|
* @ref sip_security_verify "Security-Verify" headers.
|
|
*
|
|
* The implementation of @ref sip_privacy "Privacy" header (@RFC3323) is
|
|
* also here.
|
|
*
|
|
* @author Pekka Pessi <Pekka.Pessi@nokia.com>.
|
|
*
|
|
* @date Created: Tue Jun 13 02:57:51 2000 ppessi
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
/* Avoid casting sip_t to msg_pub_t and sip_header_t to msg_header_t */
|
|
#define MSG_PUB_T struct sip_s
|
|
#define MSG_HDR_T union sip_header_u
|
|
|
|
#include "sofia-sip/sip_parser.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <limits.h>
|
|
#include <assert.h>
|
|
|
|
/* ====================================================================== */
|
|
|
|
/**@SIP_HEADER sip_authorization Authorization Header
|
|
*
|
|
* The Authorization header consists of credentials containing the
|
|
* authentication information of the user agent for the realm of the
|
|
* resource being requested. Its syntax is defined in @RFC2617 and @RFC3261
|
|
* as follows:
|
|
*
|
|
* @code
|
|
* Authorization = "Authorization" HCOLON credentials
|
|
* credentials = ("Digest" LWS digest-response)
|
|
* / other-response
|
|
* digest-response = dig-resp *(COMMA dig-resp)
|
|
* dig-resp = username / realm / nonce / digest-uri
|
|
* / dresponse / algorithm / cnonce
|
|
* / opaque / message-qop
|
|
* / nonce-count / auth-param
|
|
* username = "username" EQUAL username-value
|
|
* username-value = quoted-string
|
|
* digest-uri = "uri" EQUAL LDQUOT digest-uri-value RDQUOT
|
|
* digest-uri-value = rquest-uri ; Equal to request-uri as specified
|
|
* by HTTP/1.1
|
|
* message-qop = "qop" EQUAL qop-value
|
|
* cnonce = "cnonce" EQUAL cnonce-value
|
|
* cnonce-value = nonce-value
|
|
* nonce-count = "nc" EQUAL nc-value
|
|
* nc-value = 8LHEX
|
|
* dresponse = "response" EQUAL request-digest
|
|
* request-digest = LDQUOT 32LHEX RDQUOT
|
|
* auth-param = auth-param-name EQUAL
|
|
* ( token / quoted-string )
|
|
* auth-param-name = token
|
|
* other-response = auth-scheme LWS auth-param
|
|
* *(COMMA auth-param)
|
|
* auth-scheme = token
|
|
* @endcode
|
|
*
|
|
* The parsed Authorization header
|
|
* is stored in #sip_authorization_t structure.
|
|
*
|
|
* @sa @RFC2617, auth_mod_verify(), auth_mod_check(), auth_get_params(),
|
|
* auth_digest_response_get().
|
|
*/
|
|
|
|
/**@ingroup sip_authorization
|
|
* @typedef typedef struct sip_authorization_s sip_authorization_t;
|
|
*
|
|
* The structure #sip_authorization_t contains representation of SIP
|
|
* @Authorization header.
|
|
*
|
|
* The #sip_authorization_t is defined as follows:
|
|
* @code
|
|
* typedef struct msg_auth_s {
|
|
* msg_common_t au_common[1]; // Common fragment info
|
|
* msg_auth_t *au_next; // Link to next header
|
|
* char const *au_scheme; // Auth-scheme like "Basic" or "Digest"
|
|
* msg_param_t const *au_params; // Comma-separated parameters
|
|
* } sip_authorization_t;
|
|
* @endcode
|
|
*
|
|
*/
|
|
|
|
msg_hclass_t sip_authorization_class[] =
|
|
SIP_HEADER_CLASS_AUTH(authorization, "Authorization", single);
|
|
|
|
issize_t sip_authorization_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
|
|
{
|
|
return msg_auth_d(home, h, s, slen);
|
|
}
|
|
|
|
issize_t sip_authorization_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
|
|
{
|
|
assert(sip_is_authorization(h));
|
|
return msg_auth_e(b, bsiz, h, f);
|
|
}
|
|
|
|
/* ====================================================================== */
|
|
|
|
/**@SIP_HEADER sip_proxy_authenticate Proxy-Authenticate Header
|
|
*
|
|
* The Proxy-Authenticate header consists of a challenge that indicates the
|
|
* authentication scheme and parameters applicable to the proxy. Its syntax
|
|
* is defined in [H14.33, S10.31] as follows:
|
|
*
|
|
* @code
|
|
* Proxy-Authenticate = "Proxy-Authenticate" HCOLON challenge
|
|
* challenge = ("Digest" LWS digest-cln *(COMMA digest-cln))
|
|
* / other-challenge
|
|
* other-challenge = auth-scheme LWS auth-param
|
|
* *(COMMA auth-param)
|
|
* digest-cln = realm / domain / nonce
|
|
* / opaque / stale / algorithm
|
|
* / qop-options / auth-param
|
|
* realm = "realm" EQUAL realm-value
|
|
* realm-value = quoted-string
|
|
* domain = "domain" EQUAL LDQUOT URI
|
|
* *( 1*SP URI ) RDQUOT
|
|
* URI = absoluteURI / abs-path
|
|
* nonce = "nonce" EQUAL nonce-value
|
|
* nonce-value = quoted-string
|
|
* opaque = "opaque" EQUAL quoted-string
|
|
* stale = "stale" EQUAL ( "true" / "false" )
|
|
* algorithm = "algorithm" EQUAL ( "MD5" / "MD5-sess"
|
|
* / token )
|
|
* qop-options = "qop" EQUAL LDQUOT qop-value
|
|
* *("," qop-value) RDQUOT
|
|
* qop-value = "auth" / "auth-int" / token
|
|
* @endcode
|
|
*
|
|
*
|
|
* The parsed Proxy-Authenticate header
|
|
* is stored in #sip_proxy_authenticate_t structure.
|
|
*/
|
|
|
|
/**@ingroup sip_proxy_authenticate
|
|
* @typedef typedef struct sip_proxy_authenticate_s sip_proxy_authenticate_t;
|
|
*
|
|
* The structure #sip_proxy_authenticate_t contains representation of SIP
|
|
* @ProxyAuthenticate header.
|
|
*
|
|
* The #sip_proxy_authenticate_t is defined as follows:
|
|
* @code
|
|
* typedef struct msg_auth_s {
|
|
* msg_common_t au_common[1]; // Common fragment info
|
|
* msg_auth_t *au_next; // Link to next header
|
|
* char const *au_scheme; // Auth-scheme like "Basic" or "Digest"
|
|
* msg_param_t const *au_params; // Comma-separated parameters
|
|
* } sip_proxy_authenticate_t;
|
|
* @endcode
|
|
*
|
|
*/
|
|
|
|
msg_hclass_t sip_proxy_authenticate_class[] =
|
|
SIP_HEADER_CLASS_AUTH(proxy_authenticate, "Proxy-Authenticate", append);
|
|
|
|
issize_t sip_proxy_authenticate_d(su_home_t *home, sip_header_t *h,
|
|
char *s, isize_t slen)
|
|
{
|
|
return msg_auth_d(home, h, s, slen);
|
|
}
|
|
|
|
issize_t sip_proxy_authenticate_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
|
|
{
|
|
assert(sip_is_proxy_authenticate(h));
|
|
return msg_auth_e(b, bsiz, h, f);
|
|
}
|
|
|
|
|
|
/* ====================================================================== */
|
|
|
|
/**@SIP_HEADER sip_proxy_authorization Proxy-Authorization Header
|
|
*
|
|
* The Proxy-Authorization header consists of credentials containing the
|
|
* authentication information of the user agent for the proxy and/or realm
|
|
* of the resource being requested. Its syntax is defined in @RFC3261
|
|
* as follows:
|
|
*
|
|
* @code
|
|
* Proxy-Authorization = "Proxy-Authorization" ":" credentials
|
|
* credentials = ("Digest" LWS digest-response)
|
|
* / other-response
|
|
* @endcode
|
|
*
|
|
* @sa auth_mod_verify(), auth_mod_check(), auth_get_params(),
|
|
* auth_digest_response_get().
|
|
*
|
|
* The parsed Proxy-Authorization header
|
|
* is stored in #sip_proxy_authorization_t structure.
|
|
*/
|
|
|
|
/**@ingroup sip_proxy_authorization
|
|
* @typedef typedef struct sip_proxy_authorization_s sip_proxy_authorization_t;
|
|
*
|
|
* The structure #sip_proxy_authorization_t contains representation of SIP
|
|
* @ProxyAuthorization header.
|
|
*
|
|
* The #sip_proxy_authorization_t is defined as follows:
|
|
* @code
|
|
* typedef struct msg_auth_s {
|
|
* msg_common_t au_common[1]; // Common fragment info
|
|
* msg_auth_t *au_next; // Link to next header
|
|
* char const *au_scheme; // Auth-scheme like "Basic" or "Digest"
|
|
* msg_param_t const *au_params; // Comma-separated parameters
|
|
* } sip_proxy_authorization_t;
|
|
* @endcode
|
|
*
|
|
*/
|
|
|
|
msg_hclass_t sip_proxy_authorization_class[] =
|
|
SIP_HEADER_CLASS_AUTH(proxy_authorization, "Proxy-Authorization", append);
|
|
|
|
issize_t sip_proxy_authorization_d(su_home_t *home, sip_header_t *h,
|
|
char *s, isize_t slen)
|
|
{
|
|
return msg_auth_d(home, h, s, slen);
|
|
}
|
|
|
|
issize_t sip_proxy_authorization_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
|
|
{
|
|
assert(sip_is_proxy_authorization(h));
|
|
return msg_auth_e(b, bsiz, h, f);
|
|
}
|
|
|
|
/* ====================================================================== */
|
|
|
|
/**@SIP_HEADER sip_www_authenticate WWW-Authenticate Header
|
|
*
|
|
* The WWW-Authenticate header consists of at least one challenge that
|
|
* indicates the authentication scheme(s) and parameters applicable to the
|
|
* Request-URI. Its syntax is defined in @RFC3261 as
|
|
* follows:
|
|
*
|
|
* @code
|
|
* WWW-Authenticate = "WWW-Authenticate" HCOLON challenge
|
|
* challenge = ("Digest" LWS digest-cln *(COMMA digest-cln))
|
|
* / other-challenge
|
|
* other-challenge = auth-scheme LWS auth-param *(COMMA auth-param)
|
|
* @endcode
|
|
*
|
|
* See @ProxyAuthenticate for the definition of \<digest-cln\>.
|
|
*
|
|
* The parsed WWW-Authenticate header
|
|
* is stored in #sip_www_authenticate_t structure.
|
|
*/
|
|
|
|
/**@ingroup sip_www_authenticate
|
|
* @typedef typedef struct sip_www_authenticate_s sip_www_authenticate_t;
|
|
*
|
|
* The structure #sip_www_authenticate_t contains representation of SIP
|
|
* @WWWAuthenticate header.
|
|
*
|
|
* The #sip_www_authenticate_t is defined as follows:
|
|
* @code
|
|
* typedef struct msg_auth_s {
|
|
* msg_common_t au_common[1]; // Common fragment info
|
|
* msg_auth_t *au_next; // Link to next header
|
|
* char const *au_scheme; // Auth-scheme like "Basic" or "Digest"
|
|
* msg_param_t const *au_params; // Comma-separated parameters
|
|
* } sip_www_authenticate_t;
|
|
* @endcode
|
|
*
|
|
*/
|
|
|
|
msg_hclass_t sip_www_authenticate_class[] =
|
|
SIP_HEADER_CLASS_AUTH(www_authenticate, "WWW-Authenticate", single);
|
|
|
|
issize_t sip_www_authenticate_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
|
|
{
|
|
return msg_auth_d(home, h, s, slen);
|
|
}
|
|
|
|
issize_t sip_www_authenticate_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
|
|
{
|
|
assert(sip_is_www_authenticate(h));
|
|
return msg_auth_e(b, bsiz, h, f);
|
|
}
|
|
|
|
/**@SIP_HEADER sip_authentication_info Authentication-Info Header
|
|
*
|
|
* The @b Authentication-Info header contains either a next-nonce used by
|
|
* next request and/or authentication from server used in mutual
|
|
* authentication. The syntax of @b Authentication-Info header is defined in
|
|
* @RFC2617 and @RFC3261 as follows:
|
|
*
|
|
* @code
|
|
* Authentication-Info = "Authentication-Info" HCOLON ainfo
|
|
* *(COMMA ainfo)
|
|
* ainfo = nextnonce / message-qop
|
|
* / response-auth / cnonce
|
|
* / nonce-count
|
|
* nextnonce = "nextnonce" EQUAL nonce-value
|
|
* response-auth = "rspauth" EQUAL response-digest
|
|
* response-digest = LDQUOT *LHEX RDQUOT
|
|
* @endcode
|
|
*
|
|
* The parsed Authentication-Info header
|
|
* is stored in #sip_authentication_info_t structure.
|
|
*/
|
|
|
|
/**@ingroup sip_authentication_info
|
|
* @typedef typedef struct sip_authentication_info_s sip_authentication_info_t;
|
|
*
|
|
* The structure #sip_authentication_info_t contains representation of SIP
|
|
* @AuthenticationInfo header.
|
|
*
|
|
* The #sip_authentication_info_t is defined as follows:
|
|
* @code
|
|
* typedef struct msg_auth_info_s
|
|
* {
|
|
* msg_common_t ai_common[1]; // Common fragment info
|
|
* msg_error_t *ai_next; // Dummy link to next header
|
|
* msg_param_t *ai_items; // List of ainfo
|
|
* } sip_authentication_info_t;
|
|
* @endcode
|
|
*/
|
|
|
|
#define sip_authentication_info_dup_xtra msg_list_dup_xtra
|
|
#define sip_authentication_info_dup_one msg_list_dup_one
|
|
#define sip_authentication_info_update NULL
|
|
|
|
msg_hclass_t sip_authentication_info_class[] =
|
|
SIP_HEADER_CLASS(authentication_info, "Authentication-Info", "",
|
|
ai_params, append, authentication_info);
|
|
|
|
issize_t sip_authentication_info_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
|
|
{
|
|
return msg_list_d(home, (msg_header_t *)h, s, slen);
|
|
}
|
|
|
|
|
|
issize_t sip_authentication_info_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
|
|
{
|
|
assert(sip_is_authentication_info(h));
|
|
return msg_list_e(b, bsiz, h, f);
|
|
}
|
|
|
|
|
|
/* ====================================================================== */
|
|
|
|
/**@SIP_HEADER sip_proxy_authentication_info Proxy-Authentication-Info Header
|
|
*
|
|
* The @b Proxy-Authentication-Info header contains either a next-nonce used
|
|
* by next request and/or authentication from proxy used in mutual
|
|
* authentication. The syntax of @b Proxy-Authentication-Info header is defined
|
|
* in @RFC2617 as follows:
|
|
*
|
|
* @code
|
|
* Proxy-Authentication-Info = "Proxy-Authentication-Info" HCOLON ainfo
|
|
* *(COMMA ainfo)
|
|
* ainfo = nextnonce / message-qop
|
|
* / response-auth / cnonce
|
|
* / nonce-count
|
|
* nextnonce = "nextnonce" EQUAL nonce-value
|
|
* response-auth = "rspauth" EQUAL response-digest
|
|
* response-digest = LDQUOT *LHEX RDQUOT
|
|
* @endcode
|
|
*
|
|
* @note @b Proxy-Authentication-Info is not specified @RFC3261 and it is
|
|
* mentioned by @RFC2617 but in passage.
|
|
*
|
|
* The parsed Proxy-Authentication-Info header
|
|
* is stored in #sip_proxy_authentication_info_t structure.
|
|
*/
|
|
|
|
/**@ingroup sip_proxy_authentication_info
|
|
* @typedef typedef struct msg_authentication_info_s sip_proxy_authentication_info_t;
|
|
*
|
|
* The structure #sip_proxy_authentication_info_t contains representation of SIP
|
|
* @ProxyAuthenticationInfo header.
|
|
*
|
|
* The #sip_proxy_authentication_info_t is defined as follows:
|
|
* @code
|
|
* typedef struct msg_auth_info_s
|
|
* {
|
|
* msg_common_t ai_common[1]; // Common fragment info
|
|
* msg_error_t *ai_next; // Dummy link to next header
|
|
* msg_param_t *ai_items; // List of ainfo
|
|
* } sip_proxy_authentication_info_t;
|
|
* @endcode
|
|
*
|
|
*/
|
|
|
|
#define sip_proxy_authentication_info_dup_xtra msg_list_dup_xtra
|
|
#define sip_proxy_authentication_info_dup_one msg_list_dup_one
|
|
#define sip_proxy_authentication_info_update NULL
|
|
|
|
msg_hclass_t sip_proxy_authentication_info_class[] =
|
|
SIP_HEADER_CLASS(proxy_authentication_info, "Proxy-Authentication-Info", "",
|
|
ai_params, append, proxy_authentication_info);
|
|
|
|
issize_t sip_proxy_authentication_info_d(su_home_t *home, sip_header_t *h,
|
|
char *s, isize_t slen)
|
|
{
|
|
return msg_list_d(home, (msg_header_t *)h, s, slen);
|
|
}
|
|
|
|
issize_t sip_proxy_authentication_info_e(char b[], isize_t bsiz,
|
|
sip_header_t const *h, int f)
|
|
{
|
|
assert(sip_is_proxy_authentication_info(h)); /* This is soo popular */
|
|
return msg_list_e(b, bsiz, h, f);
|
|
}
|
|
|
|
/* ====================================================================== */
|
|
|
|
/* Functions parsing @RFC3329 SIP Security Agreement headers */
|
|
|
|
typedef struct sip_security_agree_s sip_security_agree_t;
|
|
#define sh_security_agree sh_security_client
|
|
|
|
static
|
|
issize_t sip_security_agree_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
|
|
{
|
|
sip_security_agree_t *sa = (sip_security_agree_t *)h;
|
|
|
|
isize_t n;
|
|
|
|
while (*s == ',') /* Ignore empty entries (comma-whitespace) */
|
|
*s = '\0', s += span_lws(s + 1) + 1;
|
|
|
|
if ((n = span_token(s)) == 0)
|
|
return -1;
|
|
sa->sa_mec = s; s += n; while (IS_LWS(*s)) *s++ = '\0';
|
|
if (*s == ';' && msg_params_d(home, &s, &sa->sa_params) < 0)
|
|
return -1;
|
|
|
|
return msg_parse_next_field(home, h, s, slen);
|
|
}
|
|
|
|
static
|
|
issize_t sip_security_agree_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
|
|
{
|
|
char *end = b + bsiz, *b0 = b;
|
|
sip_security_agree_t const *sa = (sip_security_agree_t const *)h;
|
|
|
|
MSG_STRING_E(b, end, sa->sa_mec);
|
|
MSG_PARAMS_E(b, end, sa->sa_params, flags);
|
|
|
|
return b - b0;
|
|
}
|
|
|
|
static
|
|
isize_t sip_security_agree_dup_xtra(sip_header_t const *h, isize_t offset)
|
|
{
|
|
sip_security_agree_t const *sa = h->sh_security_agree;
|
|
|
|
MSG_PARAMS_SIZE(offset, sa->sa_params);
|
|
offset += MSG_STRING_SIZE(sa->sa_mec);
|
|
|
|
return offset;
|
|
}
|
|
|
|
/** Duplicate one sip_security_agree_t object */
|
|
static
|
|
char *sip_security_agree_dup_one(sip_header_t *dst, sip_header_t const *src,
|
|
char *b, isize_t xtra)
|
|
{
|
|
sip_security_agree_t *sa_dst = dst->sh_security_agree;
|
|
sip_security_agree_t const *sa_src = src->sh_security_agree;
|
|
|
|
char *end = b + xtra;
|
|
b = msg_params_dup(&sa_dst->sa_params, sa_src->sa_params, b, xtra);
|
|
MSG_STRING_DUP(b, sa_dst->sa_mec, sa_src->sa_mec);
|
|
assert(b <= end); (void)end;
|
|
|
|
return b;
|
|
}
|
|
|
|
static int sip_security_agree_update(msg_common_t *h,
|
|
char const *name, isize_t namelen,
|
|
char const *value)
|
|
{
|
|
sip_security_agree_t *sa = (sip_security_agree_t *)h;
|
|
|
|
if (name == NULL) {
|
|
sa->sa_q = NULL;
|
|
sa->sa_d_alg = NULL;
|
|
sa->sa_d_qop = NULL;
|
|
sa->sa_d_ver = NULL;
|
|
}
|
|
#define MATCH(s) (namelen == strlen(#s) && !strncasecmp(name, #s, strlen(#s)))
|
|
|
|
else if (MATCH(q)) {
|
|
sa->sa_q = value;
|
|
}
|
|
else if (MATCH(d-alg)) {
|
|
sa->sa_d_alg = value;
|
|
}
|
|
else if (MATCH(d-qop)) {
|
|
sa->sa_d_qop = value;
|
|
}
|
|
else if (MATCH(d-ver)) {
|
|
sa->sa_d_ver = value;
|
|
}
|
|
|
|
#undef MATCH
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**@SIP_HEADER sip_security_client Security-Client Header
|
|
*
|
|
* The Security-Client header is defined by @RFC3329, "Security Mechanism
|
|
* Agreement for the Session Initiation Protocol (SIP)".
|
|
*
|
|
* @code
|
|
* security-client = "Security-Client" HCOLON
|
|
* sec-mechanism *(COMMA sec-mechanism)
|
|
* security-server = "Security-Server" HCOLON
|
|
* sec-mechanism *(COMMA sec-mechanism)
|
|
* security-verify = "Security-Verify" HCOLON
|
|
* sec-mechanism *(COMMA sec-mechanism)
|
|
* sec-mechanism = mechanism-name *(SEMI mech-parameters)
|
|
* mechanism-name = ( "digest" / "tls" / "ipsec-ike" /
|
|
* "ipsec-man" / token )
|
|
* mech-parameters = ( preference / digest-algorithm /
|
|
* digest-qop / digest-verify / extension )
|
|
* preference = "q" EQUAL qvalue
|
|
* qvalue = ( "0" [ "." 0*3DIGIT ] )
|
|
* / ( "1" [ "." 0*3("0") ] )
|
|
* digest-algorithm = "d-alg" EQUAL token
|
|
* digest-qop = "d-qop" EQUAL token
|
|
* digest-verify = "d-ver" EQUAL LDQUOT 32LHEX RDQUOT
|
|
* extension = generic-param
|
|
* @endcode
|
|
*
|
|
* @sa @SecurityServer, @SecurityVerify, sip_security_verify_compare(),
|
|
* sip_security_client_select(), @RFC3329
|
|
*
|
|
* The parsed Security-Client header
|
|
* is stored in #sip_security_client_t structure.
|
|
*/
|
|
|
|
/**@ingroup sip_security_client
|
|
* @typedef typedef struct sip_security_client_s sip_security_client_t;
|
|
*
|
|
* The structure #sip_security_client_t contains representation of SIP
|
|
* @SecurityClient header.
|
|
*
|
|
* The #sip_security_client_t is defined as follows:
|
|
* @code
|
|
* typedef struct sip_security_agree_s
|
|
* {
|
|
* sip_common_t sa_common[1]; // Common fragment info
|
|
* sip_security_client_t *sa_next; // Link to next mechanism
|
|
* char const *sa_mec; // Security mechanism
|
|
* msg_param_t const *sa_params; // List of mechanism parameters
|
|
* char const *sa_q; // Value of q (preference) parameter
|
|
* char const *sa_d_alg; // Value of d-alg parameter
|
|
* char const *sa_d_qop; // Value of d-qop parameter
|
|
* char const *sa_d_ver; // Value of d-ver parameter
|
|
* } sip_security_client_t;
|
|
* @endcode
|
|
*/
|
|
|
|
msg_hclass_t sip_security_client_class[] =
|
|
SIP_HEADER_CLASS(security_client, "Security-Client", "",
|
|
sa_params, append, security_agree);
|
|
|
|
issize_t sip_security_client_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
|
|
{
|
|
return sip_security_agree_d(home, h, s, slen);
|
|
}
|
|
|
|
issize_t sip_security_client_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
|
|
{
|
|
return sip_security_agree_e(b, bsiz, h, f);
|
|
}
|
|
|
|
|
|
/**@SIP_HEADER sip_security_server Security-Server Header
|
|
*
|
|
* The Security-Server header is defined by @RFC3329, "Security Mechanism
|
|
* Agreement for the Session Initiation Protocol (SIP)".
|
|
*
|
|
* @sa @SecurityClient, @SecurityVerify, sip_security_verify_compare(),
|
|
* sip_security_client_select(), @RFC3329.
|
|
*
|
|
* The parsed Security-Server header
|
|
* is stored in #sip_security_server_t structure.
|
|
*/
|
|
|
|
/**@ingroup sip_security_server
|
|
* @typedef typedef struct sip_security_server_s sip_security_server_t;
|
|
*
|
|
* The structure #sip_security_server_t contains representation of SIP
|
|
* @SecurityServer header.
|
|
*
|
|
* The #sip_security_server_t is defined as follows:
|
|
* @code
|
|
* typedef struct sip_security_agree_s
|
|
* {
|
|
* sip_common_t sa_common[1]; // Common fragment info
|
|
* sip_security_server_t *sa_next; // Link to next mechanism
|
|
* char const *sa_mec; // Security mechanism
|
|
* msg_param_t const *sa_params; // List of mechanism parameters
|
|
* char const *sa_q; // Value of q (preference) parameter
|
|
* char const *sa_d_alg; // Value of d-alg parameter
|
|
* char const *sa_d_qop; // Value of d-qop parameter
|
|
* char const *sa_d_ver; // Value of d-ver parameter
|
|
* } sip_security_server_t;
|
|
* @endcode
|
|
*/
|
|
|
|
msg_hclass_t sip_security_server_class[] =
|
|
SIP_HEADER_CLASS(security_server, "Security-Server", "",
|
|
sa_params, append, security_agree);
|
|
|
|
issize_t sip_security_server_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
|
|
{
|
|
return sip_security_agree_d(home, h, s, slen);
|
|
}
|
|
|
|
issize_t sip_security_server_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
|
|
{
|
|
return sip_security_agree_e(b, bsiz, h, f);
|
|
}
|
|
|
|
|
|
/**@SIP_HEADER sip_security_verify Security-Verify Header
|
|
*
|
|
* The Security-Verify header is defined by @RFC3329, "Security Mechanism
|
|
* Agreement for the Session Initiation Protocol (SIP)".
|
|
*
|
|
* @sa @SecurityClient, @SecurityServer, sip_security_verify_compare(),
|
|
* sip_security_client_select(), @RFC3329.
|
|
*
|
|
* The parsed Security-Verify header
|
|
* is stored in #sip_security_verify_t structure.
|
|
*/
|
|
|
|
/**@ingroup sip_security_verify
|
|
* @typedef typedef struct sip_security_verify_s sip_security_verify_t;
|
|
*
|
|
* The structure #sip_security_verify_t contains representation of SIP
|
|
* @SecurityVerify header.
|
|
*
|
|
* The #sip_security_verify_t is defined as follows:
|
|
* @code
|
|
* typedef struct sip_security_agree_s
|
|
* {
|
|
* sip_common_t sa_common[1]; // Common fragment info
|
|
* sip_security_verify_t *sa_next; // Link to next mechanism
|
|
* char const *sa_mec; // Security mechanism
|
|
* msg_param_t const *sa_params; // List of mechanism parameters
|
|
* char const *sa_q; // Value of q (preference) parameter
|
|
* char const *sa_d_alg; // Value of d-alg parameter
|
|
* char const *sa_d_qop; // Value of d-qop parameter
|
|
* char const *sa_d_ver; // Value of d-ver parameter
|
|
* } sip_security_verify_t;
|
|
* @endcode
|
|
*/
|
|
|
|
|
|
msg_hclass_t sip_security_verify_class[] =
|
|
SIP_HEADER_CLASS(security_verify, "Security-Verify", "",
|
|
sa_params, append, security_agree);
|
|
|
|
issize_t sip_security_verify_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
|
|
{
|
|
return sip_security_agree_d(home, h, s, slen);
|
|
}
|
|
|
|
issize_t sip_security_verify_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
|
|
{
|
|
return sip_security_agree_e(b, bsiz, h, f);
|
|
}
|
|
|
|
/* ====================================================================== */
|
|
/* RFC 3323 */
|
|
|
|
/**@SIP_HEADER sip_privacy Privacy Header
|
|
*
|
|
* The Privacy header is used by User-Agent to request privacy services from
|
|
* the network. Its syntax is defined in @RFC3323 as follows:
|
|
*
|
|
* @code
|
|
* Privacy-hdr = "Privacy" HCOLON priv-value *(";" priv-value)
|
|
* priv-value = "header" / "session" / "user" / "none" / "critical"
|
|
* / token
|
|
* @endcode
|
|
*
|
|
* The parsed Privacy header is stored in #sip_privacy_t structure.
|
|
*/
|
|
|
|
/**@ingroup sip_privacy
|
|
* @typedef typedef struct sip_privacy_s sip_privacy_t;
|
|
*
|
|
* The structure #sip_privacy_t contains representation of a SIP @Privacy
|
|
* header.
|
|
*
|
|
* The #sip_privacy_t is defined as follows:
|
|
* @code
|
|
* typedef struct sip_privacy_s {
|
|
* sip_common_t priv_common[1]; // Common fragment info
|
|
* sip_error_t *priv_next; // Dummy link
|
|
* msg_param_t const *priv_values; // List of privacy values
|
|
* } sip_privacy_t;
|
|
* @endcode
|
|
*/
|
|
|
|
msg_xtra_f sip_privacy_dup_xtra;
|
|
msg_dup_f sip_privacy_dup_one;
|
|
|
|
#define sip_privacy_update NULL
|
|
|
|
msg_hclass_t sip_privacy_class[] =
|
|
SIP_HEADER_CLASS(privacy, "Privacy", "", priv_values, single, privacy);
|
|
|
|
static
|
|
issize_t sip_privacy_token_scan(char *start)
|
|
{
|
|
char *s = start;
|
|
skip_token(&s);
|
|
|
|
if (s == start)
|
|
return -1;
|
|
|
|
if (IS_LWS(*s))
|
|
*s++ = '\0';
|
|
skip_lws(&s);
|
|
|
|
return s - start;
|
|
}
|
|
|
|
issize_t sip_privacy_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
|
|
{
|
|
sip_privacy_t *priv = (sip_privacy_t *)h;
|
|
|
|
while (*s == ';' || *s == ',') {
|
|
s++;
|
|
skip_lws(&s);
|
|
}
|
|
|
|
for (;;) {
|
|
if (msg_any_list_d(home, &s, (msg_param_t **)&priv->priv_values,
|
|
sip_privacy_token_scan, ';') < 0)
|
|
return -1;
|
|
|
|
if (*s == '\0')
|
|
return 0; /* Success! */
|
|
|
|
if (*s == ',')
|
|
*s++ = '\0'; /* We accept comma-separated list, too */
|
|
else if (IS_TOKEN(*s))
|
|
; /* LWS separated list... */
|
|
else
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
issize_t sip_privacy_e(char b[], isize_t bsiz, sip_header_t const *h, int f)
|
|
{
|
|
sip_privacy_t const *priv = h->sh_privacy;
|
|
char *b0 = b, *end = b + bsiz;
|
|
size_t i;
|
|
|
|
if (priv->priv_values) {
|
|
for (i = 0; priv->priv_values[i]; i++) {
|
|
if (i > 0) MSG_CHAR_E(b, end, ';');
|
|
MSG_STRING_E(b, end, priv->priv_values[i]);
|
|
}
|
|
}
|
|
|
|
MSG_TERM_E(b, end);
|
|
|
|
return b - b0;
|
|
}
|
|
|
|
isize_t sip_privacy_dup_xtra(sip_header_t const *h, isize_t offset)
|
|
{
|
|
sip_privacy_t const *priv = h->sh_privacy;
|
|
|
|
MSG_PARAMS_SIZE(offset, priv->priv_values);
|
|
|
|
return offset;
|
|
}
|
|
|
|
char *sip_privacy_dup_one(sip_header_t *dst,
|
|
sip_header_t const *src,
|
|
char *b,
|
|
isize_t xtra)
|
|
{
|
|
sip_privacy_t *priv = dst->sh_privacy;
|
|
sip_privacy_t const *o = src->sh_privacy;
|
|
char *end = b + xtra;
|
|
|
|
b = msg_params_dup(&priv->priv_values, o->priv_values, b, xtra);
|
|
|
|
assert(b <= end); (void)end;
|
|
|
|
return b;
|
|
}
|
|
|