📄 control.c
字号:
log_warn(LD_CONTROL,"Controller gave us config lines we can't parse.");
connection_write_str_to_buf("551 Couldn't parse configuration\r\n",
conn);
tor_free(config);
return 0;
}
tor_free(config);
if ((opt_err=options_trial_assign(lines, use_defaults,
clear_first, &errstring)) != SETOPT_OK) {
const char *msg;
log_warn(LD_CONTROL,
"Controller gave us config lines that didn't validate: %s",
errstring);
switch (opt_err) {
case SETOPT_ERR_MISC:
msg = "552 Unrecognized option";
break;
case SETOPT_ERR_PARSE:
msg = "513 Unacceptable option value";
break;
case SETOPT_ERR_TRANSITION:
msg = "553 Transition not allowed";
break;
case SETOPT_ERR_SETTING:
default:
msg = "553 Unable to set option";
break;
case SETOPT_OK:
msg = "551 Internal error";
tor_fragile_assert();
break;
}
connection_printf_to_buf(conn, "%s: %s\r\n", msg, errstring);
config_free_lines(lines);
tor_free(errstring);
return 0;
}
config_free_lines(lines);
send_control_done(conn);
return 0;
}
/** Called when we receive a SETCONF message: parse the body and try
* to update our configuration. Reply with a DONE or ERROR message.
* Modifies the contents of body.*/
static int
handle_control_setconf(control_connection_t *conn, uint32_t len, char *body)
{
return control_setconf_helper(conn, len, body, 0);
}
/** Called when we receive a RESETCONF message: parse the body and try
* to update our configuration. Reply with a DONE or ERROR message.
* Modifies the contents of body. */
static int
handle_control_resetconf(control_connection_t *conn, uint32_t len, char *body)
{
return control_setconf_helper(conn, len, body, 1);
}
/** Called when we receive a GETCONF message. Parse the request, and
* reply with a CONFVALUE or an ERROR message */
static int
handle_control_getconf(control_connection_t *conn, uint32_t body_len,
const char *body)
{
smartlist_t *questions = NULL;
smartlist_t *answers = NULL;
smartlist_t *unrecognized = NULL;
char *msg = NULL;
size_t msg_len;
or_options_t *options = get_options();
int i, len;
questions = smartlist_create();
(void) body_len; /* body is nul-terminated; so we can ignore len. */
smartlist_split_string(questions, body, " ",
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
answers = smartlist_create();
unrecognized = smartlist_create();
SMARTLIST_FOREACH(questions, char *, q,
{
if (!option_is_recognized(q)) {
smartlist_add(unrecognized, q);
} else {
config_line_t *answer = option_get_assignment(options,q);
if (!answer) {
const char *name = option_get_canonical_name(q);
size_t alen = strlen(name)+8;
char *astr = tor_malloc(alen);
tor_snprintf(astr, alen, "250-%s\r\n", name);
smartlist_add(answers, astr);
}
while (answer) {
config_line_t *next;
size_t alen = strlen(answer->key)+strlen(answer->value)+8;
char *astr = tor_malloc(alen);
tor_snprintf(astr, alen, "250-%s=%s\r\n",
answer->key, answer->value);
smartlist_add(answers, astr);
next = answer->next;
tor_free(answer->key);
tor_free(answer->value);
tor_free(answer);
answer = next;
}
}
});
if ((len = smartlist_len(unrecognized))) {
for (i=0; i < len-1; ++i)
connection_printf_to_buf(conn,
"552-Unrecognized configuration key \"%s\"\r\n",
(char*)smartlist_get(unrecognized, i));
connection_printf_to_buf(conn,
"552 Unrecognized configuration key \"%s\"\r\n",
(char*)smartlist_get(unrecognized, len-1));
} else if ((len = smartlist_len(answers))) {
char *tmp = smartlist_get(answers, len-1);
tor_assert(strlen(tmp)>4);
tmp[3] = ' ';
msg = smartlist_join_strings(answers, "", 0, &msg_len);
connection_write_to_buf(msg, msg_len, TO_CONN(conn));
} else {
connection_write_str_to_buf("250 OK\r\n", conn);
}
if (answers) {
SMARTLIST_FOREACH(answers, char *, cp, tor_free(cp));
smartlist_free(answers);
}
if (questions) {
SMARTLIST_FOREACH(questions, char *, cp, tor_free(cp));
smartlist_free(questions);
}
smartlist_free(unrecognized);
tor_free(msg);
return 0;
}
/** Called when we get a +LOADCONF message. */
static int
handle_control_loadconf(control_connection_t *conn, uint32_t len,
const char *body)
{
setopt_err_t retval;
char *errstring = NULL;
const char *msg = NULL;
(void) len;
retval = options_init_from_string(body, CMD_RUN_TOR, NULL, &errstring);
if (retval != SETOPT_OK) {
log_warn(LD_CONTROL,
"Controller gave us config file that didn't validate: %s",
errstring);
switch (retval) {
case SETOPT_ERR_PARSE:
msg = "552 Invalid config file";
break;
case SETOPT_ERR_TRANSITION:
msg = "553 Transition not allowed";
break;
case SETOPT_ERR_SETTING:
msg = "553 Unable to set option";
break;
case SETOPT_ERR_MISC:
default:
msg = "550 Unable to load config";
break;
case SETOPT_OK:
tor_fragile_assert();
break;
}
if (*errstring)
connection_printf_to_buf(conn, "%s: %s\r\n", msg, errstring);
else
connection_printf_to_buf(conn, "%s\r\n", msg);
tor_free(errstring);
return 0;
}
send_control_done(conn);
return 0;
}
/** Called when we get a SETEVENTS message: update conn->event_mask,
* and reply with DONE or ERROR. */
static int
handle_control_setevents(control_connection_t *conn, uint32_t len,
const char *body)
{
uint16_t event_code;
uint32_t event_mask = 0;
unsigned int extended = 0;
smartlist_t *events = smartlist_create();
(void) len;
smartlist_split_string(events, body, " ",
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
SMARTLIST_FOREACH(events, const char *, ev,
{
if (!strcasecmp(ev, "EXTENDED")) {
extended = 1;
continue;
} else if (!strcasecmp(ev, "CIRC"))
event_code = EVENT_CIRCUIT_STATUS;
else if (!strcasecmp(ev, "STREAM"))
event_code = EVENT_STREAM_STATUS;
else if (!strcasecmp(ev, "ORCONN"))
event_code = EVENT_OR_CONN_STATUS;
else if (!strcasecmp(ev, "BW"))
event_code = EVENT_BANDWIDTH_USED;
else if (!strcasecmp(ev, "DEBUG"))
event_code = EVENT_DEBUG_MSG;
else if (!strcasecmp(ev, "INFO"))
event_code = EVENT_INFO_MSG;
else if (!strcasecmp(ev, "NOTICE"))
event_code = EVENT_NOTICE_MSG;
else if (!strcasecmp(ev, "WARN"))
event_code = EVENT_WARN_MSG;
else if (!strcasecmp(ev, "ERR"))
event_code = EVENT_ERR_MSG;
else if (!strcasecmp(ev, "NEWDESC"))
event_code = EVENT_NEW_DESC;
else if (!strcasecmp(ev, "ADDRMAP"))
event_code = EVENT_ADDRMAP;
else if (!strcasecmp(ev, "AUTHDIR_NEWDESCS"))
event_code = EVENT_AUTHDIR_NEWDESCS;
else if (!strcasecmp(ev, "DESCCHANGED"))
event_code = EVENT_DESCCHANGED;
else if (!strcasecmp(ev, "NS"))
event_code = EVENT_NS;
else if (!strcasecmp(ev, "STATUS_GENERAL"))
event_code = EVENT_STATUS_GENERAL;
else if (!strcasecmp(ev, "STATUS_CLIENT"))
event_code = EVENT_STATUS_CLIENT;
else if (!strcasecmp(ev, "STATUS_SERVER"))
event_code = EVENT_STATUS_SERVER;
else if (!strcasecmp(ev, "GUARD"))
event_code = EVENT_GUARD;
else if (!strcasecmp(ev, "GUARDS")) {
/* XXXX021 This check is here to tolerate the controllers that
* depended on the buggy spec in 0.1.2.5-alpha through 0.1.2.10-rc.
* Once those versions are obsolete, stop supporting this. */
log_warn(LD_CONTROL, "Controller used obsolete 'GUARDS' event name; "
"use GUARD instead.");
event_code = EVENT_GUARD;
} else if (!strcasecmp(ev, "STREAM_BW"))
event_code = EVENT_STREAM_BANDWIDTH_USED;
else {
connection_printf_to_buf(conn, "552 Unrecognized event \"%s\"\r\n",
ev);
SMARTLIST_FOREACH(events, char *, e, tor_free(e));
smartlist_free(events);
return 0;
}
event_mask |= (1 << event_code);
});
SMARTLIST_FOREACH(events, char *, e, tor_free(e));
smartlist_free(events);
conn->event_mask = event_mask;
if (extended)
conn->use_extended_events = 1;
control_update_global_event_mask();
send_control_done(conn);
return 0;
}
/** Decode the hashed, base64'd passwords stored in <b>passwords</b>.
* Return a smartlist of acceptable passwords (unterminated strings of
* length S2K_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_create();
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))<0
|| strlen(hashed+3) != (S2K_SPECIFIER_LEN+DIGEST_LEN)*2) {
goto err;
}
} else {
if (base64_decode(decoded, sizeof(decoded), hashed, strlen(hashed))
!= S2K_SPECIFIER_LEN+DIGEST_LEN) {
goto err;
}
}
smartlist_add(sl, tor_memdup(decoded, S2K_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 AUTHENTICATE message. Check whether the
* authentication is valid, and if so, update the connection's state to
* OPEN. Reply with DONE or ERROR.
*/
static int
handle_control_authenticate(control_connection_t *conn, uint32_t len,
const char *body)
{
int used_quoted_string = 0;
or_options_t *options = get_options();
const char *errstr = NULL;
char *password;
size_t password_len;
const char *cp;
int i;
int bad_cookie=0, bad_password=0;
smartlist_t *sl = NULL;
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)<0) {
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 (TOR_ISSPACE(body[0])) {
password = tor_strdup("");
password_len = 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 (!options->CookieAuthentication && !options->HashedControlPassword &&
!options->HashedControlSessionPassword) {
/* if Tor doesn't demand any stronger authentication, then
* the controller can get in with anything. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -