Ejemplo n.º 1
0
/** Get session mode from attribute list. */
sdp_mode_t sdp_attribute_mode(sdp_attribute_t const *a, sdp_mode_t defmode)
{
  for (; a; a = a->a_next) {
    if (su_casematch(a->a_name, "sendrecv"))
      return sdp_sendrecv;
    if (su_casematch(a->a_name, "inactive"))
      return sdp_inactive;
    if (su_casematch(a->a_name, "recvonly"))
      return sdp_recvonly;
    if (su_casematch(a->a_name, "sendonly"))
      return sdp_sendonly;
  }

  return defmode;
}
Ejemplo n.º 2
0
/**Replace or append a attribute within a list of attributes.
 *
 * @retval 1 if replaced existing attribute
 * @retval 0 if attribute was appended
 * @retval -1 upon an error
 */
int sdp_attribute_replace(sdp_attribute_t **list,
			  sdp_attribute_t *a,
			  sdp_attribute_t **return_replaced)
{
  sdp_attribute_t *replaced;

  assert(list);

  if (return_replaced)
    *return_replaced = NULL;

  if (list == NULL || a == NULL)
    return -1;

  assert(a->a_name != NULL); assert(a->a_next == NULL);

  for (; *list; list = &(*list)->a_next) {
    if (su_casematch((*list)->a_name, a->a_name))
      break;
  }

  replaced = *list, *list = a;

  if (replaced) {
    a->a_next = replaced->a_next;
    replaced->a_next = NULL;

    if (return_replaced)
      *return_replaced = replaced;

    return 1;
  }

  return 0;
}
Ejemplo n.º 3
0
static int soa_static_set_params(soa_session_t *ss, tagi_t const *tags)
{
  soa_static_session_t *sss = (soa_static_session_t *)ss;
  char const *audio_aux = sss->sss_audio_aux;
  int ordered_user = sss->sss_ordered_user;
  int reuse_rejected = sss->sss_reuse_rejected;
  int n, m;

  n = tl_gets(tags,
	      SOATAG_AUDIO_AUX_REF(audio_aux),
	      SOATAG_ORDERED_USER_REF(ordered_user),
	      SOATAG_REUSE_REJECTED_REF(reuse_rejected),
	      TAG_END());

  if (n > 0 && !su_casematch(audio_aux, sss->sss_audio_aux)) {
    char *s = su_strdup(ss->ss_home, audio_aux), *tbf = sss->sss_audio_aux;
    if (s == NULL && audio_aux != NULL)
      return -1;
    sss->sss_audio_aux = s;
    if (tbf)
      su_free(ss->ss_home, tbf);
  }

  sss->sss_ordered_user = ordered_user != 0;
  sss->sss_reuse_rejected = reuse_rejected != 0;

  m = soa_base_set_params(ss, tags);
  if (m < 0)
    return m;

  return n + m;
}
Ejemplo n.º 4
0
static
int nua_refer_server_respond(nua_server_request_t *sr, tagi_t const *tags)
{
  nua_handle_t *nh = sr->sr_owner;
  struct notifier_usage *nu = nua_dialog_usage_private(sr->sr_usage);
  sip_refer_sub_t const *rs = sip_refer_sub(sr->sr_response.sip);

  if (sr->sr_status < 200 || nu == NULL) {
  }
  else if (sr->sr_status < 300 &&
	   /* No subscription if Refer-Sub: false in response */
	   (rs == NULL || !su_casematch(rs->rs_value, "false"))) {
    sr->sr_usage->du_ready = 1;

    nu->nu_expires = sip_now() + NH_PGET(nh, refer_expires);

    if (sr->sr_application)	/* Application responded to REFER */
      nu->nu_substate = nua_substate_active;
  }
  else {
    /* Destroy the implicit subscription usage */
    sr->sr_terminating = 1;
  }

  return nua_base_server_respond(sr, tags);
}
Ejemplo n.º 5
0
static void
print_attributes_without_mode(sdp_printer_t *p, sdp_attribute_t const *a)
{
  for (;a; a = a->a_next) {
    char const *name = a->a_name;
    char const *value = a->a_value;

    if (su_casematch(name, "inactive") ||
	su_casematch(name, "sendonly") ||
	su_casematch(name, "recvonly") ||
	su_casematch(name, "sendrecv"))
      continue;

    sdp_printf(p, "a=%s%s%s" CRLF, name, value ? ":" : "", value ? value : "");
  }
}
Ejemplo n.º 6
0
static int nua_refer_client_response(nua_client_request_t *cr,
				     int status, char const *phrase,
				     sip_t const *sip)
{
  nua_dialog_usage_t *du = cr->cr_usage;
  enum nua_substate substate = nua_substate_terminated;

  if (du) {
    struct event_usage *eu = nua_dialog_usage_private(du);

    if (status < 200) {
      substate = eu->eu_substate;
    }
    else if (status < 300) {
      sip_refer_sub_t const *rs = sip_refer_sub(sip);

      if (rs && su_casematch("false", rs->rs_value))
	cr->cr_terminated = 1;

      if (!cr->cr_terminated)
	substate = eu->eu_substate;
    }
  }

  return nua_base_client_tresponse(cr, status, phrase, sip,
				   NUTAG_SUBSTATE(substate),
				   SIPTAG_EVENT(du ? du->du_event : NULL),
				   TAG_END());
}
Ejemplo n.º 7
0
static
int nua_subscribe_server_report(nua_server_request_t *sr, tagi_t const *tags)
{
  nua_handle_t *nh = sr->sr_owner;
  nua_dialog_state_t *ds = nh->nh_ds;
  nua_dialog_usage_t *du = sr->sr_usage;
  struct notifier_usage *nu = nua_dialog_usage_private(du);
  enum nua_substate substate = nua_substate_terminated;
  int notify = 0;
  int retval;

  if (nu && !sr->sr_terminating) {
    substate = nu->nu_substate;
  }

  /* nu_requested is set by SUBSCRIBE and cleared when NOTIFY is sent */
  if (nu && nu->nu_requested && substate != nua_substate_embryonic) {
#if SU_HAVE_EXPERIMENTAL
    sip_t const *sip = sr->sr_request.sip;
    sip_suppress_notify_if_match_t *snim = sip_suppress_notify_if_match(sip);
    sip_suppress_body_if_match_t *sbim = sip_suppress_body_if_match(sip);

    if (!nu->nu_tag)
      notify = 1;
    else if (snim && su_casematch(snim->snim_tag, nu->nu_tag))
      notify = 0;
    else if (sbim && su_casematch(snim->snim_tag, nu->nu_tag))
      notify = 1, nu->nu_no_body = 1;
    else
#endif
      notify = 1;

    notify = notify && du->du_cr != NULL;
  }

  retval = nua_base_server_treport(sr, NUTAG_SUBSTATE(substate), TAG_END());

  if (retval >= 2 || du == NULL)
    return retval;

  if (notify) {
    /* Send NOTIFY (and terminate subscription, when needed) */
    nua_dialog_usage_refresh(nh, ds, du);
  }

  return retval;
}
Ejemplo n.º 8
0
/** Find named attribute from given lists (a or a2). */
sdp_attribute_t *sdp_attribute_find2(sdp_attribute_t const *a,
				     sdp_attribute_t const *a2,
				     char const *name)
{
  for (; a; a = a->a_next) {
    if (su_casematch(a->a_name, name))
      break;
  }

  if (a == 0)
    for (a = a2; a; a = a->a_next) {
      if (su_casematch(a->a_name, name))
	break;
    }

  return (sdp_attribute_t *)a;
}
Ejemplo n.º 9
0
/** Check if request should be processed by outbound */
int outbound_targeted_request(sip_t const *sip)
{
  return
    sip && sip->sip_request &&
    sip->sip_request->rq_method == sip_method_options &&
    sip->sip_accept &&
    sip->sip_accept->ac_type &&
    su_casematch(sip->sip_accept->ac_type, outbound_content_type);
}
Ejemplo n.º 10
0
/** Decode (parse) @ReferSub header */
issize_t sip_refer_sub_d(su_home_t *home,
			 sip_header_t *h,
			 char *s, isize_t slen)
{
  sip_refer_sub_t *rs = (sip_refer_sub_t *)h;

  if (msg_token_d(&s, &rs->rs_value) < 0)
    return -1;

  if (!su_casematch(rs->rs_value, "false") &&
      !su_casematch(rs->rs_value, "true"))
    return -1;

  if (*s)
    if (msg_params_d(home, &s, &rs->rs_params) == -1)
      return -1;

  return s - rs->rs_value;
}
Ejemplo n.º 11
0
int
count_transports(struct dig *dig,
				 char const *tport,
				 char const *tport2)
{

	int i, tcount = 0;
	struct transport const *tports = dig->tports;

	for (i = 0; tports[i].name; i++) {
		if (dig->sips && !transport_is_secure(tports[i].name))
			continue;
		if (!tport || su_casematch(tport, tports[i].name))
			tcount++;
		else if (tport2 && su_casematch(tport2, tports[i].name))
			tcount++;
	}

	return tcount;
}
Ejemplo n.º 12
0
/** Parse SIP version.
 *
 * Parse a SIP version string. Update the
 * pointer at @a ss to first non-LWS character after the version string.
 *
 * @param ss   string to be parsed [IN/OUT]
 * @param ver  value result for version [OUT]
 *
 * @retval 0 when successful,
 * @retval -1 upon an error.
 */
int sip_version_d(char **ss, char const **ver)
{
  char *s = *ss;
  char const *result;
  size_t const version_size = sizeof(sip_version_2_0) - 1;

  if (su_casenmatch(s, sip_version_2_0, version_size) &&
      !IS_TOKEN(s[version_size])) {
    result = sip_version_2_0;
    s += version_size;
  }
  else {
    /* Version consists of two tokens, separated by / */
    size_t l1 = 0, l2 = 0, n;

    result = s;

    l1 = span_token(s);
    for (n = l1; IS_LWS(s[n]); n++)
      {}
    if (s[n] == '/') {
      for (n++; IS_LWS(s[n]); n++)
        {}
      l2 = span_token(s + n);
      n += l2;
    }

    if (l1 == 0 || l2 == 0)
      return -1;

    /* If there is extra ws between tokens, compact version */
    if (n > l1 + 1 + l2) {
      s[l1] = '/';
      memmove(s + l1 + 1, s + n - l2, l2);
      s[l1 + 1 + l2] = 0;

      /* Compare again with compacted version */
      if (su_casematch(s, sip_version_2_0))
	result = sip_version_2_0;
    }

    s += n;
  }

  while (IS_WS(*s)) *s++ = '\0';

  *ss = s;

  if (ver)
    *ver = result;

  return 0;
}
Ejemplo n.º 13
0
struct transport const *
transport_by_service(struct transport const *tports, char const *s)
{
	int i;

	for (i = 0; tports[i].name; i++) {
		if (su_casematch(tports[i].service, s))
			return tports + i;
	}

	return NULL;
}
Ejemplo n.º 14
0
/** Duplicate a transport string */
void sip_transport_dup(char **pp, char const **dd, char const *s)
{
  if (s == sip_transport_udp)
    *dd = s;
  else if (s == sip_transport_tcp)
    *dd = s;
  else if (s == sip_transport_sctp)
    *dd = s;
  else if (s == sip_transport_tls)
    *dd = s;
  else if (s == sip_transport_ws)
    *dd = s;
  else if (s == sip_transport_wss)
    *dd = s;
  else if (su_casematch(s, sip_transport_udp))
    *dd = sip_transport_udp;
  else if (su_casematch(s, sip_transport_tcp))
    *dd = sip_transport_tcp;
  else if (su_casematch(s, sip_transport_sctp))
    *dd = sip_transport_sctp;
  else if (su_casematch(s, sip_transport_tls))
    *dd = sip_transport_tls;
  else if (su_casematch(s, sip_transport_ws))
    *dd = sip_transport_ws;
  else if (su_casematch(s, sip_transport_wss))
    *dd = sip_transport_wss;
  else
    MSG_STRING_DUP(*pp, *dd, s);
}
Ejemplo n.º 15
0
/** Compare @SecurityVerify header with @SecurityServer header. */
int sip_security_verify_compare(sip_security_server_t const *s,
				sip_security_verify_t const *v,
				msg_param_t *return_d_ver)
{
  size_t i, j;
  int retval, digest;
  msg_param_t const *s_params, *v_params, empty[] = { NULL };

  if (return_d_ver)
    *return_d_ver = NULL;

  if (s == NULL)
    return 0;

  for (;;s = s->sa_next, v = v->sa_next) {
    if (s == NULL || v == NULL)
      return (s == NULL) - (v == NULL);

    if ((retval = su_strcmp(s->sa_mec, v->sa_mec)))
      return retval;

    digest = su_casematch(s->sa_mec, "Digest");

    s_params = s->sa_params, v_params = v->sa_params;

    if (digest && s_params == NULL && v_params != NULL)
      s_params = empty;

    if (s_params == NULL || v_params == NULL) {
      if ((retval = (s_params == NULL) - (v_params == NULL)))
	return retval;
      continue;
    }

    for (i = 0, j = 0;; i++, j++) {
      if (digest && v_params[j] &&
	  su_casenmatch(v_params[j], "d-ver=", 6)) {
	if (return_d_ver)
	  *return_d_ver = v_params[j] + strlen("d-ver=");
	j++;
      }

      retval = su_strcmp(s_params[i], v_params[j]);

      if (retval || s_params[i] == NULL || v_params[j] == NULL)
	break;
    }

    if (retval)
      return retval;
  }
}
Ejemplo n.º 16
0
/**Get ntlm-challenge parameters.
 *
 * The function ntlm_challenge_get() searches for the ntlm authentication
 * parameters in @a params.  The parameters are assigned to the appropriate
 * fields in @a ac structure.
 *
 * @return
 *
 * The function ntlm_challenge_get() returns number of parameters
 * found, or -1 upon an error.
 */
issize_t auth_ntlm_challenge_get(su_home_t *home,
				auth_challenge_t *ac0,
				char const * const params[])
{
  ssize_t n;
  auth_challenge_t ac[1] = {{ 0 }};
  char const *md5 = NULL, *md5sess = NULL, *sha1 = NULL,
    *qop_auth = NULL, *qop_auth_int = NULL;

  ac->ac_size = sizeof(ac);

  assert(ac0);
  assert(ac0->ac_size >= sizeof(*ac));

  if (ac0 == NULL || params == NULL)
    return -1;

  n = auth_get_params(home, params,
		      "realm=", &ac->ac_realm,
		      "domain=", &ac->ac_domain,
		      "nonce=", &ac->ac_nonce,
		      "opaque=", &ac->ac_opaque,
		      "stale=", &ac->ac_stale,
		      "algorithm=", &ac->ac_algorithm,
		      "qop=", &ac->ac_qop,
		      "algorithm=md5", &md5,
		      "algorithm=md5-sess", &md5sess,
		      "algorithm=sha1", &sha1,
		      "qop=auth", &qop_auth,
		      "qop=auth-int", &qop_auth_int,
		      NULL);
  if (n < 0)
    return n;

  if (ac->ac_stale && !su_casematch(ac->ac_stale, "true"))
    ac->ac_stale = NULL;

  ac->ac_md5 = md5 != NULL || ac->ac_algorithm == NULL;
  ac->ac_md5sess = md5sess != NULL;
  ac->ac_sha1 = sha1 != NULL;
  ac->ac_auth = qop_auth != NULL;
  ac->ac_auth_int = qop_auth_int != NULL;

  auth_struct_copy(ac0, ac, sizeof(ac));

  SU_DEBUG_5(("%s(): got %d\n", "auth_ntlm_challenge_get", n));

  return n;
}
Ejemplo n.º 17
0
/* Return 1 if media type and protocol of m= line structs matches */
unsigned sdp_media_match_with(sdp_media_t const *a,
			      sdp_media_t const *b)
{
  if (a == NULL || b == NULL)
    return a == b;

  if (a->m_type == sdp_media_any || b->m_type == sdp_media_any)
    return 1;

  if (a->m_type != b->m_type ||
      (a->m_type == sdp_media_x
        && !su_casematch(b->m_type_name, a->m_type_name)))
    return 0;

  if (a->m_proto == sdp_proto_any || b->m_proto == sdp_proto_any)
    return 1;

  if (a->m_proto != b->m_proto ||
      (a->m_proto == sdp_proto_x
       && !su_casematch(b->m_proto_name, a->m_proto_name)))
    return 0;

  return 1;
}
Ejemplo n.º 18
0
/** Convert a @Via header to @Contact header.
 *
 * The @Contact URI will contain the port number if needed. If transport
 * protocol name starts with "TLS", "SIPS:" URI schema is used. Transport
 * parameter is included in the URI unless the transport protocol is UDP.
 *
 * @param home      memory home
 * @param v         @Via header field structure
 *                  (with <sent-protocol> and <sent-by> parameters)
 * @param user      username for @Contact URI (may be NULL)
 *
 * @retval contact header structure
 * @retval NULL upon an error
 *
 * @sa sip_contact_create_from_via_with_transport(),
 *     sip_contact_string_from_via()
 */
sip_contact_t *
sip_contact_create_from_via(su_home_t *home,
			    sip_via_t const *v,
			    char const *user)
{
  const char *tp;

  if (!v) return NULL;

  tp = v->v_protocol;

  if (tp == sip_transport_udp ||
      su_casematch(tp, sip_transport_udp))  /* Default is UDP */
    tp = NULL;

  return sip_contact_create_from_via_with_transport(home, v, user, tp);
}
Ejemplo n.º 19
0
static int test_casematch(void)
{
  BEGIN();

  TEST_1(!su_casematch(NULL, ""));
  TEST_1(su_casematch(NULL, NULL));
  TEST_1(!su_casematch("", NULL));

  TEST_1(!su_casenmatch(NULL, "", 1));
  TEST_1(su_casenmatch(NULL, NULL, 1));
  TEST_1(!su_casenmatch("", NULL, 1));

  TEST_1(su_casenmatch(NULL, "", 0));
  TEST_1(su_casenmatch(NULL, NULL, 0));
  TEST_1(su_casenmatch("", NULL, 0));

  TEST_1(su_casenmatch("foo", "foo", 3));
  TEST_1(su_casenmatch("FOO", "foo", 3));
  TEST_1(su_casenmatch("foo", "FOO", 3));

  TEST_1(su_casenmatch("foo", "foo", 4));
  TEST_1(su_casenmatch("FOO", "foo", 4));
  TEST_1(su_casenmatch("foo", "FOO", 4));

  TEST_1(su_casematch("foo", "foo"));
  TEST_1(su_casematch("FOO", "foo"));
  TEST_1(su_casematch("foo", "FOO"));

  TEST_1(!su_casematch("foo_", "foo"));
  TEST_1(!su_casematch("FOO_", "foo"));
  TEST_1(!su_casematch("foo_", "FOO"));

  TEST_1(su_casenmatch("foo\0X", "foo\0z", 5));
  TEST_1(su_casenmatch("FOO\0X", "foo\0z", 5));
  TEST_1(su_casenmatch("foo\0X", "FOO\0z", 5));

  END();
}
Ejemplo n.º 20
0
static
int li_name(su_localinfo_t const *hints,
	    int gni_flags,
	    su_sockaddr_t const *su,
	    char **ccanonname)
{
  char name[SU_MAXHOST];
  int error;
  int flags = hints->li_flags;

  *ccanonname = NULL;

  if ((flags & LI_CANONNAME) || hints->li_canonname) {
    if ((flags & LI_NAMEREQD) == LI_NAMEREQD)
      gni_flags |= NI_NAMEREQD;
    if (flags & LI_NUMERIC)
      gni_flags |= NI_NUMERICHOST;

    error = su_getnameinfo(su, su_sockaddr_size(su),
			   name, sizeof(name), NULL, 0,
			   gni_flags);
    if (error) {
      if ((flags & LI_NAMEREQD) == LI_NAMEREQD)
	return 1;
      SU_DEBUG_7(("li_name: getnameinfo() failed\n"));
      if (!su_inet_ntop(su->su_family, SU_ADDR(su), name, sizeof name))
	return ELI_RESOLVER;
    }

    if (hints->li_canonname && !su_casematch(name, hints->li_canonname))
      return 1;

    if (!(flags & LI_CANONNAME))
      return 0;

    if (!(*ccanonname = strdup(name)))
      return ELI_MEMORY;
  }
  return 0;
}
Ejemplo n.º 21
0
/** Find a credential header with matching scheme and realm. */
msg_auth_t *auth_mod_credentials(msg_auth_t *auth,
                                 char const *scheme,
                                 char const *realm)
{
    char const *arealm;

    for (; auth; auth = auth->au_next) {
        if (!su_casematch(auth->au_scheme, scheme))
            continue;

        if (!realm)
            return auth;

        arealm = msg_header_find_param(auth->au_common, "realm=");

        if (!arealm)
            continue;

        if (arealm[0] == '"') {
            /* Compare quoted arealm with unquoted realm */
            int i, j;
            for (i = 1, j = 0; arealm[i] != 0; i++, j++) {
                if (arealm[i] == '"' && realm[j] == 0)
                    return auth;

                if (arealm[i] == '\\' && arealm[i + 1] != '\0')
                    i++;

                if (arealm[i] != realm[j])
                    break;
            }
        } else {
            if (strcmp(arealm, realm) == 0)
                return auth;
        }
    }

    return NULL;
}
Ejemplo n.º 22
0
/** Calculate extra space required by sip_transport_dup() */
isize_t sip_transport_xtra(char const *transport)
{
  if (transport == sip_transport_udp ||
      transport == sip_transport_tcp ||
      transport == sip_transport_sctp ||
      transport == sip_transport_ws ||
      transport == sip_transport_wss ||
      transport == sip_transport_tls ||
      su_casematch(transport, sip_transport_udp) ||
      su_casematch(transport, sip_transport_tcp) ||
      su_casematch(transport, sip_transport_sctp) ||
      su_casematch(transport, sip_transport_ws) ||
      su_casematch(transport, sip_transport_wss) ||
      su_casematch(transport, sip_transport_tls))
    return 0;

  return MSG_STRING_SIZE(transport);
}
Ejemplo n.º 23
0
/** Remove a named attribute from a list of attributes. */
sdp_attribute_t *sdp_attribute_remove(sdp_attribute_t **list,
				      char const *name)
{
  sdp_attribute_t *a;

  assert(list);

  if (list == NULL)
    return NULL;
  if (name == NULL)
    return NULL;

  for (a = *list; a; list = &a->a_next, a = *list) {
    if (su_casematch(name, a->a_name))
      break;
  }

  if (a) {
    *list = a->a_next;
    a->a_next = NULL;
  }

  return a;
}
Ejemplo n.º 24
0
/** Decode transport */
issize_t sip_transport_d(char **ss, char const **ttransport)
{
  char const *transport;
  char *pn, *pv, *pt;
  size_t pn_len, pv_len, pt_len;
  char *s = *ss;

#define TRANSPORT_MATCH(t) \
  (su_casenmatch(s + 7, t + 7, (sizeof t) - 8) && \
   (!s[sizeof(t) - 1] || IS_LWS(s[sizeof(t) - 1]))	\
   && (transport = t, s += sizeof(t) - 1))

  if (!su_casenmatch(s, "SIP/2.0", 7) ||
      (!TRANSPORT_MATCH(sip_transport_udp) &&
       !TRANSPORT_MATCH(sip_transport_tcp) &&
       !TRANSPORT_MATCH(sip_transport_sctp) &&
       !TRANSPORT_MATCH(sip_transport_ws) &&
       !TRANSPORT_MATCH(sip_transport_wss) &&
       !TRANSPORT_MATCH(sip_transport_tls))) {
    /* Protocol name */
    transport = pn = s;
    skip_token(&s);
    pn_len = s - pn;
    skip_lws(&s);
    if (pn_len == 0 || *s++ != '/') return -1;
    skip_lws(&s);

    /* Protocol version */
    pv = s;
    skip_token(&s);
    pv_len = s - pv;
    skip_lws(&s);
    if (pv_len == 0 || *s++ != '/') return -1;
    skip_lws(&s);

    /* Transport protocol */
    pt = s;
    skip_token(&s);
    pt_len = s - pt;
    if (pt_len == 0) return -1;

    /* Remove whitespace between protocol name and version */
    if (pn + pn_len + 1 != pv) {
      pn[pn_len] = '/';
      pv = memmove(pn + pn_len + 1, pv, pv_len);
    }

    /* Remove whitespace between protocol version and transport */
    if (pv + pv_len + 1 != pt) {
      pv[pv_len] = '/';
      pt = memmove(pv + pv_len + 1, pt, pt_len);
      pt[pt_len] = '\0';

      /* extra whitespace? */
      if (su_casematch(transport, sip_transport_udp))
	transport = sip_transport_udp;
      else if (su_casematch(transport, sip_transport_tcp))
	transport = sip_transport_tcp;
      else if (su_casematch(transport, sip_transport_sctp))
	transport = sip_transport_sctp;
      else if (su_casematch(transport, sip_transport_ws))
	transport = sip_transport_ws;
      else if (su_casematch(transport, sip_transport_wss))
	transport = sip_transport_wss;
      else if (su_casematch(transport, sip_transport_tls))
	transport = sip_transport_tls;
    }
  }

  if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); }
  *ss = s;
  *ttransport = transport;
  return 0;
}
Ejemplo n.º 25
0
/** Find a Digest credential header with matching realm and opaque. */
msg_auth_t *auth_digest_credentials(msg_auth_t *auth,
                                    char const *realm,
                                    char const *opaque)
{
    char const *arealm, *aopaque;

    for (; auth; auth = auth->au_next) {
        if (!su_casematch(auth->au_scheme, "Digest"))
            continue;

        if (realm) {
            int cmp = 1;

            arealm = msg_header_find_param(auth->au_common, "realm=");
            if (!arealm)
                continue;

            if (arealm[0] == '"') {
                /* Compare quoted arealm with unquoted realm */
                int i, j;
                for (i = 1, j = 0, cmp = 1; arealm[i] != 0; i++, j++) {
                    if (arealm[i] == '"' && realm[j] == 0) {
                        cmp = 0;
                        break;
                    }

                    if (arealm[i] == '\\' && arealm[i + 1] != '\0')
                        i++;

                    if (arealm[i] != realm[j])
                        break;
                }
            }
            else {
                cmp = strcmp(arealm, realm);
            }

            if (cmp)
                continue;
        }

        if (opaque) {
            int cmp = 1;

            aopaque = msg_header_find_param(auth->au_common, "opaque=");
            if (!aopaque)
                continue;

            if (aopaque[0] == '"') {
                /* Compare quoted aopaque with unquoted opaque */
                int i, j;
                for (i = 1, j = 0, cmp = 1; aopaque[i] != 0; i++, j++) {
                    if (aopaque[i] == '"' && opaque[j] == 0) {
                        cmp = 0;
                        break;
                    }

                    if (aopaque[i] == '\\' && aopaque[i + 1] != '\0')
                        i++;

                    if (aopaque[i] != opaque[j])
                        break;
                }
            } else {
                cmp = strcmp(aopaque, opaque);
            }

            if (cmp)
                continue;
        }

        return auth;
    }

    return NULL;
}
Ejemplo n.º 26
0
/** Verify digest authentication */
void auth_check_digest(auth_mod_t *am,
                       auth_status_t *as,
                       auth_response_t *ar,
                       auth_challenger_t const *ach)
{
    char const *a1;
    auth_hexmd5_t a1buf, response;
    auth_passwd_t *apw;
    char const *phrase;
    msg_time_t now = msg_now();

    if (am == NULL || as == NULL || ar == NULL || ach == NULL) {
        if (as) {
            as->as_status = 500, as->as_phrase = "Internal Server Error";
            as->as_response = NULL;
        }
        return;
    }

    phrase = "Bad authorization";

#define PA "Authorization missing "

    if ((!ar->ar_username && (phrase = PA "username")) ||
            (!ar->ar_nonce && (phrase = PA "nonce")) ||
            (!ar->ar_uri && (phrase = PA "URI")) ||
            (!ar->ar_response && (phrase = PA "response")) ||
            /* (!ar->ar_opaque && (phrase = PA "opaque")) || */
            /* Check for qop */
            (ar->ar_qop &&
             ((ar->ar_auth &&
               !su_casematch(ar->ar_qop, "auth") &&
               !su_casematch(ar->ar_qop, "\"auth\"")) ||
              (ar->ar_auth_int &&
               !su_casematch(ar->ar_qop, "auth-int") &&
               !su_casematch(ar->ar_qop, "\"auth-int\"")))
             && (phrase = PA "has invalid qop"))) {
        assert(phrase);
        SU_DEBUG_5(("auth_method_digest: 400 %s\n", phrase));
        as->as_status = 400, as->as_phrase = phrase;
        as->as_response = NULL;
        return;
    }

    if (as->as_nonce_issued == 0 /* Already validated nonce */ &&
            auth_validate_digest_nonce(am, as, ar, now) < 0) {
        as->as_blacklist = am->am_blacklist;
        auth_challenge_digest(am, as, ach);
        return;
    }

    if (as->as_stale) {
        auth_challenge_digest(am, as, ach);
        return;
    }

    apw = auth_mod_getpass(am, ar->ar_username, ar->ar_realm);

    if (apw && apw->apw_hash)
        a1 = apw->apw_hash;
    else if (apw && apw->apw_pass)
        auth_digest_a1(ar, a1buf, apw->apw_pass), a1 = a1buf;
    else
        auth_digest_a1(ar, a1buf, "xyzzy"), a1 = a1buf, apw = NULL;

    if (ar->ar_md5sess)
        auth_digest_a1sess(ar, a1buf, a1), a1 = a1buf;

    auth_digest_response(ar, response, a1,
                         as->as_method, as->as_body, as->as_bodylen);

    if (!apw || strcmp(response, ar->ar_response)) {

        if (am->am_forbidden) {
            as->as_status = 403, as->as_phrase = "Forbidden";
            as->as_response = NULL;
            as->as_blacklist = am->am_blacklist;
        }
        else {
            auth_challenge_digest(am, as, ach);
            as->as_blacklist = am->am_blacklist;
        }
        SU_DEBUG_5(("auth_method_digest: response did not match\n"));

        return;
    }

    assert(apw);

    as->as_user = apw->apw_user;
    as->as_anonymous = apw == am->am_anon_user;
    as->as_ident = apw->apw_ident;

    if (am->am_nextnonce || am->am_mutual)
        auth_info_digest(am, as, ach);

    if (am->am_challenge)
        auth_challenge_digest(am, as, ach);

    SU_DEBUG_7(("auth_method_digest: successful authentication\n"));

    as->as_status = 0;	/* Successful authentication! */
    as->as_phrase = "";
}
Ejemplo n.º 27
0
/** Extract the HTTP message body, including separator line.
 *
 * @retval -1    error
 * @retval 0     cannot proceed
 * @retval other number of bytes extracted
 */
issize_t http_extract_body(msg_t *msg, http_t *http, char b[], isize_t bsiz, int eos)
{
  issize_t m = 0;
  size_t body_len;

  int flags = http->http_flags;

  if (eos && bsiz == 0) {
    msg_mark_as_complete(msg, MSG_FLG_COMPLETE);
    return 0;
  }

  if (flags & MSG_FLG_TRAILERS) {
    /* The empty line after trailers */
    if (!eos && (bsiz == 0 || (bsiz == 1 && b[0] == '\r')))
      return 0;

    m = CRLF_TEST(b);

    assert(m > 0 || eos); /* We should be looking at an empty line */

    /* We have completed trailers */
    msg_mark_as_complete(msg, MSG_FLG_COMPLETE);

    return m;
  }

  if (flags & MSG_FLG_CHUNKS)
    return http_extract_chunk(msg, http, b, bsiz, eos);

  if (!(flags & MSG_FLG_BODY)) {
    /* We are looking at a potential empty line */
    m = msg_extract_separator(msg, http, b, bsiz, eos);

    if (m == 0)			/* Not yet */
      return 0;

    http->http_flags |= MSG_FLG_BODY;
    b += m, bsiz -= m;
  }

  /* body_len is determined by rules in RFC2616 sections 4.3 and 4.4 */

  /* 1XX, 204, 304 do not have message-body, ever */
  if (http->http_status) {
    int status = http->http_status->st_status;

    if (status < 200 || status == 204 || status == 304)
      flags |= HTTP_FLG_NO_BODY;
  }

  if (flags & HTTP_FLG_NO_BODY) {
    msg_mark_as_complete(msg, MSG_FLG_COMPLETE);
    return m;
  }

  if (http->http_transfer_encoding) {
    if (/* NOTE - there is really no Transfer-Encoding: identity in RFC 2616
	 * but it was used in drafts...
	 */
	http->http_transfer_encoding->k_items &&
	http->http_transfer_encoding->k_items[0] &&
	!su_casematch(http->http_transfer_encoding->k_items[0], "identity")) {
      http->http_flags |= MSG_FLG_CHUNKS;

      if (http->http_flags & MSG_FLG_STREAMING)
	msg_set_streaming(msg, msg_start_streaming);

      if (m)
	return m;

      return http_extract_chunk(msg, http, b, bsiz, eos);
    }
  }


  if (http->http_content_length)
    body_len = http->http_content_length->l_length;
  /* We cannot parse multipart/byteranges ... */
  else if (http->http_content_type && http->http_content_type->c_type &&
	   su_casematch(http->http_content_type->c_type, "multipart/byteranges"))
    return -1;
  else if (MSG_IS_MAILBOX(flags)) /* message fragments */
    body_len = 0;
  else if (http->http_request)
    body_len = 0;
  else if (eos)
    body_len = bsiz;
  else
    return 0;			/* XXX */

  if (body_len == 0) {
    msg_mark_as_complete(msg, MSG_FLG_COMPLETE);
    return m;
  }

  if (http->http_flags & MSG_FLG_STREAMING)
    msg_set_streaming(msg, msg_start_streaming);

  if (m)
    return m;

  m = msg_extract_payload(msg, http, NULL, body_len, b, bsiz, eos);
  if (m == -1)
    return -1;

  /* We have now all message fragments in place */
  http->http_flags |= MSG_FLG_FRAGS;
  if (bsiz >= body_len) {
    msg_mark_as_complete(msg, MSG_FLG_COMPLETE);
  }

  return m;
}
Ejemplo n.º 28
0
/**@internal
 *
 * Detect NAT.
 *
 * Based on "received" and possible "rport" parameters in the top-most Via,
 * check and update our NAT status.
 *
 * @retval ob_nat_changed (2) change in public NAT binding detected
 * @retval ob_nat_detected (1) NAT binding detected
 * @retval ob_no_nat (0) no NAT binding detected
 * @retval -1 an error occurred
 */
static
int outbound_nat_detect(outbound_t *ob,
			sip_t const *request,
			sip_t const *response)
{
  sip_via_t const *v;
  int one = 1;
  char const *received, *rport;
  char *nat_detected, *nat_port;
  char *new_detected, *new_port;

  assert(request && request->sip_request);
  assert(response && response->sip_status);

  if (!ob || !response || !response->sip_via || !request->sip_via)
    return -1;

  v = response->sip_via;

  received = v->v_received;
  if (!received || !strcmp(received, request->sip_via->v_host))
    return 0;

  if (!host_is_ip_address(received)) {
    if (received[0])
      SU_DEBUG_3(("outbound(%p): Via with invalid received=%s\n",
		  (void *)ob->ob_owner, received));
    return 0;
  }

  rport = sip_via_port(v, &one); assert(rport);

  nat_detected = ob->ob_nat_detected;
  nat_port = ob->ob_nat_port;

  if (nat_detected && host_cmp(received, nat_detected) == 0) {
    if (nat_port && su_casematch(rport, nat_port))
      return 1;
    if (!v->v_rport || !v->v_rport[0])
      return 1;
  }

  if (!nat_detected) {
    SU_DEBUG_5(("outbound(%p): detected NAT: %s != %s\n",
		(void *)ob->ob_owner, v->v_host, received));
    if (ob->ob_oo && ob->ob_oo->oo_status)
      ob->ob_oo->oo_status(ob->ob_owner, ob, 101, "NAT detected", TAG_END());
  }
  else {
    SU_DEBUG_5(("outbound(%p): NAT binding changed: "
		"[%s]:%s != [%s]:%s\n",
		(void *)ob->ob_owner, nat_detected, nat_port, received, rport));
    if (ob->ob_oo && ob->ob_oo->oo_status)
      ob->ob_oo->oo_status(ob->ob_owner, ob, 102, "NAT binding changed", TAG_END());
  }

  /* Save our nat binding */
  new_detected = su_strdup(ob->ob_home, received);
  new_port = su_strdup(ob->ob_home, rport);

  if (!new_detected || !new_port) {
    su_free(ob->ob_home, new_detected);
    su_free(ob->ob_home, new_port);
    return -1;
  }

  ob->ob_nat_detected = new_detected;
  ob->ob_nat_port = new_port;

  su_free(ob->ob_home, nat_detected);
  su_free(ob->ob_home, nat_port);

  return 2;
}
Ejemplo n.º 29
0
/** Count or get matching records from cache */
static int
sres_cache_get0(sres_htable_t *htable,
		sres_rr_hash_entry_t **iter,
		uint16_t type,
		char const *domain,
		time_t now,
		sres_record_t **cached,
		int len,
		struct frame *previous)
{
  sres_cname_record_t *cname = NULL;
  int dcount = 0, derrorcount = 0, ccount = 0;

  for (; iter && *iter; iter = sres_htable_next(htable, iter)) {
    sres_record_t *rr = (*iter)->rr;

    if (rr == NULL)
      continue;
    if (now > (*iter)->rr_expires)
      continue;
    if (rr->sr_name == NULL)
      continue;
    if (!su_casematch(rr->sr_name, domain))
      continue;

    if (rr->sr_type == type || type == sres_qtype_any) {
      if (rr->sr_status == SRES_RECORD_ERR && type == sres_qtype_any)
	continue;
      if (cached) {
	if (dcount >= len)
	  return -1;
	cached[dcount] = rr, rr->sr_refcount++;
      }
      dcount++;
      if (rr->sr_status)
	derrorcount++;
    }

    if (type != sres_type_cname && rr->sr_type == sres_type_cname) {
      if (rr->sr_status == 0)
	cname = rr->sr_cname;
    }
  }

  if (cname && dcount == derrorcount) {
    /* Nothing found, trace CNAMEs */
    unsigned hash;
    struct frame *f, frame;
    frame.previous = previous;
    frame.domain = domain;

    hash = sres_hash_key(domain = cname->cn_cname);

    /* Check for cname loops */
    for (f = previous; f; f = f->previous) {
      if (su_casematch(domain, f->domain))
	break;
    }

    if (f == NULL) {
      ccount = sres_cache_get0(htable, sres_htable_hash(htable, hash),
			       type, domain, now,
			       cached ? cached + dcount : NULL,
			       cached ? len - dcount : 0,
			       &frame);
    }
    if (ccount < 0)
      return ccount;
  }

  return dcount + ccount;
}
Ejemplo n.º 30
0
su_inline
int tls_post_connection_check(tport_t *self, tls_t *tls)
{
  X509 *cert;
  int extcount;
  int i, j, error;

  if (!tls) return -1;

  cert = SSL_get_peer_certificate(tls->con);
  if (!cert) {
    SU_DEBUG_7(("%s(%p): Peer did not provide X.509 Certificate.\n", 
				__func__, (void *) self));
    if (self->tp_accepted && tls->verify_incoming)
      return X509_V_ERR_CERT_UNTRUSTED;
    else if (!self->tp_accepted && tls->verify_outgoing)
      return X509_V_ERR_CERT_UNTRUSTED;
    else 
      return X509_V_OK;
  }

  tls->subjects = su_strlst_create(tls->home);
  if (!tls->subjects)
    return X509_V_ERR_OUT_OF_MEM;

  extcount = X509_get_ext_count(cert);

  /* Find matching subjectAltName.DNS */
  for (i = 0; i < extcount; i++) {
    X509_EXTENSION *ext;
    char const *name;
#if OPENSSL_VERSION_NUMBER >  0x10000000L
    const X509V3_EXT_METHOD *vp;
#else
    X509V3_EXT_METHOD *vp;
#endif
    STACK_OF(CONF_VALUE) *values;
    CONF_VALUE *value;
    void *d2i;

    ext = X509_get_ext(cert, i);
    name = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext)));

    if (strcmp(name, "subjectAltName") != 0)
      continue;

    vp = X509V3_EXT_get(ext); if (!vp) continue;
    d2i = X509V3_EXT_d2i(ext);
    values = vp->i2v(vp, d2i, NULL);

    for (j = 0; j < sk_CONF_VALUE_num(values); j++) {
      value = sk_CONF_VALUE_value(values, j);
      if (strcmp(value->name, "DNS") == 0)
        su_strlst_dup_append(tls->subjects, value->value);
      if (strcmp(value->name, "IP") == 0)
        su_strlst_dup_append(tls->subjects, value->value);
      else if (strcmp(value->name, "URI") == 0)
        su_strlst_dup_append(tls->subjects, value->value);
    }
  }

  {
    X509_NAME *subject;
    char name[256];

    subject = X509_get_subject_name(cert);

    if (subject) {
      if (X509_NAME_get_text_by_NID(subject, NID_commonName,
				    name, sizeof name) > 0) {
	usize_t k, N = su_strlst_len(tls->subjects);
	name[(sizeof name) - 1] = '\0';

	for (k = 0; k < N; k++)
	  if (su_casematch(su_strlst_item(tls->subjects, k), name) == 0)
	    break;

	if (k >= N)
	  su_strlst_dup_append(tls->subjects, name);
      }
    }
  }

  X509_free(cert);

  error = SSL_get_verify_result(tls->con);

  if (cert && error == X509_V_OK)
    tls->x509_verified = 1;

  if (tport_log->log_level >= 7) {
    int i, len = su_strlst_len(tls->subjects);
    for (i=0; i < len; i++)
      SU_DEBUG_7(("%s(%p): Peer Certificate Subject %i: %s\n", \
				  __func__, (void *)self, i, su_strlst_item(tls->subjects, i)));
    if (i == 0)
      SU_DEBUG_7(("%s(%p): Peer Certificate provided no usable subjects.\n",
				  __func__, (void *)self));
  }

  /* Verify incoming connections */
  if (self->tp_accepted) {
    if (!tls->verify_incoming)
      return X509_V_OK;

    if (!tls->x509_verified)
      return error;

    if (tls->verify_subj_in) {
      su_strlst_t const *subjects = self->tp_pri->pri_primary->tp_subjects;
      int i, items;

      items = subjects ? su_strlst_len(subjects) : 0;
      if (items == 0)
        return X509_V_OK;

      for (i=0; i < items; i++) {
	if (tport_subject_search(su_strlst_item(subjects, i), tls->subjects))
	  return X509_V_OK;
      }
      SU_DEBUG_3(("%s(%p): Peer Subject Mismatch (incoming connection)\n", \
				  __func__, (void *)self));

      return X509_V_ERR_CERT_UNTRUSTED;
    }
  }
  /* Verify outgoing connections */
  else {
    char const *subject = self->tp_canon;
    if (!tls->verify_outgoing)
      return X509_V_OK;

    if (!tls->x509_verified || !subject)
      return error;

    if (tls->verify_subj_out) {
      if (tport_subject_search(subject, tls->subjects))
        return X509_V_OK; /* Subject match found in verified certificate chain */
      SU_DEBUG_3(("%s(%p): Peer Subject Mismatch (%s)\n", \
				  __func__, (void *)self, subject));

      return X509_V_ERR_CERT_UNTRUSTED;
    }
  }

  return error;
}