diff options
author | Miroslav Grepl <mgrepl@redhat.com> | 2014-04-11 09:37:53 +0200 |
---|---|---|
committer | Miroslav Grepl <mgrepl@redhat.com> | 2014-04-11 09:37:53 +0200 |
commit | 47be9ff57e72906660bb62a515222f482131e1fb (patch) | |
tree | 2cb0ef0ba48d73b1df7cc0915754a17e19464bb6 /sechecker/sechk_parse.c | |
download | setools-master.tar.gz setools-master.tar.xz setools-master.zip |
Create setools-3.3.7 git repomaster
Diffstat (limited to 'sechecker/sechk_parse.c')
-rw-r--r-- | sechecker/sechk_parse.c | 285 |
1 files changed, 285 insertions, 0 deletions
diff --git a/sechecker/sechk_parse.c b/sechecker/sechk_parse.c new file mode 100644 index 0000000..ae73af2 --- /dev/null +++ b/sechecker/sechk_parse.c @@ -0,0 +1,285 @@ +/* Copyright (C) 2005 Tresys Technology, LLC + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * Author: jmowery@tresys.com + * + */ + +#include "sechecker.h" +#include "sechk_parse.h" +#include <apol/util.h> +#include <libxml/xmlreader.h> +#include <errno.h> +#include <string.h> + +/* xml parser keywords */ +#define SECHK_PARSE_SECHECKER_TAG "sechecker" +#define SECHK_PARSE_PROFILE_TAG "profile" +#define SECHK_PARSE_MODULE_TAG "module" +#define SECHK_PARSE_OPTION_TAG "option" +#define SECHK_PARSE_ITEM_TAG "item" +#define SECHK_PARSE_OUTPUT_TAG "output" +#define SECHK_PARSE_VALUE_ATTRIB "value" +#define SECHK_PARSE_NAME_ATTRIB "name" +#define SECHK_PARSE_VERSION_ATTRIB "version" +#define SECHK_PARSE_OUTPUT_NONE "none" +#define SECHK_PARSE_OUTPUT_QUIET "quiet" +#define SECHK_PARSE_OUTPUT_SHORT "short" +#define SECHK_PARSE_OUTPUT_VERBOSE "verbose" + +static char *build_dtd_path(void) +{ + char *path = NULL; + size_t path_sz = 0; + +#ifdef PROFILE_INSTALL_DIR + if (apol_str_append(&path, &path_sz, "file://localhost/") == -1) + return NULL; + + if (apol_str_append(&path, &path_sz, PROFILE_INSTALL_DIR) == -1) + return NULL; + + if (apol_str_append(&path, &path_sz, "/sechecker.dtd") == -1) + return NULL; + + return path; +#endif + + return NULL; +} + + /* Parsing functions */ + +/* Parse the configuration file. */ +int sechk_lib_parse_xml_file(const char *filename, sechk_lib_t * lib) +{ + xmlTextReaderPtr reader = NULL; + xmlDtdPtr dtd = NULL; + xmlDocPtr xml = NULL; + xmlValidCtxtPtr ctxt = NULL; + int tmp, ret = 0; + char *dtd_path = NULL; + + /* this initializes the XML library and checks potential ABI mismatches + * between the version it was compiled for and the actual shared + * library used. */ + LIBXML_TEST_VERSION; + reader = xmlReaderForFile(filename, NULL, 0); + if (!reader) { + ret = errno; + if (ret != ENOENT) + fprintf(stderr, "Error: Could not create xmlReader.\n"); + goto exit_err; + } + + dtd_path = build_dtd_path(); + if (!dtd_path) { + fprintf(stderr, "Error: getting DTD path\n"); + goto exit_err; + } + dtd = xmlParseDTD(NULL, (const xmlChar *)dtd_path); + free(dtd_path); + + if (!dtd) { + fprintf(stderr, "Error: parsing DTD\n"); + goto exit_err; + } + + xml = xmlParseFile(filename); + if (!xml) { + fprintf(stderr, "Error: parsing sechecker profile\n"); + goto exit_err; + } + + ctxt = xmlNewValidCtxt(); + if (!ctxt) { + fprintf(stderr, "Error: out of memory\n"); + goto exit_err; + } + /* validate profile against the DTD */ + if (xmlValidateDtd(ctxt, xml, dtd) == 0) { + fprintf(stderr, "Error: SEChecker profile contains invalid XML. Aborting.\n"); + goto exit_err; + } + xmlFreeValidCtxt(ctxt); + xmlFreeDoc(xml); + xmlFreeDtd(dtd); + + while (1) { + ret = xmlTextReaderRead(reader); + if (ret == -1) { + ret = errno; + fprintf(stderr, "Error: Error reading xml.\n"); + goto exit_err; + } + if (ret == 0) /* no more nodes to read */ + break; + + tmp = sechk_lib_process_xml_node(reader, lib); + if (tmp == -1) + goto exit_err; + if (tmp == 1) { + ret = xmlTextReaderNext(reader); + if (ret == 0) + break; + if (ret == -1) { + ret = errno; + fprintf(stderr, "Error in xmlTextReaderNext()\n"); + goto exit_err; + } + } + } + + /* cleanup function for the XML library */ + xmlCleanupParser(); + xmlFreeTextReader(reader); + return 0; + + exit_err: + xmlCleanupParser(); + if (reader) + xmlFreeTextReader(reader); + if (ret) + errno = ret; + return -1; +} + +/* process a single node in the xml file */ +int sechk_lib_process_xml_node(xmlTextReaderPtr reader, sechk_lib_t * lib) +{ + xmlChar *attrib = NULL; + int idx; + sechk_name_value_t *nv = NULL; + static xmlChar *option = NULL; + static xmlChar *value = NULL; + static sechk_module_t *current_module = NULL; + + switch (xmlTextReaderNodeType(reader)) { + + case XML_ELEMENT_DECL: /* closing tags */ + if (xmlStrEqual(xmlTextReaderConstName(reader), (xmlChar *) SECHK_PARSE_MODULE_TAG) == 1) { + current_module = NULL; + } else if (xmlStrEqual(xmlTextReaderConstName(reader), (xmlChar *) SECHK_PARSE_OPTION_TAG) == 1) { + free(option); + option = NULL; + } + break; + + case XML_ELEMENT_NODE: /* opening tags */ + + if (xmlStrEqual(xmlTextReaderConstName(reader), (xmlChar *) SECHK_PARSE_SECHECKER_TAG) == 1) { + /* parsing the <sechecker> tag */ + attrib = xmlTextReaderGetAttribute(reader, (xmlChar *) SECHK_PARSE_VERSION_ATTRIB); + if (attrib) { +#ifdef SECHECKER_VERSION + if (atof((const char *)attrib) > atof(SECHECKER_VERSION)) { + fprintf(stderr, + "Error: sechecker version in profile is incorrect: expected %1.1f got %1.1f\n", + atof(SECHECKER_VERSION), atof((const char *)attrib)); + goto exit_err; + } +#endif + + free(attrib); + attrib = NULL; + } else { + fprintf(stderr, "Warning: sechecker version is not specified.\n"); + } + } else if (xmlStrEqual(xmlTextReaderConstName(reader), (xmlChar *) SECHK_PARSE_MODULE_TAG) == 1) { + /* parsing the <module> tag */ + attrib = xmlTextReaderGetAttribute(reader, (xmlChar *) SECHK_PARSE_NAME_ATTRIB); + if (attrib) { + if ((idx = sechk_lib_get_module_idx((const char *)attrib, lib)) == -1) { + fprintf(stderr, "Warning: module %s not found.\n", (const char *)attrib); + return 1; /* not a fatal error */ + } else { + /* set the values on the existing module */ + current_module = apol_vector_get_element(lib->modules, idx); + current_module->selected = true; + } + free(attrib); + attrib = NULL; + } else { + fprintf(stderr, "Error: module name is not specified.\n"); + goto exit_err; + } + } else if (xmlStrEqual(xmlTextReaderConstName(reader), (xmlChar *) SECHK_PARSE_OPTION_TAG) == 1) { + /* parsing the <option> tag */ + if (!current_module) { + fprintf(stderr, "Error: 'option' specified outside the scope of a module.\n"); + goto exit_err; + } + /* read the name of the option */ + option = xmlTextReaderGetAttribute(reader, (xmlChar *) SECHK_PARSE_NAME_ATTRIB); + if (!option) { + fprintf(stderr, "Error: option name is not specified.\n"); + goto exit_err; + } + /* clear the options with this name that were set by defualt for this module */ + sechk_lib_module_clear_option(current_module, (char *)option); + + } else if (xmlStrEqual(xmlTextReaderConstName(reader), (xmlChar *) SECHK_PARSE_ITEM_TAG) == 1) { + /* parsing the <item> tag */ + assert(current_module); + nv = sechk_name_value_new((char *)option, NULL); + /* read the value for this name value pair */ + value = xmlTextReaderGetAttribute(reader, (xmlChar *) SECHK_PARSE_VALUE_ATTRIB); + if (!value) { + fprintf(stderr, "Error: item value is not specified.\n"); + goto exit_err; + } + nv->value = strdup((char *)value); + free(value); + value = NULL; + /* add the nv pair to the module options */ + apol_vector_append(current_module->options, (void *)nv); + nv = NULL; + } else if (xmlStrEqual(xmlTextReaderConstName(reader), (xmlChar *) SECHK_PARSE_OUTPUT_TAG) == 1) { + if (!current_module) { + fprintf(stderr, "Error: 'output' specified outside the scope of a module.\n"); + goto exit_err; + } + attrib = xmlTextReaderGetAttribute(reader, (xmlChar *) SECHK_PARSE_VALUE_ATTRIB); + if (attrib) { + if (xmlStrEqual(attrib, (xmlChar *) SECHK_PARSE_OUTPUT_QUIET) == 1) { + current_module->outputformat = SECHK_OUT_QUIET; + } else if (xmlStrEqual(attrib, (xmlChar *) SECHK_PARSE_OUTPUT_VERBOSE) == 1) { + current_module->outputformat = SECHK_OUT_VERBOSE; + } else if (xmlStrEqual(attrib, (xmlChar *) SECHK_PARSE_OUTPUT_SHORT) == 1) { + current_module->outputformat = SECHK_OUT_SHORT; + } else if (xmlStrEqual(attrib, (xmlChar *) SECHK_PARSE_OUTPUT_NONE) == 1) { + current_module->outputformat = SECHK_OUT_NONE; + } else { + fprintf(stderr, "Error: invalid output value %s.\n", attrib); + goto exit_err; + } + free(attrib); + attrib = NULL; + } else { + fprintf(stderr, "Error: output value is not specified.\n"); + goto exit_err; + } + } + break; + } + return 0; + + exit_err: + sechk_name_value_free(nv); + errno = EIO; + return -1; +} |