diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.in | 134 | ||||
| -rw-r--r-- | src/cgi-wrapper.c | 68 | ||||
| -rw-r--r-- | src/common.c | 306 | ||||
| -rw-r--r-- | src/common.h | 62 | ||||
| -rw-r--r-- | src/mail-wrapper.c | 92 | ||||
| -rw-r--r-- | src/vsnprintf.c | 125 |
6 files changed, 0 insertions, 787 deletions
diff --git a/src/Makefile.in b/src/Makefile.in deleted file mode 100644 index 4b9f5fc6b..000000000 --- a/src/Makefile.in +++ /dev/null @@ -1,134 +0,0 @@ -# Copyright (C) 1998-2007 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -# NOTE: Makefile.in is converted into Makefile by the configure script -# in the parent directory. Once configure has run, you can recreate -# the Makefile by running just config.status. - -# Variables set by configure - -prefix= @prefix@ -exec_prefix= @exec_prefix@ -VPATH= @srcdir@ -srcdir= @srcdir@ -bindir= @bindir@ -DESTDIR= - -CC= @CC@ -CHMOD= @CHMOD@ -INSTALL= @INSTALL@ -PYTHON= @PYTHON@ - -DEFS= @DEFS@ -LIBS= @LIBS@ - -# user and group ids/names -MAIL_GROUP= @MAIL_GROUP@ -CGI_GROUP= @CGI_GROUP@ -MAILMAN_USER= @MAILMAN_USER@ - -# Customizable but not set by configure -OPT= @OPT@ -CFLAGS= @CFLAGS@ $(OPT) $(DEFS) $(LIBS) -CGIDIR= $(exec_prefix)/cgi-bin -CGIEXT= @CGIEXT@ -MAILDIR= $(exec_prefix)/mail - -SHELL= /bin/sh - -MAIL_FLAGS= -DMAIL_GROUP="\"$(MAIL_GROUP)\"" - -CGI_FLAGS= -DCGI_GROUP="\"$(CGI_GROUP)\"" - -HELPFUL= -DHELPFUL - -COMMON_FLAGS= -DPREFIX="\"$(prefix)\"" \ - -DPYTHON="\"$(PYTHON)\"" \ - $(HELPFUL) - - -# 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 -INSTALL_PROGRAM=$(INSTALL) -m $(EXEMODE) -DIRSETGID= chmod g+s - -# Fixed definitions - -CGI_PROGS= admindb admin confirm create edithtml listinfo options \ - private rmlist roster subscribe - -COMMONOBJS= common.o vsnprintf.o - -MAIL_PROGS= mailman - -#ALIAS_PROGS= addaliases - -SUID_CGI_PROGS= private - -SUID_MAIL_PROGS= - -PROGRAMS= $(CGI_PROGS) $(MAIL_PROGS) $(ALIAS_PROGS) - - -# Rules - -all: $(PROGRAMS) - -mailman: $(srcdir)/mail-wrapper.c $(COMMONOBJS) - $(CC) -I. $(MAIL_FLAGS) $(CFLAGS) $(COMMONOBJS) -o $@ $(srcdir)/mail-wrapper.c - -#addaliases: $(srcdir)/alias-wrapper.c $(COMMONOBJS) -# $(CC) -I. $(ALIAS_FLAGS) $(CFLAGS) -o $@ $(srcdir)/alias-wrapper.c - -$(CGI_PROGS): $(srcdir)/cgi-wrapper.c $(COMMONOBJS) - $(CC) -DSCRIPT="\"$@\"" -I. $(CGI_FLAGS) $(CFLAGS) $(COMMONOBJS) -o $@ $(srcdir)/cgi-wrapper.c - -common.o: $(srcdir)/common.c $(srcdir)/common.h Makefile - $(CC) -c -I. $(COMMON_FLAGS) $(CFLAGS) $(srcdir)/common.c - -vsnprintf.o: $(srcdir)/vsnprintf.c Makefile - $(CC) -c -I. $(COMMON_FLAGS) $(CFLAGS) $(srcdir)/vsnprintf.c - -install: all - for f in $(CGI_PROGS); \ - 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: - -@rm *.o - -@rm -f $(PROGRAMS) - -distclean: clean - -@rm Makefile diff --git a/src/cgi-wrapper.c b/src/cgi-wrapper.c deleted file mode 100644 index 6be29f6de..000000000 --- a/src/cgi-wrapper.c +++ /dev/null @@ -1,68 +0,0 @@ -/* cgi-wrapper.c --- Generic wrapper that will take info from a environment - * variable, and pass it to two commands. - * - * Copyright (C) 1998-2007 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include "common.h" - -/* passed in by configure */ -#define SCRIPTNAME SCRIPT -#define LOG_IDENT "Mailman cgi-wrapper (" SCRIPT ")" - -/* Group name that CGI scripts run as. See your web server's documentation - * for details. - */ -#define LEGAL_PARENT_GROUP CGI_GROUP - -const char* logident = LOG_IDENT; -char* script = SCRIPTNAME; -const char* parentgroup = LEGAL_PARENT_GROUP; - - -int -main(int argc, char** argv, char** env) -{ - int status; - char* fake_argv[3]; - - running_as_cgi = 1; - check_caller(logident, parentgroup); - - /* For these CGI programs, we can ignore argc and argv since they - * don't contain anything useful. `script' will always be the driver - * program and argv will always just contain the name of the real - * script for the driver to import and execute (padded with two dummy - * values in argv[0] and argv[1] that are ignored by run_script(). - */ - fake_argv[0] = NULL; - fake_argv[1] = NULL; - fake_argv[2] = script; - - status = run_script("driver", 3, fake_argv, env); - fatal(logident, status, "%s", strerror(errno)); - return status; -} - - - -/* - * Local Variables: - * c-file-style: "python" - * End: - */ diff --git a/src/common.c b/src/common.c deleted file mode 100644 index af6a69692..000000000 --- a/src/common.c +++ /dev/null @@ -1,306 +0,0 @@ -/* common.c --- Common routines, constants, etc. Used by all the wrappers. - * - * Copyright (C) 1998-2007 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include "common.h" - -/* Passed in by configure. */ -#define SCRIPTDIR PREFIX "/scripts/" /* trailing slash */ -#define MODULEDIR PREFIX /* no trailing slash */ - -const char* scriptdir = SCRIPTDIR; -const char* moduledir = MODULEDIR; -char* python = PYTHON; - -/* Global variable used as a flag */ -int running_as_cgi = 0; - - - -/* Some older systems don't define strerror(). Provide a replacement that is - * good enough for our purposes. - */ -#ifndef HAVE_STRERROR - -extern char *sys_errlist[]; -extern int sys_nerr; - -char* strerror(int errno) -{ - if (errno < 0 || errno >= sys_nerr) { - return "unknown error"; - } - else { - return sys_errlist[errno]; - } -} - -#endif /* ! HAVE_STRERROR */ - - - -/* Report on errors and exit - */ -#define BUFSIZE 1024 - -void -fatal(const char* ident, int exitcode, char* format, ...) -{ -#ifndef HAVE_VSNPRINTF - /* A replacement is provided in vsnprintf.c for ancient systems still - * lacking one in their C library. - */ - int vsnprintf(char*, size_t, const char*, va_list); -#endif /* !HAVE_VSNPRINTF */ - - char log_entry[BUFSIZE]; - - va_list arg_ptr; - va_start(arg_ptr, format); - - vsnprintf(log_entry, BUFSIZE, format, arg_ptr); - va_end(arg_ptr); - -#ifdef HAVE_SYSLOG - /* 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\n", log_entry); - closelog(); -#endif /* HAVE_SYSLOG */ - -#ifdef HELPFUL - /* If we're running as a CGI script, we also want to write the log - * file out as HTML, so the admin who is probably trying to debug his - * installation will have a better clue as to what's going on. - * - * Otherwise, print to stderr a short message, hopefully returned to - * the sender by the MTA. - */ - if (running_as_cgi) { - printf("Content-type: text/html\n\n"); - printf("<head>\n"); - printf("<title>Mailman CGI error!!!</title>\n"); - printf("</head><body>\n"); - printf("<h1>Mailman CGI error!!!</h1>\n"); - printf("The Mailman CGI wrapper encountered a fatal error. "); - printf("This entry is being stored in your syslog:"); - printf("\n<pre>\n"); - printf(log_entry); - printf("</pre>\n"); - } - else - fprintf(stderr, "%s\n", log_entry); -#endif /* HELPFUL */ - exit(exitcode); -} - - - -/* Is the parent process allowed to call us? - */ -void -check_caller(const char* ident, const char* parentgroup) -{ - GID_T mygid = getgid(); - struct group *mygroup = getgrgid(mygid); - char* option; - char* server; - char* wrapper; - - if (running_as_cgi) { - option = "--with-cgi-gid"; - server = "web"; - wrapper = "CGI"; - } - else { - option = "--with-mail-gid"; - server = "mail"; - 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 (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); -} - - - -/* list of environment variables which are removed from the given - * environment. Some may or may not be hand crafted and passed into - * the execv'd environment. - * - * TBD: The logic of this should be inverted. IOW, we should audit the - * Mailman CGI code for those environment variables that are used, and - * specifically white list them, removing all other variables. John Viega - * also suggests imposing a maximum size just in case Python doesn't handle - * them right (which it should because Python strings have no hard limits). - */ -static char* killenvars[] = { - "PYTHONPATH=", - "PYTHONHOME=", - "PATH=", - NULL -}; - - - -/* 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 - * - * TBD: third argument env may not be universally portable - */ -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 need to set the real gid to the effective gid because there are - * some Linux systems which do not preserve the effective gid across - * popen() calls. This breaks mail delivery unless the ~mailman/data - * directory is chown'd to the uid that runs mail programs, and that - * isn't a viable alternative. - */ -#ifdef HAVE_SETREGID - status = setregid(getegid(), -1); - if (status) - fatal(logident, SETREGID_FAILURE, "%s", strerror(errno)); -#endif /* HAVE_SETREGID */ - - /* 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 troublesome environment variables */ - for (i = 0, j = 0; i < envcnt; i++) { - char** k = &killenvars[0]; - int keep = 1; - while (*k) { - if (!strncmp(*k, env[i], strlen(*k))) { - keep = 0; - break; - } - *k++; - } - if (keep) - newenv[j++] = env[i]; - } - - /* 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 -S option (to speed executable - * start times), then the absolute path to the script, then any - * additional args passed in argv above. - */ - newargv = (char**)malloc(sizeof(char*) * (argc + 3)); - j = 0; - newargv[j++] = python; - newargv[j++] = "-S"; - newargv[j] = (char*)malloc(sizeof(char) * ( - strlen(scriptdir) + - strlen(script) + - 1)); - strcpy(newargv[j], scriptdir); - strcat(newargv[j], 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, j++; i < argc; i++) - newargv[j++] = argv[i]; - - newargv[j] = NULL; - - /* return always means failure */ - (void)execve(python, &newargv[0], &newenv[0]); - return EXECVE_FAILURE; -} - - - -/* - * Local Variables: - * c-file-style: "python" - * indent-tabs-mode: nil - * End: - */ diff --git a/src/common.h b/src/common.h deleted file mode 100644 index 092fe1bcb..000000000 --- a/src/common.h +++ /dev/null @@ -1,62 +0,0 @@ -/* common.h --- Prototypes for common routines - * - * Copyright (C) 1998-2007 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include <stdlib.h> -#include <stdarg.h> -#ifdef HAVE_SYSLOG_H -#include <syslog.h> -#endif /* HAVE_SYSLOG_H */ -#include <stdio.h> -#include <string.h> -#include <errno.h> -#include <sys/types.h> -#include <grp.h> -#include <unistd.h> - -/* GETGROUPS_T gets set in the makefile by configure */ -#define GID_T GETGROUPS_T - -extern void fatal(const char*, int, char*, ...); -extern void check_caller(const char*, const char*); -extern int run_script(const char*, int, char**, char**); - -/* Global variable used as a flag. */ -extern int running_as_cgi; - -/* Extern to reference this global from one of the wrapper mains */ -extern const char* logident; - -/* Exit codes, so it's easier to distinguish what caused fatal errors when - * looking at syslogs. - */ -#define GROUP_MISMATCH 2 -#define SETREGID_FAILURE 3 -#define EXECVE_FAILURE 4 -#define MAIL_USAGE_ERROR 5 -#define MAIL_ILLEGAL_COMMAND 6 -#define ADDALIAS_USAGE_ERROR 7 -#define GROUP_NAME_NOT_FOUND 8 - - -/* - * Local Variables: - * c-file-style: "python" - * End: - */ diff --git a/src/mail-wrapper.c b/src/mail-wrapper.c deleted file mode 100644 index 3b7a5711b..000000000 --- a/src/mail-wrapper.c +++ /dev/null @@ -1,92 +0,0 @@ -/* mail-wrapper.c --- Generic wrapper that will take info from a environment - * variable, and pass it to two commands. - * - * Copyright (C) 1998-2007 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include "common.h" - -/* Group name that your mail programs run as. See your mail server's - * documentation for details. - */ -#define LEGAL_PARENT_GROUP MAIL_GROUP - -const char* parentgroup = LEGAL_PARENT_GROUP; -const char* logident = "Mailman mail-wrapper"; - - - -const char *VALID_COMMANDS[] = { - "admin", - "bounces", - "confirm", - "join", - "leave", - "post", - "owner", - "request", - "subscribe", - "unsubscribe", - NULL /* Sentinel, don't remove */ -}; - - -int -check_command(char *command) -{ - int i = 0; - - while (VALID_COMMANDS[i] != NULL) { - if (!strcmp(command, VALID_COMMANDS[i])) - return 1; - i++; - } - return 0; -} - - - -int -main(int argc, char** argv, char** env) -{ - int status; - - /* sanity check arguments */ - if (argc < 2) - fatal(logident, MAIL_USAGE_ERROR, - "Usage: %s program [args...]", argv[0]); - - if (!check_command(argv[1])) - fatal(logident, MAIL_ILLEGAL_COMMAND, - "Illegal command: %s", argv[1]); - - check_caller(logident, parentgroup); - - /* If we got here, everything must be OK */ - status = run_script(argv[1], argc, argv, env); - fatal(logident, status, "%s", strerror(errno)); - return status; -} - - - -/* - * Local Variables: - * c-file-style: "python" - * End: - */ diff --git a/src/vsnprintf.c b/src/vsnprintf.c deleted file mode 100644 index 48eb58782..000000000 --- a/src/vsnprintf.c +++ /dev/null @@ -1,125 +0,0 @@ -/* Copyright (c) 1993 - * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de) - * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de) - * Copyright (c) 1987 Oliver Laumann - * - * 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, 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 (see the file COPYING); if not, write to the - * Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - * - **************************************************************** - */ - - -/* Implementation of vsnprintf() for systems that don't have it - * (e.g. Solaris 2.5). This hasn't been tested much in the context of - * Mailman; it was ripped from screen 3.7.6's misc.c file which contains - * the above copyright. - * - * This code has been modified slightly: - * - * - use prototypes unconditionally - * - Don't use macros for stdargs calls - * - Reformat to Python C standard - * - * RMS says it's okay to include this code in Mailman but it should be kept - * in a separate file. - * - * TBD: This file needs a security audit. - */ - -#ifndef HAVE_VSNPRINTF -#include <strings.h> -#include <stdarg.h> - -int vsnprintf(char* s, size_t n, const char* fmt, va_list stack) -{ - char *f, *sf = 0; - int i, on, argl = 0; - char myf[10], buf[20]; - char *arg, *myfp; - - on = n; - f = (char*)fmt; - arg = 0; - while (arg || (sf = index(f, '%')) || (sf = f + strlen(f))) { - if (arg == 0) { - arg = f; - argl = sf - f; - } - if (argl) { - i = argl > n - 1 ? n - 1 : argl; - strncpy(s, arg, i); - s += i; - n -= i; - if (i < argl) { - *s = 0; - return on; - } - } - arg = 0; - if (sf == 0) - continue; - f = sf; - sf = 0; - if (!*f) - break; - myfp = myf; - *myfp++ = *f++; - while (((*f >= '0' && *f <='9') || *f == '#') - && myfp - myf < 8) - { - *myfp++ = *f++; - } - *myfp++ = *f; - *myfp = 0; - if (!*f++) - break; - switch(f[-1]) - { - case '%': - arg = "%"; - break; - case 'c': - case 'o': - case 'd': - case 'x': - i = va_arg(stack, int); - sprintf(buf, myf, i); - arg = buf; - break; - case 's': - arg = va_arg(stack, char *); - if (arg == 0) - arg = "NULL"; - break; - default: - arg = ""; - break; - } - argl = strlen(arg); - } - *s = 0; - return on - n; - - va_end(stack); -} -#endif /* !HAVE_VSNPRINTF */ - - -/* - * Local Variables: - * c-file-style: "python" - * End: - */ |
