static xmlNodePtr ds_sds_get_component_root_by_id(xmlDoc *doc, const char* component_id) { xmlNodePtr component; if (component_id == NULL) { component = (xmlNodePtr)doc; } else { component = _lookup_component_in_collection(doc, component_id); if (component == NULL) { oscap_seterr(OSCAP_EFAMILY_XML, "Component of given id '%s' was not found in the document.", component_id); return NULL; } } return node_get_child_element(component, NULL); }
static int ds_sds_dump_component(const char* component_id, struct ds_sds_session *session, const char *target_filename_dirname, const char *relative_filepath) { xmlDoc *doc = ds_sds_session_get_xmlDoc(session); xmlNodePtr component = _lookup_component_in_collection(doc, component_id); if (component == NULL) { oscap_seterr(OSCAP_EFAMILY_XML, "Component of given id '%s' was not found in the document.", component_id); return -1; } xmlNodePtr inner_root = node_get_child_element(component, NULL); if (inner_root == NULL) { oscap_seterr(OSCAP_EFAMILY_XML, "Found component (id='%s') but it has no element contents, nothing to dump, skipping...", component_id); return -1; } // If the inner root is script, we have to treat it in a special way if (strcmp((const char*)inner_root->name, "script") == 0) { // the cast is safe to do because we are using the GNU basename, it doesn't // modify the string const char* file_basename = basename((char*)relative_filepath); const char* sce_filename = oscap_sprintf("%s/%s/%s",ds_sds_session_get_target_dir(session), target_filename_dirname, file_basename); int ret = ds_sds_dump_component_sce(inner_root->children, component_id, sce_filename); oscap_free(sce_filename); if (ret != 0) { return ret; } } // Otherwise we create a new XML doc we will dump the contents to. // We can't just dump node "innerXML" because namespaces have to be // handled. else { xmlDoc *new_doc = ds_doc_from_foreign_node(inner_root, doc); if (new_doc == NULL) { return -1; } struct oscap_source *source = oscap_source_new_from_xmlDoc(new_doc, relative_filepath); ds_sds_session_register_component_source(session, relative_filepath, source); } return 0; }
int ds_sds_compose_add_component_with_ref(xmlDocPtr doc, xmlNodePtr datastream, const char* filepath, const char* cref_id) { xmlNsPtr ds_ns = xmlSearchNsByHref(doc, datastream, BAD_CAST datastream_ns_uri); xmlNsPtr xlink_ns = xmlSearchNsByHref(doc, datastream, BAD_CAST xlink_ns_uri); xmlNsPtr cat_ns = xmlSearchNsByHref(doc, datastream, BAD_CAST cat_ns_uri); // In case we already have this component we just return, no need to add // it twice. We will typically have many references to OVAL files, adding // component for each reference would create unnecessarily huge datastreams int result = ds_sds_compose_has_component_ref(doc, datastream, filepath, cref_id); if (result == 0) { return 0; } if (result == -1) { // no need to free anything // oscap_seterr has already been called return -1; } xmlNodePtr cref_catalog = xmlNewNode(cat_ns, BAD_CAST "catalog"); xmlNodePtr cref_parent; bool extended_component = false; struct oscap_source *component_source = oscap_source_new_from_file(filepath); oscap_document_type_t doc_type = oscap_source_get_scap_type(component_source); if (doc_type == OSCAP_DOCUMENT_XCCDF) { cref_parent = node_get_child_element(datastream, "checklists"); if (ds_sds_compose_add_component_dependencies(doc, datastream, component_source, cref_catalog, doc_type) != 0) { // oscap_seterr has already been called oscap_source_free(component_source); return -1; } } else if (doc_type == OSCAP_DOCUMENT_CPE_DICTIONARY || doc_type == OSCAP_DOCUMENT_CPE_LANGUAGE) { cref_parent = node_get_child_element(datastream, "dictionaries"); if (cref_parent == NULL) { cref_parent = xmlNewNode(ds_ns, BAD_CAST "dictionaries"); // The <ds:dictionaries element must as the first child of the datastream xmlNodePtr first_child = datastream->xmlChildrenNode; xmlNodePtr new_node = (first_child == NULL) ? xmlAddChild(datastream, cref_parent) : xmlAddPrevSibling(first_child, cref_parent); if (new_node == NULL) { oscap_seterr(OSCAP_EFAMILY_XML, "Failed to add dictionaries element to the DataStream."); xmlFreeNode(cref_parent); cref_parent = NULL; } } if (ds_sds_compose_add_component_dependencies(doc, datastream, component_source, cref_catalog, doc_type) != 0) { oscap_source_free(component_source); return -1; } } else if (doc_type == OSCAP_DOCUMENT_OVAL_DEFINITIONS || doc_type == OSCAP_DOCUMENT_OCIL) { cref_parent = node_get_child_element(datastream, "checks"); } else { // not an XCCDF file, not an OVAL file, not a dict/lang, assume it goes into extended components extended_component = true; cref_parent = node_get_child_element(datastream, "extended-components"); } oscap_source_free(component_source); char* mangled_filepath = ds_sds_mangle_filepath(filepath); // extended components (sadly :-/) use a different ID scheme and have // a different element name than "normal" components char* comp_id = oscap_sprintf("scap_org.open-scap_%scomp_%s", extended_component ? "e" : "", mangled_filepath); int counter = 0; while (_lookup_component_in_collection(doc, comp_id) != NULL) { // While a component of the given ID already exists, generate a new one oscap_free(comp_id); comp_id = oscap_sprintf("scap_org.open-scap_%scomp_%s%03d", extended_component ? "e" : "", mangled_filepath, counter++); } oscap_free(mangled_filepath); result = ds_sds_compose_add_component_internal(doc, datastream, filepath, comp_id, extended_component); if (result == 0) { xmlNodePtr cref = xmlNewNode(ds_ns, BAD_CAST "component-ref"); xmlAddChild(cref, cref_catalog); xmlSetProp(cref, BAD_CAST "id", BAD_CAST cref_id); const char* xlink_href = oscap_sprintf("#%s", comp_id); xmlSetNsProp(cref, xlink_ns, BAD_CAST "href", BAD_CAST xlink_href); oscap_free(xlink_href); if (xmlAddChild(cref_parent, cref) == NULL) { oscap_seterr(OSCAP_EFAMILY_XML, "Failed to add component-ref/@id='%s' to the DataStream.", cref_id); result = 1; } } oscap_free(comp_id); // the source data stream XSD requires either no catalog or a non-empty one if (cref_catalog->children == NULL) { xmlUnlinkNode(cref_catalog); xmlFreeNode(cref_catalog); } return result; }