registration.c File Reference


Detailed Description

Serving-CSCF - Registration Related Operations.

Author:
Dragos Vingarzan vingarzan -at- fokus dot fraunhofer dot de

Definition in file registration.c.

#include "registration.h"
#include "../tm/tm_load.h"
#include "../cdp/cdp_load.h"
#include "sip.h"
#include "cx.h"
#include "cx_avp.h"
#include "conversion.h"
#include "registrar.h"
#include "sip_messages.h"
#include "rfc2617.h"
#include "s_persistency.h"
#include "ims_pm.h"

Go to the source code of this file.

Defines

#define get_param(src, name, dst)
#define h_inc   h+=v^(v>>3)

Functions

unsigned char get_algorithm_type (str algorithm)
 Convert the SIP Algorithm to its type.
unsigned char get_auth_scheme_type (str scheme)
 Convert the Diameter Authorization Scheme to its type.
int S_add_path_service_routes (struct sip_msg *msg, char *str1, char *str2)
 Copies the Path header from REGISTER request to reply, inserts the Service-Route.
int S_add_allow (struct sip_msg *msg, char *str1, char *str2)
 Inserts an Allow header with the given value.
int S_add_service_route (struct sip_msg *msg, char *str1, char *str2)
 Inserts a Service-Route header with the given value.
int S_add_p_charging_function_addresses (struct sip_msg *msg, char *str1, char *str2)
 Copies the P-Charging-Function-Addresses header with the saved CF values in the registrar.
int S_REGISTER_reply (struct sip_msg *msg, int code, char *text)
 Replies to a REGISTER and also adds the need headers Path and Service-Route are added.
int S_check_visited_network_id (struct sip_msg *msg, char *str1, char *str2)
 Checks if the P-Visited-Network-Id matches a regexp.
int S_is_integrity_protected (struct sip_msg *msg, char *str1, char *str2)
 Checks if the message is integrity protected.
static int matchesEarlyIMSIP (str ip, str sent_by)
 Check if the sent_by ip address matches the storred ip addreses for Early-IMS.
int S_is_authorized (struct sip_msg *msg, char *str1, char *str2)
 Checks if the message contains a valid response to a valid challenge.
int S_challenge (struct sip_msg *msg, char *str1, char *str2)
 Responds with a 401 Unauthorized containing the (new) challenge.
int pack_challenge (struct sip_msg *msg, str realm, auth_vector *av)
 Adds the WWW-Authenticate header for challenge, based on the authentication vector.
int S_MAR (struct sip_msg *msg, str public_identity, str private_identity, int count, str auth_scheme, str nonce, str auts, str server_name, str realm)
 Sends a Multimedia-Authentication-Response to retrieve some authentication vectors and maybe synchronize.
void auth_data_lock (unsigned int hash)
 Locks the required slot of the auth_data.
void auth_data_unlock (unsigned int hash)
 UnLocks the required slot of the auth_data.
int auth_data_init (int size)
 Initializes the Authorization Data structures.
void auth_data_destroy ()
 Destroy the Authorization Data structures.
auth_vectornew_auth_vector (int item_number, str auth_scheme, str authenticate, str authorization, str ck, str ik)
 Create new authorization vector.
void free_auth_vector (auth_vector *av)
 Frees the memory taken by a authentication vector.
auth_userdatanew_auth_userdata (str private_identity, str public_identity)
 Creates a new Authorization Userdata structure.
void free_auth_userdata (auth_userdata *aud)
 Deallocates the auth_userdata.
unsigned int get_hash_auth (str private_identity, str public_identity)
 Computes a hash based on the private and public identities.
auth_userdataget_auth_userdata (str private_identity, str public_identity)
 Retrieve the auth_userdata for a user.
int add_auth_vector (str private_identity, str public_identity, auth_vector *av)
 Add an authentication vector to the authentication userdata storage.
auth_vectorget_auth_vector (str private_identity, str public_identity, int status, str *nonce, unsigned int *hash)
 Retrieve an authentication vector.
int drop_auth_userdata (str private_identity, str public_identity)
 Declares all auth vectors as useless when we do a synchronization.
void start_reg_await_timer (auth_vector *av)
 Starts the reg_await_timer for an authentication vector.
void reg_await_timer (unsigned int ticks, void *param)
 Timer callback for reg await timers.

Variables

tm_binds tmb
 Structure with pointers to tm funcs.
cdp_binds cdpb
 Structure with pointers to cdp funcs.
unsigned char registration_default_algorithm_type
 fixed default algorithm for registration (if none present)
int registration_disable_early_ims
 if to disable the Early-IMS checks
int registration_disable_nass_bundled
 if to disable the NASS-Bundled checks
str scscf_name_str
 fixed name of the S-CSCF
str scscf_service_route
 the service route header
int auth_data_hash_size
 the size of the hash table
int auth_vector_timeout
 timeout for a sent auth vector to expire in sec
int auth_data_timeout
 timeout for a hash entry to expire when empty in sec
int av_request_at_once
 how many auth vectors to request in a MAR
int av_request_at_sync
 how many auth vectors to request in a sync MAR
str registration_qop_str
 the qop options to put in the authorization challenges
str algorithm_types []
str auth_scheme_types []
static str s_allow_s = {"Allow: ",7}
static str s_allow_e = {"\r\n",2}
static str s_service_route_s = {"Service-Route: <",16}
static str s_service_route_e = {";lr>\r\n",6}
static str s_p_charging_function_addresses_s = {"P-Charging-Function-Addresses:",30}
static str s_p_charging_function_addresses_1 = {" ccf=",5}
static str s_p_charging_function_addresses_2 = {" ecf=",5}
static str s_p_charging_function_addresses_3 = {";",1}
static str s_p_charging_function_addresses_e = {"\r\n",2}
char * zero_padded = "00000000000000000000000000000000"
static str empty_s = {0,0}
static str cell_id = {"dsl-location=", 13}
str S_WWW_Authorization_AKA
str S_WWW_Authorization_MD5
auth_hash_slot_tauth_data
 Authentication vector hash table.
int auth_data_hash_size
 authentication vector hash table size


Define Documentation

#define get_param ( src,
name,
dst   ) 

Value:

{\
    int i,j;\
    (dst).s=0;(dst).len=0;\
    for(i=0;i<(src).len-(name).len;i++)\
        if (strncasecmp((src).s+i,(name).s,(name).len)==0 &&\
            ((src).s[i-1]==' ' ||(src).s[i-1]==';'||(src).s[i-1]=='\t')){\
            j=i+(name).len;\
            (dst).s = (src).s+j;\
            (dst).len = 0;\
            while(j<(src).len && (src).s[j]!=','&& (src).s[j]!=' '&& (src).s[j]!='\t'&& (src).s[j]!=';') \
                j++;            \
            (dst).len = j-i-(name).len;\
            break;\
        }       \
}

Definition at line 113 of file registration.c.

#define h_inc   h+=v^(v>>3)


Function Documentation

unsigned char get_algorithm_type ( str  algorithm  ) 

Convert the SIP Algorithm to its type.

Parameters:
algorithm - the SIP Algorithm
Returns:
the algorithm type

Definition at line 135 of file registration.c.

References algorithm_types, and AUTH_UNKNOWN.

Referenced by mod_init().

00136 {   
00137     int i;
00138     for(i=0;algorithm_types[i].len>0;i++)
00139         if (algorithm_types[i].len == algorithm.len &&
00140             strncasecmp(algorithm_types[i].s,algorithm.s,algorithm.len)==0)
00141         return i;
00142     return AUTH_UNKNOWN;        
00143 }

unsigned char get_auth_scheme_type ( str  scheme  ) 

Convert the Diameter Authorization Scheme to its type.

Parameters:
scheme - the Diameter Authorization Scheme
Returns:
the SIP Algorithm

Definition at line 150 of file registration.c.

References auth_scheme_types, and AUTH_UNKNOWN.

Referenced by new_auth_vector().

00151 {
00152     int i;
00153     for(i=0;auth_scheme_types[i].len>0;i++)
00154         if (auth_scheme_types[i].len == scheme.len &&
00155             strncasecmp(auth_scheme_types[i].s,scheme.s,scheme.len)==0)
00156         return i;
00157     return AUTH_UNKNOWN;        
00158 }

int S_add_path_service_routes ( struct sip_msg *  msg,
char *  str1,
char *  str2 
)

Copies the Path header from REGISTER request to reply, inserts the Service-Route.

Parameters:
msg - the SIP message to operator on
str1 - no used
str2 - no used
Returns:
CSCF_RETURN_TRUE on success or CSCF_RETURN_FALSE if not added

Definition at line 169 of file registration.c.

References cscf_add_header_rpl(), CSCF_RETURN_FALSE, CSCF_RETURN_TRUE, M_NAME, and scscf_service_route.

00170 {
00171     struct hdr_field *h;
00172     str t={0,0};
00173     if (parse_headers(msg,HDR_EOH_F,0)<0){
00174         LOG(L_ERR,"ERR:"M_NAME":S_add_path_service_routes: Error parsing headers\n");
00175         return CSCF_RETURN_FALSE;
00176     }
00177     h = msg->headers;
00178     while(h){
00179         if (h->name.len == 4 &&
00180             strncasecmp(h->name.s,"Path",4)==0)
00181         {
00182             t.s = h->name.s;
00183             t.len = h->len;
00184             if (!cscf_add_header_rpl(msg,&(t))) return CSCF_RETURN_FALSE;
00185         }
00186         h = h->next;
00187     }
00188     
00189     if (!cscf_add_header_rpl(msg,&scscf_service_route)) return CSCF_RETURN_FALSE;
00190 
00191     return CSCF_RETURN_TRUE;
00192 }

int S_add_allow ( struct sip_msg *  msg,
char *  str1,
char *  str2 
)

Inserts an Allow header with the given value.

Parameters:
msg - the SIP message to operator on
str1 - the value to be inserted
str2 - no used
Returns:
CSCF_RETURN_TRUE on success or CSCF_RETURN_FALSE if not added

Definition at line 203 of file registration.c.

References cscf_add_header_rpl(), CSCF_RETURN_FALSE, CSCF_RETURN_TRUE, M_NAME, s_allow_e, s_allow_s, and STR_APPEND.

00204 {
00205     str hdr={0,0};
00206     str allow;
00207     allow.s = str1;
00208     allow.len = strlen(str1);
00209     
00210     hdr.len = s_allow_s.len+allow.len+s_allow_e.len;
00211     hdr.s = pkg_malloc(hdr.len);
00212     if (!hdr.s){
00213         LOG(L_ERR,"ERR:"M_NAME":S_add_allow: Error allocating %d bytes\n",hdr.len);
00214         return CSCF_RETURN_FALSE;
00215     }       
00216     hdr.len = 0;
00217     STR_APPEND(hdr,s_allow_s);
00218     STR_APPEND(hdr,allow);
00219     STR_APPEND(hdr,s_allow_e);
00220     
00221     if (!cscf_add_header_rpl(msg,&hdr)) {
00222         if (hdr.s) pkg_free(hdr.s);
00223         return CSCF_RETURN_FALSE;
00224     }
00225     
00226     if (hdr.s) pkg_free(hdr.s);
00227     return CSCF_RETURN_TRUE;
00228 }

int S_add_service_route ( struct sip_msg *  msg,
char *  str1,
char *  str2 
)

Inserts a Service-Route header with the given value.

Parameters:
msg - the SIP message to operator on
str1 - the value to be inserted
str2 - no used
Returns:
CSCF_RETURN_TRUE on success or CSCF_RETURN_FALSE if not added

Definition at line 239 of file registration.c.

References cscf_add_header_rpl(), CSCF_RETURN_FALSE, CSCF_RETURN_TRUE, M_NAME, s_service_route_e, s_service_route_s, and STR_APPEND.

00240 {
00241     str sr={0,0};
00242     str uri;
00243     uri.s = str1;
00244     uri.len = strlen(str1);
00245     
00246     sr.len = s_service_route_s.len+uri.len+s_service_route_e.len;
00247     sr.s = pkg_malloc(sr.len);
00248     if (!sr.s){
00249         LOG(L_ERR,"ERR:"M_NAME":S_add_service_route: Error allocating %d bytes\n",sr.len);
00250         return CSCF_RETURN_FALSE;
00251     }       
00252     sr.len = 0;
00253     STR_APPEND(sr,s_service_route_s);
00254     STR_APPEND(sr,uri);
00255     STR_APPEND(sr,s_service_route_e);
00256     
00257     if (!cscf_add_header_rpl(msg,&sr)) {
00258         if (sr.s) pkg_free(sr.s);
00259         return CSCF_RETURN_FALSE;
00260     }
00261     
00262     if (sr.s) pkg_free(sr.s);
00263     return CSCF_RETURN_TRUE;
00264 }

int S_add_p_charging_function_addresses ( struct sip_msg *  msg,
char *  str1,
char *  str2 
)

Copies the P-Charging-Function-Addresses header with the saved CF values in the registrar.

Parameters:
msg - the SIP REGISTER message to which reply to append
str1 - no used
str2 - no used
Returns:
CSCF_RETURN_TRUE on success or CSCF_RETURN_FALSE if not added

Definition at line 278 of file registration.c.

References _r_public::ccf1, _r_public::ccf2, cscf_add_header_rpl(), cscf_get_public_identity(), CSCF_RETURN_FALSE, CSCF_RETURN_TRUE, _r_public::ecf1, _r_public::ecf2, get_r_public(), _r_public::hash, M_NAME, r_unlock(), s_p_charging_function_addresses_1, s_p_charging_function_addresses_2, s_p_charging_function_addresses_3, s_p_charging_function_addresses_e, s_p_charging_function_addresses_s, and STR_APPEND.

00279 {
00280     str hdr={0,0};
00281     int ccnt=0,ecnt=0;
00282     str public_identity;    
00283     r_public *p=0;
00284     int ret = CSCF_RETURN_FALSE;
00285     
00286     public_identity = cscf_get_public_identity(msg);    
00287     LOG(L_INFO,"DBG:"M_NAME":S_add_p_charging_function_addresses: Looking for <%.*s>\n",public_identity.len,public_identity.s);
00288     p = get_r_public(public_identity);
00289     
00290     if (!p) {
00291         LOG(L_INFO,"DBG:"M_NAME":S_add_p_charging_function_addresses: No entry in registrar for <%.*s>\n",public_identity.len,public_identity.s);
00292         goto done;
00293     }
00294     
00295     ccnt = (p->ccf1.len!=0) + (p->ccf2.len!=0);
00296     ecnt = (p->ecf1.len!=0) + (p->ecf2.len!=0);     
00297     if (!(ccnt+ecnt)){
00298         LOG(L_INFO,"DBG:"M_NAME":S_add_p_charging_function_addresses: <%.*s> has no charging functions storred \n",public_identity.len,public_identity.s);
00299         goto done;
00300     }           
00301     
00302     hdr.len = s_p_charging_function_addresses_s.len + 
00303               s_p_charging_function_addresses_1.len * ccnt + p->ccf1.len + p->ccf2.len +
00304               s_p_charging_function_addresses_2.len * ecnt + p->ecf1.len + p->ecf2.len +
00305               s_p_charging_function_addresses_3.len * (ccnt+ecnt) +           
00306               s_p_charging_function_addresses_e.len;
00307     
00308     hdr.s = pkg_malloc(hdr.len);
00309     if (!hdr.s){
00310         LOG(L_ERR,"ERR:"M_NAME":S_add_p_charging_function_addresses: Error allocating %d bytes\n",hdr.len);
00311         goto done;
00312     }       
00313     hdr.len = 0;
00314     STR_APPEND(hdr,s_p_charging_function_addresses_s);
00315     ccnt = 0;
00316     if (p->ccf1.len) {
00317         STR_APPEND(hdr,s_p_charging_function_addresses_1);
00318         STR_APPEND(hdr,p->ccf1);        
00319         ccnt++;     
00320     } 
00321     if (p->ccf2.len) {
00322         if (ccnt) STR_APPEND(hdr,s_p_charging_function_addresses_3);
00323         STR_APPEND(hdr,s_p_charging_function_addresses_1);
00324         STR_APPEND(hdr,p->ccf2);        
00325         ccnt++;     
00326     } 
00327     if (p->ecf1.len) {
00328         if (ccnt) STR_APPEND(hdr,s_p_charging_function_addresses_3);
00329         STR_APPEND(hdr,s_p_charging_function_addresses_2);
00330         STR_APPEND(hdr,p->ecf1);        
00331         ccnt++;     
00332     } 
00333     if (p->ecf2.len) {
00334         if (ccnt) STR_APPEND(hdr,s_p_charging_function_addresses_3);
00335         STR_APPEND(hdr,s_p_charging_function_addresses_2);
00336         STR_APPEND(hdr,p->ecf2);        
00337         ccnt++;     
00338     } 
00339     
00340     STR_APPEND(hdr,s_p_charging_function_addresses_e);
00341     
00342     if (!cscf_add_header_rpl(msg,&hdr)) {
00343         LOG(L_ERR,"ERR:"M_NAME":S_add_p_charging_function_addresses: Error adding header <%.*s>\n",hdr.len,hdr.s);
00344         goto done;
00345     }
00346     ret = CSCF_RETURN_TRUE;
00347     
00348 done:   
00349     if (hdr.s) pkg_free(hdr.s);
00350     if (p) r_unlock(p->hash);
00351     return ret;
00352 }

int S_REGISTER_reply ( struct sip_msg *  msg,
int  code,
char *  text 
)

Replies to a REGISTER and also adds the need headers Path and Service-Route are added.

Parameters:
msg - the SIP message to operator on
code - Reason Code for the response
text - Reason Phrase for the response
Returns:
CSCF_RETURN_TRUE on success or CSCF_RETURN_FALSE if not added

Definition at line 363 of file registration.c.

References cscf_add_header_rpl(), cscf_reply_transactional(), M_NAME, and scscf_service_route.

Referenced by S_challenge(), S_MAR(), SAR(), and save_location().

00364 {
00365     struct hdr_field *h;
00366     str t={0,0};
00367     if (parse_headers(msg,HDR_EOH_F,0)<0){
00368         LOG(L_ERR,"ERR:"M_NAME":S_REGISTER_reply: Error parsing headers\n");
00369         return -1;
00370     }
00371     h = msg->headers;
00372     while(h){
00373         if (h->name.len == 4 &&
00374             strncasecmp(h->name.s,"Path",4)==0)
00375         {
00376             t.s = h->name.s;
00377             t.len = h->len;
00378             cscf_add_header_rpl(msg,&(t));
00379         }
00380         h = h->next;
00381     }
00382     
00383     if (code==200){
00384         cscf_add_header_rpl(msg,&scscf_service_route);
00385     }
00386     return cscf_reply_transactional(msg,code,text);
00387 }

int S_check_visited_network_id ( struct sip_msg *  msg,
char *  str1,
char *  str2 
)

Checks if the P-Visited-Network-Id matches a regexp.

Parameters:
msg - the SIP message
str1 - the regexp to check with
str2 - not used
Returns:
CSCF_RETURN_TRUE on match, CSCF_RETURN_FALSE else

Definition at line 396 of file registration.c.

References cscf_get_visited_network_id(), CSCF_RETURN_FALSE, and CSCF_RETURN_TRUE.

00397 {
00398     int ret = CSCF_RETURN_FALSE;
00399     char c;
00400     str v={0,0};
00401     regmatch_t pmatch;
00402     struct hdr_field *hdr;
00403     v = cscf_get_visited_network_id(msg,&hdr);
00404     c = v.s[v.len];
00405     v.s[v.len] = 0;
00406     if (regexec(((fparam_t*)str1)->v.regex, v.s, 1, &pmatch, 0)==0) ret = CSCF_RETURN_TRUE;
00407     v.s[v.len] = c;
00408     return ret;
00409 }

int S_is_integrity_protected ( struct sip_msg *  msg,
char *  str1,
char *  str2 
)

Checks if the message is integrity protected.

Parameters:
msg - the SIP message
str1 - the realm
str2 - not used
Returns:
- boolean values to script or break on error

Definition at line 418 of file registration.c.

References cscf_get_integrity_protected(), CSCF_RETURN_BREAK, CSCF_RETURN_FALSE, CSCF_RETURN_TRUE, and M_NAME.

00419 {
00420     str realm={0,0};
00421     int ret=0;
00422 
00423     realm.s = str1;realm.len = strlen(str1);
00424     if (!realm.len) {
00425         LOG(L_ERR,"ERR:"M_NAME":S_is_integrity_protected: No realm found\n");
00426         return CSCF_RETURN_BREAK;
00427     }
00428     if (cscf_get_integrity_protected(msg,realm)) ret = 1;
00429     
00430     LOG(L_DBG,"DBG:"M_NAME":S_is_integrity_protected: returns %d\n",ret);
00431     
00432     return ret?CSCF_RETURN_TRUE:CSCF_RETURN_FALSE;
00433 }

static int matchesEarlyIMSIP ( str  ip,
str  sent_by 
) [static]

Check if the sent_by ip address matches the storred ip addreses for Early-IMS.

Parameters:
ip - the byte array containing the 4/16 bytes of the IP address
sent_by - the sent_by parameter from the Via header
Returns:
1 on match or 0 on no match

Definition at line 441 of file registration.c.

References if.

Referenced by S_is_authorized().

00442 {
00443     struct addrinfo *ainfo,*res=0,hints;
00444     int error;
00445     char c;
00446     //int i;
00447     
00448     memset (&hints, 0, sizeof(hints));
00449     
00450     c = sent_by.s[sent_by.len];
00451     sent_by.s[sent_by.len]=0;
00452     
00453     error = getaddrinfo(sent_by.s, 0, &hints, &res);
00454     
00455     sent_by.s[sent_by.len]=c;
00456     
00457     if (error!=0){
00458         LOG(L_ERR,"ERROR:matchesEarlyIMSIP(): Error on getaddrinfo for sent_by = <%.*s>  >%s\n",
00459             sent_by.len,sent_by.s,gai_strerror(error));
00460         goto error;
00461     }
00462         
00463     for(ainfo = res;ainfo;ainfo = ainfo->ai_next)
00464     {   
00465 //      for(i=0;i<ainfo->ai_addrlen;i++)
00466 //          LOG(L_CRIT,">> %2d. \t %3d \t %.02x\n",i,ainfo->ai_addr->sa_data[i],ainfo->ai_addr->sa_data[i]);
00467         switch (ainfo->ai_family){
00468             case AF_INET:
00469                 if (ip.len==4&&memcmp(ainfo->ai_addr->sa_data+2,ip.s,4)==0)
00470                         goto success;
00471                 break;
00472             case AF_INET6:
00473                 if (ip.len==16&&memcmp(ainfo->ai_addr->sa_data+6,ip.s,16)==0)
00474                         goto success;
00475                 break;
00476             default:
00477                 LOG(L_ERR,"ERROR:matchesEarlyIMSIP(): Invalid ai_family %d\n",ainfo->ai_family);            
00478         }
00479     }
00480 error:
00481     if (res) freeaddrinfo(res);      
00482     return 0;
00483 success:
00484     if (res) freeaddrinfo(res);      
00485     return 1;   
00486 }

int S_is_authorized ( struct sip_msg *  msg,
char *  str1,
char *  str2 
)

Checks if the message contains a valid response to a valid challenge.

Parameters:
msg - the SIP message
str1 - the realm
str2 - not used
Returns:
CSCF_RETURN_TRUE if authorized, CSCF_RETURN_FALSE if not or CSCF_RETURN_ERROR on error

Definition at line 499 of file registration.c.

References algorithm_types, AUTH_AKAV1_MD5, AUTH_AKAV2_MD5, auth_data_unlock(), AUTH_DIGEST, AUTH_EARLY_IMS, AUTH_HTTP_DIGEST_MD5, AUTH_MD5, AUTH_NASS_BUNDLED, auth_scheme_types, AUTH_VECTOR_SENT, AUTH_VECTOR_UNUSED, AUTH_VECTOR_USED, AUTH_VECTOR_USELESS, _auth_vector::authenticate, _auth_vector::authorization, calc_H(), calc_HA1(), calc_response(), cscf_get_access_network_info(), cscf_get_body(), cscf_get_last_via_received(), cscf_get_last_via_sent_by(), cscf_get_nonce_response(), cscf_get_private_identity(), cscf_get_public_identity(), CSCF_RETURN_BREAK, CSCF_RETURN_ERROR, CSCF_RETURN_FALSE, CSCF_RETURN_TRUE, _r_public::early_ims_ip, get_auth_vector(), get_param, get_r_public(), HA_MD5, _r_public::hash, HASHHEXLEN, M_NAME, matchesEarlyIMSIP(), r_unlock(), registration_disable_early_ims, registration_disable_nass_bundled, S_MAR(), scscf_name_str, _auth_vector::status, STR_SHM_DUP, and _auth_vector::type.

00500 {
00501     int ret=CSCF_RETURN_FALSE;
00502     unsigned int aud_hash=0;
00503     str realm;
00504     str private_identity,public_identity;
00505     str nonce,response16,nc,cnonce,qop_str={0,0},body;
00506     enum qop_type qop=QOP_UNSPEC;
00507     str uri={0,0};
00508     HASHHEX expected,ha1,hbody;
00509     int expected_len=32;
00510     auth_vector *av=0;
00511     r_public *p=0;
00512     
00513 
00514     LOG(L_DBG,"DBG:"M_NAME":S_is_authorized: Checking if REGISTER is authorized...\n");
00515     
00516     /* First check the parameters */
00517     if (msg->first_line.type!=SIP_REQUEST||
00518         msg->first_line.u.request.method.len!=8||
00519         memcmp(msg->first_line.u.request.method.s,"REGISTER",8)!=0)
00520     {
00521         LOG(L_ERR,"ERR:"M_NAME":S_is_authorized: This message is not a REGISTER request\n");
00522         goto error;
00523     }       
00524     realm.s = str1;realm.len = strlen(str1);
00525     if (!realm.len) {
00526         LOG(L_ERR,"ERR:"M_NAME":S_is_authorized: No realm found\n");
00527         return CSCF_RETURN_BREAK;
00528     }
00529     
00530     private_identity = cscf_get_private_identity(msg,realm);
00531     if (!private_identity.len) {
00532         LOG(L_ERR,"ERR:"M_NAME":S_is_authorized: private identity missing\n");
00533         return ret;
00534     }
00535     
00536     public_identity = cscf_get_public_identity(msg);
00537     if (!public_identity.len) {
00538         LOG(L_ERR,"ERR:"M_NAME":S_is_authorized: public identity missing\n");       
00539         return ret;
00540     }
00541     
00542     /* check for Early-IMS case */
00543     if (!registration_disable_early_ims && !msg->authorization){
00544         str sent_by={0,0},received={0,0};
00545         
00546         sent_by = cscf_get_last_via_sent_by(msg);
00547         if (sent_by.len){
00548             ret = CSCF_RETURN_FALSE;
00549 
00550             LOG(L_INFO,"DBG:"M_NAME":S_is_authorized: Possible Early-IMS identified\n");
00551             received = cscf_get_last_via_received(msg);
00552             if (received.len) sent_by=received;
00553             /* if match, return authorized */
00554             p = get_r_public(public_identity);
00555             
00556             if (p && p->early_ims_ip.len!=0 &&
00557                 matchesEarlyIMSIP(p->early_ims_ip,sent_by)){
00558                 ret = CSCF_RETURN_TRUE;
00559                 goto done_early_ims;
00560             }
00561             do {
00562                 /* try and do MAR */
00563                 if (!S_MAR(msg,public_identity,private_identity,1,              
00564                     auth_scheme_types[AUTH_EARLY_IMS],empty_s,empty_s,scscf_name_str,realm)){
00565                     /* on fail, return not authorized */
00566 //                  if (p && p->early_ims_ip.s){
00567 //                      shm_free(p->early_ims_ip.s);
00568 //                      p->early_ims_ip.s=0;p->early_ims_ip.len=0;
00569 //                  }
00570                     goto done_early_ims;
00571                 }                                       
00572                 av = get_auth_vector(private_identity,public_identity,AUTH_VECTOR_UNUSED,0,&aud_hash);
00573             } while(!av);
00574             switch (av->authorization.len){
00575                 case 4:
00576                     LOG(L_ERR,"DBG:"M_NAME":S_is_authorized: IP address in MAA was <%d.%d.%d.%d>\n",
00577                         (unsigned char)av->authorization.s[0],
00578                         (unsigned char)av->authorization.s[1],
00579                         (unsigned char)av->authorization.s[2],
00580                         (unsigned char)av->authorization.s[3]);
00581                     break;
00582                 case 16:
00583                     LOG(L_ERR,"DBG:"M_NAME":S_is_authorized: IP address in MAA was <%.02x%.02x:%.02x%.02x:%.02x%.02x:%.02x%.02x:%.02x%.02x:%.02x%.02x:%.02x%.02x:%.02x%.02x>\n",
00584                         (unsigned char)av->authorization.s[0],
00585                         (unsigned char)av->authorization.s[1],
00586                         (unsigned char)av->authorization.s[2],
00587                         (unsigned char)av->authorization.s[3],
00588                         (unsigned char)av->authorization.s[4],
00589                         (unsigned char)av->authorization.s[5],
00590                         (unsigned char)av->authorization.s[6],
00591                         (unsigned char)av->authorization.s[7],
00592                         (unsigned char)av->authorization.s[8],
00593                         (unsigned char)av->authorization.s[9],
00594                         (unsigned char)av->authorization.s[10],
00595                         (unsigned char)av->authorization.s[11],
00596                         (unsigned char)av->authorization.s[12],
00597                         (unsigned char)av->authorization.s[13],
00598                         (unsigned char)av->authorization.s[14],
00599                         (unsigned char)av->authorization.s[15]
00600                         );
00601                     break;
00602             }                   
00603             if (av->authorization.len &&
00604                 matchesEarlyIMSIP(av->authorization,sent_by)){
00605                 ret = CSCF_RETURN_TRUE;
00606                 if (p) STR_SHM_DUP(p->early_ims_ip,av->authorization,"IP Early IMS");                                               
00607             }else
00608                 ret = CSCF_RETURN_FALSE;
00609         done_early_ims:                 
00610             if (p) r_unlock(p->hash);
00611             if (av) {
00612                 av->status = AUTH_VECTOR_USELESS;
00613                 auth_data_unlock(aud_hash);
00614             }
00615             return ret;                     
00616         }
00617     }
00618     /* NASS-Bundled */  
00619     if (!registration_disable_nass_bundled && !msg->authorization){
00620         str access_network_info={0,0};
00621         str dsl_location = {0,0};
00622         access_network_info = cscf_get_access_network_info(msg, 0);
00623         if (access_network_info.len)
00624         {
00625             get_param(access_network_info, cell_id, dsl_location);
00626         }
00627         if (dsl_location.len){
00628             int ret = CSCF_RETURN_FALSE;            
00629             LOG(L_ERR,"DBG:"M_NAME":S_is_authorized: Possible NASS-Bundled Authentication identified\n");
00630             do {
00631                 /* try and do MAR */
00632                 if (!S_MAR(msg,public_identity,private_identity,1,              
00633                     auth_scheme_types[AUTH_NASS_BUNDLED],empty_s,empty_s,scscf_name_str,realm)){
00634                     /* on fail, return not authorized */
00635                     goto done_nass_bundled;
00636                 }                                       
00637                 av = get_auth_vector(private_identity,public_identity,AUTH_VECTOR_UNUSED,0,&aud_hash);
00638             } while(!av);
00639             LOG(L_DBG,"DBG:"M_NAME":S_is_authorized: HSS said : <%.*s>, P sent : <%.*s>\n",
00640                 av->authorization.len,av->authorization.s, dsl_location.len, dsl_location.s);
00641             if (av->authorization.len == dsl_location.len &&
00642                 strncasecmp(av->authorization.s, dsl_location.s, dsl_location.len)==0){
00643                 ret = CSCF_RETURN_TRUE;
00644             }else
00645                 ret = CSCF_RETURN_FALSE;
00646         done_nass_bundled:  
00647             if (av) {
00648                 av->status = AUTH_VECTOR_USELESS;
00649                 auth_data_unlock(aud_hash);
00650             }
00651             return ret;                     
00652         }
00653     }
00654     
00655     if (!cscf_get_nonce_response(msg,realm,&nonce,&response16,&qop,&qop_str,&nc,&cnonce,&uri)||
00656         !nonce.len || !response16.len)
00657     {
00658         LOG(L_DBG,"DBG:"M_NAME":S_is_authorized: Nonce or reponse missing\n");
00659         return ret;
00660     }   
00661     
00662     if (qop==QOP_AUTHINT){
00663         body = cscf_get_body(msg);
00664         calc_H(&body,hbody);
00665     }
00666         
00667     av = get_auth_vector(private_identity,public_identity,AUTH_VECTOR_SENT,&nonce,&aud_hash);
00668 
00669     LOG(L_INFO,"DBG:"M_NAME":S_is_authorized: uri=%.*s nonce=%.*s response=%.*s qop=%.*s nc=%.*s cnonce=%.*s hbody=%.*s\n",
00670         uri.len,uri.s,
00671         nonce.len,nonce.s,
00672         response16.len,response16.s,
00673         qop_str.len,qop_str.s,
00674         nc.len,nc.s,
00675         cnonce.len,cnonce.s,
00676         32,hbody);
00677     
00678     if (!av) {
00679         LOG(L_ERR,"ERR:"M_NAME":S_is_authorized: no matching auth vector found - maybe timer expired\n");       
00680         return ret;
00681     }
00682     switch (av->type){
00683         case AUTH_AKAV1_MD5:
00684         case AUTH_AKAV2_MD5:
00685         case AUTH_MD5:
00686 //          LOG(L_CRIT,"A1: %.*s:%.*s:%.*s\n",private_identity.len,private_identity.s,
00687 //              realm.len,realm.s,av->authorization.len,av->authorization.s);
00688             
00689             calc_HA1(HA_MD5,&private_identity,&realm,&(av->authorization),&(av->authenticate),&cnonce,ha1);
00690             calc_response(ha1,&(av->authenticate),
00691                 &nc,
00692                 &cnonce,
00693                 &qop_str,
00694                 qop==QOP_AUTHINT,
00695                 &msg->first_line.u.request.method,&uri,hbody,expected);
00696             LOG(L_INFO,"DBG:"M_NAME":S_is_authorized: UE said: %.*s and we  expect %.*s ha1 %.*s\n",
00697                 response16.len,response16.s,/*av->authorization.len,av->authorization.s,*/32,expected,32,ha1);
00698             break;      
00699         case AUTH_DIGEST:
00700         case AUTH_HTTP_DIGEST_MD5:
00701 //          LOG(L_CRIT,"A1: %.*s:%.*s:%.*s\n",private_identity.len,private_identity.s,
00702 //              realm.len,realm.s,av->authorization.len,av->authorization.s);
00703             
00704             memcpy(ha1,av->authorization.s,HASHHEXLEN);                 
00705             calc_response(ha1,&(av->authenticate),
00706                 &nc,
00707                 &cnonce,
00708                 &qop_str,
00709                 qop==QOP_AUTHINT,
00710                 &msg->first_line.u.request.method,&uri,hbody,expected);
00711             LOG(L_INFO,"DBG:"M_NAME":S_is_authorized: UE said: %.*s and we  expect %.*s ha1 %.*s\n",
00712                 response16.len,response16.s,/*av->authorization.len,av->authorization.s,*/32,expected,32,ha1);
00713             break;      
00714         default:
00715             LOG(L_ERR,"ERR:"M_NAME":S_is_authorized: algorithm %.*s is not handled.\n",
00716                 algorithm_types[av->type].len,algorithm_types[av->type].s);
00717             goto error;
00718     }
00719 
00720     if (response16.len==expected_len && strncasecmp(response16.s,expected,response16.len)==0){  
00721         av->status = AUTH_VECTOR_USELESS;
00722         ret = CSCF_RETURN_TRUE;     
00723     }else {
00724         av->status = AUTH_VECTOR_USED;/* first mistake, you're out! (but maybe it's synchronization) */
00725         LOG(L_DBG,"DBG:"M_NAME":S_is_authorized: UE said: %.*s, but we have %.*s and expect %.*s\n",
00726             response16.len,response16.s,av->authorization.len,av->authorization.s,32,expected);     
00727     }       
00728     
00729         
00730     auth_data_unlock(aud_hash);
00731     return ret; 
00732 error:
00733 out_of_memory:
00734     if (p) r_unlock(p->hash);
00735     if (av) {
00736         auth_data_unlock(aud_hash);
00737     }
00738     ret = CSCF_RETURN_ERROR;        
00739     return ret;
00740 }

int S_challenge ( struct sip_msg *  msg,
char *  str1,
char *  str2 
)

Responds with a 401 Unauthorized containing the (new) challenge.

Parameters:
msg - the SIP message
str1 - the realm
str2<