def main(): parser = create_parser() args = parser.parse_args() xccdffile = args.xccdf_file idname = args.id_name # Step over xccdf file, and find referenced check files xccdftree = ssgcommon.parse_xml_file(xccdffile) if 'unlinked-ocilref' not in xccdffile: check_that_oval_and_rule_id_match(xccdftree) checks = xccdftree.findall(".//{%s}check" % xccdf_ns) translator = idtranslate.IDTranslator(idname) oval_linker = OVALFileLinker(translator, xccdftree, checks) oval_linker.link() oval_linker.save_linked_tree() oval_linker.link_xccdf() ocil_linker = OCILFileLinker(translator, xccdftree, checks) ocil_linker.link() ocil_linker.save_linked_tree() ocil_linker.link_xccdf() newxccdffile = xccdffile.replace("unlinked", "linked") ssgcommon.ElementTree.ElementTree(xccdftree).write(newxccdffile) sys.exit(0)
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 = ssgcommon.oval_generated_header("testoval.py", oval_version, "0.0.1") testfile = find_testfile(testfile) body = read_ovaldefgroup_file(testfile) defname = add_oval_elements(body, header) ovaltree = ET.fromstring(header + footer) # append each major element type, if it has subelements for element in [definitions, tests, objects, states, variables]: if element.getchildren(): ovaltree.append(element) # re-map all the element ids from meaningful names to meaningless # numbers testtranslator = idtranslate.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)
def main(): if len(sys.argv) < 3: sys.stderr.write("Provide an XCCDF file and an ID name scheme.\n") sys.stderr.write("This script finds check-content files (currently, " "OVAL and OCIL) referenced from XCCDF and " "synchronizes all IDs.\n") sys.exit(1) xccdffile = sys.argv[1] idname = sys.argv[2] # Step over xccdf file, and find referenced check files xccdftree = parse_xml_file(xccdffile) # Create XCCDF rule ID to assigned CCE ID mapping xccdf_to_cce_id_mapping = create_xccdf_id_to_cce_id_mapping(xccdftree) # Check that OVAL IDs and XCCDF Rule IDs match if 'unlinked-ocilref' not in xccdffile: allrules = xccdftree.findall(".//{%s}Rule" % xccdf_ns) for rule in allrules: xccdf_rule = rule.get("id") if xccdf_rule is not None: checks = rule.find("./{%s}check" % xccdf_ns) if checks is not None: for check in checks: check_name = check.get("name") # Verify match of XCCDF vs OVAL / OCIL IDs for # * the case of OVAL <check> # * the case of OCIL <check> if (not xccdf_rule == check_name and check_name is not None \ and not xccdf_rule + '_ocil' == check_name \ and not xccdf_rule == 'sample_rule'): sys.stderr.write("The OVAL / OCIL ID does not " "match the XCCDF Rule ID!\n") if '_ocil' in check_name: sys.stderr.write(" OCIL ID: \'%s\'\n" % (check_name)) else: sys.stderr.write(" OVAL ID: \'%s\'\n" % (check_name)) sys.stderr.write(" XCCDF Rule ID: \'%s\'\n" % (xccdf_rule)) sys.stderr.write("Both OVAL/OCIL and XCCDF Rule " "IDs must match!" % (xccdf_rule)) sys.exit(1) checks = xccdftree.findall(".//{%s}check" % xccdf_ns) ovalfiles = get_checkfiles(checks, oval_cs) ocilfiles = get_checkfiles(checks, ocil_cs) if len(ovalfiles) > 1 or len(ocilfiles) > 1: sys.exit("referencing more than one file per check system " + "is not yet supported by this script.") ovalfile = ovalfiles.pop() if ovalfiles else None ocilfile = ocilfiles.pop() if ocilfiles else None translator = idtranslate.IDTranslator(idname) # Rename all IDs in the oval file if ovalfile: ovaltree = parse_xml_file(ovalfile) indexed_oval_defs = {} for oval_def in ovaltree.findall(".//{%s}definition" % oval_ns): oval_id = oval_def.get("id") assert (oval_id is not None) indexed_oval_defs[oval_id] = oval_def drop_oval_checks_extending_non_existing_checks(ovaltree, indexed_oval_defs) # Add new <reference source="CCE" ref_id="CCE-ID" /> element to those OVAL # checks having CCE ID already assigned in XCCDF for particular rule. # But add the <reference> only in the case CCE is in valid form! # Exit with failure if the assignment wasn't successful # Fixes: https://github.com/OpenSCAP/scap-security-guide/issues/1092 # Fixes: https://github.com/OpenSCAP/scap-security-guide/issues/1230 # Fixes: https://github.com/OpenSCAP/scap-security-guide/issues/1229 # Fixes: https://github.com/OpenSCAP/scap-security-guide/issues/1228 add_cce_id_refs_to_oval_checks(ovaltree, xccdf_to_cce_id_mapping) # Verify all by XCCDF referenced (local) OVAL checks are defined in OVAL file # If not drop the <check-content> OVAL checksystem reference from XCCDF # Fixes: https://github.com/OpenSCAP/scap-security-guide/issues/1092 # Fixes: https://github.com/OpenSCAP/scap-security-guide/issues/1095 # Fixes: https://github.com/OpenSCAP/scap-security-guide/issues/1098 ensure_by_xccdf_referenced_oval_def_is_defined_in_oval_file( xccdftree, ovaltree, indexed_oval_defs) # Verify the XCCDF to OVAL datatype export matching constraints # Fixes: https://github.com/OpenSCAP/scap-security-guide/issues/1089 check_and_correct_xccdf_to_oval_data_export_matching_constraints( xccdftree, ovaltree) # Verify if CCE identifiers present in the XCCDF follow the required form # (either CCE-XXXX-X, or CCE-XXXXX-X). Drop from XCCDF those who don't follow it verify_correct_form_of_referenced_cce_identifiers(xccdftree) ovaltree = translator.translate(ovaltree, store_defname=True) newovalfile = ovalfile.replace("unlinked", "linked") ElementTree.ElementTree(ovaltree).write(newovalfile) # Rename all IDs in the ocil file if ocilfile: ociltree = parse_xml_file(ocilfile) ociltree = translator.translate(ociltree) newocilfile = ocilfile.replace("unlinked", "linked") ElementTree.ElementTree(ociltree).write(newocilfile) # Rename all IDs and file refs in the xccdf file for check in checks: checkcontentref = check.find("./{%s}check-content-ref" % xccdf_ns) # Don't attempt to relabel ID on empty <check-content-ref> element if checkcontentref is None: continue # Obtain the value of the 'href' attribute of particular # <check-content-ref> element checkcontentref_hrefattr = checkcontentref.get("href") # Don't attempt to relabel ID on <check-content-ref> element having # its "href" attribute set either to "http://" or to "https://" values if checkcontentref_hrefattr.startswith("http://") or \ checkcontentref_hrefattr.startswith("https://"): continue if check.get("system") == oval_cs: checkid = translator.generate_id("{" + oval_ns + "}definition", checkcontentref.get("name")) checkcontentref.set("name", checkid) checkcontentref.set("href", newovalfile) checkexports = check.findall("./{%s}check-export" % xccdf_ns) for checkexport in checkexports: newexportname = translator.generate_id( "{" + oval_ns + "}variable", checkexport.get("export-name")) checkexport.set("export-name", newexportname) if check.get("system") == ocil_cs: checkid = translator.generate_id("{" + ocil_ns + "}questionnaire", checkcontentref.get("name")) checkcontentref.set("name", checkid) checkcontentref.set("href", newocilfile) checkexport = check.find("./{%s}check-export" % xccdf_ns) if checkexport is not None: newexportname = translator.generate_id( "{" + oval_ns + "}variable", checkexport.get("export-name")) checkexport.set("export-name", newexportname) newxccdffile = xccdffile.replace("unlinked", "linked") ElementTree.ElementTree(xccdftree).write(newxccdffile) sys.exit(0)
def main(): if len(sys.argv) < 2: print "Provide an OVAL file that contains inventory definitions." print("This script extracts these definitions and writes them" + " to STDOUT.") sys.exit(1) product = sys.argv[1] idname = sys.argv[2] cpeoutdir = sys.argv[3] ovalfile = sys.argv[4] cpedictfile = sys.argv[5] # parse oval file ovaltree = parse_xml_file(ovalfile) # extract inventory definitions # making (dubious) assumption that all inventory defs are CPE defs = ovaltree.find("./{%s}definitions" % oval_ns) inventory_defs = [] for el in defs.findall(".//{%s}definition" % oval_ns): if el.get("class") != "inventory": continue inventory_defs.append(el) # Keep the list of 'id' attributes from untranslated inventory def elements inventory_defs_id_attrs = [] defs.clear() [defs.append(inventory_def) for inventory_def in inventory_defs] # Fill in that list inventory_defs_id_attrs = \ [inventory_def.get("id") for inventory_def in inventory_defs] tests = ovaltree.find("./{%s}tests" % oval_ns) cpe_tests = extract_referred_nodes(defs, tests, "test_ref") tests.clear() [tests.append(cpe_test) for cpe_test in cpe_tests] states = ovaltree.find("./{%s}states" % oval_ns) cpe_states = extract_referred_nodes(tests, states, "state_ref") states.clear() [states.append(cpe_state) for cpe_state in cpe_states] objects = ovaltree.find("./{%s}objects" % oval_ns) cpe_objects = extract_referred_nodes(tests, objects, "object_ref") env_objects = extract_referred_nodes(objects, objects, "id") objects.clear() [objects.append(cpe_object) for cpe_object in cpe_objects] # if any subelements in an object contain var_ref, return it here local_var_ref = extract_subelement(objects, 'var_ref') variables = ovaltree.find("./{%s}variables" % oval_ns) if variables is not None: cpe_variables = extract_referred_nodes(tests, variables, "var_ref") local_variables = extract_referred_nodes(variables, variables, "id") if cpe_variables: variables.clear() [variables.append(cpe_variable) for cpe_variable in cpe_variables] elif local_var_ref: for local_var in local_variables: if local_var.get('id') == local_var_ref: variables.clear() variables.append(local_var) env_obj = extract_env_obj(env_objects, local_var) objects.append(env_obj) else: ovaltree.remove(variables) # turn IDs into meaningless numbers translator = idtranslate.IDTranslator(idname) ovaltree = translator.translate(ovaltree) newovalfile = idname + "-" + product + "-" + os.path.basename(ovalfile) newovalfile = newovalfile.replace("oval-unlinked", "cpe-oval") ElementTree.ElementTree(ovaltree).write(cpeoutdir + "/" + newovalfile) # replace and sync IDs, href filenames in input cpe dictionary file cpedicttree = parse_xml_file(cpedictfile) newcpedictfile = idname + "-" + os.path.basename(cpedictfile) for check in cpedicttree.findall(".//{%s}check" % cpe_ns): checkhref = check.get("href") # If CPE OVAL references another OVAL file if checkhref == 'filename': # Sanity check -- Verify the referenced OVAL is truly defined # somewhere in the (sub)directory tree below CWD. In correct # scenario is should be located: # * either in input/oval/*.xml # * or copied by former run of "combine-ovals.py" script from # shared/ directory into build/ subdirectory refovalfilename = check.text refovalfilefound = False for dirpath, dirnames, filenames in os.walk(os.curdir, topdown=True): # Case when referenced OVAL file exists for location in fnmatch.filter(filenames, refovalfilename + '.xml'): refovalfilefound = True break # break from the inner for loop if refovalfilefound: break # break from the outer for loop shared_dir = \ os.path.dirname(os.path.dirname(os.path.realpath(__file__))) if shared_dir is not None: for dirpath, dirnames, filenames in os.walk(shared_dir, topdown=True): # Case when referenced OVAL file exists for location in fnmatch.filter(filenames, refovalfilename + '.xml'): refovalfilefound = True break # break from the inner for loop if refovalfilefound: break # break from the outer for loop # Referenced OVAL doesn't exist in the subdirtree below CWD: # * there's either typo in the refenced OVAL filename, or # * is has been forgotten to be placed into input/oval, or # * the <platform> tag of particular shared/ OVAL wasn't modified # to include the necessary referenced file. # Therefore display an error and exit with failure in such cases if not refovalfilefound: error_msg = "\n\tError: Can't locate \"%s\" OVAL file in the \ \n\tlist of OVAL checks for this product! Exiting..\n" % refovalfilename sys.stderr.write(error_msg) # sys.exit(1) check.set("href", os.path.basename(newovalfile)) # Sanity check to verify if inventory check OVAL id is present in the # list of known "id" attributes of inventory definitions. If not it # means provided ovalfile (sys.argv[1]) doesn't contain this OVAL # definition (it wasn't included due to <platform> tag restrictions) # Therefore display an error and exit with failure, since otherwise # we might end up creating invalid $(ID)-$(PROD)-cpe-oval.xml file if check.text not in inventory_defs_id_attrs: error_msg = "\n\tError: Can't locate \"%s\" definition in \"%s\". \ \n\tEnsure <platform> element is configured properly for \"%s\". \ \n\tExiting..\n" % (check.text, ovalfile, check.text) sys.stderr.write(error_msg) # sys.exit(1) # Referenced OVAL checks passed both of the above sanity tests check.text = translator.generate_id("{" + oval_ns + "}definition", check.text) ElementTree.ElementTree(cpedicttree).write(cpeoutdir + '/' + newcpedictfile) sys.exit(0)
def main(): global definitions global tests global objects global states global variables global silent_mode silent_mode = False silent_mode_options = ['-q', '--quiet', '--silent'] if len(sys.argv) < 2 or len(sys.argv) > 3: print("Provide the name of an XML file, which contains" + " the definition to test.") usage() if len(sys.argv) == 3 and sys.argv[1] in silent_mode_options: if sys.argv[2].rfind('.xml') != -1: silent_mode = True sys.argv.pop(1) else: usage() if len(sys.argv) != 2 or sys.argv[1].rfind('.xml') == -1: usage() if not len(sys.argv) == 4: try: from openscap import oscap_get_version if oscap_get_version() < 1.2: schema = 5.10 else: schema = 5.11 except ImportError: schema = parse_conf_file(conf_file) else: # FUTURE: replace with sys arg schema = '5.10' testfile = sys.argv[1] header = _header(schema) testfile = find_testfile(testfile) body = read_ovaldefgroup_file(testfile) defname = add_oval_elements(body, header) ovaltree = ET.fromstring(header + footer) # append each major element type, if it has subelements for element in [definitions, tests, objects, states, variables]: if element.getchildren(): ovaltree.append(element) # re-map all the element ids from meaningful names to meaningless # numbers testtranslator = idtranslate.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("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)