xmlNs *lookup_xccdf_ns(xmlDoc *doc, xmlNode *parent, const struct xccdf_version_info *version_info) { assert(parent != NULL); xmlNs *ns_xccdf = xmlSearchNsByHref(doc, parent, (const xmlChar *)xccdf_version_info_get_namespace_uri(version_info)); if (ns_xccdf == NULL) { ns_xccdf = xmlNewNs(parent, (const xmlChar *) xccdf_version_info_get_namespace_uri(version_info), NULL); } return ns_xccdf; }
xmlNodePtr xccdf_tailoring_to_dom(struct xccdf_tailoring *tailoring, xmlDocPtr doc, xmlNodePtr parent, const struct xccdf_version_info *version_info) { xmlNs *ns_xccdf = xmlSearchNsByHref(doc, parent, BAD_CAST xccdf_version_info_get_namespace_uri(version_info)); xmlNs *ns_tailoring = NULL; xmlNode *tailoring_node = xmlNewNode(ns_xccdf, BAD_CAST "Tailoring"); const char *xccdf_version = xccdf_version_info_get_version(version_info); #ifdef __USE_GNU if (strverscmp(xccdf_version, "1.1") >= 0 && strverscmp(xccdf_version, "1.2") < 0) { #else if (strcmp(xccdf_version, "1.1") >= 0 && strcmp(xccdf_version, "1.2") < 0) { #endif // XCCDF 1.1 does not support Tailoring! // However we will allow Tailoring export if it is done to an external // file. The namespace will be our custom xccdf-1.1-tailoring extension // namespace. if (parent != NULL) { oscap_seterr(OSCAP_EFAMILY_XML, "XCCDF 1.1 does not support embedded Tailoring elements!"); xmlFreeNode(tailoring_node); return NULL; } ns_tailoring = xmlNewNs(tailoring_node, BAD_CAST "http://open-scap.org/page/Xccdf-1.1-tailoring", BAD_CAST "cdf-11-tailoring" ); } #ifdef __USE_GNU else if (strverscmp(xccdf_version, "1.1") < 0) { #else else if (strcmp(xccdf_version, "1.1") < 0) { #endif oscap_seterr(OSCAP_EFAMILY_XML, "XCCDF Tailoring isn't supported in XCCDF version '%s'," "nor does openscap have a custom extension for this scenario. " "XCCDF Tailoring requires XCCDF 1.1 and higher, 1.2 is recommended."); xmlFreeNode(tailoring_node); return NULL; } if (!ns_xccdf) { // In cases where tailoring ends up being the root node we have to create // a namespace at the node itself. ns_xccdf = xmlNewNs(tailoring_node, BAD_CAST xccdf_version_info_get_namespace_uri(version_info), BAD_CAST "xccdf"); } if (!ns_tailoring) ns_tailoring = ns_xccdf; // We intentionally set the wrong namespace here since children of tailoring // will reuse it and we want them to have the xccdf namespace, the namespace // is set to the proper namespace before returning the tailoring. xmlSetNs(tailoring_node, ns_xccdf); if (parent) xmlAddChild(parent, tailoring_node); else xmlDocSetRootElement(doc, tailoring_node); if (tailoring->id) { xmlNewProp(tailoring_node, BAD_CAST "id", BAD_CAST tailoring->id); } if (tailoring->benchmark_ref || tailoring->benchmark_ref_version) { xmlNodePtr benchmark_ref_node = xmlNewChild(tailoring_node, ns_tailoring, BAD_CAST "benchmark", NULL); if (tailoring->benchmark_ref) xmlNewProp(benchmark_ref_node, BAD_CAST "href", BAD_CAST tailoring->benchmark_ref); if (tailoring->benchmark_ref_version) xmlNewProp(benchmark_ref_node, BAD_CAST "version", BAD_CAST tailoring->benchmark_ref_version); } struct xccdf_status_iterator *statuses = xccdf_tailoring_get_statuses(tailoring); while (xccdf_status_iterator_has_more(statuses)) { struct xccdf_status *status = xccdf_status_iterator_next(statuses); xccdf_status_to_dom(status, doc, tailoring_node, version_info); } xccdf_status_iterator_free(statuses); struct oscap_reference_iterator *dc_statuses = xccdf_tailoring_get_dc_statuses(tailoring); while (oscap_reference_iterator_has_more(dc_statuses)) { struct oscap_reference *ref = oscap_reference_iterator_next(dc_statuses); oscap_reference_to_dom(ref, tailoring_node, doc, "dc-status"); } oscap_reference_iterator_free(dc_statuses); /* version and attributes */ const char *version = xccdf_tailoring_get_version(tailoring); if (version) { xmlNode* version_node = xmlNewTextChild(tailoring_node, ns_tailoring, BAD_CAST "version", BAD_CAST version); const char *version_update = xccdf_tailoring_get_version_update(tailoring); if (version_update) xmlNewProp(version_node, BAD_CAST "update", BAD_CAST version_update); const char *version_time = xccdf_tailoring_get_version_time(tailoring); if (version_time) xmlNewProp(version_node, BAD_CAST "time", BAD_CAST version_time); } struct oscap_string_iterator* metadata = xccdf_tailoring_get_metadata(tailoring); while (oscap_string_iterator_has_more(metadata)) { const char* meta = oscap_string_iterator_next(metadata); oscap_xmlstr_to_dom(tailoring_node, "metadata", meta); } oscap_string_iterator_free(metadata); struct xccdf_profile_iterator *profiles = xccdf_tailoring_get_profiles(tailoring); while (xccdf_profile_iterator_has_more(profiles)) { struct xccdf_profile *profile = xccdf_profile_iterator_next(profiles); xccdf_item_to_dom(XITEM(profile), doc, tailoring_node); } xccdf_profile_iterator_free(profiles); xmlSetNs(tailoring_node, ns_tailoring); return tailoring_node; } int xccdf_tailoring_export(struct xccdf_tailoring *tailoring, const char *file, const struct xccdf_version_info *version_info) { __attribute__nonnull__(file); LIBXML_TEST_VERSION; xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); if (doc == NULL) { oscap_setxmlerr(xmlGetLastError()); return -1; } xccdf_tailoring_to_dom(tailoring, doc, NULL, version_info); return oscap_xml_save_filename(file, doc); } const char *xccdf_tailoring_get_id(const struct xccdf_tailoring *tailoring) { return tailoring->id; } const char *xccdf_tailoring_get_version(const struct xccdf_tailoring *tailoring) { return tailoring->version; } const char *xccdf_tailoring_get_version_update(const struct xccdf_tailoring *tailoring) { return tailoring->version_update; } const char *xccdf_tailoring_get_version_time(const struct xccdf_tailoring *tailoring) { return tailoring->version_time; } const char *xccdf_tailoring_get_benchmark_ref(const struct xccdf_tailoring *tailoring) { return tailoring->benchmark_ref; } const char *xccdf_tailoring_get_benchmark_ref_version(const struct xccdf_tailoring *tailoring) { return tailoring->benchmark_ref_version; } bool xccdf_tailoring_set_id(struct xccdf_tailoring *tailoring, const char* newval) { if (tailoring->id) oscap_free(tailoring->id); tailoring->id = oscap_strdup(newval); return true; } bool xccdf_tailoring_set_version(struct xccdf_tailoring *tailoring, const char *newval) { if (tailoring->version) oscap_free(tailoring->version); tailoring->version = oscap_strdup(newval); return true; } bool xccdf_tailoring_set_version_update(struct xccdf_tailoring *tailoring, const char *newval) { if (tailoring->version_update) oscap_free(tailoring->version_update); tailoring->version_update = oscap_strdup(newval); return true; } bool xccdf_tailoring_set_version_time(struct xccdf_tailoring *tailoring, const char *newval) { if (tailoring->version_time) oscap_free(tailoring->version_time); tailoring->version_time = oscap_strdup(newval); return true; } bool xccdf_tailoring_set_benchmark_ref(struct xccdf_tailoring *tailoring, const char *newval) { if (tailoring->benchmark_ref) oscap_free(tailoring->benchmark_ref); tailoring->benchmark_ref = oscap_strdup(newval); return true; } bool xccdf_tailoring_set_benchmark_ref_version(struct xccdf_tailoring *tailoring, const char *newval) { if (tailoring->benchmark_ref_version) oscap_free(tailoring->benchmark_ref_version); tailoring->benchmark_ref_version = oscap_strdup(newval); return true; } struct oscap_string_iterator *xccdf_tailoring_get_metadata(const struct xccdf_tailoring *tailoring) { return (struct oscap_string_iterator*) oscap_iterator_new(tailoring->metadata); } struct xccdf_profile_iterator *xccdf_tailoring_get_profiles(const struct xccdf_tailoring *tailoring) { return (struct xccdf_profile_iterator*) oscap_iterator_new(tailoring->profiles); } struct xccdf_status_iterator *xccdf_tailoring_get_statuses(const struct xccdf_tailoring *tailoring) { return (struct xccdf_status_iterator*) oscap_iterator_new(tailoring->statuses); } struct oscap_reference_iterator *xccdf_tailoring_get_dc_statuses(const struct xccdf_tailoring *tailoring) { return (struct oscap_reference_iterator*) oscap_iterator_new(tailoring->dc_statuses); } struct xccdf_profile * xccdf_tailoring_get_profile_by_id(const struct xccdf_tailoring *tailoring, const char *profile_id) { struct xccdf_profile_iterator *profit = xccdf_tailoring_get_profiles(tailoring); while (xccdf_profile_iterator_has_more(profit)) { struct xccdf_profile *profile = xccdf_profile_iterator_next(profit); if (profile == NULL) { assert(profile != NULL); continue; } if (oscap_streq(xccdf_profile_get_id(profile), profile_id)) { xccdf_profile_iterator_free(profit); return profile; } } xccdf_profile_iterator_free(profit); return NULL; }
xmlNode *xccdf_benchmark_to_dom(struct xccdf_benchmark *benchmark, xmlDocPtr doc, xmlNode *parent, void *user_args) { xmlNodePtr root_node = NULL; if (parent) { root_node = xccdf_item_to_dom(XITEM(benchmark), doc, parent); } else { root_node = xccdf_item_to_dom(XITEM(benchmark), doc, parent); xmlDocSetRootElement(doc, root_node); } // FIXME! //xmlNewProp(root_node, BAD_CAST "xsi:schemaLocation", BAD_CAST XCCDF_SCHEMA_LOCATION); xmlNs *ns_xccdf = xmlNewNs(root_node, (const xmlChar*)xccdf_version_info_get_namespace_uri(xccdf_benchmark_get_schema_version(benchmark)), NULL); xmlNs *ns_xsi = xmlNewNs(root_node, XCCDF_XSI_NAMESPACE, BAD_CAST "xsi"); xmlSetNs(root_node, ns_xsi); xmlSetNs(root_node, ns_xccdf); /* Handle attributes */ if (xccdf_benchmark_get_resolved(benchmark)) xmlNewProp(root_node, BAD_CAST "resolved", BAD_CAST "1"); else xmlNewProp(root_node, BAD_CAST "resolved", BAD_CAST "0"); const char *xmllang = xccdf_benchmark_get_lang(benchmark); if (xmllang) xmlNewProp(root_node, BAD_CAST "xml:lang", BAD_CAST xmllang); const char *style = xccdf_benchmark_get_style(benchmark); if (style) xmlNewProp(root_node, BAD_CAST "style", BAD_CAST style); const char *style_href = xccdf_benchmark_get_style_href(benchmark); if (style_href) xmlNewProp(root_node, BAD_CAST "style-href", BAD_CAST style_href); // Export plain-text elements struct xccdf_plain_text_iterator *plain_text_it = xccdf_benchmark_get_plain_texts(benchmark); while (xccdf_plain_text_iterator_has_more(plain_text_it)) { struct xccdf_plain_text *plain_text = xccdf_plain_text_iterator_next(plain_text_it); xccdf_plain_text_to_dom(plain_text, doc, root_node, xccdf_benchmark_get_schema_version(benchmark)); } xccdf_plain_text_iterator_free(plain_text_it); /* Handle children */ if (xccdf_benchmark_get_cpe_list(benchmark)) { // CPE API can only export via xmlTextWriter, we export via DOM // this is used to bridge both methods xmlTextWriterPtr writer = xmlNewTextWriterTree(doc, root_node, 0); cpe_dict_export(xccdf_benchmark_get_cpe_list(benchmark), writer); xmlFreeTextWriter(writer); } if (xccdf_benchmark_get_cpe_lang_model(benchmark)) { // CPE API can only export via xmlTextWriter, we export via DOM // this is used to bridge both methods xmlTextWriterPtr writer = xmlNewTextWriterTree(doc, root_node, 0); cpe_lang_export(xccdf_benchmark_get_cpe_lang_model(benchmark), writer); xmlFreeTextWriter(writer); } struct oscap_string_iterator *platforms = xccdf_benchmark_get_platforms(benchmark); while (oscap_string_iterator_has_more(platforms)) { xmlNode *platform_node = xmlNewTextChild(root_node, ns_xccdf, BAD_CAST "platform", NULL); const char *idref = oscap_string_iterator_next(platforms); if (idref) xmlNewProp(platform_node, BAD_CAST "idref", BAD_CAST idref); } oscap_string_iterator_free(platforms); const char *version = xccdf_benchmark_get_version(benchmark); if (version) xmlNewTextChild(root_node, ns_xccdf, BAD_CAST "version", BAD_CAST version); struct oscap_string_iterator* metadata = xccdf_item_get_metadata(XITEM(benchmark)); while (oscap_string_iterator_has_more(metadata)) { const char* meta = oscap_string_iterator_next(metadata); oscap_xmlstr_to_dom(root_node, "metadata", meta); } oscap_string_iterator_free(metadata); OSCAP_FOR(xccdf_model, model, xccdf_benchmark_get_models(benchmark)) { xmlNode *model_node = xmlNewTextChild(root_node, ns_xccdf, BAD_CAST "model", NULL); xmlNewProp(model_node, BAD_CAST "system", BAD_CAST xccdf_model_get_system(model)); }