Merge pull request #121 from shawniverson/111917sevenzip

7zip support
This commit is contained in:
Shawn Iverson 2017-12-02 13:28:09 -05:00 committed by GitHub
commit ccce3ad01e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 266 additions and 11 deletions

View file

@ -488,6 +488,13 @@ Unrar Command = /usr/bin/unrar
# RAR archive (in seconds)
Unrar Timeout = 50
# Used as unpacking engine for multiple archive formats
Un7zip Command = /usr/bin/7z
# The maximum length of time the "7z" command is allowed to run for 1
# 7zip or other 7zip compatible archive (in seconds)
Un7zip Timeout = 50
# A few viruses store their infected data in UU-encoded files, to try to
# catch out virus scanners. This rarely succeeds at all.
# Setting this option to yes means that you can apply filename and filetype

View file

@ -342,6 +342,7 @@ MCPMaxSpamAssassinTimeouts 20
MCPSpamAssassinTimeout 10
TNEFTimeout 120
UnrarTimeout 50
Un7zipTimeout 50
WhitelistMaxRecips 20
# For Qmail users
qmailhashdirectorynumber 23
@ -397,6 +398,7 @@ MCPSpamAssassinDefaultRulesDir /etc/MailScanner/mcp
MCPSpamAssassinInstallPrefix /etc/MailScanner/mcp
TNEFExpander /usr/bin/tnef --maxsize=100000000
UnrarCommand /usr/bin/unrar
Un7zipCommand /usr/bin/7z
VirusScanners auto # Space-separated list
WorkUser
WorkGroup

View file

@ -2663,7 +2663,8 @@ sub ExplodePartAndArchives {
my($size, $level, $ziperror, $tarerror, $silentviruses, $noisyviruses);
my($allziperrors, $alltarerrors, $textlevel, $failisokay);
my($linenum, $foundheader, $prevline, $line, $position, $prevpos, $nextpos);
my($cyclecounter, $rarerror, $create0files, $oleerror);
my($cyclecounter, $rarerror, $create0files, $oleerror, $sevenzerror);
my($filecommand, $PipeTimeOut, $memb, $use_unpacker);
$dir = new DirHandle;
$file = new FileHandle;
@ -2672,6 +2673,7 @@ sub ExplodePartAndArchives {
$cyclecounter = 0;
$ziperror = 0;
$tarerror = 0;
$sevenzerror = 0;
# Do they only want encryption checking and nothing else?
my $onlycheckencryption;
@ -2806,6 +2808,28 @@ sub ExplodePartAndArchives {
#$level++;
next if $level > $maxlevels;
# Do a file (magic) on every file we run into and appoint an unpacker
$PipeTimeOut = MailScanner::Config::Value('filetimeout');
$filecommand = MailScanner::Config::Value('filecommand');
$use_unpacker = '';
if ($filecommand && -x $filecommand) { # check if we got support
$memb = SafePipe("$filecommand -b '$explodeinto/$part' 2>&1",
$PipeTimeOut);
if ($memb =~ /ERROR/) {
MailScanner::Log::WarnLog("File magic error (%s)", $memb);
} elsif ( ($memb =~ /^Zip archive/i) ) { # use zip unpacker
$use_unpacker = "zip";
} elsif ( ($memb =~ /^RAR archive/i) ) { # use (official) rar unpacker
$use_unpacker = "rar";
} elsif ( ($memb =~ /^(7-zip|arj|cpio|lha(.*)|xar|GNU tar|POSIX tar|ASCII cpio) archive/i) || # use 7zip unpacker
($memb =~ /^(lzh|lzma|bzip2|gzip|xz) compressed/i) ||
($memb =~ /^(RPM|Delta-RPM|Windows imaging|\# ISO|ISO)/i) ) {
$use_unpacker = "7z";
}
}
#MailScanner::Log::WarnLog("Unpack-engine (%s) file (%s)", $use_unpacker, $part);
# Find all the zip files
#print STDERR "Looking at $explodeinto/$part\n";
#next if MailScanner::Config::Value('filecommand', $this) eq "";
@ -2831,7 +2855,7 @@ sub ExplodePartAndArchives {
$failisokay;
#print STDERR "Found a zip or rar file\n" ;
$file->close, next unless MailScanner::Config::Value('findarchivesbycontent', $this) ||
$part =~ /\.(tar\.g?z|taz|tgz|tz|gz|zip|exe|rar|uu|uue|doc|xls|ppt|dot|xlt|pps)$/i;
$part =~ /\.(tar\.g?z|taz|tgz|tz|gz|zip|exe|rar|uu|uue|doc|docx|xls|xlsx|ppt|pptx|dot|dotx|xlt|xltx|pps|ppsx)$/i;
$foundnewfiles = 1;
#print STDERR "Unpacking $part at level $level\n";
@ -2851,10 +2875,11 @@ sub ExplodePartAndArchives {
$ziperror = $this->UnpackZip($part, $explodeinto, $allowpasswords,
$insistpasswords,
$onlycheckencryption, $create0files);
#MailScanner::Log::WarnLog("UnpackZip (%s) file (%s)", $ziperror, $part);
#print STDERR "* * * * * * * Unpackzip $part returned $ziperror\n";
# If unpacking as a zip failed, try it as a rar
$rarerror = "";
if ($part =~ /\.rar$/i || $buffer eq "Rar!" or $buffer =~ /^MZ[P]?/) {
if ($part =~ /\.rar$/i || $use_unpacker eq "rar" || $buffer eq "Rar!" or $buffer =~ /^MZ[P]?/) {
$rarerror = $this->UnpackRar($part, $explodeinto, $allowpasswords,
$insistpasswords,
$onlycheckencryption, $create0files);
@ -2871,11 +2896,21 @@ sub ExplodePartAndArchives {
$onlycheckencryption, $create0files);
}
$tarerror = "";
$tarerror = 0 # $this->UnpackTar($part, $explodeinto, $allowpasswords)
if $ziperror || $part =~ /(tar\.g?z|tgz)$/i;
# $tarerror = "";
# $tarerror = 0 # $this->UnpackTar($part, $explodeinto, $allowpasswords)
# if $ziperror || $part =~ /(tar\.g?z|tgz|gz)$/i;
#print STDERR "In inner: \"$part\"\n";
if ($ziperror eq "nonpassword" || $rarerror eq "nonpassword") {
if (
($use_unpacker eq "7z") ||
($part =~ /\.(001|7z|arj|bz2|bzip2|cab|cpio|deb|dmg|fat|gz|gzip|hfs|iso|jar|lha|lzh|lzma)$/) ||
($part =~ /\.(ntfs|rpm|squashfs|swm|tar|taz|tbz|tbz2|tgz|tpz|txz|vhd|wim|xar|xz|z)$/) ) {
$sevenzerror = $this->Unpack7zip($part, $explodeinto, $allowpasswords,
$insistpasswords,
$onlycheckencryption, $create0files);
}
if ($ziperror eq "nonpassword" || $rarerror eq "nonpassword" || $sevenzerror eq "nonpassword") {
# Trim off leading type indicator character for logging.
my $f = substr($part,1);
MailScanner::Log::WarnLog("Non-password-protected archive (%s) in %s",
@ -2889,7 +2924,7 @@ sub ExplodePartAndArchives {
$this->{cantdisinfect} = 1; # Don't even think about disinfecting this!
$this->{silent}=1 if $silentviruses =~ / Zip-NonPassword | All-Viruses /i;
$this->{noisy} =1 if $noisyviruses =~ / Zip-NonPassword /i;
} elsif ($ziperror eq "password" || $rarerror eq "password") {
} elsif ($ziperror eq "password" || $rarerror eq "password" || $sevenzerror eq "password") {
# Trim off leading type indicator character for logging.
my $f = substr($part,1);
MailScanner::Log::WarnLog("Password-protected archive (%s) in %s",
@ -2903,7 +2938,7 @@ sub ExplodePartAndArchives {
$this->{cantdisinfect} = 1; # Don't even think about disinfecting this!
$this->{silent}=1 if $silentviruses =~ / Zip-Password | All-Viruses /i;
$this->{noisy} =1 if $noisyviruses =~ / Zip-Password /i;
} elsif ($ziperror && $tarerror && $rarerror && !$failisokay) {
} elsif ($ziperror && $rarerror && $sevenzerror && !$failisokay) {
# Trim off leading type indicator character for logging.
my $f = substr($part,1);
MailScanner::Log::WarnLog("Unreadable archive (%s) in %s",
@ -2995,6 +3030,216 @@ sub UnpackUUE {
}
# Unpack a 7za file into the named directory.
# Return 1 if an error occurred, else 0.
# Return 0 on success.
# Return "password" if a member was password-protected.
# Very much like UnpackZip except it uses the external "7z" command.
sub Unpack7zip {
my($this, $zipname, $explodeinto, $allowpasswords, $insistpasswords, $onlycheckencryption, $touchfiles) = @_;
my($zip, @members, $member, $name, $fh, $safename, $memb, $check, $junk,
$unzip, $unrar, $IsEncrypted, $PipeTimeOut, $PipeReturn,$NameTwo, $HasErrors,
$member2, $Stuff, $BeginInfo, $EndInfo, $ParseLine, $what, $nopathname);
# Timeout value for unrar is currently the same as that of the file
# command + 20. Julian, when you add the filetimeout to the config file
# perhaps you should think about adding a maxcommandexecutetime setting
# as well
$PipeTimeOut = MailScanner::Config::Value('un7ziptimeout');
$unzip = MailScanner::Config::Value('un7zipcommand');
return 1 unless $unzip && -x $unzip;
#MailScanner::Log::WarnLog("7ZipUnpacker: %s", $zipname);
# This part lists the archive contents and makes the list of
# file names within. "This is a list verbose option"
#$memb = SafePipe("$unrar v -p- '$explodeinto/$zipname' 2>&1",
# $PipeTimeOut);
$memb = SafePipe("$unzip l '$explodeinto/$zipname' 2>&1",
$PipeTimeOut);
if ($memb =~ /^error/i) {
MailScanner::Log::WarnLog("7ZipUnpacker: (%s)", $memb);
$HasErrors = 1;
}
#MailScanner::Log::WarnLog("7z output: %s", $memb);
$junk = "";
$Stuff = "";
$BeginInfo = 0;
$EndInfo = 0;
$ParseLine = 1;
$memb =~ s/\r//gs;
my @test = split /\n/, $memb;
$memb = '';
# Have to parse the output from the 'v' command and parse the information
# between the ----------------------------- lines
foreach $what (@test) {
#print STDERR "Processing \"$what\"\n";
#MailScanner::Log::WarnLog("7z what: %s", $what);
# Have we already hit the beginng and now find another ------ string?
# If so then we are at the end
$EndInfo = 1 if $what =~ /-{18,}$/ && $BeginInfo;
# if we are after the begning but haven't reached the end,
# then process this line
if ($BeginInfo && !$EndInfo) {
# MailScanner::Log::WarnLog("7z what: %s", $what);
# If we are on line one then it's the file name with full path
# otherwise we are on the info line containing the attributes
$what =~ s/ +/ /g;
my (@Zarray ) = split /\s/, $what;
my $Zname = pop @Zarray; # this is the most important value, other values are nice to have but this one we must have
my $Zdate = $Zarray[0];
my $Ztime = $Zarray[1];
my $Zattr = $Zarray[2];
#my $Zsize = $Zarray[3];
#my $ZCsize = $Zarray[4];
#MailScanner::Log::WarnLog("7z-members: [%s] [%s] [%s] [%s] [%s] [%s]", $Zdate, $Ztime, $Zattr, $Zsize, $ZCsize, $Zname);
$memb .= "$Zname\n" if $Zattr !~ /^d|^D/;
}
# If we have a line full of ---- and $BeginInfo is not set then
# we are at the first and we need to set $BeginInfo so next pass
# begins processing file information
if ($what =~ /-{18,}$/ && ! $BeginInfo) {
$BeginInfo = 1;
}
}
# Remove returns from the output string, exit if the archive is empty
# or the output is empty
$memb =~ s/\r//gs;
return 1 if $memb ne '' &&
$memb =~ /(No files to extract|^COMMAND_TIMED_OUT$)/si;
return 0 if $memb eq '';
#MailScanner::Log::DebugLog("Unrar : Archive Testing Completed On : %s",
# $memb);
@members = split /\n/, $memb;
$fh = new FileHandle;
foreach $member2 (@members) {
$IsEncrypted = 0;
$HasErrors = 0;
#MailScanner::Log::InfoLog("Checking member %s",$member2);
# Test the current file name to see if it's password protected
# and capture the output. If the command times out, then return
next if $member2 eq "";
$member = quotemeta $member2;
#print STDERR "Member is ***$member***\n";
#MailScanner::Log::WarnLog("Un7zip: member %s",$member );
$check = SafePipe(
"$unzip -y t '$explodeinto/$zipname' $member 2>&1",
$PipeTimeOut);
#print STDERR "Point 1\n";
return 1 if $check =~ /^COMMAND_TIMED_OUT$/;
# Check for any error with this file. Format is FileName - Error string
if ($check =~ /$member\s+-\s/i){
MailScanner::Log::WarnLog("Un7zip Error in file: %s -> %s",
$zipname,$member);
$HasErrors = 1;
}
$check =~ s/\n/:/gsi;
#MailScanner::Log::WarnLog("Got : %s", $check);
# If we get the string Encrypted then we have found a password
# protected archive and we handle it the same as zips are handled
if ($check =~ /\bEnter password(.*)\bWrong password/s) {
$IsEncrypted = 1;
MailScanner::Log::WarnLog("Password Protected archive Found");
#print STDERR "Checking member " . $member . "\n";
#print STDERR "******** Encryption = " . $IsEncrypted . "\n";
return "password" if !$allowpasswords && $IsEncrypted;
} else {
if ($insistpasswords) {
MailScanner::Log::WarnLog("Non-Password Protected archive Found");
return "nonpassword";
}
}
# If they don't want to extract, but only check for encryption,
# then skip the rest of this as we don't actually want the files
# checked against the file name/type rules
next if $onlycheckencryption;
$name = $member2;
#print STDERR "UnPackRar : Making Safe Name from $name\n";
# There is no facility to change the output name for a rar file
# but we can rename rename the files inside the archive
# prefer to use $NameTwo because there is no path attached
# $safename is guaranteed not to exist, but NameTwo gives us the
# filename without any directory information, which we use later.
$nopathname = $name;
$nopathname =~ s/^.*\///;
$safename = $this->MakeNameSafe('r'.$nopathname,$explodeinto);
$NameTwo = $safename;
$NameTwo = $1 if $NameTwo =~ /([^\/]+)$/;
#MailScanner::Log::InfoLog("UnPackRar: Member : %s", $member);
#print STDERR "UnPackRar : Safe Name is $safename\n";
#MailScanner::Log::InfoLog("UnPackRar: SafeName : %s", $safename);
$this->{file2parent}{$name} = $zipname;
$this->{file2parent}{$safename} = $zipname;
$this->{file2safefile}{$name} = $safename;
$this->{safefile2file}{$safename} = $name;
#print STDERR "Archive member \"$name\" is now \"$safename\"\n";
#$this->{file2entity}{$name} = $this->{entity};
# JKF 20090505 Don't do this: $this->{file2safefile}{$name} = $zipname;
#$this->{safefile2file}{$safename} = $zipname;
$safename = "$explodeinto/$safename";
$PipeReturn = '';
$? = 0;
if (!$IsEncrypted && !$HasErrors) {
#print STDERR "Expanding ***$member***\ninto ***$NameTwo***\n";
$PipeReturn = SafePipe(
"$unzip e -y -so '$explodeinto/$zipname' $member > \"$NameTwo\"",
$PipeTimeOut);
unless ("$?" == 0 && $PipeReturn ne 'COMMAND_TIMED_OUT'){
# The rename operation failed!, so skip the extraction of a
# potentially bad file name.
# JKF Temporary testing code
#MailScanner::Log::WarnLog("UnPackRar: RC: %s PipeReturn : ",$?,$PipeReturn);
MailScanner::Log::WarnLog("7zipUnpacker: Could not rename or use " .
"safe name in Extract, NOT Unpacking file %s", $safename);
next;
}
#MailScanner::Log::InfoLog("7zipUnacker: Done...., got %d and %s for %s", $?, $PipeReturn, $safename);
}
#MailScanner::Log::WarnLog("RC = %s : Encrypt = %s : PipeReturn = %s",
# $?,$IsEncrypted,$PipeReturn );
unless ("$?" == 0 && !$HasErrors && !$IsEncrypted &&
$PipeReturn ne 'COMMAND_TIMED_OUT') {
# If we got an error, or this file is encrypted create a zero-length
# file so the filename tests will still work.
MailScanner::Log::WarnLog("7zipUnpacker : Encrypted Or Extract Error Creating" .
" 0 length %s",$NameTwo);
$touchfiles && $fh->open(">$safename") && $fh->close();
}
}
return 0;
}
# Unpack a rar file into the named directory.
# Return 1 if an error occurred, else 0.
# Return 0 on success.

1
debian/install.sh vendored
View file

@ -364,6 +364,7 @@ BASEPACKAGES+=('gzip'); BASEPACKAGES+=('libnetaddr-ip-perl'); BASEPACKAGES+
BASEPACKAGES+=('unzip'); BASEPACKAGES+=('libnet-ldap-perl'); BASEPACKAGES+=('libsys-hostname-long-perl');
BASEPACKAGES+=('openssl'); BASEPACKAGES+=('libmail-dkim-perl'); BASEPACKAGES+=('libhtml-tokeparser-simple-perl');
BASEPACKAGES+=('perl'); BASEPACKAGES+=('libbusiness-isbn-data-perl'); BASEPACKAGES+=('libnet-dns-resolver-programmable-perl');
BASEPACKAGES+=('p7zip-full');
if [ "$parsedCommands" -gt 0 ]; then
BASEPACKAGES+=('cpanminus');

View file

@ -615,7 +615,7 @@ BASEPACKAGES="binutils gcc glibc-devel libaio make man-pages man-pages-overrides
# package is not available for their distro release it
# will be ignored during the install.
#
MOREPACKAGES="perl-Archive-Tar perl-Archive-Zip perl-Compress-Raw-Zlib perl-Compress-Zlib perl-Convert-BinHex perl-Convert-TNEF perl-CPAN perl-Data-Dump perl-DBD-SQLite perl-DBI perl-Digest-HMAC perl-Digest-SHA1 perl-Env perl-ExtUtils-MakeMaker perl-File-ShareDir-Install perl-File-Temp perl-Filesys-Df perl-Getopt-Long perl-IO-String perl-IO-stringy perl-HTML-Parser perl-HTML-Tagset perl-Inline perl-IO-Zlib perl-Mail-DKIM perl-Mail-IMAPClient perl-Mail-SPF perl-MailTools perl-MIME-tools perl-Net-CIDR perl-Net-DNS perl-Net-DNS-Resolver-Programmable perl-Net-IP perl-OLE-Storage_Lite perl-Pod-Escapes perl-Pod-Simple perl-Scalar-List-Utils perl-Storable perl-Pod-Escapes perl-Pod-Simple perl-Razor-Agent perl-Sys-Hostname-Long perl-Sys-SigAction perl-Test-Manifest perl-Test-Pod perl-Time-HiRes perl-TimeDate perl-URI perl-YAML pyzor re2c unrar tnef perl-Encode-Detect perl-LDAP perl-IO-Compress-Bzip2";
MOREPACKAGES="perl-Archive-Tar perl-Archive-Zip perl-Compress-Raw-Zlib perl-Compress-Zlib perl-Convert-BinHex perl-Convert-TNEF perl-CPAN perl-Data-Dump perl-DBD-SQLite perl-DBI perl-Digest-HMAC perl-Digest-SHA1 perl-Env perl-ExtUtils-MakeMaker perl-File-ShareDir-Install perl-File-Temp perl-Filesys-Df perl-Getopt-Long perl-IO-String perl-IO-stringy perl-HTML-Parser perl-HTML-Tagset perl-Inline perl-IO-Zlib perl-Mail-DKIM perl-Mail-IMAPClient perl-Mail-SPF perl-MailTools perl-MIME-tools perl-Net-CIDR perl-Net-DNS perl-Net-DNS-Resolver-Programmable perl-Net-IP perl-OLE-Storage_Lite perl-Pod-Escapes perl-Pod-Simple perl-Scalar-List-Utils perl-Storable perl-Pod-Escapes perl-Pod-Simple perl-Razor-Agent perl-Sys-Hostname-Long perl-Sys-SigAction perl-Test-Manifest perl-Test-Pod perl-Time-HiRes perl-TimeDate perl-URI perl-YAML pyzor re2c unrar tnef perl-Encode-Detect perl-LDAP perl-IO-Compress-Bzip2 p7zip p7zip-plugins";
# the array of perl modules needed
ARMOD=();

View file

@ -373,7 +373,7 @@ BASEPACKAGES="binutils gcc glibc-devel libaio1 make man-pages patch rpm tar time
# Packages available in the suse base 13.2. If the user elects not to use EPEL or if the
# package is not available for their distro release it will be ignored during the install.
#
MOREPACKAGES="perl-Archive-Zip perl-Convert-BinHex perl-Convert-TNEF perl-DBD-SQLite perl-DBI perl-Digest-HMAC perl-Digest-SHA1 perl-ExtUtils-MakeMaker perl-File-ShareDir-Install perl-File-Temp perl-Filesys-Df perl-Getopt-Long-Descriptive perl-IO-stringy perl-HTML-Parser perl-HTML-Tagset perl-Inline perl-Mail-DKIM perl-Mail-SPF perl-MailTools perl-MIME-tools perl-Net-CIDR-Set perl-Net-DNS perl-Net-IP perl-OLE-Storage_Lite perl-Scalar-List-Utils perl-razor-agents perl-Sys-Hostname-Long perl-Sys-SigAction perl-Test-Pod perl-TimeDate perl-URI re2c perl-Encode-Detect perl-LDAP perl-IO-Compress-Bzip2";
MOREPACKAGES="perl-Archive-Zip perl-Convert-BinHex perl-Convert-TNEF perl-DBD-SQLite perl-DBI perl-Digest-HMAC perl-Digest-SHA1 perl-ExtUtils-MakeMaker perl-File-ShareDir-Install perl-File-Temp perl-Filesys-Df perl-Getopt-Long-Descriptive perl-IO-stringy perl-HTML-Parser perl-HTML-Tagset perl-Inline perl-Mail-DKIM perl-Mail-SPF perl-MailTools perl-MIME-tools perl-Net-CIDR-Set perl-Net-DNS perl-Net-IP perl-OLE-Storage_Lite perl-Scalar-List-Utils perl-razor-agents perl-Sys-Hostname-Long perl-Sys-SigAction perl-Test-Pod perl-TimeDate perl-URI re2c perl-Encode-Detect perl-LDAP perl-IO-Compress-Bzip2 p7zip";
# the array of perl modules needed
ARMOD=();