#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "util.h" #define XMLCHARLEN 255 #define MAXSTR XMLCHARLEN /* If a default namespace is defined * * IMPORTANT: XPath 1.0 has no concept of a default namespace. Unprefixed * names in XPath only match names which have no namespace. So, if the * document uses a default namespace, it is required to associate a non-empty * prefix with the default namespace via register-namespace and add that * prefix to names in XPath expressions intended to match nodes in the default * namespace. */ xmlChar *default_namespace_prefix = (xmlChar *) "def"; #define XSLT_METADATA_NAMESPACE (xmlChar *) "http://freeipa.org/xsl/metadata/1.0" #define XSLT_METADATA_NAMESPACE_PREFIX (xmlChar *) "md" #define XPATH_OUTPUT_HANDLER (xmlChar *) "//md:output_handler/*" 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; struct passwd *pwd_info; struct group *grp_info; 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); pwd_info=getpwnam(owner); CHECK_NULL_RETURN(pwd_info, ("Cannot find user %s.\n", owner)); group=get_output_handler_parameter(node, "group", "root", 0); grp_info=getgrnam(group); CHECK_NULL_RETURN(grp_info, ("Cannot find group %s.\n", group)); 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"); fd=mkstemp(tmp_file_name); if (fd==-1) { DEBUG(0,("mkstemp failed with template %s: %s\n",tmp_file_name, strerror(errno))); free(name); return(-1); } ret=fchmod(fd, (mode_t) strtol(permission, NULL, 8)); CHECK_MINUS_ONE_RETURN(ret, ("Cannot chmod temporary file to %s: %s\n", permission, strerror(errno))); ret=fchown(fd, pwd_info->pw_uid, grp_info->gr_gid); CHECK_MINUS_ONE_RETURN(ret, ("Cannot chown temporary file to %s:%s: %s\n", owner, group, strerror(errno))); 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; struct passwd *pwd_info; struct group *grp_info; 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); pwd_info=getpwnam(user); CHECK_NULL_RETURN(pwd_info, ("Cannot find user %s.\n", user)); group=get_output_handler_parameter(node, "group", "nogroup", 0); grp_info=getgrnam(group); CHECK_NULL_RETURN(grp_info, ("Cannot find group %s.\n", group)); 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; DEBUG(3,("last argument to %s: |%s|\n",command, cur)); while ( (end_of_line = strchr(cur, '\n'))!=NULL ) { *end_of_line='\0'; DEBUG(3,("argument to %s: |%s|\n",command, cur)); 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 print_all_attributes(xmlNode *node) { xmlAttr *cur; cur=node->properties; while(cur!=NULL) { DEBUG(3, ("found attribute '%s' with value '%s'.\n", cur->name, XML_GET_CONTENT(cur->children))); cur=cur->next; } return(0); } int find_output_handler(const xmlDocPtr doc, const char *xslt_file_name) { int i; xmlXPathContextPtr xpath_context; xmlXPathObjectPtr xpath_obj; xmlDocPtr xslt_doc; xslt_doc = xmlParseFile(xslt_file_name); CHECK_NULL_FATAL(xslt_doc, ("Cannot parse file %s!\n", xslt_file_name)); xpath_context = xmlXPathNewContext(xslt_doc); CHECK_NULL_FATAL(xpath_context, ("Error: unable to create new XPath context\n")); 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; inodesetval); 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); return 0; } char *find_value_by_xpath(xmlDocPtr doc, xmlChar * xpath_expr, xmlChar * prefix, xmlChar * namespace) { xmlXPathContextPtr xpath_context; xmlXPathObjectPtr xpath_obj; char *result = NULL; /* Create xpath evaluation context */ xpath_context = xmlXPathNewContext(doc); CHECK_NULL_FATAL(xpath_context, ("Error: unable to create new XPath context\n")); /* Register a namespace */ if (xmlXPathRegisterNs(xpath_context, prefix, namespace) != 0) { DEBUG(0, ("Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", prefix , namespace)); xmlXPathFreeContext(xpath_context); return (NULL); } /* Evaluate xpath expression */ xpath_obj = xmlXPathEvalExpression(xpath_expr, xpath_context); if (xpath_obj == NULL) { DEBUG(0, ("Error: unable to evaluate xpath expression \"%s\"\n", xpath_expr)); xmlXPathFreeContext(xpath_context); return (NULL); } if (xmlXPathNodeSetIsEmpty(xpath_obj->nodesetval)) { DEBUG(0, ("Nothing found for %s\n", xpath_expr)); xmlXPathFreeObject(xpath_obj); xmlXPathFreeContext(xpath_context); return (NULL); } else if (xmlXPathNodeSetGetLength(xpath_obj->nodesetval) != 1) { DEBUG(0, ("More than one node found for %s!", xpath_expr)); xmlXPathFreeObject(xpath_obj); xmlXPathFreeContext(xpath_context); return (NULL); } else { result = (char *) xmlNodeListGetString(doc, xpath_obj->nodesetval->nodeTab[0]-> xmlChildrenNode, 1); } xmlXPathFreeObject(xpath_obj); xmlXPathFreeContext(xpath_context); return result; } int main(int argc, char **argv) { xmlDocPtr doc; xmlNodePtr root_node; xmlChar *default_namespace; xmlChar xpath_expr[XMLCHARLEN]; char *rng_file_name; char *xslt_file_name; xmlRelaxNGValidCtxtPtr rng_context; xmlDocPtr xslt_doc; // xsltStylesheetPtr parsed_stylesheet = NULL; // xmlDocPtr res; // int ret; if (argc != 2) { DEBUG(0, ("missing or to many arguments, I expect a single filename!\n")); exit(1); } doc = xmlParseFile(argv[1]); CHECK_NULL_FATAL(doc, ("Cannot parse document %s!\n", argv[1])); /* find the default namespace */ root_node = xmlDocGetRootElement(doc); CHECK_NULL_FATAL(root_node, ("Cannot find root node of document %s!\n", argv[1])); if (xmlStrncasecmp(root_node->name, (xmlChar *) "IPA", XMLCHARLEN) != 0) { DEBUG(0, ("Name of root node of document %s has to be 'ipa'!\n", argv[1])); exit(1); } CHECK_NULL_FATAL(root_node->ns->href, ("Root node of document %s must define a namespace!\n", argv[1])); default_namespace = xmlStrndup(root_node->ns->href, XMLCHARLEN); CHECK_NULL_FATAL(default_namespace, ("Cannot copy namespace!\n")); DEBUG(3, ("Default namespace of %s is %s\n", argv[1], default_namespace)); /* extract XSTLfile and RNGfile from document using XPath */ xmlStrPrintf(xpath_expr, XMLCHARLEN, (xmlChar *) "//%s:XSLTfile", default_namespace_prefix); xslt_file_name = find_value_by_xpath(doc, xpath_expr, default_namespace_prefix, default_namespace); CHECK_NULL_FATAL(xslt_file_name, ("Name of XSLT file not found.\n")); DEBUG(3, ("Found name of XSLT file: %s\n", xslt_file_name)); xmlStrPrintf(xpath_expr, XMLCHARLEN, (xmlChar *) "//%s:RNGfile", default_namespace_prefix); rng_file_name = find_value_by_xpath(doc, xpath_expr, default_namespace_prefix, default_namespace); CHECK_NULL_FATAL(rng_file_name, ("Name of RELANX NG schema file not found.\n")); DEBUG(3, ("Found name of RELAX NG schema file: %s\n", rng_file_name)); /* validate the document */ rng_context = xmlRelaxNGNewValidCtxt(xmlRelaxNGParse (xmlRelaxNGNewParserCtxt(rng_file_name))); CHECK_NULL_FATAL(rng_context, ("Failed to create RNG context\n")); if (xmlRelaxNGValidateDoc(rng_context, doc) == 0) { DEBUG(0, ("The document is valid.\n")); } else { DEBUG(0, ("Error during validation.\n")); exit(1); } xmlRelaxNGFreeValidCtxt(rng_context); free(rng_file_name); /* read the xslt file */ xslt_doc = xmlParseFile(xslt_file_name); CHECK_NULL_FATAL(xslt_doc, ("Cannot parse file %s!\n", xslt_file_name)); find_output_handler(doc, xslt_file_name); /* parsed_stylesheet = xsltParseStylesheetDoc(xslt_doc); CHECK_NULL_FATAL(parsed_stylesheet, ("Cannot parse stylesheet %s!\n", xslt_file_name)); res = xsltApplyStylesheet(parsed_stylesheet, doc, NULL); CHECK_NULL_FATAL(xslt_doc, ("Cannot apply stylesheet %s!\n", xslt_file_name)); ret = xsltSaveResultToFile(stdout, res, parsed_stylesheet); if (ret == -1) { DEBUG(0, ("Cannot save result!\n")); exit(1); } xmlFreeDoc(res); xsltFreeStylesheet(parsed_stylesheet); */ free(xslt_file_name); xmlFreeDoc(doc); return (0); }