/* * Copyright 2015 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Author: * Michal Šrubař */ #ifdef HAVE_CONFIG_H #include #endif #ifdef OS_WINDOWS #include #else #include #endif #include #if defined(OS_LINUX) #include #endif #include "common/debug_priv.h" #include "common/util.h" #include "common/_error.h" #include "common/oscapxml.h" #include "source/xslt_priv.h" #include "public/oval_agent_api.h" #include "public/oval_session.h" #include "../DS/public/ds_sds_session.h" #include "oscap_source.h" #include "oscap_helpers.h" static const char *oscap_productname = "cpe:/a:open-scap:oscap"; static const char *oval_results_report = "oval-results-report.xsl"; struct oval_session { /* Main source assigned with the main file (SDS or OVAL) */ struct oscap_source *source; struct oval_definition_model *def_model; struct oval_variable_model *var_model; struct oval_results_model *res_model; oval_agent_session_t *sess; struct ds_sds_session *sds_session; struct { struct oscap_source *definitions; struct oscap_source *variables; struct oscap_source *directives; } oval; char *datastream_id; /* particular OVAL component if there are two OVALs in one datastream */ char *component_id; struct { char *results; char *report; } export; struct { /* it's called when there is something invalid in input/output files */ xml_reporter xml_fn; } reporter; bool validation; bool export_sys_chars; bool full_validation; bool fetch_remote_resources; download_progress_calllback_t progress; }; struct oval_session *oval_session_new(const char *filename) { oscap_document_type_t scap_type; struct oval_session *session; session = (struct oval_session *) calloc(1, sizeof(struct oval_session)); session->source = oscap_source_new_from_file(filename); if ((scap_type = oscap_source_get_scap_type(session->source)) == OSCAP_DOCUMENT_UNKNOWN) { oval_session_free(session); return NULL; } if (scap_type != OSCAP_DOCUMENT_OVAL_DEFINITIONS && scap_type != OSCAP_DOCUMENT_SDS) { oscap_seterr(OSCAP_EFAMILY_OSCAP, "Session input file was determined but it" " isn't an OVAL file nor a source datastream file."); oval_session_free(session); return NULL; } session->export_sys_chars = true; dI("Created a new OVAL session from input file '%s'.", filename); return session; } void oval_session_set_variables(struct oval_session *session, const char *filename) { __attribute__nonnull__(session); oscap_source_free(session->oval.variables); if (filename != NULL) session->oval.variables = oscap_source_new_from_file(filename); else session->oval.variables = NULL; /* reset */ } void oval_session_set_directives(struct oval_session *session, const char *filename) { __attribute__nonnull__(session); oscap_source_free(session->oval.directives); if (filename != NULL) session->oval.directives = oscap_source_new_from_file(filename); else session->oval.directives = NULL; } void oval_session_set_validation(struct oval_session *session, bool validate, bool full_validation) { __attribute__nonnull__(session); session->validation = validate; session->full_validation = full_validation; } void oval_session_set_datastream_id(struct oval_session *session, const char *id) { __attribute__nonnull__(session); free(session->datastream_id); session->datastream_id = oscap_strdup(id); } void oval_session_set_component_id(struct oval_session *session, const char *id) { __attribute__nonnull__(session); free(session->component_id); session->component_id = oscap_strdup(id); } void oval_session_set_results_export(struct oval_session *session, const char *filename) { __attribute__nonnull__(session); free(session->export.results); session->export.results = oscap_strdup(filename); } void oval_session_set_report_export(struct oval_session *session, const char *filename) { __attribute__nonnull__(session); free(session->export.report); session->export.report = oscap_strdup(filename); } void oval_session_set_xml_reporter(struct oval_session *session, xml_reporter fn) { __attribute__nonnull__(session); session->reporter.xml_fn = fn; } static bool oval_session_validate(struct oval_session *session, struct oscap_source *source, oscap_document_type_t type) { if (oscap_source_get_scap_type(source) == type) { if (oscap_source_validate(source, session->reporter.xml_fn, NULL)) return false; } else { oscap_seterr(OSCAP_EFAMILY_OVAL, "Type mismatch: %s. Expecting %s " "but found %s.", oscap_source_readable_origin(source), oscap_document_type_to_string(type), oscap_document_type_to_string(oscap_source_get_scap_type(source))); return false; } return true; } static int oval_session_load_definitions(struct oval_session *session) { __attribute__nonnull__(session); __attribute__nonnull__(session->source); oscap_document_type_t type = oscap_source_get_scap_type(session->source); if (type != OSCAP_DOCUMENT_OVAL_DEFINITIONS && type != OSCAP_DOCUMENT_SDS) { oscap_seterr(OSCAP_EFAMILY_OVAL, "Type mismatch: %s. Expecting %s " "or %s but found %s.", oscap_source_readable_origin(session->source), oscap_document_type_to_string(OSCAP_DOCUMENT_OVAL_DEFINITIONS), oscap_document_type_to_string(OSCAP_DOCUMENT_SDS), oscap_document_type_to_string(type)); return 1; } else { if (session->validation && !oval_session_validate(session, session->source, type)) return 1; } if (oscap_source_get_scap_type(session->source) == OSCAP_DOCUMENT_SDS) { if ((session->sds_session = ds_sds_session_new_from_source(session->source)) == NULL) { return 1; } ds_sds_session_set_remote_resources(session->sds_session,session->fetch_remote_resources ,session->progress); ds_sds_session_set_datastream_id(session->sds_session, session->datastream_id); if (ds_sds_session_register_component_with_dependencies(session->sds_session, "checks", session->component_id, "oval.xml") != 0) { return 1; } session->oval.definitions = ds_sds_session_get_component_by_href(session->sds_session, "oval.xml"); if (session->oval.definitions == NULL) { oscap_seterr(OSCAP_EFAMILY_OVAL, "Internal error: OVAL file was not found in " "Source DataStream session cache!"); return 1; } } else { session->oval.definitions = session->source; } /* import OVAL Definitions */ if (session->def_model) oval_definition_model_free(session->def_model); session->def_model = oval_definition_model_import_source(session->oval.definitions); if (session->def_model == NULL) { oscap_seterr(OSCAP_EFAMILY_OVAL, "Failed to import the OVAL Definitions from '%s'.", oscap_source_readable_origin(session->oval.definitions)); return 1; } return 0; } static int oval_session_load_variables(struct oval_session *session) { __attribute__nonnull__(session); if (session->oval.variables != NULL) { if (session->def_model == NULL) { oscap_seterr(OSCAP_EFAMILY_OVAL, "No OVAL Definitions to bind the variables to."); return 1; } if (session->validation && !oval_session_validate(session, session->oval.variables, OSCAP_DOCUMENT_OVAL_VARIABLES)) { return 1; } /* bind external variables */ if (session->oval.variables) { session->var_model = oval_variable_model_import_source(session->oval.variables); if (session->var_model == NULL) { oscap_seterr(OSCAP_EFAMILY_OVAL, "Failed to import the OVAL Variables " "from '%s'.", session->oval.variables); return 1; } if (oval_definition_model_bind_variable_model(session->def_model, session->var_model)) { oscap_seterr(OSCAP_EFAMILY_OVAL, "Failed to bind Variables to Definitions."); return 1; } } dI("Loaded OVAL variables."); } else { dI("No external OVAL variables provided."); } return 0; } int oval_session_load(struct oval_session *session) { __attribute__nonnull__(session); int ret = 0; if ((ret = oval_session_load_definitions(session)) != 0) { return ret; } if ((ret = oval_session_load_variables(session)) != 0) { return ret; } return ret; } static int oval_session_setup_agent(struct oval_session *session) { __attribute__nonnull__(session); char *path_clone; path_clone = oscap_strdup(oscap_source_readable_origin(session->oval.definitions)); if (path_clone == NULL) { return 1; } /* free the previous Agent session if this function was already called */ if (session->sess) oval_agent_destroy_session(session->sess); char *base_name = oscap_basename(path_clone); session->sess = oval_agent_new_session(session->def_model, base_name); free(base_name); if (session->sess == NULL) { oscap_seterr(OSCAP_EFAMILY_OVAL, "Failed to create a new agent session."); free(path_clone); return 1; } free(path_clone); oval_agent_set_product_name(session->sess, (char *)oscap_productname); return 0; } int oval_session_evaluate_id(struct oval_session *session, const char *id, oval_result_t *result) { __attribute__nonnull__(session); if (id == NULL) { oscap_seterr(OSCAP_EFAMILY_OVAL, "No OVAL Definion id set."); return 1; } if (oval_session_setup_agent(session) != 0) { return 1; } oval_agent_eval_definition(session->sess, id); *result = OVAL_RESULT_NOT_EVALUATED; oval_agent_get_definition_result(session->sess, id, result); if (oscap_err()) { return 1; } session->res_model = oval_agent_get_results_model(session->sess); return 0; } int oval_session_evaluate(struct oval_session *session, agent_reporter fn, void *arg) { __attribute__nonnull__(session); if (oval_session_setup_agent(session) != 0) { return 1; } oval_agent_eval_system(session->sess, fn, arg); if (oscap_err()) { return 1; } session->res_model = oval_agent_get_results_model(session->sess); dI("OVAL evaluation successfully finished."); return 0; } int oval_session_export(struct oval_session *session) { __attribute__nonnull__(session); struct oval_directives_model *dir_model = NULL; struct oscap_source *result = NULL; /* OVAL Results */ const char *filename = NULL; int ret = 0; /* Import OVAL Directives if any */ if (session->oval.directives && session->res_model) { /* OVAL Directives can be used only if there are OVAL Resutls and these are * only available if there is a Results model which mean that either * evaluation or analyse was performed. */ dir_model = oval_directives_model_new(); if (oval_directives_model_import_source(dir_model, session->oval.directives) != 0) goto cleanup; } /* Get OVAL Results if evaluation or analyse has been done and apply * directives to them */ if (session->res_model && (session->export.results || session->export.report)) { oval_results_model_set_export_system_characteristics(session->res_model, session->export_sys_chars); result = oval_results_model_export_source(session->res_model, dir_model, NULL); filename = session->export.results; } /* Validate OVAL Results. The 'result' in condition will make sure that there is * something to validate */ if (result && session->validation && session->full_validation) { if (!oval_session_validate(session, result, OSCAP_DOCUMENT_OVAL_RESULTS)) goto cleanup; } if (session->export.results && result) { /* export to XML */ if (oscap_source_save_as(result, filename) != 0) goto cleanup; } if (session->export.report && result) { /* export to HTML */ char pwd[PATH_MAX]; if (getcwd(pwd, sizeof(pwd)) == NULL) { oscap_seterr(OSCAP_EFAMILY_GLIBC, "ERROR: %s", strerror(errno)); goto cleanup; } /* add params oscap-version & pwd */ const char *stdparams[] = { "oscap-version", oscap_get_version(), "pwd", pwd, NULL }; /* TODO: let the user set the xsl by oval_session_set_report_xsl? */ if (oscap_source_apply_xslt_path(result, oval_results_report, session->export.report, stdparams, oscap_path_to_xslt()) == -1) { goto cleanup; } } ret = 0; /* successfull export */ cleanup: if (result) oscap_source_free(result); if (dir_model) oval_directives_model_free(dir_model); return ret; } void oval_session_set_export_system_characteristics(struct oval_session *session, bool export) { session->export_sys_chars = export; } void oval_session_set_remote_resources(struct oval_session *session, bool allowed, download_progress_calllback_t callback) { session->fetch_remote_resources = allowed; session->progress = callback; } void oval_session_free(struct oval_session *session) { if (session == NULL) return; oscap_source_free(session->oval.directives); oscap_source_free(session->oval.variables); oscap_source_free(session->source); free(session->datastream_id); free(session->component_id); free(session->export.results); free(session->export.report); if (session->sess) oval_agent_destroy_session(session->sess); if (session->def_model) oval_definition_model_free(session->def_model); ds_sds_session_free(session->sds_session); free(session); }