/**
 * 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;
	int sos_reg;
	
	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;
			}
			sos_reg = cscf_get_sos_uri_param(rc->uri);
			if(sos_reg < 0)
				return 0;

			if(sos_reg>0)
				LOG(L_DBG,"DBG:"M_NAME":update_contact: with sos uri param\n");

		
//			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,&sos_reg);
				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,&sos_reg);
				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;
}
Ejemplo n.º 2
0
/**
 * Perform User Authorization Request.
 * creates and send the user authorization query
 * @param msg - the SIP message
 * @param str1 - the realm
 * @param str2 - if to do capabilities
 * @returns true if OK, false if not
 */
int I_perform_user_authorization_request(struct sip_msg* msg, char* str1, char* str2) {
    str private_identity, public_identity, visited_network_id;
    int authorization_type = AVP_IMS_UAR_REGISTRATION;
    int expires = 3600;
    struct hdr_field *hdr;
    str realm;
    contact_t *c;
    int sos_reg = 0;
    contact_body_t *b = 0;
    str call_id;
    saved_uar_transaction_t* saved_t;
    tm_cell_t *t = 0;
    int intvalue_param;
    cfg_action_t* cfg_action;

    uar_param_t* ap = (uar_param_t*) str1;
    if (fixup_get_ivalue(msg, ap->ivalue, &intvalue_param) != 0) {
        LM_ERR("no int value param passed\n");
        return CSCF_RETURN_ERROR;
    }
    cfg_action = ap->paction->next;

    realm = cscf_get_realm_from_ruri(msg);

    //check if we received what we should, we do this even though it should be done in cfg file - double checking!
    if (msg->first_line.type != SIP_REQUEST) {
        LM_ERR("ERR:I_UAR: The message is not a request\n");
        return CSCF_RETURN_ERROR;
    }
    if (msg->first_line.u.request.method.len != 8 ||
            memcmp(msg->first_line.u.request.method.s, "REGISTER", 8) != 0) {
        LM_ERR("ERR:I_UAR: The method is not a REGISTER\n");
        return CSCF_RETURN_ERROR;
    }

    private_identity = cscf_get_private_identity(msg, realm);
    if (!private_identity.len) {
        LM_ERR("ERR:I_UAR: Private Identity not found, responding with 400\n");
        cscf_reply_transactional(msg, 400, MSG_400_NO_PRIVATE);
        return CSCF_RETURN_BREAK;
    }

    public_identity = cscf_get_public_identity(msg);
    if (!public_identity.len) {
        LM_ERR("ERR:I_UAR: Public Identity not found, responding with 400\n");
        cscf_reply_transactional(msg, 400, MSG_400_NO_PUBLIC);
        return CSCF_RETURN_BREAK;

    }

    b = cscf_parse_contacts(msg);

    if (!b || (!b->contacts && !b->star)) {
        LM_DBG("DBG:I_UAR: No contacts found\n");
        return CSCF_RETURN_ERROR;
    }

    for (c = b->contacts; c; c = c->next) {

        sos_reg = cscf_get_sos_uri_param(c->uri);
        if (sos_reg == -1) {
            //error case
            LM_ERR("ERR:I_UAR: MSG_400_MALFORMED_CONTACT, responding with 400\n");
            cscf_reply_transactional(msg, 400, MSG_400_MALFORMED_CONTACT);
            return CSCF_RETURN_BREAK;
        } else if (sos_reg == -2) {
            LM_ERR("ERR:I_UAR: MSG_500_SERVER_ERROR_OUT_OF_MEMORY, responding with 500\n");
            cscf_reply_transactional(msg, 500, MSG_500_SERVER_ERROR_OUT_OF_MEMORY);
            return CSCF_RETURN_BREAK;
        }
    }

    visited_network_id = cscf_get_visited_network_id(msg, &hdr);
    if (!visited_network_id.len) {
        LM_ERR("ERR:I_UAR: Visited Network Identity not found, responding with 400\n");
        cscf_reply_transactional(msg, 400, MSG_400_NO_VISITED);
        return CSCF_RETURN_BREAK;
    }

    if (atoi(str1)) authorization_type = AVP_IMS_UAR_REGISTRATION_AND_CAPABILITIES;
    else {
        expires = cscf_get_max_expires(msg, 0);
        if (expires == 0) authorization_type = AVP_IMS_UAR_DE_REGISTRATION;
    }

    LM_DBG("SENDING UAR: PI: [%.*s], PU: [%.*s], VNID: [%.*s]\n", private_identity.len, private_identity.s,
            public_identity.len, public_identity.s,
            visited_network_id.len, visited_network_id.s);

    //before we send lets suspend the transaction
    t = tmb.t_gett();
    if (t == NULL || t == T_UNDEFINED) {
        if (tmb.t_newtran(msg) < 0) {
            LM_ERR("cannot create the transaction for UAR async\n");
            cscf_reply_transactional(msg, 480, MSG_480_DIAMETER_ERROR);
            return CSCF_RETURN_BREAK;
        }
        t = tmb.t_gett();
        if (t == NULL || t == T_UNDEFINED) {
            LM_ERR("cannot lookup the transaction\n");
            cscf_reply_transactional(msg, 480, MSG_480_DIAMETER_ERROR);
            return CSCF_RETURN_BREAK;
        }
    }

    saved_t = shm_malloc(sizeof (saved_uar_transaction_t));
    if (!saved_t) {
        LM_ERR("no more memory trying to save transaction state\n");
        return CSCF_RETURN_ERROR;

    }
    memset(saved_t, 0, sizeof (saved_uar_transaction_t));
    saved_t->act = cfg_action;

    call_id = cscf_get_call_id(msg, 0);
    saved_t->callid.s = (char*) shm_malloc(call_id.len + 1);
    if (!saved_t->callid.s) {
    	LM_ERR("no more memory trying to save transaction state : callid\n");
    	shm_free(saved_t);
    	return CSCF_RETURN_ERROR;
    }
    memset(saved_t->callid.s, 0, call_id.len + 1);
    memcpy(saved_t->callid.s, call_id.s, call_id.len);
    saved_t->callid.len = call_id.len;

    LM_DBG("Setting default AVP return code used for async callbacks to default as ERROR \n");
    create_uaa_return_code(CSCF_RETURN_ERROR);
    
    LM_DBG("Suspending SIP TM transaction\n");
    if (tmb.t_suspend(msg, &saved_t->tindex, &saved_t->tlabel) < 0) {
        LM_ERR("failed to suspend the TM processing\n");
        free_saved_uar_transaction_data(saved_t);

        cscf_reply_transactional(msg, 480, MSG_480_DIAMETER_ERROR);
        return CSCF_RETURN_BREAK;
    }

    if (cxdx_send_uar(msg, private_identity, public_identity, visited_network_id, authorization_type, sos_reg, saved_t) != 0) {
        LM_ERR("ERR:I_UAR: Error sending UAR or UAR time-out\n");
        tmb.t_cancel_suspend(saved_t->tindex, saved_t->tlabel);
        free_saved_uar_transaction_data(saved_t);
        cscf_reply_transactional(msg, 480, MSG_480_DIAMETER_ERROR);
        return CSCF_RETURN_BREAK;

    }
    //we use async replies therefore we send break and not true when successful
    return CSCF_RETURN_BREAK;
}
Ejemplo n.º 3
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;
	int sos_reg = 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);

		sos_reg = cscf_get_sos_uri_param(c->uri);
		if(sos_reg < 0)
			return 0;

			
		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 prot, mod, prot_set, mod_set;
				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_param(sec_hdr,s_prot,prot);
				get_param(sec_hdr,s_mod,mod);

				LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Protocol: <%.*s>\n", prot.len,prot.s);
				LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Mode: <%.*s>\n", mod.len,mod.s);
				if (prot.len == s_ah_inout.len && strncasecmp(prot.s,s_ah_inout.s,prot.len)==0) {
					prot_set = s_ah_inout;
				}else{
					prot_set = s_esp_inout;
				}
				if (mod.len == s_tun_inout.len && strncasecmp(mod.s,s_tun_inout.s,mod.len)==0) {
					mod_set = s_tun_inout;
				} else {
					mod_set = s_trans_inout;
				}
				LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Protocol: <%.*s>\n", prot_set.len,prot_set.s);
				LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Mode: <%.*s>\n", mod_set.len,mod_set.s);
									
				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: %u\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: %u\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, prot_set, mod_set);

				if (!ipsec) goto error;
				s->data.ipsec = ipsec;
				
				puri.port_no = ipsec->port_us;
				/*
				* this should actually be port_uc... then the cscf_get_ue_via should be 
				* changed to give rport and not the port in the via. but this would
				* break NATed clients...
				*/
			}
			break;
		}
	}

	
	rc = update_r_contact_sec(puri.host,puri.port_no,puri.proto,
			&(c->uri),&reg_state,&expires,s, &sos_reg);						

	return rc;	
error:
	if (s) free_r_security(s);
	return 0;	
}