xmlDoc *ds_doc_from_foreign_node(xmlNode *node, xmlDoc *parent) { xmlDOMWrapCtxtPtr wrap_ctxt = xmlDOMWrapNewCtxt(); xmlDocPtr new_doc = xmlNewDoc(BAD_CAST "1.0"); xmlNodePtr res_node = NULL; if (xmlDOMWrapCloneNode(wrap_ctxt, parent, node, &res_node, new_doc, NULL, 1, 0) != 0) { oscap_seterr(OSCAP_EFAMILY_XML, "Error when cloning node '%s' while dumping component " "from DataStream", node->name); xmlFreeDoc(new_doc); xmlDOMWrapFreeCtxt(wrap_ctxt); return NULL; } xmlDocSetRootElement(new_doc, res_node); if (xmlDOMWrapReconcileNamespaces(wrap_ctxt, res_node, 0) != 0) { oscap_seterr(OSCAP_EFAMILY_XML, "Internal libxml error when reconciling namespaces " "for node '%s' while dumping component.", node->name); xmlFreeDoc(new_doc); xmlDOMWrapFreeCtxt(wrap_ctxt); return NULL; } xmlDOMWrapFreeCtxt(wrap_ctxt); return new_doc; }
xmlNodePtr ds_rds_create_report(xmlDocPtr target_doc, xmlNodePtr reports_node, xmlDocPtr source_doc, const char* report_id) { xmlNsPtr arf_ns = xmlSearchNsByHref(target_doc, xmlDocGetRootElement(target_doc), BAD_CAST arf_ns_uri); xmlNodePtr report = xmlNewNode(arf_ns, BAD_CAST "report"); xmlSetProp(report, BAD_CAST "id", BAD_CAST report_id); xmlNodePtr report_content = xmlNewNode(arf_ns, BAD_CAST "content"); xmlAddChild(report, report_content); xmlDOMWrapCtxtPtr wrap_ctxt = xmlDOMWrapNewCtxt(); xmlNodePtr res_node = NULL; xmlDOMWrapCloneNode(wrap_ctxt, source_doc, xmlDocGetRootElement(source_doc), &res_node, target_doc, NULL, 1, 0); xmlAddChild(report_content, res_node); xmlDOMWrapReconcileNamespaces(wrap_ctxt, res_node, 0); xmlDOMWrapFreeCtxt(wrap_ctxt); xmlAddChild(reports_node, report); return report; }
static int ds_rds_create_from_dom(xmlDocPtr* ret, xmlDocPtr sds_doc, xmlDocPtr xccdf_result_file_doc, struct oscap_htable* oval_result_sources) { *ret = NULL; xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); xmlNodePtr root = xmlNewNode(NULL, BAD_CAST "asset-report-collection"); xmlDocSetRootElement(doc, root); xmlNsPtr arf_ns = xmlNewNs(root, BAD_CAST arf_ns_uri, BAD_CAST "arf"); xmlSetNs(root, arf_ns); xmlNsPtr core_ns = xmlNewNs(root, BAD_CAST core_ns_uri, BAD_CAST "core"); xmlNewNs(root, BAD_CAST ai_ns_uri, BAD_CAST "ai"); xmlNodePtr relationships = xmlNewNode(core_ns, BAD_CAST "relationships"); xmlNewNs(relationships, BAD_CAST arfvocab_ns_uri, BAD_CAST "arfvocab"); xmlNewNs(relationships, BAD_CAST arfrel_ns_uri, BAD_CAST "arfrel"); xmlAddChild(root, relationships); xmlNodePtr report_requests = xmlNewNode(arf_ns, BAD_CAST "report-requests"); xmlAddChild(root, report_requests); xmlNodePtr assets = xmlNewNode(arf_ns, BAD_CAST "assets"); xmlAddChild(root, assets); xmlNodePtr report_request = xmlNewNode(arf_ns, BAD_CAST "report-request"); xmlSetProp(report_request, BAD_CAST "id", BAD_CAST "collection1"); xmlNodePtr arf_content = xmlNewNode(arf_ns, BAD_CAST "content"); xmlDOMWrapCtxtPtr sds_wrap_ctxt = xmlDOMWrapNewCtxt(); xmlNodePtr sds_res_node = NULL; xmlDOMWrapCloneNode(sds_wrap_ctxt, sds_doc, xmlDocGetRootElement(sds_doc), &sds_res_node, doc, NULL, 1, 0); xmlAddChild(arf_content, sds_res_node); xmlDOMWrapReconcileNamespaces(sds_wrap_ctxt, sds_res_node, 0); xmlDOMWrapFreeCtxt(sds_wrap_ctxt); xmlAddChild(report_request, arf_content); xmlAddChild(report_requests, report_request); xmlNodePtr reports = xmlNewNode(arf_ns, BAD_CAST "reports"); ds_rds_add_xccdf_test_results(doc, reports, xccdf_result_file_doc, relationships, assets, "collection1"); unsigned int oval_report_suffix = 2; struct oscap_htable_iterator *hit = oscap_htable_iterator_new(oval_result_sources); while (oscap_htable_iterator_has_more(hit)) { struct oscap_source *oval_source = oscap_htable_iterator_next_value(hit); xmlDoc *oval_result_doc = oscap_source_get_xmlDoc(oval_source); char* report_id = oscap_sprintf("oval%i", oval_report_suffix++); ds_rds_create_report(doc, reports, oval_result_doc, report_id); oscap_free(report_id); } oscap_htable_iterator_free(hit); xmlAddChild(root, reports); *ret = doc; return 0; }
static void ds_rds_add_xccdf_test_results(xmlDocPtr doc, xmlNodePtr reports, xmlDocPtr xccdf_result_file_doc, xmlNodePtr relationships, xmlNodePtr assets, const char* report_request_id) { xmlNodePtr root_element = xmlDocGetRootElement(xccdf_result_file_doc); // There are 2 possible scenarios here: // 1) root element of given xccdf result file doc is a TestResult element // This is the easier scenario, we will just use ds_rds_create_report and // be done with it. if (strcmp((const char*)root_element->name, "TestResult") == 0) { xmlNodePtr report = ds_rds_create_report(doc, reports, xccdf_result_file_doc, "xccdf1"); ds_rds_add_relationship(doc, relationships, "arfvocab:createdFor", "xccdf1", report_request_id); xmlNodePtr asset = ds_rds_add_ai_from_xccdf_results(doc, assets, xccdf_result_file_doc); char* asset_id = (char*)xmlGetProp(asset, BAD_CAST "id"); ds_rds_add_relationship(doc, relationships, "arfrel:isAbout", "xccdf1", asset_id); // We deliberately don't act on errors in inject refs as // these aren't fatal errors. ds_rds_report_inject_refs(doc, report, asset_id); xmlFree(asset_id); } // 2) the root element is a Benchmark, TestResults are embedded within // We will have to walk through all elements, wrap each TestResult // in a xmlDoc and add them separately else if (strcmp((const char*)root_element->name, "Benchmark") == 0) { unsigned int report_suffix = 1; xmlNodePtr candidate_result = root_element->children; for (; candidate_result != NULL; candidate_result = candidate_result->next) { if (candidate_result->type != XML_ELEMENT_NODE) continue; if (strcmp((const char*)(candidate_result->name), "TestResult") != 0) continue; xmlDocPtr wrap_doc = xmlNewDoc(BAD_CAST "1.0"); xmlDOMWrapCtxtPtr wrap_ctxt = xmlDOMWrapNewCtxt(); xmlNodePtr res_node = NULL; xmlDOMWrapCloneNode(wrap_ctxt, xccdf_result_file_doc, candidate_result, &res_node, wrap_doc, NULL, 1, 0); xmlDocSetRootElement(wrap_doc, res_node); xmlDOMWrapReconcileNamespaces(wrap_ctxt, res_node, 0); xmlDOMWrapFreeCtxt(wrap_ctxt); char* report_id = oscap_sprintf("xccdf%i", report_suffix++); xmlNodePtr report = ds_rds_create_report(doc, reports, wrap_doc, report_id); ds_rds_add_relationship(doc, relationships, "arfvocab:createdFor", report_id, report_request_id); xmlNodePtr asset = ds_rds_add_ai_from_xccdf_results(doc, assets, wrap_doc); char* asset_id = (char*)xmlGetProp(asset, BAD_CAST "id"); ds_rds_add_relationship(doc, relationships, "arfrel:isAbout", report_id, asset_id); // We deliberately don't act on errors in inject ref as // these aren't fatal errors. ds_rds_report_inject_refs(doc, report, asset_id); xmlFree(asset_id); oscap_free(report_id); xmlFreeDoc(wrap_doc); } } else { char* error = oscap_sprintf( "Unknown root element '%s' in given XCCDF result document, expected TestResult or Benchmark.", (const char*)root_element->name); oscap_seterr(OSCAP_EFAMILY_XML, 0, error); oscap_free(error); } }
static int ds_sds_compose_add_component_internal(xmlDocPtr doc, xmlNodePtr datastream, const char* filepath, const char* comp_id, bool extended) { xmlNsPtr ds_ns = xmlSearchNsByHref(doc, datastream, BAD_CAST datastream_ns_uri); if (!ds_ns) { oscap_seterr(OSCAP_EFAMILY_GLIBC, "Unable to find namespace '%s' in the XML DOM tree when create " "source datastream. This is most likely an internal error!", datastream_ns_uri); return -1; } char file_timestamp[32]; strcpy(file_timestamp, "0000-00-00T00:00:00"); struct stat file_stat; if (stat(filepath, &file_stat) == 0) strftime(file_timestamp, 32, "%Y-%m-%dT%H:%M:%S", localtime(&file_stat.st_mtime)); else { oscap_seterr(OSCAP_EFAMILY_GLIBC, "Could not find file %s: %s.", filepath, strerror(errno)); // Return positive number, indicating less severe problem. // Rationale: When an OVAL file is missing during a scan it it not considered // to be deal breaker (it shall have 'notchecked' result), thus we shall allow // DataStreams with missing OVAL. return 1; } xmlNodePtr component = xmlNewNode(ds_ns, BAD_CAST (extended ? "extended-component" : "component")); xmlSetProp(component, BAD_CAST "id", BAD_CAST comp_id); xmlSetProp(component, BAD_CAST "timestamp", BAD_CAST file_timestamp); xmlNodePtr doc_root = xmlDocGetRootElement(doc); if (extended) { if (ds_sds_compose_component_add_script_content(component, filepath) == -1) { xmlFreeNode(component); return -1; } // extended components always go at the end xmlAddChild(doc_root, component); } else { struct oscap_source *component_source = oscap_source_new_from_file(filepath); xmlDoc *component_doc = oscap_source_get_xmlDoc(component_source); if (!component_doc) { oscap_seterr(OSCAP_EFAMILY_XML, "Could not read/parse XML of given input file at path '%s'.", filepath); xmlFreeNode(component); oscap_source_free(component_source); return -1; } xmlNodePtr component_root = xmlDocGetRootElement(component_doc); xmlDOMWrapCtxtPtr wrap_ctxt = xmlDOMWrapNewCtxt(); xmlNodePtr res_component_root = NULL; if (xmlDOMWrapCloneNode(wrap_ctxt, component_doc, component_root, &res_component_root, doc, NULL, 1, 0) != 0) { oscap_seterr(OSCAP_EFAMILY_XML, "Cannot clone node when adding component from file '%s' with id '%s' while " "creating source datastream.", filepath, comp_id); xmlDOMWrapFreeCtxt(wrap_ctxt); oscap_source_free(component_source); xmlFreeNode(component); return -1; } if (xmlDOMWrapReconcileNamespaces(wrap_ctxt, res_component_root, 0) != 0) { oscap_seterr(OSCAP_EFAMILY_XML, "Cannot reconcile namespaces when adding component from file '%s' with id '%s' while " "creating source datastream.", filepath, comp_id); xmlDOMWrapFreeCtxt(wrap_ctxt); oscap_source_free(component_source); xmlFreeNode(component); return -1; } xmlAddChild(component, res_component_root); xmlDOMWrapFreeCtxt(wrap_ctxt); // this component is not extended, we have to figure out if there // already is an extended-component and if so, add it right before // that component xmlNodePtr first_extended_component = node_get_child_element(doc_root, "extended-component"); if (first_extended_component == NULL) { // no extended component yet, add to the end xmlAddChild(doc_root, component); } else { xmlAddPrevSibling(first_extended_component, component); } oscap_source_free(component_source); } return 0; }