blob: 126cdf8a24e67d76896ac2957e529f50b8ad8957 [file] [log] [blame]
Ivan Suzdal184c4e32018-06-06 13:55:30 +04001from __future__ import absolute_import
2from oscap.commands import xccdf, oval
3import logging
4import os
5import salt.utils
6import shutil
7import stat
8
9_OSCAP_XCCDF_EXIT_CODES_MAP = {
10 0: True, # all rules pass
11 1: False, # there is an error during evaluation
12 2: True # there is at least one rule with either fail or unknown result
13}
14
15DIR_MODE = '0750'
16
17log = logging.getLogger(__name__)
18
19def __virtual__():
20 if not salt.utils.which('oscap'):
21 return (False, 'oscap is required.')
22 return 'oscap'
23
24def eval(evaltype,
25 benchmark,
26 profile='default',
27 xccdf_version='1.2',
28 tailoring_id=None,
Ivan Udovichenko1ad59ca2018-11-30 17:01:12 +030029 cpe=None,
Ivan Suzdal184c4e32018-06-06 13:55:30 +040030 fetch_from_master=False,
31 benchmark_url=None,
32 benchmark_basepath='output',
33 saltenv='base',
34 results_dir=None):
35 '''
36 `oscap eval` wrapper
37 :param evaltype: what to evaluate, can be `xccdf` or `oval`
38 :param profile: xccdf profile (default 'default')
39 :param xccdf_version xccdf benchmark version (default 1.2)
40 :param tailoring_id id of your tailoring data (default None)
Ivan Udovichenko1ad59ca2018-11-30 17:01:12 +030041 :param cpe CPE dictionary or language for applicability checks (default None)
Ivan Suzdal184c4e32018-06-06 13:55:30 +040042 :param fetch_from_master: fetch oscap input data from the master (default False)
43 :param benchmark_basepath: basepath where the benchmark will be searched (default 'output')
44 :param saltenv: saltenv, used for cached files (default 'base')
45 :param results_dir: directory for storing results (default {{__opts__[cachedir]}}/files/openscap/latest)
46
47 :return: success,returncode,results_dir, optionally stderr
48
49 Usage example:
50
51 salt MINION oscap.eval xccdf /tmp/myxccdf.xml tailoring_id=myenv_oscap_variables profile='anssi_nt28_high'
52 '''
53 success = False
54 stderr = None
55 returncode = None
56 pillar_data = None
57
58 latest_dir = os.path.join(__opts__['cachedir'], 'files', 'openscap', 'latest')
59 results_dir = os.path.normpath(results_dir) if results_dir else latest_dir
60
61 benchmark_url = benchmark_url if benchmark_url else \
62 'salt://{}/{}'.format(benchmark_basepath,
63 os.path.dirname(benchmark))
64
65 if fetch_from_master:
66 _ret_ = __salt__['cp.cache_dir'](benchmark_url)
67 benchmark = benchmark[1:] if os.path.isabs(benchmark) else benchmark
68 benchmark = os.path.join(__opts__['cachedir'], 'files',
69 saltenv, benchmark_basepath, benchmark)
70
71 if evaltype == 'xccdf':
72 if tailoring_id:
73 pillar_data = __salt__['pillar.get']('openscap:tailoring:{}'\
74 .format(tailoring_id))
75 (stdout, stderr, rc, temp_dir) = xccdf(benchmark,
76 profile=profile,
77 pillar_data=pillar_data,
78 tailoring_id=tailoring_id,
Ivan Udovichenko1ad59ca2018-11-30 17:01:12 +030079 cpe=cpe,
Ivan Suzdal184c4e32018-06-06 13:55:30 +040080 xccdf_version=xccdf_version)
81
82 success = _OSCAP_XCCDF_EXIT_CODES_MAP[rc]
83 elif evaltype == 'oval':
84 (stdout, stderr, rc, temp_dir) = oval(benchmark)
85 success = not rc
86 else:
87 raise RuntimeError('Unsupported oscap command "{}"'.format(evaltype))
88
89 ret = {
90 'success': success,
91 'returncode': rc,
92 'results_dir': results_dir
93 }
94
95 if success:
96 mode = int(str(stat.S_IMODE(int(DIR_MODE))), 8)
97 base_dir = os.path.dirname(results_dir)
98 if os.path.isdir(results_dir):
99 shutil.rmtree(results_dir)
100 if not os.path.isdir(base_dir):
101 os.makedirs(base_dir)
102 os.chmod(base_dir, mode)
Dmitry Teselkin4938ca02018-12-18 19:37:24 +0300103 shutil.move(temp_dir, results_dir)
Ivan Suzdal598926b2018-09-04 15:05:34 +0400104 os.chmod(results_dir, mode)
Ivan Suzdal184c4e32018-06-06 13:55:30 +0400105
106 if stderr:
107 ret['stderr'] = stderr
108
109 return ret