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/content_settings/content_settings_policy_provider.h"
6
7#include <string>
8#include <vector>
9
10#include "base/command_line.h"
11#include "chrome/browser/content_settings/content_settings_details.h"
12#include "chrome/browser/content_settings/content_settings_pattern.h"
13#include "chrome/browser/prefs/pref_service.h"
14#include "chrome/browser/prefs/scoped_user_pref_update.h"
15#include "chrome/browser/profiles/profile.h"
16#include "chrome/common/pref_names.h"
17#include "content/browser/browser_thread.h"
18#include "content/common/notification_details.h"
19#include "content/common/notification_service.h"
20#include "content/common/notification_source.h"
21#include "webkit/plugins/npapi/plugin_group.h"
22#include "webkit/plugins/npapi/plugin_list.h"
23
24namespace {
25
26// Base pref path of the prefs that contain the managed default content
27// settings values.
28const std::string kManagedSettings =
29      "profile.managed_default_content_settings";
30
31// The preferences used to manage ContentSettingsTypes.
32const char* kPrefToManageType[CONTENT_SETTINGS_NUM_TYPES] = {
33  prefs::kManagedDefaultCookiesSetting,
34  prefs::kManagedDefaultImagesSetting,
35  prefs::kManagedDefaultJavaScriptSetting,
36  prefs::kManagedDefaultPluginsSetting,
37  prefs::kManagedDefaultPopupsSetting,
38  NULL,  // Not used for Geolocation
39  NULL,  // Not used for Notifications
40};
41
42struct PrefsForManagedContentSettingsMapEntry {
43  const char* pref_name;
44  ContentSettingsType content_type;
45  ContentSetting setting;
46};
47
48const PrefsForManagedContentSettingsMapEntry
49    kPrefsForManagedContentSettingsMap[] = {
50  {
51    prefs::kManagedCookiesAllowedForUrls,
52    CONTENT_SETTINGS_TYPE_COOKIES,
53    CONTENT_SETTING_ALLOW
54  }, {
55    prefs::kManagedCookiesSessionOnlyForUrls,
56    CONTENT_SETTINGS_TYPE_COOKIES,
57    CONTENT_SETTING_SESSION_ONLY
58  }, {
59    prefs::kManagedCookiesBlockedForUrls,
60    CONTENT_SETTINGS_TYPE_COOKIES,
61    CONTENT_SETTING_BLOCK
62  }, {
63    prefs::kManagedImagesAllowedForUrls,
64    CONTENT_SETTINGS_TYPE_IMAGES,
65    CONTENT_SETTING_ALLOW
66  }, {
67    prefs::kManagedImagesBlockedForUrls,
68    CONTENT_SETTINGS_TYPE_IMAGES,
69    CONTENT_SETTING_BLOCK
70  }, {
71    prefs::kManagedJavaScriptAllowedForUrls,
72    CONTENT_SETTINGS_TYPE_JAVASCRIPT,
73    CONTENT_SETTING_ALLOW
74  }, {
75    prefs::kManagedJavaScriptBlockedForUrls,
76    CONTENT_SETTINGS_TYPE_JAVASCRIPT,
77    CONTENT_SETTING_BLOCK
78  }, {
79    prefs::kManagedPluginsAllowedForUrls,
80    CONTENT_SETTINGS_TYPE_PLUGINS,
81    CONTENT_SETTING_ALLOW
82  }, {
83    prefs::kManagedPluginsBlockedForUrls,
84    CONTENT_SETTINGS_TYPE_PLUGINS,
85    CONTENT_SETTING_BLOCK
86  }, {
87    prefs::kManagedPopupsAllowedForUrls,
88    CONTENT_SETTINGS_TYPE_POPUPS,
89    CONTENT_SETTING_ALLOW
90  }, {
91    prefs::kManagedPopupsBlockedForUrls,
92    CONTENT_SETTINGS_TYPE_POPUPS,
93    CONTENT_SETTING_BLOCK
94  }
95};
96
97}  // namespace
98
99namespace content_settings {
100
101PolicyDefaultProvider::PolicyDefaultProvider(Profile* profile)
102    : profile_(profile),
103      is_off_the_record_(profile_->IsOffTheRecord()) {
104  PrefService* prefs = profile->GetPrefs();
105
106  // Read global defaults.
107  DCHECK_EQ(arraysize(kPrefToManageType),
108            static_cast<size_t>(CONTENT_SETTINGS_NUM_TYPES));
109  ReadManagedDefaultSettings();
110
111  pref_change_registrar_.Init(prefs);
112  // The following preferences are only used to indicate if a
113  // default-content-setting is managed and to hold the managed default-setting
114  // value. If the value for any of the following perferences is set then the
115  // corresponding default-content-setting is managed. These preferences exist
116  // in parallel to the preference default-content-settings.  If a
117  // default-content-settings-type is managed any user defined excpetions
118  // (patterns) for this type are ignored.
119  pref_change_registrar_.Add(prefs::kManagedDefaultCookiesSetting, this);
120  pref_change_registrar_.Add(prefs::kManagedDefaultImagesSetting, this);
121  pref_change_registrar_.Add(prefs::kManagedDefaultJavaScriptSetting, this);
122  pref_change_registrar_.Add(prefs::kManagedDefaultPluginsSetting, this);
123  pref_change_registrar_.Add(prefs::kManagedDefaultPopupsSetting, this);
124  notification_registrar_.Add(this, NotificationType::PROFILE_DESTROYED,
125                              Source<Profile>(profile_));
126}
127
128PolicyDefaultProvider::~PolicyDefaultProvider() {
129  UnregisterObservers();
130}
131
132ContentSetting PolicyDefaultProvider::ProvideDefaultSetting(
133    ContentSettingsType content_type) const {
134  base::AutoLock auto_lock(lock_);
135  return managed_default_content_settings_.settings[content_type];
136}
137
138void PolicyDefaultProvider::UpdateDefaultSetting(
139    ContentSettingsType content_type,
140    ContentSetting setting) {
141}
142
143bool PolicyDefaultProvider::DefaultSettingIsManaged(
144    ContentSettingsType content_type) const {
145  base::AutoLock lock(lock_);
146  if (managed_default_content_settings_.settings[content_type] !=
147      CONTENT_SETTING_DEFAULT) {
148    return true;
149  } else {
150    return false;
151  }
152}
153
154void PolicyDefaultProvider::ResetToDefaults() {
155}
156
157void PolicyDefaultProvider::Observe(NotificationType type,
158                                    const NotificationSource& source,
159                                    const NotificationDetails& details) {
160  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
161
162  if (type == NotificationType::PREF_CHANGED) {
163    DCHECK_EQ(profile_->GetPrefs(), Source<PrefService>(source).ptr());
164    std::string* name = Details<std::string>(details).ptr();
165    if (*name == prefs::kManagedDefaultCookiesSetting) {
166      UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_COOKIES);
167    } else if (*name == prefs::kManagedDefaultImagesSetting) {
168      UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_IMAGES);
169    } else if (*name == prefs::kManagedDefaultJavaScriptSetting) {
170      UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_JAVASCRIPT);
171    } else if (*name == prefs::kManagedDefaultPluginsSetting) {
172      UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_PLUGINS);
173    } else if (*name == prefs::kManagedDefaultPopupsSetting) {
174      UpdateManagedDefaultSetting(CONTENT_SETTINGS_TYPE_POPUPS);
175    } else {
176      NOTREACHED() << "Unexpected preference observed";
177      return;
178    }
179
180    if (!is_off_the_record_) {
181      NotifyObservers(ContentSettingsDetails(
182            ContentSettingsPattern(), CONTENT_SETTINGS_TYPE_DEFAULT, ""));
183    }
184  } else if (type == NotificationType::PROFILE_DESTROYED) {
185    DCHECK_EQ(profile_, Source<Profile>(source).ptr());
186    UnregisterObservers();
187  } else {
188    NOTREACHED() << "Unexpected notification";
189  }
190}
191
192void PolicyDefaultProvider::UnregisterObservers() {
193  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
194  if (!profile_)
195    return;
196  pref_change_registrar_.RemoveAll();
197  notification_registrar_.Remove(this, NotificationType::PROFILE_DESTROYED,
198                                 Source<Profile>(profile_));
199  profile_ = NULL;
200}
201
202
203void PolicyDefaultProvider::NotifyObservers(
204    const ContentSettingsDetails& details) {
205  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
206  if (profile_ == NULL)
207    return;
208  NotificationService::current()->Notify(
209      NotificationType::CONTENT_SETTINGS_CHANGED,
210      Source<HostContentSettingsMap>(profile_->GetHostContentSettingsMap()),
211      Details<const ContentSettingsDetails>(&details));
212}
213
214void PolicyDefaultProvider::ReadManagedDefaultSettings() {
215  for (size_t type = 0; type < arraysize(kPrefToManageType); ++type) {
216    if (kPrefToManageType[type] == NULL) {
217      continue;
218    }
219    UpdateManagedDefaultSetting(ContentSettingsType(type));
220  }
221}
222
223void PolicyDefaultProvider::UpdateManagedDefaultSetting(
224    ContentSettingsType type) {
225  // If a pref to manage a default-content-setting was not set (NOTICE:
226  // "HasPrefPath" returns false if no value was set for a registered pref) then
227  // the default value of the preference is used. The default value of a
228  // preference to manage a default-content-settings is CONTENT_SETTING_DEFAULT.
229  // This indicates that no managed value is set. If a pref was set, than it
230  // MUST be managed.
231  PrefService* prefs = profile_->GetPrefs();
232  DCHECK(!prefs->HasPrefPath(kPrefToManageType[type]) ||
233          prefs->IsManagedPreference(kPrefToManageType[type]));
234  base::AutoLock auto_lock(lock_);
235  managed_default_content_settings_.settings[type] = IntToContentSetting(
236      prefs->GetInteger(kPrefToManageType[type]));
237}
238
239// static
240void PolicyDefaultProvider::RegisterUserPrefs(PrefService* prefs) {
241  // Preferences for default content setting policies. A policy is not set of
242  // the corresponding preferences below is set to CONTENT_SETTING_DEFAULT.
243  prefs->RegisterIntegerPref(prefs::kManagedDefaultCookiesSetting,
244      CONTENT_SETTING_DEFAULT);
245  prefs->RegisterIntegerPref(prefs::kManagedDefaultImagesSetting,
246      CONTENT_SETTING_DEFAULT);
247  prefs->RegisterIntegerPref(prefs::kManagedDefaultJavaScriptSetting,
248      CONTENT_SETTING_DEFAULT);
249  prefs->RegisterIntegerPref(prefs::kManagedDefaultPluginsSetting,
250      CONTENT_SETTING_DEFAULT);
251  prefs->RegisterIntegerPref(prefs::kManagedDefaultPopupsSetting,
252      CONTENT_SETTING_DEFAULT);
253}
254
255// ////////////////////////////////////////////////////////////////////////////
256// PolicyProvider
257
258// static
259void PolicyProvider::RegisterUserPrefs(PrefService* prefs) {
260  prefs->RegisterListPref(prefs::kManagedCookiesAllowedForUrls);
261  prefs->RegisterListPref(prefs::kManagedCookiesBlockedForUrls);
262  prefs->RegisterListPref(prefs::kManagedCookiesSessionOnlyForUrls);
263  prefs->RegisterListPref(prefs::kManagedImagesAllowedForUrls);
264  prefs->RegisterListPref(prefs::kManagedImagesBlockedForUrls);
265  prefs->RegisterListPref(prefs::kManagedJavaScriptAllowedForUrls);
266  prefs->RegisterListPref(prefs::kManagedJavaScriptBlockedForUrls);
267  prefs->RegisterListPref(prefs::kManagedPluginsAllowedForUrls);
268  prefs->RegisterListPref(prefs::kManagedPluginsBlockedForUrls);
269  prefs->RegisterListPref(prefs::kManagedPopupsAllowedForUrls);
270  prefs->RegisterListPref(prefs::kManagedPopupsBlockedForUrls);
271}
272
273PolicyProvider::PolicyProvider(Profile* profile)
274    : BaseProvider(profile->IsOffTheRecord()),
275      profile_(profile) {
276  Init();
277}
278
279PolicyProvider::~PolicyProvider() {
280  UnregisterObservers();
281}
282
283void PolicyProvider::ReadManagedContentSettingsTypes(
284    ContentSettingsType content_type) {
285  PrefService* prefs = profile_->GetPrefs();
286  if (kPrefToManageType[content_type] == NULL) {
287    content_type_is_managed_[content_type] = false;
288  } else {
289    content_type_is_managed_[content_type] =
290         prefs->IsManagedPreference(kPrefToManageType[content_type]);
291  }
292}
293
294void PolicyProvider::Init() {
295  PrefService* prefs = profile_->GetPrefs();
296
297  ReadManagedContentSettings(false);
298  for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i)
299    ReadManagedContentSettingsTypes(ContentSettingsType(i));
300
301  pref_change_registrar_.Init(prefs);
302  pref_change_registrar_.Add(prefs::kManagedCookiesBlockedForUrls, this);
303  pref_change_registrar_.Add(prefs::kManagedCookiesAllowedForUrls, this);
304  pref_change_registrar_.Add(prefs::kManagedCookiesSessionOnlyForUrls, this);
305  pref_change_registrar_.Add(prefs::kManagedImagesBlockedForUrls, this);
306  pref_change_registrar_.Add(prefs::kManagedImagesAllowedForUrls, this);
307  pref_change_registrar_.Add(prefs::kManagedJavaScriptBlockedForUrls, this);
308  pref_change_registrar_.Add(prefs::kManagedJavaScriptAllowedForUrls, this);
309  pref_change_registrar_.Add(prefs::kManagedPluginsBlockedForUrls, this);
310  pref_change_registrar_.Add(prefs::kManagedPluginsAllowedForUrls, this);
311  pref_change_registrar_.Add(prefs::kManagedPopupsBlockedForUrls, this);
312  pref_change_registrar_.Add(prefs::kManagedPopupsAllowedForUrls, this);
313
314  pref_change_registrar_.Add(prefs::kManagedDefaultCookiesSetting, this);
315  pref_change_registrar_.Add(prefs::kManagedDefaultImagesSetting, this);
316  pref_change_registrar_.Add(prefs::kManagedDefaultJavaScriptSetting, this);
317  pref_change_registrar_.Add(prefs::kManagedDefaultPluginsSetting, this);
318  pref_change_registrar_.Add(prefs::kManagedDefaultPopupsSetting, this);
319
320  notification_registrar_.Add(this, NotificationType::PROFILE_DESTROYED,
321                              Source<Profile>(profile_));
322}
323
324bool PolicyProvider::ContentSettingsTypeIsManaged(
325    ContentSettingsType content_type) {
326  return content_type_is_managed_[content_type];
327}
328
329void PolicyProvider::GetContentSettingsFromPreferences(
330    PrefService* prefs,
331    ContentSettingsRules* rules) {
332  for (size_t i = 0; i < arraysize(kPrefsForManagedContentSettingsMap); ++i) {
333    const char* pref_name = kPrefsForManagedContentSettingsMap[i].pref_name;
334    // Skip unset policies.
335    if (!prefs->HasPrefPath(pref_name)) {
336      VLOG(2) << "Skipping unset preference: " << pref_name;
337      continue;
338    }
339
340    const PrefService::Preference* pref = prefs->FindPreference(pref_name);
341    DCHECK(pref->IsManaged());
342    DCHECK_EQ(Value::TYPE_LIST, pref->GetType());
343
344    const ListValue* pattern_str_list =
345        static_cast<const ListValue*>(pref->GetValue());
346    for (size_t j = 0; j < pattern_str_list->GetSize(); ++j) {
347      std::string original_pattern_str;
348      pattern_str_list->GetString(j, &original_pattern_str);
349      ContentSettingsPattern pattern(original_pattern_str);
350      // Ignore invalid patterns.
351      if (!pattern.IsValid()) {
352        VLOG(1) << "Ignoring invalid content settings pattern: " <<
353                   pattern.AsString();
354        continue;
355      }
356      rules->push_back(MakeTuple(
357          pattern,
358          pattern,
359          kPrefsForManagedContentSettingsMap[i].content_type,
360          ProviderInterface::ResourceIdentifier(NO_RESOURCE_IDENTIFIER),
361          kPrefsForManagedContentSettingsMap[i].setting));
362    }
363  }
364}
365
366void PolicyProvider::ReadManagedContentSettings(bool overwrite) {
367  ContentSettingsRules rules;
368  PrefService* prefs = profile_->GetPrefs();
369  GetContentSettingsFromPreferences(prefs, &rules);
370  {
371    base::AutoLock auto_lock(lock());
372    HostContentSettings* content_settings_map = host_content_settings();
373    if (overwrite)
374      content_settings_map->clear();
375    for (ContentSettingsRules::iterator rule = rules.begin();
376         rule != rules.end();
377         ++rule) {
378      DispatchToMethod(this, &PolicyProvider::UpdateContentSettingsMap, *rule);
379    }
380  }
381}
382
383// Since the PolicyProvider is a read only content settings provider, all
384// methodes of the ProviderInterface that set or delete any settings do nothing.
385void PolicyProvider::SetContentSetting(
386    const ContentSettingsPattern& requesting_pattern,
387    const ContentSettingsPattern& embedding_pattern,
388    ContentSettingsType content_type,
389    const ResourceIdentifier& resource_identifier,
390    ContentSetting content_setting) {
391}
392
393ContentSetting PolicyProvider::GetContentSetting(
394    const GURL& requesting_url,
395    const GURL& embedding_url,
396    ContentSettingsType content_type,
397    const ResourceIdentifier& resource_identifier) const {
398  return BaseProvider::GetContentSetting(
399      requesting_url,
400      embedding_url,
401      content_type,
402      NO_RESOURCE_IDENTIFIER);
403}
404
405void PolicyProvider::ClearAllContentSettingsRules(
406    ContentSettingsType content_type) {
407}
408
409void PolicyProvider::ResetToDefaults() {
410}
411
412void PolicyProvider::UnregisterObservers() {
413  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
414  if (!profile_)
415    return;
416  pref_change_registrar_.RemoveAll();
417  notification_registrar_.Remove(this, NotificationType::PROFILE_DESTROYED,
418                                 Source<Profile>(profile_));
419  profile_ = NULL;
420}
421
422void PolicyProvider::NotifyObservers(
423    const ContentSettingsDetails& details) {
424  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
425  if (profile_ == NULL)
426    return;
427  NotificationService::current()->Notify(
428      NotificationType::CONTENT_SETTINGS_CHANGED,
429      Source<HostContentSettingsMap>(profile_->GetHostContentSettingsMap()),
430      Details<const ContentSettingsDetails>(&details));
431}
432
433void PolicyProvider::Observe(NotificationType type,
434                             const NotificationSource& source,
435                             const NotificationDetails& details) {
436  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
437
438  if (type == NotificationType::PREF_CHANGED) {
439    DCHECK_EQ(profile_->GetPrefs(), Source<PrefService>(source).ptr());
440    std::string* name = Details<std::string>(details).ptr();
441    if (*name == prefs::kManagedCookiesAllowedForUrls ||
442        *name == prefs::kManagedCookiesBlockedForUrls ||
443        *name == prefs::kManagedCookiesSessionOnlyForUrls ||
444        *name == prefs::kManagedImagesAllowedForUrls ||
445        *name == prefs::kManagedImagesBlockedForUrls ||
446        *name == prefs::kManagedJavaScriptAllowedForUrls ||
447        *name == prefs::kManagedJavaScriptBlockedForUrls ||
448        *name == prefs::kManagedPluginsAllowedForUrls ||
449        *name == prefs::kManagedPluginsBlockedForUrls ||
450        *name == prefs::kManagedPopupsAllowedForUrls ||
451        *name == prefs::kManagedPopupsBlockedForUrls) {
452      ReadManagedContentSettings(true);
453      NotifyObservers(ContentSettingsDetails(
454          ContentSettingsPattern(), CONTENT_SETTINGS_TYPE_DEFAULT, ""));
455      // We do not want to sent a notification when managed default content
456      // settings change. The DefaultProvider will take care of that. We are
457      // only a passive observer.
458      // TODO(markusheintz): NOTICE: This is still work in progress and part of
459      // a larger refactoring. The code will change and be much cleaner and
460      // clearer in the end.
461    } else if (*name == prefs::kManagedDefaultCookiesSetting) {
462      ReadManagedContentSettingsTypes(CONTENT_SETTINGS_TYPE_COOKIES);
463    } else if (*name == prefs::kManagedDefaultImagesSetting) {
464      ReadManagedContentSettingsTypes(CONTENT_SETTINGS_TYPE_IMAGES);
465    } else if (*name == prefs::kManagedDefaultJavaScriptSetting) {
466      ReadManagedContentSettingsTypes(CONTENT_SETTINGS_TYPE_JAVASCRIPT);
467    } else if (*name == prefs::kManagedDefaultPluginsSetting) {
468      ReadManagedContentSettingsTypes(CONTENT_SETTINGS_TYPE_PLUGINS);
469    } else if (*name == prefs::kManagedDefaultPopupsSetting) {
470      ReadManagedContentSettingsTypes(CONTENT_SETTINGS_TYPE_POPUPS);
471    }
472  } else if (type == NotificationType::PROFILE_DESTROYED) {
473    DCHECK_EQ(profile_, Source<Profile>(source).ptr());
474    UnregisterObservers();
475  } else {
476    NOTREACHED() << "Unexpected notification";
477  }
478}
479
480}  // namespace content_settings
481