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; }
void xccdf_group_to_dom(struct xccdf_group *group, xmlNode *group_node, xmlDoc *doc, xmlNode *parent) { const struct xccdf_version_info* version_info = xccdf_item_get_schema_version(XITEM(group)); xmlNs *ns_xccdf = lookup_xccdf_ns(doc, parent, version_info); /* Handle Attributes */ const char *extends = xccdf_group_get_extends(group); if (extends) xmlNewProp(group_node, BAD_CAST "extends", BAD_CAST extends); if (XITEM(group)->item.defined_flags.selected) { if (xccdf_group_get_selected(group)) xmlNewProp(group_node, BAD_CAST "selected", BAD_CAST "true"); else xmlNewProp(group_node, BAD_CAST "selected", BAD_CAST "false"); } if (XITEM(group)->item.defined_flags.weight) { float weight = xccdf_group_get_weight(group); char *weight_str = oscap_sprintf("%f", weight); xmlNewProp(group_node, BAD_CAST "weight", BAD_CAST weight_str); free(weight_str); } /* Handle Child Nodes */ xccdf_texts_to_dom(xccdf_group_get_rationale(group), group_node, "rationale"); struct oscap_string_iterator *platforms = xccdf_group_get_platforms(group); while (oscap_string_iterator_has_more(platforms)) { const char *platform = oscap_string_iterator_next(platforms); xmlNode * child = xmlNewTextChild(group_node, ns_xccdf, BAD_CAST "platform", BAD_CAST NULL); xmlNewProp(child, BAD_CAST "idref", BAD_CAST platform); } oscap_string_iterator_free(platforms); struct oscap_stringlist_iterator *lists = xccdf_group_get_requires(group); while (oscap_stringlist_iterator_has_more(lists)) { struct oscap_stringlist *list = oscap_stringlist_iterator_next(lists); struct oscap_string_iterator *strings = oscap_stringlist_get_strings(list); while (oscap_string_iterator_has_more(strings)) { const char *requires = oscap_string_iterator_next(strings); xmlNode * child = xmlNewTextChild(group_node, ns_xccdf, BAD_CAST "requires", BAD_CAST NULL); xmlNewProp(child, BAD_CAST "idref", BAD_CAST requires); } oscap_string_iterator_free(strings); } oscap_stringlist_iterator_free(lists); struct oscap_string_iterator *conflicts = xccdf_group_get_conflicts(group); while (oscap_string_iterator_has_more(conflicts)) { const char *conflict = oscap_string_iterator_next(conflicts); xmlNode * child = xmlNewTextChild(group_node, ns_xccdf, BAD_CAST "conflicts", BAD_CAST NULL); xmlNewProp(child, BAD_CAST "idref", BAD_CAST conflict); } oscap_string_iterator_free(conflicts); struct xccdf_value_iterator *values = xccdf_group_get_values(group); while (xccdf_value_iterator_has_more(values)) { struct xccdf_value *value = xccdf_value_iterator_next(values); if (XGROUP(xccdf_value_get_parent(value)) == group) { xccdf_item_to_dom((struct xccdf_item *)value, doc, group_node, version_info); } } xccdf_value_iterator_free(values); struct xccdf_item_iterator *items = xccdf_group_get_content(group); while (xccdf_item_iterator_has_more(items)) { struct xccdf_item *item = xccdf_item_iterator_next(items); if (XGROUP(xccdf_item_get_parent(item)) == group) { xccdf_item_to_dom(item, doc, group_node, version_info); } } xccdf_item_iterator_free(items); }
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)); }