* prevent templating of passwords from prompt (#59246)
* prevent templating of passwords from prompt
fixes CVE-2019-10206
(cherry picked from commit e9a37f8e3171105941892a86a1587de18126ec5b)
* Improve performane of UnsafeProxy __new__
This adds an early return to the __new__ method of the UnsafeProxy object
which avoids creating the unsafe object if the incoming object is already
unsafe.
(cherry picked from commit c1e23c22a9fedafaaa88c2119b26dc123ff1392e)
(cherry picked from commit 490f17c7f959ce153765c1f033fdc30becf0faf7)
... | ... |
@@ -42,6 +42,7 @@ from ansible.parsing.dataloader import DataLoader |
42 | 42 |
from ansible.release import __version__ |
43 | 43 |
from ansible.utils.path import unfrackpath |
44 | 44 |
from ansible.utils.vars import load_extra_vars, load_options_vars |
45 |
+from ansible.utils.unsafe_proxy import AnsibleUnsafeBytes |
|
45 | 46 |
from ansible.vars.manager import VariableManager |
46 | 47 |
from ansible.parsing.vault import PromptVaultSecret, get_file_vault_secret |
47 | 48 |
|
... | ... |
@@ -342,6 +343,13 @@ class CLI(with_metaclass(ABCMeta, object)): |
342 | 342 |
except EOFError: |
343 | 343 |
pass |
344 | 344 |
|
345 |
+ # we 'wrap' the passwords to prevent templating as |
|
346 |
+ # they can contain special chars and trigger it incorrectly |
|
347 |
+ if sshpass: |
|
348 |
+ sshpass = AnsibleUnsafeBytes(sshpass) |
|
349 |
+ if becomepass: |
|
350 |
+ becomepass = AnsibleUnsafeBytes(becomepass) |
|
351 |
+ |
|
345 | 352 |
return (sshpass, becomepass) |
346 | 353 |
|
347 | 354 |
def normalize_become_options(self): |
... | ... |
@@ -55,7 +55,7 @@ __metaclass__ = type |
55 | 55 |
|
56 | 56 |
from collections import Mapping, MutableSequence, Set |
57 | 57 |
|
58 |
-from ansible.module_utils.six import string_types, text_type |
|
58 |
+from ansible.module_utils.six import string_types, text_type, binary_type |
|
59 | 59 |
from ansible.module_utils._text import to_text |
60 | 60 |
|
61 | 61 |
|
... | ... |
@@ -70,15 +70,24 @@ class AnsibleUnsafeText(text_type, AnsibleUnsafe): |
70 | 70 |
pass |
71 | 71 |
|
72 | 72 |
|
73 |
+class AnsibleUnsafeBytes(binary_type, AnsibleUnsafe): |
|
74 |
+ pass |
|
75 |
+ |
|
76 |
+ |
|
73 | 77 |
class UnsafeProxy(object): |
74 | 78 |
def __new__(cls, obj, *args, **kwargs): |
79 |
+ if isinstance(obj, AnsibleUnsafe): |
|
80 |
+ # Already marked unsafe |
|
81 |
+ return obj |
|
82 |
+ |
|
75 | 83 |
# In our usage we should only receive unicode strings. |
76 | 84 |
# This conditional and conversion exists to sanity check the values |
77 | 85 |
# we're given but we may want to take it out for testing and sanitize |
78 | 86 |
# our input instead. |
87 |
+ # Note that this does the wrong thing if we're *intentionall* passing a byte string to this |
|
88 |
+ # function. |
|
79 | 89 |
if isinstance(obj, string_types): |
80 |
- obj = to_text(obj, errors='surrogate_or_strict') |
|
81 |
- return AnsibleUnsafeText(obj) |
|
90 |
+ obj = AnsibleUnsafeText(to_text(obj, errors='surrogate_or_strict')) |
|
82 | 91 |
return obj |
83 | 92 |
|
84 | 93 |
|