1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
|
"""
Common functions for enabling derivative products
"""
from __future__ import absolute_import
from __future__ import print_function
import re
from .xml import ElementTree
from .constants import (
standard_profiles,
OSCAP_VENDOR,
cpe_dictionary_namespace,
oval_namespace,
datastream_namespace,
)
from .build_cpe import ProductCPEs, get_linked_cpe_oval_document
from .products import load_product_yaml
def add_cpes(elem, namespace, mapping):
"""
Adds derivative CPEs next to RHEL ones, checks XCCDF elements of given
namespace.
"""
affected = False
for child in list(elem):
affected = affected or add_cpes(child, namespace, mapping)
# precompute this so that we can affect the tree while iterating
children = list(elem.findall(".//{%s}platform" % (namespace)))
for child in children:
idref = child.get("idref")
if idref in mapping:
new_platform = ElementTree.Element("{%s}platform" % (namespace))
new_platform.set("idref", mapping[idref])
# this is done for the newline and indentation
new_platform.tail = child.tail
index = list(elem).index(child)
# insert it right after the respective RHEL CPE
elem.insert(index + 1, new_platform)
affected = True
return affected
def get_cpe_item(product_yaml, cpe_ref, cpe_items_dir):
product_cpes = ProductCPEs()
product_cpes.load_cpes_from_directory_tree(cpe_items_dir, product_yaml)
return product_cpes.get_cpe(cpe_ref)
def add_cpe_item_to_dictionary(
tree_root, product_yaml_path, cpe_ref, id_name, cpe_items_dir
):
cpe_list = tree_root.find(".//{%s}cpe-list" % cpe_dictionary_namespace)
if cpe_list is not None:
product_yaml = load_product_yaml(product_yaml_path)
cpe_item = get_cpe_item(product_yaml, cpe_ref, cpe_items_dir)
cpe_item.content_id = id_name
cpe_item.set_cpe_oval_def_id()
cpe_list.append(
cpe_item.to_xml_element("ssg-%s-cpe-oval.xml" % product_yaml.get("product"))
)
return cpe_item.cpe_oval_short_def_id
return None
def add_element_to(oval_root, tag_name, component_element):
xml_el = oval_root.find(".//{%s}%s" % (oval_namespace, tag_name))
if xml_el is None:
xml_el = ElementTree.Element("{%s}%s" % (oval_namespace, tag_name))
oval_root.append(xml_el)
if xml_el.find("%s[@id='%s']" % (component_element.tag, component_element.get("id"))) is None:
xml_el.append(component_element)
def add_oval_components_to_oval_xml(oval_root, tag_name, component_dict):
for component in component_dict.values():
add_element_to(oval_root, tag_name, component.get_xml_element())
def get_cpe_oval_root(root):
for component_el in root.findall("./{%s}component" % datastream_namespace):
if "cpe-oval" in component_el.get("id", ""):
return component_el
return None
def add_oval_definition_to_cpe_oval(root, unlinked_oval_file_path, oval_def_id):
oval_cpe_root = get_cpe_oval_root(root)
if oval_cpe_root is None:
raise Exception("CPE OVAL is missing in base DS!")
oval_document = get_linked_cpe_oval_document(unlinked_oval_file_path)
references_to_keep = oval_document.get_all_references_of_definition(oval_def_id)
oval_document.keep_referenced_components(references_to_keep)
add_oval_components_to_oval_xml(
oval_cpe_root, "definitions", oval_document.definitions
)
add_oval_components_to_oval_xml(oval_cpe_root, "tests", oval_document.tests)
add_oval_components_to_oval_xml(oval_cpe_root, "objects", oval_document.objects)
add_oval_components_to_oval_xml(oval_cpe_root, "states", oval_document.states)
add_oval_components_to_oval_xml(oval_cpe_root, "variables", oval_document.variables)
def add_notice(benchmark, namespace, notice, warning):
"""
Adds derivative notice as the first notice to given benchmark.
"""
index = -1
prev_element = None
existing_notices = list(benchmark.findall("./{%s}notice" % (namespace)))
if existing_notices:
prev_element = existing_notices[0]
# insert before the first notice
index = list(benchmark).index(prev_element)
else:
existing_descriptions = list(
benchmark.findall("./{%s}description" % (namespace))
)
prev_element = existing_descriptions[-1]
# insert after the last description
index = list(benchmark).index(prev_element) + 1
if index == -1:
raise RuntimeError(
"Can't find existing notices or description in benchmark '%s'." %
(benchmark)
)
elem = ElementTree.Element("{%s}notice" % (namespace))
elem.set("id", warning)
elem.append(notice)
# this is done for the newline and indentation
elem.tail = prev_element.tail
benchmark.insert(index, elem)
return True
def remove_idents(tree_root, namespace, prod="RHEL"):
"""
Remove product identifiers from rules in XML tree
"""
ident_exp = '.*' + prod + '-*'
ref_exp = prod + '-*'
for rule in tree_root.findall(".//{%s}Rule" % (namespace)):
for ident in rule.findall(".//{%s}ident" % (namespace)):
if ident is not None:
if (re.search(r'CCE-*', ident.text) or
re.search(ident_exp, ident.text)):
rule.remove(ident)
for ref in rule.findall(".//{%s}reference" % (namespace)):
if ref.text is not None:
if re.search(ref_exp, ref.text):
rule.remove(ref)
for fix in rule.findall(".//{%s}fix" % (namespace)):
sub_elems = fix.findall(".//{%s}sub" % (namespace))
for sub_elem in sub_elems:
sub_elem.tail = re.sub(r"[\s]+- CCE-.*", "", sub_elem.tail)
sub_elem.tail = re.sub(r"CCE-[0-9]*-[0-9]*", "", sub_elem.tail)
if fix.text is not None:
fix.text = re.sub(r"[\s]+- CCE-.*", "", fix.text)
fix.text = re.sub(r"CCE-[0-9]*-[0-9]*", "", fix.text)
def remove_cce_reference(tree_root, namespace):
"""
Remove CCE identifiers from OVAL checks in XML tree
"""
for definition in tree_root.findall(".//{%s}definition" % (namespace)):
for metadata in definition.findall(".//{%s}metadata" % (namespace)):
for ref in metadata.findall(".//{%s}reference" % (namespace)):
if (re.search(r'CCE-*', ref.get("ref_id"))):
metadata.remove(ref)
def profile_handling(tree_root, namespace):
ns_profiles = []
for i in standard_profiles:
ns_profiles.append("xccdf_%s.content_profile_%s" % (OSCAP_VENDOR, i))
all_profiles = standard_profiles + ns_profiles
for profile in tree_root.findall(".//{%s}Profile" % (namespace)):
if profile.get("id") not in all_profiles:
tree_root.remove(profile)
def replace_platform(tree_root, namespace, product):
for oval in tree_root.findall(".//{%s}oval_definitions" % (namespace)):
for platform in oval.findall(".//{%s}platform" % (namespace)):
platform.text = (platform.text).replace("Red Hat Enterprise Linux", product)
|