initial commit of file from CVS for smeserver-qpsmtpd on Thu 26 Oct 11:25:19 BST 2023

master 2.7.0
Brian Read 7 months ago
parent c8bfca82cb
commit c45ac2b2d0

4
.gitignore vendored

@ -0,0 +1,4 @@
*.rpm
*.log
*spec-20*
*.tar.xz

@ -0,0 +1,21 @@
# Makefile for source rpm: smeserver-qpsmtpd
# $Id: Makefile,v 1.1 2016/02/05 23:28:48 stephdl Exp $
NAME := smeserver-qpsmtpd
SPECFILE = $(firstword $(wildcard *.spec))
define find-makefile-common
for d in common ../common ../../common ; do if [ -f $$d/Makefile.common ] ; then if [ -f $$d/CVS/Root -a -w $$/Makefile.common ] ; then cd $$d ; cvs -Q update ; fi ; echo "$$d/Makefile.common" ; break ; fi ; done
endef
MAKEFILE_COMMON := $(shell $(find-makefile-common))
ifeq ($(MAKEFILE_COMMON),)
# attept a checkout
define checkout-makefile-common
test -f CVS/Root && { cvs -Q -d $$(cat CVS/Root) checkout common && echo "common/Makefile.common" ; } || { echo "ERROR: I can't figure out how to checkout the 'common' module." ; exit -1 ; } >&2
endef
MAKEFILE_COMMON := $(shell $(checkout-makefile-common))
endif
include $(MAKEFILE_COMMON)

@ -1,3 +1,26 @@
# smeserver-qpsmtpd
# <img src="https://www.koozali.org/images/koozali/Logo/Png/Koozali_logo_2016.png" width="25%" vertical="auto" style="vertical-align:bottom"> smeserver-qpsmtpd
SMEServer Koozali developed git repo for smeserver-qpsmtpd smeserver
SMEServer Koozali developed git repo for smeserver-qpsmtpd smeserver
## Wiki
<br />https://wiki.koozali.org/Qpsmtpd
<br />https://wiki.koozali.org/Qpsmtpd:help
<br />https://wiki.koozali.org/Qpsmtpd:tls
<br />https://wiki.koozali.org/Qpsmtpd:bcc
<br />https://wiki.koozali.org/Qpsmtpd:fcrdns
<br />https://wiki.koozali.org/Qpsmtpd:tls_cert
<br />https://wiki.koozali.org/Qpsmtpd:content_log
<br />https://wiki.koozali.org/Qpsmtpd:relay
<br />https://wiki.koozali.org/Qpsmtpd:peers
<br />https://wiki.koozali.org/Qpsmtpd:helo
## Bugzilla
Show list of outstanding bugs: [here](https://bugs.koozali.org/buglist.cgi?component=smeserver-qpsmtpd&product=SME%20Server%2010.X&query_format=advanced&limit=0&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&bug_status=CONFIRMED)
## Description
<br />*This description has been generated by an LLM AI system and cannot be relied on to be fully correct.*
*Once it has been checked, then this comment will be deleted*
<br />
Qpsmtpd is an open source, high-performance, extensible SMTP server written in Perl. It provides a secure and reliable way to deliver emails, and is used in many production systems around the world. It is highly customizable, and can be extended with additional plugins to provide advanced features such as spam filtering, virus scanning, and user authentication. Qpsmtpd is reliable, fast, and highly scalable, making it ideal for high-volume email delivery. It is also easy to configure and manage, and integrates seamlessly with other email systems.

@ -0,0 +1 @@
sme10

@ -0,0 +1,220 @@
#!/usr/bin/perl -w
use esmith::Build::CreateLinks qw(:all);
foreach $event (qw(
email-update
domain-modify
domain-create
domain-delete
bootstrap-console-save
smeserver-qpsmtpd-update
))
{
event_link("domains-update-dkim", $event, "30");
}
my $service = "/var/service/qpsmtpd";
foreach $event (qw(
network-create
network-delete
smeserver-qpsmtpd-update
))
{
templates2events("$service/config/relayclients", $event);
}
foreach $event (qw(
bootstrap-console-save
console-save
email-update
network-create
network-delete
smeserver-qpsmtpd-update
))
{
templates2events("$service/peers/0", $event);
templates2events("$service/peers/local", $event);
templates2events("$service/config/peers/0", $event);
templates2events("$service/config/peers/local", $event);
}
templates2events("$service/runenv", qw(
bootstrap-console-save
console-save
email-update
smeserver-qpsmtpd-update
));
templates2events("$service/ssl/cert.pem", qw(
bootstrap-console-save
console-save
email-update
ssl-update
smeserver-qpsmtpd-update
));
templates2events($_, qw(
bootstrap-console-save
console-save
email-update
smeserver-qpsmtpd-update
))
for (qw(
/etc/mail-dmarc.ini
/home/e-smith/dkim_keys/default/selector
));
my $secure_service = "/var/service/sqpsmtpd";
templates2events("$secure_service/runenv", qw(
bootstrap-console-save
console-save
email-update
smeserver-qpsmtpd-update
));
my $control = "/var/qmail/control";
templates2events("$control/badmailfrom", qw(
bootstrap-console-save
console-save
email-update
smeserver-qpsmtpd-update
));
templates2events("$control/badrcptto", qw(
bootstrap-console-save
console-save
email-update
domain-create
domain-delete
user-create
user-delete
user-modify
group-create
group-delete
group-modify
pseudonym-create
pseudonym-delete
pseudonym-modify
smeserver-qpsmtpd-update
));
my $config = "/var/service/qpsmtpd/config";
templates2events("$config/$_", qw(
bootstrap-console-save
console-save
email-update
smeserver-qpsmtpd-update
))
for (qw(
IP
badhelo
badrcptto
badrcptto_ext
dnsbl_zones
dnsbl_allow
uribl_zones
loglevel
memory_threshold
plugins
relayclients norelayclients
rhsbl_zones
signatures_patterns
plugin_dirs
smtpgreeting
spool_dir
subject_prefix
invalid_resolvable_fromhost
timeout
timeoutsmtpd
tls_before_auth
tls_ciphers
tls_protocols
));
templates2events("$config/badrcptto_ext", qw(
domain-create
domain-delete
user-create
user-delete
user-modify
group-create
group-delete
group-modify
pseudonym-create
pseudonym-delete
pseudonym-modify
smeserver-qpsmtpd-update
));
templates2events("$config/$_", qw(
ssl-update
smeserver-qpsmtpd-update
))
for (qw(
tls_before_auth
tls_ciphers
tls_protocols
));
templates2events("$config/badhelo", 'ip-change');
templates2events("$config/goodrcptto", qw(
bootstrap-console-save
email-update
domain-create
domain-delete
user-create
user-delete
user-modify
pseudonym-create
pseudonym-delete
pseudonym-modify
group-create
group-delete
group-modify
smeserver-qpsmtpd-update
));
safe_touch("root/etc/e-smith/templates/$config/forcespamcheck/template-begin");
templates2events("$config/forcespamcheck", qw(
bootstrap-console-save
email-update
domain-create
domain-delete
user-create
user-delete
user-modify
pseudonym-create
pseudonym-delete
pseudonym-modify
group-create
group-delete
group-modify
smeserver-qpsmtpd-update
));
for my $daemon ( qw(qpsmtpd sqpsmtpd) )
{
safe_symlink("sighup",
"root/etc/e-smith/events/email-update/services2adjust/$daemon");
safe_symlink("sighup",
"root/etc/e-smith/events/ssl-update/services2adjust/$daemon");
}
for my $event ( qw(network-create network-delete) )
{
safe_symlink("sigusr1",
"root/etc/e-smith/events/$event/services2adjust/qpsmtpd");
}
my $event = 'smeserver-qpsmtpd-update';
safe_symlink("restart", "root/etc/e-smith/events/$event/services2adjust/qpsmtpd");
safe_symlink("restart", "root/etc/e-smith/events/$event/services2adjust/sqpsmtpd");
templates2events("/etc/systemd/system-preset/49-koozali.preset", $event);
event_link("systemd-reload", $event, "89");
event_link("systemd-default", $event, "88");

@ -0,0 +1 @@
bl.spamcop.net,dnsbl-1.uceprotect.net,dnsbl-2.uceprotect.net,psbl.surriel.com,zen.spamhaus.org

@ -0,0 +1 @@
multi.surbl.org,black.uribl.com,rhsbl.sorbs.net

@ -0,0 +1 @@
multi.surbl.org:8-16-64-128,black.uribl.com,rhsbl.sorbs.net

@ -0,0 +1,35 @@
{
$qpsmtpd = $DB->get('qpsmtpd');
return unless $qpsmtpd;
my $rbl = $qpsmtpd->prop('RBLList');
return unless $rbl;
my @rbl = ();
# Migrate to use , as separator instead of :
if ($rbl !~ m/,/){
my @zones = split /[:]/, $rbl;
my $fqdn_re = qr/([a-zA-Z0-9][a-zA-Z0-9\-]{1,61}\.)*[a-zA-Z0-9][a-zA-Z0-9\-]{1,61}\.[a-zA-Z]{2,}/;
if (scalar @zones == 2 && $zones[1] !~ m/^$fqdn_re$/){
# When we have only two entries, check if the second one looks like a valid hostname
# so if you only have something like dnsbl.foo.net:Sorry you are blacklisted
# it won't be migrated to dnsbl.foo.net,Sorry you are blacklisted
@rbl = ($rbl);
}
else{
@rbl = @zones;
}
}
else{
@rbl = split /[,]/, $rbl;
}
my %obsolete = map { $_ => 1} qw(
combined.njabl.org
list.dsbl.org
multihop.dsbl.org
dnsbl.ahbl.org
);
@rbl = grep { ! $obsolete{$_} } @rbl;
$qpsmtpd->set_prop('RBLList', join ',', @rbl);
}

@ -0,0 +1,3 @@
{
return unless $DB->get_prop_and_delete('qpsmtpd', 'RequireResolvableFromHost');
}

@ -0,0 +1,38 @@
{
$qpsmtpd = $DB->get('qpsmtpd');
return unless $qpsmtpd;
my $sbl = $qpsmtpd->prop('SBLList');
return unless $sbl;
my @sbl = ();
# Migrate to use , as separator instead of :
if ($sbl !~ m/,/){
my @zones = split /[:]/, $sbl;
my $fqdn_re = qr/([a-zA-Z0-9][a-zA-Z0-9\-]{1,61}\.)*[a-zA-Z0-9][a-zA-Z0-9\-]{1,61}\.[a-zA-Z]{2,}/;
if (scalar @zones == 2 && $zones[1] !~ m/^$fqdn_re$/){
# When we have only two entries, check if the second one looks like a valid hostname
# so if you only have something like rhsbl.foo.net:Sorry you are blacklisted
# it won't be migrated to rhsbl.foo.net,Sorry you are blacklisted
@sbl = ($sbl);
}
else{
@sbl = @zones;
}
}
else{
@sbl = split /[,]/, $sbl;
}
my %obsolete = map { $_ => 1} qw(
blackhole.securitysage.com
bulk.rhs.mailpolice.com
fraud.rhs.mailpolice.com
porn.rhs.mailpolice.com
adult.rhs.mailpolice.com
bogusmx.rfc-ignorant.org
ex.dnsbl.org
);
@sbl = grep { !$obsolete{$_} } @sbl;
$qpsmtpd->set_prop('SBLList', join ',', @sbl);
}

@ -0,0 +1,19 @@
{
my $smtpd = $DB->get("smtpd");
if ($smtpd){
my $qpsmtpd = $DB->get("qpsmtpd") ||
$DB->new_record("qpsmtpd", { type => "service" });
$qpsmtpd->merge_props($smtpd->props);
$smtpd->delete;
}
my $ssmtpd = $DB->get("ssmtpd");
if ($ssmtpd){
my $sqpsmtpd = $DB->get("sqpsmtpd") ||
$DB->new_record("sqpsmtpd", { type => "service" });
$sqpsmtpd->merge_props($ssmtpd->props);
$ssmtpd->delete;
}
}

@ -0,0 +1,40 @@
#!/usr/bin/perl -w
use esmith::DomainsDB;
use esmith::ConfigDB;
use File::Find;
my $d = esmith::DomainsDB->open_ro || die "Couldn't open the domains database";
my $c = esmith::ConfigDB->open_ro || die "Couldn't open the configurtion database";
my $qpsmtpd = $c->get('qpsmtpd');
die "qpsmtpd service entry not found" unless ($qpsmtpd);
my $dkim_sign = $qpsmtpd->prop('DKIMSigning') || 'disabled';
find({ wanted => \&wanted }, qw(/var/service/qpsmtpd/config/dkim/));
# Build a list of domain for which we want to sign emails
my @dkim_domains = ();
if ($dkim_sign =~ m/^enabled|yes|1|on$/){
foreach my $dom ($d->domains){
next if ($dom->prop('DKIMSigning') || 'enabled') eq 'disabled';
next if ($dom->prop('MailServer'));
push @dkim_domains, $dom->key;
}
}
sub wanted{
my $domain = $d->get($_);
if ( -l && !grep { $_ eq $domain->key } @dkim_domains ){
unlink $_;
}
}
foreach my $dom (@dkim_domains){
next if (-e '/var/service/qpsmtpd/config/dkim/' . $dom);
my $src = ( -e '/home/e-smith/dkim_keys/' . $dom ) ? '/home/e-smith/dkim_keys/' . $dom : '/home/e-smith/dkim_keys/default';
symlink $src, '/var/service/qpsmtpd/config/dkim/' . $dom;
}

@ -0,0 +1 @@
OUTPUT_FILENAME="/var/service/qpsmtpd/config/peers/0"

@ -0,0 +1 @@
PERMS=use esmith::ConfigDB; (esmith::ConfigDB->open_ro->get('qpsmtpd')->prop('access') eq "private") ? "000" : "0644"

@ -0,0 +1 @@
PERMS=use esmith::ConfigDB; (esmith::ConfigDB->open_ro->get('qpsmtpd')->prop('status') eq "enabled") ? "0644" : "0000"

@ -0,0 +1,4 @@
TEMPLATE_PATH="/home/e-smith/ssl.pem"
OUTPUT_FILENAME="/var/service/qpsmtpd/ssl/cert.pem"
GID="qpsmtpd"
PERMS=0640

@ -0,0 +1,8 @@
{
if (( $qpsmtpd{DMARCReporting} || 'disabled' ) =~ m/^1|on|enabled|yes$/){
$OUT .= '15 0 * * * qpsmtpd /usr/bin/dmarc_send_reports 2>&1 | grep -v "SSL connection failed" | logger -t "DMARC Reporting"' . "\n";
}
else{
$OUT .= "# DMARC Reporting is disabled\n";
}
}

@ -0,0 +1,5 @@
[organization]
domain = { $DomainName }
org_name = { $ldap{defaultCompany} || 'SME Server powered company' }
email = { $qpsmtpd{DMARCReportEmail} || 'admin@' . $DomainName }
extra_contact_info = { $qpsmtpd{DMARCContactInfo} || 'http://' . $DomainName }

@ -0,0 +1,3 @@
[report_store]
backend = SQL
dsn = dbi:SQLite:dbname=/var/lib/qpsmtpd/dmarc/reports.sqlite

@ -0,0 +1,3 @@
[dns]
timeout = 5
public_suffix_list = public_suffix_list

@ -0,0 +1,3 @@
[smtp]
hostname = { $SystemName . '.' . $DomainName }
smarthost = 127.0.0.1

@ -0,0 +1,2 @@
#spamer@spamdomain.com
#@spamdomain.com

@ -0,0 +1,9 @@
{
require esmith::AccountsDB;
require esmith::DomainsDB;
%Accounts = esmith::AccountsDB->as_hash;
%Domains = esmith::DomainsDB->as_hash;
"";
}

@ -0,0 +1,16 @@
{
foreach my $account ( keys %Accounts )
{
next unless ( exists $Accounts{$account}{Visible}
and $Accounts{$account}{Visible} eq "internal" );
$OUT .= "$account\n";
$OUT .= "$account\@$DomainName\n";
foreach my $domain ( keys %Domains )
{
next unless $Domains{$domain}{type} eq "domain";
$OUT .= "$account\@$domain\n";
}
}
}

@ -0,0 +1,14 @@
{
use esmith::DomainsDB;
my $ddb = esmith::DomainsDB->open_ro or die "Couldn't open DomainsDB\n";
my @rcpt_hosts = ( "$SystemName.$DomainName" );
foreach my $domain ( $ddb->get_all_by_prop( type => "domain" ) )
{
push @rcpt_hosts, $domain->key;
}
$OUT = join "\n", @rcpt_hosts;
}

@ -0,0 +1,5 @@
{
return "" unless (defined $ExternalIP);
return "[$ExternalIP]";
}

@ -0,0 +1,6 @@
0
{
# the first line of this file is being used as the IP
# address tcpserver will bind to. Use 0 to bind to all
# interfaces.
}

@ -0,0 +1,3 @@
{
$ExternalIP || "# ExternalIP not defined";
}

@ -0,0 +1 @@
# these domains never uses their domain when greeting us, so reject transactions

@ -0,0 +1 @@
@.*@ Sorry, multiple at signs not accepted here

@ -0,0 +1 @@
# Format is pattern\s+Response - don't forget to tie the pattern if required

@ -0,0 +1,8 @@
{
use esmith::AccountsDB;
use esmith::DomainsDB;
$a = esmith::AccountsDB->open_ro or die "Couldn't open AccountsDB";
$d = esmith::DomainsDB->open_ro or die "Couldn't open DomainsDB";
$OUT = '';
}

@ -0,0 +1,12 @@
{
$OUT .= '';
foreach my $alias ( $a->users, $a->groups, $a->pseudonyms ){
next unless ( $alias->prop('Visible') || '') =~ m/^(internal|none)$/i;
$OUT .= $alias->key . "\n" and next if $alias->key =~ m/@/;
foreach my $domain ( $d->domains ){
$OUT .= $alias->key . '@' . $domain->key . "\n";
}
}
}

@ -0,0 +1,23 @@
{
use esmith::util;
my @prefixes = esmith::util::computeAllLocalNetworkPrefixes($LocalIP,
$LocalNetmask);
require esmith::NetworksDB;
my $n = esmith::NetworksDB->open;
foreach my $network ($n->get_all_by_prop(type => 'network'))
{
push(@prefixes,
esmith::util::computeAllLocalNetworkPrefixes(
$network->key, $network->prop('Mask')));
}
foreach my $prefix ( @prefixes )
{
my $dot = ( $prefix =~ /\d+\.\d+\.\d+\.\d+/ ) ? '' : '.';
$OUT .= $prefix . $dot . "\n";
}
$OUT .= "127.0.0.1";
}

@ -0,0 +1,7 @@
{
my @rbllist = split /[,]/, ${qpsmtpd}{RBLList} || '';
return "# No RBLs are defined" unless (scalar @rbllist);
return join "\n", @rbllist;
}

@ -0,0 +1,6 @@
{
# rbl.mail-abuse.org
# spamsources.fabel.dk
# relays.ordb.org
# sbl.spamhaus.org
}

@ -0,0 +1,9 @@
{
use esmith::DomainsDB;
my $ddb = esmith::DomainsDB->open_ro or die "Couldn't open DomainsDB";
@domains = map $_->key, $ddb->domains;
"";
}

@ -0,0 +1,5 @@
{
return "" unless (defined $ExternalIP);
return "postmaster\@[$ExternalIP]";
}

@ -0,0 +1,8 @@
{
$OUT = "";
for my $user ( qw(admin root) )
{
$OUT .= "$user\@$_\n" for (@domains);
}
}

@ -0,0 +1,24 @@
{
# Make a list of all valid local recipients
use esmith::AccountsDB;
my %valid = map { $_ => 1 } qw(group pseudonym user mailmanlist mailinglist);
$OUT = "";
my $adb = esmith::AccountsDB->open_ro();
foreach my $account ($adb->get_all)
{
my $key = $account->key;
next unless $valid{$account->prop('type')};
if ($key =~ /\@/)
{
$OUT .= "$key\n";
}
else
{
$OUT .= "$key\@$_\n" for (@domains);
}
}
}

@ -0,0 +1,17 @@
{
$OUT = "";
use esmith::DomainsDB;
my $ddb = esmith::DomainsDB->open_ro();
for my $domain ( $ddb->domains )
{
my $mail_server = $domain->prop('MailServer')
|| $DelegateMailServer
|| 'localhost';
next if ( $mail_server eq 'localhost' );
$OUT .= '@' . $domain->key . "\n";
}
}

@ -0,0 +1,14 @@
{
# Log levels
# LOGDEBUG = 8
# LOGINFO = 7
# LOGNOTICE = 6
# LOGWARN = 5
# LOGERROR = 4
# LOGCRIT = 3
# LOGALERT = 2
# LOGEMERG = 1
# LOGRADAR = 0
return $qpsmtpd{LogLevel};
}

@ -0,0 +1,2 @@
# Format is IP, or IP part with trailing dot
# e.g. "127.0.0.1", or "192.168."

@ -0,0 +1,6 @@
{
return '' unless $GatewayIP;
# we allow access from the router, but we do not allow relaying
return $GatewayIP;
}

@ -0,0 +1,39 @@
{
# this is based on 70spamassassin fragment
# it does the same except it will force check on fetchmail inputs
# You can run the spamassassin plugin with options. See perldoc
# plugins/spamassassin for details.
#
# spamassassin
# rejects mails with a SA score higher than 20 and munges the subject
# of the score is higher than 10.
#
# spamassassin reject_threshold 20 munge_subject_threshold 10
my $status = $spamassassin{status} || 'disabled';
return "# spamassassin disabled" unless ($status eq "enabled");
my @options = qw(forcespamcheck);
if ($spamassassin{Sensitivity} eq "custom")
{
if ($spamassassin{RejectLevel} > $spamassassin{TagLevel})
{
push @options, "reject", $spamassassin{RejectLevel};
}
}
if ($spamassassin{SubjectTag} eq "enabled")
{
push @options, "munge_subject_threshold", $spamassassin{TagLevel};
}
my $size = $spamassassin{MaxMessageSize} || '';
if ($size =~ m/^\d+$/)
{
push @options, "size_limit", $size;
}
return join " ", @options;
}

@ -0,0 +1,11 @@
{
$bounce_unknown_user = 1;
$bounce_unknown_user = 0
if (defined $EmailUnknownUser and $EmailUnknownUser ne 'returntosender');
$bounce_unknown_user = 0
if (defined $DelegateMailServer and $DelegateMailServer);
"";
}

@ -0,0 +1 @@
tls ssl/cert.pem ssl/cert.pem ssl/cert.pem ssl/dhparam.pem

@ -0,0 +1,9 @@
{
# my $auth_smtp = ($qpsmtpd{Authentication} eq 'enabled') ? 'yes' : 'no';
# my $auth_ssmtp = ($sqpsmtpd{Authentication} eq 'enabled') ? 'yes' : 'no';
# $OUT = "auth/auth_cvm_unix_local";
# $OUT .= " cvm_socket /var/lib/cvm/cvm-unix-local.socket";
# $OUT .= " enable_smtp $auth_smtp";
# $OUT .= " enable_ssmtp $auth_ssmtp";
}

@ -0,0 +1,3 @@
{
$OUT .= "auth/auth_imap 127.0.0.1 143";
}

@ -0,0 +1,6 @@
{
return "# Karma plugin is disabled" unless (($qpsmtpd{Karma} || 'disabled') =~ m/^1|on|yes|enabled$/i);
my $negative = $qpsmtpd{KarmaNegative} || '2';
my $strikes = $qpsmtpd{KarmaStrikes} || '3';
$OUT .= "karma negative $negative strikes $strikes reject naughty db_dir /var/lib/qpsmtpd/karma";
}

@ -0,0 +1,7 @@
{
return "# bcc disabled" unless ($qpsmtpd{Bcc} eq "enabled");
my $user = $qpsmtpd{BccUser} || '';
return "# bcc user not set" if $user eq '';
$user .= '@' . $DomainName unless $user =~ m/\@/;
return "bcc mode " . $qpsmtpd{BccMode} . " all " . $user;
}

@ -0,0 +1 @@
helo policy { $qpsmtpd{HeloPolicy} || 'lenient' } reject naughty

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save