#include #include #include #include #include #include #include #include #include #include #include "util.h" #include "xml_helper.h" /* 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"; /** * \brief Validate a XML policy file * * Call this function bedore any further processing of a XML policy file. It * will extract the name of the RELAX NG schema file from the metadata section * together with other information and validate the file accordingly. * * \param policy_file_name name of the XML policy file * \param ipa_policy_type will contain the IPA policy type, i.e. action, * config or role, if the function returns successfully * \param xslt_file_name will contain the name of the XSLT file if the IPA * policy is either config or role (action do not need an XSLT) and if the * function returns successfully * * \return 0 on success, -1 if an error occured * */ int validate_policy(const char *policy_file_name, char **ipa_policy_type, char **xslt_file_name) { xmlDocPtr doc; char *rng_file_name; xmlRelaxNGValidCtxtPtr rng_context; xmlChar xpath_expr[XMLCHARLEN]; doc = xmlParseFile(policy_file_name); CHECK(doc, NULL, ("Cannot parse document %s!\n", policy_file_name), exit(1)); xmlStrPrintf(xpath_expr, XMLCHARLEN, (xmlChar *) "//%s:ipa/*[2]", default_namespace_prefix); *ipa_policy_type = find_by_xpath(doc, xpath_expr, FIND_NAME); CHECK(*ipa_policy_type, NULL, ("Type of IPA policy not found.\n"), exit(1)); DEBUG(3, ("Found IPA policy type: %s\n", *ipa_policy_type)); if ( strncmp(*ipa_policy_type, "ipaconfig",9) != 0 && strncmp(*ipa_policy_type, "iparole",7) != 0 && strncmp(*ipa_policy_type, "ipaaction",9) != 0) { DEBUG(0,("unknown IPA ploicy type\n")); exit(1); } xmlStrPrintf(xpath_expr, XMLCHARLEN, (xmlChar *) "//%s:RNGfile", default_namespace_prefix); rng_file_name = find_by_xpath(doc, xpath_expr, FIND_VALUE); CHECK(rng_file_name, NULL, ("Name of RELANX NG schema file not found.\n"), exit(1)); 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(rng_context, NULL, ("Failed to create RNG context\n"), exit(1)); if (xmlRelaxNGValidateDoc(rng_context, doc) == 0) { DEBUG(3, ("The document is valid.\n")); } else { DEBUG(0, ("Error during validation.\n")); exit(1); } xmlRelaxNGFreeValidCtxt(rng_context); free(rng_file_name); if (strncmp(*ipa_policy_type, "ipaaction", 9)!=0) { xmlStrPrintf(xpath_expr, XMLCHARLEN, (xmlChar *) "//%s:XSLTfile", default_namespace_prefix); *xslt_file_name = find_by_xpath(doc, xpath_expr, FIND_VALUE); CHECK(*xslt_file_name, NULL, ("Name of XSLT file not found.\n"), exit(1)); DEBUG(3, ("Found name of XSLT file: %s\n", *xslt_file_name)); } xmlFreeDoc(doc); return 0; } /** * \brief Show all attributes of an XML node * * This is a debung function to print all attribute of a XML node. * * \param node pointer to the XML node * * \return 0 * */ int print_all_attributes(const 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; } xmlChar *get_default_namespace(xmlDocPtr doc) { xmlNodePtr root_node; xmlChar *default_namespace; root_node = xmlDocGetRootElement(doc); CHECK(root_node, NULL, ("Cannot find root node of the current document!\n"), return NULL); if (xmlStrncasecmp(root_node->name, (xmlChar *) "IPA", XMLCHARLEN) != 0) { DEBUG(0, ("Name of root node of the current document has to be 'ipa'!\n")); exit(1); } CHECK(root_node->ns->href, NULL, ("Root node of the current document must define a namespace!\n"), return NULL); default_namespace = xmlStrndup(root_node->ns->href, XMLCHARLEN); CHECK(default_namespace, NULL, ("Cannot copy namespace!\n"), return NULL); DEBUG(3, ("Default namespace is %s\n", default_namespace)); return default_namespace; } /** * \brief find a single name or value defined by a XPath expression * * This function will return the name or the value of a XML node which is * selected by a XPath expression. if more than one value is found it is * considered as an error and NULL is returned. * * \param doc pointer to the already parsed XML document * \param xpath_expr a XPath expression describing the node to search for * \param type use FIND_NAME to return the name and FIND_VALUE to return the * value of the node * * \return pointer to the found string or NULL in case of an error * */ char *find_by_xpath(const xmlDocPtr doc, const xmlChar * xpath_expr, const int type) { xmlXPathContextPtr xpath_context; xmlXPathObjectPtr xpath_obj; char *result = NULL; xmlChar *namespace; namespace = get_default_namespace(doc); CHECK(namespace, NULL, ("No default namespace found.\n"), return 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, default_namespace_prefix, namespace) != 0) { DEBUG(0, ("Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", default_namespace_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 { switch (type) { case FIND_NAME: result = strdup((char *) xpath_obj->nodesetval->nodeTab[0]->name); break; case FIND_VALUE: result = (char *) xmlNodeListGetString(doc, xpath_obj->nodesetval->nodeTab[0]-> xmlChildrenNode, 1); break; default: DEBUG(0,("Unknow search type %d\n")); } } xmlFree(namespace); xmlXPathFreeObject(xpath_obj); xmlXPathFreeContext(xpath_context); return result; }