def __init__(self, filepath): self.tree = None try: with open(filepath, 'r') as xccdf_file: file_string = xccdf_file.read() tree = ElementTree.fromstring(file_string) self.tree = tree except IOError as ioerr: print("%s" % ioerr) sys.exit(1) self.indexed_rules = {} for rule in self.tree.findall(".//{%s}Rule" % (xccdf_ns)): rule_id = rule.get("id") if rule_id is None: raise RuntimeError("Can't index a rule with no id attribute!") assert (rule_id not in self.indexed_rules) self.indexed_rules[rule_id] = rule
def add_sub_element(parent, tag, data): # This is used because our YAML data contain XML and XHTML elements # ET.SubElement() escapes the < > characters by < and > # and therefore it does not add child elements # we need to do a hack instead # TODO: Remove this function after we move to Markdown everywhere in SSG try: ustr = unicode("<{0}>{1}</{0}>").format(tag, data) except NameError: ustr = str("<{0}>{1}</{0}>").format(tag, data) try: element = ET.fromstring(ustr.encode("utf-8")) except Exception: msg = ("Error adding subelement to an element '{0}' from string: '{1}'" .format(parent.tag, ustr)) raise RuntimeError(msg) parent.append(element) return element
def _add_elements(body, header): """Add oval elements to the global Elements defined above""" global definitions global tests global objects global states global variables tree = ET.fromstring(header + body + footer) tree = replace_external_vars(tree) defname = None # parse new file(string) as an etree, so we can arrange elements # appropriately for childnode in tree.findall("./{%s}def-group/*" % ovalns): # print "childnode.tag is " + childnode.tag if childnode.tag is ET.Comment: continue if childnode.tag == ("{%s}definition" % ovalns): append(definitions, childnode) defname = childnode.get("id") # extend_definition is a special case: must include a whole other # definition for defchild in childnode.findall(".//{%s}extend_definition" % ovalns): defid = defchild.get("definition_ref") extend_ref = find_testfile(defid + ".xml") includedbody = read_ovaldefgroup_file(extend_ref) # recursively add the elements in the other file _add_elements(includedbody, header) if childnode.tag.endswith("_test"): append(tests, childnode) if childnode.tag.endswith("_object"): append(objects, childnode) if childnode.tag.endswith("_state"): append(states, childnode) if childnode.tag.endswith("_variable"): append(variables, childnode) return defname
def _check_oval_version_from_oval(xml_content, oval_version): try: argument = oval_header + xml_content + oval_footer oval_file_tree = ElementTree.fromstring(argument) except ElementTree.ParseError as p: line, column = p.position lines = argument.splitlines() before = '\n'.join(lines[:line]) column_pointer = ' ' * (column - 1) + '^' sys.stderr.write( "%s\n%s\nError when parsing OVAL file.\n" % (before, column_pointer)) sys.exit(1) for defgroup in oval_file_tree.findall("./{%s}def-group" % oval_ns): file_oval_version = defgroup.get("oval_version") if file_oval_version is None: # oval_version does not exist in <def-group/> # which means the OVAL is supported for any version. # By default, that version is 5.10 file_oval_version = "5.10" if tuple(oval_version.split(".")) >= tuple(file_oval_version.split(".")): return True
def main(): global definitions global tests global objects global states global variables global silent_mode args = parse_options() silent_mode = args.silent_mode oval_version = args.oval_version testfile = args.xmlfile header = oval_generated_header("testoval.py", oval_version, "0.0.1") testfile = find_testfile(testfile) body = read_ovaldefgroup_file(testfile) defname = _add_elements(body, header) if defname is None: print("Error while evaluating oval: defname not set; missing " "definitions section?") sys.exit(1) ovaltree = ET.fromstring(header + footer) # append each major element type, if it has subelements for element in [definitions, tests, objects, states, variables]: if list(element) > 0: ovaltree.append(element) # re-map all the element ids from meaningful names to meaningless # numbers testtranslator = IDTranslator("scap-security-guide.testing") ovaltree = testtranslator.translate(ovaltree) (ovalfile, fname) = tempfile.mkstemp(prefix=defname, suffix=".xml") os.write(ovalfile, ET.tostring(ovaltree)) os.close(ovalfile) if not silent_mode: print("Evaluating with OVAL tempfile: " + fname) print("OVAL Schema Version: %s" % oval_version) print("Writing results to: " + fname + "-results") cmd = "oscap oval eval --results " + fname + "-results " + fname oscap_child = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) cmd_out = oscap_child.communicate()[0] if not silent_mode: print(cmd_out) if oscap_child.returncode != 0: if not silent_mode: print("Error launching 'oscap' command: \n\t" + cmd) sys.exit(2) if 'false' in cmd_out: # at least one from the evaluated OVAL definitions evaluated to # 'false' result, exit with '1' to indicate OVAL scan FAIL result sys.exit(1) # perhaps delete tempfile? definitions = ET.Element("definitions") tests = ET.Element("tests") objects = ET.Element("objects") states = ET.Element("states") variables = ET.Element("variables") # 'false' keyword wasn't found in oscap's command output # exit with '0' to indicate OVAL scan TRUE result sys.exit(0)