Пример #1
0
// Determine the type of a URI.
//
// Parameters:
//
// - uri - the URI to classify
// - prefer_sip - for ambiguous URIs like sip:[email protected] (which could be a global phone
// number or just a SIP URI), prefer to interpret it as SIP
// - check_np - check for the presence of Number Portability parameters and
// classify accordingly
//
URIClass URIClassifier::classify_uri(const pjsip_uri* uri, bool prefer_sip, bool check_np)
{
  URIClass ret = URIClass::UNKNOWN;

  // First, check to see if this URI has number portability data - this takes priority
  bool has_rn = false;
  bool has_npdi = false;

  if (check_np)
  {
    if (PJSIP_URI_SCHEME_IS_TEL(uri))
    {
      // If the URI is a tel URI, pull out the information from the other_params
      has_rn = (pjsip_param_find(&((pjsip_tel_uri*)uri)->other_param, &STR_RN) != NULL);
      has_npdi = (pjsip_param_find(&((pjsip_tel_uri*)uri)->other_param, &STR_NPDI) != NULL);
    }
    else if (PJSIP_URI_SCHEME_IS_SIP(uri))
    {
      // If the URI is a tel URI, pull out the information from the userinfo_params
      has_rn = (pjsip_param_find(&((pjsip_sip_uri*)uri)->userinfo_param, &STR_RN) != NULL);
      has_npdi = (pjsip_param_find(&((pjsip_sip_uri*)uri)->userinfo_param, &STR_NPDI) != NULL);
    }
  }

  if (has_rn)
  {
    if (has_npdi)
    {
      ret = FINAL_NP_DATA;
    }
    else
    {
      ret = NP_DATA;
    }
  }
  // No number portability data
  else if (PJSIP_URI_SCHEME_IS_TEL(uri))
  {
    // TEL URIs can only represent phone numbers - decide if it's a global (E.164) number or not
    pjsip_tel_uri* tel_uri = (pjsip_tel_uri*)uri;
    std::string user = PJUtils::pj_str_to_string(&tel_uri->number);
    boost::match_results<std::string::const_iterator> results;
    if (boost::regex_match(user, results, CHARS_ALLOWED_IN_GLOBAL_NUM))
    {
      ret = GLOBAL_PHONE_NUMBER;
    }
    else
    {
      ret = enforce_global ? LOCAL_PHONE_NUMBER : GLOBAL_PHONE_NUMBER;
    }
  }
  else if (PJSIP_URI_SCHEME_IS_SIP(uri))
  {
    pjsip_sip_uri* sip_uri = (pjsip_sip_uri*)uri;
    pj_str_t host = sip_uri->host;
    bool home_domain = is_home_domain(host);
    bool local_to_node = is_local_name(host);
    bool is_gruu = (pjsip_param_find(&((pjsip_sip_uri*)uri)->other_param, &STR_GR) != NULL);
    bool treat_number_as_phone = !enforce_user_phone && !prefer_sip;

    TRC_DEBUG("home domain: %s, local_to_node: %s, is_gruu: %s, enforce_user_phone: %s, prefer_sip: %s, treat_number_as_phone: %s",
              home_domain ? "true" : "false",
              local_to_node ? "true" : "false",
              is_gruu ? "true" : "false",
              enforce_user_phone ? "true" : "false",
              prefer_sip ? "true" : "false",
              treat_number_as_phone ? "true" : "false");

    bool classified = false;
    // SIP URI that's 'really' a phone number - apply the same logic as for TEL URIs
    if ((!pj_strcmp(&((pjsip_sip_uri*)uri)->user_param, &STR_USER_PHONE) ||
         (home_domain && treat_number_as_phone && !is_gruu)))
    {
      // Get the user part minus any parameters.
      std::string user = PJUtils::pj_str_to_string(&sip_uri->user);
      if (!user.empty())
      {
        std::vector<std::string> user_tokens;
        Utils::split_string(user, ';', user_tokens, 0, true);
        boost::match_results<std::string::const_iterator> results;
        if (boost::regex_match(user_tokens[0], results, CHARS_ALLOWED_IN_GLOBAL_NUM))
        {
          ret = GLOBAL_PHONE_NUMBER;
          classified = true;
        }
        else if (boost::regex_match(user_tokens[0], results, CHARS_ALLOWED_IN_LOCAL_NUM))
        {
          ret = enforce_global ? LOCAL_PHONE_NUMBER : GLOBAL_PHONE_NUMBER;
          classified = true;
        }
      }
    }
    if (!classified)
    {
      // Not a phone number - classify it based on domain
      ret = (home_domain) ? HOME_DOMAIN_SIP_URI : ((local_to_node) ? NODE_LOCAL_SIP_URI : OFFNET_SIP_URI);
    }
  }

  std::string uri_str = PJUtils::uri_to_string(PJSIP_URI_IN_OTHER, uri);
  TRC_DEBUG("Classified URI %s as %d", uri_str.c_str(), (int)ret);
  return ret;
}
Пример #2
0
static pj_status_t pjsip_url_compare( pjsip_uri_context_e context,
                                      const pjsip_sip_uri *url1,
                                      const pjsip_sip_uri *url2)
{
    const pjsip_param *p1;

    /*
     * Compare two SIP URL's according to Section 19.1.4 of RFC 3261.
     */

    /* SIP and SIPS URI are never equivalent.
     * Note: just compare the vptr to avoid string comparison.
     *       Pretty neat huh!!
     */
    if (url1->vptr != url2->vptr)
        return PJSIP_ECMPSCHEME;

    /* Comparison of the userinfo of SIP and SIPS URIs is case-sensitive.
     * This includes userinfo containing passwords or formatted as
     * telephone-subscribers.
     */
    if (pj_strcmp(&url1->user, &url2->user) != 0)
        return PJSIP_ECMPUSER;
    if (pj_strcmp(&url1->passwd, &url2->passwd) != 0)
        return PJSIP_ECMPPASSWD;

    /* Comparison of all other components of the URI is
     * case-insensitive unless explicitly defined otherwise.
     */

    /* The ordering of parameters and header fields is not significant
     * in comparing SIP and SIPS URIs.
     */

    /* Characters other than those in the reserved set (see RFC 2396 [5])
     * are equivalent to their encoding.
     */

    /* An IP address that is the result of a DNS lookup of a host name
     * does not match that host name.
     */
    if (pj_stricmp(&url1->host, &url2->host) != 0)
        return PJSIP_ECMPHOST;

    /* A URI omitting any component with a default value will not match a URI
     * explicitly containing that component with its default value.
     * For instance, a URI omitting the optional port component will not match
     * a URI explicitly declaring port 5060.
     * The same is true for the transport-parameter, ttl-parameter,
     * user-parameter, and method components.
     */

    /* Port is not allowed in To and From header.
     */
    if (context != PJSIP_URI_IN_FROMTO_HDR) {
        if (url1->port != url2->port)
            return PJSIP_ECMPPORT;
    }
    /* Transport is not allowed in From/To header. */
    if (context != PJSIP_URI_IN_FROMTO_HDR) {
        if (pj_stricmp(&url1->transport_param, &url2->transport_param) != 0)
            return PJSIP_ECMPTRANSPORTPRM;
    }
    /* TTL param is not allowed in From, To, Route, and Record-Route header. */
    if (context != PJSIP_URI_IN_FROMTO_HDR &&
            context != PJSIP_URI_IN_ROUTING_HDR)
    {
        if (url1->ttl_param != url2->ttl_param)
            return PJSIP_ECMPTTLPARAM;
    }
    /* User param is allowed in all contexes */
    if (pj_stricmp(&url1->user_param, &url2->user_param) != 0)
        return PJSIP_ECMPUSERPARAM;
    /* Method param is only allowed in external/other context. */
    if (context == PJSIP_URI_IN_OTHER) {
        if (pj_stricmp(&url1->method_param, &url2->method_param) != 0)
            return PJSIP_ECMPMETHODPARAM;
    }
    /* maddr param is not allowed in From and To header. */
    if (context != PJSIP_URI_IN_FROMTO_HDR) {
        if (pj_stricmp(&url1->maddr_param, &url2->maddr_param) != 0)
            return PJSIP_ECMPMADDRPARAM;
    }

    /* lr parameter is ignored (?) */
    /* lr param is not allowed in From, To, and Contact header. */


    /* All other uri-parameters appearing in only one URI are ignored when
     * comparing the URIs.
     */
    if (pjsip_param_cmp(&url1->other_param, &url2->other_param, 1)!=0)
        return PJSIP_ECMPOTHERPARAM;

    /* URI header components are never ignored. Any present header component
     * MUST be present in both URIs and match for the URIs to match.
     * The matching rules are defined for each header field in Section 20.
     */
    p1 = url1->header_param.next;
    while (p1 != &url1->header_param) {
        const pjsip_param *p2;
        p2 = pjsip_param_find(&url2->header_param, &p1->name);
        if (p2) {
            /* It seems too much to compare two header params according to
             * the rule of each header. We'll just compare them string to
             * string..
             */
            if (pj_stricmp(&p1->value, &p2->value) != 0)
                return PJSIP_ECMPHEADERPARAM;
        } else {
            return PJSIP_ECMPHEADERPARAM;
        }
        p1 = p1->next;
    }

    /* Equal!! Pheuww.. */
    return PJ_SUCCESS;
}
Пример #3
0
/* This tests the request creating functions against the following
 * requirements:
 *  - header params in URI creates header in the request.
 *  - method and headers params are correctly shown or hidden in
 *    request URI, From, To, and Contact header.
 */
static int txdata_test_uri_params(void)
{
    char msgbuf[512];
    pj_str_t target = pj_str("sip:alice@wonderland:5061;x-param=param%201"
			     "?X-Hdr-1=Header%201"
			     "&X-Empty-Hdr=");
    pj_str_t contact;
    pj_str_t pname = pj_str("x-param");
    pj_str_t hname = pj_str("X-Hdr-1");
    pj_str_t hemptyname = pj_str("X-Empty-Hdr");
    pjsip_from_hdr *from_hdr;
    pjsip_to_hdr *to_hdr;
    pjsip_contact_hdr *contact_hdr;
    pjsip_generic_string_hdr *hdr;
    pjsip_tx_data *tdata;
    pjsip_sip_uri *uri;
    pjsip_param *param;
    pjsip_via_hdr *via;
    pjsip_parser_err_report err_list;
    pjsip_msg *msg;
    int len;
    pj_status_t status;

    PJ_LOG(3,(THIS_FILE, "   header param in URI to create request"));

    /* Due to #930, contact argument is now parsed as Contact header, so
     * must enclose it with <> to make it be parsed as URI.
     */
    pj_ansi_snprintf(msgbuf, sizeof(msgbuf), "<%.*s>",
		     (int)target.slen, target.ptr);
    contact.ptr = msgbuf;
    contact.slen = strlen(msgbuf);

    /* Create request with header param in target URI. */
    status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, &target,
					&target, &target, &contact, NULL, -1,
					NULL, &tdata);
    if (status != 0) {
	app_perror("   error: Unable to create request", status);
	return -200;
    }

    /* Fill up the Via header to prevent syntax error on parsing */
    via = (pjsip_via_hdr*) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
    via->transport = pj_str("TCP");
    via->sent_by.host = pj_str("127.0.0.1");

    /* Print and parse the request.
     * We'll check that header params are not present in
     */
    len = pjsip_msg_print(tdata->msg, msgbuf, sizeof(msgbuf));
    if (len < 1) {
	PJ_LOG(3,(THIS_FILE, "   error: printing message"));
	pjsip_tx_data_dec_ref(tdata);
	return -250;
    }
    msgbuf[len] = '\0';

    PJ_LOG(5,(THIS_FILE, "%d bytes request created:--begin-msg--\n"
			 "%s\n"
			 "--end-msg--", len, msgbuf));

    /* Now parse the message. */
    pj_list_init(&err_list);
    msg = pjsip_parse_msg( 0, tdata->pool, msgbuf, len, &err_list);
    if (msg == NULL) {
	pjsip_parser_err_report *e;

	PJ_LOG(3,(THIS_FILE, "   error: parsing message message"));

	e = err_list.next;
	while (e != &err_list) {
	    PJ_LOG(3,(THIS_FILE, "     %s in line %d col %d hname=%.*s",
				 pj_exception_id_name(0, e->except_code),
				 e->line, e->col+1,
				 (int)e->hname.slen,
				 e->hname.ptr));
	    e = e->next;
	}

	pjsip_tx_data_dec_ref(tdata);
	return -256;
    }

    /* Check the existence of port, other_param, and header param.
     * Port is now allowed in To and From header.
     */
    /* Port in request URI. */
    uri = (pjsip_sip_uri*) pjsip_uri_get_uri(msg->line.req.uri);
    if (uri->port != 5061) {
	PJ_LOG(3,(THIS_FILE, "   error: port not present in request URI"));
	pjsip_tx_data_dec_ref(tdata);
	return -260;
    }
    /* other_param in request_uri */
    param = pjsip_param_find(&uri->other_param, &pname);
    if (param == NULL || pj_strcmp2(&param->value, "param 1") != 0) {
	PJ_LOG(3,(THIS_FILE, "   error: x-param not present in request URI"));
	pjsip_tx_data_dec_ref(tdata);
	return -261;
    }
    /* header param in request uri. */
    if (!pj_list_empty(&uri->header_param)) {
	PJ_LOG(3,(THIS_FILE, "   error: hparam in request URI"));
	pjsip_tx_data_dec_ref(tdata);
	return -262;
    }

    /* Port in From header. */
    from_hdr = (pjsip_from_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_FROM, NULL);
    uri = (pjsip_sip_uri*) pjsip_uri_get_uri(from_hdr->uri);
    if (uri->port != 0) {
	PJ_LOG(3,(THIS_FILE, "   error: port most not exist in From header"));
	pjsip_tx_data_dec_ref(tdata);
	return -270;
    }
    /* other_param in From header */
    param = pjsip_param_find(&uri->other_param, &pname);
    if (param == NULL || pj_strcmp2(&param->value, "param 1") != 0) {
	PJ_LOG(3,(THIS_FILE, "   error: x-param not present in From header"));
	pjsip_tx_data_dec_ref(tdata);
	return -271;
    }
    /* header param in From header. */
    if (!pj_list_empty(&uri->header_param)) {
	PJ_LOG(3,(THIS_FILE, "   error: hparam in From header"));
	pjsip_tx_data_dec_ref(tdata);
	return -272;
    }


    /* Port in To header. */
    to_hdr = (pjsip_to_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_TO, NULL);
    uri = (pjsip_sip_uri*) pjsip_uri_get_uri(to_hdr->uri);
    if (uri->port != 0) {
	PJ_LOG(3,(THIS_FILE, "   error: port most not exist in To header"));
	pjsip_tx_data_dec_ref(tdata);
	return -280;
    }
    /* other_param in To header */
    param = pjsip_param_find(&uri->other_param, &pname);
    if (param == NULL || pj_strcmp2(&param->value, "param 1") != 0) {
	PJ_LOG(3,(THIS_FILE, "   error: x-param not present in To header"));
	pjsip_tx_data_dec_ref(tdata);
	return -281;
    }
    /* header param in From header. */
    if (!pj_list_empty(&uri->header_param)) {
	PJ_LOG(3,(THIS_FILE, "   error: hparam in To header"));
	pjsip_tx_data_dec_ref(tdata);
	return -282;
    }



    /* Port in Contact header. */
    contact_hdr = (pjsip_contact_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, NULL);
    uri = (pjsip_sip_uri*) pjsip_uri_get_uri(contact_hdr->uri);
    if (uri->port != 5061) {
	PJ_LOG(3,(THIS_FILE, "   error: port not present in Contact header"));
	pjsip_tx_data_dec_ref(tdata);
	return -290;
    }
    /* other_param in Contact header */
    param = pjsip_param_find(&uri->other_param, &pname);
    if (param == NULL || pj_strcmp2(&param->value, "param 1") != 0) {
	PJ_LOG(3,(THIS_FILE, "   error: x-param not present in Contact header"));
	pjsip_tx_data_dec_ref(tdata);
	return -291;
    }
    /* header param in Contact header. */
    if (pj_list_empty(&uri->header_param)) {
	PJ_LOG(3,(THIS_FILE, "   error: hparam is missing in Contact header"));
	pjsip_tx_data_dec_ref(tdata);
	return -292;
    }
    /* Check for X-Hdr-1 */
    param = pjsip_param_find(&uri->header_param, &hname);
    if (param == NULL || pj_strcmp2(&param->value, "Header 1")!=0) {
	PJ_LOG(3,(THIS_FILE, "   error: hparam is missing in Contact header"));
	pjsip_tx_data_dec_ref(tdata);
	return -293;
    }
    /* Check for X-Empty-Hdr */
    param = pjsip_param_find(&uri->header_param, &hemptyname);
    if (param == NULL || pj_strcmp2(&param->value, "")!=0) {
	PJ_LOG(3,(THIS_FILE, "   error: hparam is missing in Contact header"));
	pjsip_tx_data_dec_ref(tdata);
	return -294;
    }


    /* Check that headers are present in the request. */
    hdr = (pjsip_generic_string_hdr*) 
	pjsip_msg_find_hdr_by_name(msg, &hname, NULL);
    if (hdr == NULL || pj_strcmp2(&hdr->hvalue, "Header 1")!=0) {
	PJ_LOG(3,(THIS_FILE, "   error: header X-Hdr-1 not created"));
	pjsip_tx_data_dec_ref(tdata);
	return -300;
    }

    hdr = (pjsip_generic_string_hdr*) 
	pjsip_msg_find_hdr_by_name(msg, &hemptyname, NULL);
    if (hdr == NULL || pj_strcmp2(&param->value, "")!=0) {
	PJ_LOG(3,(THIS_FILE, "   error: header X-Empty-Hdr not created"));
	pjsip_tx_data_dec_ref(tdata);
	return -330;
    }

    pjsip_tx_data_dec_ref(tdata);
    return 0;
}
Пример #4
0
void ICSCFSproutletTsx::on_rx_initial_request(pjsip_msg* req)
{
  pj_pool_t* pool = get_pool(req);

  pjsip_route_hdr* hroute = (pjsip_route_hdr*)
                                pjsip_msg_find_hdr(req, PJSIP_H_ROUTE, NULL);

  // TS 24.229 says I-CSCF processing shouldn't be done if a message has more than one Route header.
  // We've stripped one off in Sproutlet processing, so check for a second and just forward the
  // message if it's there.
  if (hroute != NULL)
  {
    send_request(req);
    return;
  }

  pjsip_uri* next_hop = PJUtils::next_hop(req);
  URIClass next_hop_class = URIClassifier::classify_uri(next_hop);
  if (req->line.req.method.id == PJSIP_ACK_METHOD &&
      next_hop == req->line.req.uri &&
      ((next_hop_class == NODE_LOCAL_SIP_URI) ||
       (next_hop_class == HOME_DOMAIN_SIP_URI)))
  {
    // Ignore ACK messages with no Route headers and a local Request-URI, as:
    // - the I-CSCF should not be handling these
    // - we've seen ACKs matching this descrption being generated at overload and looping repeatedly
    //
    // This is a fairly targeted fix for https://github.com/Metaswitch/sprout/issues/1091.
    // TODO: remove this code when #1091 is fixed by other means.
    free_msg(req);
    return;
  }

  // Create an ACR for this transaction.
  _acr = _icscf->get_acr(trail());
  _acr->rx_request(req);

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

  // Before we clone the request for retries, remove the P-Profile-Key header
  // if present.
  PJUtils::remove_hdr(req, &STR_P_PROFILE_KEY);

  // Determine orig/term and the served user's name.
  const pjsip_route_hdr* route = route_hdr();
  std::string impu;

  if ((route != NULL) &&
      (pjsip_param_find(&((pjsip_sip_uri*)route->name_addr.uri)->other_param,
                        &STR_ORIG) != NULL))
  {
    // Originating request.
    TRC_DEBUG("Originating request");
    _originating = true;
    impu = PJUtils::public_id_from_uri(PJUtils::orig_served_user(req));

    SAS::Event event(trail(), SASEvent::ICSCF_RCVD_ORIG_NON_REG, 0);
    event.add_var_param(impu);
    event.add_var_param(req->line.req.method.name.slen,
                        req->line.req.method.name.ptr);
    SAS::report_event(event);
  }
  else
  {
    // Terminating request.
    TRC_DEBUG("Terminating request");
    _originating = false;
    pjsip_uri* uri = PJUtils::term_served_user(req);

    // If the Req URI is a SIP URI with the user=phone parameter set, is not a
    // GRUU and the user part starts with '+' (i.e. is a global phone number),
    // we should replace it with a tel URI, as per TS24.229 5.3.2.1.
    if (PJSIP_URI_SCHEME_IS_SIP(uri))
    {
      URIClass uri_class = URIClassifier::classify_uri(uri);
      pjsip_sip_uri* sip_uri = (pjsip_sip_uri*)uri;

      if (uri_class == GLOBAL_PHONE_NUMBER)
      {
        TRC_DEBUG("Change request URI from SIP URI to tel URI");
        req->line.req.uri =
          PJUtils::translate_sip_uri_to_tel_uri(sip_uri, pool);
      }
    }

    impu = PJUtils::public_id_from_uri(PJUtils::term_served_user(req));

    SAS::Event event(trail(), SASEvent::ICSCF_RCVD_TERM_NON_REG, 0);
    event.add_var_param(impu);
    event.add_var_param(req->line.req.method.name.slen,
                        req->line.req.method.name.ptr);
    SAS::report_event(event);
  }

  // Create an LIR router to handle the HSS interactions and S-CSCF
  // selection.
  _router = (ICSCFRouter*)new ICSCFLIRouter(_icscf->get_hss_connection(),
                                            _icscf->get_scscf_selector(),
                                            trail(),
                                            _acr,
                                            _icscf->port(),
                                            impu,
                                            _originating);

  pjsip_sip_uri* scscf_sip_uri = NULL;

  // Use the router we just created to query the HSS for an S-CSCF to use.
  // TS 32.260 Table 5.2.1.1 says an EVENT ACR should be generated on the
  // completion of a Cx query issued in response to a SIP INVITE
  bool do_billing = (req->line.req.method.id == PJSIP_INVITE_METHOD);
  std::string wildcard;
  pjsip_status_code status_code =
    (pjsip_status_code)_router->get_scscf(pool,
                                          scscf_sip_uri,
                                          wildcard,
                                          do_billing);

  if ((!_originating) && (scscf_not_found(status_code)))
  {
    TRC_DEBUG("Couldn't find an S-CSCF, attempt to translate the URI");
    pjsip_uri* uri = PJUtils::term_served_user(req);
    URIClass uri_class = URIClassifier::classify_uri(uri, false);

    // For terminating processing, if the HSS indicates that the user does not
    // exist, and if the request URI is a tel URI, try an ENUM translation. If
    // this succeeds, go back to the HSS. See TS24.229, 5.3.2.1.
    //
    // Before doing that we should check whether the enforce_user_phone flag is
    // set. If it isn't, and we have a numeric SIP URI, it is possible that
    // this should have been a tel URI, so translate it and do the HSS lookup
    // again.  Once again, only do this for global numbers.
    if (PJSIP_URI_SCHEME_IS_SIP(uri) && (uri_class == GLOBAL_PHONE_NUMBER))
    {
      TRC_DEBUG("enforce_user_phone set to false, try using a tel URI");
      uri = PJUtils::translate_sip_uri_to_tel_uri((pjsip_sip_uri*)uri, pool);
      req->line.req.uri = uri;

      // We need to change the IMPU stored on our LIR router so that when
      // we do a new LIR we look up the new IMPU.
      impu = PJUtils::public_id_from_uri(PJUtils::term_served_user(req));
      ((ICSCFLIRouter *)_router)->change_impu(impu);
      status_code = (pjsip_status_code)_router->get_scscf(pool,
                                                          scscf_sip_uri,
                                                          wildcard,
                                                          do_billing);
    }

    if (_icscf->_enum_service)
    {
      // If we still haven't found an S-CSCF, we can now try an ENUM lookup.
      // We put this processing in a loop because in theory we may go round
      // several times before finding an S-CSCF. In reality this is unlikely
      // so we set MAX_ENUM_LOOKUPS to 2.
      for (int ii = 0;
           (ii < MAX_ENUM_LOOKUPS) && (scscf_not_found(status_code));
           ++ii)
      {
        if (PJSIP_URI_SCHEME_IS_TEL(uri))
        {
          // Do an ENUM lookup and see if we should translate the TEL URI
          pjsip_uri* original_req_uri = req->line.req.uri;
          _icscf->translate_request_uri(req, get_pool(req), trail());
          uri = req->line.req.uri;
          URIClass uri_class = URIClassifier::classify_uri(uri, false, true);

          std::string rn;

          if ((uri_class == NP_DATA) ||
              (uri_class == FINAL_NP_DATA))
          {
            // We got number portability information from ENUM - drop out and route to the BGCF.
            route_to_bgcf(req);
            return;
          }
          else if (pjsip_uri_cmp(PJSIP_URI_IN_REQ_URI,
                                 original_req_uri,
                                 req->line.req.uri) != PJ_SUCCESS)
          {
            // The URI has changed, so make sure we do a LIR lookup on it.
            impu = PJUtils::public_id_from_uri(req->line.req.uri);
            ((ICSCFLIRouter *)_router)->change_impu(impu);
          }

          // If we successfully translate the req URI and end up with either another TEL URI or a
          // local SIP URI, we should look for an S-CSCF again.
          if ((uri_class == LOCAL_PHONE_NUMBER) ||
              (uri_class == GLOBAL_PHONE_NUMBER) ||
              (uri_class == HOME_DOMAIN_SIP_URI))
          {
            // TEL or local SIP URI.  Look up the S-CSCF again.
            status_code = (pjsip_status_code)_router->get_scscf(pool,
                                                                scscf_sip_uri,
                                                                wildcard,
                                                                do_billing);
          }
          else
          {
            // Number translated to off-switch.  Drop out of the loop.
            ii = MAX_ENUM_LOOKUPS;
          }
        }
        else
        {
          // Can't translate the number, skip to the end of the loop.
          ii = MAX_ENUM_LOOKUPS;
        }
      }
    }
    else
    {
      // The user is not in the HSS and ENUM is not configured. TS 24.229
      // says that, as an alternative to ENUM, we can "forward the request to
      // the transit functionality for subsequent routeing". Let's do that
      // (currently, we assume the BGCF is the transit functionality, but that
      // may be made configurable in future).
      TRC_DEBUG("No ENUM service available - outing request directly to transit function (BGCF)");
      route_to_bgcf(req);
      return;
    }
  }

  URIClass uri_class = URIClassifier::classify_uri(req->line.req.uri);
  if (status_code == PJSIP_SC_OK)
  {
    TRC_DEBUG("Found SCSCF for non-REGISTER");

    if (_originating)
    {
      // Add the `orig` parameter.
      pjsip_param* orig_param = PJ_POOL_ALLOC_T(get_pool(req), pjsip_param);
      pj_strdup(get_pool(req), &orig_param->name, &STR_ORIG);
      orig_param->value.slen = 0;
      pj_list_insert_after(&scscf_sip_uri->other_param, orig_param);
    }

    // Add the P-Profile-Key header here if we've got a wildcard
    if (wildcard != "")
    {
      add_p_profile_header(wildcard, req);
    }

    PJUtils::add_route_header(req, scscf_sip_uri, get_pool(req));
    send_request(req);
  }
  else if ((uri_class == OFFNET_SIP_URI) ||
           (uri_class == GLOBAL_PHONE_NUMBER))
  {
    // Target is a TEL URI or not in our home domain.  Pass to the BGCF.
    route_to_bgcf(req);
  }
  else
  {
    // Target is in our home domain, but we failed to find an S-CSCF. This is the final response.
    pjsip_msg* rsp = create_response(req, status_code);
    send_response(rsp);
    free_msg(req);
  }
}
Пример #5
0
/* Public function to parse multipart message bodies into its parts */
PJ_DEF(pjsip_msg_body*) pjsip_multipart_parse(pj_pool_t *pool,
					      char *buf, pj_size_t len,
					      const pjsip_media_type *ctype,
					      unsigned options)
{
    pj_str_t boundary, delim;
    char *curptr, *endptr;
    const pjsip_param *ctype_param;
    const pj_str_t STR_BOUNDARY = { "boundary", 8 };
    pjsip_msg_body *body = NULL;

    PJ_ASSERT_RETURN(pool && buf && len && ctype && !options, NULL);

    TRACE_((THIS_FILE, "Started parsing multipart body"));

    /* Get the boundary value in the ctype */
    boundary.ptr = NULL;
    boundary.slen = 0;
    ctype_param = pjsip_param_find(&ctype->param, &STR_BOUNDARY);
    if (ctype_param) {
	boundary = ctype_param->value;
	if (boundary.slen>2 && *boundary.ptr=='"') {
	    /* Remove quote */
	    boundary.ptr++;
	    boundary.slen -= 2;
	}
	TRACE_((THIS_FILE, "Boundary is specified: '%.*s'", (int)boundary.slen,
		boundary.ptr));
    }

    if (!boundary.slen) {
	/* Boundary not found or not specified. Try to be clever, get
	 * the boundary from the body.
	 */
	char *p=buf, *end=buf+len;

	PJ_LOG(4,(THIS_FILE, "Warning: boundary parameter not found or "
			     "not specified when parsing multipart body"));

	/* Find the first "--". This "--" must be right after a CRLF, unless
	 * it really appears at the start of the buffer.
	 */
	for (;;) {
	    while (p!=end && *p!='-') ++p;
	    if (p!=end && *(p+1)=='-' &&
		((p>buf && *(p-1)=='\n') || (p==buf)))
	    {
		p+=2;
		break;
	    } else {
		++p;
	    }
	}

	if (p==end) {
	    /* Unable to determine boundary. Maybe this is not a multipart
	     * message?
	     */
	    PJ_LOG(4,(THIS_FILE, "Error: multipart boundary not specified and"
				 " unable to calculate from the body"));
	    return NULL;
	}

	boundary.ptr = p;
	while (p!=end && !pj_isspace(*p)) ++p;
	boundary.slen = p - boundary.ptr;

	TRACE_((THIS_FILE, "Boundary is calculated: '%.*s'",
		(int)boundary.slen, boundary.ptr));
    }

    /* Build the delimiter:
     *   delimiter = "--" boundary
     */
    delim.slen = boundary.slen+2;
    delim.ptr = (char*)pj_pool_alloc(pool, (int)delim.slen);
    delim.ptr[0] = '-';
    delim.ptr[1] = '-';
    pj_memcpy(delim.ptr+2, boundary.ptr, boundary.slen);

    /* Start parsing the body, skip until the first delimiter. */
    curptr = buf;
    endptr = buf + len;
    {
	pj_str_t body;

	body.ptr = buf; body.slen = len;
	curptr = pj_strstr(&body, &delim);
	if (!curptr)
	    return NULL;
    }

    body = pjsip_multipart_create(pool, ctype, &boundary);

    for (;;) {
	char *start_body, *end_body;
	pjsip_multipart_part *part;

	/* Eat the boundary */
	curptr += delim.slen;
	if (*curptr=='-' && curptr<endptr-1 && *(curptr+1)=='-') {
	    /* Found the closing delimiter */
	    curptr += 2;
	    break;
	}
	/* Optional whitespace after delimiter */
	while (curptr!=endptr && IS_SPACE(*curptr)) ++curptr;
	/* Mandatory CRLF */
	if (*curptr=='\r') ++curptr;
	if (*curptr!='\n') {
	    /* Expecting a newline here */
	    return NULL;
	}
	++curptr;

	/* We now in the start of the body */
	start_body = curptr;

	/* Find the next delimiter */
	{
	    pj_str_t subbody;

	    subbody.ptr = curptr; subbody.slen = endptr - curptr;
	    curptr = pj_strstr(&subbody, &delim);
	    if (!curptr) {
		/* We're really expecting end delimiter to be found. */
		return NULL;
	    }
	}

	end_body = curptr;

	/* The newline preceeding the delimiter is conceptually part of
	 * the delimiter, so trim it from the body.
	 */
	if (*(end_body-1) == '\n')
	    --end_body;
	if (*(end_body-1) == '\r')
	    --end_body;

	/* Now that we have determined the part's boundary, parse it
	 * to get the header and body part of the part.
	 */
	part = parse_multipart_part(pool, start_body, end_body - start_body,
				    ctype);
	if (part) {
	    pjsip_multipart_add_part(pool, body, part);
	}
    }

    return body;
}
Пример #6
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;
}
Пример #7
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);
}
static pjsip_param *get_diversion_reason(pjsip_fromto_hdr *hdr)
{
	static const pj_str_t reason_str = { "reason", 6 };
	return pjsip_param_find(&hdr->other_param, &reason_str);
}
Пример #9
0
/// Creates a MangelwurzelTsx instance.
SproutletTsx* Mangelwurzel::get_tsx(SproutletHelper* helper,
                                    const std::string& alias,
                                    pjsip_msg* req,
                                    pjsip_sip_uri*& next_hop,
                                    pj_pool_t* pool,
                                    SAS::TrailId trail)
{
  MangelwurzelTsx::Config config;

  // Find the mangewurzel Route header, parse the parameters and use them to
  // build a Config object. Then construct the MangelwurzelTsx.
  pjsip_route_hdr* route_hdr = (pjsip_route_hdr*)
                                 pjsip_msg_find_hdr(req, PJSIP_H_ROUTE, NULL);
  pjsip_sip_uri* mangelwurzel_uri;

  if (route_hdr != NULL)
  {
    mangelwurzel_uri = (pjsip_sip_uri*)route_hdr->name_addr.uri;
  }
  else
  {
    mangelwurzel_uri = (pjsip_sip_uri*)req->line.req.uri;
  }

  if (pjsip_param_find(&mangelwurzel_uri->other_param, &DIALOG_PARAM) != NULL)
  {
    config.dialog = true;
  }
  if (pjsip_param_find(&mangelwurzel_uri->other_param, &REQ_URI_PARAM) != NULL)
  {
    config.req_uri = true;
  }
  if (pjsip_param_find(&mangelwurzel_uri->other_param, &TO_PARAM) != NULL)
  {
    config.to = true;
  }
  if (pjsip_param_find(&mangelwurzel_uri->other_param, &ROUTES_PARAM) != NULL)
  {
    config.routes = true;
  }
  if (pjsip_param_find(&mangelwurzel_uri->other_param, &DOMAIN_PARAM) != NULL)
  {
    config.change_domain = true;
  }
  if (pjsip_param_find(&mangelwurzel_uri->other_param, &ORIG_PARAM) != NULL)
  {
    config.orig = true;
  }
  if (pjsip_param_find(&mangelwurzel_uri->other_param, &OOTB_PARAM) != NULL)
  {
    config.ootb = true;
  }

  // The mangalgorithm defaults to ROT_13, so only change it if REVERSE is
  // specified, but raise a log if an invalid mangalgorithm is specified.
  pjsip_param* mangalgorithm_param =
    pjsip_param_find(&mangelwurzel_uri->other_param,
                     &MANGALGORITHM_PARAM);
  if (mangalgorithm_param != NULL)
  {
    std::string mangalgorithm =
      PJUtils::pj_str_to_string(&mangalgorithm_param->value);

    if (mangalgorithm == REVERSE_MANGALGORITHM)
    {
      config.mangalgorithm = MangelwurzelTsx::REVERSE;
    }
    else if (mangalgorithm != ROT_13_MANGALGORITHM)
    {
      TRC_ERROR("Invalid mangalgorithm specified: %s",
                mangalgorithm.c_str());
      SAS::Event event(trail, SASEvent::INVALID_MANGALGORITHM, 0);
      event.add_var_param(mangalgorithm);
      SAS::report_event(event);
    }
  }

  return new MangelwurzelTsx(this, config);
}
Пример #10
0
// Determine the type of a URI.
//
// Parameters:
//
// - uri - the URI to classify
// - prefer_sip - for ambiguous URIs like sip:[email protected] (which could be a global phone
// number or just a SIP URI), prefer to interpret it as SIP
//
URIClass URIClassifier::classify_uri(const pjsip_uri* uri, bool prefer_sip)
{
  URIClass ret = URIClass::UNKNOWN;

  // First, check to see if this URI has number portability data - this takes priority
  bool has_rn = false;
  bool has_npdi = false;

  if (PJSIP_URI_SCHEME_IS_TEL(uri))
  {
    // If the URI is a tel URI, pull out the information from the other_params
    has_rn = (pjsip_param_find(&((pjsip_tel_uri*)uri)->other_param, &STR_RN) != NULL);
    has_npdi = (pjsip_param_find(&((pjsip_tel_uri*)uri)->other_param, &STR_NPDI) != NULL);
  }
  else if (PJSIP_URI_SCHEME_IS_SIP(uri))
  {
    // If the URI is a tel URI, pull out the information from the userinfo_params
    has_rn = (pjsip_param_find(&((pjsip_sip_uri*)uri)->userinfo_param, &STR_RN) != NULL);
    has_npdi = (pjsip_param_find(&((pjsip_sip_uri*)uri)->userinfo_param, &STR_NPDI) != NULL);
  }

  if (has_rn)
  {
    if (has_npdi)
    {
      ret = FINAL_NP_DATA;
    }
    else
    {
      ret = NP_DATA;
    }
  }
  // No number portability data
  else if (PJSIP_URI_SCHEME_IS_TEL(uri))
  {
    // TEL URIs can only represent phone numbers - decide if it's a global (E.164) number or not
    pjsip_tel_uri* tel_uri = (pjsip_tel_uri*)uri;
    if (tel_uri->number.slen > 0 && tel_uri->number.ptr[0] == '+')
    {
      ret = GLOBAL_PHONE_NUMBER;
    }
    else
    {
      ret = enforce_global ? LOCAL_PHONE_NUMBER : GLOBAL_PHONE_NUMBER;
    }
  }
  else if (PJSIP_URI_SCHEME_IS_SIP(uri))
  {
    pjsip_sip_uri* sip_uri = (pjsip_sip_uri*)uri;
    pj_str_t host = sip_uri->host;
    bool home_domain = is_home_domain(host);
    bool local_to_node = is_local_name(host);
    bool is_gruu = (pjsip_param_find(&((pjsip_sip_uri*)uri)->other_param, &STR_GR) != NULL);
    bool treat_number_as_phone = !enforce_user_phone && !prefer_sip;

    TRC_DEBUG("home domain: %s, local_to_node: %s, is_gruu: %s, enforce_user_phone: %s, prefer_sip: %s, treat_number_as_phone: %s",
              home_domain ? "true" : "false",
              local_to_node ? "true" : "false",
              is_gruu ? "true" : "false",
              enforce_user_phone ? "true" : "false",
              prefer_sip ? "true" : "false",
              treat_number_as_phone ? "true" : "false");

    // SIP URI that's 'really' a phone number - apply the same logic as for TEL URIs
    if ((!pj_strcmp(&((pjsip_sip_uri*)uri)->user_param, &STR_USER_PHONE) ||
         (home_domain && treat_number_as_phone && !is_gruu)))
    {
      if (sip_uri->user.slen > 0 && sip_uri->user.ptr[0] == '+')
      {
        ret = GLOBAL_PHONE_NUMBER;
      }
      else
      {
        ret = enforce_global ? LOCAL_PHONE_NUMBER : GLOBAL_PHONE_NUMBER;
      }
    }
    // Not a phone number - classify it based on domain
    else if (home_domain)
    {
      ret = HOME_DOMAIN_SIP_URI;
    }
    else if (local_to_node)
    {
      ret = NODE_LOCAL_SIP_URI;
    }
    else
    {
      ret = OFFNET_SIP_URI;
    }
  }

  TRC_DEBUG("Classified URI as %d", (int)ret);
  return ret;
}
Пример #11
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;
}
Пример #12
0
void create_challenge(pjsip_authorization_hdr* auth_hdr,
                      std::string resync,
                      pjsip_rx_data* rdata,
                      pjsip_tx_data* tdata)
{
  // Get the public and private identities from the request.
  std::string impi;
  std::string impu;
  std::string nonce;

  PJUtils::get_impi_and_impu(rdata, impi, impu);
  // Set up the authorization type, following Annex P.4 of TS 33.203.  Currently
  // only support AKA and SIP Digest, so only implement the subset of steps
  // required to distinguish between the two.
  std::string auth_type;
  if (auth_hdr != NULL)
  {
    pjsip_param* integrity =
           pjsip_param_find(&auth_hdr->credential.digest.other_param,
                            &STR_INTEGRITY_PROTECTED);

    if ((integrity != NULL) &&
        ((pj_stricmp(&integrity->value, &STR_YES) == 0) ||
         (pj_stricmp(&integrity->value, &STR_NO) == 0)))
    {
      // Authentication scheme is AKA.
      auth_type = "aka";
    }
  }

  // Get the Authentication Vector from the HSS.
  Json::Value* av = NULL;
  HTTPCode http_code = hss->get_auth_vector(impi, impu, auth_type, resync, av, get_trail(rdata));

  if ((av != NULL) &&
      (!verify_auth_vector(av, impi, get_trail(rdata))))
  {
    // Authentication Vector is badly formed.
    delete av;
    av = NULL;
  }

  if (av != NULL)
  {
    // Retrieved a valid authentication vector, so generate the challenge.
    LOG_DEBUG("Valid AV - generate challenge");
    char buf[16];
    pj_str_t random;
    random.ptr = buf;
    random.slen = sizeof(buf);

    LOG_DEBUG("Create WWW-Authenticate header");
    pjsip_www_authenticate_hdr* hdr = pjsip_www_authenticate_hdr_create(tdata->pool);

    // Set up common fields for Digest and AKA cases (both are considered
    // Digest authentication).
    hdr->scheme = STR_DIGEST;

    if (av->isMember("aka"))
    {
      // AKA authentication.
      LOG_DEBUG("Add AKA information");

      SAS::Event event(get_trail(rdata), SASEvent::AUTHENTICATION_CHALLENGE, 0);
      std::string AKA = "AKA";
      event.add_var_param(AKA);
      SAS::report_event(event);

      Json::Value& aka = (*av)["aka"];

      // Use default realm for AKA as not specified in the AV.
      pj_strdup(tdata->pool, &hdr->challenge.digest.realm, &aka_realm);
      hdr->challenge.digest.algorithm = STR_AKAV1_MD5;
      nonce = aka["challenge"].asString();
      pj_strdup2(tdata->pool, &hdr->challenge.digest.nonce, nonce.c_str());
      pj_create_random_string(buf, sizeof(buf));
      pj_strdup(tdata->pool, &hdr->challenge.digest.opaque, &random);
      hdr->challenge.digest.qop = STR_AUTH;
      hdr->challenge.digest.stale = PJ_FALSE;

      // Add the cryptography key parameter.
      pjsip_param* ck_param = (pjsip_param*)pj_pool_alloc(tdata->pool, sizeof(pjsip_param));
      ck_param->name = STR_CK;
      std::string ck = "\"" + aka["cryptkey"].asString() + "\"";
      pj_strdup2(tdata->pool, &ck_param->value, ck.c_str());
      pj_list_insert_before(&hdr->challenge.digest.other_param, ck_param);

      // Add the integrity key parameter.
      pjsip_param* ik_param = (pjsip_param*)pj_pool_alloc(tdata->pool, sizeof(pjsip_param));
      ik_param->name = STR_IK;
      std::string ik = "\"" + aka["integritykey"].asString() + "\"";
      pj_strdup2(tdata->pool, &ik_param->value, ik.c_str());
      pj_list_insert_before(&hdr->challenge.digest.other_param, ik_param);
    }
    else
    {
      // Digest authentication.
      LOG_DEBUG("Add Digest information");

      SAS::Event event(get_trail(rdata), SASEvent::AUTHENTICATION_CHALLENGE, 0);
      std::string DIGEST = "DIGEST";
      event.add_var_param(DIGEST);
      SAS::report_event(event);

      Json::Value& digest = (*av)["digest"];
      pj_strdup2(tdata->pool, &hdr->challenge.digest.realm, digest["realm"].asCString());
      hdr->challenge.digest.algorithm = STR_MD5;
      pj_create_random_string(buf, sizeof(buf));
      nonce.assign(buf, sizeof(buf));
      pj_strdup(tdata->pool, &hdr->challenge.digest.nonce, &random);
      pj_create_random_string(buf, sizeof(buf));
      pj_strdup(tdata->pool, &hdr->challenge.digest.opaque, &random);
      pj_strdup2(tdata->pool, &hdr->challenge.digest.qop, digest["qop"].asCString());
      hdr->challenge.digest.stale = PJ_FALSE;
    }

    // Add the header to the message.
    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);

    // Store the branch parameter in memcached for correlation purposes
    pjsip_via_hdr* via_hdr = (pjsip_via_hdr*)pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_VIA, NULL);
    std::string branch = (via_hdr != NULL) ? PJUtils::pj_str_to_string(&via_hdr->branch_param) : "";

    (*av)["branch"] = branch;

    // Write the authentication vector (as a JSON string) into the AV store.
    LOG_DEBUG("Write AV to store");
    uint64_t cas = 0;
    bool success = av_store->set_av(impi, nonce, av, cas, get_trail(rdata));
    if (success)
    {
      // We've written the AV into the store, so need to set a Chronos
      // timer so that an AUTHENTICATION_TIMEOUT SAR is sent to the
      // HSS when it expires.
      std::string timer_id;
      std::string chronos_body = "{\"impi\": \"" + impi + "\", \"impu\": \"" + impu +"\", \"nonce\": \"" + nonce +"\"}";
      LOG_DEBUG("Sending %s to Chronos to set AV timer", chronos_body.c_str());
      chronos->send_post(timer_id, 30, "/authentication-timeout", chronos_body, 0);
    }

    delete av;
  }
  else
  {
    std::string error_msg;

    // If we couldn't get the AV because a downstream node is overloaded then don't return
    // a 4xx error to the client.
    if ((http_code == HTTP_SERVER_UNAVAILABLE) || (http_code == HTTP_GATEWAY_TIMEOUT))
    {
      error_msg = "Downstream node is overloaded or unresponsive, unable to get Authentication vector";
      LOG_DEBUG(error_msg.c_str());
      tdata->msg->line.status.code = PJSIP_SC_SERVER_TIMEOUT;
      tdata->msg->line.status.reason = *pjsip_get_status_text(PJSIP_SC_SERVER_TIMEOUT);
    }
    else
    {
      error_msg = "Failed to get Authentication vector";
      LOG_DEBUG(error_msg.c_str());
      tdata->msg->line.status.code = PJSIP_SC_FORBIDDEN;
      tdata->msg->line.status.reason = *pjsip_get_status_text(PJSIP_SC_FORBIDDEN);
    }

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

    pjsip_tx_data_invalidate_msg(tdata);
  }
}
Пример #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;
}
Пример #14
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
    }
  }
}
Пример #15
0
pj_status_t user_lookup(pj_pool_t *pool,
                        const pjsip_auth_lookup_cred_param *param,
                        pjsip_cred_info *cred_info,
                        void* av_param)
{
  const pj_str_t* acc_name = &param->acc_name;
  const pj_str_t* realm = &param->realm;
  const pjsip_rx_data* rdata = param->rdata;
  SAS::TrailId trail = get_trail(rdata);

  pj_status_t status = PJSIP_EAUTHACCNOTFOUND;

  // Get the impi and the nonce.  There must be an authorization header otherwise
  // PJSIP wouldn't have called this method.
  std::string impi = PJUtils::pj_str_to_string(acc_name);
  pjsip_digest_credential* credentials = get_credentials(rdata);
  std::string nonce = PJUtils::pj_str_to_string(&credentials->nonce);

  // Get the Authentication Vector from the store.
  rapidjson::Document* av = (rapidjson::Document*)av_param;

  if (av == NULL)
  {
    TRC_WARNING("Received an authentication request for %s with nonce %s, but no matching AV found", impi.c_str(), nonce.c_str());
  }

  if ((av != NULL) &&
      (!verify_auth_vector(av, impi, trail)))
  {
    // Authentication vector is badly formed.
    av = NULL;                                                 // LCOV_EXCL_LINE
  }

  if (av != NULL)
  {
    pj_cstr(&cred_info->scheme, "digest");
    pj_strdup(pool, &cred_info->username, acc_name);
    if (av->HasMember("aka"))
    {
      pjsip_param* auts_param = pjsip_param_find(&credentials->other_param,
                                                 &STR_AUTS);

      // AKA authentication.  The response in the AV must be used as a
      // plain-text password for the MD5 Digest computation.  Convert the text
      // into binary as this is what PJSIP is expecting. If we find the 'auts'
      // parameter, then leave the response as the empty string in accordance
      // with RFC 3310.
      std::string response = "";
      if (((*av)["aka"].HasMember("response")) &&
          ((*av)["aka"]["response"].IsString()) &&
          auts_param == NULL)
      {
        response = (*av)["aka"]["response"].GetString();
      }

      std::string xres;
      for (size_t ii = 0; ii < response.length(); ii += 2)
      {
        xres.push_back((char)(pj_hex_digit_to_val(response[ii]) * 16 +
                              pj_hex_digit_to_val(response[ii+1])));
      }
      cred_info->data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
      pj_strdup2(pool, &cred_info->data, xres.c_str());
      TRC_DEBUG("Found AKA XRES = %.*s", cred_info->data.slen, cred_info->data.ptr);

      // Use default realm as it isn't specified in the AV.
      pj_strdup(pool, &cred_info->realm, realm);
      status = PJ_SUCCESS;
    }
    else if (av->HasMember("digest"))
    {
      std::string digest_realm = "";
      if (((*av)["digest"].HasMember("realm")) &&
          ((*av)["digest"]["realm"].IsString()))
      {
        digest_realm = (*av)["digest"]["realm"].GetString();
      }

      if (pj_strcmp2(realm, digest_realm.c_str()) == 0)
      {
        // Digest authentication, so ha1 field is hashed password.
        cred_info->data_type = PJSIP_CRED_DATA_DIGEST;
        std::string digest_ha1 = "";
        if (((*av)["digest"].HasMember("ha1")) &&
            ((*av)["digest"]["ha1"].IsString()))
        {
          digest_ha1 = (*av)["digest"]["ha1"].GetString();
        }

        pj_strdup2(pool, &cred_info->data, digest_ha1.c_str());
        cred_info->realm = *realm;
        TRC_DEBUG("Found Digest HA1 = %.*s", cred_info->data.slen, cred_info->data.ptr);
        status = PJ_SUCCESS;
      }
      else
      {
        // These credentials are for a different realm, so no credentials were
        // actually provided for us to check.
        status = PJSIP_EAUTHNOAUTH;
      }
    }

    correlate_branch_from_av(av, trail);
  }

  return status;
}
Пример #16
-1
int dummy_function()
{
    pj_caching_pool cp;
 
    sprintf(NULL, "%d", 0);
    rand();
    
#ifdef HAS_PJLIB
    pj_init();
    pj_caching_pool_init(&cp, NULL, 0);
    pj_array_erase(NULL, 0, 0, 0);
    pj_create_unique_string(NULL, NULL);
    pj_hash_create(NULL, 0);
    pj_hash_get(NULL, NULL, 0, NULL);
    pj_hash_set(NULL, NULL, NULL, 0, 0, NULL);
    pj_ioqueue_create(NULL, 0, NULL);
    pj_ioqueue_register_sock(NULL, NULL, 0, NULL, NULL, NULL);
    pj_pool_alloc(NULL, 0);
    pj_timer_heap_create(NULL, 0, NULL);
#endif

#ifdef HAS_PJLIB_STUN
    pjstun_get_mapped_addr(&cp.factory, 0, NULL, NULL, 80, NULL, 80, NULL);
#endif

#ifdef HAS_PJLIB_GETOPT
    pj_getopt_long(0, NULL, NULL, NULL, NULL);
#endif
    
#ifdef HAS_PJLIB_XML
    pj_xml_parse(NULL, NULL, 100);
    pj_xml_print(NULL, NULL, 10, PJ_FALSE);
    pj_xml_clone(NULL, NULL);
    pj_xml_node_new(NULL, NULL);
    pj_xml_attr_new(NULL, NULL, NULL);
    pj_xml_add_node(NULL, NULL);
    pj_xml_add_attr(NULL, NULL);
    pj_xml_find_node(NULL, NULL);
    pj_xml_find_next_node(NULL, NULL, NULL);
    pj_xml_find_attr(NULL, NULL, NULL);
    pj_xml_find(NULL, NULL, NULL, NULL);
#endif

#ifdef HAS_PJLIB_SCANNER
    pj_cis_buf_init(NULL);
    pj_cis_init(NULL, NULL);
    pj_cis_dup(NULL, NULL);
    pj_cis_add_alpha(NULL);
    pj_cis_add_str(NULL, NULL);

    pj_scan_init(NULL, NULL, 0, 0, NULL);
    pj_scan_fini(NULL);
    pj_scan_peek(NULL, NULL, NULL);
    pj_scan_peek_n(NULL, 0, NULL);
    pj_scan_peek_until(NULL, NULL, NULL);
    pj_scan_get(NULL, NULL, NULL);
    pj_scan_get_unescape(NULL, NULL, NULL);
    pj_scan_get_quote(NULL, 0, 0, NULL);
    pj_scan_get_n(NULL, 0, NULL);
    pj_scan_get_char(NULL);
    pj_scan_get_until(NULL, NULL, NULL);
    pj_scan_strcmp(NULL, NULL, 0);
    pj_scan_stricmp(NULL, NULL, 0);
    pj_scan_stricmp_alnum(NULL, NULL, 0);
    pj_scan_get_newline(NULL);
    pj_scan_restore_state(NULL, NULL);
#endif

#ifdef HAS_PJLIB_DNS
    pj_dns_make_query(NULL, NULL, 0, 0, NULL);
    pj_dns_parse_packet(NULL, NULL, 0, NULL);
    pj_dns_packet_dup(NULL, NULL, 0, NULL);
#endif

#ifdef HAS_PJLIB_RESOLVER
    pj_dns_resolver_create(NULL, NULL, 0, NULL, NULL, NULL);
    pj_dns_resolver_set_ns(NULL, 0, NULL, NULL);
    pj_dns_resolver_handle_events(NULL, NULL);
    pj_dns_resolver_destroy(NULL, 0);
    pj_dns_resolver_start_query(NULL, NULL, 0, 0, NULL, NULL, NULL);
    pj_dns_resolver_cancel_query(NULL, 0);
    pj_dns_resolver_add_entry(NULL, NULL, 0);
#endif

#ifdef HAS_PJLIB_SRV_RESOLVER
    pj_dns_srv_resolve(NULL, NULL, 0, NULL, NULL, PJ_FALSE, NULL, NULL);
#endif

#ifdef HAS_PJLIB_CRC32
    pj_crc32_init(NULL);
    pj_crc32_update(NULL, NULL, 0);
    pj_crc32_final(NULL);
#endif

#ifdef HAS_PJLIB_HMAC_MD5
    pj_hmac_md5(NULL, 0, NULL, 0, NULL);
#endif

#ifdef HAS_PJLIB_HMAC_SHA1
    pj_hmac_sha1(NULL, 0, NULL, 0, NULL);
#endif

#ifdef HAS_PJNATH_STUN
    pj_stun_session_create(NULL, NULL, NULL, PJ_FALSE, NULL);
    pj_stun_session_destroy(NULL);
    pj_stun_session_set_credential(NULL, NULL);
    pj_stun_session_create_req(NULL, 0, NULL, NULL);
    pj_stun_session_create_ind(NULL, 0, NULL);
    pj_stun_session_create_res(NULL, NULL, 0, NULL, NULL);
    pj_stun_session_send_msg(NULL, PJ_FALSE, NULL, 0, NULL);
#endif

#ifdef HAS_PJNATH_ICE
    pj_ice_strans_create(NULL, NULL, 0, NULL, NULL, NULL);
    pj_ice_strans_set_stun_domain(NULL, NULL, NULL);
    pj_ice_strans_create_comp(NULL, 0, 0, NULL);
    pj_ice_strans_add_cand(NULL, 0, PJ_ICE_CAND_TYPE_HOST, 0, NULL, PJ_FALSE);
    pj_ice_strans_init_ice(NULL, PJ_ICE_SESS_ROLE_CONTROLLED, NULL, NULL);
    pj_ice_strans_start_ice(NULL, NULL, NULL, 0, NULL);
    pj_ice_strans_stop_ice(NULL);
    pj_ice_strans_sendto(NULL, 0, NULL, 0, NULL, 0);
#endif

#ifdef HAS_PJSIP_CORE_MSG_ELEM
    /* Parameter container */
    pjsip_param_find(NULL, NULL);
    pjsip_param_print_on(NULL, NULL, 0, NULL, NULL, 0);

    /* SIP URI */
    pjsip_sip_uri_create(NULL, 0);
    pjsip_name_addr_create(NULL);

    /* TEL URI */
    pjsip_tel_uri_create(NULL);

    /* Message and headers */
    pjsip_msg_create(NULL, PJSIP_REQUEST_MSG);
    pjsip_msg_print(NULL, NULL, 0);
    pjsip_accept_hdr_create(NULL);
    pjsip_allow_hdr_create(NULL);
    pjsip_cid_hdr_create(NULL);
    pjsip_clen_hdr_create(NULL);
    pjsip_cseq_hdr_create(NULL);
    pjsip_contact_hdr_create(NULL);
    pjsip_ctype_hdr_create(NULL);
    pjsip_expires_hdr_create(NULL, 0);
    pjsip_from_hdr_create(NULL);
    pjsip_max_fwd_hdr_create(NULL, 0);
    pjsip_min_expires_hdr_create(NULL, 0);
    pjsip_rr_hdr_create(NULL);
    pjsip_require_hdr_create(NULL);
    pjsip_retry_after_hdr_create(NULL, 0);
    pjsip_supported_hdr_create(NULL);
    pjsip_unsupported_hdr_create(NULL);
    pjsip_via_hdr_create(NULL);
    pjsip_warning_hdr_create(NULL, 0, NULL, NULL);

    pjsip_parse_uri(NULL, NULL, 0, 0);
    pjsip_parse_msg(NULL, NULL, 0, NULL);
    pjsip_parse_rdata(NULL, 0, NULL);
    pjsip_find_msg(NULL, 0, 0, NULL);
#endif

#ifdef HAS_PJSIP_CORE
    pjsip_endpt_create(NULL, NULL, NULL);

    pjsip_tpmgr_create(NULL, NULL, NULL, NULL, NULL);
    pjsip_tpmgr_destroy(NULL);
    pjsip_transport_send(NULL, NULL, NULL, 0, NULL, NULL);


#endif

#ifdef HAS_PJSIP_CORE_MSG_UTIL
    pjsip_endpt_create_request(NULL, NULL, NULL, NULL, NULL, NULL, NULL,
			       -1, NULL, NULL);
    pjsip_endpt_create_request_from_hdr(NULL, NULL, NULL, NULL, NULL, NULL,
					NULL, -1, NULL, NULL);
    pjsip_endpt_create_response(NULL, NULL, -1, NULL, NULL);
    pjsip_endpt_create_ack(NULL, NULL, NULL, NULL);
    pjsip_endpt_create_cancel(NULL, NULL, NULL);
    pjsip_get_request_dest(NULL, NULL);
    pjsip_endpt_send_request_stateless(NULL, NULL, NULL, NULL);
    pjsip_get_response_addr(NULL, NULL, NULL);
    pjsip_endpt_send_response(NULL, NULL, NULL, NULL, NULL);
    pjsip_endpt_respond_stateless(NULL, NULL, -1, NULL, NULL, NULL);
#endif

#ifdef HAS_PJSIP_UDP_TRANSPORT
    pjsip_udp_transport_start(NULL, NULL, NULL, 1, NULL);
#endif

#ifdef HAS_PJSIP_TCP_TRANSPORT
    pjsip_tcp_transport_start(NULL, NULL, 1, NULL);
#endif

#ifdef HAS_PJSIP_TLS_TRANSPORT
    pjsip_tls_transport_start(NULL, NULL, NULL, NULL, 0, NULL);
#endif

#ifdef HAS_PJSIP_TRANSACTION
    pjsip_tsx_layer_init_module(NULL);

    pjsip_tsx_layer_destroy();
    pjsip_tsx_create_uac(NULL, NULL, NULL);
    pjsip_tsx_create_uas(NULL, NULL, NULL);
    pjsip_tsx_recv_msg(NULL, NULL);
    pjsip_tsx_send_msg(NULL, NULL);
    pjsip_tsx_terminate(NULL, 200);

    pjsip_endpt_send_request(NULL, NULL, -1, NULL, NULL);
    pjsip_endpt_respond(NULL, NULL, NULL, -1, NULL, NULL, NULL, NULL);
#endif

#ifdef HAS_PJMEDIA_SDP
    pjmedia_sdp_parse(NULL, NULL, 1024, NULL);
    pjmedia_sdp_print(NULL, NULL, 1024);
    pjmedia_sdp_validate(NULL);
    pjmedia_sdp_session_clone(NULL, NULL);
    pjmedia_sdp_session_cmp(NULL, NULL, 0);
    pjmedia_sdp_attr_to_rtpmap(NULL, NULL, NULL);
    pjmedia_sdp_attr_get_fmtp(NULL, NULL);
    pjmedia_sdp_attr_get_rtcp(NULL, NULL);
    pjmedia_sdp_conn_clone(NULL, NULL);
    pjmedia_sdp_media_clone(NULL, NULL);
    pjmedia_sdp_media_find_attr(NULL, NULL, NULL);
#endif

#ifdef HAS_PJMEDIA_SDP_NEGOTIATOR
    pjmedia_sdp_neg_create_w_local_offer(NULL, NULL, NULL);
    pjmedia_sdp_neg_create_w_remote_offer(NULL, NULL, NULL, NULL);
    pjmedia_sdp_neg_get_state(NULL);
    pjmedia_sdp_neg_negotiate(NULL, NULL, PJ_FALSE);
#endif

#ifdef HAS_PJSIP_UA_LAYER
    pjsip_ua_init_module(NULL, NULL);
    pjsip_ua_destroy();
    pjsip_dlg_create_uac(NULL, NULL, NULL, NULL, NULL, NULL);
    pjsip_dlg_create_uas_and_inc_lock(NULL, NULL, NULL, NULL);
    pjsip_dlg_terminate(NULL);
    pjsip_dlg_set_route_set(NULL, NULL);
    pjsip_dlg_create_request(NULL, NULL, -1, NULL);
    pjsip_dlg_send_request(NULL, NULL, -1, NULL);
    pjsip_dlg_create_response(NULL, NULL, -1, NULL, NULL);
    pjsip_dlg_modify_response(NULL, NULL, -1, NULL);
    pjsip_dlg_send_response(NULL, NULL, NULL);
    pjsip_dlg_respond(NULL, NULL, -1, NULL, NULL, NULL);
#endif

#ifdef HAS_PJSIP_AUTH_CLIENT
    pjsip_auth_clt_init(NULL, NULL, NULL, 0);
    pjsip_auth_clt_clone(NULL, NULL, NULL);
    pjsip_auth_clt_set_credentials(NULL, 0, NULL);
    pjsip_auth_clt_init_req(NULL, NULL);
    pjsip_auth_clt_reinit_req(NULL, NULL, NULL, NULL);
#endif

#ifdef HAS_PJSIP_INV_SESSION
    pjsip_inv_usage_init(NULL, NULL);
    pjsip_inv_create_uac(NULL, NULL, 0, NULL);
    pjsip_inv_verify_request(NULL, NULL, NULL, NULL, NULL, NULL);
    pjsip_inv_create_uas(NULL, NULL, NULL, 0, NULL);
    pjsip_inv_terminate(NULL, 200, PJ_FALSE);
    pjsip_inv_invite(NULL, NULL);
    pjsip_inv_initial_answer(NULL, NULL, 200, NULL, NULL, NULL);
    pjsip_inv_answer(NULL, 200, NULL, NULL, NULL);
    pjsip_inv_end_session(NULL, 200, NULL, NULL);
    pjsip_inv_reinvite(NULL, NULL, NULL, NULL);
    pjsip_inv_update(NULL, NULL, NULL, NULL);
    pjsip_inv_send_msg(NULL, NULL);
    pjsip_dlg_get_inv_session(NULL);
    //pjsip_tsx_get_inv_session(NULL);
    pjsip_inv_state_name(PJSIP_INV_STATE_NULL);
#endif

#ifdef HAS_PJSIP_REGC
    //pjsip_regc_get_module();
    pjsip_regc_create(NULL, NULL, NULL, NULL);
    pjsip_regc_destroy(NULL);
    pjsip_regc_get_info(NULL, NULL);
    pjsip_regc_get_pool(NULL);
    pjsip_regc_init(NULL, NULL, NULL, NULL, 0, NULL, 600);
    pjsip_regc_set_credentials(NULL, 1, NULL);
    pjsip_regc_set_route_set(NULL, NULL);
    pjsip_regc_register(NULL, PJ_TRUE, NULL);
    pjsip_regc_unregister(NULL, NULL);
    pjsip_regc_update_contact(NULL, 10, NULL);
    pjsip_regc_update_expires(NULL, 600);
    pjsip_regc_send(NULL, NULL);
#endif

#ifdef HAS_PJSIP_EVENT_FRAMEWORK
    pjsip_evsub_init_module(NULL);
    pjsip_evsub_instance();
    pjsip_evsub_register_pkg(NULL, NULL, 30, 10, NULL);
    pjsip_evsub_create_uac(NULL, NULL, NULL, 10, NULL);
    pjsip_evsub_create_uas(NULL, NULL, NULL, 10, NULL);
    pjsip_evsub_terminate(NULL, PJ_FALSE);
    pjsip_evsub_get_state(NULL);
    pjsip_evsub_get_state_name(NULL);
    pjsip_evsub_initiate(NULL, NULL, -1, NULL);
    pjsip_evsub_accept(NULL, NULL, 200, NULL);
    pjsip_evsub_notify(NULL, PJSIP_EVSUB_STATE_ACTIVE, NULL, NULL, NULL);
    pjsip_evsub_current_notify(NULL, NULL);
    pjsip_evsub_send_request(NULL, NULL);
    pjsip_tsx_get_evsub(NULL);
    pjsip_evsub_set_mod_data(NULL, 1, NULL);
    pjsip_evsub_get_mod_data(NULL, 1);
#endif

#ifdef HAS_PJSIP_CALL_TRANSFER
    pjsip_xfer_init_module(NULL);
    pjsip_xfer_create_uac(NULL, NULL, NULL);
    pjsip_xfer_create_uas(NULL, NULL, NULL, NULL);
    pjsip_xfer_initiate(NULL, NULL, NULL);
    pjsip_xfer_accept(NULL, NULL, 200, NULL);
    pjsip_xfer_notify(NULL, PJSIP_EVSUB_STATE_ACTIVE, 200, NULL, NULL);
    pjsip_xfer_current_notify(NULL, NULL);
    pjsip_xfer_send_request(NULL, NULL);
#endif

#ifdef HAS_PJSIP_PRESENCE
    pjsip_pres_init_module(NULL, NULL);
    pjsip_pres_instance();
    pjsip_pres_create_uac(NULL, NULL, 0, NULL);
    pjsip_pres_create_uas(NULL, NULL, NULL, NULL);
    pjsip_pres_terminate(NULL, PJ_FALSE);
    pjsip_pres_initiate(NULL, 100, NULL);
    pjsip_pres_accept(NULL, NULL, 200, NULL);
    pjsip_pres_notify(NULL, PJSIP_EVSUB_STATE_ACTIVE, NULL, NULL, NULL);
    pjsip_pres_current_notify(NULL, NULL);
    pjsip_pres_send_request(NULL, NULL);
    pjsip_pres_get_status(NULL, NULL);
    pjsip_pres_set_status(NULL, NULL);
#endif

#ifdef HAS_PJSIP_IS_COMPOSING
    pjsip_iscomposing_create_xml(NULL, PJ_TRUE, NULL, NULL, 0);
    pjsip_iscomposing_create_body(NULL, PJ_TRUE, NULL, NULL, 0);
    pjsip_iscomposing_parse(NULL, NULL, 0, NULL, NULL, NULL, NULL);
#endif

#ifdef HAS_PJMEDIA
    pjmedia_endpt_create(NULL, NULL, 1, NULL);
    pjmedia_endpt_destroy(NULL);
    pjmedia_endpt_create_sdp(NULL, NULL, 1, NULL, NULL);
#endif

#ifdef HAS_PJMEDIA_EC
    pjmedia_echo_create(NULL, 0, 0, 0, 0, 0, NULL);
    pjmedia_echo_destroy(NULL);
    pjmedia_echo_playback(NULL, NULL);
    pjmedia_echo_capture(NULL, NULL, 0);
    pjmedia_echo_cancel(NULL, NULL, NULL, 0, NULL);
#endif

#ifdef HAS_PJMEDIA_SND_DEV
    pjmedia_snd_init(NULL);
    pjmedia_snd_get_dev_count();
    pjmedia_snd_get_dev_info(0);
    pjmedia_snd_open(-1, -1, 8000, 1, 80, 16, NULL, NULL, NULL, NULL);
    pjmedia_snd_open_rec(-1, 8000, 1, 160, 16, NULL, NULL, NULL);
    pjmedia_snd_open_player(-1, 8000, 1, 160, 16, NULL, NULL, NULL);
    pjmedia_snd_stream_start(NULL);
    pjmedia_snd_stream_stop(NULL);
    pjmedia_snd_stream_close(NULL);
    pjmedia_snd_deinit();
#endif

#ifdef HAS_PJMEDIA_SND_PORT
    pjmedia_snd_port_create(NULL, -1, -1, 8000, 1, 180, 16, 0, NULL);
    pjmedia_snd_port_create_rec(NULL, -1, 8000, 1, 160, 16, 0, NULL);
    pjmedia_snd_port_create_player(NULL, -1, 8000, 1, 160, 16, 0, NULL);
    pjmedia_snd_port_destroy(NULL);
    pjmedia_snd_port_get_snd_stream(NULL);
    pjmedia_snd_port_connect(NULL, NULL);
    pjmedia_snd_port_get_port(NULL);
    pjmedia_snd_port_disconnect(NULL);
#endif

#ifdef HAS_PJMEDIA_RESAMPLE
    pjmedia_resample_create(NULL, PJ_TRUE, PJ_TRUE, 0, 0, 0, 0, NULL);
    pjmedia_resample_run(NULL, NULL, NULL);
#endif

#ifdef HAS_PJMEDIA_SILENCE_DET
    pjmedia_silence_det_create(NULL, 8000, 80, NULL);
    pjmedia_silence_det_detect(NULL, NULL, 0, NULL);
    pjmedia_silence_det_apply(NULL, 0);
#endif

#ifdef HAS_PJMEDIA_PLC
    pjmedia_plc_create(NULL, 8000, 80, 0, NULL);
    pjmedia_plc_save(NULL, NULL);
    pjmedia_plc_generate(NULL, NULL);
#endif

#ifdef HAS_PJMEDIA_CONFERENCE
    pjmedia_conf_create(NULL, 10, 8000, 1, 160, 16, 0, NULL);
    pjmedia_conf_destroy(NULL);
    pjmedia_conf_get_master_port(NULL);
    pjmedia_conf_add_port(NULL, NULL, NULL, NULL, NULL);
    pjmedia_conf_configure_port(NULL, 1, 0, 0);
    pjmedia_conf_connect_port(NULL, 0, 0, 0);
    pjmedia_conf_disconnect_port(NULL, 0, 0);
    pjmedia_conf_remove_port(NULL, 0);
    pjmedia_conf_enum_ports(NULL, NULL, NULL);
    pjmedia_conf_get_port_info(NULL, 0, NULL);
    pjmedia_conf_get_ports_info(NULL, NULL, NULL);
    pjmedia_conf_get_signal_level(NULL, 0, NULL, NULL);
    pjmedia_conf_adjust_rx_level(NULL, 0, 0);
    pjmedia_conf_adjust_tx_level(NULL, 0, 0);
#endif

#ifdef HAS_PJMEDIA_MASTER_PORT
    pjmedia_master_port_create(NULL, NULL, NULL, 0, NULL);
    pjmedia_master_port_start(NULL);
    pjmedia_master_port_stop(NULL);
    pjmedia_master_port_set_uport(NULL, NULL);
    pjmedia_master_port_get_uport(NULL);
    pjmedia_master_port_set_dport(NULL, NULL);
    pjmedia_master_port_get_dport(NULL);
    pjmedia_master_port_destroy(NULL, PJ_FALSE);
#endif

#ifdef HAS_PJMEDIA_RTP
    pjmedia_rtp_session_init(NULL, 0, 0);
    pjmedia_rtp_encode_rtp(NULL, 0, 0, 0, 0, NULL, NULL);
    pjmedia_rtp_decode_rtp(NULL, NULL, 0, NULL, NULL, NULL);
    pjmedia_rtp_session_update(NULL, NULL, NULL);
#endif

#ifdef HAS_PJMEDIA_RTCP
    pjmedia_rtcp_init(NULL, NULL, 0, 0, 0);
    pjmedia_rtcp_get_ntp_time(NULL, NULL);
    pjmedia_rtcp_fini(NULL);
    pjmedia_rtcp_rx_rtp(NULL, 0, 0, 0);
    pjmedia_rtcp_tx_rtp(NULL, 0);
    pjmedia_rtcp_rx_rtcp(NULL, NULL, 0);
    pjmedia_rtcp_build_rtcp(NULL, NULL, NULL);
#endif

#ifdef HAS_PJMEDIA_JBUF
    pjmedia_jbuf_create(NULL, NULL, 0, 0, 0, NULL);
    pjmedia_jbuf_set_fixed(NULL, 0);
    pjmedia_jbuf_set_adaptive(NULL, 0, 0, 0);
    pjmedia_jbuf_destroy(NULL);
    pjmedia_jbuf_put_frame(NULL, NULL, 0, 0);
    pjmedia_jbuf_get_frame(NULL, NULL, NULL);
#endif

#ifdef HAS_PJMEDIA_STREAM
    pjmedia_stream_create(NULL, NULL, NULL, NULL, NULL, NULL);
    pjmedia_stream_destroy(NULL);
    pjmedia_stream_get_port(NULL, NULL);
    pjmedia_stream_get_transport(NULL);
    pjmedia_stream_start(NULL);
    pjmedia_stream_get_stat(NULL, NULL);
    pjmedia_stream_pause(NULL, PJMEDIA_DIR_ENCODING);
    pjmedia_stream_resume(NULL, PJMEDIA_DIR_ENCODING);
    pjmedia_stream_dial_dtmf(NULL, NULL);
    pjmedia_stream_check_dtmf(NULL);
    pjmedia_stream_get_dtmf(NULL, NULL, NULL);
#endif

#ifdef HAS_PJMEDIA_TONEGEN
    pjmedia_tonegen_create(NULL, 0, 0, 0, 0, 0, NULL);
    pjmedia_tonegen_is_busy(NULL);
    pjmedia_tonegen_stop(NULL);
    pjmedia_tonegen_play(NULL, 0, NULL, 0);
    pjmedia_tonegen_play_digits(NULL, 0, NULL, 0);
    pjmedia_tonegen_get_digit_map(NULL, NULL);
    pjmedia_tonegen_set_digit_map(NULL, NULL);
#endif

#ifdef HAS_PJMEDIA_UDP_TRANSPORT
    pjmedia_transport_udp_create(NULL, NULL, 0, 0, NULL);
    pjmedia_transport_udp_close(NULL);
#endif

#ifdef HAS_PJMEDIA_FILE_PLAYER
    pjmedia_wav_player_port_create(NULL, NULL, 0, 0, 0, NULL);
    pjmedia_wav_player_port_set_pos(NULL, 0);
    pjmedia_wav_player_port_get_pos(NULL);
    pjmedia_wav_player_set_eof_cb(NULL, NULL, NULL);
#endif

#ifdef HAS_PJMEDIA_FILE_CAPTURE
    pjmedia_wav_writer_port_create(NULL, NULL, 8000, 1, 80, 16, 0, 0, NULL);
    pjmedia_wav_writer_port_get_pos(NULL);
    pjmedia_wav_writer_port_set_cb(NULL, 0, NULL, NULL);
#endif

#ifdef HAS_PJMEDIA_MEM_PLAYER
    pjmedia_mem_player_create(NULL, NULL, 1000, 8000, 1, 80, 16, 0, NULL);
#endif

#ifdef HAS_PJMEDIA_MEM_CAPTURE
    pjmedia_mem_capture_create(NULL, NULL, 1000, 8000, 1, 80, 16, 0, NULL);
#endif

#ifdef HAS_PJMEDIA_ICE
    pjmedia_ice_create(NULL, NULL, 0, NULL, NULL);
    pjmedia_ice_destroy(NULL);
    pjmedia_ice_start_init(NULL, 0, NULL, NULL, NULL);
    pjmedia_ice_init_ice(NULL, PJ_ICE_SESS_ROLE_CONTROLLED, NULL, NULL);
    pjmedia_ice_modify_sdp(NULL, NULL, NULL);
    pjmedia_ice_start_ice(NULL, NULL, NULL, 0);
    pjmedia_ice_stop_ice(NULL);
#endif

#ifdef HAS_PJMEDIA_G711_CODEC
    pjmedia_codec_g711_init(NULL);
    pjmedia_codec_g711_deinit();
#endif

#ifdef HAS_PJMEDIA_GSM_CODEC
    pjmedia_codec_gsm_init(NULL);
    pjmedia_codec_gsm_deinit();
#endif

#ifdef HAS_PJMEDIA_SPEEX_CODEC
    pjmedia_codec_speex_init(NULL, 0, 0, 0);
    pjmedia_codec_speex_deinit();
#endif

#ifdef HAS_PJMEDIA_ILBC_CODEC
    pjmedia_codec_ilbc_init(NULL, 0);
    pjmedia_codec_ilbc_deinit();
#endif

    return 0;
}