Server IP : 85.214.239.14 / Your IP : 3.144.23.138 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 : /usr/share/perl5/Amavis/In/ |
Upload File : |
# SPDX-License-Identifier: GPL-2.0-or-later package Amavis::In::Message; # this class keeps information about the message being processed use strict; use re 'taint'; BEGIN { require Exporter; use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION); $VERSION = '2.412'; @ISA = qw(Exporter); } use Amavis::Conf qw(:platform); use Amavis::In::Message::PerRecip; use Amavis::rfc2821_2822_Tools qw(rfc2822_timestamp quote_rfc2821_local qquote_rfc2821_local); use Amavis::Util qw(ll do_log orcpt_decode); sub new { my $class = $_[0]; my $self = bless({},$class); $self->skip_bytes(0); $self } sub conn_obj # ref to a connection object Amavis::In::Connection { @_<2 ? shift->{conn} : ($_[0]->{conn} = $_[1]) } sub rx_time # Unix time (s since epoch) of message reception by amavisd { @_<2 ? shift->{rx_time} : ($_[0]->{rx_time} = $_[1]) } sub partition_tag # SQL partition tag (e.g. an ISO week number 1..53, or 0) { @_<2 ? shift->{partition} : ($_[0]->{partition} = $_[1]) } sub client_proto # orig. client protocol, obtained from XFORWARD or milter { @_<2 ? shift->{cli_proto} : ($_[0]->{cli_proto} = $_[1]) } sub client_addr # original client IP addr, obtained from XFORWARD or milter { @_<2 ? shift->{cli_ip} : ($_[0]->{cli_ip} = $_[1]) } sub client_name # orig. client DNS name, obtained from XFORWARD or milter { @_<2 ? shift->{cli_name} : (shift->{cli_name} = $_[1]) } sub client_port # orig client src port num, obtained from XFORWARD or milter { @_<2 ? shift->{cli_port} : ($_[0]->{cli_port} = $_[1]) } sub client_source # LOCAL/REMOTE/undef, local_header_rewrite_clients/XFORWARD { @_<2 ? shift->{cli_source} : ($_[0]->{cli_source} = $_[1]) } sub client_helo # orig. client EHLO name, obtained from XFORWARD or milter { @_<2 ? shift->{cli_helo} : ($_[0]->{cli_helo} = $_[1]) } sub client_os_fingerprint # SMTP client's OS fingerprint, obtained from p0f { @_<2 ? shift->{cli_p0f} : ($_[0]->{cli_p0f} = $_[1]) } sub originating # originating from our users, copied from c('originating') { @_<2 ? shift->{originating}: ($_[0]->{originating} = $_[1]) } sub queue_id # MTA queue ID of message if known (Courier, milter/AM.PDP, XFORW) { @_<2 ? shift->{queue_id} : ($_[0]->{queue_id} = $_[1]) } sub log_id # task id as shown in the log, also known as am_id { @_<2 ? shift->{log_id} : ($_[0]->{log_id} = $_[1]) } sub mail_id # long-term unique id of the message on this system { @_<2 ? shift->{mail_id} : ($_[0]->{mail_id} = $_[1]) } sub secret_id # secret string to grant access to a message with mail_id { @_<2 ? $_[0]->{secret_id} : ($_[0]->{secret_id} = $_[1]) } sub parent_mail_id # original mail_id for msgs generated by amavis (DSN,notif) { @_<2 ? shift->{parent_mail_id} : ($_[0]->{parent_mail_id} = $_[1]) } sub attachment_password # scrambles a potentially dangerous released mail { @_<2 ? shift->{release_pwd}: ($_[0]->{release_pwd} = $_[1]) } sub msg_size # ESMTP SIZE value, later corrected to actual size,RFC 1870 { @_<2 ? shift->{msg_size} : ($_[0]->{msg_size} = $_[1]) } sub auth_user # ESMTP AUTH username { @_<2 ? shift->{auth_user} : ($_[0]->{auth_user} = $_[1]) } sub auth_pass # ESMTP AUTH password { @_<2 ? shift->{auth_pass} : ($_[0]->{auth_pass} = $_[1]) } sub auth_submitter # ESMTP MAIL command AUTH option value (addr-spec or "<>") { @_<2 ? shift->{auth_subm} : (shift->{auth_subm} = $_[1]) } sub tls_cipher # defined if TLS was on, e.g. contains cipher alg.,RFC 3207 { @_<2 ? shift->{auth_tlscif}: ($_[0]->{auth_tlscif} = $_[1]) } sub dsn_ret # ESMTP MAIL command RET option (DSN-RFC 3461) { @_<2 ? shift->{dsn_ret} : ($_[0]->{dsn_ret} = $_[1]) } sub dsn_envid # ESMTP MAIL command ENVID option (DSN-RFC 3461) xtext enc. { @_<2 ? shift->{dsn_envid} : ($_[0]->{dsn_envid} = $_[1]) } sub dsn_passed_on # obligation to send notification on SUCCESS was relayed { @_<2 ? shift->{dsn_pass_on}: ($_[0]->{dsn_pass_on} = $_[1]) } sub requested_by # Resent-From addr who requested release from a quarantine { @_<2 ? shift->{requested_by}:($_[0]->{requested_by} = $_[1])} sub body_type # ESMTP BODY param (RFC 6152: 7BIT, 8BITMIME) or BINARYMIME { @_<2 ? shift->{body_type} : ($_[0]->{body_type} = $_[1]) } sub smtputf8 # ESMTP SMTPUTF8 param, boolean (RFC 6531) { @_<2 ? shift->{smtputf8} : ($_[0]->{smtputf8} = $_[1]) } sub header_8bit # true if header contains non-ASCII characters { @_<2 ? shift->{header_8bit}: ($_[0]->{header_8bit} = $_[1]) } sub body_8bit # true if body contains non-ASCII characters { @_<2 ? shift->{body_8bit} : ($_[0]->{body_8bit} = $_[1]) } sub sender # envelope sender, internal form, e.g.: j doe@example.com { @_<2 ? $_[0]->{sender} : ($_[0]->{sender} = $_[1]) } sub sender_smtp # env sender, SMTP form in <>, e.g.: <"j doe"@example.com> { @_<2 ? shift->{sender_smtp}: ($_[0]->{sender_smtp} = $_[1]) } sub sender_credible # envelope sender is believed to be valid { @_<2 ? shift->{sender_cred}: ($_[0]->{sender_cred} = $_[1]) } sub sender_source # unmangled sender addr. or info from the trace (log/notif) { @_<2 ? shift->{sender_src} : ($_[0]->{sender_src} = $_[1]) } sub sender_maddr_id # maddr.id field from SQL if logging to SQL is enabled { @_<2 ? shift->{maddr_id} : ($_[0]->{maddr_id} = $_[1]) } sub mime_entity # MIME::Parser entity holding the parsed message { @_<2 ? shift->{mime_entity}: (shift->{mime_entity} = $_[1])} sub parts_root # Amavis::Unpackers::Part root object { @_<2 ? shift->{parts_root} : ($_[0]->{parts_root} = $_[1])} sub skip_bytes # file offset where mail starts, useful for quar. release { @_<2 ? shift->{file_ofs} : ($_[0]->{file_ofs} = $_[1]) } sub mail_text # RFC 5322 msg: open file handle, or MIME::Entity object { @_<2 ? shift->{mail_text} : ($_[0]->{mail_text} = $_[1]) } sub mail_text_str # RFC 5322 msg: small messages as a stringref, else undef { @_<2 ? shift->{mailtextstr}: ($_[0]->{mailtextstr} = $_[1]) } sub mail_text_fn # orig. mail filename or undef, e.g. mail_tempdir/email.txt { @_<2 ? shift->{mailtextfn} : ($_[0]->{mailtextfn} = $_[1]) } sub mail_tempdir # work directory, under $TEMPBASE or supplied by client { @_<2 ? shift->{mailtempdir}: ($_[0]->{mailtempdir} = $_[1])} sub mail_tempdir_obj # Amavis::TempDir obj when non-persistent (quar.release) { @_<2 ? shift->{tempdirobj}: ($_[0]->{tempdirobj} = $_[1])} sub header_edits # Amavis::Out::EditHeader object or undef { @_<2 ? shift->{hdr_edits} : ($_[0]->{hdr_edits} = $_[1]) } sub rfc2822_from #author addresses list (rfc allows one or more), parsed 'From' { @_<2 ? $_[0]->{hdr_from} : ($_[0]->{hdr_from} = $_[1]) } sub rfc2822_sender # sender address (rfc allows none or one), parsed 'Sender' { @_<2 ? shift->{hdr_sender} : ($_[0]->{hdr_sender} = $_[1]) } sub rfc2822_resent_from # resending author addresses list, parsed 'Resent-From' { @_<2 ? shift->{hdr_rfrom} : ($_[0]->{hdr_rfrom} = $_[1]) } sub rfc2822_resent_sender # resending sender addresses, parsed 'Resent-Sender' { @_<2 ? shift->{hdr_rsender}: ($_[0]->{hdr_rsender} = $_[1]) } sub rfc2822_to # parsed 'To' header field: a list of recipients { @_<2 ? shift->{hdr_to} : ($_[0]->{hdr_to} = $_[1]) } sub rfc2822_cc # parsed 'Cc' header field: a list of Cc recipients { @_<2 ? shift->{hdr_cc} : (shift->{hdr_cc} = $_[1]) } sub orig_header_fields # header field indices by h.f. name, hashref of arrays { @_<2 ? shift->{orig_hdr_f} : ($_[0]->{orig_hdr_f} = $_[1]) } sub orig_header # orig.h.sect, arrayref of h.fields, with folding & trailing LF { @_<2 ? shift->{orig_header}: ($_[0]->{orig_header} = $_[1]) } sub orig_header_size # size of original header, incl. a separator line,RFC 1870 { @_<2 ? shift->{orig_hdr_s} : ($_[0]->{orig_hdr_s} = $_[1]) } sub references # References & In-Reply-To message IDs, array { @_<2 ? shift->{refs} : ($_[0]->{refs} = $_[1]) } sub orig_body_size # size of original body (in bytes), RFC 1870 { @_<2 ? shift->{orig_bdy_s} : ($_[0]->{orig_bdy_s} = $_[1]) } sub body_start_pos # byte offset into a msg where mail body starts (if known) { @_<2 ? shift->{body_pos}: ($_[0]->{body_pos} = $_[1]) } sub body_digest # digest of a message body (e.g. MD5, SHA1, SHA256), hex { @_<2 ? shift->{body_digest}: ($_[0]->{body_digest} = $_[1]) } sub trace # info from Received header fields, top-down, array of hashrefs { @_<2 ? shift->{trace} : ($_[0]->{trace} = $_[1]) } sub ip_addr_trace_public # public IP addresses in 'Received from' hdr flds { @_<2 ? shift->{iptracepub} : ($_[0]->{iptracepub} = $_[1]) } sub is_mlist # mail is from a mailing list (boolean/string) { @_<2 ? shift->{is_mlist} : ($_[0]->{is_mlist} = $_[1]) } sub is_auto # mail is an auto-response (boolean/string) { @_<2 ? shift->{is_auto} : ($_[0]->{is_auto} = $_[1]) } sub is_bulk # mail from a m.list or bulk or auto-response (bool/string) { @_<2 ? $_[0]->{is_bulk} : ($_[0]->{is_bulk} = $_[1]) } sub dkim_signatures_all # a ref to a list of DKIM signature objects, or undef { @_<2 ? shift->{dkim_sall} : ($_[0]->{dkim_sall} = $_[1]) } sub dkim_signatures_valid # a ref to a list of valid DKIM signature objects { @_<2 ? shift->{dkim_sval} : ($_[0]->{dkim_sval} = $_[1]) } sub dkim_author_sig # author domain signature present and valid (bool/domain) { @_<2 ? shift->{dkim_auth_s}: ($_[0]->{dkim_auth_s} = $_[1]) } sub dkim_thirdparty_sig # third-party signature present and valid (bool/domain) { @_<2 ? shift->{dkim_3rdp_s}: ($_[0]->{dkim_3rdp_s} = $_[1]) } sub dkim_sender_sig # a sender signature is present and is valid (bool/domain) { @_<2 ? shift->{dkim_sndr_s}: (shift->{dkim_sndr_s} = $_[1]) } sub dkim_envsender_sig # boolean: envelope sender signature present and valid { @_<2 ? shift->{dkim_envs_s}: ($_[0]->{dkim_envs_s} = $_[1]) } sub dkim_signatures_new # ref to a list of DKIM signature objects, our signing { @_<2 ? shift->{dkim_snew} : ($_[0]->{dkim_snew} = $_[1]) } sub dkim_signwith_sd # ref to a pair [selector,domain] to force signing with { @_<2 ? shift->{dkim_signsd}: ($_[0]->{dkim_signsd} = $_[1]) } sub quarantined_to # list of quar mailbox names or addresses if quarantined { @_<2 ? shift->{quarantine} : ($_[0]->{quarantine} = $_[1]) } sub quar_type # list of quar types: F/Z/B/Q/M (file/zipfile/bsmtp/sql/mailbox) { @_<2 ? shift->{quar_type} : ($_[0]->{quar_type} = $_[1]) } sub dsn_sent # delivery status notification was sent(1) or suppressed(2) { @_<2 ? shift->{dsn_sent} : ($_[0]->{dsn_sent} = $_[1]) } sub client_delete # don't delete the tempdir, it is a client's responsibility { @_<2 ? shift->{client_del} :($_[0]->{client_del} = $_[1])} sub contents_category # sorted arrayref CC_VIRUS/CC_BANNED/CC_SPAM../CC_CLEAN { @_<2 ? shift->{category} : ($_[0]->{category} = $_[1]) } sub blocking_ccat # category type most responsible for blocking msg, or undef { @_<2 ? $_[0]->{bl_ccat} : ($_[0]->{bl_ccat} = $_[1]) } sub checks_performed # a hashref of checks done on a msg (for statistics/log) { @_<2 ? shift->{checks_perf}: ($_[0]->{checks_perf} = $_[1]) } sub actions_performed # listref, summarized actions & SMTP status, for logging { @_<2 ? shift->{act_perf} : ($_[0]->{act_perf} = $_[1]) } sub virusnames # a ref to a list of virus names detected, or undef { @_<2 ? shift->{virusnames} : ($_[0]->{virusnames} = $_[1]) } sub spam_report # SA terse report of tests hit (for header section reports) { @_<2 ? shift->{spam_report} : ($_[0]->{spam_report} = $_[1])} sub spam_summary # SA summary of tests hit for standard body reports { @_<2 ? shift->{spam_summary} :($_[0]->{spam_summary} = $_[1])} sub ip_repu_score # IP reputation score (info, also added to spam_level) { @_<2 ? shift->{ip_repu_score} :($_[0]->{ip_repu_score} = $_[1])} sub time_elapsed # elapsed times by section - associative array ref { @_<2 ? shift->{elapsed} : ($_[0]->{elapsed} = $_[1])} # new style of providing additional information from checkers sub supplementary_info { # holds a hash of tag/value pairs, such as SA get_tag my $self=shift; my $key=shift; !@_ ? $self->{info_tag}{$key} : ($self->{info_tag}{$key}=shift); } { no warnings 'once'; # the following methods apply on a per-message level as well, summarizing # per-recipient information as far as possible *add_contents_category = \&Amavis::In::Message::PerRecip::add_contents_category; *is_in_contents_category = \&Amavis::In::Message::PerRecip::is_in_contents_category; *setting_by_main_contents_category = \&Amavis::In::Message::PerRecip::setting_by_main_contents_category; *setting_by_main_contents_category_all = \&Amavis::In::Message::PerRecip::setting_by_main_contents_category_all; *setting_by_blocking_contents_category = \&Amavis::In::Message::PerRecip::setting_by_blocking_contents_category; *setting_by_contents_category = \&Amavis::In::Message::PerRecip::setting_by_contents_category; } # The order of entries in a per-recipient list is the original order # in which recipient addresses (e.g. obtained via 'MAIL TO:') were received. # Only the entries that were accepted (via SMTP response code 2xx) # are placed in the list. The ORDER MUST BE PRESERVED and no recipients # may be added or removed from the list (without precaution)! This is vital # to be able to produce correct per-recipient responses to an LMTP client! # sub per_recip_data { # get or set a listref of envelope recipient objects my $self = shift; # store a copy of the a given listref of recip objects if (@_) { $self->{recips} = [@{$_[0]}] } # caller may modify data if he knows what he is doing $self->{recips}; # return a list of recipient objects } sub recips { # get or set a listref of envelope recipients my $self = shift; if (@_) { # store a copy of a given listref of recipient addresses my($recips_list_ref, $set_dsn_orcpt_too) = @_; $self->per_recip_data([ map { my $per_recip_obj = Amavis::In::Message::PerRecip->new; $per_recip_obj->recip_addr($_); $per_recip_obj->recip_addr_smtp(qquote_rfc2821_local($_)); $per_recip_obj->dsn_orcpt( join(';', orcpt_decode(';'.$per_recip_obj->recip_addr_smtp))) if $set_dsn_orcpt_too; $per_recip_obj->recip_destiny(D_PASS); # default is Pass $per_recip_obj } @{$recips_list_ref} ]); } return if !defined wantarray; # don't bother # return listref of recipient addresses [ map($_->recip_addr, @{$self->per_recip_data}) ]; } # for each header field maintain a list of signature indices which covered it; # returns a list of signature indices for a given header field position # sub header_field_signed_by { my($self,$header_field_index) = @_; my $h = $self->{hdr_sig_ind}; my $hf; if (@_ > 2) { $self->{hdr_sig_ind} = $h = [] if !$h; $hf = $h->[$header_field_index]; $h->[$header_field_index] = $hf = [] if !$hf; # store signature index(es) at a given header position shift; shift; push(@$hf, @_); } $hf = $h->[$header_field_index] if $h && !$hf; $hf ? @{$hf} : (); } # return a j-th header field with a given field name, along with its index # in the array of all header fields; if a field name is undef then all # header fields are considered; search proceeds top-down if j >= 0, # or bottom up for negative values (-1=last, -2=next-to-last, ...) # sub get_header_field2 { my($self, $field_name, $j) = @_; my $orig_hfields = $self->orig_header_fields; return if !$orig_hfields; my($field_ind, $field, $all_fields, $hfield_indices); # arrayref of header field indices for a given h.field name $hfield_indices = $orig_hfields->{lc $field_name} if defined $field_name; $all_fields = $self->orig_header; if (defined $field_name) { if (!defined $hfield_indices) { # no header field with such name } elsif (ref $hfield_indices) { # $hfield_indices is an arrayref $j = 0 if !defined $j; $field_ind = $hfield_indices->[$j]; } else { # optimized: $hfield_indices is a scalar - the only element $field_ind = $hfield_indices if !defined($j) || $j == 0 || $j == -1; } } elsif (!ref $all_fields) { # no header section } elsif ($j >= 0) { # top-down, 0,1,2,... $field_ind = $j if $j <= $#$all_fields; } else { # bottom-up, -1,-2,-3,... $j += @$all_fields; # turn into an absolute index $field_ind = $j if $j >= 0; } return $field_ind if !wantarray; ($field_ind, !defined $field_ind ? undef : $all_fields->[$field_ind]); } # compatibility wrapper for pre-2.8.0 custom code # sub get_header_field { my($self, $field_name, $j) = @_; my($field_ind, $field) = $self->get_header_field2($field_name,$j); if (defined($field_ind) && wantarray) { local $1; $field_name = lc($1) if $field =~ /^([^:]*?)[ \t]*:/s; } !wantarray ? $field_ind : ($field_ind, $field_name, $field); } sub get_header_field_body { my($self, $field_name, $j) = @_; my $k; my($field_ind, $f) = $self->get_header_field2($field_name,$j); defined $f && ($k=index($f,':')) >= 0 ? substr($f,$k+1) : $f; } 1;