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