Mailman security is in part enforced by requiring it execute SGID. When the mail process or the web server attempts to execute a mailman script a C program is invoked to verify the group permission. Mailman as it is shipped only allows one group to be specified at build time. For users who build and install on their own machine this is not a limitation. However, when making a binary package to be installed on an arbitrary machine it is hard to predict the correct group to use for that installation. Therefore this patch allows us to specify at build time a list of groups that will be iterated over, if the mailman process is executing as any of one of the group in the set of groups then the permission check passes. Since the groups we build with are limited to a small number of safe groups this does not lower the security much while at the same time provides a much more friendly way to package a binary installation that will run in a wider range of installations. It was necessary to add the macro MM_FIND_GROUP_LIST to the configure.in file replacing the original use of MM_FIND_GROUP_NAME, the former operates on a list of group names while the later on a single name. MM_FIND_GROUP_LIST includes a filter parameter that was added with the notion of supporting the with-permcheck option. If filter is true then only group names that exist on the build machine are permitted in the list, otherwise all names are permitted. However, note that whenever MM_FIND_GROUP_LIST is invoked it is currently hardcoded to disable filtering and is not tied to with-permcheck, this was done because of the observation that if one is passing a list of groups it is likely one is doing so to support installations that have a group not present on the build machine, but one might still want to take advantage of the other with-permcheck functionality. diff -u mailman-2.1.2/configure.in.orig mailman-2.1.2/configure.in --- mailman-2.1.2/configure.in.orig 2003-04-21 23:34:51.000000000 -0400 +++ mailman-2.1.2/configure.in 2003-05-02 16:32:45.000000000 -0400 @@ -208,26 +208,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 < conftest.py < conftest.py <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 -u mailman-2.1.2/src/common.h.orig mailman-2.1.2/src/common.h --- mailman-2.1.2/src/common.h.orig 2002-10-21 14:48:03.000000000 -0400 +++ mailman-2.1.2/src/common.h 2003-05-02 16:28:11.000000000 -0400 @@ -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 -u mailman-2.1.2/src/mail-wrapper.c.orig mailman-2.1.2/src/mail-wrapper.c --- mailman-2.1.2/src/mail-wrapper.c.orig 2002-08-23 16:40:27.000000000 -0400 +++ mailman-2.1.2/src/mail-wrapper.c 2003-05-02 16:28:11.000000000 -0400 @@ -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 -u mailman-2.1.2/src/Makefile.in.orig mailman-2.1.2/src/Makefile.in --- mailman-2.1.2/src/Makefile.in.orig 2003-03-31 14:27:14.000000000 -0500 +++ mailman-2.1.2/src/Makefile.in 2003-05-02 16:28:11.000000000 -0400 @@ -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