Exemplo n.º 1
0
/** Update the routerset's <b>countries</b> bitarray_t. Called whenever
 * the GeoIP IPv4 database is reloaded.
 */
void
routerset_refresh_countries(routerset_t *target)
{
  int cc;
  bitarray_free(target->countries);

  if (!geoip_is_loaded(AF_INET)) {
    target->countries = NULL;
    target->n_countries = 0;
    return;
  }
  target->n_countries = geoip_get_n_countries();
  target->countries = bitarray_init_zero(target->n_countries);
  SMARTLIST_FOREACH_BEGIN(target->country_names, const char *, country) {
    cc = geoip_get_country(country);
    if (cc >= 0) {
      tor_assert(cc < target->n_countries);
      bitarray_set(target->countries, cc);
    } else {
      log_warn(LD_CONFIG, "Country code '%s' is not recognized.",
          country);
    }
  } SMARTLIST_FOREACH_END(country);
}
Exemplo n.º 2
0
/** Called when we've just received a relay data cell, when we've just
 * finished flushing all bytes to stream <b>conn</b>, or when we've flushed
 * *some* bytes to the stream <b>conn</b>.
 *
 * If conn->outbuf is not too full, and our deliver window is low, send back a
 * suitable number of stream-level sendme cells.
 */
void
sendme_connection_edge_consider_sending(edge_connection_t *conn)
{
  tor_assert(conn);

  int log_domain = TO_CONN(conn)->type == CONN_TYPE_AP ? LD_APP : LD_EXIT;

  /* Don't send it if we still have data to deliver. */
  if (connection_outbuf_too_full(TO_CONN(conn))) {
    goto end;
  }

  if (circuit_get_by_edge_conn(conn) == NULL) {
    /* This can legitimately happen if the destroy has already arrived and
     * torn down the circuit. */
    log_info(log_domain, "No circuit associated with edge connection. "
                         "Skipping sending SENDME.");
    goto end;
  }

  while (conn->deliver_window <=
         (STREAMWINDOW_START - STREAMWINDOW_INCREMENT)) {
    log_debug(log_domain, "Outbuf %" TOR_PRIuSZ ", queuing stream SENDME.",
              TO_CONN(conn)->outbuf_flushlen);
    conn->deliver_window += STREAMWINDOW_INCREMENT;
    if (connection_edge_send_command(conn, RELAY_COMMAND_SENDME,
                                     NULL, 0) < 0) {
      log_warn(LD_BUG, "connection_edge_send_command failed while sending "
                       "a SENDME. Circuit probably closed, skipping.");
      goto end; /* The circuit's closed, don't continue */
    }
  }

 end:
  return;
}
Exemplo n.º 3
0
Arquivo: nodelist.c Projeto: houqp/tor
/** Add <b>ri</b> to an appropriate node in the nodelist.  If we replace an
 * old routerinfo, and <b>ri_old_out</b> is not NULL, set *<b>ri_old_out</b>
 * to the previous routerinfo.
 */
node_t *
nodelist_set_routerinfo(routerinfo_t *ri, routerinfo_t **ri_old_out)
{
  node_t *node;
  const char *id_digest;
  int had_router = 0;
  tor_assert(ri);

  init_nodelist();
  id_digest = ri->cache_info.identity_digest;
  node = node_get_or_create(id_digest);

  if (node->ri) {
    if (!routers_have_same_or_addrs(node->ri, ri)) {
      node_addrs_changed(node);
    }
    had_router = 1;
    if (ri_old_out)
      *ri_old_out = node->ri;
  } else {
    if (ri_old_out)
      *ri_old_out = NULL;
  }
  node->ri = ri;

  if (node->country == -1)
    node_set_country(node);

  if (authdir_mode(get_options()) && !had_router) {
    const char *discard=NULL;
    uint32_t status = dirserv_router_get_status(ri, &discard);
    dirserv_set_node_flags_from_authoritative_status(node, status);
  }

  return node;
}
Exemplo n.º 4
0
/** Replace all "private" entries in *<b>policy</b> with their expanded
 * equivalents. */
void
policy_expand_private(smartlist_t **policy)
{
  static const char *private_nets[] = {
    "0.0.0.0/8", "169.254.0.0/16",
    "127.0.0.0/8", "192.168.0.0/16", "10.0.0.0/8", "172.16.0.0/12", NULL };
  uint16_t port_min, port_max;

  int i;
  smartlist_t *tmp;

  if (!*policy)
    return;

  tmp = smartlist_create();

  SMARTLIST_FOREACH(*policy, addr_policy_t *, p,
  {
     if (! p->is_private) {
       smartlist_add(tmp, p);
       continue;
     }
     for (i = 0; private_nets[i]; ++i) {
       addr_policy_t policy;
       memcpy(&policy, p, sizeof(addr_policy_t));
       policy.is_private = 0;
       policy.is_canonical = 0;
       if (parse_addr_and_port_range(private_nets[i],
                                     &policy.addr,
                                     &policy.maskbits, &port_min, &port_max)) {
         tor_assert(0);
       }
       smartlist_add(tmp, addr_policy_get_canonical_entry(&policy));
     }
     addr_policy_free(p);
  });
Exemplo n.º 5
0
/* From a given service, rendezvous cookie and handshake info, create a
 * rendezvous point circuit identifier. This can't fail. */
STATIC hs_ident_circuit_t *
create_rp_circuit_identifier(const hs_service_t *service,
                             const uint8_t *rendezvous_cookie,
                             const curve25519_public_key_t *server_pk,
                             const hs_ntor_rend_cell_keys_t *keys)
{
  hs_ident_circuit_t *ident;
  uint8_t handshake_info[CURVE25519_PUBKEY_LEN + DIGEST256_LEN];

  tor_assert(service);
  tor_assert(rendezvous_cookie);
  tor_assert(server_pk);
  tor_assert(keys);

  ident = hs_ident_circuit_new(&service->keys.identity_pk,
                               HS_IDENT_CIRCUIT_RENDEZVOUS);
  /* Copy the RENDEZVOUS_COOKIE which is the unique identifier. */
  memcpy(ident->rendezvous_cookie, rendezvous_cookie,
         sizeof(ident->rendezvous_cookie));
  /* Build the HANDSHAKE_INFO which looks like this:
   *    SERVER_PK        [32 bytes]
   *    AUTH_INPUT_MAC   [32 bytes]
   */
  memcpy(handshake_info, server_pk->public_key, CURVE25519_PUBKEY_LEN);
  memcpy(handshake_info + CURVE25519_PUBKEY_LEN, keys->rend_cell_auth_mac,
         DIGEST256_LEN);
  tor_assert(sizeof(ident->rendezvous_handshake_info) ==
             sizeof(handshake_info));
  memcpy(ident->rendezvous_handshake_info, handshake_info,
         sizeof(ident->rendezvous_handshake_info));
  /* Finally copy the NTOR_KEY_SEED for e2e encryption on the circuit. */
  tor_assert(sizeof(ident->rendezvous_ntor_key_seed) ==
             sizeof(keys->ntor_key_seed));
  memcpy(ident->rendezvous_ntor_key_seed, keys->ntor_key_seed,
         sizeof(ident->rendezvous_ntor_key_seed));
  return ident;
}
Exemplo n.º 6
0
/** Process a 'versions' cell.  The current link protocol version must be 0
 * to indicate that no version has yet been negotiated.  We compare the
 * versions in the cell to the list of versions we support, pick the
 * highest version we have in common, and continue the negotiation from
 * there.
 */
static void
command_process_versions_cell(var_cell_t *cell, or_connection_t *conn)
{
  int highest_supported_version = 0;
  const uint8_t *cp, *end;
  const int started_here = connection_or_nonopen_was_started_here(conn);
  if (conn->link_proto != 0 ||
      (conn->handshake_state && conn->handshake_state->received_versions)) {
    log_fn(LOG_PROTOCOL_WARN, LD_OR,
           "Received a VERSIONS cell on a connection with its version "
           "already set to %d; dropping", (int) conn->link_proto);
    return;
  }
  switch (conn->_base.state)
    {
    case OR_CONN_STATE_OR_HANDSHAKING_V2:
    case OR_CONN_STATE_OR_HANDSHAKING_V3:
      break;
    case OR_CONN_STATE_TLS_HANDSHAKING:
    case OR_CONN_STATE_TLS_SERVER_RENEGOTIATING:
    default:
      log_fn(LOG_PROTOCOL_WARN, LD_OR,
             "VERSIONS cell while in unexpected state");
      return;
  }

  tor_assert(conn->handshake_state);
  end = cell->payload + cell->payload_len;
  for (cp = cell->payload; cp+1 < end; ++cp) {
    uint16_t v = ntohs(get_uint16(cp));
    if (is_or_protocol_version_known(v) && v > highest_supported_version)
      highest_supported_version = v;
  }
  if (!highest_supported_version) {
    log_fn(LOG_PROTOCOL_WARN, LD_OR,
           "Couldn't find a version in common between my version list and the "
           "list in the VERSIONS cell; closing connection.");
    connection_mark_for_close(TO_CONN(conn));
    return;
  } else if (highest_supported_version == 1) {
    /* Negotiating version 1 makes no sense, since version 1 has no VERSIONS
     * cells. */
    log_fn(LOG_PROTOCOL_WARN, LD_OR,
           "Used version negotiation protocol to negotiate a v1 connection. "
           "That's crazily non-compliant. Closing connection.");
    connection_mark_for_close(TO_CONN(conn));
    return;
  } else if (highest_supported_version < 3 &&
             conn->_base.state ==  OR_CONN_STATE_OR_HANDSHAKING_V3) {
    log_fn(LOG_PROTOCOL_WARN, LD_OR,
           "Negotiated link protocol 2 or lower after doing a v3 TLS "
           "handshake. Closing connection.");
    connection_mark_for_close(TO_CONN(conn));
    return;
  }

  conn->link_proto = highest_supported_version;
  conn->handshake_state->received_versions = 1;

  if (conn->link_proto == 2) {
    log_info(LD_OR, "Negotiated version %d with %s:%d; sending NETINFO.",
             highest_supported_version,
             safe_str_client(conn->_base.address),
             conn->_base.port);

    if (connection_or_send_netinfo(conn) < 0) {
      connection_mark_for_close(TO_CONN(conn));
      return;
    }
  } else {
    const int send_versions = !started_here;
    /* If we want to authenticate, send a CERTS cell */
    const int send_certs = !started_here || public_server_mode(get_options());
    /* If we're a relay that got a connection, ask for authentication. */
    const int send_chall = !started_here && public_server_mode(get_options());
    /* If our certs cell will authenticate us, or if we have no intention of
     * authenticating, send a netinfo cell right now. */
    const int send_netinfo =
      !(started_here && public_server_mode(get_options()));
    const int send_any =
      send_versions || send_certs || send_chall || send_netinfo;
    tor_assert(conn->link_proto >= 3);

    log_info(LD_OR, "Negotiated version %d with %s:%d; %s%s%s%s%s",
             highest_supported_version,
             safe_str_client(conn->_base.address),
             conn->_base.port,
             send_any ? "Sending cells:" : "Waiting for CERTS cell",
             send_versions ? " VERSIONS" : "",
             send_certs ? " CERTS" : "",
             send_chall ? " AUTH_CHALLENGE" : "",
             send_netinfo ? " NETINFO" : "");

#ifdef DISABLE_V3_LINKPROTO_SERVERSIDE
    if (1) {
      connection_mark_for_close(TO_CONN(conn));
      return;
    }
#endif

    if (send_versions) {
      if (connection_or_send_versions(conn, 1) < 0) {
        log_warn(LD_OR, "Couldn't send versions cell");
        connection_mark_for_close(TO_CONN(conn));
        return;
      }
    }
    if (send_certs) {
      if (connection_or_send_certs_cell(conn) < 0) {
        log_warn(LD_OR, "Couldn't send certs cell");
        connection_mark_for_close(TO_CONN(conn));
        return;
      }
    }
    if (send_chall) {
      if (connection_or_send_auth_challenge_cell(conn) < 0) {
        log_warn(LD_OR, "Couldn't send auth_challenge cell");
        connection_mark_for_close(TO_CONN(conn));
        return;
      }
    }
    if (send_netinfo) {
      if (connection_or_send_netinfo(conn) < 0) {
        log_warn(LD_OR, "Couldn't send netinfo cell");
        connection_mark_for_close(TO_CONN(conn));
        return;
      }
    }
  }
}
Exemplo n.º 7
0
/** Process an AUTHENTICATE cell from an OR connection.
 *
 * If it's ill-formed or we weren't supposed to get one or we're not doing a
 * v3 handshake, then mark the connection.  If it does not authenticate the
 * other side of the connection successfully (because it isn't signed right,
 * we didn't get a CERTS cell, etc) mark the connection.  Otherwise, accept
 * the identity of the router on the other side of the connection.
 */
static void
command_process_authenticate_cell(var_cell_t *cell, or_connection_t *conn)
{
  uint8_t expected[V3_AUTH_FIXED_PART_LEN];
  const uint8_t *auth;
  int authlen;

#define ERR(s)                                                  \
  do {                                                          \
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,                      \
           "Received a bad AUTHENTICATE cell from %s:%d: %s",   \
           safe_str(conn->_base.address), conn->_base.port, (s));       \
    connection_mark_for_close(TO_CONN(conn));                   \
    return;                                                     \
  } while (0)

  if (conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING_V3)
    ERR("We're not doing a v3 handshake");
  if (conn->link_proto < 3)
    ERR("We're not using link protocol >= 3");
  if (conn->handshake_state->started_here)
    ERR("We originated this connection");
  if (conn->handshake_state->received_authenticate)
    ERR("We already got one!");
  if (conn->handshake_state->authenticated) {
    /* Should be impossible given other checks */
    ERR("The peer is already authenticated");
  }
  if (! conn->handshake_state->received_certs_cell)
    ERR("We never got a certs cell");
  if (conn->handshake_state->auth_cert == NULL)
    ERR("We never got an authentication certificate");
  if (conn->handshake_state->id_cert == NULL)
    ERR("We never got an identity certificate");
  if (cell->payload_len < 4)
    ERR("Cell was way too short");

  auth = cell->payload;
  {
    uint16_t type = ntohs(get_uint16(auth));
    uint16_t len = ntohs(get_uint16(auth+2));
    if (4 + len > cell->payload_len)
      ERR("Authenticator was truncated");

    if (type != AUTHTYPE_RSA_SHA256_TLSSECRET)
      ERR("Authenticator type was not recognized");

    auth += 4;
    authlen = len;
  }

  if (authlen < V3_AUTH_BODY_LEN + 1)
    ERR("Authenticator was too short");

  if (connection_or_compute_authenticate_cell_body(
                        conn, expected, sizeof(expected), NULL, 1) < 0)
    ERR("Couldn't compute expected AUTHENTICATE cell body");

  if (tor_memneq(expected, auth, sizeof(expected)))
    ERR("Some field in the AUTHENTICATE cell body was not as expected");

  {
    crypto_pk_t *pk = tor_tls_cert_get_key(
                                   conn->handshake_state->auth_cert);
    char d[DIGEST256_LEN];
    char *signed_data;
    size_t keysize;
    int signed_len;

    if (!pk)
      ERR("Internal error: couldn't get RSA key from AUTH cert.");
    crypto_digest256(d, (char*)auth, V3_AUTH_BODY_LEN, DIGEST_SHA256);

    keysize = crypto_pk_keysize(pk);
    signed_data = tor_malloc(keysize);
    signed_len = crypto_pk_public_checksig(pk, signed_data, keysize,
                                           (char*)auth + V3_AUTH_BODY_LEN,
                                           authlen - V3_AUTH_BODY_LEN);
    crypto_pk_free(pk);
    if (signed_len < 0) {
      tor_free(signed_data);
      ERR("Signature wasn't valid");
    }
    if (signed_len < DIGEST256_LEN) {
      tor_free(signed_data);
      ERR("Not enough data was signed");
    }
    /* Note that we deliberately allow *more* than DIGEST256_LEN bytes here,
     * in case they're later used to hold a SHA3 digest or something. */
    if (tor_memneq(signed_data, d, DIGEST256_LEN)) {
      tor_free(signed_data);
      ERR("Signature did not match data to be signed.");
    }
    tor_free(signed_data);
  }

  /* Okay, we are authenticated. */
  conn->handshake_state->received_authenticate = 1;
  conn->handshake_state->authenticated = 1;
  conn->handshake_state->digest_received_data = 0;
  {
    crypto_pk_t *identity_rcvd =
      tor_tls_cert_get_key(conn->handshake_state->id_cert);
    const digests_t *id_digests =
      tor_cert_get_id_digests(conn->handshake_state->id_cert);

    /* This must exist; we checked key type when reading the cert. */
    tor_assert(id_digests);

    memcpy(conn->handshake_state->authenticated_peer_id,
           id_digests->d[DIGEST_SHA1], DIGEST_LEN);

    connection_or_set_circid_type(conn, identity_rcvd);
    crypto_pk_free(identity_rcvd);

    connection_or_init_conn_from_address(conn,
                  &conn->_base.addr,
                  conn->_base.port,
                  (const char*)conn->handshake_state->authenticated_peer_id,
                  0);

    log_info(LD_OR, "Got an AUTHENTICATE cell from %s:%d: Looks good.",
             safe_str(conn->_base.address), conn->_base.port);
  }

#undef ERR
}
Exemplo n.º 8
0
Arquivo: procmon.c Projeto: 4ZM/Tor
/** Create a process-termination monitor for the process specifier
 * given in <b>process_spec</b>.  Return a newly allocated
 * tor_process_monitor_t on success; return NULL and store an error
 * message into *<b>msg</b> on failure.  The caller must not free
 * the returned error message.
 *
 * When the monitored process terminates, call
 * <b>cb</b>(<b>cb_arg</b>).
 */
tor_process_monitor_t *
tor_process_monitor_new(struct event_base *base,
                        const char *process_spec,
                        log_domain_mask_t log_domain,
                        tor_procmon_callback_t cb, void *cb_arg,
                        const char **msg)
{
  tor_process_monitor_t *procmon = tor_malloc(sizeof(tor_process_monitor_t));
  struct parsed_process_specifier_t ppspec;

  tor_assert(msg != NULL);
  *msg = NULL;

  if (procmon == NULL) {
    *msg = "out of memory";
    goto err;
  }

  procmon->log_domain = log_domain;

  if (parse_process_specifier(process_spec, &ppspec, msg))
    goto err;

  procmon->pid = ppspec.pid;

#ifdef MS_WINDOWS
  procmon->hproc = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
                               FALSE,
                               procmon->pid);

  if (procmon->hproc != NULL) {
    procmon->poll_hproc = 1;
    log_info(procmon->log_domain, "Successfully opened handle to process %d; "
             "monitoring it.",
             (int)(procmon->pid));
  } else {
    /* If we couldn't get a handle to the process, we'll try again the
     * first time we poll. */
    log_info(procmon->log_domain, "Failed to open handle to process %d; will "
             "try again later.",
             (int)(procmon->pid));
  }
#endif

  procmon->cb = cb;
  procmon->cb_arg = cb_arg;

#ifdef PROCMON_POLLS
  procmon->e = tor_event_new(base, -1 /* no FD */, PERIODIC_TIMER_FLAGS,
                             tor_process_monitor_poll_cb, procmon);
  /* Note: If you port this file to plain Libevent 2, check that
   * procmon->e is non-NULL.  We don't need to here because
   * tor_evtimer_new never returns NULL. */

  evtimer_add(procmon->e, &poll_interval_tv);
#else
#error OOPS?
#endif

  return procmon;
 err:
  tor_process_monitor_free(procmon);
  return NULL;
}
Exemplo n.º 9
0
/** Implement a cpuworker.  'data' is an fdarray as returned by socketpair.
 * Read and writes from fdarray[1].  Reads requests, writes answers.
 *
 *   Request format:
 *          cpuworker_request_t.
 *   Response format:
 *          cpuworker_reply_t
 */
static void
cpuworker_main(void *data)
{
  /* For talking to the parent thread/process */
  tor_socket_t *fdarray = data;
  tor_socket_t fd;

  /* variables for onion processing */
  server_onion_keys_t onion_keys;
  cpuworker_request_t req;
  cpuworker_reply_t rpl;

  fd = fdarray[1]; /* this side is ours */
#ifndef TOR_IS_MULTITHREADED
  tor_close_socket(fdarray[0]); /* this is the side of the socketpair the
                                 * parent uses */
  tor_free_all(1); /* so the child doesn't hold the parent's fd's open */
  handle_signals(0); /* ignore interrupts from the keyboard, etc */
#endif
  tor_free(data);

  setup_server_onion_keys(&onion_keys);

  for (;;) {
    if (read_all(fd, (void *)&req, sizeof(req), 1) != sizeof(req)) {
      log_info(LD_OR, "read request failed. Exiting.");
      goto end;
    }
    tor_assert(req.magic == CPUWORKER_REQUEST_MAGIC);

    memset(&rpl, 0, sizeof(rpl));

    if (req.task == CPUWORKER_TASK_ONION) {
      const create_cell_t *cc = &req.create_cell;
      created_cell_t *cell_out = &rpl.created_cell;
      struct timeval tv_start = {0,0}, tv_end;
      int n;
      rpl.timed = req.timed;
      rpl.started_at = req.started_at;
      rpl.handshake_type = cc->handshake_type;
      if (req.timed)
        tor_gettimeofday(&tv_start);
      n = onion_skin_server_handshake(cc->handshake_type,
                                      cc->onionskin, cc->handshake_len,
                                      &onion_keys,
                                      cell_out->reply,
                                      rpl.keys, CPATH_KEY_MATERIAL_LEN,
                                      rpl.rend_auth_material);
      if (n < 0) {
        /* failure */
        log_debug(LD_OR,"onion_skin_server_handshake failed.");
        memset(&rpl, 0, sizeof(rpl));
        memcpy(rpl.tag, req.tag, TAG_LEN);
        rpl.success = 0;
      } else {
        /* success */
        log_debug(LD_OR,"onion_skin_server_handshake succeeded.");
        memcpy(rpl.tag, req.tag, TAG_LEN);
        cell_out->handshake_len = n;
        switch (cc->cell_type) {
        case CELL_CREATE:
          cell_out->cell_type = CELL_CREATED; break;
        case CELL_CREATE2:
          cell_out->cell_type = CELL_CREATED2; break;
        case CELL_CREATE_FAST:
          cell_out->cell_type = CELL_CREATED_FAST; break;
        default:
          tor_assert(0);
          goto end;
        }
        rpl.success = 1;
      }
      rpl.magic = CPUWORKER_REPLY_MAGIC;
      if (req.timed) {
        struct timeval tv_diff;
        int64_t usec;
        tor_gettimeofday(&tv_end);
        timersub(&tv_end, &tv_start, &tv_diff);
        usec = ((int64_t)tv_diff.tv_sec)*1000000 + tv_diff.tv_usec;
        if (usec < 0 || usec > MAX_BELIEVABLE_ONIONSKIN_DELAY)
          rpl.n_usec = MAX_BELIEVABLE_ONIONSKIN_DELAY;
        else
          rpl.n_usec = (uint32_t) usec;
      }
      if (write_all(fd, (void*)&rpl, sizeof(rpl), 1) != sizeof(rpl)) {
        log_err(LD_BUG,"writing response buf failed. Exiting.");
        goto end;
      }
      log_debug(LD_OR,"finished writing response.");
    } else if (req.task == CPUWORKER_TASK_SHUTDOWN) {
      log_info(LD_OR,"Clean shutdown: exiting");
      goto end;
    }
    memwipe(&req, 0, sizeof(req));
    memwipe(&rpl, 0, sizeof(req));
  }
 end:
  memwipe(&req, 0, sizeof(req));
  memwipe(&rpl, 0, sizeof(req));
  release_server_onion_keys(&onion_keys);
  tor_close_socket(fd);
  crypto_thread_cleanup();
  spawn_exit();
}
Exemplo n.º 10
0
/** Called when we're trying to connect an ap conn; sends an INTRODUCE1 cell
 * down introcirc if possible.
 */
int
rend_client_send_introduction(origin_circuit_t *introcirc,
                              origin_circuit_t *rendcirc)
{
  size_t payload_len;
  int r, v3_shift = 0;
  char payload[RELAY_PAYLOAD_SIZE];
  char tmp[RELAY_PAYLOAD_SIZE];
  rend_cache_entry_t *entry;
  crypt_path_t *cpath;
  off_t dh_offset;
  crypto_pk_env_t *intro_key; /* either Bob's public key or an intro key. */

  tor_assert(introcirc->_base.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
  tor_assert(rendcirc->_base.purpose == CIRCUIT_PURPOSE_C_REND_READY);
  tor_assert(introcirc->rend_data);
  tor_assert(rendcirc->rend_data);
  tor_assert(!rend_cmp_service_ids(introcirc->rend_data->onion_address,
                                   rendcirc->rend_data->onion_address));

  if (rend_cache_lookup_entry(introcirc->rend_data->onion_address, -1,
                              &entry) < 1) {
    log_warn(LD_REND,
             "query %s didn't have valid rend desc in cache. Failing.",
             escaped_safe_str(introcirc->rend_data->onion_address));
    goto err;
  }

  /* first 20 bytes of payload are the hash of Bob's pk */
  if (entry->parsed->version == 0) { /* un-versioned descriptor */
    intro_key = entry->parsed->pk;
  } else { /* versioned descriptor */
    intro_key = NULL;
    SMARTLIST_FOREACH(entry->parsed->intro_nodes, rend_intro_point_t *,
                      intro, {
      if (!memcmp(introcirc->build_state->chosen_exit->identity_digest,
                  intro->extend_info->identity_digest, DIGEST_LEN)) {
        intro_key = intro->intro_key;
        break;
      }
    });
    if (!intro_key) {
      /** XXX This case probably means that the intro point vanished while
       * we were building a circuit to it. In the future, we should find
       * out how that happened and whether we should kill the circuits to
       * removed intro points immediately. See task 1073. */
      int num_intro_points = smartlist_len(entry->parsed->intro_nodes);
      if (rend_cache_lookup_entry(introcirc->rend_data->onion_address,
          0, &entry) > 0) {
        log_info(LD_REND, "We have both a v0 and a v2 rend desc for this "
                 "service. The v2 desc doesn't contain the introduction "
                 "point (and key) to send an INTRODUCE1/2 cell to this "
                 "introduction point. Assuming the introduction point "
                 "is for v0 rend clients and using the service key "
                 "from the v0 desc instead. (This is probably a bug, "
                 "because we shouldn't even have both a v0 and a v2 "
                 "descriptor for the same service.)");
        /* See flyspray task 1024. */
        intro_key = entry->parsed->pk;
      } else {
        log_info(LD_REND, "Internal error: could not find intro key; we "
                 "only have a v2 rend desc with %d intro points.",
                 num_intro_points);
        goto err;
      }
    }
  }
Exemplo n.º 11
0
/** Implement a cpuworker.  'data' is an fdarray as returned by socketpair.
 * Read and writes from fdarray[1].  Reads requests, writes answers.
 *
 *   Request format:
 *          Task type           [1 byte, always CPUWORKER_TASK_ONION]
 *          Opaque tag          TAG_LEN
 *          Onionskin challenge ONIONSKIN_CHALLENGE_LEN
 *   Response format:
 *          Success/failure     [1 byte, boolean.]
 *          Opaque tag          TAG_LEN
 *          Onionskin challenge ONIONSKIN_REPLY_LEN
 *          Negotiated keys     KEY_LEN*2+DIGEST_LEN*2
 *
 *  (Note: this _should_ be by addr/port, since we're concerned with specific
 * connections, not with routers (where we'd use identity).)
 */
static void
cpuworker_main(void *data)
{
  char question[ONIONSKIN_CHALLENGE_LEN];
  uint8_t question_type;
  int *fdarray = data;
  int fd;

  /* variables for onion processing */
  char keys[CPATH_KEY_MATERIAL_LEN];
  char reply_to_proxy[ONIONSKIN_REPLY_LEN];
  char buf[LEN_ONION_RESPONSE];
  char tag[TAG_LEN];
  crypto_pk_env_t *onion_key = NULL, *last_onion_key = NULL;

  fd = fdarray[1]; /* this side is ours */
#ifndef TOR_IS_MULTITHREADED
  tor_close_socket(fdarray[0]); /* this is the side of the socketpair the
                                 * parent uses */
  tor_free_all(1); /* so the child doesn't hold the parent's fd's open */
  handle_signals(0); /* ignore interrupts from the keyboard, etc */
#endif
  tor_free(data);

  dup_onion_keys(&onion_key, &last_onion_key);

  for (;;) {
    ssize_t r;

    if ((r = recv(fd, &question_type, 1, 0)) != 1) {
//      log_fn(LOG_ERR,"read type failed. Exiting.");
      if (r == 0) {
        log_info(LD_OR,
                 "CPU worker exiting because Tor process closed connection "
                 "(either rotated keys or died).");
      } else {
        log_info(LD_OR,
                 "CPU worker exiting because of error on connection to Tor "
                 "process.");
        log_info(LD_OR,"(Error on %d was %s)",
                 fd, tor_socket_strerror(tor_socket_errno(fd)));
      }
      goto end;
    }
    tor_assert(question_type == CPUWORKER_TASK_ONION);

    if (read_all(fd, tag, TAG_LEN, 1) != TAG_LEN) {
      log_err(LD_BUG,"read tag failed. Exiting.");
      goto end;
    }

    if (read_all(fd, question, ONIONSKIN_CHALLENGE_LEN, 1) !=
        ONIONSKIN_CHALLENGE_LEN) {
      log_err(LD_BUG,"read question failed. Exiting.");
      goto end;
    }

    if (question_type == CPUWORKER_TASK_ONION) {
      if (onion_skin_server_handshake(question, onion_key, last_onion_key,
          reply_to_proxy, keys, CPATH_KEY_MATERIAL_LEN) < 0) {
        /* failure */
        log_debug(LD_OR,"onion_skin_server_handshake failed.");
        *buf = 0; /* indicate failure in first byte */
        memcpy(buf+1,tag,TAG_LEN);
        /* send all zeros as answer */
        memset(buf+1+TAG_LEN, 0, LEN_ONION_RESPONSE-(1+TAG_LEN));
      } else {
        /* success */
        log_debug(LD_OR,"onion_skin_server_handshake succeeded.");
        buf[0] = 1; /* 1 means success */
        memcpy(buf+1,tag,TAG_LEN);
        memcpy(buf+1+TAG_LEN,reply_to_proxy,ONIONSKIN_REPLY_LEN);
        memcpy(buf+1+TAG_LEN+ONIONSKIN_REPLY_LEN,keys,CPATH_KEY_MATERIAL_LEN);
      }
      if (write_all(fd, buf, LEN_ONION_RESPONSE, 1) != LEN_ONION_RESPONSE) {
        log_err(LD_BUG,"writing response buf failed. Exiting.");
        goto end;
      }
      log_debug(LD_OR,"finished writing response.");
    }
  }
 end:
  if (onion_key)
    crypto_free_pk_env(onion_key);
  if (last_onion_key)
    crypto_free_pk_env(last_onion_key);
  tor_close_socket(fd);
  crypto_thread_cleanup();
  spawn_exit();
}
Exemplo n.º 12
0
/**
 * Perform the final client side of the ntor handshake, using the state in
 * <b>handshake_state</b> and the server's NTOR_REPLY_LEN-byte reply in
 * <b>handshake_reply</b>.  Generate <b>key_out_len</b> bytes of key material
 * in <b>key_out</b>. Return 0 on success, -1 on failure.
 */
int
onion_skin_ntor_client_handshake(
                             const ntor_handshake_state_t *handshake_state,
                             const uint8_t *handshake_reply,
                             uint8_t *key_out,
                             size_t key_out_len,
                             const char **msg_out)
{
  const tweakset_t *T = &proto1_tweaks;
  /* Sensitive stack-allocated material. Kept in an anonymous struct to make
   * it easy to wipe. */
  struct {
    curve25519_public_key_t pubkey_Y;
    uint8_t secret_input[SECRET_INPUT_LEN];
    uint8_t verify[DIGEST256_LEN];
    uint8_t auth_input[AUTH_INPUT_LEN];
    uint8_t auth[DIGEST256_LEN];
  } s;
  uint8_t *ai = s.auth_input, *si = s.secret_input;
  const uint8_t *auth_candidate;
  int bad;

  /* Decode input */
  memcpy(s.pubkey_Y.public_key, handshake_reply, CURVE25519_PUBKEY_LEN);
  auth_candidate = handshake_reply + CURVE25519_PUBKEY_LEN;

  /* See note in server_handshake above about checking points.  The
   * circumstances under which we'd need to check Y for membership are
   * different than those under which we'd be checking X. */

  /* Compute secret_input */
  curve25519_handshake(si, &handshake_state->seckey_x, &s.pubkey_Y);
  bad = safe_mem_is_zero(si, CURVE25519_OUTPUT_LEN);
  si += CURVE25519_OUTPUT_LEN;
  curve25519_handshake(si, &handshake_state->seckey_x,
                       &handshake_state->pubkey_B);
  bad |= (safe_mem_is_zero(si, CURVE25519_OUTPUT_LEN) << 1);
  si += CURVE25519_OUTPUT_LEN;
  APPEND(si, handshake_state->router_id, DIGEST_LEN);
  APPEND(si, handshake_state->pubkey_B.public_key, CURVE25519_PUBKEY_LEN);
  APPEND(si, handshake_state->pubkey_X.public_key, CURVE25519_PUBKEY_LEN);
  APPEND(si, s.pubkey_Y.public_key, CURVE25519_PUBKEY_LEN);
  APPEND(si, PROTOID, PROTOID_LEN);
  tor_assert(si == s.secret_input + sizeof(s.secret_input));

  /* Compute verify from secret_input */
  h_tweak(s.verify, s.secret_input, sizeof(s.secret_input), T->t_verify);

  /* Compute auth_input */
  APPEND(ai, s.verify, DIGEST256_LEN);
  APPEND(ai, handshake_state->router_id, DIGEST_LEN);
  APPEND(ai, handshake_state->pubkey_B.public_key, CURVE25519_PUBKEY_LEN);
  APPEND(ai, s.pubkey_Y.public_key, CURVE25519_PUBKEY_LEN);
  APPEND(ai, handshake_state->pubkey_X.public_key, CURVE25519_PUBKEY_LEN);
  APPEND(ai, PROTOID, PROTOID_LEN);
  APPEND(ai, SERVER_STR, SERVER_STR_LEN);
  tor_assert(ai == s.auth_input + sizeof(s.auth_input));

  /* Compute auth */
  h_tweak(s.auth, s.auth_input, sizeof(s.auth_input), T->t_mac);

  bad |= (tor_memneq(s.auth, auth_candidate, DIGEST256_LEN) << 2);

  crypto_expand_key_material_rfc5869_sha256(
                           s.secret_input, sizeof(s.secret_input),
                           (const uint8_t*)T->t_key, strlen(T->t_key),
                           (const uint8_t*)T->m_expand, strlen(T->m_expand),
                           key_out, key_out_len);

  memwipe(&s, 0, sizeof(s));

  if (bad) {
    if (bad & 4) {
      if (msg_out)
        *msg_out = NULL; /* Don't report this one; we probably just had the
                          * wrong onion key.*/
      log_fn(LOG_INFO, LD_PROTOCOL,
             "Invalid result from curve25519 handshake: %d", bad);
    }
    if (bad & 3) {
      if (msg_out)
        *msg_out = "Zero output from curve25519 handshake";
      log_fn(LOG_WARN, LD_PROTOCOL,
             "Invalid result from curve25519 handshake: %d", bad);
    }
  }

  return bad ? -1 : 0;
}
Exemplo n.º 13
0
/**
 * Perform the server side of an ntor handshake. Given an
 * NTOR_ONIONSKIN_LEN-byte message in <b>onion_skin</b>, our own identity
 * fingerprint as <b>my_node_id</b>, and an associative array mapping public
 * onion keys to curve25519_keypair_t in <b>private_keys</b>, attempt to
 * perform the handshake.  Use <b>junk_keys</b> if present if the handshake
 * indicates an unrecognized public key.  Write an NTOR_REPLY_LEN-byte
 * message to send back to the client into <b>handshake_reply_out</b>, and
 * generate <b>key_out_len</b> bytes of key material in <b>key_out</b>. Return
 * 0 on success, -1 on failure.
 */
int
onion_skin_ntor_server_handshake(const uint8_t *onion_skin,
                                 const di_digest256_map_t *private_keys,
                                 const curve25519_keypair_t *junk_keys,
                                 const uint8_t *my_node_id,
                                 uint8_t *handshake_reply_out,
                                 uint8_t *key_out,
                                 size_t key_out_len)
{
  const tweakset_t *T = &proto1_tweaks;
  /* Sensitive stack-allocated material. Kept in an anonymous struct to make
   * it easy to wipe. */
  struct {
    uint8_t secret_input[SECRET_INPUT_LEN];
    uint8_t auth_input[AUTH_INPUT_LEN];
    curve25519_public_key_t pubkey_X;
    curve25519_secret_key_t seckey_y;
    curve25519_public_key_t pubkey_Y;
    uint8_t verify[DIGEST256_LEN];
  } s;
  uint8_t *si = s.secret_input, *ai = s.auth_input;
  const curve25519_keypair_t *keypair_bB;
  int bad;

  /* Decode the onion skin */
  /* XXXX Does this possible early-return business threaten our security? */
  if (tor_memneq(onion_skin, my_node_id, DIGEST_LEN))
    return -1;
  /* Note that on key-not-found, we go through with this operation anyway,
   * using "junk_keys". This will result in failed authentication, but won't
   * leak whether we recognized the key. */
  keypair_bB = dimap_search(private_keys, onion_skin + DIGEST_LEN,
                            (void*)junk_keys);
  if (!keypair_bB)
    return -1;

  memcpy(s.pubkey_X.public_key, onion_skin+DIGEST_LEN+DIGEST256_LEN,
         CURVE25519_PUBKEY_LEN);

  /* Make y, Y */
  curve25519_secret_key_generate(&s.seckey_y, 0);
  curve25519_public_key_generate(&s.pubkey_Y, &s.seckey_y);

  /* NOTE: If we ever use a group other than curve25519, or a different
   * representation for its points, we may need to perform different or
   * additional checks on X here and on Y in the client handshake, or lose our
   * security properties. What checks we need would depend on the properties
   * of the group and its representation.
   *
   * In short: if you use anything other than curve25519, this aspect of the
   * code will need to be reconsidered carefully. */

  /* build secret_input */
  curve25519_handshake(si, &s.seckey_y, &s.pubkey_X);
  bad = safe_mem_is_zero(si, CURVE25519_OUTPUT_LEN);
  si += CURVE25519_OUTPUT_LEN;
  curve25519_handshake(si, &keypair_bB->seckey, &s.pubkey_X);
  bad |= safe_mem_is_zero(si, CURVE25519_OUTPUT_LEN);
  si += CURVE25519_OUTPUT_LEN;

  APPEND(si, my_node_id, DIGEST_LEN);
  APPEND(si, keypair_bB->pubkey.public_key, CURVE25519_PUBKEY_LEN);
  APPEND(si, s.pubkey_X.public_key, CURVE25519_PUBKEY_LEN);
  APPEND(si, s.pubkey_Y.public_key, CURVE25519_PUBKEY_LEN);
  APPEND(si, PROTOID, PROTOID_LEN);
  tor_assert(si == s.secret_input + sizeof(s.secret_input));

  /* Compute hashes of secret_input */
  h_tweak(s.verify, s.secret_input, sizeof(s.secret_input), T->t_verify);

  /* Compute auth_input */
  APPEND(ai, s.verify, DIGEST256_LEN);
  APPEND(ai, my_node_id, DIGEST_LEN);
  APPEND(ai, keypair_bB->pubkey.public_key, CURVE25519_PUBKEY_LEN);
  APPEND(ai, s.pubkey_Y.public_key, CURVE25519_PUBKEY_LEN);
  APPEND(ai, s.pubkey_X.public_key, CURVE25519_PUBKEY_LEN);
  APPEND(ai, PROTOID, PROTOID_LEN);
  APPEND(ai, SERVER_STR, SERVER_STR_LEN);
  tor_assert(ai == s.auth_input + sizeof(s.auth_input));

  /* Build the reply */
  memcpy(handshake_reply_out, s.pubkey_Y.public_key, CURVE25519_PUBKEY_LEN);
  h_tweak(handshake_reply_out+CURVE25519_PUBKEY_LEN,
          s.auth_input, sizeof(s.auth_input),
          T->t_mac);

  /* Generate the key material */
  crypto_expand_key_material_rfc5869_sha256(
                           s.secret_input, sizeof(s.secret_input),
                           (const uint8_t*)T->t_key, strlen(T->t_key),
                           (const uint8_t*)T->m_expand, strlen(T->m_expand),
                           key_out, key_out_len);

  /* Wipe all of our local state */
  memwipe(&s, 0, sizeof(s));

  return bad ? -1 : 0;
}
Exemplo n.º 14
0
uint64_t siphash24g(const void *src, unsigned long src_sz) {
	tor_assert(the_siphash_key_is_set);
	return siphash24(src, src_sz, &the_siphash_key);
}
Exemplo n.º 15
0
/** Initialize the Libevent library and set up the event base. */
void
tor_libevent_initialize(tor_libevent_cfg *torcfg)
{
  tor_assert(the_event_base == NULL);
  /* some paths below don't use torcfg, so avoid unused variable warnings */
  (void)torcfg;

#ifdef HAVE_EVENT2_EVENT_H
  {
    int attempts = 0;
    int using_threads;
    struct event_config *cfg;

  retry:
    ++attempts;
    using_threads = 0;
    cfg = event_config_new();
    tor_assert(cfg);

#if defined(_WIN32) && defined(USE_BUFFEREVENTS)
    if (! torcfg->disable_iocp) {
      evthread_use_windows_threads();
      event_config_set_flag(cfg, EVENT_BASE_FLAG_STARTUP_IOCP);
      using_iocp_bufferevents = 1;
      using_threads = 1;
    } else {
      using_iocp_bufferevents = 0;
    }
#elif defined(__COVERITY__)
    /* Avoid a 'dead code' warning below. */
    using_threads = ! torcfg->disable_iocp;
#endif

    if (!using_threads) {
      /* Telling Libevent not to try to turn locking on can avoid a needless
       * socketpair() attempt. */
      event_config_set_flag(cfg, EVENT_BASE_FLAG_NOLOCK);
    }

#if defined(LIBEVENT_VERSION_NUMBER) && LIBEVENT_VERSION_NUMBER >= V(2,0,7)
    if (torcfg->num_cpus > 0)
      event_config_set_num_cpus_hint(cfg, torcfg->num_cpus);
#endif

#if LIBEVENT_VERSION_NUMBER >= V(2,0,9)
    /* We can enable changelist support with epoll, since we don't give
     * Libevent any dup'd fds.  This lets us avoid some syscalls. */
    event_config_set_flag(cfg, EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST);
#endif

    the_event_base = event_base_new_with_config(cfg);

    event_config_free(cfg);

    if (using_threads && the_event_base == NULL && attempts < 2) {
      /* This could be a socketpair() failure, which can happen sometimes on
       * windows boxes with obnoxious firewall rules.  Downgrade and try
       * again. */
#if defined(_WIN32) && defined(USE_BUFFEREVENTS)
      if (torcfg->disable_iocp == 0) {
        log_warn(LD_GENERAL, "Unable to initialize Libevent. Trying again "
                 "with IOCP disabled.");
      } else
#endif
      {
          log_warn(LD_GENERAL, "Unable to initialize Libevent. Trying again.");
      }

      torcfg->disable_iocp = 1;
      goto retry;
    }
  }
#else
  the_event_base = event_init();
#endif

  if (!the_event_base) {
    log_err(LD_GENERAL, "Unable to initialize Libevent: cannot continue.");
    exit(1);
  }

  /* Making this a NOTICE for now so we can link bugs to a libevent versions
   * or methods better. */
  log_info(LD_GENERAL,
      "Initialized libevent version %s using method %s. Good.",
      event_get_version(), tor_libevent_get_method());

#ifdef USE_BUFFEREVENTS
  tor_libevent_set_tick_timeout(torcfg->msec_per_tick);
#endif
}
Exemplo n.º 16
0
/** Helper function: Compute the last part of the HS ntor handshake which
 *  derives key material necessary to create and handle RENDEZVOUS1
 *  cells. Function used by both client and service. The actual calculations is
 *  as follows:
 *
 *    NTOR_KEY_SEED = MAC(rend_secret_hs_input, t_hsenc)
 *    verify = MAC(rend_secret_hs_input, t_hsverify)
 *    auth_input = verify | AUTH_KEY | B | Y | X | PROTOID | "Server"
 *    auth_input_mac = MAC(auth_input, t_hsmac)
 *
 *  where in the above, AUTH_KEY is <b>intro_auth_pubkey</b>, B is
 *  <b>intro_enc_pubkey</b>, Y is <b>service_ephemeral_rend_pubkey</b>, and X
 *  is <b>client_ephemeral_enc_pubkey</b>. The provided
 *  <b>rend_secret_hs_input</b> is of size REND_SECRET_HS_INPUT_LEN.
 *
 *  The final results of NTOR_KEY_SEED and auth_input_mac are placed in
 *  <b>hs_ntor_rend_cell_keys_out</b>. Return 0 if everything went fine. */
static int
get_rendezvous1_key_material(const uint8_t *rend_secret_hs_input,
                  const ed25519_public_key_t *intro_auth_pubkey,
                  const curve25519_public_key_t *intro_enc_pubkey,
                  const curve25519_public_key_t *service_ephemeral_rend_pubkey,
                  const curve25519_public_key_t *client_ephemeral_enc_pubkey,
                  hs_ntor_rend_cell_keys_t *hs_ntor_rend_cell_keys_out)
{
  int bad = 0;
  uint8_t ntor_key_seed[DIGEST256_LEN];
  uint8_t ntor_verify[DIGEST256_LEN];
  uint8_t rend_auth_input[REND_AUTH_INPUT_LEN];
  uint8_t rend_cell_auth[DIGEST256_LEN];
  uint8_t *ptr;

  /* Let's build NTOR_KEY_SEED */
  crypto_mac_sha3_256(ntor_key_seed, sizeof(ntor_key_seed),
                      rend_secret_hs_input, REND_SECRET_HS_INPUT_LEN,
                      (const uint8_t *)T_HSENC, strlen(T_HSENC));
  bad |= safe_mem_is_zero(ntor_key_seed, DIGEST256_LEN);

  /* Let's build ntor_verify */
  crypto_mac_sha3_256(ntor_verify, sizeof(ntor_verify),
                      rend_secret_hs_input, REND_SECRET_HS_INPUT_LEN,
                      (const uint8_t *)T_HSVERIFY, strlen(T_HSVERIFY));
  bad |= safe_mem_is_zero(ntor_verify, DIGEST256_LEN);

  /* Let's build auth_input: */
  ptr = rend_auth_input;
  /* Append ntor_verify */
  APPEND(ptr, ntor_verify, sizeof(ntor_verify));
  /* Append AUTH_KEY */
  APPEND(ptr, intro_auth_pubkey->pubkey, ED25519_PUBKEY_LEN);
  /* Append B */
  APPEND(ptr, intro_enc_pubkey->public_key, CURVE25519_PUBKEY_LEN);
  /* Append Y */
  APPEND(ptr,
         service_ephemeral_rend_pubkey->public_key, CURVE25519_PUBKEY_LEN);
  /* Append X */
  APPEND(ptr,
         client_ephemeral_enc_pubkey->public_key, CURVE25519_PUBKEY_LEN);
  /* Append PROTOID */
  APPEND(ptr, PROTOID, strlen(PROTOID));
  /* Append "Server" */
  APPEND(ptr, SERVER_STR, strlen(SERVER_STR));
  tor_assert(ptr == rend_auth_input + sizeof(rend_auth_input));

  /* Let's build auth_input_mac that goes in RENDEZVOUS1 cell */
  crypto_mac_sha3_256(rend_cell_auth, sizeof(rend_cell_auth),
                      rend_auth_input, sizeof(rend_auth_input),
                      (const uint8_t *)T_HSMAC, strlen(T_HSMAC));
  bad |= safe_mem_is_zero(ntor_verify, DIGEST256_LEN);

  { /* Get the computed RENDEZVOUS1 material! */
    memcpy(&hs_ntor_rend_cell_keys_out->rend_cell_auth_mac,
           rend_cell_auth, DIGEST256_LEN);
    memcpy(&hs_ntor_rend_cell_keys_out->ntor_key_seed,
           ntor_key_seed, DIGEST256_LEN);
  }

  memwipe(rend_cell_auth, 0, sizeof(rend_cell_auth));
  memwipe(rend_auth_input, 0, sizeof(rend_auth_input));
  memwipe(ntor_key_seed, 0, sizeof(ntor_key_seed));

  return bad;
}
Exemplo n.º 17
0
/** Called when we get data from a cpuworker.  If the answer is not complete,
 * wait for a complete answer. If the answer is complete,
 * process it as appropriate.
 */
int
connection_cpu_process_inbuf(connection_t *conn)
{
  char success;
  char buf[LEN_ONION_RESPONSE];
  uint64_t conn_id;
  circid_t circ_id;
  connection_t *tmp_conn;
  or_connection_t *p_conn = NULL;
  circuit_t *circ;

  tor_assert(conn);
  tor_assert(conn->type == CONN_TYPE_CPUWORKER);

  if (!buf_datalen(conn->inbuf))
    return 0;

  if (conn->state == CPUWORKER_STATE_BUSY_ONION) {
    if (buf_datalen(conn->inbuf) < LEN_ONION_RESPONSE) /* answer available? */
      return 0; /* not yet */
    tor_assert(buf_datalen(conn->inbuf) == LEN_ONION_RESPONSE);

    connection_fetch_from_buf(&success,1,conn);
    connection_fetch_from_buf(buf,LEN_ONION_RESPONSE-1,conn);

    /* parse out the circ it was talking about */
    tag_unpack(buf, &conn_id, &circ_id);
    circ = NULL;
    tmp_conn = connection_get_by_global_id(conn_id);
    if (tmp_conn && !tmp_conn->marked_for_close &&
        tmp_conn->type == CONN_TYPE_OR)
      p_conn = TO_OR_CONN(tmp_conn);

    if (p_conn)
      circ = circuit_get_by_circid_orconn(circ_id, p_conn);

    if (success == 0) {
      log_debug(LD_OR,
                "decoding onionskin failed. "
                "(Old key or bad software.) Closing.");
      if (circ)
        circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
      goto done_processing;
    }
    if (!circ) {
      /* This happens because somebody sends us a destroy cell and the
       * circuit goes away, while the cpuworker is working. This is also
       * why our tag doesn't include a pointer to the circ, because we'd
       * never know if it's still valid.
       */
      log_debug(LD_OR,"processed onion for a circ that's gone. Dropping.");
      goto done_processing;
    }
    tor_assert(! CIRCUIT_IS_ORIGIN(circ));
    if (onionskin_answer(TO_OR_CIRCUIT(circ), CELL_CREATED, buf+TAG_LEN,
                         buf+TAG_LEN+ONIONSKIN_REPLY_LEN) < 0) {
      log_warn(LD_OR,"onionskin_answer failed. Closing.");
      circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
      goto done_processing;
    }
    log_debug(LD_OR,"onionskin_answer succeeded. Yay.");
  } else {
    tor_assert(0); /* don't ask me to do handshakes yet */
  }

done_processing:
  conn->state = CPUWORKER_STATE_IDLE;
  num_cpuworkers_busy--;
  if (conn->timestamp_created < last_rotation_time) {
    connection_mark_for_close(conn);
    num_cpuworkers--;
    spawn_enough_cpuworkers();
  } else {
    process_pending_task(conn);
  }
  return 0;
}
Exemplo n.º 18
0
/** Send a resolve request for <b>hostname</b> to the Tor listening on
 * <b>sockshost</b>:<b>socksport</b>.  Store the resulting IPv4
 * address (in host order) into *<b>result_addr</b>.
 */
static int
do_resolve(const char *hostname, uint32_t sockshost, uint16_t socksport,
           int reverse, int version,
           uint32_t *result_addr, char **result_hostname)
{
  int s;
  struct sockaddr_in socksaddr;
  char *req = NULL;
  int len = 0;

  tor_assert(hostname);
  tor_assert(result_addr);
  tor_assert(version == 4 || version == 5);

  *result_addr = 0;
  *result_hostname = NULL;

  s = tor_open_socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
  if (s<0) {
    log_sock_error("creating_socket", -1);
    return -1;
  }

  memset(&socksaddr, 0, sizeof(socksaddr));
  socksaddr.sin_family = AF_INET;
  socksaddr.sin_port = htons(socksport);
  socksaddr.sin_addr.s_addr = htonl(sockshost);
  if (connect(s, (struct sockaddr*)&socksaddr, sizeof(socksaddr))) {
    log_sock_error("connecting to SOCKS host", s);
    return -1;
  }

  if (version == 5) {
    char method_buf[2];
    if (write_all(s, "\x05\x01\x00", 3, 1) != 3) {
      log_err(LD_NET, "Error sending SOCKS5 method list.");
      return -1;
    }
    if (read_all(s, method_buf, 2, 1) != 2) {
      log_err(LD_NET, "Error reading SOCKS5 methods.");
      return -1;
    }
    if (method_buf[0] != '\x05') {
      log_err(LD_NET, "Unrecognized socks version: %u",
              (unsigned)method_buf[0]);
      return -1;
    }
    if (method_buf[1] != '\x00') {
      log_err(LD_NET, "Unrecognized socks authentication method: %u",
              (unsigned)method_buf[1]);
      return -1;
    }
  }

  if ((len = build_socks_resolve_request(&req, "", hostname, reverse,
                                         version))<0) {
    log_err(LD_BUG,"Error generating SOCKS request");
    tor_assert(!req);
    return -1;
  }
  if (write_all(s, req, len, 1) != len) {
    log_sock_error("sending SOCKS request", s);
    tor_free(req);
    return -1;
  }
  tor_free(req);

  if (version == 4) {
    char reply_buf[RESPONSE_LEN_4];
    if (read_all(s, reply_buf, RESPONSE_LEN_4, 1) != RESPONSE_LEN_4) {
      log_err(LD_NET, "Error reading SOCKS4 response.");
      return -1;
    }
    if (parse_socks4a_resolve_response(reply_buf, RESPONSE_LEN_4,
                                       result_addr)<0){
      return -1;
    }
  } else {
    char reply_buf[4];
    if (read_all(s, reply_buf, 4, 1) != 4) {
      log_err(LD_NET, "Error reading SOCKS5 response.");
      return -1;
    }
    if (reply_buf[0] != 5) {
      log_err(LD_NET, "Bad SOCKS5 reply version.");
      return -1;
    }
    if (reply_buf[1] != 0) {
      log_warn(LD_NET,"Got status response '%u': SOCKS5 request failed.",
               (unsigned)reply_buf[1]);
      return -1;
    }
    if (reply_buf[3] == 1) {
      /* IPv4 address */
      if (read_all(s, reply_buf, 4, 1) != 4) {
        log_err(LD_NET, "Error reading address in socks5 response.");
        return -1;
      }
      *result_addr = ntohl(get_uint32(reply_buf));
    } else if (reply_buf[3] == 3) {
      size_t result_len;
      if (read_all(s, reply_buf, 1, 1) != 1) {
        log_err(LD_NET, "Error reading address_length in socks5 response.");
        return -1;
      }
      result_len = *(uint8_t*)(reply_buf);
      *result_hostname = tor_malloc(result_len+1);
      if (read_all(s, *result_hostname, result_len, 1) != (int) result_len) {
        log_err(LD_NET, "Error reading hostname in socks5 response.");
        return -1;
      }
      (*result_hostname)[result_len] = '\0';
    }
  }

  return 0;
}
Exemplo n.º 19
0
void
tor_mutex_acquire(tor_mutex_t *m)
{
  tor_assert(m);
  EnterCriticalSection(&m->mutex);
}
Exemplo n.º 20
0
/* Decide if the newly received <b>commit</b> should be kept depending on
 * the current phase and state of the protocol. The <b>voter_key</b> is the
 * RSA identity key fingerprint of the authority's vote from which the
 * commit comes from. The <b>phase</b> is the phase we should be validating
 * the commit for. Return 1 if the commit should be added to our state or 0
 * if not. */
STATIC int
should_keep_commit(const sr_commit_t *commit, const char *voter_key,
                   sr_phase_t phase)
{
  const sr_commit_t *saved_commit;

  tor_assert(commit);
  tor_assert(voter_key);

  log_debug(LD_DIR, "SR: Inspecting commit from %s (voter: %s)?",
            sr_commit_get_rsa_fpr(commit),
            hex_str(voter_key, DIGEST_LEN));

  /* For a commit to be considered, it needs to be authoritative (it should
   * be the voter's own commit). */
  if (!commit_is_authoritative(commit, voter_key)) {
    log_debug(LD_DIR, "SR: Ignoring non-authoritative commit.");
    goto ignore;
  }

  /* Let's make sure, for extra safety, that this fingerprint is known to
   * us. Even though this comes from a vote, doesn't hurt to be
   * extracareful. */
  if (trusteddirserver_get_by_v3_auth_digest(commit->rsa_identity) == NULL) {
    log_warn(LD_DIR, "SR: Fingerprint %s is not from a recognized "
                     "authority. Discarding commit.",
             escaped(commit->rsa_identity));
    goto ignore;
  }

  /* Check if the authority that voted for <b>commit</b> has already posted
   * a commit before. */
  saved_commit = sr_state_get_commit(commit->rsa_identity);

  switch (phase) {
  case SR_PHASE_COMMIT:
    /* Already having a commit for an authority so ignore this one. */
    if (saved_commit) {
      /*  Receiving known commits should happen naturally since commit phase
          lasts multiple rounds. However if the commitment value changes
          during commit phase, it might be a bug so log more loudly. */
      if (!commitments_are_the_same(commit, saved_commit)) {
        log_info(LD_DIR,
                 "SR: Received altered commit from %s in commit phase.",
                 sr_commit_get_rsa_fpr(commit));
      } else {
        log_debug(LD_DIR, "SR: Ignoring known commit during commit phase.");
      }
      goto ignore;
    }

    /* A commit with a reveal value during commitment phase is very wrong. */
    if (commit_has_reveal_value(commit)) {
      log_warn(LD_DIR, "SR: Commit from authority %s has a reveal value "
                       "during COMMIT phase. (voter: %s)",
               sr_commit_get_rsa_fpr(commit),
               hex_str(voter_key, DIGEST_LEN));
      goto ignore;
    }
    break;
  case SR_PHASE_REVEAL:
    /* We are now in reveal phase. We keep a commit if and only if:
     *
     * - We have already seen a commit by this auth, AND
     * - the saved commit has the same commitment value as this one, AND
     * - the saved commit has no reveal information, AND
     * - this commit does have reveal information, AND
     * - the reveal & commit information are matching.
     *
     * If all the above are true, then we are interested in this new commit
     * for its reveal information. */

    if (!saved_commit) {
      log_debug(LD_DIR, "SR: Ignoring commit first seen in reveal phase.");
      goto ignore;
    }

    if (!commitments_are_the_same(commit, saved_commit)) {
      log_warn(LD_DIR, "SR: Commit from authority %s is different from "
                       "previous commit in our state (voter: %s)",
               sr_commit_get_rsa_fpr(commit),
               hex_str(voter_key, DIGEST_LEN));
      goto ignore;
    }

    if (commit_has_reveal_value(saved_commit)) {
      log_debug(LD_DIR, "SR: Ignoring commit with known reveal info.");
      goto ignore;
    }

    if (!commit_has_reveal_value(commit)) {
      log_debug(LD_DIR, "SR: Ignoring commit without reveal value.");
      goto ignore;
    }

    if (verify_commit_and_reveal(commit) < 0) {
      log_warn(LD_BUG, "SR: Commit from authority %s has an invalid "
                       "reveal value. (voter: %s)",
               sr_commit_get_rsa_fpr(commit),
               hex_str(voter_key, DIGEST_LEN));
      goto ignore;
    }
    break;
  default:
    tor_assert(0);
  }

  return 1;

 ignore:
  return 0;
}
Exemplo n.º 21
0
/** Called when we get data from a cpuworker.  If the answer is not complete,
 * wait for a complete answer. If the answer is complete,
 * process it as appropriate.
 */
int
connection_cpu_process_inbuf(connection_t *conn)
{
  uint64_t chan_id;
  circid_t circ_id;
  channel_t *p_chan = NULL;
  circuit_t *circ;

  tor_assert(conn);
  tor_assert(conn->type == CONN_TYPE_CPUWORKER);

  if (!connection_get_inbuf_len(conn))
    return 0;

  if (conn->state == CPUWORKER_STATE_BUSY_ONION) {
    cpuworker_reply_t rpl;
    if (connection_get_inbuf_len(conn) < sizeof(cpuworker_reply_t))
      return 0; /* not yet */
    tor_assert(connection_get_inbuf_len(conn) == sizeof(cpuworker_reply_t));

    connection_fetch_from_buf((void*)&rpl,sizeof(cpuworker_reply_t),conn);

    tor_assert(rpl.magic == CPUWORKER_REPLY_MAGIC);

    if (rpl.timed && rpl.success &&
        rpl.handshake_type <= MAX_ONION_HANDSHAKE_TYPE) {
      /* Time how long this request took. The handshake_type check should be
         needless, but let's leave it in to be safe. */
      struct timeval tv_end, tv_diff;
      int64_t usec_roundtrip;
      tor_gettimeofday(&tv_end);
      timersub(&tv_end, &rpl.started_at, &tv_diff);
      usec_roundtrip = ((int64_t)tv_diff.tv_sec)*1000000 + tv_diff.tv_usec;
      if (usec_roundtrip >= 0 &&
          usec_roundtrip < MAX_BELIEVABLE_ONIONSKIN_DELAY) {
        ++onionskins_n_processed[rpl.handshake_type];
        onionskins_usec_internal[rpl.handshake_type] += rpl.n_usec;
        onionskins_usec_roundtrip[rpl.handshake_type] += usec_roundtrip;
        if (onionskins_n_processed[rpl.handshake_type] >= 500000) {
          /* Scale down every 500000 handshakes.  On a busy server, that's
           * less impressive than it sounds. */
          onionskins_n_processed[rpl.handshake_type] /= 2;
          onionskins_usec_internal[rpl.handshake_type] /= 2;
          onionskins_usec_roundtrip[rpl.handshake_type] /= 2;
        }
      }
    }
    /* parse out the circ it was talking about */
    tag_unpack(rpl.tag, &chan_id, &circ_id);
    circ = NULL;
    log_debug(LD_OR,
              "Unpacking cpuworker reply, chan_id is " U64_FORMAT
              ", circ_id is %u",
              U64_PRINTF_ARG(chan_id), (unsigned)circ_id);
    p_chan = channel_find_by_global_id(chan_id);

    if (p_chan)
      circ = circuit_get_by_circid_channel(circ_id, p_chan);

    if (rpl.success == 0) {
      log_debug(LD_OR,
                "decoding onionskin failed. "
                "(Old key or bad software.) Closing.");
      if (circ)
        circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
      goto done_processing;
    }
    if (!circ) {
      /* This happens because somebody sends us a destroy cell and the
       * circuit goes away, while the cpuworker is working. This is also
       * why our tag doesn't include a pointer to the circ, because we'd
       * never know if it's still valid.
       */
      log_debug(LD_OR,"processed onion for a circ that's gone. Dropping.");
      goto done_processing;
    }
    tor_assert(! CIRCUIT_IS_ORIGIN(circ));
    if (onionskin_answer(TO_OR_CIRCUIT(circ),
                         &rpl.created_cell,
                         (const char*)rpl.keys,
                         rpl.rend_auth_material) < 0) {
      log_warn(LD_OR,"onionskin_answer failed. Closing.");
      circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
      goto done_processing;
    }
    log_debug(LD_OR,"onionskin_answer succeeded. Yay.");
  } else {
    tor_assert(0); /* don't ask me to do handshakes yet */
  }

 done_processing:
  conn->state = CPUWORKER_STATE_IDLE;
  num_cpuworkers_busy--;
  if (conn->timestamp_created < last_rotation_time) {
    connection_mark_for_close(conn);
    num_cpuworkers--;
    spawn_enough_cpuworkers();
  } else {
    process_pending_task(conn);
  }
  return 0;
}
Exemplo n.º 22
0
/** Helper function: called by evdns whenever the client sends a request to our
 * DNSPort.  We need to eventually answer the request <b>req</b>.
 */
static void
evdns_server_callback(struct evdns_server_request *req, void *data_)
{
  const listener_connection_t *listener = data_;
  entry_connection_t *entry_conn;
  edge_connection_t *conn;
  int i = 0;
  struct evdns_server_question *q = NULL, *supported_q = NULL;
  struct sockaddr_storage addr;
  struct sockaddr *sa;
  int addrlen;
  tor_addr_t tor_addr;
  uint16_t port;
  int err = DNS_ERR_NONE;
  char *q_name;

  tor_assert(req);

  log_info(LD_APP, "Got a new DNS request!");

  req->flags |= 0x80; /* set RA */

  /* First, check whether the requesting address matches our SOCKSPolicy. */
  if ((addrlen = evdns_server_request_get_requesting_addr(req,
                      (struct sockaddr*)&addr, (socklen_t)sizeof(addr))) < 0) {
    log_warn(LD_APP, "Couldn't get requesting address.");
    evdns_server_request_respond(req, DNS_ERR_SERVERFAILED);
    return;
  }
  (void) addrlen;
  sa = (struct sockaddr*) &addr;
  if (tor_addr_from_sockaddr(&tor_addr, sa, &port)<0) {
    log_warn(LD_APP, "Requesting address wasn't recognized.");
    evdns_server_request_respond(req, DNS_ERR_SERVERFAILED);
    return;
  }

  if (!socks_policy_permits_address(&tor_addr)) {
    log_warn(LD_APP, "Rejecting DNS request from disallowed IP.");
    evdns_server_request_respond(req, DNS_ERR_REFUSED);
    return;
  }

  /* Now, let's find the first actual question of a type we can answer in this
   * DNS request.  It makes us a little noncompliant to act like this; we
   * should fix that eventually if it turns out to make a difference for
   * anybody. */
  if (req->nquestions == 0) {
    log_info(LD_APP, "No questions in DNS request; sending back nil reply.");
    evdns_server_request_respond(req, 0);
    return;
  }
  if (req->nquestions > 1) {
    log_info(LD_APP, "Got a DNS request with more than one question; I only "
             "handle one question at a time for now.  Skipping the extras.");
  }
  for (i = 0; i < req->nquestions; ++i) {
    if (req->questions[i]->dns_question_class != EVDNS_CLASS_INET)
      continue;
    switch (req->questions[i]->type) {
      case EVDNS_TYPE_A:
      case EVDNS_TYPE_AAAA:
      case EVDNS_TYPE_PTR:
        /* We always pick the first one of these questions, if there is
           one. */
        if (! supported_q)
          supported_q = req->questions[i];
        break;
      default:
        break;
      }
  }
  if (supported_q)
    q = supported_q;
  if (!q) {
    log_info(LD_APP, "None of the questions we got were ones we're willing "
             "to support. Sending NOTIMPL.");
    evdns_server_request_respond(req, DNS_ERR_NOTIMPL);
    return;
  }

  /* Make sure the name isn't too long: This should be impossible, I think. */
  if (err == DNS_ERR_NONE && strlen(q->name) > MAX_SOCKS_ADDR_LEN-1)
    err = DNS_ERR_FORMAT;

  if (err != DNS_ERR_NONE || !supported_q) {
    /* We got an error?  There's no question we're willing to answer? Then
     * send back an answer immediately; we're done. */
    evdns_server_request_respond(req, err);
    return;
  }

  /* Make a new dummy AP connection, and attach the request to it. */
  entry_conn = entry_connection_new(CONN_TYPE_AP, AF_INET);
  conn = ENTRY_TO_EDGE_CONN(entry_conn);
  CONNECTION_AP_EXPECT_NONPENDING(entry_conn);
  TO_CONN(conn)->state = AP_CONN_STATE_RESOLVE_WAIT;
  conn->is_dns_request = 1;

  tor_addr_copy(&TO_CONN(conn)->addr, &tor_addr);
  TO_CONN(conn)->port = port;
  TO_CONN(conn)->address = tor_addr_to_str_dup(&tor_addr);

  if (q->type == EVDNS_TYPE_A || q->type == EVDNS_TYPE_AAAA ||
      q->type == EVDNS_QTYPE_ALL) {
    entry_conn->socks_request->command = SOCKS_COMMAND_RESOLVE;
  } else {
    tor_assert(q->type == EVDNS_TYPE_PTR);
    entry_conn->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR;
  }

  /* This serves our DNS port so enable DNS request by default. */
  entry_conn->entry_cfg.dns_request = 1;
  if (q->type == EVDNS_TYPE_A || q->type == EVDNS_QTYPE_ALL) {
    entry_conn->entry_cfg.ipv4_traffic = 1;
    entry_conn->entry_cfg.ipv6_traffic = 0;
    entry_conn->entry_cfg.prefer_ipv6 = 0;
  } else if (q->type == EVDNS_TYPE_AAAA) {
    entry_conn->entry_cfg.ipv4_traffic = 0;
    entry_conn->entry_cfg.ipv6_traffic = 1;
    entry_conn->entry_cfg.prefer_ipv6 = 1;
  }

  strlcpy(entry_conn->socks_request->address, q->name,
          sizeof(entry_conn->socks_request->address));

  entry_conn->socks_request->listener_type = listener->base_.type;
  entry_conn->dns_server_request = req;
  entry_conn->entry_cfg.isolation_flags = listener->entry_cfg.isolation_flags;
  entry_conn->entry_cfg.session_group = listener->entry_cfg.session_group;
  entry_conn->nym_epoch = get_signewnym_epoch();

  if (connection_add(ENTRY_TO_CONN(entry_conn)) < 0) {
    log_warn(LD_APP, "Couldn't register dummy connection for DNS request");
    evdns_server_request_respond(req, DNS_ERR_SERVERFAILED);
    connection_free(ENTRY_TO_CONN(entry_conn));
    return;
  }

  control_event_stream_status(entry_conn, STREAM_EVENT_NEW_RESOLVE, 0);

  /* Now, unless a controller asked us to leave streams unattached,
  * throw the connection over to get rewritten (which will
  * answer it immediately if it's in the cache, or completely bogus, or
  * automapped), and then attached to a circuit. */
  log_info(LD_APP, "Passing request for %s to rewrite_and_attach.",
           escaped_safe_str_client(q->name));
  q_name = tor_strdup(q->name); /* q could be freed in rewrite_and_attach */
  connection_ap_rewrite_and_attach_if_allowed(entry_conn, NULL, NULL);
  /* Now, the connection is marked if it was bad. */

  log_info(LD_APP, "Passed request for %s to rewrite_and_attach_if_allowed.",
           escaped_safe_str_client(q_name));
  tor_free(q_name);
}
Exemplo n.º 23
0
/** Try to tell a cpuworker to perform the public key operations necessary to
 * respond to <b>onionskin</b> for the circuit <b>circ</b>.
 *
 * If <b>cpuworker</b> is defined, assert that he's idle, and use him. Else,
 * look for an idle cpuworker and use him. If none idle, queue task onto the
 * pending onion list and return.  Return 0 if we successfully assign the
 * task, or -1 on failure.
 */
int
assign_onionskin_to_cpuworker(connection_t *cpuworker,
                              or_circuit_t *circ,
                              create_cell_t *onionskin)
{
  cpuworker_request_t req;
  time_t now = approx_time();
  static time_t last_culled_cpuworkers = 0;
  int should_time;

  /* Checking for wedged cpuworkers requires a linear search over all
   * connections, so let's do it only once a minute.
   */
#define CULL_CPUWORKERS_INTERVAL 60

  if (last_culled_cpuworkers + CULL_CPUWORKERS_INTERVAL <= now) {
    cull_wedged_cpuworkers();
    spawn_enough_cpuworkers();
    last_culled_cpuworkers = now;
  }

  if (1) {
    if (num_cpuworkers_busy == num_cpuworkers) {
      log_debug(LD_OR,"No idle cpuworkers. Queuing.");
      if (onion_pending_add(circ, onionskin) < 0) {
        tor_free(onionskin);
        return -1;
      }
      return 0;
    }

    if (!cpuworker)
      cpuworker = connection_get_by_type_state(CONN_TYPE_CPUWORKER,
                                               CPUWORKER_STATE_IDLE);

    tor_assert(cpuworker);

    if (!circ->p_chan) {
      log_info(LD_OR,"circ->p_chan gone. Failing circ.");
      tor_free(onionskin);
      return -1;
    }

    if (connection_or_digest_is_known_relay(circ->p_chan->identity_digest))
      rep_hist_note_circuit_handshake_assigned(onionskin->handshake_type);

    should_time = should_time_request(onionskin->handshake_type);
    memset(&req, 0, sizeof(req));
    req.magic = CPUWORKER_REQUEST_MAGIC;
    tag_pack(req.tag, circ->p_chan->global_identifier,
             circ->p_circ_id);
    req.timed = should_time;

    cpuworker->state = CPUWORKER_STATE_BUSY_ONION;
    /* touch the lastwritten timestamp, since that's how we check to
     * see how long it's been since we asked the question, and sometimes
     * we check before the first call to connection_handle_write(). */
    cpuworker->timestamp_lastwritten = now;
    num_cpuworkers_busy++;

    req.task = CPUWORKER_TASK_ONION;
    memcpy(&req.create_cell, onionskin, sizeof(create_cell_t));

    tor_free(onionskin);

    if (should_time)
      tor_gettimeofday(&req.started_at);

    connection_write_to_buf((void*)&req, sizeof(req), cpuworker);
    memwipe(&req, 0, sizeof(req));
  }
  return 0;
}
Exemplo n.º 24
0
/** <b>c</b>-\>key is known to be a real key. Update <b>options</b>
 * with <b>c</b>-\>value and return 0, or return -1 if bad value.
 *
 * Called from config_assign_line() and option_reset().
 */
static int
config_assign_value(const config_format_t *fmt, void *options,
                    config_line_t *c, char **msg)
{
  int i, ok;
  const config_var_t *var;
  void *lvalue;
  int *csv_int;
  smartlist_t *csv_str;

  CONFIG_CHECK(fmt, options);

  var = config_find_option(fmt, c->key);
  tor_assert(var);

  lvalue = STRUCT_VAR_P(options, var->var_offset);

  switch (var->type) {

  case CONFIG_TYPE_PORT:
    if (!strcasecmp(c->value, "auto")) {
      *(int *)lvalue = CFG_AUTO_PORT;
      break;
    }
    /* fall through */
  case CONFIG_TYPE_INT:
  case CONFIG_TYPE_UINT:
    i = (int)tor_parse_long(c->value, 10,
                            var->type==CONFIG_TYPE_INT ? INT_MIN : 0,
                            var->type==CONFIG_TYPE_PORT ? 65535 : INT_MAX,
                            &ok, NULL);
    if (!ok) {
      tor_asprintf(msg,
          "Int keyword '%s %s' is malformed or out of bounds.",
          c->key, c->value);
      return -1;
    }
    *(int *)lvalue = i;
    break;

  case CONFIG_TYPE_INTERVAL: {
    i = config_parse_interval(c->value, &ok);
    if (!ok) {
      tor_asprintf(msg,
          "Interval '%s %s' is malformed or out of bounds.",
          c->key, c->value);
      return -1;
    }
    *(int *)lvalue = i;
    break;
  }

  case CONFIG_TYPE_MSEC_INTERVAL: {
    i = config_parse_msec_interval(c->value, &ok);
    if (!ok) {
      tor_asprintf(msg,
          "Msec interval '%s %s' is malformed or out of bounds.",
          c->key, c->value);
      return -1;
    }
    *(int *)lvalue = i;
    break;
  }

  case CONFIG_TYPE_MEMUNIT: {
    uint64_t u64 = config_parse_memunit(c->value, &ok);
    if (!ok) {
      tor_asprintf(msg,
          "Value '%s %s' is malformed or out of bounds.",
          c->key, c->value);
      return -1;
    }
    *(uint64_t *)lvalue = u64;
    break;
  }

  case CONFIG_TYPE_BOOL:
    i = (int)tor_parse_long(c->value, 10, 0, 1, &ok, NULL);
    if (!ok) {
      tor_asprintf(msg,
          "Boolean '%s %s' expects 0 or 1.",
          c->key, c->value);
      return -1;
    }
    *(int *)lvalue = i;
    break;

  case CONFIG_TYPE_AUTOBOOL:
    if (!strcmp(c->value, "auto"))
      *(int *)lvalue = -1;
    else if (!strcmp(c->value, "0"))
      *(int *)lvalue = 0;
    else if (!strcmp(c->value, "1"))
      *(int *)lvalue = 1;
    else {
      tor_asprintf(msg, "Boolean '%s %s' expects 0, 1, or 'auto'.",
                   c->key, c->value);
      return -1;
    }
    break;

  case CONFIG_TYPE_STRING:
  case CONFIG_TYPE_FILENAME:
    tor_free(*(char **)lvalue);
    *(char **)lvalue = tor_strdup(c->value);
    break;

  case CONFIG_TYPE_DOUBLE:
    *(double *)lvalue = atof(c->value);
    break;

  case CONFIG_TYPE_ISOTIME:
    if (parse_iso_time(c->value, (time_t *)lvalue)) {
      tor_asprintf(msg,
          "Invalid time '%s' for keyword '%s'", c->value, c->key);
      return -1;
    }
    break;

  case CONFIG_TYPE_ROUTERSET:
    if (*(routerset_t**)lvalue) {
      routerset_free(*(routerset_t**)lvalue);
    }
    *(routerset_t**)lvalue = routerset_new();
    if (routerset_parse(*(routerset_t**)lvalue, c->value, c->key)<0) {
      tor_asprintf(msg, "Invalid exit list '%s' for option '%s'",
                   c->value, c->key);
      return -1;
    }
    break;

  case CONFIG_TYPE_CSV:
    if (*(smartlist_t**)lvalue) {
      SMARTLIST_FOREACH(*(smartlist_t**)lvalue, char *, cp, tor_free(cp));
      smartlist_clear(*(smartlist_t**)lvalue);
    } else {
Exemplo n.º 25
0
Arquivo: procmon.c Projeto: 4ZM/Tor
/** Libevent callback to poll for the existence of the process
 * monitored by <b>procmon_</b>. */
static void
tor_process_monitor_poll_cb(evutil_socket_t unused1, short unused2,
                            void *procmon_)
{
  tor_process_monitor_t *procmon = (tor_process_monitor_t *)(procmon_);
  int its_dead_jim;

  (void)unused1; (void)unused2;

  tor_assert(procmon != NULL);

#ifdef MS_WINDOWS
  if (procmon->poll_hproc) {
    DWORD exit_code;
    if (!GetExitCodeProcess(procmon->hproc, &exit_code)) {
      char *errmsg = format_win32_error(GetLastError());
      log_warn(procmon->log_domain, "Error \"%s\" occurred while polling "
               "handle for monitored process %d; assuming it's dead.",
               errmsg, procmon->pid);
      tor_free(errmsg);
      its_dead_jim = 1;
    } else {
      its_dead_jim = (exit_code != STILL_ACTIVE);
    }
  } else {
    /* All we can do is try to open the process, and look at the error
     * code if it fails again. */
    procmon->hproc = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
                                 FALSE,
                                 procmon->pid);

    if (procmon->hproc != NULL) {
      log_info(procmon->log_domain, "Successfully opened handle to monitored "
               "process %d.",
               procmon->pid);
      its_dead_jim = 0;
      procmon->poll_hproc = 1;
    } else {
      DWORD err_code = GetLastError();
      char *errmsg = format_win32_error(err_code);

      /* When I tested OpenProcess's error codes on Windows 7, I
       * received error code 5 (ERROR_ACCESS_DENIED) for PIDs of
       * existing processes that I could not open and error code 87
       * (ERROR_INVALID_PARAMETER) for PIDs that were not in use.
       * Since the nonexistent-process error code is sane, I'm going
       * to assume that all errors other than ERROR_INVALID_PARAMETER
       * mean that the process we are monitoring is still alive. */
      its_dead_jim = (err_code == ERROR_INVALID_PARAMETER);

      if (!its_dead_jim)
        log_info(procmon->log_domain, "Failed to open handle to monitored "
                 "process %d, and error code %lu (%s) is not 'invalid "
                 "parameter' -- assuming the process is still alive.",
                 procmon->pid,
                 err_code, errmsg);

      tor_free(errmsg);
    }
  }
#else
  /* Unix makes this part easy, if a bit racy. */
  its_dead_jim = kill(procmon->pid, 0);
  its_dead_jim = its_dead_jim && (errno == ESRCH);
#endif

  log(its_dead_jim ? LOG_NOTICE : LOG_INFO,
      procmon->log_domain, "Monitored process %d is %s.",
      (int)procmon->pid,
      its_dead_jim ? "dead" : "still alive");

  if (its_dead_jim) {
    procmon->cb(procmon->cb_arg);
#ifndef HAVE_EVENT2_EVENT_H
  } else {
    evtimer_add(procmon->e, &poll_interval_tv);
#endif
  }
}
Exemplo n.º 26
0
/** Configure accounting start/end time settings based on
 * options->AccountingStart.  Return 0 on success, -1 on failure. If
 * <b>validate_only</b> is true, do not change the current settings. */
int
accounting_parse_options(const or_options_t *options, int validate_only)
{
  time_unit_t unit;
  int ok, idx;
  long d,h,m;
  smartlist_t *items;
  const char *v = options->AccountingStart;
  const char *s;
  char *cp;

  if (!v) {
    if (!validate_only) {
      cfg_unit = UNIT_MONTH;
      cfg_start_day = 1;
      cfg_start_hour = 0;
      cfg_start_min = 0;
    }
    return 0;
  }

  items = smartlist_new();
  smartlist_split_string(items, v, NULL,
                         SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK,0);
  if (smartlist_len(items)<2) {
    log_warn(LD_CONFIG, "Too few arguments to AccountingStart");
    goto err;
  }
  s = smartlist_get(items,0);
  if (0==strcasecmp(s, "month")) {
    unit = UNIT_MONTH;
  } else if (0==strcasecmp(s, "week")) {
    unit = UNIT_WEEK;
  } else if (0==strcasecmp(s, "day")) {
    unit = UNIT_DAY;
  } else {
    log_warn(LD_CONFIG,
             "Unrecognized accounting unit '%s': only 'month', 'week',"
             " and 'day' are supported.", s);
    goto err;
  }

  switch (unit) {
  case UNIT_WEEK:
    d = tor_parse_long(smartlist_get(items,1), 10, 1, 7, &ok, NULL);
    if (!ok) {
      log_warn(LD_CONFIG, "Weekly accounting must begin on a day between "
               "1 (Monday) and 7 (Sunday)");
      goto err;
    }
    break;
  case UNIT_MONTH:
    d = tor_parse_long(smartlist_get(items,1), 10, 1, 28, &ok, NULL);
    if (!ok) {
      log_warn(LD_CONFIG, "Monthly accounting must begin on a day between "
               "1 and 28");
      goto err;
    }
    break;
  case UNIT_DAY:
    d = 0;
    break;
    /* Coverity dislikes unreachable default cases; some compilers warn on
     * switch statements missing a case.  Tell Coverity not to worry. */
    /* coverity[dead_error_begin] */
  default:
    tor_assert(0);
  }

  idx = unit==UNIT_DAY?1:2;
  if (smartlist_len(items) != (idx+1)) {
    log_warn(LD_CONFIG,"Accounting unit '%s' requires %d argument%s.",
             s, idx, (idx>1)?"s":"");
    goto err;
  }
  s = smartlist_get(items, idx);
  h = tor_parse_long(s, 10, 0, 23, &ok, &cp);
  if (!ok) {
    log_warn(LD_CONFIG,"Accounting start time not parseable: bad hour.");
    goto err;
  }
  if (!cp || *cp!=':') {
    log_warn(LD_CONFIG,
             "Accounting start time not parseable: not in HH:MM format");
    goto err;
  }
  m = tor_parse_long(cp+1, 10, 0, 59, &ok, &cp);
  if (!ok) {
    log_warn(LD_CONFIG, "Accounting start time not parseable: bad minute");
    goto err;
  }
  if (!cp || *cp!='\0') {
    log_warn(LD_CONFIG,
             "Accounting start time not parseable: not in HH:MM format");
    goto err;
  }

  if (!validate_only) {
    cfg_unit = unit;
    cfg_start_day = (int)d;
    cfg_start_hour = (int)h;
    cfg_start_min = (int)m;
  }
  SMARTLIST_FOREACH(items, char *, item, tor_free(item));
  smartlist_free(items);
  return 0;
 err:
  SMARTLIST_FOREACH(items, char *, item, tor_free(item));
  smartlist_free(items);
  return -1;
}
Exemplo n.º 27
0
/** Process a 'create' <b>cell</b> that just arrived from <b>conn</b>. Make a
 * new circuit with the p_circ_id specified in cell. Put the circuit in state
 * onionskin_pending, and pass the onionskin to the cpuworker. Circ will get
 * picked up again when the cpuworker finishes decrypting it.
 */
static void
command_process_create_cell(cell_t *cell, or_connection_t *conn)
{
  or_circuit_t *circ;
  const or_options_t *options = get_options();
  int id_is_high;

  if (we_are_hibernating()) {
    log_info(LD_OR,
             "Received create cell but we're shutting down. Sending back "
             "destroy.");
    connection_or_send_destroy(cell->circ_id, conn,
                               END_CIRC_REASON_HIBERNATING);
    return;
  }

  if (!server_mode(options) ||
      (!public_server_mode(options) && conn->is_outgoing)) {
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
           "Received create cell (type %d) from %s:%d, but we're connected "
           "to it as a client. "
           "Sending back a destroy.",
           (int)cell->command, conn->_base.address, conn->_base.port);
    connection_or_send_destroy(cell->circ_id, conn,
                               END_CIRC_REASON_TORPROTOCOL);
    return;
  }

  /* If the high bit of the circuit ID is not as expected, close the
   * circ. */
  id_is_high = cell->circ_id & (1<<15);
  if ((id_is_high && conn->circ_id_type == CIRC_ID_TYPE_HIGHER) ||
      (!id_is_high && conn->circ_id_type == CIRC_ID_TYPE_LOWER)) {
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
           "Received create cell with unexpected circ_id %d. Closing.",
           cell->circ_id);
    connection_or_send_destroy(cell->circ_id, conn,
                               END_CIRC_REASON_TORPROTOCOL);
    return;
  }

  if (circuit_id_in_use_on_orconn(cell->circ_id, conn)) {
    const node_t *node = node_get_by_id(conn->identity_digest);
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
           "Received CREATE cell (circID %d) for known circ. "
           "Dropping (age %d).",
           cell->circ_id, (int)(time(NULL) - conn->_base.timestamp_created));
    if (node) {
      char *p = esc_for_log(node_get_platform(node));
      log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
             "Details: router %s, platform %s.",
             node_describe(node), p);
      tor_free(p);
    }
    return;
  }

  circ = or_circuit_new(cell->circ_id, conn);
  circ->_base.purpose = CIRCUIT_PURPOSE_OR;
  circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_ONIONSKIN_PENDING);
  if (cell->command == CELL_CREATE) {
    char *onionskin = tor_malloc(ONIONSKIN_CHALLENGE_LEN);
    memcpy(onionskin, cell->payload, ONIONSKIN_CHALLENGE_LEN);

    /* hand it off to the cpuworkers, and then return. */
    if (assign_onionskin_to_cpuworker(NULL, circ, onionskin) < 0) {
#define WARN_HANDOFF_FAILURE_INTERVAL (6*60*60)
      static ratelim_t handoff_warning =
        RATELIM_INIT(WARN_HANDOFF_FAILURE_INTERVAL);
      char *m;
      if ((m = rate_limit_log(&handoff_warning, approx_time()))) {
        log_warn(LD_GENERAL,"Failed to hand off onionskin. Closing.%s",m);
        tor_free(m);
      }
      circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
      return;
    }
    log_debug(LD_OR,"success: handed off onionskin.");
  } else {
    /* This is a CREATE_FAST cell; we can handle it immediately without using
     * a CPU worker. */
    char keys[CPATH_KEY_MATERIAL_LEN];
    char reply[DIGEST_LEN*2];

    tor_assert(cell->command == CELL_CREATE_FAST);

    /* Make sure we never try to use the OR connection on which we
     * received this cell to satisfy an EXTEND request,  */
    conn->is_connection_with_client = 1;

    if (fast_server_handshake(cell->payload, (uint8_t*)reply,
                              (uint8_t*)keys, sizeof(keys))<0) {
      log_warn(LD_OR,"Failed to generate key material. Closing.");
      circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
      return;
    }
    if (onionskin_answer(circ, CELL_CREATED_FAST, reply, keys)<0) {
      log_warn(LD_OR,"Failed to reply to CREATE_FAST cell. Closing.");
      circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
      return;
    }
  }
}
Exemplo n.º 28
0
/** Called when we get an AUTHCHALLENGE command. */
int
handle_control_authchallenge(control_connection_t *conn, uint32_t len,
                             const char *body)
{
  const char *cp = body;
  char *client_nonce;
  size_t client_nonce_len;
  char server_hash[DIGEST256_LEN];
  char server_hash_encoded[HEX_DIGEST256_LEN+1];
  char server_nonce[SAFECOOKIE_SERVER_NONCE_LEN];
  char server_nonce_encoded[(2*SAFECOOKIE_SERVER_NONCE_LEN) + 1];

  cp += strspn(cp, " \t\n\r");
  if (!strcasecmpstart(cp, "SAFECOOKIE")) {
    cp += strlen("SAFECOOKIE");
  } else {
    connection_write_str_to_buf("513 AUTHCHALLENGE only supports SAFECOOKIE "
                                "authentication\r\n", conn);
    connection_mark_for_close(TO_CONN(conn));
    return -1;
  }

  if (!authentication_cookie_is_set) {
    connection_write_str_to_buf("515 Cookie authentication is disabled\r\n",
                                conn);
    connection_mark_for_close(TO_CONN(conn));
    return -1;
  }

  cp += strspn(cp, " \t\n\r");
  if (*cp == '"') {
    const char *newcp =
      decode_escaped_string(cp, len - (cp - body),
                            &client_nonce, &client_nonce_len);
    if (newcp == NULL) {
      connection_write_str_to_buf("513 Invalid quoted client nonce\r\n",
                                  conn);
      connection_mark_for_close(TO_CONN(conn));
      return -1;
    }
    cp = newcp;
  } else {
    size_t client_nonce_encoded_len = strspn(cp, "0123456789ABCDEFabcdef");

    client_nonce_len = client_nonce_encoded_len / 2;
    client_nonce = tor_malloc_zero(client_nonce_len);

    if (base16_decode(client_nonce, client_nonce_len,
                      cp, client_nonce_encoded_len)
                      != (int) client_nonce_len) {
      connection_write_str_to_buf("513 Invalid base16 client nonce\r\n",
                                  conn);
      connection_mark_for_close(TO_CONN(conn));
      tor_free(client_nonce);
      return -1;
    }

    cp += client_nonce_encoded_len;
  }

  cp += strspn(cp, " \t\n\r");
  if (*cp != '\0' ||
      cp != body + len) {
    connection_write_str_to_buf("513 Junk at end of AUTHCHALLENGE command\r\n",
                                conn);
    connection_mark_for_close(TO_CONN(conn));
    tor_free(client_nonce);
    return -1;
  }
  crypto_rand(server_nonce, SAFECOOKIE_SERVER_NONCE_LEN);

  /* Now compute and send the server-to-controller response, and the
   * server's nonce. */
  tor_assert(authentication_cookie != NULL);

  {
    size_t tmp_len = (AUTHENTICATION_COOKIE_LEN +
                      client_nonce_len +
                      SAFECOOKIE_SERVER_NONCE_LEN);
    char *tmp = tor_malloc_zero(tmp_len);
    char *client_hash = tor_malloc_zero(DIGEST256_LEN);
    memcpy(tmp, authentication_cookie, AUTHENTICATION_COOKIE_LEN);
    memcpy(tmp + AUTHENTICATION_COOKIE_LEN, client_nonce, client_nonce_len);
    memcpy(tmp + AUTHENTICATION_COOKIE_LEN + client_nonce_len,
           server_nonce, SAFECOOKIE_SERVER_NONCE_LEN);

    crypto_hmac_sha256(server_hash,
                       SAFECOOKIE_SERVER_TO_CONTROLLER_CONSTANT,
                       strlen(SAFECOOKIE_SERVER_TO_CONTROLLER_CONSTANT),
                       tmp,
                       tmp_len);

    crypto_hmac_sha256(client_hash,
                       SAFECOOKIE_CONTROLLER_TO_SERVER_CONSTANT,
                       strlen(SAFECOOKIE_CONTROLLER_TO_SERVER_CONSTANT),
                       tmp,
                       tmp_len);

    conn->safecookie_client_hash = client_hash;

    tor_free(tmp);
  }

  base16_encode(server_hash_encoded, sizeof(server_hash_encoded),
                server_hash, sizeof(server_hash));
  base16_encode(server_nonce_encoded, sizeof(server_nonce_encoded),
                server_nonce, sizeof(server_nonce));

  connection_printf_to_buf(conn,
                           "250 AUTHCHALLENGE SERVERHASH=%s "
                           "SERVERNONCE=%s\r\n",
                           server_hash_encoded,
                           server_nonce_encoded);

  tor_free(client_nonce);
  return 0;
}
Exemplo n.º 29
0
/** Process a 'netinfo' cell: read and act on its contents, and set the
 * connection state to "open". */
static void
command_process_netinfo_cell(cell_t *cell, or_connection_t *conn)
{
  time_t timestamp;
  uint8_t my_addr_type;
  uint8_t my_addr_len;
  const uint8_t *my_addr_ptr;
  const uint8_t *cp, *end;
  uint8_t n_other_addrs;
  time_t now = time(NULL);

  long apparent_skew = 0;
  uint32_t my_apparent_addr = 0;

  if (conn->link_proto < 2) {
    log_fn(LOG_PROTOCOL_WARN, LD_OR,
           "Received a NETINFO cell on %s connection; dropping.",
           conn->link_proto == 0 ? "non-versioned" : "a v1");
    return;
  }
  if (conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING_V2 &&
      conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING_V3) {
    log_fn(LOG_PROTOCOL_WARN, LD_OR,
           "Received a NETINFO cell on non-handshaking connection; dropping.");
    return;
  }
  tor_assert(conn->handshake_state &&
             conn->handshake_state->received_versions);

  if (conn->_base.state == OR_CONN_STATE_OR_HANDSHAKING_V3) {
    tor_assert(conn->link_proto >= 3);
    if (conn->handshake_state->started_here) {
      if (!conn->handshake_state->authenticated) {
        log_fn(LOG_PROTOCOL_WARN, LD_OR, "Got a NETINFO cell from server, "
               "but no authentication.  Closing the connection.");
        connection_mark_for_close(TO_CONN(conn));
        return;
      }
    } else {
      /* we're the server.  If the client never authenticated, we have
         some housekeeping to do.*/
      if (!conn->handshake_state->authenticated) {
        tor_assert(tor_digest_is_zero(
                  (const char*)conn->handshake_state->authenticated_peer_id));
        connection_or_set_circid_type(conn, NULL);

        connection_or_init_conn_from_address(conn,
                  &conn->_base.addr,
                  conn->_base.port,
                  (const char*)conn->handshake_state->authenticated_peer_id,
                  0);
      }
    }
  }

  /* Decode the cell. */
  timestamp = ntohl(get_uint32(cell->payload));
  if (labs(now - conn->handshake_state->sent_versions_at) < 180) {
    apparent_skew = now - timestamp;
  }

  my_addr_type = (uint8_t) cell->payload[4];
  my_addr_len = (uint8_t) cell->payload[5];
  my_addr_ptr = (uint8_t*) cell->payload + 6;
  end = cell->payload + CELL_PAYLOAD_SIZE;
  cp = cell->payload + 6 + my_addr_len;
  if (cp >= end) {
    log_fn(LOG_PROTOCOL_WARN, LD_OR,
           "Addresses too long in netinfo cell; closing connection.");
    connection_mark_for_close(TO_CONN(conn));
    return;
  } else if (my_addr_type == RESOLVED_TYPE_IPV4 && my_addr_len == 4) {
    my_apparent_addr = ntohl(get_uint32(my_addr_ptr));
  }

  n_other_addrs = (uint8_t) *cp++;
  while (n_other_addrs && cp < end-2) {
    /* Consider all the other addresses; if any matches, this connection is
     * "canonical." */
    tor_addr_t addr;
    const uint8_t *next =
      decode_address_from_payload(&addr, cp, (int)(end-cp));
    if (next == NULL) {
      log_fn(LOG_PROTOCOL_WARN,  LD_OR,
             "Bad address in netinfo cell; closing connection.");
      connection_mark_for_close(TO_CONN(conn));
      return;
    }
    if (tor_addr_eq(&addr, &conn->real_addr)) {
      conn->is_canonical = 1;
      break;
    }
    cp = next;
    --n_other_addrs;
  }

  /* Act on apparent skew. */
  /** Warn when we get a netinfo skew with at least this value. */
#define NETINFO_NOTICE_SKEW 3600
  if (labs(apparent_skew) > NETINFO_NOTICE_SKEW &&
      router_get_by_id_digest(conn->identity_digest)) {
    char dbuf[64];
    int severity;
    /*XXXX be smarter about when everybody says we are skewed. */
    if (router_digest_is_trusted_dir(conn->identity_digest))
      severity = LOG_WARN;
    else
      severity = LOG_INFO;
    format_time_interval(dbuf, sizeof(dbuf), apparent_skew);
    log_fn(severity, LD_GENERAL, "Received NETINFO cell with skewed time from "
           "server at %s:%d.  It seems that our clock is %s by %s, or "
           "that theirs is %s. Tor requires an accurate clock to work: "
           "please check your time and date settings.",
           conn->_base.address, (int)conn->_base.port,
           apparent_skew>0 ? "ahead" : "behind", dbuf,
           apparent_skew>0 ? "behind" : "ahead");
    if (severity == LOG_WARN) /* only tell the controller if an authority */
      control_event_general_status(LOG_WARN,
                          "CLOCK_SKEW SKEW=%ld SOURCE=OR:%s:%d",
                          apparent_skew,
                          conn->_base.address, conn->_base.port);
  }

  /* XXX maybe act on my_apparent_addr, if the source is sufficiently
   * trustworthy. */
  (void)my_apparent_addr;

  if (connection_or_set_state_open(conn)<0) {
    log_fn(LOG_PROTOCOL_WARN, LD_OR, "Got good NETINFO cell from %s:%d; but "
           "was unable to make the OR connection become open.",
           safe_str_client(conn->_base.address),
           conn->_base.port);
    connection_mark_for_close(TO_CONN(conn));
  } else {
    log_info(LD_OR, "Got good NETINFO cell from %s:%d; OR connection is now "
             "open, using protocol version %d. Its ID digest is %s",
             safe_str_client(conn->_base.address),
             conn->_base.port, (int)conn->link_proto,
             hex_str(conn->identity_digest, DIGEST_LEN));
  }
  assert_connection_ok(TO_CONN(conn),time(NULL));
}
Exemplo n.º 30
0
/** Called when we get an AUTHENTICATE message.  Check whether the
 * authentication is valid, and if so, update the connection's state to
 * OPEN.  Reply with DONE or ERROR.
 */
int
handle_control_authenticate(control_connection_t *conn, uint32_t len,
                            const char *body)
{
  int used_quoted_string = 0;
  const or_options_t *options = get_options();
  const char *errstr = "Unknown error";
  char *password;
  size_t password_len;
  const char *cp;
  int i;
  int bad_cookie=0, bad_password=0;
  smartlist_t *sl = NULL;

  if (!len) {
    password = tor_strdup("");
    password_len = 0;
  } else if (TOR_ISXDIGIT(body[0])) {
    cp = body;
    while (TOR_ISXDIGIT(*cp))
      ++cp;
    i = (int)(cp - body);
    tor_assert(i>0);
    password_len = i/2;
    password = tor_malloc(password_len + 1);
    if (base16_decode(password, password_len+1, body, i)
                      != (int) password_len) {
      connection_write_str_to_buf(
            "551 Invalid hexadecimal encoding.  Maybe you tried a plain text "
            "password?  If so, the standard requires that you put it in "
            "double quotes.\r\n", conn);
      connection_mark_for_close(TO_CONN(conn));
      tor_free(password);
      return 0;
    }
  } else {
    if (!decode_escaped_string(body, len, &password, &password_len)) {
      connection_write_str_to_buf("551 Invalid quoted string.  You need "
            "to put the password in double quotes.\r\n", conn);
      connection_mark_for_close(TO_CONN(conn));
      return 0;
    }
    used_quoted_string = 1;
  }

  if (conn->safecookie_client_hash != NULL) {
    /* The controller has chosen safe cookie authentication; the only
     * acceptable authentication value is the controller-to-server
     * response. */

    tor_assert(authentication_cookie_is_set);

    if (password_len != DIGEST256_LEN) {
      log_warn(LD_CONTROL,
               "Got safe cookie authentication response with wrong length "
               "(%d)", (int)password_len);
      errstr = "Wrong length for safe cookie response.";
      goto err;
    }

    if (tor_memneq(conn->safecookie_client_hash, password, DIGEST256_LEN)) {
      log_warn(LD_CONTROL,
               "Got incorrect safe cookie authentication response");
      errstr = "Safe cookie response did not match expected value.";
      goto err;
    }

    tor_free(conn->safecookie_client_hash);
    goto ok;
  }

  if (!options->CookieAuthentication && !options->HashedControlPassword &&
      !options->HashedControlSessionPassword) {
    /* if Tor doesn't demand any stronger authentication, then
     * the controller can get in with anything. */
    goto ok;
  }

  if (options->CookieAuthentication) {
    int also_password = options->HashedControlPassword != NULL ||
      options->HashedControlSessionPassword != NULL;
    if (password_len != AUTHENTICATION_COOKIE_LEN) {
      if (!also_password) {
        log_warn(LD_CONTROL, "Got authentication cookie with wrong length "
                 "(%d)", (int)password_len);
        errstr = "Wrong length on authentication cookie.";
        goto err;
      }
      bad_cookie = 1;
    } else if (tor_memneq(authentication_cookie, password, password_len)) {
      if (!also_password) {
        log_warn(LD_CONTROL, "Got mismatched authentication cookie");
        errstr = "Authentication cookie did not match expected value.";
        goto err;
      }
      bad_cookie = 1;
    } else {
      goto ok;
    }
  }

  if (options->HashedControlPassword ||
      options->HashedControlSessionPassword) {
    int bad = 0;
    smartlist_t *sl_tmp;
    char received[DIGEST_LEN];
    int also_cookie = options->CookieAuthentication;
    sl = smartlist_new();
    if (options->HashedControlPassword) {
      sl_tmp = decode_hashed_passwords(options->HashedControlPassword);
      if (!sl_tmp)
        bad = 1;
      else {
        smartlist_add_all(sl, sl_tmp);
        smartlist_free(sl_tmp);
      }
    }
    if (options->HashedControlSessionPassword) {
      sl_tmp = decode_hashed_passwords(options->HashedControlSessionPassword);
      if (!sl_tmp)
        bad = 1;
      else {
        smartlist_add_all(sl, sl_tmp);
        smartlist_free(sl_tmp);
      }
    }
    if (bad) {
      if (!also_cookie) {
        log_warn(LD_BUG,
                 "Couldn't decode HashedControlPassword: invalid base16");
        errstr="Couldn't decode HashedControlPassword value in configuration.";
        goto err;
      }
      bad_password = 1;
      SMARTLIST_FOREACH(sl, char *, str, tor_free(str));
      smartlist_free(sl);
      sl = NULL;
    } else {
      SMARTLIST_FOREACH(sl, char *, expected,
      {
        secret_to_key_rfc2440(received,DIGEST_LEN,
                              password,password_len,expected);
        if (tor_memeq(expected + S2K_RFC2440_SPECIFIER_LEN,
                      received, DIGEST_LEN))
          goto ok;
      });