Update of /cvsroot/tmda/tmda/contrib/cgi
In directory sc8-pr-cvs1:/tmp/cvs-serv20148

Modified Files:
        Session.py 
Log Message:
Major change:

Session.py now takes care of authenticating password forms and calling 
seteuid/setegid.

Bugfix:

Importing order had to be re-arranged since effective user is not known when
the script begins execution.

CGI_SESSION_PREFIX defined in a constant now since Defaults is loaded AFTER the 
value is needed.

REMOTE_ADDR is tested to prevent session hijacking.

Session now saves UID, GID, MiscUID, MiscGID, and HOME to keep from having to 
look these variables up all the time.

Minor change:

Merged Clean() into Save() to minimize user changes.


Index: Session.py
===================================================================
RCS file: /cvsroot/tmda/tmda/contrib/cgi/Session.py,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- Session.py  23 Nov 2002 06:16:05 -0000      1.1
+++ Session.py  25 Nov 2002 17:02:23 -0000      1.2
@@ -29,24 +29,31 @@
 import re
 import string
 import time
-
-os.environ["HOME"] = pwd.getpwuid(os.geteuid())[5]
+import Authenticate
 
 try:
-    import paths
+  import paths
 except ImportError:
-    pass
-
-from TMDA import Defaults
+  pass
 
 Rands = random.Random()
 
+# Constants
+CGI_SESSION_PREFIX = "/tmp/TMDASess."
+
 class Session:
   """Sessioning tool for use in CGI.
 
-Resurrect an old session by passing a form with the session ID (SID) into the
+Resurrect an old session by passing a form with the session ID (SID) into the 
 constructor.  An empty object will be created if the session has expired.  A new
-session will be created if the form does not specify an SID.
+session will be created if the form does not specify a (valid) SID.
+
+Instantiating a session will check Form["user"] and Form["password"] if they 
+exist to establish Session["UID"].  To check the validity of a session, test 
+Session.has_key("UID") before any action that might reveal sensative 
+information.
+
+Once a session is validated, the module will switch EUID to Session["UID"].
 
 The session's SID is saved as member SID.
 
@@ -57,41 +64,81 @@
   A.Save()
   print "http://some/url?SID=%s"; % A.SID
 
-The Save() member saves the session's current values on disk."""
+The Save() member saves the session's current values on disk, but can only be 
+called once a validated session has been established.  Writes are done as 
+CGI_USER, as specified in Defaults."""
   
   def __init__(self, Form):
     "Reload an existing SID or create a new one."
+    
+    global Defaults
 
-    # Existing session?
-    if Form.has_key("SID"):
+    # Existing, valid looking session?
+    if Form.has_key("SID") and \
+      re.compile("^[a-zA-Z0-9]{8}$").search(Form["SID"].value):
       self.SID = Form["SID"].value
 
-      # Valid looking session ID?
-      if re.compile("^[a-zA-Z0-9]{8}$").search(self.SID):
-        try:
-          F = open(Defaults.CGI_SESSION_PREFIX + self.SID)
-          self.Vars = pickle.load(F)
-          F.close()
-          self.Clean()
-          return
-        except:
-          pass
-      # Invalid ID
-      else: raise ValueError
+      # Resurrect session
+      try:
+        F = open(CGI_SESSION_PREFIX + self.SID)
+        self.Vars = pickle.load(F)
+        F.close()
+        os.environ["HOME"] = self.Vars["HOME"]
+        
+        # Now that we know who we are, get our defaults
+        from TMDA import Defaults
+        
+        # Make sure the session has not been hijacked
+        if os.environ["REMOTE_ADDR"] == self.Vars["IP"]: return
+      except: # Failed to resurrect session, fall through to make new SID
+        pass
+      
     # New session
     SessionChars = string.ascii_letters + string.digits
     self.SID = ""
     for i in range(8):
       self.SID += SessionChars[Rands.randrange(len(SessionChars))]
     self.Vars = {}
-    self.Clean()
 
-  def Clean(self):
-    "This member is called automatically.  You should not need to call it."
+    # Validate the new session?
+    try:
+      if Authenticate.CheckPassword(Form):
+        self.Vars["User"]  = Form["user"].value
+        PasswordRecord     = pwd.getpwnam(self.Vars["User"])
+        self.Vars["UID"]   = PasswordRecord[2]
+        self.Vars["GID"]   = PasswordRecord[3]
+        self.Vars["HOME"]  = PasswordRecord[5]
+        os.environ["HOME"] = self.Vars["HOME"]
+        self.Vars["IP"]    = os.environ["REMOTE_ADDR"]
+
+        # Now that we know who we are, get our defaults
+        from TMDA import Defaults
+
+        # Get misc user info
+        PasswordRecord  = pwd.getpwnam(Defaults.CGI_USER)
+        self.Vars["MiscUID"] = PasswordRecord[2]
+        self.Vars["MiscGID"] = PasswordRecord[3]
+
+        self.Save() # Save session & set user
+    except:
+      return
+
+  def Save(self):
+    """Save all session variables to disk and change user.  Possibly clean up 
+old sessions."""
+    # Change to CGI_USER
+    try:
+      os.seteuid(self.Vars["MiscUID"])
+      os.setegid(self.Vars["MiscGID"])
+    except: pass
+    F = open(CGI_SESSION_PREFIX + self.SID, "w")
+    pickle.dump(self.Vars, F)
+    F.close()
+
     # Clean up?
     if Rands.random() < Defaults.CGI_CLEANUP_ODDS:
       # Go through all sessions and check a-times
-      Sessions = glob.glob(Defaults.CGI_SESSION_PREFIX + "*")
+      Sessions = glob.glob(CGI_SESSION_PREFIX + "*")
       for Session in Sessions:
         try: # these commands could fail if another thread cleans simultaneously
           Stats = os.stat(Session)
@@ -99,12 +146,14 @@
           if Stats[7] + Defaults.CGI_SESSION_EXP < time.time():
             os.remove(Session)
         except: pass
-  
-  def Save(self):
-    "Save all session variables to disk."
-    F = open(Defaults.CGI_SESSION_PREFIX + self.SID, "w")
-    pickle.dump(self.Vars, F)
-    F.close()
+
+    # Change back to regular user
+    try:
+      os.seteuid(0)
+      os.setegid(0)
+      os.setegid(self.Vars["GID"])
+      os.seteuid(self.Vars["UID"])
+    except: pass
 
   def __contains__(self, a): return a in self.Vars
   def countOf(self): return len(self.Vars)

_______________________________________
tmda-cvs mailing list
http://tmda.net/lists/listinfo/tmda-cvs

Reply via email to