[PATCH] Removed message option from de/select
by Josh Adams
Fixes bug #7915
---
src/bin/secstate | 10 ++++------
src/secstate/main.py | 4 ++--
src/secstate/util.py | 4 ----
3 files changed, 6 insertions(+), 12 deletions(-)
diff --git a/src/bin/secstate b/src/bin/secstate
index f658dc9..3d8df51 100644
--- a/src/bin/secstate
+++ b/src/bin/secstate
@@ -125,9 +125,9 @@ def help(arg):
elif arg[0] == 'remove':
remove(['-h'])
elif arg[0] == 'select':
- select(['-h'])
+ select(['-h'], None)
elif arg[0] == 'deselect':
- select(['-h'])
+ select(['-h'], None)
elif arg[0] == 'audit':
audit(['-h'])
elif arg[0] == 'search':
@@ -183,17 +183,15 @@ def select(arguments, value):
sel = "de"
parser = OptionParser(usage="secstate %(sel)sselect <benchmark> [options] [id]" % {'sel':sel})
- parser.add_option('-m', '--message', action='store', type='string', dest='message',
- default=None, help="Adds message about %(sel)sselection" % {'sel':sel})
parser.add_option('-r', '--recurse', action='store_true', dest='recurse', default=False,
help="Recursively %(sel)sselect rules inside of groups or benchmarks" % {'sel':sel})
(options, args) = parser.parse_args(arguments)
if len(args) == 1:
- if not sec_instance.select(args[0], args[0], value, recurse=options.recurse, message=options.message):
+ if not sec_instance.select(args[0], args[0], value, recurse=options.recurse):
return -1
else:
for arg in args[1:]:
- if (not (sec_instance.select(args[0], arg, value, recurse=options.recurse, message=options.message))):
+ if (not (sec_instance.select(args[0], arg, value, recurse=options.recurse))):
return -1
def audit(arguments):
diff --git a/src/secstate/main.py b/src/secstate/main.py
index 711d335..d584ff5 100644
--- a/src/secstate/main.py
+++ b/src/secstate/main.py
@@ -511,13 +511,13 @@ class Secstate:
return True
- def select(self, benchmark_id, item_id, selected, recurse=False, message=None):
+ def select(self, benchmark_id, item_id, selected, recurse=False):
"""
Function: Set the specified item to be selected, as well as its subelements
Input: Benchmark id, id of rule or group, boolean value to set the items selected status
Output: Succes or failure
"""
- sel_dict = {'selected':selected, 'message':message}
+ sel_dict = {'selected':selected}
if not self.content.has_key(benchmark_id):
self.log.error("No benchmark %(id)s in datastore" % {'id':benchmark_id})
diff --git a/src/secstate/util.py b/src/secstate/util.py
index b6a25e4..387b16e 100644
--- a/src/secstate/util.py
+++ b/src/secstate/util.py
@@ -397,10 +397,6 @@ def apply_changes_profile(benchmark):
select = oscap.xccdf.select_new()
select.item = id
select.selected = sel_dict['selected']
- if sel_dict['message']:
- text = oscap.common.text_new()
- text.text = str(sel_dict['message'])
- select.add_remark(text)
prof.add_select(select)
benchmark.add_profile(prof)
--
1.7.2.2
13 years, 9 months
[PATCH] Removed references to CPE support
by Josh Adams
Fixes bug #7906
---
src/bin/secstate | 4 +---
src/secstate/main.py | 4 ++--
2 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/src/bin/secstate b/src/bin/secstate
index f658dc9..7f03e61 100644
--- a/src/bin/secstate
+++ b/src/bin/secstate
@@ -148,8 +148,6 @@ def help(arg):
def import_content(arguments):
parser = OptionParser(usage="secstate import [options] <content>")
- parser.add_option('-c', '--cpe', action='store_true', dest='cpe', default=False,
- help="Imports the specified CPE content")
parser.add_option('-p', '--puppet', action='store_true', dest='puppet', default=False,
help="Imports the specified puppet content")
parser.add_option('--profile', action='store', type='string', dest='profile', default=secstate.NONE_PROFILE,
@@ -157,7 +155,7 @@ def import_content(arguments):
(options, args) = parser.parse_args(arguments)
for arg in args:
- content = sec_instance.import_content(arg, options.cpe, options.puppet, save=True, active_profile=options.profile)
+ content = sec_instance.import_content(arg, options.puppet, save=True, active_profile=options.profile)
if content == None:
return -1
diff --git a/src/secstate/main.py b/src/secstate/main.py
index 711d335..3c63d83 100644
--- a/src/secstate/main.py
+++ b/src/secstate/main.py
@@ -391,7 +391,7 @@ class Secstate:
return benchmark
- def import_content(self, content, cpe=False, puppet=False, changes=True, save=False, active_profile=NONE_PROFILE):
+ def import_content(self, content, puppet=False, changes=True, save=False, active_profile=NONE_PROFILE):
"""
Function: Validates XCCDF/OVAL content and optionally saves it to the data store
Input: File containing content
@@ -411,7 +411,7 @@ class Secstate:
return None
if self.content.has_key(content):
- return self.import_content(self.content[content], cpe, puppet, changes, active_profile=active_profile)
+ return self.import_content(self.content[content], puppet, changes, active_profile=active_profile)
if save:
store_path = self.config.get('secstate', 'benchmark_dir')
--
1.7.2.2
13 years, 9 months
[PATCH] Fixed import with nonexistent profile
by Josh Adams
Got rid of traceback and replaced with error message.
Fixes bug #7907
---
src/secstate/main.py | 7 ++++++-
1 files changed, 6 insertions(+), 1 deletions(-)
diff --git a/src/secstate/main.py b/src/secstate/main.py
index 711d335..053e657 100644
--- a/src/secstate/main.py
+++ b/src/secstate/main.py
@@ -258,7 +258,12 @@ class Secstate:
benchmark.vals[val.id] = value_instance_to_value(val_instance)
current_profile = benchmark.config.get(benchmark.id, 'profile')
- profile = benchmark.get_item(current_profile).to_profile()
+ prof_item = benchmark.get_item(current_profile)
+ if prof_item == None:
+ self.log.error("Import failed: profile '%(prof)s' does not exist" % {'prof':current_profile})
+ return None
+
+ profile = prof_item.to_profile()
prof_sel = get_profile_selections(benchmark, profile)
for key,val in prof_sel.items():
benchmark.selections[key] = val
--
1.7.2.2
13 years, 9 months
[PATCH] Allow importing of zips with one toplevel dir
by Josh Adams
Fixes bug #7887
---
src/secstate/main.py | 8 ++++++--
1 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/secstate/main.py b/src/secstate/main.py
index 711d335..13ae9b1 100644
--- a/src/secstate/main.py
+++ b/src/secstate/main.py
@@ -372,12 +372,16 @@ class Secstate:
# Now that the files have been extracted, find the benchmark and store the content if necessary
xccdf = None
directory = None
+ extracted_files = os.listdir(extract_path)
+ if (len(extracted_files) == 1) and os.path.isdir(os.path.join(extract_path, extracted_files[0])):
+ extract_path = os.path.join(extract_path, extracted_files[0])
+
for extracted_file in os.listdir(extract_path):
print extracted_file
- if mimetypes.guess_type(extracted_file)[0] == "text/xml":
+ if mimetypes.guess_type(os.path.join(extract_path, extracted_file))[0] == "text/xml":
if is_benchmark(os.path.join(extract_path, extracted_file)):
xccdf = extracted_file
-
+
if xccdf == None:
self.log.error("Could not find XCCDF benchmark in archive %(file)s", {'file':zip})
return None
--
1.7.2.2
13 years, 9 months
[PATCH] Only require root if it secstate needs it
by Josh Adams
Allow normal users to run help, export, list, and show
Fixes bug #6967
---
src/bin/secstate | 33 +++++++++++++++++----------------
1 files changed, 17 insertions(+), 16 deletions(-)
diff --git a/src/bin/secstate b/src/bin/secstate
index f658dc9..01a9f0a 100644
--- a/src/bin/secstate
+++ b/src/bin/secstate
@@ -52,9 +52,6 @@ Sub-commands:
sec_instance = secstate.Secstate(CONFIG_FILE)
def main():
- if os.geteuid() != 0:
- sys.stderr.write("secstate must be run as root!\n")
- return -1
try:
subcommand = sys.argv[1]
@@ -77,12 +74,25 @@ def main():
if subcommand == 'help':
return help(sys.argv[arg_num:])
- if subcommand == 'import':
- return import_content(sys.argv[arg_num:])
-
elif subcommand == 'export':
return export(sys.argv[arg_num:])
+ elif subcommand == 'search':
+ return search(sys.argv[arg_num:])
+
+ elif subcommand == 'list':
+ return list_content(sys.argv[arg_num:])
+
+ elif subcommand == 'show':
+ return show(sys.argv[arg_num:])
+
+ elif os.geteuid() != 0:
+ sys.stderr.write("secstate must be run as root!\n")
+ return -1
+
+ elif subcommand == 'import':
+ return import_content(sys.argv[arg_num:])
+
elif subcommand == 'remove':
return remove_content(sys.argv[arg_num:])
@@ -94,16 +104,7 @@ def main():
elif subcommand == 'audit':
return audit(sys.argv[arg_num:])
-
- elif subcommand == 'search':
- return search(sys.argv[arg_num:])
-
- elif subcommand == 'list':
- return list_content(sys.argv[arg_num:])
-
- elif subcommand == 'show':
- return show(sys.argv[arg_num:])
-
+
elif subcommand == 'remediate':
return remediate(sys.argv[arg_num:])
--
1.7.2.2
13 years, 9 months
[PATCH] Fixed the behavior of the 'audit -a' command
by Josh Adams
Will now audit everything, even if rules are not selected
Fixes bug #7613
---
src/secstate/main.py | 13 +++++++------
1 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/src/secstate/main.py b/src/secstate/main.py
index 711d335..3b748d8 100644
--- a/src/secstate/main.py
+++ b/src/secstate/main.py
@@ -656,18 +656,19 @@ class Secstate:
# If benchmark
if scanned_content.__dict__.has_key('oval'):
- if rule != None:
- if scanned_content.get_item(rule) == None:
- self.log.error("Benchmark '%(bench)s' does not contain rule '%(id)s'" % {'bench':scanned_content.id,
- 'id':rule})
- return False
+ if all or (rule != None):
+ if rule != None:
+ if scanned_content.get_item(rule) == None:
+ self.log.error("Benchmark '%(bench)s' does not contain rule '%(id)s'" % {'bench':scanned_content.id,
+ 'id':rule})
+ return False
tmp_prof = oscap.xccdf.profile_new()
tmp_prof.id = '__tmp__'
for item in scanned_content.selections.keys():
sel = oscap.xccdf.select_new()
sel.item = item
- if item == rule or is_parent(scanned_content.get_item(item), scanned_content.get_item(rule)):
+ if all or (item == rule) or is_parent(scanned_content.get_item(item), scanned_content.get_item(rule)):
sel.selected = True
else:
sel.selected = False
--
1.7.2.2
13 years, 9 months
[PATCH] Fixed return code when importing OVAL content
by Josh Adams
Fixes bug #7413
---
src/secstate/main.py | 1 -
1 files changed, 0 insertions(+), 1 deletions(-)
diff --git a/src/secstate/main.py b/src/secstate/main.py
index 711d335..ad3720a 100644
--- a/src/secstate/main.py
+++ b/src/secstate/main.py
@@ -193,7 +193,6 @@ class Secstate:
conf_file = open(os.path.join(self.config.get('secstate', 'conf_dir'), id + ".cfg"), 'w')
config.write(conf_file)
conf_file.close()
- return None
return def_model
--
1.7.2.2
13 years, 9 months
[PATCH] Added ability to audit non-imported content
by Josh Adams
Users can now specify args for benchmarks that have been imported or for
files that have not been imported, even in the same command.
---
src/secstate/main.py | 67 ++++++++++++++++++++++++++++++++------------------
1 files changed, 43 insertions(+), 24 deletions(-)
diff --git a/src/secstate/main.py b/src/secstate/main.py
index a4a6436..711d335 100644
--- a/src/secstate/main.py
+++ b/src/secstate/main.py
@@ -273,6 +273,11 @@ class Secstate:
benchmark.vals[refval.item] = value_instance_to_value(value.get_instance_by_selector(refval.selector))
puppet_files = get_puppet_files(benchmark)
+ if store_path == None:
+ if self.content.has_key(benchmark.id):
+ puppet_files = map(lambda x: os.path.join(self.config.get('secstate', 'puppet_dir'), x), puppet_files)
+ else:
+ puppet_files = map(lambda x: os.path.join(os.path.dirname(benchmark_file), x), puppet_files)
benchmark.__dict__['puppet'] = puppet_files
benchmark.config.set(benchmark.id, 'puppet', json.dumps(list(puppet_files)))
@@ -295,7 +300,7 @@ class Secstate:
for oval in list(set(oval_files)):
shutil.copy(os.path.join(oval_path, oval), directory)
- for puppet in puppet_files:
+ for puppet in benchmark.puppet:
new_puppet = os.path.join(os.path.dirname(benchmark_file), puppet)
puppet_dir = self.config.get('secstate', 'puppet_dir')
if not os.path.isdir(puppet_dir):
@@ -311,6 +316,7 @@ class Secstate:
continue
shutil.copy(os.path.join(os.path.dirname(benchmark_file), puppet), self.config.get('secstate', 'puppet_dir'))
+ puppet = os.path.join(puppet_dir, puppet)
except (IOError, OSError), e:
self.log.error("Error importing content: %(error)s" % {'error':e})
@@ -368,8 +374,9 @@ class Secstate:
directory = None
for extracted_file in os.listdir(extract_path):
print extracted_file
- if is_benchmark(os.path.join(extract_path, extracted_file)):
- xccdf = extracted_file
+ if mimetypes.guess_type(extracted_file)[0] == "text/xml":
+ if is_benchmark(os.path.join(extract_path, extracted_file)):
+ xccdf = extracted_file
if xccdf == None:
self.log.error("Could not find XCCDF benchmark in archive %(file)s", {'file':zip})
@@ -940,7 +947,11 @@ class Secstate:
ret = self.sublist(content, arg, recurse, show_all)
return ret
- def get_passed_result_ids(self, xccdf_results):
+ def get_passed_result_ids(self, xccdf_results, original_benchmarks):
+ if original_benchmarks == None:
+ self.log.error("Error importing original benchmark")
+ return (None, None)
+
if xccdf_results == None:
return ([], set())
@@ -961,50 +972,58 @@ class Secstate:
self.log.error("Error importing benchmark %(file)s" % {'file':result})
return None, None
- if not self.content.has_key(benchmark.id):
- self.log.error("Results file does not match any imported content")
- return None, None
+ if not original_benchmarks.has_key(benchmark.id):
+ self.log.info("Results file '%(file)s' does not match any remediation content, skipping" % {'file':result})
+ continue
- imported_benchmark = self.import_content(benchmark.id)
- if imported_benchmark == None:
- self.log.error("Error loading imported content: %(id)s" % {'id':benchmark.id})
- return None, None
-
result_ids.append(benchmark.id)
passing_ids = set()
for test_result in benchmark.results:
for rule_result in test_result.rule_results:
id = rule_result.idref
result = rule_result.result
- if result != oscap.xccdf.XCCDF_RESULT_FAIL or not imported_benchmark.selections[id]:
+ if result != oscap.xccdf.XCCDF_RESULT_FAIL or not original_benchmarks[benchmark.id].selections[id]:
passing_ids.add(id)
return (result_ids, passing_ids)
def remediate_puppet(self, args, xccdf_results=None, log_dest=None, noop=False, verbose=False, yes_all=False):
- (result_ids, passing_ids) = self.get_passed_result_ids(xccdf_results)
- if result_ids == None or passing_ids == None:
- return False
template = '%s\n'
if args == []:
args = self.content.keys()
+ benchmarks = {}
for arg in args:
- if arg not in result_ids and not yes_all:
- inpt = raw_input("No results file provided for %s, remediate anyway? " % arg)
- if inpt != 'y':
- continue
-
benchmark = self.import_content(arg)
if benchmark == None:
self.log.error("Error importing content: %s" % arg)
return False
if not benchmark.__dict__.has_key('oval'):
# OVAL Definition Model, so skip
+ self.log.info("Skipping OVAL File: '%(file)s'" % {'file':arg})
continue
+ benchmarks[benchmark.id] = benchmark
+
+ (result_ids, passing_ids) = self.get_passed_result_ids(xccdf_results, benchmarks)
+ if result_ids == None or passing_ids == None:
+ return False
+
+ for bench_id,benchmark in benchmarks.items():
+ if bench_id not in result_ids and not yes_all:
+ inpt = raw_input("No results file provided for %s, remediate anyway? " % bench_id)
+ if inpt != 'y':
+ continue
+
+ if self.content.has_key(bench_id):
+ site_pp = self.config.get('secstate', 'site_pp')
+ else:
+ (site_pp_buf, site_pp) = tempfile.mkstemp()
+ for puppet in benchmark.puppet:
+ os.write(site_pp_buf, 'import "%(file)s"\n' % {'file':puppet})
+ os.close(site_pp_buf)
- self.log.info("-- Remediating %(id)s --" % {'id':arg})
+ self.log.info("-- Remediating %(id)s --" % {'id':bench_id})
try:
ignore_ids = []
for key in benchmark.selections:
@@ -1019,13 +1038,13 @@ class Secstate:
if (puppet_content["classes"] == []) and (puppet_content["parameters"] == {}):
sys.stderr.write("No remediation to be done.\n")
if verbose:
- sys.stderr.write("Either results XCCDF did not report any failurse, or failures reported did not have a well formed <fix> element in the corresponding XCCDF benchmark.\n")
+ sys.stderr.write("Either results XCCDF did not report any failures, or failures reported did not have a well formed <fix> element in the corresponding XCCDF benchmark.\n")
else:
handle, fname = tempfile.mkstemp(suffix='.yaml')
os.write(handle, template % dict_to_external(puppet_content))
os.close(handle)
- puppet_args = ['/usr/bin/puppet', '--external_node', '/usr/libexec/secstate/secstate_external_node %s' % fname, '--node_terminus', 'exec', self.config.get('secstate', 'site_pp')]
+ puppet_args = ['/usr/bin/puppet', '--external_node', '/usr/libexec/secstate/secstate_external_node %s' % fname, '--node_terminus', 'exec', site_pp]
if noop:
puppet_args.append('--noop')
if log_dest:
--
1.7.2.2
13 years, 9 months
[PATCH 1/3] Fixed typo's in help messages
by Josh Adams
From: Josh Adams <jadams@tresys>
Fixes bugs #7888, 7892, and 7894
---
src/bin/secstate | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/bin/secstate b/src/bin/secstate
index 50d05d3..18dfae2 100644
--- a/src/bin/secstate
+++ b/src/bin/secstate
@@ -182,7 +182,7 @@ def select(arguments, value):
if not value:
sel = "de"
- parser = OptionParser(usage="secstate %(sel)sselect <benchmark> <all/id>" % {'sel':sel})
+ parser = OptionParser(usage="secstate %(sel)sselect <benchmark> <id>" % {'sel':sel})
parser.add_option('-m', '--message', action='store', type='string', dest='message',
default=None, help="Adds message about %(sel)sselection" % {'sel':sel})
parser.add_option('-r', '--recurse', action='store_true', dest='recurse', default=False,
@@ -287,7 +287,7 @@ def list_content(arguments):
def show(arguments):
parser = OptionParser(usage="secstate show [options] <item id>")
parser.add_option('-v', '--verbose', action='store_true', dest='verbose', default=False,
- help="Show extra information about the item being whown")
+ help="Show extra information about the item being shown")
(options, args) = parser.parse_args(arguments)
for arg in args:
if not sec_instance.show(arg, options.verbose):
--
1.7.2.2
13 years, 9 months
[PATCH] Fixed traceback when importing invalid XML
by Josh Adams
Also fixed issue removing content that did not have associated puppet
content.
Fixes bug #7897
---
src/secstate/main.py | 23 ++++++++++++-----------
src/secstate/util.py | 8 ++++++--
2 files changed, 18 insertions(+), 13 deletions(-)
diff --git a/src/secstate/main.py b/src/secstate/main.py
index 9bd0579..3f47b7b 100644
--- a/src/secstate/main.py
+++ b/src/secstate/main.py
@@ -468,17 +468,18 @@ class Secstate:
elif self.content.has_key(benchmark_id):
cfg = load_config(self.content_configs[benchmark_id])
- rem_puppet = set(json.loads(cfg.get(benchmark_id, 'puppet')))
- in_use = set()
- for key in self.content:
- if key != benchmark_id:
- key_cfg = load_config(self.content_configs[benchmark_id])
- if key_cfg.has_option(benchmark_id, 'puppet'):
- in_use = in_use.union(rem_puppet, set(json.loads(key_cfg.get(benchmark_id, 'puppet'))))
-
- for puppet_file in rem_puppet:
- if puppet_file not in in_use:
- os.remove(os.path.join(self.config.get('secstate', 'puppet_dir'), puppet_file))
+ if cfg.has_option(benchmark_id, 'puppet'):
+ rem_puppet = set(json.loads(cfg.get(benchmark_id, 'puppet')))
+ in_use = set()
+ for key in self.content:
+ if key != benchmark_id:
+ key_cfg = load_config(self.content_configs[benchmark_id])
+ if key_cfg.has_option(benchmark_id, 'puppet'):
+ in_use = in_use.union(rem_puppet, set(json.loads(key_cfg.get(benchmark_id, 'puppet'))))
+
+ for puppet_file in rem_puppet:
+ if puppet_file not in in_use:
+ os.remove(os.path.join(self.config.get('secstate', 'puppet_dir'), puppet_file))
try:
if os.path.split(cfg.get(benchmark_id, "file"))[0] != self.config.get('secstate', 'oval_dir'):
diff --git a/src/secstate/util.py b/src/secstate/util.py
index 200036e..42d2e29 100644
--- a/src/secstate/util.py
+++ b/src/secstate/util.py
@@ -277,8 +277,12 @@ def result_to_html(input, stylesheet, output, media=None):
return True
def is_benchmark(benchmark):
- tree = xml.dom.minidom.parse(benchmark)
- return (tree.getElementsByTagName("Benchmark") != [])
+ try:
+ tree = xml.dom.minidom.parse(benchmark)
+ return (tree.getElementsByTagName("Benchmark") != [])
+ except xml.parsers.expat.ExpatError,e:
+ sys.stderr.write("Error parsing '%(file)s': %(err)s" % {'file':benchmark, 'err':e})
+ return False
def get_benchmark_id(benchmark):
tree = xml.dom.minidom.parse(benchmark)
--
1.7.2.2
13 years, 9 months