Compare commits

...

No commits in common. "c10s" and "c8-stream-2.1" have entirely different histories.

31 changed files with 2433 additions and 12 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
SOURCES/mailman-2.1.30.tgz

1
.mailman.metadata Normal file
View File

@ -0,0 +1 @@
01f3c33d057b771fd9bac3684f2f9be1d1000254 SOURCES/mailman-2.1.30.tgz

View File

@ -1,3 +0,0 @@
# Package Not Available
This package is not available on CentOS Stream 10.
It may be available on another branch.

View File

@ -0,0 +1,24 @@
#
# httpd configuration settings for use with mailman.
#
ScriptAlias /mailman/ @MMDIR@/cgi-bin/
<Directory @MMDIR@/cgi-bin/>
AllowOverride None
Options ExecCGI
Require all granted
</Directory>
Alias /pipermail/ @VARMMDIR@/archives/public/
<Directory @VARMMDIR@/archives/public>
Options MultiViews FollowSymLinks
AllowOverride None
Require all granted
AddDefaultCharset Off
</Directory>
# Uncomment the following line, replacing www.example.com with your server's
# name, to redirect queries to /mailman to the listinfo page (recommended).
# RedirectMatch ^/mailman[/]*$ http://www.example.com/mailman/listinfo

View File

@ -0,0 +1,715 @@
diff --git a/Mailman/Archiver/Makefile.in b/Mailman/Archiver/Makefile.in
index 65e46cb..dc3a1c6 100644
--- a/Mailman/Archiver/Makefile.in
+++ b/Mailman/Archiver/Makefile.in
@@ -28,7 +28,6 @@ exec_prefix= @exec_prefix@
DESTDIR=
CC= @CC@
-CHMOD= @CHMOD@
INSTALL= @INSTALL@
DEFS= @DEFS@
@@ -47,7 +46,7 @@ pipermail.py
# Modes for directories and executables created by the install
# process. Default to group-writable directories but
# user-only-writable for executables.
-DIRMODE= 775
+DIRMODE= 2775
EXEMODE= 755
FILEMODE= 644
INSTALL_PROGRAM=$(INSTALL) -m $(EXEMODE)
@@ -63,8 +62,6 @@ install:
$(INSTALL) -m $(FILEMODE) $(srcdir)/$$f $(DESTDIR)$(PACKAGEDIR); \
done
-finish:
-
clean:
distclean:
diff --git a/Mailman/Bouncers/Makefile.in b/Mailman/Bouncers/Makefile.in
index 8865a9f..8878cd9 100644
--- a/Mailman/Bouncers/Makefile.in
+++ b/Mailman/Bouncers/Makefile.in
@@ -28,7 +28,6 @@ exec_prefix= @exec_prefix@
DESTDIR=
CC= @CC@
-CHMOD= @CHMOD@
INSTALL= @INSTALL@
DEFS= @DEFS@
@@ -45,7 +44,7 @@ MODULES= *.py
# Modes for directories and executables created by the install
# process. Default to group-writable directories but
# user-only-writable for executables.
-DIRMODE= 775
+DIRMODE= 2775
EXEMODE= 755
FILEMODE= 644
INSTALL_PROGRAM=$(INSTALL) -m $(EXEMODE)
@@ -61,8 +60,6 @@ install:
$(INSTALL) -m $(FILEMODE) $(srcdir)/$$f $(DESTDIR)$(PACKAGEDIR); \
done
-finish:
-
clean:
distclean:
diff --git a/Mailman/Cgi/Makefile.in b/Mailman/Cgi/Makefile.in
index 47929e9..e20c07e 100644
--- a/Mailman/Cgi/Makefile.in
+++ b/Mailman/Cgi/Makefile.in
@@ -28,7 +28,6 @@ exec_prefix= @exec_prefix@
DESTDIR=
CC= @CC@
-CHMOD= @CHMOD@
INSTALL= @INSTALL@
DEFS= @DEFS@
@@ -47,7 +46,7 @@ CGI_MODULES= *.py
# Modes for directories and executables created by the install
# process. Default to group-writable directories but
# user-only-writable for executables.
-DIRMODE= 775
+DIRMODE= 2775
EXEMODE= 755
FILEMODE= 644
INSTALL_PROGRAM=$(INSTALL) -m $(EXEMODE)
@@ -63,8 +62,6 @@ install:
$(INSTALL) -m $(FILEMODE) $(srcdir)/$$f $(DESTDIR)$(CGIDIR); \
done
-finish:
-
clean:
distclean:
diff --git a/Mailman/Commands/Makefile.in b/Mailman/Commands/Makefile.in
index 645d78b..12bbc1b 100644
--- a/Mailman/Commands/Makefile.in
+++ b/Mailman/Commands/Makefile.in
@@ -28,7 +28,6 @@ exec_prefix= @exec_prefix@
DESTDIR=
CC= @CC@
-CHMOD= @CHMOD@
INSTALL= @INSTALL@
DEFS= @DEFS@
@@ -45,7 +44,7 @@ MODULES= *.py
# Modes for directories and executables created by the install
# process. Default to group-writable directories but
# user-only-writable for executables.
-DIRMODE= 775
+DIRMODE= 2775
EXEMODE= 755
FILEMODE= 644
INSTALL_PROGRAM=$(INSTALL) -m $(EXEMODE)
@@ -61,8 +60,6 @@ install:
$(INSTALL) -m $(FILEMODE) $(srcdir)/$$f $(DESTDIR)$(PACKAGEDIR); \
done
-finish:
-
clean:
distclean:
diff --git a/Mailman/Gui/Makefile.in b/Mailman/Gui/Makefile.in
index 000441e..9273b8a 100644
--- a/Mailman/Gui/Makefile.in
+++ b/Mailman/Gui/Makefile.in
@@ -28,7 +28,6 @@ exec_prefix= @exec_prefix@
DESTDIR=
CC= @CC@
-CHMOD= @CHMOD@
INSTALL= @INSTALL@
DEFS= @DEFS@
@@ -45,7 +44,7 @@ MODULES= *.py
# Modes for directories and executables created by the install
# process. Default to group-writable directories but
# user-only-writable for executables.
-DIRMODE= 775
+DIRMODE= 2775
EXEMODE= 755
FILEMODE= 644
INSTALL_PROGRAM=$(INSTALL) -m $(EXEMODE)
@@ -61,8 +60,6 @@ install:
$(INSTALL) -m $(FILEMODE) $(srcdir)/$$f $(DESTDIR)$(PACKAGEDIR); \
done
-finish:
-
clean:
distclean:
diff --git a/Mailman/Handlers/Makefile.in b/Mailman/Handlers/Makefile.in
index 71e5576..56ee2eb 100644
--- a/Mailman/Handlers/Makefile.in
+++ b/Mailman/Handlers/Makefile.in
@@ -28,7 +28,6 @@ exec_prefix= @exec_prefix@
DESTDIR=
CC= @CC@
-CHMOD= @CHMOD@
INSTALL= @INSTALL@
DEFS= @DEFS@
@@ -45,7 +44,7 @@ MODULES= *.py
# Modes for directories and executables created by the install
# process. Default to group-writable directories but
# user-only-writable for executables.
-DIRMODE= 775
+DIRMODE= 2775
EXEMODE= 755
FILEMODE= 644
INSTALL_PROGRAM=$(INSTALL) -m $(EXEMODE)
@@ -61,8 +60,6 @@ install:
$(INSTALL) -m $(FILEMODE) $(srcdir)/$$f $(DESTDIR)$(PACKAGEDIR); \
done
-finish:
-
clean:
distclean:
diff --git a/Mailman/Logging/Makefile.in b/Mailman/Logging/Makefile.in
index e185775..ad5c128 100644
--- a/Mailman/Logging/Makefile.in
+++ b/Mailman/Logging/Makefile.in
@@ -28,7 +28,6 @@ exec_prefix= @exec_prefix@
DESTDIR=
CC= @CC@
-CHMOD= @CHMOD@
INSTALL= @INSTALL@
DEFS= @DEFS@
@@ -45,7 +44,7 @@ MODULES= *.py
# Modes for directories and executables created by the install
# process. Default to group-writable directories but
# user-only-writable for executables.
-DIRMODE= 775
+DIRMODE= 2775
EXEMODE= 755
FILEMODE= 644
INSTALL_PROGRAM=$(INSTALL) -m $(EXEMODE)
@@ -61,8 +60,6 @@ install:
$(INSTALL) -m $(FILEMODE) $(srcdir)/$$f $(DESTDIR)$(PACKAGEDIR); \
done
-finish:
-
clean:
distclean:
diff --git a/Mailman/MTA/Makefile.in b/Mailman/MTA/Makefile.in
index 0338806..e1de296 100644
--- a/Mailman/MTA/Makefile.in
+++ b/Mailman/MTA/Makefile.in
@@ -28,7 +28,6 @@ exec_prefix= @exec_prefix@
DESTDIR=
CC= @CC@
-CHMOD= @CHMOD@
INSTALL= @INSTALL@
DEFS= @DEFS@
@@ -45,7 +44,7 @@ MODULES= *.py
# Modes for directories and executables created by the install
# process. Default to group-writable directories but
# user-only-writable for executables.
-DIRMODE= 775
+DIRMODE= 2775
EXEMODE= 755
FILEMODE= 644
INSTALL_PROGRAM=$(INSTALL) -m $(EXEMODE)
@@ -61,8 +60,6 @@ install:
$(INSTALL) -m $(FILEMODE) $(srcdir)/$$f $(DESTDIR)$(PACKAGEDIR); \
done
-finish:
-
clean:
distclean:
diff --git a/Mailman/Makefile.in b/Mailman/Makefile.in
index 93c7efd..45439f0 100644
--- a/Mailman/Makefile.in
+++ b/Mailman/Makefile.in
@@ -20,8 +20,6 @@
# Variables set by configure
-VERSION= @VERSION@
-
VPATH= @srcdir@
srcdir= @srcdir@
bindir= @bindir@
@@ -30,7 +28,6 @@ exec_prefix= @exec_prefix@
DESTDIR=
CC= @CC@
-CHMOD= @CHMOD@
INSTALL= @INSTALL@
DEFS= @DEFS@
@@ -48,7 +45,7 @@ SUBDIRS= Cgi Logging Archiver Handlers Bouncers Queue MTA Gui Commands
# Modes for directories and executables created by the install
# process. Default to group-writable directories but
# user-only-writable for executables.
-DIRMODE= 775
+DIRMODE= 2775
EXEMODE= 755
FILEMODE= 644
INSTALL_PROGRAM=$(INSTALL) -m $(EXEMODE)
@@ -79,12 +76,6 @@ install: install-here
(cd $$d; $(MAKE) DESTDIR=$(DESTDIR) install); \
done
-finish:
- @for d in $(SUBDIRS); \
- do \
- (cd $$d; $(MAKE) DESTDIR=$(DESTDIR) finish); \
- done
-
clean:
for d in $(SUBDIRS); \
do \
diff --git a/Mailman/Queue/Makefile.in b/Mailman/Queue/Makefile.in
index 179f3d9..e0e97ad 100644
--- a/Mailman/Queue/Makefile.in
+++ b/Mailman/Queue/Makefile.in
@@ -28,7 +28,6 @@ exec_prefix= @exec_prefix@
DESTDIR=
CC= @CC@
-CHMOD= @CHMOD@
INSTALL= @INSTALL@
DEFS= @DEFS@
@@ -45,7 +44,7 @@ MODULES= *.py
# Modes for directories and executables created by the install
# process. Default to group-writable directories but
# user-only-writable for executables.
-DIRMODE= 775
+DIRMODE= 2775
EXEMODE= 755
FILEMODE= 644
INSTALL_PROGRAM=$(INSTALL) -m $(EXEMODE)
@@ -61,8 +60,6 @@ install:
$(INSTALL) -m $(FILEMODE) $(srcdir)/$$f $(DESTDIR)$(PACKAGEDIR); \
done
-finish:
-
clean:
distclean:
diff --git a/Makefile.in b/Makefile.in
index 40e04f5..eb40844 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -61,11 +61,10 @@ SUBDIRS= bin cron misc Mailman scripts src templates messages tests
# Modes for directories and executables created by the install
# process. Default to group-writable directories but
# user-only-writable for executables.
-DIRMODE= 775
+DIRMODE= 2775
EXEMODE= 755
FILEMODE= 644
INSTALL_PROGRAM=$(INSTALL) -m $(EXEMODE)
-DIRSETGID= chmod g+s
DATE = $(shell python -c 'import time; print time.strftime("%d-%b-%Y"),')
LANGPACK = README-I18N.en templates messages
@@ -85,14 +84,24 @@ install: doinstall update
doinstall: $(SUBDIRS)
@echo "Creating architecture independent directories..."
+ dir=$(DESTDIR)$(prefix); \
+ if test ! -d $$dir; then \
+ echo "Creating directory hierarchy $$dir"; \
+ $(INSTALL) -d -m $(DIRMODE) $$dir; \
+ else true; \
+ fi;
+ dir=$(DESTDIR)$(var_prefix); \
+ if test ! -d $$dir; then \
+ echo "Creating directory hierarchy $$dir"; \
+ $(INSTALL) -d -m $(DIRMODE) $$dir; \
+ else true; \
+ fi;
@for d in $(VAR_DIRS); \
do \
dir=$(DESTDIR)$(var_prefix)/$$d; \
if test ! -d $$dir; then \
echo "Creating directory hierarchy $$dir"; \
- $(srcdir)/mkinstalldirs $$dir; \
- chmod $(DIRMODE) $$dir; \
- $(DIRSETGID) $$dir; \
+ $(INSTALL) -d -m $(DIRMODE) $$dir; \
else true; \
fi; \
done
@@ -102,9 +111,7 @@ doinstall: $(SUBDIRS)
dir=$(DESTDIR)$(prefix)/$$d; \
if test ! -d $$dir; then \
echo "Creating directory hierarchy $$dir"; \
- $(srcdir)/mkinstalldirs $$dir; \
- chmod $(DIRMODE) $$dir; \
- $(DIRSETGID) $$dir; \
+ $(INSTALL) -d -m $(DIRMODE) $$dir; \
else true; \
fi; \
done
@@ -114,9 +121,7 @@ doinstall: $(SUBDIRS)
dir=$(DESTDIR)$(exec_prefix)/$$d; \
if test ! -d $$dir; then \
echo "Creating directory hierarchy $$dir"; \
- $(srcdir)/mkinstalldirs $$dir; \
- chmod $(DIRMODE) $$dir; \
- $(DIRSETGID) $$dir; \
+ $(INSTALL) -d -m $(DIRMODE) $$dir; \
else true; \
fi; \
done
diff --git a/bin/Makefile.in b/bin/Makefile.in
index 22c24b0..d795333 100644
--- a/bin/Makefile.in
+++ b/bin/Makefile.in
@@ -28,7 +28,6 @@ exec_prefix= @exec_prefix@
DESTDIR=
CC= @CC@
-CHMOD= @CHMOD@
INSTALL= @INSTALL@
DEFS= @DEFS@
@@ -56,7 +55,7 @@ BUILDDIR= ../build/bin
# Modes for directories and executables created by the install
# process. Default to group-writable directories but
# user-only-writable for executables.
-DIRMODE= 775
+DIRMODE= 2775
EXEMODE= 755
FILEMODE= 644
INSTALL_PROGRAM=$(INSTALL) -m $(EXEMODE)
@@ -72,8 +71,6 @@ install:
$(INSTALL) -m $(EXEMODE) $(BUILDDIR)/$$f $(DESTDIR)$(SCRIPTSDIR); \
done
-finish:
-
clean:
distclean:
diff --git a/cron/Makefile.in b/cron/Makefile.in
index 2a7c8fd..c14d119 100644
--- a/cron/Makefile.in
+++ b/cron/Makefile.in
@@ -28,7 +28,6 @@ exec_prefix= @exec_prefix@
DESTDIR=
CC= @CC@
-CHMOD= @CHMOD@
INSTALL= @INSTALL@
DEFS= @DEFS@
@@ -68,8 +67,6 @@ install:
$(INSTALL) -m $(EXEMODE) $(BUILDDIR)/$$f $(DESTDIR)$(CRONDIR); \
done
-finish:
-
clean:
distclean:
diff --git a/messages/Makefile.in b/messages/Makefile.in
index 2bbec3f..0b8b7d6 100644
--- a/messages/Makefile.in
+++ b/messages/Makefile.in
@@ -32,7 +32,6 @@ exec_prefix= @exec_prefix@
DESTDIR=
CC= @CC@
-CHMOD= @CHMOD@
INSTALL= @INSTALL@
DEFS= @DEFS@
@@ -43,7 +42,6 @@ OPT= @OPT@
CFLAGS= $(OPT) $(DEFS)
PACKAGEDIR= $(prefix)/messages
SHELL= /bin/sh
-DIRSETGID= chmod g+s
MSGFMT= @PYTHON@ ../build/bin/msgfmt.py
MSGMERGE= msgmerge
@@ -60,7 +58,7 @@ TARGETS= $(MOFILES)
# Modes for directories and executables created by the install
# process. Default to group-writable directories but
# user-only-writable for executables.
-DIRMODE= 775
+DIRMODE= 2775
EXEMODE= 755
FILEMODE= 644
INSTALL_PROGRAM=$(INSTALL) -m $(EXEMODE)
@@ -90,9 +88,8 @@ doinstall: mofiles
do \
dir=$(DESTDIR)$(prefix)/$$d; \
echo "Creating language directory $$dir"; \
- $(srcdir)/../mkinstalldirs $$dir; \
- chmod $(DIRMODE) $$dir; \
- $(DIRSETGID) $$dir; \
+ $(INSTALL) -d -m $(DIRMODE) `dirname $$dir`; \
+ $(INSTALL) -d -m $(DIRMODE) $$dir; \
done
@for d in $(LANGUAGES); \
do \
@@ -113,8 +110,6 @@ doinstall: mofiles
mofiles: $(MOFILES)
-finish:
-
clean:
-rm -f */LC_MESSAGES/mailman.mo
diff --git a/misc/Makefile.in b/misc/Makefile.in
index 5125cd8..af99c04 100644
--- a/misc/Makefile.in
+++ b/misc/Makefile.in
@@ -30,7 +30,6 @@ var_prefix= @VAR_PREFIX@
DESTDIR=
CC= @CC@
-CHMOD= @CHMOD@
INSTALL= @INSTALL@
PYTHON= @PYTHON@
@@ -62,7 +61,7 @@ PACKAGES= $(EMAILPKG) $(JACODECSPKG) $(KOCODECSPKG)
# Modes for directories and executables created by the install
# process. Default to group-writable directories but
# user-only-writable for executables.
-DIRMODE= 775
+DIRMODE= 2775
EXEMODE= 755
FILEMODE= 644
DATAMODE= 664
@@ -101,8 +100,6 @@ install-packages:
(cd $(PKGDIR)/$$p ; umask 02 ; PYTHONPATH=$(PYTHONLIBDIR) $(PYTHON) $(SETUPCMD)); \
done
-finish:
-
clean:
distclean:
diff --git a/scripts/Makefile.in b/scripts/Makefile.in
index 49b82ec..cea250c 100644
--- a/scripts/Makefile.in
+++ b/scripts/Makefile.in
@@ -28,7 +28,6 @@ exec_prefix= @exec_prefix@
DESTDIR=
CC= @CC@
-CHMOD= @CHMOD@
INSTALL= @INSTALL@
DEFS= @DEFS@
@@ -49,7 +48,7 @@ SCRIPTS= bounces confirm driver join leave owner post request
# Modes for directories and executables created by the install
# process. Default to group-writable directories but
# user-only-writable for executables.
-DIRMODE= 775
+DIRMODE= 2775
EXEMODE= 755
FILEMODE= 644
INSTALL_PROGRAM=$(INSTALL) -m $(EXEMODE)
@@ -68,8 +67,6 @@ install:
$(INSTALL) -m $(FILEMODE) $(srcdir)/join $(DESTDIR)$(SCRIPTSDIR)/subscribe
$(INSTALL) -m $(FILEMODE) $(srcdir)/leave $(DESTDIR)$(SCRIPTSDIR)/unsubscribe
-finish:
-
clean:
distclean:
diff --git a/src/Makefile.in b/src/Makefile.in
index ce52356..7ed820b 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -28,7 +28,6 @@ bindir= @bindir@
DESTDIR=
CC= @CC@
-CHMOD= @CHMOD@
INSTALL= @INSTALL@
PYTHON= @PYTHON@
@@ -65,10 +64,9 @@ COMMON_FLAGS= -DPREFIX="\"$(prefix)\"" \
# Modes for directories and executables created by the install
# process. Default to group-writable directories but
# user-only-writable for executables.
-DIRMODE= 775
-EXEMODE= 755
+DIRMODE= 2775
+EXEMODE= 2755
INSTALL_PROGRAM=$(INSTALL) -m $(EXEMODE)
-DIRSETGID= chmod g+s
# Fixed definitions
@@ -112,20 +110,10 @@ install: all
do \
exe=$(DESTDIR)$(CGIDIR)/$$f$(CGIEXT); \
$(INSTALL_PROGRAM) $$f $$exe; \
- $(DIRSETGID) $$exe; \
done
for f in $(MAIL_PROGS); \
do \
$(INSTALL_PROGRAM) $$f $(DESTDIR)$(MAILDIR); \
- $(DIRSETGID) $(DESTDIR)$(MAILDIR)/$$f; \
- done
-
-finish:
- -for f in $(SUID_CGI_PROGS); \
- do \
- exe=$(DESTDIR)$(CGIDIR)/$$f$(CGIEXT); \
- chown $(MAILMAN_USER) $$exe; \
- chmod u+s $$exe; \
done
clean:
diff --git a/templates/Makefile.in b/templates/Makefile.in
index 3dfee3a..b23d7c1 100644
--- a/templates/Makefile.in
+++ b/templates/Makefile.in
@@ -28,7 +28,6 @@ exec_prefix= @exec_prefix@
DESTDIR=
CC= @CC@
-CHMOD= @CHMOD@
INSTALL= @INSTALL@
TRUE= @TRUE@
@@ -48,7 +47,7 @@ LANGUAGES= ar ast ca cs da de el en es et eu fi fr gl he hr hu ia it ja \
# Modes for directories and executables created by the install
# process. Default to group-writable directories but
# user-only-writable for executables.
-DIRMODE= 775
+DIRMODE= 2775
EXEMODE= 755
FILEMODE= 644
INSTALL_PROGRAM=$(INSTALL) -m $(EXEMODE)
@@ -61,15 +60,13 @@ all:
install:
for d in $(LANGUAGES); \
do \
- $(srcdir)/../mkinstalldirs $(DESTDIR)$(TEMPLATEDIR)/$$d; \
+ $(INSTALL) -d -m $(DIRMODE) $(DESTDIR)$(TEMPLATEDIR)/$$d; \
for f in $(srcdir)/$$d/*.html $(srcdir)/$$d/*.txt; \
do \
$(INSTALL) -m $(FILEMODE) $$f $(DESTDIR)$(TEMPLATEDIR)/$$d; \
done; \
done
-finish:
-
clean:
distclean:
diff --git a/tests/Makefile.in b/tests/Makefile.in
index 26d6e31..ca92425 100644
--- a/tests/Makefile.in
+++ b/tests/Makefile.in
@@ -28,7 +28,6 @@ exec_prefix= @exec_prefix@
DESTDIR=
CC= @CC@
-CHMOD= @CHMOD@
INSTALL= @INSTALL@
DEFS= @DEFS@
@@ -46,7 +45,7 @@ EXECS= $(srcdir)/onebounce.py $(srcdir)/fblast.py
# Modes for directories and executables created by the install
# process. Default to group-writable directories but
# user-only-writable for executables.
-DIRMODE= 775
+DIRMODE= 2775
EXEMODE= 755
FILEMODE= 644
INSTALL_PROGRAM=$(INSTALL) -m $(EXEMODE)
@@ -71,8 +70,6 @@ install:
(cd $$d; $(MAKE) DESTDIR=$(DESTDIR) install); \
done
-finish:
-
clean:
distclean:
diff --git a/tests/bounces/Makefile.in b/tests/bounces/Makefile.in
index 5798097..f7014cb 100644
--- a/tests/bounces/Makefile.in
+++ b/tests/bounces/Makefile.in
@@ -28,7 +28,6 @@ exec_prefix= @exec_prefix@
DESTDIR=
CC= @CC@
-CHMOD= @CHMOD@
INSTALL= @INSTALL@
DEFS= @DEFS@
@@ -46,7 +45,7 @@ BOUNCE_FILES= $(srcdir)/*.txt
# Modes for directories and executables created by the install
# process. Default to group-writable directories but
# user-only-writable for executables.
-DIRMODE= 775
+DIRMODE= 2775
EXEMODE= 755
FILEMODE= 644
INSTALL_PROGRAM=$(INSTALL) -m $(EXEMODE)
@@ -60,8 +59,6 @@ install:
$(INSTALL) -m $(FILEMODE) $$f $(DESTDIR)$(BOUNCEDIR); \
done
-finish:
-
clean:
distclean:
diff --git a/tests/msgs/Makefile.in b/tests/msgs/Makefile.in
index 736d721..edef5ae 100644
--- a/tests/msgs/Makefile.in
+++ b/tests/msgs/Makefile.in
@@ -28,7 +28,6 @@ exec_prefix= @exec_prefix@
DESTDIR=
CC= @CC@
-CHMOD= @CHMOD@
INSTALL= @INSTALL@
DEFS= @DEFS@
@@ -46,7 +45,7 @@ MSG_FILES= $(srcdir)/*.txt
# Modes for directories and executables created by the install
# process. Default to group-writable directories but
# user-only-writable for executables.
-DIRMODE= 775
+DIRMODE= 2775
EXEMODE= 755
FILEMODE= 644
INSTALL_PROGRAM=$(INSTALL) -m $(EXEMODE)
@@ -60,8 +59,6 @@ install:
$(INSTALL) -m $(FILEMODE) $$f $(DESTDIR)$(MSGSDIR); \
done
-finish:
-
clean:
distclean:

View File

@ -0,0 +1,109 @@
diff --git a/bin/mailmanctl b/bin/mailmanctl
index fa14a2c..e291df1 100644
--- a/bin/mailmanctl
+++ b/bin/mailmanctl
@@ -36,7 +36,7 @@ in the file data/master-qrunner.pid but you normally don't need to use this
pid directly. The `start', `stop', `restart', and `reopen' commands handle
everything for you.
-Usage: %(PROGRAM)s [options] [ start | stop | restart | reopen ]
+Usage: %(PROGRAM)s [options] [ start | stop | restart | reopen | status ]
Options:
@@ -90,6 +90,9 @@ Commands:
reopen - This will close all log files, causing them to be re-opened the
next time a message is written to them
+
+ status - This returns a string indicating the status of the master
+ qrunner
"""
import sys
@@ -190,6 +193,52 @@ def qrunner_state():
return 0
return 1
+def mailman_status():
+ # return status, pid
+ #
+ # These status values match the /etc/init.d status values
+ # (at least on Red Hat), try to return equivalent status if possible
+ # status is 0 if running,
+ # status is 1 if dead but pid file exists
+ # status is 2 if dead but subsys locked
+ # status is 3 if stopped (pid returned will be 0)
+ #
+ #
+ # We want any user to be able to query the status and this presents
+ # few interesting permission problems and is why we don't use
+ # qrunner_state(). The pidfile is only readable by the mailman owner
+ # and group, however the lockfile is world readable. So we will
+ # get the master pid from the lockfile. We try to determine if the
+ # master process exists by sending it a signal. If we don't have
+ # permission to signal the process, but the process exists we'll
+ # get a EPERM error, if the process does not exist then we'll get
+ # a ESRCH error.
+
+ try:
+ hostname, pid, tempfile = get_lock_data()
+ except IOError, e:
+ if e.errno == errno.ENOENT:
+ # Lock file didn't exist, can't be running
+ return 3, 0
+ else:
+ raise
+ if hostname <> socket.gethostname():
+ # not running on this host
+ return 3, 0
+ # Find out if the process exists by calling kill with a signal 0.
+ try:
+ os.kill(pid, 0)
+ except OSError, e:
+ if e.errno == errno.ESRCH:
+ # process does not exist
+ return 1, pid
+ elif e.errno == errno.EPERM:
+ # we don't have permission signal the process but it exists
+ return 0, pid
+ else:
+ raise
+ return 0, pid
+
def acquire_lock_1(force):
# Be sure we can acquire the master qrunner lock. If not, it means some
@@ -338,13 +387,15 @@ def main():
command = COMMASPACE.join(args)
usage(1, C_('Bad command: %(command)s'))
+ command = args[0].lower()
+
if checkprivs:
check_privs()
else:
- print C_('Warning! You may encounter permission problems.')
+ if command != 'status':
+ print C_('Warning! You may encounter permission problems.')
# Handle the commands
- command = args[0].lower()
if command == 'stop':
# Sent the master qrunner process a SIGINT, which is equivalent to
# giving cron/qrunner a ctrl-c or KeyboardInterrupt. This will
@@ -363,6 +414,14 @@ def main():
if not quiet:
print C_('Re-opening all log files')
kill_watcher(signal.SIGHUP)
+ elif command == 'status':
+ status, pid = mailman_status()
+ if not quiet:
+ if status == 0:
+ print C_("mailman (pid %(pid)d) is running...")
+ else:
+ print C_("mailman is stopped")
+ sys.exit(status)
elif command == 'start':
# First, complain loudly if there's no site list.
check_for_site_list()

View File

@ -0,0 +1,132 @@
diff --git a/cron/bumpdigests b/cron/bumpdigests
index 57cc45e..4002731 100755
--- a/cron/bumpdigests
+++ b/cron/bumpdigests
@@ -1,4 +1,4 @@
-#! @PYTHON@
+#! @PYTHON@ -S
#
# Copyright (C) 1998-2018 by the Free Software Foundation, Inc.
#
diff --git a/cron/checkdbs b/cron/checkdbs
index e776f15..c4d8179 100755
--- a/cron/checkdbs
+++ b/cron/checkdbs
@@ -1,4 +1,4 @@
-#! @PYTHON@
+#! @PYTHON@ -S
#
# Copyright (C) 1998-2018 by the Free Software Foundation, Inc.
#
diff --git a/cron/crontab.in.in b/cron/crontab.in.in
index 540dfc1..45c5022 100644
--- a/cron/crontab.in.in
+++ b/cron/crontab.in.in
@@ -1,27 +1,50 @@
+#
+# -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING -- WARNING --
+# ------------------ EDIT THE CORRECT FILE -------------------------
+#
+# This file is copied to /etc/cron.d/mailman from
+# @prefix@/cron/crontab.in when the mailman service is started via its
+# init.d script and the file /etc/cron.d/mailman is removed when the
+# service is stopped. Therefore any edits made directly to
+# /etc/cron.d/mailman will be lost anytime the mailman service
+# restarts.
+#
+# To make changes edit the master copy @prefix@/cron/crontab.in and then
+# restart the service to pick up the changes (/sbin/service mailman restart).
+#
+# The reason this is done this way is because the mailman cron jobs
+# should only be invoked if the mailman service is enabled and not
+# just as a consequence of installing the rpm as was the case
+# previously. The file /etc/cron.d/mailman cannot simply be linked to
+# the master copy in @prefix@/cron because for security reasons cron
+# will not process crontab files that are links or writeable by
+# anybody else but root, thus the file must be copied into /etc/cron.d
+# with the right ownership and permissions.
+#
# At 8AM every day, mail reminders to admins as to pending requests.
# They are less likely to ignore these reminders if they're mailed
# early in the morning, but of course, this is local time... ;)
-0 8 * * * @PYTHON@ -S @prefix@/cron/checkdbs
+0 8 * * * @MAILMAN_USER@ @prefix@/cron/checkdbs
#
# At 9AM, send notifications to disabled members that are due to be
# reminded to re-enable their accounts.
-0 9 * * * @PYTHON@ -S @prefix@/cron/disabled
+0 9 * * * @MAILMAN_USER@ @prefix@/cron/disabled
#
# Noon, mail digests for lists that do periodic as well as threshhold delivery.
-0 12 * * * @PYTHON@ -S @prefix@/cron/senddigests
+0 12 * * * @MAILMAN_USER@ @prefix@/cron/senddigests
#
# 5 AM on the first of each month, mail out password reminders.
-0 5 1 * * @PYTHON@ -S @prefix@/cron/mailpasswds
+0 5 1 * * @MAILMAN_USER@ @prefix@/cron/mailpasswds
#
# Every 5 mins, try to gate news to mail. You can comment this one out
# if you don't want to allow gating, or don't have any going on right now,
# or want to exclusively use a callback strategy instead of polling.
-0,5,10,15,20,25,30,35,40,45,50,55 * * * * @PYTHON@ -S @prefix@/cron/gate_news
+0,5,10,15,20,25,30,35,40,45,50,55 * * * * @MAILMAN_USER@ @prefix@/cron/gate_news
#
# At 3:27am every night, regenerate the gzip'd archive file. Only
# turn this on if the internal archiver is used and
# GZIP_ARCHIVE_TXT_FILES is false in mm_cfg.py
-27 3 * * * @PYTHON@ -S @prefix@/cron/nightly_gzip
+27 3 * * * @MAILMAN_USER@ @prefix@/cron/nightly_gzip
#
# At 4:30AM daily, cull old entries from the 'bad' and 'shunt' queues.
-30 4 * * * @PYTHON@ -S @prefix@/cron/cull_bad_shunt
+30 4 * * * @MAILMAN_USER@ @prefix@/cron/cull_bad_shunt
diff --git a/cron/disabled b/cron/disabled
index ac62582..971563d 100755
--- a/cron/disabled
+++ b/cron/disabled
@@ -1,4 +1,4 @@
-#! @PYTHON@
+#! @PYTHON@ -S
#
# Copyright (C) 2001-2018 by the Free Software Foundation, Inc.
#
diff --git a/cron/gate_news b/cron/gate_news
index c66c09e..247c834 100755
--- a/cron/gate_news
+++ b/cron/gate_news
@@ -1,4 +1,4 @@
-#! @PYTHON@
+#! @PYTHON@ -S
#
# Copyright (C) 1998-2018 by the Free Software Foundation, Inc.
#
diff --git a/cron/mailpasswds b/cron/mailpasswds
index da64376..5d8d792 100755
--- a/cron/mailpasswds
+++ b/cron/mailpasswds
@@ -1,4 +1,4 @@
-#! @PYTHON@
+#! @PYTHON@ -S
#
# Copyright (C) 1998-2018 by the Free Software Foundation, Inc.
#
diff --git a/cron/nightly_gzip b/cron/nightly_gzip
index de493d0..8af0351 100755
--- a/cron/nightly_gzip
+++ b/cron/nightly_gzip
@@ -1,4 +1,4 @@
-#! @PYTHON@
+#! @PYTHON@ -S
#
# Copyright (C) 1998-2018 by the Free Software Foundation, Inc.
#
diff --git a/cron/senddigests b/cron/senddigests
index edf27a2..c64adc1 100755
--- a/cron/senddigests
+++ b/cron/senddigests
@@ -1,4 +1,4 @@
-#! @PYTHON@
+#! @PYTHON@ -S
#
# Copyright (C) 1998-2018 by the Free Software Foundation, Inc.
#

View File

@ -0,0 +1,387 @@
diff -ruN mailman-2.1.12-a/configure.in mailman-2.1.12-b/configure.in
--- mailman-2.1.12-a/configure.in 2009-02-23 22:23:35.000000000 +0100
+++ mailman-2.1.12-b/configure.in 2009-07-28 12:19:47.000000000 +0200
@@ -249,26 +249,101 @@
fi
# new macro for finding group names
-AC_DEFUN([MM_FIND_GROUP_NAME], [
+# returns a comma separated list of quoted group names
+# the list is returned in the same order as specified with any duplicates removed
+# the filter flag must be "yes" or "no", e.g. this is permcheck
+# "no" ==> none existing groups are not filtered out
+# "yes" ==> only those groups that are in the group database are included
+# in the list
+AC_DEFUN(MM_FIND_GROUP_LIST, [
# $1 == variable name
-# $2 == user id to check for
+# $2 == white space separated list of groups to check,
+# list may contain mix of id's and names
+# $3 == filter, if == 'yes' then remove any non-existing groups
AC_SUBST($1)
changequote(,)
if test -z "$$1"
then
cat > conftest.py <<EOF
import grp
-gid = ''
+group_names = []
+seen = {}
+filter = "$3"
+
for group in "$2".split():
try:
+ gid = int(group)
+ try:
+ gname = grp.getgrgid(gid)[0]
+ except KeyError:
+ gname = ''
+ except ValueError:
try:
- gname = grp.getgrgid(int(group))[0]
- break
- except ValueError:
gname = grp.getgrnam(group)[0]
+ except KeyError:
+ if filter == "yes":
+ gname = ''
+ else:
+ gname = group
+ if gname:
+ if gname not in seen:
+ seen[gname] = 1
+ group_names.append(gname)
+
+if group_names:
+ val = '"' + '", "'.join(group_names) + '"'
+ #val = "'"+val+"'"
+else:
+ val = ''
+
+fp = open("conftest.out", "w")
+fp.write("%s\n" % val)
+fp.close()
+EOF
+ $PYTHON conftest.py
+ $1=`cat conftest.out`
+fi
+changequote([, ])
+rm -f conftest.out conftest.py])
+
+
+# new macro for finding group names
+AC_DEFUN(MM_FIND_GROUP_NAME, [
+# Given a list of tokens, either a name or a number (gid)
+# return the first one in the list that is found in the
+# group database. The return value is always a name, possibly
+# translated from a gid. If permcheck is "no" then the group
+# database is not checked, instead the first token in the list
+# which is a name is returned (e.g. the default value). If permcheck
+# is no and only gid's are in the list then the null string is returned.
+# $1 == variable name
+# $2 == group id to check for
+# $3 == permcheck, either "yes" or "no"
+AC_SUBST($1)
+changequote(,)
+if test -z "$$1"
+then
+ cat > conftest.py <<EOF
+import grp
+gname=''
+if "$3" == "yes":
+ for group in "$2".split():
+ try:
+ try:
+ gname = grp.getgrgid(int(group))[0]
+ break
+ except ValueError:
+ gname = grp.getgrnam(group)[0]
+ break
+ except KeyError:
+ gname = ''
+else:
+ for group in "$2".split():
+ try:
+ int(group)
+ except ValueError:
+ gname = group
break
- except KeyError:
- gname = ''
fp = open("conftest.out", "w")
fp.write("%s\n" % gname)
fp.close()
@@ -282,25 +357,41 @@
# new macro for finding UIDs
AC_DEFUN([MM_FIND_USER_NAME], [
+# Given a list of tokens, either a name or a number (uid)
+# return the first one in the list that is found in the
+# password database. The return value is always a name, possibly
+# translated from a uid. If permcheck is "no" then the password
+# database is not checked, instead the first token in the list
+# which is a name is returned (e.g. the default value). If permcheck
+# is no and only uid's are in the list then the null string is returned.
# $1 == variable name
# $2 == user id to check for
+# $3 == permcheck, either "yes" or "no"
AC_SUBST($1)
changequote(,)
if test -z "$$1"
then
cat > conftest.py <<EOF
import pwd
-uid = ''
-for user in "$2".split():
- try:
+uname=''
+if "$3" == "yes":
+ for user in "$2".split():
try:
- uname = pwd.getpwuid(int(user))[0]
- break
+ try:
+ uname = pwd.getpwuid(int(user))[0]
+ break
+ except ValueError:
+ uname = pwd.getpwnam(user)[0]
+ break
+ except KeyError:
+ uname = ''
+else:
+ for user in "$2".split():
+ try:
+ int(user)
except ValueError:
- uname = pwd.getpwnam(user)[0]
+ uname = user
break
- except KeyError:
- uname = ''
fp = open("conftest.out", "w")
fp.write("%s\n" % uname)
fp.close()
@@ -326,7 +417,7 @@
# User `mailman' must exist
AC_SUBST(MAILMAN_USER)
AC_MSG_CHECKING(for user name \"$USERNAME\")
-MM_FIND_USER_NAME(MAILMAN_USER, $USERNAME)
+MM_FIND_USER_NAME(MAILMAN_USER, $USERNAME, $with_permcheck)
if test -z "$MAILMAN_USER"
then
if test "$with_permcheck" = "yes"
@@ -357,7 +448,7 @@
# Target group must exist
AC_SUBST(MAILMAN_GROUP)
AC_MSG_CHECKING(for group name \"$GROUPNAME\")
-MM_FIND_GROUP_NAME(MAILMAN_GROUP, $GROUPNAME)
+MM_FIND_GROUP_NAME(MAILMAN_GROUP, $GROUPNAME, $with_permcheck)
if test -z "$MAILMAN_GROUP"
then
if test "$with_permcheck" = "yes"
@@ -380,11 +471,11 @@
prefix = "$prefixcheck"
groupname = "$GROUPNAME"
mailmangroup = "$MAILMAN_GROUP"
-try:
- mailmangid = grp.getgrnam(mailmangroup)[2]
-except KeyError:
- mailmangid = -1
problems = []
+try: mailmangid = grp.getgrnam(mailmangroup)[2]
+except KeyError:
+ problems.append("group doesn't exist: " + mailmangroup)
+ mailmangid = 41
try: statdata = os.stat(prefix)
except OSError:
problems.append("Directory doesn't exist: " + prefix)
@@ -434,7 +525,7 @@
then
with_mail_gid="mailman other mail daemon"
fi
-MM_FIND_GROUP_NAME(MAIL_GROUP, $with_mail_gid)
+MM_FIND_GROUP_LIST(MAIL_GROUP, $with_mail_gid, $with_permcheck)
if test -z "$MAIL_GROUP"
then
if test "$with_permcheck" = "yes"
@@ -461,7 +552,7 @@
with_cgi_gid="www www-data nobody"
fi
-MM_FIND_GROUP_NAME(CGI_GROUP, $with_cgi_gid)
+MM_FIND_GROUP_LIST(CGI_GROUP, $with_cgi_gid, $with_permcheck)
if test -z "$CGI_GROUP"
then
if test "$with_permcheck" = "yes"
diff -ruN mailman-2.1.12-a/src/cgi-wrapper.c mailman-2.1.12-b/src/cgi-wrapper.c
--- mailman-2.1.12-a/src/cgi-wrapper.c 2009-02-23 22:23:35.000000000 +0100
+++ mailman-2.1.12-b/src/cgi-wrapper.c 2009-07-28 12:19:47.000000000 +0200
@@ -28,11 +28,11 @@
/* Group name that CGI scripts run as. See your web server's documentation
* for details.
*/
-#define LEGAL_PARENT_GROUP CGI_GROUP
+#define LEGAL_PARENT_GROUPS CGI_GROUP
const char* logident = LOG_IDENT;
char* script = SCRIPTNAME;
-const char* parentgroup = LEGAL_PARENT_GROUP;
+const char* parentgroups[] = {LEGAL_PARENT_GROUPS};
int
@@ -42,7 +42,7 @@
char* fake_argv[3];
running_as_cgi = 1;
- check_caller(logident, parentgroup);
+ check_caller(logident, parentgroups, sizeof(parentgroups) / sizeof(parentgroups[0]));
/* For these CGI programs, we can ignore argc and argv since they
* don't contain anything useful. `script' will always be the driver
diff -ruN mailman-2.1.12-a/src/common.c mailman-2.1.12-b/src/common.c
--- mailman-2.1.12-a/src/common.c 2009-02-23 22:23:35.000000000 +0100
+++ mailman-2.1.12-b/src/common.c 2009-07-28 12:19:47.000000000 +0200
@@ -117,13 +117,14 @@
/* Is the parent process allowed to call us?
*/
void
-check_caller(const char* ident, const char* parentgroup)
+check_caller(const char* ident, const char** parentgroups, size_t numgroups)
{
GID_T mygid = getgid();
struct group *mygroup = getgrgid(mygid);
char* option;
char* server;
char* wrapper;
+ int i;
if (running_as_cgi) {
option = "--with-cgi-gid";
@@ -136,28 +137,46 @@
wrapper = "mail";
}
- if (!mygroup)
- fatal(ident, GROUP_NAME_NOT_FOUND,
- "Failure to find group name for GID %d. Mailman\n"
- "expected the %s wrapper to be executed as group\n"
- "\"%s\", but the system's %s server executed the\n"
- "wrapper as GID %d for which the name could not be\n"
- "found. Try adding GID %d to your system as \"%s\",\n"
- "or tweak your %s server to run the wrapper as group\n"
- "\"%s\".",
- mygid, wrapper, parentgroup, server, mygid, mygid,
- parentgroup, server, parentgroup);
+ if (!mygroup)
+ fatal(ident, GROUP_ID_NOT_FOUND,
+ "Failure to lookup via getgrgid() the group info for group id %d that this Mailman %s wrapper is executing under.\n"
+ "This is probably due to an incorrectly configured system and is not a Mailman problem",
+ mygid, wrapper);
+
+ for (i = 0; i < numgroups; i++) {
+ if (strcmp(parentgroups[i], mygroup->gr_name) == 0) break;
+ }
+
+ if (i >= numgroups) {
+ char *groupset = NULL;
+ size_t size = 0;
+
+ for (i = 0; i < numgroups; i++) {
+ size += strlen(parentgroups[i]) + 2;
+ }
+
+ groupset = malloc(size);
+
+ if (groupset) {
+ groupset[0] = 0;
+ for (i = 0; i < numgroups; i++) {
+ strcat(groupset, parentgroups[i]);
+ if (i < numgroups-1) strcat(groupset, ", ");
+ }
+ }
- if (strcmp(parentgroup, mygroup->gr_name))
fatal(ident, GROUP_MISMATCH,
- "Group mismatch error. Mailman expected the %s\n"
- "wrapper script to be executed as group \"%s\", but\n"
- "the system's %s server executed the %s script as\n"
- "group \"%s\". Try tweaking the %s server to run the\n"
- "script as group \"%s\", or re-run configure, \n"
- "providing the command line option `%s=%s'.",
- wrapper, parentgroup, server, wrapper, mygroup->gr_name,
- server, parentgroup, option, mygroup->gr_name);
+ "Group mismatch error. Mailman expected the %s wrapper script to be\n"
+ "executed as one of the following groups:\n"
+ "[%s],\n"
+ "but the system's %s server executed the %s script as group: \"%s\".\n"
+ "Try tweaking the %s server to run the script as one of these groups:\n"
+ "[%s],\n"
+ "or re-run configure providing the command line option:\n"
+ "'%s=%s'.",
+ wrapper, groupset, server, wrapper, mygroup->gr_name,
+ server, groupset, option, mygroup->gr_name);
+ }
}
diff -ruN mailman-2.1.12-a/src/common.h mailman-2.1.12-b/src/common.h
--- mailman-2.1.12-a/src/common.h 2009-02-23 22:23:35.000000000 +0100
+++ mailman-2.1.12-b/src/common.h 2009-07-28 12:19:47.000000000 +0200
@@ -33,7 +33,7 @@
#define GID_T GETGROUPS_T
extern void fatal(const char*, int, char*, ...);
-extern void check_caller(const char*, const char*);
+extern void check_caller(const char* ident, const char**, size_t);
extern int run_script(const char*, int, char**, char**);
/* Global variable used as a flag. */
@@ -51,7 +51,7 @@
#define MAIL_USAGE_ERROR 5
#define MAIL_ILLEGAL_COMMAND 6
#define ADDALIAS_USAGE_ERROR 7
-#define GROUP_NAME_NOT_FOUND 8
+#define GROUP_ID_NOT_FOUND 8
/*
diff -ruN mailman-2.1.12-a/src/mail-wrapper.c mailman-2.1.12-b/src/mail-wrapper.c
--- mailman-2.1.12-a/src/mail-wrapper.c 2009-02-23 22:23:35.000000000 +0100
+++ mailman-2.1.12-b/src/mail-wrapper.c 2009-07-28 12:19:47.000000000 +0200
@@ -23,9 +23,9 @@
/* Group name that your mail programs run as. See your mail server's
* documentation for details.
*/
-#define LEGAL_PARENT_GROUP MAIL_GROUP
+#define LEGAL_PARENT_GROUPS MAIL_GROUP
-const char* parentgroup = LEGAL_PARENT_GROUP;
+const char* parentgroups[] = {LEGAL_PARENT_GROUPS};
const char* logident = "Mailman mail-wrapper";
@@ -74,7 +74,7 @@
fatal(logident, MAIL_ILLEGAL_COMMAND,
"Illegal command: %s", argv[1]);
- check_caller(logident, parentgroup);
+ check_caller(logident, parentgroups, sizeof(parentgroups) / sizeof(parentgroups[0]));
/* If we got here, everything must be OK */
status = run_script(argv[1], argc, argv, env);
diff -ruN mailman-2.1.12-a/src/Makefile.in mailman-2.1.12-b/src/Makefile.in
--- mailman-2.1.12-a/src/Makefile.in 2009-02-23 22:23:35.000000000 +0100
+++ mailman-2.1.12-b/src/Makefile.in 2009-07-28 12:19:47.000000000 +0200
@@ -49,9 +49,9 @@
SHELL= /bin/sh
-MAIL_FLAGS= -DMAIL_GROUP="\"$(MAIL_GROUP)\""
+MAIL_FLAGS= -DMAIL_GROUP='$(MAIL_GROUP)'
-CGI_FLAGS= -DCGI_GROUP="\"$(CGI_GROUP)\""
+CGI_FLAGS= -DCGI_GROUP='$(CGI_GROUP)'
HELPFUL= -DHELPFUL

View File

@ -0,0 +1,243 @@
diff --git a/Mailman/Defaults.py.in b/Mailman/Defaults.py.in
index fb3f4f3..7dde965 100644
--- a/Mailman/Defaults.py.in
+++ b/Mailman/Defaults.py.in
@@ -1431,20 +1431,22 @@ AuthListPoster = 6 # List poster (Approved: <pw> header in posts only)
# Useful directories
LIST_DATA_DIR = os.path.join(VAR_PREFIX, 'lists')
-LOG_DIR = os.path.join(VAR_PREFIX, 'logs')
-LOCK_DIR = os.path.join(VAR_PREFIX, 'locks')
+LOG_DIR = '@LOG_DIR@'
+LOCK_DIR = '@LOCK_DIR@'
+CONFIG_DIR = '@CONFIG_DIR@'
DATA_DIR = os.path.join(VAR_PREFIX, 'data')
+PID_DIR = '@PID_DIR@'
SPAM_DIR = os.path.join(VAR_PREFIX, 'spam')
WRAPPER_DIR = os.path.join(EXEC_PREFIX, 'mail')
BIN_DIR = os.path.join(PREFIX, 'bin')
SCRIPTS_DIR = os.path.join(PREFIX, 'scripts')
-TEMPLATE_DIR = os.path.join(PREFIX, 'templates')
+TEMPLATE_DIR = '@TEMPLATE_DIR@'
MESSAGES_DIR = os.path.join(PREFIX, 'messages')
PUBLIC_ARCHIVE_FILE_DIR = os.path.join(VAR_PREFIX, 'archives', 'public')
PRIVATE_ARCHIVE_FILE_DIR = os.path.join(VAR_PREFIX, 'archives', 'private')
# Directories used by the qrunner subsystem
-QUEUE_DIR = os.path.join(VAR_PREFIX, 'qfiles')
+QUEUE_DIR = '@QUEUE_DIR@'
INQUEUE_DIR = os.path.join(QUEUE_DIR, 'in')
OUTQUEUE_DIR = os.path.join(QUEUE_DIR, 'out')
CMDQUEUE_DIR = os.path.join(QUEUE_DIR, 'commands')
@@ -1458,9 +1460,9 @@ RETRYQUEUE_DIR = os.path.join(QUEUE_DIR, 'retry')
MAILDIR_DIR = os.path.join(QUEUE_DIR, 'maildir')
# Other useful files
-PIDFILE = os.path.join(DATA_DIR, 'master-qrunner.pid')
-SITE_PW_FILE = os.path.join(DATA_DIR, 'adm.pw')
-LISTCREATOR_PW_FILE = os.path.join(DATA_DIR, 'creator.pw')
+PIDFILE = os.path.join(PID_DIR, 'master-qrunner.pid')
+SITE_PW_FILE = os.path.join(CONFIG_DIR, 'adm.pw')
+LISTCREATOR_PW_FILE = os.path.join(CONFIG_DIR, 'creator.pw')
# Import a bunch of version numbers
from Version import *
diff --git a/Mailman/MTA/Postfix.py b/Mailman/MTA/Postfix.py
index 801ddc0..8506b9b 100644
--- a/Mailman/MTA/Postfix.py
+++ b/Mailman/MTA/Postfix.py
@@ -32,8 +32,8 @@ from Mailman.MTA.Utils import makealiases
from Mailman.Logging.Syslog import syslog
LOCKFILE = os.path.join(mm_cfg.LOCK_DIR, 'creator')
-ALIASFILE = os.path.join(mm_cfg.DATA_DIR, 'aliases')
-VIRTFILE = os.path.join(mm_cfg.DATA_DIR, 'virtual-mailman')
+ALIASFILE = os.path.join(mm_cfg.CONFIG_DIR, 'aliases')
+VIRTFILE = os.path.join(mm_cfg.CONFIG_DIR, 'virtual-mailman')
# Desired mode for aliases(.db) and virtual-mailman(.db) for both creation
# and check_perms.
targetmode = S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH
diff --git a/Makefile.in b/Makefile.in
index eb40844..289aeee 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -28,6 +28,12 @@ bindir= @bindir@
prefix= @prefix@
exec_prefix= @exec_prefix@
var_prefix= @VAR_PREFIX@
+configdir= @CONFIG_DIR@
+lockdir= @LOCK_DIR@
+logdir= @LOG_DIR@
+piddir= @PID_DIR@
+queuedir= @QUEUE_DIR@
+templatedir= @TEMPLATE_DIR@
DESTDIR=
CC= @CC@
@@ -41,8 +47,11 @@ DEFS= @DEFS@
OPT= @OPT@
CFLAGS= @CFLAGS@ $(OPT) $(DEFS)
+FHS_DIRS= \
+ ${configdir} ${lockdir} ${logdir} ${piddir} ${queuedir} ${templatedir}
+
VAR_DIRS= \
- logs archives lists locks data spam qfiles \
+ archives lists data spam \
archives/private archives/public
ARCH_INDEP_DIRS= \
@@ -105,6 +114,15 @@ doinstall: $(SUBDIRS)
else true; \
fi; \
done
+ @for d in $(FHS_DIRS); \
+ do \
+ dir=$(DESTDIR)/$$d; \
+ if test ! -d $$dir; then \
+ echo "Creating directory $$dir"; \
+ $(INSTALL) -d -m $(DIRMODE) $$dir; \
+ else true; \
+ fi; \
+ done
chmod o-r $(DESTDIR)$(var_prefix)/archives/private
@for d in $(ARCH_INDEP_DIRS); \
do \
diff --git a/bin/check_perms b/bin/check_perms
index 137ebfb..1f45f84 100755
--- a/bin/check_perms
+++ b/bin/check_perms
@@ -183,7 +183,8 @@ def checkall():
print C_('checking mode for %(prefix)s')
dirs = {}
for d in (mm_cfg.PREFIX, mm_cfg.EXEC_PREFIX, mm_cfg.VAR_PREFIX,
- mm_cfg.LOG_DIR):
+ mm_cfg.CONFIG_DIR, mm_cfg.DATA_DIR, mm_cfg.LOCK_DIR,
+ mm_cfg.LOG_DIR, mm_cfg.QUEUE_DIR, mm_cfg.PID_DIR):
dirs[d] = True
for d in dirs.keys():
try:
diff --git a/configure.in b/configure.in
index f2eb1c0..c01129c 100644
--- a/configure.in
+++ b/configure.in
@@ -305,6 +305,72 @@ else
prefixcheck=$VAR_PREFIX
fi
+# Get the configuration file directory
+AC_SUBST(CONFIG_DIR)
+AC_MSG_CHECKING(for --with-config-dir)
+AC_ARG_WITH(config-dir, dnl
+[ --with-config-dir specify directory for configuration data other than [VAR_]PREFIX/data])
+case "$with_config_dir" in
+ yes|no|"") CONFIG_DIR="$VAR_PREFIX/data";;
+ *) CONFIG_DIR=$with_config_dir;;
+esac
+AC_MSG_RESULT($CONFIG_DIR)
+
+# Get the lock directory
+AC_SUBST(LOCK_DIR)
+AC_MSG_CHECKING(for --with-lock-dir)
+AC_ARG_WITH(lock-dir, dnl
+[ --with-lock-dir specify directory for lock files other than [VAR_]PREFIX/locks])
+case "$with_lock_dir" in
+ yes|no|"") LOCK_DIR="$VAR_PREFIX/locks";;
+ *) LOCK_DIR=$with_lock_dir;;
+esac
+AC_MSG_RESULT($LOCK_DIR)
+
+# Get the log directory
+AC_SUBST(LOG_DIR)
+AC_MSG_CHECKING(for --with-log-dir)
+AC_ARG_WITH(log-dir, dnl
+[ --with-log-dir specify directory for log files other than [VAR_]PREFIX/logs])
+case "$with_log_dir" in
+ yes|no|"") LOG_DIR="$VAR_PREFIX/logs";;
+ *) LOG_DIR=$with_log_dir;;
+esac
+AC_MSG_RESULT($LOG_DIR)
+
+# Get the pid directory
+AC_SUBST(PID_DIR)
+AC_MSG_CHECKING(for --with-pid-dir)
+AC_ARG_WITH(pid-dir, dnl
+[ --with-pid-dir specify directory for the pid file other than [VAR_]PREFIX/data])
+case "$with_pid_dir" in
+ yes|no|"") PID_DIR="$VAR_PREFIX/data";;
+ *) PID_DIR=$with_pid_dir;;
+esac
+AC_MSG_RESULT($PID_DIR)
+
+# Get the queue directory
+AC_SUBST(QUEUE_DIR)
+AC_MSG_CHECKING(for --with-queue-dir)
+AC_ARG_WITH(queue-dir, dnl
+[ --with-queue-dir specify directory for queue files other than [VAR_]PREFIX/qfiles])
+case "$with_queue_dir" in
+ yes|no|"") QUEUE_DIR="$VAR_PREFIX/qfiles";;
+ *) QUEUE_DIR=$with_queue_dir;;
+esac
+AC_MSG_RESULT($QUEUE_DIR)
+
+# Get the template directory
+AC_SUBST(TEMPLATE_DIR)
+AC_MSG_CHECKING(for --with-template-dir)
+AC_ARG_WITH(template-dir, dnl
+[ --with-template-dir specify directory for template files other than [VAR_]PREFIX/templates])
+case "$with_template_dir" in
+ yes|no|"") TEMPLATE_DIR="$VAR_PREFIX/templates";;
+ *) TEMPLATE_DIR=$with_template_dir;;
+esac
+AC_MSG_RESULT($TEMPLATE_DIR)
+
# new macro for finding group names
# returns a comma separated list of quoted group names
# the list is returned in the same order as specified with any duplicates removed
diff --git a/misc/Makefile.in b/misc/Makefile.in
index af99c04..df50a06 100644
--- a/misc/Makefile.in
+++ b/misc/Makefile.in
@@ -27,6 +27,12 @@ bindir= @bindir@
prefix= @prefix@
exec_prefix= @exec_prefix@
var_prefix= @VAR_PREFIX@
+configdir= @CONFIG_DIR@
+lockdir= @LOCK_DIR@
+logdir= @LOG_DIR@
+piddir= @PID_DIR@
+queuedir= @QUEUE_DIR@
+MAILMAN_GROUP= @MAILMAN_GROUP@
DESTDIR=
CC= @CC@
@@ -87,7 +93,7 @@ install-other:
$(INSTALL) -m $(FILEMODE) paths.py $$dir; \
done
$(INSTALL) -m $(EXEMODE) mailman $(DESTDIR)$(SCRIPTSDIR)
- $(INSTALL) -m $(FILEMODE) sitelist.cfg $(DESTDIR)$(DATADIR)
+ $(INSTALL) -m $(FILEMODE) sitelist.cfg $(DESTDIR)$(configdir)
install-packages:
if [ -z "$(EMAILPKG)" -a -d $(DESTDIR)$(PYTHONLIBDIR)/email ] ; \
diff --git a/templates/Makefile.in b/templates/Makefile.in
index b23d7c1..16930a2 100644
--- a/templates/Makefile.in
+++ b/templates/Makefile.in
@@ -25,6 +25,7 @@ srcdir= @srcdir@
bindir= @bindir@
prefix= @prefix@
exec_prefix= @exec_prefix@
+template_dir= @TEMPLATE_DIR@
DESTDIR=
CC= @CC@
@@ -37,7 +38,7 @@ DEFS= @DEFS@
OPT= @OPT@
CFLAGS= $(OPT) $(DEFS)
-TEMPLATEDIR= $(prefix)/templates
+TEMPLATEDIR= $(template_dir)
SHELL= /bin/sh

View File

@ -0,0 +1,21 @@
diff -up mailman-2.1.13/templates/en/article.html.archive-reply mailman-2.1.13/templates/en/article.html
--- mailman-2.1.13/templates/en/article.html.archive-reply 2009-12-22 19:00:43.000000000 +0100
+++ mailman-2.1.13/templates/en/article.html 2010-03-25 13:50:02.000000000 +0100
@@ -4,7 +4,7 @@
<TITLE> %(title)s
</TITLE>
<LINK REL="Index" HREF="index.html" >
- <LINK REL="made" HREF="mailto:%(email_url)s?Subject=%(subject_url)s&In-Reply-To=%(in_reply_to_url)s">
+ <LINK REL="made" HREF="mailto:%(email_url)s?Subject=Re:%%20%(subject_url)s&In-Reply-To=%(in_reply_to_url)s">
<META NAME="robots" CONTENT="index,nofollow">
<style type="text/css">
pre {
@@ -18,7 +18,7 @@
<BODY BGCOLOR="#ffffff">
<H1>%(subject_html)s</H1>
<B>%(author_html)s</B>
- <A HREF="mailto:%(email_url)s?Subject=%(subject_url)s&In-Reply-To=%(in_reply_to_url)s"
+ <A HREF="mailto:%(email_url)s?Subject=Re:%%20%(subject_url)s&In-Reply-To=%(in_reply_to_url)s"
TITLE="%(subject_html)s">%(email_html)s
</A><BR>
<I>%(datestr_html)s</I>

View File

@ -0,0 +1,25 @@
diff --git a/tests/onebounce.py b/tests/onebounce.py
index 846c4fa..85f3b98 100755
--- a/tests/onebounce.py
+++ b/tests/onebounce.py
@@ -1,4 +1,4 @@
-#! /usr/bin/env python
+#! /usr/bin/python
# Copyright (C) 2002-2018 by the Free Software Foundation, Inc.
#
diff --git a/configure.in b/configure.in
index eee7f3a..2250ade 100644
--- a/configure.in
+++ b/configure.in
@@ -892,6 +892,10 @@ cron/gate_news \
cron/mailpasswds \
cron/nightly_gzip \
cron/senddigests \
+contrib/check_perms_grsecurity.py \
+contrib/qmail-to-mailman.py \
+contrib/rotatelogs.py \
+contrib/sitemapgen
])
dnl Please make sure to leave a space at the end of the last entry.

View File

@ -0,0 +1,22 @@
diff --git a/bin/check_perms b/bin/check_perms
index 5ef3306..d50518a 100755
--- a/bin/check_perms
+++ b/bin/check_perms
@@ -70,7 +70,7 @@ class State:
STATE = State()
-DIRPERMS = S_ISGID | S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH
+DIRPERMS = S_IRWXU | S_IRGRP | S_IROTH | S_IXOTH
QFILEPERMS = S_ISGID | S_IRWXU | S_IRWXG
PYFILEPERMS = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
ARTICLEFILEPERMS = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP
@@ -195,7 +195,7 @@ def checkall():
continue
if (mode & DIRPERMS) <> DIRPERMS:
STATE.ERRORS += 1
- print C_('directory must be at least 02775: %(d)s'),
+ print C_('directory must be at least 0755: %(d)s'),
if STATE.FIX:
print C_('(fixing)')
os.chmod(d, mode | DIRPERMS)

View File

@ -0,0 +1,16 @@
=== modified file 'Mailman/Queue/CommandRunner.py'
--- Mailman/Queue/CommandRunner.py 2018-06-17 23:47:34 +0000
+++ Mailman/Queue/CommandRunner.py 2021-03-31 21:53:20 +0000
@@ -100,6 +100,11 @@
# E.g the outer Content-Type: was text/html
return
body = part.get_payload(decode=True)
+ if (part.get_content_charset(None)):
+ body = unicode(body, part.get_content_charset(),
+ errors='replace').encode(
+ Utils.GetCharSet(self.msgdata['lang']),
+ errors='replace')
# text/plain parts better have string payloads
assert isinstance(body, StringType) or isinstance(body, UnicodeType)
lines = body.splitlines()

View File

@ -0,0 +1,13 @@
=== modified file 'Mailman/Cgi/options.py'
--- Mailman/Cgi/options.py 2019-03-06 17:48:32 +0000
+++ Mailman/Cgi/options.py 2020-04-20 03:10:16 +0000
@@ -173,7 +173,7 @@
try:
Utils.ValidateEmail(user)
except Errors.EmailAddressError:
- doc.addError(_('Illegal Email Address: %(safeuser)s'))
+ doc.addError(_('Illegal Email Address'))
loginpage(mlist, doc, None, language)
print doc.Format()
return

View File

@ -0,0 +1,22 @@
=== modified file 'Mailman/Cgi/private.py'
--- Mailman/Cgi/private.py 2019-03-06 17:48:32 +0000
+++ Mailman/Cgi/private.py 2020-05-07 13:53:40 +0000
@@ -162,13 +162,9 @@
if mlist.isMember(username):
mlist.MailUserPassword(username)
elif username:
- # Not a member
- if mlist.private_roster == 0:
- # Public rosters
- safeuser = Utils.websafe(username)
- message = Bold(FontSize('+1',
- _('No such member: %(safeuser)s.'))).Format()
- else:
+ # Not a member. Don't report address in any case. It leads to
+ # Content injection. Just log if roster is not public.
+ if mlist.private_roster != 0:
syslog('mischief',
'Reminder attempt of non-member w/ private rosters: %s',
username)

View File

@ -0,0 +1,48 @@
diff -ruN mailman-2.1.12-a/Mailman/Archiver/pipermail.py mailman-2.1.12-b/Mailman/Archiver/pipermail.py
--- mailman-2.1.12-a/Mailman/Archiver/pipermail.py 2009-02-23 22:23:35.000000000 +0100
+++ mailman-2.1.12-b/Mailman/Archiver/pipermail.py 2009-07-28 12:19:53.000000000 +0200
@@ -45,24 +45,27 @@
def fixAuthor(author):
"Canonicalize a name into Last, First format"
- # If there's a comma, guess that it's already in "Last, First" format
- if ',' in author:
+ try:
+ # If there's a comma, guess that it's already in "Last, First" format
+ if ',' in author:
+ return author
+ L = author.split()
+ i = len(L) - 1
+ if i == 0:
+ return author # The string's one word--forget it
+ if author.upper() == author or author.lower() == author:
+ # Damn, the name is all upper- or lower-case.
+ while i > 0 and L[i-1].lower() in smallNameParts:
+ i = i - 1
+ else:
+ # Mixed case; assume that small parts of the last name will be
+ # in lowercase, and check them against the list.
+ while i>0 and (L[i-1][0] in lowercase or
+ L[i-1].lower() in smallNameParts):
+ i = i - 1
+ author = SPACE.join(L[-1:] + L[i:-1]) + ', ' + SPACE.join(L[:i])
+ except UnicodeDecodeError:
return author
- L = author.split()
- i = len(L) - 1
- if i == 0:
- return author # The string's one word--forget it
- if author.upper() == author or author.lower() == author:
- # Damn, the name is all upper- or lower-case.
- while i > 0 and L[i-1].lower() in smallNameParts:
- i = i - 1
- else:
- # Mixed case; assume that small parts of the last name will be
- # in lowercase, and check them against the list.
- while i>0 and (L[i-1][0] in lowercase or
- L[i-1].lower() in smallNameParts):
- i = i - 1
- author = SPACE.join(L[-1:] + L[i:-1]) + ', ' + SPACE.join(L[:i])
return author
# Abstract class for databases

View File

@ -0,0 +1,129 @@
diff --git a/Mailman/CSRFcheck.py b/Mailman/CSRFcheck.py
index a1e78d9..0940b7e 100644
--- a/Mailman/CSRFcheck.py
+++ b/Mailman/CSRFcheck.py
@@ -18,11 +18,13 @@
""" Cross-Site Request Forgery checker """
import time
+import urllib
import marshal
import binascii
from Mailman import mm_cfg
-from Mailman.Utils import sha_new
+from Mailman.Logging.Syslog import syslog
+from Mailman.Utils import UnobscureEmail, sha_new
keydict = {
'user': mm_cfg.AuthUser,
@@ -37,6 +39,10 @@ keydict = {
def csrf_token(mlist, contexts, user=None):
""" create token by mailman cookie generation algorithm """
+ if user:
+ # Unmunge a munged email address.
+ user = UnobscureEmail(urllib.unquote(user))
+
for context in contexts:
key, secret = mlist.AuthContextInfo(context, user)
if key:
@@ -49,9 +55,8 @@ def csrf_token(mlist, contexts, user=None):
token = binascii.hexlify(marshal.dumps((issued, keymac)))
return token
-def csrf_check(mlist, token):
+def csrf_check(mlist, token, options_user=None):
""" check token by mailman cookie validation algorithm """
-
try:
issued, keymac = marshal.loads(binascii.unhexlify(token))
key, received_mac = keymac.split(':', 1)
@@ -62,6 +67,17 @@ def csrf_check(mlist, token):
key, user = key.split('+', 1)
else:
user = None
+ if user:
+ # This is for CVE-2021-42097. The token is a user token because
+ # of the fix for CVE-2021-42096 but it must match the user for
+ # whom the options page is requested.
+ raw_user = UnobscureEmail(urllib.unquote(user))
+ if options_user and options_user != raw_user:
+ syslog('mischief',
+ 'Form for user %s submitted with CSRF token '
+ 'issued for %s.',
+ options_user, raw_user)
+ return False
context = keydict.get(key)
key, secret = mlist.AuthContextInfo(context, user)
assert key
diff --git a/Mailman/Cgi/options.py b/Mailman/Cgi/options.py
index ee2293e..472a02b 100644
--- a/Mailman/Cgi/options.py
+++ b/Mailman/Cgi/options.py
@@ -54,9 +54,6 @@ except NameError:
True = 1
False = 0
-AUTH_CONTEXTS = (mm_cfg.AuthListAdmin, mm_cfg.AuthSiteAdmin,
- mm_cfg.AuthListModerator, mm_cfg.AuthUser)
-
def main():
global _
@@ -124,15 +121,6 @@ def main():
print doc.Format()
return
- if set(params) - set(safe_params):
- csrf_checked = csrf_check(mlist, cgidata.getfirst('csrf_token'))
- else:
- csrf_checked = True
- # if password is present, void cookie to force password authentication.
- if cgidata.getfirst('password'):
- os.environ['HTTP_COOKIE'] = ''
- csrf_checked = True
-
# Set the language for the page. If we're coming from the listinfo cgi,
# we might have a 'language' key in the cgi data. That was an explicit
# preference to view the page in, so we should honor that here. If that's
@@ -169,6 +157,16 @@ def main():
user = user[-1].strip()
# Avoid cross-site scripting attacks
+ if set(params) - set(safe_params):
+ csrf_checked = csrf_check(mlist, cgidata.getfirst('csrf_token'),
+ Utils.UnobscureEmail(urllib.unquote(user)))
+ else:
+ csrf_checked = True
+ # if password is present, void cookie to force password authentication.
+ if cgidata.getfirst('password'):
+ os.environ['HTTP_COOKIE'] = ''
+ csrf_checked = True
+
safeuser = Utils.websafe(user)
try:
Utils.ValidateEmail(user)
@@ -868,8 +866,9 @@ def options_page(mlist, doc, user, cpuser, userlang, message=''):
mlist.FormatButton('othersubs',
_('List my other subscriptions')))
replacements['<mm-form-start>'] = (
+ # Always make the CSRF token for the user. CVE-2021-42096
mlist.FormatFormStart('options', user, mlist=mlist,
- contexts=AUTH_CONTEXTS, user=user))
+ contexts=[mm_cfg.AuthUser], user=user))
replacements['<mm-user>'] = user
replacements['<mm-presentable-user>'] = presentable_user
replacements['<mm-email-my-pw>'] = mlist.FormatButton(
diff --git a/Mailman/SecurityManager.py b/Mailman/SecurityManager.py
index 9b7f03f..e9e5ce5 100644
--- a/Mailman/SecurityManager.py
+++ b/Mailman/SecurityManager.py
@@ -104,6 +104,7 @@ class SecurityManager:
if user is None:
# A bad system error
raise TypeError, 'No user supplied for AuthUser context'
+ user = Utils.UnobscureEmail(urllib.unquote(user))
secret = self.getMemberPassword(user)
userdata = urllib.quote(Utils.ObscureEmail(user), safe='')
key += 'user+%s' % userdata

View File

@ -0,0 +1,82 @@
diff --git a/Mailman/CSRFcheck.py b/Mailman/CSRFcheck.py
index 24e3e11..81998cf 100644
--- a/Mailman/CSRFcheck.py
+++ b/Mailman/CSRFcheck.py
@@ -55,7 +55,7 @@ def csrf_token(mlist, contexts, user=None):
token = binascii.hexlify(marshal.dumps((issued, keymac)))
return token
-def csrf_check(mlist, token, options_user=None):
+def csrf_check(mlist, token, cgi_user=None):
""" check token by mailman cookie validation algorithm """
try:
issued, keymac = marshal.loads(binascii.unhexlify(token))
@@ -67,12 +67,25 @@ def csrf_check(mlist, token, options_user=None):
key, user = key.split('+', 1)
else:
user = None
+ # Don't allow unprivileged tokens for admin or admindb.
+ if cgi_user == 'admin':
+ if key not in ('admin', 'site'):
+ syslog('mischief',
+ 'admin form submitted with CSRF token issued for %s.',
+ key + '+' + user if user else key)
+ return False
+ elif cgi_user == 'admindb':
+ if key not in ('moderator', 'admin', 'site'):
+ syslog('mischief',
+ 'admindb form submitted with CSRF token issued for %s.',
+ key + '+' + user if user else key)
+ return False
if user:
# This is for CVE-2021-42097. The token is a user token because
# of the fix for CVE-2021-42096 but it must match the user for
# whom the options page is requested.
raw_user = UnobscureEmail(urllib.unquote(user))
- if options_user and options_user != raw_user:
+ if cgi_user and cgi_user != raw_user:
syslog('mischief',
'Form for user %s submitted with CSRF token '
'issued for %s.',
diff --git a/Mailman/Cgi/admin.py b/Mailman/Cgi/admin.py
index d2577b5..7c600df 100644
--- a/Mailman/Cgi/admin.py
+++ b/Mailman/Cgi/admin.py
@@ -107,7 +107,8 @@ def main():
'legend']
params = cgidata.keys()
if set(params) - set(safe_params):
- csrf_checked = csrf_check(mlist, cgidata.getfirst('csrf_token'))
+ csrf_checked = csrf_check(mlist, cgidata.getfirst('csrf_token'),
+ 'admin')
else:
csrf_checked = True
# if password is present, void cookie to force password authentication.
diff --git a/Mailman/Cgi/admindb.py b/Mailman/Cgi/admindb.py
index 58bb357..c152501 100644
--- a/Mailman/Cgi/admindb.py
+++ b/Mailman/Cgi/admindb.py
@@ -144,7 +144,8 @@ def main():
safe_params = ['adminpw', 'admlogin', 'msgid', 'sender', 'details']
params = cgidata.keys()
if set(params) - set(safe_params):
- csrf_checked = csrf_check(mlist, cgidata.getfirst('csrf_token'))
+ csrf_checked = csrf_check(mlist, cgidata.getfirst('csrf_token'),
+ 'admindb')
else:
csrf_checked = True
# if password is present, void cookie to force password authentication.
diff --git a/Mailman/Cgi/edithtml.py b/Mailman/Cgi/edithtml.py
index 1dd9e87..170e811 100644
--- a/Mailman/Cgi/edithtml.py
+++ b/Mailman/Cgi/edithtml.py
@@ -111,7 +111,8 @@ def main():
safe_params = ['VARHELP', 'adminpw', 'admlogin']
params = cgidata.keys()
if set(params) - set(safe_params):
- csrf_checked = csrf_check(mlist, cgidata.getfirst('csrf_token'))
+ csrf_checked = csrf_check(mlist, cgidata.getfirst('csrf_token'),
+ 'admin')
else:
csrf_checked = True
# if password is present, void cookie to force password authentication.

47
SOURCES/mailman-crontab-edit Executable file
View File

@ -0,0 +1,47 @@
#!/usr/bin/python2
# This script inserts the mailman user name into the crontab entries after
# the 5 time/date fields so that it can be installed under /etc/cron.d
#
# usage: mailman-crontab-edit [-s src_file] [-u mailman_user] [-d dst_file]
# src_file defaults to stdin
# mailman_user defaults to mailman
# dst_file defaults to stdout
import sys, re, getopt
srcFile = None
dstFile = None
mmUser = None
opts, args = getopt.getopt(sys.argv[1:], "s:d:u:")
for o, a in opts:
if o == "-s":
srcFile = a
if o == "-d":
dstFile = a
if o == "-u":
mmUser = a
if srcFile:
inFD = open(srcFile)
else:
inFD = sys.stdin
if dstFile:
outFD = open(dstFile, mode='w')
else:
outFD = sys.stdout
if not mmUser:
mmUser = "mailman"
comment_re = re.compile(r'^\s*#')
time_date_re = re.compile(r'(^\s*(\S+\s+){5,5})')
for line in inFD:
if not comment_re.search(line):
match = time_date_re.search(line)
if match:
line = time_date_re.sub(r'\1 %s ' % mmUser, line)
print >>outFD, line,

293
SOURCES/mailman-migrate-fhs Executable file
View File

@ -0,0 +1,293 @@
#!/usr/bin/python2
import sys
import os
import re
import shutil
import getopt
from stat import *
#------------------------------------------------------------------------------
# Command Line Args
doit = True
verbose = False
quiet = False
warn = False
force = False
print_mapping = False
remove_files = False
remove_installation = False
# Scan Results
existing_files = {}
non_existing_files = {}
# Directory and File mappings
# This is the complete directory map, it includes both data files
# and run-time files
dir_map = {
'/var/mailman' : '/var/lib/mailman',
'/var/mailman/Mailman' : '/usr/lib/mailman/Mailman',
'/var/mailman/archives' : '/var/lib/mailman/archives',
'/var/mailman/bin' : '/usr/lib/mailman/bin',
'/var/mailman/cgi-bin' : '/usr/lib/mailman/cgi-bin',
'/var/mailman/cron' : '/usr/lib/mailman/cron',
'/var/mailman/data' : '/var/lib/mailman/data',
'/var/mailman/lists' : '/var/lib/mailman/lists',
'/var/mailman/locks' : '/var/lock/mailman',
'/var/mailman/logs' : '/var/log/mailman',
'/var/mailman/mail' : '/usr/lib/mailman/mail',
'/var/mailman/messages' : '/usr/lib/mailman/messages',
'/var/mailman/pythonlib' : '/usr/lib/mailman/pythonlib',
'/var/mailman/qfiles' : '/var/spool/mailman',
'/var/spool/mailman/qfiles' : '/var/spool/mailman',
'/var/mailman/scripts' : '/usr/lib/mailman/scripts',
'/var/mailman/spam' : '/var/lib/mailman/spam',
'/var/mailman/templates' : '/usr/lib/mailman/templates',
'/var/mailman/tests' : '/usr/lib/mailman/tests'
}
# These are directories that contain data files the user may
# want to preserve from an old installation and should be copied
# into the new directory location.
data_dir_map = {
'/var/mailman/archives' : '/var/lib/mailman/archives',
'/var/mailman/data' : '/var/lib/mailman/data',
'/var/mailman/lists' : '/var/lib/mailman/lists',
'/var/mailman/logs' : '/var/log/mailman',
'/var/mailman/qfiles' : '/var/spool/mailman',
'/var/spool/mailman/qfiles' : '/var/spool/mailman',
'/var/mailman/spam' : '/var/lib/mailman/spam',
}
# These are mappings for individual files. They represent files that
# cannot be mapped via their parent dirctories, they must be treated
# individually.
file_map = {
'/var/mailman/data/adm.pw' : '/etc/mailman/adm.pw',
'/var/mailman/data/creator.pw' : '/etc/mailman/creator.pw',
'/var/mailman/data/aliases' : '/etc/mailman/aliases',
'/var/mailman/data/virtual-mailman' : '/etc/mailman/virtual-mailman',
'/var/mailman/data/sitelist.cfg' : '/etc/mailman/sitelist.cfg',
'/var/mailman/data/master-qrunner.pid' : '/var/run/mailman/master-qrunner.pid'
}
#------------------------------------------------------------------------------
def DumpMapping():
'''Print out the directory and file mappings'''
print "Directory Mapping:"
for key in dir_map.keys():
print "%s --> %s" %(key, dir_map[key])
print "\nFile Mapping:"
for key in file_map.keys():
print "%s --> %s" %(key, file_map[key])
def RecordFile(src, dst):
'''If the src files (old) exists record this as a potential
file operation. File operations are grouped into two sets,
those where the dst (new) files exists and those where it does not
exist. This is done to prevent overwriting files'''
global existing_files, non_existing_files
if not os.path.exists(src):
return
if existing_files.has_key(src):
if warn:
print "WARNING: src file already seen (%s) and has dst match: (%s)" % (src, dst)
return
if non_existing_files.has_key(src):
if warn:
print "WARNING: src file already seen (%s) does not have dst match" % (src)
return
if os.path.exists(dst):
existing_files[src] = dst
else:
non_existing_files[src] = dst
def GetCopyFiles(old_root, new_root):
'''Recursively generate a list of src files (old) in the old_root
and pair each of them with their new dst path name'''
prefix_re = re.compile("^(%s)/*(.*)" % re.escape(old_root))
dst_files_existing = []
dst_files_non_existing = []
for root, dirs, files in os.walk(old_root):
match = prefix_re.match(root)
subdir = match.group(2)
for name in files:
oldpath = os.path.join(root, name)
newpath = os.path.join(new_root, subdir, name)
RecordFile(oldpath, newpath)
def CopyFile(src_path, dst_path):
'''Copy file, preserve its mode and ownership. If the dst directory
does not exist, create it preserving the mode and ownership of the
src direcotry'''
if not doit:
print "cp %s %s" % (src_path, dst_path)
return
src_dir = os.path.dirname(src_path)
dst_dir = os.path.dirname(dst_path)
if not os.path.isdir(dst_dir):
if os.path.exists(dst_dir):
print "ERROR: dst dir exists, but is not directory (%s)" % dst_dir
return
st = os.stat(src_dir)
os.makedirs(dst_dir, st[ST_MODE])
os.chown(dst_dir, st[ST_UID], st[ST_GID])
shutil.copy2(src_path, dst_path)
st = os.stat(src_path)
os.chown(dst_path, st[ST_UID], st[ST_GID])
def RemoveFile(path):
'''Remove the file'''
if not os.path.exists(path):
if warn:
print "WARNING: attempt to remove non-existent file (%s)" % path
return
if not os.path.isfile(path):
if warn:
print "WARNING: attempt to remove non-plain file (%s)" % path
return
if not doit:
print "rm %s" % (path)
return
os.unlink(path)
def RemoveDirs(top):
'''Delete everything reachable from the directory named in 'top',
assuming there are no symbolic links.
CAUTION: This is dangerous! For example, if top == '/', it
could delete all your disk files.'''
for root, dirs, files in os.walk(top, topdown=False):
for name in files:
path = os.path.join(root, name)
if not doit:
print "rm %s" % (path)
else:
os.remove(path)
for name in dirs:
path = os.path.join(root, name)
if not doit:
print "rmdir %s" % (path)
else:
os.rmdir(path)
def Usage():
print """
This script will help you copy mailman data files from the old
directory structure to the new FHS directory structure.
Mailman should not be running when you perform this!
/sbin/service mailman stop
This script is conservative, by default it will not overwrite
any file in the new directory on the assumption it is most recent
and most correct. If you want to force overwrites use -f.
Files are copied to the new directories, if you want to remove the
old data files use -r. Hint: copy first and test, once everything is
working remove the old files with -r. If you want to remove the entire
old installation use -R
migrate [-f] [-n] [-q] [-v] [-w] [-m] [-r] [-R]
-n don't execute, but show what would be done
-f force destination overwrites
-m print mapping
-r remove old data files
-R remove entire old installation
-q be quiet
-v be verbose
-w print warnings
-h help
"""
#------------------------------------------------------------------------------
try:
opts, args = getopt.getopt(sys.argv[1:], "nfvmqwhrR")
for o, a in opts:
if o == "-n":
doit = False
elif o == "-f":
force = True
elif o == "-v":
verbose = True
elif o == "-m":
print_mapping = True
elif o == "-q":
quiet = True
elif o == "-w":
warn = True
elif o == "-r":
remove_files = True
elif o == "-R":
remove_installation = True
elif o == "-h":
Usage()
sys.exit(1)
except getopt.GetoptError, err:
print err
Usage()
sys.exit(1)
if print_mapping:
DumpMapping()
sys.exit(0)
# Generate file list
for src_dir in data_dir_map.keys():
GetCopyFiles(src_dir, dir_map[src_dir])
for src_file in file_map.keys():
RecordFile(src_file, file_map[src_file])
# Copy files
for src in non_existing_files:
dst = non_existing_files[src]
CopyFile(src, dst)
if force:
for src in existing_files:
dst = existing_files[src]
CopyFile(src, dst)
else:
if len(existing_files) > 0 and not quiet:
print "\nThe following files already exist in the destination, they will NOT be copied"
print "To force overwriting invoke with -f\n"
for src in existing_files:
dst = existing_files[src]
print "# cp %s %s" %(src, dst)
# Remove old files
if remove_files:
for src in existing_files:
RemoveFile(src)
for src in non_existing_files:
RemoveFile(src)
if remove_installation:
for old_dir in dir_map.keys():
RemoveDirs(old_dir)
sys.exit(0)

View File

@ -0,0 +1,13 @@
diff --git a/Makefile.in b/Makefile.in
index dc2fc59..45988b4 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -129,7 +129,7 @@ doinstall: $(SUBDIRS)
do \
(cd $$d; $(MAKE) DESTDIR=$(DESTDIR) install); \
done
- $(PYTHON) -c 'from compileall import *; compile_dir("$(DESTDIR)$(prefix)/Mailman", ddir="$(prefix)/Mailman")'
+ $(PYTHON) -c 'from compileall import *; compile_dir("$(DESTDIR)$(prefix)/Mailman", 20, "$(prefix)", 1)'
# Only run bin/update if we aren't installing in DESTDIR, as this
# means there are probably no lists to deal with, and it wouldn't

View File

@ -0,0 +1,70 @@
diff --git a/contrib/courier-to-mailman.py b/contrib/courier-to-mailman.py
index 922401f..572b47d 100644
--- a/contrib/courier-to-mailman.py
+++ b/contrib/courier-to-mailman.py
@@ -1,4 +1,4 @@
-#! /usr/bin/python
+#! /usr/bin/python2
# Configuration variables - Change these for your site if necessary.
#
diff --git a/tests/onebounce.py b/tests/onebounce.py
index 85f3b98..b54d075 100755
--- a/tests/onebounce.py
+++ b/tests/onebounce.py
@@ -1,4 +1,4 @@
-#! /usr/bin/python
+#! /usr/bin/python2
# Copyright (C) 2002-2018 by the Free Software Foundation, Inc.
#
diff --git a/bin/msgfmt.py b/bin/msgfmt.py
index 8a2d4e6..27a40bf 100755
--- a/bin/msgfmt.py
+++ b/bin/msgfmt.py
@@ -1,4 +1,4 @@
-#! /usr/bin/env python
+#!/usr/bin/python2
# -*- coding: iso-8859-1 -*-
# Written by Martin v. Löwis <loewis@informatik.hu-berlin.de>
diff --git a/Mailman/Archiver/pipermail.py b/Mailman/Archiver/pipermail.py
index cfca480..3d6a9d6 100644
--- a/Mailman/Archiver/pipermail.py
+++ b/Mailman/Archiver/pipermail.py
@@ -1,4 +1,4 @@
-#! /usr/bin/env python
+#! /usr/bin/python2
from __future__ import nested_scopes
diff --git a/Mailman/Archiver/pipermail.py.unicode b/Mailman/Archiver/pipermail.py.unicode
index 62fb92e..a663829 100644
--- a/Mailman/Archiver/pipermail.py.unicode
+++ b/Mailman/Archiver/pipermail.py.unicode
@@ -1,4 +1,4 @@
-#! /usr/bin/env python
+#! /usr/bin/python2
from __future__ import nested_scopes
diff --git a/Mailman/Post.py b/Mailman/Post.py
index 7f86696..b4dcfb0 100644
--- a/Mailman/Post.py
+++ b/Mailman/Post.py
@@ -1,4 +1,4 @@
-#! /usr/bin/env python
+#! /usr/bin/python2
#
# Copyright (C) 2001-2018 by the Free Software Foundation, Inc.
#
diff --git a/tests/fblast.py b/tests/fblast.py
index 092e420..905401d 100644
--- a/tests/fblast.py
+++ b/tests/fblast.py
@@ -1,4 +1,4 @@
-#! /usr/bin/env python
+#! /usr/bin/python2
"""Throw email at Mailman as fast as you can.
This is not a unit test, it's a functional test, so you can't run it within

View File

@ -2,12 +2,12 @@
%global __os_install_post %(echo '%{__os_install_post}' | sed -e 's!/usr/lib[^[:space:]]*/brp-python-bytecompile[[:space:]].*$!!g')
Summary: Mailing list manager with built in Web access
Name: mailman
Version: 2.1.29
Release: 12%{?dist}
Version: 2.1.30
Release: 1%{?dist}
Epoch: 3
Group: Applications/Internet
Source0: ftp://ftp.gnu.org/pub/gnu/mailman/mailman-%{version}.tgz
#Source0: http://prdownloads.sourceforge.net/mailman/mailman-%{version}.tgz
#Source0: http://prdownloads.sourceforge.net/mailman/mailman-%%{version}.tgz
Source1: mm_cfg.py
Source3: httpd-mailman.conf
Source4: mailman.logrotate
@ -29,11 +29,11 @@ Patch13: mailman-2.1.9-unicode.patch
Patch21: mailman-2.1.13-env-python.patch
Patch22: mailman-2.1.15-check_perms.patch
Patch24: mailman-specify_python_version.patch
Patch25: mailman-CVE-2020-12137.patch
Patch26: mailman-bouncer_oom_crash.patch
Patch27: mailman-2.1.29-login_content_injection.patch
Patch28: mailman-2.1.29-options_content_njection.patch
Patch29: mailman-2.1.29-cmd_reply_encoding.patch
Patch30: mailman-CVE-2021-42096-2021-42097.patch
Patch31: mailman-CVE-2021-44227.patch
License: GPLv2+
URL: http://www.list.org/
@ -122,11 +122,11 @@ additional installation steps, these are described in:
%patch21 -p1
%patch22 -p1
%patch24 -p1 -b .python_version
%patch25 -p0 -b .cve_obj_mime
%patch26 -p0 -b .bouncer_match
%patch27 -p0 -b .login_injection
%patch28 -p0 -b .options_injection
%patch29 -p0 -b .cmd_reply_encoding
%patch30 -p1 -b .CVE-2021-42096-2021-42097
%patch31 -p1 -b .CVE-2021-44227
#cp $RPM_SOURCE_DIR/mailman.INSTALL.REDHAT.in INSTALL.REDHAT.in
cp %{SOURCE5} INSTALL.REDHAT.in
@ -580,6 +580,19 @@ exit 0
%dir %attr(775,root,%{mmgroup}) %{lockdir}
%changelog
* Wed Jul 26 2023 Martin Osvald <mosvald@redhat.com> - 3:2.1.30-1
- New version 2.1.30
- Fixes DMARC support (#2140631)
* Sun Nov 28 2021 Martin Osvald <mosvald@redhat.com> - 3:2.1.29-12.2
- Fix for CVE-2021-44227
- Resolves: #2026871
* Tue Nov 09 2021 Martin Osvald <mosvald@redhat.com> - 3:2.1.29-12.1
- Fix for CVE-2021-42096
- Fix for CVE-2021-42097
- Resolves: #2021139, #2020692
* Mon Apr 12 2021 Tomas Korbar <tkorbar@redhat.com> - 3:2.1.29-12
- Fix encoding handling of command replies
- Resolves: rhzb#1907323

View File

@ -1 +0,0 @@
mailman package is retired on branch c10s for CS-2551

View File

@ -1 +0,0 @@
SHA512 (mailman-2.1.29.tgz) = ed25179a4580092629890664c5502908b20e326c2ed06ad4e597fb4e8de84076c369ecd7a272be5ed8a1cb4479413d0e004d87804de763ee850e4d04d9a83376