Unverified Commit 355b409e authored by IKEDA Soji's avatar IKEDA Soji Committed by GitHub
Browse files

Merge branch 'sympa-6.2' into refactor_auth.conf

parents a891ebc1 648f434f
......@@ -5,8 +5,12 @@
# Notation suggested on https://metacpan.org/pod/Carton#PERL-VERSIONS
requires 'perl', '5.16.0';
# This module provides zip/unzip for archive and shared document download/upload
requires 'Archive::Zip', '>= 1.05';
# Used to zip/unzip for archive and shared document download/upload.
# Note: Some environments not providing 'Archive::Zip::Simple*' modules may
# use a memory-consuming module 'Archive::Zip' for the alternative.
requires 'Archive::Zip::SimpleUnzip', '>= 0.024';
requires 'Archive::Zip::SimpleZip', '>= 0.021';
#requires 'Archive::Zip', '>= 1.05';
# Required to run Sympa web interface
requires 'CGI', '>= 3.51';
......@@ -204,15 +208,16 @@ feature 'Crypt::Eksblowfish', 'Used to encrypt passwords with the Bcrypt hash al
};
feature 'x509-auth', 'Required to extract user certificates for SSL clients and S/MIME messages.' => sub {
requires 'Crypt::OpenSSL::X509', '>= 1.800.1';
# Note: email() for certificate on versions < 1.909 was broken.
requires 'Crypt::OpenSSL::X509', '>= 1.909';
};
feature 'smime', 'Required to sign, verify, encrypt and decrypt S/MIME messages.' => sub {
requires 'Convert::ASN1', '>= 0.14';
requires 'Crypt::SMIME', '>= 0.15';
# Required to extract user certificates for SSL clients and S/MIME messages.
# Note: On versions < 1.808, the value() method for extension was broken.
requires 'Crypt::OpenSSL::X509', '>= 1.808';
# Note: value() for extension on versions < 1.808 was broken.
# Note: email() for certificate on versions < 1.909 was broken.
requires 'Crypt::OpenSSL::X509', '>= 1.909';
};
feature 'csv', 'CSV database driver, required if you include list members, owners or moderators from CSV file.' => sub {
......
......@@ -368,10 +368,8 @@ Subject: [%"Listmaster: internal server error"|loc(list.name)|qencode%]
[%|loc(who)%] User %1 has encountered an internal server error[%END%]
([%|loc%]Web interface[%END%] - ACTION[%|loc%]:[%END%] [%action%][% IF list.name %] - LIST[%|loc%]:[%END%] [%list.name%]@[%domain%][%END%])[%|loc%]:[%END%]
[%IF error == 'chdir_error' %][%|loc%]Unable to change directory.[%END%]
[%ELSIF error == 'no_authentication_service_name' %][%|loc%]The authentication server name is not defined.[%END%]
[%IF error == 'no_authentication_service_name' %][%|loc%]The authentication server name is not defined.[%END%]
[%ELSIF error == 'auth_conf_no_identified_user' %][%|loc%]auth.conf error: either email_http_header or host/get_email_by_uid_filter entries should be defined.[%END%]
[%ELSIF error == 'unknown_authentication_service' %][%|loc(name)%]Unknown authentication service %1.[%END%]
[%ELSIF error == 'add_user_db_failed' %][%|loc(user)%]Add user '%1' in DB failed.[%END%]
[%ELSIF error == 'update_user_db_failed' %][%|loc(user)%]Update user '%1' in DB failed[%END%][% IF old_email %][%|loc(old_email)%] (old email: %1)[%END%][%END%]
[%ELSIF error == 'add_subscriber_db_failed' %][%|loc(sub)%]Add subscriber '%1' in DB failed.[%END%]
......@@ -395,8 +393,6 @@ Subject: [%"Listmaster: internal server error"|loc(list.name)|qencode%]
[%ELSIF error == 'month_not_found' %][%|loc(month,list.name)%]Unable to find month '%1' for list '%2'[%END%][%IF dir%][%|loc(dir)%]: unable to read '%1'.[%END%][%END%]
[%ELSIF error == 'arc_not_found' %][%|loc(arc_file,list.name,path)%]Unable to find archive '%1' for list '%2'[%END%][%IF path%][%|loc(path)%]: unable to read '%1'.[%END%][%END%]
[%ELSIF error == 'inaccessible_archive' %][%|loc(list.name)%]Unable to find archive for list '%1'[%END%][%IF path%][%|loc(path)%]: unable to read '%1'.[%END%][%END%]
[%ELSIF error == 'may_not_send_me'%][%|loc()%]Unable to send archive: no message id found.[%END%]
[%ELSIF error == 'archive_not_found'%][%|loc(msgid)%]No message found in archives matching Message-ID '%1'.[%END%]
[%ELSIF error == 'cannot_save_config'%][%|loc(list.name)%]Cannot save config file for list '%1'.[%END%]
[%ELSIF error == 'failed_to_install_aliases'%][%|loc%]Failed to install aliases.[%END%]
[%ELSIF error == 'failed_to_remove_aliases'%][%|loc%]Failed to remove aliases.[%END%]
......@@ -416,7 +412,6 @@ Subject: [%"Listmaster: internal server error"|loc(list.name)|qencode%]
[%ELSIF error == 'delete_shared'%][%|loc(list.name)%]Cannot delete shared for list '%1'.[%END%]
[%ELSIF error == 'browse_shared'%][%|loc%]Impossible to browse shared documents for list '%1'.[%END%]
[%ELSIF error == 'cannot_upload'%][%|loc(path)%]Cannot upload file '%1'.[%END%]
[%ELSIF error == 'cannot_unzip' %][%|loc(name)%]Cannot unzip file '%1'.[%END%]
[%ELSIF error == 'error_during_unzip' %][%|loc(name)%]Errors while unzipping file '%1'.[%END%]
[%ELSIF error == 'cannot_send_remind' %][%|loc(from,list.name)%]Unable to send command REMIND from '%1' to list '%2'.[%END%]
[%ELSIF error == 'cannot_send_mail' %][%|loc(from,list.name)%]Unable to send mail from '%1' to list '%2'.[%END%]
......@@ -424,7 +419,6 @@ Subject: [%"Listmaster: internal server error"|loc(list.name)|qencode%]
[%ELSIF error == 'del_sub_request' %][%|loc(sub)%]Unable to delete subscription request for user '%1'.[%END%]
[%ELSIF error == 'add_file_zip' %][%|loc(file)%]Unable to add file '%1' to archives.[%END%]
[%ELSIF error == 'write_file_zip' %][%|loc(zipfile)%]Unable to write zip file '%1'.[%END%]
[%ELSIF error == 'err_404' %][%|loc(zipfile)%]File not found.[%END%]
[%ELSIF error == 'new_document_failed' %][%|loc(path,list.name)%]Unable to create a Shared Document with path '%1' for list '%2'.[%END%]
[%ELSIF error == 'cookie_error' %][%|loc%]Parameter cookie undefined, authentication failure.[%END%]
[%ELSIF error == 'cookie_error_env' %][%|loc(env)%]Cookie error: '%1' undefined, authentication failure.[%END%]
......
......@@ -236,9 +236,6 @@
[% IF report_entry == '' ~%]
[%~ ELSIF report_entry == 'month_not_found' ~%]
[%|loc(report_param.month)%]Unable to find month '%1'[%END%]
[%~ ELSIF report_entry == 'inaccessible_archive' ~%]
[%|loc(report_param.year_month)%]Archives from %1 are not accessible[%END%]
......@@ -272,9 +269,6 @@
[%~ ELSIF report_entry == 'no_identified_user' ~%]
[%|loc%]Failed to get your email address from the authentication service.[%END%]
[%~ ELSIF report_entry == 'err_404' ~%]
[%|loc(report_param.key)%]File not found.[%END%]
[%~ ELSIF report_entry == 'db_error' ~%]
[%|loc%]Database error.[%END%]
......@@ -899,6 +893,30 @@ Warning: this message may already have been sent by one of the list's moderators
[%~ ELSIF report_entry == 'no_classic_session' ~%]
[%|loc()%]You are not authorized to delete your account if you are not using the built-in authentication (i.e. you are using a LDAP authentication, a SSO system, etc.).[%END%]
[%~ ELSIF report_entry == 'unknown_authentication_service' ~%]
[%|loc(report_param.name)%]Unknown authentication service %1.[%END%]
[%~ ELSIF report_entry == 'no_message_id_to_send' ~%]
[%|loc()%]Unable to send archive: no message id found.[%END%]
[%~ ELSIF report_entry == 'no_message_id_to_view' ~%]
[%|loc()%]Unable to view archived message: no message id found.[%END%]
[%~ ELSIF report_entry == 'list_not_configured_for_tracking' ~%]
[%|loc()%]This list is not configured for tracking.[%END%]
[%~ ELSIF report_entry == 'no_message_id_in_archive' ~%]
[%|loc(report_param.msgid)%]No message found in archives matching Message-ID '%1'.[%END%]
[%~ ELSIF report_entry == 'unknown_scenario' ~%]
[%|loc(report_param.msgid)%]Unknown scenario '%1'.[%END%]
[%~ ELSIF report_entry == 'month_not_found' ~%]
[%|loc(report_param.month)%]Unable to find month '%1'[%END%]
[%~ ELSIF report_entry == 'cannot_get_privilege' ~%]
[%|loc()%]You are not allowed to get the privilege of this user.[%END%]
[%~ END ~%]
[%~ END ~%]
......@@ -17,15 +17,6 @@
</br>
[% END %]
[%###################-%]
[%#### SYSTEM ERROR -%]
[%###################-%]
[% FOREACH s_err = system_errors %]
[%|loc(s_err.action)%]SYSTEM ERROR (%1)[%END-%]
[% IF s_err.msg == 'a' %][% END %]
<br />
[% END %]
[%###################-%]
[%#### USER ERROR -%]
[%###################-%]
......
This diff is collapsed.
......@@ -193,7 +193,6 @@ nobase_modules_DATA = \
Sympa/WWW/FastCGI.pm \
Sympa/WWW/Marc.pm \
Sympa/WWW/Marc/Search.pm \
Sympa/WWW/Report.pm \
Sympa/WWW/SharedDocument.pm \
Sympa/WWW/Session.pm \
Sympa/WWW/SOAP.pm \
......
......@@ -487,6 +487,31 @@ sub error {
return undef;
}
# Old name: Sympa::DatabaseManager::_check_db_field_type().
sub is_sufficient_field_type {
my $self = shift;
my $required = shift;
my $effective = shift;
my ($required_type, $required_size, $effective_type, $effective_size);
if ($required =~ /^(\w+)(\((\d+)\))?$/) {
($required_type, $required_size) = ($1, $3);
}
if ($effective =~ /^(\w+)(\((\d+)\))?$/) {
($effective_type, $effective_size) = ($1, $3);
}
if ( ($effective_type // '') eq ($required_type // '')
and (not defined $required_size or $effective_size >= $required_size))
{
return 1;
}
return 0;
}
sub set_persistent {
my $self = shift;
my $flag = shift;
......
......@@ -8,8 +8,8 @@
# Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
# 2006, 2007, 2008, 2009, 2010, 2011 Comite Reseau des Universites
# Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016, 2017 GIP RENATER
# Copyright 2018 The Sympa Community. See the AUTHORS.md file at the
# top-level directory of this distribution and at
# Copyright 2018, 2021 The Sympa Community. See the
# AUTHORS.md file at the top-level directory of this distribution and at
# <https://github.com/sympa-community/sympa.git>.
#
# This program is free software; you can redistribute it and/or modify
......@@ -210,6 +210,32 @@ Returns:
True if the field is an auto-increment field, false otherwise
=item is_sufficient_field_type ( $required, $actual )
I<Overridable>, I<only for SQL driver>.
Checks if database field type is sufficient.
Parameters:
=over
=item $required
Required field type.
=item $actual
Actual field type.
=back
Returns:
The true value if actual field type is appropriate AND size is equal to or
greater than required size.
This method was added on Sympa 6.2.67b.1.
=item set_autoinc ( { table => $table, field => $field } )
I<Required to update database structure>.
......
......@@ -8,8 +8,8 @@
# Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
# 2006, 2007, 2008, 2009, 2010, 2011 Comite Reseau des Universites
# Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016, 2017 GIP RENATER
# Copyright 2018, 2020 The Sympa Community. See the AUTHORS.md
# file at the top-level directory of this distribution and at
# Copyright 2018, 2020, 2021 The Sympa Community. See the
# AUTHORS.md file at the top-level directory of this distribution and at
# <https://github.com/sympa-community/sympa.git>.
#
# This program is free software; you can redistribute it and/or modify
......@@ -335,6 +335,20 @@ sub get_primary_key {
return \%found_keys;
}
sub is_sufficient_field_type {
my $self = shift;
my $required = shift;
my $actual = shift;
# As of MySQL 8.0.17, the display width attribute is deprecated for
# integer data types (MeriaDB has not).
if ($required =~ /\A((?:tiny|small|medium|big)?int)(?:[(]\d+[)])?\z/
and $actual eq $1) {
return 1;
}
return $self->SUPER::is_sufficient_field_type($required, $actual);
}
sub unset_primary_key {
my $self = shift;
my $param = shift;
......
......@@ -8,6 +8,9 @@
# Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
# 2006, 2007, 2008, 2009, 2010, 2011 Comite Reseau des Universites
# Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016, 2017 GIP RENATER
# Copyright 2021 The Sympa Community. See the
# AUTHORS.md file at the top-level directory of this distribution and at
# <https://github.com/sympa-community/sympa.git>.
#
# 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
......@@ -29,11 +32,9 @@ use warnings;
use Sympa;
use Conf;
use Sympa::Constants;
use Sympa::Database;
use Sympa::DatabaseDescription;
use Sympa::Log;
use Sympa::Tools::Data;
my $log = Sympa::Log->instance;
......@@ -361,9 +362,9 @@ sub _check_fields {
## Change DB types if different and if update_db_types enabled
if ($may_update) {
unless (
_check_db_field_type(
effective_format => $real_struct{$t}{$f},
required_format => $db_struct->{$t}->{$f}
$sdm->is_sufficient_field_type(
$db_struct->{$t}->{$f},
$real_struct{$t}{$f}
)
) {
push @{$report_ref},
......@@ -693,30 +694,8 @@ sub _check_key {
return $result;
}
## Compare required DB field type
## Input : required_format, effective_format
## Output : return 1 if field type is appropriate AND size >= required size
sub _check_db_field_type {
my %param = @_;
my ($required_type, $required_size, $effective_type, $effective_size);
if ($param{'required_format'} =~ /^(\w+)(\((\d+)\))?$/) {
($required_type, $required_size) = ($1, $3);
}
if ($param{'effective_format'} =~ /^(\w+)(\((\d+)\))?$/) {
($effective_type, $effective_size) = ($1, $3);
}
if (Sympa::Tools::Data::smart_eq($effective_type, $required_type)
and (not defined $required_size or $effective_size >= $required_size))
{
return 1;
}
return 0;
}
# Moved: Use Sympa::Database::is_sufficient_field_type().
#sub _check_db_field_type;
1;
__END__
......
......@@ -31,47 +31,13 @@ use strict;
use warnings;
use English qw(-no_match_vars);
BEGIN { eval 'use Crypt::OpenSSL::X509'; }
use Conf;
use Sympa::Log;
use Sympa::Tools::Text;
my $log = Sympa::Log->instance;
=over
=item find_keys ( $that, $operation )
Find the appropriate S/MIME keys/certs for $operation of $that.
$operation can be:
=over
=item 'sign'
return the preferred signing key/cert
=item 'decrypt'
return a list of possible decryption keys/certs
=item 'encrypt'
return the preferred encryption key/cert
=back
Returnss C<($certs, $keys)>.
For 'sign' and 'encrypt', these are strings containing the absolute filename.
For 'decrypt', these are arrayrefs containing absolute filenames.
=back
=cut
# Old name: tools::smime_find_keys()
sub find_keys {
$log->syslog('debug2', '(%s, %s)', @_);
my $that = shift || '*';
my $operation = shift;
......@@ -102,8 +68,6 @@ sub find_keys {
my $k = $c;
$k =~ s/\/cert\.pem/\/private_key/;
unless ($keys{$k}) {
$log->syslog('debug3', '%s exists, but matching %s doesn\'t',
$c, $k);
delete $certs{$c};
}
}
......@@ -112,8 +76,6 @@ sub find_keys {
my $c = $k;
$c =~ s/\/private_key/\/cert\.pem/;
unless ($certs{$c}) {
$log->syslog('debug3', '%s exists, but matching %s doesn\'t',
$k, $c);
delete $keys{$k};
}
}
......@@ -130,34 +92,15 @@ sub find_keys {
$certs = "$dir/cert.pem";
$keys = "$dir/private_key";
} else {
$log->syslog('debug3', '%s: no certs/keys found for %s',
$that, $operation);
return undef;
}
}
$log->syslog('debug3', '%s: certs/keys for %s found', $that, $operation);
return ($certs, $keys);
}
BEGIN {
eval 'use Crypt::OpenSSL::X509';
eval 'use Convert::ASN1 qw()';
}
# IN: hashref:
# file => filename
# text => PEM-encoded cert
# OUT: hashref
# email => email address from cert
# subject => distinguished name
# purpose => hashref
# enc => true if v3 purpose is encryption
# sign => true if v3 purpose is signing
#
# Old name: tools::smime_parse_cert()
sub parse_cert {
$log->syslog('debug3', '(%s => %s)', @_);
my %arg = @_;
return undef unless $Crypt::OpenSSL::X509::VERSION;
......@@ -169,27 +112,23 @@ sub parse_cert {
} elsif ($arg{'file'}) {
$x509 = eval { Crypt::OpenSSL::X509->new_from_file($arg{'file'}) };
} else {
$log->syslog('err', 'Neither "text" nor "file" given');
return undef;
die 'bug in logic. Ask developer';
}
unless ($x509) {
$log->syslog('err', 'Cannot parse certificate');
return undef;
}
my %res;
$res{subject} = join '',
map { '/' . $_->as_string } @{$x509->subject_name->entries};
# Get email(s).
# The subjectAltName extension is used. The email() method that gives
# single address may be used for workaround on malformed certificates.
my @emails = _get_subjectAltName($x509, 1); # rfc822Name [1]
unless (@emails) {
@emails = ($x509->email) if $x509->email;
}
$res{email} =
{map { (Sympa::Tools::Text::canonic_email($_) => 1) } @emails};
$res{subject} = $x509->subject;
$res{notAfter} = $x509->notAfter;
$res{issuer} = $x509->issuer;
my @emails =
map { Sympa::Tools::Text::canonic_email($_) }
grep { Sympa::Tools::Text::valid_email($_) }
split / +/, ($x509->email // '');
$res{emails} = [@emails];
$res{email} = {map { ($_ => 1) } @emails};
# Check key usage roughy.
my %purposes = $x509->extensions_by_name->{keyUsage}->hash_bit_string;
......@@ -198,81 +137,106 @@ sub parse_cert {
return \%res;
}
sub _get_subjectAltName {
my $x509 = shift;
my $context_num = shift;
my $extensions = $x509->extensions_by_name;
return
unless $extensions
and $extensions->{subjectAltName}
and $extensions->{subjectAltName}->value =~ /\A#([0-9A-F]+)\z/;
my $bin = pack 'H*', $1;
my ($tag, $tnum, $len);
($tag, $tnum, $bin, $len) = _parse_asn1_single_value($bin);
return
unless defined $tag
and ($tag & ~Convert::ASN1::ASN_CONSTRUCTOR()) ==
Convert::ASN1::ASN_SEQUENCE();
my @ret;
while (length $bin) {
my $val;
($tag, $tnum, $val, $len) = _parse_asn1_single_value($bin);
last unless defined $tag;
$bin = substr $bin, $len;
next if $tag == 0 and length $val == 0;
push @ret, $val
if ($tag & 0xC0) == Convert::ASN1::ASN_CONTEXT()
and $tnum == $context_num;
}
return @ret;
}
1;
__END__
sub _parse_asn1_single_value {
my $bin = shift;
=encoding utf-8
my ($tb, $tag, $tnum) =
Convert::ASN1::asn_decode_tag2(substr $bin, 0, 10);
return unless defined $tb;
my ($lb, $len) = Convert::ASN1::asn_decode_length(substr $bin, $tb, 10);
return unless $tb + $lb + $len <= length $bin;
=head1 NAME
return ($tag, $tnum, substr($bin, $tb + $lb, $len), $tb + $lb + $len);
}
Sympa::Tools::SMIME - Tools for S/MIME messages and X.509 certificates
# NO LONGER USED
# However, this function may be useful because it can extract messages openssl
# can not (e.g. signature part not encoded by BASE64).
sub smime_extract_certs {
my ($mime, $outfile) = @_;
$log->syslog('debug2', '(%s)', $mime->mime_type);
if ($mime->mime_type =~ /application\/(x-)?pkcs7-/) {
my $pipeout;
unless (
open $pipeout,
'|-', $Conf::Conf{openssl}, 'pkcs7', '-print_certs',
'-inform' => 'der',
'-out' => $outfile
) {
$log->syslog('err', 'Unable to run openssl pkcs7: %m');
return 0;
}
print $pipeout $mime->bodyhandle->as_string;
close $pipeout;
my $status = $CHILD_ERROR >> 8;
if ($status) {
$log->syslog('err', 'Openssl pkcs7 returned an error: %s',
$status);
return 0;
}
return 1;
}
}
=head1 DESCRIPTION
1;
=head2 Functions
=over
=item find_keys ( $that, $operation )
Find the appropriate S/MIME keys/certs for $operation of $that.
$operation can be:
=over
=item 'sign'
return the preferred signing key/cert
=item 'decrypt'
return a list of possible decryption keys/certs
=item 'encrypt'
return the preferred encryption key/cert
=back
Returnss C<($certs, $keys)>.
For 'sign' and 'encrypt', these are strings containing the absolute filename.
For 'decrypt', these are arrayrefs containing absolute filenames.
=item parse_cert ( C<text>|C<file> =E<gt> $content )
Parses X.509 certificate.
Options:
=over
=item C<file> =E<gt> $filename
=item C<text> =E<gt> $text
Specifies PEM-encoded certificate.
=back
Returns a hashref containing these items:
=over
=item {email}
hashref with email addresses from cert as keys
=item {emails}
arrayref with email addresses from cert.
This was added on Sympa 6.2.67b.
=item {subject}
distinguished name
=item {purpose}
hashref containing:
=over
=item {enc}
true if v3 purpose is encryption
=item {sign}