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