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