/*
* Copyright 2009-2012 Michael Dalton
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jtaint;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXParseException;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/* Parse JavaTaint configuration file */
public final class ConfigParser extends DefaultHandler
{
private String configPath = "";
private Policy execPolicy = new Policy();
private Policy filePolicy = new Policy();
private Policy sqlPolicy = new Policy();
private Policy xssPolicy = new Policy();
private Map xssFilters = new HashMap();
private Map execWhitelist = new HashMap();
private Map fileWhitelist = new HashMap();
private Map sqlWhitelist = new HashMap();
private Map xssWhitelist = new HashMap();
private Map elemMap = new HashMap();
public ConfigParser() {
elemMap.put("jt-config", null);
elemMap.put("policy", new PolicyHandler());
elemMap.put("filter", new FilterHandler());
elemMap.put("whitelist", new WhitelistHandler());
}
public void parse() {
try {
/* Parse the config file to initialize all configuration params */
ClassLoader cl = ClassLoader.getSystemClassLoader();
InputStream is = cl.getResourceAsStream("jtaint/InstallPath");
if (is == null)
throw new RuntimeException("JavaTaint install corrupted");
BufferedReader br = new BufferedReader(new InputStreamReader(is));
configPath = br.readLine();
br.close();
configPath = configPath + File.separator + "jt-config.xml";
Log.debug("Using Config file path " + configPath);
SAXParserFactory fact = SAXParserFactory.newInstance();
fact.setValidating(true);
fact.newSAXParser().parse(new File(configPath), this);
Log.debug("JavaTaint @version@ initialized");
} catch (SAXParseException e) {
/* already reported by ConfigErrorHandler */
} catch (Throwable th) {
Log.warn(th);
}
}
/* Override ContentHandler methods for parsing */
public void startElement(String ns, String lName, String qName,
Attributes attr) throws SAXException
{
/* Namespace-aware XML parsers put name in qName, others use lName */
String name = lName == null || lName.length() == 0 ? qName : lName;
if (!elemMap.containsKey(name)) {
Log.warn("Unknown XML element " + name + " found in "
+ "configuration file (skipping)\n");
return;
}
ElemHandler eh = (ElemHandler) elemMap.get(name);
if (eh != null)
eh.start(name, attr);
}
public void endElement(String ns, String lName, String qName)
throws SAXException
{
/* Namespace-aware XML parsers put name in qName, others use lName */
String name = lName == null || lName.length() == 0 ? qName : lName;
ElemHandler eh = (ElemHandler) elemMap.get(name);
if (eh != null)
eh.end(name);
}
public void endDocument() {
if (xssFilters.size() == 0 && xssPolicy.getLogVuln()) {
Log.error("Parse configuration error: Logging of XSS "
+ "vulnerabilities enabled but no XSS filters "
+ "specified.\nPlease specify your XSS filters.\n");
xssPolicy().setLogVuln(false);
return;
}
}
/* Override ErrorHandler methods for logging errors */
public void error(SAXParseException e) {
log("Continuable parsing error ", e);
}
public void fatalError(SAXParseException e) throws SAXParseException {
log("Fatal parsing error ", e);
throw e;
}
public void warning(SAXParseException e) {
log("Parsing warning ", e);
}
private void log(String msg, SAXParseException e) {
Log.warn("Parsing config file" + configPath + "\n" + "Line " +
e.getLineNumber() + " Column " + e.getColumnNumber() +
": " + msg + "(" + e.getMessage() + ")");
}
private static void addMethod(Map m, String className, String methodName) {
Set s = (Set) m.get(className);
if (s == null)
s = new HashSet();
s.add(methodName);
m.put(className, s);
}
private abstract class ElemHandler
{
void start(String name, Attributes attrs) { }
void end(String name) { }
}
private final class PolicyHandler extends ElemHandler
{
public void start(String name, Attributes attrs) {
Policy p;
String type = attrs.getValue("type");
if (type == null) {
Log.warn("Configuration file parser error: policy "
+ "specified without type attribute "
+ "(skipping)\n");
return;
}
if ("exec".equals(type))
p = execPolicy;
else if ("file".equals(type))
p = filePolicy;
else if ("sql".equals(type))
p = sqlPolicy;
else if ("xss".equals(type))
p = xssPolicy;
else {
Log.warn("Configuration file parser error: policy has "
+ "unknown type " + type + "(skipping)\n");
return;
}
String enabled = attrs.getValue("enabled");
String logAttack = attrs.getValue("log-attack");
String logVuln = attrs.getValue("log-vuln");
if (enabled != null)
p.setEnabled(Boolean.valueOf(enabled).booleanValue());
if (logAttack != null)
p.setLogAttack(Boolean.valueOf(logAttack).booleanValue());
if (logVuln != null)
p.setLogVuln(Boolean.valueOf(logVuln).booleanValue());
}
}
private final class FilterHandler extends ElemHandler
{
public void start(String name, Attributes attrs) {
String className = attrs.getValue("class");
String methodName = attrs.getValue("method");
String type = attrs.getValue("type");
if (type == null || className == null || methodName == null
|| !"xss".equals(type)) {
Log.warn("Invalid filter (skipping)");
return;
}
/* Store class names in internal format */
addMethod(xssFilters, className.replace('.', '/'), methodName);
}
}
private final class WhitelistHandler extends ElemHandler
{
public void start(String name, Attributes attrs) {
String className = attrs.getValue("class");
String methodName = attrs.getValue("method");
String type = attrs.getValue("type");
Map m = null;
if (type == null) type = "";
if ("exec".equals(type))
m = execWhitelist;
else if ("file".equals(type))
m = fileWhitelist;
else if ("sql".equals(type))
m = sqlWhitelist;
else if ("xss".equals(type))
m = xssWhitelist;
if (m == null || className == null || methodName == null) {
Log.warn("Invalid filter (skipping)");
return;
}
addMethod(m, className, methodName);
}
}
/* Accessors for all configuration options */
public Policy execPolicy() { return execPolicy; }
public Policy filePolicy() { return filePolicy; }
public Policy sqlPolicy() { return sqlPolicy; }
public Policy xssPolicy() { return xssPolicy; }
public Map xssFilters() { return xssFilters; }
public Map execWhitelist() { return execWhitelist; }
public Map fileWhitelist() { return fileWhitelist; }
public Map sqlWhitelist() { return sqlWhitelist; }
public Map xssWhitelist() { return xssWhitelist; }
}