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