[tor-commits] [arm/master] Added validation that torrc is wizard generated

atagar at torproject.org atagar at torproject.org
Sat Aug 6 23:39:14 UTC 2011


commit 8f313c620eeec6bfa3c5845fb5c3a7ff187f82ea
Author: Damian Johnson <atagar at torproject.org>
Date:   Wed Jul 27 07:44:34 2011 -0700

    Added validation that torrc is wizard generated
    
    Doing regex checks that the options match what the arm wizard would produce.
---
 src/resources/torrcOverride/override.py |   92 ++++++++++++++++++++++++++++---
 1 files changed, 83 insertions(+), 9 deletions(-)

diff --git a/src/resources/torrcOverride/override.py b/src/resources/torrcOverride/override.py
index 21e6b28..dffa3a5 100755
--- a/src/resources/torrcOverride/override.py
+++ b/src/resources/torrcOverride/override.py
@@ -29,6 +29,7 @@ pkill -sighup tor
 """
 
 import os
+import re
 import sys
 import grp
 import pwd
@@ -41,13 +42,40 @@ USER = "tor-arm"
 GROUP = "tor-arm"
 TOR_CONFIG_FILE = "/etc/tor/torrc"
 ARM_CONFIG_FILE = "/var/lib/tor-arm/torrc"
+RUN_VERIFY = True # use 'tor --verify-config' to check the torrc
+
+# regex patterns for options the wizard may include
+WIZARD_OPT = ("^DataDirectory \S+$",
+              "^Log notice file \S+$",
+              "^ControlPort 9052$",
+              "^CookieAuthentication 1$",
+              "^RunAsDaemon 1$",
+              "^User \S+$",
+              "^ORPort (443|9001)$",
+              "^DirPort (80|9030)$",
+              "^Nickname ",
+              "^ContactInfo ",
+              "^BridgeRelay 1$",
+              "^PublishServerDescriptor 0$",
+              "^RelayBandwidthRate ",
+              "^RelayBandwidthBurst ",
+              "^AccountingMax ",
+              "^SocksPort 0$",
+              "^PortForwarding 1$",
+              "^ExitPolicy (accept|reject) \S+$",
+              "^DirPortFrontPage \S+$",
+              "^ClientOnly 1$",
+              "^MaxCircuitDirtiness ",
+              "^UseBridges 1$",
+              "^Bridge ")
 
 HELP_MSG = """Usage %s [OPTION]
   Backup the system wide torrc (%s) and replace it with the
   contents of %s.
 
-  --init    creates the necessary user and paths
-  --remove  reverts changes made with --init
+  --init            creates the necessary user and paths
+  --remove          reverts changes made with --init
+  --validate PATH   checks if the given file is wizard generated
 """ % (os.path.basename(sys.argv[0]), TOR_CONFIG_FILE, ARM_CONFIG_FILE)
 
 def init():
@@ -196,27 +224,37 @@ def replaceTorrc():
     # man, unix is really weird...
     _, status = os.waitpid(fork_pid, 0)
   
-  if status != 0:
+  if status != 0 or not os.path.exists(tf.name):
     print "The child seems to have failed; exiting!"
     tf.close()
     sys.exit(1)
   
   # attempt to verify that the config is OK
-  if os.path.exists(tf.name):
-    # construct our SU string
-    SUSTRING = "su -c 'tor --verify-config -f " + str(tf.name) + "' " + USER
-    # We raise privs to drop them with 'su'
+  if RUN_VERIFY:
+    # raise privilages to drop them with 'su'
     os.setuid(0)
     os.seteuid(0)
     os.setgid(0)
     os.setegid(0)
-    # We drop privs here and exec tor to verify it as the dropped_uid 
+    
+    # drop privilages and exec tor to verify it as the dropped_uid 
     print "Using Tor to verify that arm will not break Tor's config:"
-    success = os.system(SUSTRING)
+    verifyCmd = "su -c 'tor --verify-config -f %s' %s" % (tf.name, USER)
+    success = os.system(verifyCmd)
+    
     if success != 0:
       print "Tor says the new configuration file is invalid: %s (%s)" % (ARM_CONFIG_FILE, tf.name)
       sys.exit(1)
   
+  # validates that the torrc matches what the wizard could produce
+  torrcFile = open(tf.name)
+  torrcContents = torrcFile.readlines()
+  torrcFile.close()
+  
+  if not isWizardGenerated(torrcContents):
+    print "torrc doesn't match what we'd expect from the setup wizard"
+    sys.exit(1)
+  
   # backup the previous tor config
   if os.path.exists(TOR_CONFIG_FILE):
     try:
@@ -243,6 +281,34 @@ def replaceTorrc():
   
   sys.exit(0)
 
+def isWizardGenerated(torrcLines):
+  """
+  True if the given torrc contents could be generated by the wizard, false
+  otherwise. This just checks the basic format and options used, not the
+  validity of most generated values so this could still be rejected by tor.
+  """
+  
+  wizardPatterns = [re.compile(opt) for opt in WIZARD_OPT]
+  
+  for line in torrcLines:
+    commentStart = line.find("#")
+    if commentStart != -1: line = line[:commentStart]
+    
+    line = line.strip()
+    if not line: continue # blank line
+    
+    isRecognized = False
+    for pattern in wizardPatterns:
+      if pattern.match(line):
+        isRecognized = True
+        break
+    
+    if not isRecognized:
+      print "Unrecognized torrc contents: %s" % line
+      return False
+  
+  return True
+
 if __name__ == "__main__":
   # sanity check that we're on linux
   if os.name != "posix":
@@ -260,6 +326,14 @@ if __name__ == "__main__":
     init()
   elif len(sys.argv) == 2 and sys.argv[1] == "--remove":
     remove()
+  elif len(sys.argv) == 3 and sys.argv[1] == "--validate":
+    torrcFile = open(sys.argv[2])
+    torrcContents = torrcFile.readlines()
+    torrcFile.close()
+    
+    isValid = isWizardGenerated(torrcContents)
+    if isValid: print "torrc validated"
+    else: print "torrc invalid"
   else:
     print HELP_MSG
     sys.exit(1)





More information about the tor-commits mailing list