Commit 6dfd4746 authored by Roger Dingledine's avatar Roger Dingledine
Browse files

Allow multiple HashedControlPassword config lines, to support

multiple controller passwords.


svn:r12732
parent 9b162ef4
...@@ -63,6 +63,8 @@ Changes in version 0.2.0.13-alpha - 2007-12-?? ...@@ -63,6 +63,8 @@ Changes in version 0.2.0.13-alpha - 2007-12-??
ask about source, timestamp of arrival, purpose, etc. We need ask about source, timestamp of arrival, purpose, etc. We need
something like this to help Vidalia not do GeoIP lookups on bridge something like this to help Vidalia not do GeoIP lookups on bridge
addresses. addresses.
- Allow multiple HashedControlPassword config lines, to support
multiple controller passwords.
Changes in version 0.2.0.12-alpha - 2007-11-16 Changes in version 0.2.0.12-alpha - 2007-11-16
......
...@@ -159,7 +159,8 @@ socket. (Unix and Unix-like systems only.) ...@@ -159,7 +159,8 @@ socket. (Unix and Unix-like systems only.)
Don't allow any connections on the control port except when the other process Don't allow any connections on the control port except when the other process
knows the password whose one-way hash is \fIhashed_password\fP. You can knows the password whose one-way hash is \fIhashed_password\fP. You can
compute the hash of a password by running "tor --hash-password compute the hash of a password by running "tor --hash-password
\fIpassword\fP". \fIpassword\fP". You can provide several acceptable passwords by using
more than HashedControlPassword line.
.LP .LP
.TP .TP
\fBCookieAuthentication \fR\fB0\fR|\fB1\fP \fBCookieAuthentication \fR\fB0\fR|\fB1\fP
......
...@@ -187,7 +187,7 @@ static config_var_t _option_vars[] = { ...@@ -187,7 +187,7 @@ static config_var_t _option_vars[] = {
V(FetchUselessDescriptors, BOOL, "0"), V(FetchUselessDescriptors, BOOL, "0"),
V(Group, STRING, NULL), V(Group, STRING, NULL),
V(HardwareAccel, BOOL, "0"), V(HardwareAccel, BOOL, "0"),
V(HashedControlPassword, STRING, NULL), V(HashedControlPassword, LINELIST, NULL),
V(HidServDirectoryV2, BOOL, "0"), V(HidServDirectoryV2, BOOL, "0"),
VAR("HiddenServiceDir", LINELIST_S, RendConfigLines, NULL), VAR("HiddenServiceDir", LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceExcludeNodes", LINELIST_S, RendConfigLines, NULL), VAR("HiddenServiceExcludeNodes", LINELIST_S, RendConfigLines, NULL),
...@@ -2939,8 +2939,13 @@ options_validate(or_options_t *old_options, or_options_t *options, ...@@ -2939,8 +2939,13 @@ options_validate(or_options_t *old_options, or_options_t *options,
} }
if (options->HashedControlPassword) { if (options->HashedControlPassword) {
if (decode_hashed_password(NULL, options->HashedControlPassword)<0) smartlist_t *sl = decode_hashed_passwords(options->HashedControlPassword);
if (!sl) {
REJECT("Bad HashedControlPassword: wrong length or bad encoding"); REJECT("Bad HashedControlPassword: wrong length or bad encoding");
} else {
SMARTLIST_FOREACH(sl, char*, cp, tor_free(cp));
smartlist_free(sl);
}
} }
if (options->ControlListenAddress) { if (options->ControlListenAddress) {
......
...@@ -912,29 +912,42 @@ handle_control_setevents(control_connection_t *conn, uint32_t len, ...@@ -912,29 +912,42 @@ handle_control_setevents(control_connection_t *conn, uint32_t len,
return 0; return 0;
} }
/** Decode the hashed, base64'd password stored in <b>hashed</b>. If /** Decode the hashed, base64'd passwords stored in <b>passwords</b>.
* <b>buf</b> is provided, store the hashed password in the first * Return a smartlist of acceptable passwords (unterminated strings of
* S2K_SPECIFIER_LEN+DIGEST_LEN bytes of <b>buf</b>. Return 0 on * length S2K_SPECIFIER_LEN+DIGEST_LEN) on success, or NULL on failure.
* success, -1 on failure.
*/ */
int smartlist_t *
decode_hashed_password(char *buf, const char *hashed) decode_hashed_passwords(config_line_t *passwords)
{ {
char decoded[64]; char decoded[64];
if (!strcmpstart(hashed, "16:")) { config_line_t *cl;
if (base16_decode(decoded, sizeof(decoded), hashed+3, strlen(hashed+3))<0 smartlist_t *sl = smartlist_create();
|| strlen(hashed+3) != (S2K_SPECIFIER_LEN+DIGEST_LEN)*2) {
return -1; tor_assert(passwords);
}
} else { for (cl = passwords; cl; cl = cl->next) {
if (base64_decode(decoded, sizeof(decoded), hashed, strlen(hashed)) const char *hashed = cl->value;
!= S2K_SPECIFIER_LEN+DIGEST_LEN) {
return -1; 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));
} }
if (buf)
memcpy(buf, decoded, S2K_SPECIFIER_LEN+DIGEST_LEN); return sl;
return 0;
err:
SMARTLIST_FOREACH(sl, char*, cp, tor_free(cp));
smartlist_free(sl);
return NULL;
} }
/** Called when we get an AUTHENTICATE message. Check whether the /** Called when we get an AUTHENTICATE message. Check whether the
...@@ -953,6 +966,7 @@ handle_control_authenticate(control_connection_t *conn, uint32_t len, ...@@ -953,6 +966,7 @@ handle_control_authenticate(control_connection_t *conn, uint32_t len,
const char *cp; const char *cp;
int i; int i;
int bad_cookie=0, bad_password=0; int bad_cookie=0, bad_password=0;
smartlist_t *sl = NULL;
if (TOR_ISXDIGIT(body[0])) { if (TOR_ISXDIGIT(body[0])) {
cp = body; cp = body;
...@@ -1013,10 +1027,10 @@ handle_control_authenticate(control_connection_t *conn, uint32_t len, ...@@ -1013,10 +1027,10 @@ handle_control_authenticate(control_connection_t *conn, uint32_t len,
} }
if (options->HashedControlPassword) { if (options->HashedControlPassword) {
char expected[S2K_SPECIFIER_LEN+DIGEST_LEN];
char received[DIGEST_LEN]; char received[DIGEST_LEN];
int also_cookie = options->CookieAuthentication; int also_cookie = options->CookieAuthentication;
if (decode_hashed_password(expected, options->HashedControlPassword)<0) { sl = decode_hashed_passwords(options->HashedControlPassword);
if (!sl) {
if (!also_cookie) { if (!also_cookie) {
log_warn(LD_CONTROL, log_warn(LD_CONTROL,
"Couldn't decode HashedControlPassword: invalid base16"); "Couldn't decode HashedControlPassword: invalid base16");
...@@ -1024,9 +1038,14 @@ handle_control_authenticate(control_connection_t *conn, uint32_t len, ...@@ -1024,9 +1038,14 @@ handle_control_authenticate(control_connection_t *conn, uint32_t len,
} }
bad_password = 1; bad_password = 1;
} else { } else {
secret_to_key(received,DIGEST_LEN,password,password_len,expected); SMARTLIST_FOREACH(sl, char *, expected,
if (!memcmp(expected+S2K_SPECIFIER_LEN, received, DIGEST_LEN)) {
goto ok; 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) if (used_quoted_string)
errstr = "Password did not match HashedControlPassword value from " errstr = "Password did not match HashedControlPassword value from "
...@@ -1060,6 +1079,10 @@ handle_control_authenticate(control_connection_t *conn, uint32_t len, ...@@ -1060,6 +1079,10 @@ handle_control_authenticate(control_connection_t *conn, uint32_t len,
send_control_done(conn); send_control_done(conn);
conn->_base.state = CONTROL_CONN_STATE_OPEN; conn->_base.state = CONTROL_CONN_STATE_OPEN;
tor_free(password); tor_free(password);
if (sl) { /* clean up */
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_free(sl);
}
return 0; return 0;
} }
...@@ -2435,8 +2458,7 @@ handle_control_protocolinfo(control_connection_t *conn, uint32_t len, ...@@ -2435,8 +2458,7 @@ handle_control_protocolinfo(control_connection_t *conn, uint32_t len,
char *esc_cfile = esc_for_log(cfile); char *esc_cfile = esc_for_log(cfile);
char *methods; char *methods;
{ {
int passwd = (options->HashedControlPassword != NULL) && int passwd = (options->HashedControlPassword != NULL);
strlen(options->HashedControlPassword);
smartlist_t *mlist = smartlist_create(); smartlist_t *mlist = smartlist_create();
if (cookies) if (cookies)
smartlist_add(mlist, (char*)"COOKIE"); smartlist_add(mlist, (char*)"COOKIE");
......
...@@ -2211,8 +2211,9 @@ typedef struct { ...@@ -2211,8 +2211,9 @@ typedef struct {
* interval before hibernation? 0 for "never * interval before hibernation? 0 for "never
* hibernate." */ * hibernate." */
char *HashedControlPassword; /**< Base64-encoded hash of a password for /** Base64-encoded hash of accepted passwords for the control system. */
* the control system. */ config_line_t *HashedControlPassword;
int CookieAuthentication; /**< Boolean: do we enable cookie-based auth for int CookieAuthentication; /**< Boolean: do we enable cookie-based auth for
* the control system? */ * the control system? */
char *CookieAuthFile; /**< Location of a cookie authentication file. */ char *CookieAuthFile; /**< Location of a cookie authentication file. */
...@@ -2920,7 +2921,7 @@ int control_event_guard(const char *nickname, const char *digest, ...@@ -2920,7 +2921,7 @@ int control_event_guard(const char *nickname, const char *digest,
const char *status); const char *status);
int init_cookie_authentication(int enabled); int init_cookie_authentication(int enabled);
int decode_hashed_password(char *buf, const char *hashed); smartlist_t *decode_hashed_passwords(config_line_t *passwords);
void disable_control_logging(void); void disable_control_logging(void);
void enable_control_logging(void); void enable_control_logging(void);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment