Split command-handling and authentication from control.c

This commit is contained in:
Nick Mathewson 2019-03-25 14:03:49 -04:00
parent 4754e9058b
commit 2917ecaa97
16 changed files with 2965 additions and 2856 deletions

View file

@ -79,8 +79,8 @@ problem function-size /src/core/mainloop/connection.c:connection_handle_write_im
problem function-size /src/core/mainloop/connection.c:assert_connection_ok() 143
problem function-size /src/app/config/confparse.c:config_assign_value() 205
problem function-size /src/app/config/confparse.c:config_get_assigned_option() 129
problem file-size /src/app/config/config.c 8489
problem include-count /src/app/config/config.c 85
problem file-size /src/app/config/config.c 8490
problem include-count /src/app/config/config.c 86
problem function-size /src/app/config/config.c:options_act_reversible() 296
problem function-size /src/app/config/config.c:options_act() 588
problem function-size /src/app/config/config.c:resolve_my_address() 192
@ -96,7 +96,7 @@ problem function-size /src/app/config/config.c:parse_port_config() 452
problem function-size /src/app/config/config.c:parse_ports() 170
problem function-size /src/app/config/config.c:getinfo_helper_config() 116
problem function-size /src/app/main/ntmain.c:nt_service_install() 125
problem include-count /src/app/main/main.c 84
problem include-count /src/app/main/main.c 85
problem function-size /src/app/main/main.c:dumpstats() 102
problem function-size /src/app/main/main.c:tor_init() 136
problem function-size /src/app/main/main.c:sandbox_init_filter() 291
@ -111,19 +111,20 @@ problem function-size /src/feature/dircommon/consdiff.c:gen_ed_diff() 204
problem function-size /src/feature/dircommon/consdiff.c:apply_ed_diff() 159
problem file-size /src/feature/control/control.c 7592
problem include-count /src/feature/control/control.c 90
problem function-size /src/feature/control/control.c:handle_control_authenticate() 188
problem function-size /src/feature/control/control_auth.c:handle_control_authenticate() 188
problem function-size /src/feature/control/control_auth.c:handle_control_authchallenge() 115
problem function-size /src/feature/control/control_getinfo.c:getinfo_helper_misc() 109
problem function-size /src/feature/control/control_getinfo.c:getinfo_helper_dir() 304
problem function-size /src/feature/control/control_getinfo.c:getinfo_helper_events() 236
problem function-size /src/feature/control/control.c:handle_control_extendcircuit() 151
problem function-size /src/feature/control/control.c:handle_control_authchallenge() 115
problem function-size /src/feature/control/control.c:handle_control_hsfetch() 114
problem function-size /src/feature/control/control.c:handle_control_hspost() 117
problem function-size /src/feature/control/control.c:handle_control_add_onion() 293
problem function-size /src/feature/control/control.c:add_onion_helper_keyarg() 125
problem function-size /src/feature/control/control_cmd.c:handle_control_command() 104
problem function-size /src/feature/control/control_cmd.c:handle_control_extendcircuit() 151
problem function-size /src/feature/control/control_cmd.c:handle_control_hsfetch() 114
problem function-size /src/feature/control/control_cmd.c:handle_control_hspost() 117
problem function-size /src/feature/control/control_cmd.c:handle_control_add_onion() 293
problem function-size /src/feature/control/control_cmd.c:add_onion_helper_keyarg() 125
problem function-size /src/feature/control/control.c:connection_control_process_inbuf() 239
problem function-size /src/feature/control/control_events.c:control_event_stream_status() 119
problem include-count /src/feature/control/control_getinfo.c 51
problem include-count /src/feature/control/control_getinfo.c 52
problem function-size /src/feature/stats/rephist.c:rep_hist_load_mtbf_data() 185
problem function-size /src/feature/stats/rephist.c:rep_hist_format_exit_stats() 148
problem function-size /src/feature/dircache/consdiffmgr.c:consdiffmgr_cleanup() 115

View file

@ -86,6 +86,7 @@
#include "feature/client/entrynodes.h"
#include "feature/client/transports.h"
#include "feature/control/control.h"
#include "feature/control/control_auth.h"
#include "feature/control/control_events.h"
#include "feature/dirauth/bwauth.h"
#include "feature/dirauth/guardfraction.h"

View file

@ -43,6 +43,7 @@
#include "feature/client/entrynodes.h"
#include "feature/client/transports.h"
#include "feature/control/control.h"
#include "feature/control/control_auth.h"
#include "feature/control/control_events.h"
#include "feature/dirauth/bwauth.h"
#include "feature/dirauth/keypin.h"

View file

@ -70,7 +70,9 @@ LIBTOR_APP_A_SOURCES = \
src/feature/control/btrack_orconn_cevent.c \
src/feature/control/btrack_orconn_maps.c \
src/feature/control/control.c \
src/feature/control/control_auth.c \
src/feature/control/control_bootstrap.c \
src/feature/control/control_cmd.c \
src/feature/control/control_events.c \
src/feature/control/control_fmt.c \
src/feature/control/control_getinfo.c \
@ -290,6 +292,8 @@ noinst_HEADERS += \
src/feature/control/btrack_orconn_maps.h \
src/feature/control/btrack_sys.h \
src/feature/control/control.h \
src/feature/control/control_auth.h \
src/feature/control/control_cmd.h \
src/feature/control/control_connection_st.h \
src/feature/control/control_events.h \
src/feature/control/control_fmt.h \

File diff suppressed because it is too large Load diff

View file

@ -42,10 +42,6 @@ void connection_control_closed(control_connection_t *conn);
int connection_control_process_inbuf(control_connection_t *conn);
int init_control_cookie_authentication(int enabled);
char *get_controller_cookie_file_name(void);
struct config_line_t;
smartlist_t *decode_hashed_passwords(struct config_line_t *passwords);
void disable_control_logging(void);
void enable_control_logging(void);
@ -55,40 +51,14 @@ const char *rend_auth_type_to_string(rend_auth_type_t auth_type);
MOCK_DECL(const char *, node_describe_longname_by_id,(const char *id_digest));
void control_free_all(void);
#ifdef CONTROL_PRIVATE
#include "lib/crypt_ops/crypto_ed25519.h"
/* ADD_ONION secret key to create an ephemeral service. The command supports
* multiple versions so this union stores the key and passes it to the HS
* subsystem depending on the requested version. */
typedef union add_onion_secret_key_t {
/* Hidden service v2 secret key. */
crypto_pk_t *v2;
/* Hidden service v3 secret key. */
ed25519_secret_key_t *v3;
} add_onion_secret_key_t;
STATIC int add_onion_helper_keyarg(const char *arg, int discard_pk,
const char **key_new_alg_out,
char **key_new_blob_out,
add_onion_secret_key_t *decoded_key,
int *hs_version, char **err_msg_out);
STATIC rend_authorized_client_t *
add_onion_helper_clientauth(const char *arg, int *created, char **err_msg_out);
#endif /* defined(CONTROL_PRIVATE) */
#ifdef CONTROL_MODULE_PRIVATE
struct signal_name_t {
int sig;
const char *signal_name;
};
extern const struct signal_name_t signal_table[];
int get_cached_network_liveness(void);
void set_cached_network_liveness(int liveness);
smartlist_t * get_detached_onion_services(void);
#endif /* defined(CONTROL_MODULE_PRIVATE) */
#endif /* !defined(TOR_CONTROL_H) */

View file

@ -0,0 +1,439 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2019, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file control_auth.c
* \brief Authentication for Tor's control-socket interface.
**/
#include "core/or/or.h"
#include "app/config/config.h"
#include "core/mainloop/connection.h"
#include "feature/control/control.h"
#include "feature/control/control_auth.h"
#include "feature/control/control_connection_st.h"
#include "feature/control/control_fmt.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
#include "lib/encoding/confline.h"
#include "lib/crypt_ops/crypto_s2k.h"
/** If we're using cookie-type authentication, how long should our cookies be?
*/
#define AUTHENTICATION_COOKIE_LEN 32
/** If true, we've set authentication_cookie to a secret code and
* stored it to disk. */
static int authentication_cookie_is_set = 0;
/** If authentication_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 uint8_t *authentication_cookie = NULL;
#define SAFECOOKIE_SERVER_TO_CONTROLLER_CONSTANT \
"Tor safe cookie authentication server-to-controller hash"
#define SAFECOOKIE_CONTROLLER_TO_SERVER_CONSTANT \
"Tor safe cookie authentication controller-to-server hash"
#define SAFECOOKIE_SERVER_NONCE_LEN DIGEST256_LEN
/** Helper: Return a newly allocated string containing a path to the
* file where we store our authentication cookie. */
char *
get_controller_cookie_file_name(void)
{
const or_options_t *options = get_options();
if (options->CookieAuthFile && strlen(options->CookieAuthFile)) {
return tor_strdup(options->CookieAuthFile);
} else {
return get_datadir_fname("control_auth_cookie");
}
}
/* Initialize the cookie-based authentication system of the
* ControlPort. If <b>enabled</b> is 0, then disable the cookie
* authentication system. */
int
init_control_cookie_authentication(int enabled)
{
char *fname = NULL;
int retval;
if (!enabled) {
authentication_cookie_is_set = 0;
return 0;
}
fname = get_controller_cookie_file_name();
retval = init_cookie_authentication(fname, "", /* no header */
AUTHENTICATION_COOKIE_LEN,
get_options()->CookieAuthFileGroupReadable,
&authentication_cookie,
&authentication_cookie_is_set);
tor_free(fname);
return retval;
}
/** Decode the hashed, base64'd passwords stored in <b>passwords</b>.
* Return a smartlist of acceptable passwords (unterminated strings of
* length S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN) on success, or NULL on
* failure.
*/
smartlist_t *
decode_hashed_passwords(config_line_t *passwords)
{
char decoded[64];
config_line_t *cl;
smartlist_t *sl = smartlist_new();
tor_assert(passwords);
for (cl = passwords; cl; cl = cl->next) {
const char *hashed = cl->value;
if (!strcmpstart(hashed, "16:")) {
if (base16_decode(decoded, sizeof(decoded), hashed+3, strlen(hashed+3))
!= S2K_RFC2440_SPECIFIER_LEN + DIGEST_LEN
|| strlen(hashed+3) != (S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN)*2) {
goto err;
}
} else {
if (base64_decode(decoded, sizeof(decoded), hashed, strlen(hashed))
!= S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN) {
goto err;
}
}
smartlist_add(sl,
tor_memdup(decoded, S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN));
}
return sl;
err:
SMARTLIST_FOREACH(sl, char*, cp, tor_free(cp));
smartlist_free(sl);
return NULL;
}
/** 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;
}
/** 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;
});
SMARTLIST_FOREACH(sl, char *, str, tor_free(str));
smartlist_free(sl);
sl = NULL;
if (used_quoted_string)
errstr = "Password did not match HashedControlPassword value from "
"configuration";
else
errstr = "Password did not match HashedControlPassword value from "
"configuration. Maybe you tried a plain text password? "
"If so, the standard requires that you put it in double quotes.";
bad_password = 1;
if (!also_cookie)
goto err;
}
}
/** We only get here if both kinds of authentication failed. */
tor_assert(bad_password && bad_cookie);
log_warn(LD_CONTROL, "Bad password or authentication cookie on controller.");
errstr = "Password did not match HashedControlPassword *or* authentication "
"cookie.";
err:
tor_free(password);
connection_printf_to_buf(conn, "515 Authentication failed: %s\r\n", errstr);
connection_mark_for_close(TO_CONN(conn));
if (sl) { /* clean up */
SMARTLIST_FOREACH(sl, char *, str, tor_free(str));
smartlist_free(sl);
}
return 0;
ok:
log_info(LD_CONTROL, "Authenticated control connection ("TOR_SOCKET_T_FORMAT
")", conn->base_.s);
send_control_done(conn);
conn->base_.state = CONTROL_CONN_STATE_OPEN;
tor_free(password);
if (sl) { /* clean up */
SMARTLIST_FOREACH(sl, char *, str, tor_free(str));
smartlist_free(sl);
}
return 0;
}
void
control_auth_free_all(void)
{
if (authentication_cookie) /* Free the auth cookie */
tor_free(authentication_cookie);
authentication_cookie_is_set = 0;
}

View file

@ -0,0 +1,27 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2019, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file control_auth.h
* \brief Header file for control_auth.c.
**/
#ifndef TOR_CONTROL_AUTH_H
#define TOR_CONTROL_AUTH_H
int init_control_cookie_authentication(int enabled);
char *get_controller_cookie_file_name(void);
struct config_line_t;
smartlist_t *decode_hashed_passwords(struct config_line_t *passwords);
int handle_control_authchallenge(control_connection_t *conn, uint32_t len,
const char *body);
int handle_control_authenticate(control_connection_t *conn,
uint32_t cmd_data_len,
const char *args);
void control_auth_free_all(void);
#endif /* !defined(TOR_CONTROL_AUTH_H) */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,48 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2019, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file control_cmd.h
* \brief Header file for control_cmd.c.
**/
#ifndef TOR_CONTROL_CMD_H
#define TOR_CONTROL_CMD_H
int handle_control_command(control_connection_t *conn,
uint32_t cmd_data_len,
char *args);
void control_cmd_free_all(void);
#ifdef CONTROL_CMD_PRIVATE
#include "lib/crypt_ops/crypto_ed25519.h"
/* ADD_ONION secret key to create an ephemeral service. The command supports
* multiple versions so this union stores the key and passes it to the HS
* subsystem depending on the requested version. */
typedef union add_onion_secret_key_t {
/* Hidden service v2 secret key. */
crypto_pk_t *v2;
/* Hidden service v3 secret key. */
ed25519_secret_key_t *v3;
} add_onion_secret_key_t;
STATIC int add_onion_helper_keyarg(const char *arg, int discard_pk,
const char **key_new_alg_out,
char **key_new_blob_out,
add_onion_secret_key_t *decoded_key,
int *hs_version, char **err_msg_out);
STATIC rend_authorized_client_t *add_onion_helper_clientauth(const char *arg,
int *created, char **err_msg_out);
#endif /* defined(CONTROL_CMD_PRIVATE) */
#ifdef CONTROL_MODULE_PRIVATE
smartlist_t * get_detached_onion_services(void);
#endif /* defined(CONTROL_MODULE_PRIVATE) */
#endif /* !defined(TOR_CONTROL_CMD_H) */

View file

@ -297,3 +297,98 @@ read_escaped_data(const char *data, size_t len, char **out)
*outp = '\0';
return outp - *out;
}
/** Send a "DONE" message down the control connection <b>conn</b>. */
void
send_control_done(control_connection_t *conn)
{
connection_write_str_to_buf("250 OK\r\n", conn);
}
/** If the first <b>in_len_max</b> characters in <b>start</b> contain a
* double-quoted string with escaped characters, return the length of that
* string (as encoded, including quotes). Otherwise return -1. */
static inline int
get_escaped_string_length(const char *start, size_t in_len_max,
int *chars_out)
{
const char *cp, *end;
int chars = 0;
if (*start != '\"')
return -1;
cp = start+1;
end = start+in_len_max;
/* Calculate length. */
while (1) {
if (cp >= end) {
return -1; /* Too long. */
} else if (*cp == '\\') {
if (++cp == end)
return -1; /* Can't escape EOS. */
++cp;
++chars;
} else if (*cp == '\"') {
break;
} else {
++cp;
++chars;
}
}
if (chars_out)
*chars_out = chars;
return (int)(cp - start+1);
}
/** As decode_escaped_string, but does not decode the string: copies the
* entire thing, including quotation marks. */
const char *
extract_escaped_string(const char *start, size_t in_len_max,
char **out, size_t *out_len)
{
int length = get_escaped_string_length(start, in_len_max, NULL);
if (length<0)
return NULL;
*out_len = length;
*out = tor_strndup(start, *out_len);
return start+length;
}
/** Given a pointer to a string starting at <b>start</b> containing
* <b>in_len_max</b> characters, decode a string beginning with one double
* quote, containing any number of non-quote characters or characters escaped
* with a backslash, and ending with a final double quote. Place the resulting
* string (unquoted, unescaped) into a newly allocated string in *<b>out</b>;
* store its length in <b>out_len</b>. On success, return a pointer to the
* character immediately following the escaped string. On failure, return
* NULL. */
const char *
decode_escaped_string(const char *start, size_t in_len_max,
char **out, size_t *out_len)
{
const char *cp, *end;
char *outp;
int len, n_chars = 0;
len = get_escaped_string_length(start, in_len_max, &n_chars);
if (len<0)
return NULL;
end = start+len-1; /* Index of last quote. */
tor_assert(*end == '\"');
outp = *out = tor_malloc(len+1);
*out_len = n_chars;
cp = start+1;
while (cp < end) {
if (*cp == '\\')
++cp;
*outp++ = *cp++;
}
*outp = '\0';
tor_assert((outp - *out) == (int)*out_len);
return end+1;
}

View file

@ -25,5 +25,10 @@ char *circuit_describe_status_for_controller(origin_circuit_t *circ);
size_t write_escaped_data(const char *data, size_t len, char **out);
size_t read_escaped_data(const char *data, size_t len, char **out);
const char *extract_escaped_string(const char *start, size_t in_len_max,
char **out, size_t *out_len);
const char *decode_escaped_string(const char *start, size_t in_len_max,
char **out, size_t *out_len);
void send_control_done(control_connection_t *conn);
#endif /* !defined(TOR_CONTROL_FMT_H) */

View file

@ -24,6 +24,7 @@
#include "feature/client/bridges.h"
#include "feature/client/entrynodes.h"
#include "feature/control/control.h"
#include "feature/control/control_cmd.h"
#include "feature/control/control_events.h"
#include "feature/control/control_fmt.h"
#include "feature/control/control_getinfo.h"

View file

@ -1,12 +1,13 @@
/* Copyright (c) 2015-2019, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONTROL_PRIVATE
#define CONTROL_CMD_PRIVATE
#define CONTROL_GETINFO_PRIVATE
#include "core/or/or.h"
#include "lib/crypt_ops/crypto_ed25519.h"
#include "feature/client/bridges.h"
#include "feature/control/control.h"
#include "feature/control/control_cmd.h"
#include "feature/control/control_getinfo.h"
#include "feature/client/entrynodes.h"
#include "feature/hs/hs_common.h"

View file

@ -7,7 +7,6 @@
#define PT_PRIVATE
#define UTIL_PRIVATE
#define STATEFILE_PRIVATE
//#define CONTROL_PRIVATE
#define CONTROL_EVENTS_PRIVATE
#define PROCESS_PRIVATE
#include "core/or/or.h"

View file

@ -6,7 +6,6 @@
#include "orconfig.h"
#define COMPAT_PRIVATE
#define COMPAT_TIME_PRIVATE
#define CONTROL_PRIVATE
#define UTIL_PRIVATE
#define UTIL_MALLOC_PRIVATE
#define SOCKET_PRIVATE