/*!
 * \internal
 * \brief Create an identity header for an outgoing message
 * \param hdr_name The name of the header to create
 * \param tdata The message to place the header on
 * \param id The identification information for the new header
 * \return newly-created header
 */
static pjsip_fromto_hdr *create_new_id_hdr(const pj_str_t *hdr_name, pjsip_tx_data *tdata, const struct ast_party_id *id)
{
	pjsip_fromto_hdr *id_hdr;
	pjsip_fromto_hdr *base;
	pjsip_name_addr *id_name_addr;
	pjsip_sip_uri *id_uri;

	base = tdata->msg->type == PJSIP_REQUEST_MSG ? PJSIP_MSG_FROM_HDR(tdata->msg) :
		PJSIP_MSG_TO_HDR(tdata->msg);
	id_hdr = pjsip_from_hdr_create(tdata->pool);
	id_hdr->type = PJSIP_H_OTHER;
	pj_strdup(tdata->pool, &id_hdr->name, hdr_name);
	id_hdr->sname.slen = 0;

	id_name_addr = pjsip_uri_clone(tdata->pool, base->uri);
	id_uri = pjsip_uri_get_uri(id_name_addr->uri);

	if (id->name.valid) {
		int name_buf_len = strlen(id->name.str) * 2 + 1;
		char *name_buf = ast_alloca(name_buf_len);

		ast_escape_quoted(id->name.str, name_buf, name_buf_len);
		pj_strdup2(tdata->pool, &id_name_addr->display, name_buf);
	}

	pj_strdup2(tdata->pool, &id_uri->user, id->number.str);

	id_hdr->uri = (pjsip_uri *) id_name_addr;
	return id_hdr;
}
/// Apply the mangalgorithm to the To URI of req.
void MangelwurzelTsx::mangle_to(pjsip_msg* req, pj_pool_t* pool)
{
  pjsip_to_hdr* to_hdr = PJSIP_MSG_TO_HDR(req);

  if (to_hdr != NULL)
  {
    mangle_uri((pjsip_uri*)pjsip_uri_get_uri(to_hdr->uri), pool, false);
  }
}
void SessionExpiresHelper::process_request(pjsip_msg* req,
                                           pj_pool_t* pool,
                                           SAS::TrailId trail)
{
  // Session expires is only allowed on INVITE and UPDATE methods.
  pjsip_method* method = &req->line.req.method;

  if ((pjsip_method_cmp(method, pjsip_get_invite_method()) != 0) &&
      (pjsip_method_cmp(method, &METHOD_UPDATE) != 0))
  {
    return;
  }

  // Store if this is the initial transaction on a dialog, and if the UAC
  // supports session timers. We need both of these when processing the
  // response.
  _initial_request = (PJSIP_MSG_TO_HDR(req)->tag.slen == 0);
  _uac_supports_timer = timer_supported(req);

  // Find the session-expires header (if present) and the minimum
  // session-expires. Note that the latter has a default value.
  pjsip_session_expires_hdr* se_hdr = (pjsip_session_expires_hdr*)
    pjsip_msg_find_hdr_by_name(req, &STR_SESSION_EXPIRES, NULL);

  pjsip_min_se_hdr* min_se_hdr = (pjsip_min_se_hdr*)
    pjsip_msg_find_hdr_by_name(req, &STR_MIN_SE, NULL);

  SessionInterval min_se = (min_se_hdr != NULL) ?
                            min_se_hdr->expires :
                            DEFAULT_MIN_SE;

  if ((se_hdr != NULL) && (se_hdr->expires < _target_se))
  {
    // The request already has a session expires that is below our target. We
    // don't need to change the value.
    TRC_DEBUG("Session expires already set to %d", se_hdr->expires);
  }
  else
  {
    // No pre-existing session expires, or the current value is greater than
    // our target. Set it to as close to our target as possible, but don't set
    // it below the min-SE.
    if (se_hdr == NULL)
    {
      se_hdr = pjsip_session_expires_hdr_create(pool);
      pjsip_msg_add_hdr(req, (pjsip_hdr*)se_hdr);
    }

    se_hdr->expires = std::max(_target_se, min_se);

    TRC_DEBUG("Set session expires to %d", se_hdr->expires);
  }

  // Make a note of the session expires (we may need it when processing the
  // response)
  _se_on_req = se_hdr->expires;
}
Exemple #4
0
void PJUtils::add_integrity_protected_indication(pjsip_tx_data* tdata, Integrity integrity)
{
  pjsip_authorization_hdr* auth_hdr = (pjsip_authorization_hdr*)
                                      pjsip_msg_find_hdr(tdata->msg, PJSIP_H_AUTHORIZATION, NULL);

  if (auth_hdr == NULL)
  {
    auth_hdr = pjsip_authorization_hdr_create(tdata->pool);
    auth_hdr->scheme = pj_str("Digest");
    // Construct a default private identifier from the URI in the To header.
    LOG_DEBUG("Construct default private identity");
    pjsip_uri* to_uri = (pjsip_uri*)pjsip_uri_get_uri(PJSIP_MSG_TO_HDR(tdata->msg)->uri);
    std::string private_id = PJUtils::default_private_id_from_uri(to_uri);
    pj_strdup2(tdata->pool, &auth_hdr->credential.digest.username, private_id.c_str());
    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)auth_hdr);
  }
  pjsip_param* new_param = (pjsip_param*) pj_pool_alloc(tdata->pool, sizeof(pjsip_param));
  new_param->name = STR_INTEGRITY_PROTECTED;
  switch (integrity)
  {
  case Integrity::YES:
    new_param->value = STR_YES;
    break;

  case Integrity::NO:
    new_param->value = STR_NO;
    break;

  case Integrity::TLS_YES:
    new_param->value = STR_TLS_YES;
    break;

  case Integrity::TLS_PENDING:
    new_param->value = STR_TLS_PENDING;
    break;

  case Integrity::IP_ASSOC_YES:
    new_param->value = STR_IP_ASSOC_YES;
    break;

  case Integrity::IP_ASSOC_PENDING:
    new_param->value = STR_IP_ASSOC_PENDING;
    break;

  case Integrity::AUTH_DONE:
    new_param->value = STR_AUTH_DONE;
    break;

  default:
    break;
  }
  LOG_INFO("Adding integrity-protected=%.*s indicator to message",
           new_param->value.slen, new_param->value.ptr);
  pj_list_insert_before(&auth_hdr->credential.common.other_param, new_param);
}
static int diversion_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)
{
	pjsip_fromto_hdr *hdr = get_diversion_header(rdata);

	if (hdr) {
		set_redirecting(session, hdr, (pjsip_name_addr*)
				PJSIP_MSG_TO_HDR(rdata->msg_info.msg)->uri);
	}

	return 0;
}
/*!
 * \internal
 * \brief Overwrite fields in the outbound 'To' header
 *
 * Updates display name in an outgoing To header.
 *
 * \param tdata the outbound message data structure
 * \param to info to copy into the header
 */
static void update_to(pjsip_tx_data *tdata, char *to)
{
	pjsip_name_addr *name_addr = (pjsip_name_addr *)
		PJSIP_MSG_TO_HDR(tdata->msg)->uri;
	pjsip_uri *parsed;

	if ((parsed = pjsip_parse_uri(tdata->pool, to, strlen(to),
				      PJSIP_PARSE_URI_AS_NAMEADDR))) {
		pjsip_name_addr *parsed_name_addr = (pjsip_name_addr *)parsed;
		if (pj_strlen(&parsed_name_addr->display)) {
			pj_strdup(tdata->pool, &name_addr->display,
				  &parsed_name_addr->display);
		}
	}
}
/// Apply the mangalgorithm to the From tag, To tag (if present) and call ID of
/// req.
void MangelwurzelTsx::mangle_dialog_identifiers(pjsip_msg* req, pj_pool_t* pool)
{
  pjsip_from_hdr* from_hdr = PJSIP_MSG_FROM_HDR(req);

  if (from_hdr != NULL)
  {
    std::string from_tag = PJUtils::pj_str_to_string(&from_hdr->tag);
    mangle_string(from_tag);
    TRC_DEBUG("From tag mangled to %s", from_tag.c_str());
    from_hdr->tag = pj_strdup3(pool, from_tag.c_str());
  }

  pjsip_to_hdr* to_hdr = PJSIP_MSG_TO_HDR(req);

  if (to_hdr != NULL)
  {
    std::string to_tag = PJUtils::pj_str_to_string(&to_hdr->tag);
    mangle_string(to_tag);
    TRC_DEBUG("To tag mangled to %s", to_tag.c_str());
    to_hdr->tag = pj_strdup3(pool, to_tag.c_str());
  }

  pjsip_cid_hdr* cid_hdr = (pjsip_cid_hdr*)pjsip_msg_find_hdr(req,
                                                              PJSIP_H_CALL_ID,
                                                              NULL);
  if (cid_hdr != NULL)
  {
    std::string call_id = PJUtils::pj_str_to_string(&cid_hdr->id);
    mangle_string(call_id);
    TRC_DEBUG("Call ID manged to %s", call_id.c_str());
    cid_hdr->id = pj_strdup3(pool, call_id.c_str());

    // Report a SAS marker for the new call ID so that the two dialogs can be
    // correlated in SAS.
    TRC_DEBUG("Logging SAS Call-ID marker, Call-ID %.*s",
              cid_hdr->id.slen,
              cid_hdr->id.ptr);
    SAS::Marker cid_marker(trail(), MARKER_ID_SIP_CALL_ID, 1u);
    cid_marker.add_var_param(cid_hdr->id.slen, cid_hdr->id.ptr);
    SAS::report_marker(cid_marker, SAS::Marker::Scope::Trace);
  }
}
/*!
 * \internal
 * \brief Add a P-Asserted-Identity header to an outbound message
 * \param tdata The message to add the header to
 * \param id The identification information used to populate the header
 */
static void add_pai_header(const struct ast_sip_session *session, pjsip_tx_data *tdata, const struct ast_party_id *id)
{
	static const pj_str_t pj_pai_name = { "P-Asserted-Identity", 19 };
	pjsip_fromto_hdr *base;
	pjsip_fromto_hdr *pai_hdr;
	pjsip_fromto_hdr *old_pai;

	/* Since inv_session reuses responses, we have to make sure there's not already
	 * a P-Asserted-Identity present. If there is, we just modify the old one.
	 */
	old_pai = pjsip_msg_find_hdr_by_name(tdata->msg, &pj_pai_name, NULL);
	if (old_pai) {
		/* If type is OTHER, then the existing header was most likely
		 * added by the PJSIP_HEADER dial plan function as a simple
		 * name/value pair.  We can't pass this to modify_id_header because
		 * there are no virtual functions to get the uri.  We could parse
		 * it into a pjsip_fromto_hdr but it isn't worth it since
		 * modify_id_header is just going to overwrite the name and number
		 * anyway.  We'll just remove it from the header list instead
		 * and create a new one.
		 */
		if (old_pai->type == PJSIP_H_OTHER) {
			pj_list_erase(old_pai);
		} else {
			ast_sip_modify_id_header(tdata->pool, old_pai, id);
			add_privacy_header(tdata, id);
			return;
		}
	}

	base = tdata->msg->type == PJSIP_REQUEST_MSG ? session->saved_from_hdr :
		PJSIP_MSG_TO_HDR(tdata->msg);

	pai_hdr = create_new_id_hdr(&pj_pai_name, base, tdata, id);
	if (!pai_hdr) {
		return;
	}
	add_privacy_header(tdata, id);

	pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)pai_hdr);
}
static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata)
{
	char local_buf[256];
	char remote_buf[256];
	char *uuid;
	struct hepv3_capture_info *capture_info;
	pjsip_cid_hdr *cid_hdr;
	pjsip_from_hdr *from_hdr;
	pjsip_to_hdr *to_hdr;

	capture_info = hepv3_create_capture_info(tdata->buf.start, (size_t)(tdata->buf.cur - tdata->buf.start));
	if (!capture_info) {
		return PJ_SUCCESS;
	}

	pj_sockaddr_print(&tdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3);
	pj_sockaddr_print(&tdata->tp_info.dst_addr, remote_buf, sizeof(remote_buf), 3);

	cid_hdr = PJSIP_MSG_CID_HDR(tdata->msg);
	from_hdr = PJSIP_MSG_FROM_HDR(tdata->msg);
	to_hdr = PJSIP_MSG_TO_HDR(tdata->msg);

	uuid = assign_uuid(&cid_hdr->id, &to_hdr->tag, &from_hdr->tag);
	if (!uuid) {
		ao2_ref(capture_info, -1);
		return PJ_SUCCESS;
	}

	ast_sockaddr_parse(&capture_info->src_addr, local_buf, PARSE_PORT_REQUIRE);
	ast_sockaddr_parse(&capture_info->dst_addr, remote_buf, PARSE_PORT_REQUIRE);

	capture_info->capture_time = ast_tvnow();
	capture_info->capture_type = HEPV3_CAPTURE_TYPE_SIP;
	capture_info->uuid = uuid;
	capture_info->zipped = 0;

	hepv3_send_packet(capture_info);

	return PJ_SUCCESS;
}
static void diversion_incoming_response(struct ast_sip_session *session, pjsip_rx_data *rdata)
{
	static const pj_str_t contact_name = { "Contact", 7 };

	pjsip_status_line status = rdata->msg_info.msg->line.status;
	pjsip_fromto_hdr *div_hdr;
	pjsip_contact_hdr *contact_hdr;

	if ((status.code != 302) && (status.code != 181)) {
		return;
	}

	/* use the diversion header info if there is one. if not one then use the
           session caller id info. if that doesn't exist use info from the To hdr*/
	if (!(div_hdr = get_diversion_header(rdata)) && !session->id.number.valid) {
		div_hdr = PJSIP_MSG_TO_HDR(rdata->msg_info.msg);
	}

	contact_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &contact_name, NULL);

	set_redirecting(session, div_hdr, contact_hdr ?	(pjsip_name_addr*)contact_hdr->uri :
			(pjsip_name_addr*)PJSIP_MSG_FROM_HDR(rdata->msg_info.msg)->uri);
}
Exemple #11
0
void PJUtils::get_impi_and_impu(pjsip_rx_data* rdata, std::string& impi_out, std::string& impu_out)
{
  // Check to see if the request has already been integrity protected?
  pjsip_authorization_hdr* auth_hdr = (pjsip_authorization_hdr*)
           pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_AUTHORIZATION, NULL);

  pjsip_uri* to_uri = (pjsip_uri*)pjsip_uri_get_uri(PJSIP_MSG_TO_HDR(rdata->msg_info.msg)->uri);
  impu_out = PJUtils::public_id_from_uri(to_uri);
  if ((auth_hdr != NULL) &&
      (auth_hdr->credential.digest.username.slen != 0))
  {
    // private user identity is supplied in the Authorization header so use it.
    impi_out = PJUtils::pj_str_to_string(&auth_hdr->credential.digest.username);
    LOG_DEBUG("Private identity from authorization header = %s", impi_out.c_str());
  }
  else
  {
    // private user identity not supplied, so construct a default from the
    // public user identity by stripping the sip: prefix.
    impi_out = PJUtils::default_private_id_from_uri(to_uri);
    LOG_DEBUG("Private identity defaulted from public identity = %s", impi_out.c_str());
  }
}
void SubscriptionSproutletTsx::process_subscription_request(pjsip_msg* req)
{
  SAS::TrailId trail_id = trail();

  // Get the URI from the To header and check it is a SIP or SIPS URI.
  pjsip_uri* uri = (pjsip_uri*)pjsip_uri_get_uri(PJSIP_MSG_TO_HDR(req)->uri);

  if ((!PJSIP_URI_SCHEME_IS_SIP(uri)) && (!PJSIP_URI_SCHEME_IS_TEL(uri)))
  {
    // Reject a non-SIP/TEL URI with 404 Not Found (RFC3261 isn't clear
    // whether 404 is the right status code - it says 404 should be used if
    // the AoR isn't valid for the domain in the RequestURI).
    TRC_DEBUG("Rejecting subscribe request using invalid URI scheme");

    SAS::Event event(trail_id, SASEvent::SUBSCRIBE_FAILED_EARLY_URLSCHEME, 0);
    SAS::report_event(event);

    pjsip_msg* rsp = create_response(req, PJSIP_SC_NOT_FOUND);
    send_response(rsp);
    free_msg(req);
    return;
  }

  // Check if the contact header is present. If it isn't, we want to abort
  // processing before going any further, to avoid unnecessary work.
  pjsip_contact_hdr* contact_hdr =
             (pjsip_contact_hdr*)pjsip_msg_find_hdr(req, PJSIP_H_CONTACT, NULL);

  if (contact_hdr == NULL)
  {
    TRC_DEBUG("Unable to parse contact header from request. "
              "Aborting processing");
    pjsip_msg* rsp = create_response(req, PJSIP_SC_BAD_REQUEST);
    send_response(rsp);
    free_msg(req);
    return;
  }

  // Check if this is a subscription request from a binding that was emergency
  // registered.
  bool emergency_subscription = false;

  while (contact_hdr != NULL)
  {
    emergency_subscription = PJUtils::is_emergency_registration(contact_hdr);

    if (!emergency_subscription)
    {
      break;
    }

    contact_hdr = (pjsip_contact_hdr*) pjsip_msg_find_hdr(req,
                                                          PJSIP_H_CONTACT,
                                                          contact_hdr->next);
  }

  if (emergency_subscription)
  {
    // Reject a subscription with a Contact header containing a contact address
    // that's been registered for emergency service.
    TRC_DEBUG("Rejecting subscribe request from emergency registration");

    SAS::Event event(trail_id, SASEvent::SUBSCRIBE_FAILED_EARLY_EMERGENCY, 0);
    SAS::report_event(event);

    // Allow-Events is a mandatory header on 489 responses.
    pjsip_msg* rsp = create_response(req, PJSIP_SC_BAD_EVENT);
    pjsip_generic_string_hdr* allow_events_hdr =
                           pjsip_generic_string_hdr_create(get_pool(rsp),
                                                           &STR_ALLOW_EVENTS,
                                                           &STR_REG);
    pjsip_msg_add_hdr(rsp, (pjsip_hdr*)allow_events_hdr);
    send_response(rsp);
    free_msg(req);
    return;
  }

  // At this point we are going to attempt to process the subscribe.
  // Canonicalize the public ID from the URI in the To header.
  std::string public_id = PJUtils::public_id_from_uri(uri);

  TRC_DEBUG("Process SUBSCRIBE for public ID %s", public_id.c_str());

  // Get the call identifier from the headers.
  std::string cid = PJUtils::pj_str_to_string(&PJSIP_MSG_CID_HDR(req)->id);

  // Add SAS markers to the trail attached to the message so the trail
  // becomes searchable.
  SAS::Event event(trail_id, SASEvent::SUBSCRIBE_START, 0);
  event.add_var_param(public_id);
  SAS::report_event(event);

  // Create an ACR for the request. The node role is always considered
  // originating for SUBSCRIBE requests.
  ACR* acr = _subscription->_acr_factory->get_acr(trail_id,
                                                  ACR::CALLING_PARTY,
                                                  ACR::NODE_ROLE_ORIGINATING);
  acr->rx_request(req);

  // Work out the expiry time of the subscription.
  pjsip_expires_hdr* expires =
             (pjsip_expires_hdr*)pjsip_msg_find_hdr(req, PJSIP_H_EXPIRES, NULL);
  int expiry = (expires != NULL) ?
                expires->ivalue :
                SubscriptionSproutlet::DEFAULT_SUBSCRIPTION_EXPIRES;

  if (expiry > _subscription->_max_expires)
  {
    // Expiry is too long, set it to the maximum.
    TRC_DEBUG("Requested expiry (%d) is too long, setting to the maximum (%d)",
              expiry, _subscription->_max_expires);
    expiry = _subscription->_max_expires;
  }

  // Create a subscription object from the request that we can pass down to
  // be set into/updated in the different stores
  Subscription* new_subscription = create_subscription(req, expiry);
  HSSConnection::irs_info irs_info;
  HTTPCode rc;

  // Update or remove the subscription in the subscriber manager depending on
  // the expiry time.
  if (expiry != 0)
  {
    TRC_DEBUG("Adding/updating the subscription with ID %s",
              new_subscription->get_id().c_str());

    Subscriptions new_subscriptions;
    new_subscriptions.insert(std::make_pair(new_subscription->get_id(), new_subscription));
    rc = _subscription->_sm->update_subscriptions(
                   public_id,
                   new_subscriptions,
                   irs_info,
                   trail_id);
  }
  else
  {
    TRC_DEBUG("Removing the subscription with ID %s",
              new_subscription->get_id().c_str());

    rc = _subscription->_sm->remove_subscriptions(public_id,
                                                  {new_subscription->get_id()},
                                                  irs_info,
                                                  trail_id);
  }

  pjsip_status_code st_code =
                 determine_sm_sip_response(rc, irs_info._regstate, "SUBSCRIBE");

  pjsip_msg* rsp = create_response(req, st_code);

  if (st_code == PJSIP_SC_OK)
  {
    // The subscribe was successful. SAS log, and add headers to the response.
    TRC_DEBUG("The subscribe has been successful");

    SAS::Event sub_accepted(trail_id, SASEvent::SUBSCRIBE_ACCEPTED, 0);
    SAS::report_event(sub_accepted);

    // Add expires headers
    pjsip_expires_hdr* expires_hdr = pjsip_expires_hdr_create(get_pool(rsp),
                                                              expiry);
    pjsip_msg_add_hdr(rsp, (pjsip_hdr*)expires_hdr);

    // Add the contact header
    pjsip_contact_hdr* contact_hdr = pjsip_contact_hdr_create(get_pool(rsp));
    pjsip_name_addr* contact_uri = pjsip_name_addr_create(get_pool(rsp));
    contact_uri->uri = (pjsip_uri*)stack_data.scscf_uri;
    contact_hdr->uri = (pjsip_uri*)contact_uri;
    pjsip_msg_add_hdr(rsp, (pjsip_hdr*)contact_hdr);

    // Add a P-Charging-Function-Addresses header to the successful SUBSCRIBE
    // response containing the charging addresses returned by the HSS.
    PJUtils::add_pcfa_header(rsp,
                             get_pool(rsp),
                             irs_info._ccfs,
                             irs_info._ecfs,
                             false);

  }
  else if (st_code == PJSIP_SC_TEMPORARILY_UNAVAILABLE)
  {
    // A 480 response means that the subscriber wasn't registered. SAS log
    // this.
    TRC_DEBUG("The subscribe has failed as the subscriber (%s) wasn't registered",
              public_id.c_str());

    SAS::Event event(trail_id, SASEvent::SUBSCRIBE_FAILED_EARLY_NOT_REG, 0);
    SAS::report_event(event);
  }
  else
  {
    // The subscribe was unsuccessful.
    TRC_DEBUG("The subscribe failed with return code %d", st_code);

    SAS::Event sub_failed(trail_id, SASEvent::SUBSCRIBE_FAILED, 0);
    sub_failed.add_var_param(public_id);
    SAS::report_event(sub_failed);
  }

  // Add the to tag to the response (even if the subscribe was rejected).
  pjsip_to_hdr *to = (pjsip_to_hdr*) pjsip_msg_find_hdr(rsp,
                                                        PJSIP_H_TO,
                                                        NULL);
  pj_strdup2(get_pool(rsp), &to->tag, new_subscription->_to_tag.c_str());

  // Pass the response to the ACR.
  acr->tx_response(rsp);

  // Send the response.
  send_response(rsp);

  // Send the ACR and delete it.
  acr->send();
  delete acr; acr = NULL;

  delete new_subscription; new_subscription = NULL;
  free_msg(req);
}
Exemple #13
0
pj_bool_t authenticate_rx_request(pjsip_rx_data* rdata)
{
  TRC_DEBUG("Authentication module invoked");
  pj_status_t status;
  bool is_register = (rdata->msg_info.msg->line.req.method.id == PJSIP_REGISTER_METHOD);
  SNMP::SuccessFailCountTable* auth_stats_table = NULL;
  std::string resync;

  SAS::TrailId trail = get_trail(rdata);

  if (!needs_authentication(rdata, trail))
  {
    TRC_DEBUG("Request does not need authentication");
    return PJ_FALSE;
  }

  TRC_DEBUG("Request needs authentication");
  rapidjson::Document* av = NULL;

  const int unauth_sc = is_register ? PJSIP_SC_UNAUTHORIZED : PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED;
  int sc = unauth_sc;
  status = PJSIP_EAUTHNOAUTH;

  pjsip_digest_credential* credentials = get_credentials(rdata);

  if ((credentials != NULL) &&
      (credentials->response.slen != 0))
  {
    std::string impi = PJUtils::pj_str_to_string(&credentials->username);
    std::string nonce = PJUtils::pj_str_to_string(&credentials->nonce);
    uint64_t cas = 0;
    av = av_store->get_av(impi, nonce, cas, trail);

    if (!is_register)
    {
      // Challenged non-register requests must be SIP digest, so only one table
      // needed for this case.
      auth_stats_table = auth_stats_tables->non_register_auth_tbl;
    }
    else
    {
      if (!pj_strcmp2(&credentials->algorithm, "MD5"))
      {
        auth_stats_table = auth_stats_tables->sip_digest_auth_tbl;
      }
      else if (!pj_strcmp2(&credentials->algorithm, "AKAv1-MD5"))
      {
        auth_stats_table = auth_stats_tables->ims_aka_auth_tbl;
      }
      else
      {
        // Authorization header did not specify an algorithm, so check the av for
        // this information instead.
        if ((av != NULL) && (av->HasMember("aka")))
        {
          auth_stats_table = auth_stats_tables->ims_aka_auth_tbl;
        }
        else
        {
          // Use the digest table if the AV specified digest, or as a fallback if there was no AV
          auth_stats_table = auth_stats_tables->sip_digest_auth_tbl;
        }
      }
    }

    if (auth_stats_table != NULL)
    {
      auth_stats_table->increment_attempts();
    }

    // Request contains a response to a previous challenge, so pass it to
    // the authentication module to verify.
    TRC_DEBUG("Verify authentication information in request");
    status = pjsip_auth_srv_verify2((is_register ? &auth_srv : &auth_srv_proxy), rdata, &sc, (void*)av);

    if (status == PJ_SUCCESS)
    {
      // The authentication information in the request was verified.
      TRC_DEBUG("Request authenticated successfully");

      SAS::Event event(trail, SASEvent::AUTHENTICATION_SUCCESS, 0);
      SAS::report_event(event);

      if (auth_stats_table != NULL)
      {
        auth_stats_table->increment_successes();
      }

      // Write a tombstone flag back to the AV store, handling contention.
      // We don't actually expect anything else to be writing to this row in
      // the AV store, but there is a window condition where we failed to read
      // from the primary, successfully read from the backup (with a different
      // CAS value) and then try to write back to the primary, which fails due
      // to "contention".
      Store::Status store_status;
      do
      {
        // Set the tomestone flag in the JSON authentication vector.
        rapidjson::Value tombstone_value;
        tombstone_value.SetBool(true);
        av->AddMember("tombstone", tombstone_value, (*av).GetAllocator());

        // Store it.  If this fails due to contention, read the updated JSON.
        store_status = av_store->set_av(impi, nonce, av, cas, trail);
        if (store_status == Store::DATA_CONTENTION)
        {
          // LCOV_EXCL_START - No support for contention in UT
          TRC_DEBUG("Data contention writing tombstone - retry");
          delete av;
          av = av_store->get_av(impi, nonce, cas, trail);
          if (av == NULL)
          {
            store_status = Store::ERROR;
          }
          // LCOV_EXCL_STOP
        }
      }
      while (store_status == Store::DATA_CONTENTION);

      if (store_status != Store::OK)
      {
        // LCOV_EXCL_START
        TRC_ERROR("Tried to tombstone AV for %s/%s after processing an authentication, but failed",
                  impi.c_str(),
                  nonce.c_str());
        // LCOV_EXCL_STOP
      }

      // If doing AKA authentication, check for an AUTS parameter.  We only
      // check this if the request authenticated as actioning it otherwise
      // is a potential denial of service attack.
      if (!pj_strcmp(&credentials->algorithm, &STR_AKAV1_MD5))
      {
        TRC_DEBUG("AKA authentication so check for client resync request");
        pjsip_param* p = pjsip_param_find(&credentials->other_param,
                                          &STR_AUTS);

        if (p != NULL)
        {
          // Found AUTS parameter, so UE is requesting a resync.  We need to
          // redo the authentication, passing an auts parameter to the HSS
          // comprising the first 16 octets of the nonce (RAND) and the 14
          // octets of the auts parameter.  (See TS 33.203 and table 6.3.3 of
          // TS 29.228 for details.)
          TRC_DEBUG("AKA SQN resync request from UE");
          std::string auts = PJUtils::pj_str_to_string(&p->value);
          std::string nonce = PJUtils::pj_str_to_string(&credentials->nonce);

          // Convert the auts and nonce to binary for manipulation
          nonce = base64_decode(nonce);
          auts  = base64_decode(auts);

          if ((auts.length() != 14) ||
              (nonce.length() != 32))
          {
            // AUTS and/or nonce are malformed, so reject the request.
            TRC_WARNING("Invalid auts/nonce on resync request from private identity %.*s",
                        credentials->username.slen,
                        credentials->username.ptr);
            status = PJSIP_EAUTHINAKACRED;
            sc = PJSIP_SC_FORBIDDEN;
          }
          else
          {
            // auts and nonce are as expected, so create the resync string
            // that needs to be passed to the HSS, and act as if no
            // authentication information was received. The resync string
            // should be RAND || AUTS.
            resync = base64_encode(nonce.substr(0, 16) + auts);
            status = PJSIP_EAUTHNOAUTH;
            sc = unauth_sc;
          }
        }
      }

      if (status == PJ_SUCCESS)
      {
        // Request authentication completed, so let the message through to other
        // modules. Remove any Proxy-Authorization headers first so they are not
        // passed to downstream devices. We can't do this for Authorization
        // headers, as these may need to be included in 3rd party REGISTER
        // messages.
        while (pjsip_msg_find_remove_hdr(rdata->msg_info.msg,
                                         PJSIP_H_PROXY_AUTHORIZATION,
                                         NULL) != NULL);
        delete av;
        return PJ_FALSE;
      }
    }
  }


  // The message either has insufficient authentication information, or
  // has failed authentication.  In either case, the message will be
  // absorbed and responded to by the authentication module, so we need to
  // add SAS markers so the trail will become searchable.
  SAS::Marker start_marker(trail, MARKER_ID_START, 1u);
  SAS::report_marker(start_marker);

  // Add a SAS end marker
  SAS::Marker end_marker(trail, MARKER_ID_END, 1u);
  SAS::report_marker(end_marker);

  // Create an ACR for the message and pass the request to it.  Role is always
  // considered originating for a REGISTER request.
  ACR* acr = acr_factory->get_acr(trail,
                                  CALLING_PARTY,
                                  NODE_ROLE_ORIGINATING);
  acr->rx_request(rdata->msg_info.msg, rdata->pkt_info.timestamp);

  pjsip_tx_data* tdata;

  if ((status == PJSIP_EAUTHNOAUTH) ||
      (status == PJSIP_EAUTHACCNOTFOUND))
  {
    // No authorization information in request, or no authentication vector
    // found in the store (so request is likely stale), so must issue
    // challenge.
    TRC_DEBUG("No authentication information in request or stale nonce, so reject with challenge");
    pj_bool_t stale = (status == PJSIP_EAUTHACCNOTFOUND);

    sc = unauth_sc;

    if (stale && auth_stats_table != NULL)
    {
      auth_stats_table->increment_failures();
    }

    status = PJUtils::create_response(stack_data.endpt, rdata, sc, NULL, &tdata);

    if (status != PJ_SUCCESS)
    {
      // Failed to create a response.  This really shouldn't happen, but there
      // is nothing else we can do.
      // LCOV_EXCL_START
      delete acr;
      return PJ_TRUE;
      // LCOV_EXCL_STOP
    }

    create_challenge(credentials, stale, resync, rdata, tdata);
  }
  else
  {
    // Authentication failed.
    std::string error_msg = PJUtils::pj_status_to_string(status);

    TRC_ERROR("Authentication failed, %s", error_msg.c_str());
    if (auth_stats_table != NULL)
    {
      auth_stats_table->increment_failures();
    }
    SAS::Event event(trail, SASEvent::AUTHENTICATION_FAILED, 0);
    event.add_var_param(error_msg);
    SAS::report_event(event);

    if (sc != unauth_sc)
    {
      // Notify Homestead and the HSS that this authentication attempt
      // has definitively failed.
      std::string impi;
      std::string impu;

      PJUtils::get_impi_and_impu(rdata, impi, impu);

      hss->update_registration_state(impu, impi, HSSConnection::AUTH_FAIL, trail);
    }

    if (analytics != NULL)
    {
      analytics->auth_failure(PJUtils::pj_str_to_string(&credentials->username),
      PJUtils::public_id_from_uri((pjsip_uri*)pjsip_uri_get_uri(PJSIP_MSG_TO_HDR(rdata->msg_info.msg)->uri)));
    }

    status = PJUtils::create_response(stack_data.endpt, rdata, sc, NULL, &tdata);
    if (status != PJ_SUCCESS)
    {
      // Failed to create a response.  This really shouldn't happen, but there
      // is nothing else we can do.
      // LCOV_EXCL_START
      delete acr;
      return PJ_TRUE;
      // LCOV_EXCL_STOP
    }
  }

  acr->tx_response(tdata->msg);

  // Issue the challenge response transaction-statefully. This is so that:
  //  * if we challenge an INVITE, the UE can ACK the 407
  //  * if a challenged request gets retransmitted, we don't repeat the work
  pjsip_transaction* tsx = NULL;
  status = pjsip_tsx_create_uas2(NULL, rdata, NULL, &tsx);
  set_trail(tsx, trail);
  if (status != PJ_SUCCESS)
  {
    // LCOV_EXCL_START - defensive code not hit in UT
    TRC_WARNING("Couldn't create PJSIP transaction for authentication response: %d"
                " (sending statelessly instead)", status);
    // Send the response statelessly in this case - it's better than nothing
    pjsip_endpt_send_response2(stack_data.endpt, rdata, tdata, NULL, NULL);
    // LCOV_EXCL_STOP
  }
  else
  {
    // Let the tsx know about the original message
    pjsip_tsx_recv_msg(tsx, rdata);
    // Send our response in this transaction
    pjsip_tsx_send_msg(tsx, tdata);
  }

  // Send the ACR.
  acr->send();
  delete acr;
  delete av;
  return PJ_TRUE;
}
Exemple #14
0
/// Initialise the UAS transaction object.
pj_status_t ICSCFProxy::UASTsx::init(pjsip_rx_data* rdata)
{
  // Do the BasicProxy initialization first.
  pj_status_t status = BasicProxy::UASTsx::init(rdata);

  pjsip_msg* msg = rdata->msg_info.msg;

  // Create an ACR if ACR generation is enabled.
  _acr = create_acr();

  // Parse interesting parameters from the request for the later lookups.
  if (msg->line.req.method.id == PJSIP_REGISTER_METHOD)
  {
    // REGISTER request.
    LOG_DEBUG("I-CSCF initialize transaction for REGISTER request");
    _case = SessionCase::REGISTER;

    std::string impu;
    std::string impi;
    std::string visited_network;
    std::string auth_type;

    // Get the public identity from the To: header.
    pjsip_to_hdr* to_hdr = PJSIP_MSG_TO_HDR(msg);
    pjsip_uri* to_uri = (pjsip_uri*)pjsip_uri_get_uri(to_hdr->uri);
    impu = PJUtils::public_id_from_uri(to_uri);

    // Get the private identity from the Authentication header, or generate
    // a default if there is no Authentication header or no username in the
    // header.
    pjsip_authorization_hdr* auth_hdr =
           (pjsip_authorization_hdr*)pjsip_msg_find_hdr(msg,
                                                        PJSIP_H_AUTHORIZATION,
                                                        NULL);
    if ((auth_hdr != NULL) &&
        (auth_hdr->credential.digest.username.slen != 0))
    {
      // Get the IMPI from the username.
      impi = PJUtils::pj_str_to_string(&auth_hdr->credential.digest.username);
    }
    else
    {
      // Create a default IMPI from the IMPU by removing the sip: prefix.
      impi = impu.substr(4);
    }

    // Get the visted network identification if present.  If not, homestead will
    // default it.
    pjsip_generic_string_hdr* vn_hdr =
         (pjsip_generic_string_hdr*)pjsip_msg_find_hdr_by_name(msg,
                                                               &STR_P_V_N_I,
                                                               NULL);

    if (vn_hdr != NULL)
    {
      visited_network = PJUtils::pj_str_to_string(&vn_hdr->hvalue);
    }
    else if (PJSIP_URI_SCHEME_IS_SIP(to_uri) || PJSIP_URI_SCHEME_IS_SIPS(to_uri))
    {
      // Use the domain of the IMPU as the visited network.
      visited_network = PJUtils::pj_str_to_string(&((pjsip_sip_uri*)to_uri)->host);
    }

    // Work out what authorization type to use by looking at the expiry
    // values in the request.  (Use a default of 1 because if there is no
    // expires header or expires values in the contact headers this will
    // be a registration not a deregistration.)
    auth_type = (PJUtils::max_expires(msg, 1) > 0) ? "REG" : "DEREG";

    // Create an UAR router to handle the HSS interactions and S-CSCF
    // selection.
    _router = (ICSCFRouter*)new ICSCFUARouter(((ICSCFProxy*)_proxy)->_hss,
                                              ((ICSCFProxy*)_proxy)->_scscf_selector,
                                              trail(),
                                              _acr,
                                              impi,
                                              impu,
                                              visited_network,
                                              auth_type);
  }
  else
  {
    // Non-register request.
    LOG_DEBUG("I-CSCF initialize transaction for non-REGISTER request");

    // Check for a route header containing the orig parameter;
    pjsip_route_hdr* route = rdata->msg_info.route;

    std::string impu;

    if ((route != NULL) &&
        (pjsip_param_find(&((pjsip_sip_uri*)route->name_addr.uri)->other_param,
                          &STR_ORIG) != NULL))
    {
      // Originating request.
      LOG_DEBUG("Originating request");
      _case = SessionCase::ORIGINATING;
      impu = PJUtils::public_id_from_uri(PJUtils::orig_served_user(msg));
    }
    else
    {
      // Terminating request.
      LOG_DEBUG("Terminating request");
      _case = SessionCase::TERMINATING;
      impu = PJUtils::public_id_from_uri(PJUtils::term_served_user(msg));
    }

    // Create an LIR router to handle the HSS interactions and S-CSCF
    // selection.
    _router = (ICSCFRouter*)new ICSCFLIRouter(((ICSCFProxy*)_proxy)->_hss,
                                              ((ICSCFProxy*)_proxy)->_scscf_selector,
                                              trail(),
                                              _acr,
                                              impu,
                                              (_case == SessionCase::ORIGINATING));
  }

  // Pass the received request to the ACR.
  _acr->rx_request(rdata->msg_info.msg, rdata->pkt_info.timestamp);

  // Record whether or not this is an in-dialog request.  This is needed
  // to determine whether or not to send interim ACRs on provisional
  // responses.
  _in_dialog = (rdata->msg_info.msg->line.req.method.id != PJSIP_BYE_METHOD) &&
               (rdata->msg_info.to->tag.slen != 0);

  return status;
}
Exemple #15
0
void MementoAppServerTsx::on_initial_request(pjsip_msg* req)
{
  TRC_DEBUG("Memento processing an initial request of type %s",
           (req->line.req.method.id == PJSIP_INVITE_METHOD) ? "INVITE" : "BYE");

  // Get the current time
  time_t rawtime;
  time(&rawtime);
  tm* start_time = localtime(&rawtime);
  _start_time_xml = create_formatted_timestamp(start_time, XML_PATTERN);
  _start_time_cassandra = create_formatted_timestamp(start_time, TIMESTAMP_PATTERN);

  // Is the call originating or terminating?
  std::string served_user;
  pjsip_routing_hdr* psu_hdr = (pjsip_routing_hdr*)
                     pjsip_msg_find_hdr_by_name(req, &P_SERVED_USER, NULL);

  if (psu_hdr != NULL)
  {
    pjsip_uri* uri = (pjsip_uri*)pjsip_uri_get_uri(&psu_hdr->name_addr);
    served_user = uri_to_string(PJSIP_URI_IN_ROUTING_HDR, uri);

    pjsip_param* sescase = pjsip_param_find(&psu_hdr->other_param, &SESCASE);

    if ((sescase != NULL) &&
        (pj_stricmp(&sescase->value, &ORIG) == 0))
    {
      TRC_DEBUG("Request is originating");

      _outgoing = true;
    }
  }

  // Get the caller, callee and impu values
  if (_outgoing)
  {
    // Get the callee's URI amd name from the To header.
    _callee_uri = uri_to_string(PJSIP_URI_IN_FROMTO_HDR,
                    (pjsip_uri*)pjsip_uri_get_uri(PJSIP_MSG_TO_HDR(req)->uri));
    _callee_name = pj_str_to_string(&((pjsip_name_addr*)
                                       (PJSIP_MSG_TO_HDR(req)->uri))->display);

    // Get the caller's URI and name from the P-Asserted Identity header. If
    // this is missing, use the From header.
    pjsip_routing_hdr* asserted_id = (pjsip_routing_hdr*)
               pjsip_msg_find_hdr_by_name(req, &P_ASSERTED_IDENTITY, NULL);

    if (asserted_id != NULL)
    {
      _caller_uri = uri_to_string(PJSIP_URI_IN_FROMTO_HDR,
                       (pjsip_uri*)pjsip_uri_get_uri(&asserted_id->name_addr));
      _caller_name = pj_str_to_string(&asserted_id->name_addr.display);
    }
    else
    {
      TRC_WARNING("INVITE missing P-Asserted-Identity");
      send_request(req);
      return;
    }

    // Set the IMPU equal to the caller's URI
    _impu = _caller_uri;
  }
  else
  {
    // Get the callee's URI from the request URI. There can be no name value.
    _callee_uri =  uri_to_string(PJSIP_URI_IN_FROMTO_HDR, req->line.req.uri);

    // Get the caller's URI and name from the From header.
    _caller_uri = uri_to_string(PJSIP_URI_IN_FROMTO_HDR,
                (pjsip_uri*)pjsip_uri_get_uri(PJSIP_MSG_FROM_HDR(req)->uri));
    _caller_name = pj_str_to_string(&((pjsip_name_addr*)
                                   (PJSIP_MSG_FROM_HDR(req)->uri))->display);

    // Set the IMPU equal to the callee's URI
    _impu = _callee_uri;
  }

  // Add a unique ID containing the IMPU to the record route header.
  // This has the format:
  //     <YYYYMMDDHHMMSS>_<unique_id>_<base64 encoded impu>.memento.<home domain>
  _unique_id = std::to_string(Utils::generate_unique_integer(0,0));
  std::string encoded_impu =
     base64_encode(reinterpret_cast<const unsigned char*>(_impu.c_str()),
                                                          _impu.length());
  std::string dialog_id = std::string(_start_time_cassandra).
                          append("_").
                          append(_unique_id).
                          append("_").
                          append(encoded_impu);

  add_to_dialog(dialog_id);
  send_request(req);
}
Exemple #16
0
pj_bool_t authenticate_rx_request(pjsip_rx_data* rdata)
{
  pj_status_t status;
  std::string resync;

  SAS::TrailId trail = get_trail(rdata);

  if (rdata->tp_info.transport->local_name.port != stack_data.scscf_port)
  {
    // Request not received on S-CSCF port, so don't authenticate it.
    std::string error_msg = "Request wasn't received on S-CSCF port";
    log_sas_auth_not_needed_event(trail, error_msg);

    return PJ_FALSE;
  }

  if (rdata->msg_info.msg->line.req.method.id != PJSIP_REGISTER_METHOD)
  {
    // Non-REGISTER request, so don't do authentication as it must have come
    // from an authenticated or trusted source.
    std::string error_msg = "Request wasn't a REGISTER";
    log_sas_auth_not_needed_event(trail, error_msg);

    return PJ_FALSE;
  }

  // Authentication isn't required for emergency registrations. An emergency
  // registration is one where each Contact header contains 'sos' as the SIP
  // URI parameter.
  bool emergency_reg = true;

  pjsip_contact_hdr* contact_hdr = (pjsip_contact_hdr*)
                 pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL);

  while ((contact_hdr != NULL) && (emergency_reg))
  {
    emergency_reg = PJUtils::is_emergency_registration(contact_hdr);
    contact_hdr = (pjsip_contact_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg,
                                                          PJSIP_H_CONTACT,
                                                          contact_hdr->next);
  }

  if (emergency_reg)
  {
    std::string error_msg = "Request is an emergency REGISTER";
    log_sas_auth_not_needed_event(trail, error_msg);

    return PJ_FALSE;
  }

  // Check to see if the request has already been integrity protected?
  pjsip_authorization_hdr* auth_hdr = (pjsip_authorization_hdr*)
           pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_AUTHORIZATION, NULL);

  if ((auth_hdr != NULL) &&
      (auth_hdr->credential.digest.response.slen == 0))
  {
    // There is an authorization header with no challenge response, so check
    // for the integrity-protected indication.
    LOG_DEBUG("Authorization header in request with no challenge response");
    pjsip_param* integrity =
           pjsip_param_find(&auth_hdr->credential.digest.other_param,
                            &STR_INTEGRITY_PROTECTED);

    // Request has an integrity protected indication, so let it through if
    // it is set to a "yes" value.
    if ((integrity != NULL) &&
        ((pj_stricmp(&integrity->value, &STR_YES) == 0) ||
         (pj_stricmp(&integrity->value, &STR_TLS_YES) == 0) ||
         (pj_stricmp(&integrity->value, &STR_IP_ASSOC_YES) == 0)))
    {
      // Request is already integrity protected, so let it through.
      LOG_INFO("Request integrity protected by edge proxy");

      std::string error_msg = "Request integrity protected by edge proxy";
      log_sas_auth_not_needed_event(trail, error_msg);

      return PJ_FALSE;
    }
  }

  int sc = PJSIP_SC_UNAUTHORIZED;
  status = PJSIP_EAUTHNOAUTH;

  if ((auth_hdr != NULL) &&
      (auth_hdr->credential.digest.response.slen != 0))
  {
    std::string impi = PJUtils::pj_str_to_string(&auth_hdr->credential.digest.username);
    std::string nonce = PJUtils::pj_str_to_string(&auth_hdr->credential.digest.nonce);
    uint64_t cas = 0;

    Json::Value* av = av_store->get_av(impi, nonce, cas, trail);

    // Request contains a response to a previous challenge, so pass it to
    // the authentication module to verify.
    LOG_DEBUG("Verify authentication information in request");
    status = pjsip_auth_srv_verify2(&auth_srv, rdata, &sc, (void*)av);

    if (status == PJ_SUCCESS)
    {
      // The authentication information in the request was verified.
      LOG_DEBUG("Request authenticated successfully");

      SAS::Event event(trail, SASEvent::AUTHENTICATION_SUCCESS, 0);
      SAS::report_event(event);

      (*av)["tombstone"] = Json::Value("true");
      bool rc = av_store->set_av(impi, nonce, av, cas, trail);


      if (!rc) {
        // LCOV_EXCL_START
        LOG_ERROR("Tried to tombstone AV for %s/%s after processing an authentication, but failed",
                  impi.c_str(),
                  nonce.c_str());
        // LCOV_EXCL_STOP
      }

      // If doing AKA authentication, check for an AUTS parameter.  We only
      // check this if the request authenticated as actioning it otherwise
      // is a potential denial of service attack.
      if (!pj_strcmp(&auth_hdr->credential.digest.algorithm, &STR_AKAV1_MD5))
      {
        LOG_DEBUG("AKA authentication so check for client resync request");
        pjsip_param* p = pjsip_param_find(&auth_hdr->credential.digest.other_param,
                                          &STR_AUTS);

        if (p != NULL)
        {
          // Found AUTS parameter, so UE is requesting a resync.  We need to
          // redo the authentication, passing an auts parameter to the HSS
          // comprising the first 16 octets of the nonce (RAND) and the 14
          // octets of the auts parameter.  (See TS 33.203 and table 6.3.3 of
          // TS 29.228 for details.)
          LOG_DEBUG("AKA SQN resync request from UE");
          std::string auts = PJUtils::pj_str_to_string(&p->value);
          std::string nonce = PJUtils::pj_str_to_string(&auth_hdr->credential.digest.nonce);
          if ((auts.length() != 14) ||
              (nonce.length() != 32))
          {
            // AUTS and/or nonce are malformed, so reject the request.
            LOG_WARNING("Invalid auts/nonce on resync request from private identity %.*s",
                        auth_hdr->credential.digest.username.slen,
                        auth_hdr->credential.digest.username.ptr);
            status = PJSIP_EAUTHINAKACRED;
            sc = PJSIP_SC_FORBIDDEN;
          }
          else
          {
            // auts and nonce are as expected, so create the resync string
            // that needs to be passed to the HSS, and act as if no
            // authentication information was received.
            resync = nonce.substr(0,16) + auts;
            status = PJSIP_EAUTHNOAUTH;
            sc = PJSIP_SC_UNAUTHORIZED;
          }
        }
      }


      if (status == PJ_SUCCESS)
      {
        // Request authentication completed, so let the message through to
        // other modules.
        delete av;
        return PJ_FALSE;
      }
    }
    delete av;
  }


  // The message either has insufficient authentication information, or
  // has failed authentication.  In either case, the message will be
  // absorbed and responded to by the authentication module, so we need to
  // add SAS markers so the trail will become searchable.
  SAS::Marker start_marker(trail, MARKER_ID_START, 1u);
  SAS::report_marker(start_marker);

  PJUtils::report_sas_to_from_markers(trail, rdata->msg_info.msg);
  PJUtils::mark_sas_call_branch_ids(trail, NULL, rdata->msg_info.msg);

  // Add a SAS end marker
  SAS::Marker end_marker(trail, MARKER_ID_END, 1u);
  SAS::report_marker(end_marker);

  // Create an ACR for the message and pass the request to it.
  ACR* acr = acr_factory->get_acr(trail,
                                  CALLING_PARTY,
                                  ACR::requested_node_role(rdata->msg_info.msg));
  acr->rx_request(rdata->msg_info.msg, rdata->pkt_info.timestamp);

  pjsip_tx_data* tdata;

  if ((status == PJSIP_EAUTHNOAUTH) ||
      (status == PJSIP_EAUTHACCNOTFOUND))
  {
    // No authorization information in request, or no authentication vector
    // found in the store (so request is likely stale), so must issue
    // challenge.
    LOG_DEBUG("No authentication information in request or stale nonce, so reject with challenge");

    sc = PJSIP_SC_UNAUTHORIZED;
    status = PJUtils::create_response(stack_data.endpt, rdata, sc, NULL, &tdata);

    if (status != PJ_SUCCESS)
    {
      // Failed to create a response.  This really shouldn't happen, but there
      // is nothing else we can do.
      // LCOV_EXCL_START
      delete acr;
      return PJ_TRUE;
      // LCOV_EXCL_STOP
    }

    create_challenge(auth_hdr, resync, rdata, tdata);
  }
  else
  {
    // Authentication failed.
    std::string error_msg = PJUtils::pj_status_to_string(status);

    LOG_ERROR("Authentication failed, %s", error_msg.c_str());

    SAS::Event event(trail, SASEvent::AUTHENTICATION_FAILED, 0);
    event.add_var_param(error_msg);
    SAS::report_event(event);

    if (sc != PJSIP_SC_UNAUTHORIZED)
    {
      // Notify Homestead and the HSS that this authentication attempt
      // has definitively failed.
      std::string impi;
      std::string impu;

      PJUtils::get_impi_and_impu(rdata, impi, impu);

      hss->update_registration_state(impu, impi, HSSConnection::AUTH_FAIL, 0);
    }

    if (analytics != NULL)
    {
      analytics->auth_failure(PJUtils::pj_str_to_string(&auth_hdr->credential.digest.username),
                              PJUtils::public_id_from_uri((pjsip_uri*)pjsip_uri_get_uri(PJSIP_MSG_TO_HDR(rdata->msg_info.msg)->uri)));
    }

    // @TODO - need more diagnostics here so we can identify and flag
    // attacks.

    status = PJUtils::create_response(stack_data.endpt, rdata, sc, NULL, &tdata);
    if (status != PJ_SUCCESS)
    {
      // Failed to create a response.  This really shouldn't happen, but there
      // is nothing else we can do.
      // LCOV_EXCL_START
      delete acr;
      return PJ_TRUE;
      // LCOV_EXCL_STOP
    }
  }

  acr->tx_response(tdata->msg);

  status = pjsip_endpt_send_response2(stack_data.endpt, rdata, tdata, NULL, NULL);

  // Send the ACR.
  acr->send_message();
  delete acr;

  return PJ_TRUE;
}
Exemple #17
0
void registrar_on_tsx_state(pjsip_transaction *tsx, pjsip_event *event) {
  if (((bool)tsx->mod_data[mod_registrar.id] == DEFAULT_HANDLING_SESSION_TERMINATED) &&
      (event->type == PJSIP_EVENT_RX_MSG) &&
      ((tsx->status_code == 408) || ((tsx->status_code >= 500) && (tsx->status_code < 600)))) {
    // Can't create an AS response in UT
    // LCOV_EXCL_START
    LOG_INFO("REGISTER transaction failed with code %d", tsx->status_code);
    std::string aor = PJUtils::uri_to_string(PJSIP_URI_IN_FROMTO_HDR, (pjsip_uri*)pjsip_uri_get_uri(PJSIP_MSG_TO_HDR(tsx->last_tx->msg)->uri));

    // 3GPP TS 24.229 V12.0.0 (2013-03) 5.4.1.7 specifies that an AS failure where SESSION_TERMINATED
    // is set means that we should deregister "the currently registered public user identity" - i.e. all bindings
    RegistrationUtils::network_initiated_deregistration(ifchandler, store, aor, "*");
    // LCOV_EXCL_STOP
  }
}
void ICSCFSproutletRegTsx::on_rx_initial_request(pjsip_msg* req)
{
  // Create an ACR for this transaction.
  _acr = _icscf->get_acr(trail());
  _acr->rx_request(req);

  TRC_DEBUG("I-CSCF initialize transaction for REGISTER request");

  // Extract relevant fields from the message
  std::string impu;
  std::string impi;
  std::string visited_network;
  std::string auth_type;

  // Get the public identity from the To: header.
  pjsip_to_hdr* to_hdr = PJSIP_MSG_TO_HDR(req);
  pjsip_uri* to_uri = (pjsip_uri*)pjsip_uri_get_uri(to_hdr->uri);
  impu = PJUtils::public_id_from_uri(to_uri);

  SAS::Event reg_event(trail(), SASEvent::ICSCF_RCVD_REGISTER, 0);
  reg_event.add_var_param(impu);
  SAS::report_event(reg_event);

  // Get the private identity from the Authentication header, or generate
  // a default if there is no Authentication header or no username in the
  // header.
  pjsip_authorization_hdr* auth_hdr =
    (pjsip_authorization_hdr*)pjsip_msg_find_hdr(req,
                                                 PJSIP_H_AUTHORIZATION,
                                                 NULL);
  if ((auth_hdr != NULL) &&
      (auth_hdr->credential.digest.username.slen != 0))
  {
    // Get the IMPI from the username.
    impi = PJUtils::pj_str_to_string(&auth_hdr->credential.digest.username);
  }
  else
  {
    // Create a default IMPI from the IMPU by removing the sip: prefix.
    impi = impu.substr(4);
  }

  // Get the visited network identification if present.  If not, warn
  // (because a spec-compliant P-CSCF should default it) and use a
  // sensible default.
  pjsip_generic_string_hdr* vn_hdr =
    (pjsip_generic_string_hdr*)pjsip_msg_find_hdr_by_name(req,
                                                          &STR_P_V_N_I,
                                                          NULL);

  if (vn_hdr != NULL)
  {
    visited_network = PJUtils::pj_str_to_string(&vn_hdr->hvalue);
  }
  else if (PJSIP_URI_SCHEME_IS_SIP(to_uri) || PJSIP_URI_SCHEME_IS_SIPS(to_uri))
  {
    // Use the domain of the IMPU as the visited network.
    visited_network = PJUtils::pj_str_to_string(&((pjsip_sip_uri*)to_uri)->host);
    TRC_WARNING("No P-Visited-Network-ID in REGISTER - using %s as a default",
                visited_network.c_str());
  }

  // Work out what authorization type to use by looking at the expiry
  // values in the request.  (Use a default of 1 because if there is no
  // expires header or expires values in the contact headers this will
  // be a registration not a deregistration.)
  auth_type = PJUtils::is_deregistration(req) ? "DEREG" : "REG";

  // Remove any Route headers present on the request as we're re-routing the
  // message.
  pj_str_t route_hdr_name = pj_str((char *)"Route");
  PJUtils::remove_hdr(req, &route_hdr_name);

  // Check if this is an emergency registration. This is true if any of the
  // contact headers in the message contain the "sos" parameter.
  bool emergency = false;
  pjsip_contact_hdr* contact_hdr = (pjsip_contact_hdr*)pjsip_msg_find_hdr(req,
                                                                          PJSIP_H_CONTACT,
                                                                          NULL);
  while (contact_hdr != NULL)
  {
    if (PJUtils::is_emergency_registration(contact_hdr))
    {
      emergency = true;
      break;
    }

    contact_hdr = (pjsip_contact_hdr*) pjsip_msg_find_hdr(req,
                                                          PJSIP_H_CONTACT,
                                                          contact_hdr->next);
  }

  // Create an UAR router to handle the HSS interactions and S-CSCF
  // selection.
  _router = (ICSCFRouter*)new ICSCFUARouter(_icscf->get_hss_connection(),
                                            _icscf->get_scscf_selector(),
                                            trail(),
                                            _acr,
                                            _icscf->port(),
                                            impi,
                                            impu,
                                            visited_network,
                                            auth_type,
                                            emergency);

  // We have a router, query it for an S-CSCF to use.
  pjsip_sip_uri* scscf_sip_uri = NULL;
  std::string dummy_wildcard;
  pjsip_status_code status_code =
    (pjsip_status_code)_router->get_scscf(get_pool(req),
                                          scscf_sip_uri,
                                          dummy_wildcard);

  if (status_code == PJSIP_SC_OK)
  {
    TRC_DEBUG("Found SCSCF for REGISTER");
    req->line.req.uri = (pjsip_uri*)scscf_sip_uri;
    send_request(req);
  }
  else
  {
    pjsip_msg* rsp = create_response(req, status_code);
    send_response(rsp);
    free_msg(req);
  }
}
Exemple #19
0
static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata)
{
	char local_buf[256];
	char remote_buf[256];
	char *uuid;
	struct hepv3_capture_info *capture_info;
	pjsip_cid_hdr *cid_hdr;
	pjsip_from_hdr *from_hdr;
	pjsip_to_hdr *to_hdr;

	capture_info = hepv3_create_capture_info(tdata->buf.start, (size_t)(tdata->buf.cur - tdata->buf.start));
	if (!capture_info) {
		return PJ_SUCCESS;
	}

	if (!(tdata->tp_info.transport->flag & PJSIP_TRANSPORT_RELIABLE)) {
		pjsip_tpmgr_fla2_param prm;

		/* Attempt to determine what IP address will we send this packet out of */
		pjsip_tpmgr_fla2_param_default(&prm);
		prm.tp_type = tdata->tp_info.transport->key.type;
		pj_strset2(&prm.dst_host, tdata->tp_info.dst_name);
		prm.local_if = PJ_TRUE;

		/* If we can't get the local address use what we have already */
		if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), tdata->pool, &prm) != PJ_SUCCESS) {
			pj_sockaddr_print(&tdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3);
		} else {
			if (prm.tp_type & PJSIP_TRANSPORT_IPV6) {
				snprintf(local_buf, sizeof(local_buf), "[%.*s]:%hu",
					(int)pj_strlen(&prm.ret_addr),
					pj_strbuf(&prm.ret_addr),
					prm.ret_port);
			} else {
				snprintf(local_buf, sizeof(local_buf), "%.*s:%hu",
					(int)pj_strlen(&prm.ret_addr),
					pj_strbuf(&prm.ret_addr),
					prm.ret_port);
			}
		}
	} else {
		/* For reliable transports they can only ever come from the transport
		 * local address.
		 */
		pj_sockaddr_print(&tdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3);
	}

	pj_sockaddr_print(&tdata->tp_info.dst_addr, remote_buf, sizeof(remote_buf), 3);

	cid_hdr = PJSIP_MSG_CID_HDR(tdata->msg);
	from_hdr = PJSIP_MSG_FROM_HDR(tdata->msg);
	to_hdr = PJSIP_MSG_TO_HDR(tdata->msg);

	uuid = assign_uuid(&cid_hdr->id, &to_hdr->tag, &from_hdr->tag);
	if (!uuid) {
		ao2_ref(capture_info, -1);
		return PJ_SUCCESS;
	}

	ast_sockaddr_parse(&capture_info->src_addr, local_buf, PARSE_PORT_REQUIRE);
	ast_sockaddr_parse(&capture_info->dst_addr, remote_buf, PARSE_PORT_REQUIRE);

	capture_info->protocol_id = transport_to_protocol_id(tdata->tp_info.transport);
	capture_info->capture_time = ast_tvnow();
	capture_info->capture_type = HEPV3_CAPTURE_TYPE_SIP;
	capture_info->uuid = uuid;
	capture_info->zipped = 0;

	hepv3_send_packet(capture_info);

	return PJ_SUCCESS;
}
Exemple #20
0
// Determine whether this request should be challenged (and SAS log appropriately).
static pj_bool_t needs_authentication(pjsip_rx_data* rdata, SAS::TrailId trail)
{
  if (rdata->tp_info.transport->local_name.port != stack_data.scscf_port)
  {
    TRC_DEBUG("Request does not need authentication - not on S-CSCF port");
    // Request not received on S-CSCF port, so don't authenticate it.
    SAS::Event event(trail, SASEvent::AUTHENTICATION_NOT_NEEDED_NOT_SCSCF_PORT, 0);
    SAS::report_event(event);

    return PJ_FALSE;
  }

  if (rdata->msg_info.msg->line.req.method.id == PJSIP_REGISTER_METHOD)
  {
    // Authentication isn't required for emergency registrations. An emergency
    // registration is one where each Contact header contains 'sos' as the SIP
    // URI parameter.
    bool emergency_reg = true;

    pjsip_contact_hdr* contact_hdr = (pjsip_contact_hdr*)
      pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, NULL);

    while ((contact_hdr != NULL) && (emergency_reg))
    {
      emergency_reg = PJUtils::is_emergency_registration(contact_hdr);
      contact_hdr = (pjsip_contact_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg,
                                                            PJSIP_H_CONTACT,
                                                            contact_hdr->next);
    }

    if (emergency_reg)
    {
      SAS::Event event(trail, SASEvent::AUTHENTICATION_NOT_NEEDED_EMERGENCY_REGISTER, 0);
      SAS::report_event(event);

      return PJ_FALSE;
    }

    // Check to see if the request has already been integrity protected?
    pjsip_authorization_hdr* auth_hdr = (pjsip_authorization_hdr*)
      pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_AUTHORIZATION, NULL);

    if (auth_hdr != NULL)
    {
      // There is an authorization header, so check for the integrity-protected
      // indication.
      TRC_DEBUG("Authorization header in request");
      pjsip_param* integrity =
        pjsip_param_find(&auth_hdr->credential.digest.other_param,
                         &STR_INTEGRITY_PROTECTED);

      if ((integrity != NULL) &&
          ((pj_stricmp(&integrity->value, &STR_TLS_YES) == 0) ||
           (pj_stricmp(&integrity->value, &STR_IP_ASSOC_YES) == 0)))
      {
        // The integrity protected indicator is included and set to tls-yes or
        // ip-assoc-yes.  This indicates the client has already been authenticated
        // so we will accept this REGISTER even if there is a challenge response.
        // (Values of tls-pending or ip-assoc-pending indicate the challenge
        // should be checked.)
        TRC_INFO("SIP Digest authenticated request integrity protected by edge proxy");

        SAS::Event event(trail, SASEvent::AUTHENTICATION_NOT_NEEDED_INTEGRITY_PROTECTED, 0);
        SAS::report_event(event);

        return PJ_FALSE;
      }
      else if ((integrity != NULL) &&
               (pj_stricmp(&integrity->value, &STR_YES) == 0) &&
               (auth_hdr->credential.digest.response.slen == 0))
      {
        // The integrity protected indicator is include and set to yes.  This
        // indicates that AKA authentication is in use and the REGISTER was
        // received on an integrity protected channel, so we will let the
        // request through if there is no challenge response, but must check
        // the challenge response if included.
        TRC_INFO("AKA authenticated request integrity protected by edge proxy");

        SAS::Event event(trail, SASEvent::AUTHENTICATION_NOT_NEEDED_INTEGRITY_PROTECTED, 1);
        SAS::report_event(event);

        return PJ_FALSE;
      }
    }

    return PJ_TRUE;
  }
  else
  {
    if (PJSIP_MSG_TO_HDR(rdata->msg_info.msg)->tag.slen != 0)
    {
      // This is an in-dialog request which needs no authentication.
      return PJ_FALSE;
    }

    // Check to see if we should authenticate this non-REGISTER message - this
    if (non_register_auth_mode == NonRegisterAuthentication::NEVER)
    {
      // Configured to never authenticate non-REGISTER requests.
      SAS::Event event(trail, SASEvent::AUTHENTICATION_NOT_NEEDED_NEVER_AUTH_NON_REG, 0);
      SAS::report_event(event);
      return PJ_FALSE;
    }
    else if (non_register_auth_mode == NonRegisterAuthentication::IF_PROXY_AUTHORIZATION_PRESENT)
    {
      // Only authenticate the request if it has a Proxy-Authorization header.
      pjsip_proxy_authorization_hdr* auth_hdr = (pjsip_proxy_authorization_hdr*)
        pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_PROXY_AUTHORIZATION, NULL);

      if (auth_hdr != NULL)
      {
        // Edge proxy has explicitly asked us to authenticate this non-REGISTER
        // message
        SAS::Event event(trail, SASEvent::AUTHENTICATION_NEEDED_PROXY_AUTHORIZATION, 0);
        SAS::report_event(event);
        return PJ_TRUE;
      }
      else
      {
        // No Proxy-Authorization header - this indicates the P-CSCF trusts this
        // message so we don't need to perform further authentication.
        SAS::Event event(trail, SASEvent::AUTHENTICATION_NOT_NEEDED_PROXY_AUTHORIZATION, 0);
        SAS::report_event(event);
        return PJ_FALSE;
      }
    }
    else
    {
      // Unrecognized authentication mode - should never happen. LCOV_EXCL_START
      assert(!"Unrecognized authentication mode");
      return PJ_FALSE;
      // LCOV_EXCL_STOP
    }
  }
}