1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.owasp.dependencycheck;
19
20 import org.owasp.dependencycheck.analyzer.AnalysisPhase;
21 import org.owasp.dependencycheck.analyzer.Analyzer;
22 import org.owasp.dependencycheck.analyzer.AnalyzerService;
23 import org.owasp.dependencycheck.analyzer.FileTypeAnalyzer;
24 import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
25 import org.owasp.dependencycheck.data.nvdcve.ConnectionFactory;
26 import org.owasp.dependencycheck.data.nvdcve.CveDB;
27 import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
28 import org.owasp.dependencycheck.data.update.CachedWebDataSource;
29 import org.owasp.dependencycheck.data.update.UpdateService;
30 import org.owasp.dependencycheck.data.update.exception.UpdateException;
31 import org.owasp.dependencycheck.dependency.Dependency;
32 import org.owasp.dependencycheck.exception.NoDataException;
33 import org.owasp.dependencycheck.utils.InvalidSettingException;
34 import org.owasp.dependencycheck.utils.Settings;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 import java.io.File;
39 import java.io.FileFilter;
40 import java.util.ArrayList;
41 import java.util.Collection;
42 import java.util.EnumMap;
43 import java.util.HashSet;
44 import java.util.Iterator;
45 import java.util.List;
46 import java.util.Map;
47 import java.util.Set;
48
49
50
51
52
53
54
55 public class Engine implements FileFilter {
56
57
58
59
60 private List<Dependency> dependencies = new ArrayList<Dependency>();
61
62
63
64 private Map<AnalysisPhase, List<Analyzer>> analyzers = new EnumMap<AnalysisPhase, List<Analyzer>>(AnalysisPhase.class);
65
66
67
68
69 private Set<FileTypeAnalyzer> fileTypeAnalyzers = new HashSet<FileTypeAnalyzer>();
70
71
72
73
74 private ClassLoader serviceClassLoader = Thread.currentThread().getContextClassLoader();
75
76
77
78 private static final Logger LOGGER = LoggerFactory.getLogger(Engine.class);
79
80
81
82
83
84
85 public Engine() throws DatabaseException {
86 initializeEngine();
87 }
88
89
90
91
92
93
94
95 public Engine(ClassLoader serviceClassLoader) throws DatabaseException {
96 this.serviceClassLoader = serviceClassLoader;
97 initializeEngine();
98 }
99
100
101
102
103
104
105 protected final void initializeEngine() throws DatabaseException {
106 ConnectionFactory.initialize();
107 loadAnalyzers();
108 }
109
110
111
112
113 public void cleanup() {
114 ConnectionFactory.cleanup();
115 }
116
117
118
119
120 private void loadAnalyzers() {
121 if (!analyzers.isEmpty()) {
122 return;
123 }
124 for (AnalysisPhase phase : AnalysisPhase.values()) {
125 analyzers.put(phase, new ArrayList<Analyzer>());
126 }
127
128 final AnalyzerService service = new AnalyzerService(serviceClassLoader);
129 final List<Analyzer> iterator = service.getAnalyzers();
130 for (Analyzer a : iterator) {
131 analyzers.get(a.getAnalysisPhase()).add(a);
132 if (a instanceof FileTypeAnalyzer) {
133 this.fileTypeAnalyzers.add((FileTypeAnalyzer) a);
134 }
135 }
136 }
137
138
139
140
141
142
143
144 public List<Analyzer> getAnalyzers(AnalysisPhase phase) {
145 return analyzers.get(phase);
146 }
147
148
149
150
151
152
153 public List<Dependency> getDependencies() {
154 return dependencies;
155 }
156
157
158
159
160
161
162 public void setDependencies(List<Dependency> dependencies) {
163 this.dependencies = dependencies;
164 }
165
166
167
168
169
170
171
172
173
174 public List<Dependency> scan(String[] paths) {
175 final List<Dependency> deps = new ArrayList<Dependency>();
176 for (String path : paths) {
177 final List<Dependency> d = scan(path);
178 if (d != null) {
179 deps.addAll(d);
180 }
181 }
182 return deps;
183 }
184
185
186
187
188
189
190
191
192 public List<Dependency> scan(String path) {
193 final File file = new File(path);
194 return scan(file);
195 }
196
197
198
199
200
201
202
203
204
205 public List<Dependency> scan(File[] files) {
206 final List<Dependency> deps = new ArrayList<Dependency>();
207 for (File file : files) {
208 final List<Dependency> d = scan(file);
209 if (d != null) {
210 deps.addAll(d);
211 }
212 }
213 return deps;
214 }
215
216
217
218
219
220
221
222
223
224 public List<Dependency> scan(Collection<File> files) {
225 final List<Dependency> deps = new ArrayList<Dependency>();
226 for (File file : files) {
227 final List<Dependency> d = scan(file);
228 if (d != null) {
229 deps.addAll(d);
230 }
231 }
232 return deps;
233 }
234
235
236
237
238
239
240
241
242
243 public List<Dependency> scan(File file) {
244 if (file.exists()) {
245 if (file.isDirectory()) {
246 return scanDirectory(file);
247 } else {
248 final Dependency d = scanFile(file);
249 if (d != null) {
250 final List<Dependency> deps = new ArrayList<Dependency>();
251 deps.add(d);
252 return deps;
253 }
254 }
255 }
256 return null;
257 }
258
259
260
261
262
263
264
265 protected List<Dependency> scanDirectory(File dir) {
266 final File[] files = dir.listFiles();
267 final List<Dependency> deps = new ArrayList<Dependency>();
268 if (files != null) {
269 for (File f : files) {
270 if (f.isDirectory()) {
271 final List<Dependency> d = scanDirectory(f);
272 if (d != null) {
273 deps.addAll(d);
274 }
275 } else {
276 final Dependency d = scanFile(f);
277 deps.add(d);
278 }
279 }
280 }
281 return deps;
282 }
283
284
285
286
287
288
289
290 protected Dependency scanFile(File file) {
291 Dependency dependency = null;
292 if (file.isFile()) {
293 if (accept(file)) {
294 dependency = new Dependency(file);
295 dependencies.add(dependency);
296 }
297 } else {
298 LOGGER.debug("Path passed to scanFile(File) is not a file: {}. Skipping the file.", file);
299 }
300 return dependency;
301 }
302
303
304
305
306
307
308
309 public void analyzeDependencies() {
310 boolean autoUpdate = true;
311 try {
312 autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
313 } catch (InvalidSettingException ex) {
314 LOGGER.debug("Invalid setting for auto-update; using true.");
315 }
316 if (autoUpdate) {
317 doUpdates();
318 }
319
320
321 try {
322 ensureDataExists();
323 } catch (NoDataException ex) {
324 LOGGER.error("{}\n\nUnable to continue dependency-check analysis.", ex.getMessage());
325 LOGGER.debug("", ex);
326 return;
327 } catch (DatabaseException ex) {
328 LOGGER.error("{}\n\nUnable to continue dependency-check analysis.", ex.getMessage());
329 LOGGER.debug("", ex);
330 return;
331
332 }
333
334 LOGGER.debug("\n----------------------------------------------------\nBEGIN ANALYSIS\n----------------------------------------------------");
335 LOGGER.info("Analysis Starting");
336 final long analysisStart = System.currentTimeMillis();
337
338
339 for (AnalysisPhase phase : AnalysisPhase.values()) {
340 final List<Analyzer> analyzerList = analyzers.get(phase);
341
342 for (Analyzer a : analyzerList) {
343 a = initializeAnalyzer(a);
344
345
346
347
348
349 LOGGER.debug("Begin Analyzer '{}'", a.getName());
350 final Set<Dependency> dependencySet = new HashSet<Dependency>(dependencies);
351 for (Dependency d : dependencySet) {
352 boolean shouldAnalyze = true;
353 if (a instanceof FileTypeAnalyzer) {
354 final FileTypeAnalyzer fAnalyzer = (FileTypeAnalyzer) a;
355 shouldAnalyze = fAnalyzer.accept(d.getActualFile());
356 }
357 if (shouldAnalyze) {
358 LOGGER.debug("Begin Analysis of '{}'", d.getActualFilePath());
359 try {
360 a.analyze(d, this);
361 } catch (AnalysisException ex) {
362 LOGGER.warn("An error occurred while analyzing '{}'.", d.getActualFilePath());
363 LOGGER.debug("", ex);
364 } catch (Throwable ex) {
365
366 LOGGER.warn("An unexpected error occurred during analysis of '{}'", d.getActualFilePath());
367 LOGGER.debug("", ex);
368 }
369 }
370 }
371 }
372 }
373 for (AnalysisPhase phase : AnalysisPhase.values()) {
374 final List<Analyzer> analyzerList = analyzers.get(phase);
375
376 for (Analyzer a : analyzerList) {
377 closeAnalyzer(a);
378 }
379 }
380
381 LOGGER.debug("\n----------------------------------------------------\nEND ANALYSIS\n----------------------------------------------------");
382 LOGGER.info("Analysis Complete ({} ms)", System.currentTimeMillis() - analysisStart);
383 }
384
385
386
387
388
389
390
391 protected Analyzer initializeAnalyzer(Analyzer analyzer) {
392 try {
393 LOGGER.debug("Initializing {}", analyzer.getName());
394 analyzer.initialize();
395 } catch (Throwable ex) {
396 LOGGER.error("Exception occurred initializing {}.", analyzer.getName());
397 LOGGER.debug("", ex);
398 try {
399 analyzer.close();
400 } catch (Throwable ex1) {
401 LOGGER.trace("", ex1);
402 }
403 }
404 return analyzer;
405 }
406
407
408
409
410
411
412 protected void closeAnalyzer(Analyzer analyzer) {
413 LOGGER.debug("Closing Analyzer '{}'", analyzer.getName());
414 try {
415 analyzer.close();
416 } catch (Throwable ex) {
417 LOGGER.trace("", ex);
418 }
419 }
420
421
422
423
424 public void doUpdates() {
425 LOGGER.info("Checking for updates");
426 final long updateStart = System.currentTimeMillis();
427 final UpdateService service = new UpdateService(serviceClassLoader);
428 final Iterator<CachedWebDataSource> iterator = service.getDataSources();
429 while (iterator.hasNext()) {
430 final CachedWebDataSource source = iterator.next();
431 try {
432 source.update();
433 } catch (UpdateException ex) {
434 LOGGER.warn(
435 "Unable to update Cached Web DataSource, using local data instead. Results may not include recent vulnerabilities.");
436 LOGGER.debug("Unable to update details for {}", source.getClass().getName(), ex);
437 }
438 }
439 LOGGER.info("Check for updates complete ({} ms)", System.currentTimeMillis() - updateStart);
440 }
441
442
443
444
445
446
447 public List<Analyzer> getAnalyzers() {
448 final List<Analyzer> ret = new ArrayList<Analyzer>();
449 for (AnalysisPhase phase : AnalysisPhase.values()) {
450 final List<Analyzer> analyzerList = analyzers.get(phase);
451 ret.addAll(analyzerList);
452 }
453 return ret;
454 }
455
456
457
458
459
460
461
462 @Override
463 public boolean accept(File file) {
464 if (file == null) {
465 return false;
466 }
467 boolean scan = false;
468 for (FileTypeAnalyzer a : this.fileTypeAnalyzers) {
469
470
471 scan |= a.accept(file);
472 }
473 return scan;
474 }
475
476
477
478
479
480
481 public Set<FileTypeAnalyzer> getFileTypeAnalyzers() {
482 return this.fileTypeAnalyzers;
483 }
484
485
486
487
488
489
490
491 private void ensureDataExists() throws NoDataException, DatabaseException {
492 final CveDB cve = new CveDB();
493 try {
494 cve.open();
495 if (!cve.dataExists()) {
496 throw new NoDataException("No documents exist");
497 }
498 } catch (DatabaseException ex) {
499 throw new NoDataException(ex.getMessage(), ex);
500 } finally {
501 cve.close();
502 }
503 }
504 }