static int ds_dsd_dump_remote_component(const char* url, const char* component_id, struct ds_sds_session *session, const char *target_filename_dirname, const char *relative_filepath) { int ret = 0; size_t memory_size = 0; ds_sds_session_remote_resources_progress(session)(false, "Downloading: %s ... ", url); char* mem = oscap_acquire_url_download(url, &memory_size); if (mem == NULL) { ds_sds_session_remote_resources_progress(session)(false, "error\n", url); return -1; } ds_sds_session_remote_resources_progress(session)(false, "ok\n", url); struct oscap_source *source_file = oscap_source_new_take_memory(mem, memory_size, url); xmlDoc *doc = oscap_source_get_xmlDoc(source_file); if (doc == NULL) { ret = -1; goto cleanup; } xmlNodePtr inner_root = ds_sds_get_component_root_by_id(doc, component_id); if (ds_sds_register_component(session, doc, inner_root, component_id, target_filename_dirname, relative_filepath) != 0) { ret = -1; goto cleanup; } cleanup: oscap_source_free(source_file); return ret; }
int ds_rds_session_replace_report_with_source(struct ds_rds_session *session, struct oscap_source *source) { xmlDoc *doc = oscap_source_get_xmlDoc(session->source); xmlNode *reports_node = ds_rds_lookup_container(doc, "reports"); xmlNode *report_node = ds_rds_lookup_component(doc, "reports", "report", session->report_id); xmlDOMWrapCtxtPtr wrap_ctxt = xmlDOMWrapNewCtxt(); if (xmlDOMWrapRemoveNode(wrap_ctxt, doc, report_node, 0) != 0) { oscap_seterr(OSCAP_EFAMILY_OSCAP, "Could not remove arf:report[@id='%s'] from result DataStream", session->report_id); return 1; } struct oscap_source *prev_source = oscap_htable_detach(session->component_sources, session->report_id); oscap_source_free(prev_source); if (ds_rds_session_register_component_source(session, session->report_id, source) != 0) { return 1; } return ds_rds_create_report(doc, reports_node, oscap_source_get_xmlDoc(source), session->report_id) == NULL; }
struct oscap_source *ds_rds_create_source(struct oscap_source *sds_source, struct oscap_source *xccdf_result_source, struct oscap_htable *oval_result_sources, const char *target_file) { xmlDoc *sds_doc = oscap_source_get_xmlDoc(sds_source); if (sds_doc == NULL) { return NULL; } xmlDoc *result_file_doc = oscap_source_get_xmlDoc(xccdf_result_source); if (result_file_doc == NULL) { return NULL; } xmlDocPtr rds_doc = NULL; if (ds_rds_create_from_dom(&rds_doc, sds_doc, result_file_doc, oval_result_sources) != 0) { return NULL; } return oscap_source_new_from_xmlDoc(rds_doc, target_file); }
xmlNode *ds_sds_session_get_selected_datastream(struct ds_sds_session *session) { xmlDoc *doc = oscap_source_get_xmlDoc(session->source); xmlNode *datastream = ds_sds_lookup_datastream_in_collection(doc, session->datastream_id); if (datastream == NULL) { const char* error = session->datastream_id ? oscap_sprintf("Could not find any datastream of id '%s'", session->datastream_id) : oscap_sprintf("Could not find any datastream inside the file"); oscap_seterr(OSCAP_EFAMILY_XML, error); oscap_free(error); } return datastream; }
int ds_sds_compose_add_component(const char *target_datastream, const char *datastream_id, const char *new_component, bool extended) { struct oscap_source *sds_source = oscap_source_new_from_file(target_datastream); xmlDoc *doc = oscap_source_get_xmlDoc(sds_source); if (doc == NULL) { oscap_source_free(sds_source); return 1; } xmlNodePtr datastream = ds_sds_lookup_datastream_in_collection(doc, datastream_id); if (datastream == NULL) { const char* error = datastream_id ? oscap_sprintf("Could not find any datastream of id '%s'", datastream_id) : oscap_sprintf("Could not find any datastream inside the file"); oscap_seterr(OSCAP_EFAMILY_XML, error); oscap_free(error); oscap_source_free(sds_source); return 1; } char* mangled_path = ds_sds_mangle_filepath(new_component); char* cref_id = oscap_sprintf("scap_org.open-scap_cref_%s", mangled_path); oscap_free(mangled_path); if (ds_sds_compose_add_component_with_ref(doc, datastream, new_component, cref_id) != 0) { oscap_free(cref_id); oscap_source_free(sds_source); return 1; } oscap_free(cref_id); if (oscap_source_save_as(sds_source, NULL) != 0) { oscap_seterr(OSCAP_EFAMILY_GLIBC, "Error saving source datastream to '%s'.", target_datastream); oscap_source_free(sds_source); return 1; } oscap_source_free(sds_source); return 0; }
static int ds_sds_dump_file_component(const char* external_file, const char* component_id, struct ds_sds_session *session, const char *target_filename_dirname, const char *relative_filepath) { int ret = 0; struct oscap_source *source_file = load_referenced_source(session, external_file); xmlDoc *doc = oscap_source_get_xmlDoc(source_file); if (doc == NULL) { ret = -1; goto cleanup; } xmlNodePtr inner_root = ds_sds_get_component_root_by_id(doc, component_id); if (ds_sds_register_component(session, doc, inner_root, component_id, target_filename_dirname, relative_filepath) != 0) { ret = -1; goto cleanup; } cleanup: oscap_source_free(source_file); return ret; }
int ds_rds_create(const char* sds_file, const char* xccdf_result_file, const char** oval_result_files, const char* target_file) { struct oscap_source *sds_source = oscap_source_new_from_file(sds_file); struct oscap_source *xccdf_result_source = oscap_source_new_from_file(xccdf_result_file); struct oscap_htable *oval_result_sources = oscap_htable_new(); int result = 0; // this check is there to allow passing NULL instead of having to allocate // an empty array if (oval_result_files != NULL) { while (*oval_result_files != NULL) { struct oscap_source *oval_source = oscap_source_new_from_file(*oval_result_files); if (oscap_source_get_xmlDoc(oval_source) == NULL) { result = -1; oscap_source_free(oval_source); } else { oscap_htable_add(oval_result_sources, *oval_result_files, oval_source); } oval_result_files++; } } if (result == 0) { struct oscap_source *target_rds = ds_rds_create_source(sds_source, xccdf_result_source, oval_result_sources, target_file); result = target_rds == NULL; if (result == 0) { result = oscap_source_save_as(target_rds, NULL); } oscap_source_free(target_rds); } oscap_htable_free(oval_result_sources, (oscap_destruct_func) oscap_source_free); oscap_source_free(sds_source); oscap_source_free(xccdf_result_source); return result; }
static inline int oscap_validate_xml(struct oscap_source *source, const char *schemafile, xml_reporter reporter, void *arg) { int result = -1; xmlSchemaParserCtxtPtr parser_ctxt = NULL; xmlSchemaPtr schema = NULL; xmlSchemaValidCtxtPtr ctxt = NULL; xmlDocPtr doc = NULL; struct ctxt context = { reporter, arg, (void*) oscap_source_readable_origin(source)}; if (schemafile == NULL) { oscap_seterr(OSCAP_EFAMILY_OSCAP, "'schemafile' == NULL"); return -1; } char * schemapath = oscap_sprintf("%s%s%s", oscap_path_to_schemas(), "/", schemafile); if (access(schemapath, R_OK)) { oscap_seterr(OSCAP_EFAMILY_OSCAP, "Schema file '%s' not found in path '%s' when trying to validate '%s'", schemafile, oscap_path_to_schemas(), oscap_source_readable_origin(source)); goto cleanup; } parser_ctxt = xmlSchemaNewParserCtxt(schemapath); if (parser_ctxt == NULL) { oscap_seterr(OSCAP_EFAMILY_XML, "Could not create parser context for validation"); goto cleanup; } xmlSchemaSetParserStructuredErrors(parser_ctxt, oscap_xml_validity_handler, &context); schema = xmlSchemaParse(parser_ctxt); if (schema == NULL) { oscap_seterr(OSCAP_EFAMILY_XML, "Could not parse XML schema"); goto cleanup; } ctxt = xmlSchemaNewValidCtxt(schema); if (ctxt == NULL) { oscap_seterr(OSCAP_EFAMILY_XML, "Could not create validation context"); goto cleanup; } xmlSchemaSetValidStructuredErrors(ctxt, oscap_xml_validity_handler, &context); doc = oscap_source_get_xmlDoc(source); if (!doc) goto cleanup; result = xmlSchemaValidateDoc(ctxt, doc); /* * xmlSchemaValidateFile() returns "-1" if document is not well formed * thefore we ignore libxml internal errors here and map return code to * either pass or fail. */ if (result != 0) result = 1; /* This would be nicer * if (result == -1) * oscap_setxmlerr(xmlGetLastError()); */ cleanup: if (ctxt) xmlSchemaFreeValidCtxt(ctxt); if (schema) xmlSchemaFree(schema); if (parser_ctxt) xmlSchemaFreeParserCtxt(parser_ctxt); oscap_free(schemapath); return result; }
xmlDoc *ds_rds_session_get_xmlDoc(struct ds_rds_session *session) { return oscap_source_get_xmlDoc(session->source); }
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 int ds_sds_compose_add_component_dependencies(xmlDocPtr doc, xmlNodePtr datastream, struct oscap_source *component_source, xmlNodePtr catalog, int component_type) { xmlDocPtr component_doc = oscap_source_get_xmlDoc(component_source); if (component_doc == NULL) { return -1; } xmlXPathContextPtr xpathCtx = xmlXPathNewContext(component_doc); if (xpathCtx == NULL) { oscap_seterr(OSCAP_EFAMILY_XML, "Error: unable to create new XPath context."); return -1; } xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression( // we want robustness and support for future versions, this expression // retrieves check-content-refs from any namespace BAD_CAST _get_dep_xpath_for_type(component_type), xpathCtx); if (xpathObj == NULL) { oscap_seterr(OSCAP_EFAMILY_XML, "Error: Unable to evalute XPath expression."); xmlXPathFreeContext(xpathCtx); return -1; } xmlNsPtr cat_ns = xmlSearchNsByHref(doc, datastream, BAD_CAST cat_ns_uri); xmlNodeSetPtr nodeset = xpathObj->nodesetval; if (nodeset != NULL) { struct oscap_htable *exported = oscap_htable_new(); char* filepath_cpy = oscap_strdup(oscap_source_readable_origin(component_source)); const char* dir = dirname(filepath_cpy); for (int i = 0; i < nodeset->nodeNr; i++) { xmlNodePtr node = nodeset->nodeTab[i]; if (node->type != XML_ELEMENT_NODE) continue; if (xmlHasProp(node, BAD_CAST "href")) { char* href = (char*)xmlGetProp(node, BAD_CAST "href"); if (oscap_htable_get(exported, href) != NULL) { // This path has been already exported. Do not export duplicate. xmlFree(href); continue; } oscap_htable_add(exported, href, ""); if (oscap_acquire_url_is_supported(href)) { /* If the referenced component is remote one, do not include * it within the DataStream. Such component shall only be * downloaded once the scan is run. */ xmlFree(href); continue; } char* real_path = (strcmp(dir, "") == 0 || strcmp(dir, ".") == 0) ? oscap_strdup(href) : oscap_sprintf("%s/%s", dir, href); char* mangled_path = ds_sds_mangle_filepath(real_path); char* cref_id = oscap_sprintf("scap_org.open-scap_cref_%s", mangled_path); int counter = 0; while (ds_sds_find_component_ref(datastream, cref_id) != NULL) { // While the given component ID already exists in the document. oscap_free(cref_id); cref_id = oscap_sprintf("scap_org.open-scap_cref_%s%03d", mangled_path, counter++); } oscap_free(mangled_path); char* uri = oscap_sprintf("#%s", cref_id); // we don't want duplicated uri elements in the catalog if (ds_sds_compose_catalog_has_uri(doc, catalog, uri) == 0) { oscap_free(uri); oscap_free(cref_id); oscap_free(real_path); xmlFree(href); continue; } int ret = ds_sds_compose_add_component_with_ref(doc, datastream, real_path, cref_id); if (ret == 0) { xmlNodePtr catalog_uri = xmlNewNode(cat_ns, BAD_CAST "uri"); xmlSetProp(catalog_uri, BAD_CAST "name", BAD_CAST href); xmlSetProp(catalog_uri, BAD_CAST "uri", BAD_CAST uri); xmlAddChild(catalog, catalog_uri); } oscap_free(cref_id); oscap_free(uri); oscap_free(real_path); xmlFree(href); if (ret < 0) { // oscap_seterr has already been called oscap_htable_free0(exported); return -1; } } } oscap_htable_free0(exported); oscap_free(filepath_cpy); } xmlXPathFreeObject(xpathObj); xmlXPathFreeContext(xpathCtx); return 0; }
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; }