static struct xccdf_profile *_xccdf_tailoring_profile_get_real_parent(struct xccdf_tailoring *tailoring, struct xccdf_profile *profile) { const char *extends = xccdf_profile_get_extends(profile); struct xccdf_profile *parent_from_tailoring = xccdf_tailoring_get_profile_by_id(tailoring, extends); if (parent_from_tailoring != NULL && parent_from_tailoring != profile) { return parent_from_tailoring; } else { return XPROFILE(xccdf_benchmark_get_member(xccdf_profile_get_benchmark(profile), XCCDF_PROFILE, extends)); } }
static void xccdf_resolve_item(struct xccdf_item *item, struct xccdf_tailoring *tailoring) { assert(item != NULL); if (xccdf_item_get_type(item) == XCCDF_BENCHMARK) { xccdf_benchmark_set_resolved(xccdf_item_to_benchmark(item), true); return; // benchmark has no extends } assert(!xccdf_item_get_extends(item) || xccdf_item_get_type(item) & (XCCDF_PROFILE | XCCDF_ITEM)); struct xccdf_item *parent = NULL; if (xccdf_item_get_type(item) == XCCDF_PROFILE && tailoring != NULL) { parent = XITEM(_xccdf_tailoring_profile_get_real_parent(tailoring, XPROFILE(item))); } else { parent = xccdf_benchmark_get_member(xccdf_item_get_benchmark(item), xccdf_item_get_type(item), xccdf_item_get_extends(item)); } if (parent == NULL) return; if (xccdf_item_get_type(item) != xccdf_item_get_type(parent)) return; if (xccdf_item_get_type(item) == XCCDF_GROUP && xccdf_version_cmp(xccdf_item_get_schema_version(item), "1.2") >= 0) return; // Group/@extends= has been obsoleted in XCCDF 1.2 // resolve flags XCCDF_RESOLVE_FLAG(item, parent, selected); XCCDF_RESOLVE_FLAG(item, parent, hidden); XCCDF_RESOLVE_FLAG(item, parent, prohibit_changes); XCCDF_RESOLVE_FLAG(item, parent, interactive); XCCDF_RESOLVE_FLAG(item, parent, multiple); // resolve weight & version if (!item->item.defined_flags.weight) xccdf_item_set_weight(item, xccdf_item_get_weight(parent)); if (xccdf_item_get_version(item) == NULL) { xccdf_item_set_version(item, xccdf_item_get_version(parent)); xccdf_item_set_version_update(item, xccdf_item_get_version_update(parent)); xccdf_item_set_version_time(item, xccdf_item_get_version_time(parent)); } // resolve textual elements xccdf_resolve_textlist(item->item.title, parent->item.title, NULL); xccdf_resolve_textlist(item->item.description, parent->item.description, NULL); xccdf_resolve_textlist(item->item.question, parent->item.question, NULL); xccdf_resolve_textlist(item->item.rationale, parent->item.rationale, NULL); xccdf_resolve_textlist(item->item.warnings, parent->item.warnings, xccdf_resolve_warning); xccdf_resolve_textlist(item->item.references, parent->item.references, NULL); // resolve platforms OSCAP_FOR_STR(platform, xccdf_item_get_platforms(parent)) xccdf_item_add_platform(item, platform); // resolve properties specific to particular item type switch (xccdf_item_get_type(item)) { case XCCDF_PROFILE: xccdf_resolve_profile(item, parent); break; case XCCDF_GROUP: xccdf_resolve_group(item, parent); break; case XCCDF_RULE: xccdf_resolve_rule(item, parent); break; case XCCDF_VALUE: xccdf_resolve_value(item, parent); break; default: assert(false); } // item resolved -> it no longer has a parent xccdf_item_set_extends(item, NULL); }
struct xccdf_tailoring *xccdf_tailoring_parse(xmlTextReaderPtr reader, struct xccdf_item *benchmark) { XCCDF_ASSERT_ELEMENT(reader, XCCDFE_TAILORING); struct xccdf_tailoring *tailoring = xccdf_tailoring_new(); const char *id = xccdf_attribute_get(reader, XCCDFA_ID); xccdf_tailoring_set_id(tailoring, id); int depth = oscap_element_depth(reader) + 1; // Read to the inside of Tailoring. xmlTextReaderRead(reader); while (oscap_to_start_element(reader, depth)) { switch (xccdf_element_get(reader)) { case XCCDFE_BENCHMARK_REF: { oscap_free(tailoring->benchmark_ref); tailoring->benchmark_ref = 0; oscap_free(tailoring->benchmark_ref_version); tailoring->benchmark_ref_version = 0; const char *ref = xccdf_attribute_get(reader, XCCDFA_HREF); if (ref) tailoring->benchmark_ref = oscap_strdup(ref); const char *ref_version = xccdf_attribute_get(reader, XCCDFA_VERSION); if (ref_version) tailoring->benchmark_ref_version = oscap_strdup(ref_version); break; } case XCCDFE_STATUS: { const char *date = xccdf_attribute_get(reader, XCCDFA_DATE); char *str = oscap_element_string_copy(reader); struct xccdf_status *status = xccdf_status_new_fill(str, date); oscap_free(str); oscap_list_add(tailoring->statuses, status); break; } case XCCDFE_DC_STATUS: oscap_list_add(tailoring->dc_statuses, oscap_reference_new_parse(reader)); break; case XCCDFE_VERSION: { xmlNode *ver = xmlTextReaderExpand(reader); /* optional attributes */ tailoring->version_time = (char*) xmlGetProp(ver, BAD_CAST "time"); tailoring->version_update = (char*) xmlGetProp(ver, BAD_CAST "update"); /* content */ tailoring->version = (char *) xmlNodeGetContent(ver); if (oscap_streq(tailoring->version, "")) { oscap_free(tailoring->version); tailoring->version = NULL; } break; } case XCCDFE_METADATA: { char* xml = oscap_get_xml(reader); oscap_list_add(tailoring->metadata, oscap_strdup(xml)); oscap_free(xml); break; } case XCCDFE_PROFILE: { struct xccdf_item *item = xccdf_profile_parse(reader, benchmark); if (!xccdf_tailoring_add_profile(tailoring, XPROFILE(item))) { dW("Failed to add profile to tailoring while parsing!"); } break; } default: dW("Encountered an unknown element '%s' while parsing XCCDF Tailoring element.", xmlTextReaderConstLocalName(reader)); } xmlTextReaderRead(reader); } return tailoring; }