safe_browsing_service.cc revision 6d86b77056ed63eb6871182f42a9fd5f07550f90
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/safe_browsing/safe_browsing_service.h"
6
7#include <vector>
8
9#include "base/bind.h"
10#include "base/bind_helpers.h"
11#include "base/callback.h"
12#include "base/command_line.h"
13#include "base/debug/leak_tracker.h"
14#include "base/lazy_instance.h"
15#include "base/path_service.h"
16#include "base/prefs/pref_change_registrar.h"
17#include "base/prefs/pref_service.h"
18#include "base/stl_util.h"
19#include "base/strings/string_util.h"
20#include "base/threading/thread.h"
21#include "base/threading/thread_restrictions.h"
22#include "chrome/browser/browser_process.h"
23#include "chrome/browser/chrome_notification_types.h"
24#include "chrome/browser/prefs/tracked/tracked_preference_validation_delegate.h"
25#include "chrome/browser/profiles/profile.h"
26#include "chrome/browser/profiles/profile_manager.h"
27#include "chrome/browser/safe_browsing/client_side_detection_service.h"
28#include "chrome/browser/safe_browsing/database_manager.h"
29#include "chrome/browser/safe_browsing/download_protection_service.h"
30#include "chrome/browser/safe_browsing/incident_reporting_service.h"
31#include "chrome/browser/safe_browsing/malware_details.h"
32#include "chrome/browser/safe_browsing/ping_manager.h"
33#include "chrome/browser/safe_browsing/protocol_manager.h"
34#include "chrome/browser/safe_browsing/safe_browsing_database.h"
35#include "chrome/browser/safe_browsing/ui_manager.h"
36#include "chrome/common/chrome_constants.h"
37#include "chrome/common/chrome_paths.h"
38#include "chrome/common/chrome_switches.h"
39#include "chrome/common/pref_names.h"
40#include "chrome/common/url_constants.h"
41#include "components/metrics/metrics_service.h"
42#include "components/startup_metric_utils/startup_metric_utils.h"
43#include "content/public/browser/browser_thread.h"
44#include "content/public/browser/cookie_crypto_delegate.h"
45#include "content/public/browser/cookie_store_factory.h"
46#include "content/public/browser/notification_service.h"
47#include "net/cookies/cookie_monster.h"
48#include "net/url_request/url_request_context.h"
49#include "net/url_request/url_request_context_getter.h"
50
51#if defined(OS_WIN)
52#include "chrome/installer/util/browser_distribution.h"
53#endif
54
55#if defined(OS_ANDROID)
56#include <string>
57#include "base/metrics/field_trial.h"
58#endif
59
60using content::BrowserThread;
61
62namespace {
63
64// Filename suffix for the cookie database.
65const base::FilePath::CharType kCookiesFile[] = FILE_PATH_LITERAL(" Cookies");
66
67// The default URL prefix where browser fetches chunk updates, hashes,
68// and reports safe browsing hits and malware details.
69const char* const kSbDefaultURLPrefix =
70    "https://safebrowsing.google.com/safebrowsing";
71
72// The backup URL prefix used when there are issues establishing a connection
73// with the server at the primary URL.
74const char* const kSbBackupConnectErrorURLPrefix =
75    "https://alt1-safebrowsing.google.com/safebrowsing";
76
77// The backup URL prefix used when there are HTTP-specific issues with the
78// server at the primary URL.
79const char* const kSbBackupHttpErrorURLPrefix =
80    "https://alt2-safebrowsing.google.com/safebrowsing";
81
82// The backup URL prefix used when there are local network specific issues.
83const char* const kSbBackupNetworkErrorURLPrefix =
84    "https://alt3-safebrowsing.google.com/safebrowsing";
85
86base::FilePath CookieFilePath() {
87  return base::FilePath(
88      SafeBrowsingService::GetBaseFilename().value() + kCookiesFile);
89}
90
91}  // namespace
92
93class SafeBrowsingURLRequestContextGetter
94    : public net::URLRequestContextGetter {
95 public:
96  explicit SafeBrowsingURLRequestContextGetter(
97      SafeBrowsingService* sb_service_);
98
99  // Implementation for net::UrlRequestContextGetter.
100  virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE;
101  virtual scoped_refptr<base::SingleThreadTaskRunner>
102      GetNetworkTaskRunner() const OVERRIDE;
103
104 protected:
105  virtual ~SafeBrowsingURLRequestContextGetter();
106
107 private:
108  SafeBrowsingService* const sb_service_;  // Owned by BrowserProcess.
109  scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_;
110
111  base::debug::LeakTracker<SafeBrowsingURLRequestContextGetter> leak_tracker_;
112};
113
114SafeBrowsingURLRequestContextGetter::SafeBrowsingURLRequestContextGetter(
115    SafeBrowsingService* sb_service)
116    : sb_service_(sb_service),
117      network_task_runner_(
118          BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)) {
119}
120
121SafeBrowsingURLRequestContextGetter::~SafeBrowsingURLRequestContextGetter() {}
122
123net::URLRequestContext*
124SafeBrowsingURLRequestContextGetter::GetURLRequestContext() {
125  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
126  DCHECK(sb_service_->url_request_context_.get());
127
128  return sb_service_->url_request_context_.get();
129}
130
131scoped_refptr<base::SingleThreadTaskRunner>
132SafeBrowsingURLRequestContextGetter::GetNetworkTaskRunner() const {
133  return network_task_runner_;
134}
135
136// static
137SafeBrowsingServiceFactory* SafeBrowsingService::factory_ = NULL;
138
139// The default SafeBrowsingServiceFactory.  Global, made a singleton so we
140// don't leak it.
141class SafeBrowsingServiceFactoryImpl : public SafeBrowsingServiceFactory {
142 public:
143  virtual SafeBrowsingService* CreateSafeBrowsingService() OVERRIDE {
144    return new SafeBrowsingService();
145  }
146
147 private:
148  friend struct base::DefaultLazyInstanceTraits<SafeBrowsingServiceFactoryImpl>;
149
150  SafeBrowsingServiceFactoryImpl() { }
151
152  DISALLOW_COPY_AND_ASSIGN(SafeBrowsingServiceFactoryImpl);
153};
154
155static base::LazyInstance<SafeBrowsingServiceFactoryImpl>::Leaky
156    g_safe_browsing_service_factory_impl = LAZY_INSTANCE_INITIALIZER;
157
158// static
159base::FilePath SafeBrowsingService::GetCookieFilePathForTesting() {
160  return CookieFilePath();
161}
162
163// static
164base::FilePath SafeBrowsingService::GetBaseFilename() {
165  base::FilePath path;
166  bool result = PathService::Get(chrome::DIR_USER_DATA, &path);
167  DCHECK(result);
168  return path.Append(chrome::kSafeBrowsingBaseFilename);
169}
170
171
172// static
173SafeBrowsingService* SafeBrowsingService::CreateSafeBrowsingService() {
174  if (!factory_)
175    factory_ = g_safe_browsing_service_factory_impl.Pointer();
176  return factory_->CreateSafeBrowsingService();
177}
178
179#if defined(OS_ANDROID) && defined(FULL_SAFE_BROWSING)
180// static
181bool SafeBrowsingService::IsEnabledByFieldTrial() {
182  const std::string experiment_name =
183      base::FieldTrialList::FindFullName("SafeBrowsingAndroid");
184  return experiment_name == "Enabled";
185}
186#endif
187
188SafeBrowsingService::SafeBrowsingService()
189    : protocol_manager_(NULL),
190      ping_manager_(NULL),
191      enabled_(false) {
192}
193
194SafeBrowsingService::~SafeBrowsingService() {
195  // We should have already been shut down. If we're still enabled, then the
196  // database isn't going to be closed properly, which could lead to corruption.
197  DCHECK(!enabled_);
198}
199
200void SafeBrowsingService::Initialize() {
201  startup_metric_utils::ScopedSlowStartupUMA
202      scoped_timer("Startup.SlowStartupSafeBrowsingServiceInitialize");
203
204  url_request_context_getter_ =
205      new SafeBrowsingURLRequestContextGetter(this);
206
207  ui_manager_ = CreateUIManager();
208
209  database_manager_ = CreateDatabaseManager();
210
211  BrowserThread::PostTask(
212      BrowserThread::IO, FROM_HERE,
213      base::Bind(
214          &SafeBrowsingService::InitURLRequestContextOnIOThread, this,
215          make_scoped_refptr(g_browser_process->system_request_context())));
216
217#if defined(FULL_SAFE_BROWSING)
218  if (!CommandLine::ForCurrentProcess()->HasSwitch(
219          switches::kDisableClientSidePhishingDetection)) {
220    csd_service_.reset(safe_browsing::ClientSideDetectionService::Create(
221        url_request_context_getter_.get()));
222  }
223  download_service_.reset(new safe_browsing::DownloadProtectionService(
224      this, url_request_context_getter_.get()));
225
226  incident_service_.reset(new safe_browsing::IncidentReportingService(
227      this, url_request_context_getter_));
228#endif
229
230  // Track the safe browsing preference of existing profiles.
231  // The SafeBrowsingService will be started if any existing profile has the
232  // preference enabled. It will also listen for updates to the preferences.
233  ProfileManager* profile_manager = g_browser_process->profile_manager();
234  if (profile_manager) {
235    std::vector<Profile*> profiles = profile_manager->GetLoadedProfiles();
236    for (size_t i = 0; i < profiles.size(); ++i) {
237      if (profiles[i]->IsOffTheRecord())
238        continue;
239      AddPrefService(profiles[i]->GetPrefs());
240    }
241  }
242
243  // Track profile creation and destruction.
244  prefs_registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED,
245                       content::NotificationService::AllSources());
246  prefs_registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
247                       content::NotificationService::AllSources());
248}
249
250void SafeBrowsingService::ShutDown() {
251  // Deletes the PrefChangeRegistrars, whose dtors also unregister |this| as an
252  // observer of the preferences.
253  STLDeleteValues(&prefs_map_);
254
255  // Remove Profile creation/destruction observers.
256  prefs_registrar_.RemoveAll();
257
258  Stop(true);
259  // The IO thread is going away, so make sure the ClientSideDetectionService
260  // dtor executes now since it may call the dtor of URLFetcher which relies
261  // on it.
262  csd_service_.reset();
263  download_service_.reset();
264  incident_service_.reset();
265
266  url_request_context_getter_ = NULL;
267  BrowserThread::PostNonNestableTask(
268      BrowserThread::IO, FROM_HERE,
269      base::Bind(&SafeBrowsingService::DestroyURLRequestContextOnIOThread,
270                 this));
271}
272
273// Binhash verification is only enabled for UMA users for now.
274bool SafeBrowsingService::DownloadBinHashNeeded() const {
275  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
276
277#if defined(FULL_SAFE_BROWSING)
278  return (database_manager_->download_protection_enabled() &&
279          ui_manager_->CanReportStats()) ||
280      (download_protection_service() &&
281       download_protection_service()->enabled());
282#else
283  return false;
284#endif
285}
286
287net::URLRequestContextGetter* SafeBrowsingService::url_request_context() {
288  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
289  return url_request_context_getter_.get();
290}
291
292const scoped_refptr<SafeBrowsingUIManager>&
293SafeBrowsingService::ui_manager() const {
294  return ui_manager_;
295}
296
297const scoped_refptr<SafeBrowsingDatabaseManager>&
298SafeBrowsingService::database_manager() const {
299  return database_manager_;
300}
301
302SafeBrowsingProtocolManager* SafeBrowsingService::protocol_manager() const {
303  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
304  return protocol_manager_;
305}
306
307SafeBrowsingPingManager* SafeBrowsingService::ping_manager() const {
308  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
309  return ping_manager_;
310}
311
312scoped_ptr<TrackedPreferenceValidationDelegate>
313SafeBrowsingService::CreatePreferenceValidationDelegate(
314    Profile* profile) const {
315#if defined(FULL_SAFE_BROWSING)
316  if (incident_service_)
317    return incident_service_->CreatePreferenceValidationDelegate(profile);
318#endif
319  return scoped_ptr<TrackedPreferenceValidationDelegate>();
320}
321
322SafeBrowsingUIManager* SafeBrowsingService::CreateUIManager() {
323  return new SafeBrowsingUIManager(this);
324}
325
326SafeBrowsingDatabaseManager* SafeBrowsingService::CreateDatabaseManager() {
327#if defined(FULL_SAFE_BROWSING)
328  return new SafeBrowsingDatabaseManager(this);
329#else
330  return NULL;
331#endif
332}
333
334void SafeBrowsingService::InitURLRequestContextOnIOThread(
335    net::URLRequestContextGetter* system_url_request_context_getter) {
336  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
337  DCHECK(!url_request_context_.get());
338
339  scoped_refptr<net::CookieStore> cookie_store(
340      content::CreateCookieStore(
341          content::CookieStoreConfig(
342              CookieFilePath(),
343              content::CookieStoreConfig::EPHEMERAL_SESSION_COOKIES,
344              NULL,
345              NULL)));
346
347  url_request_context_.reset(new net::URLRequestContext);
348  // |system_url_request_context_getter| may be NULL during tests.
349  if (system_url_request_context_getter) {
350    url_request_context_->CopyFrom(
351        system_url_request_context_getter->GetURLRequestContext());
352  }
353  url_request_context_->set_cookie_store(cookie_store.get());
354}
355
356void SafeBrowsingService::DestroyURLRequestContextOnIOThread() {
357  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
358
359  url_request_context_->AssertNoURLRequests();
360
361  // Need to do the CheckForLeaks on IOThread instead of in ShutDown where
362  // url_request_context_getter_ is cleared,  since the URLRequestContextGetter
363  // will PostTask to IOTread to delete itself.
364  using base::debug::LeakTracker;
365  LeakTracker<SafeBrowsingURLRequestContextGetter>::CheckForLeaks();
366
367  url_request_context_.reset();
368}
369
370SafeBrowsingProtocolConfig SafeBrowsingService::GetProtocolConfig() const {
371  SafeBrowsingProtocolConfig config;
372  // On Windows, get the safe browsing client name from the browser
373  // distribution classes in installer util. These classes don't yet have
374  // an analog on non-Windows builds so just keep the name specified here.
375#if defined(OS_WIN)
376  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
377  config.client_name = dist->GetSafeBrowsingName();
378#else
379#if defined(GOOGLE_CHROME_BUILD)
380  config.client_name = "googlechrome";
381#else
382  config.client_name = "chromium";
383#endif
384
385  // Mark client string to allow server to differentiate mobile.
386#if defined(OS_ANDROID)
387  config.client_name.append("-a");
388#elif defined(OS_IOS)
389  config.client_name.append("-i");
390#endif
391
392#endif  // defined(OS_WIN)
393  CommandLine* cmdline = CommandLine::ForCurrentProcess();
394  config.disable_auto_update =
395      cmdline->HasSwitch(switches::kSbDisableAutoUpdate) ||
396      cmdline->HasSwitch(switches::kDisableBackgroundNetworking);
397  config.url_prefix = kSbDefaultURLPrefix;
398  config.backup_connect_error_url_prefix = kSbBackupConnectErrorURLPrefix;
399  config.backup_http_error_url_prefix = kSbBackupHttpErrorURLPrefix;
400  config.backup_network_error_url_prefix = kSbBackupNetworkErrorURLPrefix;
401
402  return config;
403}
404
405void SafeBrowsingService::StartOnIOThread(
406    net::URLRequestContextGetter* url_request_context_getter) {
407  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
408  if (enabled_)
409    return;
410  enabled_ = true;
411
412  SafeBrowsingProtocolConfig config = GetProtocolConfig();
413
414#if defined(FULL_SAFE_BROWSING)
415  DCHECK(database_manager_.get());
416  database_manager_->StartOnIOThread();
417
418  DCHECK(!protocol_manager_);
419  protocol_manager_ = SafeBrowsingProtocolManager::Create(
420      database_manager_.get(), url_request_context_getter, config);
421  protocol_manager_->Initialize();
422#endif
423
424  DCHECK(!ping_manager_);
425  ping_manager_ = SafeBrowsingPingManager::Create(
426      url_request_context_getter, config);
427}
428
429void SafeBrowsingService::StopOnIOThread(bool shutdown) {
430  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
431
432#if defined(FULL_SAFE_BROWSING)
433  database_manager_->StopOnIOThread(shutdown);
434#endif
435  ui_manager_->StopOnIOThread(shutdown);
436
437  if (enabled_) {
438    enabled_ = false;
439
440#if defined(FULL_SAFE_BROWSING)
441    // This cancels all in-flight GetHash requests. Note that database_manager_
442    // relies on the protocol_manager_ so if the latter is destroyed, the
443    // former must be stopped.
444    delete protocol_manager_;
445    protocol_manager_ = NULL;
446#endif
447    delete ping_manager_;
448    ping_manager_ = NULL;
449  }
450}
451
452void SafeBrowsingService::Start() {
453  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
454
455  BrowserThread::PostTask(
456      BrowserThread::IO, FROM_HERE,
457      base::Bind(&SafeBrowsingService::StartOnIOThread, this,
458                 url_request_context_getter_));
459}
460
461void SafeBrowsingService::Stop(bool shutdown) {
462  BrowserThread::PostTask(
463      BrowserThread::IO, FROM_HERE,
464      base::Bind(&SafeBrowsingService::StopOnIOThread, this, shutdown));
465}
466
467void SafeBrowsingService::Observe(int type,
468                                  const content::NotificationSource& source,
469                                  const content::NotificationDetails& details) {
470  switch (type) {
471    case chrome::NOTIFICATION_PROFILE_CREATED: {
472      DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
473      Profile* profile = content::Source<Profile>(source).ptr();
474      if (!profile->IsOffTheRecord())
475        AddPrefService(profile->GetPrefs());
476      break;
477    }
478    case chrome::NOTIFICATION_PROFILE_DESTROYED: {
479      DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
480      Profile* profile = content::Source<Profile>(source).ptr();
481      if (!profile->IsOffTheRecord())
482        RemovePrefService(profile->GetPrefs());
483      break;
484    }
485    default:
486      NOTREACHED();
487  }
488}
489
490void SafeBrowsingService::AddPrefService(PrefService* pref_service) {
491  DCHECK(prefs_map_.find(pref_service) == prefs_map_.end());
492  PrefChangeRegistrar* registrar = new PrefChangeRegistrar();
493  registrar->Init(pref_service);
494  registrar->Add(prefs::kSafeBrowsingEnabled,
495                 base::Bind(&SafeBrowsingService::RefreshState,
496                            base::Unretained(this)));
497  prefs_map_[pref_service] = registrar;
498  RefreshState();
499}
500
501void SafeBrowsingService::RemovePrefService(PrefService* pref_service) {
502  if (prefs_map_.find(pref_service) != prefs_map_.end()) {
503    delete prefs_map_[pref_service];
504    prefs_map_.erase(pref_service);
505    RefreshState();
506  } else {
507    NOTREACHED();
508  }
509}
510
511void SafeBrowsingService::RefreshState() {
512  // Check if any profile requires the service to be active.
513  bool enable = false;
514  std::map<PrefService*, PrefChangeRegistrar*>::iterator iter;
515  for (iter = prefs_map_.begin(); iter != prefs_map_.end(); ++iter) {
516    if (iter->first->GetBoolean(prefs::kSafeBrowsingEnabled)) {
517      enable = true;
518      break;
519    }
520  }
521
522  if (enable)
523    Start();
524  else
525    Stop(false);
526
527#if defined(FULL_SAFE_BROWSING)
528  if (csd_service_)
529    csd_service_->SetEnabledAndRefreshState(enable);
530  if (download_service_)
531    download_service_->SetEnabled(enable);
532#endif
533}
534