diff options
author | Nick Mathewson <nickm@torproject.org> | 2007-08-16 17:31:23 +0000 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2007-08-16 17:31:23 +0000 |
commit | f4398feadb8e3c1af51a825ac0eafe5abc08683d (patch) | |
tree | ff141025989fb4a5ec45f6f64b426873a78d6c53 | |
parent | b89efa770596d9bac9a03e60b5ff26bb936c0eaa (diff) | |
download | tor-f4398feadb8e3c1af51a825ac0eafe5abc08683d.tar tor-f4398feadb8e3c1af51a825ac0eafe5abc08683d.tar.gz |
r14600@catbus: nickm | 2007-08-16 13:30:22 -0400
Implement proposal 119. Backport candidate.
svn:r11138
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | doc/spec/control-spec.txt | 58 | ||||
-rw-r--r-- | doc/spec/proposals/000-index.txt | 2 | ||||
-rw-r--r-- | doc/spec/proposals/119-controlport-auth.txt | 2 | ||||
-rw-r--r-- | src/or/control.c | 108 | ||||
-rw-r--r-- | src/or/or.h | 3 |
6 files changed, 169 insertions, 10 deletions
@@ -26,6 +26,12 @@ Changes in version 0.2.0.5-alpha - 2007-??-?? - Read v3 keys from the right location. - Numerous bugfixes to directory voting code. + o Minor features (controller): + - Add a PROTOCOLINFO controller command. Like AUTHENTICATE, it is valid + before any authentication has been received. It tells a controller + what kind of authentication is expected, and what protocol is spoken. + Implements proposal 119. + o Minor bugfixes (other): - If we require CookieAuthentication but we fail to write the cookie file, we would warn but not exit, and end up in a state diff --git a/doc/spec/control-spec.txt b/doc/spec/control-spec.txt index 1c0f85b6c..e102a552b 100644 --- a/doc/spec/control-spec.txt +++ b/doc/spec/control-spec.txt @@ -231,9 +231,11 @@ $Id$ The format of the 'cookie' is implementation-dependent; see 5.1 below for information on how the standard Tor implementation handles it. - If Tor requires authentication and the controller has not yet sent an - AUTHENTICATE message, Tor sends a "514 authentication required" reply to - any other kind of message, and then closes the connection. + Before the client has authenticated, no command other than PROTOCOLINFO, + AUTHENTICATE, or QUIT is valid. If the controller sends any other command, + or sends a malformed command, or sends an unsuccessful AUTHENTICATE + command, or sends PROTOCOLINFO more than once, Tor sends an error reply and + closes the connection. (Versions of Tor before 0.1.2.16 and 0.2.0.4-alpha did not close the connection after an authentication failure.) @@ -733,6 +735,56 @@ $Id$ [Added in Tor 0.2.0.3-alpha] +3.21. PROTOCOLINFO + + The syntax is: + "PROTOCOLINFO" *(SP PIVERSION) CRLF + + The server reply format is: + "250+PROTOCOLINFO" SP PIVERSION CRLF *InfoLine "250 OK" CRLF + + InfoLine = AuthLine / VersionLine / OtherLine + + AuthLine = "250-AUTH" SP "METHODS=" AuthMethod *(",")AuthMethod + *(SP "COOKIEFILE=" AuthCookieFile) CRLF + VersionLine = "250-VERSION" SP "Tor=" TorVersion [SP Arguments] CRLF + + AuthMethod = + "NULL" / ; No authentication is required + "HASHEDPASSWORD" / ; A controller must supply the original password + "COOKIE" / ; A controller must supply the contents of a cookie + + AuthCookieFile = QuotedString + TorVersion = QuotedString + + OtherLine = "250-" Keyword [SP Arguments] CRLF + + PIVERSION: 1*DIGIT + + Tor MAY give its InfoLines in any order; controllers MUST ignore InfoLines + with keywords it does not recognize. Controllers MUST ignore extraneous + data on any InfoLine. + + PIVERSION is there in case we drastically change the syntax one day. For + now it should always be "1", for the controller protocol. Controllers MAY + provide a list of the protocol versions they support; Tor MAY select a + version that the controller does not support. + + AuthMethod is used to specify one or more control authentication + methods that Tor currently accepts. + + AuthCookieFile specifies the absolute path and filename of the + authentication cookie that Tor is expecting and is provided iff + the METHODS field contains the method "COOKIE". Controllers MUST handle + escape sequences inside this string. + + The VERSION line contains the Tor version. + + [Unlike other commands besides AUTHENTICATE, PROTOCOLINFO may be used (but + only once!) before AUTHENTICATE.] + + [PROTOCOLINFO was not supported before Tor 0.2.0.5-alpha.] + 4. Replies Reply codes follow the same 3-character format as used by SMTP, with the diff --git a/doc/spec/proposals/000-index.txt b/doc/spec/proposals/000-index.txt index 3b1e8f46e..b2de017d0 100644 --- a/doc/spec/proposals/000-index.txt +++ b/doc/spec/proposals/000-index.txt @@ -37,5 +37,5 @@ Proposals by number: 116 Two hop paths from entry guards [OPEN] 117 IPv6 exits [OPEN] 118 Advertising multiple ORPorts at once [RESEARCH] -119 New PROTOCOLINFO command for controllers [ACCEPTED] +119 New PROTOCOLINFO command for controllers [CLOSED] 120 Suicide descriptors when Tor servers stop [OPEN] diff --git a/doc/spec/proposals/119-controlport-auth.txt b/doc/spec/proposals/119-controlport-auth.txt index 8dbe1c330..f248f6828 100644 --- a/doc/spec/proposals/119-controlport-auth.txt +++ b/doc/spec/proposals/119-controlport-auth.txt @@ -4,7 +4,7 @@ Version: $Revision$ Last-Modified: $Date$ Author: Roger Dingledine Created: 14-Aug-2007 -Status: Accepted +Status: Closd Overview: diff --git a/src/or/control.c b/src/or/control.c index d210428a4..5a256783d 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -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); /** Given a control event code for a message event, return the corresponding * log severity. */ @@ -2236,6 +2237,7 @@ handle_control_closecircuit(control_connection_t *conn, uint32_t len, return 0; } +/** DOCDOC */ 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; } +/** DOCDOC */ +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)); + /* Don't tolerate bad arguments when not authenticated. */ + 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; +} + /** Called when we get a USEFEATURE command: parse the feature list, and * set up the control_connection's options properly. */ static int @@ -2340,6 +2408,21 @@ connection_control_reached_eof(control_connection_t *conn) return 0; } +/** Return true iff <b>cmd</b> is allowable (or at least forgivable) at this + * 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; +} + /** Called when data has arrived on a v1 control connection: Try to fetch * commands from conn->inbuf, and execute them. */ @@ -2433,6 +2516,7 @@ connection_control_process_inbuf(control_connection_t *conn) --data_len; } + /* Quit is always valid. */ 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; } +/** DOCDOC */ +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; +} + /** 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 @@ -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; /* all set */ - 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; } diff --git a/src/or/or.h b/src/or/or.h index a0d9b087e..f7b77a336 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -994,6 +994,9 @@ typedef struct control_connection_t { * events as appropriate. */ unsigned int use_extended_events:1; + /** True if we have sent a protocolinfo reply on this connection. */ + unsigned int have_sent_protocolinfo:1; + uint32_t incoming_cmd_len; uint32_t incoming_cmd_cur_len; char *incoming_cmd; |