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

Modified Files:
        Session.py compile tmda-cgi.c tmda-cgi.py 
Log Message:
Removed a potential security risk for users running in system-wide mode.


Index: Session.py
===================================================================
RCS file: /cvsroot/tmda/tmda/contrib/cgi/Session.py,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- Session.py  22 Feb 2003 15:45:45 -0000      1.7
+++ Session.py  25 Mar 2003 05:06:21 -0000      1.8
@@ -28,6 +28,7 @@
 import random
 import re
 import string
+import sys
 import time
 import CgiUtil
 import Authenticate
@@ -63,7 +64,36 @@
 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 __suid__(self, UID = None, GID = None):
+    """Try to change to a new user.
+
+Report an error if we can't, but should be able to."""
+    if os.environ["TMDA_CGI_MODE"] == "system-wide":
+      # If not specified, use misc. user info
+      if not UID or not GID:
+        PasswordRecord  = pwd.getpwnam(os.environ["TMDA_CGI_USER"])
+        UID = PasswordRecord[2]
+        GID = PasswordRecord[3]
+        if not UID:
+          CgiUtil.TermError("CGI_USER is UID 0.", """It is not safe to allow
+root to process session files.""", "set euid",
+            "CGI_USER = %s" % os.environ["TMDA_CGI_USER"], "Recompile CGI.")
+
+      try:
+        os.seteuid(0)
+        os.setegid(0)
+        os.setegid(GID)
+        os.seteuid(UID)
+      except OSError:
+        CgiUtil.TermError("Cannot SUID.", """File permissions on the CGI have
+been changed or the CGI is located in a nosuid partition.""", "set euid",
+          CgiUtil.FileDetails("CGI", sys.argv[0]),
+          """Recheck the CGI's permissions and owner.  The file permissions
+should be 4755 (-rwsr-xr-x) and the owner should be root.<br>Also check in which
+partition you placed the CGI.  You cannot run the CGI in system-wide mode if
+its partition is marked "nosuid" in /etc/fstab.""")
+
   def __init__(self, Form):
     "Reload an existing SID or create a new one."
     
@@ -76,12 +106,27 @@
 
       # Resurrect session
       try:
+        self.__suid__()
+        if os.stat(CGI_SESSION_PREFIX + self.SID).st_uid != os.geteuid():
+          CgiUtil.TermError("CGI_USER does not own session file.",
+            "Something suspicious is going on here.  This should not happen.",
+            "open file",
+            CgiUtil.FileDetails("Session data", CGI_SESSION_PREFIX + self.SID),
+            "No recommendation.")
         F = open(CGI_SESSION_PREFIX + self.SID)
         self.Vars = pickle.load(F)
         F.close()
+        self.__suid__(self.Vars["UID"], self.Vars["GID"])
         os.environ["HOME"] = self.Vars["HOME"]
         os.environ["USER"] = self.Vars["User"]
         
+        # Make sure the session has not been hijacked
+        if os.environ["REMOTE_ADDR"] != self.Vars["IP"]:
+          CgiUtil.TermError("User's IP address has changed.",
+            "Your IP address has changed. This is not allowed.",
+            "read session data", "%s->%s" %
+            (self.Vars["IP"], os.environ["REMOTE_ADDR"]), "Log back in.")
+        
         # Is there a TMDARC variable?
         if os.environ.has_key("TMDARC"):
           # Yes, replace it
@@ -90,11 +135,9 @@
         
         # 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 IOError: # Failed to resurrect session, fall through to make new SID
         pass
+      return
       
     # New session
     SessionChars = string.ascii_letters + string.digits
@@ -118,6 +161,7 @@
       PasswordRecord     = pwd.getpwnam(self.Vars["User"])
       self.Vars["UID"]   = PasswordRecord[2]
       self.Vars["GID"]   = PasswordRecord[3]
+      self.__suid__(self.Vars["UID"], self.Vars["GID"])
       self.Vars["HOME"]  = PasswordRecord[5]
       os.environ["USER"] = self.Vars["User"]
       os.environ["HOME"] = self.Vars["HOME"]
@@ -126,6 +170,7 @@
 
       # Now that we know who we are, get our defaults
       from TMDA import Defaults
+      self.Vars["CLEANUP"] = Defaults.CGI_CLEANUP_ODDS;
 
       # Test CGI_ACTIVE
       if not Defaults.CGI_ACTIVE:
@@ -137,22 +182,12 @@
           """Add <tt>CGI_ACTIVE = 1</tt> to one of the configuration files or
 modify<br>file permissions to allow them to be read.""")
 
-      # 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
 
   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 OSError:
-      pass
+    self.__suid__()
     try:
       F = open(CGI_SESSION_PREFIX + self.SID, "w")
       pickle.dump(self.Vars, F)
@@ -166,10 +201,10 @@
         """Add <tt>CGI_USER = "UserName"</tt> to one of the configuration files
 or modify<br>file permissions to allow them to be read.  For <tt>UserName</tt>,
 use the user name<br>configured into your web server.  For Apache, look for the
-<tt>User</tt> directive.""")
+<tt>User</tt> directive.  You may need to recompile the CGI.""")
 
     # Clean up?
-    if Rands.random() < Defaults.CGI_CLEANUP_ODDS:
+    if Rands.random() < self.Vars["CLEANUP"]:
       # Go through all sessions and check a-times
       Sessions = glob.glob(CGI_SESSION_PREFIX + "*")
       for Session in Sessions:
@@ -182,13 +217,7 @@
           pass
 
     # Change back to regular user
-    try:
-      os.seteuid(0)
-      os.setegid(0)
-      os.setegid(self.Vars["GID"])
-      os.seteuid(self.Vars["UID"])
-    except OSError:
-      pass
+    self.__suid__(self.Vars["UID"], self.Vars["GID"])
 
   def __contains__(self, a): return a in self.Vars
   def countOf(self): return len(self.Vars)

Index: compile
===================================================================
RCS file: /cvsroot/tmda/tmda/contrib/cgi/compile,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- compile     24 Mar 2003 22:55:59 -0000      1.10
+++ compile     25 Mar 2003 05:06:22 -0000      1.11
@@ -53,6 +53,11 @@
     --target <file>
        Compile as a file other than ./tmda-cgi.
 
+    -u <user>
+    --user <user>
+       Overrides the value of CGI_USER found in the configuration files.
+       (Only affects system-wide mode.)
+
 By default, this program compiles tmda-cgi in the current directory and sets
 the program to run as the user who compiled it.  If that user is root, the
 resulting CGI will run in system-wide mode.  Otherwise it will run in single-
@@ -84,10 +89,19 @@
 
 import getopt
 import os.path
+import pwd
 import re
 import string
 import sys
 
+import paths
+User = None
+try:
+  import Defaults
+  User = Defaults.CGI_USER
+except ImportError:
+  pass
+
 Program = sys.argv[0]
 Target  = "tmda-cgi"
 Perm    = 04755
@@ -104,9 +118,9 @@
   sys.exit(Code)
 
 try:
-  Opts, Args = getopt.getopt(sys.argv[1:], "c:d:i:m:nht:",
+  Opts, Args = getopt.getopt(sys.argv[1:], "c:d:i:m:nht:u:",
     ["config-file=", "display-dir=", "help", "install-prefix=", "mode=",
-     "no-su", "target="])
+     "no-su", "target=", "user="])
 except getopt.error, Msg:
   Usage(1, Msg)
 
@@ -132,6 +146,8 @@
   elif Opt in ("-n", "--no-su"):
     Perm = 0755
     Mode = "no-su"
+  elif Opt in ("-u", "--user"):
+    User = Arg
 
 # Check that we're running in Python version 2.1 or higher
 if sys.version.split()[0] < '2.1':
@@ -151,6 +167,23 @@
 when tmda-cgi is run."""
   sys.exit()
 
+# Check that User is valid and unprivileged (system-wide mode only).
+if Mode == "system-wide":
+  if not User:
+    print """Compile terminated.  System-wide mode requires that you specify a non-
+privileged CGI_USER in either a configuration file or with the -u option."""
+    sys.exit()
+  try:
+    if not pwd.getpwnam(User)[2]:
+      print """Compile terminated.  CGI_USER may not be root.  Please specify a non-
+privileged user with the -u option."""
+      sys.exit()
+  except KeyError:
+    print """Compile terminated.  System-wide mode requires that you specify a real, 
non-
+privileged CGI_USER in either a configuration file or with the -u option."""
+    sys.exit()
+
+
 Path = os.path.abspath(Path)
 
 # Create dirs.h
@@ -158,8 +191,9 @@
 F.write("""#define PYTHON "%s"
 #define INSTALL "%s"
 #define MODE "TMDA_CGI_MODE=%s"
+#define USER "TMDA_CGI_USER=%s"
 #define DISP_DIR "TMDA_CGI_DISP_DIR=%s"
-""" % (sys.executable, Path, Mode, DispDir))
+""" % (sys.executable, Path, Mode, User, DispDir))
 if os.environ.has_key("TMDARC"):
   TMDARC = os.environ["TMDARC"]
   if TMDARC.find("~") < 0:

Index: tmda-cgi.c
===================================================================
RCS file: /cvsroot/tmda/tmda/contrib/cgi/tmda-cgi.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- tmda-cgi.c  19 Feb 2003 21:26:16 -0000      1.6
+++ tmda-cgi.c  25 Mar 2003 05:06:23 -0000      1.7
@@ -29,6 +29,7 @@
   putenv(TMDARC);
 #endif
   putenv(MODE);
+  putenv(USER);
   putenv(DISP_DIR);
 
   if (!chdir(INSTALL))

Index: tmda-cgi.py
===================================================================
RCS file: /cvsroot/tmda/tmda/contrib/cgi/tmda-cgi.py,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- tmda-cgi.py 24 Mar 2003 21:54:03 -0000      1.8
+++ tmda-cgi.py 25 Mar 2003 05:06:23 -0000      1.9
@@ -31,11 +31,11 @@
   Pending.Show()
     Form:  [user, password], cmd=view, [subcmd=first|prev|next|last|batch]
            [a#=X|r|d|w|b, m#]
-    PVars: UID, GID, MiscUID, MiscGID, User, HOME, SortDir, Pager
+    PVars: UID, GID, User, HOME, SortDir, Pager
   View.Show()
     Form:  cmd=view, [subcmd=first|prev|next|last|delete|release|white|black],
            [headers=short|all], [msgid]
-    PVars: UID, GID, MiscUID, MiscGID, User, HOME, Headers, MsgID
+    PVars: UID, GID, User, HOME, Headers, MsgID
 """
 
 print "Content-type: text/html\n"

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

Reply via email to