line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Mail::Exim::ACL::Attachments; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# SPDX-License-Identifier: Artistic-1.0-Perl OR GPL-1.0-or-later |
4
|
|
|
|
|
|
|
|
5
|
1
|
|
|
1
|
|
126337
|
use 5.016; |
|
1
|
|
|
|
|
14
|
|
6
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
36
|
|
7
|
1
|
|
|
1
|
|
12
|
use utf8; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
7
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
our $VERSION = 1.005; |
10
|
|
|
|
|
|
|
|
11
|
1
|
|
|
1
|
|
74
|
use Exporter qw(import); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
68
|
|
12
|
1
|
|
|
1
|
|
721
|
use IO::Uncompress::Unzip; |
|
1
|
|
|
|
|
30961
|
|
|
1
|
|
|
|
|
965
|
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
our @EXPORT_OK = qw(check_filename check_zip); |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
# https://docs.microsoft.com/en-us/deployoffice/compat/office-file-format-reference |
17
|
|
|
|
|
|
|
# https://en.wikipedia.org/wiki/List_of_Microsoft_Office_filename_extensions |
18
|
|
|
|
|
|
|
our %MACRO_ENABLED = ( |
19
|
|
|
|
|
|
|
doc => 'Word Document', |
20
|
|
|
|
|
|
|
docb => 'Word Document', |
21
|
|
|
|
|
|
|
docm => 'Word Document', |
22
|
|
|
|
|
|
|
dot => 'Word Template', |
23
|
|
|
|
|
|
|
dotm => 'Word Template', |
24
|
|
|
|
|
|
|
one => 'OneNote Export File', |
25
|
|
|
|
|
|
|
pot => 'PowerPoint Template', |
26
|
|
|
|
|
|
|
potm => 'PowerPoint Template', |
27
|
|
|
|
|
|
|
ppa => 'PowerPoint Add-in', |
28
|
|
|
|
|
|
|
ppam => 'PowerPoint Add-in', |
29
|
|
|
|
|
|
|
pps => 'PowerPoint Slide Show', |
30
|
|
|
|
|
|
|
ppsm => 'PowerPoint Slide Show', |
31
|
|
|
|
|
|
|
ppt => 'PowerPoint Presentation', |
32
|
|
|
|
|
|
|
pptm => 'PowerPoint Presentation', |
33
|
|
|
|
|
|
|
sldm => 'PowerPoint Slide', |
34
|
|
|
|
|
|
|
vsd => 'Visio Drawing File', |
35
|
|
|
|
|
|
|
vsdm => 'Visio Drawing File', |
36
|
|
|
|
|
|
|
vss => 'Visio Stencil File', |
37
|
|
|
|
|
|
|
vssm => 'Visio Stencil File', |
38
|
|
|
|
|
|
|
vst => 'Visio Drawing Template', |
39
|
|
|
|
|
|
|
vstm => 'Visio Drawing Template', |
40
|
|
|
|
|
|
|
xla => 'Excel Add-in', |
41
|
|
|
|
|
|
|
xlam => 'Excel Add-in', |
42
|
|
|
|
|
|
|
xlm => 'Excel Macro', |
43
|
|
|
|
|
|
|
xls => 'Excel Spreadsheet', |
44
|
|
|
|
|
|
|
xlsb => 'Excel Spreadsheet', |
45
|
|
|
|
|
|
|
xlsm => 'Excel Spreadsheet', |
46
|
|
|
|
|
|
|
xlt => 'Excel Spreadsheet Template', |
47
|
|
|
|
|
|
|
xltm => 'Excel Spreadsheet Template', |
48
|
|
|
|
|
|
|
xlw => 'Excel Workspace', |
49
|
|
|
|
|
|
|
); |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# https://support.office.com/en-us/article/blocked-attachments-in-outlook-434752e1-02d3-4e90-9124-8b81e49a8519 |
52
|
|
|
|
|
|
|
our %BLOCKED_BY_OUTLOOK = ( |
53
|
|
|
|
|
|
|
ade => 'Access Project Extension', |
54
|
|
|
|
|
|
|
adp => 'Access Project', |
55
|
|
|
|
|
|
|
app => 'Executable Application', |
56
|
|
|
|
|
|
|
application => 'ClickOnce Deployment Manifest File', |
57
|
|
|
|
|
|
|
'appref-ms' => 'ClickOnce Application Reference File', |
58
|
|
|
|
|
|
|
asp => 'Active Server Page', |
59
|
|
|
|
|
|
|
aspx => 'Active Server Page Extended', |
60
|
|
|
|
|
|
|
asx => 'ASF Redirector file', |
61
|
|
|
|
|
|
|
bas => 'BASIC Source Code', |
62
|
|
|
|
|
|
|
bat => 'Batch Processing', |
63
|
|
|
|
|
|
|
bgi => 'Borland Graphics Interface', |
64
|
|
|
|
|
|
|
cab => 'Windows Cabinet File', |
65
|
|
|
|
|
|
|
cer => 'Internet Security Certificate File', |
66
|
|
|
|
|
|
|
chm => 'Compiled HTML Help', |
67
|
|
|
|
|
|
|
cmd => 'Command File', |
68
|
|
|
|
|
|
|
cnt => 'Microsoft Help Workshop Application', |
69
|
|
|
|
|
|
|
com => 'Command', |
70
|
|
|
|
|
|
|
cpl => 'Windows Control Panel Extension', |
71
|
|
|
|
|
|
|
crt => 'Certificate File', |
72
|
|
|
|
|
|
|
csh => 'csh Script', |
73
|
|
|
|
|
|
|
der => 'DER Encoded X509 Certificate File', |
74
|
|
|
|
|
|
|
diagcab => 'Microsoft Support diagnostic tools', |
75
|
|
|
|
|
|
|
exe => 'Executable File', |
76
|
|
|
|
|
|
|
fxp => 'FoxPro Compiled Source', |
77
|
|
|
|
|
|
|
gadget => 'Windows Vista gadget', |
78
|
|
|
|
|
|
|
grp => 'Microsoft program group', |
79
|
|
|
|
|
|
|
hlp => 'Windows Help File', |
80
|
|
|
|
|
|
|
hpj => 'AppWizard Help project', |
81
|
|
|
|
|
|
|
hta => 'Hypertext Application', |
82
|
|
|
|
|
|
|
htc => 'HTML component file', |
83
|
|
|
|
|
|
|
inf => 'Information or Setup File', |
84
|
|
|
|
|
|
|
ins => 'IIS Internet Communications Settings', |
85
|
|
|
|
|
|
|
iso => 'Optical Disk Media File System', |
86
|
|
|
|
|
|
|
isp => 'IIS Internet Service Provider Settings', |
87
|
|
|
|
|
|
|
its => 'Internet Document Set', |
88
|
|
|
|
|
|
|
jar => 'Java Archive', |
89
|
|
|
|
|
|
|
jnlp => 'Java Network Launch Protocol', |
90
|
|
|
|
|
|
|
js => 'JavaScript Source Code', |
91
|
|
|
|
|
|
|
jse => 'JScript Encoded Script File', |
92
|
|
|
|
|
|
|
ksh => 'UNIX Shell Script', |
93
|
|
|
|
|
|
|
lnk => 'Windows Shortcut File', |
94
|
|
|
|
|
|
|
mad => 'Access Module Shortcut', |
95
|
|
|
|
|
|
|
maf => 'Access', |
96
|
|
|
|
|
|
|
mag => 'Access Diagram Shortcut', |
97
|
|
|
|
|
|
|
mam => 'Access Macro Shortcut', |
98
|
|
|
|
|
|
|
maq => 'Access Query Shortcut', |
99
|
|
|
|
|
|
|
mar => 'Access Report Shortcut', |
100
|
|
|
|
|
|
|
mas => 'Access Stored Procedures', |
101
|
|
|
|
|
|
|
mat => 'Access Table Shortcut', |
102
|
|
|
|
|
|
|
mau => 'Media Attachment Unit', |
103
|
|
|
|
|
|
|
mav => 'Access View Shortcut', |
104
|
|
|
|
|
|
|
maw => 'Access Data Access Page', |
105
|
|
|
|
|
|
|
mcf => 'Media Container Format', |
106
|
|
|
|
|
|
|
mda => 'Access Add-in', |
107
|
|
|
|
|
|
|
mdb => 'Access Application', |
108
|
|
|
|
|
|
|
mde => 'Access MDE Database File', |
109
|
|
|
|
|
|
|
mdt => 'Access Add-in Data', |
110
|
|
|
|
|
|
|
mdw => 'Access Workgroup Information', |
111
|
|
|
|
|
|
|
mdz => 'Access Wizard Template', |
112
|
|
|
|
|
|
|
msc => 'Microsoft Management Console Snap-in Control File', |
113
|
|
|
|
|
|
|
msh => 'Microsoft Shell', |
114
|
|
|
|
|
|
|
msh1 => 'Microsoft Shell', |
115
|
|
|
|
|
|
|
msh2 => 'Microsoft Shell', |
116
|
|
|
|
|
|
|
mshxml => 'Microsoft Shell', |
117
|
|
|
|
|
|
|
msh1xml => 'Microsoft Shell', |
118
|
|
|
|
|
|
|
msh2xml => 'Microsoft Shell', |
119
|
|
|
|
|
|
|
msi => 'Windows Installer File', |
120
|
|
|
|
|
|
|
msp => 'Windows Installer Update', |
121
|
|
|
|
|
|
|
mst => 'Windows SDK Setup Transform Script', |
122
|
|
|
|
|
|
|
msu => 'Windows Update file', |
123
|
|
|
|
|
|
|
ops => 'Office Profile Settings File', |
124
|
|
|
|
|
|
|
osd => 'Open Software Description ', |
125
|
|
|
|
|
|
|
pcd => 'Visual Test', |
126
|
|
|
|
|
|
|
pif => 'Windows Program Information File', |
127
|
|
|
|
|
|
|
pl => 'Perl script', |
128
|
|
|
|
|
|
|
plg => 'Developer Studio Build Log', |
129
|
|
|
|
|
|
|
prf => 'Windows System File', |
130
|
|
|
|
|
|
|
prg => 'Program File', |
131
|
|
|
|
|
|
|
printerexport => 'Printer backup file', |
132
|
|
|
|
|
|
|
ps1 => 'Windows PowerShell', |
133
|
|
|
|
|
|
|
ps1xml => 'Windows PowerShell', |
134
|
|
|
|
|
|
|
ps2 => 'Windows PowerShell', |
135
|
|
|
|
|
|
|
ps2xml => 'Windows PowerShell', |
136
|
|
|
|
|
|
|
psc1 => 'Windows PowerShell', |
137
|
|
|
|
|
|
|
psc2 => 'Windows PowerShell', |
138
|
|
|
|
|
|
|
psd1 => 'Windows PowerShell', |
139
|
|
|
|
|
|
|
psdm1 => 'Windows PowerShell', |
140
|
|
|
|
|
|
|
pst => 'Outlook Personal Folder File', |
141
|
|
|
|
|
|
|
py => 'Python script', |
142
|
|
|
|
|
|
|
pyc => 'Python script', |
143
|
|
|
|
|
|
|
pyo => 'Python script', |
144
|
|
|
|
|
|
|
pyw => 'Python script', |
145
|
|
|
|
|
|
|
pyz => 'Python script', |
146
|
|
|
|
|
|
|
pyzw => 'Python script', |
147
|
|
|
|
|
|
|
reg => 'Registry Data File', |
148
|
|
|
|
|
|
|
scf => 'Windows Explorer Command', |
149
|
|
|
|
|
|
|
scr => 'Windows Screen Saver', |
150
|
|
|
|
|
|
|
sct => 'Windows Script Component', |
151
|
|
|
|
|
|
|
shb => 'Windows Shortcut into a Document', |
152
|
|
|
|
|
|
|
shs => 'Shell Scrap Object File', |
153
|
|
|
|
|
|
|
theme => 'Desktop theme file settings', |
154
|
|
|
|
|
|
|
tmp => 'Temporary File/Folder', |
155
|
|
|
|
|
|
|
url => 'Internet Location', |
156
|
|
|
|
|
|
|
vb => 'VBScript File or Any Visual Basic Source', |
157
|
|
|
|
|
|
|
vbe => 'VBScript Encoded Script File', |
158
|
|
|
|
|
|
|
vbp => 'Visual Basic project file', |
159
|
|
|
|
|
|
|
vbs => 'VBScript File', |
160
|
|
|
|
|
|
|
vhd => 'Virtual Hard Disk', |
161
|
|
|
|
|
|
|
vhdx => 'Virtual Hard Disk Extended', |
162
|
|
|
|
|
|
|
vsmacros => 'Visual Studio .NET Binary-based Macro Project', |
163
|
|
|
|
|
|
|
vsw => 'Visio Workspace File', |
164
|
|
|
|
|
|
|
webpnp => 'Internet printing file', |
165
|
|
|
|
|
|
|
website => 'Pinned site shortcut from Internet Explorer', |
166
|
|
|
|
|
|
|
ws => 'Windows Script File', |
167
|
|
|
|
|
|
|
wsc => 'Windows Script Component', |
168
|
|
|
|
|
|
|
wsf => 'Windows Script File', |
169
|
|
|
|
|
|
|
wsh => 'Windows Script Host Settings File', |
170
|
|
|
|
|
|
|
xbap => 'Browser applications', |
171
|
|
|
|
|
|
|
xll => 'Excel Add-in', |
172
|
|
|
|
|
|
|
xnk => 'Exchange Public Folder Shortcut', |
173
|
|
|
|
|
|
|
); |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
# File associations from 7-Zip and others |
176
|
|
|
|
|
|
|
our %ARCHIVES = ( |
177
|
|
|
|
|
|
|
'7z' => '7-Zip Archive', |
178
|
|
|
|
|
|
|
ace => 'ACE File', |
179
|
|
|
|
|
|
|
arj => 'ARJ File', |
180
|
|
|
|
|
|
|
bz2 => 'bzip2 File', |
181
|
|
|
|
|
|
|
bzip2 => 'bzip2 File', |
182
|
|
|
|
|
|
|
cpio => 'CPIO Archive', |
183
|
|
|
|
|
|
|
deb => 'Debian Package', |
184
|
|
|
|
|
|
|
dmg => 'Disk Image', |
185
|
|
|
|
|
|
|
esd => 'Disk Image', |
186
|
|
|
|
|
|
|
fat => 'Zip Archive', |
187
|
|
|
|
|
|
|
gz => 'gzip File', |
188
|
|
|
|
|
|
|
gzip => 'gzip File', |
189
|
|
|
|
|
|
|
hfs => 'Disk Image', |
190
|
|
|
|
|
|
|
lha => 'LHA File', |
191
|
|
|
|
|
|
|
lzh => 'LZH File', |
192
|
|
|
|
|
|
|
lzma => 'LZMA File', |
193
|
|
|
|
|
|
|
ntfs => 'Disk Image', |
194
|
|
|
|
|
|
|
rar => 'RAR Archive', |
195
|
|
|
|
|
|
|
rpm => 'RPM File', |
196
|
|
|
|
|
|
|
sfx => 'Self-extracting Archive', |
197
|
|
|
|
|
|
|
squashfs => 'Disk Image', |
198
|
|
|
|
|
|
|
swm => 'Disk Image', |
199
|
|
|
|
|
|
|
tar => 'tar Archive', |
200
|
|
|
|
|
|
|
taz => 'tar Archive', |
201
|
|
|
|
|
|
|
tbz => 'tar Archive', |
202
|
|
|
|
|
|
|
tbz2 => 'tar Archive', |
203
|
|
|
|
|
|
|
tgz => 'tar Archive', |
204
|
|
|
|
|
|
|
tpz => 'tar Archive', |
205
|
|
|
|
|
|
|
txz => 'tar Archive', |
206
|
|
|
|
|
|
|
uue => 'uuencoded File', |
207
|
|
|
|
|
|
|
wim => 'Disk Image', |
208
|
|
|
|
|
|
|
xar => 'XAR File', |
209
|
|
|
|
|
|
|
xz => 'XZ File', |
210
|
|
|
|
|
|
|
z => 'gzip File', |
211
|
|
|
|
|
|
|
zip => 'Zip Archive', |
212
|
|
|
|
|
|
|
); |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
our %BLOCKLIST = (%MACRO_ENABLED, %BLOCKED_BY_OUTLOOK, %ARCHIVES); |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
sub check_filename { |
217
|
9
|
|
|
9
|
1
|
7272
|
my $filename = shift; |
218
|
|
|
|
|
|
|
|
219
|
9
|
|
|
|
|
18
|
my $extension = q{}; |
220
|
9
|
50
|
|
|
|
67
|
if ($filename =~ m{[.]\h*([^.]+)\z}) { |
221
|
9
|
|
|
|
|
34
|
$extension = lc $1; |
222
|
|
|
|
|
|
|
} |
223
|
|
|
|
|
|
|
|
224
|
9
|
100
|
|
|
|
26
|
if (exists $BLOCKLIST{$extension}) { |
225
|
5
|
|
|
|
|
23
|
return 'blocked'; |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
# Reject split archives like "001" and "r01". |
229
|
4
|
100
|
|
|
|
15
|
if ($extension =~ m{\A[r\d]\d{2,}\z}) { |
230
|
2
|
|
|
|
|
9
|
return 'blocked'; |
231
|
|
|
|
|
|
|
} |
232
|
|
|
|
|
|
|
|
233
|
2
|
|
|
|
|
8
|
return 'ok'; |
234
|
|
|
|
|
|
|
} |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
sub _get_filename { |
237
|
4
|
|
|
4
|
|
7
|
my $zip = shift; |
238
|
|
|
|
|
|
|
|
239
|
4
|
|
|
|
|
6
|
my $filename; |
240
|
|
|
|
|
|
|
|
241
|
4
|
|
|
|
|
8
|
my $header = eval { $zip->getHeaderInfo }; |
|
4
|
|
|
|
|
24
|
|
242
|
4
|
100
|
|
|
|
29
|
if (defined $header) { |
243
|
3
|
|
|
|
|
8
|
$filename = $header->{Name}; |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
4
|
|
|
|
|
9
|
return $filename; |
247
|
|
|
|
|
|
|
} |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
sub check_zip { |
250
|
4
|
|
|
4
|
1
|
1901
|
my $input = shift; |
251
|
|
|
|
|
|
|
|
252
|
4
|
|
|
|
|
8
|
my $result = 'blocked'; |
253
|
|
|
|
|
|
|
|
254
|
4
|
|
|
|
|
8
|
my $zip = eval { IO::Uncompress::Unzip->new($input) }; |
|
4
|
|
|
|
|
25
|
|
255
|
4
|
50
|
|
|
|
6171
|
if (defined $zip) { |
256
|
4
|
|
|
|
|
8
|
my $status = 1; |
257
|
|
|
|
|
|
|
STREAM: |
258
|
4
|
|
|
|
|
10
|
while ($status > 0) { |
259
|
4
|
|
|
|
|
10
|
my $filename = _get_filename($zip); |
260
|
4
|
100
|
|
|
|
9
|
if (defined $filename) { |
261
|
3
|
|
|
|
|
7
|
$result = check_filename($filename); |
262
|
|
|
|
|
|
|
} |
263
|
|
|
|
|
|
|
else { |
264
|
1
|
|
|
|
|
3
|
$result = 'blocked'; |
265
|
|
|
|
|
|
|
} |
266
|
4
|
100
|
|
|
|
13
|
if ($result ne 'ok') { |
267
|
3
|
|
|
|
|
8
|
last STREAM; |
268
|
|
|
|
|
|
|
} |
269
|
1
|
|
50
|
|
|
3
|
$status = eval { $zip->nextStream } // -1; |
|
1
|
|
|
|
|
32
|
|
270
|
|
|
|
|
|
|
} |
271
|
4
|
|
|
|
|
217
|
$zip->close; |
272
|
|
|
|
|
|
|
} |
273
|
|
|
|
|
|
|
|
274
|
4
|
|
|
|
|
77
|
return $result; |
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
1; |
278
|
|
|
|
|
|
|
__END__ |