/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2006-2011 The OpenNMS Group, Inc.
* OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc.
*
* OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
*
* OpenNMS(R) is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* OpenNMS(R) is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenNMS(R). If not, see:
* http://www.gnu.org/licenses/
*
* For more information contact:
* OpenNMS(R) Licensing <license@opennms.org>
* http://www.opennms.org/
* http://www.opennms.com/
*******************************************************************************/
package org.opennms.web.vulnerability;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.servlet.ServletContext;
import org.opennms.core.resource.Vault;
import org.opennms.core.utils.ThreadCategory;
import org.opennms.netmgt.model.OnmsSeverity;
import org.opennms.web.vulnerability.filter.Filter;
import org.opennms.web.vulnerability.filter.InterfaceFilter;
import org.opennms.web.vulnerability.filter.NodeFilter;
/**
* Encapsulates all querying functionality for vulnerabilities.
*
* @author <A HREF="mailto:larry@opennms.org">Lawrence Karnowski </A>
* @author <A HREF="http://www.opennms.org/">OpenNMS </A>
* @author <A HREF="mailto:larry@opennms.org">Lawrence Karnowski </A>
* @author <A HREF="http://www.opennms.org/">OpenNMS </A>
* @version $Id: $
* @since 1.8.1
*/
public class VulnerabilityFactory extends Object {
/** Convenience class to determine sort style of a query. */
public static class SortStyle extends Object {
/* CORBA-style enumeration */
public static final int _ID = 1;
public static final int _SEVERITY = 2;
public static final int _NODE = 3;
public static final int _INTERFACE = 4;
public static final int _SERVICE = 5;
public static final int _CREATE_TIME = 6;
public static final int _RESOLVED_TIME = 7;
public static final int _PORT = 8;
public static final int _PROTOCOL = 9;
public static final SortStyle ID = new SortStyle("ID", _ID);
public static final SortStyle SEVERITY = new SortStyle("SEVERITY", _SEVERITY);
public static final SortStyle NODE = new SortStyle("NODE", _NODE);
public static final SortStyle INTERFACE = new SortStyle("INTERFACE", _INTERFACE);
public static final SortStyle SERVICE = new SortStyle("SERVICE", _SERVICE);
public static final SortStyle CREATE_TIME = new SortStyle("CREATE_TIME", _CREATE_TIME);
public static final SortStyle RESOLVED_TIME = new SortStyle("RESOLVED_TIME", _RESOLVED_TIME);
public static final SortStyle PORT = new SortStyle("PORT", _PORT);
public static final SortStyle PROTOCOL = new SortStyle("PROTOCOL", _PROTOCOL);
public static final int _REVERSE_ID = 101;
public static final int _REVERSE_SEVERITY = 102;
public static final int _REVERSE_NODE = 103;
public static final int _REVERSE_INTERFACE = 104;
public static final int _REVERSE_SERVICE = 105;
public static final int _REVERSE_CREATE_TIME = 106;
public static final int _REVERSE_RESOLVED_TIME = 107;
public static final int _REVERSE_PORT = 108;
public static final int _REVERSE_PROTOCOL = 109;
public static final SortStyle REVERSE_ID = new SortStyle("REVERSE_ID", _REVERSE_ID);
public static final SortStyle REVERSE_SEVERITY = new SortStyle("REVERSE_SEVERITY", _REVERSE_SEVERITY);
public static final SortStyle REVERSE_NODE = new SortStyle("REVERSE_NODE", _REVERSE_NODE);
public static final SortStyle REVERSE_INTERFACE = new SortStyle("REVERSE_INTERFACE", _REVERSE_INTERFACE);
public static final SortStyle REVERSE_SERVICE = new SortStyle("REVERSE_SERVICE", _REVERSE_SERVICE);
public static final SortStyle REVERSE_CREATE_TIME = new SortStyle("REVERSE_CREATE_TIME", _REVERSE_CREATE_TIME);
public static final SortStyle REVERSE_RESOLVED_TIME = new SortStyle("REVERSE_RESOLVED_TIME", _REVERSE_RESOLVED_TIME);
public static final SortStyle REVERSE_PORT = new SortStyle("REVERSE_PORT", _REVERSE_PORT);
public static final SortStyle REVERSE_PROTOCOL = new SortStyle("REVERSE_PROTOCOL", _REVERSE_PROTOCOL);
protected String name;
protected int id;
private SortStyle(String name, int id) {
this.name = name;
this.id = id;
}
public String toString() {
return "Event.SortStyle." + name;
}
public String getName() {
return name;
}
public int getId() {
return id;
}
}
/** Convenience class to determine what sort of events to include in a query. */
public static class ResolutionType extends Object {
/* CORBA-style enumeration */
public static final int _OPEN = 1;
public static final int _RESOLVED = 2;
public static final int _BOTH = 3;
public static final ResolutionType OPEN = new ResolutionType("OPEN", _OPEN);
public static final ResolutionType RESOLVED = new ResolutionType("RESOLVED", _RESOLVED);
public static final ResolutionType BOTH = new ResolutionType("BOTH", _BOTH);
protected String name;
protected int id;
private ResolutionType(String name, int id) {
this.name = name;
this.id = id;
}
public String toString() {
return "Vulnerability.ResolutionType." + name;
}
public String getName() {
return name;
}
public int getId() {
return id;
}
}
/** Constant <code>log</code> */
protected static final ThreadCategory log = ThreadCategory.getInstance(VulnerabilityFactory.class);
/** Private constructor so this class cannot be instantiated. */
private VulnerabilityFactory() {
}
/**
* Count all open vulnerabilities.
*
* @return a int.
* @throws java.sql.SQLException if any.
*/
public static int getVulnerabilityCount() throws SQLException {
return getVulnerabilityCount(ResolutionType.OPEN, new Filter[0]);
}
/**
* Count the number of vulnerabilities for a given resolution type and given
* filters..
*
* @param resType a {@link org.opennms.web.vulnerability.VulnerabilityFactory.ResolutionType} object.
* @param filters an array of {@link org.opennms.web.vulnerability.filter.Filter} objects.
* @return a int.
* @throws java.sql.SQLException if any.
*/
public static int getVulnerabilityCount(ResolutionType resType, Filter[] filters) throws SQLException {
if (resType == null || filters == null) {
throw new IllegalArgumentException("Cannot take null parameters.");
}
int vulCount = 0;
Connection conn = Vault.getDbConnection();
try {
StringBuffer select = new StringBuffer("SELECT COUNT(*) AS VULCOUNT FROM VULNERABILITIES LEFT OUTER JOIN NODE USING (NODEID) LEFT OUTER JOIN SERVICE USING (SERVICEID) WHERE ");
select.append(getResolutionTypeClause(resType));
for (Filter filter : filters) {
select.append(" AND");
select.append(filter.getParamSql());
}
PreparedStatement stmt = conn.prepareStatement(select.toString());
int parameterIndex = 1;
for (Filter filter : filters) {
parameterIndex += filter.bindParam(stmt, parameterIndex);
}
ResultSet rs = stmt.executeQuery();
if (rs.next()) {
vulCount = rs.getInt("VULCOUNT");
}
rs.close();
stmt.close();
} finally {
Vault.releaseDbConnection(conn);
}
return vulCount;
}
/**
* Return a specific vulnerability.
*
* @param vulId a int.
* @return a {@link org.opennms.web.vulnerability.Vulnerability} object.
* @throws java.sql.SQLException if any.
*/
public static Vulnerability getVulnerability(int vulId) throws SQLException {
Vulnerability vul = null;
Connection conn = Vault.getDbConnection();
try {
PreparedStatement stmt = conn.prepareStatement("SELECT VULNERABILITIES.*, NODE.NODELABEL, SERVICE.SERVICENAME FROM VULNERABILITIES LEFT OUTER JOIN NODE USING (NODEID) LEFT OUTER JOIN SERVICE USING (SERVICEID) WHERE VULNERABILITYID=? ");
stmt.setInt(1, vulId);
ResultSet rs = stmt.executeQuery();
Vulnerability[] vuls = rs2Vulnerabilities(rs);
// what do I do if this actually returns more than one
// vulnerability?
if (vuls.length > 0) {
vul = vuls[0];
}
rs.close();
stmt.close();
} finally {
Vault.releaseDbConnection(conn);
}
return vul;
}
/*
* ****************************************************************** N O D
* E M E T H O D S
* ******************************************************************
*/
/**
* Return some maximum number of vulnerabilities or less sorted by the given
* sort style for the given node.
*
* @param throttle
* a value less than one means no throttling
* @param nodeId a int.
* @param sortStyle a {@link org.opennms.web.vulnerability.VulnerabilityFactory.SortStyle} object.
* @param resType a {@link org.opennms.web.vulnerability.VulnerabilityFactory.ResolutionType} object.
* @param offset a int.
* @return an array of {@link org.opennms.web.vulnerability.Vulnerability} objects.
* @throws java.sql.SQLException if any.
*/
public static Vulnerability[] getVulnerabilitiesForNode(int nodeId, SortStyle sortStyle, ResolutionType resType, int throttle, int offset, ServletContext servletContext) throws SQLException {
if (sortStyle == null || resType == null) {
throw new IllegalArgumentException("Cannot take null parameters.");
}
Filter[] filters = new Filter[] { new NodeFilter(nodeId, servletContext) };
return (VulnerabilityFactory.getVulnerabilities(sortStyle, resType, filters, throttle, offset));
}
/**
* Return the number of vulnerabilities for this node and the given
* resolution type.
*
* @param nodeId a int.
* @param resType a {@link org.opennms.web.vulnerability.VulnerabilityFactory.ResolutionType} object.
* @return a int.
* @throws java.sql.SQLException if any.
*/
public static int getVulnerabilityCountForNode(int nodeId, ResolutionType resType, ServletContext servletContext) throws SQLException {
if (resType == null) {
throw new IllegalArgumentException("Cannot take null parameters.");
}
Filter[] filters = new Filter[] { new NodeFilter(nodeId, servletContext) };
return (getVulnerabilityCount(resType, filters));
}
/*
* ****************************************************************** I N T
* E R F A C E M E T H O D S
* ******************************************************************
*/
/**
* Return some maximum number of events or less (optionally only
* unacknowledged events) sorted by the given sort style for the given IP
* address.
*
* @param throttle
* a value less than one means no throttling
* @param offset
* which row to start on in the result list
* @param nodeId a int.
* @param ipAddress a {@link java.lang.String} object.
* @param sortStyle a {@link org.opennms.web.vulnerability.VulnerabilityFactory.SortStyle} object.
* @param resType a {@link org.opennms.web.vulnerability.VulnerabilityFactory.ResolutionType} object.
* @return an array of {@link org.opennms.web.vulnerability.Vulnerability} objects.
* @throws java.sql.SQLException if any.
*/
public static Vulnerability[] getVulnerablilitiesForInterface(int nodeId, String ipAddress, SortStyle sortStyle, ResolutionType resType, int throttle, int offset, ServletContext servletContext) throws SQLException {
if (ipAddress == null || sortStyle == null || resType == null) {
throw new IllegalArgumentException("Cannot take null parameters.");
}
Filter[] filters = new Filter[] { new NodeFilter(nodeId, servletContext), new InterfaceFilter(ipAddress) };
return (VulnerabilityFactory.getVulnerabilities(sortStyle, resType, filters, throttle, offset));
}
/**
* Return the number of vulnerabilities for this IP address and the given
* resolution type.
*
* @param nodeId a int.
* @param ipAddress a {@link java.lang.String} object.
* @param resType a {@link org.opennms.web.vulnerability.VulnerabilityFactory.ResolutionType} object.
* @return a int.
* @throws java.sql.SQLException if any.
*/
public static int getVulnerabilityCountForInterface(int nodeId, String ipAddress, ResolutionType resType, ServletContext servletContext) throws SQLException {
if (ipAddress == null || resType == null) {
throw new IllegalArgumentException("Cannot take null parameters.");
}
Filter[] filters = new Filter[] { new NodeFilter(nodeId, servletContext), new InterfaceFilter(ipAddress) };
return (getVulnerabilityCount(resType, filters));
}
/**
* Return all open vulnerabilities sorted by time.
*
* @return an array of {@link org.opennms.web.vulnerability.Vulnerability} objects.
* @throws java.sql.SQLException if any.
*/
public static Vulnerability[] getVulnerabilities() throws SQLException {
return VulnerabilityFactory.getVulnerabilities(SortStyle.ID, ResolutionType.OPEN);
}
/**
* Return all open or resolved vulnerabilities sorted by identifier.
*
* @param resType a {@link org.opennms.web.vulnerability.VulnerabilityFactory.ResolutionType} object.
* @return an array of {@link org.opennms.web.vulnerability.Vulnerability} objects.
* @throws java.sql.SQLException if any.
*/
public static Vulnerability[] getVulnerabilities(ResolutionType resType) throws SQLException {
return VulnerabilityFactory.getVulnerabilities(SortStyle.ID, resType);
}
/**
* Return all open vulnerabilities sorted by the given sort style.
*
* @param sortStyle a {@link org.opennms.web.vulnerability.VulnerabilityFactory.SortStyle} object.
* @return an array of {@link org.opennms.web.vulnerability.Vulnerability} objects.
* @throws java.sql.SQLException if any.
*/
public static Vulnerability[] getVulnerabilities(SortStyle sortStyle) throws SQLException {
return VulnerabilityFactory.getVulnerabilities(sortStyle, ResolutionType.OPEN);
}
/**
* Return all vulnerabilities (optionally only open vulnerabilities) sorted
* by the given sort style.
*
* @param sortStyle a {@link org.opennms.web.vulnerability.VulnerabilityFactory.SortStyle} object.
* @param resType a {@link org.opennms.web.vulnerability.VulnerabilityFactory.ResolutionType} object.
* @return an array of {@link org.opennms.web.vulnerability.Vulnerability} objects.
* @throws java.sql.SQLException if any.
*/
public static Vulnerability[] getVulnerabilities(SortStyle sortStyle, ResolutionType resType) throws SQLException {
return VulnerabilityFactory.getVulnerabilities(sortStyle, resType, new Filter[0]);
}
/**
* Return all vulnerabilities (optionally only open vulnerabilities) sorted
* by the given sort style.
*
* @param sortStyle a {@link org.opennms.web.vulnerability.VulnerabilityFactory.SortStyle} object.
* @param resType a {@link org.opennms.web.vulnerability.VulnerabilityFactory.ResolutionType} object.
* @param filters an array of {@link org.opennms.web.vulnerability.filter.Filter} objects.
* @return an array of {@link org.opennms.web.vulnerability.Vulnerability} objects.
* @throws java.sql.SQLException if any.
*/
public static Vulnerability[] getVulnerabilities(SortStyle sortStyle, ResolutionType resType, Filter[] filters) throws SQLException {
return VulnerabilityFactory.getVulnerabilities(sortStyle, resType, filters, -1, -1);
}
/**
* Return all vulnerabilities (optionally only open vulnerabilities) sorted
* by the given sort style.
*
* <p>
* <strong>Note: </strong> This limit/offset code is <em>Postgres
* specific!</em>
* Per <a href="mailto:shaneo@opennms.org">Shane </a>, this is okay for now
* until we can come up with an Oracle alternative too.
* </p>
*
* @param limit
* if -1 or zero, no limit or offset is used
* @param offset
* if -1, no limit or offset if used
* @param sortStyle a {@link org.opennms.web.vulnerability.VulnerabilityFactory.SortStyle} object.
* @param resType a {@link org.opennms.web.vulnerability.VulnerabilityFactory.ResolutionType} object.
* @param filters an array of {@link org.opennms.web.vulnerability.filter.Filter} objects.
* @return an array of {@link org.opennms.web.vulnerability.Vulnerability} objects.
* @throws java.sql.SQLException if any.
*/
public static Vulnerability[] getVulnerabilities(SortStyle sortStyle, ResolutionType resType, Filter[] filters, int limit, int offset) throws SQLException {
if (sortStyle == null || resType == null || filters == null) {
throw new IllegalArgumentException("Cannot take null parameters.");
}
boolean useLimits = false;
if (limit > 0 && offset > -1) {
useLimits = true;
}
Vulnerability[] vuls = null;
Connection conn = Vault.getDbConnection();
try {
StringBuffer select = new StringBuffer("SELECT VULNERABILITIES.*, NODE.NODELABEL, SERVICE.SERVICENAME FROM VULNERABILITIES LEFT OUTER JOIN NODE USING(NODEID) LEFT OUTER JOIN SERVICE USING(SERVICEID) WHERE");
select.append(getResolutionTypeClause(resType));
for (Filter filter : filters) {
select.append(" AND");
select.append(filter.getParamSql());
}
select.append(getOrderByClause(sortStyle));
if (useLimits) {
select.append(" LIMIT ");
select.append(limit);
select.append(" OFFSET ");
select.append(offset);
}
log.debug(select.toString());
PreparedStatement stmt = conn.prepareStatement(select.toString());
int parameterIndex = 1;
for (Filter filter : filters) {
parameterIndex += filter.bindParam(stmt, parameterIndex);
}
ResultSet rs = stmt.executeQuery();
vuls = rs2Vulnerabilities(rs);
rs.close();
stmt.close();
} finally {
Vault.releaseDbConnection(conn);
}
return vuls;
}
/**
* Convenience method for translating a <code>java.sql.ResultSet</code>
* containing vulnerability information into an array of
* <code>Vulnerability</code> objects.
*
* @param rs a {@link java.sql.ResultSet} object.
* @return an array of {@link org.opennms.web.vulnerability.Vulnerability} objects.
* @throws java.sql.SQLException if any.
*/
// FIXME: Don't reuse the single "element" variable for multiple objects.
protected static Vulnerability[] rs2Vulnerabilities(ResultSet rs) throws SQLException {
Vulnerability[] vuls = null;
List<Vulnerability> list = new ArrayList<Vulnerability>();
while (rs.next()) {
Vulnerability vul = new Vulnerability();
Object element = new Integer(rs.getInt("vulnerabilityId"));
vul.id = ((Integer) element).intValue();
// can be null
element = rs.getObject("nodeID");
if (element != null) {
vul.nodeId = (Integer) element;
}
// can be null
element = rs.getString("ipAddr");
vul.ipAddr = (String) element;
// can be null
element = rs.getObject("serviceID");
if (element != null) {
vul.serviceId = (Integer) element;
}
// can be null
element = rs.getString("nodeLabel");
vul.nodeLabel = (String) element;
// can be null
element = rs.getString("serviceName");
vul.serviceName = (String) element;
element = rs.getTimestamp("creationTime");
vul.createTime = new Date(((Timestamp) element).getTime());
element = rs.getTimestamp("lastAttemptTime");
vul.lastAttemptTime = new Date(((Timestamp) element).getTime());
element = rs.getTimestamp("lastScanTime");
vul.lastScanTime = new Date(((Timestamp) element).getTime());
// can be null
element = rs.getTimestamp("resolvedTime");
if (element != null) {
vul.resolvedTime = new Date(((Timestamp) element).getTime());
}
// can be null
element = rs.getString("descr");
vul.description = (String) element;
// can be null
element = rs.getString("logmsg");
vul.logMessage = (String) element;
element = new Integer(rs.getInt("severity"));
vul.severity = OnmsSeverity.get((Integer)element);
element = new Integer(rs.getInt("pluginID"));
vul.pluginId = ((Integer) element).intValue();
element = new Integer(rs.getInt("pluginSubID"));
vul.pluginSubId = ((Integer) element).intValue();
// can be null
element = rs.getString("descr");
vul.description = (String) element;
// can be null
element = rs.getObject("port");
if (element != null) {
vul.port = (Integer) element;
}
// can be null
element = rs.getString("protocol");
vul.protocol = (String) element;
// can be null
element = rs.getString("cveEntry");
vul.cveEntry = (String) element;
list.add(vul);
}
vuls = list.toArray(new Vulnerability[list.size()]);
return vuls;
}
/**
* Convenience method for getting the SQL <em>ORDER BY</em> clause related
* to a given sort style.
*
* @param sortStyle a {@link org.opennms.web.vulnerability.VulnerabilityFactory.SortStyle} object.
* @return a {@link java.lang.String} object.
*/
protected static String getOrderByClause(SortStyle sortStyle) {
if (sortStyle == null) {
throw new IllegalArgumentException("Cannot take null parameters.");
}
String clause = null;
switch (sortStyle.getId()) {
case SortStyle._ID:
clause = " ORDER BY VULNERABILITYID DESC";
break;
case SortStyle._REVERSE_ID:
clause = " ORDER BY VULNERABILITYID ASC";
break;
case SortStyle._SEVERITY:
clause = " ORDER BY SEVERITY DESC";
break;
case SortStyle._REVERSE_SEVERITY:
clause = " ORDER BY SEVERITY ASC";
break;
case SortStyle._NODE:
clause = " ORDER BY NODELABEL ASC";
break;
case SortStyle._REVERSE_NODE:
clause = " ORDER BY NODELABEL DESC";
break;
case SortStyle._INTERFACE:
clause = " ORDER BY IPADDR ASC";
break;
case SortStyle._REVERSE_INTERFACE:
clause = " ORDER BY IPADDR DESC";
break;
case SortStyle._SERVICE:
clause = " ORDER BY SERVICENAME ASC";
break;
case SortStyle._REVERSE_SERVICE:
clause = " ORDER BY SERVICENAME DESC";
break;
case SortStyle._CREATE_TIME:
clause = " ORDER BY CREATIONTIME DESC";
break;
case SortStyle._REVERSE_CREATE_TIME:
clause = " ORDER BY CREATIONTIME ASC";
break;
case SortStyle._RESOLVED_TIME:
clause = " ORDER BY RESOLVEDTIME DESC";
break;
case SortStyle._REVERSE_RESOLVED_TIME:
clause = " ORDER BY RESOLVEDTIME ASC";
break;
case SortStyle._PORT:
clause = " ORDER BY PORT ASC";
break;
case SortStyle._REVERSE_PORT:
clause = " ORDER BY PORT DESC";
break;
case SortStyle._PROTOCOL:
clause = " ORDER BY PROTOCOL ASC";
break;
case SortStyle._REVERSE_PROTOCOL:
clause = " ORDER BY PROTOCOL DESC";
break;
default:
throw new IllegalArgumentException("Unknown VulnerabilityFactory.SortStyle: " + sortStyle.getName());
}
return clause;
}
/**
* Convenience method for getting the SQL WHERE clause related to a given
* resolution type.
*
* @param resType
* the resolution type to map to a clause
* @return a {@link java.lang.String} object.
*/
protected static String getResolutionTypeClause(ResolutionType resType) {
if (resType == null) {
throw new IllegalArgumentException("Cannot take null parameters.");
}
String clause = null;
switch (resType.getId()) {
case ResolutionType._RESOLVED:
clause = " RESOLVEDTIME IS NOT NULL";
break;
case ResolutionType._OPEN:
clause = " RESOLVEDTIME IS NULL";
break;
case ResolutionType._BOTH:
clause = " TRUE"; // gets both
break;
default:
throw new IllegalArgumentException("Unknown VulnerabilityFactory.ResolutionType: " + resType.getName());
}
return clause;
}
}