Beispiel #1
0
    def fetch_file(self, in_path, out_path):
        ''' fetch a file from lxc to local '''
        super(Connection, self).fetch_file(in_path, out_path)
        self._display.vvv("FETCH %s TO %s" % (in_path, out_path), host=self.container_name)
        in_path = to_bytes(in_path, errors='surrogate_or_strict')
        out_path = to_bytes(out_path, errors='surrogate_or_strict')

        try:
            dst_file = open(out_path, "wb")
        except IOError:
            traceback.print_exc()
            msg = "failed to open output file %s" % out_path
            raise errors.AnsibleError(msg)
        try:
            def write_file(args):
                try:
                    with open(in_path, 'rb') as src_file:
                        shutil.copyfileobj(src_file, dst_file)
                finally:
                    # this is needed in the lxc child process
                    # to flush internal python buffers
                    dst_file.close()
            try:
                self.container.attach_wait(write_file, None)
            except IOError:
                traceback.print_exc()
                msg = "failed to transfer file from %s to %s" % (in_path, out_path)
                raise errors.AnsibleError(msg)
        finally:
            dst_file.close()
Beispiel #2
0
    def ask_vault_passwords(ask_new_vault_pass=False, rekey=False):
        ''' prompt for vault password and/or password change '''

        vault_pass = None
        new_vault_pass = None
        try:
            if rekey or not ask_new_vault_pass:
                vault_pass = getpass.getpass(prompt="Vault password: "******"New Vault password: "******"Confirm New Vault password: "******"Passwords do not match")
        except EOFError:
            pass

        # enforce no newline chars at the end of passwords
        if vault_pass:
            vault_pass = to_bytes(vault_pass, errors='strict', nonstring='simplerepr').strip()
        if new_vault_pass:
            new_vault_pass = to_bytes(new_vault_pass, errors='strict', nonstring='simplerepr').strip()

        if ask_new_vault_pass and not rekey:
            vault_pass = new_vault_pass

        return vault_pass, new_vault_pass
Beispiel #3
0
    def put_file(self, in_path, out_path):
        ''' transfer a file from local to lxc '''
        super(Connection, self).put_file(in_path, out_path)
        self._display.vvv("PUT %s TO %s" % (in_path, out_path), host=self.container_name)
        in_path = to_bytes(in_path, errors='surrogate_or_strict')
        out_path = to_bytes(out_path, errors='surrogate_or_strict')

        if not os.path.exists(in_path):
            msg = "file or module does not exist: %s" % in_path
            raise errors.AnsibleFileNotFound(msg)
        try:
            src_file = open(in_path, "rb")
        except IOError:
            traceback.print_exc()
            raise errors.AnsibleError("failed to open input file to %s" % in_path)
        try:
            def write_file(args):
                with open(out_path, 'wb+') as dst_file:
                    shutil.copyfileobj(src_file, dst_file)
            try:
                self.container.attach_wait(write_file, None)
            except IOError:
                traceback.print_exc()
                msg = "failed to transfer file to %s" % out_path
                raise errors.AnsibleError(msg)
        finally:
            src_file.close()
    def test_plugins_connection_ssh_fetch_file(self):
        pc = PlayContext()
        new_stdin = StringIO()
        conn = ssh.Connection(pc, new_stdin)
        conn._build_command = MagicMock()
        conn._run = MagicMock()

        conn._build_command.return_value = 'some command to run'
        conn._run.return_value = (0, '', '')
        conn.host = "some_host"

        # test with C.DEFAULT_SCP_IF_SSH enabled
        C.DEFAULT_SCP_IF_SSH = True
        conn.fetch_file('/path/to/in/file', '/path/to/dest/file')
        conn._run.assert_called_with('some command to run', None)

        conn.fetch_file(u'/path/to/in/file/with/unicode-fö〩', u'/path/to/dest/file/with/unicode-fö〩')
        conn._run.assert_called_with('some command to run', None)

        # test with C.DEFAULT_SCP_IF_SSH disabled
        C.DEFAULT_SCP_IF_SSH = False
        expected_in_data = b' '.join((b'get', to_bytes(pipes.quote('/path/to/in/file')), to_bytes(pipes.quote('/path/to/dest/file')))) + b'\n'
        conn.fetch_file('/path/to/in/file', '/path/to/dest/file')
        conn._run.assert_called_with('some command to run', expected_in_data)

        expected_in_data = b' '.join((b'get',
            to_bytes(pipes.quote('/path/to/in/file/with/unicode-fö〩')),
            to_bytes(pipes.quote('/path/to/dest/file/with/unicode-fö〩')))) + b'\n'
        conn.fetch_file(u'/path/to/in/file/with/unicode-fö〩', u'/path/to/dest/file/with/unicode-fö〩')
        conn._run.assert_called_with('some command to run', expected_in_data)

        # test that a non-zero rc raises an error
        conn._run.return_value = (1, 'stdout', 'some errors')
        self.assertRaises(AnsibleError, conn.fetch_file, '/path/to/bad/file', '/remote/path/to/file')
Beispiel #5
0
    def encrypt(self, b_plaintext, b_password):
        b_salt = os.urandom(32)
        b_key1, b_key2, b_iv = self._gen_key_initctr(b_password, b_salt)

        # PKCS#7 PAD DATA http://tools.ietf.org/html/rfc5652#section-6.3
        bs = AES.block_size
        padding_length = (bs - len(b_plaintext) % bs) or bs
        b_plaintext += to_bytes(padding_length * chr(padding_length), encoding='ascii', errors='strict')

        # COUNTER.new PARAMETERS
        # 1) nbits (integer) - Length of the counter, in bits.
        # 2) initial_value (integer) - initial value of the counter. "iv" from _gen_key_initctr

        ctr = Counter.new(128, initial_value=int(b_iv, 16))

        # AES.new PARAMETERS
        # 1) AES key, must be either 16, 24, or 32 bytes long -- "key" from _gen_key_initctr
        # 2) MODE_CTR, is the recommended mode
        # 3) counter=<CounterObject>

        cipher = AES.new(b_key1, AES.MODE_CTR, counter=ctr)

        # ENCRYPT PADDED DATA
        b_ciphertext = cipher.encrypt(b_plaintext)

        # COMBINE SALT, DIGEST AND DATA
        hmac = HMAC.new(b_key2, b_ciphertext, SHA256)
        b_vaulttext = b'\n'.join([hexlify(b_salt), to_bytes(hmac.hexdigest()), hexlify(b_ciphertext)])
        b_vaulttext = hexlify(b_vaulttext)
        return b_vaulttext
    def test_edit_file_with_vault_id(self, mock_sp_call):
        self._test_dir = self._create_test_dir()
        src_contents = to_bytes("some info in a file\nyup.")

        src_file_path = self._create_file(self._test_dir, 'src_file', content=src_contents)

        new_src_contents = to_bytes("The info is different now.")

        def faux_editor(editor_args):
            self._faux_editor(editor_args, new_src_contents)

        mock_sp_call.side_effect = faux_editor

        ve = self._vault_editor()

        ve.encrypt_file(src_file_path, self.vault_secret,
                        vault_id='vault_secrets')
        ve.edit_file(src_file_path)

        new_src_file = open(src_file_path, 'rb')
        new_src_file_contents = new_src_file.read()

        self.assertTrue(b'$ANSIBLE_VAULT;1.2;AES256;vault_secrets' in new_src_file_contents)

        src_file_plaintext = ve.vault.decrypt(new_src_file_contents)
        self.assertEqual(src_file_plaintext, new_src_contents)
    def test_edit_file_symlink(self, mock_sp_call):
        self._test_dir = self._create_test_dir()
        src_contents = to_bytes("some info in a file\nyup.")

        src_file_path = self._create_file(self._test_dir, 'src_file', content=src_contents)

        new_src_contents = to_bytes("The info is different now.")

        def faux_editor(editor_args):
            self._faux_editor(editor_args, new_src_contents)

        mock_sp_call.side_effect = faux_editor

        ve = self._vault_editor()

        ve.encrypt_file(src_file_path, self.vault_secret)

        src_file_link_path = os.path.join(self._test_dir, 'a_link_to_dest_file')

        os.symlink(src_file_path, src_file_link_path)

        ve.edit_file(src_file_link_path)

        new_src_file = open(src_file_path, 'rb')
        new_src_file_contents = new_src_file.read()

        src_file_plaintext = ve.vault.decrypt(new_src_file_contents)

        self._assert_file_is_link(src_file_link_path, src_file_path)

        self.assertEqual(src_file_plaintext, new_src_contents)
Beispiel #8
0
    def rekey_file(self, filename, new_vault_secret, new_vault_id=None):

        # follow the symlink
        filename = self._real_path(filename)

        prev = os.stat(filename)
        b_vaulttext = self.read_data(filename)
        vaulttext = to_text(b_vaulttext)

        try:
            plaintext = self.vault.decrypt(vaulttext)
        except AnsibleError as e:
            raise AnsibleError("%s for %s" % (to_bytes(e), to_bytes(filename)))

        # This is more or less an assert, see #18247
        if new_vault_secret is None:
            raise AnsibleError('The value for the new_password to rekey %s with is not valid' % filename)

        # FIXME: VaultContext...?  could rekey to a different vault_id in the same VaultSecrets

        # Need a new VaultLib because the new vault data can be a different
        # vault lib format or cipher (for ex, when we migrate 1.0 style vault data to
        # 1.1 style data we change the version and the cipher). This is where a VaultContext might help

        # the new vault will only be used for encrypting, so it doesn't need the vault secrets
        # (we will pass one in directly to encrypt)
        new_vault = VaultLib(secrets={})
        b_new_vaulttext = new_vault.encrypt(plaintext, new_vault_secret, vault_id=new_vault_id)

        self.write_data(b_new_vaulttext, filename)

        # preserve permissions
        os.chmod(filename, prev.st_mode)
        os.chown(filename, prev.st_uid, prev.st_gid)
Beispiel #9
0
    def ask_passwords(self):
        """ prompt for connection and become passwords if needed """

        op = self.options
        sshpass = None
        becomepass = None
        become_prompt = ""

        try:
            if op.ask_pass:
                sshpass = getpass.getpass(prompt="SSH password: "******"%s password[defaults to SSH password]: " % op.become_method.upper()
                if sshpass:
                    sshpass = to_bytes(sshpass, errors="strict", nonstring="simplerepr")
            else:
                become_prompt = "%s password: "******"":
                    becomepass = sshpass
                if becomepass:
                    becomepass = to_bytes(becomepass)
        except EOFError:
            pass

        return (sshpass, becomepass)
Beispiel #10
0
    def edit_file(self, filename):

        # follow the symlink
        filename = self._real_path(filename)

        b_vaulttext = self.read_data(filename)

        # vault or yaml files are always utf8
        vaulttext = to_text(b_vaulttext)

        try:
            # vaulttext gets converted back to bytes, but alas
            plaintext = self.vault.decrypt(vaulttext)
        except AnsibleError as e:
            raise AnsibleError("%s for %s" % (to_bytes(e), to_bytes(filename)))

        # Figure out the vault id from the file, to select the right secret to re-encrypt it
        # (duplicates parts of decrypt, but alas...)
        dummy, dummy, cipher_name, vault_id = parse_vaulttext_envelope(b_vaulttext)

        # if we could decrypt, the vault_id should be in secrets
        # though we could have multiple secrets for a given vault_id, pick the first one
        secrets = match_secrets(self.vault.secrets, [vault_id])
        secret = secrets[0][1]
        if cipher_name not in CIPHER_WRITE_WHITELIST:
            # we want to get rid of files encrypted with the AES cipher
            self._edit_file_helper(filename, secret, existing_data=plaintext, force_save=True)
        else:
            self._edit_file_helper(filename, secret, existing_data=plaintext, force_save=False)
Beispiel #11
0
    def _encrypt_pycrypto(b_plaintext, b_key1, b_key2, b_iv):
        # PKCS#7 PAD DATA http://tools.ietf.org/html/rfc5652#section-6.3
        bs = AES_pycrypto.block_size
        padding_length = (bs - len(b_plaintext) % bs) or bs
        b_plaintext += to_bytes(padding_length * chr(padding_length), encoding='ascii', errors='strict')

        # COUNTER.new PARAMETERS
        # 1) nbits (integer) - Length of the counter, in bits.
        # 2) initial_value (integer) - initial value of the counter. "iv" from _gen_key_initctr

        ctr = Counter_pycrypto.new(128, initial_value=int(b_iv, 16))

        # AES.new PARAMETERS
        # 1) AES key, must be either 16, 24, or 32 bytes long -- "key" from _gen_key_initctr
        # 2) MODE_CTR, is the recommended mode
        # 3) counter=<CounterObject>

        cipher = AES_pycrypto.new(b_key1, AES_pycrypto.MODE_CTR, counter=ctr)

        # ENCRYPT PADDED DATA
        b_ciphertext = cipher.encrypt(b_plaintext)

        # COMBINE SALT, DIGEST AND DATA
        hmac = HMAC_pycrypto.new(b_key2, b_ciphertext, SHA256_pycrypto)

        return to_bytes(hmac.hexdigest(), errors='surrogate_or_strict'), hexlify(b_ciphertext)
Beispiel #12
0
    def fetch_file(self, in_path, out_path):
        """ Fetch a file from container to local. """
        super(Connection, self).fetch_file(in_path, out_path)
        display.vvv("FETCH %s TO %s" % (in_path, out_path), host=self._play_context.remote_addr)

        in_path = self._prefix_login_path(in_path)
        out_dir = os.path.dirname(out_path)

        # kubectl doesn't have native support for fetching files from
        # running containers, so we use kubectl exec to implement this
        args = self._build_exec_cmd([self._play_context.executable, "-c", "dd if=%s bs=%s" % (in_path, BUFSIZE)])
        args = [to_bytes(i, errors='surrogate_or_strict') for i in args]
        actual_out_path = os.path.join(out_dir, os.path.basename(in_path))
        with open(to_bytes(actual_out_path, errors='surrogate_or_strict'), 'wb') as out_file:
            try:
                p = subprocess.Popen(args, stdin=subprocess.PIPE,
                                     stdout=out_file, stderr=subprocess.PIPE)
            except OSError:
                raise AnsibleError(
                    "{0} connection requires dd command in the container to fetch files".format(self.transport)
                )
            stdout, stderr = p.communicate()

            if p.returncode != 0:
                raise AnsibleError("failed to fetch file %s to %s:\n%s\n%s" % (in_path, out_path, stdout, stderr))

        if actual_out_path != out_path:
            os.rename(to_bytes(actual_out_path, errors='strict'), to_bytes(out_path, errors='strict'))
Beispiel #13
0
    def exec_command(self, request):
        """Sends the request to the node and returns the reply
        The method accepts two forms of request.  The first form is as a byte
        string that represents xml string be send over netconf session.
        The second form is a json-rpc (2.0) byte string.
        """
        try:
            obj = json.loads(to_text(request, errors='surrogate_or_strict'))

            if 'jsonrpc' in obj:
                if self._netconf:
                    out = self._exec_rpc(obj)
                else:
                    out = self.internal_error("netconf plugin is not supported for network_os %s" % self._play_context.network_os)
                return 0, to_bytes(out, errors='surrogate_or_strict'), b''
            else:
                err = self.invalid_request(obj)
                return 1, b'', to_bytes(err, errors='surrogate_or_strict')

        except (ValueError, TypeError):
            # to_ele operates on native strings
            request = to_native(request, errors='surrogate_or_strict')

        req = to_ele(request)
        if req is None:
            return 1, b'', b'unable to parse request'

        try:
            reply = self._manager.rpc(req)
        except RPCError as exc:
            return 1, b'', to_bytes(to_xml(exc.xml), errors='surrogate_or_strict')

        return 0, to_bytes(reply.data_xml, errors='surrogate_or_strict'), b''
Beispiel #14
0
    def ask_passwords(self):
        ''' prompt for connection and become passwords if needed '''

        op = self.options
        sshpass = None
        becomepass = None
        become_prompt = ''

        become_prompt_method = "BECOME" if C.AGNOSTIC_BECOME_PROMPT else op.become_method.upper()

        try:
            if op.ask_pass:
                sshpass = getpass.getpass(prompt="SSH password: "******"%s password[defaults to SSH password]: " % become_prompt_method
                if sshpass:
                    sshpass = to_bytes(sshpass, errors='strict', nonstring='simplerepr')
            else:
                become_prompt = "%s password: " % become_prompt_method

            if op.become_ask_pass:
                becomepass = getpass.getpass(prompt=become_prompt)
                if op.ask_pass and becomepass == '':
                    becomepass = sshpass
                if becomepass:
                    becomepass = to_bytes(becomepass)
        except EOFError:
            pass

        return (sshpass, becomepass)
Beispiel #15
0
    def test_file_encrypted(self):
        vault_password = "******"
        text_secret = TextVaultSecret(vault_password)
        vault_secrets = [('foo', text_secret)]

        password = '******'
        # 'some password' encrypted with 'test-ansible-password'

        password_file_content = '''$ANSIBLE_VAULT;1.1;AES256
61393863643638653437313566313632306462383837303132346434616433313438353634613762
3334363431623364386164616163326537366333353663650a663634306232363432626162353665
39623061353266373631636331643761306665343731376633623439313138396330346237653930
6432643864346136640a653364386634666461306231353765636662316335613235383565306437
3737
'''

        tmp_file = tempfile.NamedTemporaryFile(delete=False)
        tmp_file.write(to_bytes(password_file_content))
        tmp_file.close()

        fake_loader = DictDataLoader({tmp_file.name: 'sdfadf'})
        fake_loader._vault.secrets = vault_secrets

        secret = vault.FileVaultSecret(loader=fake_loader, filename=tmp_file.name)
        secret.load()

        os.unlink(tmp_file.name)

        self.assertEqual(secret.bytes, to_bytes(password))
Beispiel #16
0
def user_should_we_change_password(current_role_attrs, user, password, encrypted):
    """Check if we should change the user's password.

    Compare the proposed password with the existing one, comparing
    hashes if encrypted. If we can't access it assume yes.
    """

    if current_role_attrs is None:
        # on some databases, E.g. AWS RDS instances, there is no access to
        # the pg_authid relation to check the pre-existing password, so we
        # just assume password is different
        return True

    # Do we actually need to do anything?
    pwchanging = False
    if password is not None:
        # 32: MD5 hashes are represented as a sequence of 32 hexadecimal digits
        #  3: The size of the 'md5' prefix
        # When the provided password looks like a MD5-hash, value of
        # 'encrypted' is ignored.
        if ((password.startswith('md5') and len(password) == 32 + 3) or encrypted == 'UNENCRYPTED'):
            if password != current_role_attrs['rolpassword']:
                pwchanging = True
        elif encrypted == 'ENCRYPTED':
            hashed_password = '******'.format(md5(to_bytes(password) + to_bytes(user)).hexdigest())
            if hashed_password != current_role_attrs['rolpassword']:
                pwchanging = True

    return pwchanging
Beispiel #17
0
    def __init__(self, conf_file=None, defs_file=None):

        self._base_defs = {}
        self._plugins = {}
        self._parsers = {}

        self._config_file = conf_file
        self.data = ConfigData()

        if defs_file is None:
            # Create configuration definitions from source
            b_defs_file = to_bytes('%s/base.yml' % os.path.dirname(__file__))
        else:
            b_defs_file = to_bytes(defs_file)

        # consume definitions
        if os.path.exists(b_defs_file):
            with open(b_defs_file, 'rb') as config_def:
                self._base_defs = yaml_load(config_def, Loader=SafeLoader)
        else:
            raise AnsibleError("Missing base configuration definition file (bad install?): %s" % to_native(b_defs_file))

        if self._config_file is None:
            # set config using ini
            self._config_file = find_ini_config_file()

        # consume configuration
        if self._config_file:
            if os.path.exists(self._config_file):
                # initialize parser and read config
                self._parse_config_file()

        # update constants
        self.update_config_data()
Beispiel #18
0
    def run(self, terms, variables, **kwargs):
        ret = []

        for term in terms:
            relpath, params = _parse_parameters(term)
            path = self._loader.path_dwim(relpath)
            b_path = to_bytes(path, errors='surrogate_or_strict')
            chars = _gen_candidate_chars(params['chars'])

            changed = False
            content = _read_password_file(b_path)

            if content is None or b_path == to_bytes('/dev/null'):
                plaintext_password = random_password(params['length'], chars)
                salt = None
                changed = True
            else:
                plaintext_password, salt = _parse_content(content)

            if params['encrypt'] and not salt:
                changed = True
                salt = _random_salt()

            if changed and b_path != to_bytes('/dev/null'):
                content = _format_content(plaintext_password, salt, encrypt=params['encrypt'])
                _write_password_file(b_path, content)

            if params['encrypt']:
                password = do_encrypt(plaintext_password, params['encrypt'], salt=salt)
                ret.append(password)
            else:
                ret.append(plaintext_password)

        return ret
Beispiel #19
0
    def find_vars_files(self, path, name, extensions=None, allow_dir=True):
        """
        Find vars files in a given path with specified name. This will find
        files in a dir named <name>/ or a file called <name> ending in known
        extensions.
        """

        b_path = to_bytes(os.path.join(path, name))
        found = []

        if extensions is None:
            # Look for file with no extension first to find dir before file
            extensions = [''] + C.YAML_FILENAME_EXTENSIONS
        # add valid extensions to name
        for ext in extensions:

            if '.' in ext:
                full_path = b_path + to_bytes(ext)
            elif ext:
                full_path = b'.'.join([b_path, to_bytes(ext)])
            else:
                full_path = b_path

            if self.path_exists(full_path):
                if self.is_directory(full_path):
                    if allow_dir:
                        found.extend(self._get_dir_vars_files(to_text(full_path), extensions))
                    else:
                        next
                else:
                    found.append(full_path)
                break
        return found
Beispiel #20
0
    def put_file(self, in_path, out_path):
        """ Transfer a file from local to docker container """
        super(Connection, self).put_file(in_path, out_path)
        display.vvv("PUT %s TO %s" % (in_path, out_path), host=self._play_context.remote_addr)

        out_path = self._prefix_login_path(out_path)
        if not os.path.exists(to_bytes(in_path, errors='surrogate_or_strict')):
            raise AnsibleFileNotFound(
                "file or module does not exist: %s" % in_path)

        out_path = shlex_quote(out_path)
        # Older docker doesn't have native support for copying files into
        # running containers, so we use docker exec to implement this
        # Although docker version 1.8 and later provide support, the
        # owner and group of the files are always set to root
        args = self._build_exec_cmd([self._play_context.executable, "-c", "dd of=%s bs=%s" % (out_path, BUFSIZE)])
        args = [to_bytes(i, errors='surrogate_or_strict') for i in args]
        with open(to_bytes(in_path, errors='surrogate_or_strict'), 'rb') as in_file:
            try:
                p = subprocess.Popen(args, stdin=in_file,
                        stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            except OSError:
                raise AnsibleError("docker connection requires dd command in the container to put files")
            stdout, stderr = p.communicate()

            if p.returncode != 0:
                raise AnsibleError("failed to transfer file %s to %s:\n%s\n%s" % (in_path, out_path, stdout, stderr))
Beispiel #21
0
        def _check_subject(csr):
            subject = [(OpenSSL._util.lib.OBJ_txt2nid(to_bytes(sub[0])), to_bytes(sub[1])) for sub in self.subject]
            current_subject = [(OpenSSL._util.lib.OBJ_txt2nid(to_bytes(sub[0])), to_bytes(sub[1])) for sub in csr.get_subject().get_components()]
            if not set(subject) == set(current_subject):
                return False

            return True
Beispiel #22
0
    def _find_vars_files(self, path, name):
        """ Find {group,host}_vars files """

        b_path = to_bytes(os.path.join(path, name))
        found = []

        # first look for w/o extensions
        if os.path.exists(b_path):
            if os.path.isdir(b_path):
                found.extend(self._get_dir_files(to_text(b_path)))
            else:
                found.append(b_path)
        else:
            # add valid extensions to name
            for ext in C.YAML_FILENAME_EXTENSIONS:

                if '.' in ext:
                    full_path = b_path + to_bytes(ext)
                elif ext:
                    full_path = b'.'.join([b_path, to_bytes(ext)])
                else:
                    full_path = b_path

                if os.path.exists(full_path) and os.path.isfile(full_path):
                    found.append(full_path)
                    break
        return found
Beispiel #23
0
    def read_vault_password_file(self, vault_password_file):
        """
        Read a vault password from a file or if executable, execute the script and
        retrieve password from STDOUT
        """

        this_path = os.path.realpath(to_bytes(os.path.expanduser(vault_password_file), errors='surrogate_or_strict'))
        if not os.path.exists(to_bytes(this_path, errors='surrogate_or_strict')):
            raise AnsibleFileNotFound("The vault password file %s was not found" % this_path)

        if self.is_executable(this_path):
            try:
                # STDERR not captured to make it easier for users to prompt for input in their scripts
                p = subprocess.Popen(this_path, stdout=subprocess.PIPE)
            except OSError as e:
                raise AnsibleError("Problem running vault password script %s (%s)."
                        " If this is not a script, remove the executable bit from the file." % (' '.join(this_path), to_native(e)))
            stdout, stderr = p.communicate()
            self.set_vault_password(stdout.strip('\r\n'))
        else:
            try:
                f = open(this_path, "rb")
                self.set_vault_password(f.read().strip())
                f.close()
            except (OSError, IOError) as e:
                raise AnsibleError("Could not read vault password file %s: %s" % (this_path, e))
Beispiel #24
0
def modify_module(module_name, module_path, module_args, task_vars=None, module_compression='ZIP_STORED', async_timeout=0, become=False,
                  become_method=None, become_user=None, become_password=None, environment=None):
    """
    Used to insert chunks of code into modules before transfer rather than
    doing regular python imports.  This allows for more efficient transfer in
    a non-bootstrapping scenario by not moving extra files over the wire and
    also takes care of embedding arguments in the transferred modules.

    This version is done in such a way that local imports can still be
    used in the module code, so IDEs don't have to be aware of what is going on.

    Example:

    from ansible.module_utils.basic import *

       ... will result in the insertion of basic.py into the module
       from the module_utils/ directory in the source tree.

    For powershell, this code effectively no-ops, as the exec wrapper requires access to a number of
    properties not available here.

    """
    task_vars = {} if task_vars is None else task_vars
    environment = {} if environment is None else environment

    with open(module_path, 'rb') as f:

        # read in the module source
        b_module_data = f.read()

    (b_module_data, module_style, shebang) = _find_module_utils(module_name, b_module_data, module_path, module_args, task_vars, module_compression,
                                                                async_timeout=async_timeout, become=become, become_method=become_method,
                                                                become_user=become_user, become_password=become_password,
                                                                environment=environment)

    if module_style == 'binary':
        return (b_module_data, module_style, to_text(shebang, nonstring='passthru'))
    elif shebang is None:
        lines = b_module_data.split(b"\n", 1)
        if lines[0].startswith(b"#!"):
            shebang = lines[0].strip()
            args = shlex.split(str(shebang[2:]))
            interpreter = args[0]
            interpreter = to_bytes(interpreter)

            new_shebang = to_bytes(_get_shebang(interpreter, task_vars, args[1:])[0], errors='surrogate_or_strict', nonstring='passthru')
            if new_shebang:
                lines[0] = shebang = new_shebang

            if os.path.basename(interpreter).startswith(b'python'):
                lines.insert(1, to_bytes(ENCODING_STRING))
        else:
            # No shebang, assume a binary module?
            pass

        b_module_data = b"\n".join(lines)
    else:
        shebang = to_bytes(shebang, errors='surrogate_or_strict')

    return (b_module_data, module_style, to_text(shebang, nonstring='passthru'))
Beispiel #25
0
    def exec_command(self, cmd, in_data=None, sudoable=True):
        super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable)
        cmd_parts = self._shell._encode_script(cmd, as_list=True, strict_mode=False, preserve_rc=False)

        # TODO: display something meaningful here
        display.vvv("EXEC (via pipeline wrapper)")

        stdin_iterator = None

        if in_data:
            stdin_iterator = self._wrapper_payload_stream(in_data)

        result = self._winrm_exec(cmd_parts[0], cmd_parts[1:], from_exec=True, stdin_iterator=stdin_iterator)

        result.std_out = to_bytes(result.std_out)
        result.std_err = to_bytes(result.std_err)

        # parse just stderr from CLIXML output
        if self.is_clixml(result.std_err):
            try:
                result.std_err = self.parse_clixml_stream(result.std_err)
            except Exception:
                # unsure if we're guaranteed a valid xml doc- use raw output in case of error
                pass

        return (result.status_code, result.std_out, result.std_err)
Beispiel #26
0
    def test_is_equal_non_ascii_unequal(self):
        utf8_data = to_bytes(u'私はガラスを食べられます。それは私を傷つけません。')
        utf8_data2 = to_bytes(u'Pot să mănânc sticlă și ea nu mă rănește.')

        # Test for the len optimization path
        self.assertFalse(self.vault_cipher._is_equal(utf8_data, utf8_data2))
        # Test for the slower, char by char comparison path
        self.assertFalse(self.vault_cipher._is_equal(utf8_data, utf8_data[:-1] + b'P'))
Beispiel #27
0
 def get_host(self, macaddr):
     msg = OmapiMessage.open(to_bytes("host", errors='surrogate_or_strict'))
     msg.obj.append((to_bytes("hardware-address", errors='surrogate_or_strict'), pack_mac(macaddr)))
     msg.obj.append((to_bytes("hardware-type", errors='surrogate_or_strict'), struct.pack("!I", 1)))
     response = self.omapi.query_server(msg)
     if response.opcode != OMAPI_OP_UPDATE:
         return None
     return response
def fabric_ansible_display(self, msg, color=None, stderr=False,
                           screen_only=False, log_only=False):
    """ Display a message to the user

    Note: msg *must* be a unicode string to prevent UnicodeError tracebacks.
    """

    nocolor = msg
    if color:
        msg = stringc(msg, color)

    if not log_only:
        if not msg.endswith(u'\n'):
            msg2 = msg + u'\n'
        else:
            msg2 = msg

        msg2 = to_bytes(msg2, encoding=self._output_encoding(stderr=stderr))
        if sys.version_info >= (3,):
            # Convert back to text string on python3
            # We first convert to a byte string so that we get rid of
            # characters that are invalid in the user's locale
            msg2 = to_text(msg2, self._output_encoding(stderr=stderr),
                           errors='replace')

        # Note: After Display() class is refactored need to update the
        # log capture code in 'bin/ansible-connection' (and other
        # relevant places).
        if not stderr:
            fileobj = sys.stdout
        else:
            fileobj = sys.stderr

        fileobj.write(msg2)

        try:
            fileobj.flush()
        except IOError as e:
            # Ignore EPIPE in case fileobj has been prematurely closed, eg.
            # when piping to "head -n1"
            if e.errno != errno.EPIPE:
                raise

    if logger:
        msg2 = nocolor.lstrip(u'\n')

        msg2 = to_bytes(msg2)
        if sys.version_info >= (3,):
            # Convert back to text string on python3
            # We first convert to a byte string so that we get rid of
            # characters that are invalid in the user's locale
            msg2 = to_text(msg2, self._output_encoding(stderr=stderr))

        if color == CONST.COLOR_ERROR:
            logger.error(msg2)
        else:
            logger.info(msg2)
Beispiel #29
0
def print_modules(module, category_file, deprecated, options, env, template, outputname, module_map, aliases):
    modstring = module
    if modstring.startswith('_'):
        modstring = module[1:]
    modname = modstring
    if module in deprecated:
        modstring = modstring + DEPRECATED

    category_file.write("  %s - %s <%s_module>\n" % (to_bytes(modstring), to_bytes(rst_ify(module_map[module][1])), to_bytes(modname)))
Beispiel #30
0
def absent(module, dest, regexp, line, backup):

    b_dest = to_bytes(dest, errors='surrogate_or_strict')
    if not os.path.exists(b_dest):
        module.exit_json(changed=False, msg="file not present")

    msg = ''
    diff = {'before': '',
            'after': '',
            'before_header': '%s (content)' % dest,
            'after_header': '%s (content)' % dest}

    f = open(b_dest, 'rb')
    b_lines = f.readlines()
    f.close()

    if module._diff:
        diff['before'] = to_native(b('').join(b_lines))

    if regexp is not None:
        bre_c = re.compile(to_bytes(regexp, errors='surrogate_or_strict'))
    found = []

    b_line = to_bytes(line, errors='surrogate_or_strict')
    def matcher(b_cur_line):
        if regexp is not None:
            match_found = bre_c.search(b_cur_line)
        else:
            match_found = b_line == b_cur_line.rstrip(b('\r\n'))
        if match_found:
            found.append(b_cur_line)
        return not match_found

    b_lines = [l for l in b_lines if matcher(l)]
    changed = len(found) > 0

    if module._diff:
        diff['after'] = to_native(b('').join(b_lines))

    backupdest = ""
    if changed and not module.check_mode:
        if backup:
            backupdest = module.backup_local(dest)
        write_changes(module, b_lines, dest)

    if changed:
        msg = "%s line(s) removed" % len(found)

    attr_diff = {}
    msg, changed = check_file_attrs(module, changed, msg, attr_diff)

    attr_diff['before_header'] = '%s (file attributes)' % dest
    attr_diff['after_header'] = '%s (file attributes)' % dest

    difflist = [diff, attr_diff]

    module.exit_json(changed=changed, found=len(found), msg=msg, backup=backupdest, diff=difflist)
Beispiel #31
0
def set_module_args(args):
    """prepare arguments so that they will be picked up during module creation"""
    args = json.dumps({"ANSIBLE_MODULE_ARGS": args})
    basic._ANSIBLE_ARGS = to_bytes(args)  # pylint: disable=protected-access
Beispiel #32
0
 def detect_su_prompt(b_data):
     b_password_string = b"|".join([b'(\w+\'s )?' + x for x in b_SU_PROMPT_LOCALIZATIONS])
     # Colon or unicode fullwidth colon
     b_password_string = b_password_string + to_bytes(u' ?(:|:) ?')
     b_SU_PROMPT_LOCALIZATIONS_RE = re.compile(b_password_string, flags=re.IGNORECASE)
     return bool(b_SU_PROMPT_LOCALIZATIONS_RE.match(b_data))
Beispiel #33
0
    def _generate_csr(self):
        req = crypto.X509Req()
        req.set_version(self.version - 1)
        subject = req.get_subject()
        for entry in self.subject:
            if entry[1] is not None:
                # Workaround for https://github.com/pyca/pyopenssl/issues/165
                nid = OpenSSL._util.lib.OBJ_txt2nid(to_bytes(entry[0]))
                if nid == 0:
                    raise CertificateSigningRequestError(
                        'Unknown subject field identifier "{0}"'.format(
                            entry[0]))
                res = OpenSSL._util.lib.X509_NAME_add_entry_by_NID(
                    subject._name, nid, OpenSSL._util.lib.MBSTRING_UTF8,
                    to_bytes(entry[1]), -1, -1, 0)
                if res == 0:
                    raise CertificateSigningRequestError(
                        'Invalid value for subject field identifier "{0}": {1}'
                        .format(entry[0], entry[1]))

        extensions = []
        if self.subjectAltName:
            altnames = ', '.join(self.subjectAltName)
            try:
                extensions.append(
                    crypto.X509Extension(b"subjectAltName",
                                         self.subjectAltName_critical,
                                         altnames.encode('ascii')))
            except OpenSSL.crypto.Error as e:
                raise CertificateSigningRequestError(
                    'Error while parsing Subject Alternative Names {0} (check for missing type prefix, such as "DNS:"!): {1}'
                    .format(
                        ', '.join([
                            "{0}".format(san) for san in self.subjectAltName
                        ]), str(e)))

        if self.keyUsage:
            usages = ', '.join(self.keyUsage)
            extensions.append(
                crypto.X509Extension(b"keyUsage", self.keyUsage_critical,
                                     usages.encode('ascii')))

        if self.extendedKeyUsage:
            usages = ', '.join(self.extendedKeyUsage)
            extensions.append(
                crypto.X509Extension(b"extendedKeyUsage",
                                     self.extendedKeyUsage_critical,
                                     usages.encode('ascii')))

        if self.basicConstraints:
            usages = ', '.join(self.basicConstraints)
            extensions.append(
                crypto.X509Extension(b"basicConstraints",
                                     self.basicConstraints_critical,
                                     usages.encode('ascii')))

        if self.ocspMustStaple:
            extensions.append(
                crypto.X509Extension(OPENSSL_MUST_STAPLE_NAME,
                                     self.ocspMustStaple_critical,
                                     OPENSSL_MUST_STAPLE_VALUE))

        if extensions:
            req.add_extensions(extensions)

        req.set_pubkey(self.privatekey)
        req.sign(self.privatekey, self.digest)
        self.request = req

        return crypto.dump_certificate_request(crypto.FILETYPE_PEM,
                                               self.request)
Beispiel #34
0
    def _bare_run(self, cmd, in_data, sudoable=True, checkrc=True):
        '''
        Starts the command and communicates with it until it ends.
        '''

        display_cmd = list(map(shlex_quote, map(to_text, cmd)))
        display.vvv(u'SSH: EXEC {0}'.format(u' '.join(display_cmd)),
                    host=self.host)

        # Start the given command. If we don't need to pipeline data, we can try
        # to use a pseudo-tty (ssh will have been invoked with -tt). If we are
        # pipelining data, or can't create a pty, we fall back to using plain
        # old pipes.

        p = None

        if isinstance(cmd, (text_type, binary_type)):
            cmd = to_bytes(cmd)
        else:
            cmd = list(map(to_bytes, cmd))

        if not in_data:
            try:
                # Make sure stdin is a proper pty to avoid tcgetattr errors
                master, slave = pty.openpty()
                if PY3 and self._play_context.password:
                    p = subprocess.Popen(cmd,
                                         stdin=slave,
                                         stdout=subprocess.PIPE,
                                         stderr=subprocess.PIPE,
                                         pass_fds=self.sshpass_pipe)
                else:
                    p = subprocess.Popen(cmd,
                                         stdin=slave,
                                         stdout=subprocess.PIPE,
                                         stderr=subprocess.PIPE)
                stdin = os.fdopen(master, 'wb', 0)
                os.close(slave)
            except (OSError, IOError):
                p = None

        if not p:
            if PY3 and self._play_context.password:
                p = subprocess.Popen(cmd,
                                     stdin=subprocess.PIPE,
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.PIPE,
                                     pass_fds=self.sshpass_pipe)
            else:
                p = subprocess.Popen(cmd,
                                     stdin=subprocess.PIPE,
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.PIPE)
            stdin = p.stdin

        # If we are using SSH password authentication, write the password into
        # the pipe we opened in _build_command.

        if self._play_context.password:
            os.close(self.sshpass_pipe[0])
            try:
                os.write(self.sshpass_pipe[1],
                         to_bytes(self._play_context.password) + b'\n')
            except OSError as e:
                # Ignore broken pipe errors if the sshpass process has exited.
                if e.errno != errno.EPIPE or p.poll() is None:
                    raise
            os.close(self.sshpass_pipe[1])

        #
        # SSH state machine
        #

        # Now we read and accumulate output from the running process until it
        # exits. Depending on the circumstances, we may also need to write an
        # escalation password and/or pipelined input to the process.

        states = [
            'awaiting_prompt', 'awaiting_escalation', 'ready_to_send',
            'awaiting_exit'
        ]

        # Are we requesting privilege escalation? Right now, we may be invoked
        # to execute sftp/scp with sudoable=True, but we can request escalation
        # only when using ssh. Otherwise we can send initial data straightaway.

        state = states.index('ready_to_send')
        if b'ssh' in cmd:
            if self._play_context.prompt:
                # We're requesting escalation with a password, so we have to
                # wait for a password prompt.
                state = states.index('awaiting_prompt')
                display.debug(u'Initial state: %s: %s' %
                              (states[state], self._play_context.prompt))
            elif self._play_context.become and self._play_context.success_key:
                # We're requesting escalation without a password, so we have to
                # detect success/failure before sending any initial data.
                state = states.index('awaiting_escalation')
                display.debug(u'Initial state: %s: %s' %
                              (states[state], self._play_context.success_key))

        # We store accumulated stdout and stderr output from the process here,
        # but strip any privilege escalation prompt/confirmation lines first.
        # Output is accumulated into tmp_*, complete lines are extracted into
        # an array, then checked and removed or copied to stdout or stderr. We
        # set any flags based on examining the output in self._flags.

        b_stdout = b_stderr = b''
        b_tmp_stdout = b_tmp_stderr = b''

        self._flags = dict(become_prompt=False,
                           become_success=False,
                           become_error=False,
                           become_nopasswd_error=False)

        # select timeout should be longer than the connect timeout, otherwise
        # they will race each other when we can't connect, and the connect
        # timeout usually fails
        timeout = 2 + self._play_context.timeout
        for fd in (p.stdout, p.stderr):
            fcntl.fcntl(fd, fcntl.F_SETFL,
                        fcntl.fcntl(fd, fcntl.F_GETFL) | os.O_NONBLOCK)

        # TODO: bcoca would like to use SelectSelector() when open
        # filehandles is low, then switch to more efficient ones when higher.
        # select is faster when filehandles is low.
        selector = selectors.DefaultSelector()
        selector.register(p.stdout, selectors.EVENT_READ)
        selector.register(p.stderr, selectors.EVENT_READ)

        # If we can send initial data without waiting for anything, we do so
        # before we start polling
        if states[state] == 'ready_to_send' and in_data:
            self._send_initial_data(stdin, in_data)
            state += 1

        try:
            while True:
                poll = p.poll()
                events = selector.select(timeout)

                # We pay attention to timeouts only while negotiating a prompt.

                if not events:
                    # We timed out
                    if state <= states.index('awaiting_escalation'):
                        # If the process has already exited, then it's not really a
                        # timeout; we'll let the normal error handling deal with it.
                        if poll is not None:
                            break
                        self._terminate_process(p)
                        raise AnsibleError(
                            'Timeout (%ds) waiting for privilege escalation prompt: %s'
                            % (timeout, to_native(b_stdout)))

                # Read whatever output is available on stdout and stderr, and stop
                # listening to the pipe if it's been closed.

                for key, event in events:
                    if key.fileobj == p.stdout:
                        b_chunk = p.stdout.read()
                        if b_chunk == b'':
                            # stdout has been closed, stop watching it
                            selector.unregister(p.stdout)
                            # When ssh has ControlMaster (+ControlPath/Persist) enabled, the
                            # first connection goes into the background and we never see EOF
                            # on stderr. If we see EOF on stdout, lower the select timeout
                            # to reduce the time wasted selecting on stderr if we observe
                            # that the process has not yet existed after this EOF. Otherwise
                            # we may spend a long timeout period waiting for an EOF that is
                            # not going to arrive until the persisted connection closes.
                            timeout = 1
                        b_tmp_stdout += b_chunk
                        display.debug("stdout chunk (state=%s):\n>>>%s<<<\n" %
                                      (state, to_text(b_chunk)))
                    elif key.fileobj == p.stderr:
                        b_chunk = p.stderr.read()
                        if b_chunk == b'':
                            # stderr has been closed, stop watching it
                            selector.unregister(p.stderr)
                        b_tmp_stderr += b_chunk
                        display.debug("stderr chunk (state=%s):\n>>>%s<<<\n" %
                                      (state, to_text(b_chunk)))

                # We examine the output line-by-line until we have negotiated any
                # privilege escalation prompt and subsequent success/error message.
                # Afterwards, we can accumulate output without looking at it.

                if state < states.index('ready_to_send'):
                    if b_tmp_stdout:
                        b_output, b_unprocessed = self._examine_output(
                            'stdout', states[state], b_tmp_stdout, sudoable)
                        b_stdout += b_output
                        b_tmp_stdout = b_unprocessed

                    if b_tmp_stderr:
                        b_output, b_unprocessed = self._examine_output(
                            'stderr', states[state], b_tmp_stderr, sudoable)
                        b_stderr += b_output
                        b_tmp_stderr = b_unprocessed
                else:
                    b_stdout += b_tmp_stdout
                    b_stderr += b_tmp_stderr
                    b_tmp_stdout = b_tmp_stderr = b''

                # If we see a privilege escalation prompt, we send the password.
                # (If we're expecting a prompt but the escalation succeeds, we
                # didn't need the password and can carry on regardless.)

                if states[state] == 'awaiting_prompt':
                    if self._flags['become_prompt']:
                        display.debug(
                            'Sending become_pass in response to prompt')
                        stdin.write(
                            to_bytes(self._play_context.become_pass) + b'\n')
                        self._flags['become_prompt'] = False
                        state += 1
                    elif self._flags['become_success']:
                        state += 1

                # We've requested escalation (with or without a password), now we
                # wait for an error message or a successful escalation.

                if states[state] == 'awaiting_escalation':
                    if self._flags['become_success']:
                        display.debug('Escalation succeeded')
                        self._flags['become_success'] = False
                        state += 1
                    elif self._flags['become_error']:
                        display.debug('Escalation failed')
                        self._terminate_process(p)
                        self._flags['become_error'] = False
                        raise AnsibleError('Incorrect %s password' %
                                           self._play_context.become_method)
                    elif self._flags['become_nopasswd_error']:
                        display.debug('Escalation requires password')
                        self._terminate_process(p)
                        self._flags['become_nopasswd_error'] = False
                        raise AnsibleError('Missing %s password' %
                                           self._play_context.become_method)
                    elif self._flags['become_prompt']:
                        # This shouldn't happen, because we should see the "Sorry,
                        # try again" message first.
                        display.debug('Escalation prompt repeated')
                        self._terminate_process(p)
                        self._flags['become_prompt'] = False
                        raise AnsibleError('Incorrect %s password' %
                                           self._play_context.become_method)

                # Once we're sure that the privilege escalation prompt, if any, has
                # been dealt with, we can send any initial data and start waiting
                # for output.

                if states[state] == 'ready_to_send':
                    if in_data:
                        self._send_initial_data(stdin, in_data)
                    state += 1

                # Now we're awaiting_exit: has the child process exited? If it has,
                # and we've read all available output from it, we're done.

                if poll is not None:
                    if not selector.get_map() or not events:
                        break
                    # We should not see further writes to the stdout/stderr file
                    # descriptors after the process has closed, set the select
                    # timeout to gather any last writes we may have missed.
                    timeout = 0
                    continue

                # If the process has not yet exited, but we've already read EOF from
                # its stdout and stderr (and thus no longer watching any file
                # descriptors), we can just wait for it to exit.

                elif not selector.get_map():
                    p.wait()
                    break

                # Otherwise there may still be outstanding data to read.
        finally:
            selector.close()
            # close stdin after process is terminated and stdout/stderr are read
            # completely (see also issue #848)
            stdin.close()

        if C.HOST_KEY_CHECKING:
            if cmd[0] == b"sshpass" and p.returncode == 6:
                raise 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 = b'Bad configuration option: ControlPersist' in b_stderr or b'unknown configuration option: ControlPersist' in b_stderr
        if p.returncode != 0 and controlpersisterror:
            raise 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 we find a broken pipe because of ControlPersist timeout expiring (see #16731),
        # we raise a special exception so that we can retry a connection.
        controlpersist_broken_pipe = b'mux_client_hello_exchange: write packet: Broken pipe' in b_stderr
        if p.returncode == 255 and controlpersist_broken_pipe:
            raise AnsibleControlPersistBrokenPipeError(
                'SSH Error: data could not be sent because of ControlPersist broken pipe.'
            )

        if p.returncode == 255 and in_data and checkrc:
            raise AnsibleConnectionFailure(
                'SSH Error: data could not be sent to remote host "%s". Make sure this host can be reached over ssh'
                % self.host)

        return (p.returncode, b_stdout, b_stderr)
Beispiel #35
0
 def get_user_data(self):
     user_data = self.module.params.get('user_data')
     if user_data is not None:
         user_data = to_text(base64.b64encode(to_bytes(user_data)))
     return user_data
Beispiel #36
0
def run_module():
    # define the available arguments/parameters that a user can pass to
    # the module
    module_args = dict(
        instance=dict(default=None, type='str', required=True),
        username=dict(default=None, type='str', required=True, no_log=True),
        password=dict(default=None, type='str', required=True, no_log=True),
        table=dict(type='str', required=False, default='incident'),
        state=dict(choices=['present', 'absent'],
                   type='str', required=True),
        number=dict(default=None, required=False, type='str'),
        data=dict(default=None, required=False, type='dict'),
        lookup_field=dict(default='number', required=False, type='str'),
        attachment=dict(default=None, required=False, type='str')
    )
    module_required_if = [
        ['state', 'absent', ['number']],
    ]

    module = AnsibleModule(
        argument_spec=module_args,
        supports_check_mode=True,
        required_if=module_required_if
    )

    # check for pysnow
    if not HAS_PYSNOW:
        module.fail_json(msg='pysnow module required')

    params = module.params
    instance = params['instance']
    username = params['username']
    password = params['password']
    table = params['table']
    state = params['state']
    number = params['number']
    data = params['data']
    lookup_field = params['lookup_field']

    result = dict(
        changed=False,
        instance=instance,
        table=table,
        number=number,
        lookup_field=lookup_field
    )

    # check for attachments
    if params['attachment'] is not None:
        attach = params['attachment']
        b_attach = to_bytes(attach, errors='surrogate_or_strict')
        if not os.path.exists(b_attach):
            module.fail_json(msg="Attachment {0} not found".format(attach))
        result['attachment'] = attach
    else:
        attach = None

    # Connect to ServiceNow
    try:
        conn = pysnow.Client(instance=instance, user=username,
                             password=password)
    except Exception as detail:
        module.fail_json(msg='Could not connect to ServiceNow: {0}'.format(str(detail)), **result)

    # Deal with check mode
    if module.check_mode:

        # if we are in check mode and have no number, we would have created
        # a record.  We can only partially simulate this
        if number is None:
            result['record'] = dict(data)
            result['changed'] = True

        # do we want to check if the record is non-existent?
        elif state == 'absent':
            try:
                record = conn.query(table=table, query={lookup_field: number})
                res = record.get_one()
                result['record'] = dict(Success=True)
                result['changed'] = True
            except pysnow.exceptions.NoResults:
                result['record'] = None
            except Exception as detail:
                module.fail_json(msg="Unknown failure in query record: {0}".format(str(detail)), **result)

        # Let's simulate modification
        else:
            try:
                record = conn.query(table=table, query={lookup_field: number})
                res = record.get_one()
                for key, value in data.items():
                    res[key] = value
                    result['changed'] = True
                result['record'] = res
            except pysnow.exceptions.NoResults:
                snow_error = "Record does not exist"
                module.fail_json(msg=snow_error, **result)
            except Exception as detail:
                module.fail_json(msg="Unknown failure in query record: {0}".format(str(detail)), **result)
        module.exit_json(**result)

    # now for the real thing: (non-check mode)

    # are we creating a new record?
    if state == 'present' and number is None:
        try:
            record = conn.insert(table=table, payload=dict(data))
        except pysnow.UnexpectedResponse as e:
            snow_error = "Failed to create record: {0}, details: {1}".format(e.error_summary, e.error_details)
            module.fail_json(msg=snow_error, **result)
        result['record'] = record
        result['changed'] = True

    # we are deleting a record
    elif state == 'absent':
        try:
            record = conn.query(table=table, query={lookup_field: number})
            res = record.delete()
        except pysnow.exceptions.NoResults:
            res = dict(Success=True)
        except pysnow.exceptions.MultipleResults:
            snow_error = "Multiple record match"
            module.fail_json(msg=snow_error, **result)
        except pysnow.UnexpectedResponse as e:
            snow_error = "Failed to delete record: {0}, details: {1}".format(e.error_summary, e.error_details)
            module.fail_json(msg=snow_error, **result)
        except Exception as detail:
            snow_error = "Failed to delete record: {0}".format(str(detail))
            module.fail_json(msg=snow_error, **result)
        result['record'] = res
        result['changed'] = True

    # We want to update a record
    else:
        try:
            record = conn.query(table=table, query={lookup_field: number})
            if data is not None:
                res = record.update(dict(data))
                result['record'] = res
                result['changed'] = True
            else:
                res = record.get_one()
                result['record'] = res
            if attach is not None:
                res = record.attach(b_attach)
                result['changed'] = True
                result['attached_file'] = res

        except pysnow.exceptions.MultipleResults:
            snow_error = "Multiple record match"
            module.fail_json(msg=snow_error, **result)
        except pysnow.exceptions.NoResults:
            snow_error = "Record does not exist"
            module.fail_json(msg=snow_error, **result)
        except pysnow.UnexpectedResponse as e:
            snow_error = "Failed to update record: {0}, details: {1}".format(e.error_summary, e.error_details)
            module.fail_json(msg=snow_error, **result)
        except Exception as detail:
            snow_error = "Failed to update record: {0}".format(str(detail))
            module.fail_json(msg=snow_error, **result)

    module.exit_json(**result)
 def check_missing_password(self, b_output):
     b_missing_password = to_bytes(
         gettext.dgettext(
             self._play_context.become_method,
             C.BECOME_MISSING_STRINGS[self._play_context.become_method]))
     return b_missing_password and b_missing_password in b_output
Beispiel #38
0
def present(module, dest, regexp, line, insertafter, insertbefore, create,
            backup, backrefs, firstmatch):

    diff = {'before': '',
            'after': '',
            'before_header': '%s (content)' % dest,
            'after_header': '%s (content)' % dest}

    b_dest = to_bytes(dest, errors='surrogate_or_strict')
    if not os.path.exists(b_dest):
        if not create:
            module.fail_json(rc=257, msg='Destination %s does not exist !' % dest)
        b_destpath = os.path.dirname(b_dest)
        if not os.path.exists(b_destpath) and not module.check_mode:
            try:
                os.makedirs(b_destpath)
            except Exception as e:
                module.fail_json(msg='Error creating %s Error code: %s Error description: %s' % (b_destpath, e[0], e[1]))

        b_lines = []
    else:
        f = open(b_dest, 'rb')
        b_lines = f.readlines()
        f.close()

    if module._diff:
        diff['before'] = to_native(b('').join(b_lines))

    if regexp is not None:
        bre_m = re.compile(to_bytes(regexp, errors='surrogate_or_strict'))

    if insertafter not in (None, 'BOF', 'EOF'):
        bre_ins = re.compile(to_bytes(insertafter, errors='surrogate_or_strict'))
    elif insertbefore not in (None, 'BOF'):
        bre_ins = re.compile(to_bytes(insertbefore, errors='surrogate_or_strict'))
    else:
        bre_ins = None

    # index[0] is the line num where regexp has been found
    # index[1] is the line num where insertafter/inserbefore has been found
    index = [-1, -1]
    m = None
    b_line = to_bytes(line, errors='surrogate_or_strict')
    for lineno, b_cur_line in enumerate(b_lines):
        if regexp is not None:
            match_found = bre_m.search(b_cur_line)
        else:
            match_found = b_line == b_cur_line.rstrip(b('\r\n'))
        if match_found:
            index[0] = lineno
            m = match_found
        elif bre_ins is not None and bre_ins.search(b_cur_line):
            if insertafter:
                # + 1 for the next line
                index[1] = lineno + 1
                if firstmatch:
                    break
            if insertbefore:
                # index[1] for the previous line
                index[1] = lineno
                if firstmatch:
                    break

    msg = ''
    changed = False
    # Regexp matched a line in the file
    b_linesep = to_bytes(os.linesep, errors='surrogate_or_strict')
    if index[0] != -1:
        if backrefs:
            b_new_line = m.expand(b_line)
        else:
            # Don't do backref expansion if not asked.
            b_new_line = b_line

        if not b_new_line.endswith(b_linesep):
            b_new_line += b_linesep

        # If a regexp is specified and a match is found anywhere in the file, do
        # not insert the line before or after.
        if regexp is None and m:

            # Insert lines
            if insertafter and insertafter != 'EOF':

                # Ensure there is a line separator after the found string
                # at the end of the file.
                if b_lines and not b_lines[-1][-1:] in (b('\n'), b('\r')):
                    b_lines[-1] = b_lines[-1] + b_linesep

                # If the line to insert after is at the end of the file
                # use the appropriate index value.
                if len(b_lines) == index[1]:
                    if b_lines[index[1] - 1].rstrip(b('\r\n')) != b_line:
                        b_lines.append(b_line + b_linesep)
                        msg = 'line added'
                        changed = True
                elif b_lines[index[1]].rstrip(b('\r\n')) != b_line:
                    b_lines.insert(index[1], b_line + b_linesep)
                    msg = 'line added'
                    changed = True

            elif insertbefore:
                # If the line to insert before is at the beginning of the file
                # use the appropriate index value.
                if index[1] == 0:
                    if b_lines[index[1]].rstrip(b('\r\n')) != b_line:
                        b_lines.insert(index[1], b_line + b_linesep)
                        msg = 'line replaced'
                        changed = True

                elif b_lines[index[1] - 1].rstrip(b('\r\n')) != b_line:
                    b_lines.insert(index[1], b_line + b_linesep)
                    msg = 'line replaced'
                    changed = True

        elif b_lines[index[0]] != b_new_line:
            b_lines[index[0]] = b_new_line
            msg = 'line replaced'
            changed = True

    elif backrefs:
        # Do absolutely nothing, since it's not safe generating the line
        # without the regexp matching to populate the backrefs.
        pass
    # Add it to the beginning of the file
    elif insertbefore == 'BOF' or insertafter == 'BOF':
        b_lines.insert(0, b_line + b_linesep)
        msg = 'line added'
        changed = True
    # Add it to the end of the file if requested or
    # if insertafter/insertbefore didn't match anything
    # (so default behaviour is to add at the end)
    elif insertafter == 'EOF' or index[1] == -1:

        # If the file is not empty then ensure there's a newline before the added line
        if b_lines and not b_lines[-1][-1:] in (b('\n'), b('\r')):
            b_lines.append(b_linesep)

        b_lines.append(b_line + b_linesep)
        msg = 'line added'
        changed = True
    # insert matched, but not the regexp
    else:
        b_lines.insert(index[1], b_line + b_linesep)
        msg = 'line added'
        changed = True

    if module._diff:
        diff['after'] = to_native(b('').join(b_lines))

    backupdest = ""
    if changed and not module.check_mode:
        if backup and os.path.exists(b_dest):
            backupdest = module.backup_local(dest)
        write_changes(module, b_lines, dest)

    if module.check_mode and not os.path.exists(b_dest):
        module.exit_json(changed=changed, msg=msg, backup=backupdest, diff=diff)

    attr_diff = {}
    msg, changed = check_file_attrs(module, changed, msg, attr_diff)

    attr_diff['before_header'] = '%s (file attributes)' % dest
    attr_diff['after_header'] = '%s (file attributes)' % dest

    difflist = [diff, attr_diff]
    module.exit_json(changed=changed, msg=msg, backup=backupdest, diff=difflist)
Beispiel #39
0
    def __init__(self, vm_model, inventory_client, vmss=None):
        self._inventory_client = inventory_client
        self._vm_model = vm_model
        self._vmss = vmss

        self._instanceview = None

        self._powerstate = "unknown"
        self.nics = []

        # Azure often doesn't provide a globally-unique filename, so use resource name + a chunk of ID hash
        self.default_inventory_hostname = '{0}_{1}'.format(vm_model['name'], hashlib.sha1(to_bytes(vm_model['id'])).hexdigest()[0:4])

        self._hostvars = {}

        inventory_client._enqueue_get(url="{0}/instanceView".format(vm_model['id']),
                                      api_version=self._inventory_client._compute_api_version,
                                      handler=self._on_instanceview_response)

        nic_refs = vm_model['properties']['networkProfile']['networkInterfaces']
        for nic in nic_refs:
            # single-nic instances don't set primary, so figure it out...
            is_primary = nic.get('properties', {}).get('primary', len(nic_refs) == 1)
            inventory_client._enqueue_get(url=nic['id'], api_version=self._inventory_client._network_api_version,
                                          handler=self._on_nic_response,
                                          handler_args=dict(is_primary=is_primary))
Beispiel #40
0
    def display(self,
                msg,
                color=None,
                stderr=False,
                screen_only=False,
                log_only=False):
        """ Display a message to the user

        Note: msg *must* be a unicode string to prevent UnicodeError tracebacks.
        """

        nocolor = msg
        if color:
            msg = stringc(msg, color)

        if not log_only:
            if not msg.endswith(u'\n'):
                msg2 = msg + u'\n'
            else:
                msg2 = msg

            msg2 = to_bytes(msg2,
                            encoding=self._output_encoding(stderr=stderr))
            if sys.version_info >= (3, ):
                # Convert back to text string on python3
                # We first convert to a byte string so that we get rid of
                # characters that are invalid in the user's locale
                msg2 = to_text(msg2,
                               self._output_encoding(stderr=stderr),
                               errors='replace')

            # Note: After Display() class is refactored need to update the log capture
            # code in 'bin/ansible-connection' (and other relevant places).
            if not stderr:
                fileobj = sys.stdout
            else:
                fileobj = sys.stderr

            fileobj.write(msg2)

            try:
                fileobj.flush()
            except IOError as e:
                # Ignore EPIPE in case fileobj has been prematurely closed, eg.
                # when piping to "head -n1"
                if e.errno != errno.EPIPE:
                    raise

        if logger and not screen_only:
            msg2 = nocolor.lstrip(u'\n')

            msg2 = to_bytes(msg2)
            if sys.version_info >= (3, ):
                # Convert back to text string on python3
                # We first convert to a byte string so that we get rid of
                # characters that are invalid in the user's locale
                msg2 = to_text(msg2, self._output_encoding(stderr=stderr))

            if color == C.COLOR_ERROR:
                logger.error(msg2)
            else:
                logger.info(msg2)
Beispiel #41
0
    def run(self, tmp=None, task_vars=None):
        ''' handler for file transfer operations '''
        if task_vars is None:
            task_vars = dict()

        result = super(ActionModule, self).run(tmp, task_vars)
        del tmp  # tmp no longer has any effect

        try:
            creates = self._task.args.get('creates')
            if creates:
                # do not run the command if the line contains creates=filename
                # and the filename already exists. This allows idempotence
                # of command executions.
                if self._remote_file_exists(creates):
                    raise AnsibleActionSkip(
                        "%s exists, matching creates option" % creates)

            removes = self._task.args.get('removes')
            if removes:
                # do not run the command if the line contains removes=filename
                # and the filename does not exist. This allows idempotence
                # of command executions.
                if not self._remote_file_exists(removes):
                    raise AnsibleActionSkip(
                        "%s does not exist, matching removes option" % removes)

            # The chdir must be absolute, because a relative path would rely on
            # remote node behaviour & user config.
            chdir = self._task.args.get('chdir')
            if chdir:
                # Powershell is the only Windows-path aware shell
                if self._connection._shell.SHELL_FAMILY == 'powershell' and \
                        not self.windows_absolute_path_detection.matches(chdir):
                    raise AnsibleActionFail(
                        'chdir %s must be an absolute path for a Windows remote node'
                        % chdir)
                # Every other shell is unix-path-aware.
                if self._connection._shell.SHELL_FAMILY != 'powershell' and not chdir.startswith(
                        '/'):
                    raise AnsibleActionFail(
                        'chdir %s must be an absolute path for a Unix-aware remote node'
                        % chdir)

            # Split out the script as the first item in raw_params using
            # shlex.split() in order to support paths and files with spaces in the name.
            # Any arguments passed to the script will be added back later.
            raw_params = to_native(self._task.args.get('_raw_params', ''),
                                   errors='surrogate_or_strict')
            parts = [
                to_text(s, errors='surrogate_or_strict')
                for s in shlex.split(raw_params.strip())
            ]
            source = parts[0]

            # Support executable paths and files with spaces in the name.
            executable = to_native(self._task.args.get('executable', ''),
                                   errors='surrogate_or_strict')

            try:
                source = self._loader.get_real_file(
                    self._find_needle('files', source),
                    decrypt=self._task.args.get('decrypt', True))
            except AnsibleError as e:
                raise AnsibleActionFail(to_native(e))

            # now we execute script, always assume changed.
            result['changed'] = True

            if not self._play_context.check_mode:
                # transfer the file to a remote tmp location
                tmp_src = self._connection._shell.join_path(
                    self._connection._shell.tmpdir, os.path.basename(source))

                # Convert raw_params to text for the purpose of replacing the script since
                # parts and tmp_src are both unicode strings and raw_params will be different
                # depending on Python version.
                #
                # Once everything is encoded consistently, replace the script path on the remote
                # system with the remainder of the raw_params. This preserves quoting in parameters
                # that would have been removed by shlex.split().
                target_command = to_text(raw_params).strip().replace(
                    parts[0], tmp_src)

                self._transfer_file(source, tmp_src)

                # set file permissions, more permissive when the copy is done as a different user
                self._fixup_perms2((self._connection._shell.tmpdir, tmp_src),
                                   execute=True)

                # add preparation steps to one ssh roundtrip executing the script
                env_dict = dict()
                env_string = self._compute_environment_string(env_dict)

                if executable:
                    script_cmd = ' '.join(
                        [env_string, executable, target_command])
                else:
                    script_cmd = ' '.join([env_string, target_command])

            if self._play_context.check_mode:
                raise _AnsibleActionDone()

            script_cmd = self._connection._shell.wrap_for_exec(script_cmd)

            exec_data = None
            # PowerShell runs the script in a special wrapper to enable things
            # like become and environment args
            if self._connection._shell.SHELL_FAMILY == "powershell":
                # FIXME: use a more public method to get the exec payload
                pc = self._play_context
                exec_data = _create_powershell_wrapper(to_bytes(script_cmd),
                                                       {},
                                                       env_dict,
                                                       self._task.async_val,
                                                       pc.become,
                                                       pc.become_method,
                                                       pc.become_user,
                                                       pc.become_pass,
                                                       pc.become_flags,
                                                       scan_dependencies=False)
                script_cmd = "-"

            result.update(
                self._low_level_execute_command(cmd=script_cmd,
                                                in_data=exec_data,
                                                sudoable=True,
                                                chdir=chdir))

            if 'rc' in result and result['rc'] != 0:
                raise AnsibleActionFail('non-zero return code')

        except AnsibleAction as e:
            result.update(e.result)
        finally:
            self._remove_tmp_path(self._connection._shell.tmpdir)

        return result
Beispiel #42
0
def set_module_args(args):
    args = json.dumps({'ANSIBLE_MODULE_ARGS': args})
    basic._ANSIBLE_ARGS = to_bytes(args)
Beispiel #43
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(dict(
        name=dict(required=True),
        key_material=dict(required=False),
        force = dict(required=False, type='bool', default=True),
        state = dict(default='present', choices=['present', 'absent']),
        wait = dict(type='bool', default=False),
        wait_timeout = dict(default=300),
    )
    )
    module = AnsibleModule(
        argument_spec=argument_spec,
        supports_check_mode=True,
    )

    if not HAS_BOTO:
        module.fail_json(msg='boto required for this module')

    name = module.params['name']
    state = module.params.get('state')
    key_material = module.params.get('key_material')
    force = module.params.get('force')
    wait = module.params.get('wait')
    wait_timeout = int(module.params.get('wait_timeout'))

    changed = False

    ec2 = ec2_connect(module)

    # find the key if present
    key = ec2.get_key_pair(name)

    # Ensure requested key is absent
    if state == 'absent':
        if key:
            '''found a match, delete it'''
            if not module.check_mode:
                try:
                    key.delete()
                    if wait:
                        start = time.time()
                        action_complete = False
                        while (time.time() - start) < wait_timeout:
                            if not ec2.get_key_pair(name):
                                action_complete = True
                                break
                            time.sleep(1)
                        if not action_complete:
                            module.fail_json(msg="timed out while waiting for the key to be removed")
                except Exception as e:
                    module.fail_json(msg="Unable to delete key pair '%s' - %s" % (key, e))
            key = None
            changed = True

    # Ensure requested key is present
    elif state == 'present':
        if key:
            # existing key found
            if key_material and force:
                # EC2's fingerprints are non-trivial to generate, so push this key
                # to a temporary name and make ec2 calculate the fingerprint for us.
                #
                # http://blog.jbrowne.com/?p=23
                # https://forums.aws.amazon.com/thread.jspa?messageID=352828

                # find an unused name
                test = 'empty'
                while test:
                    randomchars = [random.choice(string.ascii_letters + string.digits) for x in range(0,10)]
                    tmpkeyname = "ansible-" + ''.join(randomchars)
                    test = ec2.get_key_pair(tmpkeyname)

                # create tmp key
                tmpkey = ec2.import_key_pair(tmpkeyname, to_bytes(key_material))
                # get tmp key fingerprint
                tmpfingerprint = tmpkey.fingerprint
                # delete tmp key
                tmpkey.delete()

                if key.fingerprint != tmpfingerprint:
                    if not module.check_mode:
                        key.delete()
                        key = ec2.import_key_pair(name, to_bytes(key_material))

                        if wait:
                            start = time.time()
                            action_complete = False
                            while (time.time() - start) < wait_timeout:
                                if ec2.get_key_pair(name):
                                    action_complete = True
                                    break
                                time.sleep(1)
                            if not action_complete:
                                module.fail_json(msg="timed out while waiting for the key to be re-created")

                    changed = True
            pass

        # if the key doesn't exist, create it now
        else:
            '''no match found, create it'''
            if not module.check_mode:
                if key_material:
                    '''We are providing the key, need to import'''
                    key = ec2.import_key_pair(name, to_bytes(key_material))
                else:
                    '''
                    No material provided, let AWS handle the key creation and
                    retrieve the private key
                    '''
                    key = ec2.create_key_pair(name)

                if wait:
                    start = time.time()
                    action_complete = False
                    while (time.time() - start) < wait_timeout:
                        if ec2.get_key_pair(name):
                            action_complete = True
                            break
                        time.sleep(1)
                    if not action_complete:
                        module.fail_json(msg="timed out while waiting for the key to be created")

            changed = True

    if key:
        data = {
            'name': key.name,
            'fingerprint': key.fingerprint
        }
        if key.material:
            data.update({'private_key': key.material})

        module.exit_json(changed=changed, key=data)
    else:
        module.exit_json(changed=changed, key=None)
Beispiel #44
0
    def exec_command(self, cmd, in_data=None, sudoable=True):
        ''' run a command on the ssm host '''

        super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable)

        display.vvv(u"EXEC {0}".format(to_text(cmd)), host=self.host)

        session = self._session

        mark_begin = "".join([random.choice(string.ascii_letters) for i in xrange(self.MARK_LENGTH)])
        if self.is_windows:
            mark_start = mark_begin + " $LASTEXITCODE"
        else:
            mark_start = mark_begin
        mark_end = "".join([random.choice(string.ascii_letters) for i in xrange(self.MARK_LENGTH)])

        # Wrap command in markers accordingly for the shell used
        cmd = self._wrap_command(cmd, sudoable, mark_start, mark_end)

        self._flush_stderr(session)

        for chunk in chunks(cmd, 1024):
            session.stdin.write(to_bytes(chunk, errors='surrogate_or_strict'))

        # Read stdout between the markers
        stdout = ''
        win_line = ''
        begin = False
        stop_time = int(round(time.time())) + self.get_option('ssm_timeout')
        while session.poll() is None:
            remaining = stop_time - int(round(time.time()))
            if remaining < 1:
                self._timeout = True
                display.vvvv(u"EXEC timeout stdout: {0}".format(to_text(stdout)), host=self.host)
                raise AnsibleConnectionFailure("SSM exec_command timeout on host: %s"
                                               % self.instance_id)
            if self._poll_stdout.poll(1000):
                line = self._filter_ansi(self._stdout.readline())
                display.vvvv(u"EXEC stdout line: {0}".format(to_text(line)), host=self.host)
            else:
                display.vvvv(u"EXEC remaining: {0}".format(remaining), host=self.host)
                continue

            if not begin and self.is_windows:
                win_line = win_line + line
                line = win_line

            if mark_start in line:
                begin = True
                if not line.startswith(mark_start):
                    stdout = ''
                continue
            if begin:
                if mark_end in line:
                    display.vvvv(u"POST_PROCESS: {0}".format(to_text(stdout)), host=self.host)
                    returncode, stdout = self._post_process(stdout, mark_begin)
                    break
                else:
                    stdout = stdout + line

        stderr = self._flush_stderr(session)

        return (returncode, stdout, stderr)
Beispiel #45
0
from ansible.module_utils.six import string_types
from ansible.module_utils._text import to_bytes, to_text
from ansible.parsing.utils.addresses import parse_address
from ansible.plugins import PluginLoader
from ansible.utils.path import unfrackpath

try:
    from __main__ import display
except ImportError:
    from ansible.utils.display import Display
    display = Display()

HOSTS_PATTERNS_CACHE = {}

IGNORED_ALWAYS = [b"^\.", b"^host_vars$", b"^group_vars$", b"^vars_plugins$"]
IGNORED_PATTERNS = [to_bytes(x) for x in C.INVENTORY_IGNORE_PATTERNS]
IGNORED_EXTS = [
    b'%s$' % to_bytes(re.escape(x)) for x in C.INVENTORY_IGNORE_EXTS
]

IGNORED = re.compile(b'|'.join(IGNORED_ALWAYS + IGNORED_PATTERNS +
                               IGNORED_EXTS))


def order_patterns(patterns):
    ''' takes a list of patterns and reorders them by modifier to apply them consistently '''

    # FIXME: this goes away if we apply patterns incrementally or by groups
    pattern_regular = []
    pattern_intersection = []
    pattern_exclude = []
Beispiel #46
0
    def _parse_pipeline_result(self, pipeline):
        """
        PSRP doesn't have the same concept as other protocols with its output.
        We need some extra logic to convert the pipeline streams and host
        output into the format that Ansible understands.

        :param pipeline: The finished PowerShell pipeline that invoked our
            commands
        :return: rc, stdout, stderr based on the pipeline output
        """
        # we try and get the rc from our host implementation, this is set if
        # exit or $host.SetShouldExit() is called in our pipeline, if not we
        # set to 0 if the pipeline had not errors and 1 if it did
        rc = self.host.rc or (1 if pipeline.had_errors else 0)

        # TODO: figure out a better way of merging this with the host output
        stdout_list = []
        for output in pipeline.output:
            # Not all pipeline outputs are a string or contain a __str__ value,
            # we will create our own output based on the properties of the
            # complex object if that is the case.
            if isinstance(output, GenericComplexObject) and output.to_string is None:
                obj_lines = output.property_sets
                for key, value in output.adapted_properties.items():
                    obj_lines.append(u"%s: %s" % (key, value))
                for key, value in output.extended_properties.items():
                    obj_lines.append(u"%s: %s" % (key, value))
                output_msg = u"\n".join(obj_lines)
            else:
                output_msg = to_text(output, nonstring='simplerepr')

            stdout_list.append(output_msg)

        if len(self.host.ui.stdout) > 0:
            stdout_list += self.host.ui.stdout
        stdout = u"\r\n".join(stdout_list)

        stderr_list = []
        for error in pipeline.streams.error:
            # the error record is not as fully fleshed out like we usually get
            # in PS, we will manually create it here
            command_name = "%s : " % error.command_name if error.command_name else ''
            position = "%s\r\n" % error.invocation_position_message if error.invocation_position_message else ''
            error_msg = "%s%s\r\n%s" \
                        "    + CategoryInfo          : %s\r\n" \
                        "    + FullyQualifiedErrorId : %s" \
                        % (command_name, str(error), position,
                           error.message, error.fq_error)
            stacktrace = error.script_stacktrace
            if self._play_context.verbosity >= 3 and stacktrace is not None:
                error_msg += "\r\nStackTrace:\r\n%s" % stacktrace
            stderr_list.append(error_msg)

        if len(self.host.ui.stderr) > 0:
            stderr_list += self.host.ui.stderr
        stderr = u"\r\n".join([to_text(o) for o in stderr_list])

        display.vvvvv("PSRP RC: %d" % rc, host=self._psrp_host)
        display.vvvvv("PSRP STDOUT: %s" % stdout, host=self._psrp_host)
        display.vvvvv("PSRP STDERR: %s" % stderr, host=self._psrp_host)

        # reset the host back output back to defaults, needed if running
        # multiple pipelines on the same RunspacePool
        self.host.rc = 0
        self.host.ui.stdout = []
        self.host.ui.stderr = []

        return rc, to_bytes(stdout, encoding='utf-8'), to_bytes(stderr, encoding='utf-8')
 def check_become_success(self, b_output):
     b_success_key = to_bytes(self._play_context.success_key)
     for b_line in b_output.splitlines(True):
         if b_success_key == b_line.rstrip():
             return True
     return False
 def check_incorrect_password(self, b_output):
     b_incorrect_password = to_bytes(
         gettext.dgettext(
             self._play_context.become_method,
             C.BECOME_ERROR_STRINGS[self._play_context.become_method]))
     return b_incorrect_password and b_incorrect_password in b_output
Beispiel #49
0
    def _connect(self):
        if not HAS_NCCLIENT:
            raise AnsibleError("%s: %s" % (
                missing_required_lib("ncclient"),
                to_native(NCCLIENT_IMP_ERR),
            ))

        self.queue_message("log", "ssh connection done, starting ncclient")

        allow_agent = True
        if self._play_context.password is not None:
            allow_agent = False
        setattr(self._play_context, "allow_agent", allow_agent)

        self.key_filename = (self._play_context.private_key_file
                             or self.get_option("private_key_file"))
        if self.key_filename:
            self.key_filename = str(os.path.expanduser(self.key_filename))

        self._ssh_config = self.get_option("netconf_ssh_config")
        if self._ssh_config in BOOLEANS_TRUE:
            self._ssh_config = True
        elif self._ssh_config in BOOLEANS_FALSE:
            self._ssh_config = None

        # Try to guess the network_os if the network_os is set to auto
        if self._network_os == "auto":
            for cls in netconf_loader.all(class_only=True):
                network_os = cls.guess_network_os(self)
                if network_os:
                    self.queue_message("vvv",
                                       "discovered network_os %s" % network_os)
                    self._network_os = network_os

        # If we have tried to detect the network_os but were unable to i.e. network_os is still 'auto'
        # then use default as the network_os

        if self._network_os == "auto":
            # Network os not discovered. Set it to default
            self.queue_message(
                "vvv",
                "Unable to discover network_os. Falling back to default.",
            )
            self._network_os = "default"
        try:
            ncclient_device_handler = self.netconf.get_option(
                "ncclient_device_handler")
        except KeyError:
            ncclient_device_handler = "default"
        self.queue_message(
            "vvv",
            "identified ncclient device handler: %s." %
            ncclient_device_handler,
        )
        device_params = {"name": ncclient_device_handler}

        try:
            port = self._play_context.port or 830
            self.queue_message(
                "vvv",
                "ESTABLISH NETCONF SSH CONNECTION FOR USER: %s on PORT %s TO %s WITH SSH_CONFIG = %s"
                % (
                    self._play_context.remote_user,
                    port,
                    self._play_context.remote_addr,
                    self._ssh_config,
                ),
            )
            self._manager = manager.connect(
                host=self._play_context.remote_addr,
                port=port,
                username=self._play_context.remote_user,
                password=self._play_context.password,
                key_filename=self.key_filename,
                hostkey_verify=self.get_option("host_key_checking"),
                look_for_keys=self.get_option("look_for_keys"),
                device_params=device_params,
                allow_agent=self._play_context.allow_agent,
                timeout=self.get_option("persistent_connect_timeout"),
                ssh_config=self._ssh_config,
            )

            self._manager._timeout = self.get_option(
                "persistent_command_timeout")
        except SSHUnknownHostError as exc:
            raise AnsibleConnectionFailure(to_native(exc))
        except ImportError:
            raise AnsibleError(
                "connection=netconf is not supported on {0}".format(
                    self._network_os))

        if not self._manager.connected:
            return 1, b"", b"not connected"

        self.queue_message("log",
                           "ncclient manager object created successfully")

        self._connected = True

        super(Connection, self)._connect()

        return (
            0,
            to_bytes(self._manager.session_id, errors="surrogate_or_strict"),
            b"",
        )
Beispiel #50
0
def find_ini_config_file(warnings=None):
    ''' Load INI Config File order(first found is used): ENV, CWD, HOME, /etc/ansible '''
    # FIXME: eventually deprecate ini configs

    if warnings is None:
        # Note: In this case, warnings does nothing
        warnings = set()

    # A value that can never be a valid path so that we can tell if ANSIBLE_CONFIG was set later
    # We can't use None because we could set path to None.
    SENTINEL = object

    potential_paths = []

    # Environment setting
    path_from_env = os.getenv("ANSIBLE_CONFIG", SENTINEL)
    if path_from_env is not SENTINEL:
        path_from_env = unfrackpath(path_from_env, follow=False)
        if os.path.isdir(to_bytes(path_from_env)):
            path_from_env = os.path.join(path_from_env, "ansible.cfg")
        potential_paths.append(path_from_env)

    # Current working directory
    warn_cmd_public = False
    try:
        cwd = os.getcwd()
        perms = os.stat(cwd)
        cwd_cfg = os.path.join(cwd, "ansible.cfg")
        if perms.st_mode & stat.S_IWOTH:
            # Working directory is world writable so we'll skip it.
            # Still have to look for a file here, though, so that we know if we have to warn
            if os.path.exists(cwd_cfg):
                warn_cmd_public = True
        else:
            potential_paths.append(cwd_cfg)
    except OSError:
        # If we can't access cwd, we'll simply skip it as a possible config source
        pass

    # Per user location
    potential_paths.append(unfrackpath("~/.ansible.cfg", follow=False))

    # System location
    potential_paths.append("/etc/ansible/ansible.cfg")

    for path in potential_paths:
        if os.path.exists(to_bytes(path)):
            break
    else:
        path = None

    # Emit a warning if all the following are true:
    # * We did not use a config from ANSIBLE_CONFIG
    # * There's an ansible.cfg in the current working directory that we skipped
    if path_from_env != path and warn_cmd_public:
        warnings.add(u"Ansible is being run in a world writable directory (%s),"
                     u" ignoring it as an ansible.cfg source."
                     u" For more information see"
                     u" https://docs.ansible.com/ansible/devel/reference_appendices/config.html#cfg-in-world-writable-dir"
                     % to_text(cwd))

    return path
Beispiel #51
0
    def _file_transport_command(self, in_path, out_path, sftp_action):
        # scp and sftp require square brackets for IPv6 addresses, but
        # accept them for hostnames and IPv4 addresses too.
        host = '[%s]' % self.host

        # Transfer methods to try
        methods = []

        # Use the transfer_method option if set, otherwise use scp_if_ssh
        ssh_transfer_method = self._play_context.ssh_transfer_method
        if ssh_transfer_method is not None:
            if not (ssh_transfer_method in ('smart', 'sftp', 'scp', 'piped')):
                raise AnsibleOptionsError(
                    'transfer_method needs to be one of [smart|sftp|scp|piped]'
                )
            if ssh_transfer_method == 'smart':
                methods = ['sftp', 'scp', 'piped']
            else:
                methods = [ssh_transfer_method]
        else:
            # since this can be a non-bool now, we need to handle it correctly
            scp_if_ssh = C.DEFAULT_SCP_IF_SSH
            if not isinstance(scp_if_ssh, bool):
                scp_if_ssh = scp_if_ssh.lower()
                if scp_if_ssh in BOOLEANS:
                    scp_if_ssh = boolean(scp_if_ssh, strict=False)
                elif scp_if_ssh != 'smart':
                    raise AnsibleOptionsError(
                        'scp_if_ssh needs to be one of [smart|True|False]')
            if scp_if_ssh == 'smart':
                methods = ['sftp', 'scp', 'piped']
            elif scp_if_ssh is True:
                methods = ['scp']
            else:
                methods = ['sftp']

        for method in methods:
            returncode = stdout = stderr = None
            if method == 'sftp':
                cmd = self._build_command('sftp', to_bytes(host))
                in_data = u"{0} {1} {2}\n".format(sftp_action,
                                                  shlex_quote(in_path),
                                                  shlex_quote(out_path))
                in_data = to_bytes(in_data, nonstring='passthru')
                (returncode, stdout, stderr) = self._bare_run(cmd,
                                                              in_data,
                                                              checkrc=False)
            elif method == 'scp':
                if sftp_action == 'get':
                    cmd = self._build_command(
                        'scp', u'{0}:{1}'.format(host, shlex_quote(in_path)),
                        out_path)
                else:
                    cmd = self._build_command(
                        'scp', in_path,
                        u'{0}:{1}'.format(host, shlex_quote(out_path)))
                in_data = None
                (returncode, stdout, stderr) = self._bare_run(cmd,
                                                              in_data,
                                                              checkrc=False)
            elif method == 'piped':
                if sftp_action == 'get':
                    # we pass sudoable=False to disable pty allocation, which
                    # would end up mixing stdout/stderr and screwing with newlines
                    (returncode, stdout, stderr) = self.exec_command(
                        'dd if=%s bs=%s' % (in_path, BUFSIZE), sudoable=False)
                    out_file = open(
                        to_bytes(out_path, errors='surrogate_or_strict'),
                        'wb+')
                    out_file.write(stdout)
                    out_file.close()
                else:
                    in_data = open(
                        to_bytes(in_path, errors='surrogate_or_strict'),
                        'rb').read()
                    in_data = to_bytes(in_data, nonstring='passthru')
                    (returncode, stdout, stderr) = self.exec_command(
                        'dd of=%s bs=%s' % (out_path, BUFSIZE),
                        in_data=in_data)

            # Check the return code and rollover to next method if failed
            if returncode == 0:
                return (returncode, stdout, stderr)
            else:
                # If not in smart mode, the data will be printed by the raise below
                if len(methods) > 1:
                    display.warning(
                        msg=
                        '%s transfer mechanism failed on %s. Use ANSIBLE_DEBUG=1 to see detailed information'
                        % (method, host))
                    display.debug(msg='%s' % to_native(stdout))
                    display.debug(msg='%s' % to_native(stderr))

        if returncode == 255:
            raise AnsibleConnectionFailure(
                "Failed to connect to the host via %s: %s" %
                (method, to_native(stderr)))
        else:
            raise AnsibleError("failed to transfer file to %s %s:\n%s\n%s" %
                               (to_native(in_path), to_native(out_path),
                                to_native(stdout), to_native(stderr)))
Beispiel #52
0
def ensure_type(value, value_type, origin=None):
    ''' return a configuration variable with casting
    :arg value: The value to ensure correct typing of
    :kwarg value_type: The type of the value.  This can be any of the following strings:
        :boolean: sets the value to a True or False value
        :bool: Same as 'boolean'
        :integer: Sets the value to an integer or raises a ValueType error
        :int: Same as 'integer'
        :float: Sets the value to a float or raises a ValueType error
        :list: Treats the value as a comma separated list.  Split the value
            and return it as a python list.
        :none: Sets the value to None
        :path: Expands any environment variables and tilde's in the value.
        :tmppath: Create a unique temporary directory inside of the directory
            specified by value and return its path.
        :temppath: Same as 'tmppath'
        :tmp: Same as 'tmppath'
        :pathlist: Treat the value as a typical PATH string.  (On POSIX, this
            means colon separated strings.)  Split the value and then expand
            each part for environment variables and tildes.
        :pathspec: Treat the value as a PATH string. Expands any environment variables
            tildes's in the value.
        :str: Sets the value to string types.
        :string: Same as 'str'
    '''

    basedir = None
    if origin and os.path.isabs(origin) and os.path.exists(to_bytes(origin)):
        basedir = origin

    if value_type:
        value_type = value_type.lower()

    if value_type in ('boolean', 'bool'):
        value = boolean(value, strict=False)

    elif value is not None:
        if value_type in ('integer', 'int'):
            value = int(value)

        elif value_type == 'float':
            value = float(value)

        elif value_type == 'list':
            if isinstance(value, string_types):
                value = [x.strip() for x in value.split(',')]

        elif value_type == 'none':
            if value == "None":
                value = None

        elif value_type == 'path':
            value = resolve_path(value, basedir=basedir)

        elif value_type in ('tmp', 'temppath', 'tmppath'):
            value = resolve_path(value, basedir=basedir)
            if not os.path.exists(value):
                makedirs_safe(value, 0o700)
            prefix = 'ansible-local-%s' % os.getpid()
            value = tempfile.mkdtemp(prefix=prefix, dir=value)

        elif value_type == 'pathspec':
            if isinstance(value, string_types):
                value = value.split(os.pathsep)
            value = [resolve_path(x, basedir=basedir) for x in value]

        elif value_type == 'pathlist':
            if isinstance(value, string_types):
                value = value.split(',')
            value = [resolve_path(x, basedir=basedir) for x in value]

        elif value_type in ('str', 'string'):
            value = unquote(to_text(value, errors='surrogate_or_strict'))

        # defaults to string type
        elif isinstance(value, string_types):
            value = unquote(value)

    return to_text(value, errors='surrogate_or_strict', nonstring='passthru')
Beispiel #53
0
    def _build_command(self, binary, *other_args):
        '''
        Takes a binary (ssh, scp, sftp) and optional extra arguments and returns
        a command line as an array that can be passed to subprocess.Popen.
        '''

        b_command = []

        #
        # First, the command to invoke
        #

        # If we want to use password authentication, we have to set up a pipe to
        # write the password to sshpass.

        if self._play_context.password:
            if not self._sshpass_available():
                raise AnsibleError(
                    "to use the 'ssh' connection type with passwords, you must install the sshpass program"
                )

            self.sshpass_pipe = os.pipe()
            b_command += [
                b'sshpass', b'-d' + to_bytes(self.sshpass_pipe[0],
                                             nonstring='simplerepr',
                                             errors='surrogate_or_strict')
            ]

        if binary == 'ssh':
            b_command += [
                to_bytes(self._play_context.ssh_executable,
                         errors='surrogate_or_strict')
            ]
        else:
            b_command += [to_bytes(binary, errors='surrogate_or_strict')]

        #
        # Next, additional arguments based on the configuration.
        #

        # sftp batch mode allows us to correctly catch failed transfers, but can
        # be disabled if the client side doesn't support the option. However,
        # sftp batch mode does not prompt for passwords so it must be disabled
        # if not using controlpersist and using sshpass
        if binary == 'sftp' and C.DEFAULT_SFTP_BATCH_MODE:
            if self._play_context.password:
                b_args = [b'-o', b'BatchMode=no']
                self._add_args(b_command, b_args,
                               u'disable batch mode for sshpass')
            b_command += [b'-b', b'-']

        if self._play_context.verbosity > 3:
            b_command.append(b'-vvv')

        #
        # Next, we add [ssh_connection]ssh_args from ansible.cfg.
        #

        if self._play_context.ssh_args:
            b_args = [
                to_bytes(a, errors='surrogate_or_strict')
                for a in self._split_ssh_args(self._play_context.ssh_args)
            ]
            self._add_args(b_command, b_args, u"ansible.cfg set ssh_args")

        # Now we add various arguments controlled by configuration file settings
        # (e.g. host_key_checking) or inventory variables (ansible_ssh_port) or
        # a combination thereof.

        if not C.HOST_KEY_CHECKING:
            b_args = (b"-o", b"StrictHostKeyChecking=no")
            self._add_args(
                b_command, b_args,
                u"ANSIBLE_HOST_KEY_CHECKING/host_key_checking disabled")

        if self._play_context.port is not None:
            b_args = (b"-o", b"Port=" + to_bytes(self._play_context.port,
                                                 nonstring='simplerepr',
                                                 errors='surrogate_or_strict'))
            self._add_args(
                b_command, b_args,
                u"ANSIBLE_REMOTE_PORT/remote_port/ansible_port set")

        key = self._play_context.private_key_file
        if key:
            b_args = (b"-o", b'IdentityFile="' + to_bytes(
                os.path.expanduser(key), errors='surrogate_or_strict') + b'"')
            self._add_args(
                b_command, b_args,
                u"ANSIBLE_PRIVATE_KEY_FILE/private_key_file/ansible_ssh_private_key_file set"
            )

        if not self._play_context.password:
            self._add_args(b_command, (
                b"-o", b"KbdInteractiveAuthentication=no", b"-o",
                b"PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey",
                b"-o", b"PasswordAuthentication=no"),
                           u"ansible_password/ansible_ssh_pass not set")

        user = self._play_context.remote_user
        if user:
            self._add_args(
                b_command,
                (b"-o", b"User="******"ANSIBLE_REMOTE_USER/remote_user/ansible_user/user/-u set")

        self._add_args(
            b_command,
            (b"-o", b"ConnectTimeout=" + to_bytes(self._play_context.timeout,
                                                  errors='surrogate_or_strict',
                                                  nonstring='simplerepr')),
            u"ANSIBLE_TIMEOUT/timeout set")

        # Add in any common or binary-specific arguments from the PlayContext
        # (i.e. inventory or task settings or overrides on the command line).

        for opt in (u'ssh_common_args', u'{0}_extra_args'.format(binary)):
            attr = getattr(self._play_context, opt, None)
            if attr is not None:
                b_args = [
                    to_bytes(a, errors='surrogate_or_strict')
                    for a in self._split_ssh_args(attr)
                ]
                self._add_args(b_command, b_args, u"PlayContext set %s" % opt)

        # Check if ControlPersist is enabled and add a ControlPath if one hasn't
        # already been set.

        controlpersist, controlpath = self._persistence_controls(b_command)

        if controlpersist:
            self._persistent = True

            if not controlpath:
                cpdir = unfrackpath(self.control_path_dir)
                b_cpdir = to_bytes(cpdir, errors='surrogate_or_strict')

                # The directory must exist and be writable.
                makedirs_safe(b_cpdir, 0o700)
                if not os.access(b_cpdir, os.W_OK):
                    raise AnsibleError("Cannot write to ControlPath %s" %
                                       to_native(cpdir))

                if not self.control_path:
                    self.control_path = self._create_control_path(
                        self.host, self.port, self.user)
                b_args = (b"-o", b"ControlPath=" +
                          to_bytes(self.control_path % dict(directory=cpdir),
                                   errors='surrogate_or_strict'))
                self._add_args(
                    b_command, b_args,
                    u"found only ControlPersist; added ControlPath")

        # Finally, we add any caller-supplied extras.
        if other_args:
            b_command += [to_bytes(a) for a in other_args]

        return b_command
Beispiel #54
0
    def parse_source(self, source, cache=False):
        ''' Generate or update inventory for the source provided '''

        parsed = False
        display.debug(u'Examining possible inventory source: %s' % source)

        b_source = to_bytes(source)
        # process directories as a collection of inventories
        if os.path.isdir(b_source):
            display.debug(u'Searching for inventory files in directory: %s' % source)
            for i in sorted(os.listdir(b_source)):

                display.debug(u'Considering %s' % i)
                # Skip hidden files and stuff we explicitly ignore
                if IGNORED.search(i):
                    continue

                # recursively deal with directory entries
                fullpath = os.path.join(b_source, i)
                parsed_this_one = self.parse_source(to_native(fullpath), cache=cache)
                display.debug(u'parsed %s as %s' % (fullpath, parsed_this_one))
                if not parsed:
                    parsed = parsed_this_one
        else:
            # left with strings or files, let plugins figure it out

            # set so new hosts can use for inventory_file/dir vasr
            self._inventory.current_source = source

            # get inventory plugins if needed, there should always be at least one generator
            if not self._inventory_plugins:
                self._setup_inventory_plugins()

            # try source with each plugin
            failures = []
            for plugin in self._inventory_plugins:
                plugin_name = to_native(getattr(plugin, '_load_name', getattr(plugin, '_original_path', '')))
                display.debug(u'Attempting to use plugin %s (%s)' % (plugin_name, plugin._original_path))

                # initialize and figure out if plugin wants to attempt parsing this file
                try:
                    plugin_wants = bool(plugin.verify_file(source))
                except Exception:
                    plugin_wants = False

                if plugin_wants:
                    try:
                        # in case plugin fails 1/2 way we dont want partial inventory
                        plugin.parse(self._inventory, self._loader, source, cache=cache)
                        parsed = True
                        display.vvv('Parsed %s inventory source with %s plugin' % (to_text(source), plugin_name))
                        break
                    except AnsibleParserError as e:
                        display.debug('%s was not parsable by %s' % (to_text(source), plugin_name))
                        failures.append({'src': source, 'plugin': plugin_name, 'exc': e})
                    except Exception as e:
                        display.debug('%s failed to parse %s' % (plugin_name, to_text(source)))
                        failures.append({'src': source, 'plugin': plugin_name, 'exc': e})
                else:
                    display.debug('%s did not meet %s requirements' % (to_text(source), plugin_name))
            else:
                if not parsed and failures:
                    # only if no plugin processed files should we show errors.
                    for fail in failures:
                        display.warning(u'\n* Failed to parse %s with %s plugin: %s' % (to_text(fail['src']), fail['plugin'], to_text(fail['exc'])))
                        if hasattr(fail['exc'], 'tb'):
                            display.vvv(to_text(fail['exc'].tb))
        if not parsed:
            display.warning("Unable to parse %s as an inventory source" % to_text(source))

        # clear up, jic
        self._inventory.current_source = None

        return parsed
Beispiel #55
0
def set_module_args(args):
    if 'provider' not in args:
        args['provider'] = {'transport': args.get('transport') or 'cli'}

    args = json.dumps({'ANSIBLE_MODULE_ARGS': args})
    basic._ANSIBLE_ARGS = to_bytes(args)
Beispiel #56
0
    sudo             = ('ansible_sudo',),
    sudo_user        = ('ansible_sudo_user',),
    sudo_pass        = ('ansible_sudo_password', 'ansible_sudo_pass'),
    sudo_exe         = ('ansible_sudo_exe',),
    sudo_flags       = ('ansible_sudo_flags',),
    su               = ('ansible_su',),
    su_user          = ('ansible_su_user',),
    su_pass          = ('ansible_su_password', 'ansible_su_pass'),
    su_exe           = ('ansible_su_exe',),
    su_flags         = ('ansible_su_flags',),
    executable       = ('ansible_shell_executable',),
    module_compression = ('ansible_module_compression',),
)

b_SU_PROMPT_LOCALIZATIONS = [
    to_bytes('Password'),
    to_bytes('암호'),
    to_bytes('パスワード'),
    to_bytes('Adgangskode'),
    to_bytes('Contraseña'),
    to_bytes('Contrasenya'),
    to_bytes('Hasło'),
    to_bytes('Heslo'),
    to_bytes('Jelszó'),
    to_bytes('Lösenord'),
    to_bytes('Mật khẩu'),
    to_bytes('Mot de passe'),
    to_bytes('Parola'),
    to_bytes('Parool'),
    to_bytes('Pasahitza'),
    to_bytes('Passord'),
Beispiel #57
0
    def _put_file_new(self, in_path, out_path):
        copy_script = '''begin {
    $ErrorActionPreference = "Stop"
    $WarningPreference = "Continue"
    $path = $MyInvocation.UnboundArguments[0]
    $fd = [System.IO.File]::Create($path)
    $algo = [System.Security.Cryptography.SHA1CryptoServiceProvider]::Create()
    $bytes = @()

    $bindingFlags = [System.Reflection.BindingFlags]'NonPublic, Instance'
    Function Get-Property {
        <#
        .SYNOPSIS
        Gets the private/internal property specified of the object passed in.
        #>
        Param (
            [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
            [System.Object]
            $Object,

            [Parameter(Mandatory=$true, Position=1)]
            [System.String]
            $Name
        )

        $Object.GetType().GetProperty($Name, $bindingFlags).GetValue($Object, $null)
    }

    Function Set-Property {
        <#
        .SYNOPSIS
        Sets the private/internal property specified on the object passed in.
        #>
        Param (
            [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
            [System.Object]
            $Object,

            [Parameter(Mandatory=$true, Position=1)]
            [System.String]
            $Name,

            [Parameter(Mandatory=$true, Position=2)]
            [AllowNull()]
            [System.Object]
            $Value
        )

        $Object.GetType().GetProperty($Name, $bindingFlags).SetValue($Object, $Value, $null)
    }

    Function Get-Field {
        <#
        .SYNOPSIS
        Gets the private/internal field specified of the object passed in.
        #>
        Param (
            [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
            [System.Object]
            $Object,

            [Parameter(Mandatory=$true, Position=1)]
            [System.String]
            $Name
        )

        $Object.GetType().GetField($Name, $bindingFlags).GetValue($Object)
    }

    # MaximumAllowedMemory is required to be set to so we can send input data that exceeds the limit on a PS
    # Runspace. We use reflection to access/set this property as it is not accessible publicly. This is not ideal
    # but works on all PowerShell versions I've tested with. We originally used WinRS to send the raw bytes to the
    # host but this falls flat if someone is using a custom PS configuration name so this is a workaround. This
    # isn't required for smaller files so if it fails we ignore the error and hope it wasn't needed.
    # https://github.com/PowerShell/PowerShell/blob/c8e72d1e664b1ee04a14f226adf655cced24e5f0/src/System.Management.Automation/engine/serialization.cs#L325
    try {
        $Host | Get-Property 'ExternalHost' | `
            Get-Field '_transportManager' | `
            Get-Property 'Fragmentor' | `
            Get-Property 'DeserializationContext' | `
            Set-Property 'MaximumAllowedMemory' $null
    } catch {}
}
process {
    $bytes = [System.Convert]::FromBase64String($input)
    $algo.TransformBlock($bytes, 0, $bytes.Length, $bytes, 0) > $null
    $fd.Write($bytes, 0, $bytes.Length)
}
end {
    $fd.Close()

    $algo.TransformFinalBlock($bytes, 0, 0) > $null
    $hash = [System.BitConverter]::ToString($algo.Hash).Replace('-', '').ToLowerInvariant()
    Write-Output -InputObject "{`"sha1`":`"$hash`"}"
}
'''

        # Get the buffer size of each fragment to send, subtract 82 for the fragment, message, and other header info
        # fields that PSRP adds. Adjust to size of the base64 encoded bytes length.
        buffer_size = int((self.runspace.connection.max_payload_size - 82) / 4 * 3)

        sha1_hash = sha1()

        b_in_path = to_bytes(in_path, errors='surrogate_or_strict')
        if not os.path.exists(b_in_path):
            raise AnsibleFileNotFound('file or module does not exist: "%s"' % to_native(in_path))

        def read_gen():
            offset = 0

            with open(b_in_path, 'rb') as src_fd:
                for b_data in iter((lambda: src_fd.read(buffer_size)), b""):
                    data_len = len(b_data)
                    offset += data_len
                    sha1_hash.update(b_data)

                    # PSRP technically supports sending raw bytes but that method requires a larger CLIXML message.
                    # Sending base64 is still more efficient here.
                    display.vvvvv("PSRP PUT %s to %s (offset=%d, size=%d" % (in_path, out_path, offset, data_len),
                                  host=self._psrp_host)
                    b64_data = base64.b64encode(b_data)
                    yield [to_text(b64_data)]

                if offset == 0:  # empty file
                    yield [""]

        rc, stdout, stderr = self._exec_psrp_script(copy_script, read_gen(), arguments=[out_path], force_stop=True)

        return rc, stdout, stderr, sha1_hash.hexdigest()
Beispiel #58
0
    def fetch_file(self, in_path, out_path):
        super(Connection, self).fetch_file(in_path, out_path)
        display.vvv("FETCH %s TO %s" % (in_path, out_path),
                    host=self._psrp_host)

        in_path = self._shell._unquote(in_path)
        out_path = out_path.replace('\\', '/')

        # because we are dealing with base64 data we need to get the max size
        # of the bytes that the base64 size would equal
        max_b64_size = int(self.runspace.connection.max_payload_size -
                           (self.runspace.connection.max_payload_size / 4 * 3))
        buffer_size = max_b64_size - (max_b64_size % 1024)

        # setup the file stream with read only mode
        setup_script = '''$ErrorActionPreference = "Stop"
$path = '%s'

if (Test-Path -Path $path -PathType Leaf) {
    $fs = New-Object -TypeName System.IO.FileStream -ArgumentList @(
        $path,
        [System.IO.FileMode]::Open,
        [System.IO.FileAccess]::Read,
        [System.IO.FileShare]::Read
    )
    $buffer_size = %d
} elseif (Test-Path -Path $path -PathType Container) {
    Write-Output -InputObject "[DIR]"
} else {
    Write-Error -Message "$path does not exist"
    $host.SetShouldExit(1)
}''' % (self._shell._escape(in_path), buffer_size)

        # read the file stream at the offset and return the b64 string
        read_script = '''$ErrorActionPreference = "Stop"
$fs.Seek(%d, [System.IO.SeekOrigin]::Begin) > $null
$buffer = New-Object -TypeName byte[] -ArgumentList $buffer_size
$bytes_read = $fs.Read($buffer, 0, $buffer_size)

if ($bytes_read -gt 0) {
    $bytes = $buffer[0..($bytes_read - 1)]
    Write-Output -InputObject ([System.Convert]::ToBase64String($bytes))
}'''

        # need to run the setup script outside of the local scope so the
        # file stream stays active between fetch operations
        rc, stdout, stderr = self._exec_psrp_script(setup_script,
                                                    use_local_scope=False,
                                                    force_stop=True)
        if rc != 0:
            raise AnsibleError("failed to setup file stream for fetch '%s': %s"
                               % (out_path, to_native(stderr)))
        elif stdout.strip() == '[DIR]':
            # to be consistent with other connection plugins, we assume the caller has created the target dir
            return

        b_out_path = to_bytes(out_path, errors='surrogate_or_strict')
        # to be consistent with other connection plugins, we assume the caller has created the target dir
        offset = 0
        with open(b_out_path, 'wb') as out_file:
            while True:
                display.vvvvv("PSRP FETCH %s to %s (offset=%d" %
                              (in_path, out_path, offset), host=self._psrp_host)
                rc, stdout, stderr = self._exec_psrp_script(read_script % offset, force_stop=True)
                if rc != 0:
                    raise AnsibleError("failed to transfer file to '%s': %s"
                                       % (out_path, to_native(stderr)))

                data = base64.b64decode(stdout.strip())
                out_file.write(data)
                if len(data) < buffer_size:
                    break
                offset += len(data)

            rc, stdout, stderr = self._exec_psrp_script("$fs.Close()", force_stop=True)
            if rc != 0:
                display.warning("failed to close remote file stream of file "
                                "'%s': %s" % (in_path, to_native(stderr)))
Beispiel #59
0
def main():

    # the command module is the one ansible module that does not take key=value args
    # hence don't copy this one if you are looking to build others!
    # NOTE: ensure splitter.py is kept in sync for exceptions
    module = AnsibleModule(
        argument_spec=dict(
            _raw_params=dict(),
            _uses_shell=dict(type='bool', default=False),
            argv=dict(type='list', elements='str'),
            chdir=dict(type='path'),
            executable=dict(),
            creates=dict(type='path'),
            removes=dict(type='path'),
            # The default for this really comes from the action plugin
            warn=dict(type='bool',
                      default=False,
                      removed_in_version='2.14',
                      removed_from_collection='ansible.builtin'),
            stdin=dict(required=False),
            stdin_add_newline=dict(type='bool', default=True),
            strip_empty_ends=dict(type='bool', default=True),
        ),
        supports_check_mode=True,
    )
    shell = module.params['_uses_shell']
    chdir = module.params['chdir']
    executable = module.params['executable']
    args = module.params['_raw_params']
    argv = module.params['argv']
    creates = module.params['creates']
    removes = module.params['removes']
    warn = module.params['warn']
    stdin = module.params['stdin']
    stdin_add_newline = module.params['stdin_add_newline']
    strip = module.params['strip_empty_ends']

    # we promissed these in 'always' ( _lines get autoaded on action plugin)
    r = {
        'changed': False,
        'stdout': '',
        'stderr': '',
        'rc': None,
        'cmd': None,
        'start': None,
        'end': None,
        'delta': None,
        'msg': ''
    }

    if not shell and executable:
        module.warn(
            "As of Ansible 2.4, the parameter 'executable' is no longer supported with the 'command' module. Not using '%s'."
            % executable)
        executable = None

    if (not args or args.strip() == '') and not argv:
        r['rc'] = 256
        r['msg'] = "no command given"
        module.fail_json(**r)

    if args and argv:
        r['rc'] = 256
        r['msg'] = "only command or argv can be given, not both"
        module.fail_json(**r)

    if not shell and args:
        args = shlex.split(args)

    args = args or argv
    # All args must be strings
    if is_iterable(args, include_strings=False):
        args = [
            to_native(arg,
                      errors='surrogate_or_strict',
                      nonstring='simplerepr') for arg in args
        ]

    r['cmd'] = args
    if warn:
        # nany telling you to use module instead!
        check_command(module, args)

    if chdir:
        chdir = to_bytes(chdir, errors='surrogate_or_strict')

        try:
            os.chdir(chdir)
        except (IOError, OSError) as e:
            r['msg'] = 'Unable to change directory before execution: %s' % to_text(
                e)
            module.fail_json(**r)

    # check_mode partial support, since it only really works in checking creates/removes
    if module.check_mode:
        shoulda = "Would"
    else:
        shoulda = "Did"

    # special skips for idempotence if file exists (assumes command creates)
    if creates:
        if glob.glob(creates):
            r['msg'] = "%s not run command since '%s' exists" % (shoulda,
                                                                 creates)
            r['stdout'] = "skipped, since %s exists" % creates  # TODO: deprecate

            r['rc'] = 0

    # special skips for idempotence if file does not exist (assumes command removes)
    if not r['msg'] and removes:
        if not glob.glob(removes):
            r['msg'] = "%s not run command since '%s' does not exist" % (
                shoulda, removes)
            r['stdout'] = "skipped, since %s does not exist" % removes  # TODO: deprecate
            r['rc'] = 0

    if r['msg']:
        module.exit_json(**r)

    # actually executes command (or not ...)
    if not module.check_mode:
        r['start'] = datetime.datetime.now()
        r['rc'], r['stdout'], r['stderr'] = module.run_command(
            args,
            executable=executable,
            use_unsafe_shell=shell,
            encoding=None,
            data=stdin,
            binary_data=(not stdin_add_newline))
        r['end'] = datetime.datetime.now()
    else:
        # this is partial check_mode support, since we end up skipping if we get here
        r['rc'] = 0
        r['msg'] = "Command would have run if not in check mode"
        if creates is None and removes is None:
            r['skipped'] = True

    r['changed'] = True

    # convert to text for jsonization and usability
    if r['start'] is not None and r['end'] is not None:
        # these are datetime objects, but need them as strings to pass back
        r['delta'] = to_text(r['end'] - r['start'])
        r['end'] = to_text(r['end'])
        r['start'] = to_text(r['start'])

    if strip:
        r['stdout'] = to_text(r['stdout']).rstrip("\r\n")
        r['stderr'] = to_text(r['stderr']).rstrip("\r\n")

    if r['rc'] != 0:
        r['msg'] = 'non-zero return code'
        module.fail_json(**r)

    module.exit_json(**r)
Beispiel #60
0
    def exec_command(self, cmd, in_data=None, sudoable=True):
        ''' run a command on the remote host '''

        super(Connection, self).exec_command(cmd,
                                             in_data=in_data,
                                             sudoable=sudoable)

        if in_data:
            raise 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:
            text_e = to_text(e)
            msg = u"Failed to open session"
            if text_e:
                msg += u": %s" % text_e
            raise AnsibleConnectionFailure(to_native(msg))

        # sudo usually requires a PTY (cf. requiretty option), therefore
        # we give it one by default (pty=True in ansible.cfg), and we try
        # to initialise from the calling environment when sudoable is enabled
        if self.get_option('pty') and sudoable:
            chan.get_pty(term=os.getenv('TERM', 'vt100'),
                         width=int(os.getenv('COLUMNS', 0)),
                         height=int(os.getenv('LINES', 0)))

        display.vvv("EXEC %s" % cmd, host=self._play_context.remote_addr)

        cmd = to_bytes(cmd, errors='surrogate_or_strict')

        no_prompt_out = b''
        no_prompt_err = b''
        become_output = b''

        try:
            chan.exec_command(cmd)
            if self._play_context.prompt:
                passprompt = False
                become_sucess = False
                while not (become_sucess or passprompt):
                    display.debug('Waiting for Privilege Escalation input')

                    chunk = chan.recv(bufsize)
                    display.debug("chunk is: %s" % chunk)
                    if not chunk:
                        if b'unknown user' in become_output:
                            raise AnsibleError('user %s does not exist' %
                                               self._play_context.become_user)
                        else:
                            break
                            # raise AnsibleError('ssh connection closed waiting for password prompt')
                    become_output += chunk

                    # need to check every line because we might get lectured
                    # and we might get the middle of a line in a chunk
                    for l in become_output.splitlines(True):
                        if self.check_become_success(l):
                            become_sucess = True
                            break
                        elif self.check_password_prompt(l):
                            passprompt = True
                            break

                if passprompt:
                    if self._play_context.become and self._play_context.become_pass:
                        chan.sendall(
                            to_bytes(self._play_context.become_pass) + b'\n')
                    else:
                        raise AnsibleError(
                            "A password is required but none was supplied")
                else:
                    no_prompt_out += become_output
                    no_prompt_err += become_output
        except socket.timeout:
            raise AnsibleError(
                'ssh timed out waiting for privilege escalation.\n' +
                become_output)

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

        return (chan.recv_exit_status(), no_prompt_out + stdout,
                no_prompt_out + stderr)