Merge pull request #7539 from jimi-c/issue_7503_freebsd_su_fixes

Fixes for su on freebsd
This commit is contained in:
James Cammarata 2014-05-25 15:09:58 -05:00
commit 92f16b3d6f
4 changed files with 20 additions and 6 deletions

View file

@ -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:

View file

@ -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:

View file

@ -950,9 +950,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))
) )

View file

@ -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):