#!/usr/bin/perl -w # # detachit: Pipe postfix messages through detach # # $weburi = URI prefix, ex: https://example.com/files # $webdir = file path, ex: /var/www/files # @domains = list of local domains (header check) # @attachlist = list of recipients to never detach (command line args check - match from /etc/aliases) # @detachlist = list of recipients to always detach (command line args check - match from /etc/aliases) # $attach_size = minimum attachment size to detach (in bytes) my $weburi = 'https://files.example.com'; my $webdir = '/home/example/files'; my @domains = qw(example.org example.com example.net); my @attachlist = qw(externalclient-example.com); my @detachlist = qw(entire.company); my $attach_size = 3145728; my $sendmail = '/usr/sbin/sendmail -G -i'; my $filter_dir = '/var/spool/filter'; my $temp_file = "$filter_dir/mail.$$"; my $args = join(' ', @ARGV); $args =~ s/([;<>\*\|`&\$!#\(\)\[\]\{\}:'"])/\\$1/g; (my $recipients = $args) =~ s/-f.*? -- //; # Flags my $detach_files = 0; my $check_headers = 0; # Exit codes my $ex_tempfail = 75; my $ex_unavailable = 69; # Clean up when killed my $killed = 0; $SIG{HUP} = \&sigterm; $SIG{INT} = \&sigterm; $SIG{QUIT} = \&sigterm; $SIG{TERM} = \&sigterm; sub sigterm { # Only run once if (not $killed) { unlink "$temp_file"; } $killed = 1; }; # Clean up when done END { sigterm(); } # Verify temp folder unless (-d $filter_dir) { print "$filter_dir does not exist\n"; $killed = 1; # No temp file to delete exit $ex_tempfail; } # Create temp file if (!open FILE, ">$temp_file") { print STDERR "Cannot save mail to file\n"; exit $ex_tempfail; } while () { print FILE $_; } close FILE; # Check email size $email_size = -s $temp_file; if ($email_size > $attach_size) { $check_headers = 1; } # Leave attachments alone for these addresses foreach (@attachlist) { if ($recipients =~ /\Q$_/) { $check_headers = 0; $detach_files = 0; last; } } # Always detach all attachments for all.south and all.north - even PGP messages foreach (@detachlist) { if ($recipients =~ /\Q$_/) { $check_headers = 0; $detach_files = 1; $attach_size = 0; last; } } if ($check_headers) { # Get the header my $header; if (!open FILE, "<$temp_file") { print STDERR "Cannot read temp file\n"; exit $ex_tempfail; } while () { my ($line) = $_; chomp($line); last if ($line =~ /^$/); $header .= "$_"; } # Do not 'close FILE' in case we need to check for inline PGP # Check for incoming mail (from barracuda) if ($header =~ /\[10\.0\.0\.25\]/) { # $detach_files = 1; # Always detach incoming mail $detach_files = 0; # Leave incoming mail alone } else { # Email is from a local sender # Check that *all* recipients are local $detach_files = 1; # Set to detach - will disable if external recipient is found $header =~ s/\n\s+/ /g; # Unfold multiline headers $header =~ s/\".+?\"//g; # Remove quoted names - in case any have an @ @header_lines = split ('\n', $header); HEADER: foreach (@header_lines) { if (/^(To|Cc|Bcc): (.*)/) { foreach (split(' ', $2)) { if (/.*@(.+?)(>|,|$)/) { if (!grep /$1/i, @domains) { $detach_files = 0; # External domain found - do not detach attachments last HEADER; # Stop looking once an external domain is found } } } } } } # Check for signed PGP message if ($detach_files) { # Check for PGP/MIME header if ($header =~ /\nContent-Type: multipart\/signed/) { $detach_files = 0; } else { # Check for inline PGP in first line of message if ( =~ /^-----BEGIN PGP SIGNED MESSAGE-----/) { $detach_files = 0; } } } close FILE; } if ($detach_files) { # Detach the attachments and provide a link to the detachments `/usr/local/bin/detach -d $webdir -a --hash --size $attach_size -w $weburi < $temp_file | $sendmail $args`; exit $?; } else { # Leave the mail alone `$sendmail $args <$temp_file`; exit $?; }