22
33import os
44import warnings
5+ import re
56
67__all__ = ["getcaps" ,"findmatch" ]
78
@@ -19,6 +20,11 @@ def lineno_sort_key(entry):
1920 else :
2021 return 1 , 0
2122
23+ _find_unsafe = re .compile (r'[^\xa1-\U0010FFFF\w@+=:,./-]' ).search
24+
25+ class UnsafeMailcapInput (Warning ):
26+ """Warning raised when refusing unsafe input"""
27+
2228
2329# Part 1: top-level interface.
2430
@@ -171,15 +177,22 @@ def findmatch(caps, MIMEtype, key='view', filename="/dev/null", plist=[]):
171177 entry to use.
172178
173179 """
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
174184 entries = lookup (caps , MIMEtype , key )
175185 # XXX This code should somehow check for the needsterminal flag.
176186 for e in entries :
177187 if 'test' in e :
178188 test = subst (e ['test' ], filename , plist )
189+ if test is None :
190+ continue
179191 if test and os .system (test ) != 0 :
180192 continue
181193 command = subst (e [key ], MIMEtype , filename , plist )
182- return command , e
194+ if command is not None :
195+ return command , e
183196 return None , None
184197
185198def lookup (caps , MIMEtype , key = None ):
@@ -212,14 +225,23 @@ def subst(field, MIMEtype, filename, plist=[]):
212225 elif c == 's' :
213226 res = res + filename
214227 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
215232 res = res + MIMEtype
216233 elif c == '{' :
217234 start = i
218235 while i < n and field [i ] != '}' :
219236 i = i + 1
220237 name = field [start :i ]
221238 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
223245 # XXX To do:
224246 # %n == number of parts if type is multipart/*
225247 # %F == list of alternating type and filename for parts
0 commit comments