diff -urN Zope-2.5.1-src.orig/lib/Components/initgroups/initgroups.c Zope-2.5.1-src/lib/Components/initgroups/initgroups.c
--- Zope-2.5.1-src.orig/lib/Components/initgroups/initgroups.c	Wed Dec 31 19:00:00 1969
+++ Zope-2.5.1-src/lib/Components/initgroups/initgroups.c	Mon Mar 25 21:08:41 2002
@@ -0,0 +1,48 @@
+/*****************************************************************************
+
+  Copyright (c) 2002 Zope Corporation and Contributors. All Rights Reserved.
+  
+  This software is subject to the provisions of the Zope Public License,
+  Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+  THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+  WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+  FOR A PARTICULAR PURPOSE
+  
+ ****************************************************************************/
+
+#include "Python.h"
+
+#include <grp.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static PyObject *
+initgroups_initgroups(self, args)
+PyObject *self;
+PyObject *args;
+{
+	char *username;
+	gid_t gid;
+
+	if(!PyArg_ParseTuple(args, "sl", &username, &gid))
+		return NULL;
+
+	if(initgroups(username, gid) == -1)
+		return PyErr_SetFromErrno(PyExc_OSError);
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyMethodDef InitgroupsMethods[] = {
+	{"initgroups",	initgroups_initgroups,	METH_VARARGS},
+	{NULL,		NULL}
+};
+
+void
+initinitgroups()
+{
+	(void)Py_InitModule("initgroups", InitgroupsMethods);
+}
+
diff -urN Zope-2.5.1-src.orig/lib/python/Setup20 Zope-2.5.1-src/lib/python/Setup20
--- Zope-2.5.1-src.orig/lib/python/Setup20	Fri Feb 16 14:54:25 2001
+++ Zope-2.5.1-src/lib/python/Setup20	Mon Mar 25 20:52:46 2002
@@ -18,3 +18,5 @@
 
 
 zlib ../Components/zlib/zlib.c -I../Components/zlib ../Components/zlib/adler32.c ../Components/zlib/compress.c ../Components/zlib/crc32.c ../Components/zlib/gzio.c ../Components/zlib/uncompr.c ../Components/zlib/deflate.c ../Components/zlib/trees.c ../Components/zlib/zutil.c ../Components/zlib/inflate.c ../Components/zlib/infblock.c ../Components/zlib/inftrees.c ../Components/zlib/infcodes.c ../Components/zlib/infutil.c ../Components/zlib/inffast.c
+
+initgroups	../Components/initgroups/initgroups.c
diff -urN Zope-2.5.1-src.orig/z2.py Zope-2.5.1-src/z2.py
--- Zope-2.5.1-src.orig/z2.py	Wed Nov 28 10:50:49 2001
+++ Zope-2.5.1-src/z2.py	Mon Mar 25 21:01:28 2002
@@ -72,9 +72,9 @@
     
   -u username or uid number
   
-    The username to run ZServer as. You may want to run ZServer as 'nobody'
-    or some other user with limited resouces. The only works under Unix, and
-    if ZServer is started by root. The default is: %(UID)s
+    The username to run ZServer as.  You may want to run ZServer as
+    a dedicated user.  This only works under Unix, and if ZServer
+    is started as root, and is required in that case.
 
   -P [ipaddress:]number
 
@@ -250,8 +250,9 @@
 DNS_IP=''
 
 # User id to run ZServer as. Note that this only works under Unix, and if
-# ZServer is started by root.
-UID='nobody'
+# ZServer is started by root. This no longer defaults to 'nobody' since
+# that can lead to a Zope file compromise.
+UID=None
 
 # Log file location. If this is a relative path, then it is joined the
 # the 'var' directory.
@@ -473,6 +474,11 @@
     
     zdaemon.run(sys.argv, os.path.join(CLIENT_HOME, Zpid))
 
+def _warn_nobody():
+    zLOG.LOG("z2", zLOG.INFO, "Running Zope as 'nobody' can compromise " + \
+                              "your Zope files; consider using a " + \
+                              "dedicated user account for Zope") 
+
 try:
     # Import logging support
     import zLOG
@@ -650,47 +656,89 @@
                     hostname=address,
                     port=port)
 
-    # Try to set uid to "-u" -provided uid.
-    # Try to set gid to  "-u" user's primary group. 
-    # This will only work if this script is run by root.
-    try:
-        import pwd
-        try:
-            try:    UID = string.atoi(UID)
-            except: pass
-            gid = None
-            if type(UID) == type(""):
-                uid = pwd.getpwnam(UID)[2]
-                gid = pwd.getpwnam(UID)[3]
-            elif type(UID) == type(1):
-                uid = pwd.getpwuid(UID)[2]
-                gid = pwd.getpwuid(UID)[3]
-            else:
-                raise KeyError 
-            try:
-                if gid is not None:
-                    try:
-                        os.setgid(gid)
-                    except OSError:
-                        pass
-                os.setuid(uid)
-            except OSError:
-                pass
-        except KeyError:
-            zLOG.LOG("z2", zLOG.ERROR, ("can't find UID %s" % UID))
-    except:
-        pass
-
-
-
     # if it hasn't failed at this point, create a .pid file.
     if not READ_ONLY:
+        if os.path.exists(PID_FILE): os.unlink(PID_FILE)
         pf = open(PID_FILE, 'w')
         pid=str(os.getpid())
         try: pid=str(os.getppid())+' '+pid
         except: pass
         pf.write(pid)
         pf.close()
+
+    # Warn if we were started as nobody.
+    try:
+        import pwd
+        if os.getuid():
+            if pwd.getpwuid(os.getuid())[0] == 'nobody':
+                _warn_nobody()
+    except:
+        pass
+
+    # Drop root privileges if we have them, and do some sanity checking
+    # to make sure we're not starting with an obviously insecure setup.
+    try:
+        if os.getuid() == 0:
+            try:
+                import initgroups
+            except:
+                raise SystemExit, 'initgroups is required to safely setuid'
+            if UID == None:
+                raise SystemExit, 'A user was not specified to setuid ' + \
+                                  'to; fix this to start as root'
+            import stat
+            client_home_stat = os.stat(CLIENT_HOME)
+            client_home_faults = []
+            if not (client_home_stat[stat.ST_MODE]&01000):
+                client_home_faults.append('does not have the sticky bit set')
+            if client_home_stat[stat.ST_UID] != 0:
+                client_home_faults.append('is not owned by root')
+            if len(client_home_faults) > 0:
+                raise SystemExit, CLIENT_HOME + ' ' + \
+                                  string.join(client_home_faults, ', ') + \
+                                  '; fix this to start as root'
+            try:
+                try:    UID = string.atoi(UID)
+                except: pass
+                gid = None
+                if type(UID) == type(""):
+                    uid = pwd.getpwnam(UID)[2]
+                    gid = pwd.getpwnam(UID)[3]
+                elif type(UID) == type(1):
+                    uid = pwd.getpwuid(UID)[2]
+                    gid = pwd.getpwuid(UID)[3]
+                    UID = pwd.getpwuid(UID)[0]
+                else:
+                    raise KeyError 
+                if UID == 'nobody':
+                    _warn_nobody()
+                try:
+                    initgroups.initgroups(UID, gid)
+                    if gid is not None:
+                        try:
+                            os.setgid(gid)
+                        except OSError:
+                            pass
+                    os.setuid(uid)
+                except OSError:
+                    pass
+            except KeyError:
+                zLOG.LOG("z2", zLOG.ERROR, ("Can't find UID %s" % UID))
+    except AttributeError:
+        pass
+    except:
+        raise
+
+    # Check umask sanity.
+    if os.name == 'posix':
+        # umask is silly, blame POSIX.  We have to set it to get its value.
+        current_umask = os.umask(0)
+        os.umask(current_umask)
+        if current_umask != 077: 
+            current_umask = '%03o' % current_umask
+            zLOG.LOG("z2", zLOG.INFO, 'Your umask of ' + current_umask + \
+                     ' may be too permissive; for the security of your ' + \
+                     'Zope data, it is recommended you use 077')
 
 except:
     # Log startup exception and tell zdaemon not to restart us.
