コード例 #1
0
    def build_private_data_files(self, instance, **kwargs):
        '''
        Creates temporary files containing the private data.
        Returns a dictionary i.e.,

        {
            'credentials': {
                <cyborgbackup.main.models.Credential>: '/path/to/decrypted/data',
                <cyborgbackup.main.models.Credential>: '/path/to/decrypted/data',
                <cyborgbackup.main.models.Credential>: '/path/to/decrypted/data',
            }
        }
        '''
        private_data = self.build_private_data(instance, **kwargs)
        private_data_files = {'credentials': {}}
        if private_data is not None:
            ssh_ver = get_ssh_version()
            ssh_too_old = True if ssh_ver == "unknown" else Version(
                ssh_ver) < Version("6.0")
            openssh_keys_supported = ssh_ver != "unknown" and Version(
                ssh_ver) >= Version("6.5")
            for sets, data in private_data.get('credentials', {}).items():
                # Bail out now if a private key was provided in OpenSSH format
                # and we're running an earlier version (<6.5).
                if 'OPENSSH PRIVATE KEY' in data and not openssh_keys_supported:
                    raise RuntimeError(OPENSSH_KEY_ERROR)
            listpaths = []
            for sets, data in private_data.get('credentials', {}).items():
                # OpenSSH formatted keys must have a trailing newline to be
                # accepted by ssh-add.
                if 'OPENSSH PRIVATE KEY' in data and not data.endswith('\n'):
                    data += '\n'
                # For credentials used with ssh-add, write to a named pipe which
                # will be read then closed, instead of leaving the SSH key on disk.
                if sets and not ssh_too_old:
                    name = 'credential_{}'.format(sets.key)
                    path = os.path.join(kwargs['private_data_dir'], name)
                    run.open_fifo_write(path, data)
                    listpaths.append(path)
            if len(listpaths) > 1:
                private_data_files['credentials']['ssh'] = listpaths
            elif len(listpaths) == 1:
                private_data_files['credentials']['ssh'] = listpaths[0]

        return private_data_files
コード例 #2
0
    def _run(self, cmd, sudo=False, queryargs=None):
        args = []
        rc = -1
        finalOutput = []

        if self.client_user != 'root' and sudo:
            args = ['sudo', '-E'] + args
        args += cmd

        kwargs = {}
        try:
            env = {}
            for attr in dir(settings):
                if attr == attr.upper() and attr.startswith('CYBORGBACKUP_'):
                    env[attr] = str(getattr(settings, attr))

            path = tempfile.mkdtemp(prefix='cyborgbackup_module', dir='/tmp/')
            os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
            kwargs['private_data_dir'] = path

            if 'private_data_dir' in kwargs.keys():
                env['PRIVATE_DATA_DIR'] = kwargs['private_data_dir']
            passwords = {}
            for setting in Setting.objects.filter(key__contains='ssh_key'):
                set = Setting.objects.get(
                    key=setting.key.replace('ssh_key', 'ssh_password'))
                passwords['credential_{}'.format(setting.key)] = decrypt_field(
                    set, 'value')
            kwargs['passwords'] = passwords

            private_data = {'credentials': {}}
            for sets in Setting.objects.filter(key__contains='ssh_key'):
                # If we were sent SSH credentials, decrypt them and send them
                # back (they will be written to a temporary file).
                private_data['credentials'][sets] = decrypt_field(
                    sets, 'value') or ''
            private_data_files = {'credentials': {}}
            if private_data is not None:
                listpaths = []
                for sets, data in private_data.get('credentials', {}).items():
                    # OpenSSH formatted keys must have a trailing newline to be
                    # accepted by ssh-add.
                    if 'OPENSSH PRIVATE KEY' in data and not data.endswith(
                            '\n'):
                        data += '\n'
                    # For credentials used with ssh-add, write to a named pipe which
                    # will be read then closed, instead of leaving the SSH key on disk.
                    if sets:
                        name = 'credential_{}'.format(sets.key)
                        path = os.path.join(kwargs['private_data_dir'], name)
                        run.open_fifo_write(path, data)
                        listpaths.append(path)
                if len(listpaths) > 1:
                    private_data_files['credentials']['ssh'] = listpaths
                elif len(listpaths) == 1:
                    private_data_files['credentials']['ssh'] = listpaths[0]

            kwargs['private_data_files'] = private_data_files

            # May have to serialize the value
            kwargs['private_data_files'] = private_data_files
            cwd = '/tmp'

            new_args = []
            new_args += [
                'ssh', '-Ao', 'StrictHostKeyChecking=no', '-o',
                'UserKnownHostsFile=/dev/null'
            ]
            new_args += [
                '{}@{}'.format(self.client_user, self.client.hostname)
            ]
            new_args += [
                '\"echo \'####CYBMOD#####\';', ' '.join(args),
                '; exitcode=\$?; echo \'####CYBMOD#####\'; exit \$exitcode\"'
            ]
            args = new_args

            # If there is an SSH key path defined, wrap args with ssh-agent.
            private_data_files = kwargs.get('private_data_files', {})
            if 'ssh' in private_data_files.get('credentials', {}):
                ssh_key_path = private_data_files['credentials']['ssh']
            else:
                ssh_key_path = ''
            if ssh_key_path:
                ssh_auth_sock = os.path.join(kwargs['private_data_dir'],
                                             'ssh_auth.sock')
                args = run.wrap_args_with_ssh_agent(args, ssh_key_path,
                                                    ssh_auth_sock)
            # args = cmd

            expect_passwords = {}
            d = {}

            for k, v in kwargs['passwords'].items():
                d[re.compile(r'Enter passphrase for .*' + k + r':\s*?$',
                             re.M)] = k
                d[re.compile(r'Enter passphrase for .*' + k, re.M)] = k
            d[re.compile(r'Bad passphrase, try again for .*:\s*?$', re.M)] = ''

            for k, v in d.items():
                expect_passwords[k] = kwargs['passwords'].get(v, '') or ''

            if queryargs and 'password' in queryargs.keys():
                expect_passwords[re.compile(r'Enter password: \s*?$',
                                            re.M)] = queryargs['password']

            stdout_handle = io.StringIO()

            _kw = dict(
                expect_passwords=expect_passwords,
                job_timeout=120,
                idle_timeout=None,
                pexpect_timeout=getattr(settings, 'PEXPECT_TIMEOUT', 5),
            )
            status, rc = run.run_pexpect(args, cwd, env, stdout_handle, **_kw)
            stdout_handle.flush()
            output = stdout_handle.getvalue().split('\r\n')
            finalOutput = []
            start = False
            for line in output:
                if 'Enter password: '******'Enter password: '******'')
                if line == '####CYBMOD#####' and not start:
                    start = True
                if start and line != '####CYBMOD#####' and line != '':
                    finalOutput += [line]

            shutil.rmtree(kwargs['private_data_dir'])
        except Exception:
            tb = traceback.format_exc()
            if settings.DEBUG:
                logger.exception('Exception occurred while running task')
        finally:
            try:
                logger.info('finished running, producing  events.')
            except Exception:
                logger.exception(
                    'Error flushing stdout and saving event count.')
        print(rc)
        print(status)
        return finalOutput, rc