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/chromeos/policy/configuration_policy_handler_chromeos.h"
6
7#include <string>
8#include <vector>
9
10#include "ash/magnifier/magnifier_constants.h"
11#include "base/callback.h"
12#include "base/json/json_reader.h"
13#include "base/json/json_writer.h"
14#include "base/logging.h"
15#include "base/memory/scoped_ptr.h"
16#include "base/prefs/pref_value_map.h"
17#include "base/strings/string_number_conversions.h"
18#include "base/strings/string_util.h"
19#include "base/values.h"
20#include "chrome/browser/ui/ash/chrome_launcher_prefs.h"
21#include "chrome/common/pref_names.h"
22#include "chromeos/dbus/power_policy_controller.h"
23#include "chromeos/network/onc/onc_signature.h"
24#include "chromeos/network/onc/onc_utils.h"
25#include "chromeos/network/onc/onc_validator.h"
26#include "components/onc/onc_constants.h"
27#include "components/policy/core/browser/policy_error_map.h"
28#include "components/policy/core/common/external_data_fetcher.h"
29#include "components/policy/core/common/policy_map.h"
30#include "components/policy/core/common/schema.h"
31#include "crypto/sha2.h"
32#include "grit/components_strings.h"
33#include "policy/policy_constants.h"
34#include "url/gurl.h"
35
36namespace policy {
37
38namespace {
39
40const char kSubkeyURL[] = "url";
41const char kSubkeyHash[] = "hash";
42
43bool GetSubkeyString(const base::DictionaryValue& dict,
44                     policy::PolicyErrorMap* errors,
45                     const std::string& policy,
46                     const std::string& subkey,
47                     std::string* value) {
48  const base::Value* raw_value = NULL;
49  if (!dict.GetWithoutPathExpansion(subkey, &raw_value)) {
50    errors->AddError(policy, subkey, IDS_POLICY_NOT_SPECIFIED_ERROR);
51    return false;
52  }
53  std::string string_value;
54  if (!raw_value->GetAsString(&string_value)) {
55    errors->AddError(policy, subkey, IDS_POLICY_TYPE_ERROR, "string");
56    return false;
57  }
58  if (string_value.empty()) {
59    errors->AddError(policy, subkey, IDS_POLICY_NOT_SPECIFIED_ERROR);
60    return false;
61  }
62  *value = string_value;
63  return true;
64}
65
66const char kScreenDimDelayAC[] = "AC.Delays.ScreenDim";
67const char kScreenOffDelayAC[] = "AC.Delays.ScreenOff";
68const char kIdleWarningDelayAC[] = "AC.Delays.IdleWarning";
69const char kIdleDelayAC[] = "AC.Delays.Idle";
70const char kIdleActionAC[] = "AC.IdleAction";
71
72const char kScreenDimDelayBattery[] = "Battery.Delays.ScreenDim";
73const char kScreenOffDelayBattery[] = "Battery.Delays.ScreenOff";
74const char kIdleWarningDelayBattery[] = "Battery.Delays.IdleWarning";
75const char kIdleDelayBattery[] = "Battery.Delays.Idle";
76const char kIdleActionBattery[] = "Battery.IdleAction";
77
78const char kScreenLockDelayAC[] = "AC";
79const char kScreenLockDelayBattery[] = "Battery";
80
81const char kActionSuspend[] = "Suspend";
82const char kActionLogout[] = "Logout";
83const char kActionShutdown[]  = "Shutdown";
84const char kActionDoNothing[] = "DoNothing";
85
86scoped_ptr<base::Value> GetValue(const base::DictionaryValue* dict,
87                                 const char* key) {
88  const base::Value* value = NULL;
89  if (!dict->Get(key, &value))
90    return scoped_ptr<base::Value>();
91  return scoped_ptr<base::Value>(value->DeepCopy());
92}
93
94scoped_ptr<base::Value> GetAction(const base::DictionaryValue* dict,
95                                  const char* key) {
96  scoped_ptr<base::Value> value = GetValue(dict, key);
97  std::string action;
98  if (!value || !value->GetAsString(&action))
99    return scoped_ptr<base::Value>();
100  if (action == kActionSuspend) {
101    return scoped_ptr<base::Value>(new base::FundamentalValue(
102        chromeos::PowerPolicyController::ACTION_SUSPEND));
103  }
104  if (action == kActionLogout) {
105    return scoped_ptr<base::Value>(new base::FundamentalValue(
106        chromeos::PowerPolicyController::ACTION_STOP_SESSION));
107  }
108  if (action == kActionShutdown) {
109    return scoped_ptr<base::Value>(new base::FundamentalValue(
110        chromeos::PowerPolicyController::ACTION_SHUT_DOWN));
111  }
112  if (action == kActionDoNothing) {
113    return scoped_ptr<base::Value>(new base::FundamentalValue(
114        chromeos::PowerPolicyController::ACTION_DO_NOTHING));
115  }
116  return scoped_ptr<base::Value>();
117}
118
119}  // namespace
120
121ExternalDataPolicyHandler::ExternalDataPolicyHandler(const char* policy_name)
122    : TypeCheckingPolicyHandler(policy_name, base::Value::TYPE_DICTIONARY) {
123}
124
125ExternalDataPolicyHandler::~ExternalDataPolicyHandler() {
126}
127
128bool ExternalDataPolicyHandler::CheckPolicySettings(const PolicyMap& policies,
129                                                    PolicyErrorMap* errors) {
130  if (!TypeCheckingPolicyHandler::CheckPolicySettings(policies, errors))
131    return false;
132
133  const std::string policy = policy_name();
134  const base::Value* value = policies.GetValue(policy);
135  if (!value)
136    return true;
137
138  const base::DictionaryValue* dict = NULL;
139  value->GetAsDictionary(&dict);
140  if (!dict) {
141    NOTREACHED();
142    return false;
143  }
144  std::string url_string;
145  std::string hash_string;
146  if (!GetSubkeyString(*dict, errors, policy, kSubkeyURL, &url_string) ||
147      !GetSubkeyString(*dict, errors, policy, kSubkeyHash, &hash_string)) {
148    return false;
149  }
150
151  const GURL url(url_string);
152  if (!url.is_valid()) {
153    errors->AddError(policy, kSubkeyURL, IDS_POLICY_VALUE_FORMAT_ERROR);
154    return false;
155  }
156
157  std::vector<uint8> hash;
158  if (!base::HexStringToBytes(hash_string, &hash) ||
159      hash.size() != crypto::kSHA256Length) {
160    errors->AddError(policy, kSubkeyHash, IDS_POLICY_VALUE_FORMAT_ERROR);
161    return false;
162  }
163
164  return true;
165}
166
167void ExternalDataPolicyHandler::ApplyPolicySettings(const PolicyMap& policies,
168                                                    PrefValueMap* prefs) {
169}
170
171// static
172NetworkConfigurationPolicyHandler*
173NetworkConfigurationPolicyHandler::CreateForUserPolicy() {
174  return new NetworkConfigurationPolicyHandler(
175      key::kOpenNetworkConfiguration,
176      onc::ONC_SOURCE_USER_POLICY,
177      prefs::kOpenNetworkConfiguration);
178}
179
180// static
181NetworkConfigurationPolicyHandler*
182NetworkConfigurationPolicyHandler::CreateForDevicePolicy() {
183  return new NetworkConfigurationPolicyHandler(
184      key::kDeviceOpenNetworkConfiguration,
185      onc::ONC_SOURCE_DEVICE_POLICY,
186      prefs::kDeviceOpenNetworkConfiguration);
187}
188
189NetworkConfigurationPolicyHandler::~NetworkConfigurationPolicyHandler() {}
190
191bool NetworkConfigurationPolicyHandler::CheckPolicySettings(
192    const PolicyMap& policies,
193    PolicyErrorMap* errors) {
194  const base::Value* value;
195  if (!CheckAndGetValue(policies, errors, &value))
196    return false;
197
198  if (value) {
199    std::string onc_blob;
200    value->GetAsString(&onc_blob);
201    scoped_ptr<base::DictionaryValue> root_dict =
202        chromeos::onc::ReadDictionaryFromJson(onc_blob);
203    if (root_dict.get() == NULL) {
204      errors->AddError(policy_name(), IDS_POLICY_NETWORK_CONFIG_PARSE_FAILED);
205      return false;
206    }
207
208    // Validate the ONC dictionary. We are liberal and ignore unknown field
209    // names and ignore invalid field names in kRecommended arrays.
210    chromeos::onc::Validator validator(
211        false,  // Ignore unknown fields.
212        false,  // Ignore invalid recommended field names.
213        true,   // Fail on missing fields.
214        true);  // Validate for managed ONC
215    validator.SetOncSource(onc_source_);
216
217    // ONC policies are always unencrypted.
218    chromeos::onc::Validator::Result validation_result;
219    root_dict = validator.ValidateAndRepairObject(
220        &chromeos::onc::kToplevelConfigurationSignature, *root_dict,
221        &validation_result);
222    if (validation_result == chromeos::onc::Validator::VALID_WITH_WARNINGS)
223      errors->AddError(policy_name(), IDS_POLICY_NETWORK_CONFIG_IMPORT_PARTIAL);
224    else if (validation_result == chromeos::onc::Validator::INVALID)
225      errors->AddError(policy_name(), IDS_POLICY_NETWORK_CONFIG_IMPORT_FAILED);
226
227    // In any case, don't reject the policy as some networks or certificates
228    // could still be applied.
229  }
230
231  return true;
232}
233
234void NetworkConfigurationPolicyHandler::ApplyPolicySettings(
235    const PolicyMap& policies,
236    PrefValueMap* prefs) {
237  const base::Value* value = policies.GetValue(policy_name());
238  if (!value)
239    return;
240
241  std::string onc_blob;
242  value->GetAsString(&onc_blob);
243
244  scoped_ptr<base::ListValue> network_configs(new base::ListValue);
245  base::ListValue certificates;
246  base::DictionaryValue global_network_config;
247  chromeos::onc::ParseAndValidateOncForImport(onc_blob,
248                                              onc_source_,
249                                              "",
250                                              network_configs.get(),
251                                              &global_network_config,
252                                              &certificates);
253
254  // Currently, only the per-network configuration is stored in a pref. Ignore
255  // |global_network_config| and |certificates|.
256  prefs->SetValue(pref_path_, network_configs.release());
257}
258
259void NetworkConfigurationPolicyHandler::PrepareForDisplaying(
260    PolicyMap* policies) const {
261  const PolicyMap::Entry* entry = policies->Get(policy_name());
262  if (!entry)
263    return;
264  base::Value* sanitized_config = SanitizeNetworkConfig(entry->value);
265  if (!sanitized_config)
266    sanitized_config = base::Value::CreateNullValue();
267
268  policies->Set(policy_name(), entry->level, entry->scope,
269                sanitized_config, NULL);
270}
271
272NetworkConfigurationPolicyHandler::NetworkConfigurationPolicyHandler(
273    const char* policy_name,
274    onc::ONCSource onc_source,
275    const char* pref_path)
276    : TypeCheckingPolicyHandler(policy_name, base::Value::TYPE_STRING),
277      onc_source_(onc_source),
278      pref_path_(pref_path) {
279}
280
281// static
282base::Value* NetworkConfigurationPolicyHandler::SanitizeNetworkConfig(
283    const base::Value* config) {
284  std::string json_string;
285  if (!config->GetAsString(&json_string))
286    return NULL;
287
288  scoped_ptr<base::DictionaryValue> toplevel_dict =
289      chromeos::onc::ReadDictionaryFromJson(json_string);
290  if (!toplevel_dict)
291    return NULL;
292
293  // Placeholder to insert in place of the filtered setting.
294  const char kPlaceholder[] = "********";
295
296  toplevel_dict = chromeos::onc::MaskCredentialsInOncObject(
297      chromeos::onc::kToplevelConfigurationSignature,
298      *toplevel_dict,
299      kPlaceholder);
300
301  base::JSONWriter::WriteWithOptions(toplevel_dict.get(),
302                                     base::JSONWriter::OPTIONS_PRETTY_PRINT,
303                                     &json_string);
304  return new base::StringValue(json_string);
305}
306
307PinnedLauncherAppsPolicyHandler::PinnedLauncherAppsPolicyHandler()
308    : ExtensionListPolicyHandler(key::kPinnedLauncherApps,
309                                 prefs::kPinnedLauncherApps,
310                                 false) {}
311
312PinnedLauncherAppsPolicyHandler::~PinnedLauncherAppsPolicyHandler() {}
313
314void PinnedLauncherAppsPolicyHandler::ApplyPolicySettings(
315    const PolicyMap& policies,
316    PrefValueMap* prefs) {
317  PolicyErrorMap errors;
318  const base::Value* policy_value = policies.GetValue(policy_name());
319  const base::ListValue* policy_list = NULL;
320  if (policy_value && policy_value->GetAsList(&policy_list) && policy_list) {
321    base::ListValue* pinned_apps_list = new base::ListValue();
322    for (base::ListValue::const_iterator entry(policy_list->begin());
323         entry != policy_list->end(); ++entry) {
324      std::string id;
325      if ((*entry)->GetAsString(&id)) {
326        base::DictionaryValue* app_dict = new base::DictionaryValue();
327        app_dict->SetString(ash::kPinnedAppsPrefAppIDPath, id);
328        pinned_apps_list->Append(app_dict);
329      }
330    }
331    prefs->SetValue(pref_path(), pinned_apps_list);
332  }
333}
334
335ScreenMagnifierPolicyHandler::ScreenMagnifierPolicyHandler()
336    : IntRangePolicyHandlerBase(key::kScreenMagnifierType,
337                                0, ash::MAGNIFIER_FULL, false) {
338}
339
340ScreenMagnifierPolicyHandler::~ScreenMagnifierPolicyHandler() {
341}
342
343void ScreenMagnifierPolicyHandler::ApplyPolicySettings(
344    const PolicyMap& policies,
345    PrefValueMap* prefs) {
346  const base::Value* value = policies.GetValue(policy_name());
347  int value_in_range;
348  if (value && EnsureInRange(value, &value_in_range, NULL)) {
349    prefs->SetValue(prefs::kAccessibilityScreenMagnifierEnabled,
350                    new base::FundamentalValue(value_in_range != 0));
351    prefs->SetValue(prefs::kAccessibilityScreenMagnifierType,
352                    new base::FundamentalValue(value_in_range));
353  }
354}
355
356LoginScreenPowerManagementPolicyHandler::
357    LoginScreenPowerManagementPolicyHandler(const Schema& chrome_schema)
358    : SchemaValidatingPolicyHandler(key::kDeviceLoginScreenPowerManagement,
359                                    chrome_schema.GetKnownProperty(
360                                        key::kDeviceLoginScreenPowerManagement),
361                                    SCHEMA_ALLOW_UNKNOWN) {
362}
363
364LoginScreenPowerManagementPolicyHandler::
365    ~LoginScreenPowerManagementPolicyHandler() {
366}
367
368void LoginScreenPowerManagementPolicyHandler::ApplyPolicySettings(
369    const PolicyMap& policies,
370    PrefValueMap* prefs) {
371}
372
373DeprecatedIdleActionHandler::DeprecatedIdleActionHandler()
374    : IntRangePolicyHandlerBase(
375          key::kIdleAction,
376          chromeos::PowerPolicyController::ACTION_SUSPEND,
377          chromeos::PowerPolicyController::ACTION_DO_NOTHING,
378          false) {}
379
380DeprecatedIdleActionHandler::~DeprecatedIdleActionHandler() {}
381
382void DeprecatedIdleActionHandler::ApplyPolicySettings(const PolicyMap& policies,
383                                                      PrefValueMap* prefs) {
384  const base::Value* value = policies.GetValue(policy_name());
385  if (value && EnsureInRange(value, NULL, NULL)) {
386    if (!prefs->GetValue(prefs::kPowerAcIdleAction, NULL))
387      prefs->SetValue(prefs::kPowerAcIdleAction, value->DeepCopy());
388    if (!prefs->GetValue(prefs::kPowerBatteryIdleAction, NULL))
389      prefs->SetValue(prefs::kPowerBatteryIdleAction, value->DeepCopy());
390  }
391}
392
393PowerManagementIdleSettingsPolicyHandler::
394    PowerManagementIdleSettingsPolicyHandler(const Schema& chrome_schema)
395    : SchemaValidatingPolicyHandler(
396          key::kPowerManagementIdleSettings,
397          chrome_schema.GetKnownProperty(key::kPowerManagementIdleSettings),
398          SCHEMA_ALLOW_UNKNOWN) {
399}
400
401PowerManagementIdleSettingsPolicyHandler::
402    ~PowerManagementIdleSettingsPolicyHandler() {
403}
404
405void PowerManagementIdleSettingsPolicyHandler::ApplyPolicySettings(
406    const PolicyMap& policies,
407    PrefValueMap* prefs) {
408  scoped_ptr<base::Value> policy_value;
409  if (!CheckAndGetValue(policies, NULL, &policy_value))
410    return;
411  const base::DictionaryValue* dict = NULL;
412  if (!policy_value->GetAsDictionary(&dict)) {
413    NOTREACHED();
414    return;
415  }
416  scoped_ptr<base::Value> value;
417
418  value = GetValue(dict, kScreenDimDelayAC);
419  if (value)
420    prefs->SetValue(prefs::kPowerAcScreenDimDelayMs, value.release());
421  value = GetValue(dict, kScreenOffDelayAC);
422  if (value)
423    prefs->SetValue(prefs::kPowerAcScreenOffDelayMs, value.release());
424  value = GetValue(dict, kIdleWarningDelayAC);
425  if (value)
426    prefs->SetValue(prefs::kPowerAcIdleWarningDelayMs, value.release());
427  value = GetValue(dict, kIdleDelayAC);
428  if (value)
429    prefs->SetValue(prefs::kPowerAcIdleDelayMs, value.release());
430  value = GetAction(dict, kIdleActionAC);
431  if (value)
432    prefs->SetValue(prefs::kPowerAcIdleAction, value.release());
433
434  value = GetValue(dict, kScreenDimDelayBattery);
435  if (value)
436    prefs->SetValue(prefs::kPowerBatteryScreenDimDelayMs, value.release());
437  value = GetValue(dict, kScreenOffDelayBattery);
438  if (value)
439    prefs->SetValue(prefs::kPowerBatteryScreenOffDelayMs, value.release());
440  value = GetValue(dict, kIdleWarningDelayBattery);
441  if (value)
442    prefs->SetValue(prefs::kPowerBatteryIdleWarningDelayMs, value.release());
443  value = GetValue(dict, kIdleDelayBattery);
444  if (value)
445    prefs->SetValue(prefs::kPowerBatteryIdleDelayMs, value.release());
446  value = GetAction(dict, kIdleActionBattery);
447  if (value)
448    prefs->SetValue(prefs::kPowerBatteryIdleAction, value.release());
449}
450
451ScreenLockDelayPolicyHandler::ScreenLockDelayPolicyHandler(
452    const Schema& chrome_schema)
453    : SchemaValidatingPolicyHandler(
454          key::kScreenLockDelays,
455          chrome_schema.GetKnownProperty(key::kScreenLockDelays),
456          SCHEMA_ALLOW_UNKNOWN) {
457}
458
459ScreenLockDelayPolicyHandler::~ScreenLockDelayPolicyHandler() {
460}
461
462void ScreenLockDelayPolicyHandler::ApplyPolicySettings(
463    const PolicyMap& policies,
464    PrefValueMap* prefs) {
465  scoped_ptr<base::Value> policy_value;
466  if (!CheckAndGetValue(policies, NULL, &policy_value))
467    return;
468  const base::DictionaryValue* dict = NULL;
469  if (!policy_value->GetAsDictionary(&dict)) {
470    NOTREACHED();
471    return;
472  }
473  scoped_ptr<base::Value> value;
474
475  value = GetValue(dict, kScreenLockDelayAC);
476  if (value)
477    prefs->SetValue(prefs::kPowerAcScreenLockDelayMs, value.release());
478  value = GetValue(dict, kScreenLockDelayBattery);
479  if (value)
480    prefs->SetValue(prefs::kPowerBatteryScreenLockDelayMs, value.release());
481}
482
483}  // namespace policy
484