From e16114034c94d8e0c4b101094b2ccfd9a44de5b0 Mon Sep 17 00:00:00 2001 From: Michael DeHaan Date: Fri, 27 Apr 2012 00:31:18 -0400 Subject: [PATCH] Revert "Actually wait for password prompt in remote sudo execution. Totally breaks stderr debugging and various modules. This reverts commit 6341a9547f301f04e45848e86848b878962b3dff. --- lib/ansible/connection.py | 63 ++++++++------------------------------- 1 file changed, 13 insertions(+), 50 deletions(-) diff --git a/lib/ansible/connection.py b/lib/ansible/connection.py index 08f72fc65e0..6192eba4a85 100644 --- a/lib/ansible/connection.py +++ b/lib/ansible/connection.py @@ -26,8 +26,6 @@ import re import shutil import subprocess import pipes -import socket -import random from ansible import errors # prevent paramiko warning noise @@ -39,7 +37,6 @@ with warnings.catch_warnings(): ################################################ -RANDOM_PROMPT_LEN = 32 # 32 random chars in [a-z] gives > 128 bits of entropy class Connection(object): @@ -145,53 +142,19 @@ class ParamikoConnection(object): quoted_command = '"$SHELL" -c ' + pipes.quote(cmd) chan.exec_command(quoted_command) else: - """ - Sudo strategy: - - First, if sudo doesn't need a password, it's easy: just run the - command. - - If we need a password, we want to read everything up to and - including the prompt before sending the password. This is so sudo - doesn't block sending the prompt, to catch any errors running sudo - itself, and so sudo's output doesn't gunk up the command's output. - Some systems have large login banners and slow networks, so the - prompt isn't guaranteed to be in the first chunk we read. So, we - have to keep reading until we find the password prompt, or timeout - trying. - - In order to detect the password prompt, we set it ourselves with - the sudo -p switch. We use a random prompt so that a) it's - exceedingly unlikely anyone's login material contains it and b) you - can't forge it. This can fail if passprompt_override is set in - /etc/sudoers. - - Some systems are set to remember your sudo credentials for a set - period across terminals and won't prompt for a password. We use - sudo -k so it always asks for the password every time (if one is - required) to avoid dealing with both cases. - - The "--" tells sudo that this is the end of sudo options and the - command follows. - - We shell quote the command for safety, and since we can't run a quoted - command directly with sudo (or sudo -s), we actually run the user's - shell and pass the quoted command string to the shell's -c option. - """ - prompt = '[sudo via ansible, key=%s] password: ' % ''.join(chr(random.randint(ord('a'), ord('z'))) for _ in xrange(RANDOM_PROMPT_LEN)) - sudocmd = 'sudo -k -p "%s" -- "$SHELL" -c %s' % (prompt, pipes.quote(cmd)) - sudo_output = '' - try: - chan.exec_command(sudocmd) - if self.runner.sudo_pass: - while not sudo_output.endswith(prompt): - chunk = chan.recv(bufsize) - if not chunk: - raise errors.AnsibleError('ssh connection closed waiting for sudo password prompt') - sudo_output += chunk - chan.sendall(self.runner.sudo_pass + '\n') - except socket.timeout: - raise errors.AnsibleError('ssh timed out waiting for sudo.\n' + sudo_output) + # Rather than detect if sudo wants a password this time, -k makes + # sudo always ask for a password if one is required. The "--" + # tells sudo that this is the end of sudo options and the command + # follows. Passing a quoted compound command to sudo (or sudo -s) + # directly doesn't work, so we shellquote it with pipes.quote() + # and pass the quoted string to the user's shell. + sudocmd = 'sudo -k -- "$SHELL" -c ' + pipes.quote(cmd) + chan.exec_command(sudocmd) + if self.runner.sudo_pass: + while not chan.recv_ready(): + time.sleep(0.25) + sudo_output = chan.recv(bufsize) # Pull prompt, catch errors, eat sudo output + chan.sendall(self.runner.sudo_pass + '\n') stdin = chan.makefile('wb', bufsize) stdout = chan.makefile('rb', bufsize)