diff options
Diffstat (limited to 'worker/output_handler.c')
-rw-r--r-- | worker/output_handler.c | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/worker/output_handler.c b/worker/output_handler.c new file mode 100644 index 0000000..728f53b --- /dev/null +++ b/worker/output_handler.c @@ -0,0 +1,261 @@ +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> +#include <libgen.h> + + +#include <libxml/tree.h> +#include <libxml/parser.h> +#include <libxml/xpath.h> +#include <libxml/xpathInternals.h> +#include <libxml/relaxng.h> + +#include <libxslt/xslt.h> +#include <libxslt/xsltInternals.h> +#include <libxslt/transform.h> +#include <libxslt/xsltutils.h> + +#include "util.h" +#include "xml_helper.h" +#include "helpers.h" + +char *get_output_handler_parameter(xmlNode *node, const char *name, const char *default_value, const int required) { + char *value; + + DEBUG(3,("Search for attribute '%s'.\n",name)); + value = (char *) xmlGetProp(node, (xmlChar *) name); + if (required == 1) { + CHECK_NULL_FATAL(value, ("Cannot find required attribute '%s' for output handler.\n", name)); + DEBUG(3,("Found required attribute '%s' with value '%s'.\n",name, value)); + } else if (required == 0 ) { + if (value == NULL) { + DEBUG(3,("Optional attribute '%s' not found, using default '%s'.\n",name, default_value)); + if (default_value != NULL ) value=strdup(default_value); + } else { + DEBUG(3,("Found optional attribute '%s' with value '%s'.\n",name, value)); + } + } else { + DEBUG(0,("I am not allowed to be here, aborting ...\n")); + exit(-1); + } + + return value; +} + +int output_handler_file(xmlNode *node, const xmlDocPtr doc, const char *xslt_file_name) { + char *name; + char *owner; + char *group; + char *permission; + char *param_name; + char *param_value; + struct stat stat_buffer; + char *dir_name; + char *tmp_file_name; + char *buffer; + int ret; + int fd; + xsltStylesheetPtr parsed_stylesheet = NULL; + xmlDocPtr res; + + name=get_output_handler_parameter(node, "name", NULL, 1); + + buffer=strdup(name); + CHECK_NULL_RETURN(buffer ,("strdup failed\n")); + dir_name=dirname(buffer); + if( (ret=stat(dir_name, &stat_buffer)) == -1) { + DEBUG(0,("stat on %s failed: %s\n",dir_name, strerror(errno))); + free(name); + return -1; + } + if(!S_ISDIR(stat_buffer.st_mode)) { + DEBUG(0,("%s is not a directory!\n",dir_name)); + free(name); + return -1; + } + free(buffer); + + if( (ret=lstat(name, &stat_buffer)) == -1) { + DEBUG(0,("stat on %s failed: %s\n",name, strerror(errno))); + free(name); + return -1; + } + if(!S_ISREG(stat_buffer.st_mode)) { + DEBUG(0,("%s is not a regular file!\n",name)); + free(name); + return -1; + } + + owner=get_output_handler_parameter(node, "owner", "root", 0); + group=get_output_handler_parameter(node, "group", "root", 0); + + permission=get_output_handler_parameter(node, "permission", "0400", 0); + param_name=get_output_handler_parameter(node, "param_name", NULL, 0); + param_value=get_output_handler_parameter(node, "param_value", NULL, 0); + + /* TODO: create backup copy */ + + tmp_file_name=(char *) malloc(strlen(name)+7); + CHECK_NULL_RETURN(tmp_file_name,("malloc failed.")); + strcpy(tmp_file_name, name); + strcat(tmp_file_name, ".XXXXXX"); + open_temporary_file(tmp_file_name, permission, owner, group, NULL); + + parsed_stylesheet = xsltParseStylesheetFile((xmlChar *) xslt_file_name); + CHECK_NULL_FATAL(parsed_stylesheet, ("Cannot parse stylesheet!\n")); + + res = xsltApplyStylesheet(parsed_stylesheet, doc, NULL); + CHECK_NULL_FATAL(res, ("Cannot apply stylesheet!\n")); + ret = xsltSaveResultToFd(fd, res, parsed_stylesheet); + if (ret == -1) { + DEBUG(0, ("Cannot save result!\n")); + exit(1); + } + xmlFreeDoc(res); + xsltFreeStylesheet(parsed_stylesheet); + + close(fd); + ret=rename(tmp_file_name, name); + CHECK_MINUS_ONE_RETURN(ret, ("Cannot rename %s to %s: %s\n", tmp_file_name, name, strerror(errno) )); + + free(tmp_file_name); + + free(name); + free(owner); + free(group); + free(permission); + free(param_name); + free(param_value); + return 0; +} + +int output_handler_exec_with_args(xmlNode *node, const xmlDocPtr doc, const char *xslt_file_name) { + char *command; + char *arguments; + char *user; + char *group; + char *param_name; + char *param_value; + int ret; + struct stat stat_buffer; + xsltStylesheetPtr parsed_stylesheet = NULL; + xmlDocPtr res; + xmlChar *result_string; + int result_length; + char *cur; + char *end_of_line; + + command=get_output_handler_parameter(node, "command", NULL, 1); + + if( (ret=stat(command, &stat_buffer)) == -1) { + DEBUG(0,("stat on %s failed: %s\n",command, strerror(errno))); + free(command); + return -1; + } + + + arguments=get_output_handler_parameter(node, "arguments", NULL, 0); + + user=get_output_handler_parameter(node, "user", "nobody", 0); + group=get_output_handler_parameter(node, "group", "nobody", 0); + + param_name=get_output_handler_parameter(node, "param_name", NULL, 0); + param_value=get_output_handler_parameter(node, "param_value", NULL, 0); + + parsed_stylesheet = xsltParseStylesheetFile((xmlChar *) xslt_file_name); + CHECK_NULL_FATAL(parsed_stylesheet, ("Cannot parse stylesheet!\n")); + + res = xsltApplyStylesheet(parsed_stylesheet, doc, NULL); + CHECK_NULL_FATAL(res, ("Cannot apply stylesheet!\n")); + ret = xsltSaveResultToString(&result_string, &result_length, res, parsed_stylesheet); + if (ret == -1) { + DEBUG(0, ("Cannot save result!\n")); + exit(1); + } + xmlFreeDoc(res); + xsltFreeStylesheet(parsed_stylesheet); + + cur=(char *)result_string; + while ( (end_of_line = strchr(cur, '\n'))!=NULL ) { + *end_of_line='\0'; + DEBUG(3,("found argument to %s: |%s|\n",command, cur)); + ret=exec_command(command, user, group, arguments, cur); + DEBUG(3,("exec_command retrun value: %d\n",ret)); + cur=end_of_line+1; + }; + + free(result_string); + + free(command); + free(arguments); + free(user); + free(group); + free(param_name); + free(param_value); + return 0; +} + +int find_output_handler(const char *policy_file_name, const char *xslt_file_name) { + int i; + xmlXPathContextPtr xpath_context; + xmlXPathObjectPtr xpath_obj; + xmlDocPtr xslt_doc; + xmlDocPtr doc; + + doc = xmlParseFile(policy_file_name); + CHECK(doc, NULL, ("Cannot parse file %s!\n", policy_file_name), exit(1)); + + xslt_doc = xmlParseFile(xslt_file_name); + CHECK(xslt_doc, NULL, ("Cannot parse file %s!\n", xslt_file_name), exit(1)); + + xpath_context = xmlXPathNewContext(xslt_doc); + CHECK(xpath_context, NULL, ("Error: unable to create new XPath context\n"), exit(1)); + + if (xmlXPathRegisterNs(xpath_context, XSLT_METADATA_NAMESPACE_PREFIX, XSLT_METADATA_NAMESPACE) != 0) { + DEBUG(0, + ("Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", + XSLT_METADATA_NAMESPACE_PREFIX, XSLT_METADATA_NAMESPACE)); + xmlXPathFreeContext(xpath_context); + return 0; + } + + xpath_obj = xmlXPathEvalExpression(XPATH_OUTPUT_HANDLER, xpath_context); + if (xpath_obj == NULL) { + DEBUG(0, + ("Error: unable to evaluate xpath expression \"%s\"\n", + XPATH_OUTPUT_HANDLER)); + xmlXPathFreeContext(xpath_context); + return 0; + } + + if (xmlXPathNodeSetIsEmpty(xpath_obj->nodesetval)) { + DEBUG(0, ("Nothing found for %s\n", XPATH_OUTPUT_HANDLER)); + xmlXPathFreeObject(xpath_obj); + xmlXPathFreeContext(xpath_context); + return 0; + } + + for (i=0; i<xmlXPathNodeSetGetLength(xpath_obj->nodesetval); i++) { + DEBUG(3, ("found output_handler: %s\n",(char *) xpath_obj->nodesetval->nodeTab[i]->name)); + print_all_attributes(xpath_obj->nodesetval->nodeTab[i]); + if ( xmlStrEqual(xpath_obj->nodesetval->nodeTab[i]->name, (xmlChar *) "file" )) { + output_handler_file(xpath_obj->nodesetval->nodeTab[i], doc, xslt_file_name); + } else if ( xmlStrEqual(xpath_obj->nodesetval->nodeTab[i]->name, (xmlChar *) "exec_with_args" )) { + output_handler_exec_with_args(xpath_obj->nodesetval->nodeTab[i], doc, xslt_file_name); + } else { + DEBUG(0, ("Unknow outout handler '%s'.\n", xpath_obj->nodesetval->nodeTab[i]->name)); + xmlXPathFreeObject(xpath_obj); + xmlXPathFreeContext(xpath_context); + return -1; + } + } + + + xmlXPathFreeObject(xpath_obj); + xmlXPathFreeContext(xpath_context); + xmlFreeDoc(xslt_doc); + xmlFreeDoc(doc); + return 0; +} |