diff --git a/src/or/config.c b/src/or/config.c index afdee3d3d4..6dad0194e7 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -1474,8 +1474,14 @@ options_act(const or_options_t *old_options) return -1; } - if (init_cookie_authentication(options->CookieAuthentication) < 0) { - log_warn(LD_CONFIG,"Error creating cookie authentication file."); + if (init_control_auth_cookie_authentication(options->CookieAuthentication) < 0) { + log_warn(LD_CONFIG,"Error creating control cookie authentication file."); + return -1; + } + + /* If we have an ExtORPort, initialize its auth cookie. */ + if (init_ext_or_auth_cookie_authentication(!!options->ExtORPort_lines) < 0) { + log_warn(LD_CONFIG,"Error creating Extended ORPort cookie file."); return -1; } diff --git a/src/or/connection.c b/src/or/connection.c index 130b1ecefb..ad8e39c9a1 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -592,8 +592,10 @@ connection_free_(connection_t *conn) log_warn(LD_BUG, "called on OR conn with non-zeroed identity_digest"); connection_or_remove_from_identity_map(TO_OR_CONN(conn)); } - if (conn->type == CONN_TYPE_OR || conn->type == CONN_TYPE_EXT_OR) + if (conn->type == CONN_TYPE_OR || conn->type == CONN_TYPE_EXT_OR) { connection_or_remove_from_ext_or_id_map(TO_OR_CONN(conn)); + tor_free(TO_OR_CONN(conn)->ext_or_conn_id); + } #ifdef USE_BUFFEREVENTS if (conn->type == CONN_TYPE_OR && TO_OR_CONN(conn)->bucket_cfg) { @@ -4343,6 +4345,7 @@ assert_connection_ok(connection_t *conn, time_t now) switch (conn->type) { case CONN_TYPE_OR: + case CONN_TYPE_EXT_OR: tor_assert(conn->magic == OR_CONNECTION_MAGIC); break; case CONN_TYPE_AP: @@ -4447,6 +4450,9 @@ assert_connection_ok(connection_t *conn, time_t now) case CONN_TYPE_OR: tor_assert(conn->state >= OR_CONN_STATE_MIN_); tor_assert(conn->state <= OR_CONN_STATE_MAX_); + case CONN_TYPE_EXT_OR: + tor_assert(conn->state >= EXT_OR_CONN_STATE_MIN_); + tor_assert(conn->state <= EXT_OR_CONN_STATE_MAX_); break; case CONN_TYPE_EXIT: tor_assert(conn->state >= EXIT_CONN_STATE_MIN_); @@ -4580,6 +4586,7 @@ connection_free_all(void) /* Unlink everything from the identity map. */ connection_or_clear_identity_map(); + connection_or_clear_ext_or_id_map(); /* Clear out our list of broken connections */ clear_broken_connection_map(0); diff --git a/src/or/connection_or.c b/src/or/connection_or.c index ec5733fe18..e6fbb792d8 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -185,8 +185,10 @@ void connection_or_remove_from_ext_or_id_map(or_connection_t *conn) { or_connection_t *tmp; - if (!orconn_identity_map) - orconn_identity_map = digestmap_new(); + if (!orconn_ext_or_id_map) + return; + if (!conn->ext_or_conn_id) + return; tmp = digestmap_remove(orconn_ext_or_id_map, conn->ext_or_conn_id); if (!tor_digest_is_zero(conn->ext_or_conn_id)) @@ -200,6 +202,7 @@ void connection_or_clear_ext_or_id_map(void) { digestmap_free(orconn_ext_or_id_map, NULL); + orconn_ext_or_id_map = NULL; } /** Creates an Extended ORPort identifier for conn and deposits @@ -214,13 +217,16 @@ connection_or_set_ext_or_identifier(or_connection_t *conn) orconn_ext_or_id_map = digestmap_new(); /* Remove any previous identifiers: */ - if (!tor_digest_is_zero(conn->ext_or_conn_id)) + if (conn->ext_or_conn_id && !tor_digest_is_zero(conn->ext_or_conn_id)) connection_or_remove_from_ext_or_id_map(conn); do { crypto_rand(random_id, sizeof(random_id)); } while (digestmap_get(orconn_ext_or_id_map, random_id)); + if (!conn->ext_or_conn_id) + conn->ext_or_conn_id = tor_malloc_zero(EXT_OR_CONN_ID_LEN); + memcpy(conn->ext_or_conn_id, random_id, EXT_OR_CONN_ID_LEN); tmp = digestmap_set(orconn_ext_or_id_map, random_id, conn); @@ -2484,7 +2490,75 @@ connection_ext_or_transition(or_connection_t *conn) connection_tls_start_handshake(conn, 1); } -#define EXT_OR_CMD_WANT_CONTROL 0x0003 +/** DOCDOCDOC */ +#define EXT_OR_PORT_AUTH_COOKIE_LEN 32 +#define EXT_OR_PORT_AUTH_COOKIE_HEADER_LEN 32 +#define EXT_OR_PORT_AUTH_COOKIE_FILE_LEN EXT_OR_PORT_AUTH_COOKIE_LEN+EXT_OR_PORT_AUTH_COOKIE_HEADER_LEN +#define EXT_OR_PORT_AUTH_COOKIE_HEADER "! Extended ORPort Auth Cookie !\x0a" + +/** If true, we've set ext_or_auth_cookie to a secret code and stored + * it to disk. */ +static int ext_or_auth_cookie_is_set = 0; +/** If ext_or_auth_cookie_is_set, a secret cookie that we've stored to disk + * and which we're using to authenticate controllers. (If the controller can + * read it off disk, it has permission to connect.) */ +static char ext_or_auth_cookie[EXT_OR_PORT_AUTH_COOKIE_LEN] = {0}; + +/** Helper: Return a newly allocated string containing a path to the + * file where we store our authentication cookie. */ +char * +get_ext_or_auth_cookie_file(void) +{ + const or_options_t *options = get_options(); + if (options->ExtORPortCookieAuthFile && strlen(options->ExtORPortCookieAuthFile)) { + return tor_strdup(options->ExtORPortCookieAuthFile); + } else { + return get_datadir_fname("extended_orport_auth_cookie"); + } +} + +/** Choose a random authentication cookie and write it to disk. + * Anybody who can read the cookie from disk will be considered + * authorized to use the control connection. Return -1 if we can't + * write the file, or 0 on success. */ +int +init_ext_or_auth_cookie_authentication(int is_enabled) +{ + char *fname; + char cookie_file_string[EXT_OR_PORT_AUTH_COOKIE_FILE_LEN]; + + if (!is_enabled) { + ext_or_auth_cookie_is_set = 0; + return 0; + } + + /* We don't want to generate a new cookie every time we call + * options_act(). One should be enough. */ + if (ext_or_auth_cookie_is_set) + return 0; /* all set */ + + fname = get_ext_or_auth_cookie_file(); + crypto_rand(ext_or_auth_cookie, EXT_OR_PORT_AUTH_COOKIE_LEN); + ext_or_auth_cookie_is_set = 1; + + memcpy(cookie_file_string, EXT_OR_PORT_AUTH_COOKIE_HEADER, EXT_OR_PORT_AUTH_COOKIE_HEADER_LEN); + memcpy(cookie_file_string+EXT_OR_PORT_AUTH_COOKIE_HEADER_LEN, + ext_or_auth_cookie, EXT_OR_PORT_AUTH_COOKIE_LEN); + + if (write_bytes_to_file(fname, cookie_file_string, + EXT_OR_PORT_AUTH_COOKIE_FILE_LEN, 1)) { + log_warn(LD_FS,"Error writing authentication cookie to %s.", + escaped(fname)); + tor_free(fname); + return -1; + } + + log_warn(LD_GENERAL, "Generated Extended ORPort cookie file in '%s'.", + fname); + + tor_free(fname); + return 0; +} /** Extended ORPort commands (Transport-to-Bridge) */ #define EXT_OR_CMD_TB_DONE 0x0000 @@ -2553,14 +2627,6 @@ connection_ext_or_process_inbuf(or_connection_t *or_conn) /* record the address */ tor_addr_copy(&conn->addr, &addr); conn->port = port; - } else if (command->cmd == EXT_OR_CMD_WANT_CONTROL) { - char response[128]; - char *cp; - memcpy(response, or_conn->ext_or_conn_id, EXT_OR_CONN_ID_LEN); - cp = response+EXT_OR_CONN_ID_LEN; - /* XXXX write the TransportControlPort; advance cp. */ - connection_write_ext_or_command(conn, EXT_OR_CMD_BT_OKAY, response, - cp-response); } else { log_notice(LD_NET, "Got an Extended ORPort command we don't understand (%u).", command->cmd); @@ -2569,6 +2635,8 @@ connection_ext_or_process_inbuf(or_connection_t *or_conn) ext_or_cmd_free(command); } + return 0; + err: ext_or_cmd_free(command); return -1; diff --git a/src/or/connection_or.h b/src/or/connection_or.h index a80871d5c9..1e9a652b45 100644 --- a/src/or/connection_or.h +++ b/src/or/connection_or.h @@ -104,5 +104,8 @@ void connection_or_clear_ext_or_id_map(void); int connection_ext_or_finished_flushing(or_connection_t *conn); int connection_ext_or_process_inbuf(or_connection_t *or_conn); +int init_ext_or_auth_cookie_authentication(int is_enabled); +char *get_ext_or_auth_cookie_file(void); + #endif diff --git a/src/or/control.c b/src/or/control.c index 3f8d47c554..e83a8e08cd 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -4451,7 +4451,7 @@ get_cookie_file(void) * authorized to use the control connection. Return -1 if we can't * write the file, or 0 on success. */ int -init_cookie_authentication(int enabled) +init_control_auth_cookie_authentication(int enabled) { char *fname; if (!enabled) { diff --git a/src/or/control.h b/src/or/control.h index d0f682067e..663824ce31 100644 --- a/src/or/control.h +++ b/src/or/control.h @@ -77,7 +77,7 @@ int control_event_buildtimeout_set(const circuit_build_times_t *cbt, buildtimeout_set_event_t type); int control_event_signal(uintptr_t signal); -int init_cookie_authentication(int enabled); +int init_control_auth_cookie_authentication(int enabled); smartlist_t *decode_hashed_passwords(config_line_t *passwords); void disable_control_logging(void); void enable_control_logging(void); diff --git a/src/or/transports.c b/src/or/transports.c index 15faa98d40..877dc0c335 100644 --- a/src/or/transports.c +++ b/src/or/transports.c @@ -96,6 +96,7 @@ #include "router.h" #include "statefile.h" #include "entrynodes.h" +#include "connection_or.h" static process_environment_t * create_managed_proxy_environment(const managed_proxy_t *mp); @@ -1194,6 +1195,8 @@ get_bindaddr_for_server_proxy(const managed_proxy_t *mp) static process_environment_t * create_managed_proxy_environment(const managed_proxy_t *mp) { + const or_options_t *options = get_options(); + /* Environment variables to be added to or set in mp's environment. */ smartlist_t *envs = smartlist_new(); /* XXXX The next time someone touches this code, shorten the name of @@ -1257,7 +1260,22 @@ create_managed_proxy_environment(const managed_proxy_t *mp) * (If we remove this line entirely, some joker will stick this * variable in Tor's environment and crash PTs that try to parse * it even when not run in server mode.) */ - smartlist_add(envs, tor_strdup("TOR_PT_EXTENDED_SERVER_PORT=")); + + if (options->ExtORPort) { + char *ext_or_addrport_tmp = + get_first_listener_addrport_string(CONN_TYPE_EXT_OR_LISTENER); + char *cookie_file_loc = get_ext_or_auth_cookie_file(); + + smartlist_add_asprintf(envs, "TOR_PT_EXTENDED_SERVER_PORT=%s", + ext_or_addrport_tmp); + smartlist_add_asprintf(envs, "TOR_PT_AUTH_COOKIE_FILE=%s", cookie_file_loc); + + tor_free(ext_or_addrport_tmp); + tor_free(cookie_file_loc); + + } else { + smartlist_add_asprintf(envs, "TOR_PT_EXTENDED_SERVER_PORT="); + } } SMARTLIST_FOREACH_BEGIN(envs, const char *, env_var) {