import java.net.*; import java.io.*; import java.util.*; import javax.xml.parsers.*; import org.xml.sax.*; import org.w3c.dom.*; /* * SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * EXPRESSLY DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * An instance of this class encapsulates the data * of a platform-specification of the CPE 2.0 Language, * as parsed into a DOM Element object. (Remember that * a platform-specification has one or more definitions * in CPE language each with an identifier). * * @version 1.4 * @author Neal Ziring, NSA * */ public class CPELanguage { /** Namespace of the CPE Language */ public static final String NAMESPACE = "http://cpe.mitre.org/language/2.0"; /** Name of the root element of the CPE Language */ public static final String PLATFORM_SPEC_NAME = "platform-specification"; /** Name of a platform definition in CPE Language */ public static final String PLATFORM_NAME = "platform"; /** Name of a logical test element in CPE Language */ public static final String LOGICAL_TEST_NAME = "logical-test"; /** Name of a fact ref element in CPE Language */ public static final String FACT_REF_NAME = "fact-ref"; /** Name of the fact-ref attribute holding a CPE Name */ public static final String CPE_NAME_ATTR = "name"; /** Name of the logical-test operator attribute */ public static final String OPERATOR_ATTR = "operator"; /** Name of the logical-test negation attribute */ public static final String NEGATE_ATTR = "negate"; /** Name of the id attribute */ public static final String ID_ATTR = "id"; /** Operator for disjunction: OR */ public static final String OPERATOR_OR = "or"; /** Operator for conjunction: AND */ public static final String OPERATOR_AND = "and"; static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; static final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema"; final String JAXP_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource"; private Element platformSpec; private Map definitions; /** * Initialize a CPELanguage object from a W3C Element. * The element must be the platform-specification * element in the CPE Language schema. If the * element is not the CPE Language platform-specification * element, then IllegalArgumentException will be thrown. */ public CPELanguage(Element ps) { System.err.println("In ctor, full tagname is " + ps.getTagName()); System.err.println("In ctor, node name is " + ps.getNodeName()); System.err.println("In ctor, local name is " + ps.getLocalName()); if (!(ps.getLocalName().equals(PLATFORM_SPEC_NAME) && ps.getNamespaceURI().equals(NAMESPACE))) { throw new IllegalArgumentException("Bad CPE Language element"); } platformSpec = ps; definitions = new HashMap(); String defn_id; Element defn; Node n; NodeList kids; String lname; kids = platformSpec.getChildNodes(); for(int i = 0; i < kids.getLength(); i++) { n = kids.item(i); if (n.getNodeType() == Node.ELEMENT_NODE) { defn = (Element)n; lname = defn.getLocalName(); if (lname.equals(PLATFORM_NAME)) { defn_id = defn.getAttribute(ID_ATTR); definitions.put(defn_id, defn); } } } } /** * Return the number of definitions in this * CPE Language platform-specification. */ public int getSize() { return definitions.size(); } /** * Return all the ids from this platform-specification. */ public Set getDefinitionIds() { return definitions.keySet(); } /** * Get a particular definition from the * list of definitions. */ public Element getDefinition(String id) { return (Element)(definitions.get(id)); } /** * */ public String toString() { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); pw.print("CPELanguage["); pw.print(getSize() + ", ids=("); Iterator it; it = getDefinitionIds().iterator(); while(it.hasNext()) { pw.print(it.next().toString()); pw.print(" "); } pw.print("), "); pw.print(platformSpec.toString()); pw.print("]"); pw.flush(); return sw.toString(); } /** * Match a specified one of the definitions in this * platform-specification against a set of known * CPE Names. See also languageMatch, below. */ public boolean matchDefinition(String id, Collection k) { Element defn; defn = getDefinition(id); return languageMatch(k, defn); } /** * Match a given CPE Language definition against a known * set of CPE Names. This static method returns true * iff matching against the known set of CPE Names can * satisfy the CPE Language expression. Objects in the * input collection k must be CPEName objects, other * objects are ignored. If the input defn is not a DOM * Element from CPE 2.0 Language namespace, then an * IllegalArgumentException is thrown. If any of the * fact-ref elements contain improper CPE Name URIs, then * an IllegalArgumentException is thrown. * * @param k A collection of CPEName objects * @param defn A DOM Element, a platform from a platform-specification * @return true if the known set can satisfy the language expression */ public static boolean languageMatch(Collection k, Element defn) { boolean answer = false; NodeList kids; String tag; if (!(defn.getNamespaceURI().equals(NAMESPACE))) { throw new IllegalArgumentException("Definition is not a CPE Language element"); } tag = defn.getLocalName(); if (tag.equals(PLATFORM_NAME)) { kids = defn.getElementsByTagNameNS(NAMESPACE,LOGICAL_TEST_NAME); if (kids.getLength() > 0) { Element lt; /* Note: only first logical-test is used */ lt = (Element)(kids.item(0)); answer = languageMatch(k, lt); } } else if (tag.equals(FACT_REF_NAME)) { CPEName fact = null; try { fact = new CPEName(defn.getAttribute(CPE_NAME_ATTR)); answer = fact.nameMatch(k); } catch (URISyntaxException usx) { IllegalArgumentException e; e = new IllegalArgumentException("Bad CPE Name in fact-ref element"); e.initCause(usx); throw e; } } else if (tag.equals(LOGICAL_TEST_NAME)) { int i; Node kid; String op, neg; int maxcount, count; boolean negate = false; answer = false; kids = defn.getChildNodes(); maxcount = 0; count = 0; for(i = 0; i < kids.getLength(); i++) { kid = kids.item(i); if (kid.getNodeType() == Node.ELEMENT_NODE) { maxcount++; if (languageMatch(k,(Element)kid)) { count++; } } } op = defn.getAttribute(OPERATOR_ATTR); if (((count >= maxcount) && op.equalsIgnoreCase(OPERATOR_AND)) || ((count > 0) && op.equalsIgnoreCase(OPERATOR_OR))) { answer = true; } neg = defn.getAttribute(NEGATE_ATTR); negate = (neg.startsWith("T") || neg.startsWith("t") || neg.equals("1") || neg.equalsIgnoreCase("yes")); if (negate) { answer = !answer; } } return answer; } /** * Main for testing. */ public static void main(String [] args) { if (args.length == 0) { System.err.println("Usage: java CPELanguage cpe-file [cpe-name ...]"); System.err.println(" (cpe-file should be an XML file that obeys the CPE 2.0 Language schema)"); System.exit(1); } DocumentBuilderFactory dbf; DocumentBuilder db; InputSource is; Document doc = null; /* create a parser and load in the CPE Language file */ try { dbf = DocumentBuilderFactory.newInstance(); // dbf.setValidating(true); dbf.setNamespaceAware(true); dbf.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA); db = dbf.newDocumentBuilder(); is = new InputSource(args[0]); doc = db.parse(is); } catch (Exception e1) { System.err.println("Error in parsing: " + e1); System.exit(2); } CPELanguage cpel = null; try { cpel = new CPELanguage(doc.getDocumentElement()); } catch (Exception e2) { System.err.println("Error in CPE Language element: " + e2); e2.printStackTrace(); System.exit(3); } System.out.println("Read CPE Language object: " + cpel.toString()); if (args.length > 1) { System.out.println("There seem to be " + (args.length - 1) + " additional CPE Names on command line."); Set k; CPEName cpe; k = new HashSet(); for(int i = 1; i < args.length; i++) { try { cpe = new CPEName(args[i]); k.add(cpe); } catch (URISyntaxException usx) { System.err.println("Bad CPE name: " + usx); } } Iterator it; System.out.println("Loaded collection of CPE Names"); for(it = k.iterator(); it.hasNext(); ) { System.out.println("\t" + it.next().toString()); } System.out.println("Testing matching for all ids"); for(it = cpel.getDefinitionIds().iterator(); it.hasNext(); ) { String id; id = (String)(it.next()); System.out.println("Id " + id); if (cpel.matchDefinition(id, k)) { System.out.println("Id " + id + " is satisfied by the collection k"); } else { System.out.println("Id " + id + " is NOT satisfied by the collection"); } } } } }