Browse Source

Allow multiple HashedControlPassword config lines, to support
multiple controller passwords.


svn:r12732

Roger Dingledine 17 years ago
parent
commit
6dfd47467e
5 changed files with 62 additions and 31 deletions
  1. 2 0
      ChangeLog
  2. 2 1
      doc/tor.1.in
  3. 7 2
      src/or/config.c
  4. 47 25
      src/or/control.c
  5. 4 3
      src/or/or.h

+ 2 - 0
ChangeLog

@@ -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

+ 2 - 1
doc/tor.1.in

@@ -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

+ 7 - 2
src/or/config.c

@@ -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,
   }
   }
 
 
   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) {

+ 47 - 25
src/or/control.c

@@ -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,
   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,
   }
   }
 
 
   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,
       }
       }
       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,
   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,
     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");

+ 4 - 3
src/or/or.h

@@ -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,
                         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);