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.io.UnsupportedEncodingException;
36 import java.security.MessageDigest;
37 import java.security.NoSuchAlgorithmException;
38 import java.util.regex.Matcher;
39 import java.util.regex.Pattern;
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
66
67
68 private static final Pattern PROJECT = Pattern.compile(
69 "^ *project *\\([ \\n]*(\\w+)[ \\n]*.*?\\)", REGEX_OPTIONS);
70
71
72
73
74
75
76
77
78 private static final Pattern SET_VERSION = Pattern
79 .compile(
80 "^ *set\\s*\\(\\s*(\\w+)_version\\s+\"?(\\d+(?:\\.\\d+)+)[\\s\"]?\\)",
81 REGEX_OPTIONS);
82
83
84
85
86 private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(".cmake")
87 .addFilenames("CMakeLists.txt").build();
88
89
90
91
92 private static MessageDigest sha1 = null;
93
94 static {
95 try {
96 sha1 = MessageDigest.getInstance("SHA1");
97 } catch (NoSuchAlgorithmException e) {
98 LOGGER.error(e.getMessage());
99 }
100 }
101
102
103
104
105
106
107
108 @Override
109 public String getName() {
110 return "CMake Analyzer";
111 }
112
113
114
115
116
117
118 @Override
119 public AnalysisPhase getAnalysisPhase() {
120 return AnalysisPhase.INFORMATION_COLLECTION;
121 }
122
123
124
125
126
127
128 @Override
129 protected FileFilter getFileFilter() {
130 return FILTER;
131 }
132
133
134
135
136
137
138 @Override
139 protected void initializeFileTypeAnalyzer() throws Exception {
140
141 }
142
143
144
145
146
147
148
149
150 @Override
151 protected void analyzeFileType(Dependency dependency, Engine engine)
152 throws AnalysisException {
153 final File file = dependency.getActualFile();
154 final String parentName = file.getParentFile().getName();
155 final String name = file.getName();
156 dependency.setDisplayFileName(String.format("%s%c%s", parentName, File.separatorChar, name));
157 String contents;
158 try {
159 contents = FileUtils.readFileToString(file).trim();
160 } catch (IOException e) {
161 throw new AnalysisException(
162 "Problem occurred while reading dependency file.", e);
163 }
164
165 if (StringUtils.isNotBlank(contents)) {
166 final Matcher m = PROJECT.matcher(contents);
167 int count = 0;
168 while (m.find()) {
169 count++;
170 LOGGER.debug(String.format(
171 "Found project command match with %d groups: %s",
172 m.groupCount(), m.group(0)));
173 final String group = m.group(1);
174 LOGGER.debug("Group 1: " + group);
175 dependency.getProductEvidence().addEvidence(name, "Project",
176 group, Confidence.HIGH);
177 }
178 LOGGER.debug("Found {} matches.", count);
179 analyzeSetVersionCommand(dependency, engine, contents);
180 }
181 }
182
183
184
185
186
187
188
189
190
191 private void analyzeSetVersionCommand(Dependency dependency, Engine engine, String contents) {
192 Dependency currentDep = dependency;
193
194 final Matcher m = SET_VERSION.matcher(contents);
195 int count = 0;
196 while (m.find()) {
197 count++;
198 LOGGER.debug("Found project command match with {} groups: {}",
199 m.groupCount(), m.group(0));
200 String product = m.group(1);
201 final String version = m.group(2);
202 LOGGER.debug("Group 1: " + product);
203 LOGGER.debug("Group 2: " + version);
204 final String aliasPrefix = "ALIASOF_";
205 if (product.startsWith(aliasPrefix)) {
206 product = product.replaceFirst(aliasPrefix, "");
207 }
208 if (count > 1) {
209
210 currentDep = new Dependency(dependency.getActualFile());
211 currentDep.setDisplayFileName(String.format("%s:%s", dependency.getDisplayFileName(), product));
212 final String filePath = String.format("%s:%s", dependency.getFilePath(), product);
213 currentDep.setFilePath(filePath);
214
215 byte[] path;
216 try {
217 path = filePath.getBytes("UTF-8");
218 } catch (UnsupportedEncodingException ex) {
219 path = filePath.getBytes();
220 }
221 currentDep.setSha1sum(Checksum.getHex(sha1.digest(path)));
222 engine.getDependencies().add(currentDep);
223 }
224 final String source = currentDep.getDisplayFileName();
225 currentDep.getProductEvidence().addEvidence(source, "Product",
226 product, Confidence.MEDIUM);
227 currentDep.getVersionEvidence().addEvidence(source, "Version",
228 version, Confidence.MEDIUM);
229 }
230 LOGGER.debug(String.format("Found %d matches.", count));
231 }
232
233 @Override
234 protected String getAnalyzerEnabledSettingKey() {
235 return Settings.KEYS.ANALYZER_CMAKE_ENABLED;
236 }
237 }