|
1 | 1 | """Mailcap file handling. See RFC 1524.""" |
2 | 2 |
|
3 | 3 | import os |
| 4 | +import warnings |
| 5 | +import re |
4 | 6 |
|
5 | 7 | __all__ = ["getcaps","findmatch"] |
6 | 8 |
|
| 9 | +_find_unsafe = re.compile(r'[^\w@%+=:,./-]').search |
| 10 | + |
| 11 | +class UnsafeMailcapInput(Warning): |
| 12 | + """Warning raised when refusing unsafe input""" |
| 13 | + |
7 | 14 | # Part 1: top-level interface. |
8 | 15 |
|
9 | 16 | def getcaps(): |
@@ -149,10 +156,13 @@ def findmatch(caps, MIMEtype, key='view', filename="/dev/null", plist=[]): |
149 | 156 | for e in entries: |
150 | 157 | if 'test' in e: |
151 | 158 | test = subst(e['test'], filename, plist) |
| 159 | + if test is None: |
| 160 | + continue |
152 | 161 | if test and os.system(test) != 0: |
153 | 162 | continue |
154 | 163 | command = subst(e[key], MIMEtype, filename, plist) |
155 | | - return command, e |
| 164 | + if command is not None: |
| 165 | + return command, e |
156 | 166 | return None, None |
157 | 167 |
|
158 | 168 | def lookup(caps, MIMEtype, key=None): |
@@ -184,14 +194,23 @@ def subst(field, MIMEtype, filename, plist=[]): |
184 | 194 | elif c == 's': |
185 | 195 | res = res + filename |
186 | 196 | elif c == 't': |
| 197 | + if _find_unsafe(MIMEtype): |
| 198 | + msg = "Refusing to substitute MIME type %r into a shell command." % (MIMEtype,) |
| 199 | + warnings.warn(msg, UnsafeMailcapInput) |
| 200 | + return None |
187 | 201 | res = res + MIMEtype |
188 | 202 | elif c == '{': |
189 | 203 | start = i |
190 | 204 | while i < n and field[i] != '}': |
191 | 205 | i = i+1 |
192 | 206 | name = field[start:i] |
193 | 207 | i = i+1 |
194 | | - res = res + findparam(name, plist) |
| 208 | + param = findparam(name, plist) |
| 209 | + if _find_unsafe(param): |
| 210 | + msg = "Refusing to substitute parameter %r (%s) into a shell command" % (param, name) |
| 211 | + warnings.warn(msg, UnsafeMailcapInput) |
| 212 | + return None |
| 213 | + res = res + param |
195 | 214 | # XXX To do: |
196 | 215 | # %n == number of parts if type is multipart/* |
197 | 216 | # %F == list of alternating type and filename for parts |
|
0 commit comments