1// Copyright (c) 2011 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 "base/callback.h"
8#include "base/command_line.h"
9#include "base/lazy_instance.h"
10#include "base/path_service.h"
11#include "base/stl_util-inl.h"
12#include "base/string_util.h"
13#include "base/threading/thread_restrictions.h"
14#include "chrome/browser/browser_process.h"
15#include "chrome/browser/metrics/metrics_service.h"
16#include "chrome/browser/prefs/pref_service.h"
17#include "chrome/browser/profiles/profile_manager.h"
18#include "chrome/browser/safe_browsing/malware_details.h"
19#include "chrome/browser/safe_browsing/protocol_manager.h"
20#include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
21#include "chrome/browser/safe_browsing/safe_browsing_database.h"
22#include "chrome/browser/tab_contents/tab_util.h"
23#include "chrome/common/chrome_constants.h"
24#include "chrome/common/chrome_paths.h"
25#include "chrome/common/chrome_switches.h"
26#include "chrome/common/pref_names.h"
27#include "chrome/common/url_constants.h"
28#include "content/browser/browser_thread.h"
29#include "content/browser/tab_contents/tab_contents.h"
30#include "net/base/registry_controlled_domain.h"
31#include "net/url_request/url_request_context_getter.h"
32
33#if defined(OS_WIN)
34#include "chrome/installer/util/browser_distribution.h"
35#endif
36
37namespace {
38
39// The default URL prefix where browser fetches chunk updates, hashes,
40// and reports safe browsing hits.
41const char* const kSbDefaultInfoURLPrefix =
42    "http://safebrowsing.clients.google.com/safebrowsing";
43
44// The default URL prefix where browser fetches MAC client key and reports
45// malware details.
46const char* const kSbDefaultMacKeyURLPrefix =
47    "https://sb-ssl.google.com/safebrowsing";
48
49// When download url check takes this long, client's callback will be called
50// without waiting for the result.
51const int64 kDownloadUrlCheckTimeoutMs = 10000;
52
53// Similar to kDownloadUrlCheckTimeoutMs, but for download hash checks.
54const int64 kDownloadHashCheckTimeoutMs = 10000;
55
56// TODO(lzheng): Replace this with Profile* ProfileManager::GetDefaultProfile().
57Profile* GetDefaultProfile() {
58  FilePath user_data_dir;
59  PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
60  ProfileManager* profile_manager = g_browser_process->profile_manager();
61  return profile_manager->GetDefaultProfile(user_data_dir);
62}
63
64// Records disposition information about the check.  |hit| should be
65// |true| if there were any prefix hits in |full_hashes|.
66void RecordGetHashCheckStatus(
67    bool hit,
68    bool is_download,
69    const std::vector<SBFullHashResult>& full_hashes) {
70  SafeBrowsingProtocolManager::ResultType result;
71  if (full_hashes.empty()) {
72    result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_EMPTY;
73  } else if (hit) {
74    result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_HIT;
75  } else {
76    result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_MISS;
77  }
78  SafeBrowsingProtocolManager::RecordGetHashResult(is_download, result);
79}
80
81}  // namespace
82
83// static
84SafeBrowsingServiceFactory* SafeBrowsingService::factory_ = NULL;
85
86// The default SafeBrowsingServiceFactory.  Global, made a singleton so we
87// don't leak it.
88class SafeBrowsingServiceFactoryImpl : public SafeBrowsingServiceFactory {
89 public:
90  virtual SafeBrowsingService* CreateSafeBrowsingService() {
91    return new SafeBrowsingService();
92  }
93
94 private:
95  friend struct base::DefaultLazyInstanceTraits<SafeBrowsingServiceFactoryImpl>;
96
97  SafeBrowsingServiceFactoryImpl() { }
98
99  DISALLOW_COPY_AND_ASSIGN(SafeBrowsingServiceFactoryImpl);
100};
101
102static base::LazyInstance<SafeBrowsingServiceFactoryImpl>
103    g_safe_browsing_service_factory_impl(base::LINKER_INITIALIZED);
104
105struct SafeBrowsingService::WhiteListedEntry {
106  int render_process_host_id;
107  int render_view_id;
108  std::string domain;
109  UrlCheckResult result;
110};
111
112SafeBrowsingService::UnsafeResource::UnsafeResource()
113    : resource_type(ResourceType::MAIN_FRAME),
114      threat_type(SAFE),
115      client(NULL),
116      render_process_host_id(-1),
117      render_view_id(-1) {
118}
119
120SafeBrowsingService::UnsafeResource::~UnsafeResource() {}
121
122SafeBrowsingService::SafeBrowsingCheck::SafeBrowsingCheck()
123    : full_hash(NULL),
124      client(NULL),
125      need_get_hash(false),
126      result(SAFE),
127      is_download(false),
128      timeout_task(NULL) {
129}
130
131SafeBrowsingService::SafeBrowsingCheck::~SafeBrowsingCheck() {}
132
133void SafeBrowsingService::Client::OnSafeBrowsingResult(
134    const SafeBrowsingCheck& check) {
135  if (!check.urls.empty()) {
136
137    DCHECK(!check.full_hash.get());
138    if (!check.is_download) {
139      DCHECK_EQ(1U, check.urls.size());
140      OnBrowseUrlCheckResult(check.urls[0], check.result);
141    } else {
142      OnDownloadUrlCheckResult(check.urls, check.result);
143    }
144  } else if (check.full_hash.get()) {
145    OnDownloadHashCheckResult(
146        safe_browsing_util::SBFullHashToString(*check.full_hash),
147        check.result);
148  } else {
149    NOTREACHED();
150  }
151}
152
153/* static */
154SafeBrowsingService* SafeBrowsingService::CreateSafeBrowsingService() {
155  if (!factory_)
156    factory_ = g_safe_browsing_service_factory_impl.Pointer();
157  return factory_->CreateSafeBrowsingService();
158}
159
160SafeBrowsingService::SafeBrowsingService()
161    : database_(NULL),
162      protocol_manager_(NULL),
163      enabled_(false),
164      enable_download_protection_(false),
165      enable_csd_whitelist_(false),
166      update_in_progress_(false),
167      database_update_in_progress_(false),
168      closing_database_(false),
169      download_urlcheck_timeout_ms_(kDownloadUrlCheckTimeoutMs),
170      download_hashcheck_timeout_ms_(kDownloadHashCheckTimeoutMs) {
171}
172
173void SafeBrowsingService::Initialize() {
174  // Get the profile's preference for SafeBrowsing.
175  PrefService* pref_service = GetDefaultProfile()->GetPrefs();
176  if (pref_service->GetBoolean(prefs::kSafeBrowsingEnabled))
177    Start();
178}
179
180void SafeBrowsingService::ShutDown() {
181  BrowserThread::PostTask(
182      BrowserThread::IO, FROM_HERE,
183      NewRunnableMethod(this, &SafeBrowsingService::OnIOShutdown));
184}
185
186bool SafeBrowsingService::CanCheckUrl(const GURL& url) const {
187  return url.SchemeIs(chrome::kFtpScheme) ||
188         url.SchemeIs(chrome::kHttpScheme) ||
189         url.SchemeIs(chrome::kHttpsScheme);
190}
191
192// Only report SafeBrowsing related stats when UMA is enabled and
193// safe browsing is enabled.
194bool SafeBrowsingService::CanReportStats() const {
195  const MetricsService* metrics = g_browser_process->metrics_service();
196  const PrefService* pref_service = GetDefaultProfile()->GetPrefs();
197  return metrics && metrics->reporting_active() &&
198      pref_service && pref_service->GetBoolean(prefs::kSafeBrowsingEnabled);
199}
200
201// Binhash verification is only enabled for UMA users for now.
202bool SafeBrowsingService::DownloadBinHashNeeded() const {
203  return enable_download_protection_ && CanReportStats();
204}
205
206bool SafeBrowsingService::CheckDownloadUrl(const std::vector<GURL>& url_chain,
207                                           Client* client) {
208  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
209  if (!enabled_ || !enable_download_protection_)
210    return true;
211
212  // We need to check the database for url prefix, and later may fetch the url
213  // from the safebrowsing backends. These need to be asynchronous.
214  SafeBrowsingCheck* check = new SafeBrowsingCheck();
215  check->urls = url_chain;
216  StartDownloadCheck(
217      check,
218      client,
219      NewRunnableMethod(this,
220                        &SafeBrowsingService::CheckDownloadUrlOnSBThread,
221                        check),
222      download_urlcheck_timeout_ms_);
223  return false;
224}
225
226bool SafeBrowsingService::CheckDownloadHash(const std::string& full_hash,
227                                            Client* client) {
228  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
229  DCHECK(!full_hash.empty());
230  if (!enabled_ || !enable_download_protection_ || full_hash.empty())
231    return true;
232
233  // We need to check the database for url prefix, and later may fetch the url
234  // from the safebrowsing backends. These need to be asynchronous.
235  SafeBrowsingCheck* check = new SafeBrowsingCheck();
236  check->full_hash.reset(new SBFullHash);
237  safe_browsing_util::StringToSBFullHash(full_hash, check->full_hash.get());
238  StartDownloadCheck(
239      check,
240      client,
241      NewRunnableMethod(this,
242                        &SafeBrowsingService::CheckDownloadHashOnSBThread,
243                        check),
244      download_hashcheck_timeout_ms_);
245  return false;
246}
247
248bool SafeBrowsingService::MatchCsdWhitelistUrl(const GURL& url) {
249  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
250  if (!enabled_ || !enable_csd_whitelist_ || !MakeDatabaseAvailable()) {
251    // There is something funky going on here -- for example, perhaps the user
252    // has not restarted since enabling metrics reporting, so we haven't
253    // enabled the csd whitelist yet.  Just to be safe we return true in this
254    // case.
255    return true;
256  }
257  return database_->ContainsCsdWhitelistedUrl(url);
258}
259
260bool SafeBrowsingService::CheckBrowseUrl(const GURL& url,
261                                         Client* client) {
262  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
263  if (!enabled_)
264    return true;
265
266  if (!CanCheckUrl(url))
267    return true;
268
269  const base::TimeTicks start = base::TimeTicks::Now();
270  if (!MakeDatabaseAvailable()) {
271    QueuedCheck check;
272    check.client = client;
273    check.url = url;
274    check.start = start;
275    queued_checks_.push_back(check);
276    return false;
277  }
278
279  std::string list;
280  std::vector<SBPrefix> prefix_hits;
281  std::vector<SBFullHashResult> full_hits;
282  bool prefix_match =
283      database_->ContainsBrowseUrl(url, &list, &prefix_hits,
284                                   &full_hits,
285                                   protocol_manager_->last_update());
286
287  UMA_HISTOGRAM_TIMES("SB2.FilterCheck", base::TimeTicks::Now() - start);
288
289  if (!prefix_match)
290    return true;  // URL is okay.
291
292  // Needs to be asynchronous, since we could be in the constructor of a
293  // ResourceDispatcherHost event handler which can't pause there.
294  SafeBrowsingCheck* check = new SafeBrowsingCheck();
295  check->urls.push_back(url);
296  check->client = client;
297  check->result = SAFE;
298  check->is_download = false;
299  check->need_get_hash = full_hits.empty();
300  check->prefix_hits.swap(prefix_hits);
301  check->full_hits.swap(full_hits);
302  checks_.insert(check);
303
304  BrowserThread::PostTask(
305      BrowserThread::IO, FROM_HERE,
306      NewRunnableMethod(this, &SafeBrowsingService::OnCheckDone, check));
307
308  return false;
309}
310
311void SafeBrowsingService::CancelCheck(Client* client) {
312  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
313  for (CurrentChecks::iterator i = checks_.begin(); i != checks_.end(); ++i) {
314    // We can't delete matching checks here because the db thread has a copy of
315    // the pointer.  Instead, we simply NULL out the client, and when the db
316    // thread calls us back, we'll clean up the check.
317    if ((*i)->client == client)
318      (*i)->client = NULL;
319  }
320
321  // Scan the queued clients store. Clients may be here if they requested a URL
322  // check before the database has finished loading.
323  for (std::deque<QueuedCheck>::iterator it(queued_checks_.begin());
324       it != queued_checks_.end(); ) {
325    // In this case it's safe to delete matches entirely since nothing has a
326    // pointer to them.
327    if (it->client == client)
328      it = queued_checks_.erase(it);
329    else
330      ++it;
331  }
332}
333
334void SafeBrowsingService::DisplayBlockingPage(
335    const GURL& url,
336    const GURL& original_url,
337    const std::vector<GURL>& redirect_urls,
338    ResourceType::Type resource_type,
339    UrlCheckResult result,
340    Client* client,
341    int render_process_host_id,
342    int render_view_id) {
343  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
344
345  // Check if the user has already ignored our warning for this render_view
346  // and domain.
347  for (size_t i = 0; i < white_listed_entries_.size(); ++i) {
348    const WhiteListedEntry& entry = white_listed_entries_[i];
349    if (entry.render_process_host_id == render_process_host_id &&
350        entry.render_view_id == render_view_id &&
351        entry.result == result &&
352        entry.domain ==
353        net::RegistryControlledDomainService::GetDomainAndRegistry(url)) {
354      MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
355          this, &SafeBrowsingService::NotifyClientBlockingComplete,
356          client, true));
357      return;
358    }
359  }
360
361  UnsafeResource resource;
362  resource.url = url;
363  resource.original_url = original_url;
364  resource.redirect_urls = redirect_urls;
365  resource.resource_type = resource_type;
366  resource.threat_type= result;
367  resource.client = client;
368  resource.render_process_host_id = render_process_host_id;
369  resource.render_view_id = render_view_id;
370
371  // The blocking page must be created from the UI thread.
372  BrowserThread::PostTask(
373      BrowserThread::UI, FROM_HERE,
374      NewRunnableMethod(
375          this, &SafeBrowsingService::DoDisplayBlockingPage, resource));
376}
377
378void SafeBrowsingService::HandleGetHashResults(
379    SafeBrowsingCheck* check,
380    const std::vector<SBFullHashResult>& full_hashes,
381    bool can_cache) {
382  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
383
384  if (!enabled_)
385    return;
386
387  // If the service has been shut down, |check| should have been deleted.
388  DCHECK(checks_.find(check) != checks_.end());
389
390  // |start| is set before calling |GetFullHash()|, which should be
391  // the only path which gets to here.
392  DCHECK(!check->start.is_null());
393  UMA_HISTOGRAM_LONG_TIMES("SB2.Network",
394                           base::TimeTicks::Now() - check->start);
395
396  std::vector<SBPrefix> prefixes = check->prefix_hits;
397  OnHandleGetHashResults(check, full_hashes);  // 'check' is deleted here.
398
399  if (can_cache && MakeDatabaseAvailable()) {
400    // Cache the GetHash results in memory:
401    database_->CacheHashResults(prefixes, full_hashes);
402  }
403}
404
405void SafeBrowsingService::HandleChunk(const std::string& list,
406                                      SBChunkList* chunks) {
407  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
408  DCHECK(enabled_);
409  safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
410      this, &SafeBrowsingService::HandleChunkForDatabase, list, chunks));
411}
412
413void SafeBrowsingService::HandleChunkDelete(
414    std::vector<SBChunkDelete>* chunk_deletes) {
415  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
416  DCHECK(enabled_);
417  safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
418      this, &SafeBrowsingService::DeleteChunks, chunk_deletes));
419}
420
421void SafeBrowsingService::UpdateStarted() {
422  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
423  DCHECK(enabled_);
424  DCHECK(!update_in_progress_);
425  update_in_progress_ = true;
426  safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
427      this, &SafeBrowsingService::GetAllChunksFromDatabase));
428}
429
430void SafeBrowsingService::UpdateFinished(bool update_succeeded) {
431  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
432  DCHECK(enabled_);
433  if (update_in_progress_) {
434    update_in_progress_ = false;
435    safe_browsing_thread_->message_loop()->PostTask(FROM_HERE,
436        NewRunnableMethod(this,
437                          &SafeBrowsingService::DatabaseUpdateFinished,
438                          update_succeeded));
439  }
440}
441
442bool SafeBrowsingService::IsUpdateInProgress() const {
443  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
444  return update_in_progress_;
445}
446
447void SafeBrowsingService::OnBlockingPageDone(
448    const std::vector<UnsafeResource>& resources,
449    bool proceed) {
450  for (std::vector<UnsafeResource>::const_iterator iter = resources.begin();
451       iter != resources.end(); ++iter) {
452    const UnsafeResource& resource = *iter;
453    NotifyClientBlockingComplete(resource.client, proceed);
454
455    if (proceed) {
456      // Whitelist this domain and warning type for the given tab.
457      WhiteListedEntry entry;
458      entry.render_process_host_id = resource.render_process_host_id;
459      entry.render_view_id = resource.render_view_id;
460      entry.domain = net::RegistryControlledDomainService::GetDomainAndRegistry(
461            resource.url);
462      entry.result = resource.threat_type;
463      white_listed_entries_.push_back(entry);
464    }
465  }
466}
467
468void SafeBrowsingService::OnNewMacKeys(const std::string& client_key,
469                                       const std::string& wrapped_key) {
470  PrefService* prefs = g_browser_process->local_state();
471  if (prefs) {
472    prefs->SetString(prefs::kSafeBrowsingClientKey, client_key);
473    prefs->SetString(prefs::kSafeBrowsingWrappedKey, wrapped_key);
474  }
475}
476
477void SafeBrowsingService::OnEnable(bool enabled) {
478  if (enabled)
479    Start();
480  else
481    ShutDown();
482}
483
484// static
485void SafeBrowsingService::RegisterPrefs(PrefService* prefs) {
486  prefs->RegisterStringPref(prefs::kSafeBrowsingClientKey, "");
487  prefs->RegisterStringPref(prefs::kSafeBrowsingWrappedKey, "");
488}
489
490void SafeBrowsingService::CloseDatabase() {
491  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
492
493  // Cases to avoid:
494  //  * If |closing_database_| is true, continuing will queue up a second
495  //    request, |closing_database_| will be reset after handling the first
496  //    request, and if any functions on the db thread recreate the database, we
497  //    could start using it on the IO thread and then have the second request
498  //    handler delete it out from under us.
499  //  * If |database_| is NULL, then either no creation request is in flight, in
500  //    which case we don't need to do anything, or one is in flight, in which
501  //    case the database will be recreated before our deletion request is
502  //    handled, and could be used on the IO thread in that time period, leading
503  //    to the same problem as above.
504  //  * If |queued_checks_| is non-empty and |database_| is non-NULL, we're
505  //    about to be called back (in DatabaseLoadComplete()).  This will call
506  //    CheckUrl(), which will want the database.  Closing the database here
507  //    would lead to an infinite loop in DatabaseLoadComplete(), and even if it
508  //    didn't, it would be pointless since we'd just want to recreate.
509  //
510  // The first two cases above are handled by checking DatabaseAvailable().
511  if (!DatabaseAvailable() || !queued_checks_.empty())
512    return;
513
514  closing_database_ = true;
515  if (safe_browsing_thread_.get()) {
516    safe_browsing_thread_->message_loop()->PostTask(FROM_HERE,
517        NewRunnableMethod(this, &SafeBrowsingService::OnCloseDatabase));
518  }
519}
520
521void SafeBrowsingService::ResetDatabase() {
522  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
523  DCHECK(enabled_);
524  safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
525      this, &SafeBrowsingService::OnResetDatabase));
526}
527
528void SafeBrowsingService::LogPauseDelay(base::TimeDelta time) {
529  UMA_HISTOGRAM_LONG_TIMES("SB2.Delay", time);
530}
531
532SafeBrowsingService::~SafeBrowsingService() {
533  // We should have already been shut down.  If we're still enabled, then the
534  // database isn't going to be closed properly, which could lead to corruption.
535  DCHECK(!enabled_);
536}
537
538void SafeBrowsingService::OnIOInitialize(
539    const std::string& client_key,
540    const std::string& wrapped_key,
541    net::URLRequestContextGetter* request_context_getter) {
542  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
543  enabled_ = true;
544
545  MakeDatabaseAvailable();
546
547  // On Windows, get the safe browsing client name from the browser
548  // distribution classes in installer util. These classes don't yet have
549  // an analog on non-Windows builds so just keep the name specified here.
550#if defined(OS_WIN)
551  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
552  std::string client_name(dist->GetSafeBrowsingName());
553#else
554#if defined(GOOGLE_CHROME_BUILD)
555  std::string client_name("googlechrome");
556#else
557  std::string client_name("chromium");
558#endif
559#endif
560  CommandLine* cmdline = CommandLine::ForCurrentProcess();
561  bool disable_auto_update =
562      cmdline->HasSwitch(switches::kSbDisableAutoUpdate) ||
563      cmdline->HasSwitch(switches::kDisableBackgroundNetworking);
564  std::string info_url_prefix =
565      cmdline->HasSwitch(switches::kSbInfoURLPrefix) ?
566      cmdline->GetSwitchValueASCII(switches::kSbInfoURLPrefix) :
567      kSbDefaultInfoURLPrefix;
568  std::string mackey_url_prefix =
569      cmdline->HasSwitch(switches::kSbMacKeyURLPrefix) ?
570      cmdline->GetSwitchValueASCII(switches::kSbMacKeyURLPrefix) :
571      kSbDefaultMacKeyURLPrefix;
572
573  DCHECK(!protocol_manager_);
574  protocol_manager_ =
575      SafeBrowsingProtocolManager::Create(this,
576                                          client_name,
577                                          client_key,
578                                          wrapped_key,
579                                          request_context_getter,
580                                          info_url_prefix,
581                                          mackey_url_prefix,
582                                          disable_auto_update);
583
584  protocol_manager_->Initialize();
585}
586
587void SafeBrowsingService::OnIOShutdown() {
588  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
589  if (!enabled_)
590    return;
591
592  enabled_ = false;
593
594  // This cancels all in-flight GetHash requests.
595  delete protocol_manager_;
596  protocol_manager_ = NULL;
597
598  // Delete queued checks, calling back any clients with 'SAFE'.
599  // If we don't do this here we may fail to close the database below.
600  while (!queued_checks_.empty()) {
601    QueuedCheck queued = queued_checks_.front();
602    if (queued.client) {
603      SafeBrowsingCheck sb_check;
604      sb_check.urls.push_back(queued.url);
605      sb_check.client = queued.client;
606      sb_check.result = SAFE;
607      queued.client->OnSafeBrowsingResult(sb_check);
608    }
609    queued_checks_.pop_front();
610  }
611
612  // Close the database.  We don't simply DeleteSoon() because if a close is
613  // already pending, we'll double-free, and we don't set |database_| to NULL
614  // because if there is still anything running on the db thread, it could
615  // create a new database object (via GetDatabase()) that would then leak.
616  CloseDatabase();
617
618  // Flush the database thread. Any in-progress database check results will be
619  // ignored and cleaned up below.
620  //
621  // Note that to avoid leaking the database, we rely on the fact that no new
622  // tasks will be added to the db thread between the call above and this one.
623  // See comments on the declaration of |safe_browsing_thread_|.
624  {
625    // A ScopedAllowIO object is required to join the thread when calling Stop.
626    // See http://crbug.com/72696.
627    base::ThreadRestrictions::ScopedAllowIO allow_io_for_thread_join;
628    safe_browsing_thread_.reset();
629  }
630
631  // Delete pending checks, calling back any clients with 'SAFE'.  We have
632  // to do this after the db thread returns because methods on it can have
633  // copies of these pointers, so deleting them might lead to accessing garbage.
634  for (CurrentChecks::iterator it = checks_.begin();
635       it != checks_.end(); ++it) {
636    SafeBrowsingCheck* check = *it;
637    if (check->client) {
638      check->result = SAFE;
639      check->client->OnSafeBrowsingResult(*check);
640    }
641    if (check->timeout_task)
642      check->timeout_task->Cancel();
643  }
644  STLDeleteElements(&checks_);
645
646  gethash_requests_.clear();
647}
648
649bool SafeBrowsingService::DatabaseAvailable() const {
650  base::AutoLock lock(database_lock_);
651  return !closing_database_ && (database_ != NULL);
652}
653
654bool SafeBrowsingService::MakeDatabaseAvailable() {
655  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
656  DCHECK(enabled_);
657  if (DatabaseAvailable())
658    return true;
659  safe_browsing_thread_->message_loop()->PostTask(FROM_HERE,
660      NewRunnableMethod(this, &SafeBrowsingService::GetDatabase));
661  return false;
662}
663
664SafeBrowsingDatabase* SafeBrowsingService::GetDatabase() {
665  DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
666  if (database_)
667    return database_;
668
669  FilePath path;
670  bool result = PathService::Get(chrome::DIR_USER_DATA, &path);
671  DCHECK(result);
672  path = path.Append(chrome::kSafeBrowsingBaseFilename);
673
674  const base::TimeTicks before = base::TimeTicks::Now();
675
676  SafeBrowsingDatabase* database =
677      SafeBrowsingDatabase::Create(enable_download_protection_,
678                                   enable_csd_whitelist_);
679
680  database->Init(path);
681  {
682    // Acquiring the lock here guarantees correct ordering between the writes to
683    // the new database object above, and the setting of |databse_| below.
684    base::AutoLock lock(database_lock_);
685    database_ = database;
686  }
687
688  BrowserThread::PostTask(
689      BrowserThread::IO, FROM_HERE,
690      NewRunnableMethod(this, &SafeBrowsingService::DatabaseLoadComplete));
691
692  UMA_HISTOGRAM_TIMES("SB2.DatabaseOpen", base::TimeTicks::Now() - before);
693  return database_;
694}
695
696void SafeBrowsingService::OnCheckDone(SafeBrowsingCheck* check) {
697  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
698
699  if (!enabled_)
700    return;
701
702  // If the service has been shut down, |check| should have been deleted.
703  DCHECK(checks_.find(check) != checks_.end());
704
705  if (check->client && check->need_get_hash) {
706    // We have a partial match so we need to query Google for the full hash.
707    // Clean up will happen in HandleGetHashResults.
708
709    // See if we have a GetHash request already in progress for this particular
710    // prefix. If so, we just append ourselves to the list of interested parties
711    // when the results arrive. We only do this for checks involving one prefix,
712    // since that is the common case (multiple prefixes will issue the request
713    // as normal).
714    if (check->prefix_hits.size() == 1) {
715      SBPrefix prefix = check->prefix_hits[0];
716      GetHashRequests::iterator it = gethash_requests_.find(prefix);
717      if (it != gethash_requests_.end()) {
718        // There's already a request in progress.
719        it->second.push_back(check);
720        return;
721      }
722
723      // No request in progress, so we're the first for this prefix.
724      GetHashRequestors requestors;
725      requestors.push_back(check);
726      gethash_requests_[prefix] = requestors;
727    }
728
729    // Reset the start time so that we can measure the network time without the
730    // database time.
731    check->start = base::TimeTicks::Now();
732    protocol_manager_->GetFullHash(check, check->prefix_hits);
733  } else {
734    // We may have cached results for previous GetHash queries.  Since
735    // this data comes from cache, don't histogram hits.
736    HandleOneCheck(check, check->full_hits);
737  }
738}
739
740void SafeBrowsingService::GetAllChunksFromDatabase() {
741  DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
742
743  bool database_error = true;
744  std::vector<SBListChunkRanges> lists;
745  DCHECK(!database_update_in_progress_);
746  database_update_in_progress_ = true;
747  GetDatabase();  // This guarantees that |database_| is non-NULL.
748  if (database_->UpdateStarted(&lists)) {
749    database_error = false;
750  } else {
751    database_->UpdateFinished(false);
752  }
753
754  BrowserThread::PostTask(
755      BrowserThread::IO, FROM_HERE,
756      NewRunnableMethod(
757          this, &SafeBrowsingService::OnGetAllChunksFromDatabase, lists,
758          database_error));
759}
760
761void SafeBrowsingService::OnGetAllChunksFromDatabase(
762    const std::vector<SBListChunkRanges>& lists, bool database_error) {
763  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
764  if (enabled_)
765    protocol_manager_->OnGetChunksComplete(lists, database_error);
766}
767
768void SafeBrowsingService::OnChunkInserted() {
769  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
770  if (enabled_)
771    protocol_manager_->OnChunkInserted();
772}
773
774void SafeBrowsingService::DatabaseLoadComplete() {
775  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
776  if (!enabled_)
777    return;
778
779  HISTOGRAM_COUNTS("SB.QueueDepth", queued_checks_.size());
780  if (queued_checks_.empty())
781    return;
782
783  // If the database isn't already available, calling CheckUrl() in the loop
784  // below will add the check back to the queue, and we'll infinite-loop.
785  DCHECK(DatabaseAvailable());
786  while (!queued_checks_.empty()) {
787    QueuedCheck check = queued_checks_.front();
788    DCHECK(!check.start.is_null());
789    HISTOGRAM_TIMES("SB.QueueDelay", base::TimeTicks::Now() - check.start);
790    // If CheckUrl() determines the URL is safe immediately, it doesn't call the
791    // client's handler function (because normally it's being directly called by
792    // the client).  Since we're not the client, we have to convey this result.
793    if (check.client && CheckBrowseUrl(check.url, check.client)) {
794      SafeBrowsingCheck sb_check;
795      sb_check.urls.push_back(check.url);
796      sb_check.client = check.client;
797      sb_check.result = SAFE;
798      check.client->OnSafeBrowsingResult(sb_check);
799    }
800    queued_checks_.pop_front();
801  }
802}
803
804void SafeBrowsingService::HandleChunkForDatabase(
805    const std::string& list_name, SBChunkList* chunks) {
806  DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
807  if (chunks) {
808    GetDatabase()->InsertChunks(list_name, *chunks);
809    delete chunks;
810  }
811  BrowserThread::PostTask(
812      BrowserThread::IO, FROM_HERE,
813      NewRunnableMethod(this, &SafeBrowsingService::OnChunkInserted));
814}
815
816void SafeBrowsingService::DeleteChunks(
817    std::vector<SBChunkDelete>* chunk_deletes) {
818  DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
819  if (chunk_deletes) {
820    GetDatabase()->DeleteChunks(*chunk_deletes);
821    delete chunk_deletes;
822  }
823}
824
825SafeBrowsingService::UrlCheckResult SafeBrowsingService::GetResultFromListname(
826    const std::string& list_name) {
827  if (safe_browsing_util::IsPhishingList(list_name)) {
828    return URL_PHISHING;
829  }
830
831  if (safe_browsing_util::IsMalwareList(list_name)) {
832    return URL_MALWARE;
833  }
834
835  if (safe_browsing_util::IsBadbinurlList(list_name)) {
836    return BINARY_MALWARE_URL;
837  }
838
839  if (safe_browsing_util::IsBadbinhashList(list_name)) {
840    return BINARY_MALWARE_HASH;
841  }
842
843  DVLOG(1) << "Unknown safe browsing list " << list_name;
844  return SAFE;
845}
846
847void SafeBrowsingService::NotifyClientBlockingComplete(Client* client,
848                                                       bool proceed) {
849  client->OnBlockingPageComplete(proceed);
850}
851
852void SafeBrowsingService::DatabaseUpdateFinished(bool update_succeeded) {
853  DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
854  GetDatabase()->UpdateFinished(update_succeeded);
855  DCHECK(database_update_in_progress_);
856  database_update_in_progress_ = false;
857}
858
859void SafeBrowsingService::Start() {
860  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
861  DCHECK(!safe_browsing_thread_.get());
862  safe_browsing_thread_.reset(new base::Thread("Chrome_SafeBrowsingThread"));
863  if (!safe_browsing_thread_->Start())
864    return;
865
866  // Retrieve client MAC keys.
867  PrefService* local_state = g_browser_process->local_state();
868  DCHECK(local_state);
869  std::string client_key, wrapped_key;
870  if (local_state) {
871    client_key =
872      local_state->GetString(prefs::kSafeBrowsingClientKey);
873    wrapped_key =
874      local_state->GetString(prefs::kSafeBrowsingWrappedKey);
875  }
876
877  // We will issue network fetches using the default profile's request context.
878  scoped_refptr<net::URLRequestContextGetter> request_context_getter(
879      GetDefaultProfile()->GetRequestContext());
880
881  CommandLine* cmdline = CommandLine::ForCurrentProcess();
882  enable_download_protection_ =
883      !cmdline->HasSwitch(switches::kSbDisableDownloadProtection);
884
885  // We only download the csd-whitelist if client-side phishing detection is
886  // enabled and if the user has opted in with stats collection.  Note: we
887  // cannot check whether the metrics_service() object is created because it
888  // may be initialized after this method is called.
889#ifdef OS_CHROMEOS
890  // Client-side detection is disabled on ChromeOS for now, so don't bother
891  // downloading the whitelist.
892  enable_csd_whitelist_ = false;
893#else
894  enable_csd_whitelist_ =
895      (!cmdline->HasSwitch(switches::kDisableClientSidePhishingDetection) &&
896       local_state && local_state->GetBoolean(prefs::kMetricsReportingEnabled));
897#endif
898
899  BrowserThread::PostTask(
900      BrowserThread::IO, FROM_HERE,
901      NewRunnableMethod(
902          this, &SafeBrowsingService::OnIOInitialize, client_key, wrapped_key,
903          request_context_getter));
904}
905
906void SafeBrowsingService::OnCloseDatabase() {
907  DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
908  DCHECK(closing_database_);
909
910  // Because |closing_database_| is true, nothing on the IO thread will be
911  // accessing the database, so it's safe to delete and then NULL the pointer.
912  delete database_;
913  database_ = NULL;
914
915  // Acquiring the lock here guarantees correct ordering between the resetting
916  // of |database_| above and of |closing_database_| below, which ensures there
917  // won't be a window during which the IO thread falsely believes the database
918  // is available.
919  base::AutoLock lock(database_lock_);
920  closing_database_ = false;
921}
922
923void SafeBrowsingService::OnResetDatabase() {
924  DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
925  GetDatabase()->ResetDatabase();
926}
927
928void SafeBrowsingService::CacheHashResults(
929  const std::vector<SBPrefix>& prefixes,
930  const std::vector<SBFullHashResult>& full_hashes) {
931  DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
932  GetDatabase()->CacheHashResults(prefixes, full_hashes);
933}
934
935void SafeBrowsingService::OnHandleGetHashResults(
936    SafeBrowsingCheck* check,
937    const std::vector<SBFullHashResult>& full_hashes) {
938  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
939  bool is_download = check->is_download;
940  SBPrefix prefix = check->prefix_hits[0];
941  GetHashRequests::iterator it = gethash_requests_.find(prefix);
942  if (check->prefix_hits.size() > 1 || it == gethash_requests_.end()) {
943    const bool hit = HandleOneCheck(check, full_hashes);
944    RecordGetHashCheckStatus(hit, is_download, full_hashes);
945    return;
946  }
947
948  // Call back all interested parties, noting if any has a hit.
949  GetHashRequestors& requestors = it->second;
950  bool hit = false;
951  for (GetHashRequestors::iterator r = requestors.begin();
952       r != requestors.end(); ++r) {
953    if (HandleOneCheck(*r, full_hashes))
954      hit = true;
955  }
956  RecordGetHashCheckStatus(hit, is_download, full_hashes);
957
958  gethash_requests_.erase(it);
959}
960
961bool SafeBrowsingService::HandleOneCheck(
962    SafeBrowsingCheck* check,
963    const std::vector<SBFullHashResult>& full_hashes) {
964  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
965  DCHECK(check);
966
967  // Always calculate the index, for recording hits.
968  int index = -1;
969  if (!check->urls.empty()) {
970    for (size_t i = 0; i < check->urls.size(); ++i) {
971      index = safe_browsing_util::GetUrlHashIndex(check->urls[i], full_hashes);
972      if (index != -1)
973        break;
974    }
975  } else {
976    index = safe_browsing_util::GetHashIndex(*(check->full_hash), full_hashes);
977  }
978
979  // |client| is NULL if the request was cancelled.
980  if (check->client) {
981    check->result = SAFE;
982    if (index != -1)
983      check->result = GetResultFromListname(full_hashes[index].list_name);
984  }
985  SafeBrowsingCheckDone(check);
986  return (index != -1);
987}
988
989void SafeBrowsingService::DoDisplayBlockingPage(
990    const UnsafeResource& resource) {
991  // The tab might have been closed.
992  TabContents* wc =
993      tab_util::GetTabContentsByID(resource.render_process_host_id,
994                                   resource.render_view_id);
995
996  if (!wc) {
997    // The tab is gone and we did not have a chance at showing the interstitial.
998    // Just act as "Don't Proceed" was chosen.
999    std::vector<UnsafeResource> resources;
1000    resources.push_back(resource);
1001    BrowserThread::PostTask(
1002      BrowserThread::IO, FROM_HERE,
1003      NewRunnableMethod(
1004          this, &SafeBrowsingService::OnBlockingPageDone, resources, false));
1005    return;
1006  }
1007
1008  if (resource.threat_type != SafeBrowsingService::SAFE && CanReportStats()) {
1009    GURL page_url = wc->GetURL();
1010    GURL referrer_url;
1011    NavigationEntry* entry = wc->controller().GetActiveEntry();
1012    if (entry)
1013      referrer_url = entry->referrer();
1014    bool is_subresource = resource.resource_type != ResourceType::MAIN_FRAME;
1015
1016    // When the malicious url is on the main frame, and resource.original_url
1017    // is not the same as the resource.url, that means we have a redirect from
1018    // resource.original_url to resource.url.
1019    // Also, at this point, page_url points to the _previous_ page that we
1020    // were on. We replace page_url with resource.original_url and referrer
1021    // with page_url.
1022    if (!is_subresource &&
1023        !resource.original_url.is_empty() &&
1024        resource.original_url != resource.url) {
1025      referrer_url = page_url;
1026      page_url = resource.original_url;
1027    }
1028    ReportSafeBrowsingHit(resource.url, page_url, referrer_url, is_subresource,
1029                          resource.threat_type, std::string() /* post_data */);
1030  }
1031
1032  SafeBrowsingBlockingPage::ShowBlockingPage(this, resource);
1033}
1034
1035// A safebrowsing hit is sent after a blocking page for malware/phishing
1036// or after the warning dialog for download urls, only for UMA users.
1037void SafeBrowsingService::ReportSafeBrowsingHit(
1038    const GURL& malicious_url,
1039    const GURL& page_url,
1040    const GURL& referrer_url,
1041    bool is_subresource,
1042    SafeBrowsingService::UrlCheckResult threat_type,
1043    const std::string& post_data) {
1044  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1045  if (!CanReportStats())
1046    return;
1047
1048  BrowserThread::PostTask(
1049      BrowserThread::IO, FROM_HERE,
1050      NewRunnableMethod(
1051          this,
1052          &SafeBrowsingService::ReportSafeBrowsingHitOnIOThread,
1053          malicious_url,
1054          page_url,
1055          referrer_url,
1056          is_subresource,
1057          threat_type,
1058          post_data));
1059}
1060
1061void SafeBrowsingService::ReportSafeBrowsingHitOnIOThread(
1062    const GURL& malicious_url,
1063    const GURL& page_url,
1064    const GURL& referrer_url,
1065    bool is_subresource,
1066    SafeBrowsingService::UrlCheckResult threat_type,
1067    const std::string& post_data) {
1068  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1069  if (!enabled_)
1070    return;
1071
1072  DVLOG(1) << "ReportSafeBrowsingHit: " << malicious_url << " " << page_url
1073           << " " << referrer_url << " " << is_subresource << " "
1074           << threat_type;
1075  protocol_manager_->ReportSafeBrowsingHit(malicious_url, page_url,
1076                                           referrer_url, is_subresource,
1077                                           threat_type, post_data);
1078}
1079
1080// If the user had opted-in to send MalwareDetails, this gets called
1081// when the report is ready.
1082void SafeBrowsingService::SendSerializedMalwareDetails(
1083    const std::string& serialized) {
1084  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1085  if (!serialized.empty()) {
1086    DVLOG(1) << "Sending serialized malware details.";
1087    protocol_manager_->ReportMalwareDetails(serialized);
1088  }
1089}
1090
1091void SafeBrowsingService::CheckDownloadHashOnSBThread(
1092    SafeBrowsingCheck* check) {
1093  DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
1094  DCHECK(enable_download_protection_);
1095
1096  if (!database_->ContainsDownloadHashPrefix(check->full_hash->prefix)) {
1097    // Good, we don't have hash for this url prefix.
1098    check->result = SAFE;
1099    BrowserThread::PostTask(
1100        BrowserThread::IO, FROM_HERE,
1101        NewRunnableMethod(this,
1102                          &SafeBrowsingService::CheckDownloadHashDone,
1103                          check));
1104    return;
1105  }
1106
1107  check->need_get_hash = true;
1108  check->prefix_hits.push_back(check->full_hash->prefix);
1109  BrowserThread::PostTask(
1110      BrowserThread::IO, FROM_HERE,
1111      NewRunnableMethod(this, &SafeBrowsingService::OnCheckDone, check));
1112}
1113
1114void SafeBrowsingService::CheckDownloadUrlOnSBThread(SafeBrowsingCheck* check) {
1115  DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
1116  DCHECK(enable_download_protection_);
1117
1118  std::vector<SBPrefix> prefix_hits;
1119
1120  if (!database_->ContainsDownloadUrl(check->urls, &prefix_hits)) {
1121    // Good, we don't have hash for this url prefix.
1122    check->result = SAFE;
1123    BrowserThread::PostTask(
1124        BrowserThread::IO, FROM_HERE,
1125        NewRunnableMethod(this,
1126                          &SafeBrowsingService::CheckDownloadUrlDone,
1127                          check));
1128    return;
1129  }
1130
1131  check->need_get_hash = true;
1132  check->prefix_hits.clear();
1133  check->prefix_hits = prefix_hits;
1134  BrowserThread::PostTask(
1135      BrowserThread::IO, FROM_HERE,
1136      NewRunnableMethod(this, &SafeBrowsingService::OnCheckDone, check));
1137}
1138
1139void SafeBrowsingService::TimeoutCallback(SafeBrowsingCheck* check) {
1140  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1141  DCHECK(check);
1142
1143  if (!enabled_)
1144    return;
1145
1146  DCHECK(checks_.find(check) != checks_.end());
1147  DCHECK_EQ(check->result, SAFE);
1148  if (check->client) {
1149    check->client->OnSafeBrowsingResult(*check);
1150    check->client = NULL;
1151  }
1152  check->timeout_task = NULL;
1153}
1154
1155void SafeBrowsingService::CheckDownloadUrlDone(SafeBrowsingCheck* check) {
1156  DCHECK(enable_download_protection_);
1157  SafeBrowsingCheckDone(check);
1158}
1159
1160void SafeBrowsingService::CheckDownloadHashDone(SafeBrowsingCheck* check) {
1161  DCHECK(enable_download_protection_);
1162  SafeBrowsingCheckDone(check);
1163}
1164
1165void SafeBrowsingService::SafeBrowsingCheckDone(SafeBrowsingCheck* check) {
1166  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1167  DCHECK(check);
1168
1169  if (!enabled_)
1170    return;
1171
1172  VLOG(1) << "SafeBrowsingCheckDone: " << check->result;
1173  DCHECK(checks_.find(check) != checks_.end());
1174  if (check->client)
1175    check->client->OnSafeBrowsingResult(*check);
1176  if (check->timeout_task)
1177    check->timeout_task->Cancel();
1178  checks_.erase(check);
1179  delete check;
1180}
1181
1182void SafeBrowsingService::StartDownloadCheck(SafeBrowsingCheck* check,
1183                                             Client* client,
1184                                             CancelableTask* task,
1185                                             int64 timeout_ms) {
1186  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1187  check->client = client;
1188  check->result = SAFE;
1189  check->is_download = true;
1190  check->timeout_task =
1191      NewRunnableMethod(this, &SafeBrowsingService::TimeoutCallback, check);
1192  checks_.insert(check);
1193
1194  safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, task);
1195
1196  MessageLoop::current()->PostDelayedTask(
1197      FROM_HERE, check->timeout_task, timeout_ms);
1198}
1199