Exemplo n.º 1
0
static
void he_recv_message(nth_engine_t * he,
		     tport_t * tport, msg_t *msg, void *arg, su_time_t now)
{
  nth_client_t *hc, **hcp;
  tp_name_t const *tpn;

  for (hcp = hc_htable_hash(he->he_clients, (hash_value_t)(uintptr_t) tport);
       (hc = *hcp); hcp = hc_htable_next(he->he_clients, hcp)) {
    if (hc->hc_tport == tport) {
      if (hc_recv(hc, msg, http_object(msg)) < 0)
	msg_destroy(msg);
      return;
    }
  }

  /* Extra response? Framing error? */

  tpn = tport_name(tport);

  if (msg_size(msg))
    SU_DEBUG_3(("nth client: received extra data ("MOD_ZU" bytes) "
		"from %s/%s:%s\n",
		(size_t)msg_size(msg),
		tpn->tpn_proto, tpn->tpn_host, tpn->tpn_port));
  else
    SU_DEBUG_3(("nth client: received extra data from %s/%s:%s\n",
		tpn->tpn_proto, tpn->tpn_host, tpn->tpn_port));

  msg_destroy(msg);
  tport_shutdown(tport, 2);
}
Exemplo n.º 2
0
static
int tls_verify_cb(int ok, X509_STORE_CTX *store)
{
  if (!ok)
  {
    char data[256];

    X509 *cert = X509_STORE_CTX_get_current_cert(store);
    int  depth = X509_STORE_CTX_get_error_depth(store);
    int  err = X509_STORE_CTX_get_error(store);
    int  sslidx = SSL_get_ex_data_X509_STORE_CTX_idx();
    SSL  *ssl = X509_STORE_CTX_get_ex_data(store, sslidx);
    tls_t *tls = SSL_get_ex_data(ssl, tls_ex_data_idx);

    assert(tls);

#define TLS_VERIFY_CB_CLEAR_ERROR(OK,ERR,STORE) \
                   do {\
                     OK = 1;\
		     ERR = X509_V_OK;\
		     X509_STORE_CTX_set_error(STORE,ERR);\
		   } while (0)

    if (tls->accept && !tls->verify_incoming)
      TLS_VERIFY_CB_CLEAR_ERROR(ok, err, store);
    else if (!tls->accept && !tls->verify_outgoing)
      TLS_VERIFY_CB_CLEAR_ERROR(ok, err, store);
    else switch (err) {
      case X509_V_ERR_CERT_NOT_YET_VALID:
      case X509_V_ERR_CERT_HAS_EXPIRED:
      case X509_V_ERR_CRL_NOT_YET_VALID:
      case X509_V_ERR_CRL_HAS_EXPIRED:
        if (!tls->verify_date)
	  TLS_VERIFY_CB_CLEAR_ERROR(ok, err, store);

      default:
        break;
    }

    if (!ok) {
      SU_DEBUG_3(("-Error with certificate at depth: %i\n", depth));
      X509_NAME_oneline(X509_get_issuer_name(cert), data, 256);
      SU_DEBUG_3(("  issuer   = %s\n", data));
      X509_NAME_oneline(X509_get_subject_name(cert), data, 256);
      SU_DEBUG_3(("  subject  = %s\n", data));
      SU_DEBUG_3(("  err %i:%s\n", err, X509_verify_cert_error_string(err)));
    }

  }

  return ok;
}
Exemplo n.º 3
0
/**Create a resolver.
 *
 * The function sres_resolver_create() is used to allocate and initialize
 * the resolver object using the Sofia asynchronous reactor #su_root_t.
 */
sres_resolver_t *
sres_resolver_create(su_root_t *root,
		     char const *conf_file_path,
		     tag_type_t tag, tag_value_t value, ...)
{
  sres_resolver_t *res;
  sres_sofia_t *srs;
  sres_cache_t *cache = NULL;
  ta_list ta;

  if (root == NULL)
    return su_seterrno(EFAULT), (void *)NULL;

  ta_start(ta, tag, value);
  tl_gets(ta_args(ta),
	  SRESTAG_RESOLV_CONF_REF(conf_file_path),
	  SRESTAG_CACHE_REF(cache),
	  TAG_END());
  ta_end(ta);

  res = sres_resolver_new_with_cache(conf_file_path, cache, NULL);
  srs = res ? su_zalloc(0, sizeof *srs) : NULL;

  if (res && srs) {
    su_timer_t *t;

    srs->srs_resolver = res;
    srs->srs_root = root;
    srs->srs_socket = INVALID_SOCKET;

    sres_resolver_set_async(res, sres_sofia_update, srs, 0);

    t = su_timer_create(su_root_task(root), SRES_RETRANSMIT_INTERVAL);
    srs->srs_timer = t;

    if (!srs->srs_timer)
      SU_DEBUG_3(("sres: cannot create timer\n"));
#if nomore
    else if (su_timer_set_for_ever(t, sres_sofia_timer, srs) < 0)
      SU_DEBUG_3(("sres: cannot set timer\n"));
#else
    else if (sres_resolver_set_timer_cb(res, sres_sofia_set_timer, srs) < 0)
      SU_DEBUG_3(("sres: cannot set timer cb\n"));
#endif
    else
      return res;		/* Success! */

    sres_resolver_destroy(res), res = NULL;
  }

  return res;
}
Exemplo n.º 4
0
/** Keepalive timer. */
void tport_keepalive_timer(tport_t *self, su_time_t now)
{
  unsigned timeout = self->tp_params->tpp_pingpong;

  if (timeout != 0) {
    if (self->tp_ptime.tv_sec && !self->tp_recv_close &&
	su_time_cmp(su_time_add(self->tp_ptime, timeout), now) < 0) {
      SU_DEBUG_3(("%s(%p): %s to " TPN_FORMAT "%s\n",
		  __func__, (void *)self,
		  "closing connection", TPN_ARGS(self->tp_name),
		  " because of PONG timeout"));
      tport_error_report(self, EPIPE, NULL);
      if (!self->tp_closed)
	tport_close(self);
      return;
    }
  }

  timeout = self->tp_params->tpp_keepalive;

  if (timeout != 0 && timeout != UINT_MAX) {
    if (su_time_cmp(su_time_add(self->tp_ktime, timeout), now) < 0) {
      tport_tcp_ping(self, now);
    }
  }
}
Exemplo n.º 5
0
static
void nua_dialog_log_usage(nua_owner_t *own, nua_dialog_state_t *ds)
{
  nua_dialog_usage_t *du;

  if (SU_LOG->log_level >= 3) {
    char buffer[160];
    size_t l = 0, N = sizeof buffer;
    ssize_t n;

    buffer[0] = '\0';

    for (du = ds->ds_usage; du; du = du->du_next) {
      msg_header_t const *h = (void *)du->du_event;

      if (!h)
	continue;

      n = sip_event_e(buffer + l, N - l, h, 0);
      if (n == -1)
	break;
      l += (size_t)n;
      if (du->du_next && l + 2 < sizeof(buffer)) {
	strcpy(buffer + l, ", ");
	l += 2;
      }
    }

    SU_DEBUG_3(("nua(%p): handle with %s%s%s\n", (void *)own,
		ds->ds_has_session ? "session and " : "",
		ds->ds_has_events ? "events " : "",
		buffer));
  }
}
Exemplo n.º 6
0
int forwarder_shutdown(forwarder_t *f)
{
  forwarder_t *f_peer = f->f_peer;
  su_sockaddr_t *su = f->f_dest;
  char buf[SU_ADDRSIZE];

  SU_DEBUG_3(("forwarder_shutdown: shutdown from %s:%u\n",
	      su_inet_ntop(su->su_family, SU_ADDR(su), buf, sizeof(buf)),
	      ntohs(su->su_port)));

  if (su_root_unregister(f->f_pr->pr_root, f->f_wait, forwarder_recv, f) < 0) {
    SU_DEBUG_1(("%s: su_root_unregister failed\n", __func__));
  }

  if (shutdown(f->f_socket, 0) < 0) {
    SU_DEBUG_1(("shutdown(0): %s\n", su_strerror(su_errno())));
  }
  f_peer->f_shutdown = 1;
  if (!f_peer->f_buf) {
    if (shutdown(f_peer->f_socket, 1) < 0) {
      SU_DEBUG_1(("shutdown(1): %s\n", su_strerror(su_errno())));
    }
    if (f->f_shutdown) {
      forwarder_close(f);
    }
  }
  return 0;
}
Exemplo n.º 7
0
/** Refresh subscription */
static void nua_subscribe_usage_refresh(nua_handle_t *nh,
					nua_dialog_state_t *ds,
					nua_dialog_usage_t *du,
					sip_time_t now)
{
  nua_client_request_t *cr = du->du_cr;
  struct event_usage *eu = nua_dialog_usage_private(du);

  assert(eu);

  if (eu->eu_final_wait) {
    /* Did not receive NOTIFY for fetch */
    sip_event_t const *o = du->du_event;
    char const *id = o ? o->o_id : NULL;

    SU_DEBUG_3(("nua(%p): event %s%s%s fetch timeouts\n",
		(void *)nh, o ? o->o_type : "(empty)",
		id ? "; id=" : "", id ? id : ""));

    nua_stack_tevent(nh->nh_nua, nh,  NULL,
		     nua_i_notify, 408, "Fetch Timeouts without NOTIFY",
		     NUTAG_SUBSTATE(nua_substate_terminated),
		     SIPTAG_EVENT(du->du_event),
		     TAG_END());
    nua_dialog_usage_remove(nh, ds, du, NULL, NULL);

    return;
  }

  if (cr) {
    if (nua_client_resend_request(cr, 0) >= 0)
      return;
  }
  else if (eu->eu_refer) {
    /*
     * XXX - If we have received a NOTIFY, we should try to terminate
     * subscription
     */
  }

  if (!eu->eu_unsolicited)
    nua_stack_tevent(nh->nh_nua, nh, NULL,
		     nua_i_notify, NUA_ERROR_AT(__FILE__, __LINE__),
		     NUTAG_SUBSTATE(nua_substate_terminated),
		     SIPTAG_EVENT(du->du_event),
		     TAG_END());

  nua_dialog_usage_remove(nh, ds, du, NULL, NULL);
}
Exemplo n.º 8
0
/**
 * Create a new leg object
 *
 * @param agent    agent object
 * @param callback function which is called for each
 *                 incoming request belonging to this leg
 * @param magic    call leg context
 * @param i        optional @CallID
 *                 (if @c NULL, an ID generated by @b NTA is used)
 * @param from     optional @From (local address)
 * @param to       optional @To (remote address)
 * @param extra    optional extra header
 * @param headers  va_list of optional extra headers
 *
 * @deprecated Use nta_leg_tcreate() instead.
 */
nta_leg_t *nta_leg_vcreate(nta_agent_t *agent,
			   nta_request_f *callback,
			   nta_leg_magic_t *magic,
			   sip_call_id_t const *i,
			   sip_from_t const *from,
			   sip_to_t const *to,
			   void const *extra, va_list headers)
{
  sip_route_t const *route = NULL;
  sip_cseq_t const *cseq = NULL;

  for (; extra ; extra = va_arg(headers, void *)) {
    sip_header_t const *h = (sip_header_t const *)extra;

    if (h == SIP_NONE)
      continue;
    else if (sip_call_id_p(h)) {
      if (i == NULL) i = h->sh_call_id;
    }
    else if (sip_from_p(h)) {
      if (from == NULL) from = h->sh_from;
    }
    else if (sip_to_p(h)) {
      if (to == NULL) to = h->sh_to;
    }
    else if (sip_route_p(h)) {
      route = h->sh_route;
    }
    else if (sip_cseq_p(h)) {
      cseq = h->sh_cseq;
    }
    else {
      SU_DEBUG_3(("nta_leg_create: extra header %s\n", 
		  sip_header_name(h, 0)));
    }
  }

  return nta_leg_tcreate(agent, callback, magic,
			 NTATAG_NO_DIALOG(i == SIP_NONE->sh_call_id),
			 TAG_IF(i != SIP_NONE->sh_call_id, SIPTAG_CALL_ID(i)),
			 TAG_IF(from != SIP_NONE->sh_from, SIPTAG_FROM(from)),
			 TAG_IF(to != SIP_NONE->sh_to, SIPTAG_TO(to)),
			 SIPTAG_ROUTE(route),
			 SIPTAG_CSEQ(cseq),
			 TAG_END());
}
Exemplo n.º 9
0
/** Close a peer pair */
void forwarder_close(forwarder_t *f)
{
  su_sockaddr_t *su1, *su2;
  char const *d1, *d2;
  char buf1[SU_ADDRSIZE], buf2[SU_ADDRSIZE];

  if (f->f_upstream)
    su1 = f->f_dest, su2 = f->f_peer->f_dest, d1 = "up", d2 = "down";
  else
    su2 = f->f_dest, su1 = f->f_peer->f_dest, d2 = "up", d1 = "down";

  SU_DEBUG_3(("forwarder_close: connection from %s:%u to %s:%d\n",
	      su_inet_ntop(su1->su_family, SU_ADDR(su1), buf1, sizeof(buf1)),
	      ntohs(su1->su_port),
	      su_inet_ntop(su2->su_family, SU_ADDR(su2), buf2, sizeof(buf2)),
	      ntohs(su2->su_port)));

  forwarder_destroy(f);
}
Exemplo n.º 10
0
/** Create a port using /dev/poll or poll().
 */
su_port_t *su_devpoll_port_create(void)
{
  su_port_t *self;
  int devpoll = open("/dev/poll", O_RDWR);

  if (devpoll == -1) {
    /* Fallback to poll() */
    SU_DEBUG_3(("%s(): open(\"%s\") => %u: %s\n",
		"su_devpoll_port_create", "/dev/poll",
		errno, strerror(errno)));
    return su_poll_port_create();
  }

  self = su_home_new(sizeof *self);
  if (!self) {
    close(devpoll);
    return self;
  }

  if (su_home_destructor(su_port_home(self), su_devpoll_port_deinit) < 0 ||
      !(self->sup_indices =
	su_zalloc(su_port_home(self),
		  (sizeof self->sup_indices[0]) *
		  (self->sup_size_indices = 64)))) {
    su_home_unref(su_port_home(self));
    close(devpoll);
    return NULL;
  }

  self->sup_devpoll = devpoll;
  self->sup_multishot = SU_ENABLE_MULTISHOT_POLL;

  if (su_socket_port_init(self->sup_base, su_devpoll_port_vtable) < 0)
    return su_home_unref(su_port_home(self)), NULL;

  SU_DEBUG_9(("%s(%p): devpoll_create() => %u: %s\n",
	      "su_port_create", (void *)self, self->sup_devpoll, "OK"));

  return self;
}
Exemplo n.º 11
0
/** Accept a connection. */
int forwarder_accept(proxy_t *pr, su_wait_t *w, forwarder_t *f0)
{
  forwarder_t *f;
  su_sockaddr_t *su;
  socklen_t  sulen;
  int events;

  events = su_wait_events(w, f0->f_socket);

  f = forwarder_create(pr);

  if (f) {
    su = f->f_dest;
    sulen = sizeof(f->f_dest);
    f->f_socket = accept(f0->f_socket, &su->su_sa, &sulen);
    f->f_upstream = 1;
    if (f->f_socket != INVALID_SOCKET) {
      char buf[SU_ADDRSIZE];

      SU_DEBUG_3(("accept: connection from %s:%u\n",
		  su_inet_ntop(su->su_family, SU_ADDR(su), buf, sizeof(buf)),
		  ntohs(su->su_port)));

      if (!su_wait_create(f->f_wait, f->f_socket, SU_WAIT_IN) &&
	  !su_wait_create(f->f_wait + 1, f->f_socket, SU_WAIT_OUT)) {
	if (forwarder_stream_peer(pr, f) != SOCKET_ERROR) {
	  /* success */
	  return 0;
	}
      }
      else {
	SU_DEBUG_1(("%s: cannot create wait objects\n", __func__));
      }
    }
  }

  forwarder_destroy(f);

  return 0;
}
Exemplo n.º 12
0
static int process_response_to_keepalive_options(outbound_t *ob,
						 nta_outgoing_t *orq,
						 sip_t const *sip,
						 int status,
						 char const *phrase)
{
  int binding_check;
  int challenged = 0, credentials = 0;
  msg_t *_reqmsg = nta_outgoing_getrequest(orq);
  sip_t *request = sip_object(_reqmsg); msg_destroy(_reqmsg);

  if (sip == NULL) {
    SU_DEBUG_3(("outbound(%p): keepalive %u %s\n", (void *)ob->ob_owner,
		status, phrase));
    ob->ob_oo->oo_keepalive_error(ob->ob_owner, ob, status, phrase, TAG_END());
    return 0;
  }

  if (status == 401 || status == 407) {
    if (sip->sip_www_authenticate)
      challenged += auc_challenge(ob->ob_keepalive.auc,
				  ob->ob_home,
				  sip->sip_www_authenticate,
				  sip_authorization_class) > 0;
    if (sip->sip_proxy_authenticate)
      challenged += auc_challenge(ob->ob_keepalive.auc,
				  ob->ob_home,
				  sip->sip_proxy_authenticate,
				  sip_proxy_authorization_class) > 0;
    if (ob->ob_oo->oo_credentials)
      credentials = ob->ob_oo->oo_credentials(ob->ob_owner,
					      ob->ob_keepalive.auc);
  }

  binding_check = outbound_nat_detect(ob, request, sip);

  if (binding_check > 1) {
    /* Bindings have changed */
    if (outbound_contacts_from_via(ob, sip->sip_via) == 0) {
      /* XXX - Destroy old keepalive template message */

      /* re-REGISTER */
      ob->ob_oo->oo_refresh(ob->ob_owner, ob);
      return 0;
    }
  }

  if (binding_check <= 1 && ob->ob_registered && ob->ob_keepalive.validating) {
    int failed = 0;
    unsigned loglevel = 3;

    if (challenged > 0 && credentials > 0) {
      keepalive_options_with_registration_probe(ob);
      return 0;
    }

    if (status < 300 && ob->ob_keepalive.validated) {
      loglevel = 5;
      if (ob->ob_validated)
	loglevel = 99;		/* only once */
      ob->ob_validated = ob->ob_once_validated = 1;
    }
    else if (status == 401 || status == 407 || status == 403)
      loglevel = 5, failed = 1;
    else
      loglevel = 3, failed = 1;

    if (loglevel >= SU_LOG->log_level) {
      sip_contact_t const *m = ob->ob_rcontact;

      if  (m)
	su_llog(SU_LOG, loglevel,
		"outbound(%p): %s <" URL_PRINT_FORMAT ">\n",
		(void *)ob->ob_owner,
		failed ? "FAILED to validate" : "validated",
		URL_PRINT_ARGS(m->m_url));
      else
	su_llog(SU_LOG, loglevel,
		"outbound(%p): %s registration\n",
		(void *)ob->ob_owner,
		failed ? "FAILED to validate" : "validated");

      if (failed)
	su_llog(SU_LOG, loglevel, "outbound(%p): FAILED with %u %s\n",
		(void *)ob->ob_owner, status, phrase);
    }

    if (failed)
      ob->ob_oo->oo_probe_error(ob->ob_owner, ob, status, phrase, TAG_END());
  }
  else if (status == 408) {
    SU_DEBUG_3(("outbound(%p): keepalive timeout\n", (void *)ob->ob_owner));
    ob->ob_oo->oo_keepalive_error(ob->ob_owner, ob, status, phrase, TAG_END());
    return 0;
  }

  ob->ob_keepalive.validating = 0;

  if (ob->ob_keepalive.timer)
    su_timer_set(ob->ob_keepalive.timer, keepalive_timer, ob);

  return 0;
}
Exemplo n.º 13
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;
}
Exemplo n.º 14
0
int tls_connect(su_root_magic_t *magic, su_wait_t *w, tport_t *self)
{
  tport_master_t *mr = self->tp_master;
  tport_tls_t *tlstp = (tport_tls_t *)self;
  tls_t *tls;
  int events = su_wait_events(w, self->tp_socket);
  int error;

  SU_DEBUG_7(("%s(%p): events%s%s%s%s\n", __func__, (void *)self,
              events & (SU_WAIT_CONNECT) ? " CONNECTING" : "",
              events & SU_WAIT_IN  ? " NEGOTIATING" : "",
              events & SU_WAIT_ERR ? " ERROR" : "",
              events & SU_WAIT_HUP ? " HANGUP" : ""));

#if HAVE_POLL
  assert(w->fd == self->tp_socket);
#endif

  if (events & SU_WAIT_ERR)
    tport_error_event(self);

  if (events & SU_WAIT_HUP && !self->tp_closed)
    tport_hup_event(self);

  if (self->tp_closed)
    return 0;

  error = su_soerror(self->tp_socket);
  if (error) {
    tport_error_report(self, error, NULL);
    return 0;
  }

  if ((tls = tlstp->tlstp_context) == NULL) {
    SU_DEBUG_3(("%s(%p): Error: no TLS context data for connected socket.\n",
                __func__, (void *)tlstp));
    tport_close(self);
    tport_set_secondary_timer(self);
    return 0;
  }

  if (self->tp_is_connected == 0) {
    int ret, status;

    ret = self->tp_accepted ? SSL_accept(tls->con) : SSL_connect(tls->con);
    status = SSL_get_error(tls->con, ret);

    switch (status) {
      case SSL_ERROR_WANT_READ:
        /* OpenSSL is waiting for the peer to send handshake data */
        self->tp_events = SU_WAIT_IN | SU_WAIT_ERR | SU_WAIT_HUP;
        su_root_eventmask(mr->mr_root, self->tp_index,
		          self->tp_socket, self->tp_events);
        return 0;

      case SSL_ERROR_WANT_WRITE:
        /* OpenSSL is waiting for the peer to receive handshake data */
        self->tp_events = SU_WAIT_IN | SU_WAIT_ERR | SU_WAIT_HUP | SU_WAIT_OUT;
        su_root_eventmask(mr->mr_root, self->tp_index,
                           self->tp_socket, self->tp_events);
        return 0;

      case SSL_ERROR_NONE:
        /* TLS Handshake complete */
	status = tls_post_connection_check(self, tls);
        if ( status == X509_V_OK ) {
          su_wait_t wait[1] = {SU_WAIT_INIT};
          tport_master_t *mr = self->tp_master;

          su_root_deregister(mr->mr_root, self->tp_index);
          self->tp_index = -1;
          self->tp_events = SU_WAIT_IN | SU_WAIT_ERR | SU_WAIT_HUP;

          if ((su_wait_create(wait, self->tp_socket, self->tp_events) == -1) ||
             ((self->tp_index = su_root_register(mr->mr_root, wait, tport_wakeup,
                                                           self, 0)) == -1)) {
            tport_close(self);
            tport_set_secondary_timer(self);
	    return 0;
          }

          tls->read_events = SU_WAIT_IN;
          tls->write_events = 0;
          self->tp_is_connected = 1;
	  self->tp_verified = tls->x509_verified;
	  self->tp_subjects = tls->subjects;

	  if (tport_has_queued(self))
            tport_send_event(self);
          else
            tport_set_secondary_timer(self);

          return 0;
	}
	break;

      default:
        {
	  char errbuf[64];
	  ERR_error_string_n(status, errbuf, 64);
          SU_DEBUG_3(("%s(%p): TLS setup failed (%s)\n",
					  __func__, (void *)self, errbuf));
        }
        break;
    }
  }

  /* TLS Handshake Failed or Peer Certificate did not Verify */
  tport_close(self);
  tport_set_secondary_timer(self);

  return 0;
}
Exemplo n.º 15
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;
}
Exemplo n.º 16
0
static
int tls_init_context(tls_t *tls, tls_issues_t const *ti)
{
  int verify;
  static int random_loaded;

  ONCE_INIT(tls_init_once);

  if (!random_loaded) {
    random_loaded = 1;

    if (ti->randFile &&
	!RAND_load_file(ti->randFile, 1024 * 1024)) {
      if (ti->configured > 1) {
	SU_DEBUG_3(("%s: cannot open randFile %s\n",
		   "tls_init_context", ti->randFile));
	tls_log_errors(3, "tls_init_context", 0);
      }
      /* errno = EIO; */
      /* return -1; */
    }
  }

#if HAVE_SIGPIPE
  /* Avoid possible SIGPIPE when sending close_notify */
  signal(SIGPIPE, SIG_IGN);
#endif

  if (tls->ctx == NULL)
    if (!(tls->ctx = SSL_CTX_new((SSL_METHOD*)SSLv23_method()))) {
      tls_log_errors(1, "SSL_CTX_new() failed", 0);
      errno = EIO;
      return -1;
    }
  if (!(ti->version & TPTLS_VERSION_SSLv2))
    SSL_CTX_set_options(tls->ctx, SSL_OP_NO_SSLv2);
  if (!(ti->version & TPTLS_VERSION_SSLv3))
    SSL_CTX_set_options(tls->ctx, SSL_OP_NO_SSLv3);
  if (!(ti->version & TPTLS_VERSION_TLSv1))
    SSL_CTX_set_options(tls->ctx, SSL_OP_NO_TLSv1);
  if (!(ti->version & TPTLS_VERSION_TLSv1_1))
    SSL_CTX_set_options(tls->ctx, SSL_OP_NO_TLSv1_1);
  if (!(ti->version & TPTLS_VERSION_TLSv1_2))
    SSL_CTX_set_options(tls->ctx, SSL_OP_NO_TLSv1_2);
  SSL_CTX_sess_set_remove_cb(tls->ctx, NULL);
  SSL_CTX_set_timeout(tls->ctx, ti->timeout);

  /* Set callback if we have a passphrase */
  if (ti->passphrase != NULL) {
    SSL_CTX_set_default_passwd_cb(tls->ctx, passwd_cb);
    SSL_CTX_set_default_passwd_cb_userdata(tls->ctx, (void *)ti);
  }

  if (!SSL_CTX_use_certificate_file(tls->ctx,
				    ti->cert,
				    SSL_FILETYPE_PEM)) {
    if (ti->configured > 0) {
      SU_DEBUG_1(("%s: invalid local certificate: %s\n",
		 "tls_init_context", ti->cert));
      tls_log_errors(3, "tls_init_context", 0);
#if require_client_certificate
      errno = EIO;
      return -1;
#endif
    }
  }

  if (!SSL_CTX_use_PrivateKey_file(tls->ctx,
                                   ti->key,
                                   SSL_FILETYPE_PEM)) {
    if (ti->configured > 0) {
      SU_DEBUG_1(("%s: invalid private key: %s\n",
		 "tls_init_context", ti->key));
      tls_log_errors(3, "tls_init_context(key)", 0);
#if require_client_certificate
      errno = EIO;
      return -1;
#endif
    }
  }

  if (!SSL_CTX_check_private_key(tls->ctx)) {
    if (ti->configured > 0) {
      SU_DEBUG_1(("%s: private key does not match the certificate public key\n",
		  "tls_init_context"));
    }
#if require_client_certificate
    errno = EIO;
    return -1;
#endif
  }

  if (!SSL_CTX_load_verify_locations(tls->ctx,
                                     ti->CAfile,
                                     ti->CApath)) {
    SU_DEBUG_1(("%s: error loading CA list: %s\n",
		 "tls_init_context", ti->CAfile));
    if (ti->configured > 0)
      tls_log_errors(3, "tls_init_context(CA)", 0);
    errno = EIO;
    return -1;
  }

  /* corresponds to (enum tport_tls_verify_policy) */
  tls->verify_incoming = (ti->policy & 0x1) ? 1 : 0;
  tls->verify_outgoing = (ti->policy & 0x2) ? 1 : 0;
  tls->verify_subj_in  = (ti->policy & 0x4) ? tls->verify_incoming : 0;
  tls->verify_subj_out = (ti->policy & 0x8) ? tls->verify_outgoing : 0;
  tls->verify_date     = (ti->verify_date)  ? 1 : 0;

  if (tls->verify_incoming)
    verify = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
  else
    verify = SSL_VERIFY_NONE;

  SSL_CTX_set_verify_depth(tls->ctx, ti->verify_depth);
  SSL_CTX_set_verify(tls->ctx, verify, tls_verify_cb);

  if (tls_init_ecdh_curve(tls) == 0) {
    SU_DEBUG_3(("%s\n", "tls: initialized ECDH"));
  } else {
    SU_DEBUG_3(("%s\n", "tls: failed to initialize ECDH"));
  }

  if (!SSL_CTX_set_cipher_list(tls->ctx, ti->ciphers)) {
    SU_DEBUG_1(("%s: error setting cipher list\n", "tls_init_context"));
    tls_log_errors(3, "tls_init_context", 0);
    errno = EIO;
    return -1;
  }

  return 0;
}
Exemplo n.º 17
0
int tport_udp_init_primary(tport_primary_t *pri,
			   tp_name_t tpn[1],
			   su_addrinfo_t *ai,
			   tagi_t const *tags,
			   char const **return_culprit)
{
  unsigned rmem = 0, wmem = 0;
  int events = SU_WAIT_IN;
  int s;
#if HAVE_IP_ADD_MEMBERSHIP
  su_sockaddr_t *su = (su_sockaddr_t *)ai->ai_addr;
#endif
  int const one = 1; (void)one;

  s = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
  if (s == INVALID_SOCKET)
    return *return_culprit = "socket", -1;

  pri->pri_primary->tp_socket = s;

  if (tport_bind_socket(s, ai, return_culprit) < 0)
    return -1;

  tport_set_tos(s, ai, pri->pri_params->tpp_tos);

#if HAVE_IP_ADD_MEMBERSHIP
  if (ai->ai_family == AF_INET &&
      IN_MULTICAST(ntohl(su->su_sin.sin_addr.s_addr))) {
    /* Try to join to the multicast group */
    /* Bind to the SIP address like
       <sip:88.77.66.55:5060;maddr=224.0.1.75;transport=udp> */
    struct ip_mreq imr[1];
    struct in_addr iface;

    memset(imr, 0, sizeof imr);

    imr->imr_multiaddr = su->su_sin.sin_addr;

    if (host_is_ip4_address(tpn->tpn_canon) &&
	su_inet_pton(AF_INET, tpn->tpn_canon, &iface) > 0) {
      imr->imr_interface = iface;
    }

    if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, imr, (sizeof imr)) < 0) {
      SU_DEBUG_3(("setsockopt(%s): %s\n",
		  "IP_ADD_MEMBERSHIP", su_strerror(su_errno())));
    }
#if HAVE_IP_MULTICAST_LOOP
    else
      if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &one, sizeof one) < 0) {
	SU_DEBUG_3(("setsockopt(%s): %s\n",
		    "IP_MULTICAST_LOOP", su_strerror(su_errno())));
    }
#endif
  }
#endif

#if HAVE_IP_MTU_DISCOVER
  {
    /* Turn off DF flag on Linux */
    int dont = IP_PMTUDISC_DONT;
    if (setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &dont, sizeof(dont)) < 0) {
	SU_DEBUG_3(("setsockopt(%s): %s\n",
		    "IP_MTU_DISCOVER", su_strerror(su_errno())));
    }
  }
#endif

#if HAVE_IP_RECVERR
  if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) {
    if (setsockopt(s, IPPROTO_IP, IP_RECVERR, &one, sizeof(one)) < 0) {
      if (ai->ai_family == AF_INET)
	SU_DEBUG_3(("setsockopt(%s): %s\n",
		    "IPVRECVERR", su_strerror(su_errno())));
    }
    events |= SU_WAIT_ERR;
  }
#endif
#if HAVE_IPV6_RECVERR
  if (ai->ai_family == AF_INET6) {
    if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVERR, &one, sizeof(one)) < 0)
      SU_DEBUG_3(("setsockopt(IPV6_RECVERR): %s\n", su_strerror(su_errno())));
    events |= SU_WAIT_ERR;
  }
#endif

  tl_gets(tags,
	  TPTAG_UDP_RMEM_REF(rmem),
	  TPTAG_UDP_WMEM_REF(wmem),
	  TAG_END());

  if (rmem != 0 &&
#if HAVE_SO_RCVBUFFORCE
      setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, (void *)&rmem, sizeof rmem) < 0 &&
#endif
      setsockopt(s, SOL_SOCKET, SO_RCVBUF, (void *)&rmem, sizeof rmem) < 0) {
    SU_DEBUG_3(("setsockopt(SO_RCVBUF): %s\n",
		su_strerror(su_errno())));
  }

  if (wmem != 0 &&
#if HAVE_SO_SNDBUFFORCE
      setsockopt(s, SOL_SOCKET, SO_SNDBUFFORCE, (void *)&wmem, sizeof wmem) < 0 &&
#endif
      setsockopt(s, SOL_SOCKET, SO_SNDBUF, (void *)&wmem, sizeof wmem) < 0) {
    SU_DEBUG_3(("setsockopt(SO_SNDBUF): %s\n",
		su_strerror(su_errno())));
  }

  pri->pri_primary->tp_events = events;

  tport_init_compressor(pri->pri_primary, tpn->tpn_comp, tags);

  tport_check_trunc(pri->pri_primary, ai);

#if HAVE_SOFIA_STUN
  tport_stun_server_add_socket(pri->pri_primary);
#endif

  return 0;
}
Exemplo n.º 18
0
/** Send to stream */
ssize_t tport_send_stream_ws(tport_t const *self, msg_t *msg,
			  msg_iovec_t iov[],
			  size_t iovlen)
{
  size_t i, j, n, m, size = 0;
  ssize_t nerror;
  tport_ws_t *wstp = (tport_ws_t *)self;

  enum { WSBUFSIZE = 2048 };

  for (i = 0; i < iovlen; i = j) {
    char *buf = wstp->wstp_buffer;
    unsigned wsbufsize = WSBUFSIZE;

    if (i + 1 == iovlen) {
		buf = NULL;		/* Don't bother copying single chunk */
	}

    if (buf &&
		(char *)iov[i].siv_base - buf < WSBUFSIZE &&
		(char *)iov[i].siv_base - buf >= 0) {
		wsbufsize = buf + WSBUFSIZE - (char *)iov[i].siv_base;
		assert(wsbufsize <= WSBUFSIZE);
    }

    for (j = i, m = 0; buf && j < iovlen; j++) {
		if (m + iov[j].siv_len > wsbufsize) {
			break;
		}
		if (buf + m != iov[j].siv_base) {
			memcpy(buf + m, iov[j].siv_base, iov[j].siv_len);
		}
		m += iov[j].siv_len; iov[j].siv_len = 0;
    }
	
    if (j == i) {
      buf = iov[i].siv_base, m = iov[i].siv_len, j++;
	} else {
      iov[j].siv_base = buf, iov[j].siv_len = m;
	}

	nerror = ws_feed_buf(&wstp->ws, buf, m);
	
    SU_DEBUG_9(("tport_ws_writevec: vec %p %p %lu ("MOD_ZD")\n",
		(void *)&wstp->ws, (void *)iov[i].siv_base, (LU)iov[i].siv_len,
		nerror));

    if (nerror == -1) {
      int err = su_errno();
      if (su_is_blocking(err))
	break;
      SU_DEBUG_3(("ws_write: %s\n", strerror(err)));
      return -1;
    }

    n = (size_t)nerror;
    size += n;

    /* Return if the write buffer is full for now */
    if (n != m)
      break;
  }

  ws_send_buf(&wstp->ws, WSOC_TEXT);


  return size;
}
Exemplo n.º 19
0
/** Receive datagram.
 *
 * @retval -1 error
 * @retval 0  end-of-stream
 * @retval 1  normal receive (should never happen)
 * @retval 2  incomplete recv, call me again (should never happen)
 * @retval 3  STUN keepalive, ignore
 */
int tport_recv_dgram(tport_t *self)
{
  msg_t *msg;
  ssize_t n, veclen, N;
  su_addrinfo_t *ai;
  su_sockaddr_t *from;
  socklen_t fromlen;
  msg_iovec_t iovec[msg_n_fragments] = {{ 0 }};
  uint8_t sample[1];

  /* Simulate packet loss */
  if (self->tp_params->tpp_drop &&
      (unsigned)su_randint(0, 1000) < self->tp_params->tpp_drop) {
    su_recv(self->tp_socket, sample, 1, 0);
    SU_DEBUG_3(("tport(%p): simulated packet loss!\n", (void *)self));
    return 0;
  }

  assert(self->tp_msg == NULL);

#if nomore
  /* We used to resize the buffer, but it fragments the memory */
  N = 65535;
#else
  N = (ssize_t)su_getmsgsize(self->tp_socket);
  if (N == -1) {
    int err = su_errno();
    SU_DEBUG_1(("%s(%p): su_getmsgsize(): %s (%d)\n", __func__, (void *)self,
		su_strerror(err), err));
    return -1;
  }
  if (N == 0) {
    su_recv(self->tp_socket, sample, 1, 0);
    SU_DEBUG_3(("tport(%p): zero length packet", (void *)self));
    return 0;
  }
#endif

  veclen = tport_recv_iovec(self, &self->tp_msg, iovec, N, 1);
  if (veclen == -1)
    return -1;

  msg = self->tp_msg;

  ai = msg_addrinfo(msg);
  from = (su_sockaddr_t *)ai->ai_addr, fromlen = (socklen_t)(ai->ai_addrlen);

  n = su_vrecv(self->tp_socket, iovec, veclen, 0, from, &fromlen);

  ai->ai_addrlen = fromlen;

  if (n == SOCKET_ERROR) {
    int error = su_errno();
    msg_destroy(msg); self->tp_msg = NULL;
    su_seterrno(error);

    if (su_is_blocking(error))
      return 0;
    else
      return -1;
  }
  else if (n <= 1) {
    SU_DEBUG_1(("%s(%p): runt of "MOD_ZD" bytes\n",
		"tport_recv_dgram", (void *)self, n));
    msg_destroy(msg), self->tp_msg = NULL;
    return 0;
  }

  tport_recv_bytes(self, n, n);

  SU_CANONIZE_SOCKADDR(from);

  if (self->tp_master->mr_dump_file)
    tport_dump_iovec(self, msg, n, iovec, veclen, "recv", "from");

  *sample = *((uint8_t *)iovec[0].mv_base);

  /* Commit received data into buffer. This may relocate iovec contents */
  msg_recv_commit(msg, n, 1);

  if ((sample[0] & 0xf8) == 0xf8)
    /* SigComp */
    return tport_recv_comp_dgram(self, self->tp_comp, &self->tp_msg,
				 from, fromlen);
#if HAVE_SOFIA_STUN
  else if (sample[0] == 0 || sample[0] == 1)
    /* STUN request or response */
    return tport_recv_stun_dgram(self, &self->tp_msg, from, fromlen);
#endif
  else
    return 0;
}
Exemplo n.º 20
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;
}
Exemplo n.º 21
0
/** Process UDP error event. */
int tport_udp_error(tport_t const *self, su_sockaddr_t name[1])
{
  struct cmsghdr *c;
  struct sock_extended_err *ee;
  su_sockaddr_t *from;
  char control[512];
  char errmsg[64 + 768];
  struct iovec iov[1];
  struct msghdr msg[1] = {{ 0 }};
  int n;

  msg->msg_name = name, msg->msg_namelen = sizeof(*name);
  msg->msg_iov = iov, msg->msg_iovlen = 1;
  iov->iov_base = errmsg, iov->iov_len = sizeof(errmsg);
  msg->msg_control = control, msg->msg_controllen = sizeof(control);

  n = recvmsg(self->tp_socket, msg, MSG_ERRQUEUE);

  if (n < 0) {
    int err = su_errno();
    if (!su_is_blocking(err))
      SU_DEBUG_1(("%s: recvmsg: %s\n", __func__, su_strerror(err)));
    return 0;
  }

  if ((msg->msg_flags & MSG_ERRQUEUE) != MSG_ERRQUEUE) {
    SU_DEBUG_1(("%s: recvmsg: no errqueue\n", __func__));
    return 0;
  }

  if (msg->msg_flags & MSG_CTRUNC) {
    SU_DEBUG_1(("%s: extended error was truncated\n", __func__));
    return 0;
  }

  if (msg->msg_flags & MSG_TRUNC) {
    /* ICMP message may contain original message... */
    SU_DEBUG_3(("%s: icmp(6) message was truncated (at %d)\n", __func__, n));
  }

  /* Go through the ancillary data */
  for (c = CMSG_FIRSTHDR(msg); c; c = CMSG_NXTHDR(msg, c)) {
    if (0
#if HAVE_IP_RECVERR
	|| (c->cmsg_level == IPPROTO_IP && c->cmsg_type == IP_RECVERR)
#endif
#if HAVE_IPV6_RECVERR
	|| (c->cmsg_level == IPPROTO_IPV6 && c->cmsg_type == IPV6_RECVERR)
#endif
	) {
      char info[128];
      char const *origin;

      ee = (struct sock_extended_err *)CMSG_DATA(c);
      from = (su_sockaddr_t *)SO_EE_OFFENDER(ee);
      info[0] = '\0';

      switch (ee->ee_origin) {
      case SO_EE_ORIGIN_LOCAL:
	origin = "local";
	break;
      case SO_EE_ORIGIN_ICMP:
	origin = "icmp";
	snprintf(info, sizeof(info), " type=%u code=%u",
		 ee->ee_type, ee->ee_code);
	break;
      case SO_EE_ORIGIN_ICMP6:
	origin = "icmp6";
	snprintf(info, sizeof(info), " type=%u code=%u",
		ee->ee_type, ee->ee_code);
	break;
      case SO_EE_ORIGIN_NONE:
	origin = "none";
	break;
      default:
	origin = "unknown";
	break;
      }

      if (ee->ee_info)
	snprintf(info + strlen(info), sizeof(info) - strlen(info),
		 " info=%08x", ee->ee_info);

      SU_DEBUG_3(("%s: %s (%d) [%s%s]\n",
		  __func__, su_strerror(ee->ee_errno), ee->ee_errno,
		  origin, info));
      if (from->su_family != AF_UNSPEC)
	SU_DEBUG_3(("\treported by [%s]:%u\n",
		    su_inet_ntop(from->su_family, SU_ADDR(from),
				 info, sizeof(info)),
		    ntohs(from->su_port)));

      if (msg->msg_namelen == 0)
	name->su_family = AF_UNSPEC;

      SU_CANONIZE_SOCKADDR(name);

      return ee->ee_errno;
    }
  }

  return 0;
}
Exemplo n.º 22
0
/** Read authentication database */
static
int auth_readdb_internal(auth_mod_t *am, int always)
{
    FILE *f;
    char *data, *s;
    size_t len, i, n, N;
    ssize_t slen;
    auth_passwd_t *apw;

    if (!am->am_stat)
        am->am_stat = su_zalloc(am->am_home, sizeof (*am->am_stat));

    f = fopen(am->am_db, "rb");

    if (f) {
        void *buffer = NULL;
        auth_passwd_t *fresh = NULL;

#if HAVE_FLOCK
        int locked;

        /* Obtain shared lock on the database file */
        if (flock(fileno(f), LOCK_SH | (always ? 0 : LOCK_NB)) == 0) {
            locked = 1;
        } else {
            locked = 0;

            if (errno == ENOLCK) {
                ;
            }
            else if (errno == EWOULDBLOCK) {
                SU_DEBUG_3(("auth(%s): user file \"%s\" is busy, trying again later\n",
                            am->am_scheme->asch_method, am->am_db));
                fclose(f);
                return always ? -1 : 0;
            }
            else {
                SU_DEBUG_3(("auth(%s): flock(\"%s\"): %s (%u)\n",
                            am->am_scheme->asch_method, am->am_db,
                            strerror(errno), errno));
                fclose(f);
                return always ? -1 : 0;
            }
        }
#endif
        if (am->am_stat)
            stat(am->am_db, am->am_stat); /* too bad if this fails */

        slen = readfile(am->am_home, f, &buffer, 1);

#if HAVE_FLOCK
        /* Release shared lock on the database file */
        if (locked && flock(fileno(f), LOCK_UN) == -1) {
            SU_DEBUG_0(("auth(%s): un-flock(\"%s\"): %s (%u)\n",
                        am->am_scheme->asch_method, am->am_db, strerror(errno), errno));
            fclose(f);
            return -1;
        }
#endif

        fclose(f);

        if (slen < 0)
            return -1;
        len = (size_t)slen;

        /* Count number of entries in new buffer */
        for (i = am->am_anonymous, s = data = buffer;
                s < data + len;
                s += n + strspn(s + n, "\r\n")) {
            n = strcspn(s, "\r\n");
            if (*s != '#' && *s != '\n' && *s != '\r')
                i++;
        }

        N = i, i = 0;

        if (N > 0) {
            size_t size = (N * 5 + 3) / 4;
            if (auth_htable_resize(am->am_home, am->am_users, size) < 0 ||
                    !(fresh = su_zalloc(am->am_home, sizeof(*fresh) * N))) {
                su_free(am->am_home, buffer);
                return -1;
            }
        }

        if (am->am_anonymous) {
            assert(i < N);

            apw = fresh + i++;

            apw->apw_index = msg_hash_string("anonymous");
            apw->apw_user = "******";
            apw->apw_pass = "";
            apw->apw_realm = "";

            am->am_anon_user = apw;

            if (auth_htable_is_full(am->am_users))
                auth_htable_resize(am->am_home, am->am_users, 0);

            auth_htable_append_local(am->am_users, apw);
        }

        apw = NULL;

        for (data = buffer, s = data;
                s < data + len && i < N;
                s += n + strspn(s + n, "\r\n")) {
            char *user, *pass, *realm, *ident;

            n = strcspn(s, "\r\n");
            if (*s == '#')
                continue;

            user = s;
            s[n++] = '\0';
            if (!(pass = strchr(user, ':')))
                continue;

            *pass++ = '\0';
            if (!*pass || !*user)
                continue;

            if ((realm = strchr(pass, ':')))
                *realm++ = '\0';
            else
                realm = "";

            if ((ident = strchr(realm, ':')))
                *ident++ = '\0';
            else
                ident = "";

            apw = fresh + i++;

            apw->apw_index = msg_hash_string(user);
            apw->apw_user = user;
            apw->apw_ident = ident;

            /* Check for htdigest format */
            if (span_hexdigit(realm) == 32 && realm[32] == '\0') {
                apw->apw_realm = pass;
                apw->apw_hash = realm;
            } else {
                apw->apw_pass = pass;
                apw->apw_realm = realm;
            }

            if (auth_htable_is_full(am->am_users))
                auth_htable_resize(am->am_home, am->am_users, 0);

            auth_htable_append_local(am->am_users, apw);
        }

        assert(i <= N);
        N = i;

        /* Remove from hash those entries that were read from old passwd file */
        for (i = 0; i < am->am_local_count; i++) {
            if (am->am_locals[i].apw_type == auth_apw_local)
                auth_htable_remove(am->am_users, &am->am_locals[i]);
        }

        if (am->am_locals)
            su_free(am->am_home, am->am_locals); /* Free old entries */
        if (am->am_buffer)
            su_free(am->am_home, am->am_buffer); /* Free old passwd file contents */

        SU_DEBUG_5(("auth(%s): read %u entries from \"%s\"\n",
                    am->am_scheme->asch_method, (unsigned)N, am->am_db));

        am->am_locals = fresh;
        am->am_local_count = N;
        am->am_buffer = buffer;

        return 0;
    }

    return -1;
}
Exemplo n.º 23
0
/**Forward a request belonging to the leg 
 * (stdarg version of nta_outgoing_forward()).
 *
 * @deprecated
 * Use nta_outgoing_mcreate() instead.
 */
nta_outgoing_t *nta_outgoing_vforward(nta_leg_t *leg,
				      nta_response_f *callback,
				      nta_outgoing_magic_t *magic,
				      url_string_t const *route_url,
				      url_string_t const *request_uri,
				      nta_incoming_t const *ireq,
				      sip_t const *isip,
				      void const *extra,
				      va_list headers)
{
  nta_agent_t *agent = leg->leg_agent;
  nta_outgoing_t *orq = NULL;
  msg_t *msg, *imsg;
  sip_t *sip;
  su_home_t *home;

  assert(leg); assert(ireq); 

  if (isip == NULL) 
    imsg = ireq->irq_request, isip = sip_object(ireq->irq_request);
  else if (isip == sip_object(ireq->irq_request))
    imsg = ireq->irq_request;
  else if (isip == sip_object(ireq->irq_request2))
    imsg = ireq->irq_request2;
  else {
    SU_DEBUG_3(("nta_outgoing_forward: invalid arguments\n"));
    return NULL;
  }

  assert(isip); assert(isip->sip_request);

  if (!route_url)
    route_url = (url_string_t *)agent->sa_default_proxy;

  if (!(msg = nta_msg_create(agent, 0)))
    return NULL;

  msg_clone(msg, imsg);

  sip = sip_object(msg); 
  home = msg_home(msg);
  
  /* Copy the SIP headers from the @c imsg message */
  do {
    if (sip_copy_all(msg, sip, isip) < 0)
      break;
    if (sip_add_headers(msg, sip, extra, headers) < 0)
      break;
    if (!route_url && sip->sip_route) {
      request_uri = (url_string_t *)sip->sip_route->r_url;
      if (!sip_route_remove(msg, sip))
	break;
    }
    if (request_uri) {
      sip_request_t *rq;

      rq = sip_request_create(home,
			      sip->sip_request->rq_method, 
			      sip->sip_request->rq_method_name, 
			      request_uri,
			      NULL);

      if (!rq || sip_header_insert(msg, sip, (sip_header_t *)rq) < 0)
	break;
    }
    
    if ((orq = nta_outgoing_mcreate(agent, callback, magic, route_url, msg)))
      return orq;

  } while (0);

  msg_destroy(msg);
  return NULL;
}
Exemplo n.º 24
0
/**Update registered socket.
 *
 * @retval 0 if success
 * @retval -1 upon failure
 */
static int sres_sofia_update(sres_sofia_t *srs,
			     su_socket_t new_socket,
			     su_socket_t old_socket)
{
  char const *what = NULL;
  su_wait_t wait[1];
  sres_sofia_register_t *reg = NULL;
  sres_sofia_register_t *old_reg = NULL;
  int i, index = -1, error = 0;
  int N = SRES_MAX_NAMESERVERS;

  SU_DEBUG_9(("sres_sofia_update(%p, %d, %d)\n",
	      (void *)srs, (int)new_socket, (int)old_socket));

  if (srs == NULL)
    return 0;

  if (srs->srs_root == NULL)
    return -1;

  if (old_socket == new_socket) {
    if (old_socket == INVALID_SOCKET) {
      sres_resolver_set_async(srs->srs_resolver, sres_sofia_update, NULL, 0);
      /* Destroy srs */
      for (i = 0; i < N; i++) {
	if (!srs->srs_reg[i].reg_index)
	  continue;
	su_root_deregister(srs->srs_root, srs->srs_reg[i].reg_index);
	memset(&srs->srs_reg[i], 0, sizeof(srs->srs_reg[i]));
      }
      su_timer_destroy(srs->srs_timer), srs->srs_timer = NULL;
      su_free(NULL, srs);
    }
    return 0;
  }

  if (old_socket != INVALID_SOCKET)
    for (i = 0; i < N; i++)
      if ((srs->srs_reg + i)->reg_socket == old_socket) {
	old_reg = srs->srs_reg + i;
	break;
      }

  if (new_socket != INVALID_SOCKET) {
    if (old_reg == NULL) {
      for (i = 0; i < N; i++) {
	if (!(srs->srs_reg + i)->reg_ptr)
	  break;
      }
      if (i > N)
	return su_seterrno(ENOMEM);

      reg = srs->srs_reg + i;
    }
    else
      reg = old_reg;
  }

  if (reg) {
    if (su_wait_create(wait, new_socket, SU_WAIT_IN | SU_WAIT_ERR) == -1) {
      reg = NULL;
      what = "su_wait_create";
      error = su_errno();
    }

    if (reg)
      index = su_root_register(srs->srs_root, wait, sres_sofia_poll, reg, 0);

    if (index < 0) {
      reg = NULL;
      what = "su_root_register";
      error = su_errno();
      su_wait_destroy(wait);
    }
  }

  if (old_reg) {
    if (old_socket == srs->srs_socket)
      srs->srs_socket = INVALID_SOCKET;
    su_root_deregister(srs->srs_root, old_reg->reg_index);
    memset(old_reg, 0, sizeof *old_reg);
  }

  if (reg) {
    srs->srs_socket = new_socket;

    reg->reg_ptr = srs;
    reg->reg_socket = new_socket;
    reg->reg_index = index;
  }

  if (!what)
    return 0;		/* success */

  SU_DEBUG_3(("sres: %s: %s\n", what, su_strerror(error)));

  return su_seterrno(error);
}
Exemplo n.º 25
0
/** Respond without creating a request structure */
static void server_reply(server_t *srv, tport_t *tport,
			 msg_t *request, msg_t *response,
			 int status, char const *phrase)
{
  http_t *http;
  http_payload_t *pl;
  int close;
  http_status_t st[1];
  char const *req_version = NULL;

  if (status < 200 || status >= 600)
    status = 500, phrase = http_500_internal_server;

  http = http_object(request);

  if (http && http->http_request)
    req_version = http->http_request->rq_version;

  close = status >= 200 &&
    (!srv->srv_persistent
     || status == 400
     || (http && http->http_request &&
	 http->http_request->rq_version != http_version_1_1)
     || (http && http->http_connection &&
	 msg_params_find(http->http_connection->k_items, "close")));

  msg_destroy(request);

  http = http_object(response);

  pl = http_payload_format(msg_home(response),
			   "<html>\n"
			   "<head><title>%u %s</title></head>\n"
			   "<body><h2>%u %s</h2></body>\n"
			   "</html>\n", status, phrase, status, phrase);

  msg_header_insert(response, (msg_pub_t *)http, (msg_header_t *)pl);

  if (req_version != http_version_0_9) {
    http_status_init(st);
    st->st_version = http_version_1_1;
    st->st_status = status;
    st->st_phrase = phrase;

    http_add_tl(response, http,
		HTTPTAG_STATUS(st),
		HTTPTAG_SERVER(srv->srv_server),
		HTTPTAG_CONTENT_TYPE_STR("text/html"),
		HTTPTAG_SEPARATOR_STR("\r\n"),
		TAG_IF(close, HTTPTAG_CONNECTION_STR("close")),
		TAG_END());

    msg_serialize(response, (msg_pub_t *)http);
  } else {
    /* Just send the response */
    *msg_chain_head(response) = (msg_header_t *)pl;
    close = 1;
  }

  if (tport_tqsend(tport, response, NULL,
		   TPTAG_CLOSE_AFTER(close),
		   TAG_END()) == -1) {
    SU_DEBUG_3(("server_reply(): cannot queue response\n"));
    tport_shutdown(tport, 2);
  }

  msg_destroy(response);
}
Exemplo n.º 26
0
static
int tls_init_context(tls_t *tls, tls_issues_t const *ti)
{
  int verify;
  static int random_loaded;

  ONCE_INIT(tls_init_once);

  if (!random_loaded) {
    random_loaded = 1;

    if (ti->randFile &&
	!RAND_load_file(ti->randFile, 1024 * 1024)) {
      if (ti->configured > 1) {
	SU_DEBUG_3(("%s: cannot open randFile %s\n",
		   "tls_init_context", ti->randFile));
	tls_log_errors(3, "tls_init_context", 0);
      }
      /* errno = EIO; */
      /* return -1; */
    }
  }

#if HAVE_SIGPIPE
  /* Avoid possible SIGPIPE when sending close_notify */
  signal(SIGPIPE, SIG_IGN);
#endif

  if (tls->ctx == NULL) {
    const SSL_METHOD *meth;

    /* meth = SSLv3_method(); */
    /* meth = SSLv23_method(); */

    if (ti->version)
      meth = TLSv1_method();
    else
      meth = SSLv23_method();

    tls->ctx = SSL_CTX_new((SSL_METHOD*)meth);
  }

  if (tls->ctx == NULL) {
    tls_log_errors(1, "tls_init_context", 0);
    errno = EIO;
    return -1;
  }

  if (!SSL_CTX_use_certificate_file(tls->ctx,
				    ti->cert,
				    SSL_FILETYPE_PEM)) {
    if (ti->configured > 0) {
      SU_DEBUG_1(("%s: invalid local certificate: %s\n",
		 "tls_init_context", ti->cert));
      tls_log_errors(3, "tls_init_context", 0);
#if require_client_certificate
      errno = EIO;
      return -1;
#endif
    }
  }

  if (!SSL_CTX_use_PrivateKey_file(tls->ctx,
                                   ti->key,
                                   SSL_FILETYPE_PEM)) {
    if (ti->configured > 0) {
      SU_DEBUG_1(("%s: invalid private key: %s\n",
		 "tls_init_context", ti->key));
      tls_log_errors(3, "tls_init_context(key)", 0);
#if require_client_certificate
      errno = EIO;
      return -1;
#endif
    }
  }

  if (!SSL_CTX_check_private_key(tls->ctx)) {
    if (ti->configured > 0) {
      SU_DEBUG_1(("%s: private key does not match the certificate public key\n",
		  "tls_init_context"));
    }
#if require_client_certificate
    errno = EIO;
    return -1;
#endif
  }

  if (!SSL_CTX_load_verify_locations(tls->ctx,
                                     ti->CAfile,
                                     ti->CApath)) {
    SU_DEBUG_1(("%s: error loading CA list: %s\n",
		 "tls_init_context", ti->CAfile));
    if (ti->configured > 0)
      tls_log_errors(3, "tls_init_context(CA)", 0);
    errno = EIO;
    return -1;
  }

  /* corresponds to (enum tport_tls_verify_policy) */
  tls->verify_incoming = (ti->policy & 0x1) ? 1 : 0;
  tls->verify_outgoing = (ti->policy & 0x2) ? 1 : 0;
  tls->verify_subj_in  = (ti->policy & 0x4) ? tls->verify_incoming : 0;
  tls->verify_subj_out = (ti->policy & 0x8) ? tls->verify_outgoing : 0;
  tls->verify_date     = (ti->verify_date)  ? 1 : 0;

  if (tls->verify_incoming)
    verify = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
  else
    verify = SSL_VERIFY_NONE;

  SSL_CTX_set_verify_depth(tls->ctx, ti->verify_depth);
  SSL_CTX_set_verify(tls->ctx, verify, tls_verify_cb);

  if (!SSL_CTX_set_cipher_list(tls->ctx, ti->cipher)) {
    SU_DEBUG_1(("%s: error setting cipher list\n", "tls_init_context"));
    tls_log_errors(3, "tls_init_context", 0);
    errno = EIO;
    return -1;
  }

  return 0;
}