[tor-commits] [arm/master] Dropping the TorCtl connection completely

atagar at torproject.org atagar at torproject.org
Mon Dec 17 04:25:17 UTC 2012


commit 2cea89cad359352ff2a78988e5647a728516f65f
Author: Damian Johnson <atagar at torproject.org>
Date:   Sun Dec 16 19:46:49 2012 -0800

    Dropping the TorCtl connection completely
    
    Removing the TorCtl connection from arm. Barring some lingering imports we
    should now be able to drop the library from arm. Yay!
---
 src/cli/controller.py  |   27 +++--------
 src/cli/headerPanel.py |   27 ++--------
 src/starter.py         |  122 ++++++++++-------------------------------------
 src/util/torTools.py   |   29 ++++++------
 4 files changed, 53 insertions(+), 152 deletions(-)

diff --git a/src/cli/controller.py b/src/cli/controller.py
index 9c3a4eb..f01ef8a 100644
--- a/src/cli/controller.py
+++ b/src/cli/controller.py
@@ -543,26 +543,13 @@ class TorManager:
     unsuccessful.
     """
     
-    torctlConn, authType, authValue = TorCtl.preauth_connect(controlPort = int(CONFIG["wizard.default"]["Control"]))
-    
-    if not torctlConn:
-      msg = "Unable to start tor, try running \"tor -f %s\" to see the error output" % self.getTorrcPath()
-      raise IOError(msg)
-    
-    if authType == TorCtl.AUTH_TYPE.COOKIE:
-      try:
-        authCookieSize = os.path.getsize(authValue)
-        if authCookieSize != 32:
-          raise IOError("authentication cookie '%s' is the wrong size (%i bytes instead of 32)" % (authValue, authCookieSize))
-        
-        torctlConn.authenticate(authValue)
-        
-        controller = Controller.from_port(control_port = int(CONFIG["wizard.default"]["Control"]))
-        controller.authenticate()
-        
-        torTools.getConn().init(torctlConn, controller)
-      except Exception, exc:
-        raise IOError("Unable to connect to Tor: %s" % exc)
+    try:
+      controller = Controller.from_port(control_port = int(CONFIG["wizard.default"]["Control"]))
+      controller.authenticate()
+      
+      torTools.getConn().init(controller)
+    except Exception, exc:
+      raise IOError("Unable to connect to Tor: %s" % exc)
 
 def shutdownDaemons():
   """
diff --git a/src/cli/headerPanel.py b/src/cli/headerPanel.py
index c9541c4..ce43e06 100644
--- a/src/cli/headerPanel.py
+++ b/src/cli/headerPanel.py
@@ -138,25 +138,23 @@ class HeaderPanel(panel.Panel, threading.Thread):
     if key in (ord('n'), ord('N')) and torTools.getConn().isNewnymAvailable():
       self.sendNewnym()
     elif key in (ord('r'), ord('R')) and not self._isTorConnected:
-      torctlConn, controller = None, None
+      controller = None
       allowPortConnection, allowSocketConnection, _ = starter.allowConnectionTypes()
       
       if os.path.exists(self._config["startup.interface.socket"]) and allowSocketConnection:
         try:
-          torctlConn = torTools.connect_socket(self._config["startup.interface.socket"])
-          
           # TODO: um... what about passwords?
           controller = Controller.from_socket_file(self._config["startup.interface.socket"])
           controller.authenticate()
         except (IOError, stem.SocketError), exc:
-          torctlConn, controller = None, None
+          controller = None
           
           if not allowPortConnection:
             cli.popups.showMsg("Unable to reconnect (%s)" % exc, 3)
       elif not allowPortConnection:
         cli.popups.showMsg("Unable to reconnect (socket '%s' doesn't exist)" % self._config["startup.interface.socket"], 3)
       
-      if not torctlConn and allowPortConnection:
+      if not controller and allowPortConnection:
         # TODO: This has diverged from starter.py's connection, for instance it
         # doesn't account for relative cookie paths or multiple authentication
         # methods. We can't use the starter.py's connection function directly
@@ -165,19 +163,6 @@ class HeaderPanel(panel.Panel, threading.Thread):
         
         try:
           ctlAddr, ctlPort = self._config["startup.interface.ipAddress"], self._config["startup.interface.port"]
-          tmpConn, authType, authValue = TorCtl.TorCtl.preauth_connect(ctlAddr, ctlPort)
-          
-          if authType == TorCtl.TorCtl.AUTH_TYPE.PASSWORD:
-            authValue = cli.popups.inputPrompt("Controller Password: ")
-            if not authValue: raise IOError() # cancel reconnection
-          elif authType == TorCtl.TorCtl.AUTH_TYPE.COOKIE:
-            authCookieSize = os.path.getsize(authValue)
-            if authCookieSize != 32:
-              raise IOError("authentication cookie '%s' is the wrong size (%i bytes instead of 32)" % (authValue, authCookieSize))
-          
-          tmpConn.authenticate(authValue)
-          torctlConn = tmpConn
-          
           controller = Controller.from_port(ctlAddr, ctlPort)
           
           try:
@@ -185,7 +170,7 @@ class HeaderPanel(panel.Panel, threading.Thread):
           except stem.connection.MissingPassword:
             controller.authenticate(authValue) # already got the password above
         except Exception, exc:
-          torctlConn, controller = None, None
+          controller = None
           
           # attempts to use the wizard port too
           try:
@@ -196,8 +181,8 @@ class HeaderPanel(panel.Panel, threading.Thread):
             # displays notice for the first failed connection attempt
             if exc.args: cli.popups.showMsg("Unable to reconnect (%s)" % exc, 3)
       
-      if torctlConn and controller:
-        torTools.getConn().init(torctlConn, controller)
+      if controller:
+        torTools.getConn().init(controller)
         log.log(log.NOTICE, "Reconnected to Tor's control port")
         cli.popups.showMsg("Tor reconnected", 1)
     else: isKeystrokeConsumed = False
diff --git a/src/starter.py b/src/starter.py
index 8b2bbb3..01a6086 100644
--- a/src/starter.py
+++ b/src/starter.py
@@ -29,10 +29,8 @@ import util.torInterpretor
 import util.torTools
 import util.uiTools
 
-import TorCtl.TorCtl
-import TorCtl.TorUtil
-
 from stem.control import Controller
+import stem.connection
 
 LOG_DUMP_PATH = os.path.expanduser("~/.arm/log")
 DEFAULT_CONFIG = os.path.expanduser("~/.arm/armrc")
@@ -207,90 +205,27 @@ def _loadConfigurationDescriptions(pathPrefix):
         msg = DESC_INTERNAL_LOAD_FAILED_MSG % util.sysTools.getFileErrorMsg(exc)
         util.log.log(CONFIG["log.configDescriptions.internalLoadFailed"], msg)
 
-def _torCtlConnect(controlAddr="127.0.0.1", controlPort=9051, passphrase=None, incorrectPasswordMsg="", printError=True):
+def _getController(controlAddr="127.0.0.1", controlPort=9051, passphrase=None, incorrectPasswordMsg="", printError=True):
   """
-  Custom handler for establishing a TorCtl connection.
+  Custom handler for establishing a stem connection (... needs an overhaul).
   """
   
-  conn, controller = None, None
+  controller = None
   try:
-    #conn, authType, authValue = TorCtl.TorCtl.preauth_connect(controlAddr, controlPort)
-    conn, authTypes, authValue = util.torTools.preauth_connect_alt(controlAddr, controlPort)
-    
-    if TorCtl.TorCtl.AUTH_TYPE.PASSWORD in authTypes:
-      # password authentication, promting for the password if it wasn't provided
-      #
-      # TODO: When handling multi-auth we should try to authenticate via the
-      # cookie first, then fall back to prompting the user for their password.
-      # With the stack of fixes and hacks we have here jerry-rigging that in
-      # without trying cookie auth twice will be a pita so leaving this alone
-      # for now. Stem will handle most of this transparently, letting us handle
-      # this much more elegantly.
-      
-      if not passphrase:
-        try: passphrase = getpass.getpass("Controller password: ")
-        except KeyboardInterrupt: return None, None
-    
-    if TorCtl.TorCtl.AUTH_TYPE.COOKIE in authTypes and authValue[0] != "/":
-      # Connecting to the control port will probably fail if it's using cookie
-      # authentication and the cookie path is relative (unfortunately this is
-      # the case for TBB). This is discussed in:
-      # https://trac.torproject.org/projects/tor/ticket/1101
-      #
-      # This is best effort. If we can't expand the path then it's still
-      # attempted since we might be running in tor's pwd.
-      
-      torPid = util.torTools.getPid(controlPort)
-      if torPid:
-        try: conn._cookiePath = util.sysTools.expandRelativePath(authValue, torPid)
-        except IOError: pass
+    chroot = util.torTools.getConn().getPathPrefix()
+    controller = Controller.from_port(controlAddr, controlPort)
     
-    # appends the path prefix if it's set
-    if TorCtl.TorCtl.AUTH_TYPE.COOKIE in authTypes:
-      pathPrefix = util.torTools.getConn().getPathPrefix()
-      
-      # The os.path.join function is kinda stupid. If given an absolute path
-      # with the second argument then it will swallow the prefix. Ie...
-      # os.path.join("/tmp", "/foo") => "/foo"
-      
-      if pathPrefix:
-        pathSuffix = conn._cookiePath
-        if pathSuffix.startswith("/"): pathSuffix = pathSuffix[1:]
-        
-        conn._cookiePath = os.path.join(pathPrefix, pathSuffix)
-      
-      # Abort if the file isn't 32 bytes long. This is to avoid exposing
-      # arbitrary file content to the port.
-      #
-      # Without this a malicious socket could, for instance, claim that
-      # '~/.bash_history' or '~/.ssh/id_rsa' was its authentication cookie to
-      # trick us into reading it for them with our current permissions.
-      #
-      # https://trac.torproject.org/projects/tor/ticket/4305
-      
+    try:
+      controller.authenticate(password = passphrase, chroot_path = chroot)
+    except stem.connection.MissingPassword:
       try:
-        authCookieSize = os.path.getsize(conn._cookiePath)
-        if authCookieSize != 32:
-          raise IOError("authentication cookie '%s' is the wrong size (%i bytes instead of 32)" % (conn._cookiePath, authCookieSize))
-      except Exception, exc:
-        # if the above fails then either...
-        # - raise an exception if cookie auth is the only method we have to
-        #   authenticate
-        # - suppress the exception and try the other connection methods if we
-        #   have alternatives
-        if len(authTypes) == 1: raise exc
-        else: conn._authTypes.remove(TorCtl.TorCtl.AUTH_TYPE.COOKIE)
-    
-    conn.authenticate(passphrase)
-    
-    # Damn well everything above this is covered by stem. :P
+        passphrase = getpass.getpass("Controller password: ")
+        controller.authenticate(password = passphrase, chroot_path = chroot)
+      except:
+        return None
     
-    controller = Controller.from_port(controlAddr, controlPort)
-    controller.authenticate(password = passphrase, chroot_path = util.torTools.getConn().getPathPrefix())
-    
-    return conn, controller
+    return controller
   except Exception, exc:
-    if conn: conn.close()
     if controller: controller.close()
     
     # attempts to connect with the default wizard address too
@@ -304,19 +239,19 @@ def _torCtlConnect(controlAddr="127.0.0.1", controlPort=9051, passphrase=None, i
       # connection failure. Otherwise, return the connection result.
       
       if controlPort != wizardPort:
-        connResult, controller = _torCtlConnect(controlAddr, wizardPort)
-        if connResult != None: return connResult, controller
-      else: return None, None # wizard connection attempt, don't print anything
+        controller = _getController(controlAddr, wizardPort)
+        if controller != None: return controller
+      else: return None # wizard connection attempt, don't print anything
     
     if passphrase and str(exc) == "Unable to authenticate: password incorrect":
       # provide a warning that the provided password didn't work, then try
       # again prompting for the user to enter it
       print incorrectPasswordMsg
-      return _torCtlConnect(controlAddr, controlPort)
+      return _getController(controlAddr, controlPort)
     elif printError:
       print exc
     
-    return None, None
+    return None
 
 def _dumpConfig():
   """
@@ -488,21 +423,16 @@ if __name__ == '__main__':
       print "Unrecognized event flag: %s" % flag
     sys.exit()
   
-  # temporarily disables TorCtl logging to prevent issues from going to stdout while starting
-  TorCtl.TorUtil.loglevel = "NONE"
-  
   # By default attempts to connect using the control socket if it exists. This
   # skips attempting to connect by socket or port if the user has given
   # arguments for connecting to the other.
   
-  conn, controller = None, None
+  controller = None
   allowPortConnection, allowSocketConnection, allowDetachedStart = allowConnectionTypes()
   
   socketPath = param["startup.interface.socket"]
   if os.path.exists(socketPath) and allowSocketConnection:
     try:
-      conn = util.torTools.connect_socket(socketPath)
-      
       # TODO: um... what about passwords?
       # https://trac.torproject.org/6881
       
@@ -514,12 +444,12 @@ if __name__ == '__main__':
   elif not allowPortConnection:
     print "Socket '%s' doesn't exist" % socketPath
   
-  if (not conn or not controller) and allowPortConnection:
-    # sets up TorCtl connection, prompting for the passphrase if necessary and
+  if not controller and allowPortConnection:
+    # sets up stem connection, prompting for the passphrase if necessary and
     # sending problems to stdout if they arise
     authPassword = config.get("startup.controlPassword", CONFIG["startup.controlPassword"])
     incorrectPasswordMsg = "Password found in '%s' was incorrect" % configPath
-    conn, controller = _torCtlConnect(controlAddr, controlPort, authPassword, incorrectPasswordMsg, not allowDetachedStart)
+    controller = _getController(controlAddr, controlPort, authPassword, incorrectPasswordMsg, not allowDetachedStart)
     
     # removing references to the controller password so the memory can be freed
     # (unfortunately python does allow for direct access to the memory so this
@@ -537,7 +467,7 @@ if __name__ == '__main__':
       if pwLineNum != None:
         del config.rawContents[i]
   
-  if (conn is None or controller is None) and not allowDetachedStart: sys.exit(1)
+  if controller is None and not allowDetachedStart: sys.exit(1)
   
   # initializing the connection may require user input (for the password)
   # skewing the startup time results so this isn't counted
@@ -545,8 +475,8 @@ if __name__ == '__main__':
   controllerWrapper = util.torTools.getConn()
   
   torUser = None
-  if conn and controller:
-    controllerWrapper.init(conn, controller)
+  if controller:
+    controllerWrapper.init(controller)
     
     # give a notice if tor is running with root
     torUser = controllerWrapper.getMyUser()
diff --git a/src/util/torTools.py b/src/util/torTools.py
index 5ac29ea..0357b32 100644
--- a/src/util/torTools.py
+++ b/src/util/torTools.py
@@ -483,7 +483,6 @@ class Controller(TorCtl.PostEventListener):
   
   def __init__(self):
     TorCtl.PostEventListener.__init__(self)
-    self.conn = None                    # None if uninitialized or controller's been closed
     self.controller = None
     self.connLock = threading.RLock()
     self.statusListeners = []           # callback functions for tor's state changes
@@ -522,25 +521,22 @@ class Controller(TorCtl.PostEventListener):
     # cached parameters for custom getters (None if unset or possibly changed)
     self._cachedParam = {}
   
-  def init(self, conn, controller):
+  def init(self, controller):
     """
     Uses the given TorCtl instance for future operations, notifying listeners
     about the change.
     
     Arguments:
-      conn - TorCtl instance to be used
       controller - stem based Controller instance
     """
     
     # TODO: We should reuse our controller instance so event listeners will be
     # re-attached. This is a point of regression until we do... :(
     
-    if conn.is_live() and controller.is_alive() and conn != self.conn:
+    if controller.is_alive() and controller != self.controller:
       self.connLock.acquire()
       
-      if self.conn: self.close() # shut down current connection
-      self.conn = conn
-      
+      if self.controller: self.close() # shut down current connection
       self.controller = controller
       log.log(log.INFO, "Stem connected to tor version %s" % self.controller.get_version())
       
@@ -583,10 +579,7 @@ class Controller(TorCtl.PostEventListener):
     """
     
     self.connLock.acquire()
-    if self.conn:
-      self.conn.close()
-      self.conn = None
-      
+    if self.controller:
       self.controller.close()
       self.controller = None
       
@@ -610,8 +603,8 @@ class Controller(TorCtl.PostEventListener):
     self.connLock.acquire()
     
     result = False
-    if self.conn:
-      if self.conn.is_live() and self.controller.is_alive(): result = True
+    if self.controller:
+      if self.controller.is_alive(): result = True
       else: self.close()
     
     self.connLock.release()
@@ -622,7 +615,10 @@ class Controller(TorCtl.PostEventListener):
     Provides the time of the last registered tor message.
     """
     
-    return self.controller.get_latest_heartbeat()
+    if self.isAlive():
+      return self.controller.get_latest_heartbeat()
+    else:
+      return 0
   
   def getInfo(self, param, default = UNDEFINED):
     """
@@ -912,7 +908,10 @@ class Controller(TorCtl.PostEventListener):
     false otherwise.
     """
     
-    return self.controller.is_geoip_unavailable()
+    if self.isAlive():
+      return self.controller.is_geoip_unavailable()
+    else:
+      return False
   
   def getMyPid(self):
     """





More information about the tor-commits mailing list