Coverage Report - org.owasp.dependencycheck.data.nvdcve.CveDB
 
Classes in this File Line Coverage Branch Coverage Complexity
CveDB
47%
124/260
64%
49/76
6.778
 
 1  
 /*
 2  
  * This file is part of dependency-check-core.
 3  
  *
 4  
  * Dependency-check-core is free software: you can redistribute it and/or modify it
 5  
  * under the terms of the GNU General Public License as published by the Free
 6  
  * Software Foundation, either version 3 of the License, or (at your option) any
 7  
  * later version.
 8  
  *
 9  
  * Dependency-check-core is distributed in the hope that it will be useful, but
 10  
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  
  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 12  
  * details.
 13  
  *
 14  
  * You should have received a copy of the GNU General Public License along with
 15  
  * dependency-check-core. If not, see http://www.gnu.org/licenses/.
 16  
  *
 17  
  * Copyright (c) 2012 Jeremy Long. All Rights Reserved.
 18  
  */
 19  
 package org.owasp.dependencycheck.data.nvdcve;
 20  
 
 21  
 import java.io.UnsupportedEncodingException;
 22  
 import java.sql.PreparedStatement;
 23  
 import java.sql.ResultSet;
 24  
 import java.sql.SQLException;
 25  
 import java.sql.Statement;
 26  
 import java.util.ArrayList;
 27  
 import java.util.HashSet;
 28  
 import java.util.List;
 29  
 import java.util.Set;
 30  
 import java.util.logging.Level;
 31  
 import java.util.logging.Logger;
 32  
 import org.owasp.dependencycheck.data.BaseDB;
 33  
 import org.owasp.dependencycheck.data.cwe.CweDB;
 34  
 import org.owasp.dependencycheck.dependency.Reference;
 35  
 import org.owasp.dependencycheck.dependency.Vulnerability;
 36  
 import org.owasp.dependencycheck.dependency.VulnerableSoftware;
 37  
 import org.owasp.dependencycheck.utils.DependencyVersion;
 38  
 import org.owasp.dependencycheck.utils.DependencyVersionUtil;
 39  
 
 40  
 /**
 41  
  * The database holding information about the NVD CVE data.
 42  
  *
 43  
  * @author Jeremy Long (jeremy.long@owasp.org)
 44  
  */
 45  21
 public class CveDB extends BaseDB {
 46  
 
 47  
     //<editor-fold defaultstate="collapsed" desc="Constants to create, maintain, and retrieve data from the CVE Database">
 48  
     /**
 49  
      * SQL Statement to delete references by vulnerability ID.
 50  
      */
 51  
     private static final String DELETE_REFERENCE = "DELETE FROM reference WHERE cveid = ?";
 52  
     /**
 53  
      * SQL Statement to delete software by vulnerability ID.
 54  
      */
 55  
     private static final String DELETE_SOFTWARE = "DELETE FROM software WHERE cveid = ?";
 56  
     /**
 57  
      * SQL Statement to delete a vulnerability by CVE.
 58  
      */
 59  
     private static final String DELETE_VULNERABILITY = "DELETE FROM vulnerability WHERE id = ?";
 60  
     /**
 61  
      * SQL Statement to cleanup orphan entries. Yes, the db schema could be a
 62  
      * little tighter, but what we have works well to keep the data file size
 63  
      * down a bit.
 64  
      */
 65  
     private static final String CLEANUP_ORPHANS = "DELETE FROM CpeEntry WHERE id not in (SELECT CPEEntryId FROM Software); ";
 66  
     /**
 67  
      * SQL Statement to insert a new reference.
 68  
      */
 69  
     private static final String INSERT_REFERENCE = "INSERT INTO reference (cveid, name, url, source) VALUES (?, ?, ?, ?)";
 70  
     /**
 71  
      * SQL Statement to insert a new software.
 72  
      */
 73  
     private static final String INSERT_SOFTWARE = "INSERT INTO software (cveid, cpeEntryId, previousVersion) VALUES (?, ?, ?)";
 74  
     /**
 75  
      * SQL Statement to insert a new cpe.
 76  
      */
 77  
     private static final String INSERT_CPE = "INSERT INTO cpeEntry (cpe, vendor, product) VALUES (?, ?, ?)";
 78  
     /**
 79  
      * SQL Statement to get a CPEProductID.
 80  
      */
 81  
     private static final String SELECT_CPE_ID = "SELECT id FROM cpeEntry WHERE cpe = ?";
 82  
     /**
 83  
      * SQL Statement to insert a new vulnerability.
 84  
      */
 85  
     private static final String INSERT_VULNERABILITY = "INSERT INTO vulnerability (cve, description, cwe, cvssScore, cvssAccessVector, "
 86  
             + "cvssAccessComplexity, cvssAuthentication, cvssConfidentialityImpact, cvssIntegrityImpact, cvssAvailabilityImpact) "
 87  
             + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
 88  
     /**
 89  
      * SQL Statement to update a vulnerability.
 90  
      */
 91  
     private static final String UPDATE_VULNERABILITY = "UPDATE vulnerability SET description=?, cwe=?, cvssScore=?, cvssAccessVector=?, "
 92  
             + "cvssAccessComplexity=?, cvssAuthentication=?, cvssConfidentialityImpact=?, cvssIntegrityImpact=?, cvssAvailabilityImpact=? "
 93  
             + "WHERE id=?";
 94  
     /**
 95  
      * SQL Statement to find CVE entries based on CPE data.
 96  
      */
 97  
     private static final String SELECT_CVE_FROM_SOFTWARE = "SELECT cve, cpe, previousVersion "
 98  
             + "FROM software INNER JOIN vulnerability ON vulnerability.id = software.cveId "
 99  
             + "INNER JOIN cpeEntry ON cpeEntry.id = software.cpeEntryId "
 100  
             + "WHERE vendor = ? AND product = ?";
 101  
     //unfortunately, the version info is too complicated to do in a select. Need to filter this afterwards
 102  
     //        + " AND (version = '-' OR previousVersion IS NOT NULL OR version=?)";
 103  
     //
 104  
     /**
 105  
      * SQL Statement to find the CPE entry based on the vendor and product.
 106  
      */
 107  
     private static final String SELECT_CPE_ENTRIES = "SELECT cpe FROM cpeEntry WHERE vendor = ? AND product = ?";
 108  
     /**
 109  
      * SQL Statement to select references by CVEID.
 110  
      */
 111  
     private static final String SELECT_REFERENCE = "SELECT source, name, url FROM reference WHERE cveid = ?";
 112  
     /**
 113  
      * SQL Statement to select vendor and product for lucene index.
 114  
      */
 115  
     private static final String SELECT_VENDOR_PRODUCT_LIST = "SELECT vendor, product FROM cpeEntry GROUP BY vendor, product";
 116  
     /**
 117  
      * SQL Statement to select software by CVEID.
 118  
      */
 119  
     private static final String SELECT_SOFTWARE = "SELECT cpe, previousVersion "
 120  
             + "FROM software INNER JOIN cpeEntry ON software.cpeEntryId = cpeEntry.id WHERE cveid = ?";
 121  
 //    public static final String SELECT_SOFTWARE = "SELECT part, vendor, product, version, revision, previousVersion "
 122  
 //            + "FROM software INNER JOIN cpeProduct ON cpeProduct.id = software.cpeProductId LEFT JOIN cpeVersion ON "
 123  
 //            + "software.cpeVersionId = cpeVersion.id LEFT JOIN Version ON cpeVersion.versionId = version.id WHERE cveid = ?";
 124  
     /**
 125  
      * SQL Statement to select a vulnerability by CVEID.
 126  
      */
 127  
     private static final String SELECT_VULNERABILITY = "SELECT id, description, cwe, cvssScore, cvssAccessVector, cvssAccessComplexity, "
 128  
             + "cvssAuthentication, cvssConfidentialityImpact, cvssIntegrityImpact, cvssAvailabilityImpact FROM vulnerability WHERE cve = ?";
 129  
     /**
 130  
      * SQL Statement to select a vulnerability's primary key.
 131  
      */
 132  
     private static final String SELECT_VULNERABILITY_ID = "SELECT id FROM vulnerability WHERE cve = ?";
 133  
     //</editor-fold>
 134  
 
 135  
     /**
 136  
      * Searches the CPE entries in the database and retrieves all entries for a
 137  
      * given vendor and product combination. The returned list will include all
 138  
      * versions of the product that are registered in the NVD CVE data.
 139  
      *
 140  
      * @param vendor the identified vendor name of the dependency being analyzed
 141  
      * @param product the identified name of the product of the dependency being
 142  
      * analyzed
 143  
      * @return a set of vulnerable software
 144  
      */
 145  
     public Set<VulnerableSoftware> getCPEs(String vendor, String product) {
 146  72
         final Set<VulnerableSoftware> cpe = new HashSet<VulnerableSoftware>();
 147  72
         ResultSet rs = null;
 148  72
         PreparedStatement ps = null;
 149  
         try {
 150  72
             ps = getConnection().prepareStatement(SELECT_CPE_ENTRIES);
 151  72
             ps.setString(1, vendor);
 152  72
             ps.setString(2, product);
 153  72
             rs = ps.executeQuery();
 154  
 
 155  4462
             while (rs.next()) {
 156  4390
                 final VulnerableSoftware vs = new VulnerableSoftware();
 157  4390
                 vs.setCpe(rs.getString(1));
 158  4390
                 cpe.add(vs);
 159  4390
             }
 160  0
         } catch (SQLException ex) {
 161  0
             Logger.getLogger(CveDB.class.getName()).log(Level.SEVERE, null, ex);
 162  
         } finally {
 163  72
             closeResultSet(rs);
 164  72
             closeStatement(ps);
 165  72
         }
 166  72
         return cpe;
 167  
     }
 168  
 
 169  
     /**
 170  
      * Returns the entire list of vendor/product combinations.
 171  
      *
 172  
      * @return the entire list of vendor/product combinations.
 173  
      */
 174  
     public ResultSet getVendorProductList() {
 175  11
         ResultSet rs = null;
 176  
         try {
 177  11
             final PreparedStatement ps = getConnection().prepareStatement(SELECT_VENDOR_PRODUCT_LIST);
 178  11
             rs = ps.executeQuery();
 179  0
         } catch (SQLException ex) {
 180  0
             Logger.getLogger(CveDB.class.getName()).log(Level.SEVERE, null, ex);
 181  11
         } // can't close the statement in the PS as the resultset is returned, closing PS would close the resultset
 182  11
         return rs;
 183  
     }
 184  
 
 185  
     /**
 186  
      * Retrieves the vulnerabilities associated with the specified CPE.
 187  
      *
 188  
      * @param cpeStr the CPE name
 189  
      * @return a list of Vulnerabilities
 190  
      * @throws DatabaseException thrown if there is an exception retrieving data
 191  
      */
 192  
     public List<Vulnerability> getVulnerabilities(String cpeStr) throws DatabaseException {
 193  12
         ResultSet rs = null;
 194  12
         final VulnerableSoftware cpe = new VulnerableSoftware();
 195  
         try {
 196  12
             cpe.parseName(cpeStr);
 197  0
         } catch (UnsupportedEncodingException ex) {
 198  0
             Logger.getLogger(CveDB.class.getName()).log(Level.FINEST, null, ex);
 199  12
         }
 200  12
         final DependencyVersion detectedVersion = parseDependencyVersion(cpe);
 201  12
         final List<Vulnerability> vulnerabilities = new ArrayList<Vulnerability>();
 202  
 
 203  
         PreparedStatement ps;
 204  12
         final HashSet<String> cveEntries = new HashSet<String>();
 205  
         try {
 206  12
             ps = getConnection().prepareStatement(SELECT_CVE_FROM_SOFTWARE);
 207  12
             ps.setString(1, cpe.getVendor());
 208  12
             ps.setString(2, cpe.getProduct());
 209  12
             rs = ps.executeQuery();
 210  4591
             while (rs.next()) {
 211  4579
                 final String cveId = rs.getString(1);
 212  4579
                 final String cpeId = rs.getString(2);
 213  4579
                 final String previous = rs.getString(3);
 214  4579
                 if (!cveEntries.contains(cveId) && isAffected(cpe.getVendor(), cpe.getProduct(), detectedVersion, cpeId, previous)) {
 215  61
                     cveEntries.add(cveId);
 216  
                 }
 217  4579
             }
 218  12
             closeResultSet(rs);
 219  12
             closeStatement(ps);
 220  12
             for (String cve : cveEntries) {
 221  61
                 final Vulnerability v = getVulnerability(cve);
 222  61
                 vulnerabilities.add(v);
 223  61
             }
 224  
 
 225  0
         } catch (SQLException ex) {
 226  0
             throw new DatabaseException("Exception retrieving vulnerability for " + cpeStr, ex);
 227  
         } finally {
 228  12
             closeResultSet(rs);
 229  12
         }
 230  12
         return vulnerabilities;
 231  
     }
 232  
 
 233  
     /**
 234  
      * Gets a vulnerability for the provided CVE.
 235  
      *
 236  
      * @param cve the CVE to lookup
 237  
      * @return a vulnerability object
 238  
      * @throws DatabaseException if an exception occurs
 239  
      */
 240  
     private Vulnerability getVulnerability(String cve) throws DatabaseException {
 241  61
         PreparedStatement psV = null;
 242  61
         PreparedStatement psR = null;
 243  61
         PreparedStatement psS = null;
 244  61
         ResultSet rsV = null;
 245  61
         ResultSet rsR = null;
 246  61
         ResultSet rsS = null;
 247  61
         Vulnerability vuln = null;
 248  
         try {
 249  61
             psV = getConnection().prepareStatement(SELECT_VULNERABILITY);
 250  61
             psV.setString(1, cve);
 251  61
             rsV = psV.executeQuery();
 252  61
             if (rsV.next()) {
 253  61
                 vuln = new Vulnerability();
 254  61
                 vuln.setName(cve);
 255  61
                 vuln.setDescription(rsV.getString(2));
 256  61
                 String cwe = rsV.getString(3);
 257  61
                 if (cwe != null) {
 258  50
                     final String name = CweDB.getCweName(cwe);
 259  50
                     if (name != null) {
 260  48
                         cwe += " " + name;
 261  
                     }
 262  
                 }
 263  61
                 final int cveId = rsV.getInt(1);
 264  61
                 vuln.setCwe(cwe);
 265  61
                 vuln.setCvssScore(rsV.getFloat(4));
 266  61
                 vuln.setCvssAccessVector(rsV.getString(5));
 267  61
                 vuln.setCvssAccessComplexity(rsV.getString(6));
 268  61
                 vuln.setCvssAuthentication(rsV.getString(7));
 269  61
                 vuln.setCvssConfidentialityImpact(rsV.getString(8));
 270  61
                 vuln.setCvssIntegrityImpact(rsV.getString(9));
 271  61
                 vuln.setCvssAvailabilityImpact(rsV.getString(10));
 272  
 
 273  61
                 psR = getConnection().prepareStatement(SELECT_REFERENCE);
 274  61
                 psR.setInt(1, cveId);
 275  61
                 rsR = psR.executeQuery();
 276  477
                 while (rsR.next()) {
 277  416
                     vuln.addReference(rsR.getString(1), rsR.getString(2), rsR.getString(3));
 278  
                 }
 279  61
                 psS = getConnection().prepareStatement(SELECT_SOFTWARE);
 280  61
                 psS.setInt(1, cveId);
 281  61
                 rsS = psS.executeQuery();
 282  2765
                 while (rsS.next()) {
 283  2704
                     final String cpe = rsS.getString(1);
 284  2704
                     final String prevVersion = rsS.getString(2);
 285  2704
                     if (prevVersion == null) {
 286  2662
                         vuln.addVulnerableSoftware(cpe);
 287  
                     } else {
 288  42
                         vuln.addVulnerableSoftware(cpe, prevVersion);
 289  
                     }
 290  2704
                 }
 291  
             }
 292  0
         } catch (SQLException ex) {
 293  0
             throw new DatabaseException("Error retrieving " + cve, ex);
 294  
         } finally {
 295  61
             closeResultSet(rsV);
 296  61
             closeResultSet(rsR);
 297  61
             closeResultSet(rsS);
 298  61
             closeStatement(psV);
 299  61
             closeStatement(psR);
 300  61
             closeStatement(psS);
 301  61
         }
 302  61
         return vuln;
 303  
     }
 304  
 
 305  
     /**
 306  
      * Updates the vulnerability within the database. If the vulnerability does
 307  
      * not exist it will be added.
 308  
      *
 309  
      * @param vuln the vulnerability to add to the database
 310  
      * @throws DatabaseException is thrown if the database
 311  
      */
 312  
     public void updateVulnerability(Vulnerability vuln) throws DatabaseException {
 313  0
         PreparedStatement selectVulnerabilityId = null;
 314  0
         PreparedStatement deleteVulnerability = null;
 315  0
         PreparedStatement deleteReferences = null;
 316  0
         PreparedStatement deleteSoftware = null;
 317  0
         PreparedStatement updateVulnerability = null;
 318  0
         PreparedStatement insertVulnerability = null;
 319  0
         PreparedStatement insertReference = null;
 320  0
         PreparedStatement selectCpeId = null;
 321  0
         PreparedStatement insertCpe = null;
 322  0
         PreparedStatement insertSoftware = null;
 323  
 
 324  
         try {
 325  0
             selectVulnerabilityId = getConnection().prepareStatement(SELECT_VULNERABILITY_ID);
 326  0
             deleteVulnerability = getConnection().prepareStatement(DELETE_VULNERABILITY);
 327  0
             deleteReferences = getConnection().prepareStatement(DELETE_REFERENCE);
 328  0
             deleteSoftware = getConnection().prepareStatement(DELETE_SOFTWARE);
 329  0
             updateVulnerability = getConnection().prepareStatement(UPDATE_VULNERABILITY);
 330  0
             insertVulnerability = getConnection().prepareStatement(INSERT_VULNERABILITY, Statement.RETURN_GENERATED_KEYS);
 331  0
             insertReference = getConnection().prepareStatement(INSERT_REFERENCE);
 332  0
             selectCpeId = getConnection().prepareStatement(SELECT_CPE_ID);
 333  0
             insertCpe = getConnection().prepareStatement(INSERT_CPE, Statement.RETURN_GENERATED_KEYS);
 334  0
             insertSoftware = getConnection().prepareStatement(INSERT_SOFTWARE);
 335  0
             int vulnerabilityId = 0;
 336  0
             selectVulnerabilityId.setString(1, vuln.getName());
 337  0
             ResultSet rs = selectVulnerabilityId.executeQuery();
 338  0
             if (rs.next()) {
 339  0
                 vulnerabilityId = rs.getInt(1);
 340  
                 // first delete any existing vulnerability info. We don't know what was updated. yes, slower but atm easier.
 341  0
                 deleteReferences.setInt(1, vulnerabilityId);
 342  0
                 deleteReferences.execute();
 343  0
                 deleteSoftware.setInt(1, vulnerabilityId);
 344  0
                 deleteSoftware.execute();
 345  
             }
 346  0
             closeResultSet(rs);
 347  0
             rs = null;
 348  0
             if (vulnerabilityId != 0) {
 349  0
                 if (vuln.getDescription().contains("** REJECT **")) {
 350  0
                     deleteVulnerability.setInt(1, vulnerabilityId);
 351  0
                     deleteVulnerability.executeUpdate();
 352  
                 } else {
 353  0
                     updateVulnerability.setString(1, vuln.getDescription());
 354  0
                     updateVulnerability.setString(2, vuln.getCwe());
 355  0
                     updateVulnerability.setFloat(3, vuln.getCvssScore());
 356  0
                     updateVulnerability.setString(4, vuln.getCvssAccessVector());
 357  0
                     updateVulnerability.setString(5, vuln.getCvssAccessComplexity());
 358  0
                     updateVulnerability.setString(6, vuln.getCvssAuthentication());
 359  0
                     updateVulnerability.setString(7, vuln.getCvssConfidentialityImpact());
 360  0
                     updateVulnerability.setString(8, vuln.getCvssIntegrityImpact());
 361  0
                     updateVulnerability.setString(9, vuln.getCvssAvailabilityImpact());
 362  0
                     updateVulnerability.setInt(10, vulnerabilityId);
 363  0
                     updateVulnerability.executeUpdate();
 364  
                 }
 365  
             } else {
 366  0
                 insertVulnerability.setString(1, vuln.getName());
 367  0
                 insertVulnerability.setString(2, vuln.getDescription());
 368  0
                 insertVulnerability.setString(3, vuln.getCwe());
 369  0
                 insertVulnerability.setFloat(4, vuln.getCvssScore());
 370  0
                 insertVulnerability.setString(5, vuln.getCvssAccessVector());
 371  0
                 insertVulnerability.setString(6, vuln.getCvssAccessComplexity());
 372  0
                 insertVulnerability.setString(7, vuln.getCvssAuthentication());
 373  0
                 insertVulnerability.setString(8, vuln.getCvssConfidentialityImpact());
 374  0
                 insertVulnerability.setString(9, vuln.getCvssIntegrityImpact());
 375  0
                 insertVulnerability.setString(10, vuln.getCvssAvailabilityImpact());
 376  0
                 insertVulnerability.execute();
 377  
                 try {
 378  0
                     rs = insertVulnerability.getGeneratedKeys();
 379  0
                     rs.next();
 380  0
                     vulnerabilityId = rs.getInt(1);
 381  0
                 } catch (SQLException ex) {
 382  0
                     final String msg = String.format("Unable to retrieve id for new vulnerability for '%s'", vuln.getName());
 383  0
                     throw new DatabaseException(msg, ex);
 384  
                 } finally {
 385  0
                     closeResultSet(rs);
 386  0
                     rs = null;
 387  0
                 }
 388  
             }
 389  0
             insertReference.setInt(1, vulnerabilityId);
 390  0
             for (Reference r : vuln.getReferences()) {
 391  0
                 insertReference.setString(2, r.getName());
 392  0
                 insertReference.setString(3, r.getUrl());
 393  0
                 insertReference.setString(4, r.getSource());
 394  0
                 insertReference.execute();
 395  
             }
 396  0
             for (VulnerableSoftware s : vuln.getVulnerableSoftware()) {
 397  0
                 int cpeProductId = 0;
 398  0
                 selectCpeId.setString(1, s.getName());
 399  
                 try {
 400  0
                     rs = selectCpeId.executeQuery();
 401  0
                     if (rs.next()) {
 402  0
                         cpeProductId = rs.getInt(1);
 403  
                     }
 404  0
                 } catch (SQLException ex) {
 405  0
                     throw new DatabaseException("Unable to get primary key for new cpe: " + s.getName(), ex);
 406  
                 } finally {
 407  0
                     closeResultSet(rs);
 408  0
                     rs = null;
 409  0
                 }
 410  
 
 411  0
                 if (cpeProductId == 0) {
 412  0
                     insertCpe.setString(1, s.getName());
 413  0
                     insertCpe.setString(2, s.getVendor());
 414  0
                     insertCpe.setString(3, s.getProduct());
 415  0
                     insertCpe.executeUpdate();
 416  0
                     cpeProductId = getGeneratedKey(insertCpe);
 417  
                 }
 418  0
                 if (cpeProductId == 0) {
 419  0
                     throw new DatabaseException("Unable to retrieve cpeProductId - no data returned");
 420  
                 }
 421  
 
 422  0
                 insertSoftware.setInt(1, vulnerabilityId);
 423  0
                 insertSoftware.setInt(2, cpeProductId);
 424  0
                 if (s.getPreviousVersion() == null) {
 425  0
                     insertSoftware.setNull(3, java.sql.Types.VARCHAR);
 426  
                 } else {
 427  0
                     insertSoftware.setString(3, s.getPreviousVersion());
 428  
                 }
 429  0
                 insertSoftware.execute();
 430  0
             }
 431  
 
 432  0
         } catch (SQLException ex) {
 433  0
             final String msg = String.format("Error updating '%s'", vuln.getName());
 434  0
             Logger.getLogger(CveDB.class.getName()).log(Level.FINE, null, ex);
 435  0
             throw new DatabaseException(msg, ex);
 436  
         } finally {
 437  0
             closeStatement(selectVulnerabilityId);
 438  0
             closeStatement(deleteReferences);
 439  0
             closeStatement(deleteSoftware);
 440  0
             closeStatement(updateVulnerability);
 441  0
             closeStatement(deleteVulnerability);
 442  0
             closeStatement(insertVulnerability);
 443  0
             closeStatement(insertReference);
 444  0
             closeStatement(selectCpeId);
 445  0
             closeStatement(insertCpe);
 446  0
             closeStatement(insertSoftware);
 447  0
         }
 448  0
     }
 449  
 
 450  
     /**
 451  
      * It is possible that orphaned rows may be generated during database
 452  
      * updates. This should be called after all updates have been completed to
 453  
      * ensure orphan entries are removed.
 454  
      */
 455  
     public void cleanupDatabase() {
 456  0
         PreparedStatement ps = null;
 457  
         try {
 458  0
             ps = getConnection().prepareStatement(CLEANUP_ORPHANS);
 459  0
             if (ps != null) {
 460  0
                 ps.executeUpdate();
 461  
             }
 462  0
         } catch (SQLException ex) {
 463  0
             Logger.getLogger(CveDB.class.getName()).log(Level.SEVERE, null, ex);
 464  
         } finally {
 465  0
             closeStatement(ps);
 466  0
         }
 467  0
     }
 468  
 
 469  
     /**
 470  
      * Determines if the given identifiedVersion is affected by the given cpeId
 471  
      * and previous version flag. A non-null, non-empty string passed to the
 472  
      * previous version argument indicates that all previous versions are
 473  
      * affected.
 474  
      *
 475  
      * @param vendor the vendor of the dependency being analyzed
 476  
      * @param product the product name of the dependency being analyzed
 477  
      * @param identifiedVersion the identified version of the dependency being
 478  
      * analyzed
 479  
      * @param cpeId the cpe identifier of software that has a known
 480  
      * vulnerability
 481  
      * @param previous a flag indicating if previous versions of the product are
 482  
      * vulnerable
 483  
      * @return true if the identified version is affected, otherwise false
 484  
      */
 485  
     private boolean isAffected(String vendor, String product, DependencyVersion identifiedVersion, String cpeId, String previous) {
 486  3528
         boolean affected = false;
 487  3528
         final boolean isStruts = "apache".equals(vendor) && "struts".equals(product);
 488  3528
         final DependencyVersion v = parseDependencyVersion(cpeId);
 489  3528
         final boolean prevAffected = previous == null ? false : !previous.isEmpty();
 490  3528
         if (identifiedVersion == null || "-".equals(identifiedVersion.toString())) {
 491  96
             if (v == null || "-".equals(v.toString())) {
 492  0
                 affected = true;
 493  
             }
 494  3432
         } else if (identifiedVersion.equals(v) || (prevAffected && identifiedVersion.compareTo(v) < 0)) {
 495  83
             if (isStruts) { //struts 2 vulns don't affect struts 1
 496  72
                 if (identifiedVersion.getVersionParts().get(0).equals(v.getVersionParts().get(0))) {
 497  50
                     affected = true;
 498  
                 }
 499  
             } else {
 500  11
                 affected = true;
 501  
             }
 502  
         }
 503  
         /*
 504  
          * TODO consider utilizing the matchThreeVersion method to get additional results. However, this
 505  
          *      might also introduce false positives.
 506  
          */
 507  3528
         return affected;
 508  
     }
 509  
 
 510  
     /**
 511  
      * Parses the version (including revision) from a CPE identifier. If no
 512  
      * version is identified then a '-' is returned.
 513  
      *
 514  
      * @param cpeStr a cpe identifier
 515  
      * @return a dependency version
 516  
      */
 517  
     private DependencyVersion parseDependencyVersion(String cpeStr) {
 518  3528
         final VulnerableSoftware cpe = new VulnerableSoftware();
 519  
         try {
 520  3528
             cpe.parseName(cpeStr);
 521  0
         } catch (UnsupportedEncodingException ex) {
 522  
             //never going to happen.
 523  0
             Logger.getLogger(CveDB.class.getName()).log(Level.FINEST, null, ex);
 524  3528
         }
 525  3528
         return parseDependencyVersion(cpe);
 526  
     }
 527  
 
 528  
     /**
 529  
      * Takes a CPE and parses out the version number. If no version is
 530  
      * identified then a '-' is returned.
 531  
      *
 532  
      * @param cpe a cpe object
 533  
      * @return a dependency version
 534  
      */
 535  
     private DependencyVersion parseDependencyVersion(VulnerableSoftware cpe) {
 536  
         DependencyVersion cpeVersion;
 537  3540
         if (cpe.getVersion() != null && cpe.getVersion().length() > 0) {
 538  
             String versionText;
 539  3536
             if (cpe.getRevision() != null && cpe.getRevision().length() > 0) {
 540  441
                 versionText = String.format("%s.%s", cpe.getVersion(), cpe.getRevision());
 541  
             } else {
 542  3095
                 versionText = cpe.getVersion();
 543  
             }
 544  3536
             cpeVersion = DependencyVersionUtil.parseVersion(versionText);
 545  3536
         } else {
 546  4
             cpeVersion = new DependencyVersion("-");
 547  
         }
 548  3540
         return cpeVersion;
 549  
     }
 550  
 }