• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 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 "components/policy/core/common/policy_proto_decoders.h"
6 
7 #include <limits>
8 #include <memory>
9 
10 #include "base/json/json_reader.h"
11 #include "base/logging.h"
12 #include "base/values.h"
13 #include "components/policy/core/common/cloud/cloud_external_data_manager.h"
14 #include "components/policy/core/common/policy_map.h"
15 #include "components/policy/policy_constants.h"
16 #include "components/policy/proto/cloud_policy.pb.h"
17 
18 namespace policy {
19 
20 namespace em = enterprise_management;
21 
22 namespace {
23 
24 // Returns true and sets |level| to a PolicyLevel if the policy has been set
25 // at that level. Returns false if the policy is not set, or has been set at
26 // the level of PolicyOptions::UNSET.
27 template <class AnyPolicyProto>
GetPolicyLevel(const AnyPolicyProto & policy_proto,PolicyLevel * level)28 bool GetPolicyLevel(const AnyPolicyProto& policy_proto, PolicyLevel* level) {
29   if (!policy_proto.has_value()) {
30     return false;
31   }
32   if (!policy_proto.has_policy_options()) {
33     *level = POLICY_LEVEL_MANDATORY;  // Default level.
34     return true;
35   }
36   switch (policy_proto.policy_options().mode()) {
37     case em::PolicyOptions::MANDATORY:
38       *level = POLICY_LEVEL_MANDATORY;
39       return true;
40     case em::PolicyOptions::RECOMMENDED:
41       *level = POLICY_LEVEL_RECOMMENDED;
42       return true;
43     case em::PolicyOptions::UNSET:
44       return false;
45   }
46 }
47 
48 // Convert a BooleanPolicyProto to a bool base::Value.
DecodeBooleanProto(const em::BooleanPolicyProto & proto)49 std::unique_ptr<base::Value> DecodeBooleanProto(
50     const em::BooleanPolicyProto& proto) {
51   return std::make_unique<base::Value>(proto.value());
52 }
53 
54 // Convert an IntegerPolicyProto to an int base::Value.
DecodeIntegerProto(const em::IntegerPolicyProto & proto,std::string * error)55 std::unique_ptr<base::Value> DecodeIntegerProto(
56     const em::IntegerPolicyProto& proto,
57     std::string* error) {
58   google::protobuf::int64 value = proto.value();
59 
60   if (value < std::numeric_limits<int>::min() ||
61       value > std::numeric_limits<int>::max()) {
62     LOG(WARNING) << "Integer value " << value << " out of numeric limits";
63     *error = "Number out of range - invalid int32";
64     return std::make_unique<base::Value>(std::to_string(value));
65   }
66 
67   return std::make_unique<base::Value>(static_cast<int>(value));
68 }
69 
70 // Convert a StringPolicyProto to a string base::Value.
DecodeStringProto(const em::StringPolicyProto & proto)71 std::unique_ptr<base::Value> DecodeStringProto(
72     const em::StringPolicyProto& proto) {
73   return std::make_unique<base::Value>(proto.value());
74 }
75 
76 // Convert a StringListPolicyProto to a List base::Value, where each list value
77 // is of Type::STRING.
DecodeStringListProto(const em::StringListPolicyProto & proto)78 std::unique_ptr<base::Value> DecodeStringListProto(
79     const em::StringListPolicyProto& proto) {
80   auto list_value = std::make_unique<base::ListValue>();
81   for (const auto& entry : proto.value().entries())
82     list_value->AppendString(entry);
83   return std::move(list_value);
84 }
85 
86 // Convert a StringPolicyProto to a base::Value of any type (for example,
87 // Type::DICTIONARY or Type::LIST) by parsing it as JSON.
DecodeJsonProto(const em::StringPolicyProto & proto,std::string * error)88 std::unique_ptr<base::Value> DecodeJsonProto(const em::StringPolicyProto& proto,
89                                              std::string* error) {
90   const std::string& json = proto.value();
91   std::unique_ptr<base::Value> parsed_value =
92       base::JSONReader::ReadAndReturnError(
93           json, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, error);
94 
95   if (!parsed_value) {
96     // Can't parse as JSON so return it as a string, and leave it to the handler
97     // to validate.
98     LOG(WARNING) << "Invalid JSON: " << json;
99     return std::make_unique<base::Value>(json);
100   }
101 
102   // Accept any Value type that parsed as JSON, and leave it to the handler to
103   // convert and check the concrete type.
104   error->clear();
105   return parsed_value;
106 }
107 
108 }  // namespace
109 
DecodeProtoFields(const em::CloudPolicySettings & policy,base::WeakPtr<CloudExternalDataManager> external_data_manager,PolicySource source,PolicyScope scope,PolicyMap * map)110 void DecodeProtoFields(
111     const em::CloudPolicySettings& policy,
112     base::WeakPtr<CloudExternalDataManager> external_data_manager,
113     PolicySource source,
114     PolicyScope scope,
115     PolicyMap* map) {
116   PolicyLevel level;
117 
118   // Access arrays are terminated by a struct that contains only nullptrs.
119   for (const BooleanPolicyAccess* access = &kBooleanPolicyAccess[0];
120        access->policy_key; access++) {
121     if (!(policy.*access->has_proto)())
122       continue;
123 
124     const em::BooleanPolicyProto& proto = (policy.*access->get_proto)();
125     if (!GetPolicyLevel(proto, &level))
126       continue;
127 
128     map->Set(access->policy_key, level, scope, source,
129              DecodeBooleanProto(proto), nullptr);
130   }
131 
132   for (const IntegerPolicyAccess* access = &kIntegerPolicyAccess[0];
133        access->policy_key; access++) {
134     if (!(policy.*access->has_proto)())
135       continue;
136 
137     const em::IntegerPolicyProto& proto = (policy.*access->get_proto)();
138     if (!GetPolicyLevel(proto, &level))
139       continue;
140 
141     std::string error;
142     map->Set(access->policy_key, level, scope, source,
143              DecodeIntegerProto(proto, &error), nullptr);
144     if (!error.empty())
145       map->SetError(access->policy_key, error);
146   }
147 
148   for (const StringPolicyAccess* access = &kStringPolicyAccess[0];
149        access->policy_key; access++) {
150     if (!(policy.*access->has_proto)())
151       continue;
152 
153     const em::StringPolicyProto& proto = (policy.*access->get_proto)();
154     if (!GetPolicyLevel(proto, &level))
155       continue;
156 
157     std::string error;
158     std::unique_ptr<base::Value> value =
159         (access->type == StringPolicyType::STRING)
160             ? DecodeStringProto(proto)
161             : DecodeJsonProto(proto, &error);
162 
163     std::unique_ptr<ExternalDataFetcher> external_data_fetcher =
164         (access->type == StringPolicyType::EXTERNAL)
165             ? std::make_unique<ExternalDataFetcher>(external_data_manager,
166                                                     access->policy_key)
167             : nullptr;
168 
169     map->Set(access->policy_key, level, scope, source, std::move(value),
170              std::move(external_data_fetcher));
171     if (!error.empty())
172       map->SetError(access->policy_key, error);
173   }
174 
175   for (const StringListPolicyAccess* access = &kStringListPolicyAccess[0];
176        access->policy_key; access++) {
177     if (!(policy.*access->has_proto)())
178       continue;
179 
180     const em::StringListPolicyProto& proto = (policy.*access->get_proto)();
181     if (!GetPolicyLevel(proto, &level))
182       continue;
183 
184     map->Set(access->policy_key, level, scope, source,
185              DecodeStringListProto(proto), nullptr);
186   }
187 }
188 
189 }  // namespace policy