From d01188033ff0c2139f34ea5143b01dcf1b880a02 Mon Sep 17 00:00:00 2001 From: James Cammarata Date: Thu, 21 Aug 2014 13:09:32 -0500 Subject: [PATCH] Checking for localized versions of the su password prompt Fixes #8681 --- .../runner/connection_plugins/paramiko_ssh.py | 3 +- lib/ansible/runner/connection_plugins/ssh.py | 3 +- lib/ansible/utils/__init__.py | 4 +- lib/ansible/utils/su_prompts.py | 60 +++++++++++++++++++ test/units/TestUtils.py | 17 +++--- 5 files changed, 72 insertions(+), 15 deletions(-) create mode 100644 lib/ansible/utils/su_prompts.py diff --git a/lib/ansible/runner/connection_plugins/paramiko_ssh.py b/lib/ansible/runner/connection_plugins/paramiko_ssh.py index 93b193022f..a9bffe678e 100644 --- a/lib/ansible/runner/connection_plugins/paramiko_ssh.py +++ b/lib/ansible/runner/connection_plugins/paramiko_ssh.py @@ -225,7 +225,6 @@ class Connection(object): shcmd, prompt, success_key = utils.make_sudo_cmd(sudo_user, executable, cmd) elif self.runner.su or su: shcmd, prompt, success_key = utils.make_su_cmd(su_user, executable, cmd) - prompt_re = re.compile(prompt) vvv("EXEC %s" % shcmd, host=self.host) sudo_output = '' @@ -240,7 +239,7 @@ class Connection(object): if success_key in sudo_output or \ (self.runner.sudo_pass and sudo_output.endswith(prompt)) or \ - (self.runner.su_pass and prompt_re.match(sudo_output)): + (self.runner.su_pass and utils.su_prompts.check_su_prompt(sudo_output)): break chunk = chan.recv(bufsize) diff --git a/lib/ansible/runner/connection_plugins/ssh.py b/lib/ansible/runner/connection_plugins/ssh.py index ec5d6edd34..f63f0af020 100644 --- a/lib/ansible/runner/connection_plugins/ssh.py +++ b/lib/ansible/runner/connection_plugins/ssh.py @@ -275,7 +275,6 @@ class Connection(object): if su and su_user: sudocmd, prompt, success_key = utils.make_su_cmd(su_user, executable, cmd) - prompt_re = re.compile(prompt) ssh_cmd.append(sudocmd) elif not self.runner.sudo or not sudoable: prompt = None @@ -319,7 +318,7 @@ class Connection(object): while True: if success_key in sudo_output or \ (self.runner.sudo_pass and sudo_output.endswith(prompt)) or \ - (self.runner.su_pass and prompt_re.match(sudo_output)): + (self.runner.su_pass and utils.su_prompts.check_su_prompt(sudo_output)): break rfd, wfd, efd = select.select([p.stdout, p.stderr], [], diff --git a/lib/ansible/utils/__init__.py b/lib/ansible/utils/__init__.py index 15a47494c9..a75c1a57e5 100644 --- a/lib/ansible/utils/__init__.py +++ b/lib/ansible/utils/__init__.py @@ -28,6 +28,7 @@ from ansible import errors from ansible import __version__ from ansible.utils.display_functions import * from ansible.utils.plugins import * +from ansible.utils.su_prompts import * from ansible.callbacks import display from ansible.module_utils.splitter import split_args, unquote import ansible.constants as C @@ -1175,13 +1176,12 @@ def make_su_cmd(su_user, executable, cmd): """ # TODO: work on this function randbits = ''.join(chr(random.randint(ord('a'), ord('z'))) for x in xrange(32)) - prompt = '[Pp]assword: ?$' success_key = 'SUDO-SUCCESS-%s' % randbits sudocmd = '%s %s %s -c "%s -c %s"' % ( C.DEFAULT_SU_EXE, C.DEFAULT_SU_FLAGS, su_user, executable or '$SHELL', pipes.quote('echo %s; %s' % (success_key, cmd)) ) - return ('/bin/sh -c ' + pipes.quote(sudocmd), prompt, success_key) + return ('/bin/sh -c ' + pipes.quote(sudocmd), None, success_key) _TO_UNICODE_TYPES = (unicode, type(None)) diff --git a/lib/ansible/utils/su_prompts.py b/lib/ansible/utils/su_prompts.py new file mode 100644 index 0000000000..f6641a4321 --- /dev/null +++ b/lib/ansible/utils/su_prompts.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- + +# (c) 2012-2014, Michael DeHaan +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +import re + +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', + 'ססמה', + 'Лозинка', + 'Парола', + 'Пароль', + 'गुप्तशब्द', + 'शब्दकूट', + 'సంకేతపదము', + 'හස්පදය', + '密码', + '密碼', +] + +SU_PROMPT_LOCALIZATIONS_RE = re.compile("|".join([x + ' ?: ?' for x in SU_PROMPT_LOCALIZATIONS]), flags=re.IGNORECASE) + +def check_su_prompt(data): + return bool(SU_PROMPT_LOCALIZATIONS_RE.match(data)) + diff --git a/test/units/TestUtils.py b/test/units/TestUtils.py index dda9d5c676..044f070f1d 100644 --- a/test/units/TestUtils.py +++ b/test/units/TestUtils.py @@ -484,21 +484,20 @@ class TestUtils(unittest.TestCase): self.assertEqual(ansible.utils.boolean(0), False) self.assertEqual(ansible.utils.boolean("foo"), False) - #def test_make_sudo_cmd(self): - # cmd = ansible.utils.make_sudo_cmd('root', '/bin/sh', '/bin/ls') - # self.assertTrue(isinstance(cmd, tuple)) - # self.assertEqual(len(cmd), 3) - # self.assertTrue('-u root' in cmd[0]) - # self.assertTrue('-p "[sudo via ansible, key=' in cmd[0] and cmd[1].startswith('[sudo via ansible, key')) - # self.assertTrue('echo SUDO-SUCCESS-' in cmd[0] and cmd[2].startswith('SUDO-SUCCESS-')) - # self.assertTrue('sudo -k' in cmd[0]) + def test_make_sudo_cmd(self): + cmd = ansible.utils.make_sudo_cmd('root', '/bin/sh', '/bin/ls') + self.assertTrue(isinstance(cmd, tuple)) + self.assertEqual(len(cmd), 3) + self.assertTrue('-u root' in cmd[0]) + self.assertTrue('-p "[sudo via ansible, key=' in cmd[0] and cmd[1].startswith('[sudo via ansible, key')) + self.assertTrue('echo SUDO-SUCCESS-' in cmd[0] and cmd[2].startswith('SUDO-SUCCESS-')) + self.assertTrue('sudo -k' in cmd[0]) def test_make_su_cmd(self): cmd = ansible.utils.make_su_cmd('root', '/bin/sh', '/bin/ls') self.assertTrue(isinstance(cmd, tuple)) self.assertEqual(len(cmd), 3) self.assertTrue('root -c "/bin/sh' in cmd[0] or ' root -c /bin/sh' in cmd[0]) - self.assertTrue(re.compile(cmd[1])) self.assertTrue('echo SUDO-SUCCESS-' in cmd[0] and cmd[2].startswith('SUDO-SUCCESS-')) def test_to_unicode(self):