2
2
3
3
import os
4
4
import warnings
5
+ import re
5
6
6
7
__all__ = ["getcaps" ,"findmatch" ]
7
8
@@ -19,6 +20,11 @@ def lineno_sort_key(entry):
19
20
else :
20
21
return 1 , 0
21
22
23
+ _find_unsafe = re .compile (r'[^\xa1-\U0010FFFF\w@+=:,./-]' ).search
24
+
25
+ class UnsafeMailcapInput (Warning ):
26
+ """Warning raised when refusing unsafe input"""
27
+
22
28
23
29
# Part 1: top-level interface.
24
30
@@ -171,15 +177,22 @@ def findmatch(caps, MIMEtype, key='view', filename="/dev/null", plist=[]):
171
177
entry to use.
172
178
173
179
"""
180
+ if _find_unsafe (filename ):
181
+ msg = "Refusing to use mailcap with filename %r. Use a safe temporary filename." % (filename ,)
182
+ warnings .warn (msg , UnsafeMailcapInput )
183
+ return None , None
174
184
entries = lookup (caps , MIMEtype , key )
175
185
# XXX This code should somehow check for the needsterminal flag.
176
186
for e in entries :
177
187
if 'test' in e :
178
188
test = subst (e ['test' ], filename , plist )
189
+ if test is None :
190
+ continue
179
191
if test and os .system (test ) != 0 :
180
192
continue
181
193
command = subst (e [key ], MIMEtype , filename , plist )
182
- return command , e
194
+ if command is not None :
195
+ return command , e
183
196
return None , None
184
197
185
198
def lookup (caps , MIMEtype , key = None ):
@@ -212,14 +225,23 @@ def subst(field, MIMEtype, filename, plist=[]):
212
225
elif c == 's' :
213
226
res = res + filename
214
227
elif c == 't' :
228
+ if _find_unsafe (MIMEtype ):
229
+ msg = "Refusing to substitute MIME type %r into a shell command." % (MIMEtype ,)
230
+ warnings .warn (msg , UnsafeMailcapInput )
231
+ return None
215
232
res = res + MIMEtype
216
233
elif c == '{' :
217
234
start = i
218
235
while i < n and field [i ] != '}' :
219
236
i = i + 1
220
237
name = field [start :i ]
221
238
i = i + 1
222
- res = res + findparam (name , plist )
239
+ param = findparam (name , plist )
240
+ if _find_unsafe (param ):
241
+ msg = "Refusing to substitute parameter %r (%s) into a shell command" % (param , name )
242
+ warnings .warn (msg , UnsafeMailcapInput )
243
+ return None
244
+ res = res + param
223
245
# XXX To do:
224
246
# %n == number of parts if type is multipart/*
225
247
# %F == list of alternating type and filename for parts
0 commit comments