From 0a4b5d24845fb86bade3ab3c38a6202862d6caad Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sun, 23 Sep 2012 20:43:08 +0200 Subject: List creation via a Postfix local alias. --- cgi-bin/index.cgi | 48 -------------------------- cgi-bin/index.fcgi | 47 +++++++++++++++++++++++++ config.in | 8 +++++ default.in | 15 ++++---- misc/mklist/INSTALL | 56 ++++++++++++++++++++++++++++++ misc/mklist/README | 17 +++++++++ misc/mklist/mklist.pl | 95 +++++++++++++++++++++++++-------------------------- 7 files changed, 182 insertions(+), 104 deletions(-) delete mode 100755 cgi-bin/index.cgi create mode 100755 cgi-bin/index.fcgi create mode 100644 misc/mklist/INSTALL create mode 100644 misc/mklist/README diff --git a/cgi-bin/index.cgi b/cgi-bin/index.cgi deleted file mode 100755 index 5efa469..0000000 --- a/cgi-bin/index.cgi +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/perl - -use 5.010_000; -use strict; -use warnings; -use utf8; - -=head1 NAME - -index.cgi - - -=cut - -use lib 'lib'; -use Fripost::Panel::Interface; - -# TODO: Try out Fast CGI -#use CGI::Fast(); -# -#while (my $q = new CGI::Fast){ -# my $app = new WebApp(QUERY => $q); -# $app->run(); -#} - -my @config = 'default.in'; -push @config, 'config.in' if -f 'config.in'; - -my $cgi = Fripost::Panel::Interface->new( - PARAMS => { cfg_file => [ @config ], format => 'equal' } -); -$cgi->run(); - -=head1 AUTHOR - -Guilhem Moulin C<< >> - -=head1 COPYRIGHT - -Copyright 2012 Guilhem Moulin. - -=head1 LICENSE - -This program is free software; you can redistribute it and/or modify it -under the same terms as perl itself. - -=cut - -__END__ diff --git a/cgi-bin/index.fcgi b/cgi-bin/index.fcgi new file mode 100755 index 0000000..8e551d8 --- /dev/null +++ b/cgi-bin/index.fcgi @@ -0,0 +1,47 @@ +#!/usr/bin/perl + +use 5.010_000; +use strict; +use warnings; +use utf8; + +=head1 NAME + +index.fcgi - + +=cut + +use CGI::Fast (); +use File::Spec::Functions 'catfile'; +use lib 'lib'; +use Fripost::Panel::Interface; + + +my $config_dir = '/etc/fripost-panel'; +my @config = catfile ('./', 'default.in'); +push @config, catfile ($config_dir, 'config.in') if -f catfile ($config_dir, 'config.in'); + +while (my $q = CGI::Fast::->new){ + my $cgi = Fripost::Panel::Interface::->new( + QUERY => $q, + PARAMS => { cfg_file => [ @config ], format => 'equal' } + ); + $cgi->run(); +} + +=head1 AUTHOR + +Guilhem Moulin C<< >> + +=head1 COPYRIGHT + +Copyright 2012 Guilhem Moulin. + +=head1 LICENSE + +This program is free software; you can redistribute it and/or modify it +under the same terms as perl itself. + +=cut + +__END__ diff --git a/config.in b/config.in index 1a245f7..c2011d1 100644 --- a/config.in +++ b/config.in @@ -20,3 +20,11 @@ ldap_authcPW = panel # The minimum password length. password_min_length = 12 + +# GnuPG private key and passphrase. +gpg_private_key_id = ECFA6E43 +gpg_private_key_passphrase = xxxxxxxxxxxx + +# URL prefixes of the admin web interface for the list managers. +listurl_mailman = http://smtp.fripost.org/cgi-bin/mailman/admin/ +listurl_schleuder = http://smtp.fripost.org/ diff --git a/default.in b/default.in index ef32710..ec6a4c7 100644 --- a/default.in +++ b/default.in @@ -4,13 +4,8 @@ # which overrides the below. - -# Non absolute paths are be relative to this directory. -pwd = ./ - - # Directory for templates -tmpl_path = template/ +tmpl_path = ./template/ # Session configuration @@ -32,11 +27,15 @@ cgi-bin = /cgi-bin/ # A timeout for idle connections, after which the user is automatically # logged out -timeout = 30m +timeout = 15m # The minimum password length. password_min_length = 8 # LDAP configuration -ldap_uri =ldap://127.0.0.1:389 +ldap_uri = ldap://127.0.0.1:389 + + +# GnuPG home +gpghome = /etc/fripost-panel/gnupg/ diff --git a/misc/mklist/INSTALL b/misc/mklist/INSTALL new file mode 100644 index 0000000..660bcf9 --- /dev/null +++ b/misc/mklist/INSTALL @@ -0,0 +1,56 @@ +sudo apt-get install libmail-gnupg-perl libmime-tools-perl libconfig-auto-perl + +Also, Fripost's schema (module Fripost::Schema) needs to be found in the +library path. + + addgroup mklist + adduser list mklist + adduser schleuder mklist + mkdir -m 0700 -p /etc/mklist/gnupg-{mailman,schleuder} + chown 'list:list' /etc/mklist/gnupg-mailman + chown 'schleuder:schleuder' /etc/mklist/gnupg-schleuder + cp ./config /etc/mklist/ + + mkdir /etc/postfix-lists/{mailman,schleuder} + chown list:list /etc/postfix-lists/mailman + chown schleuder:schleuder /etc/postfix-lists/schleuder + +To add a key: + + ggp --homedir /etc/mklist/gnupg --import < /path/to/pubkey.pub + +for each list manager. For instance, + + sudo -u www-data gpg --homedir /etc/fripost-panel/gnupg/ -a --export ECFA6E43 | sudo -u list gpg --homedir /etc/mklist/gnupg-mailman/ --import + sudo -u www-data gpg --homedir /etc/fripost-panel/gnupg/ -a --export ECFA6E43 | sudo -u schleuder gpg --homedir /etc/mklist/gnupg-schleuder/ --import + +(Don't forget to whitelist the key ID in the configuration file.) + + +Postfix's lookup table (/etc/postfix-lists/transport_mklist) + + mklist#fripost.org+mailman@lists.fripost.org mklist-mailman: + mklist#fripost.org+schleuder@lists.fripost.org mklist-schleuder: + +Postfix's master.cf + + mklist-mailman unix - n n - - pipe + flags=FR directory=/opt/fripost-panel/ user=list:list + argv=/opt/fripost-panel/misc/mklist/mklist.pl mailman ${size} + + mklist-schleuder unix - n n - - pipe + flags=FR directory=/opt/fripost-panel/ user=schleuder:schleuder + argv=/opt/fripost-panel/misc/mklist/mklist.pl schleuder ${size} + +Postfix's main.cf + transport_maps = cdb:$config_directory/transport_mklist + cdb:$config_directory/mailman/transport + cdb:$config_directory/schleuder/transport + + mklist-mailman_destination_concurrency_limit = 1 + mklist-mailman_destination_recpipient_limit = 1 + mklist-mailman_time_limit = 10m + + mklist-schleuder_destination_concurrency_limit = 1 + mklist-schleuder_destination_recpipient_limit = 1 + mklist-schleuder_time_limit = 2h diff --git a/misc/mklist/README b/misc/mklist/README new file mode 100644 index 0000000..0454713 --- /dev/null +++ b/misc/mklist/README @@ -0,0 +1,17 @@ +This is the script that should be used to finalize list creation. +Living alongside with the list managers, Postfix should feed it (pipe) +with emails to mklist+{mailman,schleuder}@lists.fripost.org . + +The email's body must have the following format: + + listname + admin + password + +Also, the email should have a valid GPG-signature. The list of GPG +fingerprints allowed to create lists can be found in the configuration +file. + +Upon GPG-verification, the script orders the list manager to create a +new list with the given credentials, and updates the LDAP directory +(removes the 'pending' status and adds list commands entries). diff --git a/misc/mklist/mklist.pl b/misc/mklist/mklist.pl index 105178a..37c05e5 100755 --- a/misc/mklist/mklist.pl +++ b/misc/mklist/mklist.pl @@ -9,11 +9,11 @@ our $VERSION = '0.01'; =head1 NAME -mklist.pl - Create a new list +mklist.pl - Create a new list =head1 SYNOPSIS -B {B|B} < email +B {B|B} [size] < email =cut @@ -21,23 +21,27 @@ B {B|B} < email ####################################################################### # -use Mail::GnuPG; -use MIME::Parser; -use File::Spec::Functions; +use File::Spec::Functions qw/catfile catdir/; use Fcntl qw/:flock SEEK_END/; use POSIX qw/setuid setgid/; use Pod::Usage; use Config::Auto; -use lib '../../../panel/lib'; +use lib 'lib'; +use Mail::GnuPG; +use MIME::Parser; use Fripost::Schema; my $transport = shift; pod2usage(2) unless defined $transport and grep { $transport eq $_} qw/mailman schleuder/; - use Cwd; +my $configdir = catdir('/','etc','mklist'); +my $config = Config::Auto::parse( catfile($configdir, 'config'), + format => "equal" ); -my $config = Config::Auto::parse( './config', format => "equal" ); +my $size = shift; +die "Email size $size is bigger than the maximum authorized (".$config->{max_size}.").\n" + if defined $config->{max_size} and defined $size and $size > $config->{max_size}; # Drop root privileges unless ($<) { @@ -66,7 +70,7 @@ my ($list, $owner, $password); $msg->mime_type eq 'multipart/signed' and $msg->parts; - my $gpg = Mail::GnuPG::->new; + my $gpg = Mail::GnuPG::->new( keydir => catdir($configdir,'gnupg-'.$transport) ); die "Error: The message is not GPG/MIME signed.\n" unless $gpg->is_signed( $msg ); @@ -78,7 +82,7 @@ my ($list, $owner, $password); die "Error: 0x$key ($addr) is not authorized to create lists.\n" unless grep { $key eq $_ } - (ref $config->{authorized_pubkeys} eq 'ARRAY' ? + (ref $config->{authorized_pubkeys} eq 'ARRAY' ? @{$config->{authorized_pubkeys}} : $config->{authorized_pubkeys} ); @@ -100,7 +104,7 @@ my ($l,$d) = split /\@/, $list, 2; ####################################################################### # # Ensure that the root DN has been created, otherwise doing the below is -# useless. +# useless. { # It's pointless to have a global variable here, since after the list @@ -116,34 +120,32 @@ my ($l,$d) = split /\@/, $list, 2; # # Create the list -#if ($transport eq 'mailman') { -# system ( '/var/lib/mailman/bin/newlist', '-q' -# , '-u', 'smtp.fripost.org' # TODO: that should be $mydestination -# , $list -# , $owner -# , $password -# ); -# die "newlist exited with status $?\n" if $?; -#} -# -#elsif ($transport eq 'schleuder') { -# system ( '/usr/bin/schleuder-newlist' -# , $list -# , '-email', $list -# , '-realname', $l -# , '-nointeractive' -# , '-adminaddress', $owner -# , '-initmember', $owner -# , '-initmemberkey', # TODO: that needs to be a file -# ); -# die "schleuder-newlist exited with status $?\n" if $?; -# system ( '/usr/bin/ruby', '/opt/webschleuder/contrib/enable_webschleuder.rb' -# , $list -# , $password -# ); -# # TODO: try not to use the password in the command argument -# die "enable_webschleuder exited with status $?\n" if $?; -#} +if ($transport eq 'mailman') { + system ( '/var/lib/mailman/bin/newlist', '-q' + , '-u', 'smtp.fripost.org' # TODO: that should be $mydestination + , $list + , $owner + , $password + ); + die "newlist died with status $?\n" if $?; +} + +elsif ($transport eq 'schleuder') { + system ( '/usr/bin/schleuder-newlist' + , $list + , '-email', $list + , '-realname', $l + , '-nointeractive' + , '-adminaddress', $owner + ); + die "schleuder-newlist died with status $?\n" if $?; + my $pid = open PW, '|-', '/opt/webschleuder/contrib/enable_webschleuder.rb', $list + or die "Cannot open: $!"; + print PW $password or die "Cannot print: $!"; + close PW; + my $r = $? >> 8; + die "enable_webschleuder died with status $r\n" if $r; +} # List the commands that are to be added to the LDAP directory and the lookup table. my @cmds = $transport eq 'mailman' ? qw/admin bounces confirm join leave owner request subscribe unsubscribe/ : @@ -167,9 +169,7 @@ my @cmds = $transport eq 'mailman' ? qw/admin bounces confirm join leave owner r # Create/update the Postfix lookup table. { - - my $db = File::Spec::Functions::catfile( $config->{postfix_data_dir}, - 'transport_'.$transport ); + my $db = catfile( $config->{postfix_data_dir}, $transport, 'transport' ); my $new = not (-e $db); open my $fh, '>>', $db or die "Cannot open $db: $!"; flock $fh, LOCK_EX or die "Cannot lock $db: $!"; @@ -178,17 +178,16 @@ my @cmds = $transport eq 'mailman' ? qw/admin bounces confirm join leave owner r print $fh "# Do not modify this file! Use $0 to create lists instead.\n" or die "Cannot print: $!"; } - - - print $fh "\n# ".$list." - ".localtime."\n"; + + print $fh "\n# ".$list." - ".(localtime)."\n"; &print_transport($fh, undef); foreach (@cmds) { &print_transport($fh, $_); } - + close $fh or die "Cannot close $db: $!"; - + # Compile the lookup table (Postfix takes care of the race condition here). system ('/usr/sbin/postmap', '-c', $config->{postfix_config_dir}, $db); - die "postmap exited with status $?\n" if $?; + die "postmap died with status $?\n" if $?; } -- cgit v1.2.3