encryption support in ezmlm-web:

* add separate keyring support
* implement interface option blacklisting
* improved some code style
manual:
* document INTERFACE_OPTIONS_BLACKLIST and GPG_KEYRING_DEFAULT_LOCATION
This commit is contained in:
lars 2008-09-18 11:56:16 +00:00
parent 1497aeecb5
commit e2e370747f
6 changed files with 166 additions and 44 deletions

View File

@ -82,6 +82,14 @@ $DEFAULT_OPTIONS = "aBDFGHiJkLMNOpQRSTUWx";
# available values are: easy, normal and expert
#$DEFAULT_INTERFACE_TYPE = "normal";
# exclude some interface options from being displayed
# BEWARE: this does not protect the specific option from being changed.
# It just hides the visible interface items. Anyone can still craft a manual
# http request, that could change the specified options.
# See the list of filenames below $TEMPLATE_DIR/config_options/. The
# blacklist may contain any of these filenames (without '.cs' extension).
#$INTERFACE_OPTIONS_BLACKLIST = ('lang_select', 'mime_reject');
# What is the title of this document?
$HTML_TITLE = "ezmlm-web - a mailinglist administration interface";
@ -112,7 +120,15 @@ $HTML_CSS_COLOR = "/ezmlm-web/color-red-blue.css";
# setting individually
$HTML_LANGUAGE = "en";
# turn support for encrypted mailing lists on or off - defaults to 0 (off)
# see https://systemausfall.org/toolforge/gpgpy-ezmlm for details
# enabled support for encrypted mailing lists - defaults to 0 (off)
# This include keyring management and mailing list handling in general.
#$GPG_SUPPORT = 0;
# Define the default location of gnupg keyrings used for mailing list
# encryption. If the location starts with a slash ('/'), then it is considered
# to be an absolute path. Otherwise it is relative to the current list
# directory. For the ezmlm-gpg mailing list encryption system, the default
# (".gnupg") is usable.
#$GPG_KEYRING_DEFAULT_LOCATION = ".gnupg";

View File

@ -32,7 +32,8 @@ use MIME::QuotedPrint;
# optional modules - they will be loaded later if they are available
#Encode
#Mail::Ezmlm::Gpg
#Mail::Ezmlm::Ezmlm-GPG
#Mail::Ezmlm::GpgKeyRing
#Mail::Address OR Email::Address
@ -94,10 +95,11 @@ use vars qw[$FILE_UPLOAD $WEBUSERS_FILE $MAIL_DOMAIN $HTML_TITLE];
use vars qw[$TEMPLATE_DIR $LANGUAGE_DIR $HTML_LANGUAGE];
use vars qw[$HTML_CSS_COMMON $HTML_CSS_COLOR];
use vars qw[$MAIL_ADDRESS_PREFIX @HTML_LINKS];
use vars qw[@INTERFACE_OPTIONS_BLACKLIST];
# default interface template (basic/normal/expert)
use vars qw[$DEFAULT_INTERFACE_TYPE];
# some settings for encrypted mailing lists
use vars qw[$GPG_SUPPORT];
use vars qw[$GPG_SUPPORT $GPG_KEYRING_DEFAULT_LOCATION];
# settings for multi-domain setups
use vars qw[%DOMAINS $CURRENT_DOMAIN];
# cached data
@ -141,15 +143,19 @@ unless (my $return = do $config_file) {
####### validate configuration and apply some default settings ##########
# do we support encrypted mailing lists?
# see https://systemausfall.org/toolforge/crypto-ezmlm
# do we support encrypted mailing lists an keyring management?
$GPG_SUPPORT = 0 unless defined($GPG_SUPPORT);
if ($GPG_SUPPORT) {
if (&safely_import_module("Mail::Ezmlm::Gpg")) {
$GPG_SUPPORT = 1;
} else {
$GPG_SUPPORT = 0;
warn "WARNING: Support for encrypted mailinglists is disabled, as the module Mail::Ezmlm::Gpg failed to load!";
my @crypto_modules = (
"Mail::Ezmlm::GpgKeyRing",
"Mail::Ezmlm::Ezmlm-GPG",
);
for my $module_name (@crypto_modules) {
unless (&safely_import_module($module_name)) {
$GPG_SUPPORT = 0;
warn "WARNING: Support for encryption features is disabled, "
. "because the module '$module_name' failed to load!";
}
}
}
@ -223,6 +229,13 @@ $HTML_TITLE = '' unless defined($HTML_TITLE);
# check DEFAULT_INTERFACE_TYPE
$DEFAULT_INTERFACE_TYPE = 'normal' unless defined($DEFAULT_INTERFACE_TYPE);
# check possible blacklist of interface options (since v3.3)
@INTERFACE_OPTIONS_BLACKLIST = () unless defined(@INTERFACE_OPTIONS_BLACKLIST);
# check the configured detault location of gnupg keyrings
$GPG_KEYRING_DEFAULT_LOCATION = ".gnupg"
unless defined($GPG_KEYRING_DEFAULT_LOCATION);
# determine MAIL_DOMAIN
unless (defined($MAIL_DOMAIN) && ($MAIL_DOMAIN ne '')) {
if ((-e "$QMAIL_BASE/virtualdomains") && open(VD, "<$QMAIL_BASE/virtualdomains")) {
@ -875,10 +888,13 @@ sub set_pagedata4list {
$list = new Mail::Ezmlm("$LIST_DIR/$listname");
$pagedata->setValue("Data.List.Name", "$listname");
$pagedata->setValue("Data.List.Address", &this_listaddress);
$pagedata->setValue("Data.List.Address", &get_listaddress($listname));
# do we support encryption? Set some data if the list is encrypted ...
&set_pagedata_crypto($listname) if ($GPG_SUPPORT);
# set global or module-specific blacklist of list options
&set_pagedata_options_blacklist($list);
# do we support encryption? Show a possible keyring ...
&set_pagedata_keyring($list) if ($GPG_SUPPORT);
# is this a moderation/administration list?
&set_pagedata4part_list($part_type) if ($part_type ne '');
@ -896,11 +912,79 @@ sub set_pagedata4list {
# ---------------------------------------------------------------------------
sub set_pagedata_options_blacklist {
my $list = shift;
my ($item, @list_blacklist);
# check if the function "get_options_blacklist" exists for the list object
eval {@list_blacklist = $list->get_options_blacklist();};
# use an empty blacklist, if the member function was not defined
@list_blacklist = () if ($@);
foreach $item (@list_blacklist, @INTERFACE_OPTIONS_BLACKLIST) {
$pagedata->setValue("Data.List.OptionsBlackList." . $item, $item);
}
}
# ---------------------------------------------------------------------------
sub get_keyring_location {
my $list = shift;
my $keyring_location;
if ($list->can("get_keyring_location")) {
$keyring_location = $list->get_keyring_location();
} elsif ($GPG_KEYRING_DEFAULT_LOCATION =~ m#^/#) {
$keyring_location = $GPG_KEYRING_DEFAULT_LOCATION;
} else {
$keyring_location = $list->thislist() . '/' . $GPG_KEYRING_DEFAULT_LOCATION;
}
return $keyring_location;
}
# ---------------------------------------------------------------------------
sub set_pagedata_keyring {
my $list = shift;
my ($keyring_location, $keyring, @gpg_keys);
$keyring_location = &get_keyring_location($list);
# continue only, if keyring_location is defined and accessible
if (defined($keyring_location) && (-r $keyring_location)) {
$keyring = Mail::Ezmlm::GpgKeyRing->new($keyring_location);
} else {
# no keyring available -> we are finished
return;
}
# retrieve the currently available public keys
@gpg_keys = $keyring->get_public_keys();
for (my $i = 0; $i < @gpg_keys; $i++) {
$pagedata->setValue("Data.List.gnupg_keys.public.$i.id" , $gpg_keys[$i]{id});
$pagedata->setValue("Data.List.gnupg_keys.public.$i.email" , $gpg_keys[$i]{email});
$pagedata->setValue("Data.List.gnupg_keys.public.$i.name" , $gpg_keys[$i]{name});
$pagedata->setValue("Data.List.gnupg_keys.public.$i.expires" , $gpg_keys[$i]{expires});
}
# retrieve the currently available secret keys
@gpg_keys = $keyring->get_secret_keys();
for (my $i = 0; $i < @gpg_keys; $i++) {
$pagedata->setValue("Data.List.gnupg_keys.secret.$i.id" , $gpg_keys[$i]{id});
$pagedata->setValue("Data.List.gnupg_keys.secret.$i.email" , $gpg_keys[$i]{email});
$pagedata->setValue("Data.List.gnupg_keys.secret.$i.name" , $gpg_keys[$i]{name});
$pagedata->setValue("Data.List.gnupg_keys.secret.$i.expires" , $gpg_keys[$i]{expires});
}
# enable "keyring" feature in the interface
$pagedata->setValue("Data.List.Features.GpgKeyring", 1);
}
# ---------------------------------------------------------------------------
sub set_pagedata_crypto {
# extract hdf-data for encrypted lists
my ($listname) = @_;
my ($gpg_list, %config, $item, @gpg_keys, $gpg_key);
my ($gpg_list, %config, $item);
$gpg_list = new Mail::Ezmlm::Gpg("$LIST_DIR/$listname");
@ -914,23 +998,6 @@ sub set_pagedata_crypto {
$pagedata->setValue("Data.List.Options.gnupg_$item", $config{$item});
}
# retrieve the currently available public keys
@gpg_keys = $gpg_list->get_public_keys();
for (my $i = 0; $i < @gpg_keys; $i++) {
$pagedata->setValue("Data.List.gnupg_keys.public.$i.id" , $gpg_keys[$i]{id});
$pagedata->setValue("Data.List.gnupg_keys.public.$i.email" , $gpg_keys[$i]{email});
$pagedata->setValue("Data.List.gnupg_keys.public.$i.name" , $gpg_keys[$i]{name});
$pagedata->setValue("Data.List.gnupg_keys.public.$i.expires" , $gpg_keys[$i]{expires});
}
# retrieve the currently available secret keys
@gpg_keys = $gpg_list->get_secret_keys();
for (my $i = 0; $i < @gpg_keys; $i++) {
$pagedata->setValue("Data.List.gnupg_keys.secret.$i.id" , $gpg_keys[$i]{id});
$pagedata->setValue("Data.List.gnupg_keys.secret.$i.email" , $gpg_keys[$i]{email});
$pagedata->setValue("Data.List.gnupg_keys.secret.$i.name" , $gpg_keys[$i]{name});
$pagedata->setValue("Data.List.gnupg_keys.secret.$i.expires" , $gpg_keys[$i]{expires});
}
}
# ---------------------------------------------------------------------------
@ -988,11 +1055,11 @@ sub set_pagedata_misc_configfiles {
sub set_pagedata_subscribers {
my ($list, $listname, $part_type) = @_;
my ($list, $part_type) = @_;
my ($i, $address, $addr_name, %pretty);
$i = 0;
tie %pretty, "DB_File", "$LIST_DIR/$listname/webnames" if ($PRETTY_NAMES);
tie %pretty, "DB_File", $list->thislist() . "/webnames" if ($PRETTY_NAMES);
foreach $address (sort $list->subscribers($part_type)) {
if ($address ne '') {
$pagedata->setValue("Data.List.Subscribers." . $i . '.address', "$address");
@ -1636,7 +1703,7 @@ sub set_pagedata4part_list {
# Work out the address of this list ...
$list = new Mail::Ezmlm("$LIST_DIR/" . $q->param('list'));
$listaddress = &this_listaddress();
$listaddress = &get_listaddress($q->param('list'));
$pagedata->setValue("Data.List.PartType", "$part");
@ -1987,7 +2054,7 @@ sub gnupg_generate_key {
}
if ($list->generate_private_key($key_name, $key_comment,
&this_listaddress(), $key_size, $key_expires)) {
&get_listaddress($listname), $key_size, $key_expires)) {
$pagename = 'gnupg_secret';
return (0==0);
} else {
@ -2053,8 +2120,8 @@ sub update_config_crypto {
}
# Any changes? Otherwise just return.
# beware: the length function returns "1" for empty hashes
return (0==0) if (length(%switches) <= 1);
# "scalar keys %..." calculates the length the length of a hash
return (0==0) if (scalar keys %switches == 0);
# update the configuration file
if ($list->update(%switches)) {
@ -2338,11 +2405,12 @@ sub output_mime_examples {
# ------------------------------------------------------------------------
sub this_listaddress {
sub get_listaddress {
# Work out the address of this list ... Used often so put in its own subroutine ...
my ($list, $listaddress);
$list = new Mail::Ezmlm("$LIST_DIR/" . $q->param('list'));
my $listname = shift;
my ($listaddress, $list);
$list = new Mail::Ezmlm("$LIST_DIR/" . $listname);
chomp($listaddress = $list->getpart('outlocal'));
$listaddress .= '@';
chomp($listaddress .= $list->getpart('outhost'));

View File

@ -108,9 +108,22 @@ selects a different language. The default value is \fIen\fR.
.IP \fB$DEFAULT_INTERFACE_TYPE\fR
Set the default interface template. Available values are \fIeasy\fR,
\fInormal\fR and \fIexpert\fR. The default value is \fInormal\fR.
.IP \fB$INTERFACE_OPTIONS_BLACKLIST\fR
Exclude some list options from being displayed via the web interface.
BEWARE: this does not protect the specific option from being changed.
It just hides the visible interface items. Anyone can still craft a manual
http request, that could change the specified options.
See the list of filenames below \fI$TEMPLATE_DIR/config_options/\fR. The
blacklist may contain any of these filenames (without '.cs' extension).
.IP \fB$GPG_SUPPORT\fR
Enable support for encrypted mailing lists. Currently this feature is still
considered as beta quality. User reports are warmly welcome!
.IP \fB$GPG_KEYRING_DEFAULT_LOCATION\fR
This setting defines the default location of gnupg keyrings used for mailing list
encryption. If the location starts with a slash ('/'), then it is considered
to be an absolute path. Otherwise it is relative to the directory of the current
list. For the ezmlm-gpg mailing list encryption system, the default (".gnupg") is
usable.
.IP \fB%DOMAINS\fR
This hash of hashes (\fIname\fR associated with a hash of domain specific
information) can be used to define a multi-domain setup. See the example
@ -123,6 +136,18 @@ more details.
$LIST_DIR = "$HOME_DIR/lists";
$LANGUAGE_DIR = "/usr/local/share/ezmlm-web/lang";
$TEMPLATE_DIR = "/usr/local/share/ezmlm-web/template";
.IP "Some more examples of settings:"
.sp
.nf
$QMAIL_BASE = $Mail::Ezmlm::QMAIL_BASE . '/control';
$MAIL_ADDRESS_PREFIX = "lists-";
$DEFAULT_OPTIONS = "aBDFGHiJkLMNOpQRSTUWx";
$INTERFACE_OPTIONS_BLACKLIST = ('lang_select', 'mime_reject');
$HTML_TITLE = "ezmlm-web - a mailinglist administration interface";
$HTML_CSS_COMMON = "/ezmlm-web/default.css";
$HTML_CSS_COLOR = "/ezmlm-web/color-red-blue.css";
$HTML_LANGUAGE = "en";
$GPG_KEYRING_DEFAULT_LOCATION = ".gnupg";
.SH AUTHOR
Written by Lars Kruse
.SH "REPORTING BUGS"

View File

@ -17,6 +17,7 @@ Data.Action
Data.areDefaultTextsAvailable
Data.ErrorMessage
Data.List.Address
Data.List.OptionsBlackList
Data.List.CharSet
Data.List.CustomizedFiles.*
Data.List.DefaultFiles.*

View File

@ -53,11 +53,22 @@ def:limit_string_len(text,limit)
else ?><?cs var:text ?><?cs /if ?><?cs
/def ?><?cs
def:show_one_option(optname)
?><?cs set:blacklist_found = 0 ?><?cs
each:black_opt = Data.List.OptionsBlackList
?><?cs if:black_opt == optname ?><?cs set:blacklist_found = 1 ?><?cs
/if ?><?cs
/each ?><?cs
if:blacklist_found == 0 ?><?cs
linclude:TemplateDir + '/config_options/' + optname + '.cs' ?><?cs
/if ?><?cs
/def ?><?cs
def:show_options(element)
?><?cs if:subcount(element) == 0 ?><li><?cs
linclude:TemplateDir + '/config_options/' + element + '.cs' ?></li><?cs
call:show_one_option(element) ?></li><?cs
else ?><?cs if:element["Self"] ?><li><?cs
linclude:TemplateDir + '/config_options/' + element["Self"] + '.cs' ?><?cs
call:show_one_option(element["Self"]) ?><?cs
/if ?><ul><?cs each:opts = element ?><?cs if:name(opts) != "Self" ?><?cs
call:show_options(opts) ?><?cs
/if ?><?cs /each
@ -65,6 +76,7 @@ def:show_options(element)
/if ?><?cs
/def ?><?cs
def:is_substring(text_in, search_in)
?><?cs set:text = text_in
?><?cs set:search = search_in

View File

@ -132,7 +132,7 @@
var:html_escape(Lang.Menue.ConfigAll) ?></a></li><?cs /if ?>
</ul></li>
<?cs if:(subcount(UI.Navigation.Gnupg) > 0) && (Data.List.Features.Crypto)
<?cs if:(subcount(UI.Navigation.Gnupg) > 0) && (Data.List.Features.GpgKeyring)
?><li><font class="no_link"><?cs var:html_escape(Lang.Menue.Gnupg)
?></font>
<ul>