Example #1
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);
}
Example #2
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 print_subs(int log_level)
{
	r_subscription *s;
	int i;
#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 */

	LOG(log_level,ANSI_GREEN"INF:"M_NAME":----------  Subscription list begin ---------\n");
	for(i=0;i<subscriptions_hash_size;i++){
		subs_lock(i);
		s = subscriptions[i].head;
		r_act_time();
		while(s){
			LOG(log_level,ANSI_GREEN"INF:"M_NAME":[%4u]\tP: <"ANSI_BLUE"%.*s"ANSI_GREEN"> D:["ANSI_CYAN"%5d"ANSI_GREEN"] E:["ANSI_MAGENTA"%5d"ANSI_GREEN"] Att:[%2d]\n",
				s->hash,s->req_uri.len,s->req_uri.s,s->duration,(int)(s->expires-time_now),s->attempts_left);
			s = s->next;			
		}
		subs_unlock(i);
	}
	LOG(log_level,ANSI_GREEN"INF:"M_NAME":----------  Subscription list end -----------\n");	
}
/**
 * Look if there are no more public ids or contacts registered and expires the subscription
 * \note must be called with lock on the domain
 * @param p - the r_public to update.
 * @returns the expiration is seconds
 */
static inline long r_update_subscription_status(r_public *p)
{
	r_subscriber *s;
	r_contact *c;
	long expires=0;
	int cnt=0;
	
	r_act_time();
	
	c = p->head;
	while(c){
		if (r_valid_contact(c)){
			if (c->expires-time_now+30>expires)
				expires = c->expires-time_now+30;
			cnt++;
		}
		c = c->next;
	}		
	if (!cnt){
		s = p->shead;
		while(s){
			s->expires = time_now-1;
			s = s->next;
		}	
	}
	return expires;
}
Example #5
0
/**
 * 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,&reg_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,&reg_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;
}
/**
 * The Subscription timer looks for almost expired subscriptions and subscribes again.
 * @param ticks - the current time
 * @param param - the generic parameter
 */
void subscription_timer(unsigned int ticks, void* param)
{
	r_subscription *s,*ns;
	int i;
	#ifdef WITH_IMS_PM
		int subs_cnt=0;
	#endif
	for(i=0;i<subscriptions_hash_size;i++){
		subs_lock(i);
		s = subscriptions[i].head;
		r_act_time();
		while(s){
			ns = s->next;			
			if (s->attempts_left > 0 ){
				/* attempt to send a subscribe */
				if (!r_send_subscribe(s,s->duration)){
					LOG(L_ERR,"ERR:"M_NAME":subscription_timer: Error on SUBSCRIBE (%d times)... droping\n",
						pcscf_subscribe_retries);
					del_r_subscription_nolock(s);
				}else{
					s->attempts_left--;
					#ifdef WITH_IMS_PM
						subs_cnt++;
					#endif
				}
			}else if (s->attempts_left==0) {
				/* we failed to many times, drop the subscription */
				LOG(L_ERR,"ERR:"M_NAME":subscription_timer: Error on SUBSCRIBE for %d times... aborting\n",pcscf_subscribe_retries);
				del_r_subscription_nolock(s);										
			}else{
				/* we are subscribed already */
				/* if expired, drop it */
				if (s->expires<time_now) 
					del_r_subscription_nolock(s);
				#ifdef WITH_IMS_PM
					else subs_cnt++;
				#endif
					
				/* if not expired, check for renewal */
//		Commented as the S-CSCF should adjust the subscription time accordingly				
//				if ((s->duration<1200 && s->expires-time_now<s->duration/2)||
//					(s->duration>=1200 && s->expires-time_now<600))
//				{
//					/* if we need a resubscribe, we mark it as such and try to subscribe again */					
//					s->attempts_left = pcscf_subscribe_retries;
//					ns = s;
//				}
			}
			s = ns;
		}	
		subs_unlock(i);
	}
	print_subs(L_INFO);
	#ifdef WITH_IMS_PM
		IMS_PM_LOG01(RD_NbrSubs,subs_cnt);
	#endif	
}
Example #7
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":         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");
}
Example #8
0
/**
 * Saves the IPSec information into the P-CSCF registrar for this contact.
 * @param req - REGISTER request
 * @param rpl - REGISTER respons
 * @param spi_uc - SPI for UE client
 * @param spi_us - SPI for UE server
 * @param spi_pc - SPI for PCSCF client
 * @param spi_ps - SPI for PCSCF server
 * @param port_uc - port for UE client
 * @param port_us - port for UE server
 * @param ealg_setkey - Chypher algorithm
 * @param ck_esp - Cypher Key
 * @param alg_setkey - Integrity algorithm
 * @param ik_esp - Integrity Key
 */
void save_contact_ipsec(struct sip_msg *req,struct sip_msg *rpl,
	int spi_uc,int spi_us,int spi_pc,int spi_ps,int port_uc,int port_us,
	str ealg_setkey,str ck_esp,str alg_setkey,str ik_esp)
{
	contact_t* c=0;
	contact_body_t* b=0;	
	r_contact *rc;
	enum Reg_States reg_state=REG_PENDING;
	int expires,pending_expires=60;
	struct sip_uri puri;
	r_ipsec *ipsec;

	
	if (parse_headers(rpl, HDR_EOH_F, 0) <0) {
		LOG(L_ERR,"ERR:"M_NAME":save_contact_ipsec: error parsing headers\n");
		return ;
	}	
	
	b = cscf_parse_contacts(req);
	
	if (!b||!b->contacts) {
		LOG(L_ERR,"ERR:"M_NAME":save_contact_ipsec: No contacts found\n");
		return;
	}
	
	if (b) c = b->contacts;
			
	r_act_time();
	while(c){
		LOG(L_DBG,"DBG:"M_NAME":save_contact_ipsec: <%.*s>\n",c->uri.len,c->uri.s);
		
		expires = time_now+pending_expires;
		
		if (parse_uri(c->uri.s,c->uri.len,&puri)<0){
			LOG(L_DBG,"DBG:"M_NAME":save_contact_ipsec: Error parsing Contact URI <%.*s>\n",c->uri.len,c->uri.s);
			goto next;			
		}
		if (puri.port_no==0) puri.port_no=5060;
		LOG(L_DBG,"DBG:"M_NAME":save_contact_ipsec: %d %.*s : %d\n",
			puri.proto, puri.host.len,puri.host.s,puri.port_no);

		ipsec = new_r_ipsec(spi_uc,spi_us,spi_pc,spi_ps,port_uc,port_us,
			ealg_setkey,ck_esp,alg_setkey,ik_esp);
			
		rc = update_r_contact_sec(puri.host,ipsec->port_us,puri.proto,
			&(c->uri),&reg_state,&expires,
			ipsec);

next:		
		c = c->next;
	}
	
	//print_r(L_CRIT);
}
/**
 * Generate notifications and put them in the notification queue to be sent
 * \note Must be called with a lock on the r_public pv
 * @param pv - r_public to generate for
 * @param c - r_contact to generate for or NULL if for all
 * @param ps - r_subscriber to generated for or NULL if for all
 * @param event_type - event type
 * @param send_now - whether to send immediately or delay
 * @returns 1 on success, 0 on failure
 */
int S_event_reg(void *pv,void *c,void *ps,int event_type,int send_now)
{
	r_public *p=(r_public*)pv;
	r_subscriber *s=(r_subscriber*)ps;
	str content={0,0};
	long subsExpires=-1;

	r_act_time();
	switch (event_type){
		case IMS_REGISTRAR_NONE:
			if (send_now) notification_timer(0,0);
			return 0;
			break;
		case IMS_REGISTRAR_SUBSCRIBE:
			content = r_get_reginfo_full(p,event_type,&subsExpires);
			r_create_notifications(p,0,s,content,subsExpires);			
			if (content.s) pkg_free(content.s);
			if (send_now) notification_timer(0,0);
			return 1;
			break;
		case IMS_REGISTRAR_UNSUBSCRIBE:
			subsExpires=0;
			r_create_notifications(p,0,s,content,subsExpires);			
			if (content.s) pkg_free(content.s);
			if (send_now) notification_timer(0,0);
			return 1;
			break;
			
		case IMS_REGISTRAR_CONTACT_REGISTERED:
		case IMS_REGISTRAR_CONTACT_CREATED:	
		case IMS_REGISTRAR_CONTACT_REFRESHED:
		case IMS_REGISTRAR_CONTACT_SHORTENED:
		case IMS_REGISTRAR_CONTACT_EXPIRED:
		case IMS_REGISTRAR_CONTACT_DEACTIVATED:
		case IMS_REGISTRAR_CONTACT_PROBATION:
		case IMS_REGISTRAR_CONTACT_UNREGISTERED:
		case IMS_REGISTRAR_CONTACT_REJECTED:
			content = r_get_reginfo_partial(p,c,event_type,&subsExpires);	
			r_create_notifications(p,c,s,content,subsExpires);
			if (content.s) pkg_free(content.s);
			if (send_now) notification_timer(0,0);
			return 1;
			break;
				
		default:
			LOG(L_ERR,"ERR:"M_NAME":S_event_reg: Unknown event %d\n",event_type);
			if (send_now) notification_timer(0,0);
			return 0;	
	}		
}
Example #10
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;
}
Example #11
0
void print_subs(int log_level)
{
	r_subscription *s;
	int i;
	LOG(log_level,ANSI_GREEN"INF:"M_NAME":----------  Subscription list begin ---------\n");
	for(i=0;i<subscriptions_hash_size;i++){
		subs_lock(i);
		s = subscriptions[i].head;
		r_act_time();
		while(s){
			LOG(log_level,ANSI_GREEN"INF:"M_NAME":[%4u]\tP: <"ANSI_BLUE"%.*s"ANSI_GREEN"> D:["ANSI_CYAN"%5d"ANSI_GREEN"] E:["ANSI_MAGENTA"%5d"ANSI_GREEN"] Att:[%2d]\n",
				s->hash,s->req_uri.len,s->req_uri.s,s->duration,(int)(s->expires-time_now),s->attempts_left);
			s = s->next;			
		}
		subs_unlock(i);
	}
	LOG(log_level,ANSI_GREEN"INF:"M_NAME":----------  Subscription list end -----------\n");	
}
Example #12
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");
}
Example #13
0
/**
 * 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;
}
/**
 * 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");
}
Example #15
0
/**
 * 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;	
}
Example #16
0
/**
 * Saves the Contact Security information into the P-CSCF registrar for this contact.
 * @param req - REGISTER request
 * @param auth - WWW-Authenticate header
 * @param sec_hdr - Security header
 * @param type - Security Type
 * @param q - Preference Value
 */
r_contact* save_contact_security(struct sip_msg *req, str auth, str sec_hdr,r_security_type type,float q)
{
	contact_t* c=0;
	contact_body_t* b=0;	
	r_contact *rc;
	enum Reg_States reg_state=REG_PENDING;
	int expires,pending_expires=60;
	struct sip_uri puri;
	r_security *s=0;
	
	b = cscf_parse_contacts(req);
	
	if (!b||!b->contacts) {
		LOG(L_ERR,"ERR:"M_NAME":save_contact_security: No contacts found\n");
		goto error; 
	}
	
	if (b) c = b->contacts;
			
	r_act_time();
	/* the Security works for just 1 contact/registration! */
	if(c){
		LOG(L_DBG,"DBG:"M_NAME":save_contact_security: <%.*s>\n",c->uri.len,c->uri.s);
		
		expires = time_now+pending_expires;
		
		if (parse_uri(c->uri.s,c->uri.len,&puri)<0){
			LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Error parsing Contact URI <%.*s>\n",c->uri.len,c->uri.s);
			goto error;			
		}
		if (puri.port_no==0) puri.port_no=5060;
		LOG(L_DBG,"DBG:"M_NAME":save_contact_security: %d %.*s : %d\n",
			puri.proto, puri.host.len,puri.host.s,puri.port_no);

		if (type == SEC_TLS) 
			puri.proto = PROTO_TLS;

		/* create the r_security structure */
		s = new_r_security(sec_hdr,type,q);
		if (!s) goto error;	

		switch(type) {
			case SEC_NONE:
				break;
			case SEC_TLS:
				// r_tls creation happens on 200
				break;
			case SEC_IPSEC:
			{
				/* then parse the parameters */
				r_ipsec *ipsec;	
				str ck,ik,ealg,alg,tmp;
				str alg_setkey,ealg_setkey;
				unsigned int spi_uc,spi_us;
        		unsigned int spi_pc,spi_ps;
				int port_uc,port_us;
				char ck_c[64],ik_c[64];
				str ck_esp={ck_c,0},ik_esp={ik_c,0};
									
				get_qparam(auth,s_ck,ck);
				LOG(L_DBG,"DBG:"M_NAME":save_contact_security: CK: <%.*s>\n",
					ck.len,ck.s);
				get_qparam(auth,s_ik,ik);
				LOG(L_DBG,"DBG:"M_NAME":save_contact_security: IK: <%.*s>\n",
					ik.len,ik.s);		
				get_param(sec_hdr,s_ealg,ealg);
				LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Enc Algorithm: <%.*s>\n",
					ealg.len,ealg.s);
				get_param(sec_hdr,s_alg,alg);
				LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Int Algorithm: <%.*s>\n",
					alg.len,alg.s);
				/* and for spis */
				get_param(sec_hdr,s_spi_c,tmp);
				strtoint(tmp,spi_uc);
				LOG(L_DBG,"DBG:"M_NAME":save_contact_security: SPI-C: %d\n",
					spi_uc);
				get_param(sec_hdr,s_spi_s,tmp);
				strtoint(tmp,spi_us);
				LOG(L_DBG,"DBG:"M_NAME":save_contact_security: SPI-S: %d\n",
					spi_us);
				/* and for ports */
				get_param(sec_hdr,s_port_c,tmp);
				strtoint(tmp,port_uc);
				LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Port-C: %d\n",
					port_uc);
				get_param(sec_hdr,s_port_s,tmp);
				strtoint(tmp,port_us);
				LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Port-S: %d\n",
					port_us);
		
				ck_esp.s[ck_esp.len++]='0';
				ck_esp.s[ck_esp.len++]='x';	
				if (ealg.len == s_des_in.len && strncasecmp(ealg.s,s_des_in.s,ealg.len)==0) {
					memcpy(ck_esp.s+ck_esp.len,ck.s,32);ck_esp.len+=32;
					memcpy(ck_esp.s+ck_esp.len,ck.s,16);ck_esp.len+=16;
					ealg_setkey = s_des_out;
				}
				else
				if (ealg.len == s_aes_in.len && strncasecmp(ealg.s,s_aes_in.s,ealg.len)==0) {
					memcpy(ck_esp.s+ck_esp.len,ck.s,ck.len);ck_esp.len+=ck.len;
					ealg_setkey = s_aes_out;
				}else {
					memcpy(ck_esp.s+ck_esp.len,ck.s,ck.len);ck_esp.len+=ck.len;
					ealg_setkey = s_null_out;
					ealg = s_null_out;
				}
			
				ik_esp.s[ik_esp.len++]='0';
				ik_esp.s[ik_esp.len++]='x';		
				if (alg.len == s_md5_in.len && strncasecmp(alg.s,s_md5_in.s,alg.len)==0) {
					memcpy(ik_esp.s+ik_esp.len,ik.s,ik.len);ik_esp.len+=ik.len;
					alg_setkey = s_md5_out;
				}
				else
				if (alg.len == s_sha_in.len && strncasecmp(alg.s,s_sha_in.s,alg.len)==0) {		
					memcpy(ik_esp.s+ik_esp.len,ik.s,ik.len);ik_esp.len+=ik.len;
					memcpy(ik_esp.s+ik_esp.len,"00000000",8);ik_esp.len+=8;
					alg_setkey = s_sha_out;
				}else{
					LOG(L_ERR,"ERR:"M_NAME":save_contact_security: Unknown Integrity algorithm <%.*s>\n",alg.len,alg.s);
					goto error;
				}
				
				spi_pc=get_next_spi();	
				spi_ps=get_next_spi();	

				ipsec = new_r_ipsec(spi_uc,spi_us,spi_pc,spi_ps,port_uc,port_us,
					ealg_setkey,ealg, ck_esp,alg_setkey,alg, ik_esp);
				if (!ipsec) goto error;
				s->data.ipsec = ipsec;
			}
				break;
		}
	}
	
	rc = update_r_contact_sec(puri.host,puri.port_no,puri.proto,
			&(c->uri),&reg_state,&expires,s);						

	return rc;	
error:
	if (s) free_r_security(s);
	return 0;	
}
Example #17
0
/**
 * 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;
}
/**
 * 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;	
}