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