/******************************************************************************* * 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; } }