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/device_policy_decoder_chromeos.h"
6
7#include <limits>
8#include <string>
9
10#include "base/callback.h"
11#include "base/json/json_reader.h"
12#include "base/logging.h"
13#include "base/values.h"
14#include "chrome/browser/browser_process.h"
15#include "chrome/browser/chromeos/policy/device_local_account.h"
16#include "chrome/browser/chromeos/policy/enterprise_install_attributes.h"
17#include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h"
18#include "chromeos/dbus/dbus_thread_manager.h"
19#include "chromeos/dbus/update_engine_client.h"
20#include "chromeos/settings/cros_settings_names.h"
21#include "components/policy/core/browser/browser_policy_connector.h"
22#include "components/policy/core/common/external_data_fetcher.h"
23#include "components/policy/core/common/policy_map.h"
24#include "components/policy/core/common/schema.h"
25#include "policy/policy_constants.h"
26#include "third_party/cros_system_api/dbus/service_constants.h"
27
28using google::protobuf::RepeatedField;
29using google::protobuf::RepeatedPtrField;
30
31namespace em = enterprise_management;
32
33namespace policy {
34
35namespace {
36
37// Decodes a protobuf integer to an IntegerValue. Returns NULL in case the input
38// value is out of bounds.
39scoped_ptr<base::Value> DecodeIntegerValue(google::protobuf::int64 value) {
40  if (value < std::numeric_limits<int>::min() ||
41      value > std::numeric_limits<int>::max()) {
42    LOG(WARNING) << "Integer value " << value
43                 << " out of numeric limits, ignoring.";
44    return scoped_ptr<base::Value>();
45  }
46
47  return scoped_ptr<base::Value>(
48      new base::FundamentalValue(static_cast<int>(value)));
49}
50
51// Decodes a JSON string to a base::Value, and drops unknown properties
52// according to a policy schema. |policy_name| is the name of a policy schema
53// defined in policy_templates.json. Returns NULL in case the input is not a
54// valid JSON string.
55scoped_ptr<base::Value> DecodeJsonStringAndDropUnknownBySchema(
56    const std::string& json_string,
57    const std::string& policy_name) {
58  std::string error;
59  base::Value* root(base::JSONReader::ReadAndReturnError(
60      json_string, base::JSON_ALLOW_TRAILING_COMMAS, NULL, &error));
61
62  if (!root) {
63    LOG(WARNING) << "Invalid JSON string: " << error << ", ignoring.";
64    return scoped_ptr<base::Value>();
65  }
66
67  const Schema& schema = g_browser_process
68                             ->browser_policy_connector()
69                             ->GetChromeSchema()
70                             .GetKnownProperty(policy_name);
71
72  if (schema.valid()) {
73    std::string error_path;
74    bool changed = false;
75
76    if (!schema.Normalize(
77            root, SCHEMA_ALLOW_UNKNOWN, &error_path, &error, &changed)) {
78      LOG(WARNING) << "Invalid policy value for " << policy_name << ": "
79                   << error << " at " << error_path << ".";
80      return scoped_ptr<base::Value>();
81    }
82
83    if (changed) {
84      LOG(WARNING) << "Some properties in " << policy_name
85                   << " were dropped: " << error << " at " << error_path << ".";
86    }
87  } else {
88    LOG(WARNING) << "Unknown or invalid policy schema for " << policy_name
89                 << ".";
90    return scoped_ptr<base::Value>();
91  }
92
93  return scoped_ptr<base::Value>(root);
94}
95
96base::Value* DecodeConnectionType(int value) {
97  static const char* const kConnectionTypes[] = {
98    shill::kTypeEthernet,
99    shill::kTypeWifi,
100    shill::kTypeWimax,
101    shill::kTypeBluetooth,
102    shill::kTypeCellular,
103  };
104
105  if (value < 0 || value >= static_cast<int>(arraysize(kConnectionTypes)))
106    return NULL;
107
108  return new base::StringValue(kConnectionTypes[value]);
109}
110
111void DecodeLoginPolicies(const em::ChromeDeviceSettingsProto& policy,
112                         PolicyMap* policies) {
113  if (policy.has_guest_mode_enabled()) {
114    const em::GuestModeEnabledProto& container(policy.guest_mode_enabled());
115    if (container.has_guest_mode_enabled()) {
116      policies->Set(key::kDeviceGuestModeEnabled,
117                    POLICY_LEVEL_MANDATORY,
118                    POLICY_SCOPE_MACHINE,
119                    new base::FundamentalValue(
120                        container.guest_mode_enabled()),
121                    NULL);
122    }
123  }
124
125  if (policy.has_show_user_names()) {
126    const em::ShowUserNamesOnSigninProto& container(policy.show_user_names());
127    if (container.has_show_user_names()) {
128      policies->Set(key::kDeviceShowUserNamesOnSignin,
129                    POLICY_LEVEL_MANDATORY,
130                    POLICY_SCOPE_MACHINE,
131                    new base::FundamentalValue(
132                        container.show_user_names()),
133                    NULL);
134    }
135  }
136
137  if (policy.has_allow_new_users()) {
138    const em::AllowNewUsersProto& container(policy.allow_new_users());
139    if (container.has_allow_new_users()) {
140      policies->Set(key::kDeviceAllowNewUsers,
141                    POLICY_LEVEL_MANDATORY,
142                    POLICY_SCOPE_MACHINE,
143                    new base::FundamentalValue(
144                        container.allow_new_users()),
145                    NULL);
146    }
147  }
148
149  if (policy.has_user_whitelist()) {
150    const em::UserWhitelistProto& container(policy.user_whitelist());
151    base::ListValue* whitelist = new base::ListValue();
152    RepeatedPtrField<std::string>::const_iterator entry;
153    for (entry = container.user_whitelist().begin();
154         entry != container.user_whitelist().end();
155         ++entry) {
156      whitelist->Append(new base::StringValue(*entry));
157    }
158    policies->Set(key::kDeviceUserWhitelist,
159                  POLICY_LEVEL_MANDATORY,
160                  POLICY_SCOPE_MACHINE,
161                  whitelist,
162                  NULL);
163  }
164
165  if (policy.has_ephemeral_users_enabled()) {
166    const em::EphemeralUsersEnabledProto& container(
167        policy.ephemeral_users_enabled());
168    if (container.has_ephemeral_users_enabled()) {
169      policies->Set(key::kDeviceEphemeralUsersEnabled,
170                    POLICY_LEVEL_MANDATORY,
171                    POLICY_SCOPE_MACHINE,
172                    new base::FundamentalValue(
173                        container.ephemeral_users_enabled()),
174                    NULL);
175    }
176  }
177
178  if (policy.has_device_local_accounts()) {
179    const em::DeviceLocalAccountsProto& container(
180        policy.device_local_accounts());
181    const RepeatedPtrField<em::DeviceLocalAccountInfoProto>& accounts =
182        container.account();
183    scoped_ptr<base::ListValue> account_list(new base::ListValue());
184    RepeatedPtrField<em::DeviceLocalAccountInfoProto>::const_iterator entry;
185    for (entry = accounts.begin(); entry != accounts.end(); ++entry) {
186      scoped_ptr<base::DictionaryValue> entry_dict(
187          new base::DictionaryValue());
188      if (entry->has_type()) {
189        if (entry->has_account_id()) {
190          entry_dict->SetStringWithoutPathExpansion(
191              chromeos::kAccountsPrefDeviceLocalAccountsKeyId,
192              entry->account_id());
193        }
194        entry_dict->SetIntegerWithoutPathExpansion(
195            chromeos::kAccountsPrefDeviceLocalAccountsKeyType, entry->type());
196        if (entry->kiosk_app().has_app_id()) {
197          entry_dict->SetStringWithoutPathExpansion(
198              chromeos::kAccountsPrefDeviceLocalAccountsKeyKioskAppId,
199              entry->kiosk_app().app_id());
200        }
201      } else if (entry->has_deprecated_public_session_id()) {
202        // Deprecated public session specification.
203        entry_dict->SetStringWithoutPathExpansion(
204            chromeos::kAccountsPrefDeviceLocalAccountsKeyId,
205            entry->deprecated_public_session_id());
206        entry_dict->SetIntegerWithoutPathExpansion(
207            chromeos::kAccountsPrefDeviceLocalAccountsKeyType,
208            DeviceLocalAccount::TYPE_PUBLIC_SESSION);
209      }
210      account_list->Append(entry_dict.release());
211    }
212    policies->Set(key::kDeviceLocalAccounts,
213                  POLICY_LEVEL_MANDATORY,
214                  POLICY_SCOPE_MACHINE,
215                  account_list.release(),
216                  NULL);
217    if (container.has_auto_login_id()) {
218      policies->Set(key::kDeviceLocalAccountAutoLoginId,
219                    POLICY_LEVEL_MANDATORY,
220                    POLICY_SCOPE_MACHINE,
221                    new base::StringValue(container.auto_login_id()),
222                    NULL);
223    }
224    if (container.has_auto_login_delay()) {
225      policies->Set(key::kDeviceLocalAccountAutoLoginDelay,
226                    POLICY_LEVEL_MANDATORY,
227                    POLICY_SCOPE_MACHINE,
228                    DecodeIntegerValue(container.auto_login_delay()).release(),
229                    NULL);
230    }
231    if (container.has_enable_auto_login_bailout()) {
232      policies->Set(key::kDeviceLocalAccountAutoLoginBailoutEnabled,
233                    POLICY_LEVEL_MANDATORY,
234                    POLICY_SCOPE_MACHINE,
235                    new base::FundamentalValue(
236                        container.enable_auto_login_bailout()),
237                    NULL);
238    }
239    if (container.has_prompt_for_network_when_offline()) {
240      policies->Set(key::kDeviceLocalAccountPromptForNetworkWhenOffline,
241                    POLICY_LEVEL_MANDATORY,
242                    POLICY_SCOPE_MACHINE,
243                    new base::FundamentalValue(
244                        container.prompt_for_network_when_offline()),
245                    NULL);
246    }
247  }
248
249  if (policy.has_supervised_users_settings()) {
250    const em::SupervisedUsersSettingsProto& container =
251        policy.supervised_users_settings();
252    if (container.has_supervised_users_enabled()) {
253      base::Value* value = new base::FundamentalValue(
254          container.supervised_users_enabled());
255      policies->Set(key::kSupervisedUsersEnabled,
256                    POLICY_LEVEL_MANDATORY,
257                    POLICY_SCOPE_MACHINE,
258                    value,
259                    NULL);
260    }
261  }
262
263  if (policy.has_saml_settings()) {
264    const em::SAMLSettingsProto& container(policy.saml_settings());
265    if (container.has_transfer_saml_cookies()) {
266      policies->Set(key::kDeviceTransferSAMLCookies,
267                    POLICY_LEVEL_MANDATORY,
268                    POLICY_SCOPE_MACHINE,
269                    new base::FundamentalValue(
270                        container.transfer_saml_cookies()),
271                    NULL);
272    }
273  }
274}
275
276void DecodeKioskPolicies(const em::ChromeDeviceSettingsProto& policy,
277                         PolicyMap* policies,
278                         EnterpriseInstallAttributes* install_attributes) {
279  // No policies if this is not KIOSK.
280  if (install_attributes->GetMode() != DEVICE_MODE_RETAIL_KIOSK)
281    return;
282
283  if (policy.has_forced_logout_timeouts()) {
284    const em::ForcedLogoutTimeoutsProto& container(
285        policy.forced_logout_timeouts());
286    if (container.has_idle_logout_timeout()) {
287      policies->Set(
288          key::kDeviceIdleLogoutTimeout,
289          POLICY_LEVEL_MANDATORY,
290          POLICY_SCOPE_MACHINE,
291          DecodeIntegerValue(container.idle_logout_timeout()).release(),
292          NULL);
293    }
294    if (container.has_idle_logout_warning_duration()) {
295      policies->Set(key::kDeviceIdleLogoutWarningDuration,
296                    POLICY_LEVEL_MANDATORY,
297                    POLICY_SCOPE_MACHINE,
298                    DecodeIntegerValue(container.idle_logout_warning_duration())
299                        .release(),
300                    NULL);
301    }
302  }
303
304  if (policy.has_login_screen_saver()) {
305    const em::ScreenSaverProto& container(
306        policy.login_screen_saver());
307    if (container.has_screen_saver_extension_id()) {
308      policies->Set(key::kDeviceLoginScreenSaverId,
309                    POLICY_LEVEL_MANDATORY,
310                    POLICY_SCOPE_MACHINE,
311                    new base::StringValue(
312                        container.screen_saver_extension_id()),
313                    NULL);
314    }
315    if (container.has_screen_saver_timeout()) {
316      policies->Set(
317          key::kDeviceLoginScreenSaverTimeout,
318          POLICY_LEVEL_MANDATORY,
319          POLICY_SCOPE_MACHINE,
320          DecodeIntegerValue(container.screen_saver_timeout()).release(),
321          NULL);
322    }
323  }
324
325  if (policy.has_app_pack()) {
326    const em::AppPackProto& container(policy.app_pack());
327    base::ListValue* app_pack_list = new base::ListValue();
328    for (int i = 0; i < container.app_pack_size(); ++i) {
329      const em::AppPackEntryProto& entry(container.app_pack(i));
330      if (entry.has_extension_id() && entry.has_update_url()) {
331        base::DictionaryValue* dict = new base::DictionaryValue();
332        dict->SetString(chromeos::kAppPackKeyExtensionId, entry.extension_id());
333        dict->SetString(chromeos::kAppPackKeyUpdateUrl, entry.update_url());
334        app_pack_list->Append(dict);
335      }
336    }
337    policies->Set(key::kDeviceAppPack,
338                  POLICY_LEVEL_MANDATORY,
339                  POLICY_SCOPE_MACHINE,
340                  app_pack_list,
341                  NULL);
342  }
343
344  if (policy.has_pinned_apps()) {
345    const em::PinnedAppsProto& container(policy.pinned_apps());
346    base::ListValue* pinned_apps_list = new base::ListValue();
347    for (int i = 0; i < container.app_id_size(); ++i) {
348      pinned_apps_list->Append(
349          new base::StringValue(container.app_id(i)));
350    }
351
352    policies->Set(key::kPinnedLauncherApps,
353                  POLICY_LEVEL_RECOMMENDED,
354                  POLICY_SCOPE_MACHINE,
355                  pinned_apps_list,
356                  NULL);
357  }
358}
359
360void DecodeNetworkPolicies(const em::ChromeDeviceSettingsProto& policy,
361                           PolicyMap* policies,
362                           EnterpriseInstallAttributes* install_attributes) {
363  if (policy.has_device_proxy_settings()) {
364    const em::DeviceProxySettingsProto& container(
365        policy.device_proxy_settings());
366    scoped_ptr<base::DictionaryValue> proxy_settings(new base::DictionaryValue);
367    if (container.has_proxy_mode())
368      proxy_settings->SetString(key::kProxyMode, container.proxy_mode());
369    if (container.has_proxy_server())
370      proxy_settings->SetString(key::kProxyServer, container.proxy_server());
371    if (container.has_proxy_pac_url())
372      proxy_settings->SetString(key::kProxyPacUrl, container.proxy_pac_url());
373    if (container.has_proxy_bypass_list()) {
374      proxy_settings->SetString(key::kProxyBypassList,
375                                container.proxy_bypass_list());
376    }
377
378    // Figure out the level. Proxy policy is mandatory in kiosk mode.
379    PolicyLevel level = POLICY_LEVEL_RECOMMENDED;
380    if (install_attributes->GetMode() == DEVICE_MODE_RETAIL_KIOSK)
381      level = POLICY_LEVEL_MANDATORY;
382
383    if (!proxy_settings->empty()) {
384      policies->Set(key::kProxySettings,
385                    level,
386                    POLICY_SCOPE_MACHINE,
387                    proxy_settings.release(),
388                    NULL);
389    }
390  }
391
392  if (policy.has_data_roaming_enabled()) {
393    const em::DataRoamingEnabledProto& container(policy.data_roaming_enabled());
394    if (container.has_data_roaming_enabled()) {
395      policies->Set(key::kDeviceDataRoamingEnabled,
396                    POLICY_LEVEL_MANDATORY,
397                    POLICY_SCOPE_MACHINE,
398                    new base::FundamentalValue(
399                        container.data_roaming_enabled()),
400                    NULL);
401    }
402  }
403
404  if (policy.has_open_network_configuration() &&
405      policy.open_network_configuration().has_open_network_configuration()) {
406    std::string config(
407        policy.open_network_configuration().open_network_configuration());
408    policies->Set(key::kDeviceOpenNetworkConfiguration,
409                  POLICY_LEVEL_MANDATORY,
410                  POLICY_SCOPE_MACHINE,
411                  new base::StringValue(config),
412                  NULL);
413  }
414}
415
416void DecodeReportingPolicies(const em::ChromeDeviceSettingsProto& policy,
417                             PolicyMap* policies) {
418  if (policy.has_device_reporting()) {
419    const em::DeviceReportingProto& container(policy.device_reporting());
420    if (container.has_report_version_info()) {
421      policies->Set(key::kReportDeviceVersionInfo,
422                    POLICY_LEVEL_MANDATORY,
423                    POLICY_SCOPE_MACHINE,
424                    new base::FundamentalValue(
425                        container.report_version_info()),
426                    NULL);
427    }
428    if (container.has_report_activity_times()) {
429      policies->Set(key::kReportDeviceActivityTimes,
430                    POLICY_LEVEL_MANDATORY,
431                    POLICY_SCOPE_MACHINE,
432                    new base::FundamentalValue(
433                        container.report_activity_times()),
434                    NULL);
435    }
436    if (container.has_report_boot_mode()) {
437      policies->Set(key::kReportDeviceBootMode,
438                    POLICY_LEVEL_MANDATORY,
439                    POLICY_SCOPE_MACHINE,
440                    new base::FundamentalValue(
441                        container.report_boot_mode()),
442                    NULL);
443    }
444    if (container.has_report_location()) {
445      policies->Set(key::kReportDeviceLocation,
446                    POLICY_LEVEL_MANDATORY,
447                    POLICY_SCOPE_MACHINE,
448                    new base::FundamentalValue(
449                        container.report_location()),
450                    NULL);
451    }
452    if (container.has_report_network_interfaces()) {
453      policies->Set(key::kReportDeviceNetworkInterfaces,
454                    POLICY_LEVEL_MANDATORY,
455                    POLICY_SCOPE_MACHINE,
456                    new base::FundamentalValue(
457                        container.report_network_interfaces()),
458                    NULL);
459    }
460    if (container.has_report_users()) {
461      policies->Set(key::kReportDeviceUsers,
462                    POLICY_LEVEL_MANDATORY,
463                    POLICY_SCOPE_MACHINE,
464                    new base::FundamentalValue(container.report_users()),
465                    NULL);
466    }
467  }
468}
469
470void DecodeAutoUpdatePolicies(const em::ChromeDeviceSettingsProto& policy,
471                              PolicyMap* policies) {
472  if (policy.has_release_channel()) {
473    const em::ReleaseChannelProto& container(policy.release_channel());
474    if (container.has_release_channel()) {
475      std::string channel(container.release_channel());
476      policies->Set(key::kChromeOsReleaseChannel,
477                    POLICY_LEVEL_MANDATORY,
478                    POLICY_SCOPE_MACHINE,
479                    new base::StringValue(channel),
480                    NULL);
481      // TODO(dubroy): Once http://crosbug.com/17015 is implemented, we won't
482      // have to pass the channel in here, only ping the update engine to tell
483      // it to fetch the channel from the policy.
484      chromeos::DBusThreadManager::Get()->GetUpdateEngineClient()->
485          SetChannel(channel, false);
486    }
487    if (container.has_release_channel_delegated()) {
488      policies->Set(key::kChromeOsReleaseChannelDelegated,
489                    POLICY_LEVEL_MANDATORY,
490                    POLICY_SCOPE_MACHINE,
491                    new base::FundamentalValue(
492                        container.release_channel_delegated()),
493                    NULL);
494    }
495  }
496
497  if (policy.has_auto_update_settings()) {
498    const em::AutoUpdateSettingsProto& container(policy.auto_update_settings());
499    if (container.has_update_disabled()) {
500      policies->Set(key::kDeviceAutoUpdateDisabled,
501                    POLICY_LEVEL_MANDATORY,
502                    POLICY_SCOPE_MACHINE,
503                    new base::FundamentalValue(
504                        container.update_disabled()),
505                    NULL);
506    }
507
508    if (container.has_target_version_prefix()) {
509      policies->Set(key::kDeviceTargetVersionPrefix,
510                    POLICY_LEVEL_MANDATORY,
511                    POLICY_SCOPE_MACHINE,
512                    new base::StringValue(
513                        container.target_version_prefix()),
514                    NULL);
515    }
516
517    // target_version_display_name is not actually a policy, but a display
518    // string for target_version_prefix, so we ignore it.
519
520    if (container.has_scatter_factor_in_seconds()) {
521      policies->Set(key::kDeviceUpdateScatterFactor,
522                    POLICY_LEVEL_MANDATORY,
523                    POLICY_SCOPE_MACHINE,
524                    new base::FundamentalValue(static_cast<int>(
525                        container.scatter_factor_in_seconds())),
526                    NULL);
527    }
528
529    if (container.allowed_connection_types_size()) {
530      base::ListValue* allowed_connection_types = new base::ListValue();
531      RepeatedField<int>::const_iterator entry;
532      for (entry = container.allowed_connection_types().begin();
533           entry != container.allowed_connection_types().end();
534           ++entry) {
535        base::Value* value = DecodeConnectionType(*entry);
536        if (value)
537          allowed_connection_types->Append(value);
538      }
539      policies->Set(key::kDeviceUpdateAllowedConnectionTypes,
540                    POLICY_LEVEL_MANDATORY,
541                    POLICY_SCOPE_MACHINE,
542                    allowed_connection_types,
543                    NULL);
544    }
545
546    if (container.has_http_downloads_enabled()) {
547      policies->Set(
548          key::kDeviceUpdateHttpDownloadsEnabled,
549          POLICY_LEVEL_MANDATORY,
550          POLICY_SCOPE_MACHINE,
551          new base::FundamentalValue(container.http_downloads_enabled()),
552          NULL);
553    }
554
555    if (container.has_reboot_after_update()) {
556      policies->Set(key::kRebootAfterUpdate,
557                    POLICY_LEVEL_MANDATORY,
558                    POLICY_SCOPE_MACHINE,
559                    new base::FundamentalValue(
560                        container.reboot_after_update()),
561                    NULL);
562    }
563
564    if (container.has_p2p_enabled()) {
565      policies->Set(key::kDeviceAutoUpdateP2PEnabled,
566                    POLICY_LEVEL_MANDATORY,
567                    POLICY_SCOPE_MACHINE,
568                    new base::FundamentalValue(container.p2p_enabled()),
569                    NULL);
570    }
571  }
572}
573
574void DecodeAccessibilityPolicies(const em::ChromeDeviceSettingsProto& policy,
575                                 PolicyMap* policies) {
576  if (policy.has_accessibility_settings()) {
577    const em::AccessibilitySettingsProto&
578        container(policy.accessibility_settings());
579
580    if (container.has_login_screen_default_large_cursor_enabled()) {
581      policies->Set(
582          key::kDeviceLoginScreenDefaultLargeCursorEnabled,
583          POLICY_LEVEL_MANDATORY,
584          POLICY_SCOPE_MACHINE,
585          new base::FundamentalValue(
586              container.login_screen_default_large_cursor_enabled()),
587          NULL);
588    }
589
590    if (container.has_login_screen_default_spoken_feedback_enabled()) {
591      policies->Set(
592          key::kDeviceLoginScreenDefaultSpokenFeedbackEnabled,
593          POLICY_LEVEL_MANDATORY,
594          POLICY_SCOPE_MACHINE,
595          new base::FundamentalValue(
596              container.login_screen_default_spoken_feedback_enabled()),
597          NULL);
598    }
599
600    if (container.has_login_screen_default_high_contrast_enabled()) {
601      policies->Set(
602          key::kDeviceLoginScreenDefaultHighContrastEnabled,
603          POLICY_LEVEL_MANDATORY,
604          POLICY_SCOPE_MACHINE,
605          new base::FundamentalValue(
606              container.login_screen_default_high_contrast_enabled()),
607          NULL);
608    }
609
610    if (container.has_login_screen_default_screen_magnifier_type()) {
611      policies->Set(
612          key::kDeviceLoginScreenDefaultScreenMagnifierType,
613          POLICY_LEVEL_MANDATORY,
614          POLICY_SCOPE_MACHINE,
615          DecodeIntegerValue(
616              container.login_screen_default_screen_magnifier_type()).release(),
617          NULL);
618    }
619    if (container.has_login_screen_default_virtual_keyboard_enabled()) {
620      policies->Set(
621          key::kDeviceLoginScreenDefaultVirtualKeyboardEnabled,
622          POLICY_LEVEL_MANDATORY,
623          POLICY_SCOPE_MACHINE,
624          new base::FundamentalValue(
625              container.login_screen_default_virtual_keyboard_enabled()),
626          NULL);
627    }
628  }
629}
630
631void DecodeGenericPolicies(const em::ChromeDeviceSettingsProto& policy,
632                           PolicyMap* policies) {
633  if (policy.has_device_policy_refresh_rate()) {
634    const em::DevicePolicyRefreshRateProto& container(
635        policy.device_policy_refresh_rate());
636    if (container.has_device_policy_refresh_rate()) {
637      policies->Set(
638          key::kDevicePolicyRefreshRate,
639          POLICY_LEVEL_MANDATORY,
640          POLICY_SCOPE_MACHINE,
641          DecodeIntegerValue(container.device_policy_refresh_rate()).release(),
642          NULL);
643    }
644  }
645
646  if (policy.has_metrics_enabled()) {
647    const em::MetricsEnabledProto& container(policy.metrics_enabled());
648    if (container.has_metrics_enabled()) {
649      policies->Set(key::kDeviceMetricsReportingEnabled,
650                    POLICY_LEVEL_MANDATORY,
651                    POLICY_SCOPE_MACHINE,
652                    new base::FundamentalValue(
653                        container.metrics_enabled()),
654                    NULL);
655    }
656  }
657
658  if (policy.has_start_up_urls()) {
659    const em::StartUpUrlsProto& container(policy.start_up_urls());
660    base::ListValue* urls = new base::ListValue();
661    RepeatedPtrField<std::string>::const_iterator entry;
662    for (entry = container.start_up_urls().begin();
663         entry != container.start_up_urls().end();
664         ++entry) {
665      urls->Append(new base::StringValue(*entry));
666    }
667    policies->Set(key::kDeviceStartUpUrls,
668                  POLICY_LEVEL_MANDATORY,
669                  POLICY_SCOPE_MACHINE,
670                  urls,
671                  NULL);
672  }
673
674  if (policy.has_system_timezone()) {
675    if (policy.system_timezone().has_timezone()) {
676      policies->Set(key::kSystemTimezone,
677                    POLICY_LEVEL_MANDATORY,
678                    POLICY_SCOPE_MACHINE,
679                    new base::StringValue(
680                        policy.system_timezone().timezone()),
681                    NULL);
682    }
683  }
684
685  if (policy.has_use_24hour_clock()) {
686    if (policy.use_24hour_clock().has_use_24hour_clock()) {
687      policies->Set(key::kSystemUse24HourClock,
688                    POLICY_LEVEL_MANDATORY,
689                    POLICY_SCOPE_MACHINE,
690                    new base::FundamentalValue(
691                        policy.use_24hour_clock().use_24hour_clock()),
692                    NULL);
693    }
694  }
695
696  if (policy.has_allow_redeem_offers()) {
697    const em::AllowRedeemChromeOsRegistrationOffersProto& container(
698        policy.allow_redeem_offers());
699    if (container.has_allow_redeem_offers()) {
700      policies->Set(key::kDeviceAllowRedeemChromeOsRegistrationOffers,
701                    POLICY_LEVEL_MANDATORY,
702                    POLICY_SCOPE_MACHINE,
703                    new base::FundamentalValue(
704                        container.allow_redeem_offers()),
705                    NULL);
706    }
707  }
708
709  if (policy.has_uptime_limit()) {
710    const em::UptimeLimitProto& container(policy.uptime_limit());
711    if (container.has_uptime_limit()) {
712      policies->Set(key::kUptimeLimit,
713                    POLICY_LEVEL_MANDATORY,
714                    POLICY_SCOPE_MACHINE,
715                    DecodeIntegerValue(container.uptime_limit()).release(),
716                    NULL);
717    }
718  }
719
720  if (policy.has_start_up_flags()) {
721    const em::StartUpFlagsProto& container(policy.start_up_flags());
722    base::ListValue* flags = new base::ListValue();
723    RepeatedPtrField<std::string>::const_iterator entry;
724    for (entry = container.flags().begin();
725         entry != container.flags().end();
726         ++entry) {
727      flags->Append(new base::StringValue(*entry));
728    }
729    policies->Set(key::kDeviceStartUpFlags,
730                  POLICY_LEVEL_MANDATORY,
731                  POLICY_SCOPE_MACHINE,
732                  flags,
733                  NULL);
734  }
735
736  if (policy.has_variations_parameter()) {
737    if (policy.variations_parameter().has_parameter()) {
738      policies->Set(key::kDeviceVariationsRestrictParameter,
739                    POLICY_LEVEL_MANDATORY,
740                    POLICY_SCOPE_MACHINE,
741                    new base::StringValue(
742                        policy.variations_parameter().parameter()),
743                    NULL);
744    }
745  }
746
747  if (policy.has_attestation_settings()) {
748    if (policy.attestation_settings().has_attestation_enabled()) {
749      policies->Set(key::kAttestationEnabledForDevice,
750                    POLICY_LEVEL_MANDATORY,
751                    POLICY_SCOPE_MACHINE,
752                    new base::FundamentalValue(
753                        policy.attestation_settings().attestation_enabled()),
754                    NULL);
755    }
756    if (policy.attestation_settings().has_content_protection_enabled()) {
757      policies->Set(
758          key::kAttestationForContentProtectionEnabled,
759          POLICY_LEVEL_MANDATORY,
760          POLICY_SCOPE_MACHINE,
761          new base::FundamentalValue(
762              policy.attestation_settings().content_protection_enabled()),
763          NULL);
764    }
765  }
766
767  if (policy.has_login_screen_power_management()) {
768    const em::LoginScreenPowerManagementProto& container(
769        policy.login_screen_power_management());
770    if (container.has_login_screen_power_management()) {
771      scoped_ptr<base::Value> decoded_json;
772      decoded_json = DecodeJsonStringAndDropUnknownBySchema(
773          container.login_screen_power_management(),
774          key::kDeviceLoginScreenPowerManagement);
775      if (decoded_json) {
776        policies->Set(key::kDeviceLoginScreenPowerManagement,
777                      POLICY_LEVEL_MANDATORY,
778                      POLICY_SCOPE_MACHINE,
779                      decoded_json.release(),
780                      NULL);
781      }
782    }
783  }
784
785  if (policy.has_system_settings()) {
786    const em::SystemSettingsProto& container(policy.system_settings());
787    if (container.has_block_devmode()) {
788      policies->Set(
789          key::kDeviceBlockDevmode,
790          POLICY_LEVEL_MANDATORY,
791          POLICY_SCOPE_MACHINE,
792          new base::FundamentalValue(container.block_devmode()),
793          NULL);
794    }
795  }
796}
797
798}  // namespace
799
800void DecodeDevicePolicy(const em::ChromeDeviceSettingsProto& policy,
801                        PolicyMap* policies,
802                        EnterpriseInstallAttributes* install_attributes) {
803  // TODO(achuith): Remove this once crbug.com/263527 is resolved.
804  VLOG(2) << "DecodeDevicePolicy " << policy.SerializeAsString();
805
806  // Decode the various groups of policies.
807  DecodeLoginPolicies(policy, policies);
808  DecodeKioskPolicies(policy, policies, install_attributes);
809  DecodeNetworkPolicies(policy, policies, install_attributes);
810  DecodeReportingPolicies(policy, policies);
811  DecodeAutoUpdatePolicies(policy, policies);
812  DecodeAccessibilityPolicies(policy, policies);
813  DecodeGenericPolicies(policy, policies);
814}
815
816}  // namespace policy
817