fix issue #5372 on ssh_alt: accept -K option even for a user with NOPASSWD

This commit is contained in:
jeromew 2013-12-31 14:29:46 -05:00
parent 99616d0c80
commit b2cd4a62de

View file

@ -151,6 +151,9 @@ class Connection(object):
ssh_cmd = self._password_cmd() ssh_cmd = self._password_cmd()
ssh_cmd += ["ssh", "-C"] ssh_cmd += ["ssh", "-C"]
if not in_data: if not in_data:
# we can only use tty when we are not pipelining the modules. piping data into /usr/bin/python
# inside a tty automatically invokes the python interactive-mode but the modules are not
# compatible with the interactive-mode ("unexpected indent" mainly because of empty lines)
ssh_cmd += ["-tt"] ssh_cmd += ["-tt"]
if utils.VERBOSITY > 3: if utils.VERBOSITY > 3:
ssh_cmd += ["-vvv"] ssh_cmd += ["-vvv"]
@ -200,31 +203,52 @@ class Connection(object):
p = subprocess.Popen(ssh_cmd, stdin=subprocess.PIPE, p = subprocess.Popen(ssh_cmd, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdin = p.stdin stdin = p.stdin
self._send_password() self._send_password()
if self.runner.sudo and sudoable and self.runner.sudo_pass: if self.runner.sudo and sudoable and self.runner.sudo_pass:
# several cases are handled for sudo privileges with password
# * NOPASSWD (tty & no-tty): detect success_key on stdout
# * without NOPASSWD:
# * detect prompt on stdout (tty)
# * detect prompt on stderr (no-tty)
fcntl.fcntl(p.stdout, fcntl.F_SETFL, fcntl.fcntl(p.stdout, fcntl.F_SETFL,
fcntl.fcntl(p.stdout, fcntl.F_GETFL) | os.O_NONBLOCK) 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)
sudo_output = '' sudo_output = ''
if in_data: sudo_errput = ''
# no terminal => no prompt on output. process is waiting for sudo_pass
stdin.write(self.runner.sudo_pass + '\n')
while not sudo_output.endswith(prompt) and success_key not in sudo_output: while not sudo_output.endswith(prompt) and success_key not in sudo_output:
rfd, wfd, efd = select.select([p.stdout], [], rfd, wfd, efd = select.select([p.stdout, p.stderr], [],
[p.stdout], self.runner.timeout) [p.stdout], self.runner.timeout)
if p.stderr in rfd:
chunk = p.stderr.read()
if not chunk:
raise errors.AnsibleError('ssh connection closed waiting for sudo password prompt')
sudo_errput += chunk
incorrect_password = gettext.dgettext(
"sudo", "Sorry, try again.")
if sudo_errput.strip().endswith("%s%s" % (prompt, incorrect_password)):
raise errors.AnsibleError('Incorrect sudo password')
elif sudo_errput.endswith(prompt):
stdin.write(self.runner.sudo_pass + '\n')
if p.stdout in rfd: if p.stdout in rfd:
chunk = p.stdout.read() chunk = p.stdout.read()
if not chunk: if not chunk:
raise errors.AnsibleError('ssh connection closed waiting for sudo password prompt') raise errors.AnsibleError('ssh connection closed waiting for sudo password prompt')
sudo_output += chunk sudo_output += chunk
else:
if not rfd:
# timeout. wrap up process communication
stdout = p.communicate() stdout = p.communicate()
raise errors.AnsibleError('ssh connection error waiting for sudo password prompt') raise errors.AnsibleError('ssh connection error waiting for sudo password prompt')
if success_key not in sudo_output: if success_key not in sudo_output:
stdin.write(self.runner.sudo_pass + '\n') stdin.write(self.runner.sudo_pass + '\n')
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)
# We can't use p.communicate here because the ControlMaster may have stdout open as well # We can't use p.communicate here because the ControlMaster may have stdout open as well
stdout = '' stdout = ''
stderr = '' stderr = ''