--- amavisd.orig Sun Jul 4 03:19:35 2004 +++ amavisd Wed Aug 11 00:31:32 2004 @@ -87,6 +87,7 @@ # Amavis::Lookup::LDAP # Amavis::In::AMCL # Amavis::In::SMTP +# Amavis::In::QMQPqq # Amavis::AV # Amavis::SpamControl # Amavis::Unpackers @@ -227,6 +228,7 @@ $max_servers $max_requests $child_timeout %current_policy_bank %policy_bank %interface_policy $unix_socketname $inet_socket_port $inet_socket_bind + $inet_smtp_port $inet_qmqpqq_port $myhostname $insert_received_line $gets_addr_in_quoted_form $relayhost_is_client $smtpd_recipient_limit @@ -1094,6 +1096,9 @@ if ($do_syslog) { openlog($ident, LOG_PID, $syslog_facility); } else { + if(!defined $logfile) { + die 'No $LOGFILE is defined while not logging via syslog!'; + } $loghandle = IO::File->new($logfile,'>>') or die "Failed to open log file $logfile: $!"; $loghandle->autoflush(1); @@ -1175,7 +1180,7 @@ &retcode &exit_status_str &prolong_timer &sanitize_str &strip_tempdir &rmdir_recursively &read_text &read_l10n_templates &read_hash - &run_command &run_command_consumer); + &run_command &run_command_consumer &if_exists_in_array); } use subs @EXPORT_OK; use POSIX qw(WIFEXITED WIFSIGNALED WIFSTOPPED @@ -1618,6 +1623,19 @@ ($proc_fh, $pid); # return pipe file handle to the subprocess and its PID } +# returns undef if value does not exist in array or position of the first occurence in the array +sub if_exists_in_array($$) { +my($value,$ref) = @_; +(ref $ref eq 'ARRAY') || return(undef); + +for(my $i=0;$i<@{$ref};$i++) { + if($value eq $ref->[$i]) { + return($i); + } + } +return(undef); +} + 1; # @@ -1699,18 +1717,26 @@ sub received_line($$$$) { my($conn, $msginfo, $id, $folded) = @_; my($smtp_proto, $recips) = ($conn->smtp_proto, $msginfo->recips); + my($proto,$helo); + if(defined $conn->smtp_proto) { + $proto = $conn->smtp_proto; + $helo = $conn->smtp_helo; + } elsif (defined $conn->qmqp_proto) { + $proto = $conn->qmqp_proto; + $helo = $conn->qmqp_helo; + } my($client_ip) = $conn->client_ip; if ($client_ip =~ /:/ && $client_ip !~ /^IPv6:/i) { $client_ip = 'IPv6:' . $client_ip; } my($s) = sprintf("from %s%s\n by %s%s (amavisd-new, %s)", - ($conn->smtp_helo eq '' ? 'unknown' : $conn->smtp_helo), + ($helo eq '' ? 'unknown' : $helo), ($client_ip eq '' ? '' : " ([$client_ip])"), c('localhost_name'), ($conn->socket_ip eq '' ? '' : sprintf(" (%s [%s])", $myhostname, $conn->socket_ip) ), ($conn->socket_port eq '' ? 'unix socket' : "port ".$conn->socket_port) ); - $s .= "\n with $smtp_proto" if $smtp_proto =~ /^(ES|S|L)MTP\z/i; + $s .= "\n with $proto" if defined $proto; $s .= "\n id $id" if $id ne ''; # do not disclose recipients if more than one $s .= "\n for " . qquote_rfc2821_local(@$recips) if @$recips == 1; @@ -2878,6 +2904,10 @@ { my($self)=shift; !@_ ? $self->{smtp_proto}: ($self->{smtp_proto}=shift) } sub smtp_helo # (E)SMTP HELO/EHLO parameter { my($self)=shift; !@_ ? $self->{smtp_helo} : ($self->{smtp_helo}=shift) } +sub qmqp_proto # QMQP/QMQPqq + { my($self)=shift; !@_ ? $self->{qmqp_proto}: ($self->{qmqp_proto}=shift) } +sub qmqp_helo # for future use maybe + { my($self)=shift; !@_ ? $self->{qmqp_helo} : ($self->{qmqp_helo}=shift) } 1; @@ -5268,7 +5298,7 @@ BEGIN { import Amavis::Conf qw(:platform :sa :confvars c cr ca); import Amavis::Util qw(untaint min max do_log debug_oneshot am_id - prolong_timer); + prolong_timer if_exists_in_array); import Amavis::Timing qw(section_time snmp_count); import Amavis::Log; import Amavis::Lookup qw(lookup lookup_ip_acl); @@ -5296,7 +5326,7 @@ use vars qw( $extra_code_sql $extra_code_ldap - $extra_code_in_amcl $extra_code_in_smtp + $extra_code_in_amcl $extra_code_in_smtp $extra_code_in_qmqpqq $extra_code_antivirus $extra_code_antispam $extra_code_unpackers); use vars qw($spam_level $spam_status $spam_report); use vars qw($user_id_sql $wb_listed_sql); @@ -5314,6 +5344,8 @@ @banned_filename @bad_headers); use vars qw($amcl_in_obj $smtp_in_obj); # Amavis::In::AMCL and In::SMTP objects +use vars qw($qmqpqq_in_obj); # Amavis::In::QMQPqq object +use vars qw($inet_smtp_port $inet_qmqpqq_port); use vars qw($sql_policy $sql_wblist); # Amavis::Lookup::SQL objects use vars qw($ldap_wblist); # Array Ref. [whitelist, blacklist] @@ -5359,6 +5391,7 @@ do_log(1,"Lookup::LDAP code ".($extra_code_ldap ?'':" NOT")." loaded"); do_log(1,"AMCL-in protocol code ".($extra_code_in_amcl?'':" NOT")." loaded"); do_log(1,"SMTP-in protocol code ".($extra_code_in_smtp?'':" NOT")." loaded"); + do_log(1,"QMQPqq-in protocol code ".($extra_code_in_qmqpqq?'':" NOT")." loaded"); do_log(1,"ANTI-VIRUS code ".($extra_code_antivirus?'':" NOT")." loaded"); do_log(1,"ANTI-SPAM code ".($extra_code_antispam ?'':" NOT")." loaded"); do_log(1,"Unpackers code ".($extra_code_unpackers?'':" NOT")." loaded"); @@ -5760,13 +5793,19 @@ # amavis policy delegation protocol (e.g. new milter helper program) $amcl_in_obj = Amavis::In::AMCL->new if !$amcl_in_obj; $amcl_in_obj->process_policy_request($sock, $conn, \&check_mail, 0); - } elsif (!$extra_code_in_smtp) { + } elsif (!$extra_code_in_smtp && !$extra_code_in_qmqpqq) { die ("incoming TCP connection, but dynamic code " . - "to handle SMTP or LMTP not loaded"); - } else { # defaults to SMTP or LMTP + "to handle SMTP, LMTP or QMQPqq not loaded"); + } elsif (defined if_exists_in_array($prop->{sockport},$inet_smtp_port)) { $smtp_in_obj = Amavis::In::SMTP->new if !$smtp_in_obj; $smtp_in_obj->process_smtp_request( $sock, ($suggested_protocol eq 'LMTP'?1:0), $conn, \&check_mail); + } elsif(defined if_exists_in_array($prop->{sockport},$inet_qmqpqq_port)) { + $qmqpqq_in_obj = Amavis::In::QMQPqq->new if !$qmqpqq_in_obj; + $qmqpqq_in_obj->process_qmqpqq_request($sock,$conn,\&check_mail); + } else { # better to be safe than sorry + die ("dynamic code to handle incomming TCP connection on port '" . + "$prop->{sockport}' is not loaded or does not exist (yet)"); } } else { die ("unsupported protocol: " . $sock->NS_proto); @@ -5818,6 +5857,7 @@ $0 = sprintf("amavisd (ch%d-finish)", $child_invocation_count); # do_log(0,"Amavis::In::SMTP::DESTROY will be called from 'child_finish_hook'"); $smtp_in_obj = undef; # calls Amavis::In::SMTP::DESTROY + $qmqpqq_in_obj = undef; # calls Amavis::In::QMQPqq::DESTROY $amcl_in_obj = undef; # (currently does nothing for Amavis::In::AMCL) $body_digest_cache = undef; # calls Amavis::Cache::DESTROY } @@ -5888,6 +5928,7 @@ @virusname = (); @banned_filename = (); @bad_headers = (); $spam_level = undef; $spam_status = undef; $spam_report = undef; + $qmqpqq_in_obj = undef; # calls Amavis::In::QMQPqq::DESTROY # comment out to retain SQL cache entries for the whole child lifetime: $sql_policy->clear_cache if defined $sql_policy; $sql_wblist->clear_cache if defined $sql_wblist; @@ -6393,8 +6434,8 @@ snmp_count('OutForwHoldMsgs') if $hold ne ''; last if $done_all; } - prolong_timer($which_section); } + prolong_timer($which_section); $which_section = "delivery-notification"; my($dsn_needed); @@ -7343,7 +7384,7 @@ do { local($/) = "__DATA__\n"; # set line terminator to this string map { chomp($_ = ) } ( $extra_code_sql, $extra_code_ldap, - $extra_code_in_amcl, $extra_code_in_smtp, + $extra_code_in_amcl, $extra_code_in_smtp, $extra_code_in_qmqpqq, $extra_code_antivirus, $extra_code_antispam, $extra_code_unpackers, $Amavis::Conf::log_templ, $Amavis::Conf::log_recip_templ); if ($unicode_aware) { @@ -7367,7 +7408,7 @@ $Amavis::Conf::log_recip_templ = $1 if $Amavis::Conf::log_recip_templ=~/^(.*?)[\r\n]+\z/s; -my($config_file) = '/etc/amavisd.conf'; # default location of config file +my($config_file) = '/usr/local/etc/amavisd.conf'; # default location of config file # Consider droping privileges early, before reading config file. # This is only possible if running under chroot will not be needed. @@ -7456,13 +7497,90 @@ $extra_code_in_amcl = 1; # release memory occupied by the source code } -if ($inet_socket_port eq '' || ref $inet_socket_port && !@$inet_socket_port) { - $extra_code_in_smtp = undef; -} else { - eval $extra_code_in_smtp or die "Problem in the In::SMTP code: $@"; - $extra_code_in_smtp = 1; # release memory occupied by the source code -} - +# make it a reference +$inet_socket_port = ($inet_socket_port eq ''? + undef : (ref $inet_socket_port? + (@$inet_socket_port ? + $inet_socket_port : undef) : [$inet_socket_port])); + +if(!ref $inet_socket_port) { + $extra_code_in_smtp = undef; + $extra_code_in_qmqpqq = undef; + } +else { + # make it a reference + $inet_smtp_port = ($inet_smtp_port eq ''? + undef : (ref $inet_smtp_port? + (@$inet_smtp_port ? + [@$inet_smtp_port] : undef) : [$inet_smtp_port])); + # make it a reference + $inet_qmqpqq_port = ($inet_qmqpqq_port eq ''? + undef : (ref $inet_qmqpqq_port ? + (@$inet_qmqpqq_port ? + [@$inet_qmqpqq_port] : undef) : [$inet_qmqpqq_port])); + + # check whether these two does not overlay + if(ref $inet_smtp_port && ref $inet_qmqpqq_port) { + foreach my $port (@$inet_smtp_port) { + (!defined if_exists_in_array($port,$inet_qmqpqq_port)) || + die("QMQPqq port '$port' is already assigned to SMTP/LMTP"); + } + } + + # check whether every $inet_socket_port is assigned some service + foreach my $port (@$inet_socket_port) { + if(ref $inet_smtp_port && defined if_exists_in_array($port,$inet_smtp_port)) { + next; + } + if(ref $inet_qmqpqq_port && defined if_exists_in_array($port,$inet_qmqpqq_port)) { + next; + } + die("Port '$port' is not assigned any service"); + } + + if(ref $inet_smtp_port) { + # check whether $inet_smtp_port is in $inet_socket_port + my $if_any = undef; + foreach my $port (@$inet_smtp_port) { + if(defined if_exists_in_array($port,$inet_socket_port)) { + $if_any = 1; + last; + } + } + if(!$if_any) { + $extra_code_in_smtp = undef; # feature not a bug + } + else { + eval $extra_code_in_smtp || die("Problem in the In::SMTP code: $@"); + $extra_code_in_smtp = 1; # release memory occupied by the source code + } + } + else { + $extra_code_in_smtp = undef; + } + + if(ref $inet_qmqpqq_port) { + # check whether $inet_qmqpqq_port is in $inet_socket_port + my $if_any = undef; + foreach my $port (@$inet_qmqpqq_port) { + if(defined if_exists_in_array($port,$inet_socket_port)) { + $if_any = 1; + last; + } + } + if(!$if_any) { + $extra_code_in_qmqpqq = undef; # feature not a bug + } + else { + eval $extra_code_in_qmqpqq || die("Problem in the In::QMQPqq code: $@"); + $extra_code_in_qmqpqq = 1; # release memory occupied by the source code + } + } + else { + $extra_code_in_qmqpqq = undef; + } + } + my($bpvcm) = ca('bypass_virus_checks_maps'); if (!@{ca('av_scanners')} && !@{ca('av_scanners_backup')}) { $extra_code_antivirus = undef; @@ -9143,6 +9261,333 @@ or die "Error writing a SMTP response to the socket: $!"; @{$self->{smtp_outbuf}} = (); } +} + +1; + +__DATA__ +# +package Amavis::In::QMQPqq; +use strict; + +BEGIN { + use Exporter (); + use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION); + $VERSION = '1.15'; + @ISA = qw(Exporter); +} +use POSIX qw(strftime); +use Errno qw(ENOENT); +use Time::HiRes qw(time); + +BEGIN { + import Amavis::Conf qw(:platform :confvars :dynamic_confvars c); + import Amavis::Util qw(do_log am_id prolong_timer debug_oneshot + sanitize_str strip_tempdir rmdir_recursively); + import Amavis::Lookup qw(lookup); + import Amavis::Timing qw(section_time); + import Amavis::rfc2821_2822_Tools; + import Amavis::In::Message; + import Amavis::In::Connection; +} + +sub new($) { + my($class) = @_; + my($self) = bless {}, $class; + $self->{fh_pers} = undef; # persistent file handle for email.txt + $self->{tempdir_pers} = undef; # temporary directory for check_mail + $self->{preserve} = undef; # don't delete tempdir on exit + $self->{tempdir_empty} = 1; # anything of interest in tempdir? + $self->{bytesleft} = undef; # bytes left for whole package + $self->{len} = undef; # set by getlen() method + $self->{sock} = undef; # connected socket + $self->{proto} = undef; # protocol + $self->{session_closed_normally} = undef; # closed properly? (waited for K/Z/D) + $self; +} + +sub preserve_evidence # try to preserve temporary files etc in case of trouble + { my($self)=shift; !@_ ? $self->{preserve} : ($self->{preserve}=shift) } + +sub DESTROY { + my($self) = shift; +# do_log(0, "Amavis::In::QMQPqq::DESTROY called"); + $self->{fh_pers}->close + or die "Can't close temp file: $!" if $self->{fh_pers}; + my($errn) = $self->{tempdir_pers} eq '' ? ENOENT + : (stat($self->{tempdir_pers}) ? 0 : 0+$!); + if (defined $self->{tempdir_pers} && $errn != ENOENT) { + # this will not be included in the TIMING report, + # but it only occurs infrequently and doesn't take that long + if ($self->preserve_evidence && !$self->{tempdir_empty}) { + do_log(0, "tempdir is to be PRESERVED: ".$self->{tempdir_pers}); + } else { + do_log(2, "tempdir being removed: ".$self->{tempdir_pers}); + rmdir_recursively($self->{tempdir_pers}); + } + } + if (! $self->{session_closed_normally}) { + $self->qmqpqq_resp("Z","Service shutting down, closing channel"); + } +} + +sub prepare_tempdir($) { + my($self) = @_; + if (! defined $self->{tempdir_pers} ) { + # invent a name for a temporary directory for this child, and create it + my($now_iso8601) = strftime("%Y%m%dT%H%M%S", localtime); + $self->{tempdir_pers} = sprintf("%s/amavis-%s-%05d", + $TEMPBASE, $now_iso8601, $$); + } + my($errn) = stat($self->{tempdir_pers}) ? 0 : 0+$!; + if ($errn == ENOENT || ! -d _) { + mkdir($self->{tempdir_pers}, 0750) + or die "Can't create directory $self->{tempdir_pers}: $!"; + $self->{tempdir_empty} = 1; + section_time('mkdir tempdir'); + } + # prepare temporary file for writing (and reading later) + my($fname) = $self->{tempdir_pers} . "/email.txt"; + my($errn) = stat($fname) ? 0 : 0+$!; + if ($self->{fh_pers} && !$errn && -f _) { + $self->{fh_pers}->seek(0,0) or die "Can't rewind mail file: $!"; + $self->{fh_pers}->truncate(0) or die "Can't truncate mail file: $!"; + } else { + $self->{fh_pers} = IO::File->new($fname, 'w+', 0640) + or die "Can't create file $fname: $!"; + section_time('create email.txt'); + } +} + + +# get byte, die if no bytes left +sub getbyte($) { +my($self) = shift; +if(!$self->{bytesleft}--) { + die("No bytes left"); + } +if(defined($_ = $self->{sock}->getc)) { + return($_); + } +die("EOF on socket"); +} + +sub getlen($) { +my($self) = shift; +my($ch,$len); + +for(;;) { + $ch = $self->getbyte; + if($ch eq ':') { + return($self->{len} = $len); + } + if($ch !~ /^\d$/) { + die("Char '$ch' is not a number while determining length"); + } + $len .= $ch; + } +} + +sub getcomma($) { +my($self) = shift; +if($self->getbyte ne ',') { + die("Comma expected, found '$_'"); + } +} + +sub getnetstring($$) { +my($self) = shift; +($self->{sock}->read($_[0],$self->getlen) == $self->{len}) || + die("EOF on socket"); +$self->{bytesleft} -= $self->{len}; +$self->getcomma; +} + + +# Accept a QMQPqq connect +# and call content checking for the message received +# +sub process_qmqpqq_request($$$$) { +my($self,$sock,$conn,$check_mail) = @_; +# $sock: connected socket from Net::Server +# $conn: information about client connection +# $check_mail: subroutine ref to be called with file handle + +$self->{proto} = "QMQPqq"; +$self->{sock} = $sock; # store $sock info for getbyte() method +$self->{bytesleft} = 20; # initial bytesleft value, there should + # NEVER EVER be longer email than 10^20 (approximately) + # bytes but increase if needed ;) +$self->{len} = undef; + +my($msginfo); + +my($sender,@recips); + +my($len); + +$conn->qmqp_proto("QMQPqq"); +$conn->qmqp_helo("QMQPqq client"); # for future possible use +eval { + # get length of whole package + $self->{bytesleft} = $self->getlen; + + # get length of 'email' + $len = $self->getlen; + section_time('initial length determination'); + + am_id(sprintf("%05d-%02d",$$,$Amavis::child_invocation_count)); + + # prepare tempdir + $self->prepare_tempdir; + $msginfo = Amavis::In::Message->new; + $msginfo->rx_time(time); + $msginfo->delivery_method(c('forward_method')); + + # get 'email' + $self->{tempdir_empty} = 0; + my $size = 16384; + while(($len > 0) && ($sock->read($_,($len >= $size ? $size : $size = $len)) == $size)) { + (print {$self->{fh_pers}} $_) || + die("Can't write to mail file: $!"); + $len -= $size; + } + if($len > 0) { + die("EOF on socket"); + } + $self->{fh_pers}->flush || die("Can't flush mail file: $!"); + $self->{fh_pers}->seek(0,1) || die("Can't seek on file: $!"); + $self->{bytesleft} -= $self->{len}; + section_time('email receiving'); + # comma has to follow + $self->getcomma; + + # get sender + $self->getnetstring($sender); + section_time('sender receiving'); + + # get recips + my $i = 0; + while($self->{bytesleft}) { + $self->getnetstring($recips[$i++]); + } + section_time('recips receiving'); + + # final comma has to follow + $self->{bytesleft} = 1; + $self->getcomma; + + $msginfo->sender($sender); + $msginfo->recips(\@recips); + + do_log(1, sprintf("%s:%s:%s %s: <%s> -> %s Received: %s", + $self->{proto},$conn->socket_ip eq $inet_socket_bind ? + '' : '['.$conn->socket_ip.']', + $conn->socket_port, $self->{tempdir_pers}, + $sender, join(',', map{"<$_>"}@recips), + join(' ', + ($msginfo->msg_size eq '' ? () + : 'SIZE='.$msginfo->msg_size), + ($msginfo->body_type eq '' ? () + : 'BODY='.$msginfo->body_type), + received_line($conn,$msginfo,am_id(),0) ) + )); + + $msginfo->mail_text($self->{fh_pers}); + $msginfo->mail_tempdir($self->{tempdir_pers}); + my($smtp_resp,$exit_code,$preserve_evidence) = + &$check_mail($conn,$msginfo,0,$self->{tempdir_pers}); + + if ($preserve_evidence) { + $self->preserve_evidence(1); + } + if ($smtp_resp !~ /^4/ && + grep { !$_->recip_done } @{$msginfo->per_recip_data}) { + die("TROUBLE/MISCONFIG: not all recipients done, ". + "\$forward_method is \"$forward_method\""); + } + + # all ok + if($smtp_resp =~ /^2/) { + $self->qmqpqq_resp("K",$smtp_resp); + } + # permanent reject + elsif($smtp_resp =~ /^5/) { + $self->qmqpqq_resp("D",$smtp_resp); + } + # temporary reject (or other error if !~ /^4/) + else { + $self->qmqpqq_resp("Z",$smtp_resp); + } + }; + +alarm(0); do_log(5,"timer stopped after QMQPqq eval"); + +if($@ ne '') { + chomp($@); + + do_log(0,"QMQPqq: NOTICE: $@"); + $self->qmqpqq_resp("Z","Service shutting down, $@"); + } + +if ($self->preserve_evidence && !$self->{tempdir_empty}) { + # keep evidence in case of trouble + do_log(0,"PRESERVING EVIDENCE in ".$self->{tempdir_pers}); + $self->{fh_pers}->close or die "Can't close mail file: $!"; + $self->{fh_pers} = undef; $self->{tempdir_pers} = undef; + $self->{tempdir_empty} = 1; + } + +# cleanup, but leave directory (and file handle +# if possible) for reuse +if ($self->{fh_pers} && !$can_truncate) { + # truncate is not standard across all Unix variants, + # it is not Posix, but is XPG4-UNIX. + # So if we can't truncate a file and leave it open, + # we have to create it anew later, at some cost. + # + $self->{fh_pers}->close or die "Can't close mail file: $!"; + $self->{fh_pers} = undef; + unlink($self->{tempdir_pers}."/email.txt") + or die "Can't delete file ". + $self->{tempdir_pers}."/email.txt: $!"; + section_time('delete email.txt'); + } + +if (defined $self->{tempdir_pers}) { # prepare for the next one + strip_tempdir($self->{tempdir_pers}); + $self->{tempdir_empty} = 1; + } + +$self->preserve_evidence(0); # reset +# report elapsed times by section for each transaction +do_log(2, Amavis::Timing::report()); + +$self->{session_closed_normally} = 1; +# closes connection after child_finish_hook +} + +# sends a QMQPqq response consisting of K/D/Z code and an optional message; +# slow down evil clients by delaying response on permanent errors +sub qmqpqq_resp($$$;$$) { +my($self,$code,$resp,$penalize,$line) = @_; +if($code !~ /^(K|Z|D)$/) { + die("Internal error(2): bad QMQPqq response code: '$code'"); + } +if($penalize) { + do_log(0,"QMQPqq: $resp; PENALIZE: $line"); + sleep 5; + section_time('QMQPqq penalty wait'); + } +my($taint) = substr($resp,0,0); +$resp = sanitize_str($resp,1); +do_log(4,"QMQPqq> $resp"); +print($self->netstring($code . $resp)); +} + +sub netstring($$) { +my($self,$string) = @_; +return(sprintf("%d:%s,",length($string),$string)); } 1; --- amavisd.conf.orig Wed Aug 11 00:37:10 2004 +++ amavisd.conf Wed Aug 11 00:33:45 2004 @@ -31,7 +31,9 @@ $QUARANTINEDIR = '/var/virusmails'; # $daemon_chroot_dir = $MYHOME; # (default is undef, meaning: do not chroot) -$inet_socket_port = 10024; # accept SMTP on this local TCP port(s) (Postfix) +$inet_socket_port = [10024,10628]; # accept connections on this local TCP port(s) +$inet_smtp_port = 10024; # accept SMTP/LMTP on this local TCP port(s); +$inet_qmqpqq_port = 10628; # accept QMQPqq on this local TCP port(s); # $unix_socketname = "$MYHOME/amavisd.sock"; # when using sendmail milter $sa_mail_body_size_limit = 200*1024; # don't waste time on SA if mail is larger --- amavisd.conf-default.orig Wed Aug 11 00:38:36 2004 +++ amavisd.conf-default Wed Aug 11 00:39:59 2004 @@ -50,7 +50,9 @@ ## MTA INTERFACE - INPUT # $unix_socketname = undef; # amavis helper protocol socket -# $inet_socket_port = undef; # accept SMTP on this local TCP port(s) +# $inet_socket_port = undef; # accept connections on this local TCP port(s) +# $inet_smtp_port = undef; # accept SMTP/LMTP connections on this local TCP port(s) +# $inet_qmqpqq_port = undef; # accept QMQPqq connections on this local TCP port(s) # $inet_socket_bind = '127.0.0.1'; # @inet_acl = qw( 127.0.0.1 ::1 ); # @mynetworks = qw( 127.0.0.0/8 ::1 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 ); --- amavisd.conf-sample.orig Wed Aug 11 00:50:14 2004 +++ amavisd.conf-sample Wed Aug 11 00:50:08 2004 @@ -208,9 +208,14 @@ # SMTP SERVER (INPUT) PROTOCOL SETTINGS (e.g. with Postfix, Exim v4, ...) # (used when MTA is configured to pass mail to amavisd via SMTP or LMTP) -$inet_socket_port = 10024; # accept SMTP on this local TCP port - # (default is undef, i.e. disabled) +$inet_socket_port = [10024,10628]; # accept connections on this local TCP port # multiple ports may be provided: $inet_socket_port = [10024, 10026, 10028]; +$inet_smtp_port = 10024; # accept SMTP/LMTP connections on this local TCP port +# multiple_ports may be provided: $inet_smtp_port = [10024,10025]; +$inet_qmqpqq_port = 10628; # accept QMQPqq connections on this local TCP port +# multiple_ports may be provided: $inet_qmqpqq_port = [10628,10629]; +## +# $inet_socket_port has to reflect $inet_smtp_port and $inet_qmqpqq_port ports # SMTP SERVER (INPUT) access control # - do not allow free access to the amavisd SMTP port !!!