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 f24c10c32b)
This commit is contained in:
Toshio Kuratomi 2016-10-15 13:57:21 -07:00
parent 3d3ebbf98e
commit e1101f78bd
3 changed files with 42 additions and 41 deletions

View file

@ -31,6 +31,7 @@ import string
from ansible.compat.six import iteritems, string_types from ansible.compat.six import iteritems, string_types
from ansible import constants as C from ansible import constants as C
from ansible.errors import AnsibleError from ansible.errors import AnsibleError
from ansible.module_utils._text import to_bytes
from ansible.playbook.attribute import FieldAttribute from ansible.playbook.attribute import FieldAttribute
from ansible.playbook.base import Base from ansible.playbook.base import Base
from ansible.utils.boolean import boolean from ansible.utils.boolean import boolean
@ -84,38 +85,38 @@ MAGIC_VARIABLE_MAPPING = dict(
module_compression = ('ansible_module_compression',), module_compression = ('ansible_module_compression',),
) )
SU_PROMPT_LOCALIZATIONS = [ b_SU_PROMPT_LOCALIZATIONS = [
'Password', to_bytes('Password'),
'암호', to_bytes('암호'),
'パスワード', to_bytes('パスワード'),
'Adgangskode', to_bytes('Adgangskode'),
'Contraseña', to_bytes('Contraseña'),
'Contrasenya', to_bytes('Contrasenya'),
'Hasło', to_bytes('Hasło'),
'Heslo', to_bytes('Heslo'),
'Jelszó', to_bytes('Jelszó'),
'Lösenord', to_bytes('Lösenord'),
'Mật khẩu', to_bytes('Mật khẩu'),
'Mot de passe', to_bytes('Mot de passe'),
'Parola', to_bytes('Parola'),
'Parool', to_bytes('Parool'),
'Pasahitza', to_bytes('Pasahitza'),
'Passord', to_bytes('Passord'),
'Passwort', to_bytes('Passwort'),
'Salasana', to_bytes('Salasana'),
'Sandi', to_bytes('Sandi'),
'Senha', to_bytes('Senha'),
'Wachtwoord', 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 = ( TASK_ATTRIBUTE_OVERRIDES = (
@ -515,9 +516,9 @@ class PlayContext(Base):
elif self.become_method == 'su': elif self.become_method == 'su':
# passing code ref to examine prompt as simple string comparisson isn't good enough with su # passing code ref to examine prompt as simple string comparisson isn't good enough with su
def detect_su_prompt(data): def detect_su_prompt(b_data):
SU_PROMPT_LOCALIZATIONS_RE = re.compile("|".join(['(\w+\'s )?' + x + ' ?: ?' for x in SU_PROMPT_LOCALIZATIONS]), flags=re.IGNORECASE) 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(SU_PROMPT_LOCALIZATIONS_RE.match(data)) return bool(b_SU_PROMPT_LOCALIZATIONS_RE.match(b_data))
prompt = detect_su_prompt prompt = detect_su_prompt
becomecmd = '%s %s %s -c %s' % (exe, flags, self.become_user, pipes.quote(command)) 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) becomecmd = '%s -b %s -u %s %s' % (exe, flags, self.become_user, success_cmd)
elif self.become_method == 'ksu': elif self.become_method == 'ksu':
def detect_ksu_prompt(data): def detect_ksu_prompt(b_data):
return re.match("Kerberos password for .*@.*:", data) return re.match(b"Kerberos password for .*@.*:", b_data)
prompt = detect_ksu_prompt prompt = detect_ksu_prompt
becomecmd = '%s %s %s -e %s' % (exe, self.become_user, flags, command) becomecmd = '%s %s %s -e %s' % (exe, self.become_user, flags, command)

View file

@ -90,7 +90,7 @@ class Connection(ConnectionBase):
if self._play_context.prompt and sudoable: 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.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) 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): 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) 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() chunk = p.stderr.read()
else: else:
stdout, stderr = p.communicate() 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: if not chunk:
stdout, stderr = p.communicate() 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 become_output += chunk
if not self.check_become_success(become_output): if not self.check_become_success(become_output):
p.stdin.write(to_bytes(self._play_context.become_pass, errors='surrogate_or_strict') + b'\n') p.stdin.write(to_bytes(self._play_context.become_pass, errors='surrogate_or_strict') + b'\n')

View file

@ -310,7 +310,7 @@ class Connection(ConnectionBase):
if passprompt: if passprompt:
if self._play_context.become and self._play_context.become_pass: 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: else:
raise AnsibleError("A password is reqired but none was supplied") raise AnsibleError("A password is reqired but none was supplied")
else: else: