1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.owasp.dependencycheck.analyzer;
19
20 import org.apache.commons.io.FileUtils;
21 import org.apache.commons.lang3.StringUtils;
22 import org.owasp.dependencycheck.Engine;
23 import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
24 import org.owasp.dependencycheck.dependency.Confidence;
25 import org.owasp.dependencycheck.dependency.Dependency;
26 import org.owasp.dependencycheck.utils.Checksum;
27 import org.owasp.dependencycheck.utils.FileFilterBuilder;
28 import org.owasp.dependencycheck.utils.Settings;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32 import java.io.File;
33 import java.io.FileFilter;
34 import java.io.IOException;
35 import java.security.MessageDigest;
36 import java.security.NoSuchAlgorithmException;
37 import java.util.regex.Matcher;
38 import java.util.regex.Pattern;
39
40
41
42
43
44
45
46
47
48
49
50
51
52 public class CMakeAnalyzer extends AbstractFileTypeAnalyzer {
53
54
55
56
57 private static final Logger LOGGER = LoggerFactory.getLogger(CMakeAnalyzer.class);
58
59
60
61
62 private static final int REGEX_OPTIONS = Pattern.DOTALL
63 | Pattern.CASE_INSENSITIVE | Pattern.MULTILINE;
64
65 private static final Pattern PROJECT = Pattern.compile(
66 "^ *project *\\([ \\n]*(\\w+)[ \\n]*.*?\\)", REGEX_OPTIONS);
67
68
69
70 private static final Pattern SET_VERSION = Pattern
71 .compile(
72 "^ *set\\s*\\(\\s*(\\w+)_version\\s+\"?(\\d+(?:\\.\\d+)+)[\\s\"]?\\)",
73 REGEX_OPTIONS);
74
75
76
77
78 private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(".cmake")
79 .addFilenames("CMakeLists.txt").build();
80
81
82
83
84 private static MessageDigest sha1 = null;
85
86 static {
87 try {
88 sha1 = MessageDigest.getInstance("SHA1");
89 } catch (NoSuchAlgorithmException e) {
90 LOGGER.error(e.getMessage());
91 }
92 }
93
94
95
96
97
98
99
100 @Override
101 public String getName() {
102 return "CMake Analyzer";
103 }
104
105
106
107
108
109
110 @Override
111 public AnalysisPhase getAnalysisPhase() {
112 return AnalysisPhase.INFORMATION_COLLECTION;
113 }
114
115
116
117
118
119
120 @Override
121 protected FileFilter getFileFilter() {
122 return FILTER;
123 }
124
125
126
127
128
129
130 @Override
131 protected void initializeFileTypeAnalyzer() throws Exception {
132
133 }
134
135
136
137
138
139
140
141
142 @Override
143 protected void analyzeFileType(Dependency dependency, Engine engine)
144 throws AnalysisException {
145 final File file = dependency.getActualFile();
146 final String parentName = file.getParentFile().getName();
147 final String name = file.getName();
148 dependency.setDisplayFileName(String.format("%s%c%s", parentName, File.separatorChar, name));
149 String contents;
150 try {
151 contents = FileUtils.readFileToString(file).trim();
152 } catch (IOException e) {
153 throw new AnalysisException(
154 "Problem occurred while reading dependency file.", e);
155 }
156
157 if (StringUtils.isNotBlank(contents)) {
158 final Matcher m = PROJECT.matcher(contents);
159 int count = 0;
160 while (m.find()) {
161 count++;
162 LOGGER.debug(String.format(
163 "Found project command match with %d groups: %s",
164 m.groupCount(), m.group(0)));
165 final String group = m.group(1);
166 LOGGER.debug("Group 1: " + group);
167 dependency.getProductEvidence().addEvidence(name, "Project",
168 group, Confidence.HIGH);
169 }
170 LOGGER.debug("Found {} matches.", count);
171 analyzeSetVersionCommand(dependency, engine, contents);
172 }
173 }
174
175 private void analyzeSetVersionCommand(Dependency dependency, Engine engine, String contents) {
176 final Dependency orig = dependency;
177 final Matcher m = SET_VERSION.matcher(contents);
178 int count = 0;
179 while (m.find()) {
180 count++;
181 LOGGER.debug("Found project command match with {} groups: {}",
182 m.groupCount(), m.group(0));
183 String product = m.group(1);
184 final String version = m.group(2);
185 LOGGER.debug("Group 1: " + product);
186 LOGGER.debug("Group 2: " + version);
187 final String aliasPrefix = "ALIASOF_";
188 if (product.startsWith(aliasPrefix)) {
189 product = product.replaceFirst(aliasPrefix, "");
190 }
191 if (count > 1) {
192
193 dependency = new Dependency(orig.getActualFile());
194 dependency.setDisplayFileName(String.format("%s:%s", orig.getDisplayFileName(), product));
195 final String filePath = String.format("%s:%s", orig.getFilePath(), product);
196 dependency.setFilePath(filePath);
197
198
199 dependency.setSha1sum(Checksum.getHex(sha1.digest(filePath.getBytes())));
200 engine.getDependencies().add(dependency);
201 }
202 final String source = dependency.getDisplayFileName();
203 dependency.getProductEvidence().addEvidence(source, "Product",
204 product, Confidence.MEDIUM);
205 dependency.getVersionEvidence().addEvidence(source, "Version",
206 version, Confidence.MEDIUM);
207 }
208 LOGGER.debug(String.format("Found %d matches.", count));
209 }
210
211 @Override
212 protected String getAnalyzerEnabledSettingKey() {
213 return Settings.KEYS.ANALYZER_CMAKE_ENABLED;
214 }
215 }