Fixes for su on freebsd

Addresses multiple issues when using su on freebsd including
* su prompt differs between platforms, so turned that check into a
  regex comparison instead of a simple string comparison
* not using '-c' after su causes problems, so added that for all
  platforms
* fixed quoting issues due to multiple uses of '-c' introduced by
  the above fix

Fixes #7503
Fixes #7507
pull/7539/head
James Cammarata 11 years ago
parent 10414145b2
commit 1e672a0fec

@ -31,6 +31,7 @@ import random
import logging import logging
import traceback import traceback
import fcntl import fcntl
import re
import sys import sys
from termios import tcflush, TCIFLUSH from termios import tcflush, TCIFLUSH
from binascii import hexlify from binascii import hexlify
@ -210,12 +211,17 @@ class Connection(object):
shcmd, prompt, success_key = utils.make_sudo_cmd(sudo_user, executable, cmd) shcmd, prompt, success_key = utils.make_sudo_cmd(sudo_user, executable, cmd)
elif self.runner.su or su: elif self.runner.su or su:
shcmd, prompt, success_key = utils.make_su_cmd(su_user, executable, cmd) shcmd, prompt, success_key = utils.make_su_cmd(su_user, executable, cmd)
prompt_re = re.compile(prompt)
vvv("EXEC %s" % shcmd, host=self.host) vvv("EXEC %s" % shcmd, host=self.host)
sudo_output = '' sudo_output = ''
try: try:
chan.exec_command(shcmd) chan.exec_command(shcmd)
if self.runner.sudo_pass or self.runner.su_pass: if self.runner.sudo_pass or self.runner.su_pass:
while not sudo_output.endswith(prompt) and success_key not in sudo_output: 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)):
break
chunk = chan.recv(bufsize) chunk = chan.recv(bufsize)
if not chunk: if not chunk:
if 'unknown user' in sudo_output: if 'unknown user' in sudo_output:

@ -17,6 +17,7 @@
# #
import os import os
import re
import subprocess import subprocess
import shlex import shlex
import pipes import pipes
@ -268,6 +269,7 @@ class Connection(object):
if su and su_user: if su and su_user:
sudocmd, prompt, success_key = utils.make_su_cmd(su_user, executable, cmd) sudocmd, prompt, success_key = utils.make_su_cmd(su_user, executable, cmd)
prompt_re = re.compile(prompt)
ssh_cmd.append(sudocmd) ssh_cmd.append(sudocmd)
elif not self.runner.sudo or not sudoable: elif not self.runner.sudo or not sudoable:
prompt = None prompt = None
@ -308,7 +310,12 @@ class Connection(object):
sudo_output = '' sudo_output = ''
sudo_errput = '' sudo_errput = ''
while not sudo_output.endswith(prompt) and success_key not in sudo_output: 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)):
break
rfd, wfd, efd = select.select([p.stdout, p.stderr], [], rfd, wfd, efd = select.select([p.stdout, p.stderr], [],
[p.stdout], self.runner.timeout) [p.stdout], self.runner.timeout)
if p.stderr in rfd: if p.stderr in rfd:

@ -952,9 +952,9 @@ def make_su_cmd(su_user, executable, cmd):
""" """
# TODO: work on this function # TODO: work on this function
randbits = ''.join(chr(random.randint(ord('a'), ord('z'))) for x in xrange(32)) randbits = ''.join(chr(random.randint(ord('a'), ord('z'))) for x in xrange(32))
prompt = 'assword: ' prompt = '[Pp]assword: ?$'
success_key = 'SUDO-SUCCESS-%s' % randbits success_key = 'SUDO-SUCCESS-%s' % randbits
sudocmd = '%s %s %s %s -c %s' % ( sudocmd = '%s %s %s -c "%s -c %s"' % (
C.DEFAULT_SU_EXE, C.DEFAULT_SU_FLAGS, su_user, executable or '$SHELL', C.DEFAULT_SU_EXE, C.DEFAULT_SU_FLAGS, su_user, executable or '$SHELL',
pipes.quote('echo %s; %s' % (success_key, cmd)) pipes.quote('echo %s; %s' % (success_key, cmd))
) )

@ -3,6 +3,7 @@
import unittest import unittest
import os import os
import os.path import os.path
import re
import tempfile import tempfile
import yaml import yaml
import passlib.hash import passlib.hash
@ -511,8 +512,8 @@ class TestUtils(unittest.TestCase):
cmd = ansible.utils.make_su_cmd('root', '/bin/sh', '/bin/ls') cmd = ansible.utils.make_su_cmd('root', '/bin/sh', '/bin/ls')
self.assertTrue(isinstance(cmd, tuple)) self.assertTrue(isinstance(cmd, tuple))
self.assertEqual(len(cmd), 3) self.assertEqual(len(cmd), 3)
self.assertTrue(' root /bin/sh' in cmd[0]) self.assertTrue(' root -c "/bin/sh' in cmd[0])
self.assertTrue(cmd[1] == 'assword: ') self.assertTrue(re.compile(cmd[1]))
self.assertTrue('echo SUDO-SUCCESS-' in cmd[0] and cmd[2].startswith('SUDO-SUCCESS-')) self.assertTrue('echo SUDO-SUCCESS-' in cmd[0] and cmd[2].startswith('SUDO-SUCCESS-'))
def test_to_unicode(self): def test_to_unicode(self):

Loading…
Cancel
Save