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