diff options
Diffstat (limited to '')
-rw-r--r-- | contrib/check_perms_grsecurity.py | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/contrib/check_perms_grsecurity.py b/contrib/check_perms_grsecurity.py new file mode 100644 index 00000000..7b27a19f --- /dev/null +++ b/contrib/check_perms_grsecurity.py @@ -0,0 +1,180 @@ +#! @PYTHON@ +# +# Copyright (C) 1998,1999,2000,2001,2002 by the Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +"""Fixes for running Mailman under the `secure-linux' patch or grsecurity. + +Run check_perms -f and only then check_perms_grsecurity.py -f +Note that you will have to re-run this script after a mailman upgrade and +that check_perms will undo part of what this script does + +If you use Solar Designer's secure-linux patch, it prevents a process from +linking (hard link) to a file it doesn't own. +Grsecurity (http://grsecurity.net/) can have the same restriction depending +on how it was built, including other restrictions like preventing you to run +a program if it is located in a directory writable by a non root user. + +As a result Mailman has to be changed so that the whole tree is owned by +Mailman, and the CGIs and some of the programs in the bin tree (the ones +that lock config.pck files) are SUID Mailman. The idea is that config.pck +files have to be owned by the mailman UID and only touched by programs that +are UID mailman. +At the same time, We have to make sure that at least 3 directories under +~mailman aren't writable by mailman: mail, cgi-bin, and bin + +Binary commands that are changed to be SUID mailman are also made unreadable +and unrunnable by people who aren't in the mailman group. This shouldn't +affect much since most of those commands would fail work if you weren't part +of the mailman group anyway. +Scripts in ~mailman/bin/ are not made suid or sgid, they need to be run by +user mailman or root to work. + +Marc <marc_soft@merlins.org>/<marc_bts@vasoftware.com> +2000/10/27 - Initial version for secure_linux/openwall and mailman 2.0 +2001/12/09 - Updated version for grsecurity and mailman 2.1 +""" + +import sys +import os +import paths +import re +import glob +import pwd +import grp +from Mailman import mm_cfg +from Mailman.mm_cfg import MAILMAN_USER, MAILMAN_GROUP +from stat import * + +# Directories that we don't want writable by mailman. +dirstochownroot= ( 'mail', 'cgi-bin', 'bin' ) + +# Those are the programs that we patch so that they insist being run under the +# mailman uid or as root. +binfilestopatch= ( 'add_members', 'change_pw', 'check_db', 'clone_member', + 'config_list', 'newlist', 'qrunner', 'remove_members', + 'rmlist', 'sync_members', 'update', 'withlist' ) + +def main(argv): + binpath = paths.prefix + '/bin/' + droplib = binpath + 'CheckFixUid.py' + + if len(argv) < 2 or argv[1] != "-f": + print __doc__ + sys.exit(1) + + print "Making select directories owned and writable by root only" + for dir in dirstochownroot: + dirpath = paths.prefix + '/' + dir + os.chown(dirpath, 0, MAILMAN_GID) + os.chmod(dirpath, 02755) + print dirpath + + print + + file = paths.prefix + '/data/last_mailman_version' + print "Making" + file + "owned by mailman (not root)" + uid = pwd.getpwnam(MAILMAN_USER)[2] + gid = grp.getgrnam(MAILMAN_GROUP)[2] + os.chown(file, uid, gid) + print + + if not os.path.exists(droplib): + print "Creating " + droplib + fp = open(droplib, 'w', 0644) + fp.write("""import sys +import os +import grp, pwd +from Mailman.mm_cfg import MAILMAN_USER, MAILMAN_GROUP + +class CheckFixUid: + if os.geteuid() == 0: + uid = pwd.getpwnam(MAILMAN_USER)[2] + gid = grp.getgrnam(MAILMAN_GROUP)[2] + os.setgid(gid) + os.setuid(uid) + if os.geteuid() != uid: + print "You need to run this script as root or mailman because it was configured to run" + print "on a linux system with a security patch which restricts hard links" + sys.exit() +""") + fp.close() + else: + print "Skipping creation of " + droplib + + + print "\nMaking cgis setuid mailman" + cgis = glob.glob(paths.prefix + '/cgi-bin/*') + + for file in cgis: + print file + os.chown(file, uid, gid) + os.chmod(file, 06755) + + print "\nMaking mail wrapper setuid mailman" + file= paths.prefix + '/mail/mailman' + os.chown(file, uid, gid) + os.chmod(file, 06755) + print file + + print "\nEnsuring that all config.db/pck files are owned by Mailman" + cdbs = glob.glob(paths.prefix + '/lists/*/config.db*') + cpcks = glob.glob(paths.prefix + '/lists/*/config.pck*') + + for file in cdbs + cpcks: + stat = os.stat(file) + if (stat[ST_UID] != uid or stat[ST_GID] != gid): + print file + os.chown(file, uid, gid) + + print "\nPatching mailman scripts to change the uid to mailman" + + for script in binfilestopatch: + filefd = open(script, "r") + file = filefd.readlines() + filefd.close() + + patched = 0 + try: + file.index("import CheckFixUid\n") + print "Not patching " + script + ", already patched" + except ValueError: + file.insert(file.index("import paths\n")+1, "import CheckFixUid\n") + for i in range(len(file)-1, 0, -1): + object=re.compile("^([ ]*)main\(").search(file[i]) + # Special hack to support patching of update + object2=re.compile("^([ ]*).*=[ ]*main\(").search(file[i]) + if object: + print "Patching " + script + file.insert(i, + object.group(1) + "CheckFixUid.CheckFixUid()\n") + patched=1 + break + if object2: + print "Patching " + script + file.insert(i, + object2.group(1) + "CheckFixUid.CheckFixUid()\n") + patched=1 + break + + if patched==0: + print "Warning, file "+script+" couldn't be patched." + print "If you use it, mailman may not function properly" + else: + filefd=open(script, "w") + filefd.writelines(file) + +main(sys.argv) |