OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/download/quarantine.h" | 5 #include "content/browser/download/quarantine.h" |
6 | 6 |
7 #include <windows.h> | 7 #include <windows.h> |
8 | 8 |
9 #include <cguid.h> | 9 #include <cguid.h> |
10 #include <objbase.h> | 10 #include <objbase.h> |
11 #include <shellapi.h> | 11 #include <shellapi.h> |
12 #include <shlobj.h> | 12 #include <shlobj.h> |
13 #include <shobjidl.h> | 13 #include <shobjidl.h> |
| 14 #include <wininet.h> |
14 | 15 |
15 #include "base/files/file_util.h" | 16 #include "base/files/file_util.h" |
16 #include "base/guid.h" | 17 #include "base/guid.h" |
17 #include "base/logging.h" | 18 #include "base/logging.h" |
18 #include "base/macros.h" | 19 #include "base/macros.h" |
19 #include "base/metrics/histogram_macros.h" | 20 #include "base/metrics/histogram_macros.h" |
20 #include "base/metrics/sparse_histogram.h" | 21 #include "base/metrics/sparse_histogram.h" |
21 #include "base/strings/string_piece.h" | 22 #include "base/strings/string_piece.h" |
22 #include "base/strings/utf_string_conversions.h" | 23 #include "base/strings/utf_string_conversions.h" |
23 #include "base/threading/thread_restrictions.h" | 24 #include "base/threading/thread_restrictions.h" |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
164 // Typical |save_result| values: | 165 // Typical |save_result| values: |
165 // S_OK : The file was okay. If any viruses were found, they were cleaned. | 166 // S_OK : The file was okay. If any viruses were found, they were cleaned. |
166 // E_FAIL : Virus infected. | 167 // E_FAIL : Virus infected. |
167 // INET_E_SECURITY_PROBLEM : The file was blocked due to security policy. | 168 // INET_E_SECURITY_PROBLEM : The file was blocked due to security policy. |
168 // | 169 // |
169 // Any other return value indicates an unexpected error during the scan. | 170 // Any other return value indicates an unexpected error during the scan. |
170 // | 171 // |
171 // |full_path| : is the path to the downloaded file. This should be the final | 172 // |full_path| : is the path to the downloaded file. This should be the final |
172 // path of the download. Must be present. | 173 // path of the download. Must be present. |
173 // |source_url|: the source URL for the download. If empty, the source will | 174 // |source_url|: the source URL for the download. If empty, the source will |
174 // not be set. | 175 // be set to 'about:internet'. |
| 176 // |referrer_url|: the referrer URL for the download. If empty, the referrer |
| 177 // will not be set. |
175 // |client_guid|: the GUID to be set in the IAttachmentExecute client slot. | 178 // |client_guid|: the GUID to be set in the IAttachmentExecute client slot. |
176 // Used to identify the app to the system AV function. | 179 // Used to identify the app to the system AV function. |
177 // If GUID_NULL is passed, no client GUID is set. | 180 // If GUID_NULL is passed, no client GUID is set. |
178 // |save_result|: Receives the result of invoking IAttachmentExecute::Save(). | 181 // |save_result|: Receives the result of invoking IAttachmentExecute::Save(). |
179 bool InvokeAttachmentServices(const base::FilePath& full_path, | 182 bool InvokeAttachmentServices(const base::FilePath& full_path, |
180 const std::string& source_url, | 183 const std::string& source_url, |
| 184 const std::string& referrer_url, |
181 const GUID& client_guid, | 185 const GUID& client_guid, |
182 HRESULT* save_result) { | 186 HRESULT* save_result) { |
183 base::win::ScopedComPtr<IAttachmentExecute> attachment_services; | 187 base::win::ScopedComPtr<IAttachmentExecute> attachment_services; |
184 HRESULT hr = attachment_services.CreateInstance(CLSID_AttachmentServices); | 188 HRESULT hr = attachment_services.CreateInstance(CLSID_AttachmentServices); |
185 *save_result = S_OK; | 189 *save_result = S_OK; |
186 | 190 |
187 if (FAILED(hr)) { | 191 if (FAILED(hr)) { |
188 // The thread must have COM initialized. | 192 // The thread must have COM initialized. |
189 DCHECK_NE(CO_E_NOTINITIALIZED, hr); | 193 DCHECK_NE(CO_E_NOTINITIALIZED, hr); |
190 RecordAttachmentServicesResult( | 194 RecordAttachmentServicesResult( |
191 AttachmentServicesResult::NO_ATTACHMENT_SERVICES); | 195 AttachmentServicesResult::NO_ATTACHMENT_SERVICES); |
192 return false; | 196 return false; |
193 } | 197 } |
194 | 198 |
| 199 // Note that it is mandatory to check the return values from here on out. If |
| 200 // setting one of the parameters fails, it could leave the object in a state |
| 201 // where the final Save() call will also fail. |
| 202 |
195 hr = attachment_services->SetClientGuid(client_guid); | 203 hr = attachment_services->SetClientGuid(client_guid); |
196 if (FAILED(hr)) { | 204 if (FAILED(hr)) { |
197 RecordAttachmentServicesResult( | 205 RecordAttachmentServicesResult( |
198 AttachmentServicesResult::FAILED_TO_SET_PARAMETER); | 206 AttachmentServicesResult::FAILED_TO_SET_PARAMETER); |
199 return false; | 207 return false; |
200 } | 208 } |
201 | 209 |
202 hr = attachment_services->SetLocalPath(full_path.value().c_str()); | 210 hr = attachment_services->SetLocalPath(full_path.value().c_str()); |
203 if (FAILED(hr)) { | 211 if (FAILED(hr)) { |
204 RecordAttachmentServicesResult( | 212 RecordAttachmentServicesResult( |
205 AttachmentServicesResult::FAILED_TO_SET_PARAMETER); | 213 AttachmentServicesResult::FAILED_TO_SET_PARAMETER); |
206 return false; | 214 return false; |
207 } | 215 } |
208 | 216 |
209 // Note: SetSource looks like it needs to be called, even if empty. | 217 // The source URL could be empty if it was not a valid URL or was not HTTP/S. |
210 // Docs say it is optional, but it appears not calling it at all sets | 218 // If so, user "about:internet" as a fallback URL. The latter is known to |
211 // a zone that is too restrictive. | 219 // reliably map to the Internet zone. |
212 hr = attachment_services->SetSource(base::UTF8ToWide(source_url).c_str()); | 220 // |
| 221 // In addition, URLs that are longer than INTERNET_MAX_URL_LENGTH are also |
| 222 // known to cause problems for URLMon. Hence also use "about:internet" in |
| 223 // these cases. See http://crbug.com/601538. |
| 224 hr = attachment_services->SetSource( |
| 225 source_url.empty() || source_url.size() > INTERNET_MAX_URL_LENGTH |
| 226 ? L"about:internet" |
| 227 : base::UTF8ToWide(source_url).c_str()); |
213 if (FAILED(hr)) { | 228 if (FAILED(hr)) { |
214 RecordAttachmentServicesResult( | 229 RecordAttachmentServicesResult( |
215 AttachmentServicesResult::FAILED_TO_SET_PARAMETER); | 230 AttachmentServicesResult::FAILED_TO_SET_PARAMETER); |
216 return false; | 231 return false; |
217 } | 232 } |
218 | 233 |
| 234 // Only set referrer if one is present and shorter than |
| 235 // INTERNET_MAX_URL_LENGTH. Also, the source_url is authoritative for |
| 236 // determining the relative danger of |full_path| so we don't consider it an |
| 237 // error if we have to skip the |referrer_url|. |
| 238 if (!referrer_url.empty() && referrer_url.size() < INTERNET_MAX_URL_LENGTH) { |
| 239 hr = attachment_services->SetReferrer( |
| 240 base::UTF8ToWide(referrer_url).c_str()); |
| 241 if (FAILED(hr)) { |
| 242 RecordAttachmentServicesResult( |
| 243 AttachmentServicesResult::FAILED_TO_SET_PARAMETER); |
| 244 return false; |
| 245 } |
| 246 } |
| 247 |
219 { | 248 { |
220 // This method has been known to take longer than 10 seconds in some | 249 // This method has been known to take longer than 10 seconds in some |
221 // instances. | 250 // instances. |
222 SCOPED_UMA_HISTOGRAM_LONG_TIMER("Download.AttachmentServices.Duration"); | 251 SCOPED_UMA_HISTOGRAM_LONG_TIMER("Download.AttachmentServices.Duration"); |
223 *save_result = attachment_services->Save(); | 252 *save_result = attachment_services->Save(); |
224 } | 253 } |
225 RecordAttachmentServicesSaveResult(full_path, *save_result); | 254 RecordAttachmentServicesSaveResult(full_path, *save_result); |
226 return true; | 255 return true; |
227 } | 256 } |
228 | 257 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
273 } | 302 } |
274 | 303 |
275 if (file_size == 0 || IsEqualGUID(guid, GUID_NULL)) { | 304 if (file_size == 0 || IsEqualGUID(guid, GUID_NULL)) { |
276 // Calling InvokeAttachmentServices on an empty file can result in the file | 305 // Calling InvokeAttachmentServices on an empty file can result in the file |
277 // being deleted. Also an anti-virus scan doesn't make a lot of sense to | 306 // being deleted. Also an anti-virus scan doesn't make a lot of sense to |
278 // perform on an empty file. | 307 // perform on an empty file. |
279 return SetInternetZoneIdentifierDirectly(file); | 308 return SetInternetZoneIdentifierDirectly(file); |
280 } | 309 } |
281 | 310 |
282 HRESULT save_result = S_OK; | 311 HRESULT save_result = S_OK; |
283 bool attachment_services_available = | 312 bool attachment_services_available = InvokeAttachmentServices( |
284 InvokeAttachmentServices(file, source_url.spec(), guid, &save_result); | 313 file, source_url.spec(), referrer_url.spec(), guid, &save_result); |
285 if (!attachment_services_available) | 314 if (!attachment_services_available) |
286 return SetInternetZoneIdentifierDirectly(file); | 315 return SetInternetZoneIdentifierDirectly(file); |
287 | 316 |
288 // If the download file is missing after the call, then treat this as an | 317 // If the download file is missing after the call, then treat this as an |
289 // interrupted download. | 318 // interrupted download. |
290 // | 319 // |
291 // If InvokeAttachmentServices() failed, but the downloaded file is still | 320 // If InvokeAttachmentServices() failed, but the downloaded file is still |
292 // around, then don't interrupt the download. Attachment Execution Services | 321 // around, then don't interrupt the download. Attachment Execution Services |
293 // deletes the submitted file if the downloaded file is blocked by policy or | 322 // deletes the submitted file if the downloaded file is blocked by policy or |
294 // if it was found to be infected. | 323 // if it was found to be infected. |
295 // | 324 // |
296 // If the file is still there, then the error could be due to Windows | 325 // If the file is still there, then the error could be due to Windows |
297 // Attachment Services not being available or some other error during the AES | 326 // Attachment Services not being available or some other error during the AES |
298 // invocation. In either case, we don't surface the error to the user. | 327 // invocation. In either case, we don't surface the error to the user. |
299 if (!base::PathExists(file)) | 328 if (!base::PathExists(file)) |
300 return FailedSaveResultToQuarantineResult(save_result); | 329 return FailedSaveResultToQuarantineResult(save_result); |
301 return QuarantineFileResult::OK; | 330 return QuarantineFileResult::OK; |
302 } | 331 } |
303 | 332 |
304 } // namespace content | 333 } // namespace content |
OLD | NEW |