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/policy_loader_mac.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/bind_helpers.h" | |
9 #include "base/callback.h" | |
10 #include "base/file_util.h" | |
11 #include "base/mac/foundation_util.h" | |
12 #include "base/mac/scoped_cftyperef.h" | |
13 #include "base/path_service.h" | |
14 #include "base/platform_file.h" | |
15 #include "base/sequenced_task_runner.h" | |
16 #include "base/strings/sys_string_conversions.h" | |
17 #include "base/values.h" | |
18 #include "chrome/browser/policy/policy_load_status.h" | |
19 #include "components/policy/core/common/external_data_fetcher.h" | |
20 #include "components/policy/core/common/policy_bundle.h" | |
21 #include "components/policy/core/common/policy_map.h" | |
22 #include "components/policy/core/common/preferences_mac.h" | |
23 #include "components/policy/core/common/schema.h" | |
24 #include "components/policy/core/common/schema_map.h" | |
25 | |
26 using base::mac::CFCast; | |
27 using base::ScopedCFTypeRef; | |
28 | |
29 namespace policy { | |
30 | |
31 namespace { | |
32 | |
33 // Callback function for CFDictionaryApplyFunction. |key| and |value| are an | |
34 // entry of the CFDictionary that should be converted into an equivalent entry | |
35 // in the DictionaryValue in |context|. | |
36 void DictionaryEntryToValue(const void* key, const void* value, void* context) { | |
37 if (CFStringRef cf_key = CFCast<CFStringRef>(key)) { | |
38 base::Value* converted = | |
39 PolicyLoaderMac::CreateValueFromProperty( | |
40 static_cast<CFPropertyListRef>(value)); | |
41 if (converted) { | |
42 const std::string string = base::SysCFStringRefToUTF8(cf_key); | |
43 static_cast<base::DictionaryValue *>(context)->Set(string, converted); | |
44 } | |
45 } | |
46 } | |
47 | |
48 // Callback function for CFArrayApplyFunction. |value| is an entry of the | |
49 // CFArray that should be converted into an equivalent entry in the ListValue | |
50 // in |context|. | |
51 void ArrayEntryToValue(const void* value, void* context) { | |
52 base::Value* converted = | |
53 PolicyLoaderMac::CreateValueFromProperty( | |
54 static_cast<CFPropertyListRef>(value)); | |
55 if (converted) | |
56 static_cast<base::ListValue *>(context)->Append(converted); | |
57 } | |
58 | |
59 } // namespace | |
60 | |
61 PolicyLoaderMac::PolicyLoaderMac( | |
62 scoped_refptr<base::SequencedTaskRunner> task_runner, | |
63 const base::FilePath& managed_policy_path, | |
64 MacPreferences* preferences) | |
65 : AsyncPolicyLoader(task_runner), | |
66 preferences_(preferences), | |
67 managed_policy_path_(managed_policy_path) {} | |
68 | |
69 PolicyLoaderMac::~PolicyLoaderMac() {} | |
70 | |
71 void PolicyLoaderMac::InitOnBackgroundThread() { | |
72 if (!managed_policy_path_.empty()) { | |
73 watcher_.Watch( | |
74 managed_policy_path_, false, | |
75 base::Bind(&PolicyLoaderMac::OnFileUpdated, base::Unretained(this))); | |
76 } | |
77 } | |
78 | |
79 scoped_ptr<PolicyBundle> PolicyLoaderMac::Load() { | |
80 preferences_->AppSynchronize(kCFPreferencesCurrentApplication); | |
81 scoped_ptr<PolicyBundle> bundle(new PolicyBundle()); | |
82 | |
83 // Load Chrome's policy. | |
84 PolicyMap& chrome_policy = | |
85 bundle->Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())); | |
86 | |
87 PolicyLoadStatusSample status; | |
88 bool policy_present = false; | |
89 const Schema* schema = | |
90 schema_map()->GetSchema(PolicyNamespace(POLICY_DOMAIN_CHROME, "")); | |
91 for (Schema::Iterator it = schema->GetPropertiesIterator(); | |
92 !it.IsAtEnd(); it.Advance()) { | |
93 base::ScopedCFTypeRef<CFStringRef> name( | |
94 base::SysUTF8ToCFStringRef(it.key())); | |
95 base::ScopedCFTypeRef<CFPropertyListRef> value( | |
96 preferences_->CopyAppValue(name, kCFPreferencesCurrentApplication)); | |
97 if (!value.get()) | |
98 continue; | |
99 policy_present = true; | |
100 bool forced = | |
101 preferences_->AppValueIsForced(name, kCFPreferencesCurrentApplication); | |
102 PolicyLevel level = forced ? POLICY_LEVEL_MANDATORY : | |
103 POLICY_LEVEL_RECOMMENDED; | |
104 // TODO(joaodasilva): figure the policy scope. | |
105 base::Value* policy = CreateValueFromProperty(value); | |
106 if (policy) | |
107 chrome_policy.Set(it.key(), level, POLICY_SCOPE_USER, policy, NULL); | |
108 else | |
109 status.Add(POLICY_LOAD_STATUS_PARSE_ERROR); | |
110 } | |
111 | |
112 if (!policy_present) | |
113 status.Add(POLICY_LOAD_STATUS_NO_POLICY); | |
114 | |
115 // Load policy for the registered components. | |
116 LoadPolicyForDomain(POLICY_DOMAIN_EXTENSIONS, "extensions", bundle.get()); | |
117 | |
118 return bundle.Pass(); | |
119 } | |
120 | |
121 base::Time PolicyLoaderMac::LastModificationTime() { | |
122 base::PlatformFileInfo file_info; | |
123 if (!base::GetFileInfo(managed_policy_path_, &file_info) || | |
124 file_info.is_directory) { | |
125 return base::Time(); | |
126 } | |
127 | |
128 return file_info.last_modified; | |
129 } | |
130 | |
131 // static | |
132 base::Value* PolicyLoaderMac::CreateValueFromProperty( | |
133 CFPropertyListRef property) { | |
134 if (CFCast<CFNullRef>(property)) | |
135 return base::Value::CreateNullValue(); | |
136 | |
137 if (CFBooleanRef boolean = CFCast<CFBooleanRef>(property)) | |
138 return base::Value::CreateBooleanValue(CFBooleanGetValue(boolean)); | |
139 | |
140 if (CFNumberRef number = CFCast<CFNumberRef>(property)) { | |
141 // CFNumberGetValue() converts values implicitly when the conversion is not | |
142 // lossy. Check the type before trying to convert. | |
143 if (CFNumberIsFloatType(number)) { | |
144 double double_value; | |
145 if (CFNumberGetValue(number, kCFNumberDoubleType, &double_value)) | |
146 return base::Value::CreateDoubleValue(double_value); | |
147 } else { | |
148 int int_value; | |
149 if (CFNumberGetValue(number, kCFNumberIntType, &int_value)) | |
150 return base::Value::CreateIntegerValue(int_value); | |
151 } | |
152 } | |
153 | |
154 if (CFStringRef string = CFCast<CFStringRef>(property)) | |
155 return base::Value::CreateStringValue(base::SysCFStringRefToUTF8(string)); | |
156 | |
157 if (CFDictionaryRef dict = CFCast<CFDictionaryRef>(property)) { | |
158 base::DictionaryValue* dict_value = new base::DictionaryValue(); | |
159 CFDictionaryApplyFunction(dict, DictionaryEntryToValue, dict_value); | |
160 return dict_value; | |
161 } | |
162 | |
163 if (CFArrayRef array = CFCast<CFArrayRef>(property)) { | |
164 base::ListValue* list_value = new base::ListValue(); | |
165 CFArrayApplyFunction(array, | |
166 CFRangeMake(0, CFArrayGetCount(array)), | |
167 ArrayEntryToValue, | |
168 list_value); | |
169 return list_value; | |
170 } | |
171 | |
172 return NULL; | |
173 } | |
174 | |
175 void PolicyLoaderMac::LoadPolicyForDomain( | |
176 PolicyDomain domain, | |
177 const std::string& domain_name, | |
178 PolicyBundle* bundle) { | |
179 std::string id_prefix(base::mac::BaseBundleID()); | |
180 id_prefix.append(".").append(domain_name).append("."); | |
181 | |
182 const ComponentMap* components = schema_map()->GetComponents(domain); | |
183 if (!components) | |
184 return; | |
185 | |
186 for (ComponentMap::const_iterator it = components->begin(); | |
187 it != components->end(); ++it) { | |
188 PolicyMap policy; | |
189 LoadPolicyForComponent(id_prefix + it->first, it->second, &policy); | |
190 if (!policy.empty()) | |
191 bundle->Get(PolicyNamespace(domain, it->first)).Swap(&policy); | |
192 } | |
193 } | |
194 | |
195 void PolicyLoaderMac::LoadPolicyForComponent( | |
196 const std::string& bundle_id_string, | |
197 const Schema& schema, | |
198 PolicyMap* policy) { | |
199 // TODO(joaodasilva): Extensions may be registered in a ComponentMap | |
200 // without a schema, to allow a graceful update of the Legacy Browser Support | |
201 // extension on Windows. Remove this check once that support is removed. | |
202 if (!schema.valid()) | |
203 return; | |
204 | |
205 base::ScopedCFTypeRef<CFStringRef> bundle_id( | |
206 base::SysUTF8ToCFStringRef(bundle_id_string)); | |
207 preferences_->AppSynchronize(bundle_id); | |
208 | |
209 for (Schema::Iterator it = schema.GetPropertiesIterator(); | |
210 !it.IsAtEnd(); it.Advance()) { | |
211 base::ScopedCFTypeRef<CFStringRef> pref_name( | |
212 base::SysUTF8ToCFStringRef(it.key())); | |
213 base::ScopedCFTypeRef<CFPropertyListRef> value( | |
214 preferences_->CopyAppValue(pref_name, bundle_id)); | |
215 if (!value.get()) | |
216 continue; | |
217 bool forced = | |
218 preferences_->AppValueIsForced(pref_name, bundle_id); | |
219 PolicyLevel level = forced ? POLICY_LEVEL_MANDATORY : | |
220 POLICY_LEVEL_RECOMMENDED; | |
221 scoped_ptr<base::Value> policy_value(CreateValueFromProperty(value)); | |
222 if (policy_value) { | |
223 policy->Set(it.key(), level, POLICY_SCOPE_USER, | |
224 policy_value.release(), NULL); | |
225 } | |
226 } | |
227 } | |
228 | |
229 void PolicyLoaderMac::OnFileUpdated(const base::FilePath& path, bool error) { | |
230 if (!error) | |
231 Reload(false); | |
232 } | |
233 | |
234 } // namespace policy | |
OLD | NEW |