Server IP : 85.214.239.14 / Your IP : 3.129.71.13 Web Server : Apache/2.4.62 (Debian) System : Linux h2886529.stratoserver.net 4.9.0 #1 SMP Tue Jan 9 19:45:01 MSK 2024 x86_64 User : www-data ( 33) PHP Version : 7.4.18 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare, MySQL : OFF | cURL : OFF | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /sbin/ |
Upload File : |
#!/usr/bin/perl -T # SPDX-License-Identifier: BSD-2-Clause #------------------------------------------------------------------------------ # This is amavisd-submit, a simple demonstrational program, taking an email # message on stdin and submiting it to amavisd daemon. It is functionally # much like the old amavis.c helper program, except that it talks a new # AM.PDP protocol with the amavisd daemon. See README.protocol for the # description of AM.PDP protocol. # # Author: Mark Martinec <Mark.Martinec@ijs.si> # # Copyright (c) 2004,2010-2014, Mark Martinec # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # The views and conclusions contained in the software and documentation are # those of the authors and should not be interpreted as representing official # policies, either expressed or implied, of the Jozef Stefan Institute. # (the above license is the 2-clause BSD license, also known as # a "Simplified BSD License", and pertains to this program only) # # Patches and problem reports are welcome. # The latest version of this program is available at: # http://www.ijs.si/software/amavisd/ #------------------------------------------------------------------------------ # Usage: # amavisd-submit sender recip1 recip2 recip3 ... <email.msg # (should run under the same GID as amavisd, to make files accessible to it) # # To be placed in amavisd.conf: # $interface_policy{'SOCK'} = 'AM.PDP'; # $policy_bank{'AM.PDP'} = { protocol=>'AM.PDP' }; # $unix_socketname = '/var/amavis/amavisd.sock'; use warnings; use warnings FATAL => 'utf8'; no warnings 'uninitialized'; use strict; use re 'taint'; use IO::Socket; use IO::File; use File::Temp (); use Time::HiRes (); BEGIN { use vars qw($VERSION); $VERSION = 2.101; use vars qw($log_level $socketname $tempbase $io_socket_module_name); ### USER CONFIGURABLE: $log_level = 0; $tempbase = '/var/lib/amavis/tmp'; # where to create a temp directory with a msg $socketname = '/var/lib/amavis/amavisd.sock'; # $socketname = '127.0.0.1:9998'; # $socketname = '[::1]:9998'; ### END OF USER CONFIGURABLE # load a suitable sockets module if ($socketname =~ m{^/}) { require IO::Socket::UNIX; $io_socket_module_name = 'IO::Socket::UNIX'; } elsif (eval { require IO::Socket::IP }) { # prefer using module IO::Socket::IP if available, $io_socket_module_name = 'IO::Socket::IP'; } elsif (eval { require IO::Socket::INET6 }) { # otherwise fall back to IO::Socket::INET6 $io_socket_module_name = 'IO::Socket::INET6'; } elsif (eval { require IO::Socket::INET }) { $io_socket_module_name = 'IO::Socket::INET'; } $io_socket_module_name or die "No suitable socket module available"; } sub sanitize_str { my($str, $keep_eol) = @_; my(%map) = ("\r" => '\\r', "\n" => '\\n', "\f" => '\\f', "\t" => '\\t', "\b" => '\\b', "\e" => '\\e', "\\" => '\\\\'); if ($keep_eol) { $str =~ s/([^\012\040-\133\135-\176])/ # and \240-\376 ? exists($map{$1}) ? $map{$1} : sprintf(ord($1)>255 ? '\\x{%04x}' : '\\%03o', ord($1))/eg; } else { $str =~ s/([^\040-\133\135-\176])/ # and \240-\376 ? exists($map{$1}) ? $map{$1} : sprintf(ord($1)>255 ? '\\x{%04x}' : '\\%03o', ord($1))/eg; } $str; } sub ll($) { my($level) = @_; $level <= $log_level; } sub do_log($$;@) { my($level, $errmsg, @args) = @_; $errmsg = sprintf($errmsg,@args) if @args; print STDERR sanitize_str($errmsg),"\n" if $level <= $log_level; } sub proto_decode($) { my($str) = @_; $str =~ s/%([0-9a-fA-F]{2})/pack("C",hex($1))/eg; $str; } sub proto_encode($@) { my($attribute_name,@strings) = @_; local($1); $attribute_name =~ # encode all but alfanumerics, '_' and '-' s/([^0-9a-zA-Z_-])/sprintf("%%%02x",ord($1))/eg; for (@strings) { # encode % and nonprintables s/([^\041-\044\046-\176])/sprintf("%%%02x",ord($1))/eg; } $attribute_name . '=' . join(' ',@strings); } sub ask_amavisd($$) { my($sock,$query_ref) = @_; my(@encoded_query) = map { /^([^=]+)=(.*)\z/s; proto_encode($1,$2) } @$query_ref; do_log(2, "> %s", $_) for @encoded_query; $sock->print( map($_."\015\012", (@encoded_query,'')) ) or die "Can't write response to socket: $!"; $sock->flush or die "Can't flush on socket: $!"; my(%attr); local($/) = "\015\012"; # set line terminator to CRLF # must not use \r and \n, which may not be \015 and \012 on certain platforms do_log(2, "waiting for response"); while(<$sock>) { last if /^\015\012\z/; # end of response if (/^ ([^=\000\012]*?) (=|:[ \t]*) ([^\012]*?) \015\012 \z/xsi) { my $attr_name = proto_decode($1); my $attr_val = proto_decode($3); if (!exists $attr{$attr_name}) { $attr{$attr_name} = [] } push(@{$attr{$attr_name}}, $attr_val); } } if (!defined($_) && $! != 0) { die "read from socket failed: $!" } \%attr; } sub usage(;$) { my($msg) = @_; print STDERR $msg,"\n\n" if $msg ne ''; my $prog = $0; $prog =~ s{^.*/(?=[^/]+\z)}{}; print STDERR "$prog version $VERSION\n"; die "Usage: \$ $prog sender recip1 recip2 ... < email.msg\n"; } # Main program starts here $SIG{INT} = sub { die "\n" }; # do the END code block when interrupted $SIG{TERM} = sub { die "\n" }; # do the END code block when killed umask(0027); # set our preferred umask @ARGV >= 1 or usage("Not enough arguments"); my($sock, %sock_args); if ($io_socket_module_name eq 'IO::Socket::UNIX') { %sock_args = (Type => &SOCK_STREAM, Peer => $socketname); } else { %sock_args = (Type => &SOCK_STREAM, PeerAddr => $socketname); } do_log(2, "Connecting to %s using a module %s", $socketname, $io_socket_module_name); $sock = $io_socket_module_name->new(%sock_args) or die "Can't connect to a $io_socket_module_name socket $socketname: $!\n"; my $tempdir = File::Temp::tempdir('amavis-XXXXXXXXXX', DIR => $tempbase); defined $tempdir && $tempdir ne '' or die "Can't create a temporary directory: $!"; chmod(0750, $tempdir) or die "Can't change protection on directory $tempdir: $!"; my $fname = "$tempdir/email.txt"; # copy message from stdin to a file email.txt in the temporary directory my $fh = IO::File->new; $fh->open($fname, O_CREAT|O_EXCL|O_RDWR, 0640) or die "Can't create file $fname: $!"; my($nbytes,$buff); while (($nbytes=read(STDIN,$buff,32768)) > 0) { $fh->print($buff) or die "Error writing to $fname: $!"; } defined $nbytes or die "Error reading mail file: $!"; $fh->close or die "Error closing $fname: $!"; close(STDIN) or die "Error closing STDIN: $!"; my(@query) = ( 'request=AM.PDP', "mail_file=$fname", "tempdir=$tempdir", 'tempdir_removed_by=server', map("sender=<$_>", shift(@ARGV)), map("recipient=<$_>", @ARGV), # 'delivery_care_of=server', # 'protocol_name=ESMTP', # 'helo_name=b.example.com', # 'client_address=::1', ); my $attr_ref = ask_amavisd($sock,\@query); if (ll(2)) { for my $attr_name (keys %$attr_ref) { for my $attr_val (@{$attr_ref->{$attr_name}}) { do_log(2, "< %s=%s", $attr_name,$attr_val); } } } my($setreply,$exit_code); $setreply = $attr_ref->{'setreply'}->[0] if $attr_ref->{'setreply'}; $exit_code = $attr_ref->{'exit_code'}->[0] if $attr_ref->{'exit_code'}; if (defined $setreply && $setreply =~ /^2\d\d/) { # all ok do_log(1, "%s", $setreply); } elsif (!defined($setreply)) { do_log(0, "Error, missing 'setreply' attribute"); } else { do_log(0, "%s", $setreply); } # may do another request here if needed ... $sock->close or die "Error closing socket: $!"; $exit_code = 0 if $exit_code==99; # same thing in this case, both is ok exit 0+$exit_code; END { # remove a temporary file and directory if necessary if (defined $fname && -f $fname) { unlink $fname or warn "Error deleting file $fname: $!"; } if (defined $tempdir && -d $tempdir) { rmdir $tempdir or warn "Error deleting temporary directory $tempdir: $!"; } }