00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
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
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
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
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
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
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
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
00366 break;
00367 case SEC_IPSEC:
00368 {
00369
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
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
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
00454
00455
00456
00457 }
00458 break;
00459 }
00460 }
00461
00462 rc = update_r_contact_sec(puri.host,puri.port_no,puri.proto,
00463 &(c->uri),®_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
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
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
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
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
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
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
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
00687
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
00752 expires = cscf_get_max_expires(req);
00753
00754
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
00773
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
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
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
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
00857 c->reg_state = DEREGISTERED;
00858 r_act_time();
00859 c->expires = time_now + 60;
00860 }
00861 r_unlock(c->hash);
00862
00863
00864
00865
00866
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
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
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
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
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
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
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)
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)
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