@ -87,46 +87,46 @@ static void auth_store_cleanup(void *data)
AST_THREADSTORAGE_CUSTOM ( auth_store , NULL , auth_store_cleanup ) ;
AST_THREADSTORAGE_CUSTOM ( auth_store , NULL , auth_store_cleanup ) ;
/*!
/*!
* \ brief Store authentication information in thread - local storage
* \ brief Store shallow copy authentication information in thread - local storage
*/
*/
static int store_auth ( struct ast_sip_auth * auth )
static int store_auth ( const struct ast_sip_auth * auth )
{
{
struct ast_sip_auth * * pointing ;
const struct ast_sip_auth * * pointing ;
pointing = ast_threadstorage_get ( & auth_store , sizeof ( pointing ) ) ;
pointing = ast_threadstorage_get ( & auth_store , sizeof ( pointing ) ) ;
if ( ! pointing | | * pointing ) {
if ( ! pointing ) {
return - 1 ;
return - 1 ;
}
}
ao2_ref ( auth , + 1 ) ;
* pointing = auth ;
* pointing = auth ;
return 0 ;
return 0 ;
}
}
/*!
/*!
* \ brief Remove authentication information from thread - local storage
* \ brief Remove shallow copy authentication information from thread - local storage
*/
*/
static int remove_auth ( void )
static int remove_auth ( void )
{
{
struct ast_sip_auth * * pointing ;
struct ast_sip_auth * * pointing ;
pointing = ast_threadstorage_get ( & auth_store , sizeof ( pointing ) ) ;
pointing = ast_threadstorage_get ( & auth_store , sizeof ( pointing ) ) ;
if ( ! pointing ) {
if ( ! pointing ) {
return - 1 ;
return - 1 ;
}
}
ao2_cleanup ( * pointing ) ;
* pointing = NULL ;
* pointing = NULL ;
return 0 ;
return 0 ;
}
}
/*!
/*!
* \ brief Retrieve authentication information from thread - local storage
* \ brief Retrieve shallow copy authentication information from thread - local storage
*/
*/
static struct ast_sip_auth * get_auth ( void )
static const struct ast_sip_auth * get_auth ( void )
{
{
struct ast_sip_auth * * auth ;
struct ast_sip_auth * * auth ;
auth = ast_threadstorage_get ( & auth_store , sizeof ( auth ) ) ;
auth = ast_threadstorage_get ( & auth_store , sizeof ( auth ) ) ;
if ( auth & & * auth ) {
if ( auth ) {
ao2_ref ( * auth , + 1 ) ;
return * auth ;
return * auth ;
}
}
return NULL ;
return NULL ;
@ -150,7 +150,9 @@ static struct ast_sip_auth *get_auth(void)
static pj_status_t digest_lookup ( pj_pool_t * pool , const pj_str_t * realm ,
static pj_status_t digest_lookup ( pj_pool_t * pool , const pj_str_t * realm ,
const pj_str_t * acc_name , pjsip_cred_info * info )
const pj_str_t * acc_name , pjsip_cred_info * info )
{
{
RAII_VAR ( struct ast_sip_auth * , auth , get_auth ( ) , ao2_cleanup ) ;
const struct ast_sip_auth * auth ;
auth = get_auth ( ) ;
if ( ! auth ) {
if ( ! auth ) {
return PJSIP_SC_FORBIDDEN ;
return PJSIP_SC_FORBIDDEN ;
}
}
@ -312,7 +314,7 @@ enum digest_verify_result {
* \ return CMP_MATCH on successful authentication
* \ return CMP_MATCH on successful authentication
* \ return 0 on failed authentication
* \ return 0 on failed authentication
*/
*/
static int verify ( struct ast_sip_auth * auth , pjsip_rx_data * rdata , pj_pool_t * pool )
static int verify ( const struct ast_sip_auth * auth , pjsip_rx_data * rdata , pj_pool_t * pool )
{
{
pj_status_t authed ;
pj_status_t authed ;
int response_code ;
int response_code ;
@ -329,9 +331,7 @@ static int verify(struct ast_sip_auth *auth, pjsip_rx_data *rdata, pj_pool_t *po
setup_auth_srv ( pool , & auth_server , auth - > realm ) ;
setup_auth_srv ( pool , & auth_server , auth - > realm ) ;
store_auth ( auth ) ;
store_auth ( auth ) ;
authed = pjsip_auth_srv_verify ( & auth_server , rdata , & response_code ) ;
authed = pjsip_auth_srv_verify ( & auth_server , rdata , & response_code ) ;
remove_auth ( ) ;
remove_auth ( ) ;
if ( authed = = PJ_SUCCESS ) {
if ( authed = = PJ_SUCCESS ) {
@ -389,47 +389,88 @@ static enum ast_sip_check_auth_result digest_check_auth(struct ast_sip_endpoint
pjsip_rx_data * rdata , pjsip_tx_data * tdata )
pjsip_rx_data * rdata , pjsip_tx_data * tdata )
{
{
struct ast_sip_auth * * auths ;
struct ast_sip_auth * * auths ;
struct ast_sip_auth * * auths_shallow ;
enum digest_verify_result * verify_res ;
enum digest_verify_result * verify_res ;
struct ast_sip_endpoint * artificial_endpoint ;
enum ast_sip_check_auth_result res ;
enum ast_sip_check_auth_result res ;
int i ;
int idx ;
int is_artificial ;
int failures = 0 ;
int failures = 0 ;
size_t auth_size ;
size_t auth_size ;
RAII_VAR ( struct ast_sip_endpoint * , artificial_endpoint ,
ast_sip_get_artificial_endpoint ( ) , ao2_cleanup ) ;
auth_size = AST_VECTOR_SIZE ( & endpoint - > inbound_auths ) ;
auth_size = AST_VECTOR_SIZE ( & endpoint - > inbound_auths ) ;
ast_assert ( 0 < auth_size ) ;
auths = ast_alloca ( auth_size * sizeof ( * auths ) ) ;
auths = ast_alloca ( auth_size * sizeof ( * auths ) ) ;
verify_res = ast_alloca ( auth_size * sizeof ( * verify_res ) ) ;
verify_res = ast_alloca ( auth_size * sizeof ( * verify_res ) ) ;
if ( ! auths ) {
artificial_endpoint = ast_sip_get_artificial_endpoint ( ) ;
if ( ! artificial_endpoint ) {
/* Should not happen except possibly if we are shutting down. */
return AST_SIP_AUTHENTICATION_ERROR ;
return AST_SIP_AUTHENTICATION_ERROR ;
}
}
if ( endpoint = = artificial_endpoint ) {
is_artificial = endpoint = = artificial_endpoint ;
ao2_ref ( artificial_endpoint , - 1 ) ;
if ( is_artificial ) {
ast_assert ( auth_size = = 1 ) ;
auths [ 0 ] = ast_sip_get_artificial_auth ( ) ;
auths [ 0 ] = ast_sip_get_artificial_auth ( ) ;
} else if ( ast_sip_retrieve_auths ( & endpoint - > inbound_auths , auths ) ) {
if ( ! auths [ 0 ] ) {
res = AST_SIP_AUTHENTICATION_ERROR ;
/* Should not happen except possibly if we are shutting down. */
goto cleanup ;
return AST_SIP_AUTHENTICATION_ERROR ;
}
} else {
memset ( auths , 0 , auth_size * sizeof ( * auths ) ) ;
if ( ast_sip_retrieve_auths ( & endpoint - > inbound_auths , auths ) ) {
res = AST_SIP_AUTHENTICATION_ERROR ;
goto cleanup ;
}
}
}
for ( i = 0 ; i < auth_size ; + + i ) {
/* Setup shallow copy of auths */
if ( ast_strlen_zero ( auths [ i ] - > realm ) ) {
if ( ast_strlen_zero ( default_realm ) ) {
ast_string_field_set ( auths [ i ] , realm , default_realm ) ;
auths_shallow = auths ;
} else {
/*
* Set default realm on a shallow copy of the authentication
* objects that don ' t have a realm set .
*/
auths_shallow = ast_alloca ( auth_size * sizeof ( * auths_shallow ) ) ;
for ( idx = 0 ; idx < auth_size ; + + idx ) {
if ( ast_strlen_zero ( auths [ idx ] - > realm ) ) {
/*
* Make a shallow copy and set the default realm on it .
*
* The stack allocation is OK here . Normally this will
* loop one time . If you have multiple auths then you
* shouldn ' t need more auths than the normal complement
* of fingers and toes . Otherwise , you should check
* your sanity for setting up your system up that way .
*/
auths_shallow [ idx ] = ast_alloca ( sizeof ( * * auths_shallow ) ) ;
memcpy ( auths_shallow [ idx ] , auths [ idx ] , sizeof ( * * auths_shallow ) ) ;
* ( ( char * * ) ( & auths_shallow [ idx ] - > realm ) ) = default_realm ;
ast_debug ( 3 , " Using default realm '%s' on incoming auth '%s'. \n " ,
default_realm , ast_sorcery_object_get_id ( auths_shallow [ idx ] ) ) ;
} else {
auths_shallow [ idx ] = auths [ idx ] ;
}
}
}
verify_res [ i ] = verify ( auths [ i ] , rdata , tdata - > pool ) ;
}
if ( verify_res [ i ] = = AUTH_SUCCESS ) {
for ( idx = 0 ; idx < auth_size ; + + idx ) {
verify_res [ idx ] = verify ( auths_shallow [ idx ] , rdata , tdata - > pool ) ;
if ( verify_res [ idx ] = = AUTH_SUCCESS ) {
res = AST_SIP_AUTHENTICATION_SUCCESS ;
res = AST_SIP_AUTHENTICATION_SUCCESS ;
goto cleanup ;
goto cleanup ;
}
}
if ( verify_res [ i ] = = AUTH_FAIL ) {
if ( verify_res [ i dx ] = = AUTH_FAIL ) {
failures + + ;
failures + + ;
}
}
}
}
for ( i = 0 ; i < auth_size ; + + i ) {
for ( i dx = 0 ; i dx < auth_size ; + + i dx ) {
challenge ( auths [ i ] - > realm , tdata , rdata , verify_res [ i ] = = AUTH_STALE ) ;
challenge ( auths _shallow [ i dx ] - > realm , tdata , rdata , verify_res [ i dx ] = = AUTH_STALE ) ;
}
}
if ( failures = = auth_size ) {
if ( failures = = auth_size ) {