def exec_command(self, cmd, tmp_path, become_user, **kwargs):
        executable = kwargs.get('executable', '/bin/sh')
        sudoable = kwargs.get('sudoable', False)
        if 'su' in kwargs or 'su_user' in kwargs:
            raise errors.AnsibleError("Internal Error: this module does not support running commands via su")

        if kwargs.get('in_data'):
            raise errors.AnsibleError("Internal Error: this module does not support optimized module pipelining")

        if sudoable and getattr(self.runner, 'become', False) and self.runner.become_method not in self.become_methods_supported:
            raise errors.AnsibleError("Internal Error: this module does not support running commands via %s" % self.runner.become_method)

        become = getattr(self.runner, 'become', False) or getattr(self.runner, 'sudo', False)
        remote_cmd = []
        if not become or not sudoable:
            if executable:
                remote_cmd.append(executable + ' -c ' + pipes.quote(cmd))
            else:
                remote_cmd.append(cmd)
        else:
            if hasattr(self.runner, 'become_exe'):
                becomecmd, prompt, success_key = utils.make_become_cmd(cmd, become_user, executable, self.runner.become_method, '', self.runner.become_exe)
            elif hasattr(self.runner, 'sudo_exe'):
                becomecmd, prompt, success_key = utils.make_sudo_cmd(self.runner.sudo_exe, become_user, executable, cmd)
            else:
                becomecmd, prompt, success_key = utils.make_sudo_cmd(become_user, executable, cmd)
            remote_cmd.append(becomecmd)
        remote_cmd = ' '.join(remote_cmd)
        vvv("execnet exec_command %r" % remote_cmd)
        rc, stdout, stderr = self.rpc.exec_command(remote_cmd)
        return (rc, '', stdout, stderr)
Esempio n. 2
0
    def exec_command(self,
                     cmd,
                     tmp_path,
                     sudo_user,
                     sudoable=False,
                     executable='/bin/sh'):
        ''' run a command on the remote host '''

        if self.runner.sudo or sudoable and sudo_user:
            cmd, prompt = utils.make_sudo_cmd(sudo_user, executable, cmd)

        vvv("EXEC COMMAND %s" % cmd)

        data = dict(
            mode='command',
            cmd=cmd,
            tmp_path=tmp_path,
            executable=executable,
        )
        data = utils.jsonify(data)
        data = utils.encrypt(self.key, data)
        if self.send_data(data):
            raise errors.AnisbleError("Failed to send command to %s" %
                                      self.host)

        response = self.recv_data()
        if not response:
            raise errors.AnsibleError("Failed to get a response from %s" %
                                      self.host)
        response = utils.decrypt(self.key, response)
        response = utils.parse_json(response)

        return (response.get('rc', None), '', response.get('stdout', ''),
                response.get('stderr', ''))
Esempio n. 3
0
 def _su_sudo_cmd(self, cmd):
     if self.runner.su and self.runner.su_user:
         return utils.make_su_cmd(self.runner.su_user, '/bin/sh', cmd)
     elif self.runner.sudo:
         return utils.make_sudo_cmd(self.runner.sudo_user, '/bin/sh', cmd)
     else:
         return cmd, None, None
Esempio n. 4
0
    def exec_command(self,
                     cmd,
                     tmp_path,
                     sudo_user,
                     sudoable=False,
                     executable='/bin/sh'):
        ''' run a command on the local host '''

        if not self.runner.sudo or not sudoable:
            if executable:
                local_cmd = [executable, '-c', cmd]
            else:
                local_cmd = cmd
        else:
            local_cmd, prompt = utils.make_sudo_cmd(sudo_user, executable, cmd)

        vvv("EXEC %s" % (local_cmd), host=self.host)
        p = subprocess.Popen(local_cmd,
                             shell=isinstance(local_cmd, basestring),
                             cwd=self.runner.basedir,
                             executable=executable or None,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)

        if self.runner.sudo and sudoable and self.runner.sudo_pass:
            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)
            sudo_output = ''
            while not sudo_output.endswith(prompt):
                rfd, wfd, efd = select.select([p.stdout, p.stderr], [],
                                              [p.stdout, p.stderr],
                                              self.runner.timeout)
                if p.stdout in rfd:
                    chunk = p.stdout.read()
                elif p.stderr in rfd:
                    chunk = p.stderr.read()
                else:
                    stdout, stderr = p.communicate()
                    raise errors.AnsibleError(
                        'timeout waiting for sudo password prompt:\n' +
                        sudo_output)
                if not chunk:
                    stdout, stderr = p.communicate()
                    raise errors.AnsibleError(
                        'sudo output closed while waiting for password prompt:\n'
                        + sudo_output)
                sudo_output += chunk
            p.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.stderr, fcntl.F_SETFL,
                        fcntl.fcntl(p.stderr, fcntl.F_GETFL) & ~os.O_NONBLOCK)

        stdout, stderr = p.communicate()
        return (p.returncode, '', stdout, stderr)
    def exec_command(self,
                     cmd,
                     tmp_path,
                     sudo_user,
                     sudoable=False,
                     executable='/bin/sh',
                     in_data=None):
        ''' run a command on the remote host '''

        if in_data:
            raise errors.AnsibleError(
                "Internal Error: this module does not support optimized module pipelining"
            )

        if executable == "":
            executable = constants.DEFAULT_EXECUTABLE

        if self.runner.sudo and sudoable and sudo_user:
            cmd, prompt, success_key = utils.make_sudo_cmd(
                sudo_user, executable, cmd)

        vvv("EXEC COMMAND %s" % cmd)

        data = dict(
            mode='command',
            cmd=cmd,
            tmp_path=tmp_path,
            executable=executable,
        )
        data = utils.jsonify(data)
        data = utils.encrypt(self.key, data)
        if self.send_data(data):
            raise errors.AnsibleError("Failed to send command to %s" %
                                      self.host)

        while True:
            # we loop here while waiting for the response, because a
            # long running command may cause us to receive keepalive packets
            # ({"pong":"true"}) rather than the response we want.
            response = self.recv_data()
            if not response:
                raise errors.AnsibleError("Failed to get a response from %s" %
                                          self.host)
            response = utils.decrypt(self.key, response)
            response = utils.parse_json(response)
            if "pong" in response:
                # it's a keepalive, go back to waiting
                vvvv("%s: received a keepalive packet" % self.host)
                continue
            else:
                vvvv("%s: received the response" % self.host)
                break

        return (response.get('rc', None), '', response.get('stdout', ''),
                response.get('stderr', ''))
Esempio n. 6
0
    def exec_command(self, cmd, tmp_path, sudo_user=None, sudoable=False, executable='/bin/sh', in_data=None, su=None, su_user=None):
        ''' run a command on the local host '''

        # su requires to be run from a terminal, and therefore isn't supported here (yet?)
        if su or su_user:
            raise errors.AnsibleError("Internal Error: this module does not support running commands via su")

        if in_data:
            raise errors.AnsibleError("Internal Error: this module does not support optimized module pipelining")

        if not self.runner.sudo or not sudoable:
            if executable:
                local_cmd = executable.split() + ['-c', cmd]
            else:
                local_cmd = cmd
        else:
            local_cmd, prompt, success_key = utils.make_sudo_cmd(sudo_user, executable, cmd)
        executable = executable.split()[0] if executable else None

        vvv("EXEC %s" % (local_cmd), host=self.host)
        p = subprocess.Popen(local_cmd, shell=isinstance(local_cmd, basestring),
                             cwd=self.runner.basedir, executable=executable,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE, stderr=subprocess.PIPE)

        if self.runner.sudo and sudoable and self.runner.sudo_pass:
            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)
            sudo_output = ''
            while not sudo_output.endswith(prompt) and success_key not in sudo_output:
                rfd, wfd, efd = select.select([p.stdout, p.stderr], [],
                                              [p.stdout, p.stderr], self.runner.timeout)
                if p.stdout in rfd:
                    chunk = p.stdout.read()
                elif p.stderr in rfd:
                    chunk = p.stderr.read()
                else:
                    stdout, stderr = p.communicate()
                    raise errors.AnsibleError('timeout waiting for sudo password prompt:\n' + sudo_output)
                if not chunk:
                    stdout, stderr = p.communicate()
                    raise errors.AnsibleError('sudo output closed while waiting for password prompt:\n' + sudo_output)
                sudo_output += chunk
            if success_key not in sudo_output:
                p.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.stderr, fcntl.F_SETFL, fcntl.fcntl(p.stderr, fcntl.F_GETFL) & ~os.O_NONBLOCK)

        stdout, stderr = p.communicate()
        return (p.returncode, '', stdout, stderr)
Esempio n. 7
0
    def exec_command(self, cmd, tmp_path, sudo_user=None, sudoable=False, executable='/bin/sh', in_data=None, su=None, su_user=None):
        ''' run a command on the local host '''

        # su requires to be run from a terminal, and therefore isn't supported here (yet?)
        if su or su_user:
            raise errors.AnsibleError("Internal Error: this module does not support running commands via su")

        if in_data:
            raise errors.AnsibleError("Internal Error: this module does not support optimized module pipelining")

        if not self.runner.sudo or not sudoable:
            if executable:
                local_cmd = [executable, '-c', cmd]
            else:
                local_cmd = cmd
        else:
            local_cmd, prompt, success_key = utils.make_sudo_cmd(sudo_user, executable, cmd)

        vvv("EXEC %s" % (local_cmd), host=self.host)
        p = subprocess.Popen(local_cmd, shell=isinstance(local_cmd, basestring),
                             cwd=self.runner.basedir, executable=executable or None,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE, stderr=subprocess.PIPE)

        if self.runner.sudo and sudoable and self.runner.sudo_pass:
            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)
            sudo_output = ''
            while not sudo_output.endswith(prompt) and success_key not in sudo_output:
                rfd, wfd, efd = select.select([p.stdout, p.stderr], [],
                                              [p.stdout, p.stderr], self.runner.timeout)
                if p.stdout in rfd:
                    chunk = p.stdout.read()
                elif p.stderr in rfd:
                    chunk = p.stderr.read()
                else:
                    stdout, stderr = p.communicate()
                    raise errors.AnsibleError('timeout waiting for sudo password prompt:\n' + sudo_output)
                if not chunk:
                    stdout, stderr = p.communicate()
                    raise errors.AnsibleError('sudo output closed while waiting for password prompt:\n' + sudo_output)
                sudo_output += chunk
            if success_key not in sudo_output:
                p.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.stderr, fcntl.F_SETFL, fcntl.fcntl(p.stderr, fcntl.F_GETFL) & ~os.O_NONBLOCK)

        stdout, stderr = p.communicate()
        return (p.returncode, '', stdout, stderr)
Esempio n. 8
0
    def exec_command(self, cmd, tmp_path, sudo_user=None, sudoable=False, executable='/bin/sh', in_data=None, su=None, su_user=None):
        ''' run a command on the remote host '''

        if su or su_user:
            raise AnsibleError("Internal Error: this module does not support running commands via su")

        if in_data:
            raise AnsibleError("Internal Error: this module does not support optimized module pipelining")

        if executable == "":
            executable = constants.DEFAULT_EXECUTABLE

        if self.runner.sudo and sudoable and sudo_user:
            cmd, prompt, success_key = utils.make_sudo_cmd(sudo_user, executable, cmd)

        vvv("EXEC COMMAND %s" % cmd)

        data = dict(
            mode='command',
            cmd=cmd,
            tmp_path=tmp_path,
            executable=executable,
        )
        data = utils.jsonify(data)
        data = utils.encrypt(self.key, data)
        if self.send_data(data):
            raise AnsibleError("Failed to send command to %s" % self.host)
        
        while True:
            # we loop here while waiting for the response, because a 
            # long running command may cause us to receive keepalive packets
            # ({"pong":"true"}) rather than the response we want. 
            response = self.recv_data()
            if not response:
                raise AnsibleError("Failed to get a response from %s" % self.host)
            response = utils.decrypt(self.key, response)
            response = utils.parse_json(response)
            if "pong" in response:
                # it's a keepalive, go back to waiting
                vvvv("%s: received a keepalive packet" % self.host)
                continue
            else:
                vvvv("%s: received the response" % self.host)
                break

        return (response.get('rc',None), '', response.get('stdout',''), response.get('stderr',''))
Esempio n. 9
0
    def exec_command(self, cmd, tmp_path, sudo_user, sudoable=False, executable='/bin/sh'):
        ''' run a command on the local host '''

        if not self.runner.sudo or not sudoable:
            if executable:
                local_cmd = [executable, '-c', cmd]
            else:
                local_cmd = cmd
        else:
            local_cmd, prompt = utils.make_sudo_cmd(sudo_user, executable, cmd)

        vvv("EXEC %s" % (local_cmd), host=self.host)
        p = subprocess.Popen(local_cmd, shell=isinstance(local_cmd, basestring),
                             cwd=self.runner.basedir, executable=executable or None,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE, stderr=subprocess.PIPE)

        if self.runner.sudo and sudoable and self.runner.sudo_pass:
            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)
            sudo_output = ''
            while not sudo_output.endswith(prompt):
                rfd, wfd, efd = select.select([p.stdout, p.stderr], [],
                                              [p.stdout, p.stderr], self.runner.timeout)
                if p.stdout in rfd:
                    chunk = p.stdout.read()
                elif p.stderr in rfd:
                    chunk = p.stderr.read()
                else:
                    stdout, stderr = p.communicate()
                    raise errors.AnsibleError('timeout waiting for sudo password prompt:\n' + sudo_output)
                if not chunk:
                    stdout, stderr = p.communicate()
                    raise errors.AnsibleError('sudo output closed while waiting for password prompt:\n' + sudo_output)
                sudo_output += chunk
            p.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.stderr, fcntl.F_SETFL, fcntl.fcntl(p.stderr, fcntl.F_GETFL) & ~os.O_NONBLOCK)

        stdout, stderr = p.communicate()
        return (p.returncode, '', stdout, stderr)
Esempio n. 10
0
    def exec_command(self, cmd, tmp_path, sudo_user, sudoable=False, executable='/bin/sh', in_data=None, su=None, su_user=None):
        if su or su_user:
            raise errors.AnsibleError("Internal Error: this module does not support running commands via su")

        if in_data:
            raise errors.AnsibleError("Internal Error: this module does not support optimized module pipelining")

        remote_cmd = []
        if not self.runner.sudo or not sudoable:
            if executable:
                remote_cmd.append(executable + ' -c ' + pipes.quote(cmd))
            else:
                remote_cmd.append(cmd)
        else:
            sudocmd, prompt, success_key = utils.make_sudo_cmd(sudo_user, executable, cmd)
            remote_cmd.append(sudocmd)
        remote_cmd = ' '.join(remote_cmd)
        vvv("execnet exec_command %r" % remote_cmd)
        rc, stdout, stderr = self.rpc.exec_command(remote_cmd)
        return (rc, '', stdout, stderr)
Esempio n. 11
0
    def exec_command(self, cmd, tmp_path, sudo_user=None, sudoable=False, executable='/bin/sh', in_data=None, su_user=None, su=False):
        ''' run a command on the remote host '''

        ssh_cmd = self._password_cmd()
        ssh_cmd += ["ssh", "-C"]
        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"]
        if utils.VERBOSITY > 3:
            ssh_cmd += ["-vvv"]
        else:
            ssh_cmd += ["-q"]
        ssh_cmd += self.common_args

        if self.ipv6:
            ssh_cmd += ['-6']
        ssh_cmd += [self.host]

        if su and su_user:
            sudocmd, prompt, success_key = utils.make_su_cmd(su_user, executable, cmd)
            ssh_cmd.append(sudocmd)
        elif not self.runner.sudo or not sudoable:
            prompt = None
            if executable:
                ssh_cmd.append(executable + ' -c ' + pipes.quote(cmd))
            else:
                ssh_cmd.append(cmd)
        else:
            sudocmd, prompt, success_key = utils.make_sudo_cmd(sudo_user, executable, cmd)
            ssh_cmd.append(sudocmd)

        vvv("EXEC %s" % ' '.join(ssh_cmd), host=self.host)

        not_in_host_file = self.not_in_host_file(self.host)

        if C.HOST_KEY_CHECKING and not_in_host_file:
            # lock around the initial SSH connectivity so the user prompt about whether to add 
            # the host to known hosts is not intermingled with multiprocess output.
            fcntl.lockf(self.runner.process_lockfile, fcntl.LOCK_EX)
            fcntl.lockf(self.runner.output_lockfile, fcntl.LOCK_EX)

        # create process
        (p, stdin) = self._run(ssh_cmd, in_data)

        self._send_password()

        no_prompt_out = ''
        no_prompt_err = ''
        if (self.runner.sudo and sudoable and self.runner.sudo_pass) or \
                (self.runner.su and su and self.runner.su_pass):
            (no_prompt_out, no_prompt_err) = self.send_su_sudo_password(p, stdin, success_key, sudoable, prompt)

        com = self.CommunicateCallbacks(self.runner, in_data, su=su, sudoable=sudoable, prompt=prompt)
        returncode = self._communicate(p, stdin, callbacks=(com.stdin_cb, com.stdout_cb, com.stderr_cb))

        if C.HOST_KEY_CHECKING and not_in_host_file:
            # lock around the initial SSH connectivity so the user prompt about whether to add 
            # the host to known hosts is not intermingled with multiprocess output.
            fcntl.lockf(self.runner.output_lockfile, fcntl.LOCK_UN)
            fcntl.lockf(self.runner.process_lockfile, fcntl.LOCK_UN)
        controlpersisterror = 'Bad configuration option: ControlPersist' in com.stderr or \
                              'unknown configuration option: ControlPersist' in com.stderr

        if C.HOST_KEY_CHECKING:
            if ssh_cmd[0] == "sshpass" and p.returncode == 6:
                raise errors.AnsibleError('Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this.  Please add this host\'s fingerprint to your known_hosts file to manage this host.')

        if p.returncode != 0 and controlpersisterror:
            raise errors.AnsibleError('using -c ssh on certain older ssh versions may not support ControlPersist, set ANSIBLE_SSH_ARGS="" (or ssh_args in [ssh_connection] section of the config file) before running again')
        if p.returncode == 255 and (in_data or self.runner.module_name == 'raw'):
            raise errors.AnsibleError('SSH Error: data could not be sent to the remote host. Make sure this host can be reached over ssh')

        return (p.returncode, '', no_prompt_out + com.stdout, no_prompt_err + com.stderr)
Esempio n. 12
0
    def exec_command(self,
                     cmd,
                     tmp_path,
                     sudo_user,
                     sudoable=False,
                     executable='/bin/sh'):
        ''' run a command on the remote host '''

        ssh_cmd = self._password_cmd()
        ssh_cmd += ["ssh", "-tt", "-q"] + self.common_args
        if self.ipv6:
            ssh_cmd += ['-6']
        ssh_cmd += [self.host]

        if not self.runner.sudo or not sudoable:
            if executable:
                ssh_cmd.append(executable + ' -c ' + pipes.quote(cmd))
            else:
                ssh_cmd.append(cmd)
        else:
            sudocmd, prompt = utils.make_sudo_cmd(sudo_user, executable, cmd)
            ssh_cmd.append(sudocmd)

        vvv("EXEC %s" % ssh_cmd, host=self.host)

        dounlocking = False
        if C.HOST_KEY_CHECKING:
            if self.not_in_host_file(self.host):
                dounlocking = True
                # lock around the initial SSH connectivity so the user prompt about whether to add
                # the host to known hosts is not intermingled with multiprocess output.
                fcntl.lockf(self.runner.process_lockfile, fcntl.LOCK_EX)
                fcntl.lockf(self.runner.output_lockfile, fcntl.LOCK_EX)

        try:
            # Make sure stdin is a proper (pseudo) pty to avoid: tcgetattr errors
            import pty
            master, slave = pty.openpty()
            p = subprocess.Popen(ssh_cmd,
                                 stdin=slave,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE)
            stdin = os.fdopen(master, 'w', 0)
        except:
            p = subprocess.Popen(ssh_cmd,
                                 stdin=subprocess.PIPE,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE)
            stdin = p.stdin

        self._send_password()

        if self.runner.sudo and sudoable and self.runner.sudo_pass:
            fcntl.fcntl(p.stdout, fcntl.F_SETFL,
                        fcntl.fcntl(p.stdout, fcntl.F_GETFL) | os.O_NONBLOCK)
            sudo_output = ''
            while not sudo_output.endswith(prompt):
                rfd, wfd, efd = select.select([p.stdout], [], [p.stdout],
                                              self.runner.timeout)
                if p.stdout in rfd:
                    chunk = p.stdout.read()
                    if not chunk:
                        raise errors.AnsibleError(
                            'ssh connection closed waiting for sudo password prompt'
                        )
                    sudo_output += chunk
                else:
                    stdout = p.communicate()
                    raise errors.AnsibleError(
                        'ssh connection error waiting for sudo password prompt'
                    )
            stdin.write(self.runner.sudo_pass + '\n')
            fcntl.fcntl(p.stdout, fcntl.F_SETFL,
                        fcntl.fcntl(p.stdout, fcntl.F_GETFL) & ~os.O_NONBLOCK)

        # We can't use p.communicate here because the ControlMaster may have stdout open as well
        stdout = ''
        stderr = ''
        while True:
            rfd, wfd, efd = select.select([p.stdout, p.stderr], [],
                                          [p.stdout, p.stderr], 1)

            # fail early if the sudo password is wrong
            if self.runner.sudo and sudoable and self.runner.sudo_pass:
                incorrect_password = gettext.dgettext("sudo",
                                                      "Sorry, try again.")
                if stdout.endswith("%s\r\n%s" % (incorrect_password, prompt)):
                    raise errors.AnsibleError('Incorrect sudo password')

            if p.stdout in rfd:
                dat = os.read(p.stdout.fileno(), 9000)
                stdout += dat
                if dat == '':
                    p.wait()
                    break
            elif p.stderr in rfd:
                dat = os.read(p.stderr.fileno(), 9000)
                stderr += dat
                if dat == '':
                    p.wait()
                    break
            elif p.poll() is not None:
                break
        stdin.close(
        )  # close stdin after we read from stdout (see also issue #848)

        if dounlocking:
            fcntl.lockf(self.runner.output_lockfile, fcntl.LOCK_UN)
            fcntl.lockf(self.runner.process_lockfile, fcntl.LOCK_UN)

        if p.returncode != 0 and stderr.find(
                'Bad configuration option: ControlPersist') != -1:
            raise errors.AnsibleError(
                'using -c ssh on certain older ssh versions may not support ControlPersist, set ANSIBLE_SSH_ARGS="" (or ansible_ssh_args in the config file) before running again'
            )

        return (p.returncode, '', stdout, stderr)
Esempio n. 13
0
        if not self.runner.sudo or not sudoable:
            if executable:
                quoted_command = executable + ' -c ' + pipes.quote(cmd)
            else:
                quoted_command = cmd
            vvv("EXEC %s" % quoted_command, host=self.host)
            chan.exec_command(quoted_command)
        else:
            # sudo usually requires a PTY (cf. requiretty option), therefore
            # we give it one, and we try to initialise from the calling
            # environment
            chan.get_pty(term=os.getenv('TERM', 'vt100'),
                         width=int(os.getenv('COLUMNS', 0)),
                         height=int(os.getenv('LINES', 0)))
            shcmd, prompt = utils.make_sudo_cmd(sudo_user, executable, cmd)
            vvv("EXEC %s" % shcmd, host=self.host)
            sudo_output = ''
            try:
                chan.exec_command(shcmd)
                if self.runner.sudo_pass:
                    while not sudo_output.endswith(prompt):
                        chunk = chan.recv(bufsize)
                        if not chunk:
                            if 'unknown user' in sudo_output:
                                raise errors.AnsibleError(
                                    'user %s does not exist' % sudo_user)
                            else:
                                raise errors.AnsibleError(
                                    'ssh connection ' +
                                    'closed waiting for password prompt')
Esempio n. 14
0
    def exec_command(self, cmd, tmp_path, sudo_user, sudoable=False, executable="/bin/sh", in_data=None):
        """ run a command on the remote host """

        ssh_cmd = self._password_cmd()
        ssh_cmd += ["ssh", "-C"]
        if not in_data:
            ssh_cmd += ["-tt"]
        if utils.VERBOSITY > 3:
            ssh_cmd += ["-vvv"]
        else:
            ssh_cmd += ["-q"]
        ssh_cmd += self.common_args

        if self.ipv6:
            ssh_cmd += ["-6"]
        ssh_cmd += [self.host]

        if not self.runner.sudo or not sudoable:
            if executable:
                ssh_cmd.append(executable + " -c " + pipes.quote(cmd))
            else:
                ssh_cmd.append(cmd)
        else:
            sudocmd, prompt, success_key = utils.make_sudo_cmd(sudo_user, executable, cmd)
            ssh_cmd.append(sudocmd)

        vvv("EXEC %s" % ssh_cmd, host=self.host)

        not_in_host_file = self.not_in_host_file(self.host)

        if C.HOST_KEY_CHECKING and not_in_host_file:
            # lock around the initial SSH connectivity so the user prompt about whether to add
            # the host to known hosts is not intermingled with multiprocess output.
            fcntl.lockf(self.runner.process_lockfile, fcntl.LOCK_EX)
            fcntl.lockf(self.runner.output_lockfile, fcntl.LOCK_EX)

        # create process
        if in_data:
            # do not use pseudo-pty
            p = subprocess.Popen(ssh_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            stdin = p.stdin
        else:
            # try to use upseudo-pty
            try:
                # Make sure stdin is a proper (pseudo) pty to avoid: tcgetattr errors
                master, slave = pty.openpty()
                p = subprocess.Popen(ssh_cmd, stdin=slave, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                stdin = os.fdopen(master, "w", 0)
                os.close(slave)
            except:
                p = subprocess.Popen(ssh_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                stdin = p.stdin

        self._send_password()

        if self.runner.sudo and sudoable and self.runner.sudo_pass:
            fcntl.fcntl(p.stdout, fcntl.F_SETFL, fcntl.fcntl(p.stdout, fcntl.F_GETFL) | os.O_NONBLOCK)
            sudo_output = ""
            if in_data:
                # 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:
                rfd, wfd, efd = select.select([p.stdout], [], [p.stdout], self.runner.timeout)
                if p.stdout in rfd:
                    chunk = p.stdout.read()
                    if not chunk:
                        raise errors.AnsibleError("ssh connection closed waiting for sudo password prompt")
                    sudo_output += chunk
                else:
                    stdout = p.communicate()
                    raise errors.AnsibleError("ssh connection error waiting for sudo password prompt")
            if success_key not in sudo_output:
                stdin.write(self.runner.sudo_pass + "\n")
            fcntl.fcntl(p.stdout, fcntl.F_SETFL, fcntl.fcntl(p.stdout, fcntl.F_GETFL) & ~os.O_NONBLOCK)
        # We can't use p.communicate here because the ControlMaster may have stdout open as well
        stdout = ""
        stderr = ""
        rpipes = [p.stdout, p.stderr]
        if in_data:
            try:
                stdin.write(in_data)
                stdin.close()
            except:
                raise errors.AnsibleError(
                    "SSH Error: data could not be sent to the remote host. Make sure this host can be reached over ssh"
                )
        while True:
            rfd, wfd, efd = select.select(rpipes, [], rpipes, 1)

            # fail early if the sudo password is wrong
            if self.runner.sudo and sudoable and self.runner.sudo_pass:
                incorrect_password = gettext.dgettext("sudo", "Sorry, try again.")
                if stdout.endswith("%s\r\n%s" % (incorrect_password, prompt)):
                    raise errors.AnsibleError("Incorrect sudo password")

            if p.stdout in rfd:
                dat = os.read(p.stdout.fileno(), 9000)
                stdout += dat
                if dat == "":
                    rpipes.remove(p.stdout)
            if p.stderr in rfd:
                dat = os.read(p.stderr.fileno(), 9000)
                stderr += dat
                if dat == "":
                    rpipes.remove(p.stderr)
            # only break out if we've emptied the pipes, or there is nothing to
            # read from and the process has finished.
            if (not rpipes or not rfd) and p.poll() is not None:
                break
            # Calling wait while there are still pipes to read can cause a lock
            elif not rpipes and p.poll() == None:
                p.wait()
        stdin.close()  # close stdin after we read from stdout (see also issue #848)

        if C.HOST_KEY_CHECKING and not_in_host_file:
            # lock around the initial SSH connectivity so the user prompt about whether to add
            # the host to known hosts is not intermingled with multiprocess output.
            fcntl.lockf(self.runner.output_lockfile, fcntl.LOCK_UN)
            fcntl.lockf(self.runner.process_lockfile, fcntl.LOCK_UN)
        controlpersisterror = (
            stderr.find("Bad configuration option: ControlPersist") != -1
            or stderr.find("unknown configuration option: ControlPersist") != -1
        )
        if p.returncode != 0 and controlpersisterror:
            raise errors.AnsibleError(
                'using -c ssh on certain older ssh versions may not support ControlPersist, set ANSIBLE_SSH_ARGS="" (or ansible_ssh_args in the config file) before running again'
            )
        if p.returncode == 255 and in_data:
            raise errors.AnsibleError(
                "SSH Error: data could not be sent to the remote host. Make sure this host can be reached over ssh"
            )

        return (p.returncode, "", stdout, stderr)
Esempio n. 15
0
File: ssh.py Progetto: grlee/ansible
    def exec_command(self, cmd, tmp_path, sudo_user=None, sudoable=False, executable='/bin/sh', in_data=None, su_user=None, su=False):
        ''' run a command on the remote host '''

        ssh_cmd = self._password_cmd()
        ssh_cmd += ["ssh", "-C"]
        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"]
        if utils.VERBOSITY > 3:
            ssh_cmd += ["-vvv"]
        else:
            ssh_cmd += ["-q"]
        ssh_cmd += self.common_args

        if self.ipv6:
            ssh_cmd += ['-6']
        ssh_cmd += [self.host]

        if su and su_user:
            sudocmd, prompt, success_key = utils.make_su_cmd(su_user, executable, cmd)
            ssh_cmd.append(sudocmd)
        elif not self.runner.sudo or not sudoable:
            if executable:
                ssh_cmd.append(executable + ' -c ' + pipes.quote(cmd))
            else:
                ssh_cmd.append(cmd)
        else:
            sudocmd, prompt, success_key = utils.make_sudo_cmd(sudo_user, executable, cmd)
            ssh_cmd.append(sudocmd)

        vvv("EXEC %s" % ssh_cmd, host=self.host)

        not_in_host_file = self.not_in_host_file(self.host)

        if C.HOST_KEY_CHECKING and not_in_host_file:
            # lock around the initial SSH connectivity so the user prompt about whether to add 
            # the host to known hosts is not intermingled with multiprocess output.
            fcntl.lockf(self.runner.process_lockfile, fcntl.LOCK_EX)
            fcntl.lockf(self.runner.output_lockfile, fcntl.LOCK_EX)

        # create process
        if in_data:
            # do not use pseudo-pty
            p = subprocess.Popen(ssh_cmd, stdin=subprocess.PIPE,
                                     stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            stdin = p.stdin
        else:
            # try to use upseudo-pty
            try:
                # Make sure stdin is a proper (pseudo) pty to avoid: tcgetattr errors
                master, slave = pty.openpty()
                p = subprocess.Popen(ssh_cmd, stdin=slave,
                                     stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                stdin = os.fdopen(master, 'w', 0)
                os.close(slave)
            except:
                p = subprocess.Popen(ssh_cmd, stdin=subprocess.PIPE,
                                     stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                stdin = p.stdin

        self._send_password()

        if (self.runner.sudo and sudoable and self.runner.sudo_pass) or \
                (self.runner.su and su and self.runner.su_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_GETFL) | os.O_NONBLOCK)
            fcntl.fcntl(p.stderr, fcntl.F_SETFL,
                        fcntl.fcntl(p.stderr, fcntl.F_GETFL) | os.O_NONBLOCK)
            sudo_output = ''
            sudo_errput = ''

            while not sudo_output.endswith(prompt) and success_key not in sudo_output:
                rfd, wfd, efd = select.select([p.stdout, p.stderr], [],
                                              [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 or su 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:
                    chunk = p.stdout.read()
                    if not chunk:
                        raise errors.AnsibleError('ssh connection closed waiting for sudo or su password prompt')
                    sudo_output += chunk

                if not rfd:
                    # timeout. wrap up process communication
                    stdout = p.communicate()
                    raise errors.AnsibleError('ssh connection error waiting for sudo or su password prompt')

            if success_key not in sudo_output:
                if sudoable:
                    stdin.write(self.runner.sudo_pass + '\n')
                elif su:
                    stdin.write(self.runner.su_pass + '\n')
            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
        stdout = ''
        stderr = ''
        rpipes = [p.stdout, p.stderr]
        if in_data:
            try:
                stdin.write(in_data)
                stdin.close()
            except:
                raise errors.AnsibleError('SSH Error: data could not be sent to the remote host. Make sure this host can be reached over ssh')
        while True:
            rfd, wfd, efd = select.select(rpipes, [], rpipes, 1)

            # fail early if the sudo/su password is wrong
            if self.runner.sudo and sudoable and self.runner.sudo_pass:
                incorrect_password = gettext.dgettext(
                    "sudo", "Sorry, try again.")
                if stdout.endswith("%s\r\n%s" % (incorrect_password, prompt)):
                    raise errors.AnsibleError('Incorrect sudo password')

            if self.runner.su and su and self.runner.sudo_pass:
                incorrect_password = gettext.dgettext(
                    "su", "Sorry")
                if stdout.endswith("%s\r\n%s" % (incorrect_password, prompt)):
                    raise errors.AnsibleError('Incorrect su password')

            if p.stdout in rfd:
                dat = os.read(p.stdout.fileno(), 9000)
                stdout += dat
                if dat == '':
                    rpipes.remove(p.stdout)
            if p.stderr in rfd:
                dat = os.read(p.stderr.fileno(), 9000)
                stderr += dat
                if dat == '':
                    rpipes.remove(p.stderr)
            # only break out if we've emptied the pipes, or there is nothing to
            # read from and the process has finished.
            if (not rpipes or not rfd) and p.poll() is not None:
                break
            # Calling wait while there are still pipes to read can cause a lock
            elif not rpipes and p.poll() == None:
                p.wait()
                # the process has finished and the pipes are empty,
                # if we loop and do the select it waits all the timeout
                break
        stdin.close() # close stdin after we read from stdout (see also issue #848)
        
        if C.HOST_KEY_CHECKING and not_in_host_file:
            # lock around the initial SSH connectivity so the user prompt about whether to add 
            # the host to known hosts is not intermingled with multiprocess output.
            fcntl.lockf(self.runner.output_lockfile, fcntl.LOCK_UN)
            fcntl.lockf(self.runner.process_lockfile, fcntl.LOCK_UN)
        controlpersisterror = 'Bad configuration option: ControlPersist' in stderr or \
                              'unknown configuration option: ControlPersist' in stderr

        if C.HOST_KEY_CHECKING:
            if ssh_cmd[0] == "sshpass" and p.returncode == 6:
                raise errors.AnsibleError('Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this.  Please add this host\'s fingerprint to your known_hosts file to manage this host.')

        if p.returncode != 0 and controlpersisterror:
            raise errors.AnsibleError('using -c ssh on certain older ssh versions may not support ControlPersist, set ANSIBLE_SSH_ARGS="" (or ansible_ssh_args in the config file) before running again')
        if p.returncode == 255 and in_data:
            raise errors.AnsibleError('SSH Error: data could not be sent to the remote host. Make sure this host can be reached over ssh')

        return (p.returncode, '', stdout, stderr)
Esempio n. 16
0
            else:
                quoted_command = cmd
            vvv("EXEC %s" % quoted_command, host=self.host)
            chan.exec_command(quoted_command)

        else:

            # sudo usually requires a PTY (cf. requiretty option), therefore
            # we give it one by default (pty=True in ansble.cfg), and we try
            # to initialise from the calling environment
            if C.PARAMIKO_PTY:
                chan.get_pty(term=os.getenv('TERM', 'vt100'),
                             width=int(os.getenv('COLUMNS', 0)),
                             height=int(os.getenv('LINES', 0)))
            if self.runner.sudo or sudoable:
                shcmd, prompt, success_key = utils.make_sudo_cmd(
                    self.runner.sudo_exe, sudo_user, executable, cmd)
            elif self.runner.su or su:
                shcmd, prompt, success_key = utils.make_su_cmd(
                    su_user, executable, cmd)

            vvv("EXEC %s" % shcmd, host=self.host)
            sudo_output = ''

            try:

                chan.exec_command(shcmd)

                if self.runner.sudo_pass or self.runner.su_pass:

                    while True:
Esempio n. 17
0
        if not self.runner.sudo or not sudoable:
            if executable:
                quoted_command = executable + ' -c ' + pipes.quote(cmd)
            else:
                quoted_command = cmd
            vvv("EXEC %s" % quoted_command, host=self.host)
            chan.exec_command(quoted_command)
        else:
            # sudo usually requires a PTY (cf. requiretty option), therefore
            # we give it one, and we try to initialise from the calling
            # environment
            chan.get_pty(term=os.getenv('TERM', 'vt100'),
                         width=int(os.getenv('COLUMNS', 0)),
                         height=int(os.getenv('LINES', 0)))
            shcmd, prompt = utils.make_sudo_cmd(sudo_user, executable, cmd)
            vvv("EXEC %s" % shcmd, host=self.host)
            sudo_output = ''
            try:
                chan.exec_command(shcmd)
                if self.runner.sudo_pass:
                    while not sudo_output.endswith(prompt):
                        chunk = chan.recv(bufsize)
                        if not chunk:
                            if 'unknown user' in sudo_output:
                                raise errors.AnsibleError(
                                    'user %s does not exist' % sudo_user)
                            else:
                                raise errors.AnsibleError('ssh connection ' +
                                    'closed waiting for password prompt')
                        sudo_output += chunk
Esempio n. 18
0
File: ssh.py Progetto: Minione/iwct
    def exec_command(self, cmd, tmp_path, sudo_user,sudoable=False, executable='/bin/sh'):
        ''' run a command on the remote host '''

        ssh_cmd = self._password_cmd()
        ssh_cmd += ["ssh", "-tt", "-q"] + self.common_args + [self.host]

        if not self.runner.sudo or not sudoable:
            if executable:
                ssh_cmd.append(executable + ' -c ' + pipes.quote(cmd))
            else:
                ssh_cmd.append(cmd)
        else:
            sudocmd, prompt = utils.make_sudo_cmd(sudo_user, executable, cmd)
            ssh_cmd.append(sudocmd)

        vvv("EXEC %s" % ssh_cmd, host=self.host)
        try:
            # Make sure stdin is a proper (pseudo) pty to avoid: tcgetattr errors
            import pty
            master, slave = pty.openpty()
            p = subprocess.Popen(ssh_cmd, stdin=slave,
                                 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            stdin = os.fdopen(master, 'w', 0)
        except:
            p = subprocess.Popen(ssh_cmd, stdin=subprocess.PIPE,
                                 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            stdin = p.stdin

        self._send_password()

        if self.runner.sudo and sudoable and self.runner.sudo_pass:
            fcntl.fcntl(p.stdout, fcntl.F_SETFL,
                        fcntl.fcntl(p.stdout, fcntl.F_GETFL) | os.O_NONBLOCK)
            sudo_output = ''
            while not sudo_output.endswith(prompt):
                rfd, wfd, efd = select.select([p.stdout], [],
                                              [p.stdout], self.runner.timeout)
                if p.stdout in rfd:
                    chunk = p.stdout.read()
                    if not chunk:
                        raise errors.AnsibleError('ssh connection closed waiting for sudo password prompt')
                    sudo_output += chunk
                else:
                    stdout = p.communicate()
                    raise errors.AnsibleError('ssh connection error waiting for sudo password prompt')
            stdin.write(self.runner.sudo_pass + '\n')
            fcntl.fcntl(p.stdout, fcntl.F_SETFL, fcntl.fcntl(p.stdout, fcntl.F_GETFL) & ~os.O_NONBLOCK)

        # We can't use p.communicate here because the ControlMaster may have stdout open as well
        stdout = ''
        stderr = ''
        while True:
            rfd, wfd, efd = select.select([p.stdout, p.stderr], [], [p.stdout, p.stderr], 1)
            if p.stdout in rfd:
                dat = os.read(p.stdout.fileno(), 9000)
                stdout += dat
                if dat == '':
                    p.wait()
                    break
            elif p.stderr in rfd:
                dat = os.read(p.stderr.fileno(), 9000)
                stderr += dat
                if dat == '':
                    p.wait()
                    break
            elif p.poll() is not None:
                break
        stdin.close() # close stdin after we read from stdout (see also issue #848)

        if p.returncode != 0 and stderr.find('Bad configuration option: ControlPersist') != -1:
            raise errors.AnsibleError('using -c ssh on certain older ssh versions may not support ControlPersist, set ANSIBLE_SSH_ARGS="" (or ansible_ssh_args in the config file) before running again')

        return (p.returncode, '', stdout, stderr)
Esempio n. 19
0
 if not (self.runner.sudo and sudoable) and not (self.runner.su and su) or in_data:
     if executable:
         quoted_command = executable + ' -c ' + pipes.quote(cmd)
     else:
         quoted_command = cmd
     vvv("EXEC ALT no-tty %s" % quoted_command, host=self.host)
     chan.exec_command(quoted_command)
 else:
     # sudo usually requires a PTY (cf. requiretty option), therefore
     # we give it one by default (pty=True in ansble.cfg), and we try
     # to initialise from the calling environment
     if C.PARAMIKO_PTY:
         chan.get_pty(term=os.getenv('TERM', 'vt100'),
                      width=int(os.getenv('COLUMNS', 0)),
                      height=int(os.getenv('LINES', 0)))
     shcmd, prompt, success_key = utils.make_sudo_cmd(sudo_user, executable, cmd)
     vvv("EXEC %s" % shcmd, host=self.host)
     sudo_output = ''
     try:
         chan.exec_command(shcmd)
         if self.runner.sudo_pass or self.runner.su_pass:
             while not sudo_output.endswith(prompt) and success_key not in sudo_output:
                 chunk = chan.recv(bufsize)
                 if not chunk:
                     if 'unknown user' in sudo_output:
                         raise errors.AnsibleError(
                             'user %s does not exist' % sudo_user)
                     else:
                         raise errors.AnsibleError('ssh connection ' +
                             'closed waiting for password prompt')
                 sudo_output += chunk
Esempio n. 20
0
    def exec_command(self, cmd, tmp_path, sudo_user,sudoable=False, executable='/bin/sh', in_data=None):
        ''' run a command on the remote host '''

        ssh_cmd = self._password_cmd()
        ssh_cmd += ["ssh", "-C"]
        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"]
        if utils.VERBOSITY > 3:
            ssh_cmd += ["-vvv"]
        else:
            ssh_cmd += ["-q"]
        ssh_cmd += self.common_args

        if self.ipv6:
            ssh_cmd += ['-6']
        ssh_cmd += [self.host]

        if not self.runner.sudo or not sudoable:
            if executable:
                ssh_cmd.append(executable + ' -c ' + pipes.quote(cmd))
            else:
                ssh_cmd.append(cmd)
        else:
            sudocmd, prompt, success_key = utils.make_sudo_cmd(sudo_user, executable, cmd)
            ssh_cmd.append(sudocmd)

        vvv("EXEC %s" % ssh_cmd, host=self.host)

        not_in_host_file = self.not_in_host_file(self.host)

        if C.HOST_KEY_CHECKING and not_in_host_file:
            # lock around the initial SSH connectivity so the user prompt about whether to add 
            # the host to known hosts is not intermingled with multiprocess output.
            fcntl.lockf(self.runner.process_lockfile, fcntl.LOCK_EX)
            fcntl.lockf(self.runner.output_lockfile, fcntl.LOCK_EX)
        
        # create process
        if in_data:
            # do not use pseudo-pty
            p = subprocess.Popen(ssh_cmd, stdin=subprocess.PIPE,
                                     stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            stdin = p.stdin
        else:
            # try to use upseudo-pty
            try:
                # Make sure stdin is a proper (pseudo) pty to avoid: tcgetattr errors
                master, slave = pty.openpty()
                p = subprocess.Popen(ssh_cmd, stdin=slave,
                                     stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                stdin = os.fdopen(master, 'w', 0)
                os.close(slave)
            except:
                p = subprocess.Popen(ssh_cmd, stdin=subprocess.PIPE,
                                     stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                stdin = p.stdin

        self._send_password()

        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_GETFL) | os.O_NONBLOCK)
            fcntl.fcntl(p.stderr, fcntl.F_SETFL,
                        fcntl.fcntl(p.stderr, fcntl.F_GETFL) | os.O_NONBLOCK)
            sudo_output = ''
            sudo_errput = ''

            while not sudo_output.endswith(prompt) and success_key not in sudo_output:
                rfd, wfd, efd = select.select([p.stdout, p.stderr], [],
                                              [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:
                    chunk = p.stdout.read()
                    if not chunk:
                        raise errors.AnsibleError('ssh connection closed waiting for sudo password prompt')
                    sudo_output += chunk

                if not rfd:
                    # timeout. wrap up process communication
                    stdout = p.communicate()
                    raise errors.AnsibleError('ssh connection error waiting for sudo password prompt')

            if success_key not in sudo_output:
                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.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
        stdout = ''
        stderr = ''
        rpipes = [p.stdout, p.stderr]
        if in_data:
            try:
                stdin.write(in_data)
                stdin.close()
            except:
                raise errors.AnsibleError('SSH Error: data could not be sent to the remote host. Make sure this host can be reached over ssh')
        while True:
            rfd, wfd, efd = select.select(rpipes, [], rpipes, 1)

            # fail early if the sudo password is wrong
            if self.runner.sudo and sudoable and self.runner.sudo_pass:
                incorrect_password = gettext.dgettext(
                    "sudo", "Sorry, try again.")
                if stdout.endswith("%s\r\n%s" % (incorrect_password, prompt)):
                    raise errors.AnsibleError('Incorrect sudo password') 

            if p.stdout in rfd:
                dat = os.read(p.stdout.fileno(), 9000)
                stdout += dat
                if dat == '':
                    rpipes.remove(p.stdout)
            if p.stderr in rfd:
                dat = os.read(p.stderr.fileno(), 9000)
                stderr += dat
                if dat == '':
                    rpipes.remove(p.stderr)
            # only break out if we've emptied the pipes, or there is nothing to
            # read from and the process has finished.
            if (not rpipes or not rfd) and p.poll() is not None:
                break
            # Calling wait while there are still pipes to read can cause a lock
            elif not rpipes and p.poll() == None:
                p.wait()
        stdin.close() # close stdin after we read from stdout (see also issue #848)
        
        if C.HOST_KEY_CHECKING and not_in_host_file:
            # lock around the initial SSH connectivity so the user prompt about whether to add 
            # the host to known hosts is not intermingled with multiprocess output.
            fcntl.lockf(self.runner.output_lockfile, fcntl.LOCK_UN)
            fcntl.lockf(self.runner.process_lockfile, fcntl.LOCK_UN)
        controlpersisterror = stderr.find('Bad configuration option: ControlPersist') != -1 or stderr.find('unknown configuration option: ControlPersist') != -1
        if p.returncode != 0 and controlpersisterror:
            raise errors.AnsibleError('using -c ssh on certain older ssh versions may not support ControlPersist, set ANSIBLE_SSH_ARGS="" (or ansible_ssh_args in the config file) before running again')
        if p.returncode == 255 and in_data:
            raise errors.AnsibleError('SSH Error: data could not be sent to the remote host. Make sure this host can be reached over ssh')

        return (p.returncode, '', stdout, stderr)
Esempio n. 21
0
            else:
                quoted_command = cmd
            vvv("EXEC %s" % quoted_command, host=self.host)
            chan.exec_command(quoted_command)

        else:

            # sudo usually requires a PTY (cf. requiretty option), therefore
            # we give it one by default (pty=True in ansble.cfg), and we try
            # to initialise from the calling environment
            if C.PARAMIKO_PTY:
                chan.get_pty(term=os.getenv('TERM', 'vt100'),
                             width=int(os.getenv('COLUMNS', 0)),
                             height=int(os.getenv('LINES', 0)))
            if self.runner.sudo or sudoable:
                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 = ''

            try:

                chan.exec_command(shcmd)

                if self.runner.sudo_pass or self.runner.su_pass:

                    while True:
Esempio n. 22
0
    def exec_command(self,
                     cmd,
                     tmp_path,
                     sudo_user=None,
                     sudoable=False,
                     executable='/bin/sh',
                     in_data=None,
                     su=False,
                     su_user=None):
        ''' run a command on the remote host '''

        if in_data:
            raise errors.AnsibleError(
                "Internal Error: this module does not support optimized module pipelining"
            )

        ssh_cmd = self._password_cmd()
        ssh_cmd += ["ssh", "-tt"]
        if utils.VERBOSITY > 3:
            ssh_cmd += ["-vvv"]
        else:
            ssh_cmd += ["-q"]
        ssh_cmd += self.common_args

        if self.ipv6:
            ssh_cmd += ['-6']
        ssh_cmd += [self.host]

        if su and su_user:
            sudocmd, prompt, success_key = utils.make_su_cmd(
                su_user, executable, cmd)
            ssh_cmd.append(sudocmd)
        elif not self.runner.sudo or not sudoable:
            if executable:
                ssh_cmd.append(executable + ' -c ' + pipes.quote(cmd))
            else:
                ssh_cmd.append(cmd)
        else:
            sudocmd, prompt, success_key = utils.make_sudo_cmd(
                sudo_user, executable, cmd)
            ssh_cmd.append(sudocmd)

        vvv("EXEC %s" % ssh_cmd, host=self.host)

        not_in_host_file = self.not_in_host_file(self.host)

        if C.HOST_KEY_CHECKING and not_in_host_file:
            # lock around the initial SSH connectivity so the user prompt about whether to add
            # the host to known hosts is not intermingled with multiprocess output.
            fcntl.lockf(self.runner.process_lockfile, fcntl.LOCK_EX)
            fcntl.lockf(self.runner.output_lockfile, fcntl.LOCK_EX)

        try:
            # Make sure stdin is a proper (pseudo) pty to avoid: tcgetattr errors
            master, slave = pty.openpty()
            p = subprocess.Popen(ssh_cmd,
                                 stdin=slave,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE)
            stdin = os.fdopen(master, 'w', 0)
            os.close(slave)
        except:
            p = subprocess.Popen(ssh_cmd,
                                 stdin=subprocess.PIPE,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE)
            stdin = p.stdin

        self._send_password()

        if (self.runner.sudo and sudoable and self.runner.sudo_pass) or \
                (self.runner.su and su and self.runner.su_pass):
            fcntl.fcntl(p.stdout, fcntl.F_SETFL,
                        fcntl.fcntl(p.stdout, fcntl.F_GETFL) | os.O_NONBLOCK)
            sudo_output = ''
            while not sudo_output.endswith(
                    prompt) and success_key not in sudo_output:
                rfd, wfd, efd = select.select([p.stdout], [], [p.stdout],
                                              self.runner.timeout)
                if p.stdout in rfd:
                    chunk = p.stdout.read()
                    if not chunk:
                        raise errors.AnsibleError(
                            'ssh connection closed waiting for sudo or su password prompt'
                        )
                    sudo_output += chunk
                else:
                    stdout = p.communicate()
                    raise errors.AnsibleError(
                        'ssh connection error waiting for sudo or su password prompt'
                    )

            if success_key not in sudo_output:
                if sudoable:
                    stdin.write(self.runner.sudo_pass + '\n')
                elif su:
                    stdin.write(self.runner.su_pass + '\n')
            fcntl.fcntl(p.stdout, fcntl.F_SETFL,
                        fcntl.fcntl(p.stdout, fcntl.F_GETFL) & ~os.O_NONBLOCK)

        # We can't use p.communicate here because the ControlMaster may have stdout open as well
        stdout = ''
        stderr = ''
        rpipes = [p.stdout, p.stderr]
        while True:
            rfd, wfd, efd = select.select(rpipes, [], rpipes, 1)

            # fail early if the sudo/su password is wrong
            if self.runner.sudo and sudoable and self.runner.sudo_pass:
                incorrect_password = gettext.dgettext("sudo",
                                                      "Sorry, try again.")
                if stdout.endswith("%s\r\n%s" % (incorrect_password, prompt)):
                    raise errors.AnsibleError('Incorrect sudo password')

            if self.runner.su and su and self.runner.su_pass:
                incorrect_password = gettext.dgettext(
                    "su", "su: Authentication failure")
                if stdout.endswith("%s\r\n%s" % (incorrect_password, prompt)):
                    raise errors.AnsibleError('Incorrect su password')

            if p.stdout in rfd:
                dat = os.read(p.stdout.fileno(), 9000)
                stdout += dat
                if dat == '':
                    rpipes.remove(p.stdout)
            if p.stderr in rfd:
                dat = os.read(p.stderr.fileno(), 9000)
                stderr += dat
                if dat == '':
                    rpipes.remove(p.stderr)
            # only break out if we've emptied the pipes, or there is nothing to
            # read from and the process has finished.
            if (not rpipes or not rfd) and p.poll() is not None:
                break
            # Calling wait while there are still pipes to read can cause a lock
            elif not rpipes and p.poll() == None:
                p.wait()
                # the process has finished and the pipes are empty,
                # if we loop and do the select it waits all the timeout
                break
        stdin.close(
        )  # close stdin after we read from stdout (see also issue #848)

        if C.HOST_KEY_CHECKING and not_in_host_file:
            # lock around the initial SSH connectivity so the user prompt about whether to add
            # the host to known hosts is not intermingled with multiprocess output.
            fcntl.lockf(self.runner.output_lockfile, fcntl.LOCK_UN)
            fcntl.lockf(self.runner.process_lockfile, fcntl.LOCK_UN)

        if C.HOST_KEY_CHECKING:
            if ssh_cmd[0] == "sshpass" and p.returncode == 6:
                raise errors.AnsibleError(
                    'Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this.  Please add this host\'s fingerprint to your known_hosts file to manage this host.'
                )

        controlpersisterror = stderr.find(
            'Bad configuration option: ControlPersist') != -1 or stderr.find(
                'unknown configuration option: ControlPersist') != -1
        if p.returncode != 0 and controlpersisterror:
            raise errors.AnsibleError(
                'using -c ssh on certain older ssh versions may not support ControlPersist, set ANSIBLE_SSH_ARGS="" (or ansible_ssh_args in the config file) before running again'
            )

        return (p.returncode, '', stdout, stderr)
Esempio n. 23
0
    def exec_command(self,
                     cmd,
                     tmp_path,
                     sudo_user=None,
                     sudoable=False,
                     executable='/bin/sh',
                     in_data=None,
                     su=None,
                     su_user=None):
        ''' run a command on the remote host '''

        if in_data:
            raise errors.AnsibleError(
                "Internal Error: this module does not support optimized module pipelining"
            )

        bufsize = 4096

        try:

            self.ssh.get_transport().set_keepalive(5)
            chan = self.ssh.get_transport().open_session()

        except Exception as e:

            msg = "Failed to open session"
            if len(str(e)) > 0:
                msg += ": %s" % str(e)
            raise errors.AnsibleConnectionFailed(msg)

        no_prompt_out = ''
        no_prompt_err = ''
        if not (self.runner.sudo and sudoable) and not (self.runner.su and su):

            if executable:
                quoted_command = executable + ' -c ' + pipes.quote(cmd)
            else:
                quoted_command = cmd
            vvv("EXEC %s" % quoted_command, host=self.host)
            chan.exec_command(quoted_command)

        else:

            # sudo usually requires a PTY (cf. requiretty option), therefore
            # we give it one by default (pty=True in ansble.cfg), and we try
            # to initialise from the calling environment
            if C.PARAMIKO_PTY:
                chan.get_pty(term=os.getenv('TERM', 'vt100'),
                             width=int(os.getenv('COLUMNS', 0)),
                             height=int(os.getenv('LINES', 0)))
            if self.runner.sudo or sudoable:
                shcmd, prompt, success_key = utils.make_sudo_cmd(
                    self.runner.sudo_exe, sudo_user, executable, cmd)
            elif self.runner.su or su:
                shcmd, prompt, success_key = utils.make_su_cmd(
                    su_user, executable, cmd)

            vvv("EXEC %s" % shcmd, host=self.host)
            sudo_output = ''

            try:

                chan.exec_command(shcmd)

                if self.runner.sudo_pass or self.runner.su_pass:

                    while True:

                        if success_key in sudo_output or \
                            (self.runner.sudo_pass and sudo_output.endswith(prompt)) or \
                            (self.runner.su_pass and utils.su_prompts.check_su_prompt(sudo_output)):
                            break
                        chunk = chan.recv(bufsize)

                        if not chunk:
                            if 'unknown user' in sudo_output:
                                raise errors.AnsibleError(
                                    'user %s does not exist' % sudo_user)
                            else:
                                raise errors.AnsibleError(
                                    'ssh connection ' +
                                    'closed waiting for password prompt')
                        sudo_output += chunk

                    if success_key not in sudo_output:

                        if sudoable:
                            chan.sendall(self.runner.sudo_pass + '\n')
                        elif su:
                            chan.sendall(self.runner.su_pass + '\n')
                    else:
                        no_prompt_out += sudo_output
                        no_prompt_err += sudo_output

            except socket.timeout:

                raise errors.AnsibleError('ssh timed out waiting for sudo.\n' +
                                          sudo_output)

        stdout = ''.join(chan.makefile('rb', bufsize))
        stderr = ''.join(chan.makefile_stderr('rb', bufsize))

        return (chan.recv_exit_status(), '', no_prompt_out + stdout,
                no_prompt_out + stderr)
Esempio n. 24
0
File: ssh.py Progetto: heathkh/iwct
    def exec_command(self,
                     cmd,
                     tmp_path,
                     sudo_user,
                     sudoable=False,
                     executable='/bin/sh'):
        ''' run a command on the remote host '''

        ssh_cmd = self._password_cmd()
        ssh_cmd += ["ssh", "-tt", "-q"] + self.common_args + [self.host]

        if not self.runner.sudo or not sudoable:
            if executable:
                ssh_cmd.append(executable + ' -c ' + pipes.quote(cmd))
            else:
                ssh_cmd.append(cmd)
        else:
            sudocmd, prompt = utils.make_sudo_cmd(sudo_user, executable, cmd)
            ssh_cmd.append(sudocmd)

        vvv("EXEC %s" % ssh_cmd, host=self.host)
        try:
            # Make sure stdin is a proper (pseudo) pty to avoid: tcgetattr errors
            import pty
            master, slave = pty.openpty()
            p = subprocess.Popen(ssh_cmd,
                                 stdin=slave,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE)
            stdin = os.fdopen(master, 'w', 0)
        except:
            p = subprocess.Popen(ssh_cmd,
                                 stdin=subprocess.PIPE,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE)
            stdin = p.stdin

        self._send_password()

        if self.runner.sudo and sudoable and self.runner.sudo_pass:
            fcntl.fcntl(p.stdout, fcntl.F_SETFL,
                        fcntl.fcntl(p.stdout, fcntl.F_GETFL) | os.O_NONBLOCK)
            sudo_output = ''
            while not sudo_output.endswith(prompt):
                rfd, wfd, efd = select.select([p.stdout], [], [p.stdout],
                                              self.runner.timeout)
                if p.stdout in rfd:
                    chunk = p.stdout.read()
                    if not chunk:
                        raise errors.AnsibleError(
                            'ssh connection closed waiting for sudo password prompt'
                        )
                    sudo_output += chunk
                else:
                    stdout = p.communicate()
                    raise errors.AnsibleError(
                        'ssh connection error waiting for sudo password prompt'
                    )
            stdin.write(self.runner.sudo_pass + '\n')
            fcntl.fcntl(p.stdout, fcntl.F_SETFL,
                        fcntl.fcntl(p.stdout, fcntl.F_GETFL) & ~os.O_NONBLOCK)

        # We can't use p.communicate here because the ControlMaster may have stdout open as well
        stdout = ''
        stderr = ''
        while True:
            rfd, wfd, efd = select.select([p.stdout, p.stderr], [],
                                          [p.stdout, p.stderr], 1)
            if p.stdout in rfd:
                dat = os.read(p.stdout.fileno(), 9000)
                stdout += dat
                if dat == '':
                    p.wait()
                    break
            elif p.stderr in rfd:
                dat = os.read(p.stderr.fileno(), 9000)
                stderr += dat
                if dat == '':
                    p.wait()
                    break
            elif p.poll() is not None:
                break
        stdin.close(
        )  # close stdin after we read from stdout (see also issue #848)

        if p.returncode != 0 and stderr.find(
                'Bad configuration option: ControlPersist') != -1:
            raise errors.AnsibleError(
                'using -c ssh on certain older ssh versions may not support ControlPersist, set ANSIBLE_SSH_ARGS="" (or ansible_ssh_args in the config file) before running again'
            )

        return (p.returncode, '', stdout, stderr)
Esempio n. 25
0
            else:
                quoted_command = cmd
            vvv("EXEC %s" % quoted_command, host=self.host)
            chan.exec_command(quoted_command)

        else:

            # sudo usually requires a PTY (cf. requiretty option), therefore
            # we give it one by default (pty=True in ansble.cfg), and we try
            # to initialise from the calling environment
            if C.PARAMIKO_PTY:
                chan.get_pty(term=os.getenv('TERM', 'vt100'),
                             width=int(os.getenv('COLUMNS', 0)),
                             height=int(os.getenv('LINES', 0)))
            if self.runner.sudo or sudoable:
                shcmd, prompt, success_key = utils.make_sudo_cmd(self.runner.sudo_exe, sudo_user, executable, cmd)
            elif self.runner.su or su:
                shcmd, prompt, success_key = utils.make_su_cmd(su_user, executable, cmd)

            vvv("EXEC %s" % shcmd, host=self.host)
            sudo_output = ''

            try:

                chan.exec_command(shcmd)

                if self.runner.sudo_pass or self.runner.su_pass:

                    while True:

                        if success_key in sudo_output or \
Esempio n. 26
0
    def exec_command(self,
                     cmd,
                     tmp_path,
                     sudo_user=None,
                     sudoable=False,
                     executable='/bin/sh',
                     in_data=None,
                     su_user=None,
                     su=False):
        ''' run a command on the remote host '''

        ssh_cmd = self._password_cmd()
        ssh_cmd += ["ssh", "-C"]
        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"]
        if utils.VERBOSITY > 3:
            ssh_cmd += ["-vvv"]
        else:
            ssh_cmd += ["-q"]
        ssh_cmd += self.common_args

        if self.ipv6:
            ssh_cmd += ['-6']
        #ssh_cmd += [self.host]
        ssh_cmd += [self.sliver_name]

        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
            if executable:
                ssh_cmd.append(executable + ' -c ' + pipes.quote(cmd))
            else:
                ssh_cmd.append(cmd)
        else:
            sudocmd, prompt, success_key = utils.make_sudo_cmd(
                sudo_user, executable, cmd)
            ssh_cmd.append(sudocmd)

        vvv("EXEC %s" % ssh_cmd, host=self.host)

        not_in_host_file = self.not_in_host_file(self.host)

        if C.HOST_KEY_CHECKING and not_in_host_file:
            # lock around the initial SSH connectivity so the user prompt about whether to add
            # the host to known hosts is not intermingled with multiprocess output.
            fcntl.lockf(self.runner.process_lockfile, fcntl.LOCK_EX)
            fcntl.lockf(self.runner.output_lockfile, fcntl.LOCK_EX)

        # create process
        (p, stdin) = self._run(ssh_cmd, in_data)

        self._send_password()

        if (self.runner.sudo and sudoable and self.runner.sudo_pass) or \
                (self.runner.su and su and self.runner.su_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_GETFL) | os.O_NONBLOCK)
            fcntl.fcntl(p.stderr, fcntl.F_SETFL,
                        fcntl.fcntl(p.stderr, fcntl.F_GETFL) | os.O_NONBLOCK)
            sudo_output = ''
            sudo_errput = ''

            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], [],
                                              [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 or su 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:
                    chunk = p.stdout.read()
                    if not chunk:
                        raise errors.AnsibleError(
                            'ssh connection closed waiting for sudo or su password prompt'
                        )
                    sudo_output += chunk

                if not rfd:
                    # timeout. wrap up process communication
                    stdout = p.communicate()
                    raise errors.AnsibleError(
                        'ssh connection error waiting for sudo or su password prompt'
                    )

            if success_key not in sudo_output:
                if sudoable:
                    stdin.write(self.runner.sudo_pass + '\n')
                elif su:
                    stdin.write(self.runner.su_pass + '\n')

        (returncode, stdout, stderr) = self._communicate(p,
                                                         stdin,
                                                         in_data,
                                                         su=su,
                                                         sudoable=sudoable,
                                                         prompt=prompt)

        if C.HOST_KEY_CHECKING and not_in_host_file:
            # lock around the initial SSH connectivity so the user prompt about whether to add
            # the host to known hosts is not intermingled with multiprocess output.
            fcntl.lockf(self.runner.output_lockfile, fcntl.LOCK_UN)
            fcntl.lockf(self.runner.process_lockfile, fcntl.LOCK_UN)
        controlpersisterror = 'Bad configuration option: ControlPersist' in stderr or \
                              'unknown configuration option: ControlPersist' in stderr

        if C.HOST_KEY_CHECKING:
            if ssh_cmd[0] == "sshpass" and p.returncode == 6:
                raise errors.AnsibleError(
                    'Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this.  Please add this host\'s fingerprint to your known_hosts file to manage this host.'
                )

        if p.returncode != 0 and controlpersisterror:
            raise errors.AnsibleError(
                'using -c ssh on certain older ssh versions may not support ControlPersist, set ANSIBLE_SSH_ARGS="" (or ssh_args in [ssh_connection] section of the config file) before running again'
            )
        if p.returncode == 255 and (in_data
                                    or self.runner.module_name == 'raw'):
            raise errors.AnsibleError(
                'SSH Error: data could not be sent to the remote host. Make sure this host can be reached over ssh'
            )

        return (p.returncode, '', stdout, stderr)
Esempio n. 27
0
    def exec_command(
        self, cmd, tmp_path, sudo_user=None, sudoable=False, executable="/bin/sh", in_data=None, su_user=None, su=False
    ):
        """ run a command on the remote host """

        ssh_cmd = self._password_cmd()
        ssh_cmd += ["ssh", "-C"]
        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"]
        if utils.VERBOSITY > 3:
            ssh_cmd += ["-vvv"]
        else:
            ssh_cmd += ["-q"]
        ssh_cmd += self.common_args

        if self.ipv6:
            ssh_cmd += ["-6"]
        ssh_cmd += [self.host]

        if su and su_user:
            sudocmd, prompt, success_key = utils.make_su_cmd(su_user, executable, cmd)
            ssh_cmd.append(sudocmd)
        elif not self.runner.sudo or not sudoable:
            prompt = None
            if executable:
                ssh_cmd.append(executable + " -c " + pipes.quote(cmd))
            else:
                ssh_cmd.append(cmd)
        else:
            sudocmd, prompt, success_key = utils.make_sudo_cmd(self.runner.sudo_exe, sudo_user, executable, cmd)
            ssh_cmd.append(sudocmd)

        vvv("EXEC %s" % " ".join(ssh_cmd), host=self.host)

        not_in_host_file = self.not_in_host_file(self.host)

        if C.HOST_KEY_CHECKING and not_in_host_file:
            # lock around the initial SSH connectivity so the user prompt about whether to add
            # the host to known hosts is not intermingled with multiprocess output.
            fcntl.lockf(self.runner.process_lockfile, fcntl.LOCK_EX)
            fcntl.lockf(self.runner.output_lockfile, fcntl.LOCK_EX)

        # create process
        (p, stdin) = self._run(ssh_cmd, in_data)

        self._send_password()

        no_prompt_out = ""
        no_prompt_err = ""
        if (self.runner.sudo and sudoable and self.runner.sudo_pass) or (self.runner.su and su and self.runner.su_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_GETFL) | os.O_NONBLOCK)
            fcntl.fcntl(p.stderr, fcntl.F_SETFL, fcntl.fcntl(p.stderr, fcntl.F_GETFL) | os.O_NONBLOCK)
            sudo_output = ""
            sudo_errput = ""

            while True:
                if (
                    success_key in sudo_output
                    or (self.runner.sudo_pass and sudo_output.endswith(prompt))
                    or (self.runner.su_pass and utils.su_prompts.check_su_prompt(sudo_output))
                ):
                    break

                rfd, wfd, efd = select.select([p.stdout, p.stderr], [], [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 or su 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 prompt and sudo_errput.endswith(prompt):
                        stdin.write(self.runner.sudo_pass + "\n")

                if p.stdout in rfd:
                    chunk = p.stdout.read()
                    if not chunk:
                        raise errors.AnsibleError("ssh connection closed waiting for sudo or su password prompt")
                    sudo_output += chunk

                if not rfd:
                    # timeout. wrap up process communication
                    stdout = p.communicate()
                    raise errors.AnsibleError("ssh connection error waiting for sudo or su password prompt")

            if success_key not in sudo_output:
                if sudoable:
                    stdin.write(self.runner.sudo_pass + "\n")
                elif su:
                    stdin.write(self.runner.su_pass + "\n")
            else:
                no_prompt_out += sudo_output
                no_prompt_err += sudo_errput

        (returncode, stdout, stderr) = self._communicate(p, stdin, in_data, su=su, sudoable=sudoable, prompt=prompt)

        if C.HOST_KEY_CHECKING and not_in_host_file:
            # lock around the initial SSH connectivity so the user prompt about whether to add
            # the host to known hosts is not intermingled with multiprocess output.
            fcntl.lockf(self.runner.output_lockfile, fcntl.LOCK_UN)
            fcntl.lockf(self.runner.process_lockfile, fcntl.LOCK_UN)
        controlpersisterror = (
            "Bad configuration option: ControlPersist" in stderr
            or "unknown configuration option: ControlPersist" in stderr
        )

        if C.HOST_KEY_CHECKING:
            if ssh_cmd[0] == "sshpass" and p.returncode == 6:
                raise errors.AnsibleError(
                    "Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this.  Please add this host's fingerprint to your known_hosts file to manage this host."
                )

        if p.returncode != 0 and controlpersisterror:
            raise errors.AnsibleError(
                'using -c ssh on certain older ssh versions may not support ControlPersist, set ANSIBLE_SSH_ARGS="" (or ssh_args in [ssh_connection] section of the config file) before running again'
            )
        if p.returncode == 255 and (in_data or self.runner.module_name == "raw"):
            raise errors.AnsibleError(
                "SSH Error: data could not be sent to the remote host. Make sure this host can be reached over ssh"
            )

        return (p.returncode, "", no_prompt_out + stdout, no_prompt_err + stderr)
Esempio n. 28
0
    def exec_command(self, cmd, tmp_path, sudo_user,sudoable=False, executable='/bin/sh'):
        ''' run a command on the remote host '''

        ssh_cmd = self._password_cmd()
        ssh_cmd += ["ssh", "-tt"]
        if utils.VERBOSITY > 3:
            ssh_cmd += ["-vvv"]
        else:
            ssh_cmd += ["-q"]
        ssh_cmd += self.common_args

        if self.ipv6:
            ssh_cmd += ['-6']
        ssh_cmd += [self.host]

        if not self.runner.sudo or not sudoable:
            if executable:
                ssh_cmd.append(executable + ' -c ' + pipes.quote(cmd))
            else:
                ssh_cmd.append(cmd)
        else:
            sudocmd, prompt = utils.make_sudo_cmd(sudo_user, executable, cmd)
            ssh_cmd.append(sudocmd)

        vvv("EXEC %s" % ssh_cmd, host=self.host)

        not_in_host_file = self.not_in_host_file(self.host)

        if C.HOST_KEY_CHECKING and not_in_host_file:
            # lock around the initial SSH connectivity so the user prompt about whether to add 
            # the host to known hosts is not intermingled with multiprocess output.
            fcntl.lockf(self.runner.process_lockfile, fcntl.LOCK_EX)
            fcntl.lockf(self.runner.output_lockfile, fcntl.LOCK_EX)
        


        try:
            # Make sure stdin is a proper (pseudo) pty to avoid: tcgetattr errors
            master, slave = pty.openpty()
            p = subprocess.Popen(ssh_cmd, stdin=slave,
                                 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            stdin = os.fdopen(master, 'w', 0)
            os.close(slave)
        except:
            p = subprocess.Popen(ssh_cmd, stdin=subprocess.PIPE,
                                 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            stdin = p.stdin

        self._send_password()

        if self.runner.sudo and sudoable and self.runner.sudo_pass:
            fcntl.fcntl(p.stdout, fcntl.F_SETFL,
                        fcntl.fcntl(p.stdout, fcntl.F_GETFL) | os.O_NONBLOCK)
            sudo_output = ''
            while not sudo_output.endswith(prompt):
                rfd, wfd, efd = select.select([p.stdout], [],
                                              [p.stdout], self.runner.timeout)
                if p.stdout in rfd:
                    chunk = p.stdout.read()
                    if not chunk:
                        raise errors.AnsibleError('ssh connection closed waiting for sudo password prompt')
                    sudo_output += chunk
                else:
                    stdout = p.communicate()
                    raise errors.AnsibleError('ssh connection error waiting for sudo password prompt')
            stdin.write(self.runner.sudo_pass + '\n')
            fcntl.fcntl(p.stdout, fcntl.F_SETFL, fcntl.fcntl(p.stdout, fcntl.F_GETFL) & ~os.O_NONBLOCK)

        # We can't use p.communicate here because the ControlMaster may have stdout open as well
        stdout = ''
        stderr = ''
        while True:
            rfd, wfd, efd = select.select([p.stdout, p.stderr], [], [p.stdout, p.stderr], 1)

            # fail early if the sudo password is wrong
            if self.runner.sudo and sudoable and self.runner.sudo_pass:
                incorrect_password = gettext.dgettext(
                    "sudo", "Sorry, try again.")
                if stdout.endswith("%s\r\n%s" % (incorrect_password, prompt)):
                    raise errors.AnsibleError('Incorrect sudo password') 

            if p.stdout in rfd:
                dat = os.read(p.stdout.fileno(), 9000)
                stdout += dat
                if dat == '':
                    p.wait()
                    break
            elif p.stderr in rfd:
                dat = os.read(p.stderr.fileno(), 9000)
                stderr += dat
                if dat == '':
                    p.wait()
                    break
            elif p.poll() is not None:
                break
        stdin.close() # close stdin after we read from stdout (see also issue #848)
        
        if C.HOST_KEY_CHECKING and not_in_host_file:
            # lock around the initial SSH connectivity so the user prompt about whether to add 
            # the host to known hosts is not intermingled with multiprocess output.
            fcntl.lockf(self.runner.output_lockfile, fcntl.LOCK_UN)
            fcntl.lockf(self.runner.process_lockfile, fcntl.LOCK_UN)

        if p.returncode != 0 and stderr.find('Bad configuration option: ControlPersist') != -1:
            raise errors.AnsibleError('using -c ssh on certain older ssh versions may not support ControlPersist, set ANSIBLE_SSH_ARGS="" (or ansible_ssh_args in the config file) before running again')

        return (p.returncode, '', stdout, stderr)