/** * Updates the r_contact with the new security values. * @param host - the host part of the contact, in string * @param port - the port number of the contact * @param transport - the transport of the contact * @param uri - URI of the contact * @param reg_state - Registration state * @param expires - expires in * @param ipsec - the new IPSec tunnel * @returns the newly added r_public, 0 on error */ r_contact* update_r_contact_sec(str host,int port,int transport, str *uri,enum Reg_States *reg_state,int *expires, r_security *s, int * sos_reg) { r_contact *c = NULL; r_reg_type sos_mask = NORMAL_REG; if(sos_reg && (*sos_reg)>0){ LOG(L_DBG,"DBG:"M_NAME":update_r_contact_sec: with sos uri param\n"); sos_mask = EMERG_REG; } c = get_r_contact(host,port,transport, sos_mask); if (!c){ if (uri&®_state){ c = add_r_contact(host,port,transport,*uri,*reg_state,*expires,(str*) 0,0,0,sos_mask); c->security_temp = s; r_unlock(c->hash); return c; } else return 0; }else{ if (c->security_temp){ P_security_drop(c,c->security_temp); free_r_security(c->security_temp); } c->security_temp = s; c->sos_flag = sos_mask; r_unlock(c->hash); return c; } }
/** * Processes a notification and updates the registrar info. * @param n - the notification * @param expires - the Subscription-Status expires parameter * @returns 1 on success, 0 on error */ int r_notification_process(r_notification *n,int expires) { r_registration *r; r_regcontact *rc; r_contact *c; struct sip_uri puri; enum Reg_States reg_state; int expires2; r_subscription *s=0; r_notification_print(n); if (!n) return 0; r_act_time(); r = n->registration; while(r){ rc = r->contact; while(rc){ if (parse_uri(rc->uri.s,rc->uri.len,&puri)<0){ LOG(L_ERR,"ERR:"M_NAME":r_notification_process: Error parsing Contact URI <%.*s>\n", rc->uri.len,rc->uri.s); goto next; } // LOG(L_CRIT,"DBG:"M_NAME":r_notification_process: refreshing contacts <%.*s> [%d]\n",rc->uri.len,rc->uri.s,rc->expires); if (rc->state==IMS_REGINFO_TERMINATED){ reg_state = DEREGISTERED; expires2 = time_now+30; c = update_r_contact(puri.host,puri.port_no,puri.proto, 0,®_state,&expires2,0,0,0); if (c) { LOG(L_DBG,"DBG:"M_NAME":r_notification_process: expired contact <%.*s>\n", c->uri.len,c->uri.s); r_unlock(c->hash); } }else{ reg_state = REGISTERED; expires2 = rc->expires+time_now; c = update_r_contact(puri.host,puri.port_no,puri.proto, 0,®_state,&expires2,0,0,0); if (c) { LOG(L_DBG,"DBG:"M_NAME":r_notification_process: refreshing contact <%.*s> [%d]\n", c->uri.len,c->uri.s,rc->expires); r_unlock(c->hash); } } next: rc = rc->next; } s = get_r_subscription(r->aor); if (s){ update_r_subscription(s,expires); subs_unlock(s->hash); } r = r->next; } return 1; }
r_public* get_matching_wildcard_psi(str aor) { r_public *p=0; t_regexp_unit *t; regex_t exp; char *c,*temp; int len; int errcode; p = registrar[r_hash_size].head; r_lock(r_hash_size); while (p) { for(t=p->regexp->head;t;t=t->next) { LOG(L_DBG,"get_matching_wildcard_psi match %.*s with %s\n",aor.len,aor.s,t->s); c=shm_malloc((aor.len)+1); memcpy(c,aor.s,aor.len); c[aor.len]='\0'; errcode=regcomp(&(exp),t->s,REG_ICASE|REG_EXTENDED|REG_NOSUB); if(errcode!=0) { // there was an error LOG(L_DBG,"there was at least ONE error in regcomp %i\n",errcode); //shm_free(temp); temp=NULL; len=regerror(errcode,&(exp),NULL,0); temp=shm_malloc(len); regerror(errcode,&(exp),temp,len); LOG(L_DBG,"and that was %s",temp); shm_free(temp); temp=NULL; //shm_free(newwpsi); r_unlock(r_hash_size); return NULL; } if (regexec(&(exp),c,0,NULL,0)==0) { //LOG(L_DBG,"A match has been produced!!!!!\n"); shm_free(c); return p; } else { //LOG(L_ERR,"there was no match\n"); } shm_free(c); } p=p->next; } LOG(L_ERR,"get_r_public (Trying wildcard PSI) found no match\n"); r_unlock(r_hash_size); return 0; }
/** * Expires all the contacts of public identities that are related to the given private id * @param private_id - private identity to expire contacts for */ void r_private_expire(str private_id) { int expire,i; r_public *p; r_contact *c; r_act_time(); expire = time_now; for(i=0;i<r_hash_size;i++){ r_lock(i); for(p = registrar[i].head;p;p=p->next){ if (p->s){ lock_get(p->s->lock); if (p->s->private_identity.len == private_id.len && strncasecmp(p->s->private_identity.s,private_id.s,private_id.len)==0){ for(c=p->head;c;c=c->next) c->expires = expire; } lock_release(p->s->lock); } } r_unlock(i); } print_r(L_ALERT); }
void* thread_fn(void* arg) { lli slee, start, end; lli loops_ps = loops_per_sec; double lratio = 1.0 - ratio; double wratio = lratio / (1. - lratio); lli loops, i; int syncl = sync_barrier; int local_finish; long long int interval = *((long long int*)arg); while(1) { r_lock(); /* begin reading */ if (syncl) { pthread_barrier_wait(&barrier); // this can't fail according to docs } local_finish = finished; r_unlock(); if (local_finish) { break; } start = GET_TIME(); mysleep(interval); end = GET_TIME(); slee = end - start; loops = (lli)(loops_ps * slee * wratio / 1000000.0); for (i=0; i < loops; i++) { LOOP(); } } return 0; }
/** * Searches for a r_public record and returns it. * \note Aquires the lock on the hash slot on success, so release it when you are done. * @param aor - the address of record to look for * @returns - the r_public found, 0 if not found */ r_public* get_r_public(str aor) { r_public *p=0; unsigned int hash; hash = get_aor_hash(aor,r_hash_size); r_lock(hash); p = registrar[hash].head; while(p){ if (p->aor.len == aor.len && strncasecmp(p->aor.s,aor.s,aor.len)==0) return p; p = p->next; } r_unlock(hash); /* * Here i plan to put the function that tries to match the aor with the wPSI * There might be an issue * if i return this locked, then i have to wait for the lock in the next one... * mmmh... might be an issue * */ if (scscf_support_wildcardPSI) return(get_matching_wildcard_psi(aor)); else return 0; }
/** * Expires all the contacts for the given public id * @param public_id - public identity to expire contacts for */ void r_public_expire(str public_id) { int expire; r_public *r_pub; r_contact * r_cont ; r_act_time(); expire = time_now; r_pub = get_r_public(public_id); if (!r_pub){ LOG(L_ERR,"ERR:"M_NAME":set_expires: identity not found in registrar <%.*s>\n",public_id.len,public_id.s); return; } r_cont = r_pub->head; while(r_cont!=NULL){ r_cont->expires = expire; r_cont=r_cont->next; } r_unlock(r_pub->hash); print_r(L_ALERT); }
/** * Debug print the contents of the entire registrar. * @param log_level - logging level */ void print_r(int log_level) { r_public *p; r_contact *c; r_subscriber *s; int i; if (debug<log_level) return; /* to avoid useless calls when nothing will be printed */ r_act_time(); LOG(log_level,ANSI_GREEN"INF:"M_NAME":---------- Registrar Contents begin --------\n"); for(i=0;i<r_hash_size;i++){ r_lock(i); p = registrar[i].head; while(p){ LOG(log_level,ANSI_GREEN"INF:"M_NAME":[%4d] P: <"ANSI_BLUE"%.*s"ANSI_GREEN"> R["ANSI_MAGENTA"%2d"ANSI_GREEN"] Early-IMS: <"ANSI_YELLOW"%.*s"ANSI_GREEN"> \n",i, p->aor.len,p->aor.s,p->reg_state,p->early_ims_ip.len,p->early_ims_ip.s); if (p->ccf1.len) LOG(log_level,ANSI_GREEN"INF:"M_NAME": CCF1: <"ANSI_MAGENTA"%.*s"ANSI_GREEN"> CCF2: <"ANSI_MAGENTA"%.*s"ANSI_GREEN"> \n", p->ccf1.len,p->ccf1.s,p->ccf2.len,p->ccf2.s); if (p->ecf1.len) LOG(log_level,ANSI_GREEN"INF:"M_NAME": ECF1: <"ANSI_MAGENTA"%.*s"ANSI_GREEN"> ECF2: <"ANSI_MAGENTA"%.*s"ANSI_GREEN"> \n", p->ecf1.len,p->ecf1.s,p->ecf2.len,p->ecf2.s); c = p->head; while(c){ LOG(log_level,ANSI_GREEN"INF:"M_NAME": C: <"ANSI_RED"%.*s"ANSI_GREEN"> Exp:["ANSI_MAGENTA"%4ld"ANSI_GREEN"]\n", c->uri.len,c->uri.s,c->expires-time_now); LOG(log_level,ANSI_GREEN"INF:"M_NAME": UP: {"ANSI_BLUE" iptv[%s], text[%s], data[%s], audio[%s], video[%s], control[%s], isfocus[%s], automata[%s], application[%s]\n mobility[%s]"ANSI_GREEN" }\n", ((c->user_pref->iptv == TRUE)?"yes":"no"), ((c->user_pref->text == TRUE)?"yes":"no"), ((c->user_pref->data == TRUE)?"yes":"no"), ((c->user_pref->audio == TRUE)?"yes":"no"), ((c->user_pref->video == TRUE)?"yes":"no"), ((c->user_pref->control == TRUE)?"yes":"no"), ((c->user_pref->isfocus == TRUE)?"yes":"no"), ((c->user_pref->automata == TRUE)?"yes":"no"), ((c->user_pref->application== TRUE)?"yes":"no"), ((c->user_pref->mobility.val_list[0] == MOBILE)?"mobile":"fixed") ) ; LOG(log_level,ANSI_GREEN"INF:"M_NAME": Path:"ANSI_YELLOW"%.*s"ANSI_GREEN"\n",c->path.len,c->path.s); LOG(log_level,ANSI_GREEN"INF:"M_NAME": UA: <%.*s>\n", c->ua.len,c->ua.s); c = c->next; } s = p->shead; while(s){ LOG(log_level,ANSI_GREEN"INF:"M_NAME": S: Event["ANSI_BLUE"%d"ANSI_GREEN "] Exp:["ANSI_MAGENTA"%4ld"ANSI_GREEN"] <"ANSI_CYAN"%.*s"ANSI_GREEN"> \n", s->event,s->expires-time_now,s->subscriber.len,s->subscriber.s); s = s->next; } p = p->next; } r_unlock(i); } LOG(log_level,"INF:"M_NAME":---------- Registrar Contents end ----------\n"); }
r_public* get_r_public_wpsi(str pi) { r_public *p=0; r_lock(r_hash_size); p = registrar[r_hash_size].head; while(p){ if (p->aor.len == pi.len && strncasecmp(p->aor.s,pi.s,pi.len)==0) return p; p = p->next; } r_unlock(r_hash_size); return 0; }
/** * Searches for a r_public record and returns its expiration value. * @param aor - the address of record to look for * @returns - the expiration of the r_public if found or -999 if not found */ int get_r_public_expires(str aor) { int max_expires=-999; r_contact *c; r_public *p=get_r_public(aor); if (!p) return -999; r_act_time(); for(c=p->head;c;c=c->next) if (c->expires-time_now>max_expires){ max_expires = c->expires - time_now; } r_unlock(p->hash); return max_expires; }
/** * Searches for a r_public record and returns it. * \note Aquires the lock on the hash slot on success, so release it when you are done. * @param aor - the address of record to look for * @returns - the r_public found, 0 if not found */ r_public* get_r_public(str aor) { r_public *p=0; unsigned int hash; hash = get_aor_hash(aor,r_hash_size); r_lock(hash); p = registrar[hash].head; while(p){ if (p->aor.len == aor.len && strncasecmp(p->aor.s,aor.s,aor.len)==0) return p; p = p->next; } r_unlock(hash); return 0; }
/** * Destroy the registrar */ void r_storage_destroy() { int i; r_contact *c,*nc; for(i=0;i<r_hash_size;i++){ r_lock(i); c = registrar[i].head; while(c){ nc = c->next; free_r_contact(c); c = nc; } r_unlock(i); lock_dealloc(registrar[i].lock); } shm_free(registrar); }
/** * Destroy the registrar */ void r_storage_destroy() { int i; r_public *p,*np; for(i=0;i<r_hash_size;i++){ r_lock(i); p = registrar[i].head; while(p){ np = p->next; free_r_public(p); p = np; } r_unlock(i); lock_dealloc(registrar[i].lock); } shm_free(registrar); }
/** * Searches for a r_contact contact and returns it. * \note Will lock the hash_slot if found! So release it when you are done! * @param host - the IP in string format * @param port - the port number * @param transport - the transport type * @param sos_mask - type of registration * @returns - the r_contact found, 0 if not found */ r_contact* get_r_contact(str host,int port,int transport, r_reg_type sos_mask) { r_contact *c=0; unsigned int hash; if (!registrar) return 0; hash = get_contact_hash(host,port,transport,r_hash_size); r_lock(hash); c = registrar[hash].head; while(c){ if (c->port == port && (c->sos_flag & sos_mask) && // c->transport == transport && /* because xten doesn't care about protocols */ c->host.len == host.len && strncasecmp(c->host.s,host.s,host.len)==0) return c; c = c->next; } r_unlock(hash); return 0; }
/** * Debug print the contents of the entire registrar. * @param log_level - logging level */ void print_r(int log_level) { r_public *p; r_contact *c; r_subscriber *s; int i; if (debug<log_level) return; /* to avoid useless calls when nothing will be printed */ r_act_time(); LOG(log_level,ANSI_GREEN"INF:"M_NAME":---------- Registrar Contents begin --------\n"); for(i=0;i<r_hash_size;i++){ r_lock(i); p = registrar[i].head; while(p){ LOG(log_level,ANSI_GREEN"INF:"M_NAME":[%4d] P: <"ANSI_BLUE"%.*s"ANSI_GREEN"> R["ANSI_MAGENTA"%2d"ANSI_GREEN"] Early-IMS: <"ANSI_YELLOW"%.*s"ANSI_GREEN"> \n",i, p->aor.len,p->aor.s,p->reg_state,p->early_ims_ip.len,p->early_ims_ip.s); if (p->ccf1.len) LOG(log_level,ANSI_GREEN"INF:"M_NAME": CCF1: <"ANSI_MAGENTA"%.*s"ANSI_GREEN"> CCF2: <"ANSI_MAGENTA"%.*s"ANSI_GREEN"> \n", p->ccf1.len,p->ccf1.s,p->ccf2.len,p->ccf2.s); if (p->ecf1.len) LOG(log_level,ANSI_GREEN"INF:"M_NAME": ECF1: <"ANSI_MAGENTA"%.*s"ANSI_GREEN"> ECF2: <"ANSI_MAGENTA"%.*s"ANSI_GREEN"> \n", p->ecf1.len,p->ecf1.s,p->ecf2.len,p->ecf2.s); c = p->head; while(c){ LOG(log_level,ANSI_GREEN"INF:"M_NAME": C: <"ANSI_RED"%.*s"ANSI_GREEN"> Exp:["ANSI_MAGENTA"%4ld"ANSI_GREEN"]\n", c->uri.len,c->uri.s,c->expires-time_now); LOG(log_level,ANSI_GREEN"INF:"M_NAME": Path:"ANSI_YELLOW"%.*s"ANSI_GREEN"\n",c->path.len,c->path.s); LOG(log_level,ANSI_GREEN"INF:"M_NAME": UA: <%.*s>\n", c->ua.len,c->ua.s); c = c->next; } s = p->shead; while(s){ LOG(log_level,ANSI_GREEN"INF:"M_NAME": S: Event["ANSI_BLUE"%d"ANSI_GREEN "] Exp:["ANSI_MAGENTA"%4ld"ANSI_GREEN"] <"ANSI_CYAN"%.*s"ANSI_GREEN"> \n", s->event,s->expires-time_now,s->subscriber.len,s->subscriber.s); s = s->next; } p = p->next; } r_unlock(i); } LOG(log_level,"INF:"M_NAME":---------- Registrar Contents end ----------\n"); }
r_contact * get_next_em_r_contact(str pub_id, contact_t * crt_contact){ r_contact * c = NULL; r_public * crt_pub_id; unsigned int hash; if (!registrar) return 0; for(hash=0; hash<r_hash_size;hash++){ r_lock(hash); for(c = registrar[hash].head;c!=NULL; c=c->next){ if(!(c->sos_flag & EMERG_REG)) continue; if(crt_contact->uri.len == c->uri.len && strncasecmp(crt_contact->uri.s, c->uri.s, crt_contact->uri.len) ==0){ LOG(L_DBG,"DBG:"M_NAME":update_contacts: found contact %.*s, but on the same host\n", crt_contact->uri.len, crt_contact->uri.s); continue; } crt_pub_id = c->head; if(!crt_pub_id) continue; if(crt_pub_id->aor.len == pub_id.len && strncasecmp(crt_pub_id->aor.s,pub_id.s,pub_id.len)==0) { LOG(L_DBG,"DBG:"M_NAME":get_next_em_r_contact: found contact %.*s:%i\n", c->host.len, c->host.s, c->port); return c; } } r_unlock(hash); } return 0; }
/** * Process a Push Profile Request and return the Answer for it. * @param ppr - the PPR Diameter request * @returns the PPA Diameter answer */ AAAMessage* Cx_PPA(AAAMessage * ppr) { AAAMessage *ppa_msg; str ppr_data; ims_subscription *imss; int i,j; r_public *pu; str ccf1,ccf2,ecf1,ecf2; ppa_msg = cdpb.AAACreateResponse(ppr); if (!ppa_msg) return 0; if((ppr_data=Cx_get_user_data(ppr)).len != 0){ LOG(L_INFO,"INFO:"M_NAME":Cx_PPA(): Received a User_Data PPR!\n"); imss=parse_user_data(ppr_data); print_user_data(L_ALERT,imss); for(i=0;i<imss->service_profiles_cnt;i++) for(j=0;j<imss->service_profiles[i].public_identities_cnt;j++){ pu = update_r_public(imss->service_profiles[i].public_identities[j].public_identity, 0,&imss,0,0,0,0); if (!pu) continue; r_unlock(pu->hash); } } else{ if (Cx_get_charging_info(ppr,&ccf1,&ccf2,&ecf1,&ecf2)){ LOG(L_INFO,"INFO:"M_NAME":Cx_PPA(): Received a Charging Info PPR - NOT IMPLEMENTED\n"); //TODO find all r_public that should be updated and update } } Cx_add_vendor_specific_appid(ppa_msg,IMS_vendor_id_3GPP,IMS_Cx,0 /*IMS_Cx*/); Cx_add_auth_session_state(ppa_msg,1); Cx_add_result_code(ppa_msg,DIAMETER_SUCCESS); #ifdef WITH_IMS_PM ims_pm_diameter_answer(ppa_msg); #endif return ppa_msg; }
/** * Loads the registrar data from the last snapshot. * @returns 1 on success or 0 on failure */ int load_snapshot_registrar() { bin_data x; r_contact *c; int k,max; FILE *f; switch (pcscf_persistency_mode){ case NO_PERSISTENCY: k=0; case WITH_FILES: f = bin_load_from_file_open(pcscf_persistency_location,"pregistrar"); if (!f) return 0; bin_alloc(&x,128*1024); k=bin_load_from_file_read(f,&x); max = x.max; x.max=0; LOG(L_INFO,"INFO:"M_NAME":load_snapshot_registrar: max %d len %d\n",x.max,x.len); while(x.max<x.len){ c = bin_decode_r_contact(&x); if (!c) return 0; LOG(L_INFO,"INFO:"M_NAME":load_snapshot_registrar: Loaded r_contact for <%.*s>\n",c->uri.len,c->uri.s); r_lock(c->hash); c->prev = registrar[c->hash].tail; c->next = 0; if (registrar[c->hash].tail) registrar[c->hash].tail->next = c; registrar[c->hash].tail = c; if (!registrar[c->hash].head) registrar[c->hash].head = c; r_unlock(c->hash); memmove(x.s,x.s+x.max,x.len-x.max); x.len -= x.max; x.max = max; k=bin_load_from_file_read(f,&x); max = x.max; x.max = 0; } bin_free(&x); bin_load_from_file_close(f); k = 1; break; case WITH_DATABASE_BULK: k=bin_load_from_db(&x, P_REGISTRAR); x.max=0; LOG(L_INFO,"INFO:"M_NAME":load_snapshot_registrar: max %d len %d\n",x.max,x.len); while(x.max<x.len){ c = bin_decode_r_contact(&x); if (!c) return 0; LOG(L_INFO,"INFO:"M_NAME":load_snapshot_registrar: Loaded r_contact for <%.*s>\n",c->uri.len,c->uri.s); r_lock(c->hash); c->prev = registrar[c->hash].tail; c->next = 0; if (registrar[c->hash].tail) registrar[c->hash].tail->next = c; registrar[c->hash].tail = c; if (!registrar[c->hash].head) registrar[c->hash].head = c; r_unlock(c->hash); } bin_free(&x); break; case WITH_DATABASE_CACHE: k=bin_load_from_db(NULL, P_REGISTRAR); //ignore x, x is empty break; default: LOG(L_ERR,"ERR:"M_NAME":load_snapshot_registrar: Can't resume because no such mode %d\n",pcscf_persistency_mode); k=0; } if (!k) goto error; return 1; error: return 0; }
/** * Updates the r_public with the new reg_state and ims_subscription values. * If not found, it will be inserted. * \note Aquires the lock on the hash_slot on success, so release it when you are done. * @param aor - the address of record * @param reg_state - new registration state, NULL if no update necessary * @param s - the new subscription attached, NULL if no update necessary * @returns the update r_public or NULL on error */ r_public* update_r_public(str aor,enum Reg_States *reg_state,ims_subscription **s, str *ccf1, str *ccf2, str *ecf1, str *ecf2) { r_public *p=0; //LOG(L_CRIT,"update_r_public():with aor %.*s\n",aor.len,aor.s); if ((*s)->wpsi) { p = get_r_public_wpsi(aor); } else { p = get_r_public(aor); } if (!p){ //LOG(L_DBG,"updating a new r_public profile\n"); if (reg_state && *reg_state && *reg_state!=NOT_REGISTERED && s){ p = add_r_public(aor,*reg_state,*s); if (!p) return p; if (ccf1) { if (p->ccf1.s) shm_free(p->ccf1.s); STR_SHM_DUP( &(p->ccf1), ccf1,"SHM CCF1"); } if (ccf2) { if (p->ccf2.s) shm_free(p->ccf2.s); STR_SHM_DUP( &(p->ccf2), ccf2,"SHM CCF2"); } if (ecf1) { if (p->ecf1.s) shm_free(p->ecf1.s); STR_SHM_DUP( &(p->ecf1), ecf1,"SHM ECF1"); } if (ecf2) { if (p->ecf2.s) shm_free(p->ecf2.s); STR_SHM_DUP( &(p->ecf2), ecf2,"SHM ECF2"); } //LOG(L_DBG,"update_r_public(): it was actually adding\n"); return p; } else return 0; }else{ //LOG(L_DBG,"updating a not so new r_public profile\n"); if (reg_state) p->reg_state = *reg_state; if (*s) { if (p->s){ lock_get(p->s->lock); if (p->s->ref_count==1){ free_user_data(p->s); }else{ p->s->ref_count--; lock_release(p->s->lock); } } p->s = *s; lock_get(p->s->lock); p->s->ref_count++; lock_release(p->s->lock); if ((*s)->wpsi) { p->s=NULL; if (p->prev) p->prev->next=p->next; else registrar[r_hash_size].head=p->next; if (p->next) p->next->prev=p->prev; else registrar[r_hash_size].tail=p->prev; free_r_public(p); r_unlock(r_hash_size); p=add_r_public(aor,0,*s); } } if (ccf1) { if (p->ccf1.s) shm_free(p->ccf1.s); STR_SHM_DUP( &(p->ccf1), ccf1,"SHM CCF1"); } if (ccf2) { if (p->ccf2.s) shm_free(p->ccf2.s); STR_SHM_DUP( &(p->ccf2), ccf2,"SHM CCF2"); } if (ecf1) { if (p->ecf1.s) shm_free(p->ecf1.s); STR_SHM_DUP( &(p->ecf1), ecf1,"SHM ECF1"); } if (ecf2) { if (p->ecf2.s) shm_free(p->ecf2.s); STR_SHM_DUP( &(p->ecf2), ecf2,"SHM ECF2"); } //LOG(L_DBG,"update_r_public(): return normaly\n"); return p; } out_of_memory: return p; }
/** * Creates the full reginfo XML. * @param pv - the r_public to create for * @param event_type - event type * @param subsExpires - subscription expiration * @returns the str with the XML content */ str r_get_reginfo_full(void *pv,int event_type,long *subsExpires) { str x={0,0}; str buf,pad; char bufc[MAX_REGINFO_SIZE],padc[MAX_REGINFO_SIZE]; r_public *p=(r_public*)pv,*p2; r_contact *c; r_contact_param *cp; ims_public_identity *pi; int i,j; unsigned int hash; buf.s = bufc; buf.len=0; pad.s = padc; pad.len=0; *subsExpires = r_update_subscription_status(p); STR_APPEND(buf,xml_start); sprintf(pad.s,r_reginfo_s.s,"%d",r_full.len,r_full.s); pad.len = strlen(pad.s); STR_APPEND(buf,pad); if (p->s){ for(i=0;i<p->s->service_profiles_cnt;i++) for(j=0;j<p->s->service_profiles[i].public_identities_cnt;j++){ pi = &(p->s->service_profiles[i].public_identities[j]); if (!pi->barring){ hash = get_aor_hash(pi->public_identity,r_hash_size); if (hash == p->hash) /* because we already have the lock on p->hash */ p2 = get_r_public_nolock(pi->public_identity); else p2 = get_r_public(pi->public_identity); if (p2){ if (p2->reg_state==REGISTERED) sprintf(pad.s,registration_s.s,p2->aor.len,p2->aor.s,p2,r_active.len,r_active.s); else sprintf(pad.s,registration_s.s,p2->aor.len,p2->aor.s,p2,r_terminated.len,r_terminated.s); pad.len = strlen(pad.s); STR_APPEND(buf,pad); c = p2->head; while(c){ if(c->qvalue != -1) { float q = (float)c->qvalue/1000; sprintf(pad.s,contact_s_q.s,c,r_active.len,r_active.s,r_registered.len,r_registered.s,c->expires-time_now, q); } else sprintf(pad.s,contact_s.s,c,r_active.len,r_active.s,r_registered.len,r_registered.s,c->expires-time_now); pad.len = strlen(pad.s); STR_APPEND(buf,pad); STR_APPEND(buf,uri_s); STR_APPEND(buf,c->uri); STR_APPEND(buf,uri_e); for(cp=c->parameters;cp;cp=cp->next){ sprintf(pad.s,unknown_param_s.s,cp->name.len,cp->name.s); pad.len = strlen(pad.s); STR_APPEND(buf,pad); STR_APPEND(buf,cp->value); STR_APPEND(buf,unknown_param_e); } STR_APPEND(buf,contact_e); c = c->next; } STR_APPEND(buf,registration_e); if (p2->hash != p->hash) r_unlock(p2->hash); } } } } STR_APPEND(buf,r_reginfo_e); x.s = pkg_malloc(buf.len+1); if (x.s){ x.len = buf.len; memcpy(x.s,buf.s,buf.len); x.s[x.len]=0; } return x; }
/** * Save this subscription. * @param msg - the SIP SUBSCRIBE message * @param str1 - not used * @param str2 - not used * @returns #CSCF_RETURN_TRUE if allowed, #CSCF_RETURN_FALSE if not, #CSCF_RETURN_ERROR on error */ int S_subscribe(struct sip_msg *msg,char *str1,char *str2) { int ret=CSCF_RETURN_FALSE; struct sip_uri puri; str uri={0,0}; str event; int event_i=IMS_EVENT_NONE; int expires=0,expires_time=0; str subscriber; r_public *p=0; r_subscriber *s=0,*new_s=0; dlg_t *dialog=0; LOG(L_DBG,"DBG:"M_NAME":S_subscribe: Saving SUBSCRIBE\n"); /* First check the parameters */ if (msg->first_line.type!=SIP_REQUEST) { LOG(L_ERR,"ERR:"M_NAME":S_subscribe: This message is not a request\n"); goto error; } if (msg->first_line.u.request.method.len != 9 || memcmp(msg->first_line.u.request.method.s,"SUBSCRIBE",9)!=0) { LOG(L_ERR,"ERR:"M_NAME":S_subscribe: This message is not a SUBSCRIBE\n"); goto error; } /* 1. Get the event */ event = cscf_get_event(msg); if (event.len!=3||strncasecmp(event.s,"reg",3)!=0){ LOG(L_ERR,"ERR:"M_NAME":S_subscribe: Accepting only <Event: reg>. Found: <%.*s>\n", event.len,event.s); ret = CSCF_RETURN_FALSE; goto done; } if (event.len==0 && strncasecmp(event.s,"reg",3)==0) event_i = IMS_EVENT_REG; /* 2. Get the target of the SUBSCRIBE from RequestURI */ if (msg->new_uri.s) uri = msg->new_uri; else uri = msg->first_line.u.request.uri; if (parse_uri(uri.s, uri.len, &puri) < 0) { LOG(L_ERR,"ERR:"M_NAME":S_subscribe: Error parsing uri <%.*s>\n", uri.len,uri.s); goto error; } uri.len = lookup_sip.len+puri.user.len+1+puri.host.len; uri.s = pkg_malloc(uri.len); if (!uri.s){ LOG(L_ERR,"ERR:"M_NAME":S_subscribe: Error allocating %d bytes\n",uri.len); goto error; } uri.len=0; memcpy(uri.s,lookup_sip.s,lookup_sip.len); uri.len+=lookup_sip.len; memcpy(uri.s+uri.len,puri.user.s,puri.user.len); uri.len+=puri.user.len; uri.s[uri.len++]='@'; memcpy(uri.s+uri.len,puri.host.s,puri.host.len); uri.len+=puri.host.len; /* 3. Get the Subscriber's Identity */ subscriber = cscf_get_contact(msg); if (!subscriber.len){ LOG(L_ERR,"ERR:"M_NAME":S_subscribe: Contact empty.\n"); ret = CSCF_RETURN_FALSE; goto done; } LOG(L_DBG,"DBG:"M_NAME":S_subscribe: Contact <%.*s>.\n", subscriber.len,subscriber.s); p = get_r_public(uri); /* Registration is possible even if the user is not registered... so just create one */ if (!p){ p = add_r_public(uri,0,0); } if (!p){ LOG(L_ERR,"ERR:"M_NAME":S_subscribe: Identity not found and error on creation <%.*s>\n", uri.len,uri.s); ret = CSCF_RETURN_FALSE; goto done; } expires = cscf_get_expires_hdr(msg,0); if (expires == -1) expires = subscription_default_expires; if (expires > 0) { if (expires < subscription_min_expires) expires = subscription_min_expires; if (expires > subscription_max_expires) expires = subscription_max_expires; r_act_time(); expires_time = expires + time_now; /* get the old subscriber - if any */ s = get_r_subscriber(p,subscriber,event_i); if (!s){ /* create a new dialog */ if (tmb.new_dlg_uas(msg, 200, &dialog) < 0) { LOG(L_ERR,"ERR:"M_NAME":S_subscribe: Error while creating dialog state\n"); ret = CSCF_RETURN_FALSE; goto error; } }else dialog = s->dialog; /* update the subscriber */ if ((new_s=update_r_subscriber(p,subscriber,event_i,&expires_time,dialog))!=0){ //if (!s) /* Only on first subscription, not on refreshes, send a notify */ S_event_reg(p,0,new_s,IMS_REGISTRAR_SUBSCRIBE,0); ret = CSCF_RETURN_TRUE; } else ret = CSCF_RETURN_FALSE; }else{ /* Unsubscribe */ /* get the old subscriber - if any */ r_act_time(); s = get_r_subscriber(p,subscriber,event_i); if (s) { s->expires = time_now; S_event_reg(p,0,s,IMS_REGISTRAR_UNSUBSCRIBE,1); del_r_subscriber(p,s); } ret = CSCF_RETURN_TRUE; } done: r_unlock(p->hash); if (expires ==0 )S_SUBSCRIBE_reply(msg,200,MSG_REG_UNSUBSCRIBE_OK,&expires,&uri); else S_SUBSCRIBE_reply(msg,200,MSG_REG_SUBSCRIBE_OK,&expires,&uri); if (uri.s) pkg_free(uri.s); return ret; error: if (p) r_unlock(p->hash); if (uri.s) pkg_free(uri.s); ret=CSCF_RETURN_FALSE; return ret; }
/** * Check if this message quallifies for a subscription. * Only 3 entities can subscribe: * - the user agent to its own state * - the P-CSCF specified in a Path header for that user * - AS (not implemented yet * \todo Allow also the AS listed in iFC and not belonging to a 3rd party * @param msg - the SIP SUBSCRIBE message * @param str1 - not used * @param str2 - not used * @returns #CSCF_RETURN_TRUE if allowed, #CSCF_RETURN_FALSE if not, #CSCF_RETURN_ERROR on error */ int S_can_subscribe(struct sip_msg *msg,char *str1,char *str2) { int ret=CSCF_RETURN_FALSE; struct sip_uri puri; str uri={0,0}; str event; str asserted_id; r_public *p=0; r_contact *c=0; ims_public_identity *pi=0; int i,j; LOG(L_DBG,"DBG:"M_NAME":S_can_subscribe: Checking if allowed to SUBSCRIBE\n"); /* First check the parameters */ if (msg->first_line.type!=SIP_REQUEST) { LOG(L_ERR,"ERR:"M_NAME":S_can_subscribe: This message is not a request\n"); goto error; } if (msg->first_line.u.request.method.len != 9 || memcmp(msg->first_line.u.request.method.s,"SUBSCRIBE",9)!=0) { LOG(L_ERR,"ERR:"M_NAME":S_can_subscribe: This message is not a SUBSCRIBE\n"); goto error; } /* 1. Get the event */ event = cscf_get_event(msg); if (event.len!=3||strncasecmp(event.s,"reg",3)!=0){ LOG(L_ERR,"ERR:"M_NAME":S_can_subscribe: Accepting only <Event: reg>. Found: <%.*s>\n", event.len,event.s); ret = CSCF_RETURN_FALSE; goto done; } /* 2. Get the target of the SUBSCRIBE from RequestURI */ if (msg->new_uri.s) uri = msg->new_uri; else uri = msg->first_line.u.request.uri; if (parse_uri(uri.s, uri.len, &puri) < 0) { LOG(L_ERR,"ERR:"M_NAME":S_can_subscribe: Error parsing uri <%.*s>\n", uri.len,uri.s); goto error; } uri.len = lookup_sip.len+puri.user.len+1+puri.host.len; uri.s = pkg_malloc(uri.len); if (!uri.s){ LOG(L_ERR,"ERR:"M_NAME":S_can_subscribe: Error allocating %d bytes\n",uri.len); goto error; } uri.len=0; memcpy(uri.s,lookup_sip.s,lookup_sip.len); uri.len+=lookup_sip.len; memcpy(uri.s+uri.len,puri.user.s,puri.user.len); uri.len+=puri.user.len; uri.s[uri.len++]='@'; memcpy(uri.s+uri.len,puri.host.s,puri.host.len); uri.len+=puri.host.len; /* 3. Check if the asserted identity is in the same group with the ReqURI */ asserted_id = cscf_get_asserted_identity(msg); if (!asserted_id.len){ LOG(L_ERR,"ERR:"M_NAME":S_can_subscribe: P-Asserted-Identity empty.\n"); ret = CSCF_RETURN_FALSE; goto done; } LOG(L_DBG,"DBG:"M_NAME":S_can_subscribe: P-Asserted-Identity <%.*s>.\n", asserted_id.len,asserted_id.s); p = get_r_public(uri); if (!p){ LOG(L_ERR,"ERR:"M_NAME":S_can_subscribe: Identity not found <%.*s>\n", uri.len,uri.s); ret = CSCF_RETURN_FALSE; goto done; } if (p->aor.len == asserted_id.len && strncasecmp(p->aor.s,asserted_id.s,asserted_id.len)==0) { LOG(L_DBG,"DBG:"M_NAME":S_can_subscribe: Identity found as AOR <%.*s>\n", uri.len,uri.s); ret = CSCF_RETURN_TRUE; goto done; } if (p->s){ for(i=0;i<p->s->service_profiles_cnt;i++) for(j=0;j<p->s->service_profiles[i].public_identities_cnt;j++) { pi = &(p->s->service_profiles[i].public_identities[j]); if (!pi->barring && pi->public_identity.len == asserted_id.len && strncasecmp(pi->public_identity.s,asserted_id.s,asserted_id.len)==0) { LOG(L_DBG,"DBG:"M_NAME":S_can_subscribe: Identity found in SP[%d][%d]\n", i,j); ret = CSCF_RETURN_TRUE; goto done; } } } /* 4. Check if it present in any of the Path headers */ c=p->head; while(c){ if (c->path.len){ for(i=0;i<c->path.len-asserted_id.len;i++) if (strncasecmp(c->path.s+i,asserted_id.s,asserted_id.len)==0){ LOG(L_DBG,"DBG:"M_NAME":S_can_subscribe: Identity found in Path <%.*s>\n", c->path.len,c->path.s); ret = CSCF_RETURN_TRUE; goto done; } } c = c->next; } done: if (p) r_unlock(p->hash); if (uri.s) pkg_free(uri.s); return ret; error: if (p) r_unlock(p->hash); if (uri.s) pkg_free(uri.s); ret=CSCF_RETURN_ERROR; return ret; }
/** * Process the 200 response for REGISTER and creates the first Security-Associations. * The rest of the SA are not set. * could come over that one. * @param rpl - the 200 response * @param str1 - not used * @param str2 - not used * @returns 1 if ok, 0 if not */ int P_security_200(struct sip_msg *rpl,char *str1, char *str2) { struct sip_msg *req; str sec_hdr; r_security_type sec_type; float sec_q; struct hdr_field *h; struct via_body *vb; r_contact *c; r_ipsec *i; int expires; unsigned long s_hash; char out_rpl[256],out_req[256],inc_rpl[256]; if (!pcscf_use_ipsec &&!pcscf_use_tls) goto ret_false; req = cscf_get_request_from_reply(rpl); if (!req){ LOG(L_ERR,"ERR:"M_NAME":P_security_200: No transactional request found.\n"); goto error; } sec_hdr = cscf_get_pref_security_header(req,s_security_client, &sec_type,&sec_q); if (!sec_hdr.len) { LOG(L_DBG,"DBG:"M_NAME":P_security_200: No Security-Verify header found.\n"); goto error; } /* find the expires (reg or dereg?) */ expires = cscf_get_max_expires(req); /* get the IPSec info from the registrar */ vb = cscf_get_first_via(req,&h); LOG(L_DBG,"DBG:"M_NAME":P_security_200: Looking for <%d://%.*s:%d> \n", vb->proto,vb->host.len,vb->host.s,vb->port); c = get_r_contact(vb->host,vb->port,vb->proto); r_act_time(); if (!c){ LOG(L_ERR,"ERR:"M_NAME":P_security_200: Contact not found\n"); goto error; } if (c->security_temp){ if (c->security && c->security->type == SEC_TLS && (c->security->data.tls && c->security->data.tls->port_tls==req->rcv.src_port&& c->security->data.tls->session_hash!=0 && c->security->data.tls->session_hash == tls_get_session_hash(req))){ /* don't replace security when doing an integrity protected REGISTER with * possible attack-garbage from security_temp */ P_security_drop(c,c->security_temp); free_r_security(c->security_temp); c->security_temp = 0; } else { if (c->security) { P_security_drop(c,c->security); free_r_security(c->security); } c->security = c->security_temp; c->security_temp = 0; } } switch(sec_type){ case SEC_NONE: break; case SEC_TLS: if (c->security && pcscf_use_tls) { r_tls *tls; int port_tls = req->rcv.src_port; s_hash = get_tls_session_hash(req); if (!s_hash){ LOG(L_ERR,"ERR:"M_NAME":P_security_200: Session Hash could not be obtained !\n"); r_unlock(c->hash); goto error; } tls = new_r_tls(port_tls, s_hash); if (!tls) goto error; c->security->data.tls = tls; } r_unlock(c->hash); break; case SEC_IPSEC: if (!r_valid_contact(c)||!c->security||!c->security->data.ipsec ){ LOG(L_DBG,"DBG:"M_NAME":P_security_200: Contact expired or no IPSec info\n"); r_unlock(c->hash); goto error; } i = c->security->data.ipsec; /* P_Out_Rpl */ sprintf(out_rpl,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s", pcscf_ipsec_P_Out_Rpl, c->host.len,c->host.s, i->port_uc, pcscf_ipsec_host, pcscf_ipsec_port_s, i->spi_uc, i->ealg.len,i->ealg.s, i->ck.len,i->ck.s, i->alg.len,i->alg.s, i->ik.len,i->ik.s ); /* P_Out_Req */ sprintf(out_req,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s", pcscf_ipsec_P_Out_Req, c->host.len,c->host.s, i->port_us, pcscf_ipsec_host, pcscf_ipsec_port_c, i->spi_us, i->ealg.len,i->ealg.s, i->ck.len,i->ck.s, i->alg.len,i->alg.s, i->ik.len,i->ik.s ); /* P_Out_Inc_Rpl */ sprintf(inc_rpl,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s", pcscf_ipsec_P_Inc_Rpl, c->host.len,c->host.s, i->port_us, pcscf_ipsec_host, pcscf_ipsec_port_c, i->spi_pc, i->ealg.len,i->ealg.s, i->ck.len,i->ck.s, i->alg.len,i->alg.s, i->ik.len,i->ik.s ); if (expires<=0) { /* Deregister */ c->reg_state = DEREGISTERED; r_act_time(); c->expires = time_now + 60; } r_unlock(c->hash); //print_r(L_CRIT); /* run the IPSec scripts */ /* Registration */ execute_cmd(out_rpl); execute_cmd(out_req); execute_cmd(inc_rpl); break; } return CSCF_RETURN_TRUE; ret_false: return CSCF_RETURN_FALSE; error: return CSCF_RETURN_ERROR; }
/** * Process the 401 response for REGISTER and creates the first Security-Associations. * IPSEc: Only the SA for P_Inc_Req - Incoming Requests is set now as the next REGISTER * could come over that one. * @param rpl - the 401 response * @param str1 - not used * @param str2 - not used * @returns 1 if ok, 0 if not */ int P_security_401(struct sip_msg *rpl,char *str1, char *str2) { struct sip_msg *req; struct hdr_field *hdr; str sec_hdr,sec_srv={0,0}; r_security_type sec_type; char cmd[256]; r_contact *c; r_ipsec *ipsec; float sec_q=-1; str auth; if (!pcscf_use_ipsec &&!pcscf_use_tls) goto ret_false; req = cscf_get_request_from_reply(rpl); if (!req){ LOG(L_ERR,"ERR:"M_NAME":P_security_401: No transactional request found.\n"); goto error; } auth = cscf_get_authenticate(rpl,&hdr); if (!auth.len){ LOG(L_ERR,"ERR:"M_NAME":P_security_401: No WWW-Authenticate header found.\n"); goto ret_false; } sec_hdr = cscf_get_pref_security_header(req,s_security_client, &sec_type,&sec_q); if (!sec_hdr.len) { LOG(L_DBG,"DBG:"M_NAME":P_security_401: No Security-Client header found.\n"); goto ret_false; } LOG(L_INFO,"DBG:"M_NAME":P_security_401: Security-Client header found : <%.*s>.\n", sec_hdr.len, sec_hdr.s); /* save data into registrar */ c = save_contact_security(req, auth, sec_hdr, sec_type, sec_q); if (!c) goto error; switch(sec_type){ case SEC_NONE: break; case SEC_TLS: /* try to add the Security-Server header */ sec_srv.len = s_security_server_s.len+sec_hdr.len+s_security_server_e.len; sec_srv.s = pkg_malloc(sec_srv.len); if (!sec_srv.s){ LOG(L_ERR,"ERR:"M_NAME":P_security_401: Error allocating %d pkg bytes \n",sec_srv.len); goto error; } sec_srv.len=0; STR_APPEND(sec_srv,s_security_server_s); STR_APPEND(sec_srv,sec_hdr); STR_APPEND(sec_srv,s_security_server_e); if (!cscf_add_header(rpl,&sec_srv,HDR_OTHER_T)) { LOG(L_ERR,"ERR:"M_NAME":P_security_401: Error adding header <%.*s> \n",sec_srv.len,sec_srv.s); pkg_free(sec_srv.s); goto error; } break; case SEC_IPSEC: ipsec = c->security_temp->data.ipsec; /* try to add the Security-Server header */ 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", ipsec->r_ealg.len,ipsec->r_ealg.s, ipsec->r_alg.len,ipsec->r_alg.s, ipsec->spi_pc,ipsec->spi_ps, pcscf_ipsec_port_c,pcscf_ipsec_port_s); sec_srv.len = strlen(cmd); sec_srv.s = pkg_malloc(sec_srv.len); if (!sec_srv.s){ LOG(L_ERR,"ERR:"M_NAME":P_security_401: Error allocating %d pkg bytes \n",sec_srv.len); goto error; } memcpy(sec_srv.s,cmd,sec_srv.len); if (!cscf_add_header(rpl,&sec_srv,HDR_OTHER_T)) { LOG(L_ERR,"ERR:"M_NAME":P_security_401: Error adding header <%.*s> \n",sec_srv.len,sec_srv.s); pkg_free(sec_srv.s); goto error; } /* run the IPSec script */ /* P_Inc_Req */ sprintf(cmd,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s", pcscf_ipsec_P_Inc_Req, c->host.len,c->host.s, ipsec->port_uc, pcscf_ipsec_host, pcscf_ipsec_port_s, ipsec->spi_ps, ipsec->ealg.len,ipsec->ealg.s, ipsec->ck.len,ipsec->ck.s, ipsec->alg.len,ipsec->alg.s, ipsec->ik.len,ipsec->ik.s); r_unlock(c->hash); execute_cmd(cmd); break; } return CSCF_RETURN_TRUE; ret_false: return CSCF_RETURN_FALSE; error: return CSCF_RETURN_ERROR; }
/** * Process the REGISTER and verify Client-Security. * @param req - Register request * @param str1 - not used * @param str2 - not used * @returns 1 if ok, 0 if not */ int P_verify_security(struct sip_msg *req,char *str1, char *str2) { str sec_hdr; struct hdr_field *h; struct via_body *vb; r_contact *c; r_security *s; r_security_type sec_type; float sec_q; str ealg,alg,tmp; unsigned int spi_pc,spi_ps;; int port_pc,port_ps; vb = cscf_get_first_via(req,&h); 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); c = get_r_contact(vb->host,vb->port,vb->proto); r_act_time(); if (!c){ //first register LOG(L_DBG,"DBG:"M_NAME":P_verify_security: No Contact found ! \n"); return CSCF_RETURN_TRUE; } if (!r_valid_contact(c) || !c->security_temp){ LOG(L_DBG,"DBG:"M_NAME":P_verify_security: No security temp !.\n"); r_unlock(c->hash); return CSCF_RETURN_TRUE; } sec_hdr = cscf_get_pref_security_header(req,s_security_verify, &sec_type,&sec_q); if (!sec_hdr.len) { LOG(L_DBG,"DBG:"M_NAME":P_verify_security: No Security-Verify header found.\n"); r_unlock(c->hash); return CSCF_RETURN_TRUE; } s = c->security_temp; switch (s->type) { case SEC_NONE: break; case SEC_TLS: if (sec_type != SEC_TLS || req->rcv.dst_port != pcscf_tls_port) goto error; break; case SEC_IPSEC: if (sec_type != SEC_IPSEC || req->rcv.dst_port != pcscf_ipsec_port_s) { LOG(L_INFO,"DBG:"M_NAME":P_verify_security: Not IPSEC tunnel!.\n"); r_unlock(c->hash); goto error; } get_param(sec_hdr,s_ealg,ealg); get_param(sec_hdr,s_alg,alg); /* and for spis */ get_param(sec_hdr,s_spi_c,tmp); strtoint(tmp,spi_pc); get_param(sec_hdr,s_spi_s,tmp); strtoint(tmp,spi_ps); /* and for ports */ get_param(sec_hdr,s_port_c,tmp); strtoint(tmp,port_pc); get_param(sec_hdr,s_port_s,tmp); strtoint(tmp,port_ps); if ((s->data.ipsec->r_ealg.len != ealg.len || strncasecmp(s->data.ipsec->r_ealg.s, ealg.s, ealg.len)) || (s->data.ipsec->r_alg.len != alg.len || strncasecmp(s->data.ipsec->r_alg.s, alg.s, alg.len)) || (s->data.ipsec->spi_pc != spi_pc) || (s->data.ipsec->spi_ps != spi_ps) || (pcscf_ipsec_port_c != port_pc) || (pcscf_ipsec_port_s != port_ps)) { LOG(L_INFO,"DBG:"M_NAME":P_verify_security: No valid Security-Verify header!.\n"); r_unlock(c->hash); goto error; } break; } r_unlock(c->hash); return CSCF_RETURN_TRUE; error: return CSCF_RETURN_FALSE; }
/** * Process the 200 response for REGISTER and creates the first Security-Associations. * The rest of the SA are not set. * could come over that one. * @param rpl - the 200 response * @param str1 - not used * @param str2 - not used * @returns 1 if ok, 0 if not */ int P_IPSec_200(struct sip_msg *rpl,char *str1, char *str2) { struct sip_msg *req; struct hdr_field *hdr; str sec_cli; struct hdr_field *h; struct via_body *vb; r_contact *c; r_ipsec *i; int expires; char out_rpl[256],out_req[256],inc_rpl[256]; req = cscf_get_request_from_reply(rpl); if (!req){ LOG(L_ERR,"ERR:"M_NAME":P_ipsec_200: No transactional request found.\n"); goto error; } /* just to jump out if no IPSec is employed - the info is already saved */ sec_cli = cscf_get_security_client(req,&hdr); if (!sec_cli.len){ LOG(L_DBG,"DBG:"M_NAME":P_ipsec_200: No Security-Client header found.\n"); goto error; } /* find the expires (reg or dereg?) */ expires = cscf_get_max_expires(req); /* get the IPSec info from the registrar */ vb = cscf_get_first_via(req,&h); // if (!h||!h->parsed){ // LOG(L_ERR,"ERR:"M_NAME":P_ipsec_200: Error extracting sender's id.\n"); // goto error; // } // vb = (struct via_body*) h->parsed; LOG(L_DBG,"DBG:"M_NAME":P_ipsec_200: Looking for <%d://%.*s:%d> \n", vb->proto,vb->host.len,vb->host.s,vb->port); c = get_r_contact(vb->host,vb->port,vb->proto); r_act_time(); if (!c){ LOG(L_ERR,"ERR:"M_NAME":P_ipsec_200: Contact not found\n"); goto error; } if (!r_valid_contact(c)||!c->ipsec){ LOG(L_DBG,"DBG:"M_NAME":P_ipsec_200: Contact expired or no IPSec info\n"); r_unlock(c->hash); goto error; } i = c->ipsec; /* P_Out_Rpl */ sprintf(out_rpl,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s", pcscf_ipsec_P_Out_Rpl, c->host.len,c->host.s, i->port_uc, pcscf_ipsec_host, pcscf_ipsec_port_s, i->spi_uc, i->ealg.len,i->ealg.s, i->ck.len,i->ck.s, i->alg.len,i->alg.s, i->ik.len,i->ik.s ); /* P_Out_Req */ sprintf(out_req,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s", pcscf_ipsec_P_Out_Req, c->host.len,c->host.s, i->port_us, pcscf_ipsec_host, pcscf_ipsec_port_c, i->spi_us, i->ealg.len,i->ealg.s, i->ck.len,i->ck.s, i->alg.len,i->alg.s, i->ik.len,i->ik.s ); /* P_Out_Inc_Rpl */ sprintf(inc_rpl,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s", pcscf_ipsec_P_Inc_Rpl, c->host.len,c->host.s, i->port_us, pcscf_ipsec_host, pcscf_ipsec_port_c, i->spi_pc, i->ealg.len,i->ealg.s, i->ck.len,i->ck.s, i->alg.len,i->alg.s, i->ik.len,i->ik.s ); if (expires<=0) { /* Deregister */ c->reg_state = DEREGISTERED; r_act_time(); c->expires = time_now + 60; } r_unlock(c->hash); //print_r(L_CRIT); /* run the IPSec scripts */ /* Registration */ execute_cmd(out_rpl); execute_cmd(out_req); execute_cmd(inc_rpl); return 1; error: return 0; }
/** * Debug print the contents of the entire registrar. */ void print_r(int log_level) { r_public *p; r_contact *c; int i,j; #ifdef SER_MOD_INTERFACE if (!is_printable(log_level)) #else if (debug<log_level) #endif return; /* to avoid useless calls when nothing will be printed */ r_act_time(); LOG(log_level,"INF:"M_NAME":---------- Registrar Contents begin --------\n"); if (!registrar) return; for(i=0;i<r_hash_size;i++){ r_lock(i); c = registrar[i].head; while(c){ LOG(log_level,ANSI_GREEN"INF:"M_NAME":[%4d] C: <"ANSI_RED"%d://%.*s:%d"ANSI_GREEN"> Exp:["ANSI_MAGENTA"%4ld"ANSI_GREEN"] R:["ANSI_MAGENTA"%2d"ANSI_GREEN"] SOS:["ANSI_MAGENTA"%c"ANSI_GREEN"] <%.*s>\n",i, c->transport,c->host.len,c->host.s,c->port, c->expires-time_now,c->reg_state, (c->sos_flag & EMERG_REG)?'X':' ', c->uri.len,c->uri.s); for(j=0;j<c->service_route_cnt;j++) LOG(log_level,ANSI_GREEN"INF:"M_NAME": SR: <"ANSI_YELLOW"%.*s"ANSI_GREEN">\n",c->service_route[j].len,c->service_route[j].s); if(c->pinhole) { if (c->pinhole->nat_addr.len>=4) LOG(log_level,ANSI_GREEN"INF:"M_NAME": NAT:<"ANSI_CYAN"%d://%d.%d.%d.%d:%d"ANSI_GREEN">\n", c->pinhole->proto, c->pinhole->nat_addr.u.addr[0], c->pinhole->nat_addr.u.addr[1], c->pinhole->nat_addr.u.addr[2], c->pinhole->nat_addr.u.addr[3], (unsigned short)c->pinhole->nat_port); } if (c->security){ switch(c->security->type){ case SEC_NONE: break; case SEC_TLS: if (c->security->data.tls) LOG(log_level,ANSI_GREEN"INF:"M_NAME": TLS: %.*s tls://%.*s:%d\n", c->security->sec_header.len,c->security->sec_header.s, c->host.len,c->host.s,c->security->data.tls->port_tls); break; case SEC_IPSEC: if (c->security->data.ipsec) LOG(log_level,ANSI_GREEN"INF:"M_NAME": IPSec: UAS: %d:%d->%d UAC: %d:%d<-%d E[%.*s] I[%.*s]\n", c->security->data.ipsec->spi_uc,c->security->data.ipsec->port_uc,c->security->data.ipsec->spi_ps, c->security->data.ipsec->spi_us,c->security->data.ipsec->port_us,c->security->data.ipsec->spi_pc, c->security->data.ipsec->ealg.len,c->security->data.ipsec->ealg.s,c->security->data.ipsec->alg.len,c->security->data.ipsec->alg.s); } } if (c->security_temp){ switch(c->security_temp->type){ case SEC_NONE: break; case SEC_TLS: if (c->security_temp->data.tls) LOG(log_level,ANSI_GREEN"INF:"M_NAME": TLS: %.*s tls://%.*s:%d\n", c->security_temp->sec_header.len,c->security_temp->sec_header.s, c->host.len,c->host.s,c->security_temp->data.tls->port_tls); break; case SEC_IPSEC: if (c->security_temp->data.ipsec) LOG(log_level,ANSI_GREEN"INF:"M_NAME": Temp.IPSec: UAS: %d:%d->%d UAC: %d:%d<-%d E[%.*s] I[%.*s]\n", c->security_temp->data.ipsec->spi_uc,c->security_temp->data.ipsec->port_uc,c->security_temp->data.ipsec->spi_ps, c->security_temp->data.ipsec->spi_us,c->security_temp->data.ipsec->port_us,c->security_temp->data.ipsec->spi_pc, c->security_temp->data.ipsec->ealg.len,c->security_temp->data.ipsec->ealg.s,c->security_temp->data.ipsec->alg.len,c->security_temp->data.ipsec->alg.s); } } p = c->head; while(p){ LOG(log_level,ANSI_GREEN"INF:"M_NAME": P: D[%c] <"ANSI_BLUE"%.*s"ANSI_GREEN"> \n", (p->is_default?'X':' '),p->aor.len,p->aor.s); p = p->next; } c = c->next; } r_unlock(i); } LOG(log_level,"INF:"M_NAME":---------- Registrar Contents end ----------\n"); }
/** * Creates a snapshots of the registrar and then calls the dumping function. * @returns 1 on success or 0 on failure */ int make_snapshot_registrar() { bin_data x={0,0,0}; r_contact *c; int i,k; time_t unique = time(0); FILE *f; switch (pcscf_persistency_mode) { case NO_PERSISTENCY: return 0; case WITH_FILES: f = bin_dump_to_file_create(pcscf_persistency_location,"pregistrar",unique); if (!f) return 0; for(i=0;i<r_hash_size;i++){ if (!bin_alloc(&x,1024)) goto error; r_lock(i); c = registrar[i].head; if (c){ while(c){ if (!bin_encode_r_contact(&x,c)) goto error; c = c->next; } r_unlock(i); k = bind_dump_to_file_append(f,&x); if (k!=x.len) { LOG(L_ERR,"ERR:"M_NAME":make_snapshot_registrar: error while dumping to file - only wrote %d bytes of %d \n",k,x.len); r_unlock(i); bin_free(&x); return 0; } } else r_unlock(i); bin_free(&x); } return bind_dump_to_file_close(f,pcscf_persistency_location,"pregistrar",unique); break; case WITH_DATABASE_BULK: if (!bin_alloc(&x,1024)) goto error; for(i=0;i<r_hash_size;i++){ r_lock(i); c = registrar[i].head; while(c){ if (!bin_encode_r_contact(&x,c)) goto error; c = c->next; } r_unlock(i); } return bin_dump_to_db(&x, P_REGISTRAR); case WITH_DATABASE_CACHE: return bin_dump_to_db(NULL, P_REGISTRAR); //ignore x, x is empty default: LOG(L_ERR,"ERR:"M_NAME":make_snapshot_registrar: Snapshot done but no such mode %d\n",pcscf_persistency_mode); return 0; } error: if (x.s) bin_free(&x); return 0; }