Пример #1
0
/**Check that we support all features which UAC requires.
 *
 * The list of supported features is compared with the list of features
 * required by the UAC. If some features are not listed as supported, return
 * 420. If @a irq is non-NULL, the 420 response message is sent to the
 * client along with list of unsupported features in the @Unsupported
 * header, too.
 *
 * @param   irq incoming transaction object (may be NULL).
 * @param   sip contents of the SIP message
 * @param supported   list of protocol features supported
 * @param tag, value, ... optional list of tagged arguments used
 *                        when responding to the transaction
 *
 * @return 0 if successful.
 * 420 if any of the required features is not supported.
 */
int nta_check_required(nta_incoming_t *irq,
		       sip_t const *sip,
		       sip_supported_t const *supported,
		       tag_type_t tag, tag_value_t value, ...)
{
  int status = 0;

  if (sip->sip_require) {
    su_home_t home[SU_HOME_AUTO_SIZE(512)];
    sip_unsupported_t *us;

    su_home_auto(home, sizeof home);

    us = sip_has_unsupported(home, supported, sip->sip_require);

    if (us) {
      status = 420;
      if (irq) {
	ta_list ta;
	ta_start(ta, tag, value);
	nta_incoming_treply(irq,
			    SIP_420_BAD_EXTENSION,
			    SIPTAG_UNSUPPORTED(us),
			    SIPTAG_SUPPORTED(supported),
			    ta_tags(ta));
	ta_end(ta);
      }
    }

    su_home_deinit(home);
  }

  return status;
}
Пример #2
0
/** Create a http site object.
 *
 * The function nth_site_create() allocates and initializes a web site
 * object. A web site object can be either
 * - a primary http server (@a parent is NULL),
 * - a virtual http server (@a address contains hostpart), or
 * - a site within a server
 *   (@a address does not have hostpart, only path part).
 *
 * @param parent pointer to parent site
 *               (NULL when creating a primary server object)
 * @param callback pointer to callback function called when
 *                 a request is received
 * @param magic    application context included in callback parameters
 * @param address  absolute or relative URI specifying the address of
 *                 site
 * @param tag, value, ... list of tagged parameters
 *
 * @TAGS
 * If the @a parent is NULL, the list of tagged parameters must contain
 * NTHTAG_ROOT() used to create the server engine. Tags supported when @a
 * parent is NULL are NTHTAG_ROOT(), NTHTAG_MCLASS(), TPTAG_REUSE(),
 * HTTPTAG_SERVER(), and HTTPTAG_SERVER_STR(). All the tags are passed to
 * tport_tcreate() and tport_tbind(), too.
 *
 * @since Support for multiple sites was added to @VERSION_1_12_4
 */
nth_site_t *nth_site_create(nth_site_t *parent,
			    nth_request_f *callback,
			    nth_site_magic_t *magic,
			    url_string_t const *address,
			    tag_type_t tag, tag_value_t value,
			    ...)
{
  nth_site_t *site = NULL, **prev = NULL;
  su_home_t home[SU_HOME_AUTO_SIZE(256)];
  url_t *url, url0[1];
  server_t *srv = NULL;
  ta_list ta;
  char *path = NULL;
  size_t usize;
  int is_host, is_path, wildcard = 0;

  su_home_auto(home, sizeof home);

  if (parent && url_is_string(address)) {
    char const *s = (char const *)address;
    size_t sep = strcspn(s, "/:");

    if (parent->site_path) {
      /* subpath */
      url_init(url0, (enum url_type_e)parent->site_url->url_type);
      url0->url_path = s;
      address = (url_string_t*)url0;
    }
    else if (s[sep] == ':')
      /* absolute URL with scheme */;
    else if (s[sep] == '\0' && strchr(s, '.') && host_is_valid(s)) {
      /* looks like a domain name */;
      url_init(url0, (enum url_type_e)parent->site_url->url_type);
      url0->url_host = s;
      address = (url_string_t*)url0;
    }
    else {
      /* looks like a path */
      url_init(url0, (enum url_type_e)parent->site_url->url_type);
      url0->url_path = s;
      address = (url_string_t*)url0;
    }
  }

  url = url_hdup(home, address->us_url);

  if (!url || !callback)
    return NULL;

  is_host = url->url_host != NULL;
  is_path = url->url_path != NULL;

  if (is_host && is_path) {
    SU_DEBUG_3(("nth_site_create(): virtual host and path simultanously\n"));
    errno = EINVAL;
    goto error;
  }

  if (!parent && !is_host) {
    SU_DEBUG_3(("nth_site_create(): host is required\n"));
    errno = EINVAL;
    goto error;
  }

  if (parent) {
    if (!parent->site_isdir) {
      SU_DEBUG_3(("nth_site_create(): invalid parent resource \n"));
      errno = EINVAL;
      goto error;
    }

    srv = parent->site_server; assert(srv);
    if (is_host) {
      prev = site_get_host(&srv->srv_sites, url->url_host, url->url_port);

      if (prev == NULL) {
	SU_DEBUG_3(("nth_site_create(): host %s:%s already exists\n",
		    url->url_host, url->url_port ? url->url_port : ""));
	errno = EEXIST;
	goto error;
      }
    }
    else {
      size_t i, j;

      path = (char *)url->url_path;
      while (path[0] == '/')
	path++;

      /* Remove duplicate // */
      for (i = j = 0; path[i];) {
	while (path[i] == '/' && path[i + 1] == '/')
	  i++;
	path[j++] = path[i++];
      }
      path[j] = path[i];

      url = url0, *url = *parent->site_url;

      if (url->url_path) {
	url->url_path = su_strcat(home, url->url_path, path);
	if (!url->url_path)
	  goto error;
	path = (char *)url->url_path + strlen(parent->site_url->url_path);
      }
      else
	url->url_path = path;

      prev = site_get_rslot(parent, path, &path);

      if (!prev || path[0] == '\0') {
	SU_DEBUG_3(("nth_site_create(): directory \"%s\" already exists\n",
		    url->url_path));
	errno = EEXIST;
	goto error;
      }
    }
  }

  if (!parent) {
    if (strcmp(url->url_host, "*") == 0 ||
	host_cmp(url->url_host, "0.0.0.0") == 0 ||
	host_cmp(url->url_host, "::") == 0)
      wildcard = 1, url->url_host = "*";
  }

  usize = sizeof(*url) + url_xtra(url);

  ta_start(ta, tag, value);

  if (!parent) {
    srv = server_create(url, ta_tags(ta));
    prev = &srv->srv_sites;
  }

  if (srv && (site = su_zalloc(srv->srv_home, (sizeof *site) + usize))) {
    site->site_url = (url_t *)(site + 1);
    url_dup((void *)(site->site_url + 1), usize - sizeof(*url),
	    site->site_url, url);

    assert(prev);
    if ((site->site_next = *prev))
      site->site_next->site_prev = &site->site_next;
    *prev = site, site->site_prev = prev;
    site->site_server = srv;

    if (path) {
      size_t path_len;

      site->site_path = site->site_url->url_path + (path - url->url_path);
      path_len = strlen(site->site_path); assert(path_len > 0);
      if (path_len > 0 && site->site_path[path_len - 1] == '/')
	path_len--, site->site_isdir = 1;
      site->site_path_len = path_len;
    }
    else {
      site->site_isdir = is_host;
      site->site_path = "";
      site->site_path_len = 0;
    }

    site->site_wildcard = wildcard;
    site->site_callback = callback;
    site->site_magic = magic;

    if (parent)
      site->site_auth = parent->site_auth;

    nth_site_set_params(site, ta_tags(ta));
  }

  ta_end(ta);

 error:
  su_home_deinit(home);
  return site;
}
Пример #3
0
/**
 * Updates the modified copy of local SDP based
 * on application provided local SDP and remote SDP.
 */
static int offer_answer_step(soa_session_t *ss,
			     enum offer_answer_action action,
			     char const *by)
{
  soa_static_session_t *sss = (soa_static_session_t *)ss;

  sdp_session_t *local = ss->ss_local->ssd_sdp;
  sdp_session_t local0[1];

  sdp_session_t *user = ss->ss_user->ssd_sdp;
  unsigned user_version = ss->ss_user_version;

  sdp_session_t *remote = ss->ss_remote->ssd_sdp;
  unsigned remote_version = ss->ss_remote_version;

  int fresh = 0;

  sdp_origin_t o[1] = {{ sizeof(o) }};
  sdp_connection_t *c, c0[1] = {{ sizeof(c0) }};
  char c0_buffer[64];

  sdp_time_t t[1] = {{ sizeof(t) }};

  int *u2s = NULL, *s2u = NULL, *tbf;

  sdp_session_t *latest = NULL, *previous = NULL;

  char const *phrase = "Internal Media Error";

  su_home_t tmphome[SU_HOME_AUTO_SIZE(8192)];

  su_home_auto(tmphome, sizeof tmphome);

  SU_DEBUG_7(("soa_static_offer_answer_action(%p, %s): called\n",
	      (void *)ss, by));

  if (user == NULL)
    return soa_set_status(ss, 500, "No session set by user");

  if (action == generate_offer)
    remote = NULL;
  else if (remote == NULL)
    return soa_set_status(ss, 500, "No remote SDP");

  /* Pre-negotiation Step: Expand truncated remote SDP */
  if (local && remote) switch (action) {
  case generate_answer:
  case process_answer:
    if (sdp_media_count(remote, sdp_media_any, "*", (sdp_proto_e)0, (sdp_text_t)0) <
	sdp_media_count(local, sdp_media_any, "*", (sdp_proto_e)0, (sdp_text_t)0)) {
      SU_DEBUG_5(("%s: remote %s is truncated: expanding\n",
		  by, action == generate_answer ? "offer" : "answer"));
      remote = soa_sdp_expand_media(tmphome, remote, local);
      if (remote == NULL)
	return soa_set_status(ss, 500, "Cannot expand remote session");
    }
  default:
    break;
  }

  /* Step A: Create local SDP session (based on user-supplied SDP) */
  if (local == NULL) switch (action) {
  case generate_offer:
  case generate_answer:
    SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by,
		"generating local description"));

    fresh = 1;
    local = local0;
    *local = *user, local->sdp_media = NULL;

    o->o_username = "******";
    o->o_address = c0;
    c0->c_address = c0_buffer;

    if (!local->sdp_origin)
      local->sdp_origin = o;
    break;

  case process_answer:
  default:
    goto internal_error;
  }

  /* Step B: upgrade local SDP (add m= lines to it)  */
  switch (action) {
  case generate_offer:
    /* Upgrade local SDP based on user SDP */
    if (local != local0 && ss->ss_local_user_version == user_version)
      break;
    if (local != local0)
      *local0 = *local, local = local0;
    SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by,
		"upgrade with local description"));
    if (soa_sdp_upgrade(ss, tmphome, local, user, NULL, &u2s, &s2u) < 0)
      goto internal_error;
    break;
  case generate_answer:
    /* Upgrade local SDP based on remote SDP */
    if (ss->ss_local_user_version == user_version &&
	ss->ss_local_remote_version == remote_version)
      break;
    if (1) {
      if (local != local0)
	*local0 = *local, local = local0;
      SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by,
		  "upgrade with remote description"));
      if (soa_sdp_upgrade(ss, tmphome, local, user, remote, &u2s, &s2u) < 0)
	goto internal_error;
    }
    break;
  case process_answer:
  default:
    break;
  }


  /* Step C: reject media */
  switch (action) {
  case generate_offer:
    /* Local media is marked as rejected already in upgrade phase */
    break;
  case generate_answer:
  case process_answer:
    if (ss->ss_local_remote_version == remote_version)
      break;
    if (soa_sdp_reject_is_needed(local, remote)) {
      if (local != local0) {
	*local0 = *local, local = local0;
#define DUP_LOCAL(local)					 \
	do {							 \
	  if (!local->sdp_media) break;				 \
	  local->sdp_media =					 \
	    sdp_media_dup_all(tmphome, local->sdp_media, local); \
	  if (!local->sdp_media)				 \
	    goto internal_error;				 \
	} while (0)
	DUP_LOCAL(local);
      }
      SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by,
		  "marking rejected media"));
      soa_sdp_reject(tmphome, local, remote);
    }
    break;
  default:
    break;
  }

  /* Step D: Set media mode bits */
  switch (action) {
    int const *s2u_;

  case generate_offer:
  case generate_answer:
  case process_answer:
    s2u_ = s2u;

    if (!s2u_) s2u_ = sss->sss_s2u;

    if (soa_sdp_mode_set(user, s2u_, local, remote, ss->ss_hold, 1)) {
      if (local != local0) {
	*local0 = *local, local = local0;
	DUP_LOCAL(local);
      }

      soa_sdp_mode_set(user, s2u_, local, remote, ss->ss_hold, 0);
    }
    break;
  default:
    break;
  }

  /* Step E: Upgrade codecs by answer. */
  switch (action) {
  case process_answer:
    /* Upgrade local SDP based on remote SDP */
    if (ss->ss_local_remote_version == remote_version)
      break;
    if (1 /* We don't have good test for codecs */) {
      SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by,
		  "upgrade codecs with remote description"));
      if (local != local0) {
	*local0 = *local, local = local0;
	DUP_LOCAL(local);
      }
      soa_sdp_session_upgrade_rtpmaps(ss, local, remote);
    }
    break;
  case generate_offer:
  case generate_answer:
  default:
    break;
  }

  /* Step F0: Initialize o= line */
  if (fresh) {
	if (user->sdp_origin) {
      o->o_username = user->sdp_origin->o_username;

	  if (user->sdp_origin->o_address)
	    o->o_address = user->sdp_origin->o_address;

      if (user->sdp_origin->o_id)
		  o->o_id = user->sdp_origin->o_id;

	  if (user->sdp_origin->o_version && user->sdp_origin->o_version != o->o_version) {
		  o->o_version = user->sdp_origin->o_version;
		  o->o_version--;
	  }
	}

    if (soa_init_sdp_origin_with_session(ss, o, c0_buffer, local) < 0) {
      phrase = "Cannot Get IP Address for Session Description";
      goto internal_error;
    }

    local->sdp_origin = o;
  }

  /* Step F: Update c= line(s) */
  switch (action) {
    sdp_connection_t *user_c, *local_c;

  case generate_offer:
  case generate_answer:
    user_c = user->sdp_connection;
    if (!soa_check_sdp_connection(user_c))
      user_c = NULL;

    local_c = local->sdp_connection;
    if (!soa_check_sdp_connection(local_c))
      local_c = NULL;

    if (ss->ss_local_user_version != user_version ||
	local_c == NULL ||
	(user_c != NULL && sdp_connection_cmp(local_c, user_c))) {
      sdp_media_t *m;

      if (user_c)
	c = user_c;
      else
	c = local->sdp_origin->o_address;

      /* Every m= line (even rejected one) must have a c= line
       * or there must be a c= line at session level
       */
      for (m = local->sdp_media; m; m = m->m_next)
	if (m->m_connections == NULL)
	  break;

      if (m) {
	if (local != local0) {
	  *local0 = *local, local = local0;
	  DUP_LOCAL(local);
	}
	local->sdp_connection = c;
      }
    }
    break;

  default:
    break;
  }

  soa_description_free(ss, ss->ss_previous);
  su_free(ss->ss_home, sss->sss_previous.u2s), sss->sss_previous.u2s = NULL;
  su_free(ss->ss_home, sss->sss_previous.s2u), sss->sss_previous.s2u = NULL;

  if (u2s) {
    u2s = u2s_alloc(ss->ss_home, u2s);
    s2u = u2s_alloc(ss->ss_home, s2u);
    if (!u2s || !s2u)
      goto internal_error;
  }

  if (ss->ss_local->ssd_sdp != local &&
      sdp_session_cmp(ss->ss_local->ssd_sdp, local)) {
    int bump;

    switch (action) {
    case generate_offer:
      bump = sdp_session_cmp(local, sss->sss_latest);
      break;
    case generate_answer:
      bump = 1;
      break;
    case process_answer:
    default:
      bump = 0;
      break;
    }

    if (bump) {
      /* Upgrade the version number */
      if (local->sdp_origin != o)
	*o = *local->sdp_origin, local->sdp_origin = o;
      o->o_version++;
    }

    /* Do sanity checks for the created SDP */
    if (!local->sdp_subject)	/* s= is mandatory */
      local->sdp_subject = "-";
    if (!local->sdp_time)	/* t= is mandatory */
      local->sdp_time = t;

    if (action == generate_offer) {
      /* Keep a copy of previous session state */
      int *previous_u2s = u2s_alloc(ss->ss_home, sss->sss_u2s);
      int *previous_s2u = u2s_alloc(ss->ss_home, sss->sss_s2u);

      if ((sss->sss_u2s && !previous_u2s) || (sss->sss_s2u && !previous_s2u))
	goto internal_error;

      *ss->ss_previous = *ss->ss_local;
      memset(ss->ss_local, 0, (sizeof *ss->ss_local));
      ss->ss_previous_user_version = ss->ss_local_user_version;
      ss->ss_previous_remote_version = ss->ss_local_remote_version;
      sss->sss_previous.u2s = previous_u2s;
      sss->sss_previous.s2u = previous_s2u;
    }

    SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by,
		"storing local description"));

    /* Update the unparsed and pretty-printed descriptions  */
    if (soa_description_set(ss, ss->ss_local, local, NULL, 0) < 0) {
      if (action == generate_offer) {
	/* Remove 2nd reference to local session state */
	memset(ss->ss_previous, 0, (sizeof *ss->ss_previous));
	ss->ss_previous_user_version = 0;
	ss->ss_previous_remote_version = 0;
	su_free(ss->ss_home, sss->sss_previous.u2s), sss->sss_previous.u2s = NULL;
	su_free(ss->ss_home, sss->sss_previous.s2u), sss->sss_previous.s2u = NULL;
      }

      su_free(ss->ss_home, u2s), su_free(ss->ss_home, s2u);

      goto internal_error;
    }

    if (bump) {
      latest = sdp_session_dup(ss->ss_home, ss->ss_local->ssd_sdp);
      previous = sss->sss_latest;
    }
  }

  if (u2s) {
    tbf = sss->sss_u2s, sss->sss_u2s = u2s, su_free(ss->ss_home, tbf);
    tbf = sss->sss_s2u, sss->sss_s2u = s2u, su_free(ss->ss_home, tbf);
  }

  /* Update version numbers */
  switch (action) {
  case generate_offer:
    ss->ss_local_user_version = user_version;
    sss->sss_latest = latest;
    break;
  case generate_answer:
    ss->ss_local_user_version = user_version;
    ss->ss_local_remote_version = remote_version;
    sss->sss_latest = latest;
    break;
  case process_answer:
    ss->ss_local_remote_version = remote_version;
  default:
    break;
  }

  if (previous)
    su_free(ss->ss_home, previous);

  su_home_deinit(tmphome);
  return 0;

 internal_error:
  su_home_deinit(tmphome);
  return soa_set_status(ss, 500, phrase);
}
Пример #4
0
static int tport_ws_init_primary_secure(tport_primary_t *pri,
				 tp_name_t tpn[1],
				 su_addrinfo_t *ai,
				 tagi_t const *tags,
				 char const **return_culprit)
{
  tport_ws_primary_t *wspri = (tport_ws_primary_t *)pri;
  const char *cert = "/ssl.pem";
  const char *key = "/ssl.pem";
  char *homedir;
  char *tbf = NULL;
  su_home_t autohome[SU_HOME_AUTO_SIZE(1024)];
  char const *path = NULL;
  int ret = -1;

  su_home_auto(autohome, sizeof autohome);

  tl_gets(tags,
	  TPTAG_CERTIFICATE_REF(path),
	  TAG_END());

  if (!path) {
    homedir = getenv("HOME");
    if (!homedir)
      homedir = "";
    path = tbf = su_sprintf(autohome, "%s/.sip/auth", homedir);
  }

  if (path) {
    key  = su_sprintf(autohome, "%s/%s", path, "wss.key");
	if (access(key, R_OK) != 0) key = NULL;
	cert = su_sprintf(autohome, "%s/%s", path, "wss.crt");
	if (access(cert, R_OK) != 0) cert = NULL;
	if ( !key )  key  = su_sprintf(autohome, "%s/%s", path, "wss.pem");
	if ( !cert ) cert = su_sprintf(autohome, "%s/%s", path, "wss.pem");
	if (access(key, R_OK) != 0) key = NULL;
	if (access(cert, R_OK) != 0) cert = NULL;
  }

  init_ssl();

  //  OpenSSL_add_all_algorithms();   /* load & register cryptos */                                                                                       
  //  SSL_load_error_strings();     /* load all error messages */                                                                                         
  wspri->ssl_method = SSLv23_server_method();   /* create server instance */
  wspri->ssl_ctx = SSL_CTX_new((SSL_METHOD *)wspri->ssl_method);         /* create context */
  SSL_CTX_sess_set_remove_cb(wspri->ssl_ctx, NULL);
  wspri->ws_secure = 1;

  if ( !wspri->ssl_ctx ) goto done;

  /* set the local certificate from CertFile */
  SSL_CTX_use_certificate_file(wspri->ssl_ctx, cert, SSL_FILETYPE_PEM);
  /* set the private key from KeyFile */
  SSL_CTX_use_PrivateKey_file(wspri->ssl_ctx, key, SSL_FILETYPE_PEM);
  /* verify private key */
  if ( !SSL_CTX_check_private_key(wspri->ssl_ctx) ) {
	  goto done;
  }

  SSL_CTX_set_cipher_list(wspri->ssl_ctx, "HIGH:!DSS:!aNULL@STRENGTH");

  ret = tport_ws_init_primary(pri, tpn, ai, tags, return_culprit);

 done:
  su_home_zap(autohome);
  return ret;
}
Пример #5
0
static int test_auto(void)
{
  BEGIN();

  int i;
  su_home_t tmphome[SU_HOME_AUTO_SIZE(8000)];
  char *b = NULL;
  su_home_stat_t hs[1];

  TEST_1(!su_home_auto(tmphome, sizeof tmphome[0]));
  TEST_1(su_home_auto(tmphome, sizeof tmphome));

  for (i = 0; i < 8192; i++)
    TEST_1(su_alloc(tmphome, 12));

  TEST_VOID(su_home_deinit(tmphome));

  TEST_1(su_home_auto(tmphome, sizeof tmphome));

  su_home_init_stats(tmphome);

  for (i = 1; i < 8192; i++) {
    TEST_1(b = su_realloc(tmphome, b, i));
    b[i - 1] = '\125';
  }

  for (i = 1; i < 8192; i++) {
    TEST(b[i - 1], '\125');
  }

  for (i = 1; i < 8192; i++) {
    TEST_1(b = su_realloc(tmphome, b, i));
    b[i - 1] = '\125';

    if ((i % 32) == 0)
      TEST_1(b = su_realloc(tmphome, b, 1));
  }

  su_home_get_stats(tmphome, 0, hs, sizeof *hs);

  TEST64(hs->hs_allocs.hsa_preload + hs->hs_allocs.hsa_number,
	  8191 + 8191 + 8191 / 32);
  TEST64(hs->hs_frees.hsf_preload + hs->hs_frees.hsf_number,
	 8191 + 8191 + 8191 / 32 - 1);
  /*
    This test depends on macro SU_HOME_AUTO_SIZE() calculating
    offsetof(su_block_t, sub_nodes[7]) correctly with

    ((3 * sizeof (void *) + 4 * sizeof(unsigned) +
      7 * (sizeof (long) + sizeof(void *)) + 7)
  */
  TEST_1(hs->hs_frees.hsf_preload == hs->hs_allocs.hsa_preload);

  su_free(tmphome, b);

  for (i = 1; i < 8192; i++)
    TEST_1(b = su_alloc(tmphome, 1));

  TEST_VOID(su_home_deinit(tmphome));

  END();
}