| OLD | NEW |
| (Empty) |
| 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/policy/user_policy_cache.h" | |
| 6 | |
| 7 #include <limits> | |
| 8 #include <string> | |
| 9 | |
| 10 #include "base/basictypes.h" | |
| 11 #include "base/file_path.h" | |
| 12 #include "base/logging.h" | |
| 13 #include "base/metrics/histogram.h" | |
| 14 #include "chrome/browser/policy/enterprise_metrics.h" | |
| 15 #include "chrome/browser/policy/policy_map.h" | |
| 16 #include "chrome/browser/policy/proto/cloud_policy.pb.h" | |
| 17 #include "chrome/browser/policy/proto/device_management_local.pb.h" | |
| 18 #include "chrome/browser/policy/proto/old_generic_format.pb.h" | |
| 19 | |
| 20 namespace em = enterprise_management; | |
| 21 | |
| 22 namespace policy { | |
| 23 | |
| 24 // Decodes a CloudPolicySettings object into a PolicyMap. All the policies will | |
| 25 // be POLICY_SCOPE_USER. The PolicyLevel is decoded from the protobuf. | |
| 26 // The implementation is generated code in policy/cloud_policy_generated.cc. | |
| 27 void DecodePolicy(const em::CloudPolicySettings& policy, PolicyMap* map); | |
| 28 | |
| 29 UserPolicyCache::UserPolicyCache(const FilePath& backing_file_path, | |
| 30 bool wait_for_policy_fetch) | |
| 31 : ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)), | |
| 32 disk_cache_ready_(false), | |
| 33 fetch_ready_(!wait_for_policy_fetch) { | |
| 34 disk_cache_ = new UserPolicyDiskCache(weak_ptr_factory_.GetWeakPtr(), | |
| 35 backing_file_path); | |
| 36 } | |
| 37 | |
| 38 UserPolicyCache::~UserPolicyCache() { | |
| 39 } | |
| 40 | |
| 41 void UserPolicyCache::Load() { | |
| 42 disk_cache_->Load(); | |
| 43 } | |
| 44 | |
| 45 bool UserPolicyCache::SetPolicy(const em::PolicyFetchResponse& policy) { | |
| 46 base::Time now = base::Time::NowFromSystemTime(); | |
| 47 set_last_policy_refresh_time(now); | |
| 48 base::Time timestamp; | |
| 49 if (!SetPolicyInternal(policy, ×tamp, false)) | |
| 50 return false; | |
| 51 UMA_HISTOGRAM_ENUMERATION(kMetricPolicy, kMetricPolicyFetchOK, | |
| 52 kMetricPolicySize); | |
| 53 | |
| 54 if (timestamp > base::Time::NowFromSystemTime() + | |
| 55 base::TimeDelta::FromMinutes(1)) { | |
| 56 LOG(WARNING) << "Server returned policy with timestamp from the future, " | |
| 57 "not persisting to disk."; | |
| 58 return false; | |
| 59 } | |
| 60 | |
| 61 em::CachedCloudPolicyResponse cached_policy; | |
| 62 cached_policy.mutable_cloud_policy()->CopyFrom(policy); | |
| 63 disk_cache_->Store(cached_policy); | |
| 64 return true; | |
| 65 } | |
| 66 | |
| 67 void UserPolicyCache::SetUnmanaged() { | |
| 68 DCHECK(CalledOnValidThread()); | |
| 69 SetUnmanagedInternal(base::Time::NowFromSystemTime()); | |
| 70 | |
| 71 em::CachedCloudPolicyResponse cached_policy; | |
| 72 cached_policy.set_unmanaged(true); | |
| 73 cached_policy.set_timestamp(base::Time::NowFromSystemTime().ToTimeT()); | |
| 74 disk_cache_->Store(cached_policy); | |
| 75 } | |
| 76 | |
| 77 void UserPolicyCache::SetFetchingDone() { | |
| 78 CloudPolicyCacheBase::SetFetchingDone(); | |
| 79 if (!fetch_ready_) | |
| 80 DVLOG(1) << "SetFetchingDone, cache is now fetch_ready_"; | |
| 81 fetch_ready_ = true; | |
| 82 CheckIfReady(); | |
| 83 } | |
| 84 | |
| 85 void UserPolicyCache::OnDiskCacheLoaded( | |
| 86 UserPolicyDiskCache::LoadResult result, | |
| 87 const em::CachedCloudPolicyResponse& cached_response) { | |
| 88 if (IsReady()) | |
| 89 return; | |
| 90 | |
| 91 if (result == UserPolicyDiskCache::LOAD_RESULT_SUCCESS) { | |
| 92 if (cached_response.unmanaged()) { | |
| 93 SetUnmanagedInternal(base::Time::FromTimeT(cached_response.timestamp())); | |
| 94 } else if (cached_response.has_cloud_policy()) { | |
| 95 base::Time timestamp; | |
| 96 if (SetPolicyInternal(cached_response.cloud_policy(), ×tamp, true)) | |
| 97 set_last_policy_refresh_time(timestamp); | |
| 98 } | |
| 99 } | |
| 100 | |
| 101 // Ready to feed policy up the chain! | |
| 102 disk_cache_ready_ = true; | |
| 103 CheckIfReady(); | |
| 104 } | |
| 105 | |
| 106 bool UserPolicyCache::DecodePolicyData(const em::PolicyData& policy_data, | |
| 107 PolicyMap* policies) { | |
| 108 // TODO(jkummerow): Verify policy_data.device_token(). Needs final | |
| 109 // specification which token we're actually sending / expecting to get back. | |
| 110 em::CloudPolicySettings policy; | |
| 111 if (!policy.ParseFromString(policy_data.policy_value())) { | |
| 112 LOG(WARNING) << "Failed to parse CloudPolicySettings protobuf."; | |
| 113 return false; | |
| 114 } | |
| 115 DecodePolicy(policy, policies); | |
| 116 MaybeDecodeOldstylePolicy(policy_data.policy_value(), policies); | |
| 117 return true; | |
| 118 } | |
| 119 | |
| 120 void UserPolicyCache::CheckIfReady() { | |
| 121 if (!IsReady() && disk_cache_ready_ && fetch_ready_) | |
| 122 SetReady(); | |
| 123 } | |
| 124 | |
| 125 // Everything below is only needed for supporting old-style GenericNamedValue | |
| 126 // based policy data and can be removed once this support is no longer needed. | |
| 127 | |
| 128 using google::protobuf::RepeatedField; | |
| 129 using google::protobuf::RepeatedPtrField; | |
| 130 | |
| 131 void UserPolicyCache::MaybeDecodeOldstylePolicy( | |
| 132 const std::string& policy_data, | |
| 133 PolicyMap* policies) { | |
| 134 // Return immediately if we already have policy information in the maps. | |
| 135 if (!policies->empty()) | |
| 136 return; | |
| 137 em::LegacyChromeSettingsProto policy; | |
| 138 // Return if the input string doesn't match the protobuf definition. | |
| 139 if (!policy.ParseFromString(policy_data)) | |
| 140 return; | |
| 141 // Return if there's no old-style policy to decode. | |
| 142 if (policy.named_value_size() == 0) | |
| 143 return; | |
| 144 | |
| 145 // Inspect GenericNamedValues and decode them. | |
| 146 DictionaryValue result; | |
| 147 RepeatedPtrField<em::GenericNamedValue>::const_iterator named_value; | |
| 148 for (named_value = policy.named_value().begin(); | |
| 149 named_value != policy.named_value().end(); | |
| 150 ++named_value) { | |
| 151 if (named_value->has_value()) { | |
| 152 Value* decoded_value = DecodeValue(named_value->value()); | |
| 153 if (decoded_value) | |
| 154 result.Set(named_value->name(), decoded_value); | |
| 155 } | |
| 156 } | |
| 157 policies->LoadFrom(&result, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER); | |
| 158 } | |
| 159 | |
| 160 Value* UserPolicyCache::DecodeIntegerValue( | |
| 161 google::protobuf::int64 value) const { | |
| 162 if (value < std::numeric_limits<int>::min() || | |
| 163 value > std::numeric_limits<int>::max()) { | |
| 164 LOG(WARNING) << "Integer value " << value | |
| 165 << " out of numeric limits, ignoring."; | |
| 166 return NULL; | |
| 167 } | |
| 168 | |
| 169 return Value::CreateIntegerValue(static_cast<int>(value)); | |
| 170 } | |
| 171 | |
| 172 Value* UserPolicyCache::DecodeValue(const em::GenericValue& value) const { | |
| 173 if (!value.has_value_type()) | |
| 174 return NULL; | |
| 175 | |
| 176 switch (value.value_type()) { | |
| 177 case em::GenericValue::VALUE_TYPE_BOOL: | |
| 178 if (value.has_bool_value()) | |
| 179 return Value::CreateBooleanValue(value.bool_value()); | |
| 180 return NULL; | |
| 181 case em::GenericValue::VALUE_TYPE_INT64: | |
| 182 if (value.has_int64_value()) | |
| 183 return DecodeIntegerValue(value.int64_value()); | |
| 184 return NULL; | |
| 185 case em::GenericValue::VALUE_TYPE_STRING: | |
| 186 if (value.has_string_value()) | |
| 187 return Value::CreateStringValue(value.string_value()); | |
| 188 return NULL; | |
| 189 case em::GenericValue::VALUE_TYPE_DOUBLE: | |
| 190 if (value.has_double_value()) | |
| 191 return Value::CreateDoubleValue(value.double_value()); | |
| 192 return NULL; | |
| 193 case em::GenericValue::VALUE_TYPE_BYTES: | |
| 194 if (value.has_bytes_value()) { | |
| 195 std::string bytes = value.bytes_value(); | |
| 196 return base::BinaryValue::CreateWithCopiedBuffer(bytes.c_str(), | |
| 197 bytes.size()); | |
| 198 } | |
| 199 return NULL; | |
| 200 case em::GenericValue::VALUE_TYPE_BOOL_ARRAY: { | |
| 201 ListValue* list = new ListValue; | |
| 202 RepeatedField<bool>::const_iterator i; | |
| 203 for (i = value.bool_array().begin(); i != value.bool_array().end(); ++i) | |
| 204 list->Append(Value::CreateBooleanValue(*i)); | |
| 205 return list; | |
| 206 } | |
| 207 case em::GenericValue::VALUE_TYPE_INT64_ARRAY: { | |
| 208 ListValue* list = new ListValue; | |
| 209 RepeatedField<google::protobuf::int64>::const_iterator i; | |
| 210 for (i = value.int64_array().begin(); | |
| 211 i != value.int64_array().end(); ++i) { | |
| 212 Value* int_value = DecodeIntegerValue(*i); | |
| 213 if (int_value) | |
| 214 list->Append(int_value); | |
| 215 } | |
| 216 return list; | |
| 217 } | |
| 218 case em::GenericValue::VALUE_TYPE_STRING_ARRAY: { | |
| 219 ListValue* list = new ListValue; | |
| 220 RepeatedPtrField<std::string>::const_iterator i; | |
| 221 for (i = value.string_array().begin(); | |
| 222 i != value.string_array().end(); ++i) | |
| 223 list->Append(Value::CreateStringValue(*i)); | |
| 224 return list; | |
| 225 } | |
| 226 case em::GenericValue::VALUE_TYPE_DOUBLE_ARRAY: { | |
| 227 ListValue* list = new ListValue; | |
| 228 RepeatedField<double>::const_iterator i; | |
| 229 for (i = value.double_array().begin(); | |
| 230 i != value.double_array().end(); ++i) | |
| 231 list->Append(Value::CreateDoubleValue(*i)); | |
| 232 return list; | |
| 233 } | |
| 234 default: | |
| 235 NOTREACHED() << "Unhandled value type"; | |
| 236 } | |
| 237 | |
| 238 return NULL; | |
| 239 } | |
| 240 | |
| 241 } // namespace policy | |
| OLD | NEW |