summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbwarsaw1998-05-26 18:42:44 +0000
committerbwarsaw1998-05-26 18:42:44 +0000
commit4b77f88dc96acf9e971908c1badf3305ee618ca1 (patch)
treec425088f9db12fb3f826136f167be5cdc77a9bb4 /src
parenta38041fa64fb30b661a9a55a6c9a3c313ba453a4 (diff)
downloadmailman-4b77f88dc96acf9e971908c1badf3305ee618ca1.tar.gz
mailman-4b77f88dc96acf9e971908c1badf3305ee618ca1.tar.zst
mailman-4b77f88dc96acf9e971908c1badf3305ee618ca1.zip
Several important changes.
1. For mail-wrapper.c and cgi-wrapper.c, most common routines have been moved to common.c. While there were some differences in the way these two wrappers worked (most notably in the error handling and reporting when UID's and GID's didn't match), they were easily merged. Fatal errors now always syslog and exit(1). 2. The exec*() call for running the new process has been changed and made consistent. For improved security, the absolute path to the Python interpreter (as discovered by configure) is compiled into these programs, and the environment variable PYTHONPATH is set to include only the absolute path the the installed Mailman package ($prefix/Mailman). Scripts are invoked by exec'ing the Python interpreter with the first argument being the absolute path to the script to run, along with any additional arguments on argc/argv. See the function run_script() in common.c for details. 3. alias-wrapper.c has not yet been fully merged. I gathered from Ken that it doesn't work completely well anyway. 4. check_caller() in common.c still checks the gid, but as we discussed before, this may be redundant. I wanted one check-in with a history of this feature first though. 5. Added an Emacs turd at the end of all files so that the C code will be edited using Python's standard C style. Reformatted existing code. 6. Removed pseudo-log history from comments at top of files.
Diffstat (limited to 'src')
-rw-r--r--src/alias-wrapper.c45
-rw-r--r--src/cgi-wrapper.c134
-rw-r--r--src/common.c171
-rw-r--r--src/common.h31
-rw-r--r--src/mail-wrapper.c174
5 files changed, 323 insertions, 232 deletions
diff --git a/src/alias-wrapper.c b/src/alias-wrapper.c
index 0b0132246..7930b7ca3 100644
--- a/src/alias-wrapper.c
+++ b/src/alias-wrapper.c
@@ -1,29 +1,28 @@
-/*
-** alias-wrapper.c:
-** wrapper to allow the mailman user to modify the aliases database.
-**
-** Copyright (C) 1998 by the Free Software Foundation, Inc.
-**
-** This program is free software; you can redistribute it and/or
-** modify it under the terms of the GNU General Public License
-** as published by the Free Software Foundation; either version 2
-** of the License, or (at your option) any later version.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-**
-** You should have received a copy of the GNU General Public License
-** along with this program; if not, write to the Free Software
-** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-*/
+/* alias-wrapper.c --- wrapper to allow the mailman user to modify the aliases
+ * database.
+ *
+ * Copyright (C) 1998 by the Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
#include <stdio.h>
-
-const int LEGAL_PARENT_UID = 9001; /* mailman's UID */
-const int LEGAL_PARENT_GID = 6; /* mailman's GID */
+/* passed in from configure script */
+const int LEGAL_PARENT_UID = ALIAS_UID; /* mailman's UID */
+const int LEGAL_PARENT_GID = ALIAS_GID; /* mail's GID */
const char* SENDMAIL_CMD = "/usr/sbin/sendmail";
const char* ALIAS_FILE = "/etc/aliases";
diff --git a/src/cgi-wrapper.c b/src/cgi-wrapper.c
index 37226adcb..6d45e4004 100644
--- a/src/cgi-wrapper.c
+++ b/src/cgi-wrapper.c
@@ -1,105 +1,53 @@
-/*
-** cgi-wrapper.c:
-** generic wrapper that will take info from a environment
-** variable, and pass it to two commands.
-**
-** Copyright (C) 1998 by the Free Software Foundation, Inc.
-**
-** This program is free software; you can redistribute it and/or
-** modify it under the terms of the GNU General Public License
-** as published by the Free Software Foundation; either version 2
-** of the License, or (at your option) any later version.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-**
-** You should have received a copy of the GNU General Public License
-** along with this program; if not, write to the Free Software
-** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-**
-** 10-17-96 : Hal Schechner (hal-j@channel21.com)
-**
-** 12-14-96 : John Viega (viega@list.org)
-** changed to work on 1 command, take a list of
-** valid commands, just pass on argv, and use
-** execvp() Also threw in some useful feedback for
-** when there's a failure, mainly for future
-** debugging.
-**
-** 03-31-98 : John Viega (viega@list.org)
-** Consolidated all CGI wrappers into 1, removed
-** checking the command name, (it was not real
-** security anyway...) and changed it to use
-** syslog on error. This definitely doesn't have
-** any of Hal's code left ;-)
-**
-*/
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <syslog.h>
-
-#define COMMAND "/home/mailman/mailman/cgi/" ## SCRIPT
-#define LOG_IDENT "Mailman-wrapper (" ## SCRIPT ## ")"
-
-const int LEGAL_PARENT_UID = 60001; /* nobody's UID */
-const int LEGAL_PARENT_GID = 60001; /* nobody's GID */
+/* cgi-wrapper.c --- Generic wrapper that will take info from a environment
+ * variable, and pass it to two commands.
+ *
+ * Copyright (C) 1998 by the Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
-/*
-** Report an error then exit.
-*/
-void
-err(char *format, ...)
-{
- char log_entry[1024];
+#include "common.h"
- va_list arg_ptr;
- va_start(arg_ptr, format);
- vsprintf(log_entry, format, arg_ptr);
- va_end(arg_ptr);
+/* passed in by configure */
+#define SCRIPTNAME SCRIPT
+#define LOG_IDENT "Mailman cgi-wrapper (" ## SCRIPT ## ")"
+#define LEGAL_PARENT_UID CGI_UID /* nobody's UID */
+#define LEGAL_PARENT_GID CGI_GID /* nobody's GID */
- /* Write to the console, maillog is often mostly ignored, and root
- * should definitely know about any problems.
- */
- openlog(LOG_IDENT, LOG_CONS, LOG_MAIL);
- syslog(LOG_ERR, "%s", log_entry);
- closelog();
- exit(0);
-}
+const char* logident = LOG_IDENT;
+const char* script = SCRIPTNAME;
+const int parentuid = LEGAL_PARENT_UID;
+const int parentgid = LEGAL_PARENT_GID;
-/*
-** is the parent process allowed to call us?
-*/
-void
-check_caller()
+int
+main(int argc, char** argv, char** env)
{
- /* compare to our parent's uid */
- if (LEGAL_PARENT_UID != getuid()) {
- err("Attempt to exec cgi %d made by uid %d",
- LEGAL_PARENT_UID,
- getuid());
- }
- if (LEGAL_PARENT_GID != getgid()) {
- err("Attempt to exec cgi %d made by gid %d",
- LEGAL_PARENT_GID,
- getgid());
- }
-}
+ int status;
+ check_caller(logident, parentuid, parentgid);
-int
-main(int argc, char **argv, char **env)
-{
- int i;
+ /* if we get here, the caller is OK */
+ status = setuid(geteuid());
+ if (status)
+ fatal(logident, "%s", strerror(errno));
- check_caller();
- /* If we get here, the caller is OK. */
- setuid(geteuid());
- execve(COMMAND, &argv[0], env);
- err("execve of %s failed!", COMMAND);
+ status = run_script(script, argc, argv, env);
+ fatal(logident, "%s", strerror(errno));
+ return status;
}
diff --git a/src/common.c b/src/common.c
new file mode 100644
index 000000000..f21b49759
--- /dev/null
+++ b/src/common.c
@@ -0,0 +1,171 @@
+/* common.c --- Common routines, constants, etc. Used by all the wrappers.
+ *
+ * Copyright (C) 1998 by the Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "common.h"
+
+/* passed in by configure */
+#define SCRIPTDIR PREFIX ## "/scripts/" /* trailing slash */
+#define MODULEDIR PREFIX ## "/Mailman" /* no trailing slash */
+
+const char* prefixdir = PREFIX;
+const char* scriptdir = SCRIPTDIR;
+const char* moduledir = MODULEDIR;
+char* python = PYTHON;
+
+
+
+/* Report on errors and exit
+ */
+void
+fatal(const char* ident, const char* format, ...)
+{
+ char log_entry[1024];
+
+ va_list arg_ptr;
+ va_start(arg_ptr, format);
+ vsprintf(log_entry, format, arg_ptr);
+ va_end(arg_ptr);
+
+ /* Write to the console, maillog is often mostly ignored, and root
+ * should definitely know about any problems.
+ */
+ openlog(ident, LOG_CONS, LOG_MAIL);
+ syslog(LOG_ERR, "%s", log_entry);
+ closelog();
+ exit(1);
+}
+
+
+
+/* Is the parent process allowed to call us?
+ */
+void
+check_caller(const char* ident, uid_t parentuid, gid_t parentgid)
+{
+ /* compare to our parent's uid */
+ if (parentuid != getuid()) {
+ fatal(ident,
+ "Attempt to exec script with invalid uid %d, expected %d",
+ getuid(), parentuid);
+ }
+ if (parentgid != getgid()) {
+ fatal(ident,
+ "Attempt to exec script with invalid gid %d, expected %d",
+ getgid(), parentgid);
+ }
+}
+
+
+
+/* Run a Python script out of the script directory
+ *
+ * args[0] should be the abs path to the Python script to execute
+ * argv[1:] are other args for the script
+ * env may or may not contain PYTHONPATH, we'll substitute our own
+ */
+int
+run_script(const char* script, int argc, char** argv, char** env)
+{
+ const char envstr[] = "PYTHONPATH=";
+ const int envlen = strlen(envstr);
+
+ int envcnt = 0;
+ int i, j, status;
+ char** newenv;
+ char** newargv;
+
+ /* We want to tightly control how the CGI scripts get executed.
+ * For portability and security, the path to the Python executable
+ * is hard-coded into this C wrapper, rather than encoded in the #!
+ * line of the script that gets executed. So we invoke those
+ * scripts by passing the script name on the command line to the
+ * Python executable.
+ *
+ * We also need to hack on the PYTHONPATH environment variable so
+ * that the path to the installed Mailman modules will show up
+ * first on sys.path.
+ *
+ */
+ for (envcnt = 0; env[envcnt]; envcnt++)
+ ;
+
+ /* okay to be a little too big */
+ newenv = (char**)malloc(sizeof(char*) * (envcnt + 2));
+
+ /* filter out any existing PYTHONPATH in the environment */
+ for (i = 0, j = 0; i < envcnt; i++)
+ if (strncmp(envstr, env[i], envlen)) {
+ newenv[i] = env[j];
+ j++;
+ }
+
+ /* Tack on our own version of PYTHONPATH, which should contain only
+ * the path to the Mailman package modules.
+ *
+ * $(PREFIX)/modules
+ */
+ newenv[j] = (char*)malloc(sizeof(char) * (
+ strlen(envstr) +
+ strlen(moduledir) +
+ 1));
+ strcpy(newenv[j], envstr);
+ strcat(newenv[j], moduledir);
+ j++;
+
+ newenv[j] = NULL;
+
+ /* Now put together argv. This will contain first the absolute path
+ * to the python executable, then the absolute path to the script,
+ * then any additional args passed in argv above.
+ */
+ newargv = (char**)malloc(sizeof(char*) * (argc + 2));
+ newargv[0] = python;
+ newargv[1] = (char*)malloc(sizeof(char) * (
+ strlen(scriptdir) +
+ strlen(script) +
+ 1));
+ strcpy(newargv[1], scriptdir);
+ strcat(newargv[1], script);
+
+ /* now tack on all the rest of the arguments. we can skip argv's
+ * first two arguments because, for cgi-wrapper there is only argv[0].
+ * For mail-wrapper, argv[1] is the mail command (e.g. post,
+ * mailowner, or mailcmd) and argv[2] is the listname. The mail
+ * command to execute gets passed in as this function's `script'
+ * parameter and becomes the argument to the python interpreter. The
+ * list name therefore should become argv[2] to this process.
+ *
+ * TBD: have to make sure this works with alias-wrapper.
+ */
+ for (i = 2; i < argc; i++)
+ newargv[i] = argv[i];
+
+ newargv[i] = NULL;
+
+ status = execve(python, &newargv[0], &newenv[0]);
+ return status;
+}
+
+
+
+/*
+ * Local Variables:
+ * c-file-style: "python"
+ * End:
+ */
diff --git a/src/common.h b/src/common.h
new file mode 100644
index 000000000..a72a4c258
--- /dev/null
+++ b/src/common.h
@@ -0,0 +1,31 @@
+/* common.h --- Prototypes for common routines
+ *
+ * Copyright (C) 1998 by the Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+void fatal(const char*, const char*, ...);
+void check_caller(const char*, uid_t, gid_t);
+int run_script(const char*, int, char**, char**);
diff --git a/src/mail-wrapper.c b/src/mail-wrapper.c
index ea15c409c..1c5390ee9 100644
--- a/src/mail-wrapper.c
+++ b/src/mail-wrapper.c
@@ -1,49 +1,40 @@
-/*
-** mail-wrapper.c:
-** generic wrapper that will take info from a environment
-** variable, and pass it to two commands.
-**
-** Copyright (C) 1998 by the Free Software Foundation, Inc.
-**
-** This program is free software; you can redistribute it and/or
-** modify it under the terms of the GNU General Public License
-** as published by the Free Software Foundation; either version 2
-** of the License, or (at your option) any later version.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-**
-** You should have received a copy of the GNU General Public License
-** along with this program; if not, write to the Free Software
-** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-**
-** 10-17-96 : Hal Schechner (hal-j@channel21.com)
-**
-** 12-14-96 : John Viega (viega@list.org)
-** changed to work on 1 command, take a list of
-** valid commands, just pass on argv, and use
-** execvp() Also threw in some useful feedback for
-** when there's a failure, mainly for future
-** debugging. Made it a root script so we could
-** call setuid()
-**
-** Chmod this 4755.
-**
-*/
-#include <stdio.h>
+/* mail-wrapper.c --- Generic wrapper that will take info from a environment
+ * variable, and pass it to two commands.
+ *
+ * Copyright (C) 1998 by the Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "common.h"
-const char *COMMAND_LOCATION = "/home/mailman/mailman/scripts";
+/* TBD: Should make these arrays too?... */
+#define LEGAL_PARENT_UID MAIL_UID /* mail's UID */
+#define LEGAL_PARENT_GID MAIL_GID /* mail's GID */
-extern int errno;
-FILE *f;
+const int parentuid = LEGAL_PARENT_UID;
+const int parentgid = LEGAL_PARENT_GID;
+const char* logident = "Mailman mail-wrapper";
+
+
const char *VALID_COMMANDS[] = {
"post",
"mailcmd",
"mailowner",
- NULL /* Sentinal, don't remove */
+ NULL /* Sentinel, don't remove */
};
@@ -52,115 +43,66 @@ const char *VALID_COMMANDS[] = {
*/
const char *LEGAL_PARENT_NAMES[] = {
"sendmail",
- NULL /* Sentinal, don't remove */
+ NULL /* Sentinel, don't remove */
};
-/* Should make these arrays too... */
-const int LEGAL_PARENT_UID = 1; /* mail's UID */
-const int LEGAL_PARENT_GID = 1; /* mail's GID */
-
-
-/*
-** what is the name of the process with pid of 'pid'
-*/
-char *
-get_process_name(int pid)
-{
- FILE *proc;
- char fname[30];
- char tmp[255];
- static char procname[255];
-
- sprintf(fname, "/proc/%d/status", pid);
- proc = fopen(fname, "r");
- fgets(tmp, 256, proc);
- sscanf(tmp, "Name: %s\n", procname);
- fclose(proc);
- return procname;
-}
-
+
int
-valid_parent(char *parent)
+check_parent(char *parent)
{
int i = 0;
- while (LEGAL_PARENT_NAMES[i] != NULL) {
- if (!strcmp(parent, LEGAL_PARENT_NAMES[i])) {
+ while (LEGAL_PARENT_NAMES[i]) {
+ if (!strcmp(parent, LEGAL_PARENT_NAMES[i]))
return 1;
- }
i++;
}
return 0;
}
-/*
-** is the parent process allowed to call us?
-*/
-int
-legal_caller()
-{
- /* compare to our parent's uid */
- if (LEGAL_PARENT_UID != getuid()) {
- /* fprintf(f,"GOT UID %d.\n", getuid()); */
- printf("GOT UID %d.\n", getuid());
- return 0;
- }
- if (LEGAL_PARENT_GID != getgid()) {
- /* fprintf(f,"GOT GID %d.\n", getgid()); */
- printf("GOT GID %d.\n", getgid());
- return 0;
- }
- return 1;
-}
-
-
int
-valid_command(char *command)
+check_command(char *command)
{
int i = 0;
while (VALID_COMMANDS[i] != NULL) {
- if (!strcmp(command, VALID_COMMANDS[i])) {
+ if (!strcmp(command, VALID_COMMANDS[i]))
return 1;
- }
i++;
}
return 0;
}
+
int
-main(int argc, char **argv)
+main(int argc, char** argv, char** env)
{
- char *command;
- int i;
-
- if (argc < 2) {
- printf("Usage: %s program [args...]\n", argv[0]);
- fflush(stdout);
- exit(0);
- }
- i = strlen(argv[1]) + strlen(COMMAND_LOCATION) + 2;
- command = (char *)malloc(sizeof(char) * i);
- sprintf(command, "%s/%s", COMMAND_LOCATION, argv[1]);
+ int status;
- if (!valid_command(argv[1])) {
- printf("Illegal command.\n");
- }
- else {
- if (legal_caller()) {
- setuid(geteuid());
- execv(command, &argv[1]);
- }
- else {
- printf("Illegal caller!\n");
- }
- }
+ /* sanity check arguments */
+ if (argc < 2)
+ fatal(logident, "Usage: %s program [args...]\n", argv[0]);
+
+ if (!check_command(argv[1]))
+ fatal(logident, "Illegal command: %s", argv[1]);
+
+ check_caller(logident, parentuid, parentgid);
+
+ /* If we got here, everything must be OK */
+ status = setuid(geteuid());
+ if (status)
+ fatal(logident, "%s", strerror(errno));
+
+ status = run_script(argv[1], argc, argv, env);
+ fatal(logident, "%s", strerror(errno));
+ return status;
}
+
/*
* Local Variables: