|
@@ -142,6 +142,7 @@ static int write_stream_target_to_buf(edge_connection_t *conn, char *buf,
|
|
|
size_t len);
|
|
|
static void orconn_target_get_name(int long_names, char *buf, size_t len,
|
|
|
or_connection_t *conn);
|
|
|
+static char *get_cookie_file(void);
|
|
|
|
|
|
|
|
|
* log severity. */
|
|
@@ -2236,6 +2237,7 @@ handle_control_closecircuit(control_connection_t *conn, uint32_t len,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
static int
|
|
|
handle_control_resolve(control_connection_t *conn, uint32_t len,
|
|
|
const char *body)
|
|
@@ -2270,6 +2272,72 @@ handle_control_resolve(control_connection_t *conn, uint32_t len,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+static int
|
|
|
+handle_control_protocolinfo(control_connection_t *conn, uint32_t len,
|
|
|
+ const char *body)
|
|
|
+{
|
|
|
+ const char *bad_arg = NULL;
|
|
|
+ smartlist_t *args;
|
|
|
+ (void)len;
|
|
|
+
|
|
|
+ conn->have_sent_protocolinfo = 1;
|
|
|
+ args = smartlist_create();
|
|
|
+ smartlist_split_string(args, body, " ",
|
|
|
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
|
|
|
+ SMARTLIST_FOREACH(args, const char *, arg, {
|
|
|
+ int ok;
|
|
|
+ tor_parse_long(arg, 10, 0, LONG_MAX, &ok, NULL);
|
|
|
+ if (!ok) {
|
|
|
+ bad_arg = arg;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if (bad_arg) {
|
|
|
+ connection_printf_to_buf(conn, "513 No such version %s\r\n",
|
|
|
+ escaped(bad_arg));
|
|
|
+
|
|
|
+ if (!STATE_IS_OPEN(TO_CONN(conn)->state))
|
|
|
+ connection_mark_for_close(TO_CONN(conn));
|
|
|
+ goto done;
|
|
|
+ } else {
|
|
|
+ or_options_t *options = get_options();
|
|
|
+ int cookies = options->CookieAuthentication;
|
|
|
+ char *cfile = get_cookie_file();
|
|
|
+ char *esc_cfile = esc_for_log(cfile);
|
|
|
+ char *methods;
|
|
|
+ {
|
|
|
+ int passwd = (options->HashedControlPassword != NULL) &&
|
|
|
+ strlen(options->HashedControlPassword);
|
|
|
+ smartlist_t *mlist = smartlist_create();
|
|
|
+ if (cookies)
|
|
|
+ smartlist_add(mlist, (char*)"COOKIE");
|
|
|
+ if (passwd)
|
|
|
+ smartlist_add(mlist, (char*)"HASHEDPASSWORD");
|
|
|
+ if (!cookies && !passwd)
|
|
|
+ smartlist_add(mlist, (char*)"NULL");
|
|
|
+ methods = smartlist_join_strings(mlist, ",", 0, NULL);
|
|
|
+ smartlist_free(mlist);
|
|
|
+ }
|
|
|
+
|
|
|
+ connection_printf_to_buf(conn,
|
|
|
+ "250+PROTOCOLINFO 1\r\n"
|
|
|
+ "250-AUTH METHODS=%s%s%s\r\n"
|
|
|
+ "250-VERSION Tor=%s\r\n"
|
|
|
+ "250 OK\r\n",
|
|
|
+ methods,
|
|
|
+ cookies?" COOKIEFILE=":"",
|
|
|
+ cookies?esc_cfile:"",
|
|
|
+ escaped(VERSION));
|
|
|
+ tor_free(cfile);
|
|
|
+ tor_free(esc_cfile);
|
|
|
+ }
|
|
|
+ done:
|
|
|
+ SMARTLIST_FOREACH(args, char *, cp, tor_free(cp));
|
|
|
+ smartlist_free(args);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
* set up the control_connection's options properly. */
|
|
|
static int
|
|
@@ -2340,6 +2408,21 @@ connection_control_reached_eof(control_connection_t *conn)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ * stage of the protocol. */
|
|
|
+static int
|
|
|
+is_valid_initial_command(control_connection_t *conn, const char *cmd)
|
|
|
+{
|
|
|
+ if (conn->_base.state == CONTROL_CONN_STATE_OPEN)
|
|
|
+ return 1;
|
|
|
+ if (!strcasecmp(cmd, "PROTOCOLINFO"))
|
|
|
+ return !conn->have_sent_protocolinfo;
|
|
|
+ if (!strcasecmp(cmd, "AUTHENTICATE") ||
|
|
|
+ !strcasecmp(cmd, "QUIT"))
|
|
|
+ return 1;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
* commands from conn->inbuf, and execute them.
|
|
|
*/
|
|
@@ -2433,6 +2516,7 @@ connection_control_process_inbuf(control_connection_t *conn)
|
|
|
--data_len;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
if (!strcasecmp(conn->incoming_cmd, "QUIT")) {
|
|
|
connection_write_str_to_buf("250 closing connection\r\n", conn);
|
|
|
connection_mark_for_close(TO_CONN(conn));
|
|
@@ -2440,7 +2524,7 @@ connection_control_process_inbuf(control_connection_t *conn)
|
|
|
}
|
|
|
|
|
|
if (conn->_base.state == CONTROL_CONN_STATE_NEEDAUTH &&
|
|
|
- strcasecmp(conn->incoming_cmd, "AUTHENTICATE")) {
|
|
|
+ !is_valid_initial_command(conn, conn->incoming_cmd)) {
|
|
|
connection_write_str_to_buf("514 Authentication required.\r\n", conn);
|
|
|
connection_mark_for_close(TO_CONN(conn));
|
|
|
return 0;
|
|
@@ -2503,6 +2587,9 @@ connection_control_process_inbuf(control_connection_t *conn)
|
|
|
} else if (!strcasecmp(conn->incoming_cmd, "RESOLVE")) {
|
|
|
if (handle_control_resolve(conn, data_len, args))
|
|
|
return -1;
|
|
|
+ } else if (!strcasecmp(conn->incoming_cmd, "PROTOCOLINFO")) {
|
|
|
+ if (handle_control_protocolinfo(conn, data_len, args))
|
|
|
+ return -1;
|
|
|
} else {
|
|
|
connection_printf_to_buf(conn, "510 Unrecognized command \"%s\"\r\n",
|
|
|
conn->incoming_cmd);
|
|
@@ -3343,6 +3430,17 @@ control_event_guard(const char *nickname, const char *digest,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+static char *
|
|
|
+get_cookie_file(void)
|
|
|
+{
|
|
|
+ const char *datadir = get_options()->DataDirectory;
|
|
|
+ size_t len = strlen(datadir)+64;
|
|
|
+ char *fname = tor_malloc(len);
|
|
|
+ tor_snprintf(fname, len, "%s"PATH_SEPARATOR"control_auth_cookie", datadir);
|
|
|
+ return fname;
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
* Anybody who can read the cookie from disk will be considered
|
|
|
* authorized to use the control connection. Return -1 if we can't
|
|
@@ -3350,8 +3448,7 @@ control_event_guard(const char *nickname, const char *digest,
|
|
|
int
|
|
|
init_cookie_authentication(int enabled)
|
|
|
{
|
|
|
- char fname[512];
|
|
|
-
|
|
|
+ char *fname;
|
|
|
if (!enabled) {
|
|
|
authentication_cookie_is_set = 0;
|
|
|
return 0;
|
|
@@ -3362,17 +3459,18 @@ init_cookie_authentication(int enabled)
|
|
|
if (authentication_cookie_is_set)
|
|
|
return 0;
|
|
|
|
|
|
- tor_snprintf(fname, sizeof(fname), "%s"PATH_SEPARATOR"control_auth_cookie",
|
|
|
- get_options()->DataDirectory);
|
|
|
+ fname = get_cookie_file();
|
|
|
crypto_rand(authentication_cookie, AUTHENTICATION_COOKIE_LEN);
|
|
|
authentication_cookie_is_set = 1;
|
|
|
if (write_bytes_to_file(fname, authentication_cookie,
|
|
|
AUTHENTICATION_COOKIE_LEN, 1)) {
|
|
|
log_warn(LD_FS,"Error writing authentication cookie to %s.",
|
|
|
escaped(fname));
|
|
|
+ tor_free(fname);
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
+ tor_free(fname);
|
|
|
return 0;
|
|
|
}
|
|
|
|