On Sat, 2004-10-16 at 04:30, Fil wrote:
> I would like to know if this check can be expanded to list all GID that
> mailman will accept? Or if I should just be more carful in setting up my
> system? :)

We patch mailman to accept multiple GID's. The patch is attached. It
includes changes to configure to accept a list of GID's so don't forget
if you apply the patch you'll have to run autoconf to generate a new
configure.

BTW, the preferred solution as you allude to is to be rigorous with the
identity and permissions of system components. This patch is more of a
concession to the dilemma of distributing mailman in an environment
where other packages and configurations may be installed which are
beyond our control than a suggested approach. Ideally this would not be
necessary and for what its worth I have some misgivings about it. Our
distribution is moving to a more constrained set of packages and much
more security driven. This patch which has been in our RPM for a while
is on the table for removal because of these security concerns.
-- 
John Dennis <[EMAIL PROTECTED]>
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 <<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()
@@ -241,25 +316,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()
@@ -285,7 +376,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"
@@ -316,7 +407,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"
@@ -339,11 +430,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)
@@ -393,7 +484,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"
@@ -420,7 +511,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 -u mailman-2.1.2/src/cgi-wrapper.c.orig mailman-2.1.2/src/cgi-wrapper.c
--- mailman-2.1.2/src/cgi-wrapper.c.orig	2002-08-23 16:39:47.000000000 -0400
+++ mailman-2.1.2/src/cgi-wrapper.c	2003-05-02 16:28:11.000000000 -0400
@@ -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 -u mailman-2.1.2/src/common.c.orig mailman-2.1.2/src/common.c
--- mailman-2.1.2/src/common.c.orig	2002-09-04 21:29:57.000000000 -0400
+++ mailman-2.1.2/src/common.c	2003-05-02 16:28:11.000000000 -0400
@@ -116,13 +116,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,22 +137,45 @@
 	}
 
 	if (!mygroup)
-		fatal(ident, GROUP_NAME_NOT_FOUND,
-		      "Failure to find group name %s.  Try adding this group\n"
-		      "to your system, or re-run configure, providing an\n"
-		      "existing group name with the command line option %s.",
-		      parentgroup, option);
+		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 -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
 
_______________________________________________
Mailman-Developers mailing list
[EMAIL PROTECTED]
http://mail.python.org/mailman/listinfo/mailman-developers
Unsubscribe: 
http://mail.python.org/mailman/options/mailman-developers/archive%40jab.org

Reply via email to