>From fc6a9ce73035e078374cec25666dadb8fb305a1e Mon Sep 17 00:00:00 2001 From: Shawn Wells Date: Sun, 22 Dec 2013 14:48:47 -0500 Subject: [PATCH 04/25] Added testcheck.py to shared/oval/ Signed-off-by: Shawn Wells --- :000000 100644 0000000... ef052c6... A shared/oval/.gitignore :000000 100755 0000000... 77f078a... A shared/oval/idtranslate.py :000000 100644 0000000... c64edce... A shared/oval/idtranslate.pyc :000000 100755 0000000... 72e724e... A shared/oval/testcheck.py shared/oval/.gitignore | 1 + shared/oval/idtranslate.py | 138 ++++++++++++++++++++++++++++++++++++++++++++ shared/oval/idtranslate.pyc | Bin 0 -> 5083 bytes shared/oval/testcheck.py | 124 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 263 insertions(+) diff --git a/shared/oval/.gitignore b/shared/oval/.gitignore new file mode 100644 index 0000000..ef052c6 --- /dev/null +++ b/shared/oval/.gitignore @@ -0,0 +1 @@ +testids.ini diff --git a/shared/oval/idtranslate.py b/shared/oval/idtranslate.py new file mode 100755 index 0000000..77f078a --- /dev/null +++ b/shared/oval/idtranslate.py @@ -0,0 +1,138 @@ +import ConfigParser, sys +import lxml.etree as ET + +# This class is designed to handle the mapping of meaningful, human-readable +# names to IDs in the formats required by the SCAP checking systems, such as +# OVAL and OCIL. + +oval_ns = "http://oval.mitre.org/XMLSchema/oval-definitions-5" +oval_cs = "http://oval.mitre.org/XMLSchema/oval-definitions-5" + +ocil_ns = "http://scap.nist.gov/schema/ocil/2.0" +ocil_cs = "http://scap.nist.gov/schema/ocil/2" + +ovaltag_to_abbrev = { + 'definition' : 'def', + 'criteria' : 'crit', + 'test' : 'tst', + 'object' : 'obj', + 'state' : 'ste', + 'variable' : 'var', +} + +ociltag_to_abbrev = { + 'questionnaire' : 'questionnaire', + 'action' : 'testaction', + 'question' : 'question', + 'artifact' : 'artifact', + 'variable' : 'variable', +} + +ovalrefattr_to_tag = { + "definition_ref" : "definition", + "test_ref" : "test", + "object_ref" : "object", + "state_ref" : "state", + "var_ref" : "variable", +} + +ocilrefattr_to_tag = { + "question_ref" : "question", +} + +ocilrefchild_to_tag = { + "test_action_ref" : "action", +} + +def split_namespace(tag): + # returns a tuple of (namespace,name) removing any fragment id from namespace + if tag[:1] == "{": + namespace, name = tag[1:].split("}", 1) + return namespace.split("#")[0], name + else: + return (None,tag) + +def namespace_to_prefix(tag): + namespace, name = split_namespace(tag) + if namespace == ocil_ns: + return "ocil" + if namespace == oval_ns: + return "oval" + sys.exit("Error: unknown checksystem referenced in tag : %s" % tag) + +def tagname_to_abbrev(tag): + namespace, tag = split_namespace(tag) + if tag == "extend_definition": + return tag + # grab the last part of the tag name to determine its type + tag = tag.rsplit("_", 1)[-1] + if namespace == ocil_ns: + return ociltag_to_abbrev[tag] + if namespace == oval_ns: + return ovaltag_to_abbrev[tag] + sys.exit("Error: unknown checksystem referenced in tag : %s" % tag) + +class idtranslator: + def __init__(self, fname, content_id): + self.fname = fname + self.content_id = content_id + self.config = ConfigParser.ConfigParser() + f = self.config.read(fname) + if len(f) == 0: + self.__setup() + + def __get_next_id(self): + i = self.config.getint("general", "next_id") + n = "%d" % (i + 1) + self.config.set("general", "next_id", n) + return i + + def save(self): + fd = open(self.fname, "wb") + self.config.write(fd) + + def __setup(self): + self.config.add_section("general") + self.config.set("general", "next_id", "100") + self.config.add_section("assigned") + + def assign_id(self, tagname, name): + i = None + try: + i = self.config.getint("assigned", name) + except: + i = self.__get_next_id() + self.config.set("assigned", name, str(i)) + + str_id = "%s:%s:%s:%d" % (namespace_to_prefix(tagname), self.content_id, tagname_to_abbrev(tagname), i) + return str_id + + def translate(self, tree, store_defname=False): + for element in tree.getiterator(): + idname = element.get("id") + if idname: + # store the old name if requested (for OVAL definitions) + if store_defname and element.tag == "{" + oval_ns + "}definition": + metadata = element.find("{" + oval_ns + "}metadata") + if metadata is None: + metadata = ET.SubElement(element, "metadata") + defnam = ET.SubElement(metadata, "reference", ref_id=idname, source=self.content_id) + # set the element to the new identifier + element.set("id", self.assign_id(element.tag, idname)) + #continue + if element.tag == "{" + oval_ns + "}filter": + element.text = self.assign_id("{" + oval_ns + "}state", element.text) + continue + for attr in element.keys(): + if attr in ovalrefattr_to_tag.keys(): + element.set(attr,self.assign_id( "{" + oval_ns + "}" + ovalrefattr_to_tag[attr], element.get(attr))) + if attr in ocilrefattr_to_tag.keys(): + element.set(attr, self.assign_id("{" + ocil_ns + "}" + ocilrefattr_to_tag[attr], element.get(attr))) + if element.tag == "{" + ocil_ns + "}test_action_ref": + element.text = self.assign_id("{" + ocil_ns + "}action", element.text) + + self.save() + # note: the ini file is not tracked by git, see .gitignore + return tree + + diff --git a/shared/oval/idtranslate.pyc b/shared/oval/idtranslate.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c64edce37a86aa1bfad41860c6002474258d203f GIT binary patch literal 5083 zcmb_f-Etg96+S(?TJ7pTRxDY;jyJYNwg72uS49LPAi;4`6pnyVDh`4$jCNYmNUK?S zy7go5UfEB<9d|qcRXhMM!4vQTTyP2BcY3ueM5v-b(oRqJnbW7w`OZ&wSN=9V@y8GU z6nA9sSHb%OJZ{>EWcV5Bifj%0Mz+j3J(B&3Y*i(TWNS>@nq;7iOIDSwy5tywUX!&9 zq&i*=$tLiclxzyGX~|~rnw4x$*0vgwgZT~q*0O7o&Exf^;J21t7yQ=1rHm8G2-ypu zO-Qzg*OX*8@S2fqDKNeTiIb8;SIGDp22(nim+U46SoxN`hFzHOwsxSzZS7!@ret>{ zdxyhUB0t}PPDVCccL7WO5BzPohv@EkfApx`?wzFF)x+GEcC}aTw!irF>1Joo9;W(X zC9^wuk^8(?xRv+Zz0ow+Nsm^G-1*hr-bvdHrgZXd`{C++cjv!i^mG>`HJqZMa6$MF1%mEGe! zvu(GRmNwH+Z0DIT)53M()zzaHo)|f5kPO#plSCItG-qy_#pvHb`vf1oS_~8}LIVp4 zA@T;P0;qg|^dZZ_Cd}GLnWzxo1xz#mZL_78t8G2Redr*W+ykufq%3>oqvmmOQ1niV zCeovG;9ej!51VkNEp5@USu-!1KHY6TYA(AL5sjNvkD)<{N#Q~tLfI$4l)-iFS?(3_ z_!dU-+iY&5xk`lRA#aFn;(N&vRL{@84YFg%in(T{OjRF6nvpRK&tnWOBYhsQ0cn7_ ziDw_-7!h0qE249$53V8pPZ?5RT2h}>)knW(_$du}x{u1Nqmf@Ug#8;>-=29}WXUK= zHI5SvZ>@y?qpuia!B4Hu8K2^>qtUz? zdGjhANu{tVeK}hB2Ozp@Xa;VK7U0ObKAzqkrCYD;kd1%z@DK6057AicKk%LCwgcZ8 z?V#>N+R=o04Ib=@Ri)I#s<&Qa6Rt}ficNXk|2tUo@|3Zd-Ic6VZyr}#dX zWo6yDN)Iz2lZ5+ck~~F!ke?0HFtf^W==K>1VV^M9&5T(H=ulxIr06gsL-k^L(v1|*5DYyuhM)`E zfW{QI3z5_9k;i*Swg?_qyII{&v9Z~Z=4vjd>||GIDbvWMCl<$DaU3wW)%Apy1U2pv zIu~7!oH3XD%yLXW4+BJx4Z&dAvJrm=ZA?j;1`qDv4~HY?^4-E_7hFCGo;1sl5_-0Z z*D-EUpO`3IrTGlMLF)YqUB}`qW{wV~W2rYE#o#ySpd_GfyjW5&a5~Z;XM`gUD)Ovo zi!llTz))7g0X|eV#6mQxIE1P&@&ytE5gvkryyF5;2E&T%RAr%$f>lNCP@j$XW3-O= zEW1a8U)JK$DZa^ukrRIxjeiTxr3!N)o)yw?Jn&`wE@!dK#4BjRxkBSjD_+W!e466V{-E=xg8jdfKGZ-YP0PNL4r)?}RtT7o@ zqC?{cY?jfe(%rMe?y6NEQ8(?ypOZ!7h+bj{BpnxS7E0i)5QJ}$?VD`2*!%*G=WUHQ z4+KYNFYji9pwVke*b}%NsG?VGy?SIl_~858+1&?dZkX9x4Q}OAG2_GkiOOhnxzF)L K1?bfqQ~w12&o?yy literal 0 HcmV?d00001 diff --git a/shared/oval/testcheck.py b/shared/oval/testcheck.py new file mode 100755 index 0000000..72e724e --- /dev/null +++ b/shared/oval/testcheck.py @@ -0,0 +1,124 @@ +#!/usr/bin/python + +import sys, os, tempfile, subprocess, platform +import idtranslate +import lxml.etree as ET + +header = ''' + + + testcheck.py + 0.0.1 + 5.10 + 2011-09-23T13:44:00 + ''' +footer = '' + +ovalns = "{http://oval.mitre.org/XMLSchema/oval-definitions-5}" + +# globals, to make recursion easier in case we encounter extend_definition +definitions = ET.Element("definitions") +tests = ET.Element("tests") +objects = ET.Element("objects") +states = ET.Element("states") +variables = ET.Element("variables") + +# add oval elements to the global Elements defined above +def add_oval_elements(body): + tree = ET.fromstring(header + body + footer) + tree = replace_external_vars(tree) + # parse new file(string) as an etree, so we can arrange elements appropriately + for childnode in tree.findall("./" + ovalns + "def-group/*"): + # print "childnode.tag is " + childnode.tag + if childnode.tag is ET.Comment: continue + if childnode.tag == ( ovalns + "definition"): + definitions.append(childnode) + defname = childnode.get("id") + # extend_definition is a special case: must include a whole other definition + for defchild in childnode.findall(".//" + ovalns + "extend_definition"): + defid = defchild.get("definition_ref") + includedbody = read_ovaldefgroup_file(defid+".xml") + # recursively add the elements in the other file + add_oval_elements(includedbody) + if childnode.tag.endswith("_test"): tests.append(childnode) + if childnode.tag.endswith("_object"): objects.append(childnode) + if childnode.tag.endswith("_state"): states.append(childnode) + if childnode.tag.endswith("_variable"): variables.append(childnode) + return defname + +# replace external_variables with local_variables, so the definition can be tested +# independently of an XCCDF file +def replace_external_vars(tree): + # external_variable is a special case: we turn it into a local_variable so we can test + for node in tree.findall(".//"+ovalns+"external_variable"): + print "external_variable with id : " + node.get("id") + extvar_id = node.get("id") + #for envkey, envval in os.environ.iteritems(): + # print envkey + " = " + envval + #sys.exit() + if extvar_id not in os.environ.keys(): + sys.exit("external_variable specified, but no value provided via environment variable") + node.tag = ovalns + "local_variable" # replace tag name: external -> local + literal = ET.Element("literal_component") + literal.text = os.environ[extvar_id] + node.append(literal) + # TODO: assignment of external_variable via environment vars, for testing + return tree + + +def read_ovaldefgroup_file(testfile): + with open( testfile, 'r') as f: + body = f.read() + return body + +def main(): + global definitions + global tests + global objects + global states + global variables + + if len(sys.argv) < 2: + print "Provide the name of an XML file, which contains the definition to test." + sys.exit(1) + + for testfile in sys.argv[1:]: + body = read_ovaldefgroup_file(testfile) + defname = add_oval_elements(body) + 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("testids.ini", "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) + print "Evaluating with OVAL tempfile : " + fname + print "Writing results to : " + fname + "-results" + subprocess.call("oscap oval eval --results "+ fname + "-results " + fname, shell=True) + # perhaps delete tempfile? + definitions = ET.Element("definitions") + tests = ET.Element("tests") + objects = ET.Element("objects") + states = ET.Element("states") + variables = ET.Element("variables") + + sys.exit(0) + +if __name__ == "__main__": + main() + -- 1.8.3.1