* Sun Apr 28 2024 Jean-Philippe Pialasse <jpp@koozali.org> 1.0.0-1.sme

- upgrade to last version [SME: 11802]
- reapply our specific patches, rewrite them if necessary
  added qpsmtpd-0.96-bz12450-auth_imap-perport.patch from SME10
- apply last fixes in git since v 1.0.0
  postfix: avoid logging full headers;Load plugins in qpsmtpd-forkserver;
  Fix received_line hook behaviour; Add missing use statement for NetAddr::IP
master
parent 0e6c3d3925
commit e908e9a691

@ -1,56 +0,0 @@
diff -Nur -x '*.orig' -x '*.rej' qpsmtpd-0.95/plugins/tls mezzanine_patched_qpsmtpd-0.95/plugins/tls
--- qpsmtpd-0.95/plugins/tls 2016-01-07 19:14:45.099736554 +0100
+++ mezzanine_patched_qpsmtpd-0.95/plugins/tls 2016-01-07 19:14:30.152736181 +0100
@@ -62,6 +62,14 @@
and put a suitable string in config/tls_ciphers (e.g. "DEFAULT" or
"HIGH:MEDIUM")
+=head1 SSL/TLS protocols versions
+
+By default, SSLv2 and SSLv3 are not accepted, leaving only TLSv1,
+TLSv1.1 or TLSv1.2 enabled. You can customize this in config/tls_protocols
+For example, this will also disabled TLSv1, leaving only TLSv1.1 and TLSv1.2
+
+SSLv23:!SSLv2:!SSLv3:!TLSv1
+
=cut
use strict;
@@ -94,6 +102,7 @@
$self->tls_ca($ca);
$self->tls_dhparam($dhparam);
$self->tls_ciphers($self->qp->config('tls_ciphers') || 'HIGH');
+ $self->tls_protocols($self->qp->config('tls_protocols') || 'SSLv23:!SSLv2:!SSLv3');
$self->log(LOGDEBUG, "ciphers: " . $self->tls_ciphers);
@@ -102,7 +111,7 @@
IO::Socket::SSL::SSL_Context->new(
# Disable SSLv2 and SSLv3 to avoid POODLE attacks. This is already
# the default in sufficiently recent versions of IO::Socket::SSL
- SSL_version => 'SSLv23:!SSLv3:!SSLv2',
+ SSL_version => $self->tls_protocols,
SSL_use_cert => 1,
SSL_cert_file => $self->tls_cert,
SSL_key_file => $self->tls_key,
@@ -226,6 +235,7 @@
my $tlssocket =
IO::Socket::SSL->new_from_fd(
fileno(STDIN), '+>',
+ SSL_version => $self->tls_protocols,
SSL_use_cert => 1,
SSL_cert_file => $self->tls_cert,
SSL_key_file => $self->tls_key,
@@ -286,6 +296,12 @@
$self->{_tls_ciphers};
}
+sub tls_protocols {
+ my $self = shift;
+ @_ and $self->{_tls_protocols} = shift;
+ $self->{_tls_protocols};
+}
+
sub ssl_context {
my $self = shift;
@_ and $self->{_ssl_ctx} = shift;

@ -1,13 +0,0 @@
diff -Nur -x '*.orig' -x '*.rej' qpsmtpd-0.95/plugins/spamassassin mezzanine_patched_qpsmtpd-0.95/plugins/spamassassin
--- qpsmtpd-0.95/plugins/spamassassin 2015-02-11 23:00:25.000000000 +0100
+++ mezzanine_patched_qpsmtpd-0.95/plugins/spamassassin 2015-12-16 22:07:17.554311238 +0100
@@ -172,7 +172,8 @@
return DECLINED if $self->is_immune();
- if ($transaction->data_size > 500_000) {
+ my $limit = $self->{_args}->{size_limit} || 500_000;
+ if ($transaction->data_size > $limit) {
$self->log(LOGINFO,
"skip, too large (" . $transaction->data_size . ")");
return DECLINED;

@ -1,11 +0,0 @@
diff -Nur -x '*.orig' -x '*.rej' qpsmtpd-0.96/plugins/dmarc mezzanine_patched_qpsmtpd-0.96/plugins/dmarc
--- qpsmtpd-0.96/plugins/dmarc 2016-05-03 09:10:34.624577605 +0200
+++ mezzanine_patched_qpsmtpd-0.96/plugins/dmarc 2016-05-03 09:10:14.160581205 +0200
@@ -154,6 +154,7 @@
};
};
+ $transaction->notes('dmarc_result', $dmarc->result);
my $disposition = $dmarc->result->disposition;
my $result = $dmarc->result->result;
my $auth_str = "dmarc=$result";

@ -1,12 +0,0 @@
diff -Nur qpsmtpd-0.96/lib/Qpsmtpd.pm qpsmtpd-0.96_bz9460/lib/Qpsmtpd.pm
--- qpsmtpd-0.96/lib/Qpsmtpd.pm 2016-02-16 23:52:02.000000000 +0100
+++ qpsmtpd-0.96_bz9460/lib/Qpsmtpd.pm 2016-05-16 11:52:07.041152848 +0200
@@ -448,7 +448,7 @@
sub address {
my $self = shift;
my $addr = Qpsmtpd::Address->new(@_);
- $addr->qp($self);
+ $addr->qp($self) if $addr;
return $addr;
}

@ -1,12 +0,0 @@
diff -Nur --no-dereference qpsmtpd-0.96.old/qpsmtpd-forkserver qpsmtpd-0.96/qpsmtpd-forkserver
--- qpsmtpd-0.96.old/qpsmtpd-forkserver 2021-11-15 11:59:33.048000000 -0500
+++ qpsmtpd-0.96/qpsmtpd-forkserver 2021-11-15 12:00:46.276000000 -0500
@@ -193,7 +193,7 @@
POSIX::setuid($quid) or die "unable to change uid: $!\n";
$> = $quid;
-#$qpsmtpd->load_plugins;
+$qpsmtpd->load_plugins;
foreach my $addr (@LISTENADDR) {
::log(LOGINFO, "Listening on $addr->{addr}:$addr->{port}");

@ -0,0 +1,74 @@
diff -Nur --no-dereference qpsmtpd-0.96.old/plugins/auth/auth_imap qpsmtpd-0.96/plugins/auth/auth_imap
--- qpsmtpd-0.96.old/plugins/auth/auth_imap 2016-02-16 17:52:02.000000000 -0500
+++ qpsmtpd-0.96/plugins/auth/auth_imap 2023-12-18 12:14:23.581000000 -0500
@@ -25,17 +25,30 @@
relay or a primary mail server. The principal benefit is ease of adminstration when
an existing IMAP service is already established.
-head1 AUTHOR Christopher Heschong
+=head1 AUTHOR Christopher Heschong
Edits to add SSL support and updated for latest qpsmtpd version - James Turnbull <james@lovedthanlost.net>
=head1 COPYRIGHT AND LICENSE Copyright (c) 2004 Christopher Heschong
This plugin is licensed under the same terms as the qpsmtpd package itself.
Please see the LICENSE file included with qpsmtpd for details.
+
+=head1 SYNOPSIS
+
+In config/plugins:
+
+ auth/auth_imap \
+ enable_smtp no \
+ enable_ssmtp yes
=cut
use Net::IMAP::Simple;
+use Qpsmtpd::Constants;
+
+use Socket;
+use constant SMTP_PORT => getservbyname("smtp", "tcp") || 25;
+use constant SSMTP_PORT => getservbyname("ssmtp", "tcp") || 465;
sub register {
my ($self, $qp, @args) = @_;
@@ -51,16 +64,35 @@
if (@args > 1 and $args[1] =~ /^(\d+)$/) {
$self->{_imap_port} = $1;
}
+ if (@args > 2 and ($args[3] eq "enable_smtp" ) ) {
+ $self->{_enable_smtp}= $args[4] || 'no';
+ }
+ if (@args > 4 and ( $args[5] eq "enable_ssmtp" )) {
+ $self->{_enable_ssmtp} = $args[6] || 'yes';
+ }
$self->log(LOGWARN, "WARNING: Ignoring additional arguments.")
- if (@args > 2);
+ if (@args > 6);
}
else {
die("No IMAP server specified in plugins file.");
}
# set any values that are not already
- $self->{_imap_server} ||= "127.0.0.1";
- $self->{_imap_port} ||= 143;
+ $self->{_imap_server} ||= "127.0.0.1";
+ $self->{_imap_port} ||= 143;
+ $self->{_enable_smtp} ||= 'no';
+ $self->{_enable_ssmtp} ||= 'yes';
+
+ my $port = $ENV{PORT} || SMTP_PORT;
+
+ if ($self->{_enable_smtp} ne 'yes' && ($port == SMTP_PORT || $port == 587)) {
+ $self->log(LOGDEBUG, "skip: enable_smtp=no");
+ return 0;
+ }
+ if ($port == SSMTP_PORT && $self->{_enable_ssmtp} ne 'yes') {
+ $self->log(LOGDEBUG, "skip: enable_ssmtp=no");
+ return 0;
+ };
$self->register_hook("auth-login", "auth_imap");
$self->register_hook("auth-plain", "auth_imap");

@ -1,12 +0,0 @@
diff -Nur qpsmtpd-0.96/plugins/karma qpsmtpd-0.96_bz9462/plugins/karma
--- qpsmtpd-0.96/plugins/karma 2016-05-09 23:56:51.145450697 +0200
+++ qpsmtpd-0.96_bz9462/plugins/karma 2016-05-09 23:57:34.484446254 +0200
@@ -449,7 +449,7 @@
my $history = ($nice || 0) - $naughty;
my $log_mess = '';
- if ($karma <= $self->{_args}{strikes}) { # Enough negative strikes ?
+ if ($karma <= -$self->{_args}{strikes}) { # Enough negative strikes ?
$history--;
my $negative_limit = 0 - $self->{_args}{negative};
if ($history <= $negative_limit) {

@ -1,12 +0,0 @@
diff -Nur qpsmtpd-0.96/plugins/dmarc qpsmtpd-0.96_bz9206/plugins/dmarc
--- qpsmtpd-0.96/plugins/dmarc 2016-05-28 10:29:34.469470149 +0200
+++ qpsmtpd-0.96_bz9206/plugins/dmarc 2016-05-28 10:33:36.482470978 +0200
@@ -145,7 +145,7 @@
my $pol;
eval { $pol = $dmarc->result->published; };
if ( $self->{_args}{reporting} && $pol ) {
- if ( $dmarc->has_valid_reporting_uri($pol->rua) ) {
+ if ( $pol->rua && $dmarc->has_valid_reporting_uri($pol->rua) ) {
eval { $dmarc->save_aggregate(); };
$self->log(LOGERROR, $@ ) if $@;
}

@ -1,15 +0,0 @@
diff -Nur -x '*.orig' -x '*.rej' qpsmtpd-0.96/lib/Qpsmtpd/TcpServer.pm mezzanine_patched_qpsmtpd-0.96/lib/Qpsmtpd/TcpServer.pm
--- qpsmtpd-0.96/lib/Qpsmtpd/TcpServer.pm 2016-02-16 23:52:02.000000000 +0100
+++ mezzanine_patched_qpsmtpd-0.96/lib/Qpsmtpd/TcpServer.pm 2016-04-15 19:13:13.873874838 +0200
@@ -120,7 +120,10 @@
while (<STDIN>) {
alarm 0;
$_ =~ s/\r?\n$//s; # advanced chomp
- $self->log(LOGINFO, "dispatching $_");
+ my $log = $_;
+ $log =~ s/AUTH PLAIN (.*)/AUTH PLAIN <hidden credentials>/
+ unless ($self->config('loglevel') || '6') >= 7;
+ $self->log(LOGINFO, "dispatching $log");
$self->connection->notes('original_string', $_);
defined $self->dispatch(split / +/, $_, 2)
or $self->respond(502, "command unrecognized: '$_'");

@ -1,14 +0,0 @@
diff -Nur qpsmtpd-0.96/plugins/dkim qpsmtpd-0.96_bz9480/plugins/dkim
--- qpsmtpd-0.96/plugins/dkim 2016-07-05 22:08:55.700102610 +0200
+++ qpsmtpd-0.96_bz9480/plugins/dkim 2016-07-05 22:11:51.485075880 +0200
@@ -262,7 +262,9 @@
push @data, "selector: " . $dkim->signature->selector if $dkim->signature;
push @data, "result: " . $dkim->result_detail if $dkim->result_detail;
- foreach my $policy ($dkim->policies) {
+ my @policies = eval { $dkim->policies };
+
+ foreach my $policy (@policies) {
next if !$policy;
push @data, "policy: " . $policy->as_string;
push @data, "name: " . $policy->name;

@ -1,62 +0,0 @@
diff -Nur -x '*.orig' -x '*.rej' qpsmtpd-0.96/docs/hooks.md mezzanine_patched_qpsmtpd-0.96/docs/hooks.md
--- qpsmtpd-0.96/docs/hooks.md 2016-02-16 23:52:02.000000000 +0100
+++ mezzanine_patched_qpsmtpd-0.96/docs/hooks.md 2016-05-03 21:56:38.216306190 +0200
@@ -343,26 +343,20 @@
The `data_post_headers` hook is called after the client sends the final .\r\n of
a message and before the message is processed by `data_post`. This hook is
-primarily used by plugins that insert new headers (ex: Received-SPF) and/or
+used by plugins that insert new headers (ex: Received-SPF) and/or
modify headers such as appending to Authentication-Results (SPF, DKIM, DMARC).
When it is desirable to have these header modifications evaluated by filtering
software (spamassassin, dspam, etc.) running on `data_post`, this hook should be
used instead of `data_post`.
-Allowed return codes are
-
-- DENY
-
- Return a hard failure code
+Note that you cannot reject in this hook, use the data_post hook instead
-- DENYSOFT
-
- Return a soft failure code
+Allowed return codes are
-- DENY\_DISCONNECT / DENYSOFT\_DISCONNECT
+- DECLINED
- as above but with disconnect
+ Do nothing
## hook\_data\_post
diff -Nur -x '*.orig' -x '*.rej' qpsmtpd-0.96/plugins/dmarc mezzanine_patched_qpsmtpd-0.96/plugins/dmarc
--- qpsmtpd-0.96/plugins/dmarc 2016-02-16 23:52:02.000000000 +0100
+++ mezzanine_patched_qpsmtpd-0.96/plugins/dmarc 2016-05-03 21:57:11.943312651 +0200
@@ -102,6 +102,7 @@
else {
$self->{_dmarc} = Mail::DMARC::PurePerl->new();
$self->register_hook('data_post_headers', 'check_dmarc');
+ $self->register_hook('data_post', 'reject_dmarc');
};
}
@@ -189,6 +190,13 @@
return DECLINED if $self->is_immune;
$self->adjust_karma(-3);
-# at what point do we reject?
- return $self->get_reject("failed DMARC policy");
+ # Add a mark now so the data_post hook can do the real reject
+ $transaction->notes('reject_dmarc', '1');
+}
+
+sub reject_dmarc {
+ my ($self, $transaction) = @_;
+ return $self->get_reject("failed DMARC policy")
+ if ($transaction->notes('reject_dmarc'));
+ return DECLINED;
}

@ -1,12 +0,0 @@
diff -Nur -x '*.orig' -x '*.rej' qpsmtpd-0.96/plugins/karma_tool mezzanine_patched_qpsmtpd-0.96/plugins/karma_tool
--- qpsmtpd-0.96/plugins/karma_tool 2016-02-16 23:52:02.000000000 +0100
+++ mezzanine_patched_qpsmtpd-0.96/plugins/karma_tool 2016-05-04 22:22:03.913868169 +0200
@@ -63,7 +63,7 @@
my ( $self ) = @_;
return $self->{db} if $self->{db};
$self->{db} = Qpsmtpd::DB->new( name => 'karma' );
- $self->{db}->dir(
+ $self->{db}->candidate_dirs(
$self->{args}{db_dir},
qw( /var/lib/qpsmtpd/karma ./var/db ./config . ) );
my $path = $self->{db}->path;

@ -1,46 +0,0 @@
diff -Nur -x '*.orig' -x '*.rej' qpsmtpd-0.96/plugins/karma mezzanine_patched_qpsmtpd-0.96/plugins/karma
--- qpsmtpd-0.96/plugins/karma 2016-02-16 23:52:02.000000000 +0100
+++ mezzanine_patched_qpsmtpd-0.96/plugins/karma 2016-04-20 18:39:43.299979947 +0200
@@ -50,6 +50,16 @@
penalize a "mostly good" sender. Raising it to 2 reduces that possibility to
improbable.
+=head2 strikes <integer>
+
+How many strikes is needed to consider the mail nice or naughty.
+Various plugins can adjust the karma (see USING KARMA IN OTHER PLUGINS).
+For example, with the default value of 3, if the karma of this message is 3
+or above, the mail is considered to be a nice one. If it's -3 or less, it's
+considered a naughty one. Between -2 and +2 it's neutral
+
+Default: 3
+
=head2 penalty_days <days>
The number of days a naughty sender is refused connections. Use a decimal
@@ -238,6 +248,7 @@
$self->log(LOGERROR, "Bad arguments") if @_ % 2;
$self->{_args} = {@_};
$self->{_args}{negative} ||= 1;
+ $self->{_args}{strikes} ||= 3;
$self->{_args}{penalty_days} ||= 1;
$self->{_args}{reject_type} ||= 'disconnect';
@@ -428,7 +439,7 @@
my $history = ($nice || 0) - $naughty;
my $log_mess = '';
- if ($karma < -2) { # they achieved at least 2 strikes
+ if ($karma <= $self->{_args}{strikes}) { # Enough negative strikes ?
$history--;
my $negative_limit = 0 - $self->{_args}{negative};
if ($history <= $negative_limit) {
@@ -445,7 +456,7 @@
$log_mess = "negative";
}
}
- elsif ($karma > 2) {
+ elsif ($karma >= $self->{_args}{strikes}) {
$nice++;
$log_mess = "positive";
}

@ -1,86 +0,0 @@
diff -Nur -x '*.orig' -x '*.rej' qpsmtpd-0.96/config.sample/karma_tlds mezzanine_patched_qpsmtpd-0.96/config.sample/karma_tlds
--- qpsmtpd-0.96/config.sample/karma_tlds 1970-01-01 01:00:00.000000000 +0100
+++ mezzanine_patched_qpsmtpd-0.96/config.sample/karma_tlds 2016-04-20 20:44:35.881444632 +0200
@@ -0,0 +1,14 @@
+# Karma to apply depending on the tld of the envelope sender
+# Used by the karma plugin
+# Warning: setting karma too low can blacklist the entire tld
+work:-4
+rocks:-3
+ninja:-3
+info:-2
+biz:-2
+pw:-2
+me:-1
+us:-5
+eu:-4
+link:-3
+science:-6
diff -Nur -x '*.orig' -x '*.rej' qpsmtpd-0.96/plugins/karma mezzanine_patched_qpsmtpd-0.96/plugins/karma
--- qpsmtpd-0.96/plugins/karma 2016-04-20 20:44:38.326444593 +0200
+++ mezzanine_patched_qpsmtpd-0.96/plugins/karma 2016-04-20 19:18:31.922041433 +0200
@@ -102,6 +102,20 @@
Adjust the quantity of logging for this plugin. See docs/logging.pod
+=head1 CONFIG FILES
+
+This plugin uses the following configuration files. All are optional.
+
+=head2 karma_tlds
+
+This file can contain semicolon separated tld and the corresponding
+karma adjustment to apply when the envelope sender match. It can be used to
+penalize "spammy" tlds, or to raise the karma from (mostly) good tlds.
+
+jp:-4
+ch:-3
+fr:+1
+
=head1 BENEFITS
Karma reduces the resources wasted by naughty mailers. When used with
@@ -352,18 +366,14 @@
my $full_from = $self->connection->notes('envelope_from');
$self->illegal_envelope_format( $full_from );
- my %spammy_tlds = (
- map { $_ => 4 } qw/ info pw /,
- map { $_ => 3 } qw/ tw biz /,
- map { $_ => 2 } qw/ cl br fr be jp no se sg /,
- );
- foreach my $tld ( keys %spammy_tlds ) {
+ my $karma_tlds = $self->get_karma_tlds() or return DECLINED;
+ foreach my $tld ( keys %$karma_tlds ) {
my $len = length $tld;
- my $score = $spammy_tlds{$tld} or next;
+ my $score = $karma_tlds->{$tld} or next;
$len ++;
if ( $sender->host && ".$tld" eq substr($sender->host,-$len,$len) ) {
- $self->log(LOGINFO, "penalizing .$tld envelope sender");
- $self->adjust_karma(-$score);
+ $self->log(LOGINFO, "adjusting karma for .$tld envelope sender");
+ $self->adjust_karma($score);
}
}
@@ -479,6 +489,19 @@
}
}
+sub get_karma_tlds {
+ my $self = shift;
+
+ my %karma_tlds =
+ map { (split /:/, $_, 2)[0, 1] } $self->qp->config('karma_tlds');
+ if (!%karma_tlds) {
+ $self->log(LOGDEBUG, "no specific karma for tlds defined");
+ return;
+ }
+
+ return \%karma_tlds;
+}
+
sub parse_db_record {
my ($self, $value) = @_;

@ -1,104 +0,0 @@
diff -Nur -x '*.orig' -x '*.rej' qpsmtpd-0.96/plugins/sender_permitted_from mezzanine_patched_qpsmtpd-0.96/plugins/sender_permitted_from
--- qpsmtpd-0.96/plugins/sender_permitted_from 2016-02-16 23:52:02.000000000 +0100
+++ mezzanine_patched_qpsmtpd-0.96/plugins/sender_permitted_from 2016-05-04 18:33:37.510387152 +0200
@@ -37,6 +37,37 @@
SPF levels above 4 are for crusaders who don't mind rejecting some valid mail when the sending server administrator hasn't dotted his i's and crossed his t's. May the deities bless their obsessive little hearts.
+=head2 no_dmarc_policy
+
+When used with the dmarc plugin, you don't want sender_permitted_from to reject anything, because dmarc needs to check the sender's domain policy.
+So you'll most likely have reject 1.
+But then, if the sender's domain has no dmarc policy, you might want to reject solely based on SPF result. This is what this setting is for. A first hook runs at the mail stage and evaluate SPF. Then a second hook runs at the data_post stage (after dmarc), so you have a second chance to reject.
+
+Like reject, you can set a value to indicate how agressive you want to be:
+
+ 0 do not reject (default)
+ 1 reject if SPF record says 'fail'
+ 2 stricter reject. Also rejects 'softfail'
+ 3 reject 'neutral'
+ 4 reject if no SPF records, or a syntax error
+
+Just like reject, the recommanded value is 1. 2 will be a bit more agressive. 3 and 4 will most likely reject some valid emails.
+
+So, for example, you can use something like this:
+
+sender_permetted_from reject 1 no_dmarc_policy 1
+dkim reject 0
+dmarc reject 1 reporting 1
+
+Note this setting will only have effect if:
+
+ * dmarc plugin is used, and loaded after sender_permetted_from in your plugin's config
+ * the reject value is either 1 or 2 (meaning, no reject at the mail stage)
+ * dmarc ran with no error
+ * the sender's domain has no dmarc policy published (that means, no _dmarc DNS entry)
+
+Note that if a domain has a dmarc "p=none" policy, then this setting has no effect. Only if there's no dmarc policy at all it'll be used.
+
=head1 SEE ALSO
http://spf.pobox.com/
@@ -82,8 +113,10 @@
if (!$self->{_args}{reject} && $self->qp->config('spfbehavior')) {
$self->{_args}{reject} = $self->qp->config('spfbehavior');
}
+ $self->{_args}{no_dmarc_policy} ||= 0;
$self->register_hook('mail', 'evaluate_spf');
$self->register_hook('data_post_headers', 'add_spf_header');
+ $self->register_hook('data_post', 'no_dmarc_policy') if $self->{_args}{no_dmarc_policy} > 0;
}
sub evaluate_spf {
@@ -202,6 +235,51 @@
return DECLINED;
}
+sub no_dmarc_policy {
+ my ($self, $transaction) = @_;
+ return DECLINED if $self->is_immune;
+ unless ($self->{_args}{no_dmarc_policy}){
+ return DECLINED;
+ }
+ if ($transaction->notes('spfquery') && $transaction->notes('dmarc_result')){
+ my $spf_result = $transaction->notes('spfquery')->code;
+ my $why = $transaction->notes('spfquery')->local_explanation;
+ my $dmarc_dispo = $transaction->notes('dmarc_result')->disposition;
+ return DECLINED unless $dmarc_dispo eq 'none';
+ my $comment = '';
+ if ($transaction->notes('dmarc_result')->reason &&
+ $transaction->notes('dmarc_result')->reason->[0] &&
+ $transaction->notes('dmarc_result')->reason->[0]->comment){
+ $comment = $transaction->notes('dmarc_result')->reason->[0]->comment;
+ }
+ return DECLINED unless $comment eq 'no policy';
+ # No SPF or syntaxe error: reject if no_dmarc_policy is at least 4
+ if ((!$spf_result || $spf_result =~ m/(?:permerror|error|none)/) && $self->{_args}{no_dmarc_policy} >= 4){
+ $self->log(LOGINFO, "fail, $spf_result, $why");
+ return DENY, "SPF - $spf_result: $why";
+ }
+ # All other reject levels require an SPF code
+ return DECLINED unless $spf_result;
+ # Neutral
+ if ($spf_result eq 'neutral' && $self->{_args}{no_dmarc_policy} >= 3){
+ $self->log(LOGINFO, "fail, $spf_result, $why");
+ return DENY, "SPF - $spf_result: $why";
+ }
+ # Softfail
+ if ($spf_result eq 'softfail' && $self->{_args}{no_dmarc_policy} >= 2){
+ $self->log(LOGINFO, "fail, $spf_result, $why");
+ return DENY, "SPF - $spf_result: $why";
+ }
+ # Fail
+ if ($spf_result eq 'fail' && $self->{_args}{no_dmarc_policy} >= 1){
+ $self->log(LOGINFO, "fail, $spf_result, $why");
+ return DENY, "SPF - $spf_result: $why";
+ }
+ }
+ $self->log(LOGINFO, 'pass');
+ return DECLINED;
+}
+
sub handle_code_none {
my ($self, $reject, $why) = @_;

@ -1,12 +0,0 @@
diff -Nur -x '*.orig' -x '*.rej' qpsmtpd-0.96/lib/Qpsmtpd/Plugin.pm mezzanine_patched_qpsmtpd-0.96/lib/Qpsmtpd/Plugin.pm
--- qpsmtpd-0.96/lib/Qpsmtpd/Plugin.pm 2016-04-25 18:16:52.626824508 +0200
+++ mezzanine_patched_qpsmtpd-0.96/lib/Qpsmtpd/Plugin.pm 2016-04-25 18:16:24.785825492 +0200
@@ -228,7 +228,7 @@
# the naughty plugin will reject later
if ($reject eq 'naughty') {
$self->log(LOGINFO, "fail, NAUGHTY" . $log_mess);
- return $self->store_deferred_reject($smtp_mess);
+ return $self->store_deferred_reject('(' . $self->plugin_name . ') ' . $smtp_mess);
}
# they asked for reject, we give them reject

@ -1,20 +0,0 @@
diff -Nur -x '*.orig' -x '*.rej' qpsmtpd-0.96/plugins/uribl mezzanine_patched_qpsmtpd-0.96/plugins/uribl
--- qpsmtpd-0.96/plugins/uribl 2016-02-16 23:52:02.000000000 +0100
+++ mezzanine_patched_qpsmtpd-0.96/plugins/uribl 2016-04-18 22:10:13.565072798 +0200
@@ -271,6 +271,7 @@
if ($l =~ /(.*)=$/) {
push @qp_continuations, $1;
+ next;
}
elsif (@qp_continuations) {
$l = join('', @qp_continuations, $l);
@@ -498,7 +499,7 @@
return \@matches;
}
-sub hook_data {
+sub hook_data_post {
my ($self, $transaction) = @_;
return DECLINED if $self->is_immune();

@ -1,31 +0,0 @@
diff -Nur qpsmtpd-0.96/plugins/uribl qpsmtpd-0.96_bz9467/plugins/uribl
--- qpsmtpd-0.96/plugins/uribl 2016-07-11 22:28:55.105488861 +0200
+++ qpsmtpd-0.96_bz9467/plugins/uribl 2016-07-11 22:32:14.607442677 +0200
@@ -96,6 +96,9 @@
use Time::HiRes qw(time);
use IO::Select;
+use Data::Validate::Domain;
+
+my $v = Data::Validate::Domain->new;
# ccTLDs that allocate domain names within a strict two-level hierarchy,
# as in *.co.uk
@@ -348,7 +351,7 @@
museum|name|net|org|pro|tel|travel|
[a-zA-Z]{2})
)(?!\w)
- }gix
+ }gix && $v->is_domain($1)
)
{
my $host = lc $1;
@@ -393,7 +396,7 @@
museum|name|net|org|pro|tel|travel|
[a-zA-Z]{2})
)
- }gix
+ }gix && $v->is_domain($1)
)
{
my $host = lc $1;

@ -1,13 +0,0 @@
diff -Nur -x '*.orig' -x '*.rej' qpsmtpd-0.96/plugins/helo mezzanine_patched_qpsmtpd-0.96/plugins/helo
--- qpsmtpd-0.96/plugins/helo 2016-02-16 23:52:02.000000000 +0100
+++ mezzanine_patched_qpsmtpd-0.96/plugins/helo 2016-04-15 19:25:32.953870666 +0200
@@ -521,7 +521,8 @@
my ($dns_name, $helo_name) = @_;
return if !$dns_name;
- return if split(/\./, $dns_name) < 2; # not a FQDN
+ my @dots = split(/\./, $dns_name);
+ return if scalar @dots < 2; # not a FQDN
if ($dns_name eq $helo_name) {
$self->log(LOGDEBUG, "reverse name match");

@ -0,0 +1,30 @@
--- qpsmtpd/plugins/uribl.ori 2024-04-28 22:37:31.090000000 -0400
+++ qpsmtpd/plugins/uribl 2024-04-28 22:40:04.111000000 -0400
@@ -102,6 +102,9 @@
use Time::HiRes qw(time);
use IO::Select;
+use Data::Validate::Domain;
+
+my $v = Data::Validate::Domain->new;
# ccTLDs that allocate domain names within a strict two-level hierarchy,
# as in *.co.uk
@@ -358,7 +361,7 @@
[a-zA-Z0-9](?:[a-zA-Z0-9\-]+\.)+ # hostname
(?:$tlds4regex|[a-zA-Z]{2}) # tld
)(?!\w)
- }gix
+ }gix && $v->is_domain($1)
)
{
my $host = lc $1;
@@ -400,7 +403,7 @@
[a-zA-Z0-9](?:[a-zA-Z0-9\-]+\.)+ # hostname
(?:$tlds4regex|[a-zA-Z]{2}) # tld
)(?!\w)
- }gix
+ }gix && $v->is_domain($1)
)
{
my $host = lc $1;

BIN
qpsmtpd-1.0.0.tar.gz (Stored with Git LFS)

Binary file not shown.

@ -0,0 +1,53 @@
diff --git a/lib/Qpsmtpd/Postfix.pm b/lib/Qpsmtpd/Postfix.pm
index 2946bba..6a98816 100644
--- a/lib/Qpsmtpd/Postfix.pm
+++ b/lib/Qpsmtpd/Postfix.pm
@@ -206,7 +206,7 @@ sub inject_mail {
my $hdr = $transaction->header->as_string;
for (split(/\r?\n/, $hdr)) {
- print STDERR "hdr: $_\n";
+ # print STDERR "hdr: $_\n";
$strm->print_msg_line($_);
}
$transaction->body_resetpos;
diff --git a/lib/Qpsmtpd/SMTP.pm b/lib/Qpsmtpd/SMTP.pm
index 70e25c5..913879d 100644
--- a/lib/Qpsmtpd/SMTP.pm
+++ b/lib/Qpsmtpd/SMTP.pm
@@ -860,8 +860,8 @@ sub received_line {
my $header_str;
my ($rc, @received) =
$self->run_hooks("received_line", $smtp, $authheader, $sslheader);
- if ($rc == OK) {
- return join("\n", @received);
+ if ($rc == OK) {
+ $header_str = join("\n", @received);
}
else { # assume $rc == DECLINED
$header_str =
diff --git a/plugins/whitelist b/plugins/whitelist
index 3f9c10e..e79da8e 100644
--- a/plugins/whitelist
+++ b/plugins/whitelist
@@ -99,6 +99,7 @@ use strict;
use warnings;
use Qpsmtpd::Constants;
+use NetAddr::IP;
my $VERSION = 0.02;
diff --git a/qpsmtpd-forkserver b/qpsmtpd-forkserver
index f0f9e58..ef151a6 100755
--- a/qpsmtpd-forkserver
+++ b/qpsmtpd-forkserver
@@ -193,7 +193,7 @@ POSIX::setgid($qgid) or die "unable to change gid: $!\n";
POSIX::setuid($quid) or die "unable to change uid: $!\n";
$> = $quid;
-#$qpsmtpd->load_plugins;
+$qpsmtpd->load_plugins;
foreach my $addr (@LISTENADDR) {
::log(LOGINFO, "Listening on $addr->{addr}:$addr->{port}");

@ -1,8 +1,8 @@
# $Id: qpsmtpd.spec,v 1.30 2021/11/16 23:13:14 jpp Exp $
Name: qpsmtpd
Version: 0.96
Release: 21%{?dist}
Version: 1.0.0
Release: 1%{?dist}
Summary: qpsmtpd + qpsmtpd-apache
License: MIT
Group: System Environment/Daemons
@ -26,33 +26,18 @@ Source4: in.qpsmtpd
Source5: qpsmtpd.conf
Source6: README.selinux
Patch1: qpsmtpd-0.95-spamassassin_size_limit.patch
Patch2: qpsmtpd-0.95-qpsmtpd_forserver_keepalive.patch
Patch3: qpsmtpd-0.95-notls_conf.patch
Patch4: qpsmtpd-0.95-allow_tls_proto_from_conf.patch
Patch5: qpsmtpd-0.96-set_hooks.patch
Patch6: qpsmtpd-0.96-warn_implicit_split.patch
Patch7: qpsmtpd-0.96-dont_log_credentials_except_in_debug.patch
Patch8: qpsmtpd-0.96-uribl_data_post.patch
Patch9: qpsmtpd-0.96-karma_strikes.patch
Patch10: qpsmtpd-0.96-more_badrcptto.patch
Patch11: qpsmtpd-0.96-karma_tlds_conf.patch
Patch12: qpsmtpd-0.96-store_original_plugin_name.patch
Patch13: qpsmtpd-0.96-fix_karma_tool_dir_path.patch
Patch14: qpsmtpd-0.96-dkim_no_sign_for_others_on_symlinks.patch
Patch15: qpsmtpd-0.96-fix_dmarc_reject.patch
Patch16: qpsmtpd-0.96-add_dmarc_result_notes.patch
Patch17: qpsmtpd-0.96-spf_on_no_dmarc_policy.patch
Patch18: qpsmtpd-0.96-check_negative_karma_strikes.patch
Patch19: qpsmtpd-0.96-addr_defined_before_use.patch
Patch20: qpsmtpd-0.96-check_rua_is_defined.patch
Patch21: qpsmtpd-0.96-remove_karma_rcpt_handler.patch
Patch22: qpsmtpd-0.96-eval_dkim_policies.patch
Patch23: qpsmtpd-0.96-uribl_validate_domains.patch
Patch24: qpsmtpd-0.96-bz10112-whitelist.patch
Patch25: qpsmtpd-0.96-SME10139-Message-Id.patch
Patch26: qpsmtpd-0.96-bz10290-spamassassin-fetchmail.patch
Patch27: qpsmtpd-0.96-bz10387-load_plugins-on-start.patch
Patch1: qpsmtpd-0.95-qpsmtpd_forserver_keepalive.patch
Patch2: qpsmtpd-0.95-notls_conf.patch
Patch3: qpsmtpd-0.96-set_hooks.patch
Patch4: qpsmtpd-0.96-more_badrcptto.patch
Patch5: qpsmtpd-0.96-dkim_no_sign_for_others_on_symlinks.patch
Patch6: qpsmtpd-0.96-remove_karma_rcpt_handler.patch
Patch7: qpsmtpd-1.0.0-uribl_validate_domains.patch
Patch8: qpsmtpd-0.96-bz10112-whitelist.patch
Patch9: qpsmtpd-0.96-SME10139-Message-Id.patch
Patch10: qpsmtpd-0.96-bz10290-spamassassin-fetchmail.patch
Patch11: qpsmtpd-0.96-bz12450-auth_imap-perport.patch
Patch12: qpsmtpd-v1.0.0-20240428.patch
%description
qpsmtpd is a flexible smtpd daemon written in Perl. Apart from the core
@ -75,6 +60,7 @@ that turns Apache into an SMTP server using Qpsmtpd.
%prep
%setup -q
%patch1 -p1
%patch2 -p1
%patch3 -p1
@ -87,21 +73,6 @@ that turns Apache into an SMTP server using Qpsmtpd.
%patch10 -p1
%patch11 -p1
%patch12 -p1
%patch13 -p1
%patch14 -p1
%patch15 -p1
%patch16 -p1
%patch17 -p1
%patch18 -p1
%patch19 -p1
%patch20 -p1
%patch21 -p1
%patch22 -p1
%patch23 -p1
%patch24 -p1
%patch25 -p1
%patch26 -p1
%patch27 -p1
%build
CFLAGS="$RPM_OPT_FLAGS" perl Makefile.PL INSTALLDIRS="vendor" PREFIX="%{buildroot}%{_prefix}"
@ -174,6 +145,14 @@ fi
%changelog
* Sun Apr 28 2024 Jean-Philippe Pialasse <jpp@koozali.org> 1.0.0-1.sme
- upgrade to last version [SME: 11802]
- reapply our specific patches, rewrite them if necessary
added qpsmtpd-0.96-bz12450-auth_imap-perport.patch from SME10
- apply last fixes in git since v 1.0.0
postfix: avoid logging full headers;Load plugins in qpsmtpd-forkserver;
Fix received_line hook behaviour; Add missing use statement for NetAddr::IP
* Fri Jul 14 2023 BogusDateBot
- Eliminated rpmbuild "bogus date" warnings due to inconsistent weekday,
by assuming the date is correct and changing the weekday.

Loading…
Cancel
Save