From e1101f78bd0549abc62e8794c4f6a7499171769d Mon Sep 17 00:00:00 2001 From: Toshio Kuratomi Date: Sat, 15 Oct 2016 13:57:21 -0700 Subject: [PATCH] Fixes to handle non-ascii become passwords Fixes for non-ascii passwords on * both python2 and python3, * local and paramiko_ssh (ssh tested working with these changes) * sudo and su Fixes #16557 (cherry picked from commit f24c10c32be86d3eb792d109fb6fdad19bbfcf4c) --- lib/ansible/playbook/play_context.py | 75 ++++++++++--------- lib/ansible/plugins/connection/local.py | 6 +- .../plugins/connection/paramiko_ssh.py | 2 +- 3 files changed, 42 insertions(+), 41 deletions(-) diff --git a/lib/ansible/playbook/play_context.py b/lib/ansible/playbook/play_context.py index b038862b202..46ba98d98bd 100644 --- a/lib/ansible/playbook/play_context.py +++ b/lib/ansible/playbook/play_context.py @@ -31,6 +31,7 @@ import string from ansible.compat.six import iteritems, string_types from ansible import constants as C from ansible.errors import AnsibleError +from ansible.module_utils._text import to_bytes from ansible.playbook.attribute import FieldAttribute from ansible.playbook.base import Base from ansible.utils.boolean import boolean @@ -84,38 +85,38 @@ MAGIC_VARIABLE_MAPPING = dict( module_compression = ('ansible_module_compression',), ) -SU_PROMPT_LOCALIZATIONS = [ - 'Password', - '암호', - 'パスワード', - 'Adgangskode', - 'Contraseña', - 'Contrasenya', - 'Hasło', - 'Heslo', - 'Jelszó', - 'Lösenord', - 'Mật khẩu', - 'Mot de passe', - 'Parola', - 'Parool', - 'Pasahitza', - 'Passord', - 'Passwort', - 'Salasana', - 'Sandi', - 'Senha', - 'Wachtwoord', - 'ססמה', - 'Лозинка', - 'Парола', - 'Пароль', - 'गुप्तशब्द', - 'शब्दकूट', - 'సంకేతపదము', - 'හස්පදය', - '密码', - '密碼', +b_SU_PROMPT_LOCALIZATIONS = [ + to_bytes('Password'), + to_bytes('암호'), + to_bytes('パスワード'), + to_bytes('Adgangskode'), + to_bytes('Contraseña'), + to_bytes('Contrasenya'), + to_bytes('Hasło'), + to_bytes('Heslo'), + to_bytes('Jelszó'), + to_bytes('Lösenord'), + to_bytes('Mật khẩu'), + to_bytes('Mot de passe'), + to_bytes('Parola'), + to_bytes('Parool'), + to_bytes('Pasahitza'), + to_bytes('Passord'), + to_bytes('Passwort'), + to_bytes('Salasana'), + to_bytes('Sandi'), + to_bytes('Senha'), + to_bytes('Wachtwoord'), + to_bytes('ססמה'), + to_bytes('Лозинка'), + to_bytes('Парола'), + to_bytes('Пароль'), + to_bytes('गुप्तशब्द'), + to_bytes('शब्दकूट'), + to_bytes('సంకేతపదము'), + to_bytes('හස්පදය'), + to_bytes('密码'), + to_bytes('密碼'), ] TASK_ATTRIBUTE_OVERRIDES = ( @@ -515,9 +516,9 @@ class PlayContext(Base): elif self.become_method == 'su': # passing code ref to examine prompt as simple string comparisson isn't good enough with su - def detect_su_prompt(data): - SU_PROMPT_LOCALIZATIONS_RE = re.compile("|".join(['(\w+\'s )?' + x + ' ?: ?' for x in SU_PROMPT_LOCALIZATIONS]), flags=re.IGNORECASE) - return bool(SU_PROMPT_LOCALIZATIONS_RE.match(data)) + def detect_su_prompt(b_data): + b_SU_PROMPT_LOCALIZATIONS_RE = re.compile(b"|".join([b'(\w+\'s )?' + x + b' ?: ?' for x in b_SU_PROMPT_LOCALIZATIONS]), flags=re.IGNORECASE) + return bool(b_SU_PROMPT_LOCALIZATIONS_RE.match(b_data)) prompt = detect_su_prompt becomecmd = '%s %s %s -c %s' % (exe, flags, self.become_user, pipes.quote(command)) @@ -528,8 +529,8 @@ class PlayContext(Base): becomecmd = '%s -b %s -u %s %s' % (exe, flags, self.become_user, success_cmd) elif self.become_method == 'ksu': - def detect_ksu_prompt(data): - return re.match("Kerberos password for .*@.*:", data) + def detect_ksu_prompt(b_data): + return re.match(b"Kerberos password for .*@.*:", b_data) prompt = detect_ksu_prompt becomecmd = '%s %s %s -e %s' % (exe, self.become_user, flags, command) diff --git a/lib/ansible/plugins/connection/local.py b/lib/ansible/plugins/connection/local.py index 537e804689f..da25f1e2306 100644 --- a/lib/ansible/plugins/connection/local.py +++ b/lib/ansible/plugins/connection/local.py @@ -90,7 +90,7 @@ class Connection(ConnectionBase): if self._play_context.prompt and sudoable: fcntl.fcntl(p.stdout, fcntl.F_SETFL, fcntl.fcntl(p.stdout, fcntl.F_GETFL) | os.O_NONBLOCK) fcntl.fcntl(p.stderr, fcntl.F_SETFL, fcntl.fcntl(p.stderr, fcntl.F_GETFL) | os.O_NONBLOCK) - become_output = '' + become_output = b'' while not self.check_become_success(become_output) and not self.check_password_prompt(become_output): rfd, wfd, efd = select.select([p.stdout, p.stderr], [], [p.stdout, p.stderr], self._play_context.timeout) @@ -100,10 +100,10 @@ class Connection(ConnectionBase): chunk = p.stderr.read() else: stdout, stderr = p.communicate() - raise AnsibleError('timeout waiting for privilege escalation password prompt:\n' + become_output) + raise AnsibleError('timeout waiting for privilege escalation password prompt:\n' + to_native(become_output)) if not chunk: stdout, stderr = p.communicate() - raise AnsibleError('privilege output closed while waiting for password prompt:\n' + become_output) + raise AnsibleError('privilege output closed while waiting for password prompt:\n' + to_native(become_output)) become_output += chunk if not self.check_become_success(become_output): p.stdin.write(to_bytes(self._play_context.become_pass, errors='surrogate_or_strict') + b'\n') diff --git a/lib/ansible/plugins/connection/paramiko_ssh.py b/lib/ansible/plugins/connection/paramiko_ssh.py index 4fdf0fe4bd0..5e98665ef75 100644 --- a/lib/ansible/plugins/connection/paramiko_ssh.py +++ b/lib/ansible/plugins/connection/paramiko_ssh.py @@ -310,7 +310,7 @@ class Connection(ConnectionBase): if passprompt: if self._play_context.become and self._play_context.become_pass: - chan.sendall(self._play_context.become_pass + '\n') + chan.sendall(to_bytes(self._play_context.become_pass) + b'\n') else: raise AnsibleError("A password is reqired but none was supplied") else: