// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/content_settings/content_settings_policy_provider.h" #include <string> #include <vector> #include "base/command_line.h" #include "chrome/browser/content_settings/content_settings_details.h" #include "chrome/browser/content_settings/content_settings_pattern.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/prefs/scoped_user_pref_update.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/pref_names.h" #include "content/browser/browser_thread.h" #include "content/common/notification_details.h" #include "content/common/notification_service.h" #include "content/common/notification_source.h" #include "webkit/plugins/npapi/plugin_group.h" #include "webkit/plugins/npapi/plugin_list.h" namespace { // Base pref path of the prefs that contain the managed default content // settings values. const std::string kManagedSettings = "profile.managed_default_content_settings"; // The preferences used to manage ContentSettingsTypes. const char* kPrefToManageType[CONTENT_SETTINGS_NUM_TYPES] = { prefs::kManagedDefaultCookiesSetting, prefs::kManagedDefaultImagesSetting, prefs::kManagedDefaultJavaScriptSetting, prefs::kManagedDefaultPluginsSetting, prefs::kManagedDefaultPopupsSetting, NULL, // Not used for Geolocation NULL, // Not used for Notifications }; struct PrefsForManagedContentSettingsMapEntry { const char* pref_name; ContentSettingsType content_type; ContentSetting setting; }; const PrefsForManagedContentSettingsMapEntry kPrefsForManagedContentSettingsMap[] = { { prefs::kManagedCookiesAllowedForUrls, CONTENT_SETTINGS_TYPE_COOKIES, CONTENT_SETTING_ALLOW }, { prefs::kManagedCookiesSessionOnlyForUrls, CONTENT_SETTINGS_TYPE_COOKIES, CONTENT_SETTING_SESSION_ONLY }, { prefs::kManagedCookiesBlockedForUrls, CONTENT_SETTINGS_TYPE_COOKIES, CONTENT_SETTING_BLOCK }, { prefs::kManagedImagesAllowedForUrls, CONTENT_SETTINGS_TYPE_IMAGES, CONTENT_SETTING_ALLOW }, { prefs::kManagedImagesBlockedForUrls, CONTENT_SETTINGS_TYPE_IMAGES, CONTENT_SETTING_BLOCK }, { prefs::kManagedJavaScriptAllowedForUrls, CONTENT_SETTINGS_TYPE_JAVASCRIPT, CONTENT_SETTING_ALLOW }, { prefs::kManagedJavaScriptBlockedForUrls, CONTENT_SETTINGS_TYPE_JAVASCRIPT, CONTENT_SETTING_BLOCK }, { prefs::kManagedPluginsAllowedForUrls, CONTENT_SETTINGS_TYPE_PLUGINS, CONTENT_SETTING_ALLOW }, { prefs::kManagedPluginsBlockedForUrls, CONTENT_SETTINGS_TYPE_PLUGINS, CONTENT_SETTING_BLOCK }, { prefs::kManagedPopupsAllowedForUrls, CONTENT_SETTINGS_TYPE_POPUPS, CONTENT_SETTING_ALLOW }, { prefs::kManagedPopupsBlockedForUrls, CONTENT_SETTINGS_TYPE_POPUPS, CONTENT_SETTING_BLOCK } }; } // namespace namespace content_settings { PolicyDefaultProvider::PolicyDefaultProvider(Profile* profile) : profile_(profile), is_off_the_record_(profile_->IsOffTheRecord()) { PrefService* prefs = profile->GetPrefs(); // Read global defaults. DCHECK_EQ(arraysize(kPrefToManageType), static_cast<size_t>(CONTENT_SETTINGS_NUM_TYPES)); ReadManagedDefaultSettings(); pref_change_registrar_.Init(prefs); // The following preferences are only used to indicate if a // default-content-setting is managed and to hold the managed default-setting // value. If the value for any of the following perferences is set then the // corresponding default-content-setting is managed. These preferences exist // in parallel to the preference default-content-settings. If a // default-content-settings-type is managed any user defined excpetions // (patterns) for this type are ignored. pref_change_registrar_.Add(prefs::kManagedDefaultCookiesSetting, this); pref_change_registrar_.Add(prefs::kManagedDefaultImagesSetting, this); pref_change_registrar_.Add(prefs::kManagedDefaultJavaScriptSetting, this); pref_change_registrar_.Add(prefs::kManagedDefaultPluginsSetting, this); pref_change_registrar_.Add(prefs::kManagedDefaultPopupsSetting, this); notification_registrar_.Add(this, NotificationType::PROFILE_DESTROYED, Source<Profile>(profile_)); } PolicyDefaultProvider::~PolicyDefaultProvider() { UnregisterObservers(); } ContentSetting PolicyDefaultProvider::ProvideDefaultSetting( ContentSettingsType content_type) const { base::AutoLock auto_lock(lock_); return managed_default_content_settings_.settings[content_type]; } void PolicyDefaultProvider::UpdateDefaultSetting( ContentSettingsType content_type, ContentSetting setting) { } bool PolicyDefaultProvider::DefaultSettingIsManaged( ContentSettingsType content_type) const { base::AutoLock lock(lock_); if (managed_default_content_settings_.settings[content_type] != CONTENT_SETTING_DEFAULT) { return true; } else { return false; } } void PolicyDefaultProvider::ResetToDefaults() { } void PolicyDefaultProvider::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); if (type == NotificationType::PREF_CHANGED) { DCHECK_EQ(profile_->GetPrefs(), Source<PrefService>(source).ptr()); std::string* name = Details<std::string>(details).ptr(); if (*name == prefs::kManagedDefaultCookiesSetting) { UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES); } else if (*name == prefs::kManagedDefaultImagesSetting) { UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_IMAGES); } else if (*name == prefs::kManagedDefaultJavaScriptSetting) { UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_JAVASCRIPT); } else if (*name == prefs::kManagedDefaultPluginsSetting) { UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_PLUGINS); } else if (*name == prefs::kManagedDefaultPopupsSetting) { UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_POPUPS); } else { NOTREACHED() << "Unexpected preference observed"; return; } if (!is_off_the_record_) { NotifyObservers(ContentSettingsDetails( ContentSettingsPattern(), CONTENT_SETTINGS_TYPE_DEFAULT, "")); } } else if (type == NotificationType::PROFILE_DESTROYED) { DCHECK_EQ(profile_, Source<Profile>(source).ptr()); UnregisterObservers(); } else { NOTREACHED() << "Unexpected notification"; } } void PolicyDefaultProvider::UnregisterObservers() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); if (!profile_) return; pref_change_registrar_.RemoveAll(); notification_registrar_.Remove(this, NotificationType::PROFILE_DESTROYED, Source<Profile>(profile_)); profile_ = NULL; } void PolicyDefaultProvider::NotifyObservers( const ContentSettingsDetails& details) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); if (profile_ == NULL) return; NotificationService::current()->Notify( NotificationType::CONTENT_SETTINGS_CHANGED, Source<HostContentSettingsMap>(profile_->GetHostContentSettingsMap()), Details<const ContentSettingsDetails>(&details)); } void PolicyDefaultProvider::ReadManagedDefaultSettings() { for (size_t type = 0; type < arraysize(kPrefToManageType); ++type) { if (kPrefToManageType[type] == NULL) { continue; } UpdateManagedDefaultSetting(ContentSettingsType(type)); } } void PolicyDefaultProvider::UpdateManagedDefaultSetting( ContentSettingsType type) { // If a pref to manage a default-content-setting was not set (NOTICE: // "HasPrefPath" returns false if no value was set for a registered pref) then // the default value of the preference is used. The default value of a // preference to manage a default-content-settings is CONTENT_SETTING_DEFAULT. // This indicates that no managed value is set. If a pref was set, than it // MUST be managed. PrefService* prefs = profile_->GetPrefs(); DCHECK(!prefs->HasPrefPath(kPrefToManageType[type]) || prefs->IsManagedPreference(kPrefToManageType[type])); base::AutoLock auto_lock(lock_); managed_default_content_settings_.settings[type] = IntToContentSetting( prefs->GetInteger(kPrefToManageType[type])); } // static void PolicyDefaultProvider::RegisterUserPrefs(PrefService* prefs) { // Preferences for default content setting policies. A policy is not set of // the corresponding preferences below is set to CONTENT_SETTING_DEFAULT. prefs->RegisterIntegerPref(prefs::kManagedDefaultCookiesSetting, CONTENT_SETTING_DEFAULT); prefs->RegisterIntegerPref(prefs::kManagedDefaultImagesSetting, CONTENT_SETTING_DEFAULT); prefs->RegisterIntegerPref(prefs::kManagedDefaultJavaScriptSetting, CONTENT_SETTING_DEFAULT); prefs->RegisterIntegerPref(prefs::kManagedDefaultPluginsSetting, CONTENT_SETTING_DEFAULT); prefs->RegisterIntegerPref(prefs::kManagedDefaultPopupsSetting, CONTENT_SETTING_DEFAULT); } // //////////////////////////////////////////////////////////////////////////// // PolicyProvider // static void PolicyProvider::RegisterUserPrefs(PrefService* prefs) { prefs->RegisterListPref(prefs::kManagedCookiesAllowedForUrls); prefs->RegisterListPref(prefs::kManagedCookiesBlockedForUrls); prefs->RegisterListPref(prefs::kManagedCookiesSessionOnlyForUrls); prefs->RegisterListPref(prefs::kManagedImagesAllowedForUrls); prefs->RegisterListPref(prefs::kManagedImagesBlockedForUrls); prefs->RegisterListPref(prefs::kManagedJavaScriptAllowedForUrls); prefs->RegisterListPref(prefs::kManagedJavaScriptBlockedForUrls); prefs->RegisterListPref(prefs::kManagedPluginsAllowedForUrls); prefs->RegisterListPref(prefs::kManagedPluginsBlockedForUrls); prefs->RegisterListPref(prefs::kManagedPopupsAllowedForUrls); prefs->RegisterListPref(prefs::kManagedPopupsBlockedForUrls); } PolicyProvider::PolicyProvider(Profile* profile) : BaseProvider(profile->IsOffTheRecord()), profile_(profile) { Init(); } PolicyProvider::~PolicyProvider() { UnregisterObservers(); } void PolicyProvider::ReadManagedContentSettingsTypes( ContentSettingsType content_type) { PrefService* prefs = profile_->GetPrefs(); if (kPrefToManageType[content_type] == NULL) { content_type_is_managed_[content_type] = false; } else { content_type_is_managed_[content_type] = prefs->IsManagedPreference(kPrefToManageType[content_type]); } } void PolicyProvider::Init() { PrefService* prefs = profile_->GetPrefs(); ReadManagedContentSettings(false); for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) ReadManagedContentSettingsTypes(ContentSettingsType(i)); pref_change_registrar_.Init(prefs); pref_change_registrar_.Add(prefs::kManagedCookiesBlockedForUrls, this); pref_change_registrar_.Add(prefs::kManagedCookiesAllowedForUrls, this); pref_change_registrar_.Add(prefs::kManagedCookiesSessionOnlyForUrls, this); pref_change_registrar_.Add(prefs::kManagedImagesBlockedForUrls, this); pref_change_registrar_.Add(prefs::kManagedImagesAllowedForUrls, this); pref_change_registrar_.Add(prefs::kManagedJavaScriptBlockedForUrls, this); pref_change_registrar_.Add(prefs::kManagedJavaScriptAllowedForUrls, this); pref_change_registrar_.Add(prefs::kManagedPluginsBlockedForUrls, this); pref_change_registrar_.Add(prefs::kManagedPluginsAllowedForUrls, this); pref_change_registrar_.Add(prefs::kManagedPopupsBlockedForUrls, this); pref_change_registrar_.Add(prefs::kManagedPopupsAllowedForUrls, this); pref_change_registrar_.Add(prefs::kManagedDefaultCookiesSetting, this); pref_change_registrar_.Add(prefs::kManagedDefaultImagesSetting, this); pref_change_registrar_.Add(prefs::kManagedDefaultJavaScriptSetting, this); pref_change_registrar_.Add(prefs::kManagedDefaultPluginsSetting, this); pref_change_registrar_.Add(prefs::kManagedDefaultPopupsSetting, this); notification_registrar_.Add(this, NotificationType::PROFILE_DESTROYED, Source<Profile>(profile_)); } bool PolicyProvider::ContentSettingsTypeIsManaged( ContentSettingsType content_type) { return content_type_is_managed_[content_type]; } void PolicyProvider::GetContentSettingsFromPreferences( PrefService* prefs, ContentSettingsRules* rules) { for (size_t i = 0; i < arraysize(kPrefsForManagedContentSettingsMap); ++i) { const char* pref_name = kPrefsForManagedContentSettingsMap[i].pref_name; // Skip unset policies. if (!prefs->HasPrefPath(pref_name)) { VLOG(2) << "Skipping unset preference: " << pref_name; continue; } const PrefService::Preference* pref = prefs->FindPreference(pref_name); DCHECK(pref->IsManaged()); DCHECK_EQ(Value::TYPE_LIST, pref->GetType()); const ListValue* pattern_str_list = static_cast<const ListValue*>(pref->GetValue()); for (size_t j = 0; j < pattern_str_list->GetSize(); ++j) { std::string original_pattern_str; pattern_str_list->GetString(j, &original_pattern_str); ContentSettingsPattern pattern(original_pattern_str); // Ignore invalid patterns. if (!pattern.IsValid()) { VLOG(1) << "Ignoring invalid content settings pattern: " << pattern.AsString(); continue; } rules->push_back(MakeTuple( pattern, pattern, kPrefsForManagedContentSettingsMap[i].content_type, ProviderInterface::ResourceIdentifier(NO_RESOURCE_IDENTIFIER), kPrefsForManagedContentSettingsMap[i].setting)); } } } void PolicyProvider::ReadManagedContentSettings(bool overwrite) { ContentSettingsRules rules; PrefService* prefs = profile_->GetPrefs(); GetContentSettingsFromPreferences(prefs, &rules); { base::AutoLock auto_lock(lock()); HostContentSettings* content_settings_map = host_content_settings(); if (overwrite) content_settings_map->clear(); for (ContentSettingsRules::iterator rule = rules.begin(); rule != rules.end(); ++rule) { DispatchToMethod(this, &PolicyProvider::UpdateContentSettingsMap, *rule); } } } // Since the PolicyProvider is a read only content settings provider, all // methodes of the ProviderInterface that set or delete any settings do nothing. void PolicyProvider::SetContentSetting( const ContentSettingsPattern& requesting_pattern, const ContentSettingsPattern& embedding_pattern, ContentSettingsType content_type, const ResourceIdentifier& resource_identifier, ContentSetting content_setting) { } ContentSetting PolicyProvider::GetContentSetting( const GURL& requesting_url, const GURL& embedding_url, ContentSettingsType content_type, const ResourceIdentifier& resource_identifier) const { return BaseProvider::GetContentSetting( requesting_url, embedding_url, content_type, NO_RESOURCE_IDENTIFIER); } void PolicyProvider::ClearAllContentSettingsRules( ContentSettingsType content_type) { } void PolicyProvider::ResetToDefaults() { } void PolicyProvider::UnregisterObservers() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); if (!profile_) return; pref_change_registrar_.RemoveAll(); notification_registrar_.Remove(this, NotificationType::PROFILE_DESTROYED, Source<Profile>(profile_)); profile_ = NULL; } void PolicyProvider::NotifyObservers( const ContentSettingsDetails& details) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); if (profile_ == NULL) return; NotificationService::current()->Notify( NotificationType::CONTENT_SETTINGS_CHANGED, Source<HostContentSettingsMap>(profile_->GetHostContentSettingsMap()), Details<const ContentSettingsDetails>(&details)); } void PolicyProvider::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); if (type == NotificationType::PREF_CHANGED) { DCHECK_EQ(profile_->GetPrefs(), Source<PrefService>(source).ptr()); std::string* name = Details<std::string>(details).ptr(); if (*name == prefs::kManagedCookiesAllowedForUrls || *name == prefs::kManagedCookiesBlockedForUrls || *name == prefs::kManagedCookiesSessionOnlyForUrls || *name == prefs::kManagedImagesAllowedForUrls || *name == prefs::kManagedImagesBlockedForUrls || *name == prefs::kManagedJavaScriptAllowedForUrls || *name == prefs::kManagedJavaScriptBlockedForUrls || *name == prefs::kManagedPluginsAllowedForUrls || *name == prefs::kManagedPluginsBlockedForUrls || *name == prefs::kManagedPopupsAllowedForUrls || *name == prefs::kManagedPopupsBlockedForUrls) { ReadManagedContentSettings(true); NotifyObservers(ContentSettingsDetails( ContentSettingsPattern(), CONTENT_SETTINGS_TYPE_DEFAULT, "")); // We do not want to sent a notification when managed default content // settings change. The DefaultProvider will take care of that. We are // only a passive observer. // TODO(markusheintz): NOTICE: This is still work in progress and part of // a larger refactoring. The code will change and be much cleaner and // clearer in the end. } else if (*name == prefs::kManagedDefaultCookiesSetting) { ReadManagedContentSettingsTypes(CONTENT_SETTINGS_TYPE_COOKIES); } else if (*name == prefs::kManagedDefaultImagesSetting) { ReadManagedContentSettingsTypes(CONTENT_SETTINGS_TYPE_IMAGES); } else if (*name == prefs::kManagedDefaultJavaScriptSetting) { ReadManagedContentSettingsTypes(CONTENT_SETTINGS_TYPE_JAVASCRIPT); } else if (*name == prefs::kManagedDefaultPluginsSetting) { ReadManagedContentSettingsTypes(CONTENT_SETTINGS_TYPE_PLUGINS); } else if (*name == prefs::kManagedDefaultPopupsSetting) { ReadManagedContentSettingsTypes(CONTENT_SETTINGS_TYPE_POPUPS); } } else if (type == NotificationType::PROFILE_DESTROYED) { DCHECK_EQ(profile_, Source<Profile>(source).ptr()); UnregisterObservers(); } else { NOTREACHED() << "Unexpected notification"; } } } // namespace content_settings