security.c

Go to the documentation of this file.
00001 /*
00002  * $Id: security.c 476 2007-11-02 18:41:52Z vingarzan $
00003  *  
00004  * Copyright (C) 2004-2006 FhG Fokus
00005  *
00006  * This file is part of Open IMS Core - an open source IMS CSCFs & HSS
00007  * implementation
00008  *
00009  * Open IMS Core is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * For a license to use the Open IMS Core software under conditions
00015  * other than those described here, or to purchase support for this
00016  * software, please contact Fraunhofer FOKUS by e-mail at the following
00017  * addresses:
00018  *     info@open-ims.org
00019  *
00020  * Open IMS Core is distributed in the hope that it will be useful,
00021  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00022  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023  * GNU General Public License for more details.
00024  * 
00025  * It has to be noted that this Open Source IMS Core System is not 
00026  * intended to become or act as a product in a commercial context! Its 
00027  * sole purpose is to provide an IMS core reference implementation for 
00028  * IMS technology testing and IMS application prototyping for research 
00029  * purposes, typically performed in IMS test-beds.
00030  * 
00031  * Users of the Open Source IMS Core System have to be aware that IMS
00032  * technology may be subject of patents and licence terms, as being 
00033  * specified within the various IMS-related IETF, ITU-T, ETSI, and 3GPP
00034  * standards. Thus all Open IMS Core users have to take notice of this 
00035  * fact and have to agree to check out carefully before installing, 
00036  * using and extending the Open Source IMS Core System, if related 
00037  * patents and licences may become applicable to the intended usage 
00038  * context.  
00039  *
00040  * You should have received a copy of the GNU General Public License
00041  * along with this program; if not, write to the Free Software
00042  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00043  * 
00044  */
00045  
00063 #include <signal.h> 
00064 #include <stdlib.h>
00065 
00066 #include "security.h"
00067 
00068 
00069 #include "mod.h"
00070 #include "sip.h"
00071 #include "registration.h"
00072 #include "registrar.h"
00073 #include "registrar_subscribe.h"
00074 #include "../../ip_addr.h"
00075 #include "../../data_lump.h"
00076 
00077 extern int   pcscf_use_ipsec;           
00078 extern char* pcscf_ipsec_host;          
00079 extern int   pcscf_ipsec_port_c;        
00080 extern int   pcscf_ipsec_port_s;        
00082 extern char* pcscf_ipsec_P_Inc_Req;     
00083 extern char* pcscf_ipsec_P_Out_Rpl;     
00084 extern char* pcscf_ipsec_P_Out_Req;     
00085 extern char* pcscf_ipsec_P_Inc_Rpl;     
00086 extern char* pcscf_ipsec_P_Drop;        
00088 extern r_hash_slot *registrar;          
00089 extern int r_hash_size;                 
00091 int current_spi=5000;       
00092 extern int pcscf_use_tls;                   
00093 extern int pcscf_tls_port;                  
00094 extern int tls_disable;
00095 
00101 int get_next_spi()
00102 {
00103     return current_spi++;
00104 }
00105 
00106 
00107 
00108 #define get_qparam(src,name,dst) \
00109 {\
00110     int i,j;\
00111     (dst).s=0;(dst).len=0;\
00112     for(i=0;i<(src).len-(name).len;i++)\
00113         if (strncasecmp((src).s+i,(name).s,(name).len)==0){\
00114             j=i+(name).len;\
00115             (dst).s = (src).s+j;\
00116             (dst).len = 0;\
00117             while(j<(src).len && (src).s[j]!='\"') \
00118                 j++;            \
00119             (dst).len = j-i-(name).len;\
00120             break;\
00121         }       \
00122 }
00123     
00124 #define get_param(src,name,dst) \
00125 {\
00126     int i,j;\
00127     (dst).s=0;(dst).len=0;\
00128     for(i=0;i<(src).len-(name).len;i++)\
00129         if (strncasecmp((src).s+i,(name).s,(name).len)==0 &&\
00130             ((src).s[i-1]==' ' ||(src).s[i-1]==';'||(src).s[i-1]=='\t')){\
00131             j=i+(name).len;\
00132             (dst).s = (src).s+j;\
00133             (dst).len = 0;\
00134             while(j<(src).len && (src).s[j]!=','&& (src).s[j]!=' '&& (src).s[j]!='\t'&& (src).s[j]!=';') \
00135                 j++;            \
00136             (dst).len = j-i-(name).len;\
00137             break;\
00138         }       \
00139 }
00140 
00141 #define strtoint(src,dest) \
00142 {\
00143     int i;\
00144     (dest)=0;\
00145     for(i=0;i<(src).len;i++)\
00146         if ((src).s[i]>='0' && (src).s[i]<='9')\
00147             (dest) = (dest)*10 + (src).s[i] -'0';\
00148 }
00149 
00150 str s_security_client={"Security-Client",15};
00151 str s_security_verify={"Security-Verify",15};
00152 
00153 str s_security_server_s={"Security-Server: ",17};
00154 str s_security_server_e={"\r\n",2};
00155 
00156 static str s_ck={"ck=\"",4};
00157 static str s_ik={"ik=\"",4};
00158 static str s_ealg={"ealg=",5};
00159 static str s_alg={"alg=",4};
00160 static str s_spi_c={"spi-c=",6};
00161 static str s_spi_s={"spi-s=",6};
00162 static str s_port_c={"port-c=",7};
00163 static str s_port_s={"port-s=",7};
00164 
00165 static str s_des_in={"des-ede3-cbc",12};
00166 static str s_des_out={"3des-cbc",8};
00167 static str s_aes_in={"aes-cbc",7};
00168 static str s_aes_out={"rijndael-cbc",12};
00169 //static str s_null_in={"null",4};
00170 static str s_null_out={"null",4};
00171 
00172 static str s_md5_in={"hmac-md5-96",11};
00173 static str s_md5_out={"hmac-md5",8};
00174 static str s_sha_in={"hmac-sha-1-96",13};
00175 static str s_sha_out={"hmac-sha1",9};
00176 
00177 extern time_t time_now;
00178 
00179 
00180 static str s_tls={"tls", 3};
00181 static str s_ipsec={"ipsec-3gpp", 10};
00182 static str s_q={"q=", 2};
00183 
00189 unsigned long tls_get_session_hash(struct sip_msg *req)
00190 {
00191     unsigned long s_hash = 0;
00192     if (!pcscf_use_tls) return 0;
00193     s_hash = get_tls_session_hash(req);
00194     if (!s_hash){
00195         LOG(L_ERR,"ERR:"M_NAME":tls_get_session_hash: Session Hash could not be obtained !\n");
00196         return 0;
00197     }
00198     return s_hash;
00199 }
00200 
00205 static int str_trim(str *s)
00206 {
00207     int i;
00208     for (i = 0;i < s->len; i++)
00209     {
00210         if (s->s[i] != '\r' && s->s[i] != '\t' && s->s[i] != ' ')
00211         {
00212             break;
00213         }
00214     }
00215     s->s = s->s + i;    
00216     s->len -= i;
00217 
00218     for (i = s->len;i >=0; i--)
00219     {
00220         if (s->s[i] == '\r' && s->s[i] == '\t' && s->s[i] == ' ')
00221         {
00222             s->len--;
00223         }
00224         else
00225         {
00226             break;
00227         }
00228     }
00229     return 1;
00230 }
00231 
00237 static r_security_type cscf_get_security_type(str security_header_body)
00238 {
00239     str sec_type_s;
00240     int i;
00241     
00242     sec_type_s.s = security_header_body.s;
00243     sec_type_s.len = security_header_body.len;
00244     for (i = 0; i< security_header_body.len; i++)
00245         if (security_header_body.s[i] == ';') {
00246             sec_type_s.len = i;
00247             break;
00248         }   
00249     str_trim(&sec_type_s);
00250     if (sec_type_s.len==s_tls.len &&
00251         !strncasecmp(sec_type_s.s, s_tls.s , s_tls.len))
00252         return SEC_TLS;
00253     else if (sec_type_s.len==s_ipsec.len &&
00254             !strncasecmp(sec_type_s.s, s_ipsec.s , s_ipsec.len))
00255             return SEC_IPSEC;
00256     return SEC_NONE;
00257 }
00258 
00267 str cscf_get_pref_security_header(struct sip_msg *req, str header_name,r_security_type *type, float *q)
00268 {
00269     str q_sec={0,0},t_sec;
00270     r_security_type q_type=SEC_NONE,t_type;
00271     float q_q=-1,t_q;
00272     struct hdr_field *hdr=0;    
00273     str tmp={0,0};
00274     char c; 
00275 
00276         
00277     /* first find the highest q */
00278     for(hdr = cscf_get_next_header(req,header_name,(void*)0);hdr;hdr = cscf_get_next_header(req,header_name,hdr)){
00279         t_sec = hdr->body;
00280         /* if unknown type, skip */
00281         t_type = cscf_get_security_type(t_sec);
00282         if (t_type==SEC_NONE ||
00283             (!pcscf_use_ipsec&&t_type==SEC_IPSEC)||
00284             (!pcscf_use_tls&&t_type==SEC_TLS)) continue;
00285         /* check if q is maximum */
00286         get_param(t_sec,s_q,tmp);
00287         if (tmp.len) {
00288             c = tmp.s[tmp.len];
00289             tmp.s[tmp.len]=0;           
00290             t_q = atof(tmp.s);
00291             tmp.s[tmp.len]=c;
00292         }   
00293         else t_q = -1;
00294         if (t_q > q_q || q_sec.len==0)  {           
00295             q_sec = t_sec;
00296             q_q = t_q;
00297             q_type = t_type;
00298         }       
00299     }
00300 
00301     if (!q_sec.len) {
00302         LOG(L_INFO,"DBG:"M_NAME":cscf_get_pref_security_header: No known Security header found.\n");
00303         return q_sec;
00304     }   
00305     
00306     if (type) *type = q_type;
00307     if (q) *q = q_q;
00308     return q_sec;
00309 }
00310 
00311 
00320 r_contact* save_contact_security(struct sip_msg *req, str auth, str sec_hdr,r_security_type type,float q)
00321 {
00322     contact_t* c=0;
00323     contact_body_t* b=0;    
00324     r_contact *rc;
00325     enum Reg_States reg_state=REG_PENDING;
00326     int expires,pending_expires=60;
00327     struct sip_uri puri;
00328     r_security *s=0;
00329     
00330     b = cscf_parse_contacts(req);
00331     
00332     if (!b||!b->contacts) {
00333         LOG(L_ERR,"ERR:"M_NAME":save_contact_security: No contacts found\n");
00334         goto error; 
00335     }
00336     
00337     if (b) c = b->contacts;
00338             
00339     r_act_time();
00340     /* the Security works for just 1 contact/registration! */
00341     if(c){
00342         LOG(L_DBG,"DBG:"M_NAME":save_contact_security: <%.*s>\n",c->uri.len,c->uri.s);
00343         
00344         expires = time_now+pending_expires;
00345         
00346         if (parse_uri(c->uri.s,c->uri.len,&puri)<0){
00347             LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Error parsing Contact URI <%.*s>\n",c->uri.len,c->uri.s);
00348             goto error;         
00349         }
00350         if (puri.port_no==0) puri.port_no=5060;
00351         LOG(L_DBG,"DBG:"M_NAME":save_contact_security: %d %.*s : %d\n",
00352             puri.proto, puri.host.len,puri.host.s,puri.port_no);
00353 
00354         if (type == SEC_TLS) 
00355             puri.proto = PROTO_TLS;
00356 
00357         /* create the r_security structure */
00358         s = new_r_security(sec_hdr,type,q);
00359         if (!s) goto error; 
00360 
00361         switch(type) {
00362             case SEC_NONE:
00363                 break;
00364             case SEC_TLS:
00365                 // r_tls creation happens on 200
00366                 break;
00367             case SEC_IPSEC:
00368             {
00369                 /* then parse the parameters */
00370                 r_ipsec *ipsec; 
00371                 str ck,ik,ealg,alg,tmp;
00372                 str alg_setkey,ealg_setkey;
00373                 unsigned int spi_uc,spi_us;
00374                 unsigned int spi_pc,spi_ps;
00375                 int port_uc,port_us;
00376                 char ck_c[64],ik_c[64];
00377                 str ck_esp={ck_c,0},ik_esp={ik_c,0};
00378                                     
00379                 get_qparam(auth,s_ck,ck);
00380                 LOG(L_DBG,"DBG:"M_NAME":save_contact_security: CK: <%.*s>\n",
00381                     ck.len,ck.s);
00382                 get_qparam(auth,s_ik,ik);
00383                 LOG(L_DBG,"DBG:"M_NAME":save_contact_security: IK: <%.*s>\n",
00384                     ik.len,ik.s);       
00385                 get_param(sec_hdr,s_ealg,ealg);
00386                 LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Enc Algorithm: <%.*s>\n",
00387                     ealg.len,ealg.s);
00388                 get_param(sec_hdr,s_alg,alg);
00389                 LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Int Algorithm: <%.*s>\n",
00390                     alg.len,alg.s);
00391                 /* and for spis */
00392                 get_param(sec_hdr,s_spi_c,tmp);
00393                 strtoint(tmp,spi_uc);
00394                 LOG(L_DBG,"DBG:"M_NAME":save_contact_security: SPI-C: %d\n",
00395                     spi_uc);
00396                 get_param(sec_hdr,s_spi_s,tmp);
00397                 strtoint(tmp,spi_us);
00398                 LOG(L_DBG,"DBG:"M_NAME":save_contact_security: SPI-S: %d\n",
00399                     spi_us);
00400                 /* and for ports */
00401                 get_param(sec_hdr,s_port_c,tmp);
00402                 strtoint(tmp,port_uc);
00403                 LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Port-C: %d\n",
00404                     port_uc);
00405                 get_param(sec_hdr,s_port_s,tmp);
00406                 strtoint(tmp,port_us);
00407                 LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Port-S: %d\n",
00408                     port_us);
00409         
00410                 ck_esp.s[ck_esp.len++]='0';
00411                 ck_esp.s[ck_esp.len++]='x'; 
00412                 if (ealg.len == s_des_in.len && strncasecmp(ealg.s,s_des_in.s,ealg.len)==0) {
00413                     memcpy(ck_esp.s+ck_esp.len,ck.s,32);ck_esp.len+=32;
00414                     memcpy(ck_esp.s+ck_esp.len,ck.s,16);ck_esp.len+=16;
00415                     ealg_setkey = s_des_out;
00416                 }
00417                 else
00418                 if (ealg.len == s_aes_in.len && strncasecmp(ealg.s,s_aes_in.s,ealg.len)==0) {
00419                     memcpy(ck_esp.s+ck_esp.len,ck.s,ck.len);ck_esp.len+=ck.len;
00420                     ealg_setkey = s_aes_out;
00421                 }else {
00422                     memcpy(ck_esp.s+ck_esp.len,ck.s,ck.len);ck_esp.len+=ck.len;
00423                     ealg_setkey = s_null_out;
00424                     ealg = s_null_out;
00425                 }
00426             
00427                 ik_esp.s[ik_esp.len++]='0';
00428                 ik_esp.s[ik_esp.len++]='x';     
00429                 if (alg.len == s_md5_in.len && strncasecmp(alg.s,s_md5_in.s,alg.len)==0) {
00430                     memcpy(ik_esp.s+ik_esp.len,ik.s,ik.len);ik_esp.len+=ik.len;
00431                     alg_setkey = s_md5_out;
00432                 }
00433                 else
00434                 if (alg.len == s_sha_in.len && strncasecmp(alg.s,s_sha_in.s,alg.len)==0) {      
00435                     memcpy(ik_esp.s+ik_esp.len,ik.s,ik.len);ik_esp.len+=ik.len;
00436                     memcpy(ik_esp.s+ik_esp.len,"00000000",8);ik_esp.len+=8;
00437                     alg_setkey = s_sha_out;
00438                 }else{
00439                     LOG(L_ERR,"ERR:"M_NAME":save_contact_security: Unknown Integrity algorithm <%.*s>\n",alg.len,alg.s);
00440                     goto error;
00441                 }
00442                 
00443                 spi_pc=get_next_spi();  
00444                 spi_ps=get_next_spi();  
00445 
00446                 ipsec = new_r_ipsec(spi_uc,spi_us,spi_pc,spi_ps,port_uc,port_us,
00447                     ealg_setkey,ealg, ck_esp,alg_setkey,alg, ik_esp);
00448                 if (!ipsec) goto error;
00449                 s->data.ipsec = ipsec;
00450                 
00451                 puri.port_no = ipsec->port_us;
00452                 /*
00453                  * this should actually be port_uc... then the cscf_get_ue_via should be 
00454                  * changed to give rport and not the port in the via. but this would
00455                  * break NATed clients...
00456                  */
00457             }
00458                 break;
00459         }
00460     }
00461     
00462     rc = update_r_contact_sec(puri.host,puri.port_no,puri.proto,
00463             &(c->uri),&reg_state,&expires,s);                       
00464 
00465     return rc;  
00466 error:
00467     if (s) free_r_security(s);
00468     return 0;   
00469 }
00470 
00479 inline int execute_cmd(char *cmd)
00480 {
00481     FILE *p;
00482     void *prev;
00483     char out[256];
00484     LOG(L_INFO,"INF:"M_NAME":execute_cmd: [%s]\n",cmd);     
00485     /* because SER forked dies when a chield dies, SIGCHLD is masked temporary */
00486     prev = signal(SIGCHLD,SIG_DFL);
00487     p = popen(cmd,"r");
00488     if (!p) {       
00489         LOG(L_ERR,"ERR:"M_NAME":execute_cmd: Error executing cmd> %s\n",cmd);
00490         signal(SIGCHLD,prev);   
00491         return 0;
00492     }
00493     while(fgets(out,256,p))
00494         LOG(L_DBG,"DBG:"M_NAME":execute_cmd: > %s",out);
00495     pclose(p);
00496     signal(SIGCHLD,prev);   
00497     return 1;
00498 }
00499 
00507 int P_verify_security(struct sip_msg *req,char *str1, char *str2)
00508 {
00509     str sec_hdr;
00510     struct hdr_field *h;
00511     struct via_body *vb;
00512     r_contact *c;
00513     r_security *s;
00514     r_security_type sec_type;
00515     float sec_q;
00516     
00517     str ealg,alg,tmp;
00518     unsigned int spi_pc,spi_ps;;
00519     int port_pc,port_ps;
00520 
00521     vb = cscf_get_first_via(req,&h);
00522 
00523     LOG(L_INFO,"DBG:"M_NAME":P_verify_security: Looking for <%d://%.*s:%d> \n", vb->proto,vb->host.len,vb->host.s,vb->port);
00524 
00525     c = get_r_contact(vb->host,vb->port,vb->proto);
00526 
00527     r_act_time();
00528     if (!c){
00529         //first register
00530         LOG(L_DBG,"DBG:"M_NAME":P_verify_security: No Contact found ! \n");
00531         return CSCF_RETURN_TRUE;
00532     }
00533 
00534     if (!r_valid_contact(c) || !c->security_temp){
00535         LOG(L_DBG,"DBG:"M_NAME":P_verify_security: No security temp !.\n");
00536         r_unlock(c->hash);
00537         return CSCF_RETURN_TRUE;
00538     }
00539 
00540     sec_hdr = cscf_get_pref_security_header(req,s_security_verify, &sec_type,&sec_q);
00541     if (!sec_hdr.len)
00542     {   
00543         LOG(L_DBG,"DBG:"M_NAME":P_verify_security: No Security-Verify header found.\n");
00544         r_unlock(c->hash);
00545         return CSCF_RETURN_TRUE;
00546     }
00547     
00548     s = c->security_temp;
00549     
00550     switch (s->type)
00551     {
00552     case SEC_NONE:
00553         break;
00554     case SEC_TLS:
00555         if (sec_type != SEC_TLS || req->rcv.dst_port != pcscf_tls_port)
00556                     goto error;
00557         break;
00558     case SEC_IPSEC:
00559         if (sec_type != SEC_IPSEC || req->rcv.dst_port != pcscf_ipsec_port_s)
00560         {
00561             LOG(L_INFO,"DBG:"M_NAME":P_verify_security: Not IPSEC tunnel!.\n");
00562             r_unlock(c->hash);
00563             goto error;
00564         }
00565         get_param(sec_hdr,s_ealg,ealg);
00566         get_param(sec_hdr,s_alg,alg);
00567         /* and for spis */
00568         get_param(sec_hdr,s_spi_c,tmp);
00569         strtoint(tmp,spi_pc);
00570         get_param(sec_hdr,s_spi_s,tmp);
00571         strtoint(tmp,spi_ps);
00572         /* and for ports */
00573         get_param(sec_hdr,s_port_c,tmp);
00574         strtoint(tmp,port_pc);
00575         get_param(sec_hdr,s_port_s,tmp);
00576         strtoint(tmp,port_ps);
00577         if ((s->data.ipsec->r_ealg.len != ealg.len || strncasecmp(s->data.ipsec->r_ealg.s, ealg.s, ealg.len)) ||
00578                 (s->data.ipsec->r_alg.len != alg.len || strncasecmp(s->data.ipsec->r_alg.s, alg.s, alg.len)) || 
00579                 (s->data.ipsec->spi_pc != spi_pc) ||
00580                 (s->data.ipsec->spi_ps != spi_ps) ||
00581                 (pcscf_ipsec_port_c != port_pc) ||
00582                 (pcscf_ipsec_port_s != port_ps))
00583         {       
00584             LOG(L_INFO,"DBG:"M_NAME":P_verify_security: No valid Security-Verify header!.\n");
00585             r_unlock(c->hash);
00586             goto error;
00587         }
00588         break;
00589     }
00590     r_unlock(c->hash);
00591     
00592     return CSCF_RETURN_TRUE;
00593 error:  
00594     return CSCF_RETURN_FALSE;
00595 }
00596 
00606 int P_security_401(struct sip_msg *rpl,char *str1, char *str2)
00607 {
00608     struct sip_msg *req;
00609     struct hdr_field *hdr;  
00610     str sec_hdr,sec_srv={0,0};
00611     r_security_type sec_type;
00612     char cmd[256];
00613     r_contact *c;
00614     r_ipsec *ipsec;
00615     float sec_q=-1;
00616     str auth;
00617 
00618     if (!pcscf_use_ipsec &&!pcscf_use_tls) goto ret_false;
00619     
00620     req = cscf_get_request_from_reply(rpl);
00621     if (!req){
00622         LOG(L_ERR,"ERR:"M_NAME":P_security_401: No transactional request found.\n");
00623         goto error;
00624     }
00625     auth = cscf_get_authenticate(rpl,&hdr);
00626     if (!auth.len){
00627         LOG(L_ERR,"ERR:"M_NAME":P_security_401: No WWW-Authenticate header found.\n");
00628         goto ret_false; 
00629     }
00630     
00631     sec_hdr = cscf_get_pref_security_header(req,s_security_client, &sec_type,&sec_q);
00632     if (!sec_hdr.len) { 
00633         LOG(L_DBG,"DBG:"M_NAME":P_security_401: No Security-Client header found.\n");
00634         goto ret_false;
00635     }
00636     LOG(L_INFO,"DBG:"M_NAME":P_security_401: Security-Client header found : <%.*s>.\n", sec_hdr.len, sec_hdr.s);    
00637 
00638 
00639     /* save data into registrar */
00640     c = save_contact_security(req, auth, sec_hdr, sec_type, sec_q); 
00641     if (!c) goto error;
00642     switch(sec_type){
00643         case SEC_NONE:
00644             break;
00645         case SEC_TLS:           
00646             /* try to add the Security-Server header */     
00647             sec_srv.len = s_security_server_s.len+sec_hdr.len+s_security_server_e.len;
00648             sec_srv.s = pkg_malloc(sec_srv.len);
00649             if (!sec_srv.s){
00650                 LOG(L_ERR,"ERR:"M_NAME":P_security_401: Error allocating %d pkg bytes \n",sec_srv.len);
00651                 goto error;
00652             }
00653             sec_srv.len=0;
00654             STR_APPEND(sec_srv,s_security_server_s);
00655             STR_APPEND(sec_srv,sec_hdr);
00656             STR_APPEND(sec_srv,s_security_server_e);
00657 
00658             if (!cscf_add_header(rpl,&sec_srv,HDR_OTHER_T)) {
00659                 LOG(L_ERR,"ERR:"M_NAME":P_security_401: Error adding header <%.*s> \n",sec_srv.len,sec_srv.s);
00660                 pkg_free(sec_srv.s);
00661                 goto error;
00662             }
00663             break;
00664         case SEC_IPSEC:
00665             ipsec = c->security_temp->data.ipsec;
00666             /* try to add the Security-Server header */
00667             sprintf(cmd,"Security-Server: ipsec-3gpp; ealg=%.*s; alg=%.*s; spi-c=%d; spi-s=%d; port-c=%d; port-s=%d; q=0.1\r\n",
00668                 ipsec->r_ealg.len,ipsec->r_ealg.s,
00669                 ipsec->r_alg.len,ipsec->r_alg.s,
00670                 ipsec->spi_pc,ipsec->spi_ps,
00671                 pcscf_ipsec_port_c,pcscf_ipsec_port_s);
00672             
00673             sec_srv.len = strlen(cmd);
00674             sec_srv.s = pkg_malloc(sec_srv.len);
00675             if (!sec_srv.s){
00676                 LOG(L_ERR,"ERR:"M_NAME":P_security_401: Error allocating %d pkg bytes \n",sec_srv.len);
00677                 goto error;
00678             }
00679             memcpy(sec_srv.s,cmd,sec_srv.len);
00680             if (!cscf_add_header(rpl,&sec_srv,HDR_OTHER_T)) {
00681                 LOG(L_ERR,"ERR:"M_NAME":P_security_401: Error adding header <%.*s> \n",sec_srv.len,sec_srv.s);
00682                 pkg_free(sec_srv.s);
00683                 goto error;
00684             }
00685     
00686             /* run the IPSec script */  
00687             /* P_Inc_Req */
00688             sprintf(cmd,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s",
00689                 pcscf_ipsec_P_Inc_Req,
00690                 c->host.len,c->host.s,
00691                 ipsec->port_uc,
00692                 pcscf_ipsec_host,
00693                 pcscf_ipsec_port_s,
00694                 ipsec->spi_ps,
00695                 ipsec->ealg.len,ipsec->ealg.s,
00696                 ipsec->ck.len,ipsec->ck.s,
00697                 ipsec->alg.len,ipsec->alg.s,
00698                 ipsec->ik.len,ipsec->ik.s);
00699 
00700             r_unlock(c->hash);
00701                 
00702             execute_cmd(cmd);
00703             break;                      
00704     }
00705     
00706     return CSCF_RETURN_TRUE;
00707 ret_false:
00708     return CSCF_RETURN_FALSE;
00709 error:
00710     return CSCF_RETURN_ERROR;
00711 }
00712 
00713 
00723 int P_security_200(struct sip_msg *rpl,char *str1, char *str2)
00724 {
00725     struct sip_msg *req;
00726     str sec_hdr;
00727     r_security_type sec_type;
00728     float sec_q;
00729     struct hdr_field *h;
00730     struct via_body *vb;
00731     r_contact *c;
00732     r_ipsec *i;
00733     int expires;
00734     unsigned long s_hash;
00735     char out_rpl[256],out_req[256],inc_rpl[256];
00736 
00737     if (!pcscf_use_ipsec &&!pcscf_use_tls) goto ret_false;
00738 
00739     req = cscf_get_request_from_reply(rpl);
00740     if (!req){
00741         LOG(L_ERR,"ERR:"M_NAME":P_security_200: No transactional request found.\n");
00742         goto error;
00743     }   
00744 
00745     sec_hdr = cscf_get_pref_security_header(req,s_security_client, &sec_type,&sec_q);   
00746     if (!sec_hdr.len) { 
00747         LOG(L_DBG,"DBG:"M_NAME":P_security_200: No Security-Verify header found.\n");
00748         goto error;
00749     }
00750     
00751     /* find the expires (reg or dereg?) */
00752     expires = cscf_get_max_expires(req);
00753     
00754     /* get the IPSec info from the registrar */
00755     
00756     vb = cscf_get_first_via(req,&h);    
00757     LOG(L_DBG,"DBG:"M_NAME":P_security_200: Looking for <%d://%.*s:%d> \n",
00758         vb->proto,vb->host.len,vb->host.s,vb->port);
00759 
00760     c = get_r_contact(vb->host,vb->port,vb->proto);
00761         
00762     r_act_time();
00763     if (!c){
00764         LOG(L_ERR,"ERR:"M_NAME":P_security_200: Contact not found\n");      
00765         goto error;
00766     }
00767     
00768     if (c->security_temp){
00769         if (c->security && c->security->type == SEC_TLS && 
00770                 (c->security->data.tls && c->security->data.tls->port_tls==req->rcv.src_port&& 
00771                  c->security->data.tls->session_hash!=0 && c->security->data.tls->session_hash == tls_get_session_hash(req))){
00772             /* don't replace security when doing an integrity protected REGISTER with
00773              *  possible attack-garbage from security_temp */
00774             P_security_drop(c,c->security_temp);
00775             free_r_security(c->security_temp);
00776             c->security_temp = 0;
00777         }
00778         else
00779         {   
00780             if (c->security) {
00781                 P_security_drop(c,c->security);
00782                 free_r_security(c->security);
00783             }
00784             
00785             c->security = c->security_temp;
00786             c->security_temp = 0;
00787         }
00788     }   
00789     
00790     switch(sec_type){
00791         case SEC_NONE:
00792             break;
00793         case SEC_TLS:
00794             if (c->security && pcscf_use_tls) {
00795                 r_tls *tls;
00796                 int port_tls = req->rcv.src_port;
00797                 s_hash = get_tls_session_hash(req);
00798                 if (!s_hash){
00799                     LOG(L_ERR,"ERR:"M_NAME":P_security_200: Session Hash could not be obtained !\n");
00800                     r_unlock(c->hash);
00801                     goto error;
00802                 }   
00803                 tls = new_r_tls(port_tls, s_hash);
00804                 if (!tls) goto error;
00805                 c->security->data.tls = tls;
00806             }       
00807             r_unlock(c->hash);
00808             break;
00809         case SEC_IPSEC:
00810             if (!r_valid_contact(c)||!c->security||!c->security->data.ipsec ){
00811                 LOG(L_DBG,"DBG:"M_NAME":P_security_200: Contact expired or no IPSec info\n");
00812                 r_unlock(c->hash);
00813                 goto error;
00814             }
00815             i = c->security->data.ipsec;
00816             
00817             /* P_Out_Rpl */
00818             sprintf(out_rpl,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s",
00819                 pcscf_ipsec_P_Out_Rpl,
00820                 c->host.len,c->host.s,
00821                 i->port_uc,
00822                 pcscf_ipsec_host,
00823                 pcscf_ipsec_port_s,
00824                 i->spi_uc,
00825                 i->ealg.len,i->ealg.s,
00826                 i->ck.len,i->ck.s,
00827                 i->alg.len,i->alg.s,
00828                 i->ik.len,i->ik.s   );                  
00829     
00830             /* P_Out_Req */
00831             sprintf(out_req,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s",
00832                 pcscf_ipsec_P_Out_Req,
00833                 c->host.len,c->host.s,
00834                 i->port_us,
00835                 pcscf_ipsec_host,
00836                 pcscf_ipsec_port_c,
00837                 i->spi_us,
00838                 i->ealg.len,i->ealg.s,
00839                 i->ck.len,i->ck.s,
00840                 i->alg.len,i->alg.s,
00841                 i->ik.len,i->ik.s   );                              
00842             /* P_Out_Inc_Rpl */
00843             sprintf(inc_rpl,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s",
00844                 pcscf_ipsec_P_Inc_Rpl,
00845                 c->host.len,c->host.s,
00846                 i->port_us,
00847                 pcscf_ipsec_host,
00848                 pcscf_ipsec_port_c,
00849                 i->spi_pc,
00850                 i->ealg.len,i->ealg.s,
00851                 i->ck.len,i->ck.s,
00852                 i->alg.len,i->alg.s,
00853                 i->ik.len,i->ik.s   );                              
00854                 
00855             if (expires<=0) {
00856                 /* Deregister */
00857                 c->reg_state = DEREGISTERED;
00858                 r_act_time();
00859                 c->expires = time_now + 60;
00860             }           
00861             r_unlock(c->hash);
00862         
00863             //print_r(L_CRIT);
00864             
00865             /* run the IPSec scripts */ 
00866             /* Registration */
00867             execute_cmd(out_rpl);       
00868             execute_cmd(out_req);       
00869             execute_cmd(inc_rpl);
00870             break;
00871     }
00872     
00873     return CSCF_RETURN_TRUE;
00874 ret_false:
00875     return CSCF_RETURN_FALSE;
00876 error:
00877     return CSCF_RETURN_ERROR;
00878 }
00879 
00880 
00888 void P_security_drop(r_contact *c,r_security *s)
00889 {
00890     char drop[256];
00891     r_ipsec *i;
00892     if (!s||!c) return;
00893     switch (s->type){
00894         case SEC_NONE:
00895             break;
00896         case SEC_TLS:
00897             //TODO!!!
00898             break;
00899         case SEC_IPSEC:
00900             i = s->data.ipsec;
00901             if (!i) return;
00902             sprintf(drop,"%s %.*s %d %d %s %d %d %d %d %d %d",
00903                 pcscf_ipsec_P_Drop,
00904                 c->host.len,c->host.s,
00905                 i->port_uc,
00906                 i->port_us,
00907                 pcscf_ipsec_host,
00908                 pcscf_ipsec_port_c,
00909                 pcscf_ipsec_port_s,
00910                 i->spi_uc,
00911                 i->spi_us,
00912                 i->spi_pc,
00913                 i->spi_ps);     
00914             execute_cmd(drop);
00915             break;
00916     }
00917 }
00918 
00919 
00927 int P_check_via_sent_by(struct sip_msg *msg,char *str1, char *str2)
00928 {
00929     int ret = CSCF_RETURN_FALSE;
00930     struct ip_addr *src_ip;
00931     char *src_ip_ch;
00932     str sent_by={0,0};
00933 
00934 
00935     /* get the real receive IP address */
00936     src_ip = &(msg->rcv.src_ip);
00937     src_ip_ch = ip_addr2a(src_ip);
00938     LOG(L_DBG,"DBG:"M_NAME":P_check_sent_by(): Received from <%s>\n",src_ip_ch);             
00939 
00940     /* find the sent-by Via parameter */
00941     sent_by = cscf_get_last_via_sent_by(msg);
00942     LOG(L_DBG,"DBG:"M_NAME":P_check_sent_by(): Via sent-by=<%.*s>\n",sent_by.len,sent_by.s);
00943             
00944     /* if not found, exit now */    
00945     if (sent_by.len == 0) {
00946         LOG(L_DBG,"DBG:"M_NAME":P_check_sent_by(): Via does not contain a sent-by value\n");
00947         return ret;
00948     }       
00949     
00950     /* if found, check if it is matching */
00951     if (sent_by.len==strlen(src_ip_ch) &&
00952         strncasecmp(sent_by.s,src_ip_ch,sent_by.len)==0){
00953             ret = CSCF_RETURN_TRUE;
00954             LOG(L_DBG,"DBG:"M_NAME":P_check_sent_by(): sent-by matches the actual IP received from\n");
00955     }else{
00956         ret = CSCF_RETURN_FALSE;
00957         LOG(L_DBG,"DBG:"M_NAME":P_check_sent_by(): sent-by does not match the actual IP received from\n");
00958     }   
00959     return ret;
00960 }
00961 
00962 
00970 int P_follows_via_list(struct sip_msg *rpl,char *str1, char *str2)
00971 {
00972     int h_req_pos, h_rpl_pos,indx_rpl, indx_req;
00973     struct hdr_field *h_req=NULL, *h_out_req, *h_rpl=NULL, *h_out_rpl;
00974     str via_req={0,0}, via_rpl={0,0};
00975 
00976     struct sip_msg *req = cscf_get_request_from_reply(rpl); 
00977     if (!req){
00978         LOG(L_ERR,"ERR:"M_NAME":P_follows_via_list: No transactional request found.\n");
00979         return CSCF_RETURN_ERROR;
00980     }   
00981 
00982     indx_rpl = indx_req = 0;
00983     //get via headers
00984     via_rpl = cscf_get_next_via_str(rpl, 0, 0, &h_out_rpl, &h_rpl_pos);
00985     while (via_rpl.len)
00986     {
00987         if (indx_rpl > 0) //first header from reply shouldn't be checked
00988         {
00989             if (indx_req == 0)
00990             {
00991                 via_req = cscf_get_next_via_str(req, 0, 0, &h_out_req, &h_req_pos);
00992                 if (!via_req.len || !cscf_str_via_matching(&via_req, &via_rpl))
00993                 {
00994                     LOG(L_INFO,"DBG:"M_NAME":P_follows_via_list: first via not matching <%.*s>!=<%.*s>\n",
00995                         via_req.len,via_req.s,via_rpl.len,via_rpl.s);
00996                     return CSCF_RETURN_FALSE; 
00997                 }
00998             }
00999             else
01000             {
01001                 if (!via_req.len || (via_req.len!=via_rpl.len) || (strncasecmp(via_req.s, via_rpl.s, via_req.len)))
01002                 {
01003                     LOG(L_INFO,"DBG:"M_NAME":P_follows_via_list: not matching <%.*s>!=<%.*s>\n",
01004                         via_req.len,via_req.s,via_rpl.len,via_rpl.s);
01005                     return CSCF_RETURN_FALSE;
01006                 }
01007             }
01008             indx_req++;
01009             h_req = h_out_req;
01010             if (!h_req)
01011             {
01012                 break;
01013             }
01014             via_req = cscf_get_next_via_str(req, h_req, h_req_pos , &h_out_req, &h_req_pos);
01015         }
01016         indx_rpl++;
01017         h_rpl = h_out_rpl;
01018         if (!h_rpl) break;
01019         via_rpl = cscf_get_next_via_str(rpl, h_rpl, h_rpl_pos , &h_out_rpl, &h_rpl_pos);
01020     }
01021 
01022     if (h_out_req || h_out_rpl) //remaining headers ...
01023     { 
01024         LOG(L_INFO,"DBG:"M_NAME":P_follows_via_list: header count not matching \n");
01025         return CSCF_RETURN_FALSE;
01026     }
01027     return CSCF_RETURN_TRUE;
01028 }
01029 
01030 static str via_hdr_s={"Via: ",5};
01031 static str via_hdr_e={"\r\n",2};
010