📄 control.c
字号:
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 (memcmp(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_create();
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_CONTROL,
"Couldn't decode HashedControlPassword: invalid base16");
errstr="Couldn't decode HashedControlPassword value in configuration.";
}
bad_password = 1;
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_free(sl);
} else {
SMARTLIST_FOREACH(sl, char *, expected,
{
secret_to_key(received,DIGEST_LEN,password,password_len,expected);
if (!memcmp(expected+S2K_SPECIFIER_LEN, received, DIGEST_LEN))
goto ok;
});
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_free(sl);
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);
if (!errstr)
errstr = "Unknown reason.";
connection_printf_to_buf(conn, "515 Authentication failed: %s\r\n",
errstr);
connection_mark_for_close(TO_CONN(conn));
return 0;
ok:
log_info(LD_CONTROL, "Authenticated control connection (%d)", 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 *, cp, tor_free(cp));
smartlist_free(sl);
}
return 0;
}
/** Called when we get a SAVECONF command. Try to flush the current options to
* disk, and report success or failure. */
static int
handle_control_saveconf(control_connection_t *conn, uint32_t len,
const char *body)
{
(void) len;
(void) body;
if (options_save_current()<0) {
connection_write_str_to_buf(
"551 Unable to write configuration to disk.\r\n", conn);
} else {
send_control_done(conn);
}
return 0;
}
/** Called when we get a SIGNAL command. React to the provided signal, and
* report success or failure. (If the signal results in a shutdown, success
* may not be reported.) */
static int
handle_control_signal(control_connection_t *conn, uint32_t len,
const char *body)
{
int sig;
int n = 0;
char *s;
(void) len;
while (body[n] && ! TOR_ISSPACE(body[n]))
++n;
s = tor_strndup(body, n);
if (!strcasecmp(s, "RELOAD") || !strcasecmp(s, "HUP"))
sig = SIGHUP;
else if (!strcasecmp(s, "SHUTDOWN") || !strcasecmp(s, "INT"))
sig = SIGINT;
else if (!strcasecmp(s, "DUMP") || !strcasecmp(s, "USR1"))
sig = SIGUSR1;
else if (!strcasecmp(s, "DEBUG") || !strcasecmp(s, "USR2"))
sig = SIGUSR2;
else if (!strcasecmp(s, "HALT") || !strcasecmp(s, "TERM"))
sig = SIGTERM;
else if (!strcasecmp(s, "NEWNYM"))
sig = SIGNEWNYM;
else if (!strcasecmp(s, "CLEARDNSCACHE"))
sig = SIGCLEARDNSCACHE;
else {
connection_printf_to_buf(conn, "552 Unrecognized signal code \"%s\"\r\n",
s);
sig = -1;
}
tor_free(s);
if (sig<0)
return 0;
send_control_done(conn);
/* Flush the "done" first if the signal might make us shut down. */
if (sig == SIGTERM || sig == SIGINT)
connection_handle_write(TO_CONN(conn), 1);
control_signal_act(sig);
return 0;
}
/** Called when we get a MAPADDRESS command; try to bind all listed addresses,
* and report success or failrue. */
static int
handle_control_mapaddress(control_connection_t *conn, uint32_t len,
const char *body)
{
smartlist_t *elts;
smartlist_t *lines;
smartlist_t *reply;
char *r;
size_t sz;
(void) len; /* body is nul-terminated, so it's safe to ignore the length. */
lines = smartlist_create();
elts = smartlist_create();
reply = smartlist_create();
smartlist_split_string(lines, body, " ",
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
SMARTLIST_FOREACH(lines, char *, line,
{
tor_strlower(line);
smartlist_split_string(elts, line, "=", 0, 2);
if (smartlist_len(elts) == 2) {
const char *from = smartlist_get(elts,0);
const char *to = smartlist_get(elts,1);
size_t anslen = strlen(line)+512;
char *ans = tor_malloc(anslen);
if (address_is_invalid_destination(to, 1)) {
tor_snprintf(ans, anslen,
"512-syntax error: invalid address '%s'", to);
smartlist_add(reply, ans);
log_warn(LD_CONTROL,
"Skipping invalid argument '%s' in MapAddress msg", to);
} else if (!strcmp(from, ".") || !strcmp(from, "0.0.0.0")) {
const char *address = addressmap_register_virtual_address(
!strcmp(from,".") ? RESOLVED_TYPE_HOSTNAME : RESOLVED_TYPE_IPV4,
tor_strdup(to));
if (!address) {
tor_snprintf(ans, anslen,
"451-resource exhausted: skipping '%s'", line);
smartlist_add(reply, ans);
log_warn(LD_CONTROL,
"Unable to allocate address for '%s' in MapAddress msg",
safe_str(line));
} else {
tor_snprintf(ans, anslen, "250-%s=%s", address, to);
smartlist_add(reply, ans);
}
} else {
addressmap_register(from, tor_strdup(to), 1, ADDRMAPSRC_CONTROLLER);
tor_snprintf(ans, anslen, "250-%s", line);
smartlist_add(reply, ans);
}
} else {
size_t anslen = strlen(line)+256;
char *ans = tor_malloc(anslen);
tor_snprintf(ans, anslen, "512-syntax error: mapping '%s' is "
"not of expected form 'foo=bar'.", line);
smartlist_add(reply, ans);
log_info(LD_CONTROL, "Skipping MapAddress '%s': wrong "
"number of items.", safe_str(line));
}
SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp));
smartlist_clear(elts);
});
SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp));
smartlist_free(lines);
smartlist_free(elts);
if (smartlist_len(reply)) {
((char*)smartlist_get(reply,smartlist_len(reply)-1))[3] = ' ';
r = smartlist_join_strings(reply, "\r\n", 1, &sz);
connection_write_to_buf(r, sz, TO_CONN(conn));
tor_free(r);
} else {
const char *response =
"512 syntax error: not enough arguments to mapaddress.\r\n";
connection_write_to_buf(response, strlen(response), TO_CONN(conn));
}
SMARTLIST_FOREACH(reply, char *, cp, tor_free(cp));
smartlist_free(reply);
return 0;
}
/** Implementation helper for GETINFO: knows the answers for various
* trivial-to-implement questions. */
static int
getinfo_helper_misc(control_connection_t *conn, const char *question,
char **answer)
{
(void) conn;
if (!strcmp(question, "version")) {
*answer = tor_strdup(get_version());
} else if (!strcmp(question, "config-file")) {
*answer = tor_strdup(get_torrc_fname());
} else if (!strcmp(question, "info/names")) {
*answer = list_getinfo_options();
} else if (!strcmp(question, "events/names")) {
*answer = tor_strdup("CIRC STREAM ORCONN BW DEBUG INFO NOTICE WARN ERR "
"NEWDESC ADDRMAP AUTHDIR_NEWDESCS DESCCHANGED "
"NS STATUS_GENERAL STATUS_CLIENT STATUS_SERVER "
"GUARD STREAM_BW");
} else if (!strcmp(question, "features/names")) {
*answer = tor_strdup("VERBOSE_NAMES EXTENDED_EVENTS");
} else if (!strcmp(question, "address")) {
uint32_t addr;
if (router_pick_published_address(get_options(), &addr) < 0)
return -1;
*answer = tor_dup_addr(addr);
} else if (!strcmp(question, "dir-usage")) {
*answer = directory_dump_request_log();
} else if (!strcmp(question, "fingerprint")) {
routerinfo_t *me = router_get_my_routerinfo();
if (!me)
return -1;
*answer = tor_malloc(HEX_DIGEST_LEN+1);
base16_encode(*answer, HEX_DIGEST_LEN+1, me->cache_info.identity_digest,
DIGEST_LEN);
}
return 0;
}
/** Awful hack: return a newly allocated string based on a routerinfo and
* (possibly) an extrainfo, sticking the read-history and write-history from
* <b>ei</b> into the resulting string. The thing you get back won't
* necessarily have a valid signature.
*
* New code should never use this; it's for backward compatibiliy.
*
* NOTE: <b>ri_body</b> is as returned by signed_descriptor_get_body: it might
* not be NUL-terminated. */
static char *
munge_extrainfo_into_routerinfo(const char *ri_body, signed_descriptor_t *ri,
signed_descriptor_t *ei)
{
char *out = NULL, *outp;
int i;
const char *router_sig;
const char *ei_body = signed_descriptor_get_body(ei);
size_t ri_len = ri->signed_descriptor_len;
size_t ei_len = ei->signed_descriptor_len;
if (!ei_body)
goto bail;
outp = out = tor_malloc(ri_len+ei_len+1);
if (!(router_sig = tor_memstr(ri_body, ri_len, "\nrouter-signature")))
goto bail;
++router_sig;
memcpy(out, ri_body, router_sig-ri_body);
outp += router_sig-ri_body;
for (i=0; i < 2; ++i) {
const char *kwd = i?"\nwrite-history ":"\nread-history ";
const char *cp, *eol;
if (!(cp = tor_memstr(ei_body, ei_len, kwd)))
continue;
++cp;
eol = memchr(cp, '\n', ei_len - (cp-ei_body));
memcpy(outp, cp, eol-cp+1);
outp += eol-cp+1;
}
memcpy(outp, router_sig, ri_len - (router_sig-ri_body));
*outp++ = '\0';
tor_assert(outp-out < (int)(ri_len+ei_len+1));
return out;
bail:
tor_free(out);
return tor_strndup(ri_body, ri->signed_descriptor_len);
}
/** Implementation helper for GETINFO: knows the answers for questions about
* directory information. */
static int
getinfo_helper_dir(control_connection_t *control_conn,
const char *question, char **answer)
{
if (!strcmpstart(question, "desc/id/")) {
routerinfo_t *ri = router_get_by_hexdigest(question+strlen("desc/id/"));
if (ri) {
const char *body = signed_descriptor_get_body(&ri->cache_info);
if (body)
*answer = tor_strndup(body, ri->cache_info.signed_descriptor_len);
}
} else if (!strcmpstart(question, "desc/name/")) {
routerinfo_t *ri = router_get_by_nickname(question+strlen("desc/name/"),1);
if (ri) {
const char *body = signed_descriptor_get_body(&ri->cache_info);
if (body)
*answer = tor_strndup(body, ri->cache_info.signed_descriptor_len);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -